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