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