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