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