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