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