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