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