]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
1. fixed bug with the index of the last column in EVT_COL_CLICK being shifted
[wxWidgets.git] / src / generic / grid.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: grid.cpp
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5 // Modified by:
6 // Created: 1/08/1999
7 // RCS-ID: $Id$
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "grid.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #include "wx/defs.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
26 #include "gridg.cpp"
27 #else
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/log.h"
34 #endif
35
36 #include "wx/textfile.h"
37 #include "wx/generic/grid.h"
38
39 // ----------------------------------------------------------------------------
40 // array classes instantiation
41 // ----------------------------------------------------------------------------
42
43 struct wxGridCellWithAttr
44 {
45 wxGridCellWithAttr(int row, int col, const wxGridCellAttr *pAttr)
46 : coords(row, col), attr(*pAttr)
47 {
48 }
49
50 wxGridCellCoords coords;
51 wxGridCellAttr attr;
52 };
53
54 WX_DECLARE_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
55
56 #include "wx/arrimpl.cpp"
57
58 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
59 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
60
61 // ----------------------------------------------------------------------------
62 // private classes
63 // ----------------------------------------------------------------------------
64
65 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
66 {
67 public:
68 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
69 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
70 const wxPoint &pos, const wxSize &size );
71
72 private:
73 wxGrid *m_owner;
74
75 void OnPaint( wxPaintEvent& event );
76 void OnMouseEvent( wxMouseEvent& event );
77 void OnKeyDown( wxKeyEvent& event );
78
79 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
80 DECLARE_EVENT_TABLE()
81 };
82
83
84 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
85 {
86 public:
87 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
88 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
89 const wxPoint &pos, const wxSize &size );
90
91 private:
92 wxGrid *m_owner;
93
94 void OnPaint( wxPaintEvent &event );
95 void OnMouseEvent( wxMouseEvent& event );
96 void OnKeyDown( wxKeyEvent& event );
97
98 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
99 DECLARE_EVENT_TABLE()
100 };
101
102
103 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
104 {
105 public:
106 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
107 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
108 const wxPoint &pos, const wxSize &size );
109
110 private:
111 wxGrid *m_owner;
112
113 void OnMouseEvent( wxMouseEvent& event );
114 void OnKeyDown( wxKeyEvent& event );
115 void OnPaint( wxPaintEvent& event );
116
117 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
118 DECLARE_EVENT_TABLE()
119 };
120
121 class WXDLLEXPORT wxGridWindow : public wxPanel
122 {
123 public:
124 wxGridWindow()
125 {
126 m_owner = (wxGrid *)NULL;
127 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
128 m_colLabelWin = (wxGridColLabelWindow *)NULL;
129 }
130
131 wxGridWindow( wxGrid *parent,
132 wxGridRowLabelWindow *rowLblWin,
133 wxGridColLabelWindow *colLblWin,
134 wxWindowID id, const wxPoint &pos, const wxSize &size );
135 ~wxGridWindow();
136
137 void ScrollWindow( int dx, int dy, const wxRect *rect );
138
139 private:
140 wxGrid *m_owner;
141 wxGridRowLabelWindow *m_rowLabelWin;
142 wxGridColLabelWindow *m_colLabelWin;
143
144 void OnPaint( wxPaintEvent &event );
145 void OnMouseEvent( wxMouseEvent& event );
146 void OnKeyDown( wxKeyEvent& );
147
148 DECLARE_DYNAMIC_CLASS(wxGridWindow)
149 DECLARE_EVENT_TABLE()
150 };
151
152 // the internal data representation used by wxGridCellAttrProvider
153 //
154 // TODO make it more efficient
155 class WXDLLEXPORT wxGridCellAttrProviderData
156 {
157 public:
158 void SetAttr(const wxGridCellAttr *attr, int row, int col);
159 wxGridCellAttr *GetAttr(int row, int col) const;
160
161 private:
162 // searches for the attr for given cell, returns wxNOT_FOUND if not found
163 int FindIndex(int row, int col) const;
164
165 wxGridCellWithAttrArray m_attrs;
166 };
167
168 // ----------------------------------------------------------------------------
169 // conditional compilation
170 // ----------------------------------------------------------------------------
171
172 #ifndef WXGRID_DRAW_LINES
173 #define WXGRID_DRAW_LINES 1
174 #endif
175
176 //////////////////////////////////////////////////////////////////////
177
178 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
179 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
180
181 // scroll line size
182 // TODO: fixed so far - make configurable later (and also different for x/y)
183 static const size_t GRID_SCROLL_LINE = 10;
184
185 // ----------------------------------------------------------------------------
186 // wxGridCellAttrProviderData
187 // ----------------------------------------------------------------------------
188
189 void wxGridCellAttrProviderData::SetAttr(const wxGridCellAttr *attr,
190 int row, int col)
191 {
192 int n = FindIndex(row, col);
193 if ( n == wxNOT_FOUND )
194 {
195 // add the attribute
196 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
197 }
198 else
199 {
200 if ( attr )
201 {
202 // change the attribute
203 m_attrs[(size_t)n].attr = *attr;
204 }
205 else
206 {
207 // remove this attribute
208 m_attrs.RemoveAt((size_t)n);
209 }
210 }
211
212 delete attr;
213 }
214
215 wxGridCellAttr *wxGridCellAttrProviderData::GetAttr(int row, int col) const
216 {
217 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
218
219 int n = FindIndex(row, col);
220 if ( n != wxNOT_FOUND )
221 {
222 attr = new wxGridCellAttr(m_attrs[(size_t)n].attr);
223 }
224
225 return attr;
226 }
227
228 int wxGridCellAttrProviderData::FindIndex(int row, int col) const
229 {
230 size_t count = m_attrs.GetCount();
231 for ( size_t n = 0; n < count; n++ )
232 {
233 const wxGridCellCoords& coords = m_attrs[n].coords;
234 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
235 {
236 return n;
237 }
238 }
239
240 return wxNOT_FOUND;
241 }
242
243 // ----------------------------------------------------------------------------
244 // wxGridCellAttrProvider
245 // ----------------------------------------------------------------------------
246
247 wxGridCellAttrProvider::wxGridCellAttrProvider()
248 {
249 m_data = (wxGridCellAttrProviderData *)NULL;
250 }
251
252 wxGridCellAttrProvider::~wxGridCellAttrProvider()
253 {
254 delete m_data;
255 }
256
257 void wxGridCellAttrProvider::InitData()
258 {
259 m_data = new wxGridCellAttrProviderData;
260 }
261
262 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
263 {
264 return m_data ? m_data->GetAttr(row, col) : (wxGridCellAttr *)NULL;
265 }
266
267 void wxGridCellAttrProvider::SetAttr(const wxGridCellAttr *attr,
268 int row, int col)
269 {
270 if ( !m_data )
271 InitData();
272
273 m_data->SetAttr(attr, row, col);
274 }
275
276 //////////////////////////////////////////////////////////////////////
277 //
278 // Abstract base class for grid data (the model)
279 //
280 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
281
282
283 wxGridTableBase::wxGridTableBase()
284 {
285 m_view = (wxGrid *) NULL;
286 m_attrProvider = (wxGridCellAttrProvider *) NULL;
287 }
288
289 wxGridTableBase::~wxGridTableBase()
290 {
291 delete m_attrProvider;
292 }
293
294 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
295 {
296 delete m_attrProvider;
297 m_attrProvider = attrProvider;
298 }
299
300 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
301 {
302 if ( m_attrProvider )
303 return m_attrProvider->GetAttr(row, col);
304 else
305 return (wxGridCellAttr *)NULL;
306 }
307
308 void wxGridTableBase::SetAttr(const wxGridCellAttr *attr, int row, int col )
309 {
310 if ( m_attrProvider )
311 {
312 m_attrProvider->SetAttr(attr, row, col);
313 }
314 else
315 {
316 // as we take ownership of the pointer and don't store it, we must
317 // free it now
318 delete attr;
319 }
320 }
321
322 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
323 {
324 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
325 "but your derived table class does not override this function") );
326
327 return FALSE;
328 }
329
330 bool wxGridTableBase::AppendRows( size_t numRows )
331 {
332 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
333 "but your derived table class does not override this function"));
334
335 return FALSE;
336 }
337
338 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
339 {
340 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
341 "but your derived table class does not override this function"));
342
343 return FALSE;
344 }
345
346 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
347 {
348 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
349 "but your derived table class does not override this function"));
350
351 return FALSE;
352 }
353
354 bool wxGridTableBase::AppendCols( size_t numCols )
355 {
356 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
357 "but your derived table class does not override this function"));
358
359 return FALSE;
360 }
361
362 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
363 {
364 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
365 "but your derived table class does not override this function"));
366
367 return FALSE;
368 }
369
370
371 wxString wxGridTableBase::GetRowLabelValue( int row )
372 {
373 wxString s;
374 s << row;
375 return s;
376 }
377
378 wxString wxGridTableBase::GetColLabelValue( int col )
379 {
380 // default col labels are:
381 // cols 0 to 25 : A-Z
382 // cols 26 to 675 : AA-ZZ
383 // etc.
384
385 wxString s;
386 unsigned int i, n;
387 for ( n = 1; ; n++ )
388 {
389 s += (_T('A') + (wxChar)( col%26 ));
390 col = col/26 - 1;
391 if ( col < 0 ) break;
392 }
393
394 // reverse the string...
395 wxString s2;
396 for ( i = 0; i < n; i++ )
397 {
398 s2 += s[n-i-1];
399 }
400
401 return s2;
402 }
403
404
405
406 //////////////////////////////////////////////////////////////////////
407 //
408 // Message class for the grid table to send requests and notifications
409 // to the grid view
410 //
411
412 wxGridTableMessage::wxGridTableMessage()
413 {
414 m_table = (wxGridTableBase *) NULL;
415 m_id = -1;
416 m_comInt1 = -1;
417 m_comInt2 = -1;
418 }
419
420 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
421 int commandInt1, int commandInt2 )
422 {
423 m_table = table;
424 m_id = id;
425 m_comInt1 = commandInt1;
426 m_comInt2 = commandInt2;
427 }
428
429
430
431 //////////////////////////////////////////////////////////////////////
432 //
433 // A basic grid table for string data. An object of this class will
434 // created by wxGrid if you don't specify an alternative table class.
435 //
436
437 WX_DEFINE_OBJARRAY(wxGridStringArray)
438
439 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
440
441 wxGridStringTable::wxGridStringTable()
442 : wxGridTableBase()
443 {
444 }
445
446 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
447 : wxGridTableBase()
448 {
449 int row, col;
450
451 m_data.Alloc( numRows );
452
453 wxArrayString sa;
454 sa.Alloc( numCols );
455 for ( col = 0; col < numCols; col++ )
456 {
457 sa.Add( wxEmptyString );
458 }
459
460 for ( row = 0; row < numRows; row++ )
461 {
462 m_data.Add( sa );
463 }
464 }
465
466 wxGridStringTable::~wxGridStringTable()
467 {
468 }
469
470 long wxGridStringTable::GetNumberRows()
471 {
472 return m_data.GetCount();
473 }
474
475 long wxGridStringTable::GetNumberCols()
476 {
477 if ( m_data.GetCount() > 0 )
478 return m_data[0].GetCount();
479 else
480 return 0;
481 }
482
483 wxString wxGridStringTable::GetValue( int row, int col )
484 {
485 // TODO: bounds checking
486 //
487 return m_data[row][col];
488 }
489
490 void wxGridStringTable::SetValue( int row, int col, const wxString& s )
491 {
492 // TODO: bounds checking
493 //
494 m_data[row][col] = s;
495 }
496
497 bool wxGridStringTable::IsEmptyCell( int row, int col )
498 {
499 // TODO: bounds checking
500 //
501 return (m_data[row][col] == wxEmptyString);
502 }
503
504
505 void wxGridStringTable::Clear()
506 {
507 int row, col;
508 int numRows, numCols;
509
510 numRows = m_data.GetCount();
511 if ( numRows > 0 )
512 {
513 numCols = m_data[0].GetCount();
514
515 for ( row = 0; row < numRows; row++ )
516 {
517 for ( col = 0; col < numCols; col++ )
518 {
519 m_data[row][col] = wxEmptyString;
520 }
521 }
522 }
523 }
524
525
526 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
527 {
528 size_t row, col;
529
530 size_t curNumRows = m_data.GetCount();
531 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
532
533 if ( pos >= curNumRows )
534 {
535 return AppendRows( numRows );
536 }
537
538 wxArrayString sa;
539 sa.Alloc( curNumCols );
540 for ( col = 0; col < curNumCols; col++ )
541 {
542 sa.Add( wxEmptyString );
543 }
544
545 for ( row = pos; row < pos + numRows; row++ )
546 {
547 m_data.Insert( sa, row );
548 }
549
550 if ( GetView() )
551 {
552 wxGridTableMessage msg( this,
553 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
554 pos,
555 numRows );
556
557 GetView()->ProcessTableMessage( msg );
558 }
559
560 return TRUE;
561 }
562
563 bool wxGridStringTable::AppendRows( size_t numRows )
564 {
565 size_t row, col;
566
567 size_t curNumRows = m_data.GetCount();
568 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
569
570 wxArrayString sa;
571 if ( curNumCols > 0 )
572 {
573 sa.Alloc( curNumCols );
574 for ( col = 0; col < curNumCols; col++ )
575 {
576 sa.Add( wxEmptyString );
577 }
578 }
579
580 for ( row = 0; row < numRows; row++ )
581 {
582 m_data.Add( sa );
583 }
584
585 if ( GetView() )
586 {
587 wxGridTableMessage msg( this,
588 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
589 numRows );
590
591 GetView()->ProcessTableMessage( msg );
592 }
593
594 return TRUE;
595 }
596
597 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
598 {
599 size_t n;
600
601 size_t curNumRows = m_data.GetCount();
602
603 if ( pos >= curNumRows )
604 {
605 wxString errmsg;
606 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
607 "Pos value is invalid for present table with %d rows",
608 pos, numRows, curNumRows );
609 wxFAIL_MSG( wxT(errmsg) );
610 return FALSE;
611 }
612
613 if ( numRows > curNumRows - pos )
614 {
615 numRows = curNumRows - pos;
616 }
617
618 if ( numRows >= curNumRows )
619 {
620 m_data.Empty(); // don't release memory just yet
621 }
622 else
623 {
624 for ( n = 0; n < numRows; n++ )
625 {
626 m_data.Remove( pos );
627 }
628 }
629
630 if ( GetView() )
631 {
632 wxGridTableMessage msg( this,
633 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
634 pos,
635 numRows );
636
637 GetView()->ProcessTableMessage( msg );
638 }
639
640 return TRUE;
641 }
642
643 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
644 {
645 size_t row, col;
646
647 size_t curNumRows = m_data.GetCount();
648 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
649
650 if ( pos >= curNumCols )
651 {
652 return AppendCols( numCols );
653 }
654
655 for ( row = 0; row < curNumRows; row++ )
656 {
657 for ( col = pos; col < pos + numCols; col++ )
658 {
659 m_data[row].Insert( wxEmptyString, col );
660 }
661 }
662
663 if ( GetView() )
664 {
665 wxGridTableMessage msg( this,
666 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
667 pos,
668 numCols );
669
670 GetView()->ProcessTableMessage( msg );
671 }
672
673 return TRUE;
674 }
675
676 bool wxGridStringTable::AppendCols( size_t numCols )
677 {
678 size_t row, n;
679
680 size_t curNumRows = m_data.GetCount();
681 if ( !curNumRows )
682 {
683 // TODO: something better than this ?
684 //
685 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
686 "Call AppendRows() first") );
687 return FALSE;
688 }
689
690 for ( row = 0; row < curNumRows; row++ )
691 {
692 for ( n = 0; n < numCols; n++ )
693 {
694 m_data[row].Add( wxEmptyString );
695 }
696 }
697
698 if ( GetView() )
699 {
700 wxGridTableMessage msg( this,
701 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
702 numCols );
703
704 GetView()->ProcessTableMessage( msg );
705 }
706
707 return TRUE;
708 }
709
710 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
711 {
712 size_t row, n;
713
714 size_t curNumRows = m_data.GetCount();
715 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
716
717 if ( pos >= curNumCols )
718 {
719 wxString errmsg;
720 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
721 "Pos value is invalid for present table with %d cols",
722 pos, numCols, curNumCols );
723 wxFAIL_MSG( wxT( errmsg ) );
724 return FALSE;
725 }
726
727 if ( numCols > curNumCols - pos )
728 {
729 numCols = curNumCols - pos;
730 }
731
732 for ( row = 0; row < curNumRows; row++ )
733 {
734 if ( numCols >= curNumCols )
735 {
736 m_data[row].Clear();
737 }
738 else
739 {
740 for ( n = 0; n < numCols; n++ )
741 {
742 m_data[row].Remove( pos );
743 }
744 }
745 }
746
747 if ( GetView() )
748 {
749 wxGridTableMessage msg( this,
750 wxGRIDTABLE_NOTIFY_COLS_DELETED,
751 pos,
752 numCols );
753
754 GetView()->ProcessTableMessage( msg );
755 }
756
757 return TRUE;
758 }
759
760 wxString wxGridStringTable::GetRowLabelValue( int row )
761 {
762 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
763 {
764 // using default label
765 //
766 return wxGridTableBase::GetRowLabelValue( row );
767 }
768 else
769 {
770 return m_rowLabels[ row ];
771 }
772 }
773
774 wxString wxGridStringTable::GetColLabelValue( int col )
775 {
776 if ( col > (int)(m_colLabels.GetCount()) - 1 )
777 {
778 // using default label
779 //
780 return wxGridTableBase::GetColLabelValue( col );
781 }
782 else
783 {
784 return m_colLabels[ col ];
785 }
786 }
787
788 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
789 {
790 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
791 {
792 int n = m_rowLabels.GetCount();
793 int i;
794 for ( i = n; i <= row; i++ )
795 {
796 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
797 }
798 }
799
800 m_rowLabels[row] = value;
801 }
802
803 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
804 {
805 if ( col > (int)(m_colLabels.GetCount()) - 1 )
806 {
807 int n = m_colLabels.GetCount();
808 int i;
809 for ( i = n; i <= col; i++ )
810 {
811 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
812 }
813 }
814
815 m_colLabels[col] = value;
816 }
817
818
819
820
821 //////////////////////////////////////////////////////////////////////
822
823 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl )
824
825 BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl )
826 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown )
827 END_EVENT_TABLE()
828
829
830 wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
831 wxGrid *grid,
832 bool isCellControl,
833 wxWindowID id,
834 const wxString& value,
835 const wxPoint& pos,
836 const wxSize& size,
837 long style )
838 : wxTextCtrl( par, id, value, pos, size, style )
839 {
840 m_grid = grid;
841 m_isCellControl = isCellControl;
842 }
843
844
845 void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
846 {
847 switch ( event.KeyCode() )
848 {
849 case WXK_ESCAPE:
850 m_grid->SetEditControlValue( startValue );
851 SetInsertionPointEnd();
852 break;
853
854 case WXK_UP:
855 case WXK_DOWN:
856 case WXK_LEFT:
857 case WXK_RIGHT:
858 case WXK_PRIOR:
859 case WXK_NEXT:
860 case WXK_SPACE:
861 if ( m_isCellControl )
862 {
863 // send the event to the parent grid, skipping the
864 // event if nothing happens
865 //
866 event.Skip( m_grid->ProcessEvent( event ) );
867 }
868 else
869 {
870 // default text control response within the top edit
871 // control
872 //
873 event.Skip();
874 }
875 break;
876
877 case WXK_RETURN:
878 if ( m_isCellControl )
879 {
880 if ( !m_grid->ProcessEvent( event ) )
881 {
882 #if defined(__WXMOTIF__) || defined(__WXGTK__)
883 // wxMotif needs a little extra help...
884 //
885 int pos = GetInsertionPoint();
886 wxString s( GetValue() );
887 s = s.Left(pos) + "\n" + s.Mid(pos);
888 SetValue(s);
889 SetInsertionPoint( pos );
890 #else
891 // the other ports can handle a Return key press
892 //
893 event.Skip();
894 #endif
895 }
896 }
897 break;
898
899 case WXK_HOME:
900 case WXK_END:
901 if ( m_isCellControl )
902 {
903 // send the event to the parent grid, skipping the
904 // event if nothing happens
905 //
906 event.Skip( m_grid->ProcessEvent( event ) );
907 }
908 else
909 {
910 // default text control response within the top edit
911 // control
912 //
913 event.Skip();
914 }
915 break;
916
917 default:
918 event.Skip();
919 }
920 }
921
922 void wxGridTextCtrl::SetStartValue( const wxString& s )
923 {
924 startValue = s;
925 wxTextCtrl::SetValue(s);
926 }
927
928
929
930 //////////////////////////////////////////////////////////////////////
931
932 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
933
934 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
935 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
936 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
937 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
938 END_EVENT_TABLE()
939
940 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
941 wxWindowID id,
942 const wxPoint &pos, const wxSize &size )
943 : wxWindow( parent, id, pos, size )
944 {
945 m_owner = parent;
946 }
947
948 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
949 {
950 wxPaintDC dc(this);
951
952 // NO - don't do this because it will set both the x and y origin
953 // coords to match the parent scrolled window and we just want to
954 // set the y coord - MB
955 //
956 // m_owner->PrepareDC( dc );
957
958 int x, y;
959 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
960 dc.SetDeviceOrigin( 0, -y );
961
962 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
963 m_owner->DrawRowLabels( dc );
964 }
965
966
967 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
968 {
969 m_owner->ProcessRowLabelMouseEvent( event );
970 }
971
972
973 // This seems to be required for wxMotif otherwise the mouse
974 // cursor must be in the cell edit control to get key events
975 //
976 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
977 {
978 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
979 }
980
981
982
983 //////////////////////////////////////////////////////////////////////
984
985 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
986
987 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
988 EVT_PAINT( wxGridColLabelWindow::OnPaint )
989 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
990 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
991 END_EVENT_TABLE()
992
993 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
994 wxWindowID id,
995 const wxPoint &pos, const wxSize &size )
996 : wxWindow( parent, id, pos, size )
997 {
998 m_owner = parent;
999 }
1000
1001 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
1002 {
1003 wxPaintDC dc(this);
1004
1005 // NO - don't do this because it will set both the x and y origin
1006 // coords to match the parent scrolled window and we just want to
1007 // set the x coord - MB
1008 //
1009 // m_owner->PrepareDC( dc );
1010
1011 int x, y;
1012 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1013 dc.SetDeviceOrigin( -x, 0 );
1014
1015 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
1016 m_owner->DrawColLabels( dc );
1017 }
1018
1019
1020 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
1021 {
1022 m_owner->ProcessColLabelMouseEvent( event );
1023 }
1024
1025
1026 // This seems to be required for wxMotif otherwise the mouse
1027 // cursor must be in the cell edit control to get key events
1028 //
1029 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
1030 {
1031 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1032 }
1033
1034
1035
1036 //////////////////////////////////////////////////////////////////////
1037
1038 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
1039
1040 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
1041 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
1042 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
1043 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
1044 END_EVENT_TABLE()
1045
1046 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
1047 wxWindowID id,
1048 const wxPoint &pos, const wxSize &size )
1049 : wxWindow( parent, id, pos, size )
1050 {
1051 m_owner = parent;
1052 }
1053
1054 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
1055 {
1056 wxPaintDC dc(this);
1057
1058 int client_height = 0;
1059 int client_width = 0;
1060 GetClientSize( &client_width, &client_height );
1061
1062 dc.SetPen( *wxBLACK_PEN );
1063 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
1064 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
1065
1066 dc.SetPen( *wxWHITE_PEN );
1067 dc.DrawLine( 0, 0, client_width, 0 );
1068 dc.DrawLine( 0, 0, 0, client_height );
1069 }
1070
1071
1072 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
1073 {
1074 m_owner->ProcessCornerLabelMouseEvent( event );
1075 }
1076
1077
1078 // This seems to be required for wxMotif otherwise the mouse
1079 // cursor must be in the cell edit control to get key events
1080 //
1081 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
1082 {
1083 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1084 }
1085
1086
1087
1088 //////////////////////////////////////////////////////////////////////
1089
1090 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
1091
1092 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
1093 EVT_PAINT( wxGridWindow::OnPaint )
1094 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
1095 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
1096 END_EVENT_TABLE()
1097
1098 wxGridWindow::wxGridWindow( wxGrid *parent,
1099 wxGridRowLabelWindow *rowLblWin,
1100 wxGridColLabelWindow *colLblWin,
1101 wxWindowID id, const wxPoint &pos, const wxSize &size )
1102 : wxPanel( parent, id, pos, size, 0, "grid window" )
1103 {
1104 m_owner = parent;
1105 m_rowLabelWin = rowLblWin;
1106 m_colLabelWin = colLblWin;
1107
1108 SetBackgroundColour( "WHITE" );
1109 }
1110
1111
1112 wxGridWindow::~wxGridWindow()
1113 {
1114 }
1115
1116
1117 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1118 {
1119 wxPaintDC dc( this );
1120 m_owner->PrepareDC( dc );
1121 wxRegion reg = GetUpdateRegion();
1122 m_owner->CalcCellsExposed( reg );
1123 m_owner->DrawGridCellArea( dc );
1124 #if WXGRID_DRAW_LINES
1125 m_owner->DrawAllGridLines( dc, reg );
1126 #endif
1127 }
1128
1129
1130 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1131 {
1132 wxPanel::ScrollWindow( dx, dy, rect );
1133 m_rowLabelWin->ScrollWindow( 0, dy, rect );
1134 m_colLabelWin->ScrollWindow( dx, 0, rect );
1135 }
1136
1137
1138 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
1139 {
1140 m_owner->ProcessGridCellMouseEvent( event );
1141 }
1142
1143
1144 // This seems to be required for wxMotif otherwise the mouse
1145 // cursor must be in the cell edit control to get key events
1146 //
1147 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
1148 {
1149 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1150 }
1151
1152
1153
1154 //////////////////////////////////////////////////////////////////////
1155
1156 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
1157
1158 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
1159 EVT_PAINT( wxGrid::OnPaint )
1160 EVT_SIZE( wxGrid::OnSize )
1161 EVT_KEY_DOWN( wxGrid::OnKeyDown )
1162 END_EVENT_TABLE()
1163
1164 wxGrid::wxGrid( wxWindow *parent,
1165 wxWindowID id,
1166 const wxPoint& pos,
1167 const wxSize& size,
1168 long style,
1169 const wxString& name )
1170 : wxScrolledWindow( parent, id, pos, size, style, name )
1171 {
1172 Create();
1173 }
1174
1175
1176 wxGrid::~wxGrid()
1177 {
1178 delete m_table;
1179 }
1180
1181
1182 //
1183 // ----- internal init and update functions
1184 //
1185
1186 void wxGrid::Create()
1187 {
1188 m_created = FALSE; // set to TRUE by CreateGrid
1189 m_displayed = FALSE; // set to TRUE by OnPaint
1190
1191 m_table = (wxGridTableBase *) NULL;
1192 m_cellEditCtrl = (wxWindow *) NULL;
1193
1194 m_numRows = 0;
1195 m_numCols = 0;
1196 m_currentCellCoords = wxGridNoCellCoords;
1197
1198 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1199 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1200
1201 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
1202 -1,
1203 wxDefaultPosition,
1204 wxDefaultSize );
1205
1206 m_rowLabelWin = new wxGridRowLabelWindow( this,
1207 -1,
1208 wxDefaultPosition,
1209 wxDefaultSize );
1210
1211 m_colLabelWin = new wxGridColLabelWindow( this,
1212 -1,
1213 wxDefaultPosition,
1214 wxDefaultSize );
1215
1216 m_gridWin = new wxGridWindow( this,
1217 m_rowLabelWin,
1218 m_colLabelWin,
1219 -1,
1220 wxDefaultPosition,
1221 wxDefaultSize );
1222
1223 SetTargetWindow( m_gridWin );
1224 }
1225
1226
1227 bool wxGrid::CreateGrid( int numRows, int numCols )
1228 {
1229 if ( m_created )
1230 {
1231 wxFAIL_MSG( wxT("wxGrid::CreateGrid called more than once") );
1232 return FALSE;
1233 }
1234 else
1235 {
1236 m_numRows = numRows;
1237 m_numCols = numCols;
1238
1239 m_table = new wxGridStringTable( m_numRows, m_numCols );
1240 m_table->SetView( this );
1241 Init();
1242 m_created = TRUE;
1243 }
1244
1245 return m_created;
1246 }
1247
1248
1249 void wxGrid::Init()
1250 {
1251 int i;
1252
1253 if ( m_numRows <= 0 )
1254 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
1255
1256 if ( m_numCols <= 0 )
1257 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
1258
1259 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1260 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1261
1262 if ( m_rowLabelWin )
1263 {
1264 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
1265 }
1266 else
1267 {
1268 m_labelBackgroundColour = wxColour( _T("WHITE") );
1269 }
1270
1271 m_labelTextColour = wxColour( _T("BLACK") );
1272
1273 // TODO: something better than this ?
1274 //
1275 m_labelFont = this->GetFont();
1276 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
1277
1278 m_rowLabelHorizAlign = wxLEFT;
1279 m_rowLabelVertAlign = wxCENTRE;
1280
1281 m_colLabelHorizAlign = wxCENTRE;
1282 m_colLabelVertAlign = wxTOP;
1283
1284 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1285 m_defaultRowHeight = m_gridWin->GetCharHeight();
1286
1287 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1288 m_defaultRowHeight += 8;
1289 #else
1290 m_defaultRowHeight += 4;
1291 #endif
1292
1293 m_rowHeights.Alloc( m_numRows );
1294 m_rowBottoms.Alloc( m_numRows );
1295 int rowBottom = 0;
1296 for ( i = 0; i < m_numRows; i++ )
1297 {
1298 m_rowHeights.Add( m_defaultRowHeight );
1299 rowBottom += m_defaultRowHeight;
1300 m_rowBottoms.Add( rowBottom );
1301 }
1302
1303 m_colWidths.Alloc( m_numCols );
1304 m_colRights.Alloc( m_numCols );
1305 int colRight = 0;
1306 for ( i = 0; i < m_numCols; i++ )
1307 {
1308 m_colWidths.Add( m_defaultColWidth );
1309 colRight += m_defaultColWidth;
1310 m_colRights.Add( colRight );
1311 }
1312
1313 // TODO: improve this by using wxSystemSettings?
1314 //
1315 m_defaultCellFont = GetFont();
1316
1317 m_defaultCellHAlign = wxLEFT;
1318 m_defaultCellVAlign = wxTOP;
1319
1320 m_gridLineColour = wxColour( 128, 128, 255 );
1321 m_gridLinesEnabled = TRUE;
1322
1323 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1324 m_dragLastPos = -1;
1325 m_dragRowOrCol = -1;
1326 m_isDragging = FALSE;
1327
1328 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
1329 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
1330
1331 m_currentCellCoords = wxGridNoCellCoords;
1332
1333 m_selectedTopLeft = wxGridNoCellCoords;
1334 m_selectedBottomRight = wxGridNoCellCoords;
1335
1336 m_editable = TRUE; // default for whole grid
1337
1338 m_inOnKeyDown = FALSE;
1339 m_batchCount = 0;
1340
1341 // TODO: extend this to other types of controls
1342 //
1343 m_cellEditCtrl = new wxGridTextCtrl( m_gridWin,
1344 this,
1345 TRUE,
1346 wxGRID_CELLCTRL,
1347 "",
1348 wxPoint(1,1),
1349 wxSize(1,1)
1350 #if defined(__WXMSW__)
1351 , wxTE_MULTILINE | wxTE_NO_VSCROLL
1352 #endif
1353 );
1354
1355 m_cellEditCtrl->Show( FALSE );
1356 m_cellEditCtrlEnabled = TRUE;
1357 m_editCtrlType = wxGRID_TEXTCTRL;
1358 }
1359
1360
1361 void wxGrid::CalcDimensions()
1362 {
1363 int cw, ch;
1364 GetClientSize( &cw, &ch );
1365
1366 if ( m_numRows > 0 && m_numCols > 0 )
1367 {
1368 int right = m_colRights[ m_numCols-1 ] + 50;
1369 int bottom = m_rowBottoms[ m_numRows-1 ] + 50;
1370
1371 // TODO: restore the scroll position that we had before sizing
1372 //
1373 int x, y;
1374 GetViewStart( &x, &y );
1375 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
1376 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
1377 x, y );
1378 }
1379 }
1380
1381
1382 void wxGrid::CalcWindowSizes()
1383 {
1384 int cw, ch;
1385 GetClientSize( &cw, &ch );
1386
1387 if ( m_cornerLabelWin->IsShown() )
1388 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
1389
1390 if ( m_colLabelWin->IsShown() )
1391 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
1392
1393 if ( m_rowLabelWin->IsShown() )
1394 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
1395
1396 if ( m_gridWin->IsShown() )
1397 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
1398 }
1399
1400
1401 // this is called when the grid table sends a message to say that it
1402 // has been redimensioned
1403 //
1404 bool wxGrid::Redimension( wxGridTableMessage& msg )
1405 {
1406 int i;
1407
1408 switch ( msg.GetId() )
1409 {
1410 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1411 {
1412 size_t pos = msg.GetCommandInt();
1413 int numRows = msg.GetCommandInt2();
1414 for ( i = 0; i < numRows; i++ )
1415 {
1416 m_rowHeights.Insert( m_defaultRowHeight, pos );
1417 m_rowBottoms.Insert( 0, pos );
1418 }
1419 m_numRows += numRows;
1420
1421 int bottom = 0;
1422 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
1423
1424 for ( i = pos; i < m_numRows; i++ )
1425 {
1426 bottom += m_rowHeights[i];
1427 m_rowBottoms[i] = bottom;
1428 }
1429 CalcDimensions();
1430 }
1431 return TRUE;
1432
1433 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1434 {
1435 int numRows = msg.GetCommandInt();
1436 for ( i = 0; i < numRows; i++ )
1437 {
1438 m_rowHeights.Add( m_defaultRowHeight );
1439 m_rowBottoms.Add( 0 );
1440 }
1441
1442 int oldNumRows = m_numRows;
1443 m_numRows += numRows;
1444
1445 int bottom = 0;
1446 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
1447
1448 for ( i = oldNumRows; i < m_numRows; i++ )
1449 {
1450 bottom += m_rowHeights[i];
1451 m_rowBottoms[i] = bottom;
1452 }
1453 CalcDimensions();
1454 }
1455 return TRUE;
1456
1457 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
1458 {
1459 size_t pos = msg.GetCommandInt();
1460 int numRows = msg.GetCommandInt2();
1461 for ( i = 0; i < numRows; i++ )
1462 {
1463 m_rowHeights.Remove( pos );
1464 m_rowBottoms.Remove( pos );
1465 }
1466 m_numRows -= numRows;
1467
1468 if ( !m_numRows )
1469 {
1470 m_numCols = 0;
1471 m_colWidths.Clear();
1472 m_colRights.Clear();
1473 m_currentCellCoords = wxGridNoCellCoords;
1474 }
1475 else
1476 {
1477 if ( m_currentCellCoords.GetRow() >= m_numRows )
1478 m_currentCellCoords.Set( 0, 0 );
1479
1480 int h = 0;
1481 for ( i = 0; i < m_numRows; i++ )
1482 {
1483 h += m_rowHeights[i];
1484 m_rowBottoms[i] = h;
1485 }
1486 }
1487
1488 CalcDimensions();
1489 }
1490 return TRUE;
1491
1492 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
1493 {
1494 size_t pos = msg.GetCommandInt();
1495 int numCols = msg.GetCommandInt2();
1496 for ( i = 0; i < numCols; i++ )
1497 {
1498 m_colWidths.Insert( m_defaultColWidth, pos );
1499 m_colRights.Insert( 0, pos );
1500 }
1501 m_numCols += numCols;
1502
1503 int right = 0;
1504 if ( pos > 0 ) right = m_colRights[pos-1];
1505
1506 for ( i = pos; i < m_numCols; i++ )
1507 {
1508 right += m_colWidths[i];
1509 m_colRights[i] = right;
1510 }
1511 CalcDimensions();
1512 }
1513 return TRUE;
1514
1515 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
1516 {
1517 int numCols = msg.GetCommandInt();
1518 for ( i = 0; i < numCols; i++ )
1519 {
1520 m_colWidths.Add( m_defaultColWidth );
1521 m_colRights.Add( 0 );
1522 }
1523
1524 int oldNumCols = m_numCols;
1525 m_numCols += numCols;
1526
1527 int right = 0;
1528 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
1529
1530 for ( i = oldNumCols; i < m_numCols; i++ )
1531 {
1532 right += m_colWidths[i];
1533 m_colRights[i] = right;
1534 }
1535 CalcDimensions();
1536 }
1537 return TRUE;
1538
1539 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
1540 {
1541 size_t pos = msg.GetCommandInt();
1542 int numCols = msg.GetCommandInt2();
1543 for ( i = 0; i < numCols; i++ )
1544 {
1545 m_colWidths.Remove( pos );
1546 m_colRights.Remove( pos );
1547 }
1548 m_numCols -= numCols;
1549
1550 if ( !m_numCols )
1551 {
1552 #if 0 // leave the row alone here so that AppendCols will work subsequently
1553 m_numRows = 0;
1554 m_rowHeights.Clear();
1555 m_rowBottoms.Clear();
1556 #endif
1557 m_currentCellCoords = wxGridNoCellCoords;
1558 }
1559 else
1560 {
1561 if ( m_currentCellCoords.GetCol() >= m_numCols )
1562 m_currentCellCoords.Set( 0, 0 );
1563
1564 int w = 0;
1565 for ( i = 0; i < m_numCols; i++ )
1566 {
1567 w += m_colWidths[i];
1568 m_colRights[i] = w;
1569 }
1570 }
1571 CalcDimensions();
1572 }
1573 return TRUE;
1574 }
1575
1576 return FALSE;
1577 }
1578
1579
1580 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
1581 {
1582 wxRegionIterator iter( reg );
1583 wxRect r;
1584
1585 m_rowLabelsExposed.Empty();
1586
1587 int top, bottom;
1588 while ( iter )
1589 {
1590 r = iter.GetRect();
1591
1592 // TODO: remove this when we can...
1593 // There is a bug in wxMotif that gives garbage update
1594 // rectangles if you jump-scroll a long way by clicking the
1595 // scrollbar with middle button. This is a work-around
1596 //
1597 #if defined(__WXMOTIF__)
1598 int cw, ch;
1599 m_gridWin->GetClientSize( &cw, &ch );
1600 if ( r.GetTop() > ch ) r.SetTop( 0 );
1601 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1602 #endif
1603
1604 // logical bounds of update region
1605 //
1606 int dummy;
1607 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
1608 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
1609
1610 // find the row labels within these bounds
1611 //
1612 int row;
1613 int rowTop;
1614 for ( row = 0; row < m_numRows; row++ )
1615 {
1616 if ( m_rowBottoms[row] < top ) continue;
1617
1618 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1619 if ( rowTop > bottom ) break;
1620
1621 m_rowLabelsExposed.Add( row );
1622 }
1623
1624 iter++ ;
1625 }
1626 }
1627
1628
1629 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
1630 {
1631 wxRegionIterator iter( reg );
1632 wxRect r;
1633
1634 m_colLabelsExposed.Empty();
1635
1636 int left, right;
1637 while ( iter )
1638 {
1639 r = iter.GetRect();
1640
1641 // TODO: remove this when we can...
1642 // There is a bug in wxMotif that gives garbage update
1643 // rectangles if you jump-scroll a long way by clicking the
1644 // scrollbar with middle button. This is a work-around
1645 //
1646 #if defined(__WXMOTIF__)
1647 int cw, ch;
1648 m_gridWin->GetClientSize( &cw, &ch );
1649 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1650 r.SetRight( wxMin( r.GetRight(), cw ) );
1651 #endif
1652
1653 // logical bounds of update region
1654 //
1655 int dummy;
1656 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
1657 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
1658
1659 // find the cells within these bounds
1660 //
1661 int col;
1662 int colLeft;
1663 for ( col = 0; col < m_numCols; col++ )
1664 {
1665 if ( m_colRights[col] < left ) continue;
1666
1667 colLeft = m_colRights[col] - m_colWidths[col];
1668 if ( colLeft > right ) break;
1669
1670 m_colLabelsExposed.Add( col );
1671 }
1672
1673 iter++ ;
1674 }
1675 }
1676
1677
1678 void wxGrid::CalcCellsExposed( wxRegion& reg )
1679 {
1680 wxRegionIterator iter( reg );
1681 wxRect r;
1682
1683 m_cellsExposed.Empty();
1684 m_rowsExposed.Empty();
1685 m_colsExposed.Empty();
1686
1687 int left, top, right, bottom;
1688 while ( iter )
1689 {
1690 r = iter.GetRect();
1691
1692 // TODO: remove this when we can...
1693 // There is a bug in wxMotif that gives garbage update
1694 // rectangles if you jump-scroll a long way by clicking the
1695 // scrollbar with middle button. This is a work-around
1696 //
1697 #if defined(__WXMOTIF__)
1698 int cw, ch;
1699 m_gridWin->GetClientSize( &cw, &ch );
1700 if ( r.GetTop() > ch ) r.SetTop( 0 );
1701 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1702 r.SetRight( wxMin( r.GetRight(), cw ) );
1703 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1704 #endif
1705
1706 // logical bounds of update region
1707 //
1708 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
1709 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
1710
1711 // find the cells within these bounds
1712 //
1713 int row, col;
1714 int colLeft, rowTop;
1715 for ( row = 0; row < m_numRows; row++ )
1716 {
1717 if ( m_rowBottoms[row] < top ) continue;
1718
1719 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1720 if ( rowTop > bottom ) break;
1721
1722 m_rowsExposed.Add( row );
1723
1724 for ( col = 0; col < m_numCols; col++ )
1725 {
1726 if ( m_colRights[col] < left ) continue;
1727
1728 colLeft = m_colRights[col] - m_colWidths[col];
1729 if ( colLeft > right ) break;
1730
1731 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
1732 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
1733 }
1734 }
1735
1736 iter++ ;
1737 }
1738 }
1739
1740
1741 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
1742 {
1743 int x, y, row;
1744 wxPoint pos( event.GetPosition() );
1745 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1746
1747 if ( event.Dragging() )
1748 {
1749 m_isDragging = TRUE;
1750
1751 if ( event.LeftIsDown() )
1752 {
1753 switch( m_cursorMode )
1754 {
1755 case WXGRID_CURSOR_RESIZE_ROW:
1756 {
1757 int cw, ch, left, dummy;
1758 m_gridWin->GetClientSize( &cw, &ch );
1759 CalcUnscrolledPosition( 0, 0, &left, &dummy );
1760
1761 wxClientDC dc( m_gridWin );
1762 PrepareDC( dc );
1763 dc.SetLogicalFunction(wxINVERT);
1764 if ( m_dragLastPos >= 0 )
1765 {
1766 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1767 }
1768 dc.DrawLine( left, y, left+cw, y );
1769 m_dragLastPos = y;
1770 }
1771 break;
1772
1773 case WXGRID_CURSOR_SELECT_ROW:
1774 {
1775 if ( (row = YToRow( y )) >= 0 &&
1776 !IsInSelection( row, 0 ) )
1777 {
1778 SelectRow( row, TRUE );
1779 }
1780 }
1781 break;
1782 }
1783 }
1784 return;
1785 }
1786
1787 m_isDragging = FALSE;
1788
1789
1790 // ------------ Left button pressed
1791 //
1792 if ( event.LeftDown() )
1793 {
1794 // don't send a label click event for a hit on the
1795 // edge of the row label - this is probably the user
1796 // wanting to resize the row
1797 //
1798 if ( YToEdgeOfRow(y) < 0 )
1799 {
1800 row = YToRow(y);
1801 if ( row >= 0 &&
1802 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
1803 {
1804 SelectRow( row, event.ShiftDown() );
1805 m_cursorMode = WXGRID_CURSOR_SELECT_ROW;
1806 }
1807 }
1808 else
1809 {
1810 // starting to drag-resize a row
1811 //
1812 m_rowLabelWin->CaptureMouse();
1813 }
1814 }
1815
1816
1817 // ------------ Left double click
1818 //
1819 else if (event.LeftDClick() )
1820 {
1821 if ( YToEdgeOfRow(y) < 0 )
1822 {
1823 row = YToRow(y);
1824 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
1825 }
1826 }
1827
1828
1829 // ------------ Left button released
1830 //
1831 else if ( event.LeftUp() )
1832 {
1833 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
1834 {
1835 m_rowLabelWin->ReleaseMouse();
1836
1837 if ( m_dragLastPos >= 0 )
1838 {
1839 // erase the last line and resize the row
1840 //
1841 int cw, ch, left, dummy;
1842 m_gridWin->GetClientSize( &cw, &ch );
1843 CalcUnscrolledPosition( 0, 0, &left, &dummy );
1844
1845 wxClientDC dc( m_gridWin );
1846 PrepareDC( dc );
1847 dc.SetLogicalFunction( wxINVERT );
1848 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1849 HideCellEditControl();
1850
1851 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
1852 SetRowSize( m_dragRowOrCol, wxMax( y - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
1853 if ( !GetBatchCount() )
1854 {
1855 // Only needed to get the correct rect.y:
1856 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
1857 rect.x = 0;
1858 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
1859 rect.width = m_rowLabelWidth;
1860 rect.height = ch - rect.y;
1861 m_rowLabelWin->Refresh( TRUE, &rect );
1862 rect.width = cw;
1863 m_gridWin->Refresh( FALSE, &rect );
1864 }
1865
1866 ShowCellEditControl();
1867
1868 // Note: we are ending the event *after* doing
1869 // default processing in this case
1870 //
1871 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
1872 }
1873 }
1874
1875 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1876 m_dragLastPos = -1;
1877 }
1878
1879
1880 // ------------ Right button down
1881 //
1882 else if ( event.RightDown() )
1883 {
1884 row = YToRow(y);
1885 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
1886 {
1887 // no default action at the moment
1888 }
1889 }
1890
1891
1892 // ------------ Right double click
1893 //
1894 else if ( event.RightDClick() )
1895 {
1896 row = YToRow(y);
1897 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
1898 {
1899 // no default action at the moment
1900 }
1901 }
1902
1903
1904 // ------------ No buttons down and mouse moving
1905 //
1906 else if ( event.Moving() )
1907 {
1908 m_dragRowOrCol = YToEdgeOfRow( y );
1909 if ( m_dragRowOrCol >= 0 )
1910 {
1911 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1912 {
1913 m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
1914 m_rowLabelWin->SetCursor( m_rowResizeCursor );
1915 }
1916 }
1917 else
1918 {
1919 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1920 if ( m_rowLabelWin->GetCursor() == m_rowResizeCursor )
1921 m_rowLabelWin->SetCursor( *wxSTANDARD_CURSOR );
1922 }
1923 }
1924 }
1925
1926
1927 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
1928 {
1929 int x, y, col;
1930 wxPoint pos( event.GetPosition() );
1931 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1932
1933 if ( event.Dragging() )
1934 {
1935 m_isDragging = TRUE;
1936
1937 if ( event.LeftIsDown() )
1938 {
1939 switch( m_cursorMode )
1940 {
1941 case WXGRID_CURSOR_RESIZE_COL:
1942 {
1943 int cw, ch, dummy, top;
1944 m_gridWin->GetClientSize( &cw, &ch );
1945 CalcUnscrolledPosition( 0, 0, &dummy, &top );
1946
1947 wxClientDC dc( m_gridWin );
1948 PrepareDC( dc );
1949 dc.SetLogicalFunction(wxINVERT);
1950 if ( m_dragLastPos >= 0 )
1951 {
1952 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1953 }
1954 dc.DrawLine( x, top, x, top+ch );
1955 m_dragLastPos = x;
1956 }
1957 break;
1958
1959 case WXGRID_CURSOR_SELECT_COL:
1960 {
1961 if ( (col = XToCol( x )) >= 0 &&
1962 !IsInSelection( 0, col ) )
1963 {
1964 SelectCol( col, TRUE );
1965 }
1966 }
1967 break;
1968 }
1969 }
1970 return;
1971 }
1972
1973 m_isDragging = FALSE;
1974
1975
1976 // ------------ Left button pressed
1977 //
1978 if ( event.LeftDown() )
1979 {
1980 // don't send a label click event for a hit on the
1981 // edge of the col label - this is probably the user
1982 // wanting to resize the col
1983 //
1984 if ( XToEdgeOfCol(x) < 0 )
1985 {
1986 col = XToCol(x);
1987 if ( col >= 0 &&
1988 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
1989 {
1990 SelectCol( col, event.ShiftDown() );
1991 m_cursorMode = WXGRID_CURSOR_SELECT_COL;
1992 }
1993 }
1994 else
1995 {
1996 // starting to drag-resize a col
1997 //
1998 m_colLabelWin->CaptureMouse();
1999 }
2000 }
2001
2002
2003 // ------------ Left double click
2004 //
2005 if ( event.LeftDClick() )
2006 {
2007 if ( XToEdgeOfCol(x) < 0 )
2008 {
2009 col = XToCol(x);
2010 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2011 }
2012 }
2013
2014
2015 // ------------ Left button released
2016 //
2017 else if ( event.LeftUp() )
2018 {
2019 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2020 {
2021 m_colLabelWin->ReleaseMouse();
2022
2023 if ( m_dragLastPos >= 0 )
2024 {
2025 // erase the last line and resize the col
2026 //
2027 int cw, ch, dummy, top;
2028 m_gridWin->GetClientSize( &cw, &ch );
2029 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2030
2031 wxClientDC dc( m_gridWin );
2032 PrepareDC( dc );
2033 dc.SetLogicalFunction( wxINVERT );
2034 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2035 HideCellEditControl();
2036
2037 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
2038 SetColSize( m_dragRowOrCol, wxMax( x - colLeft, WXGRID_MIN_COL_WIDTH ) );
2039
2040 if ( !GetBatchCount() )
2041 {
2042 // Only needed to get the correct rect.x:
2043 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
2044 rect.y = 0;
2045 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
2046 rect.width = cw - rect.x;
2047 rect.height = m_colLabelHeight;
2048 m_colLabelWin->Refresh( TRUE, &rect );
2049 rect.height = ch;
2050 m_gridWin->Refresh( FALSE, &rect );
2051 }
2052
2053 ShowCellEditControl();
2054
2055 // Note: we are ending the event *after* doing
2056 // default processing in this case
2057 //
2058 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2059 }
2060 }
2061
2062 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
2063 m_dragLastPos = -1;
2064 }
2065
2066
2067 // ------------ Right button down
2068 //
2069 else if ( event.RightDown() )
2070 {
2071 col = XToCol(x);
2072 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2073 {
2074 // no default action at the moment
2075 }
2076 }
2077
2078
2079 // ------------ Right double click
2080 //
2081 else if ( event.RightDClick() )
2082 {
2083 col = XToCol(x);
2084 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2085 {
2086 // no default action at the moment
2087 }
2088 }
2089
2090
2091 // ------------ No buttons down and mouse moving
2092 //
2093 else if ( event.Moving() )
2094 {
2095 m_dragRowOrCol = XToEdgeOfCol( x );
2096 if ( m_dragRowOrCol >= 0 )
2097 {
2098 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2099 {
2100 m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
2101 m_colLabelWin->SetCursor( m_colResizeCursor );
2102 }
2103 }
2104 else
2105 {
2106 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
2107 if ( m_colLabelWin->GetCursor() == m_colResizeCursor )
2108 m_colLabelWin->SetCursor( *wxSTANDARD_CURSOR );
2109 }
2110 }
2111 }
2112
2113
2114 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
2115 {
2116 if ( event.LeftDown() )
2117 {
2118 // indicate corner label by having both row and
2119 // col args == -1
2120 //
2121 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2122 {
2123 SelectAll();
2124 }
2125 }
2126
2127 else if ( event.LeftDClick() )
2128 {
2129 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2130 }
2131
2132 else if ( event.RightDown() )
2133 {
2134 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
2135 {
2136 // no default action at the moment
2137 }
2138 }
2139
2140 else if ( event.RightDClick() )
2141 {
2142 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2143 {
2144 // no default action at the moment
2145 }
2146 }
2147 }
2148
2149
2150 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
2151 {
2152 int x, y;
2153 wxPoint pos( event.GetPosition() );
2154 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2155
2156 wxGridCellCoords coords;
2157 XYToCell( x, y, coords );
2158
2159 if ( event.Dragging() )
2160 {
2161 m_isDragging = TRUE;
2162 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2163 {
2164 // Hide the edit control, so it
2165 // won't interfer with drag-shrinking.
2166 if ( IsCellEditControlEnabled() )
2167 HideCellEditControl();
2168 if ( coords != wxGridNoCellCoords )
2169 {
2170 if ( !IsSelection() )
2171 {
2172 SelectBlock( coords, coords );
2173 }
2174 else
2175 {
2176 SelectBlock( m_currentCellCoords, coords );
2177 }
2178 }
2179 }
2180
2181 return;
2182 }
2183
2184 m_isDragging = FALSE;
2185
2186 if ( coords != wxGridNoCellCoords )
2187 {
2188 if ( event.LeftDown() )
2189 {
2190 if ( event.ShiftDown() )
2191 {
2192 SelectBlock( m_currentCellCoords, coords );
2193 }
2194 else
2195 {
2196 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
2197 coords.GetRow(),
2198 coords.GetCol(),
2199 event ) )
2200 {
2201 MakeCellVisible( coords );
2202 SetCurrentCell( coords );
2203 }
2204 }
2205 }
2206
2207
2208 // ------------ Left double click
2209 //
2210 else if ( event.LeftDClick() )
2211 {
2212 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
2213 coords.GetRow(),
2214 coords.GetCol(),
2215 event );
2216 }
2217
2218
2219 // ------------ Left button released
2220 //
2221 else if ( event.LeftUp() )
2222 {
2223 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2224 {
2225 if ( IsSelection() )
2226 {
2227 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
2228 }
2229 }
2230
2231 // Show the edit control, if it has
2232 // been hidden for drag-shrinking.
2233 if ( IsCellEditControlEnabled() )
2234 ShowCellEditControl();
2235
2236 m_dragLastPos = -1;
2237 }
2238
2239
2240 // ------------ Right button down
2241 //
2242 else if ( event.RightDown() )
2243 {
2244 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
2245 coords.GetRow(),
2246 coords.GetCol(),
2247 event ) )
2248 {
2249 // no default action at the moment
2250 }
2251 }
2252
2253
2254 // ------------ Right double click
2255 //
2256 else if ( event.RightDClick() )
2257 {
2258 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2259 coords.GetRow(),
2260 coords.GetCol(),
2261 event ) )
2262 {
2263 // no default action at the moment
2264 }
2265 }
2266
2267 // ------------ Moving and no button action
2268 //
2269 else if ( event.Moving() && !event.IsButton() )
2270 {
2271 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
2272 }
2273 }
2274 }
2275
2276
2277 //
2278 // ------ interaction with data model
2279 //
2280 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
2281 {
2282 switch ( msg.GetId() )
2283 {
2284 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
2285 return GetModelValues();
2286
2287 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
2288 return SetModelValues();
2289
2290 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
2291 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2292 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2293 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2294 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2295 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2296 return Redimension( msg );
2297
2298 default:
2299 return FALSE;
2300 }
2301 }
2302
2303
2304
2305 // The behaviour of this function depends on the grid table class
2306 // Clear() function. For the default wxGridStringTable class the
2307 // behavious is to replace all cell contents with wxEmptyString but
2308 // not to change the number of rows or cols.
2309 //
2310 void wxGrid::ClearGrid()
2311 {
2312 if ( m_table )
2313 {
2314 m_table->Clear();
2315 SetEditControlValue();
2316 if ( !GetBatchCount() ) m_gridWin->Refresh();
2317 }
2318 }
2319
2320
2321 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2322 {
2323 // TODO: something with updateLabels flag
2324
2325 if ( !m_created )
2326 {
2327 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2328 return FALSE;
2329 }
2330
2331 if ( m_table )
2332 {
2333 bool ok = m_table->InsertRows( pos, numRows );
2334
2335 // the table will have sent the results of the insert row
2336 // operation to this view object as a grid table message
2337 //
2338 if ( ok )
2339 {
2340 if ( m_numCols == 0 )
2341 {
2342 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2343 //
2344 // TODO: perhaps instead of appending the default number of cols
2345 // we should remember what the last non-zero number of cols was ?
2346 //
2347 }
2348
2349 if ( m_currentCellCoords == wxGridNoCellCoords )
2350 {
2351 // if we have just inserted cols into an empty grid the current
2352 // cell will be undefined...
2353 //
2354 SetCurrentCell( 0, 0 );
2355 }
2356
2357 ClearSelection();
2358 if ( !GetBatchCount() ) Refresh();
2359 }
2360
2361 SetEditControlValue();
2362 return ok;
2363 }
2364 else
2365 {
2366 return FALSE;
2367 }
2368 }
2369
2370
2371 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
2372 {
2373 // TODO: something with updateLabels flag
2374
2375 if ( !m_created )
2376 {
2377 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2378 return FALSE;
2379 }
2380
2381 if ( m_table && m_table->AppendRows( numRows ) )
2382 {
2383 if ( m_currentCellCoords == wxGridNoCellCoords )
2384 {
2385 // if we have just inserted cols into an empty grid the current
2386 // cell will be undefined...
2387 //
2388 SetCurrentCell( 0, 0 );
2389 }
2390
2391 // the table will have sent the results of the append row
2392 // operation to this view object as a grid table message
2393 //
2394 ClearSelection();
2395 if ( !GetBatchCount() ) Refresh();
2396 return TRUE;
2397 }
2398 else
2399 {
2400 return FALSE;
2401 }
2402 }
2403
2404
2405 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2406 {
2407 // TODO: something with updateLabels flag
2408
2409 if ( !m_created )
2410 {
2411 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2412 return FALSE;
2413 }
2414
2415 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2416 {
2417 // the table will have sent the results of the delete row
2418 // operation to this view object as a grid table message
2419 //
2420 if ( m_numRows > 0 )
2421 SetEditControlValue();
2422 else
2423 HideCellEditControl();
2424
2425 ClearSelection();
2426 if ( !GetBatchCount() ) Refresh();
2427 return TRUE;
2428 }
2429 else
2430 {
2431 return FALSE;
2432 }
2433 }
2434
2435
2436 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2437 {
2438 // TODO: something with updateLabels flag
2439
2440 if ( !m_created )
2441 {
2442 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2443 return FALSE;
2444 }
2445
2446 if ( m_table )
2447 {
2448 HideCellEditControl();
2449 bool ok = m_table->InsertCols( pos, numCols );
2450
2451 // the table will have sent the results of the insert col
2452 // operation to this view object as a grid table message
2453 //
2454 if ( ok )
2455 {
2456 if ( m_currentCellCoords == wxGridNoCellCoords )
2457 {
2458 // if we have just inserted cols into an empty grid the current
2459 // cell will be undefined...
2460 //
2461 SetCurrentCell( 0, 0 );
2462 }
2463
2464 ClearSelection();
2465 if ( !GetBatchCount() ) Refresh();
2466 }
2467
2468 SetEditControlValue();
2469 return ok;
2470 }
2471 else
2472 {
2473 return FALSE;
2474 }
2475 }
2476
2477
2478 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
2479 {
2480 // TODO: something with updateLabels flag
2481
2482 if ( !m_created )
2483 {
2484 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2485 return FALSE;
2486 }
2487
2488 if ( m_table && m_table->AppendCols( numCols ) )
2489 {
2490 // the table will have sent the results of the append col
2491 // operation to this view object as a grid table message
2492 //
2493 if ( m_currentCellCoords == wxGridNoCellCoords )
2494 {
2495 // if we have just inserted cols into an empty grid the current
2496 // cell will be undefined...
2497 //
2498 SetCurrentCell( 0, 0 );
2499 }
2500
2501 ClearSelection();
2502 if ( !GetBatchCount() ) Refresh();
2503 return TRUE;
2504 }
2505 else
2506 {
2507 return FALSE;
2508 }
2509 }
2510
2511
2512 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2513 {
2514 // TODO: something with updateLabels flag
2515
2516 if ( !m_created )
2517 {
2518 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2519 return FALSE;
2520 }
2521
2522 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2523 {
2524 // the table will have sent the results of the delete col
2525 // operation to this view object as a grid table message
2526 //
2527 if ( m_numCols > 0 )
2528 SetEditControlValue();
2529 else
2530 HideCellEditControl();
2531
2532 ClearSelection();
2533 if ( !GetBatchCount() ) Refresh();
2534 return TRUE;
2535 }
2536 else
2537 {
2538 return FALSE;
2539 }
2540 }
2541
2542
2543
2544 //
2545 // ----- event handlers
2546 //
2547
2548 // Generate a grid event based on a mouse event and
2549 // return the result of ProcessEvent()
2550 //
2551 bool wxGrid::SendEvent( const wxEventType type,
2552 int row, int col,
2553 wxMouseEvent& mouseEv )
2554 {
2555 if ( type == EVT_GRID_ROW_SIZE ||
2556 type == EVT_GRID_COL_SIZE )
2557 {
2558 int rowOrCol = (row == -1 ? col : row);
2559
2560 wxGridSizeEvent gridEvt( GetId(),
2561 type,
2562 this,
2563 rowOrCol,
2564 mouseEv.GetX(), mouseEv.GetY(),
2565 mouseEv.ControlDown(),
2566 mouseEv.ShiftDown(),
2567 mouseEv.AltDown(),
2568 mouseEv.MetaDown() );
2569
2570 return GetEventHandler()->ProcessEvent(gridEvt);
2571 }
2572 else if ( type == EVT_GRID_RANGE_SELECT )
2573 {
2574 wxGridRangeSelectEvent gridEvt( GetId(),
2575 type,
2576 this,
2577 m_selectedTopLeft,
2578 m_selectedBottomRight,
2579 mouseEv.ControlDown(),
2580 mouseEv.ShiftDown(),
2581 mouseEv.AltDown(),
2582 mouseEv.MetaDown() );
2583
2584 return GetEventHandler()->ProcessEvent(gridEvt);
2585 }
2586 else
2587 {
2588 wxGridEvent gridEvt( GetId(),
2589 type,
2590 this,
2591 row, col,
2592 mouseEv.GetX(), mouseEv.GetY(),
2593 mouseEv.ControlDown(),
2594 mouseEv.ShiftDown(),
2595 mouseEv.AltDown(),
2596 mouseEv.MetaDown() );
2597
2598 return GetEventHandler()->ProcessEvent(gridEvt);
2599 }
2600 }
2601
2602
2603 // Generate a grid event of specified type and return the result
2604 // of ProcessEvent().
2605 //
2606 bool wxGrid::SendEvent( const wxEventType type,
2607 int row, int col )
2608 {
2609 if ( type == EVT_GRID_ROW_SIZE ||
2610 type == EVT_GRID_COL_SIZE )
2611 {
2612 int rowOrCol = (row == -1 ? col : row);
2613
2614 wxGridSizeEvent gridEvt( GetId(),
2615 type,
2616 this,
2617 rowOrCol );
2618
2619 return GetEventHandler()->ProcessEvent(gridEvt);
2620 }
2621 else
2622 {
2623 wxGridEvent gridEvt( GetId(),
2624 type,
2625 this,
2626 row, col );
2627
2628 return GetEventHandler()->ProcessEvent(gridEvt);
2629 }
2630 }
2631
2632
2633 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
2634 {
2635 wxPaintDC dc( this );
2636
2637 if ( m_currentCellCoords == wxGridNoCellCoords &&
2638 m_numRows && m_numCols )
2639 {
2640 m_currentCellCoords.Set(0, 0);
2641 SetEditControlValue();
2642 ShowCellEditControl();
2643 }
2644
2645 m_displayed = TRUE;
2646 }
2647
2648
2649 // This is just here to make sure that CalcDimensions gets called when
2650 // the grid view is resized... then the size event is skipped to allow
2651 // the box sizers to handle everything
2652 //
2653 void wxGrid::OnSize( wxSizeEvent& event )
2654 {
2655 CalcWindowSizes();
2656 CalcDimensions();
2657 }
2658
2659
2660 void wxGrid::OnKeyDown( wxKeyEvent& event )
2661 {
2662 if ( m_inOnKeyDown )
2663 {
2664 // shouldn't be here - we are going round in circles...
2665 //
2666 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
2667 }
2668
2669 m_inOnKeyDown = TRUE;
2670
2671 // propagate the event up and see if it gets processed
2672 //
2673 wxWindow *parent = GetParent();
2674 wxKeyEvent keyEvt( event );
2675 keyEvt.SetEventObject( parent );
2676
2677 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
2678 {
2679 // try local handlers
2680 //
2681 switch ( event.KeyCode() )
2682 {
2683 case WXK_UP:
2684 if ( event.ControlDown() )
2685 {
2686 MoveCursorUpBlock();
2687 }
2688 else
2689 {
2690 MoveCursorUp();
2691 }
2692 break;
2693
2694 case WXK_DOWN:
2695 if ( event.ControlDown() )
2696 {
2697 MoveCursorDownBlock();
2698 }
2699 else
2700 {
2701 MoveCursorDown();
2702 }
2703 break;
2704
2705 case WXK_LEFT:
2706 if ( event.ControlDown() )
2707 {
2708 MoveCursorLeftBlock();
2709 }
2710 else
2711 {
2712 MoveCursorLeft();
2713 }
2714 break;
2715
2716 case WXK_RIGHT:
2717 if ( event.ControlDown() )
2718 {
2719 MoveCursorRightBlock();
2720 }
2721 else
2722 {
2723 MoveCursorRight();
2724 }
2725 break;
2726
2727 case WXK_SPACE:
2728 if ( !IsEditable() )
2729 {
2730 MoveCursorRight();
2731 }
2732 else
2733 {
2734 event.Skip();
2735 }
2736 break;
2737
2738 case WXK_RETURN:
2739 if ( event.ControlDown() )
2740 {
2741 event.Skip(); // to let the edit control have the return
2742 }
2743 else
2744 {
2745 MoveCursorDown();
2746 }
2747 break;
2748
2749 case WXK_HOME:
2750 if ( event.ControlDown() )
2751 {
2752 MakeCellVisible( 0, 0 );
2753 SetCurrentCell( 0, 0 );
2754 }
2755 else
2756 {
2757 event.Skip();
2758 }
2759 break;
2760
2761 case WXK_END:
2762 if ( event.ControlDown() )
2763 {
2764 MakeCellVisible( m_numRows-1, m_numCols-1 );
2765 SetCurrentCell( m_numRows-1, m_numCols-1 );
2766 }
2767 else
2768 {
2769 event.Skip();
2770 }
2771 break;
2772
2773 case WXK_PRIOR:
2774 MovePageUp();
2775 break;
2776
2777 case WXK_NEXT:
2778 MovePageDown();
2779 break;
2780
2781 default:
2782 // now try the cell edit control
2783 //
2784 if ( IsCellEditControlEnabled() )
2785 {
2786 event.SetEventObject( m_cellEditCtrl );
2787 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2788 }
2789 break;
2790 }
2791 }
2792
2793 m_inOnKeyDown = FALSE;
2794 }
2795
2796
2797 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
2798 {
2799 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
2800 {
2801 // the event has been intercepted - do nothing
2802 return;
2803 }
2804
2805 if ( m_displayed &&
2806 m_currentCellCoords != wxGridNoCellCoords )
2807 {
2808 HideCellEditControl();
2809 SaveEditControlValue();
2810 }
2811
2812 m_currentCellCoords = coords;
2813
2814 SetEditControlValue();
2815
2816 if ( m_displayed )
2817 {
2818 ShowCellEditControl();
2819
2820 if ( IsSelection() )
2821 {
2822 wxRect r( SelectionToDeviceRect() );
2823 ClearSelection();
2824 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
2825 }
2826 }
2827 }
2828
2829
2830 //
2831 // ------ functions to get/send data (see also public functions)
2832 //
2833
2834 bool wxGrid::GetModelValues()
2835 {
2836 if ( m_table )
2837 {
2838 // all we need to do is repaint the grid
2839 //
2840 m_gridWin->Refresh();
2841 return TRUE;
2842 }
2843
2844 return FALSE;
2845 }
2846
2847
2848 bool wxGrid::SetModelValues()
2849 {
2850 int row, col;
2851
2852 if ( m_table )
2853 {
2854 for ( row = 0; row < m_numRows; row++ )
2855 {
2856 for ( col = 0; col < m_numCols; col++ )
2857 {
2858 m_table->SetValue( row, col, GetCellValue(row, col) );
2859 }
2860 }
2861
2862 return TRUE;
2863 }
2864
2865 return FALSE;
2866 }
2867
2868
2869
2870 // Note - this function only draws cells that are in the list of
2871 // exposed cells (usually set from the update region by
2872 // CalcExposedCells)
2873 //
2874 void wxGrid::DrawGridCellArea( wxDC& dc )
2875 {
2876 if ( !m_numRows || !m_numCols ) return;
2877
2878 size_t i;
2879 size_t numCells = m_cellsExposed.GetCount();
2880
2881 for ( i = 0; i < numCells; i++ )
2882 {
2883 DrawCell( dc, m_cellsExposed[i] );
2884 }
2885 }
2886
2887
2888 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
2889 {
2890 if ( m_colWidths[coords.GetCol()] <=0 ||
2891 m_rowHeights[coords.GetRow()] <= 0 ) return;
2892
2893 #if !WXGRID_DRAW_LINES
2894 if ( m_gridLinesEnabled )
2895 DrawCellBorder( dc, coords );
2896 #endif
2897
2898 DrawCellBackground( dc, coords );
2899
2900 // TODO: separate functions here for different kinds of cells ?
2901 // e.g. text, image
2902 //
2903 DrawCellValue( dc, coords );
2904 }
2905
2906
2907 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
2908 {
2909 if ( m_colWidths[coords.GetCol()] <=0 ||
2910 m_rowHeights[coords.GetRow()] <= 0 ) return;
2911
2912 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
2913 int row = coords.GetRow();
2914 int col = coords.GetCol();
2915
2916 // right hand border
2917 //
2918 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
2919 m_colRights[col], m_rowBottoms[row] );
2920
2921 // bottom border
2922 //
2923 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
2924 m_colRights[col], m_rowBottoms[row] );
2925 }
2926
2927
2928 void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
2929 {
2930 if ( m_colWidths[coords.GetCol()] <=0 ||
2931 m_rowHeights[coords.GetRow()] <= 0 ) return;
2932
2933 int row = coords.GetRow();
2934 int col = coords.GetCol();
2935
2936 dc.SetBackgroundMode( wxSOLID );
2937
2938 if ( IsInSelection( coords ) )
2939 {
2940 // TODO: improve this
2941 //
2942 dc.SetBrush( *wxBLACK_BRUSH );
2943 }
2944 else
2945 {
2946 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
2947 }
2948
2949 dc.SetPen( *wxTRANSPARENT_PEN );
2950
2951 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
2952 m_rowBottoms[row] - m_rowHeights[row] + 1,
2953 m_colWidths[col]-1,
2954 m_rowHeights[row]-1 );
2955 }
2956
2957
2958 void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
2959 {
2960 if ( m_colWidths[coords.GetCol()] <=0 ||
2961 m_rowHeights[coords.GetRow()] <= 0 ) return;
2962
2963 int row = coords.GetRow();
2964 int col = coords.GetCol();
2965
2966 dc.SetBackgroundMode( wxTRANSPARENT );
2967
2968 if ( IsInSelection( row, col ) )
2969 {
2970 // TODO: improve this
2971 //
2972 dc.SetTextBackground( wxColour(0, 0, 0) );
2973 dc.SetTextForeground( wxColour(255, 255, 255) );
2974 }
2975 else
2976 {
2977 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
2978 dc.SetTextForeground( GetCellTextColour(row, col) );
2979 }
2980 dc.SetFont( GetCellFont(row, col) );
2981
2982 int hAlign, vAlign;
2983 GetCellAlignment( row, col, &hAlign, &vAlign );
2984
2985 wxRect rect;
2986 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2987 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2988 rect.SetWidth( m_colWidths[col] - 4 );
2989 rect.SetHeight( m_rowHeights[row] - 4 );
2990
2991 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
2992 }
2993
2994
2995
2996 // TODO: remove this ???
2997 // This is used to redraw all grid lines e.g. when the grid line colour
2998 // has been changed
2999 //
3000 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
3001 {
3002 if ( !m_gridLinesEnabled ||
3003 !m_numRows ||
3004 !m_numCols ) return;
3005
3006 int top, bottom, left, right;
3007
3008 if (reg.IsEmpty()){
3009 int cw, ch;
3010 m_gridWin->GetClientSize(&cw, &ch);
3011
3012 // virtual coords of visible area
3013 //
3014 CalcUnscrolledPosition( 0, 0, &left, &top );
3015 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3016 }
3017 else{
3018 wxCoord x, y, w, h;
3019 reg.GetBox(x, y, w, h);
3020 CalcUnscrolledPosition( x, y, &left, &top );
3021 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3022 }
3023
3024 // avoid drawing grid lines past the last row and col
3025 //
3026 right = wxMin( right, m_colRights[m_numCols-1] );
3027 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3028
3029 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3030
3031 // horizontal grid lines
3032 //
3033 int i;
3034 for ( i = 0; i < m_numRows; i++ )
3035 {
3036 if ( m_rowBottoms[i] > bottom )
3037 {
3038 break;
3039 }
3040 else if ( m_rowBottoms[i] >= top )
3041 {
3042 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
3043 }
3044 }
3045
3046
3047 // vertical grid lines
3048 //
3049 for ( i = 0; i < m_numCols; i++ )
3050 {
3051 if ( m_colRights[i] > right )
3052 {
3053 break;
3054 }
3055 else if ( m_colRights[i] >= left )
3056 {
3057 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
3058 }
3059 }
3060 }
3061
3062
3063 void wxGrid::DrawRowLabels( wxDC& dc )
3064 {
3065 if ( !m_numRows || !m_numCols ) return;
3066
3067 size_t i;
3068 size_t numLabels = m_rowLabelsExposed.GetCount();
3069
3070 for ( i = 0; i < numLabels; i++ )
3071 {
3072 DrawRowLabel( dc, m_rowLabelsExposed[i] );
3073 }
3074 }
3075
3076
3077 void wxGrid::DrawRowLabel( wxDC& dc, int row )
3078 {
3079 if ( m_rowHeights[row] <= 0 ) return;
3080
3081 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
3082
3083 dc.SetPen( *wxBLACK_PEN );
3084 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3085 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3086
3087 dc.DrawLine( 0, m_rowBottoms[row]-1,
3088 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3089
3090 dc.SetPen( *wxWHITE_PEN );
3091 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3092 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
3093
3094 dc.SetBackgroundMode( wxTRANSPARENT );
3095 dc.SetTextForeground( GetLabelTextColour() );
3096 dc.SetFont( GetLabelFont() );
3097
3098 int hAlign, vAlign;
3099 GetRowLabelAlignment( &hAlign, &vAlign );
3100
3101 wxRect rect;
3102 rect.SetX( 2 );
3103 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3104 rect.SetWidth( m_rowLabelWidth - 4 );
3105 rect.SetHeight( m_rowHeights[row] - 4 );
3106 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
3107 }
3108
3109
3110 void wxGrid::DrawColLabels( wxDC& dc )
3111 {
3112 if ( !m_numRows || !m_numCols ) return;
3113
3114 size_t i;
3115 size_t numLabels = m_colLabelsExposed.GetCount();
3116
3117 for ( i = 0; i < numLabels; i++ )
3118 {
3119 DrawColLabel( dc, m_colLabelsExposed[i] );
3120 }
3121 }
3122
3123
3124 void wxGrid::DrawColLabel( wxDC& dc, int col )
3125 {
3126 if ( m_colWidths[col] <= 0 ) return;
3127
3128 int colLeft = m_colRights[col] - m_colWidths[col];
3129
3130 dc.SetPen( *wxBLACK_PEN );
3131 dc.DrawLine( m_colRights[col]-1, 0,
3132 m_colRights[col]-1, m_colLabelHeight-1 );
3133
3134 dc.DrawLine( colLeft, m_colLabelHeight-1,
3135 m_colRights[col]-1, m_colLabelHeight-1 );
3136
3137 dc.SetPen( *wxWHITE_PEN );
3138 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
3139 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
3140
3141 dc.SetBackgroundMode( wxTRANSPARENT );
3142 dc.SetTextForeground( GetLabelTextColour() );
3143 dc.SetFont( GetLabelFont() );
3144
3145 dc.SetBackgroundMode( wxTRANSPARENT );
3146 dc.SetTextForeground( GetLabelTextColour() );
3147 dc.SetFont( GetLabelFont() );
3148
3149 int hAlign, vAlign;
3150 GetColLabelAlignment( &hAlign, &vAlign );
3151
3152 wxRect rect;
3153 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3154 rect.SetY( 2 );
3155 rect.SetWidth( m_colWidths[col] - 4 );
3156 rect.SetHeight( m_colLabelHeight - 4 );
3157 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
3158 }
3159
3160
3161 void wxGrid::DrawTextRectangle( wxDC& dc,
3162 const wxString& value,
3163 const wxRect& rect,
3164 int horizAlign,
3165 int vertAlign )
3166 {
3167 long textWidth, textHeight;
3168 long lineWidth, lineHeight;
3169 wxArrayString lines;
3170
3171 dc.SetClippingRegion( rect );
3172 StringToLines( value, lines );
3173 if ( lines.GetCount() )
3174 {
3175 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
3176 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
3177
3178 float x, y;
3179 switch ( horizAlign )
3180 {
3181 case wxRIGHT:
3182 x = rect.x + (rect.width - textWidth - 1);
3183 break;
3184
3185 case wxCENTRE:
3186 x = rect.x + ((rect.width - textWidth)/2);
3187 break;
3188
3189 case wxLEFT:
3190 default:
3191 x = rect.x + 1;
3192 break;
3193 }
3194
3195 switch ( vertAlign )
3196 {
3197 case wxBOTTOM:
3198 y = rect.y + (rect.height - textHeight - 1);
3199 break;
3200
3201 case wxCENTRE:
3202 y = rect.y + ((rect.height - textHeight)/2);
3203 break;
3204
3205 case wxTOP:
3206 default:
3207 y = rect.y + 1;
3208 break;
3209 }
3210
3211 for ( size_t i = 0; i < lines.GetCount(); i++ )
3212 {
3213 dc.DrawText( lines[i], (long)x, (long)y );
3214 y += lineHeight;
3215 }
3216 }
3217
3218 dc.DestroyClippingRegion();
3219 }
3220
3221
3222 // Split multi line text up into an array of strings. Any existing
3223 // contents of the string array are preserved.
3224 //
3225 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
3226 {
3227 int startPos = 0;
3228 int pos;
3229 wxTextFile tf;
3230 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
3231 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
3232
3233 while ( startPos < (int)tVal.Length() )
3234 {
3235 pos = tVal.Mid(startPos).Find( eol );
3236 if ( pos < 0 )
3237 {
3238 break;
3239 }
3240 else if ( pos == 0 )
3241 {
3242 lines.Add( wxEmptyString );
3243 }
3244 else
3245 {
3246 lines.Add( value.Mid(startPos, pos) );
3247 }
3248 startPos += pos+1;
3249 }
3250 if ( startPos < (int)value.Length() )
3251 {
3252 lines.Add( value.Mid( startPos ) );
3253 }
3254 }
3255
3256
3257 void wxGrid::GetTextBoxSize( wxDC& dc,
3258 wxArrayString& lines,
3259 long *width, long *height )
3260 {
3261 long w = 0;
3262 long h = 0;
3263 long lineW, lineH;
3264
3265 size_t i;
3266 for ( i = 0; i < lines.GetCount(); i++ )
3267 {
3268 dc.GetTextExtent( lines[i], &lineW, &lineH );
3269 w = wxMax( w, lineW );
3270 h += lineH;
3271 }
3272
3273 *width = w;
3274 *height = h;
3275 }
3276
3277
3278 //
3279 // ------ Edit control functions
3280 //
3281
3282
3283 void wxGrid::EnableEditing( bool edit )
3284 {
3285 // TODO: improve this ?
3286 //
3287 if ( edit != m_editable )
3288 {
3289 m_editable = edit;
3290
3291 // TODO: extend this for other edit control types
3292 //
3293 if ( m_editCtrlType == wxGRID_TEXTCTRL )
3294 {
3295 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
3296 }
3297 }
3298 }
3299
3300
3301 #if 0 // disabled for the moment - the cell control is always active
3302 void wxGrid::EnableCellEditControl( bool enable )
3303 {
3304 if ( m_cellEditCtrl &&
3305 enable != m_cellEditCtrlEnabled )
3306 {
3307 m_cellEditCtrlEnabled = enable;
3308
3309 if ( m_cellEditCtrlEnabled )
3310 {
3311 SetEditControlValue();
3312 ShowCellEditControl();
3313 }
3314 else
3315 {
3316 HideCellEditControl();
3317 SaveEditControlValue();
3318 }
3319 }
3320 }
3321 #endif
3322
3323
3324 void wxGrid::ShowCellEditControl()
3325 {
3326 wxRect rect;
3327
3328 if ( IsCellEditControlEnabled() )
3329 {
3330 if ( !IsVisible( m_currentCellCoords ) )
3331 {
3332 return;
3333 }
3334 else
3335 {
3336 rect = CellToRect( m_currentCellCoords );
3337
3338 // convert to scrolled coords
3339 //
3340 int left, top, right, bottom;
3341 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
3342 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
3343
3344 int cw, ch;
3345 m_gridWin->GetClientSize( &cw, &ch );
3346
3347 // Make the edit control large enough to allow for internal margins
3348 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3349 //
3350 int extra;
3351 #if defined(__WXMOTIF__)
3352 if ( m_currentCellCoords.GetRow() == 0 ||
3353 m_currentCellCoords.GetCol() == 0 )
3354 {
3355 extra = 2;
3356 }
3357 else
3358 {
3359 extra = 4;
3360 }
3361 #else
3362 if ( m_currentCellCoords.GetRow() == 0 ||
3363 m_currentCellCoords.GetCol() == 0 )
3364 {
3365 extra = 1;
3366 }
3367 else
3368 {
3369 extra = 2;
3370 }
3371 #endif
3372
3373 #if defined(__WXGTK__)
3374 int top_diff = 0;
3375 int left_diff = 0;
3376 if (left != 0) left_diff++;
3377 if (top != 0) top_diff++;
3378 rect.SetLeft( left + left_diff );
3379 rect.SetTop( top + top_diff );
3380 rect.SetRight( rect.GetRight() - left_diff );
3381 rect.SetBottom( rect.GetBottom() - top_diff );
3382 #else
3383 rect.SetLeft( wxMax(0, left - extra) );
3384 rect.SetTop( wxMax(0, top - extra) );
3385 rect.SetRight( rect.GetRight() + 2*extra );
3386 rect.SetBottom( rect.GetBottom() + 2*extra );
3387 #endif
3388
3389 m_cellEditCtrl->SetSize( rect );
3390 m_cellEditCtrl->Show( TRUE );
3391
3392 switch ( m_editCtrlType )
3393 {
3394 case wxGRID_TEXTCTRL:
3395 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3396 break;
3397
3398 case wxGRID_CHECKBOX:
3399 // TODO: anything ???
3400 //
3401 break;
3402
3403 case wxGRID_CHOICE:
3404 // TODO: anything ???
3405 //
3406 break;
3407
3408 case wxGRID_COMBOBOX:
3409 // TODO: anything ???
3410 //
3411 break;
3412 }
3413
3414 m_cellEditCtrl->SetFocus();
3415 }
3416 }
3417 }
3418
3419
3420 void wxGrid::HideCellEditControl()
3421 {
3422 if ( IsCellEditControlEnabled() )
3423 {
3424 m_cellEditCtrl->Show( FALSE );
3425 }
3426 }
3427
3428
3429 void wxGrid::SetEditControlValue( const wxString& value )
3430 {
3431 if ( m_table )
3432 {
3433 wxString s;
3434 if ( !value )
3435 s = GetCellValue(m_currentCellCoords);
3436 else
3437 s = value;
3438
3439 if ( IsCellEditControlEnabled() )
3440 {
3441 switch ( m_editCtrlType )
3442 {
3443 case wxGRID_TEXTCTRL:
3444 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3445 break;
3446
3447 case wxGRID_CHECKBOX:
3448 // TODO: implement this
3449 //
3450 break;
3451
3452 case wxGRID_CHOICE:
3453 // TODO: implement this
3454 //
3455 break;
3456
3457 case wxGRID_COMBOBOX:
3458 // TODO: implement this
3459 //
3460 break;
3461 }
3462 }
3463 }
3464 }
3465
3466
3467 void wxGrid::SaveEditControlValue()
3468 {
3469 if ( m_table )
3470 {
3471 wxWindow *ctrl = (wxWindow *)NULL;
3472
3473 if ( IsCellEditControlEnabled() )
3474 {
3475 ctrl = m_cellEditCtrl;
3476 }
3477 else
3478 {
3479 return;
3480 }
3481
3482 bool valueChanged = FALSE;
3483
3484 switch ( m_editCtrlType )
3485 {
3486 case wxGRID_TEXTCTRL:
3487 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3488 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3489 SetCellValue( m_currentCellCoords,
3490 ((wxTextCtrl *) ctrl)->GetValue() );
3491 break;
3492
3493 case wxGRID_CHECKBOX:
3494 // TODO: implement this
3495 //
3496 break;
3497
3498 case wxGRID_CHOICE:
3499 // TODO: implement this
3500 //
3501 break;
3502
3503 case wxGRID_COMBOBOX:
3504 // TODO: implement this
3505 //
3506 break;
3507 }
3508
3509 if ( valueChanged )
3510 {
3511 SendEvent( EVT_GRID_CELL_CHANGE,
3512 m_currentCellCoords.GetRow(),
3513 m_currentCellCoords.GetCol() );
3514 }
3515 }
3516 }
3517
3518
3519 //
3520 // ------ Grid location functions
3521 // Note that all of these functions work with the logical coordinates of
3522 // grid cells and labels so you will need to convert from device
3523 // coordinates for mouse events etc.
3524 //
3525
3526 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
3527 {
3528 int row = YToRow(y);
3529 int col = XToCol(x);
3530
3531 if ( row == -1 || col == -1 )
3532 {
3533 coords = wxGridNoCellCoords;
3534 }
3535 else
3536 {
3537 coords.Set( row, col );
3538 }
3539 }
3540
3541
3542 int wxGrid::YToRow( int y )
3543 {
3544 int i;
3545
3546 for ( i = 0; i < m_numRows; i++ )
3547 {
3548 if ( y < m_rowBottoms[i] ) return i;
3549 }
3550
3551 return -1;
3552 }
3553
3554
3555 int wxGrid::XToCol( int x )
3556 {
3557 int i;
3558
3559 for ( i = 0; i < m_numCols; i++ )
3560 {
3561 if ( x < m_colRights[i] ) return i;
3562 }
3563
3564 return -1;
3565 }
3566
3567
3568 // return the row number that that the y coord is near the edge of, or
3569 // -1 if not near an edge
3570 //
3571 int wxGrid::YToEdgeOfRow( int y )
3572 {
3573 int i, d;
3574
3575 for ( i = 0; i < m_numRows; i++ )
3576 {
3577 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
3578 {
3579 d = abs( y - m_rowBottoms[i] );
3580 {
3581 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3582 }
3583 }
3584 }
3585
3586 return -1;
3587 }
3588
3589
3590 // return the col number that that the x coord is near the edge of, or
3591 // -1 if not near an edge
3592 //
3593 int wxGrid::XToEdgeOfCol( int x )
3594 {
3595 int i, d;
3596
3597 for ( i = 0; i < m_numCols; i++ )
3598 {
3599 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3600 {
3601 d = abs( x - m_colRights[i] );
3602 {
3603 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3604 }
3605 }
3606 }
3607
3608 return -1;
3609 }
3610
3611
3612 wxRect wxGrid::CellToRect( int row, int col )
3613 {
3614 wxRect rect( -1, -1, -1, -1 );
3615
3616 if ( row >= 0 && row < m_numRows &&
3617 col >= 0 && col < m_numCols )
3618 {
3619 rect.x = m_colRights[col] - m_colWidths[col];
3620 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3621 rect.width = m_colWidths[col];
3622 rect.height = m_rowHeights[ row ];
3623 }
3624
3625 return rect;
3626 }
3627
3628
3629 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3630 {
3631 // get the cell rectangle in logical coords
3632 //
3633 wxRect r( CellToRect( row, col ) );
3634
3635 // convert to device coords
3636 //
3637 int left, top, right, bottom;
3638 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3639 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3640
3641 // check against the client area of the grid window
3642 //
3643 int cw, ch;
3644 m_gridWin->GetClientSize( &cw, &ch );
3645
3646 if ( wholeCellVisible )
3647 {
3648 // is the cell wholly visible ?
3649 //
3650 return ( left >= 0 && right <= cw &&
3651 top >= 0 && bottom <= ch );
3652 }
3653 else
3654 {
3655 // is the cell partly visible ?
3656 //
3657 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3658 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3659 }
3660 }
3661
3662
3663 // make the specified cell location visible by doing a minimal amount
3664 // of scrolling
3665 //
3666 void wxGrid::MakeCellVisible( int row, int col )
3667 {
3668 int i;
3669 int xpos = -1, ypos = -1;
3670
3671 if ( row >= 0 && row < m_numRows &&
3672 col >= 0 && col < m_numCols )
3673 {
3674 // get the cell rectangle in logical coords
3675 //
3676 wxRect r( CellToRect( row, col ) );
3677
3678 // convert to device coords
3679 //
3680 int left, top, right, bottom;
3681 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3682 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3683
3684 int cw, ch;
3685 m_gridWin->GetClientSize( &cw, &ch );
3686
3687 if ( top < 0 )
3688 {
3689 ypos = r.GetTop();
3690 }
3691 else if ( bottom > ch )
3692 {
3693 int h = r.GetHeight();
3694 ypos = r.GetTop();
3695 for ( i = row-1; i >= 0; i-- )
3696 {
3697 if ( h + m_rowHeights[i] > ch ) break;
3698
3699 h += m_rowHeights[i];
3700 ypos -= m_rowHeights[i];
3701 }
3702
3703 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3704 // have rounding errors (this is important, because if we do, we
3705 // might not scroll at all and some cells won't be redrawn)
3706 ypos += GRID_SCROLL_LINE / 2;
3707 }
3708
3709 if ( left < 0 )
3710 {
3711 xpos = r.GetLeft();
3712 }
3713 else if ( right > cw )
3714 {
3715 int w = r.GetWidth();
3716 xpos = r.GetLeft();
3717 for ( i = col-1; i >= 0; i-- )
3718 {
3719 if ( w + m_colWidths[i] > cw ) break;
3720
3721 w += m_colWidths[i];
3722 xpos -= m_colWidths[i];
3723 }
3724
3725 // see comment for ypos above
3726 xpos += GRID_SCROLL_LINE / 2;
3727 }
3728
3729 if ( xpos != -1 || ypos != -1 )
3730 {
3731 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
3732 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
3733 Scroll( xpos, ypos );
3734 AdjustScrollbars();
3735 }
3736 }
3737 }
3738
3739
3740 //
3741 // ------ Grid cursor movement functions
3742 //
3743
3744 bool wxGrid::MoveCursorUp()
3745 {
3746 if ( m_currentCellCoords != wxGridNoCellCoords &&
3747 m_currentCellCoords.GetRow() > 0 )
3748 {
3749 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3750 m_currentCellCoords.GetCol() );
3751
3752 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3753 m_currentCellCoords.GetCol() );
3754
3755 return TRUE;
3756 }
3757
3758 return FALSE;
3759 }
3760
3761
3762 bool wxGrid::MoveCursorDown()
3763 {
3764 // TODO: allow for scrolling
3765 //
3766 if ( m_currentCellCoords != wxGridNoCellCoords &&
3767 m_currentCellCoords.GetRow() < m_numRows-1 )
3768 {
3769 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3770 m_currentCellCoords.GetCol() );
3771
3772 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3773 m_currentCellCoords.GetCol() );
3774
3775 return TRUE;
3776 }
3777
3778 return FALSE;
3779 }
3780
3781
3782 bool wxGrid::MoveCursorLeft()
3783 {
3784 if ( m_currentCellCoords != wxGridNoCellCoords &&
3785 m_currentCellCoords.GetCol() > 0 )
3786 {
3787 MakeCellVisible( m_currentCellCoords.GetRow(),
3788 m_currentCellCoords.GetCol() - 1 );
3789
3790 SetCurrentCell( m_currentCellCoords.GetRow(),
3791 m_currentCellCoords.GetCol() - 1 );
3792
3793 return TRUE;
3794 }
3795
3796 return FALSE;
3797 }
3798
3799
3800 bool wxGrid::MoveCursorRight()
3801 {
3802 if ( m_currentCellCoords != wxGridNoCellCoords &&
3803 m_currentCellCoords.GetCol() < m_numCols - 1 )
3804 {
3805 MakeCellVisible( m_currentCellCoords.GetRow(),
3806 m_currentCellCoords.GetCol() + 1 );
3807
3808 SetCurrentCell( m_currentCellCoords.GetRow(),
3809 m_currentCellCoords.GetCol() + 1 );
3810
3811 return TRUE;
3812 }
3813
3814 return FALSE;
3815 }
3816
3817
3818 bool wxGrid::MovePageUp()
3819 {
3820 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
3821
3822 int row = m_currentCellCoords.GetRow();
3823 if ( row > 0 )
3824 {
3825 int cw, ch;
3826 m_gridWin->GetClientSize( &cw, &ch );
3827
3828 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3829 int newRow = YToRow( y - ch + 1 );
3830 if ( newRow == -1 )
3831 {
3832 newRow = 0;
3833 }
3834 else if ( newRow == row )
3835 {
3836 newRow = row - 1;
3837 }
3838
3839 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3840 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
3841
3842 return TRUE;
3843 }
3844
3845 return FALSE;
3846 }
3847
3848 bool wxGrid::MovePageDown()
3849 {
3850 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
3851
3852 int row = m_currentCellCoords.GetRow();
3853 if ( row < m_numRows )
3854 {
3855 int cw, ch;
3856 m_gridWin->GetClientSize( &cw, &ch );
3857
3858 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3859 int newRow = YToRow( y + ch );
3860 if ( newRow == -1 )
3861 {
3862 newRow = m_numRows - 1;
3863 }
3864 else if ( newRow == row )
3865 {
3866 newRow = row + 1;
3867 }
3868
3869 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3870 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
3871
3872 return TRUE;
3873 }
3874
3875 return FALSE;
3876 }
3877
3878 bool wxGrid::MoveCursorUpBlock()
3879 {
3880 if ( m_table &&
3881 m_currentCellCoords != wxGridNoCellCoords &&
3882 m_currentCellCoords.GetRow() > 0 )
3883 {
3884 int row = m_currentCellCoords.GetRow();
3885 int col = m_currentCellCoords.GetCol();
3886
3887 if ( m_table->IsEmptyCell(row, col) )
3888 {
3889 // starting in an empty cell: find the next block of
3890 // non-empty cells
3891 //
3892 while ( row > 0 )
3893 {
3894 row-- ;
3895 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3896 }
3897 }
3898 else if ( m_table->IsEmptyCell(row-1, col) )
3899 {
3900 // starting at the top of a block: find the next block
3901 //
3902 row--;
3903 while ( row > 0 )
3904 {
3905 row-- ;
3906 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3907 }
3908 }
3909 else
3910 {
3911 // starting within a block: find the top of the block
3912 //
3913 while ( row > 0 )
3914 {
3915 row-- ;
3916 if ( m_table->IsEmptyCell(row, col) )
3917 {
3918 row++ ;
3919 break;
3920 }
3921 }
3922 }
3923
3924 MakeCellVisible( row, col );
3925 SetCurrentCell( row, col );
3926
3927 return TRUE;
3928 }
3929
3930 return FALSE;
3931 }
3932
3933 bool wxGrid::MoveCursorDownBlock()
3934 {
3935 if ( m_table &&
3936 m_currentCellCoords != wxGridNoCellCoords &&
3937 m_currentCellCoords.GetRow() < m_numRows-1 )
3938 {
3939 int row = m_currentCellCoords.GetRow();
3940 int col = m_currentCellCoords.GetCol();
3941
3942 if ( m_table->IsEmptyCell(row, col) )
3943 {
3944 // starting in an empty cell: find the next block of
3945 // non-empty cells
3946 //
3947 while ( row < m_numRows-1 )
3948 {
3949 row++ ;
3950 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3951 }
3952 }
3953 else if ( m_table->IsEmptyCell(row+1, col) )
3954 {
3955 // starting at the bottom of a block: find the next block
3956 //
3957 row++;
3958 while ( row < m_numRows-1 )
3959 {
3960 row++ ;
3961 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3962 }
3963 }
3964 else
3965 {
3966 // starting within a block: find the bottom of the block
3967 //
3968 while ( row < m_numRows-1 )
3969 {
3970 row++ ;
3971 if ( m_table->IsEmptyCell(row, col) )
3972 {
3973 row-- ;
3974 break;
3975 }
3976 }
3977 }
3978
3979 MakeCellVisible( row, col );
3980 SetCurrentCell( row, col );
3981
3982 return TRUE;
3983 }
3984
3985 return FALSE;
3986 }
3987
3988 bool wxGrid::MoveCursorLeftBlock()
3989 {
3990 if ( m_table &&
3991 m_currentCellCoords != wxGridNoCellCoords &&
3992 m_currentCellCoords.GetCol() > 0 )
3993 {
3994 int row = m_currentCellCoords.GetRow();
3995 int col = m_currentCellCoords.GetCol();
3996
3997 if ( m_table->IsEmptyCell(row, col) )
3998 {
3999 // starting in an empty cell: find the next block of
4000 // non-empty cells
4001 //
4002 while ( col > 0 )
4003 {
4004 col-- ;
4005 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4006 }
4007 }
4008 else if ( m_table->IsEmptyCell(row, col-1) )
4009 {
4010 // starting at the left of a block: find the next block
4011 //
4012 col--;
4013 while ( col > 0 )
4014 {
4015 col-- ;
4016 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4017 }
4018 }
4019 else
4020 {
4021 // starting within a block: find the left of the block
4022 //
4023 while ( col > 0 )
4024 {
4025 col-- ;
4026 if ( m_table->IsEmptyCell(row, col) )
4027 {
4028 col++ ;
4029 break;
4030 }
4031 }
4032 }
4033
4034 MakeCellVisible( row, col );
4035 SetCurrentCell( row, col );
4036
4037 return TRUE;
4038 }
4039
4040 return FALSE;
4041 }
4042
4043 bool wxGrid::MoveCursorRightBlock()
4044 {
4045 if ( m_table &&
4046 m_currentCellCoords != wxGridNoCellCoords &&
4047 m_currentCellCoords.GetCol() < m_numCols-1 )
4048 {
4049 int row = m_currentCellCoords.GetRow();
4050 int col = m_currentCellCoords.GetCol();
4051
4052 if ( m_table->IsEmptyCell(row, col) )
4053 {
4054 // starting in an empty cell: find the next block of
4055 // non-empty cells
4056 //
4057 while ( col < m_numCols-1 )
4058 {
4059 col++ ;
4060 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4061 }
4062 }
4063 else if ( m_table->IsEmptyCell(row, col+1) )
4064 {
4065 // starting at the right of a block: find the next block
4066 //
4067 col++;
4068 while ( col < m_numCols-1 )
4069 {
4070 col++ ;
4071 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4072 }
4073 }
4074 else
4075 {
4076 // starting within a block: find the right of the block
4077 //
4078 while ( col < m_numCols-1 )
4079 {
4080 col++ ;
4081 if ( m_table->IsEmptyCell(row, col) )
4082 {
4083 col-- ;
4084 break;
4085 }
4086 }
4087 }
4088
4089 MakeCellVisible( row, col );
4090 SetCurrentCell( row, col );
4091
4092 return TRUE;
4093 }
4094
4095 return FALSE;
4096 }
4097
4098
4099
4100 //
4101 // ------ Label values and formatting
4102 //
4103
4104 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4105 {
4106 *horiz = m_rowLabelHorizAlign;
4107 *vert = m_rowLabelVertAlign;
4108 }
4109
4110 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4111 {
4112 *horiz = m_colLabelHorizAlign;
4113 *vert = m_colLabelVertAlign;
4114 }
4115
4116 wxString wxGrid::GetRowLabelValue( int row )
4117 {
4118 if ( m_table )
4119 {
4120 return m_table->GetRowLabelValue( row );
4121 }
4122 else
4123 {
4124 wxString s;
4125 s << row;
4126 return s;
4127 }
4128 }
4129
4130 wxString wxGrid::GetColLabelValue( int col )
4131 {
4132 if ( m_table )
4133 {
4134 return m_table->GetColLabelValue( col );
4135 }
4136 else
4137 {
4138 wxString s;
4139 s << col;
4140 return s;
4141 }
4142 }
4143
4144
4145 void wxGrid::SetRowLabelSize( int width )
4146 {
4147 width = wxMax( width, 0 );
4148 if ( width != m_rowLabelWidth )
4149 {
4150 if ( width == 0 )
4151 {
4152 m_rowLabelWin->Show( FALSE );
4153 m_cornerLabelWin->Show( FALSE );
4154 }
4155 else if ( m_rowLabelWidth == 0 )
4156 {
4157 m_rowLabelWin->Show( TRUE );
4158 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
4159 }
4160
4161 m_rowLabelWidth = width;
4162 CalcWindowSizes();
4163 Refresh( TRUE );
4164 }
4165 }
4166
4167
4168 void wxGrid::SetColLabelSize( int height )
4169 {
4170 height = wxMax( height, 0 );
4171 if ( height != m_colLabelHeight )
4172 {
4173 if ( height == 0 )
4174 {
4175 m_colLabelWin->Show( FALSE );
4176 m_cornerLabelWin->Show( FALSE );
4177 }
4178 else if ( m_colLabelHeight == 0 )
4179 {
4180 m_colLabelWin->Show( TRUE );
4181 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
4182 }
4183
4184 m_colLabelHeight = height;
4185 CalcWindowSizes();
4186 Refresh( TRUE );
4187 }
4188 }
4189
4190
4191 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4192 {
4193 if ( m_labelBackgroundColour != colour )
4194 {
4195 m_labelBackgroundColour = colour;
4196 m_rowLabelWin->SetBackgroundColour( colour );
4197 m_colLabelWin->SetBackgroundColour( colour );
4198 m_cornerLabelWin->SetBackgroundColour( colour );
4199
4200 if ( !GetBatchCount() )
4201 {
4202 m_rowLabelWin->Refresh();
4203 m_colLabelWin->Refresh();
4204 m_cornerLabelWin->Refresh();
4205 }
4206 }
4207 }
4208
4209 void wxGrid::SetLabelTextColour( const wxColour& colour )
4210 {
4211 if ( m_labelTextColour != colour )
4212 {
4213 m_labelTextColour = colour;
4214 if ( !GetBatchCount() )
4215 {
4216 m_rowLabelWin->Refresh();
4217 m_colLabelWin->Refresh();
4218 }
4219 }
4220 }
4221
4222 void wxGrid::SetLabelFont( const wxFont& font )
4223 {
4224 m_labelFont = font;
4225 if ( !GetBatchCount() )
4226 {
4227 m_rowLabelWin->Refresh();
4228 m_colLabelWin->Refresh();
4229 }
4230 }
4231
4232 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
4233 {
4234 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4235 {
4236 m_rowLabelHorizAlign = horiz;
4237 }
4238
4239 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4240 {
4241 m_rowLabelVertAlign = vert;
4242 }
4243
4244 if ( !GetBatchCount() )
4245 {
4246 m_rowLabelWin->Refresh();
4247 }
4248 }
4249
4250 void wxGrid::SetColLabelAlignment( int horiz, int vert )
4251 {
4252 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4253 {
4254 m_colLabelHorizAlign = horiz;
4255 }
4256
4257 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4258 {
4259 m_colLabelVertAlign = vert;
4260 }
4261
4262 if ( !GetBatchCount() )
4263 {
4264 m_colLabelWin->Refresh();
4265 }
4266 }
4267
4268 void wxGrid::SetRowLabelValue( int row, const wxString& s )
4269 {
4270 if ( m_table )
4271 {
4272 m_table->SetRowLabelValue( row, s );
4273 if ( !GetBatchCount() )
4274 {
4275 wxRect rect = CellToRect( row, 0);
4276 if ( rect.height > 0 )
4277 {
4278 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
4279 rect.x = m_left;
4280 rect.width = m_rowLabelWidth;
4281 m_rowLabelWin->Refresh( TRUE, &rect );
4282 }
4283 }
4284 }
4285 }
4286
4287 void wxGrid::SetColLabelValue( int col, const wxString& s )
4288 {
4289 if ( m_table )
4290 {
4291 m_table->SetColLabelValue( col, s );
4292 if ( !GetBatchCount() )
4293 {
4294 wxRect rect = CellToRect( 0, col );
4295 if ( rect.width > 0 )
4296 {
4297 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
4298 rect.y = m_top;
4299 rect.height = m_colLabelHeight;
4300 m_colLabelWin->Refresh( TRUE, &rect );
4301 }
4302 }
4303 }
4304 }
4305
4306 void wxGrid::SetGridLineColour( const wxColour& colour )
4307 {
4308 if ( m_gridLineColour != colour )
4309 {
4310 m_gridLineColour = colour;
4311
4312 wxClientDC dc( m_gridWin );
4313 PrepareDC( dc );
4314 DrawAllGridLines( dc, wxRegion() );
4315 }
4316 }
4317
4318 void wxGrid::EnableGridLines( bool enable )
4319 {
4320 if ( enable != m_gridLinesEnabled )
4321 {
4322 m_gridLinesEnabled = enable;
4323
4324 if ( !GetBatchCount() )
4325 {
4326 if ( enable )
4327 {
4328 wxClientDC dc( m_gridWin );
4329 PrepareDC( dc );
4330 DrawAllGridLines( dc, wxRegion() );
4331 }
4332 else
4333 {
4334 m_gridWin->Refresh();
4335 }
4336 }
4337 }
4338 }
4339
4340
4341 int wxGrid::GetDefaultRowSize()
4342 {
4343 return m_defaultRowHeight;
4344 }
4345
4346 int wxGrid::GetRowSize( int row )
4347 {
4348 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
4349
4350 return m_rowHeights[row];
4351 }
4352
4353 int wxGrid::GetDefaultColSize()
4354 {
4355 return m_defaultColWidth;
4356 }
4357
4358 int wxGrid::GetColSize( int col )
4359 {
4360 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
4361
4362 return m_colWidths[col];
4363 }
4364
4365 wxColour wxGrid::GetDefaultCellBackgroundColour()
4366 {
4367 return m_gridWin->GetBackgroundColour();
4368 }
4369
4370 // TODO VZ: this must be optimized to allow only retrieveing attr once!
4371
4372 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
4373 {
4374 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4375
4376 wxColour colour;
4377 if ( attr && attr->HasBackgroundColour() )
4378 colour = attr->GetBackgroundColour();
4379 else
4380 colour = GetDefaultCellBackgroundColour();
4381
4382 delete attr;
4383
4384 return colour;
4385 }
4386
4387 wxColour wxGrid::GetDefaultCellTextColour()
4388 {
4389 return m_gridWin->GetForegroundColour();
4390 }
4391
4392 wxColour wxGrid::GetCellTextColour( int row, int col )
4393 {
4394 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4395
4396 wxColour colour;
4397 if ( attr && attr->HasTextColour() )
4398 colour = attr->GetTextColour();
4399 else
4400 colour = GetDefaultCellTextColour();
4401
4402 delete attr;
4403
4404 return colour;
4405 }
4406
4407
4408 wxFont wxGrid::GetDefaultCellFont()
4409 {
4410 return m_defaultCellFont;
4411 }
4412
4413 wxFont wxGrid::GetCellFont( int row, int col )
4414 {
4415 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4416
4417 wxFont font;
4418 if ( attr && attr->HasFont() )
4419 font = attr->GetFont();
4420 else
4421 font = GetDefaultCellFont();
4422
4423 delete attr;
4424
4425 return font;
4426 }
4427
4428 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
4429 {
4430 if ( horiz )
4431 *horiz = m_defaultCellHAlign;
4432 if ( vert )
4433 *vert = m_defaultCellVAlign;
4434 }
4435
4436 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
4437 {
4438 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4439
4440 if ( attr && attr->HasAlignment() )
4441 attr->GetAlignment(horiz, vert);
4442 else
4443 GetDefaultCellAlignment(horiz, vert);
4444
4445 delete attr;
4446 }
4447
4448 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
4449 {
4450 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
4451
4452 if ( resizeExistingRows )
4453 {
4454 int row;
4455 int bottom = 0;
4456 for ( row = 0; row < m_numRows; row++ )
4457 {
4458 m_rowHeights[row] = m_defaultRowHeight;
4459 bottom += m_defaultRowHeight;
4460 m_rowBottoms[row] = bottom;
4461 }
4462 CalcDimensions();
4463 }
4464 }
4465
4466 void wxGrid::SetRowSize( int row, int height )
4467 {
4468 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
4469
4470 int i;
4471
4472 int h = wxMax( 0, height );
4473 int diff = h - m_rowHeights[row];
4474
4475 m_rowHeights[row] = h;
4476 for ( i = row; i < m_numRows; i++ )
4477 {
4478 m_rowBottoms[i] += diff;
4479 }
4480 CalcDimensions();
4481
4482 // Note: we are ending the event *after* doing
4483 // default processing in this case
4484 //
4485 SendEvent( EVT_GRID_ROW_SIZE,
4486 row, -1 );
4487 }
4488
4489 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4490 {
4491 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4492
4493 if ( resizeExistingCols )
4494 {
4495 int col;
4496 int right = 0;
4497 for ( col = 0; col < m_numCols; col++ )
4498 {
4499 m_colWidths[col] = m_defaultColWidth;
4500 right += m_defaultColWidth;
4501 m_colRights[col] = right;
4502 }
4503 CalcDimensions();
4504 }
4505 }
4506
4507 void wxGrid::SetColSize( int col, int width )
4508 {
4509 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
4510
4511 int i;
4512
4513 int w = wxMax( 0, width );
4514 int diff = w - m_colWidths[col];
4515 m_colWidths[col] = w;
4516
4517 for ( i = col; i < m_numCols; i++ )
4518 {
4519 m_colRights[i] += diff;
4520 }
4521 CalcDimensions();
4522
4523 // Note: we are ending the event *after* doing
4524 // default processing in this case
4525 //
4526 SendEvent( EVT_GRID_COL_SIZE,
4527 -1, col );
4528 }
4529
4530 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
4531 {
4532 m_gridWin->SetBackgroundColour(col);
4533 }
4534
4535 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
4536 {
4537 m_gridWin->SetForegroundColour(col);
4538 }
4539
4540 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
4541 {
4542 m_defaultCellHAlign = horiz;
4543 m_defaultCellVAlign = vert;
4544 }
4545
4546 bool wxGrid::CanHaveAttributes()
4547 {
4548 if ( !m_table )
4549 {
4550 return FALSE;
4551 }
4552
4553 if ( !m_table->GetAttrProvider() )
4554 {
4555 // use the default attr provider by default
4556 // (another choice would be to just return FALSE thus forcing the user
4557 // to it himself)
4558 m_table->SetAttrProvider(new wxGridCellAttrProvider);
4559 }
4560
4561 return TRUE;
4562 }
4563
4564 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
4565 {
4566 if ( CanHaveAttributes() )
4567 {
4568 wxGridCellAttr *attr = new wxGridCellAttr;
4569 attr->SetBackgroundColour(colour);
4570
4571 m_table->SetAttr(attr, row, col);
4572 }
4573 }
4574
4575 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
4576 {
4577 if ( CanHaveAttributes() )
4578 {
4579 wxGridCellAttr *attr = new wxGridCellAttr;
4580 attr->SetTextColour(colour);
4581
4582 m_table->SetAttr(attr, row, col);
4583 }
4584 }
4585
4586 void wxGrid::SetDefaultCellFont( const wxFont& font )
4587 {
4588 m_defaultCellFont = font;
4589 }
4590
4591 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
4592 {
4593 if ( CanHaveAttributes() )
4594 {
4595 wxGridCellAttr *attr = new wxGridCellAttr;
4596 attr->SetFont(font);
4597
4598 m_table->SetAttr(attr, row, col);
4599 }
4600 }
4601
4602 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
4603 {
4604 if ( CanHaveAttributes() )
4605 {
4606 wxGridCellAttr *attr = new wxGridCellAttr;
4607 attr->SetAlignment(horiz, vert);
4608
4609 m_table->SetAttr(attr, row, col);
4610 }
4611 }
4612
4613
4614
4615 //
4616 // ------ cell value accessor functions
4617 //
4618
4619 void wxGrid::SetCellValue( int row, int col, const wxString& s )
4620 {
4621 if ( m_table )
4622 {
4623 m_table->SetValue( row, col, s.c_str() );
4624 if ( !GetBatchCount() )
4625 {
4626 wxClientDC dc( m_gridWin );
4627 PrepareDC( dc );
4628 DrawCell( dc, wxGridCellCoords(row, col) );
4629 }
4630
4631 #if 0 // TODO: edit in place
4632
4633 if ( m_currentCellCoords.GetRow() == row &&
4634 m_currentCellCoords.GetCol() == col )
4635 {
4636 SetEditControlValue( s );
4637 }
4638 #endif
4639
4640 }
4641 }
4642
4643
4644 //
4645 // ------ Block, row and col selection
4646 //
4647
4648 void wxGrid::SelectRow( int row, bool addToSelected )
4649 {
4650 wxRect r;
4651
4652 if ( IsSelection() && addToSelected )
4653 {
4654 wxRect rect[4];
4655 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4656 int i;
4657
4658 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4659 wxCoord oldTop = m_selectedTopLeft.GetRow();
4660 wxCoord oldRight = m_selectedBottomRight.GetCol();
4661 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4662
4663 if ( oldTop > row )
4664 {
4665 need_refresh[0] = TRUE;
4666 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
4667 wxGridCellCoords ( oldTop - 1,
4668 m_numCols - 1 ) );
4669 m_selectedTopLeft.SetRow( row );
4670 }
4671
4672 if ( oldLeft > 0 )
4673 {
4674 need_refresh[1] = TRUE;
4675 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
4676 wxGridCellCoords ( oldBottom,
4677 oldLeft - 1 ) );
4678
4679 m_selectedTopLeft.SetCol( 0 );
4680 }
4681
4682 if ( oldBottom < row )
4683 {
4684 need_refresh[2] = TRUE;
4685 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
4686 wxGridCellCoords ( row,
4687 m_numCols - 1 ) );
4688 m_selectedBottomRight.SetRow( row );
4689 }
4690
4691 if ( oldRight < m_numCols - 1 )
4692 {
4693 need_refresh[3] = TRUE;
4694 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
4695 oldRight + 1 ),
4696 wxGridCellCoords ( oldBottom,
4697 m_numCols - 1 ) );
4698 m_selectedBottomRight.SetCol( m_numCols - 1 );
4699 }
4700
4701 for (i = 0; i < 4; i++ )
4702 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4703 m_gridWin->Refresh( FALSE, &(rect[i]) );
4704 }
4705 else
4706 {
4707 r = SelectionToDeviceRect();
4708 ClearSelection();
4709 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4710
4711 m_selectedTopLeft.Set( row, 0 );
4712 m_selectedBottomRight.Set( row, m_numCols-1 );
4713 r = SelectionToDeviceRect();
4714 m_gridWin->Refresh( FALSE, &r );
4715 }
4716
4717 wxGridRangeSelectEvent gridEvt( GetId(),
4718 EVT_GRID_RANGE_SELECT,
4719 this,
4720 m_selectedTopLeft,
4721 m_selectedBottomRight );
4722
4723 GetEventHandler()->ProcessEvent(gridEvt);
4724 }
4725
4726
4727 void wxGrid::SelectCol( int col, bool addToSelected )
4728 {
4729 if ( IsSelection() && addToSelected )
4730 {
4731 wxRect rect[4];
4732 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4733 int i;
4734
4735 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4736 wxCoord oldTop = m_selectedTopLeft.GetRow();
4737 wxCoord oldRight = m_selectedBottomRight.GetCol();
4738 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4739
4740 if ( oldLeft > col )
4741 {
4742 need_refresh[0] = TRUE;
4743 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
4744 wxGridCellCoords ( m_numRows - 1,
4745 oldLeft - 1 ) );
4746 m_selectedTopLeft.SetCol( col );
4747 }
4748
4749 if ( oldTop > 0 )
4750 {
4751 need_refresh[1] = TRUE;
4752 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
4753 wxGridCellCoords ( oldTop - 1,
4754 oldRight ) );
4755 m_selectedTopLeft.SetRow( 0 );
4756 }
4757
4758 if ( oldRight < col )
4759 {
4760 need_refresh[2] = TRUE;
4761 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
4762 wxGridCellCoords ( m_numRows - 1,
4763 col ) );
4764 m_selectedBottomRight.SetCol( col );
4765 }
4766
4767 if ( oldBottom < m_numRows - 1 )
4768 {
4769 need_refresh[3] = TRUE;
4770 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
4771 oldLeft ),
4772 wxGridCellCoords ( m_numRows - 1,
4773 oldRight ) );
4774 m_selectedBottomRight.SetRow( m_numRows - 1 );
4775 }
4776
4777 for (i = 0; i < 4; i++ )
4778 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4779 m_gridWin->Refresh( FALSE, &(rect[i]) );
4780 }
4781 else
4782 {
4783 wxRect r;
4784
4785 r = SelectionToDeviceRect();
4786 ClearSelection();
4787 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4788
4789 m_selectedTopLeft.Set( 0, col );
4790 m_selectedBottomRight.Set( m_numRows-1, col );
4791 r = SelectionToDeviceRect();
4792 m_gridWin->Refresh( FALSE, &r );
4793 }
4794
4795 wxGridRangeSelectEvent gridEvt( GetId(),
4796 EVT_GRID_RANGE_SELECT,
4797 this,
4798 m_selectedTopLeft,
4799 m_selectedBottomRight );
4800
4801 GetEventHandler()->ProcessEvent(gridEvt);
4802 }
4803
4804
4805 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
4806 {
4807 int temp;
4808 wxGridCellCoords updateTopLeft, updateBottomRight;
4809
4810 if ( topRow > bottomRow )
4811 {
4812 temp = topRow;
4813 topRow = bottomRow;
4814 bottomRow = temp;
4815 }
4816
4817 if ( leftCol > rightCol )
4818 {
4819 temp = leftCol;
4820 leftCol = rightCol;
4821 rightCol = temp;
4822 }
4823
4824 updateTopLeft = wxGridCellCoords( topRow, leftCol );
4825 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
4826
4827 if ( m_selectedTopLeft != updateTopLeft ||
4828 m_selectedBottomRight != updateBottomRight )
4829 {
4830 // Compute two optimal update rectangles:
4831 // Either one rectangle is a real subset of the
4832 // other, or they are (almost) disjoint!
4833 wxRect rect[4];
4834 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4835 int i;
4836
4837 // Store intermediate values
4838 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4839 wxCoord oldTop = m_selectedTopLeft.GetRow();
4840 wxCoord oldRight = m_selectedBottomRight.GetCol();
4841 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4842
4843 // Determine the outer/inner coordinates.
4844 if (oldLeft > leftCol)
4845 {
4846 temp = oldLeft;
4847 oldLeft = leftCol;
4848 leftCol = temp;
4849 }
4850 if (oldTop > topRow )
4851 {
4852 temp = oldTop;
4853 oldTop = topRow;
4854 topRow = temp;
4855 }
4856 if (oldRight < rightCol )
4857 {
4858 temp = oldRight;
4859 oldRight = rightCol;
4860 rightCol = temp;
4861 }
4862 if (oldBottom < bottomRow)
4863 {
4864 temp = oldBottom;
4865 oldBottom = bottomRow;
4866 bottomRow = temp;
4867 }
4868
4869 // Now, either the stuff marked old is the outer
4870 // rectangle or we don't have a situation where one
4871 // is contained in the other.
4872
4873 if ( oldLeft < leftCol )
4874 {
4875 need_refresh[0] = TRUE;
4876 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4877 oldLeft ),
4878 wxGridCellCoords ( oldBottom,
4879 leftCol - 1 ) );
4880 }
4881
4882 if ( oldTop < topRow )
4883 {
4884 need_refresh[1] = TRUE;
4885 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4886 leftCol ),
4887 wxGridCellCoords ( topRow - 1,
4888 rightCol ) );
4889 }
4890
4891 if ( oldRight > rightCol )
4892 {
4893 need_refresh[2] = TRUE;
4894 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4895 rightCol + 1 ),
4896 wxGridCellCoords ( oldBottom,
4897 oldRight ) );
4898 }
4899
4900 if ( oldBottom > bottomRow )
4901 {
4902 need_refresh[3] = TRUE;
4903 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
4904 leftCol ),
4905 wxGridCellCoords ( oldBottom,
4906 rightCol ) );
4907 }
4908
4909
4910 // Change Selection
4911 m_selectedTopLeft = updateTopLeft;
4912 m_selectedBottomRight = updateBottomRight;
4913
4914 // various Refresh() calls
4915 for (i = 0; i < 4; i++ )
4916 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4917 m_gridWin->Refresh( FALSE, &(rect[i]) );
4918 }
4919
4920 // only generate an event if the block is not being selected by
4921 // dragging the mouse (in which case the event will be generated in
4922 // the mouse event handler)
4923 if ( !m_isDragging )
4924 {
4925 wxGridRangeSelectEvent gridEvt( GetId(),
4926 EVT_GRID_RANGE_SELECT,
4927 this,
4928 m_selectedTopLeft,
4929 m_selectedBottomRight );
4930
4931 GetEventHandler()->ProcessEvent(gridEvt);
4932 }
4933 }
4934
4935 void wxGrid::SelectAll()
4936 {
4937 m_selectedTopLeft.Set( 0, 0 );
4938 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
4939
4940 m_gridWin->Refresh();
4941 }
4942
4943
4944 void wxGrid::ClearSelection()
4945 {
4946 m_selectedTopLeft = wxGridNoCellCoords;
4947 m_selectedBottomRight = wxGridNoCellCoords;
4948 }
4949
4950
4951 // This function returns the rectangle that encloses the given block
4952 // in device coords clipped to the client size of the grid window.
4953 //
4954 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
4955 const wxGridCellCoords &bottomRight )
4956 {
4957 wxRect rect( wxGridNoCellRect );
4958 wxRect cellRect;
4959
4960 cellRect = CellToRect( topLeft );
4961 if ( cellRect != wxGridNoCellRect )
4962 {
4963 rect = cellRect;
4964 }
4965 else
4966 {
4967 rect = wxRect( 0, 0, 0, 0 );
4968 }
4969
4970 cellRect = CellToRect( bottomRight );
4971 if ( cellRect != wxGridNoCellRect )
4972 {
4973 rect += cellRect;
4974 }
4975 else
4976 {
4977 return wxGridNoCellRect;
4978 }
4979
4980 // convert to scrolled coords
4981 //
4982 int left, top, right, bottom;
4983 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4984 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
4985
4986 int cw, ch;
4987 m_gridWin->GetClientSize( &cw, &ch );
4988
4989 rect.SetLeft( wxMax(0, left) );
4990 rect.SetTop( wxMax(0, top) );
4991 rect.SetRight( wxMin(cw, right) );
4992 rect.SetBottom( wxMin(ch, bottom) );
4993
4994 return rect;
4995 }
4996
4997
4998
4999 //
5000 // ------ Grid event classes
5001 //
5002
5003 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5004
5005 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5006 int row, int col, int x, int y,
5007 bool control, bool shift, bool alt, bool meta )
5008 : wxNotifyEvent( type, id )
5009 {
5010 m_row = row;
5011 m_col = col;
5012 m_x = x;
5013 m_y = y;
5014 m_control = control;
5015 m_shift = shift;
5016 m_alt = alt;
5017 m_meta = meta;
5018
5019 SetEventObject(obj);
5020 }
5021
5022
5023 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5024
5025 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5026 int rowOrCol, int x, int y,
5027 bool control, bool shift, bool alt, bool meta )
5028 : wxNotifyEvent( type, id )
5029 {
5030 m_rowOrCol = rowOrCol;
5031 m_x = x;
5032 m_y = y;
5033 m_control = control;
5034 m_shift = shift;
5035 m_alt = alt;
5036 m_meta = meta;
5037
5038 SetEventObject(obj);
5039 }
5040
5041
5042 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5043
5044 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
5045 const wxGridCellCoords& topLeft,
5046 const wxGridCellCoords& bottomRight,
5047 bool control, bool shift, bool alt, bool meta )
5048 : wxNotifyEvent( type, id )
5049 {
5050 m_topLeft = topLeft;
5051 m_bottomRight = bottomRight;
5052 m_control = control;
5053 m_shift = shift;
5054 m_alt = alt;
5055 m_meta = meta;
5056
5057 SetEventObject(obj);
5058 }
5059
5060
5061 #endif // ifndef wxUSE_NEW_GRID
5062