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