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