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