]> git.saurik.com Git - wxWidgets.git/blob - src/generic/grid.cpp
82eef22b3b40ede78a487310c32eb56a0ba4ff68
[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 // This avoids a crash in SetScrollbars
1133 //
1134 if ( !m_displayed ) return;
1135
1136 int cw, ch;
1137 GetClientSize( &cw, &ch );
1138
1139 if ( m_numRows > 0 && m_numCols > 0 )
1140 {
1141 int right = m_colRights[ m_numCols-1 ] + 50;
1142 int bottom = m_rowBottoms[ m_numRows-1 ] + 50;
1143
1144 // TODO: restore the scroll position that we had before sizing
1145 //
1146 int x, y;
1147 GetViewStart( &x, &y );
1148 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
1149 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
1150 x, y );
1151 }
1152 }
1153
1154
1155 // this is called when the grid table sends a message to say that it
1156 // has been redimensioned
1157 //
1158 bool wxGrid::Redimension( wxGridTableMessage& msg )
1159 {
1160 int i;
1161
1162 switch ( msg.GetId() )
1163 {
1164 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1165 {
1166 size_t pos = msg.GetCommandInt();
1167 int numRows = msg.GetCommandInt2();
1168 for ( i = 0; i < numRows; i++ )
1169 {
1170 m_rowHeights.Insert( m_defaultRowHeight, pos );
1171 m_rowBottoms.Insert( 0, pos );
1172 }
1173 m_numRows += numRows;
1174
1175 int bottom = 0;
1176 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
1177
1178 for ( i = pos; i < m_numRows; i++ )
1179 {
1180 bottom += m_rowHeights[i];
1181 m_rowBottoms[i] = bottom;
1182 }
1183 CalcDimensions();
1184 }
1185 return TRUE;
1186
1187 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1188 {
1189 int numRows = msg.GetCommandInt();
1190 for ( i = 0; i < numRows; i++ )
1191 {
1192 m_rowHeights.Add( m_defaultRowHeight );
1193 m_rowBottoms.Add( 0 );
1194 }
1195
1196 int oldNumRows = m_numRows;
1197 m_numRows += numRows;
1198
1199 int bottom = 0;
1200 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
1201
1202 for ( i = oldNumRows; i < m_numRows; i++ )
1203 {
1204 bottom += m_rowHeights[i];
1205 m_rowBottoms[i] = bottom;
1206 }
1207 CalcDimensions();
1208 }
1209 return TRUE;
1210
1211 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
1212 {
1213 size_t pos = msg.GetCommandInt();
1214 int numRows = msg.GetCommandInt2();
1215 for ( i = 0; i < numRows; i++ )
1216 {
1217 m_rowHeights.Remove( pos );
1218 m_rowBottoms.Remove( pos );
1219 }
1220 m_numRows -= numRows;
1221
1222 if ( !m_numRows )
1223 {
1224 m_numCols = 0;
1225 m_colWidths.Clear();
1226 m_colRights.Clear();
1227 m_currentCellCoords = wxGridNoCellCoords;
1228 }
1229 else
1230 {
1231 if ( m_currentCellCoords.GetRow() >= m_numRows )
1232 m_currentCellCoords.Set( 0, 0 );
1233
1234 int h = 0;
1235 for ( i = 0; i < m_numRows; i++ )
1236 {
1237 h += m_rowHeights[i];
1238 m_rowBottoms[i] = h;
1239 }
1240 }
1241
1242 CalcDimensions();
1243 }
1244 return TRUE;
1245
1246 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
1247 {
1248 size_t pos = msg.GetCommandInt();
1249 int numCols = msg.GetCommandInt2();
1250 for ( i = 0; i < numCols; i++ )
1251 {
1252 m_colWidths.Insert( m_defaultColWidth, pos );
1253 m_colRights.Insert( 0, pos );
1254 }
1255 m_numCols += numCols;
1256
1257 int right = 0;
1258 if ( pos > 0 ) right = m_colRights[pos-1];
1259
1260 for ( i = pos; i < m_numCols; i++ )
1261 {
1262 right += m_colWidths[i];
1263 m_colRights[i] = right;
1264 }
1265 CalcDimensions();
1266 }
1267 return TRUE;
1268
1269 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
1270 {
1271 int numCols = msg.GetCommandInt();
1272 for ( i = 0; i < numCols; i++ )
1273 {
1274 m_colWidths.Add( m_defaultColWidth );
1275 m_colRights.Add( 0 );
1276 }
1277
1278 int oldNumCols = m_numCols;
1279 m_numCols += numCols;
1280
1281 int right = 0;
1282 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
1283
1284 for ( i = oldNumCols; i < m_numCols; i++ )
1285 {
1286 right += m_colWidths[i];
1287 m_colRights[i] = right;
1288 }
1289 CalcDimensions();
1290 }
1291 return TRUE;
1292
1293 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
1294 {
1295 size_t pos = msg.GetCommandInt();
1296 int numCols = msg.GetCommandInt2();
1297 for ( i = 0; i < numCols; i++ )
1298 {
1299 m_colWidths.Remove( pos );
1300 m_colRights.Remove( pos );
1301 }
1302 m_numCols -= numCols;
1303
1304 if ( !m_numCols )
1305 {
1306 #if 0 // leave the row alone here so that AppendCols will work subsequently
1307 m_numRows = 0;
1308 m_rowHeights.Clear();
1309 m_rowBottoms.Clear();
1310 #endif
1311 m_currentCellCoords = wxGridNoCellCoords;
1312 }
1313 else
1314 {
1315 if ( m_currentCellCoords.GetCol() >= m_numCols )
1316 m_currentCellCoords.Set( 0, 0 );
1317
1318 int w = 0;
1319 for ( i = 0; i < m_numCols; i++ )
1320 {
1321 w += m_colWidths[i];
1322 m_colRights[i] = w;
1323 }
1324 }
1325 CalcDimensions();
1326 }
1327 return TRUE;
1328 }
1329
1330 return FALSE;
1331 }
1332
1333
1334 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
1335 {
1336 wxRegionIterator iter( reg );
1337 wxRect r;
1338
1339 m_rowLabelsExposed.Empty();
1340
1341 int top, bottom;
1342 while ( iter )
1343 {
1344 r = iter.GetRect();
1345
1346 // TODO: remove this when we can...
1347 // There is a bug in wxMotif that gives garbage update
1348 // rectangles if you jump-scroll a long way by clicking the
1349 // scrollbar with middle button. This is a work-around
1350 //
1351 #if defined(__WXMOTIF__)
1352 int cw, ch;
1353 m_gridWin->GetClientSize( &cw, &ch );
1354 if ( r.GetTop() > ch ) r.SetTop( 0 );
1355 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1356 #endif
1357
1358 // logical bounds of update region
1359 //
1360 int dummy;
1361 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
1362 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
1363
1364 // find the row labels within these bounds
1365 //
1366 int row;
1367 int rowTop;
1368 for ( row = 0; row < m_numRows; row++ )
1369 {
1370 if ( m_rowBottoms[row] < top ) continue;
1371
1372 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1373 if ( rowTop > bottom ) break;
1374
1375 m_rowLabelsExposed.Add( row );
1376 }
1377
1378 iter++ ;
1379 }
1380 }
1381
1382
1383 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
1384 {
1385 wxRegionIterator iter( reg );
1386 wxRect r;
1387
1388 m_colLabelsExposed.Empty();
1389
1390 int left, right;
1391 while ( iter )
1392 {
1393 r = iter.GetRect();
1394
1395 // TODO: remove this when we can...
1396 // There is a bug in wxMotif that gives garbage update
1397 // rectangles if you jump-scroll a long way by clicking the
1398 // scrollbar with middle button. This is a work-around
1399 //
1400 #if defined(__WXMOTIF__)
1401 int cw, ch;
1402 m_gridWin->GetClientSize( &cw, &ch );
1403 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1404 r.SetRight( wxMin( r.GetRight(), cw ) );
1405 #endif
1406
1407 // logical bounds of update region
1408 //
1409 int dummy;
1410 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
1411 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
1412
1413 // find the cells within these bounds
1414 //
1415 int col;
1416 int colLeft;
1417 for ( col = 0; col < m_numCols; col++ )
1418 {
1419 if ( m_colRights[col] < left ) continue;
1420
1421 colLeft = m_colRights[col] - m_colWidths[col];
1422 if ( colLeft > right ) break;
1423
1424 m_colLabelsExposed.Add( col );
1425 }
1426
1427 iter++ ;
1428 }
1429 }
1430
1431
1432 void wxGrid::CalcCellsExposed( wxRegion& reg )
1433 {
1434 wxRegionIterator iter( reg );
1435 wxRect r;
1436
1437 m_cellsExposed.Empty();
1438 m_rowsExposed.Empty();
1439 m_colsExposed.Empty();
1440
1441 int left, top, right, bottom;
1442 while ( iter )
1443 {
1444 r = iter.GetRect();
1445
1446 // TODO: remove this when we can...
1447 // There is a bug in wxMotif that gives garbage update
1448 // rectangles if you jump-scroll a long way by clicking the
1449 // scrollbar with middle button. This is a work-around
1450 //
1451 #if defined(__WXMOTIF__)
1452 int cw, ch;
1453 m_gridWin->GetClientSize( &cw, &ch );
1454 if ( r.GetTop() > ch ) r.SetTop( 0 );
1455 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1456 r.SetRight( wxMin( r.GetRight(), cw ) );
1457 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1458 #endif
1459
1460 // logical bounds of update region
1461 //
1462 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
1463 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
1464
1465 // find the cells within these bounds
1466 //
1467 int row, col;
1468 int colLeft, rowTop;
1469 for ( row = 0; row < m_numRows; row++ )
1470 {
1471 if ( m_rowBottoms[row] < top ) continue;
1472
1473 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1474 if ( rowTop > bottom ) break;
1475
1476 m_rowsExposed.Add( row );
1477
1478 for ( col = 0; col < m_numCols; col++ )
1479 {
1480 if ( m_colRights[col] < left ) continue;
1481
1482 colLeft = m_colRights[col] - m_colWidths[col];
1483 if ( colLeft > right ) break;
1484
1485 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
1486 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
1487 }
1488 }
1489
1490 iter++ ;
1491 }
1492 }
1493
1494
1495 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
1496 {
1497 int x, y, row;
1498 wxPoint pos( event.GetPosition() );
1499 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1500
1501 if ( event.Dragging() )
1502 {
1503 m_isDragging = TRUE;
1504
1505 if ( event.LeftIsDown() )
1506 {
1507 switch( m_cursorMode )
1508 {
1509 case WXGRID_CURSOR_RESIZE_ROW:
1510 {
1511 int cw, ch, left, dummy;
1512 m_gridWin->GetClientSize( &cw, &ch );
1513 CalcUnscrolledPosition( 0, 0, &left, &dummy );
1514
1515 wxClientDC dc( m_gridWin );
1516 PrepareDC( dc );
1517 dc.SetLogicalFunction(wxINVERT);
1518 if ( m_dragLastPos >= 0 )
1519 {
1520 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1521 }
1522 dc.DrawLine( left, y, left+cw, y );
1523 m_dragLastPos = y;
1524 }
1525 break;
1526
1527 case WXGRID_CURSOR_SELECT_ROW:
1528 {
1529 if ( (row = YToRow( y )) >= 0 &&
1530 !IsInSelection( row, 0 ) )
1531 {
1532 SelectRow( row, TRUE );
1533 }
1534 }
1535 break;
1536 }
1537 }
1538 return;
1539 }
1540
1541 m_isDragging = FALSE;
1542
1543
1544 // ------------ Left button pressed
1545 //
1546 if ( event.LeftDown() )
1547 {
1548 // don't send a label click event for a hit on the
1549 // edge of the row label - this is probably the user
1550 // wanting to resize the row
1551 //
1552 if ( YToEdgeOfRow(y) < 0 )
1553 {
1554 row = YToRow(y);
1555 if ( row >= 0 &&
1556 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
1557 {
1558 SelectRow( row, event.ShiftDown() );
1559 m_cursorMode = WXGRID_CURSOR_SELECT_ROW;
1560 }
1561 }
1562 else
1563 {
1564 // starting to drag-resize a row
1565 //
1566 m_rowLabelWin->CaptureMouse();
1567 }
1568 }
1569
1570
1571 // ------------ Left double click
1572 //
1573 else if (event.LeftDClick() )
1574 {
1575 if ( YToEdgeOfRow(y) < 0 )
1576 {
1577 row = YToRow(y);
1578 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
1579 }
1580 }
1581
1582
1583 // ------------ Left button released
1584 //
1585 else if ( event.LeftUp() )
1586 {
1587 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
1588 {
1589 m_rowLabelWin->ReleaseMouse();
1590
1591 if ( m_dragLastPos >= 0 )
1592 {
1593 // erase the last line and resize the row
1594 //
1595 int cw, ch, left, dummy;
1596 m_gridWin->GetClientSize( &cw, &ch );
1597 CalcUnscrolledPosition( 0, 0, &left, &dummy );
1598
1599 wxClientDC dc( m_gridWin );
1600 PrepareDC( dc );
1601 dc.SetLogicalFunction( wxINVERT );
1602 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1603 HideCellEditControl();
1604
1605 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
1606 SetRowSize( m_dragRowOrCol, wxMax( y - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
1607 if ( !GetBatchCount() )
1608 {
1609 // Only needed to get the correct rect.y:
1610 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
1611 rect.x = 0;
1612 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
1613 rect.width = m_rowLabelWidth;
1614 rect.height = ch - rect.y;
1615 m_rowLabelWin->Refresh( TRUE, &rect );
1616 rect.width = cw;
1617 m_gridWin->Refresh( FALSE, &rect );
1618 }
1619
1620 ShowCellEditControl();
1621
1622 // Note: we are ending the event *after* doing
1623 // default processing in this case
1624 //
1625 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
1626 }
1627 }
1628
1629 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1630 m_dragLastPos = -1;
1631 }
1632
1633
1634 // ------------ Right button down
1635 //
1636 else if ( event.RightDown() )
1637 {
1638 row = YToRow(y);
1639 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
1640 {
1641 // no default action at the moment
1642 }
1643 }
1644
1645
1646 // ------------ Right double click
1647 //
1648 else if ( event.RightDClick() )
1649 {
1650 row = YToRow(y);
1651 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
1652 {
1653 // no default action at the moment
1654 }
1655 }
1656
1657
1658 // ------------ No buttons down and mouse moving
1659 //
1660 else if ( event.Moving() )
1661 {
1662 m_dragRowOrCol = YToEdgeOfRow( y );
1663 if ( m_dragRowOrCol >= 0 )
1664 {
1665 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1666 {
1667 m_cursorMode = WXGRID_CURSOR_RESIZE_ROW;
1668 m_rowLabelWin->SetCursor( m_rowResizeCursor );
1669 }
1670 }
1671 else
1672 {
1673 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1674 if ( m_rowLabelWin->GetCursor() == m_rowResizeCursor )
1675 m_rowLabelWin->SetCursor( *wxSTANDARD_CURSOR );
1676 }
1677 }
1678 }
1679
1680
1681 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
1682 {
1683 int x, y, col;
1684 wxPoint pos( event.GetPosition() );
1685 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1686
1687 if ( event.Dragging() )
1688 {
1689 m_isDragging = TRUE;
1690
1691 if ( event.LeftIsDown() )
1692 {
1693 switch( m_cursorMode )
1694 {
1695 case WXGRID_CURSOR_RESIZE_COL:
1696 {
1697 int cw, ch, dummy, top;
1698 m_gridWin->GetClientSize( &cw, &ch );
1699 CalcUnscrolledPosition( 0, 0, &dummy, &top );
1700
1701 wxClientDC dc( m_gridWin );
1702 PrepareDC( dc );
1703 dc.SetLogicalFunction(wxINVERT);
1704 if ( m_dragLastPos >= 0 )
1705 {
1706 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1707 }
1708 dc.DrawLine( x, top, x, top+ch );
1709 m_dragLastPos = x;
1710 }
1711 break;
1712
1713 case WXGRID_CURSOR_SELECT_COL:
1714 {
1715 if ( (col = XToCol( x )) >= 0 &&
1716 !IsInSelection( 0, col ) )
1717 {
1718 SelectCol( col, TRUE );
1719 }
1720 }
1721 break;
1722 }
1723 }
1724 return;
1725 }
1726
1727 m_isDragging = FALSE;
1728
1729
1730 // ------------ Left button pressed
1731 //
1732 if ( event.LeftDown() )
1733 {
1734 // don't send a label click event for a hit on the
1735 // edge of the col label - this is probably the user
1736 // wanting to resize the col
1737 //
1738 if ( XToEdgeOfCol(x) < 0 )
1739 {
1740 col = XToCol(x);
1741 if ( col >= 0 &&
1742 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
1743 {
1744 SelectCol( col, event.ShiftDown() );
1745 m_cursorMode = WXGRID_CURSOR_SELECT_COL;
1746 }
1747 }
1748 else
1749 {
1750 // starting to drag-resize a col
1751 //
1752 m_colLabelWin->CaptureMouse();
1753 }
1754 }
1755
1756
1757 // ------------ Left double click
1758 //
1759 if ( event.LeftDClick() )
1760 {
1761 if ( XToEdgeOfCol(x) < 0 )
1762 {
1763 col = XToCol(x);
1764 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
1765 }
1766 }
1767
1768
1769 // ------------ Left button released
1770 //
1771 else if ( event.LeftUp() )
1772 {
1773 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
1774 {
1775 m_colLabelWin->ReleaseMouse();
1776
1777 if ( m_dragLastPos >= 0 )
1778 {
1779 // erase the last line and resize the col
1780 //
1781 int cw, ch, dummy, top;
1782 m_gridWin->GetClientSize( &cw, &ch );
1783 CalcUnscrolledPosition( 0, 0, &dummy, &top );
1784
1785 wxClientDC dc( m_gridWin );
1786 PrepareDC( dc );
1787 dc.SetLogicalFunction( wxINVERT );
1788 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1789 HideCellEditControl();
1790
1791 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
1792 SetColSize( m_dragRowOrCol, wxMax( x - colLeft, WXGRID_MIN_COL_WIDTH ) );
1793
1794 if ( !GetBatchCount() )
1795 {
1796 // Only needed to get the correct rect.x:
1797 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
1798 rect.y = 0;
1799 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
1800 rect.width = cw - rect.x;
1801 rect.height = m_colLabelHeight;
1802 m_colLabelWin->Refresh( TRUE, &rect );
1803 rect.height = ch;
1804 m_gridWin->Refresh( FALSE, &rect );
1805 }
1806
1807 ShowCellEditControl();
1808
1809 // Note: we are ending the event *after* doing
1810 // default processing in this case
1811 //
1812 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
1813 }
1814 }
1815
1816 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1817 m_dragLastPos = -1;
1818 }
1819
1820
1821 // ------------ Right button down
1822 //
1823 else if ( event.RightDown() )
1824 {
1825 col = XToCol(x);
1826 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
1827 {
1828 // no default action at the moment
1829 }
1830 }
1831
1832
1833 // ------------ Right double click
1834 //
1835 else if ( event.RightDClick() )
1836 {
1837 col = XToCol(x);
1838 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
1839 {
1840 // no default action at the moment
1841 }
1842 }
1843
1844
1845 // ------------ No buttons down and mouse moving
1846 //
1847 else if ( event.Moving() )
1848 {
1849 m_dragRowOrCol = XToEdgeOfCol( x );
1850 if ( m_dragRowOrCol >= 0 )
1851 {
1852 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1853 {
1854 m_cursorMode = WXGRID_CURSOR_RESIZE_COL;
1855 m_colLabelWin->SetCursor( m_colResizeCursor );
1856 }
1857 }
1858 else
1859 {
1860 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1861 if ( m_colLabelWin->GetCursor() == m_colResizeCursor )
1862 m_colLabelWin->SetCursor( *wxSTANDARD_CURSOR );
1863 }
1864 }
1865 }
1866
1867
1868 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
1869 {
1870 if ( event.LeftDown() )
1871 {
1872 // indicate corner label by having both row and
1873 // col args == -1
1874 //
1875 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
1876 {
1877 SelectAll();
1878 }
1879 }
1880
1881 else if ( event.LeftDClick() )
1882 {
1883 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
1884 }
1885
1886 else if ( event.RightDown() )
1887 {
1888 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
1889 {
1890 // no default action at the moment
1891 }
1892 }
1893
1894 else if ( event.RightDClick() )
1895 {
1896 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
1897 {
1898 // no default action at the moment
1899 }
1900 }
1901 }
1902
1903
1904 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
1905 {
1906 int x, y;
1907 wxPoint pos( event.GetPosition() );
1908 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1909
1910 wxGridCellCoords coords;
1911 XYToCell( x, y, coords );
1912
1913 if ( event.Dragging() )
1914 {
1915 m_isDragging = TRUE;
1916 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1917 {
1918 // Hide the edit control, so it
1919 // won't interfer with drag-shrinking.
1920 if ( IsCellEditControlEnabled() )
1921 HideCellEditControl();
1922 if ( coords != wxGridNoCellCoords )
1923 {
1924 if ( !IsSelection() )
1925 {
1926 SelectBlock( coords, coords );
1927 }
1928 else
1929 {
1930 SelectBlock( m_currentCellCoords, coords );
1931 }
1932 }
1933 }
1934
1935 return;
1936 }
1937
1938 m_isDragging = FALSE;
1939
1940 if ( coords != wxGridNoCellCoords )
1941 {
1942 if ( event.LeftDown() )
1943 {
1944 if ( event.ShiftDown() )
1945 {
1946 SelectBlock( m_currentCellCoords, coords );
1947 }
1948 else
1949 {
1950 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
1951 coords.GetRow(),
1952 coords.GetCol(),
1953 event ) )
1954 {
1955 MakeCellVisible( coords );
1956 SetCurrentCell( coords );
1957 }
1958 }
1959 }
1960
1961
1962 // ------------ Left double click
1963 //
1964 else if ( event.LeftDClick() )
1965 {
1966 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
1967 coords.GetRow(),
1968 coords.GetCol(),
1969 event );
1970 }
1971
1972
1973 // ------------ Left button released
1974 //
1975 else if ( event.LeftUp() )
1976 {
1977 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1978 {
1979 if ( IsSelection() )
1980 {
1981 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
1982 }
1983 }
1984
1985 // Show the edit control, if it has
1986 // been hidden for drag-shrinking.
1987 if ( IsCellEditControlEnabled() )
1988 ShowCellEditControl();
1989
1990 m_dragLastPos = -1;
1991 }
1992
1993
1994 // ------------ Right button down
1995 //
1996 else if ( event.RightDown() )
1997 {
1998 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
1999 coords.GetRow(),
2000 coords.GetCol(),
2001 event ) )
2002 {
2003 // no default action at the moment
2004 }
2005 }
2006
2007
2008 // ------------ Right double click
2009 //
2010 else if ( event.RightDClick() )
2011 {
2012 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2013 coords.GetRow(),
2014 coords.GetCol(),
2015 event ) )
2016 {
2017 // no default action at the moment
2018 }
2019 }
2020
2021 // ------------ Moving and no button action
2022 //
2023 else if ( event.Moving() && !event.IsButton() )
2024 {
2025 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
2026 }
2027 }
2028 }
2029
2030
2031 //
2032 // ------ interaction with data model
2033 //
2034 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
2035 {
2036 switch ( msg.GetId() )
2037 {
2038 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
2039 return GetModelValues();
2040
2041 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
2042 return SetModelValues();
2043
2044 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
2045 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2046 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2047 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2048 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2049 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2050 return Redimension( msg );
2051
2052 default:
2053 return FALSE;
2054 }
2055 }
2056
2057
2058
2059 // The behaviour of this function depends on the grid table class
2060 // Clear() function. For the default wxGridStringTable class the
2061 // behavious is to replace all cell contents with wxEmptyString but
2062 // not to change the number of rows or cols.
2063 //
2064 void wxGrid::ClearGrid()
2065 {
2066 if ( m_table )
2067 {
2068 m_table->Clear();
2069 SetEditControlValue();
2070 if ( !GetBatchCount() ) m_gridWin->Refresh();
2071 }
2072 }
2073
2074
2075 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2076 {
2077 // TODO: something with updateLabels flag
2078
2079 if ( !m_created )
2080 {
2081 wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2082 return FALSE;
2083 }
2084
2085 if ( m_table )
2086 {
2087 bool ok = m_table->InsertRows( pos, numRows );
2088
2089 // the table will have sent the results of the insert row
2090 // operation to this view object as a grid table message
2091 //
2092 if ( ok )
2093 {
2094 if ( m_numCols == 0 )
2095 {
2096 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2097 //
2098 // TODO: perhaps instead of appending the default number of cols
2099 // we should remember what the last non-zero number of cols was ?
2100 //
2101 }
2102
2103 if ( m_currentCellCoords == wxGridNoCellCoords )
2104 {
2105 // if we have just inserted cols into an empty grid the current
2106 // cell will be undefined...
2107 //
2108 SetCurrentCell( 0, 0 );
2109 }
2110
2111 ClearSelection();
2112 if ( !GetBatchCount() ) Refresh();
2113 }
2114
2115 SetEditControlValue();
2116 return ok;
2117 }
2118 else
2119 {
2120 return FALSE;
2121 }
2122 }
2123
2124
2125 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
2126 {
2127 // TODO: something with updateLabels flag
2128
2129 if ( !m_created )
2130 {
2131 wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2132 return FALSE;
2133 }
2134
2135 if ( m_table && m_table->AppendRows( numRows ) )
2136 {
2137 if ( m_currentCellCoords == wxGridNoCellCoords )
2138 {
2139 // if we have just inserted cols into an empty grid the current
2140 // cell will be undefined...
2141 //
2142 SetCurrentCell( 0, 0 );
2143 }
2144
2145 // the table will have sent the results of the append row
2146 // operation to this view object as a grid table message
2147 //
2148 ClearSelection();
2149 if ( !GetBatchCount() ) Refresh();
2150 return TRUE;
2151 }
2152 else
2153 {
2154 return FALSE;
2155 }
2156 }
2157
2158
2159 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2160 {
2161 // TODO: something with updateLabels flag
2162
2163 if ( !m_created )
2164 {
2165 wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2166 return FALSE;
2167 }
2168
2169 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2170 {
2171 // the table will have sent the results of the delete row
2172 // operation to this view object as a grid table message
2173 //
2174 if ( m_numRows > 0 )
2175 SetEditControlValue();
2176 else
2177 HideCellEditControl();
2178
2179 ClearSelection();
2180 if ( !GetBatchCount() ) Refresh();
2181 return TRUE;
2182 }
2183 else
2184 {
2185 return FALSE;
2186 }
2187 }
2188
2189
2190 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2191 {
2192 // TODO: something with updateLabels flag
2193
2194 if ( !m_created )
2195 {
2196 wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2197 return FALSE;
2198 }
2199
2200 if ( m_table )
2201 {
2202 HideCellEditControl();
2203 bool ok = m_table->InsertCols( pos, numCols );
2204
2205 // the table will have sent the results of the insert col
2206 // operation to this view object as a grid table message
2207 //
2208 if ( ok )
2209 {
2210 if ( m_currentCellCoords == wxGridNoCellCoords )
2211 {
2212 // if we have just inserted cols into an empty grid the current
2213 // cell will be undefined...
2214 //
2215 SetCurrentCell( 0, 0 );
2216 }
2217
2218 ClearSelection();
2219 if ( !GetBatchCount() ) Refresh();
2220 }
2221
2222 SetEditControlValue();
2223 return ok;
2224 }
2225 else
2226 {
2227 return FALSE;
2228 }
2229 }
2230
2231
2232 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
2233 {
2234 // TODO: something with updateLabels flag
2235
2236 if ( !m_created )
2237 {
2238 wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2239 return FALSE;
2240 }
2241
2242 if ( m_table && m_table->AppendCols( numCols ) )
2243 {
2244 // the table will have sent the results of the append col
2245 // operation to this view object as a grid table message
2246 //
2247 if ( m_currentCellCoords == wxGridNoCellCoords )
2248 {
2249 // if we have just inserted cols into an empty grid the current
2250 // cell will be undefined...
2251 //
2252 SetCurrentCell( 0, 0 );
2253 }
2254
2255 ClearSelection();
2256 if ( !GetBatchCount() ) Refresh();
2257 return TRUE;
2258 }
2259 else
2260 {
2261 return FALSE;
2262 }
2263 }
2264
2265
2266 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2267 {
2268 // TODO: something with updateLabels flag
2269
2270 if ( !m_created )
2271 {
2272 wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2273 return FALSE;
2274 }
2275
2276 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2277 {
2278 // the table will have sent the results of the delete col
2279 // operation to this view object as a grid table message
2280 //
2281 if ( m_numCols > 0 )
2282 SetEditControlValue();
2283 else
2284 HideCellEditControl();
2285
2286 ClearSelection();
2287 if ( !GetBatchCount() ) Refresh();
2288 return TRUE;
2289 }
2290 else
2291 {
2292 return FALSE;
2293 }
2294 }
2295
2296
2297
2298 //
2299 // ----- event handlers
2300 //
2301
2302 // Generate a grid event based on a mouse event and
2303 // return the result of ProcessEvent()
2304 //
2305 bool wxGrid::SendEvent( const wxEventType type,
2306 int row, int col,
2307 wxMouseEvent& mouseEv )
2308 {
2309 if ( type == EVT_GRID_ROW_SIZE ||
2310 type == EVT_GRID_COL_SIZE )
2311 {
2312 int rowOrCol = (row == -1 ? col : row);
2313
2314 wxGridSizeEvent gridEvt( GetId(),
2315 type,
2316 this,
2317 rowOrCol,
2318 mouseEv.GetX(), mouseEv.GetY(),
2319 mouseEv.ControlDown(),
2320 mouseEv.ShiftDown(),
2321 mouseEv.AltDown(),
2322 mouseEv.MetaDown() );
2323
2324 return GetEventHandler()->ProcessEvent(gridEvt);
2325 }
2326 else if ( type == EVT_GRID_RANGE_SELECT )
2327 {
2328 wxGridRangeSelectEvent gridEvt( GetId(),
2329 type,
2330 this,
2331 m_selectedTopLeft,
2332 m_selectedBottomRight,
2333 mouseEv.ControlDown(),
2334 mouseEv.ShiftDown(),
2335 mouseEv.AltDown(),
2336 mouseEv.MetaDown() );
2337
2338 return GetEventHandler()->ProcessEvent(gridEvt);
2339 }
2340 else
2341 {
2342 wxGridEvent gridEvt( GetId(),
2343 type,
2344 this,
2345 row, col,
2346 mouseEv.GetX(), mouseEv.GetY(),
2347 mouseEv.ControlDown(),
2348 mouseEv.ShiftDown(),
2349 mouseEv.AltDown(),
2350 mouseEv.MetaDown() );
2351
2352 return GetEventHandler()->ProcessEvent(gridEvt);
2353 }
2354 }
2355
2356
2357 // Generate a grid event of specified type and return the result
2358 // of ProcessEvent().
2359 //
2360 bool wxGrid::SendEvent( const wxEventType type,
2361 int row, int col )
2362 {
2363 if ( type == EVT_GRID_ROW_SIZE ||
2364 type == EVT_GRID_COL_SIZE )
2365 {
2366 int rowOrCol = (row == -1 ? col : row);
2367
2368 wxGridSizeEvent gridEvt( GetId(),
2369 type,
2370 this,
2371 rowOrCol );
2372
2373 return GetEventHandler()->ProcessEvent(gridEvt);
2374 }
2375 else
2376 {
2377 wxGridEvent gridEvt( GetId(),
2378 type,
2379 this,
2380 row, col );
2381
2382 return GetEventHandler()->ProcessEvent(gridEvt);
2383 }
2384 }
2385
2386
2387 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
2388 {
2389 wxPaintDC dc( this );
2390
2391 if ( m_currentCellCoords == wxGridNoCellCoords &&
2392 m_numRows && m_numCols )
2393 {
2394 m_currentCellCoords.Set(0, 0);
2395 SetEditControlValue();
2396 ShowCellEditControl();
2397 }
2398
2399 m_displayed = TRUE;
2400 }
2401
2402
2403 // This is just here to make sure that CalcDimensions gets called when
2404 // the grid view is resized... then the size event is skipped to allow
2405 // the box sizers to handle everything
2406 //
2407 void wxGrid::OnSize( wxSizeEvent& event )
2408 {
2409 CalcDimensions();
2410 event.Skip();
2411 }
2412
2413
2414 void wxGrid::OnKeyDown( wxKeyEvent& event )
2415 {
2416 if ( m_inOnKeyDown )
2417 {
2418 // shouldn't be here - we are going round in circles...
2419 //
2420 wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
2421 }
2422
2423 m_inOnKeyDown = TRUE;
2424
2425 // propagate the event up and see if it gets processed
2426 //
2427 wxWindow *parent = GetParent();
2428 wxKeyEvent keyEvt( event );
2429 keyEvt.SetEventObject( parent );
2430
2431 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
2432 {
2433 // try local handlers
2434 //
2435 switch ( event.KeyCode() )
2436 {
2437 case WXK_UP:
2438 if ( event.ControlDown() )
2439 {
2440 MoveCursorUpBlock();
2441 }
2442 else
2443 {
2444 MoveCursorUp();
2445 }
2446 break;
2447
2448 case WXK_DOWN:
2449 if ( event.ControlDown() )
2450 {
2451 MoveCursorDownBlock();
2452 }
2453 else
2454 {
2455 MoveCursorDown();
2456 }
2457 break;
2458
2459 case WXK_LEFT:
2460 if ( event.ControlDown() )
2461 {
2462 MoveCursorLeftBlock();
2463 }
2464 else
2465 {
2466 MoveCursorLeft();
2467 }
2468 break;
2469
2470 case WXK_RIGHT:
2471 if ( event.ControlDown() )
2472 {
2473 MoveCursorRightBlock();
2474 }
2475 else
2476 {
2477 MoveCursorRight();
2478 }
2479 break;
2480
2481 case WXK_SPACE:
2482 if ( !IsEditable() )
2483 {
2484 MoveCursorRight();
2485 }
2486 else
2487 {
2488 event.Skip();
2489 }
2490 break;
2491
2492 case WXK_RETURN:
2493 if ( event.ControlDown() )
2494 {
2495 event.Skip(); // to let the edit control have the return
2496 }
2497 else
2498 {
2499 MoveCursorDown();
2500 }
2501 break;
2502
2503 case WXK_HOME:
2504 if ( event.ControlDown() )
2505 {
2506 MakeCellVisible( 0, 0 );
2507 SetCurrentCell( 0, 0 );
2508 }
2509 else
2510 {
2511 event.Skip();
2512 }
2513 break;
2514
2515 case WXK_END:
2516 if ( event.ControlDown() )
2517 {
2518 MakeCellVisible( m_numRows-1, m_numCols-1 );
2519 SetCurrentCell( m_numRows-1, m_numCols-1 );
2520 }
2521 else
2522 {
2523 event.Skip();
2524 }
2525 break;
2526
2527 case WXK_PRIOR:
2528 MovePageUp();
2529 break;
2530
2531 case WXK_NEXT:
2532 MovePageDown();
2533 break;
2534
2535 default:
2536 // now try the cell edit control
2537 //
2538 if ( IsCellEditControlEnabled() )
2539 {
2540 event.SetEventObject( m_cellEditCtrl );
2541 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2542 }
2543 break;
2544 }
2545 }
2546
2547 m_inOnKeyDown = FALSE;
2548 }
2549
2550
2551 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
2552 {
2553 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
2554 {
2555 // the event has been intercepted - do nothing
2556 return;
2557 }
2558
2559 if ( m_displayed &&
2560 m_currentCellCoords != wxGridNoCellCoords )
2561 {
2562 HideCellEditControl();
2563 SaveEditControlValue();
2564 }
2565
2566 m_currentCellCoords = coords;
2567
2568 SetEditControlValue();
2569
2570 if ( m_displayed )
2571 {
2572 ShowCellEditControl();
2573
2574 if ( IsSelection() )
2575 {
2576 wxRect r( SelectionToDeviceRect() );
2577 ClearSelection();
2578 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
2579 }
2580 }
2581 }
2582
2583
2584 //
2585 // ------ functions to get/send data (see also public functions)
2586 //
2587
2588 bool wxGrid::GetModelValues()
2589 {
2590 if ( m_table )
2591 {
2592 // all we need to do is repaint the grid
2593 //
2594 m_gridWin->Refresh();
2595 return TRUE;
2596 }
2597
2598 return FALSE;
2599 }
2600
2601
2602 bool wxGrid::SetModelValues()
2603 {
2604 int row, col;
2605
2606 if ( m_table )
2607 {
2608 for ( row = 0; row < m_numRows; row++ )
2609 {
2610 for ( col = 0; col < m_numCols; col++ )
2611 {
2612 m_table->SetValue( row, col, GetCellValue(row, col) );
2613 }
2614 }
2615
2616 return TRUE;
2617 }
2618
2619 return FALSE;
2620 }
2621
2622
2623
2624 // Note - this function only draws cells that are in the list of
2625 // exposed cells (usually set from the update region by
2626 // CalcExposedCells)
2627 //
2628 void wxGrid::DrawGridCellArea( wxDC& dc )
2629 {
2630 if ( !m_numRows || !m_numCols ) return;
2631
2632 size_t i;
2633 size_t numCells = m_cellsExposed.GetCount();
2634
2635 for ( i = 0; i < numCells; i++ )
2636 {
2637 DrawCell( dc, m_cellsExposed[i] );
2638 }
2639 }
2640
2641
2642 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
2643 {
2644 if ( m_colWidths[coords.GetCol()] <=0 ||
2645 m_rowHeights[coords.GetRow()] <= 0 ) return;
2646
2647 #if !WXGRID_DRAW_LINES
2648 if ( m_gridLinesEnabled )
2649 DrawCellBorder( dc, coords );
2650 #endif
2651
2652 DrawCellBackground( dc, coords );
2653
2654 // TODO: separate functions here for different kinds of cells ?
2655 // e.g. text, image
2656 //
2657 DrawCellValue( dc, coords );
2658 }
2659
2660
2661 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
2662 {
2663 if ( m_colWidths[coords.GetCol()] <=0 ||
2664 m_rowHeights[coords.GetRow()] <= 0 ) return;
2665
2666 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
2667 int row = coords.GetRow();
2668 int col = coords.GetCol();
2669
2670 // right hand border
2671 //
2672 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
2673 m_colRights[col], m_rowBottoms[row] );
2674
2675 // bottom border
2676 //
2677 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
2678 m_colRights[col], m_rowBottoms[row] );
2679 }
2680
2681
2682 void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
2683 {
2684 if ( m_colWidths[coords.GetCol()] <=0 ||
2685 m_rowHeights[coords.GetRow()] <= 0 ) return;
2686
2687 int row = coords.GetRow();
2688 int col = coords.GetCol();
2689
2690 dc.SetBackgroundMode( wxSOLID );
2691
2692 if ( IsInSelection( coords ) )
2693 {
2694 // TODO: improve this
2695 //
2696 dc.SetBrush( *wxBLACK_BRUSH );
2697 }
2698 else
2699 {
2700 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
2701 }
2702
2703 dc.SetPen( *wxTRANSPARENT_PEN );
2704
2705 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
2706 m_rowBottoms[row] - m_rowHeights[row] + 1,
2707 m_colWidths[col]-1,
2708 m_rowHeights[row]-1 );
2709 }
2710
2711
2712 void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
2713 {
2714 if ( m_colWidths[coords.GetCol()] <=0 ||
2715 m_rowHeights[coords.GetRow()] <= 0 ) return;
2716
2717 int row = coords.GetRow();
2718 int col = coords.GetCol();
2719
2720 dc.SetBackgroundMode( wxTRANSPARENT );
2721
2722 if ( IsInSelection( row, col ) )
2723 {
2724 // TODO: improve this
2725 //
2726 dc.SetTextBackground( wxColour(0, 0, 0) );
2727 dc.SetTextForeground( wxColour(255, 255, 255) );
2728 }
2729 else
2730 {
2731 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
2732 dc.SetTextForeground( GetCellTextColour(row, col) );
2733 }
2734 dc.SetFont( GetCellFont(row, col) );
2735
2736 int hAlign, vAlign;
2737 GetCellAlignment( row, col, &hAlign, &vAlign );
2738
2739 wxRect rect;
2740 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2741 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2742 rect.SetWidth( m_colWidths[col] - 4 );
2743 rect.SetHeight( m_rowHeights[row] - 4 );
2744
2745 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
2746 }
2747
2748
2749
2750 // TODO: remove this ???
2751 // This is used to redraw all grid lines e.g. when the grid line colour
2752 // has been changed
2753 //
2754 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
2755 {
2756 if ( !m_gridLinesEnabled ||
2757 !m_numRows ||
2758 !m_numCols ) return;
2759
2760 int top, bottom, left, right;
2761
2762 if (reg.IsEmpty()){
2763 int cw, ch;
2764 m_gridWin->GetClientSize(&cw, &ch);
2765
2766 // virtual coords of visible area
2767 //
2768 CalcUnscrolledPosition( 0, 0, &left, &top );
2769 CalcUnscrolledPosition( cw, ch, &right, &bottom );
2770 }
2771 else{
2772 wxCoord x, y, w, h;
2773 reg.GetBox(x, y, w, h);
2774 CalcUnscrolledPosition( x, y, &left, &top );
2775 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
2776 }
2777
2778 // avoid drawing grid lines past the last row and col
2779 //
2780 right = wxMin( right, m_colRights[m_numCols-1] );
2781 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
2782
2783 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
2784
2785 // horizontal grid lines
2786 //
2787 int i;
2788 for ( i = 0; i < m_numRows; i++ )
2789 {
2790 if ( m_rowBottoms[i] > bottom )
2791 {
2792 break;
2793 }
2794 else if ( m_rowBottoms[i] >= top )
2795 {
2796 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
2797 }
2798 }
2799
2800
2801 // vertical grid lines
2802 //
2803 for ( i = 0; i < m_numCols; i++ )
2804 {
2805 if ( m_colRights[i] > right )
2806 {
2807 break;
2808 }
2809 else if ( m_colRights[i] >= left )
2810 {
2811 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
2812 }
2813 }
2814 }
2815
2816
2817 void wxGrid::DrawRowLabels( wxDC& dc )
2818 {
2819 if ( !m_numRows || !m_numCols ) return;
2820
2821 size_t i;
2822 size_t numLabels = m_rowLabelsExposed.GetCount();
2823
2824 for ( i = 0; i < numLabels; i++ )
2825 {
2826 DrawRowLabel( dc, m_rowLabelsExposed[i] );
2827 }
2828 }
2829
2830
2831 void wxGrid::DrawRowLabel( wxDC& dc, int row )
2832 {
2833 if ( m_rowHeights[row] <= 0 ) return;
2834
2835 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
2836
2837 dc.SetPen( *wxBLACK_PEN );
2838 dc.DrawLine( m_rowLabelWidth-1, rowTop,
2839 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
2840
2841 dc.DrawLine( 0, m_rowBottoms[row]-1,
2842 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
2843
2844 dc.SetPen( *wxWHITE_PEN );
2845 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
2846 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
2847
2848 dc.SetBackgroundMode( wxTRANSPARENT );
2849 dc.SetTextForeground( GetLabelTextColour() );
2850 dc.SetFont( GetLabelFont() );
2851
2852 int hAlign, vAlign;
2853 GetRowLabelAlignment( &hAlign, &vAlign );
2854
2855 wxRect rect;
2856 rect.SetX( 2 );
2857 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
2858 rect.SetWidth( m_rowLabelWidth - 4 );
2859 rect.SetHeight( m_rowHeights[row] - 4 );
2860 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
2861 }
2862
2863
2864 void wxGrid::DrawColLabels( wxDC& dc )
2865 {
2866 if ( !m_numRows || !m_numCols ) return;
2867
2868 size_t i;
2869 size_t numLabels = m_colLabelsExposed.GetCount();
2870
2871 for ( i = 0; i < numLabels; i++ )
2872 {
2873 DrawColLabel( dc, m_colLabelsExposed[i] );
2874 }
2875 }
2876
2877
2878 void wxGrid::DrawColLabel( wxDC& dc, int col )
2879 {
2880 if ( m_colWidths[col] <= 0 ) return;
2881
2882 int colLeft = m_colRights[col] - m_colWidths[col];
2883
2884 dc.SetPen( *wxBLACK_PEN );
2885 dc.DrawLine( m_colRights[col]-1, 0,
2886 m_colRights[col]-1, m_colLabelHeight-1 );
2887
2888 dc.DrawLine( colLeft, m_colLabelHeight-1,
2889 m_colRights[col]-1, m_colLabelHeight-1 );
2890
2891 dc.SetPen( *wxWHITE_PEN );
2892 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
2893 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
2894
2895 dc.SetBackgroundMode( wxTRANSPARENT );
2896 dc.SetTextForeground( GetLabelTextColour() );
2897 dc.SetFont( GetLabelFont() );
2898
2899 dc.SetBackgroundMode( wxTRANSPARENT );
2900 dc.SetTextForeground( GetLabelTextColour() );
2901 dc.SetFont( GetLabelFont() );
2902
2903 int hAlign, vAlign;
2904 GetColLabelAlignment( &hAlign, &vAlign );
2905
2906 wxRect rect;
2907 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
2908 rect.SetY( 2 );
2909 rect.SetWidth( m_colWidths[col] - 4 );
2910 rect.SetHeight( m_colLabelHeight - 4 );
2911 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
2912 }
2913
2914
2915 void wxGrid::DrawTextRectangle( wxDC& dc,
2916 const wxString& value,
2917 const wxRect& rect,
2918 int horizAlign,
2919 int vertAlign )
2920 {
2921 long textWidth, textHeight;
2922 long lineWidth, lineHeight;
2923 wxArrayString lines;
2924
2925 dc.SetClippingRegion( rect );
2926 StringToLines( value, lines );
2927 if ( lines.GetCount() )
2928 {
2929 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
2930 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
2931
2932 float x, y;
2933 switch ( horizAlign )
2934 {
2935 case wxRIGHT:
2936 x = rect.x + (rect.width - textWidth - 1);
2937 break;
2938
2939 case wxCENTRE:
2940 x = rect.x + ((rect.width - textWidth)/2);
2941 break;
2942
2943 case wxLEFT:
2944 default:
2945 x = rect.x + 1;
2946 break;
2947 }
2948
2949 switch ( vertAlign )
2950 {
2951 case wxBOTTOM:
2952 y = rect.y + (rect.height - textHeight - 1);
2953 break;
2954
2955 case wxCENTRE:
2956 y = rect.y + ((rect.height - textHeight)/2);
2957 break;
2958
2959 case wxTOP:
2960 default:
2961 y = rect.y + 1;
2962 break;
2963 }
2964
2965 for ( size_t i = 0; i < lines.GetCount(); i++ )
2966 {
2967 dc.DrawText( lines[i], (long)x, (long)y );
2968 y += lineHeight;
2969 }
2970 }
2971
2972 dc.DestroyClippingRegion();
2973 }
2974
2975
2976 // Split multi line text up into an array of strings. Any existing
2977 // contents of the string array are preserved.
2978 //
2979 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
2980 {
2981 // TODO: this won't work for WXMAC ? (lines end with '\r')
2982 // => use wxTextFile functions then (VZ)
2983 int startPos = 0;
2984 int pos;
2985 while ( startPos < (int)value.Length() )
2986 {
2987 pos = value.Mid(startPos).Find( '\n' );
2988 if ( pos < 0 )
2989 {
2990 break;
2991 }
2992 else if ( pos == 0 )
2993 {
2994 lines.Add( wxEmptyString );
2995 }
2996 else
2997 {
2998 if ( value[startPos+pos-1] == '\r' )
2999 {
3000 lines.Add( value.Mid(startPos, pos-1) );
3001 }
3002 else
3003 {
3004 lines.Add( value.Mid(startPos, pos) );
3005 }
3006 }
3007 startPos += pos+1;
3008 }
3009 if ( startPos < (int)value.Length() )
3010 {
3011 lines.Add( value.Mid( startPos ) );
3012 }
3013 }
3014
3015
3016 void wxGrid::GetTextBoxSize( wxDC& dc,
3017 wxArrayString& lines,
3018 long *width, long *height )
3019 {
3020 long w = 0;
3021 long h = 0;
3022 long lineW, lineH;
3023
3024 size_t i;
3025 for ( i = 0; i < lines.GetCount(); i++ )
3026 {
3027 dc.GetTextExtent( lines[i], &lineW, &lineH );
3028 w = wxMax( w, lineW );
3029 h += lineH;
3030 }
3031
3032 *width = w;
3033 *height = h;
3034 }
3035
3036
3037 //
3038 // ------ Edit control functions
3039 //
3040
3041
3042 void wxGrid::EnableEditing( bool edit )
3043 {
3044 // TODO: improve this ?
3045 //
3046 if ( edit != m_editable )
3047 {
3048 m_editable = edit;
3049
3050 // TODO: extend this for other edit control types
3051 //
3052 if ( m_editCtrlType == wxGRID_TEXTCTRL )
3053 {
3054 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
3055 }
3056 }
3057 }
3058
3059
3060 #if 0 // disabled for the moment - the cell control is always active
3061 void wxGrid::EnableCellEditControl( bool enable )
3062 {
3063 if ( m_cellEditCtrl &&
3064 enable != m_cellEditCtrlEnabled )
3065 {
3066 m_cellEditCtrlEnabled = enable;
3067
3068 if ( m_cellEditCtrlEnabled )
3069 {
3070 SetEditControlValue();
3071 ShowCellEditControl();
3072 }
3073 else
3074 {
3075 HideCellEditControl();
3076 SaveEditControlValue();
3077 }
3078 }
3079 }
3080 #endif
3081
3082
3083 void wxGrid::ShowCellEditControl()
3084 {
3085 wxRect rect;
3086
3087 if ( IsCellEditControlEnabled() )
3088 {
3089 if ( !IsVisible( m_currentCellCoords ) )
3090 {
3091 return;
3092 }
3093 else
3094 {
3095 rect = CellToRect( m_currentCellCoords );
3096
3097 // convert to scrolled coords
3098 //
3099 int left, top, right, bottom;
3100 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
3101 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
3102
3103 int cw, ch;
3104 m_gridWin->GetClientSize( &cw, &ch );
3105
3106 // Make the edit control large enough to allow for internal margins
3107 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3108 //
3109 int extra;
3110 #if defined(__WXMOTIF__)
3111 if ( m_currentCellCoords.GetRow() == 0 ||
3112 m_currentCellCoords.GetCol() == 0 )
3113 {
3114 extra = 2;
3115 }
3116 else
3117 {
3118 extra = 4;
3119 }
3120 #else
3121 if ( m_currentCellCoords.GetRow() == 0 ||
3122 m_currentCellCoords.GetCol() == 0 )
3123 {
3124 extra = 1;
3125 }
3126 else
3127 {
3128 extra = 2;
3129 }
3130 #endif
3131
3132 #if defined(__WXGTK__)
3133 int top_diff = 0;
3134 int left_diff = 0;
3135 if (left != 0) left_diff++;
3136 if (top != 0) top_diff++;
3137 rect.SetLeft( left + left_diff );
3138 rect.SetTop( top + top_diff );
3139 rect.SetRight( rect.GetRight() - left_diff );
3140 rect.SetBottom( rect.GetBottom() - top_diff );
3141 #else
3142 rect.SetLeft( wxMax(0, left - extra) );
3143 rect.SetTop( wxMax(0, top - extra) );
3144 rect.SetRight( rect.GetRight() + 2*extra );
3145 rect.SetBottom( rect.GetBottom() + 2*extra );
3146 #endif
3147
3148 m_cellEditCtrl->SetSize( rect );
3149 m_cellEditCtrl->Show( TRUE );
3150
3151 switch ( m_editCtrlType )
3152 {
3153 case wxGRID_TEXTCTRL:
3154 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3155 break;
3156
3157 case wxGRID_CHECKBOX:
3158 // TODO: anything ???
3159 //
3160 break;
3161
3162 case wxGRID_CHOICE:
3163 // TODO: anything ???
3164 //
3165 break;
3166
3167 case wxGRID_COMBOBOX:
3168 // TODO: anything ???
3169 //
3170 break;
3171 }
3172
3173 m_cellEditCtrl->SetFocus();
3174 }
3175 }
3176 }
3177
3178
3179 void wxGrid::HideCellEditControl()
3180 {
3181 if ( IsCellEditControlEnabled() )
3182 {
3183 m_cellEditCtrl->Show( FALSE );
3184 }
3185 }
3186
3187
3188 void wxGrid::SetEditControlValue( const wxString& value )
3189 {
3190 if ( m_table )
3191 {
3192 wxString s;
3193 if ( !value )
3194 s = GetCellValue(m_currentCellCoords);
3195 else
3196 s = value;
3197
3198 if ( IsCellEditControlEnabled() )
3199 {
3200 switch ( m_editCtrlType )
3201 {
3202 case wxGRID_TEXTCTRL:
3203 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3204 break;
3205
3206 case wxGRID_CHECKBOX:
3207 // TODO: implement this
3208 //
3209 break;
3210
3211 case wxGRID_CHOICE:
3212 // TODO: implement this
3213 //
3214 break;
3215
3216 case wxGRID_COMBOBOX:
3217 // TODO: implement this
3218 //
3219 break;
3220 }
3221 }
3222 }
3223 }
3224
3225
3226 void wxGrid::SaveEditControlValue()
3227 {
3228 if ( m_table )
3229 {
3230 wxWindow *ctrl = (wxWindow *)NULL;
3231
3232 if ( IsCellEditControlEnabled() )
3233 {
3234 ctrl = m_cellEditCtrl;
3235 }
3236 else
3237 {
3238 return;
3239 }
3240
3241 bool valueChanged = FALSE;
3242
3243 switch ( m_editCtrlType )
3244 {
3245 case wxGRID_TEXTCTRL:
3246 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3247 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3248 SetCellValue( m_currentCellCoords,
3249 ((wxTextCtrl *) ctrl)->GetValue() );
3250 break;
3251
3252 case wxGRID_CHECKBOX:
3253 // TODO: implement this
3254 //
3255 break;
3256
3257 case wxGRID_CHOICE:
3258 // TODO: implement this
3259 //
3260 break;
3261
3262 case wxGRID_COMBOBOX:
3263 // TODO: implement this
3264 //
3265 break;
3266 }
3267
3268 if ( valueChanged )
3269 {
3270 SendEvent( EVT_GRID_CELL_CHANGE,
3271 m_currentCellCoords.GetRow(),
3272 m_currentCellCoords.GetCol() );
3273 }
3274 }
3275 }
3276
3277
3278 //
3279 // ------ Grid location functions
3280 // Note that all of these functions work with the logical coordinates of
3281 // grid cells and labels so you will need to convert from device
3282 // coordinates for mouse events etc.
3283 //
3284
3285 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
3286 {
3287 int row = YToRow(y);
3288 int col = XToCol(x);
3289
3290 if ( row == -1 || col == -1 )
3291 {
3292 coords = wxGridNoCellCoords;
3293 }
3294 else
3295 {
3296 coords.Set( row, col );
3297 }
3298 }
3299
3300
3301 int wxGrid::YToRow( int y )
3302 {
3303 int i;
3304
3305 for ( i = 0; i < m_numRows; i++ )
3306 {
3307 if ( y < m_rowBottoms[i] ) return i;
3308 }
3309
3310 return -1;
3311 }
3312
3313
3314 int wxGrid::XToCol( int x )
3315 {
3316 int i;
3317
3318 for ( i = 0; i < m_numCols; i++ )
3319 {
3320 if ( x < m_colRights[i] ) return i;
3321 }
3322
3323 return -1;
3324 }
3325
3326
3327 // return the row number that that the y coord is near the edge of, or
3328 // -1 if not near an edge
3329 //
3330 int wxGrid::YToEdgeOfRow( int y )
3331 {
3332 int i, d;
3333
3334 for ( i = 0; i < m_numRows; i++ )
3335 {
3336 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
3337 {
3338 d = abs( y - m_rowBottoms[i] );
3339 {
3340 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3341 }
3342 }
3343 }
3344
3345 return -1;
3346 }
3347
3348
3349 // return the col number that that the x coord is near the edge of, or
3350 // -1 if not near an edge
3351 //
3352 int wxGrid::XToEdgeOfCol( int x )
3353 {
3354 int i, d;
3355
3356 for ( i = 0; i < m_numCols; i++ )
3357 {
3358 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3359 {
3360 d = abs( x - m_colRights[i] );
3361 {
3362 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3363 }
3364 }
3365 }
3366
3367 return -1;
3368 }
3369
3370
3371 wxRect wxGrid::CellToRect( int row, int col )
3372 {
3373 wxRect rect( -1, -1, -1, -1 );
3374
3375 if ( row >= 0 && row < m_numRows &&
3376 col >= 0 && col < m_numCols )
3377 {
3378 rect.x = m_colRights[col] - m_colWidths[col];
3379 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3380 rect.width = m_colWidths[col];
3381 rect.height = m_rowHeights[ row ];
3382 }
3383
3384 return rect;
3385 }
3386
3387
3388 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3389 {
3390 // get the cell rectangle in logical coords
3391 //
3392 wxRect r( CellToRect( row, col ) );
3393
3394 // convert to device coords
3395 //
3396 int left, top, right, bottom;
3397 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3398 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3399
3400 // check against the client area of the grid window
3401 //
3402 int cw, ch;
3403 m_gridWin->GetClientSize( &cw, &ch );
3404
3405 if ( wholeCellVisible )
3406 {
3407 // is the cell wholly visible ?
3408 //
3409 return ( left >= 0 && right <= cw &&
3410 top >= 0 && bottom <= ch );
3411 }
3412 else
3413 {
3414 // is the cell partly visible ?
3415 //
3416 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3417 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3418 }
3419 }
3420
3421
3422 // make the specified cell location visible by doing a minimal amount
3423 // of scrolling
3424 //
3425 void wxGrid::MakeCellVisible( int row, int col )
3426 {
3427 int i;
3428 int xpos = -1, ypos = -1;
3429
3430 if ( row >= 0 && row < m_numRows &&
3431 col >= 0 && col < m_numCols )
3432 {
3433 // get the cell rectangle in logical coords
3434 //
3435 wxRect r( CellToRect( row, col ) );
3436
3437 // convert to device coords
3438 //
3439 int left, top, right, bottom;
3440 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3441 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3442
3443 int cw, ch;
3444 m_gridWin->GetClientSize( &cw, &ch );
3445
3446 if ( top < 0 )
3447 {
3448 ypos = r.GetTop();
3449 }
3450 else if ( bottom > ch )
3451 {
3452 int h = r.GetHeight();
3453 ypos = r.GetTop();
3454 for ( i = row-1; i >= 0; i-- )
3455 {
3456 if ( h + m_rowHeights[i] > ch ) break;
3457
3458 h += m_rowHeights[i];
3459 ypos -= m_rowHeights[i];
3460 }
3461
3462 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3463 // have rounding errors (this is important, because if we do, we
3464 // might not scroll at all and some cells won't be redrawn)
3465 ypos += GRID_SCROLL_LINE / 2;
3466 }
3467
3468 if ( left < 0 )
3469 {
3470 xpos = r.GetLeft();
3471 }
3472 else if ( right > cw )
3473 {
3474 int w = r.GetWidth();
3475 xpos = r.GetLeft();
3476 for ( i = col-1; i >= 0; i-- )
3477 {
3478 if ( w + m_colWidths[i] > cw ) break;
3479
3480 w += m_colWidths[i];
3481 xpos -= m_colWidths[i];
3482 }
3483
3484 // see comment for ypos above
3485 xpos += GRID_SCROLL_LINE / 2;
3486 }
3487
3488 if ( xpos != -1 || ypos != -1 )
3489 {
3490 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
3491 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
3492 Scroll( xpos, ypos );
3493 AdjustScrollbars();
3494 }
3495 }
3496 }
3497
3498
3499 //
3500 // ------ Grid cursor movement functions
3501 //
3502
3503 bool wxGrid::MoveCursorUp()
3504 {
3505 if ( m_currentCellCoords != wxGridNoCellCoords &&
3506 m_currentCellCoords.GetRow() > 0 )
3507 {
3508 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3509 m_currentCellCoords.GetCol() );
3510
3511 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3512 m_currentCellCoords.GetCol() );
3513
3514 return TRUE;
3515 }
3516
3517 return FALSE;
3518 }
3519
3520
3521 bool wxGrid::MoveCursorDown()
3522 {
3523 // TODO: allow for scrolling
3524 //
3525 if ( m_currentCellCoords != wxGridNoCellCoords &&
3526 m_currentCellCoords.GetRow() < m_numRows-1 )
3527 {
3528 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3529 m_currentCellCoords.GetCol() );
3530
3531 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3532 m_currentCellCoords.GetCol() );
3533
3534 return TRUE;
3535 }
3536
3537 return FALSE;
3538 }
3539
3540
3541 bool wxGrid::MoveCursorLeft()
3542 {
3543 if ( m_currentCellCoords != wxGridNoCellCoords &&
3544 m_currentCellCoords.GetCol() > 0 )
3545 {
3546 MakeCellVisible( m_currentCellCoords.GetRow(),
3547 m_currentCellCoords.GetCol() - 1 );
3548
3549 SetCurrentCell( m_currentCellCoords.GetRow(),
3550 m_currentCellCoords.GetCol() - 1 );
3551
3552 return TRUE;
3553 }
3554
3555 return FALSE;
3556 }
3557
3558
3559 bool wxGrid::MoveCursorRight()
3560 {
3561 if ( m_currentCellCoords != wxGridNoCellCoords &&
3562 m_currentCellCoords.GetCol() < m_numCols - 1 )
3563 {
3564 MakeCellVisible( m_currentCellCoords.GetRow(),
3565 m_currentCellCoords.GetCol() + 1 );
3566
3567 SetCurrentCell( m_currentCellCoords.GetRow(),
3568 m_currentCellCoords.GetCol() + 1 );
3569
3570 return TRUE;
3571 }
3572
3573 return FALSE;
3574 }
3575
3576
3577 bool wxGrid::MovePageUp()
3578 {
3579 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
3580
3581 int row = m_currentCellCoords.GetRow();
3582 if ( row > 0 )
3583 {
3584 int cw, ch;
3585 m_gridWin->GetClientSize( &cw, &ch );
3586
3587 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3588 int newRow = YToRow( y - ch + 1 );
3589 if ( newRow == -1 )
3590 {
3591 newRow = 0;
3592 }
3593 else if ( newRow == row )
3594 {
3595 newRow = row - 1;
3596 }
3597
3598 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3599 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
3600
3601 return TRUE;
3602 }
3603
3604 return FALSE;
3605 }
3606
3607 bool wxGrid::MovePageDown()
3608 {
3609 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
3610
3611 int row = m_currentCellCoords.GetRow();
3612 if ( row < m_numRows )
3613 {
3614 int cw, ch;
3615 m_gridWin->GetClientSize( &cw, &ch );
3616
3617 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
3618 int newRow = YToRow( y + ch );
3619 if ( newRow == -1 )
3620 {
3621 newRow = m_numRows - 1;
3622 }
3623 else if ( newRow == row )
3624 {
3625 newRow = row + 1;
3626 }
3627
3628 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
3629 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
3630
3631 return TRUE;
3632 }
3633
3634 return FALSE;
3635 }
3636
3637 bool wxGrid::MoveCursorUpBlock()
3638 {
3639 if ( m_table &&
3640 m_currentCellCoords != wxGridNoCellCoords &&
3641 m_currentCellCoords.GetRow() > 0 )
3642 {
3643 int row = m_currentCellCoords.GetRow();
3644 int col = m_currentCellCoords.GetCol();
3645
3646 if ( m_table->IsEmptyCell(row, col) )
3647 {
3648 // starting in an empty cell: find the next block of
3649 // non-empty cells
3650 //
3651 while ( row > 0 )
3652 {
3653 row-- ;
3654 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3655 }
3656 }
3657 else if ( m_table->IsEmptyCell(row-1, col) )
3658 {
3659 // starting at the top of a block: find the next block
3660 //
3661 row--;
3662 while ( row > 0 )
3663 {
3664 row-- ;
3665 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3666 }
3667 }
3668 else
3669 {
3670 // starting within a block: find the top of the block
3671 //
3672 while ( row > 0 )
3673 {
3674 row-- ;
3675 if ( m_table->IsEmptyCell(row, col) )
3676 {
3677 row++ ;
3678 break;
3679 }
3680 }
3681 }
3682
3683 MakeCellVisible( row, col );
3684 SetCurrentCell( row, col );
3685
3686 return TRUE;
3687 }
3688
3689 return FALSE;
3690 }
3691
3692 bool wxGrid::MoveCursorDownBlock()
3693 {
3694 if ( m_table &&
3695 m_currentCellCoords != wxGridNoCellCoords &&
3696 m_currentCellCoords.GetRow() < m_numRows-1 )
3697 {
3698 int row = m_currentCellCoords.GetRow();
3699 int col = m_currentCellCoords.GetCol();
3700
3701 if ( m_table->IsEmptyCell(row, col) )
3702 {
3703 // starting in an empty cell: find the next block of
3704 // non-empty cells
3705 //
3706 while ( row < m_numRows-1 )
3707 {
3708 row++ ;
3709 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3710 }
3711 }
3712 else if ( m_table->IsEmptyCell(row+1, col) )
3713 {
3714 // starting at the bottom of a block: find the next block
3715 //
3716 row++;
3717 while ( row < m_numRows-1 )
3718 {
3719 row++ ;
3720 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3721 }
3722 }
3723 else
3724 {
3725 // starting within a block: find the bottom of the block
3726 //
3727 while ( row < m_numRows-1 )
3728 {
3729 row++ ;
3730 if ( m_table->IsEmptyCell(row, col) )
3731 {
3732 row-- ;
3733 break;
3734 }
3735 }
3736 }
3737
3738 MakeCellVisible( row, col );
3739 SetCurrentCell( row, col );
3740
3741 return TRUE;
3742 }
3743
3744 return FALSE;
3745 }
3746
3747 bool wxGrid::MoveCursorLeftBlock()
3748 {
3749 if ( m_table &&
3750 m_currentCellCoords != wxGridNoCellCoords &&
3751 m_currentCellCoords.GetCol() > 0 )
3752 {
3753 int row = m_currentCellCoords.GetRow();
3754 int col = m_currentCellCoords.GetCol();
3755
3756 if ( m_table->IsEmptyCell(row, col) )
3757 {
3758 // starting in an empty cell: find the next block of
3759 // non-empty cells
3760 //
3761 while ( col > 0 )
3762 {
3763 col-- ;
3764 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3765 }
3766 }
3767 else if ( m_table->IsEmptyCell(row, col-1) )
3768 {
3769 // starting at the left of a block: find the next block
3770 //
3771 col--;
3772 while ( col > 0 )
3773 {
3774 col-- ;
3775 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3776 }
3777 }
3778 else
3779 {
3780 // starting within a block: find the left of the block
3781 //
3782 while ( col > 0 )
3783 {
3784 col-- ;
3785 if ( m_table->IsEmptyCell(row, col) )
3786 {
3787 col++ ;
3788 break;
3789 }
3790 }
3791 }
3792
3793 MakeCellVisible( row, col );
3794 SetCurrentCell( row, col );
3795
3796 return TRUE;
3797 }
3798
3799 return FALSE;
3800 }
3801
3802 bool wxGrid::MoveCursorRightBlock()
3803 {
3804 if ( m_table &&
3805 m_currentCellCoords != wxGridNoCellCoords &&
3806 m_currentCellCoords.GetCol() < m_numCols-1 )
3807 {
3808 int row = m_currentCellCoords.GetRow();
3809 int col = m_currentCellCoords.GetCol();
3810
3811 if ( m_table->IsEmptyCell(row, col) )
3812 {
3813 // starting in an empty cell: find the next block of
3814 // non-empty cells
3815 //
3816 while ( col < m_numCols-1 )
3817 {
3818 col++ ;
3819 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3820 }
3821 }
3822 else if ( m_table->IsEmptyCell(row, col+1) )
3823 {
3824 // starting at the right of a block: find the next block
3825 //
3826 col++;
3827 while ( col < m_numCols-1 )
3828 {
3829 col++ ;
3830 if ( !(m_table->IsEmptyCell(row, col)) ) break;
3831 }
3832 }
3833 else
3834 {
3835 // starting within a block: find the right of the block
3836 //
3837 while ( col < m_numCols-1 )
3838 {
3839 col++ ;
3840 if ( m_table->IsEmptyCell(row, col) )
3841 {
3842 col-- ;
3843 break;
3844 }
3845 }
3846 }
3847
3848 MakeCellVisible( row, col );
3849 SetCurrentCell( row, col );
3850
3851 return TRUE;
3852 }
3853
3854 return FALSE;
3855 }
3856
3857
3858
3859 //
3860 // ------ Label values and formatting
3861 //
3862
3863 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
3864 {
3865 *horiz = m_rowLabelHorizAlign;
3866 *vert = m_rowLabelVertAlign;
3867 }
3868
3869 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
3870 {
3871 *horiz = m_colLabelHorizAlign;
3872 *vert = m_colLabelVertAlign;
3873 }
3874
3875 wxString wxGrid::GetRowLabelValue( int row )
3876 {
3877 if ( m_table )
3878 {
3879 return m_table->GetRowLabelValue( row );
3880 }
3881 else
3882 {
3883 wxString s;
3884 s << row;
3885 return s;
3886 }
3887 }
3888
3889 wxString wxGrid::GetColLabelValue( int col )
3890 {
3891 if ( m_table )
3892 {
3893 return m_table->GetColLabelValue( col );
3894 }
3895 else
3896 {
3897 wxString s;
3898 s << col;
3899 return s;
3900 }
3901 }
3902
3903
3904 void wxGrid::SetRowLabelSize( int width )
3905 {
3906 wxSize sz;
3907
3908 width = wxMax( width, 0 );
3909 if ( width != m_rowLabelWidth )
3910 {
3911 // Hiding the row labels (and possible the corner label)
3912 //
3913 if ( width == 0 )
3914 {
3915 m_rowLabelWin->Show( FALSE );
3916
3917 // If the col labels are on display we need to hide the
3918 // corner label and remove it from the top sizer
3919 //
3920 if ( m_colLabelHeight > 0 )
3921 {
3922 m_cornerLabelWin->Show( FALSE );
3923 m_topSizer->Remove( m_cornerLabelWin );
3924 }
3925
3926 m_middleSizer->Remove( m_rowLabelWin );
3927 }
3928 else
3929 {
3930 // Displaying the row labels (and possibly the corner
3931 // label) after being hidden
3932 //
3933 if ( m_rowLabelWidth == 0 )
3934 {
3935 m_rowLabelWin->Show( TRUE );
3936
3937 if ( m_colLabelHeight > 0 )
3938 {
3939 m_cornerLabelWin->Show( TRUE );
3940 m_topSizer->Prepend( m_cornerLabelWin, 0 );
3941 }
3942
3943 m_middleSizer->Prepend( m_rowLabelWin, 0, wxEXPAND );
3944 }
3945
3946
3947 // set the width of the corner label if it is on display
3948 //
3949 if ( m_colLabelHeight > 0 )
3950 {
3951 wxList& childList = m_topSizer->GetChildren();
3952 wxNode *node = childList.First();
3953 while (node)
3954 {
3955 wxSizerItem *item = (wxSizerItem*)node->Data();
3956 if ( item->GetWindow() == m_cornerLabelWin )
3957 {
3958 item->SetInitSize( width, m_colLabelHeight );
3959 break;
3960 }
3961 node = node->Next();
3962 }
3963 }
3964
3965 // set the width of the row labels
3966 //
3967 wxList& childList = m_middleSizer->GetChildren();
3968 wxNode *node = childList.First();
3969 while (node)
3970 {
3971 wxSizerItem *item = (wxSizerItem*)node->Data();
3972 if ( item->GetWindow() == m_rowLabelWin )
3973 {
3974 sz = item->GetWindow()->GetSize();
3975 item->SetInitSize( width, sz.GetHeight() );
3976 break;
3977 }
3978 node = node->Next();
3979 }
3980 }
3981
3982 m_rowLabelWidth = width;
3983 m_mainSizer->Layout();
3984 }
3985 }
3986
3987
3988 void wxGrid::SetColLabelSize( int height )
3989 {
3990 wxSize sz;
3991
3992 if ( height < 0 ) height = 0;
3993 if ( height != m_colLabelHeight )
3994 {
3995 // hiding the column labels
3996 //
3997 if ( height == 0 )
3998 {
3999 m_cornerLabelWin->Show( FALSE );
4000 m_colLabelWin->Show( FALSE );
4001
4002 // Note: this call will actually delete the sizer
4003 //
4004 m_mainSizer->Remove( m_topSizer );
4005 m_topSizer = (wxBoxSizer *)NULL;
4006 }
4007 else
4008 {
4009 // column labels to be displayed after being hidden
4010 //
4011 if ( m_colLabelHeight == 0 )
4012 {
4013 // recreate the top sizer
4014 //
4015 m_topSizer = new wxBoxSizer( wxHORIZONTAL );
4016
4017 if ( m_rowLabelWidth > 0 )
4018 m_topSizer->Add( m_cornerLabelWin, 0 );
4019
4020 m_topSizer->Add( m_colLabelWin, 1 );
4021 m_mainSizer->Prepend( m_topSizer, 0, wxEXPAND );
4022
4023 // only show the corner label if the row labels are
4024 // also displayed
4025 //
4026 if ( m_rowLabelWidth > 0 )
4027 m_cornerLabelWin->Show( TRUE );
4028
4029 m_colLabelWin->Show( TRUE );
4030 }
4031
4032 wxList& childList = m_topSizer->GetChildren();
4033 wxNode *node = childList.First();
4034 while (node)
4035 {
4036 wxSizerItem *item = (wxSizerItem*)node->Data();
4037
4038 if ( (item->GetWindow() == m_cornerLabelWin && m_rowLabelWidth > 0) ||
4039 item->GetWindow() == m_colLabelWin )
4040 {
4041 sz = item->GetWindow()->GetSize();
4042 item->SetInitSize( sz.GetWidth(), height );
4043 }
4044 node = node->Next();
4045 }
4046 }
4047
4048 m_colLabelHeight = height;
4049 m_mainSizer->Layout();
4050 }
4051 }
4052
4053
4054 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4055 {
4056 if ( m_labelBackgroundColour != colour )
4057 {
4058 m_labelBackgroundColour = colour;
4059 m_rowLabelWin->SetBackgroundColour( colour );
4060 m_colLabelWin->SetBackgroundColour( colour );
4061 m_cornerLabelWin->SetBackgroundColour( colour );
4062
4063 if ( !GetBatchCount() )
4064 {
4065 m_rowLabelWin->Refresh();
4066 m_colLabelWin->Refresh();
4067 m_cornerLabelWin->Refresh();
4068 }
4069 }
4070 }
4071
4072 void wxGrid::SetLabelTextColour( const wxColour& colour )
4073 {
4074 if ( m_labelTextColour != colour )
4075 {
4076 m_labelTextColour = colour;
4077 if ( !GetBatchCount() )
4078 {
4079 m_rowLabelWin->Refresh();
4080 m_colLabelWin->Refresh();
4081 }
4082 }
4083 }
4084
4085 void wxGrid::SetLabelFont( const wxFont& font )
4086 {
4087 m_labelFont = font;
4088 if ( !GetBatchCount() )
4089 {
4090 m_rowLabelWin->Refresh();
4091 m_colLabelWin->Refresh();
4092 }
4093 }
4094
4095 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
4096 {
4097 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4098 {
4099 m_rowLabelHorizAlign = horiz;
4100 }
4101
4102 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4103 {
4104 m_rowLabelVertAlign = vert;
4105 }
4106
4107 if ( !GetBatchCount() )
4108 {
4109 m_rowLabelWin->Refresh();
4110 }
4111 }
4112
4113 void wxGrid::SetColLabelAlignment( int horiz, int vert )
4114 {
4115 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4116 {
4117 m_colLabelHorizAlign = horiz;
4118 }
4119
4120 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4121 {
4122 m_colLabelVertAlign = vert;
4123 }
4124
4125 if ( !GetBatchCount() )
4126 {
4127 m_colLabelWin->Refresh();
4128 }
4129 }
4130
4131 void wxGrid::SetRowLabelValue( int row, const wxString& s )
4132 {
4133 if ( m_table )
4134 {
4135 m_table->SetRowLabelValue( row, s );
4136 if ( !GetBatchCount() )
4137 {
4138 wxRect rect = CellToRect( row, 0);
4139 if ( rect.height > 0 )
4140 {
4141 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
4142 rect.x = m_left;
4143 rect.width = m_rowLabelWidth;
4144 m_rowLabelWin->Refresh( TRUE, &rect );
4145 }
4146 }
4147 }
4148 }
4149
4150 void wxGrid::SetColLabelValue( int col, const wxString& s )
4151 {
4152 if ( m_table )
4153 {
4154 m_table->SetColLabelValue( col, s );
4155 if ( !GetBatchCount() )
4156 {
4157 wxRect rect = CellToRect( 0, col );
4158 if ( rect.width > 0 )
4159 {
4160 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
4161 rect.y = m_top;
4162 rect.height = m_colLabelHeight;
4163 m_colLabelWin->Refresh( TRUE, &rect );
4164 }
4165 }
4166 }
4167 }
4168
4169 void wxGrid::SetGridLineColour( const wxColour& colour )
4170 {
4171 if ( m_gridLineColour != colour )
4172 {
4173 m_gridLineColour = colour;
4174
4175 wxClientDC dc( m_gridWin );
4176 PrepareDC( dc );
4177 DrawAllGridLines( dc, wxRegion() );
4178 }
4179 }
4180
4181 void wxGrid::EnableGridLines( bool enable )
4182 {
4183 if ( enable != m_gridLinesEnabled )
4184 {
4185 m_gridLinesEnabled = enable;
4186
4187 if ( !GetBatchCount() )
4188 {
4189 if ( enable )
4190 {
4191 wxClientDC dc( m_gridWin );
4192 PrepareDC( dc );
4193 DrawAllGridLines( dc, wxRegion() );
4194 }
4195 else
4196 {
4197 m_gridWin->Refresh();
4198 }
4199 }
4200 }
4201 }
4202
4203
4204 int wxGrid::GetDefaultRowSize()
4205 {
4206 return m_defaultRowHeight;
4207 }
4208
4209 int wxGrid::GetRowSize( int row )
4210 {
4211 if ( row >= 0 && row < m_numRows )
4212 return m_rowHeights[row];
4213 else
4214 return 0; // TODO: log an error here
4215 }
4216
4217 int wxGrid::GetDefaultColSize()
4218 {
4219 return m_defaultColWidth;
4220 }
4221
4222 int wxGrid::GetColSize( int col )
4223 {
4224 if ( col >= 0 && col < m_numCols )
4225 return m_colWidths[col];
4226 else
4227 return 0; // TODO: log an error here
4228 }
4229
4230 wxColour wxGrid::GetDefaultCellBackgroundColour()
4231 {
4232 // TODO: replace this temp test code
4233 //
4234 return wxColour( 255, 255, 255 );
4235 }
4236
4237 wxColour wxGrid::GetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col) )
4238 {
4239 // TODO: replace this temp test code
4240 //
4241 return wxColour( 255, 255, 255 );
4242 }
4243
4244 wxColour wxGrid::GetDefaultCellTextColour()
4245 {
4246 // TODO: replace this temp test code
4247 //
4248 return wxColour( 0, 0, 0 );
4249 }
4250
4251 wxColour wxGrid::GetCellTextColour( int WXUNUSED(row), int WXUNUSED(col) )
4252 {
4253 // TODO: replace this temp test code
4254 //
4255 return wxColour( 0, 0, 0 );
4256 }
4257
4258
4259 wxFont wxGrid::GetDefaultCellFont()
4260 {
4261 return m_defaultCellFont;
4262 }
4263
4264 wxFont wxGrid::GetCellFont( int WXUNUSED(row), int WXUNUSED(col) )
4265 {
4266 // TODO: replace this temp test code
4267 //
4268 return m_defaultCellFont;
4269 }
4270
4271 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
4272 {
4273 // TODO: replace this temp test code
4274 //
4275 *horiz = wxLEFT;
4276 *vert = wxTOP;
4277 }
4278
4279 void wxGrid::GetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int *horiz, int *vert )
4280 {
4281 // TODO: replace this temp test code
4282 //
4283 *horiz = wxLEFT;
4284 *vert = wxTOP;
4285 }
4286
4287 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
4288 {
4289 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
4290
4291 if ( resizeExistingRows )
4292 {
4293 int row;
4294 int bottom = 0;
4295 for ( row = 0; row < m_numRows; row++ )
4296 {
4297 m_rowHeights[row] = m_defaultRowHeight;
4298 bottom += m_defaultRowHeight;
4299 m_rowBottoms[row] = bottom;
4300 }
4301 CalcDimensions();
4302 }
4303 }
4304
4305 void wxGrid::SetRowSize( int row, int height )
4306 {
4307 int i;
4308
4309 if ( row >= 0 && row < m_numRows )
4310 {
4311 int h = wxMax( 0, height );
4312 int diff = h - m_rowHeights[row];
4313
4314 m_rowHeights[row] = h;
4315 for ( i = row; i < m_numRows; i++ )
4316 {
4317 m_rowBottoms[i] += diff;
4318 }
4319 CalcDimensions();
4320
4321 // Note: we are ending the event *after* doing
4322 // default processing in this case
4323 //
4324 SendEvent( EVT_GRID_ROW_SIZE,
4325 row, -1 );
4326 }
4327 else
4328 {
4329 // TODO: log an error here
4330 }
4331 }
4332
4333 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4334 {
4335 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4336
4337 if ( resizeExistingCols )
4338 {
4339 int col;
4340 int right = 0;
4341 for ( col = 0; col < m_numCols; col++ )
4342 {
4343 m_colWidths[col] = m_defaultColWidth;
4344 right += m_defaultColWidth;
4345 m_colRights[col] = right;
4346 }
4347 CalcDimensions();
4348 }
4349 }
4350
4351 void wxGrid::SetColSize( int col, int width )
4352 {
4353 int i;
4354
4355 if ( col >= 0 && col < m_numCols )
4356 {
4357 int w = wxMax( 0, width );
4358 int diff = w - m_colWidths[col];
4359 m_colWidths[col] = w;
4360
4361 for ( i = col; i < m_numCols; i++ )
4362 {
4363 m_colRights[i] += diff;
4364 }
4365 CalcDimensions();
4366
4367 // Note: we are ending the event *after* doing
4368 // default processing in this case
4369 //
4370 SendEvent( EVT_GRID_COL_SIZE,
4371 -1, col );
4372 }
4373 else
4374 {
4375 // TODO: log an error here
4376 }
4377 }
4378
4379 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& )
4380 {
4381 // TODO: everything !!!
4382 //
4383 }
4384
4385 void wxGrid::SetCellBackgroundColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
4386 {
4387 // TODO: everything !!!
4388 //
4389 }
4390
4391 void wxGrid::SetDefaultCellTextColour( const wxColour& )
4392 {
4393 // TODO: everything !!!
4394 //
4395 }
4396
4397 void wxGrid::SetCellTextColour( int WXUNUSED(row), int WXUNUSED(col), const wxColour& )
4398 {
4399 // TODO: everything !!!
4400 //
4401 }
4402
4403 void wxGrid::SetDefaultCellFont( const wxFont& )
4404 {
4405 // TODO: everything !!!
4406 //
4407 }
4408
4409 void wxGrid::SetCellFont( int WXUNUSED(row), int WXUNUSED(col), const wxFont& )
4410 {
4411 // TODO: everything !!!
4412 //
4413 }
4414
4415 void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz), int WXUNUSED(vert) )
4416 {
4417 // TODO: everything !!!
4418 //
4419 }
4420
4421 void wxGrid::SetCellAlignment( int WXUNUSED(row), int WXUNUSED(col), int WXUNUSED(horiz), int WXUNUSED(vert) )
4422 {
4423 // TODO: everything !!!
4424 //
4425 }
4426
4427
4428
4429 //
4430 // ------ cell value accessor functions
4431 //
4432
4433 void wxGrid::SetCellValue( int row, int col, const wxString& s )
4434 {
4435 if ( m_table )
4436 {
4437 m_table->SetValue( row, col, s.c_str() );
4438 if ( !GetBatchCount() )
4439 {
4440 wxClientDC dc( m_gridWin );
4441 PrepareDC( dc );
4442 DrawCell( dc, wxGridCellCoords(row, col) );
4443 }
4444
4445 #if 0 // TODO: edit in place
4446
4447 if ( m_currentCellCoords.GetRow() == row &&
4448 m_currentCellCoords.GetCol() == col )
4449 {
4450 SetEditControlValue( s );
4451 }
4452 #endif
4453
4454 }
4455 }
4456
4457
4458 //
4459 // ------ Block, row and col selection
4460 //
4461
4462 void wxGrid::SelectRow( int row, bool addToSelected )
4463 {
4464 wxRect r;
4465
4466 if ( IsSelection() && addToSelected )
4467 {
4468 wxRect rect[4];
4469 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4470 int i;
4471
4472 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4473 wxCoord oldTop = m_selectedTopLeft.GetRow();
4474 wxCoord oldRight = m_selectedBottomRight.GetCol();
4475 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4476
4477 if ( oldTop > row )
4478 {
4479 need_refresh[0] = TRUE;
4480 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
4481 wxGridCellCoords ( oldTop - 1,
4482 m_numCols - 1 ) );
4483 m_selectedTopLeft.SetRow( row );
4484 }
4485
4486 if ( oldLeft > 0 )
4487 {
4488 need_refresh[1] = TRUE;
4489 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
4490 wxGridCellCoords ( oldBottom,
4491 oldLeft - 1 ) );
4492
4493 m_selectedTopLeft.SetCol( 0 );
4494 }
4495
4496 if ( oldBottom < row )
4497 {
4498 need_refresh[2] = TRUE;
4499 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
4500 wxGridCellCoords ( row,
4501 m_numCols - 1 ) );
4502 m_selectedBottomRight.SetRow( row );
4503 }
4504
4505 if ( oldRight < m_numCols - 1 )
4506 {
4507 need_refresh[3] = TRUE;
4508 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
4509 oldRight + 1 ),
4510 wxGridCellCoords ( oldBottom,
4511 m_numCols - 1 ) );
4512 m_selectedBottomRight.SetCol( m_numCols - 1 );
4513 }
4514
4515 for (i = 0; i < 4; i++ )
4516 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4517 m_gridWin->Refresh( FALSE, &(rect[i]) );
4518 }
4519 else
4520 {
4521 r = SelectionToDeviceRect();
4522 ClearSelection();
4523 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4524
4525 m_selectedTopLeft.Set( row, 0 );
4526 m_selectedBottomRight.Set( row, m_numCols-1 );
4527 r = SelectionToDeviceRect();
4528 m_gridWin->Refresh( FALSE, &r );
4529 }
4530
4531 wxGridRangeSelectEvent gridEvt( GetId(),
4532 EVT_GRID_RANGE_SELECT,
4533 this,
4534 m_selectedTopLeft,
4535 m_selectedBottomRight );
4536
4537 GetEventHandler()->ProcessEvent(gridEvt);
4538 }
4539
4540
4541 void wxGrid::SelectCol( int col, bool addToSelected )
4542 {
4543 if ( IsSelection() && addToSelected )
4544 {
4545 wxRect rect[4];
4546 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4547 int i;
4548
4549 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4550 wxCoord oldTop = m_selectedTopLeft.GetRow();
4551 wxCoord oldRight = m_selectedBottomRight.GetCol();
4552 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4553
4554 if ( oldLeft > col )
4555 {
4556 need_refresh[0] = TRUE;
4557 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
4558 wxGridCellCoords ( m_numRows - 1,
4559 oldLeft - 1 ) );
4560 m_selectedTopLeft.SetCol( col );
4561 }
4562
4563 if ( oldTop > 0 )
4564 {
4565 need_refresh[1] = TRUE;
4566 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
4567 wxGridCellCoords ( oldTop - 1,
4568 oldRight ) );
4569 m_selectedTopLeft.SetRow( 0 );
4570 }
4571
4572 if ( oldRight < col )
4573 {
4574 need_refresh[2] = TRUE;
4575 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
4576 wxGridCellCoords ( m_numRows - 1,
4577 col ) );
4578 m_selectedBottomRight.SetCol( col );
4579 }
4580
4581 if ( oldBottom < m_numRows - 1 )
4582 {
4583 need_refresh[3] = TRUE;
4584 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
4585 oldLeft ),
4586 wxGridCellCoords ( m_numRows - 1,
4587 oldRight ) );
4588 m_selectedBottomRight.SetRow( m_numRows - 1 );
4589 }
4590
4591 for (i = 0; i < 4; i++ )
4592 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4593 m_gridWin->Refresh( FALSE, &(rect[i]) );
4594 }
4595 else
4596 {
4597 wxRect r;
4598
4599 r = SelectionToDeviceRect();
4600 ClearSelection();
4601 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4602
4603 m_selectedTopLeft.Set( 0, col );
4604 m_selectedBottomRight.Set( m_numRows-1, col );
4605 r = SelectionToDeviceRect();
4606 m_gridWin->Refresh( FALSE, &r );
4607 }
4608
4609 wxGridRangeSelectEvent gridEvt( GetId(),
4610 EVT_GRID_RANGE_SELECT,
4611 this,
4612 m_selectedTopLeft,
4613 m_selectedBottomRight );
4614
4615 GetEventHandler()->ProcessEvent(gridEvt);
4616 }
4617
4618
4619 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
4620 {
4621 int temp;
4622 wxGridCellCoords updateTopLeft, updateBottomRight;
4623
4624 if ( topRow > bottomRow )
4625 {
4626 temp = topRow;
4627 topRow = bottomRow;
4628 bottomRow = temp;
4629 }
4630
4631 if ( leftCol > rightCol )
4632 {
4633 temp = leftCol;
4634 leftCol = rightCol;
4635 rightCol = temp;
4636 }
4637
4638 updateTopLeft = wxGridCellCoords( topRow, leftCol );
4639 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
4640
4641 if ( m_selectedTopLeft != updateTopLeft ||
4642 m_selectedBottomRight != updateBottomRight )
4643 {
4644 // Compute two optimal update rectangles:
4645 // Either one rectangle is a real subset of the
4646 // other, or they are (almost) disjoint!
4647 wxRect rect[4];
4648 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4649 int i;
4650
4651 // Store intermediate values
4652 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4653 wxCoord oldTop = m_selectedTopLeft.GetRow();
4654 wxCoord oldRight = m_selectedBottomRight.GetCol();
4655 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4656
4657 // Determine the outer/inner coordinates.
4658 if (oldLeft > leftCol)
4659 {
4660 temp = oldLeft;
4661 oldLeft = leftCol;
4662 leftCol = temp;
4663 }
4664 if (oldTop > topRow )
4665 {
4666 temp = oldTop;
4667 oldTop = topRow;
4668 topRow = temp;
4669 }
4670 if (oldRight < rightCol )
4671 {
4672 temp = oldRight;
4673 oldRight = rightCol;
4674 rightCol = temp;
4675 }
4676 if (oldBottom < bottomRow)
4677 {
4678 temp = oldBottom;
4679 oldBottom = bottomRow;
4680 bottomRow = temp;
4681 }
4682
4683 // Now, either the stuff marked old is the outer
4684 // rectangle or we don't have a situation where one
4685 // is contained in the other.
4686
4687 if ( oldLeft < leftCol )
4688 {
4689 need_refresh[0] = TRUE;
4690 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4691 oldLeft ),
4692 wxGridCellCoords ( oldBottom,
4693 leftCol - 1 ) );
4694 }
4695
4696 if ( oldTop < topRow )
4697 {
4698 need_refresh[1] = TRUE;
4699 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4700 leftCol ),
4701 wxGridCellCoords ( topRow - 1,
4702 rightCol ) );
4703 }
4704
4705 if ( oldRight > rightCol )
4706 {
4707 need_refresh[2] = TRUE;
4708 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
4709 rightCol + 1 ),
4710 wxGridCellCoords ( oldBottom,
4711 oldRight ) );
4712 }
4713
4714 if ( oldBottom > bottomRow )
4715 {
4716 need_refresh[3] = TRUE;
4717 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
4718 leftCol ),
4719 wxGridCellCoords ( oldBottom,
4720 rightCol ) );
4721 }
4722
4723
4724 // Change Selection
4725 m_selectedTopLeft = updateTopLeft;
4726 m_selectedBottomRight = updateBottomRight;
4727
4728 // various Refresh() calls
4729 for (i = 0; i < 4; i++ )
4730 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4731 m_gridWin->Refresh( FALSE, &(rect[i]) );
4732 }
4733
4734 // only generate an event if the block is not being selected by
4735 // dragging the mouse (in which case the event will be generated in
4736 // the mouse event handler)
4737 if ( !m_isDragging )
4738 {
4739 wxGridRangeSelectEvent gridEvt( GetId(),
4740 EVT_GRID_RANGE_SELECT,
4741 this,
4742 m_selectedTopLeft,
4743 m_selectedBottomRight );
4744
4745 GetEventHandler()->ProcessEvent(gridEvt);
4746 }
4747 }
4748
4749 void wxGrid::SelectAll()
4750 {
4751 m_selectedTopLeft.Set( 0, 0 );
4752 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
4753
4754 m_gridWin->Refresh();
4755 }
4756
4757
4758 void wxGrid::ClearSelection()
4759 {
4760 m_selectedTopLeft = wxGridNoCellCoords;
4761 m_selectedBottomRight = wxGridNoCellCoords;
4762 }
4763
4764
4765 // This function returns the rectangle that encloses the given block
4766 // in device coords clipped to the client size of the grid window.
4767 //
4768 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
4769 const wxGridCellCoords &bottomRight )
4770 {
4771 wxRect rect( wxGridNoCellRect );
4772 wxRect cellRect;
4773
4774 cellRect = CellToRect( topLeft );
4775 if ( cellRect != wxGridNoCellRect )
4776 {
4777 rect = cellRect;
4778 }
4779 else
4780 {
4781 rect = wxRect( 0, 0, 0, 0 );
4782 }
4783
4784 cellRect = CellToRect( bottomRight );
4785 if ( cellRect != wxGridNoCellRect )
4786 {
4787 rect += cellRect;
4788 }
4789 else
4790 {
4791 return wxGridNoCellRect;
4792 }
4793
4794 // convert to scrolled coords
4795 //
4796 int left, top, right, bottom;
4797 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
4798 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
4799
4800 int cw, ch;
4801 m_gridWin->GetClientSize( &cw, &ch );
4802
4803 rect.SetLeft( wxMax(0, left) );
4804 rect.SetTop( wxMax(0, top) );
4805 rect.SetRight( wxMin(cw, right) );
4806 rect.SetBottom( wxMin(ch, bottom) );
4807
4808 return rect;
4809 }
4810
4811
4812
4813 //
4814 // ------ Grid event classes
4815 //
4816
4817 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
4818
4819 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
4820 int row, int col, int x, int y,
4821 bool control, bool shift, bool alt, bool meta )
4822 : wxNotifyEvent( type, id )
4823 {
4824 m_row = row;
4825 m_col = col;
4826 m_x = x;
4827 m_y = y;
4828 m_control = control;
4829 m_shift = shift;
4830 m_alt = alt;
4831 m_meta = meta;
4832
4833 SetEventObject(obj);
4834 }
4835
4836
4837 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
4838
4839 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
4840 int rowOrCol, int x, int y,
4841 bool control, bool shift, bool alt, bool meta )
4842 : wxNotifyEvent( type, id )
4843 {
4844 m_rowOrCol = rowOrCol;
4845 m_x = x;
4846 m_y = y;
4847 m_control = control;
4848 m_shift = shift;
4849 m_alt = alt;
4850 m_meta = meta;
4851
4852 SetEventObject(obj);
4853 }
4854
4855
4856 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
4857
4858 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
4859 const wxGridCellCoords& topLeft,
4860 const wxGridCellCoords& bottomRight,
4861 bool control, bool shift, bool alt, bool meta )
4862 : wxNotifyEvent( type, id )
4863 {
4864 m_topLeft = topLeft;
4865 m_bottomRight = bottomRight;
4866 m_control = control;
4867 m_shift = shift;
4868 m_alt = alt;
4869 m_meta = meta;
4870
4871 SetEventObject(obj);
4872 }
4873
4874
4875 #endif // ifndef wxUSE_NEW_GRID
4876