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