fixed setting more than one attr for a cell
[wxWidgets.git] / src / generic / grid.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: grid.cpp
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
5 // Modified by:
6 // Created: 1/08/1999
7 // RCS-ID: $Id$
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "grid.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #include "wx/defs.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
26 #include "gridg.cpp"
27 #else
28
29 #ifndef WX_PRECOMP
30 #include "wx/utils.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/log.h"
34 #endif
35
36 // this include needs to be outside precomp for BCC
37 #include "wx/textfile.h"
38
39 #include "wx/generic/grid.h"
40
41 // ----------------------------------------------------------------------------
42 // array classes instantiation
43 // ----------------------------------------------------------------------------
44
45 struct wxGridCellWithAttr
46 {
47 wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
48 : coords(row, col), attr(attr_)
49 {
50 }
51
52 ~wxGridCellWithAttr()
53 {
54 attr->DecRef();
55 }
56
57 wxGridCellCoords coords;
58 wxGridCellAttr *attr;
59 };
60
61 WX_DECLARE_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
62
63 #include "wx/arrimpl.cpp"
64
65 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
66 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
67
68 // ----------------------------------------------------------------------------
69 // private classes
70 // ----------------------------------------------------------------------------
71
72 class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
73 {
74 public:
75 wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
76 wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
77 const wxPoint &pos, const wxSize &size );
78
79 private:
80 wxGrid *m_owner;
81
82 void OnPaint( wxPaintEvent& event );
83 void OnMouseEvent( wxMouseEvent& event );
84 void OnKeyDown( wxKeyEvent& event );
85
86 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
87 DECLARE_EVENT_TABLE()
88 };
89
90
91 class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
92 {
93 public:
94 wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
95 wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
96 const wxPoint &pos, const wxSize &size );
97
98 private:
99 wxGrid *m_owner;
100
101 void OnPaint( wxPaintEvent &event );
102 void OnMouseEvent( wxMouseEvent& event );
103 void OnKeyDown( wxKeyEvent& event );
104
105 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
106 DECLARE_EVENT_TABLE()
107 };
108
109
110 class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
111 {
112 public:
113 wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
114 wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
115 const wxPoint &pos, const wxSize &size );
116
117 private:
118 wxGrid *m_owner;
119
120 void OnMouseEvent( wxMouseEvent& event );
121 void OnKeyDown( wxKeyEvent& event );
122 void OnPaint( wxPaintEvent& event );
123
124 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
125 DECLARE_EVENT_TABLE()
126 };
127
128 class WXDLLEXPORT wxGridWindow : public wxPanel
129 {
130 public:
131 wxGridWindow()
132 {
133 m_owner = (wxGrid *)NULL;
134 m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
135 m_colLabelWin = (wxGridColLabelWindow *)NULL;
136 }
137
138 wxGridWindow( wxGrid *parent,
139 wxGridRowLabelWindow *rowLblWin,
140 wxGridColLabelWindow *colLblWin,
141 wxWindowID id, const wxPoint &pos, const wxSize &size );
142 ~wxGridWindow();
143
144 void ScrollWindow( int dx, int dy, const wxRect *rect );
145
146 private:
147 wxGrid *m_owner;
148 wxGridRowLabelWindow *m_rowLabelWin;
149 wxGridColLabelWindow *m_colLabelWin;
150
151 void OnPaint( wxPaintEvent &event );
152 void OnMouseEvent( wxMouseEvent& event );
153 void OnKeyDown( wxKeyEvent& );
154
155 DECLARE_DYNAMIC_CLASS(wxGridWindow)
156 DECLARE_EVENT_TABLE()
157 };
158
159 // the internal data representation used by wxGridCellAttrProvider
160 //
161 // TODO make it more efficient
162 class WXDLLEXPORT wxGridCellAttrProviderData
163 {
164 public:
165 void SetAttr(wxGridCellAttr *attr, int row, int col);
166 wxGridCellAttr *GetAttr(int row, int col) const;
167
168 private:
169 // searches for the attr for given cell, returns wxNOT_FOUND if not found
170 int FindIndex(int row, int col) const;
171
172 wxGridCellWithAttrArray m_attrs;
173 };
174
175 // ----------------------------------------------------------------------------
176 // conditional compilation
177 // ----------------------------------------------------------------------------
178
179 #ifndef WXGRID_DRAW_LINES
180 #define WXGRID_DRAW_LINES 1
181 #endif
182
183 //////////////////////////////////////////////////////////////////////
184
185 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
186 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
187
188 // scroll line size
189 // TODO: fixed so far - make configurable later (and also different for x/y)
190 static const size_t GRID_SCROLL_LINE = 10;
191
192 // ----------------------------------------------------------------------------
193 // wxGridCellAttrProviderData
194 // ----------------------------------------------------------------------------
195
196 void wxGridCellAttrProviderData::SetAttr(wxGridCellAttr *attr,
197 int row, int col)
198 {
199 int n = FindIndex(row, col);
200 if ( n == wxNOT_FOUND )
201 {
202 // add the attribute
203 m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
204 }
205 else
206 {
207 if ( attr )
208 {
209 // change the attribute
210 m_attrs[(size_t)n].attr = attr;
211 }
212 else
213 {
214 // remove this attribute
215 m_attrs.RemoveAt((size_t)n);
216 }
217 }
218 }
219
220 wxGridCellAttr *wxGridCellAttrProviderData::GetAttr(int row, int col) const
221 {
222 wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
223
224 int n = FindIndex(row, col);
225 if ( n != wxNOT_FOUND )
226 {
227 attr = m_attrs[(size_t)n].attr;
228 attr->IncRef();
229 }
230
231 return attr;
232 }
233
234 int wxGridCellAttrProviderData::FindIndex(int row, int col) const
235 {
236 size_t count = m_attrs.GetCount();
237 for ( size_t n = 0; n < count; n++ )
238 {
239 const wxGridCellCoords& coords = m_attrs[n].coords;
240 if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
241 {
242 return n;
243 }
244 }
245
246 return wxNOT_FOUND;
247 }
248
249 // ----------------------------------------------------------------------------
250 // wxGridCellAttrProvider
251 // ----------------------------------------------------------------------------
252
253 wxGridCellAttrProvider::wxGridCellAttrProvider()
254 {
255 m_data = (wxGridCellAttrProviderData *)NULL;
256 }
257
258 wxGridCellAttrProvider::~wxGridCellAttrProvider()
259 {
260 delete m_data;
261 }
262
263 void wxGridCellAttrProvider::InitData()
264 {
265 m_data = new wxGridCellAttrProviderData;
266 }
267
268 wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col) const
269 {
270 return m_data ? m_data->GetAttr(row, col) : (wxGridCellAttr *)NULL;
271 }
272
273 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
274 int row, int col)
275 {
276 if ( !m_data )
277 InitData();
278
279 m_data->SetAttr(attr, row, col);
280 }
281
282 //////////////////////////////////////////////////////////////////////
283 //
284 // Abstract base class for grid data (the model)
285 //
286 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
287
288
289 wxGridTableBase::wxGridTableBase()
290 {
291 m_view = (wxGrid *) NULL;
292 m_attrProvider = (wxGridCellAttrProvider *) NULL;
293 }
294
295 wxGridTableBase::~wxGridTableBase()
296 {
297 delete m_attrProvider;
298 }
299
300 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
301 {
302 delete m_attrProvider;
303 m_attrProvider = attrProvider;
304 }
305
306 wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col)
307 {
308 if ( m_attrProvider )
309 return m_attrProvider->GetAttr(row, col);
310 else
311 return (wxGridCellAttr *)NULL;
312 }
313
314 void wxGridTableBase::SetAttr(wxGridCellAttr *attr, int row, int col )
315 {
316 if ( m_attrProvider )
317 {
318 m_attrProvider->SetAttr(attr, row, col);
319 }
320 else
321 {
322 // as we take ownership of the pointer and don't store it, we must
323 // free it now
324 attr->SafeDecRef();
325 }
326 }
327
328 bool wxGridTableBase::InsertRows( size_t pos, size_t numRows )
329 {
330 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
331 "but your derived table class does not override this function") );
332
333 return FALSE;
334 }
335
336 bool wxGridTableBase::AppendRows( size_t numRows )
337 {
338 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
339 "but your derived table class does not override this function"));
340
341 return FALSE;
342 }
343
344 bool wxGridTableBase::DeleteRows( size_t pos, size_t numRows )
345 {
346 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
347 "but your derived table class does not override this function"));
348
349 return FALSE;
350 }
351
352 bool wxGridTableBase::InsertCols( size_t pos, size_t numCols )
353 {
354 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
355 "but your derived table class does not override this function"));
356
357 return FALSE;
358 }
359
360 bool wxGridTableBase::AppendCols( size_t numCols )
361 {
362 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
363 "but your derived table class does not override this function"));
364
365 return FALSE;
366 }
367
368 bool wxGridTableBase::DeleteCols( size_t pos, size_t numCols )
369 {
370 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
371 "but your derived table class does not override this function"));
372
373 return FALSE;
374 }
375
376
377 wxString wxGridTableBase::GetRowLabelValue( int row )
378 {
379 wxString s;
380 s << row;
381 return s;
382 }
383
384 wxString wxGridTableBase::GetColLabelValue( int col )
385 {
386 // default col labels are:
387 // cols 0 to 25 : A-Z
388 // cols 26 to 675 : AA-ZZ
389 // etc.
390
391 wxString s;
392 unsigned int i, n;
393 for ( n = 1; ; n++ )
394 {
395 s += (_T('A') + (wxChar)( col%26 ));
396 col = col/26 - 1;
397 if ( col < 0 ) break;
398 }
399
400 // reverse the string...
401 wxString s2;
402 for ( i = 0; i < n; i++ )
403 {
404 s2 += s[n-i-1];
405 }
406
407 return s2;
408 }
409
410
411
412 //////////////////////////////////////////////////////////////////////
413 //
414 // Message class for the grid table to send requests and notifications
415 // to the grid view
416 //
417
418 wxGridTableMessage::wxGridTableMessage()
419 {
420 m_table = (wxGridTableBase *) NULL;
421 m_id = -1;
422 m_comInt1 = -1;
423 m_comInt2 = -1;
424 }
425
426 wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
427 int commandInt1, int commandInt2 )
428 {
429 m_table = table;
430 m_id = id;
431 m_comInt1 = commandInt1;
432 m_comInt2 = commandInt2;
433 }
434
435
436
437 //////////////////////////////////////////////////////////////////////
438 //
439 // A basic grid table for string data. An object of this class will
440 // created by wxGrid if you don't specify an alternative table class.
441 //
442
443 WX_DEFINE_OBJARRAY(wxGridStringArray)
444
445 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
446
447 wxGridStringTable::wxGridStringTable()
448 : wxGridTableBase()
449 {
450 }
451
452 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
453 : wxGridTableBase()
454 {
455 int row, col;
456
457 m_data.Alloc( numRows );
458
459 wxArrayString sa;
460 sa.Alloc( numCols );
461 for ( col = 0; col < numCols; col++ )
462 {
463 sa.Add( wxEmptyString );
464 }
465
466 for ( row = 0; row < numRows; row++ )
467 {
468 m_data.Add( sa );
469 }
470 }
471
472 wxGridStringTable::~wxGridStringTable()
473 {
474 }
475
476 long wxGridStringTable::GetNumberRows()
477 {
478 return m_data.GetCount();
479 }
480
481 long wxGridStringTable::GetNumberCols()
482 {
483 if ( m_data.GetCount() > 0 )
484 return m_data[0].GetCount();
485 else
486 return 0;
487 }
488
489 wxString wxGridStringTable::GetValue( int row, int col )
490 {
491 // TODO: bounds checking
492 //
493 return m_data[row][col];
494 }
495
496 void wxGridStringTable::SetValue( int row, int col, const wxString& s )
497 {
498 // TODO: bounds checking
499 //
500 m_data[row][col] = s;
501 }
502
503 bool wxGridStringTable::IsEmptyCell( int row, int col )
504 {
505 // TODO: bounds checking
506 //
507 return (m_data[row][col] == wxEmptyString);
508 }
509
510
511 void wxGridStringTable::Clear()
512 {
513 int row, col;
514 int numRows, numCols;
515
516 numRows = m_data.GetCount();
517 if ( numRows > 0 )
518 {
519 numCols = m_data[0].GetCount();
520
521 for ( row = 0; row < numRows; row++ )
522 {
523 for ( col = 0; col < numCols; col++ )
524 {
525 m_data[row][col] = wxEmptyString;
526 }
527 }
528 }
529 }
530
531
532 bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
533 {
534 size_t row, col;
535
536 size_t curNumRows = m_data.GetCount();
537 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
538
539 if ( pos >= curNumRows )
540 {
541 return AppendRows( numRows );
542 }
543
544 wxArrayString sa;
545 sa.Alloc( curNumCols );
546 for ( col = 0; col < curNumCols; col++ )
547 {
548 sa.Add( wxEmptyString );
549 }
550
551 for ( row = pos; row < pos + numRows; row++ )
552 {
553 m_data.Insert( sa, row );
554 }
555
556 if ( GetView() )
557 {
558 wxGridTableMessage msg( this,
559 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
560 pos,
561 numRows );
562
563 GetView()->ProcessTableMessage( msg );
564 }
565
566 return TRUE;
567 }
568
569 bool wxGridStringTable::AppendRows( size_t numRows )
570 {
571 size_t row, col;
572
573 size_t curNumRows = m_data.GetCount();
574 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
575
576 wxArrayString sa;
577 if ( curNumCols > 0 )
578 {
579 sa.Alloc( curNumCols );
580 for ( col = 0; col < curNumCols; col++ )
581 {
582 sa.Add( wxEmptyString );
583 }
584 }
585
586 for ( row = 0; row < numRows; row++ )
587 {
588 m_data.Add( sa );
589 }
590
591 if ( GetView() )
592 {
593 wxGridTableMessage msg( this,
594 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
595 numRows );
596
597 GetView()->ProcessTableMessage( msg );
598 }
599
600 return TRUE;
601 }
602
603 bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
604 {
605 size_t n;
606
607 size_t curNumRows = m_data.GetCount();
608
609 if ( pos >= curNumRows )
610 {
611 wxString errmsg;
612 errmsg.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
613 "Pos value is invalid for present table with %d rows",
614 pos, numRows, curNumRows );
615 wxFAIL_MSG( wxT(errmsg) );
616 return FALSE;
617 }
618
619 if ( numRows > curNumRows - pos )
620 {
621 numRows = curNumRows - pos;
622 }
623
624 if ( numRows >= curNumRows )
625 {
626 m_data.Empty(); // don't release memory just yet
627 }
628 else
629 {
630 for ( n = 0; n < numRows; n++ )
631 {
632 m_data.Remove( pos );
633 }
634 }
635
636 if ( GetView() )
637 {
638 wxGridTableMessage msg( this,
639 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
640 pos,
641 numRows );
642
643 GetView()->ProcessTableMessage( msg );
644 }
645
646 return TRUE;
647 }
648
649 bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
650 {
651 size_t row, col;
652
653 size_t curNumRows = m_data.GetCount();
654 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
655
656 if ( pos >= curNumCols )
657 {
658 return AppendCols( numCols );
659 }
660
661 for ( row = 0; row < curNumRows; row++ )
662 {
663 for ( col = pos; col < pos + numCols; col++ )
664 {
665 m_data[row].Insert( wxEmptyString, col );
666 }
667 }
668
669 if ( GetView() )
670 {
671 wxGridTableMessage msg( this,
672 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
673 pos,
674 numCols );
675
676 GetView()->ProcessTableMessage( msg );
677 }
678
679 return TRUE;
680 }
681
682 bool wxGridStringTable::AppendCols( size_t numCols )
683 {
684 size_t row, n;
685
686 size_t curNumRows = m_data.GetCount();
687 if ( !curNumRows )
688 {
689 // TODO: something better than this ?
690 //
691 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
692 "Call AppendRows() first") );
693 return FALSE;
694 }
695
696 for ( row = 0; row < curNumRows; row++ )
697 {
698 for ( n = 0; n < numCols; n++ )
699 {
700 m_data[row].Add( wxEmptyString );
701 }
702 }
703
704 if ( GetView() )
705 {
706 wxGridTableMessage msg( this,
707 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
708 numCols );
709
710 GetView()->ProcessTableMessage( msg );
711 }
712
713 return TRUE;
714 }
715
716 bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
717 {
718 size_t row, n;
719
720 size_t curNumRows = m_data.GetCount();
721 size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() : 0 );
722
723 if ( pos >= curNumCols )
724 {
725 wxString errmsg;
726 errmsg.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
727 "Pos value is invalid for present table with %d cols",
728 pos, numCols, curNumCols );
729 wxFAIL_MSG( wxT( errmsg ) );
730 return FALSE;
731 }
732
733 if ( numCols > curNumCols - pos )
734 {
735 numCols = curNumCols - pos;
736 }
737
738 for ( row = 0; row < curNumRows; row++ )
739 {
740 if ( numCols >= curNumCols )
741 {
742 m_data[row].Clear();
743 }
744 else
745 {
746 for ( n = 0; n < numCols; n++ )
747 {
748 m_data[row].Remove( pos );
749 }
750 }
751 }
752
753 if ( GetView() )
754 {
755 wxGridTableMessage msg( this,
756 wxGRIDTABLE_NOTIFY_COLS_DELETED,
757 pos,
758 numCols );
759
760 GetView()->ProcessTableMessage( msg );
761 }
762
763 return TRUE;
764 }
765
766 wxString wxGridStringTable::GetRowLabelValue( int row )
767 {
768 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
769 {
770 // using default label
771 //
772 return wxGridTableBase::GetRowLabelValue( row );
773 }
774 else
775 {
776 return m_rowLabels[ row ];
777 }
778 }
779
780 wxString wxGridStringTable::GetColLabelValue( int col )
781 {
782 if ( col > (int)(m_colLabels.GetCount()) - 1 )
783 {
784 // using default label
785 //
786 return wxGridTableBase::GetColLabelValue( col );
787 }
788 else
789 {
790 return m_colLabels[ col ];
791 }
792 }
793
794 void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
795 {
796 if ( row > (int)(m_rowLabels.GetCount()) - 1 )
797 {
798 int n = m_rowLabels.GetCount();
799 int i;
800 for ( i = n; i <= row; i++ )
801 {
802 m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
803 }
804 }
805
806 m_rowLabels[row] = value;
807 }
808
809 void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
810 {
811 if ( col > (int)(m_colLabels.GetCount()) - 1 )
812 {
813 int n = m_colLabels.GetCount();
814 int i;
815 for ( i = n; i <= col; i++ )
816 {
817 m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
818 }
819 }
820
821 m_colLabels[col] = value;
822 }
823
824
825
826
827 //////////////////////////////////////////////////////////////////////
828
829 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl, wxTextCtrl )
830
831 BEGIN_EVENT_TABLE( wxGridTextCtrl, wxTextCtrl )
832 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown )
833 END_EVENT_TABLE()
834
835
836 wxGridTextCtrl::wxGridTextCtrl( wxWindow *par,
837 wxGrid *grid,
838 bool isCellControl,
839 wxWindowID id,
840 const wxString& value,
841 const wxPoint& pos,
842 const wxSize& size,
843 long style )
844 : wxTextCtrl( par, id, value, pos, size, style )
845 {
846 m_grid = grid;
847 m_isCellControl = isCellControl;
848 }
849
850
851 void wxGridTextCtrl::OnKeyDown( wxKeyEvent& event )
852 {
853 switch ( event.KeyCode() )
854 {
855 case WXK_ESCAPE:
856 m_grid->SetEditControlValue( startValue );
857 SetInsertionPointEnd();
858 break;
859
860 case WXK_UP:
861 case WXK_DOWN:
862 case WXK_LEFT:
863 case WXK_RIGHT:
864 case WXK_PRIOR:
865 case WXK_NEXT:
866 case WXK_SPACE:
867 if ( m_isCellControl )
868 {
869 // send the event to the parent grid, skipping the
870 // event if nothing happens
871 //
872 event.Skip( m_grid->ProcessEvent( event ) );
873 }
874 else
875 {
876 // default text control response within the top edit
877 // control
878 //
879 event.Skip();
880 }
881 break;
882
883 case WXK_RETURN:
884 if ( m_isCellControl )
885 {
886 if ( !m_grid->ProcessEvent( event ) )
887 {
888 #if defined(__WXMOTIF__) || defined(__WXGTK__)
889 // wxMotif needs a little extra help...
890 //
891 int pos = GetInsertionPoint();
892 wxString s( GetValue() );
893 s = s.Left(pos) + "\n" + s.Mid(pos);
894 SetValue(s);
895 SetInsertionPoint( pos );
896 #else
897 // the other ports can handle a Return key press
898 //
899 event.Skip();
900 #endif
901 }
902 }
903 break;
904
905 case WXK_HOME:
906 case WXK_END:
907 if ( m_isCellControl )
908 {
909 // send the event to the parent grid, skipping the
910 // event if nothing happens
911 //
912 event.Skip( m_grid->ProcessEvent( event ) );
913 }
914 else
915 {
916 // default text control response within the top edit
917 // control
918 //
919 event.Skip();
920 }
921 break;
922
923 default:
924 event.Skip();
925 }
926 }
927
928 void wxGridTextCtrl::SetStartValue( const wxString& s )
929 {
930 startValue = s;
931 wxTextCtrl::SetValue(s);
932 }
933
934
935
936 //////////////////////////////////////////////////////////////////////
937
938 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
939
940 BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
941 EVT_PAINT( wxGridRowLabelWindow::OnPaint )
942 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
943 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
944 END_EVENT_TABLE()
945
946 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
947 wxWindowID id,
948 const wxPoint &pos, const wxSize &size )
949 : wxWindow( parent, id, pos, size )
950 {
951 m_owner = parent;
952 }
953
954 void wxGridRowLabelWindow::OnPaint( wxPaintEvent &event )
955 {
956 wxPaintDC dc(this);
957
958 // NO - don't do this because it will set both the x and y origin
959 // coords to match the parent scrolled window and we just want to
960 // set the y coord - MB
961 //
962 // m_owner->PrepareDC( dc );
963
964 int x, y;
965 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
966 dc.SetDeviceOrigin( 0, -y );
967
968 m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
969 m_owner->DrawRowLabels( dc );
970 }
971
972
973 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
974 {
975 m_owner->ProcessRowLabelMouseEvent( event );
976 }
977
978
979 // This seems to be required for wxMotif otherwise the mouse
980 // cursor must be in the cell edit control to get key events
981 //
982 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
983 {
984 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
985 }
986
987
988
989 //////////////////////////////////////////////////////////////////////
990
991 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
992
993 BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
994 EVT_PAINT( wxGridColLabelWindow::OnPaint )
995 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
996 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
997 END_EVENT_TABLE()
998
999 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
1000 wxWindowID id,
1001 const wxPoint &pos, const wxSize &size )
1002 : wxWindow( parent, id, pos, size )
1003 {
1004 m_owner = parent;
1005 }
1006
1007 void wxGridColLabelWindow::OnPaint( wxPaintEvent &event )
1008 {
1009 wxPaintDC dc(this);
1010
1011 // NO - don't do this because it will set both the x and y origin
1012 // coords to match the parent scrolled window and we just want to
1013 // set the x coord - MB
1014 //
1015 // m_owner->PrepareDC( dc );
1016
1017 int x, y;
1018 m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
1019 dc.SetDeviceOrigin( -x, 0 );
1020
1021 m_owner->CalcColLabelsExposed( GetUpdateRegion() );
1022 m_owner->DrawColLabels( dc );
1023 }
1024
1025
1026 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
1027 {
1028 m_owner->ProcessColLabelMouseEvent( event );
1029 }
1030
1031
1032 // This seems to be required for wxMotif otherwise the mouse
1033 // cursor must be in the cell edit control to get key events
1034 //
1035 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
1036 {
1037 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1038 }
1039
1040
1041
1042 //////////////////////////////////////////////////////////////////////
1043
1044 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
1045
1046 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
1047 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
1048 EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
1049 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
1050 END_EVENT_TABLE()
1051
1052 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
1053 wxWindowID id,
1054 const wxPoint &pos, const wxSize &size )
1055 : wxWindow( parent, id, pos, size )
1056 {
1057 m_owner = parent;
1058 }
1059
1060 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
1061 {
1062 wxPaintDC dc(this);
1063
1064 int client_height = 0;
1065 int client_width = 0;
1066 GetClientSize( &client_width, &client_height );
1067
1068 dc.SetPen( *wxBLACK_PEN );
1069 dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
1070 dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
1071
1072 dc.SetPen( *wxWHITE_PEN );
1073 dc.DrawLine( 0, 0, client_width, 0 );
1074 dc.DrawLine( 0, 0, 0, client_height );
1075 }
1076
1077
1078 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
1079 {
1080 m_owner->ProcessCornerLabelMouseEvent( event );
1081 }
1082
1083
1084 // This seems to be required for wxMotif otherwise the mouse
1085 // cursor must be in the cell edit control to get key events
1086 //
1087 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
1088 {
1089 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1090 }
1091
1092
1093
1094 //////////////////////////////////////////////////////////////////////
1095
1096 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxPanel )
1097
1098 BEGIN_EVENT_TABLE( wxGridWindow, wxPanel )
1099 EVT_PAINT( wxGridWindow::OnPaint )
1100 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
1101 EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
1102 END_EVENT_TABLE()
1103
1104 wxGridWindow::wxGridWindow( wxGrid *parent,
1105 wxGridRowLabelWindow *rowLblWin,
1106 wxGridColLabelWindow *colLblWin,
1107 wxWindowID id, const wxPoint &pos, const wxSize &size )
1108 : wxPanel( parent, id, pos, size, 0, "grid window" )
1109 {
1110 m_owner = parent;
1111 m_rowLabelWin = rowLblWin;
1112 m_colLabelWin = colLblWin;
1113
1114 SetBackgroundColour( "WHITE" );
1115 }
1116
1117
1118 wxGridWindow::~wxGridWindow()
1119 {
1120 }
1121
1122
1123 void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1124 {
1125 wxPaintDC dc( this );
1126 m_owner->PrepareDC( dc );
1127 wxRegion reg = GetUpdateRegion();
1128 m_owner->CalcCellsExposed( reg );
1129 m_owner->DrawGridCellArea( dc );
1130 #if WXGRID_DRAW_LINES
1131 m_owner->DrawAllGridLines( dc, reg );
1132 #endif
1133 }
1134
1135
1136 void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
1137 {
1138 wxPanel::ScrollWindow( dx, dy, rect );
1139 m_rowLabelWin->ScrollWindow( 0, dy, rect );
1140 m_colLabelWin->ScrollWindow( dx, 0, rect );
1141 }
1142
1143
1144 void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
1145 {
1146 m_owner->ProcessGridCellMouseEvent( event );
1147 }
1148
1149
1150 // This seems to be required for wxMotif otherwise the mouse
1151 // cursor must be in the cell edit control to get key events
1152 //
1153 void wxGridWindow::OnKeyDown( wxKeyEvent& event )
1154 {
1155 if ( !m_owner->ProcessEvent( event ) ) event.Skip();
1156 }
1157
1158
1159
1160 //////////////////////////////////////////////////////////////////////
1161
1162 IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
1163
1164 BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
1165 EVT_PAINT( wxGrid::OnPaint )
1166 EVT_SIZE( wxGrid::OnSize )
1167 EVT_KEY_DOWN( wxGrid::OnKeyDown )
1168 END_EVENT_TABLE()
1169
1170 wxGrid::wxGrid( wxWindow *parent,
1171 wxWindowID id,
1172 const wxPoint& pos,
1173 const wxSize& size,
1174 long style,
1175 const wxString& name )
1176 : wxScrolledWindow( parent, id, pos, size, style, name )
1177 {
1178 Create();
1179 }
1180
1181
1182 wxGrid::~wxGrid()
1183 {
1184 delete m_table;
1185 }
1186
1187
1188 //
1189 // ----- internal init and update functions
1190 //
1191
1192 void wxGrid::Create()
1193 {
1194 m_created = FALSE; // set to TRUE by CreateGrid
1195 m_displayed = FALSE; // set to TRUE by OnPaint
1196
1197 m_table = (wxGridTableBase *) NULL;
1198 m_cellEditCtrl = (wxWindow *) NULL;
1199
1200 m_numRows = 0;
1201 m_numCols = 0;
1202 m_currentCellCoords = wxGridNoCellCoords;
1203
1204 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1205 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1206
1207 m_cornerLabelWin = new wxGridCornerLabelWindow( this,
1208 -1,
1209 wxDefaultPosition,
1210 wxDefaultSize );
1211
1212 m_rowLabelWin = new wxGridRowLabelWindow( this,
1213 -1,
1214 wxDefaultPosition,
1215 wxDefaultSize );
1216
1217 m_colLabelWin = new wxGridColLabelWindow( this,
1218 -1,
1219 wxDefaultPosition,
1220 wxDefaultSize );
1221
1222 m_gridWin = new wxGridWindow( this,
1223 m_rowLabelWin,
1224 m_colLabelWin,
1225 -1,
1226 wxDefaultPosition,
1227 wxDefaultSize );
1228
1229 SetTargetWindow( m_gridWin );
1230 }
1231
1232
1233 bool wxGrid::CreateGrid( int numRows, int numCols )
1234 {
1235 if ( m_created )
1236 {
1237 wxFAIL_MSG( wxT("wxGrid::CreateGrid called more than once") );
1238 return FALSE;
1239 }
1240 else
1241 {
1242 m_numRows = numRows;
1243 m_numCols = numCols;
1244
1245 m_table = new wxGridStringTable( m_numRows, m_numCols );
1246 m_table->SetView( this );
1247 Init();
1248 m_created = TRUE;
1249 }
1250
1251 return m_created;
1252 }
1253
1254
1255 void wxGrid::Init()
1256 {
1257 int i;
1258
1259 if ( m_numRows <= 0 )
1260 m_numRows = WXGRID_DEFAULT_NUMBER_ROWS;
1261
1262 if ( m_numCols <= 0 )
1263 m_numCols = WXGRID_DEFAULT_NUMBER_COLS;
1264
1265 m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
1266 m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
1267
1268 if ( m_rowLabelWin )
1269 {
1270 m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
1271 }
1272 else
1273 {
1274 m_labelBackgroundColour = wxColour( _T("WHITE") );
1275 }
1276
1277 m_labelTextColour = wxColour( _T("BLACK") );
1278
1279 // TODO: something better than this ?
1280 //
1281 m_labelFont = this->GetFont();
1282 m_labelFont.SetWeight( m_labelFont.GetWeight() + 2 );
1283
1284 m_rowLabelHorizAlign = wxLEFT;
1285 m_rowLabelVertAlign = wxCENTRE;
1286
1287 m_colLabelHorizAlign = wxCENTRE;
1288 m_colLabelVertAlign = wxTOP;
1289
1290 m_defaultColWidth = WXGRID_DEFAULT_COL_WIDTH;
1291 m_defaultRowHeight = m_gridWin->GetCharHeight();
1292
1293 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1294 m_defaultRowHeight += 8;
1295 #else
1296 m_defaultRowHeight += 4;
1297 #endif
1298
1299 m_rowHeights.Alloc( m_numRows );
1300 m_rowBottoms.Alloc( m_numRows );
1301 int rowBottom = 0;
1302 for ( i = 0; i < m_numRows; i++ )
1303 {
1304 m_rowHeights.Add( m_defaultRowHeight );
1305 rowBottom += m_defaultRowHeight;
1306 m_rowBottoms.Add( rowBottom );
1307 }
1308
1309 m_colWidths.Alloc( m_numCols );
1310 m_colRights.Alloc( m_numCols );
1311 int colRight = 0;
1312 for ( i = 0; i < m_numCols; i++ )
1313 {
1314 m_colWidths.Add( m_defaultColWidth );
1315 colRight += m_defaultColWidth;
1316 m_colRights.Add( colRight );
1317 }
1318
1319 // TODO: improve this by using wxSystemSettings?
1320 //
1321 m_defaultCellFont = GetFont();
1322
1323 m_defaultCellHAlign = wxLEFT;
1324 m_defaultCellVAlign = wxTOP;
1325
1326 m_gridLineColour = wxColour( 128, 128, 255 );
1327 m_gridLinesEnabled = TRUE;
1328
1329 m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
1330 m_winCapture = (wxWindow *)NULL;
1331 m_dragLastPos = -1;
1332 m_dragRowOrCol = -1;
1333 m_isDragging = FALSE;
1334
1335 m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
1336 m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
1337
1338 m_currentCellCoords = wxGridNoCellCoords;
1339
1340 m_selectedTopLeft = wxGridNoCellCoords;
1341 m_selectedBottomRight = wxGridNoCellCoords;
1342
1343 m_editable = TRUE; // default for whole grid
1344
1345 m_inOnKeyDown = FALSE;
1346 m_batchCount = 0;
1347
1348 // TODO: extend this to other types of controls
1349 //
1350 m_cellEditCtrl = new wxGridTextCtrl( m_gridWin,
1351 this,
1352 TRUE,
1353 wxGRID_CELLCTRL,
1354 "",
1355 wxPoint(1,1),
1356 wxSize(1,1)
1357 #if defined(__WXMSW__)
1358 , wxTE_MULTILINE | wxTE_NO_VSCROLL
1359 #endif
1360 );
1361
1362 m_cellEditCtrl->Show( FALSE );
1363 m_cellEditCtrlEnabled = TRUE;
1364 m_editCtrlType = wxGRID_TEXTCTRL;
1365 }
1366
1367
1368 void wxGrid::CalcDimensions()
1369 {
1370 int cw, ch;
1371 GetClientSize( &cw, &ch );
1372
1373 if ( m_numRows > 0 && m_numCols > 0 )
1374 {
1375 int right = m_colRights[ m_numCols-1 ] + 50;
1376 int bottom = m_rowBottoms[ m_numRows-1 ] + 50;
1377
1378 // TODO: restore the scroll position that we had before sizing
1379 //
1380 int x, y;
1381 GetViewStart( &x, &y );
1382 SetScrollbars( GRID_SCROLL_LINE, GRID_SCROLL_LINE,
1383 right/GRID_SCROLL_LINE, bottom/GRID_SCROLL_LINE,
1384 x, y );
1385 }
1386 }
1387
1388
1389 void wxGrid::CalcWindowSizes()
1390 {
1391 int cw, ch;
1392 GetClientSize( &cw, &ch );
1393
1394 if ( m_cornerLabelWin->IsShown() )
1395 m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
1396
1397 if ( m_colLabelWin->IsShown() )
1398 m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
1399
1400 if ( m_rowLabelWin->IsShown() )
1401 m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
1402
1403 if ( m_gridWin->IsShown() )
1404 m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
1405 }
1406
1407
1408 // this is called when the grid table sends a message to say that it
1409 // has been redimensioned
1410 //
1411 bool wxGrid::Redimension( wxGridTableMessage& msg )
1412 {
1413 int i;
1414
1415 switch ( msg.GetId() )
1416 {
1417 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
1418 {
1419 size_t pos = msg.GetCommandInt();
1420 int numRows = msg.GetCommandInt2();
1421 for ( i = 0; i < numRows; i++ )
1422 {
1423 m_rowHeights.Insert( m_defaultRowHeight, pos );
1424 m_rowBottoms.Insert( 0, pos );
1425 }
1426 m_numRows += numRows;
1427
1428 int bottom = 0;
1429 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
1430
1431 for ( i = pos; i < m_numRows; i++ )
1432 {
1433 bottom += m_rowHeights[i];
1434 m_rowBottoms[i] = bottom;
1435 }
1436 CalcDimensions();
1437 }
1438 return TRUE;
1439
1440 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
1441 {
1442 int numRows = msg.GetCommandInt();
1443 for ( i = 0; i < numRows; i++ )
1444 {
1445 m_rowHeights.Add( m_defaultRowHeight );
1446 m_rowBottoms.Add( 0 );
1447 }
1448
1449 int oldNumRows = m_numRows;
1450 m_numRows += numRows;
1451
1452 int bottom = 0;
1453 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
1454
1455 for ( i = oldNumRows; i < m_numRows; i++ )
1456 {
1457 bottom += m_rowHeights[i];
1458 m_rowBottoms[i] = bottom;
1459 }
1460 CalcDimensions();
1461 }
1462 return TRUE;
1463
1464 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
1465 {
1466 size_t pos = msg.GetCommandInt();
1467 int numRows = msg.GetCommandInt2();
1468 for ( i = 0; i < numRows; i++ )
1469 {
1470 m_rowHeights.Remove( pos );
1471 m_rowBottoms.Remove( pos );
1472 }
1473 m_numRows -= numRows;
1474
1475 if ( !m_numRows )
1476 {
1477 m_numCols = 0;
1478 m_colWidths.Clear();
1479 m_colRights.Clear();
1480 m_currentCellCoords = wxGridNoCellCoords;
1481 }
1482 else
1483 {
1484 if ( m_currentCellCoords.GetRow() >= m_numRows )
1485 m_currentCellCoords.Set( 0, 0 );
1486
1487 int h = 0;
1488 for ( i = 0; i < m_numRows; i++ )
1489 {
1490 h += m_rowHeights[i];
1491 m_rowBottoms[i] = h;
1492 }
1493 }
1494
1495 CalcDimensions();
1496 }
1497 return TRUE;
1498
1499 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
1500 {
1501 size_t pos = msg.GetCommandInt();
1502 int numCols = msg.GetCommandInt2();
1503 for ( i = 0; i < numCols; i++ )
1504 {
1505 m_colWidths.Insert( m_defaultColWidth, pos );
1506 m_colRights.Insert( 0, pos );
1507 }
1508 m_numCols += numCols;
1509
1510 int right = 0;
1511 if ( pos > 0 ) right = m_colRights[pos-1];
1512
1513 for ( i = pos; i < m_numCols; i++ )
1514 {
1515 right += m_colWidths[i];
1516 m_colRights[i] = right;
1517 }
1518 CalcDimensions();
1519 }
1520 return TRUE;
1521
1522 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
1523 {
1524 int numCols = msg.GetCommandInt();
1525 for ( i = 0; i < numCols; i++ )
1526 {
1527 m_colWidths.Add( m_defaultColWidth );
1528 m_colRights.Add( 0 );
1529 }
1530
1531 int oldNumCols = m_numCols;
1532 m_numCols += numCols;
1533
1534 int right = 0;
1535 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
1536
1537 for ( i = oldNumCols; i < m_numCols; i++ )
1538 {
1539 right += m_colWidths[i];
1540 m_colRights[i] = right;
1541 }
1542 CalcDimensions();
1543 }
1544 return TRUE;
1545
1546 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
1547 {
1548 size_t pos = msg.GetCommandInt();
1549 int numCols = msg.GetCommandInt2();
1550 for ( i = 0; i < numCols; i++ )
1551 {
1552 m_colWidths.Remove( pos );
1553 m_colRights.Remove( pos );
1554 }
1555 m_numCols -= numCols;
1556
1557 if ( !m_numCols )
1558 {
1559 #if 0 // leave the row alone here so that AppendCols will work subsequently
1560 m_numRows = 0;
1561 m_rowHeights.Clear();
1562 m_rowBottoms.Clear();
1563 #endif
1564 m_currentCellCoords = wxGridNoCellCoords;
1565 }
1566 else
1567 {
1568 if ( m_currentCellCoords.GetCol() >= m_numCols )
1569 m_currentCellCoords.Set( 0, 0 );
1570
1571 int w = 0;
1572 for ( i = 0; i < m_numCols; i++ )
1573 {
1574 w += m_colWidths[i];
1575 m_colRights[i] = w;
1576 }
1577 }
1578 CalcDimensions();
1579 }
1580 return TRUE;
1581 }
1582
1583 return FALSE;
1584 }
1585
1586
1587 void wxGrid::CalcRowLabelsExposed( wxRegion& reg )
1588 {
1589 wxRegionIterator iter( reg );
1590 wxRect r;
1591
1592 m_rowLabelsExposed.Empty();
1593
1594 int top, bottom;
1595 while ( iter )
1596 {
1597 r = iter.GetRect();
1598
1599 // TODO: remove this when we can...
1600 // There is a bug in wxMotif that gives garbage update
1601 // rectangles if you jump-scroll a long way by clicking the
1602 // scrollbar with middle button. This is a work-around
1603 //
1604 #if defined(__WXMOTIF__)
1605 int cw, ch;
1606 m_gridWin->GetClientSize( &cw, &ch );
1607 if ( r.GetTop() > ch ) r.SetTop( 0 );
1608 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1609 #endif
1610
1611 // logical bounds of update region
1612 //
1613 int dummy;
1614 CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
1615 CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
1616
1617 // find the row labels within these bounds
1618 //
1619 int row;
1620 int rowTop;
1621 for ( row = 0; row < m_numRows; row++ )
1622 {
1623 if ( m_rowBottoms[row] < top ) continue;
1624
1625 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1626 if ( rowTop > bottom ) break;
1627
1628 m_rowLabelsExposed.Add( row );
1629 }
1630
1631 iter++ ;
1632 }
1633 }
1634
1635
1636 void wxGrid::CalcColLabelsExposed( wxRegion& reg )
1637 {
1638 wxRegionIterator iter( reg );
1639 wxRect r;
1640
1641 m_colLabelsExposed.Empty();
1642
1643 int left, right;
1644 while ( iter )
1645 {
1646 r = iter.GetRect();
1647
1648 // TODO: remove this when we can...
1649 // There is a bug in wxMotif that gives garbage update
1650 // rectangles if you jump-scroll a long way by clicking the
1651 // scrollbar with middle button. This is a work-around
1652 //
1653 #if defined(__WXMOTIF__)
1654 int cw, ch;
1655 m_gridWin->GetClientSize( &cw, &ch );
1656 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1657 r.SetRight( wxMin( r.GetRight(), cw ) );
1658 #endif
1659
1660 // logical bounds of update region
1661 //
1662 int dummy;
1663 CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
1664 CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
1665
1666 // find the cells within these bounds
1667 //
1668 int col;
1669 int colLeft;
1670 for ( col = 0; col < m_numCols; col++ )
1671 {
1672 if ( m_colRights[col] < left ) continue;
1673
1674 colLeft = m_colRights[col] - m_colWidths[col];
1675 if ( colLeft > right ) break;
1676
1677 m_colLabelsExposed.Add( col );
1678 }
1679
1680 iter++ ;
1681 }
1682 }
1683
1684
1685 void wxGrid::CalcCellsExposed( wxRegion& reg )
1686 {
1687 wxRegionIterator iter( reg );
1688 wxRect r;
1689
1690 m_cellsExposed.Empty();
1691 m_rowsExposed.Empty();
1692 m_colsExposed.Empty();
1693
1694 int left, top, right, bottom;
1695 while ( iter )
1696 {
1697 r = iter.GetRect();
1698
1699 // TODO: remove this when we can...
1700 // There is a bug in wxMotif that gives garbage update
1701 // rectangles if you jump-scroll a long way by clicking the
1702 // scrollbar with middle button. This is a work-around
1703 //
1704 #if defined(__WXMOTIF__)
1705 int cw, ch;
1706 m_gridWin->GetClientSize( &cw, &ch );
1707 if ( r.GetTop() > ch ) r.SetTop( 0 );
1708 if ( r.GetLeft() > cw ) r.SetLeft( 0 );
1709 r.SetRight( wxMin( r.GetRight(), cw ) );
1710 r.SetBottom( wxMin( r.GetBottom(), ch ) );
1711 #endif
1712
1713 // logical bounds of update region
1714 //
1715 CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
1716 CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
1717
1718 // find the cells within these bounds
1719 //
1720 int row, col;
1721 int colLeft, rowTop;
1722 for ( row = 0; row < m_numRows; row++ )
1723 {
1724 if ( m_rowBottoms[row] < top ) continue;
1725
1726 rowTop = m_rowBottoms[row] - m_rowHeights[row];
1727 if ( rowTop > bottom ) break;
1728
1729 m_rowsExposed.Add( row );
1730
1731 for ( col = 0; col < m_numCols; col++ )
1732 {
1733 if ( m_colRights[col] < left ) continue;
1734
1735 colLeft = m_colRights[col] - m_colWidths[col];
1736 if ( colLeft > right ) break;
1737
1738 if ( m_colsExposed.Index( col ) == wxNOT_FOUND ) m_colsExposed.Add( col );
1739 m_cellsExposed.Add( wxGridCellCoords( row, col ) );
1740 }
1741 }
1742
1743 iter++ ;
1744 }
1745 }
1746
1747
1748 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
1749 {
1750 int x, y, row;
1751 wxPoint pos( event.GetPosition() );
1752 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1753
1754 if ( event.Dragging() )
1755 {
1756 m_isDragging = TRUE;
1757
1758 if ( event.LeftIsDown() )
1759 {
1760 switch( m_cursorMode )
1761 {
1762 case WXGRID_CURSOR_RESIZE_ROW:
1763 {
1764 int cw, ch, left, dummy;
1765 m_gridWin->GetClientSize( &cw, &ch );
1766 CalcUnscrolledPosition( 0, 0, &left, &dummy );
1767
1768 wxClientDC dc( m_gridWin );
1769 PrepareDC( dc );
1770 dc.SetLogicalFunction(wxINVERT);
1771 if ( m_dragLastPos >= 0 )
1772 {
1773 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
1774 }
1775 dc.DrawLine( left, y, left+cw, y );
1776 m_dragLastPos = y;
1777 }
1778 break;
1779
1780 case WXGRID_CURSOR_SELECT_ROW:
1781 if ( (row = YToRow( y )) >= 0 &&
1782 !IsInSelection( row, 0 ) )
1783 {
1784 SelectRow( row, TRUE );
1785 }
1786
1787 // default label to suppress warnings about "enumeration value
1788 // 'xxx' not handled in switch
1789 default:
1790 break;
1791 }
1792 }
1793 return;
1794 }
1795
1796 m_isDragging = FALSE;
1797
1798
1799 // ------------ Entering or leaving the window
1800 //
1801 if ( event.Entering() || event.Leaving() )
1802 {
1803 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
1804 }
1805
1806
1807 // ------------ Left button pressed
1808 //
1809 else if ( event.LeftDown() )
1810 {
1811 // don't send a label click event for a hit on the
1812 // edge of the row label - this is probably the user
1813 // wanting to resize the row
1814 //
1815 if ( YToEdgeOfRow(y) < 0 )
1816 {
1817 row = YToRow(y);
1818 if ( row >= 0 &&
1819 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
1820 {
1821 SelectRow( row, event.ShiftDown() );
1822 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
1823 }
1824 }
1825 else
1826 {
1827 // starting to drag-resize a row
1828 //
1829 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
1830 }
1831 }
1832
1833
1834 // ------------ Left double click
1835 //
1836 else if (event.LeftDClick() )
1837 {
1838 if ( YToEdgeOfRow(y) < 0 )
1839 {
1840 row = YToRow(y);
1841 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
1842 }
1843 }
1844
1845
1846 // ------------ Left button released
1847 //
1848 else if ( event.LeftUp() )
1849 {
1850 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
1851 {
1852 DoEndDragResizeRow();
1853
1854 // Note: we are ending the event *after* doing
1855 // default processing in this case
1856 //
1857 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
1858 }
1859
1860 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
1861 m_dragLastPos = -1;
1862 }
1863
1864
1865 // ------------ Right button down
1866 //
1867 else if ( event.RightDown() )
1868 {
1869 row = YToRow(y);
1870 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
1871 {
1872 // no default action at the moment
1873 }
1874 }
1875
1876
1877 // ------------ Right double click
1878 //
1879 else if ( event.RightDClick() )
1880 {
1881 row = YToRow(y);
1882 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
1883 {
1884 // no default action at the moment
1885 }
1886 }
1887
1888
1889 // ------------ No buttons down and mouse moving
1890 //
1891 else if ( event.Moving() )
1892 {
1893 m_dragRowOrCol = YToEdgeOfRow( y );
1894 if ( m_dragRowOrCol >= 0 )
1895 {
1896 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
1897 {
1898 // don't capture the mouse yet
1899 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
1900 }
1901 }
1902 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
1903 {
1904 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
1905 }
1906 }
1907 }
1908
1909
1910 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
1911 {
1912 int x, y, col;
1913 wxPoint pos( event.GetPosition() );
1914 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
1915
1916 if ( event.Dragging() )
1917 {
1918 m_isDragging = TRUE;
1919
1920 if ( event.LeftIsDown() )
1921 {
1922 switch( m_cursorMode )
1923 {
1924 case WXGRID_CURSOR_RESIZE_COL:
1925 {
1926 int cw, ch, dummy, top;
1927 m_gridWin->GetClientSize( &cw, &ch );
1928 CalcUnscrolledPosition( 0, 0, &dummy, &top );
1929
1930 wxClientDC dc( m_gridWin );
1931 PrepareDC( dc );
1932 dc.SetLogicalFunction(wxINVERT);
1933 if ( m_dragLastPos >= 0 )
1934 {
1935 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
1936 }
1937 dc.DrawLine( x, top, x, top+ch );
1938 m_dragLastPos = x;
1939 }
1940 break;
1941
1942 case WXGRID_CURSOR_SELECT_COL:
1943 if ( (col = XToCol( x )) >= 0 &&
1944 !IsInSelection( 0, col ) )
1945 {
1946 SelectCol( col, TRUE );
1947 }
1948
1949 // default label to suppress warnings about "enumeration value
1950 // 'xxx' not handled in switch
1951 default:
1952 break;
1953 }
1954 }
1955 return;
1956 }
1957
1958 m_isDragging = FALSE;
1959
1960
1961 // ------------ Entering or leaving the window
1962 //
1963 if ( event.Entering() || event.Leaving() )
1964 {
1965 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
1966 }
1967
1968
1969 // ------------ Left button pressed
1970 //
1971 else if ( event.LeftDown() )
1972 {
1973 // don't send a label click event for a hit on the
1974 // edge of the col label - this is probably the user
1975 // wanting to resize the col
1976 //
1977 if ( XToEdgeOfCol(x) < 0 )
1978 {
1979 col = XToCol(x);
1980 if ( col >= 0 &&
1981 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
1982 {
1983 SelectCol( col, event.ShiftDown() );
1984 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
1985 }
1986 }
1987 else
1988 {
1989 // starting to drag-resize a col
1990 //
1991 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
1992 }
1993 }
1994
1995
1996 // ------------ Left double click
1997 //
1998 if ( event.LeftDClick() )
1999 {
2000 if ( XToEdgeOfCol(x) < 0 )
2001 {
2002 col = XToCol(x);
2003 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
2004 }
2005 }
2006
2007
2008 // ------------ Left button released
2009 //
2010 else if ( event.LeftUp() )
2011 {
2012 if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2013 {
2014 DoEndDragResizeCol();
2015
2016 // Note: we are ending the event *after* doing
2017 // default processing in this case
2018 //
2019 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2020 }
2021
2022 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
2023 m_dragLastPos = -1;
2024 }
2025
2026
2027 // ------------ Right button down
2028 //
2029 else if ( event.RightDown() )
2030 {
2031 col = XToCol(x);
2032 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
2033 {
2034 // no default action at the moment
2035 }
2036 }
2037
2038
2039 // ------------ Right double click
2040 //
2041 else if ( event.RightDClick() )
2042 {
2043 col = XToCol(x);
2044 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
2045 {
2046 // no default action at the moment
2047 }
2048 }
2049
2050
2051 // ------------ No buttons down and mouse moving
2052 //
2053 else if ( event.Moving() )
2054 {
2055 m_dragRowOrCol = XToEdgeOfCol( x );
2056 if ( m_dragRowOrCol >= 0 )
2057 {
2058 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2059 {
2060 // don't capture the cursor yet
2061 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
2062 }
2063 }
2064 else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2065 {
2066 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
2067 }
2068 }
2069 }
2070
2071
2072 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
2073 {
2074 if ( event.LeftDown() )
2075 {
2076 // indicate corner label by having both row and
2077 // col args == -1
2078 //
2079 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
2080 {
2081 SelectAll();
2082 }
2083 }
2084
2085 else if ( event.LeftDClick() )
2086 {
2087 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
2088 }
2089
2090 else if ( event.RightDown() )
2091 {
2092 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
2093 {
2094 // no default action at the moment
2095 }
2096 }
2097
2098 else if ( event.RightDClick() )
2099 {
2100 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
2101 {
2102 // no default action at the moment
2103 }
2104 }
2105 }
2106
2107 void wxGrid::ChangeCursorMode(CursorMode mode,
2108 wxWindow *win,
2109 bool captureMouse)
2110 {
2111 #ifdef __WXDEBUG__
2112 static const wxChar *cursorModes[] =
2113 {
2114 _T("SELECT_CELL"),
2115 _T("RESIZE_ROW"),
2116 _T("RESIZE_COL"),
2117 _T("SELECT_ROW"),
2118 _T("SELECT_COL")
2119 };
2120
2121 wxLogTrace(_T("grid"),
2122 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
2123 win == m_colLabelWin ? _T("colLabelWin")
2124 : win ? _T("rowLabelWin")
2125 : _T("gridWin"),
2126 cursorModes[m_cursorMode], cursorModes[mode]);
2127 #endif // __WXDEBUG__
2128
2129 if ( mode == m_cursorMode )
2130 return;
2131
2132 if ( !win )
2133 {
2134 // by default use the grid itself
2135 win = m_gridWin;
2136 }
2137
2138 if ( m_winCapture )
2139 {
2140 m_winCapture->ReleaseMouse();
2141 m_winCapture = (wxWindow *)NULL;
2142 }
2143
2144 m_cursorMode = mode;
2145
2146 switch ( m_cursorMode )
2147 {
2148 case WXGRID_CURSOR_RESIZE_ROW:
2149 win->SetCursor( m_rowResizeCursor );
2150 break;
2151
2152 case WXGRID_CURSOR_RESIZE_COL:
2153 win->SetCursor( m_colResizeCursor );
2154 break;
2155
2156 default:
2157 win->SetCursor( *wxSTANDARD_CURSOR );
2158 }
2159
2160 // we need to capture mouse when resizing
2161 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
2162 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
2163
2164 if ( captureMouse && resize )
2165 {
2166 win->CaptureMouse();
2167 m_winCapture = win;
2168 }
2169 }
2170
2171 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
2172 {
2173 int x, y;
2174 wxPoint pos( event.GetPosition() );
2175 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2176
2177 wxGridCellCoords coords;
2178 XYToCell( x, y, coords );
2179
2180 if ( event.Dragging() )
2181 {
2182 m_isDragging = TRUE;
2183 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2184 {
2185 // Hide the edit control, so it
2186 // won't interfer with drag-shrinking.
2187 if ( IsCellEditControlEnabled() )
2188 HideCellEditControl();
2189 if ( coords != wxGridNoCellCoords )
2190 {
2191 if ( !IsSelection() )
2192 {
2193 SelectBlock( coords, coords );
2194 }
2195 else
2196 {
2197 SelectBlock( m_currentCellCoords, coords );
2198 }
2199 }
2200 }
2201 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2202 {
2203 int cw, ch, left, dummy;
2204 m_gridWin->GetClientSize( &cw, &ch );
2205 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2206
2207 wxClientDC dc( m_gridWin );
2208 PrepareDC( dc );
2209 dc.SetLogicalFunction(wxINVERT);
2210 if ( m_dragLastPos >= 0 )
2211 {
2212 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2213 }
2214 dc.DrawLine( left, y, left+cw, y );
2215 m_dragLastPos = y;
2216 }
2217 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2218 {
2219 int cw, ch, dummy, top;
2220 m_gridWin->GetClientSize( &cw, &ch );
2221 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2222
2223 wxClientDC dc( m_gridWin );
2224 PrepareDC( dc );
2225 dc.SetLogicalFunction(wxINVERT);
2226 if ( m_dragLastPos >= 0 )
2227 {
2228 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2229 }
2230 dc.DrawLine( x, top, x, top+ch );
2231 m_dragLastPos = x;
2232 }
2233
2234 return;
2235 }
2236
2237 m_isDragging = FALSE;
2238
2239 if ( coords != wxGridNoCellCoords )
2240 {
2241 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
2242 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
2243 // wxGTK
2244 #if 0
2245 if ( event.Entering() || event.Leaving() )
2246 {
2247 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2248 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
2249 }
2250 else
2251 #endif // 0
2252
2253 // ------------ Left button pressed
2254 //
2255 if ( event.LeftDown() )
2256 {
2257 if ( event.ShiftDown() )
2258 {
2259 SelectBlock( m_currentCellCoords, coords );
2260 }
2261 else if ( XToEdgeOfCol(x) < 0 &&
2262 YToEdgeOfRow(y) < 0 )
2263 {
2264 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
2265 coords.GetRow(),
2266 coords.GetCol(),
2267 event ) )
2268 {
2269 MakeCellVisible( coords );
2270 SetCurrentCell( coords );
2271 }
2272 }
2273 }
2274
2275
2276 // ------------ Left double click
2277 //
2278 else if ( event.LeftDClick() )
2279 {
2280 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
2281 {
2282 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
2283 coords.GetRow(),
2284 coords.GetCol(),
2285 event );
2286 }
2287 }
2288
2289
2290 // ------------ Left button released
2291 //
2292 else if ( event.LeftUp() )
2293 {
2294 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2295 {
2296 if ( IsSelection() )
2297 {
2298 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
2299 }
2300
2301 // Show the edit control, if it has
2302 // been hidden for drag-shrinking.
2303 if ( IsCellEditControlEnabled() )
2304 ShowCellEditControl();
2305 }
2306 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2307 {
2308 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2309 DoEndDragResizeRow();
2310
2311 // Note: we are ending the event *after* doing
2312 // default processing in this case
2313 //
2314 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2315 }
2316 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2317 {
2318 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2319 DoEndDragResizeCol();
2320
2321 // Note: we are ending the event *after* doing
2322 // default processing in this case
2323 //
2324 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2325 }
2326
2327 m_dragLastPos = -1;
2328 }
2329
2330
2331 // ------------ Right button down
2332 //
2333 else if ( event.RightDown() )
2334 {
2335 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
2336 coords.GetRow(),
2337 coords.GetCol(),
2338 event ) )
2339 {
2340 // no default action at the moment
2341 }
2342 }
2343
2344
2345 // ------------ Right double click
2346 //
2347 else if ( event.RightDClick() )
2348 {
2349 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2350 coords.GetRow(),
2351 coords.GetCol(),
2352 event ) )
2353 {
2354 // no default action at the moment
2355 }
2356 }
2357
2358 // ------------ Moving and no button action
2359 //
2360 else if ( event.Moving() && !event.IsButton() )
2361 {
2362 int dragRow = YToEdgeOfRow( y );
2363 int dragCol = XToEdgeOfCol( x );
2364
2365 // Dragging on the corner of a cell to resize in both
2366 // directions is not implemented yet...
2367 //
2368 if ( dragRow >= 0 && dragCol >= 0 )
2369 {
2370 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2371 return;
2372 }
2373
2374 if ( dragRow >= 0 )
2375 {
2376 m_dragRowOrCol = dragRow;
2377
2378 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2379 {
2380 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
2381 }
2382
2383 return;
2384 }
2385
2386 if ( dragCol >= 0 )
2387 {
2388 m_dragRowOrCol = dragCol;
2389
2390 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2391 {
2392 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
2393 }
2394
2395 return;
2396 }
2397
2398 // Neither on a row or col edge
2399 //
2400 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2401 {
2402 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2403 }
2404 }
2405 }
2406 }
2407
2408
2409 void wxGrid::DoEndDragResizeRow()
2410 {
2411 if ( m_dragLastPos >= 0 )
2412 {
2413 // erase the last line and resize the row
2414 //
2415 int cw, ch, left, dummy;
2416 m_gridWin->GetClientSize( &cw, &ch );
2417 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2418
2419 wxClientDC dc( m_gridWin );
2420 PrepareDC( dc );
2421 dc.SetLogicalFunction( wxINVERT );
2422 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2423 HideCellEditControl();
2424
2425 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
2426 SetRowSize( m_dragRowOrCol,
2427 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
2428
2429 if ( !GetBatchCount() )
2430 {
2431 // Only needed to get the correct rect.y:
2432 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
2433 rect.x = 0;
2434 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
2435 rect.width = m_rowLabelWidth;
2436 rect.height = ch - rect.y;
2437 m_rowLabelWin->Refresh( TRUE, &rect );
2438 rect.width = cw;
2439 m_gridWin->Refresh( FALSE, &rect );
2440 }
2441
2442 ShowCellEditControl();
2443 }
2444 }
2445
2446
2447 void wxGrid::DoEndDragResizeCol()
2448 {
2449 if ( m_dragLastPos >= 0 )
2450 {
2451 // erase the last line and resize the col
2452 //
2453 int cw, ch, dummy, top;
2454 m_gridWin->GetClientSize( &cw, &ch );
2455 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2456
2457 wxClientDC dc( m_gridWin );
2458 PrepareDC( dc );
2459 dc.SetLogicalFunction( wxINVERT );
2460 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2461 HideCellEditControl();
2462
2463 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
2464 SetColSize( m_dragRowOrCol,
2465 wxMax( m_dragLastPos - colLeft, WXGRID_MIN_COL_WIDTH ) );
2466
2467 if ( !GetBatchCount() )
2468 {
2469 // Only needed to get the correct rect.x:
2470 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
2471 rect.y = 0;
2472 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
2473 rect.width = cw - rect.x;
2474 rect.height = m_colLabelHeight;
2475 m_colLabelWin->Refresh( TRUE, &rect );
2476 rect.height = ch;
2477 m_gridWin->Refresh( FALSE, &rect );
2478 }
2479
2480 ShowCellEditControl();
2481 }
2482 }
2483
2484
2485
2486 //
2487 // ------ interaction with data model
2488 //
2489 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
2490 {
2491 switch ( msg.GetId() )
2492 {
2493 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
2494 return GetModelValues();
2495
2496 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
2497 return SetModelValues();
2498
2499 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
2500 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2501 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2502 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2503 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2504 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2505 return Redimension( msg );
2506
2507 default:
2508 return FALSE;
2509 }
2510 }
2511
2512
2513
2514 // The behaviour of this function depends on the grid table class
2515 // Clear() function. For the default wxGridStringTable class the
2516 // behavious is to replace all cell contents with wxEmptyString but
2517 // not to change the number of rows or cols.
2518 //
2519 void wxGrid::ClearGrid()
2520 {
2521 if ( m_table )
2522 {
2523 m_table->Clear();
2524 SetEditControlValue();
2525 if ( !GetBatchCount() ) m_gridWin->Refresh();
2526 }
2527 }
2528
2529
2530 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2531 {
2532 // TODO: something with updateLabels flag
2533
2534 if ( !m_created )
2535 {
2536 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2537 return FALSE;
2538 }
2539
2540 if ( m_table )
2541 {
2542 bool ok = m_table->InsertRows( pos, numRows );
2543
2544 // the table will have sent the results of the insert row
2545 // operation to this view object as a grid table message
2546 //
2547 if ( ok )
2548 {
2549 if ( m_numCols == 0 )
2550 {
2551 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2552 //
2553 // TODO: perhaps instead of appending the default number of cols
2554 // we should remember what the last non-zero number of cols was ?
2555 //
2556 }
2557
2558 if ( m_currentCellCoords == wxGridNoCellCoords )
2559 {
2560 // if we have just inserted cols into an empty grid the current
2561 // cell will be undefined...
2562 //
2563 SetCurrentCell( 0, 0 );
2564 }
2565
2566 ClearSelection();
2567 if ( !GetBatchCount() ) Refresh();
2568 }
2569
2570 SetEditControlValue();
2571 return ok;
2572 }
2573 else
2574 {
2575 return FALSE;
2576 }
2577 }
2578
2579
2580 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
2581 {
2582 // TODO: something with updateLabels flag
2583
2584 if ( !m_created )
2585 {
2586 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2587 return FALSE;
2588 }
2589
2590 if ( m_table && m_table->AppendRows( numRows ) )
2591 {
2592 if ( m_currentCellCoords == wxGridNoCellCoords )
2593 {
2594 // if we have just inserted cols into an empty grid the current
2595 // cell will be undefined...
2596 //
2597 SetCurrentCell( 0, 0 );
2598 }
2599
2600 // the table will have sent the results of the append row
2601 // operation to this view object as a grid table message
2602 //
2603 ClearSelection();
2604 if ( !GetBatchCount() ) Refresh();
2605 return TRUE;
2606 }
2607 else
2608 {
2609 return FALSE;
2610 }
2611 }
2612
2613
2614 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2615 {
2616 // TODO: something with updateLabels flag
2617
2618 if ( !m_created )
2619 {
2620 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2621 return FALSE;
2622 }
2623
2624 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2625 {
2626 // the table will have sent the results of the delete row
2627 // operation to this view object as a grid table message
2628 //
2629 if ( m_numRows > 0 )
2630 SetEditControlValue();
2631 else
2632 HideCellEditControl();
2633
2634 ClearSelection();
2635 if ( !GetBatchCount() ) Refresh();
2636 return TRUE;
2637 }
2638 else
2639 {
2640 return FALSE;
2641 }
2642 }
2643
2644
2645 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2646 {
2647 // TODO: something with updateLabels flag
2648
2649 if ( !m_created )
2650 {
2651 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2652 return FALSE;
2653 }
2654
2655 if ( m_table )
2656 {
2657 HideCellEditControl();
2658 bool ok = m_table->InsertCols( pos, numCols );
2659
2660 // the table will have sent the results of the insert col
2661 // operation to this view object as a grid table message
2662 //
2663 if ( ok )
2664 {
2665 if ( m_currentCellCoords == wxGridNoCellCoords )
2666 {
2667 // if we have just inserted cols into an empty grid the current
2668 // cell will be undefined...
2669 //
2670 SetCurrentCell( 0, 0 );
2671 }
2672
2673 ClearSelection();
2674 if ( !GetBatchCount() ) Refresh();
2675 }
2676
2677 SetEditControlValue();
2678 return ok;
2679 }
2680 else
2681 {
2682 return FALSE;
2683 }
2684 }
2685
2686
2687 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
2688 {
2689 // TODO: something with updateLabels flag
2690
2691 if ( !m_created )
2692 {
2693 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2694 return FALSE;
2695 }
2696
2697 if ( m_table && m_table->AppendCols( numCols ) )
2698 {
2699 // the table will have sent the results of the append col
2700 // operation to this view object as a grid table message
2701 //
2702 if ( m_currentCellCoords == wxGridNoCellCoords )
2703 {
2704 // if we have just inserted cols into an empty grid the current
2705 // cell will be undefined...
2706 //
2707 SetCurrentCell( 0, 0 );
2708 }
2709
2710 ClearSelection();
2711 if ( !GetBatchCount() ) Refresh();
2712 return TRUE;
2713 }
2714 else
2715 {
2716 return FALSE;
2717 }
2718 }
2719
2720
2721 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2722 {
2723 // TODO: something with updateLabels flag
2724
2725 if ( !m_created )
2726 {
2727 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2728 return FALSE;
2729 }
2730
2731 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2732 {
2733 // the table will have sent the results of the delete col
2734 // operation to this view object as a grid table message
2735 //
2736 if ( m_numCols > 0 )
2737 SetEditControlValue();
2738 else
2739 HideCellEditControl();
2740
2741 ClearSelection();
2742 if ( !GetBatchCount() ) Refresh();
2743 return TRUE;
2744 }
2745 else
2746 {
2747 return FALSE;
2748 }
2749 }
2750
2751
2752
2753 //
2754 // ----- event handlers
2755 //
2756
2757 // Generate a grid event based on a mouse event and
2758 // return the result of ProcessEvent()
2759 //
2760 bool wxGrid::SendEvent( const wxEventType type,
2761 int row, int col,
2762 wxMouseEvent& mouseEv )
2763 {
2764 if ( type == EVT_GRID_ROW_SIZE ||
2765 type == EVT_GRID_COL_SIZE )
2766 {
2767 int rowOrCol = (row == -1 ? col : row);
2768
2769 wxGridSizeEvent gridEvt( GetId(),
2770 type,
2771 this,
2772 rowOrCol,
2773 mouseEv.GetX(), mouseEv.GetY(),
2774 mouseEv.ControlDown(),
2775 mouseEv.ShiftDown(),
2776 mouseEv.AltDown(),
2777 mouseEv.MetaDown() );
2778
2779 return GetEventHandler()->ProcessEvent(gridEvt);
2780 }
2781 else if ( type == EVT_GRID_RANGE_SELECT )
2782 {
2783 wxGridRangeSelectEvent gridEvt( GetId(),
2784 type,
2785 this,
2786 m_selectedTopLeft,
2787 m_selectedBottomRight,
2788 mouseEv.ControlDown(),
2789 mouseEv.ShiftDown(),
2790 mouseEv.AltDown(),
2791 mouseEv.MetaDown() );
2792
2793 return GetEventHandler()->ProcessEvent(gridEvt);
2794 }
2795 else
2796 {
2797 wxGridEvent gridEvt( GetId(),
2798 type,
2799 this,
2800 row, col,
2801 mouseEv.GetX(), mouseEv.GetY(),
2802 mouseEv.ControlDown(),
2803 mouseEv.ShiftDown(),
2804 mouseEv.AltDown(),
2805 mouseEv.MetaDown() );
2806
2807 return GetEventHandler()->ProcessEvent(gridEvt);
2808 }
2809 }
2810
2811
2812 // Generate a grid event of specified type and return the result
2813 // of ProcessEvent().
2814 //
2815 bool wxGrid::SendEvent( const wxEventType type,
2816 int row, int col )
2817 {
2818 if ( type == EVT_GRID_ROW_SIZE ||
2819 type == EVT_GRID_COL_SIZE )
2820 {
2821 int rowOrCol = (row == -1 ? col : row);
2822
2823 wxGridSizeEvent gridEvt( GetId(),
2824 type,
2825 this,
2826 rowOrCol );
2827
2828 return GetEventHandler()->ProcessEvent(gridEvt);
2829 }
2830 else
2831 {
2832 wxGridEvent gridEvt( GetId(),
2833 type,
2834 this,
2835 row, col );
2836
2837 return GetEventHandler()->ProcessEvent(gridEvt);
2838 }
2839 }
2840
2841
2842 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
2843 {
2844 wxPaintDC dc( this );
2845
2846 if ( m_currentCellCoords == wxGridNoCellCoords &&
2847 m_numRows && m_numCols )
2848 {
2849 m_currentCellCoords.Set(0, 0);
2850 SetEditControlValue();
2851 ShowCellEditControl();
2852 }
2853
2854 m_displayed = TRUE;
2855 }
2856
2857
2858 // This is just here to make sure that CalcDimensions gets called when
2859 // the grid view is resized... then the size event is skipped to allow
2860 // the box sizers to handle everything
2861 //
2862 void wxGrid::OnSize( wxSizeEvent& event )
2863 {
2864 CalcWindowSizes();
2865 CalcDimensions();
2866 }
2867
2868
2869 void wxGrid::OnKeyDown( wxKeyEvent& event )
2870 {
2871 if ( m_inOnKeyDown )
2872 {
2873 // shouldn't be here - we are going round in circles...
2874 //
2875 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
2876 }
2877
2878 m_inOnKeyDown = TRUE;
2879
2880 // propagate the event up and see if it gets processed
2881 //
2882 wxWindow *parent = GetParent();
2883 wxKeyEvent keyEvt( event );
2884 keyEvt.SetEventObject( parent );
2885
2886 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
2887 {
2888 // try local handlers
2889 //
2890 switch ( event.KeyCode() )
2891 {
2892 case WXK_UP:
2893 if ( event.ControlDown() )
2894 {
2895 MoveCursorUpBlock();
2896 }
2897 else
2898 {
2899 MoveCursorUp();
2900 }
2901 break;
2902
2903 case WXK_DOWN:
2904 if ( event.ControlDown() )
2905 {
2906 MoveCursorDownBlock();
2907 }
2908 else
2909 {
2910 MoveCursorDown();
2911 }
2912 break;
2913
2914 case WXK_LEFT:
2915 if ( event.ControlDown() )
2916 {
2917 MoveCursorLeftBlock();
2918 }
2919 else
2920 {
2921 MoveCursorLeft();
2922 }
2923 break;
2924
2925 case WXK_RIGHT:
2926 if ( event.ControlDown() )
2927 {
2928 MoveCursorRightBlock();
2929 }
2930 else
2931 {
2932 MoveCursorRight();
2933 }
2934 break;
2935
2936 case WXK_SPACE:
2937 if ( !IsEditable() )
2938 {
2939 MoveCursorRight();
2940 }
2941 else
2942 {
2943 event.Skip();
2944 }
2945 break;
2946
2947 case WXK_RETURN:
2948 if ( event.ControlDown() )
2949 {
2950 event.Skip(); // to let the edit control have the return
2951 }
2952 else
2953 {
2954 MoveCursorDown();
2955 }
2956 break;
2957
2958 case WXK_HOME:
2959 if ( event.ControlDown() )
2960 {
2961 MakeCellVisible( 0, 0 );
2962 SetCurrentCell( 0, 0 );
2963 }
2964 else
2965 {
2966 event.Skip();
2967 }
2968 break;
2969
2970 case WXK_END:
2971 if ( event.ControlDown() )
2972 {
2973 MakeCellVisible( m_numRows-1, m_numCols-1 );
2974 SetCurrentCell( m_numRows-1, m_numCols-1 );
2975 }
2976 else
2977 {
2978 event.Skip();
2979 }
2980 break;
2981
2982 case WXK_PRIOR:
2983 MovePageUp();
2984 break;
2985
2986 case WXK_NEXT:
2987 MovePageDown();
2988 break;
2989
2990 default:
2991 // now try the cell edit control
2992 //
2993 if ( IsCellEditControlEnabled() )
2994 {
2995 event.SetEventObject( m_cellEditCtrl );
2996 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2997 }
2998 break;
2999 }
3000 }
3001
3002 m_inOnKeyDown = FALSE;
3003 }
3004
3005
3006 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
3007 {
3008 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
3009 {
3010 // the event has been intercepted - do nothing
3011 return;
3012 }
3013
3014 if ( m_displayed &&
3015 m_currentCellCoords != wxGridNoCellCoords )
3016 {
3017 HideCellEditControl();
3018 SaveEditControlValue();
3019 }
3020
3021 m_currentCellCoords = coords;
3022
3023 SetEditControlValue();
3024
3025 if ( m_displayed )
3026 {
3027 ShowCellEditControl();
3028
3029 if ( IsSelection() )
3030 {
3031 wxRect r( SelectionToDeviceRect() );
3032 ClearSelection();
3033 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
3034 }
3035 }
3036 }
3037
3038
3039 //
3040 // ------ functions to get/send data (see also public functions)
3041 //
3042
3043 bool wxGrid::GetModelValues()
3044 {
3045 if ( m_table )
3046 {
3047 // all we need to do is repaint the grid
3048 //
3049 m_gridWin->Refresh();
3050 return TRUE;
3051 }
3052
3053 return FALSE;
3054 }
3055
3056
3057 bool wxGrid::SetModelValues()
3058 {
3059 int row, col;
3060
3061 if ( m_table )
3062 {
3063 for ( row = 0; row < m_numRows; row++ )
3064 {
3065 for ( col = 0; col < m_numCols; col++ )
3066 {
3067 m_table->SetValue( row, col, GetCellValue(row, col) );
3068 }
3069 }
3070
3071 return TRUE;
3072 }
3073
3074 return FALSE;
3075 }
3076
3077
3078
3079 // Note - this function only draws cells that are in the list of
3080 // exposed cells (usually set from the update region by
3081 // CalcExposedCells)
3082 //
3083 void wxGrid::DrawGridCellArea( wxDC& dc )
3084 {
3085 if ( !m_numRows || !m_numCols ) return;
3086
3087 size_t i;
3088 size_t numCells = m_cellsExposed.GetCount();
3089
3090 for ( i = 0; i < numCells; i++ )
3091 {
3092 DrawCell( dc, m_cellsExposed[i] );
3093 }
3094 }
3095
3096
3097 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
3098 {
3099 if ( m_colWidths[coords.GetCol()] <=0 ||
3100 m_rowHeights[coords.GetRow()] <= 0 ) return;
3101
3102 #if !WXGRID_DRAW_LINES
3103 if ( m_gridLinesEnabled )
3104 DrawCellBorder( dc, coords );
3105 #endif
3106
3107 DrawCellBackground( dc, coords );
3108
3109 // TODO: separate functions here for different kinds of cells ?
3110 // e.g. text, image
3111 //
3112 DrawCellValue( dc, coords );
3113 }
3114
3115
3116 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
3117 {
3118 if ( m_colWidths[coords.GetCol()] <=0 ||
3119 m_rowHeights[coords.GetRow()] <= 0 ) return;
3120
3121 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3122 int row = coords.GetRow();
3123 int col = coords.GetCol();
3124
3125 // right hand border
3126 //
3127 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
3128 m_colRights[col], m_rowBottoms[row] );
3129
3130 // bottom border
3131 //
3132 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
3133 m_colRights[col], m_rowBottoms[row] );
3134 }
3135
3136
3137 void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
3138 {
3139 if ( m_colWidths[coords.GetCol()] <=0 ||
3140 m_rowHeights[coords.GetRow()] <= 0 ) return;
3141
3142 int row = coords.GetRow();
3143 int col = coords.GetCol();
3144
3145 dc.SetBackgroundMode( wxSOLID );
3146
3147 if ( IsInSelection( coords ) )
3148 {
3149 // TODO: improve this
3150 //
3151 dc.SetBrush( *wxBLACK_BRUSH );
3152 }
3153 else
3154 {
3155 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
3156 }
3157
3158 dc.SetPen( *wxTRANSPARENT_PEN );
3159
3160 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
3161 m_rowBottoms[row] - m_rowHeights[row] + 1,
3162 m_colWidths[col]-1,
3163 m_rowHeights[row]-1 );
3164 }
3165
3166
3167 void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
3168 {
3169 if ( m_colWidths[coords.GetCol()] <=0 ||
3170 m_rowHeights[coords.GetRow()] <= 0 ) return;
3171
3172 int row = coords.GetRow();
3173 int col = coords.GetCol();
3174
3175 dc.SetBackgroundMode( wxTRANSPARENT );
3176
3177 if ( IsInSelection( row, col ) )
3178 {
3179 // TODO: improve this
3180 //
3181 dc.SetTextBackground( wxColour(0, 0, 0) );
3182 dc.SetTextForeground( wxColour(255, 255, 255) );
3183 }
3184 else
3185 {
3186 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
3187 dc.SetTextForeground( GetCellTextColour(row, col) );
3188 }
3189 dc.SetFont( GetCellFont(row, col) );
3190
3191 int hAlign, vAlign;
3192 GetCellAlignment( row, col, &hAlign, &vAlign );
3193
3194 wxRect rect;
3195 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3196 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3197 rect.SetWidth( m_colWidths[col] - 4 );
3198 rect.SetHeight( m_rowHeights[row] - 4 );
3199
3200 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
3201 }
3202
3203
3204
3205 // TODO: remove this ???
3206 // This is used to redraw all grid lines e.g. when the grid line colour
3207 // has been changed
3208 //
3209 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
3210 {
3211 if ( !m_gridLinesEnabled ||
3212 !m_numRows ||
3213 !m_numCols ) return;
3214
3215 int top, bottom, left, right;
3216
3217 if (reg.IsEmpty()){
3218 int cw, ch;
3219 m_gridWin->GetClientSize(&cw, &ch);
3220
3221 // virtual coords of visible area
3222 //
3223 CalcUnscrolledPosition( 0, 0, &left, &top );
3224 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3225 }
3226 else{
3227 wxCoord x, y, w, h;
3228 reg.GetBox(x, y, w, h);
3229 CalcUnscrolledPosition( x, y, &left, &top );
3230 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3231 }
3232
3233 // avoid drawing grid lines past the last row and col
3234 //
3235 right = wxMin( right, m_colRights[m_numCols-1] );
3236 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3237
3238 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3239
3240 // horizontal grid lines
3241 //
3242 int i;
3243 for ( i = 0; i < m_numRows; i++ )
3244 {
3245 if ( m_rowBottoms[i] > bottom )
3246 {
3247 break;
3248 }
3249 else if ( m_rowBottoms[i] >= top )
3250 {
3251 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
3252 }
3253 }
3254
3255
3256 // vertical grid lines
3257 //
3258 for ( i = 0; i < m_numCols; i++ )
3259 {
3260 if ( m_colRights[i] > right )
3261 {
3262 break;
3263 }
3264 else if ( m_colRights[i] >= left )
3265 {
3266 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
3267 }
3268 }
3269 }
3270
3271
3272 void wxGrid::DrawRowLabels( wxDC& dc )
3273 {
3274 if ( !m_numRows || !m_numCols ) return;
3275
3276 size_t i;
3277 size_t numLabels = m_rowLabelsExposed.GetCount();
3278
3279 for ( i = 0; i < numLabels; i++ )
3280 {
3281 DrawRowLabel( dc, m_rowLabelsExposed[i] );
3282 }
3283 }
3284
3285
3286 void wxGrid::DrawRowLabel( wxDC& dc, int row )
3287 {
3288 if ( m_rowHeights[row] <= 0 ) return;
3289
3290 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
3291
3292 dc.SetPen( *wxBLACK_PEN );
3293 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3294 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3295
3296 dc.DrawLine( 0, m_rowBottoms[row]-1,
3297 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3298
3299 dc.SetPen( *wxWHITE_PEN );
3300 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3301 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
3302
3303 dc.SetBackgroundMode( wxTRANSPARENT );
3304 dc.SetTextForeground( GetLabelTextColour() );
3305 dc.SetFont( GetLabelFont() );
3306
3307 int hAlign, vAlign;
3308 GetRowLabelAlignment( &hAlign, &vAlign );
3309
3310 wxRect rect;
3311 rect.SetX( 2 );
3312 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3313 rect.SetWidth( m_rowLabelWidth - 4 );
3314 rect.SetHeight( m_rowHeights[row] - 4 );
3315 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
3316 }
3317
3318
3319 void wxGrid::DrawColLabels( wxDC& dc )
3320 {
3321 if ( !m_numRows || !m_numCols ) return;
3322
3323 size_t i;
3324 size_t numLabels = m_colLabelsExposed.GetCount();
3325
3326 for ( i = 0; i < numLabels; i++ )
3327 {
3328 DrawColLabel( dc, m_colLabelsExposed[i] );
3329 }
3330 }
3331
3332
3333 void wxGrid::DrawColLabel( wxDC& dc, int col )
3334 {
3335 if ( m_colWidths[col] <= 0 ) return;
3336
3337 int colLeft = m_colRights[col] - m_colWidths[col];
3338
3339 dc.SetPen( *wxBLACK_PEN );
3340 dc.DrawLine( m_colRights[col]-1, 0,
3341 m_colRights[col]-1, m_colLabelHeight-1 );
3342
3343 dc.DrawLine( colLeft, m_colLabelHeight-1,
3344 m_colRights[col]-1, m_colLabelHeight-1 );
3345
3346 dc.SetPen( *wxWHITE_PEN );
3347 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
3348 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
3349
3350 dc.SetBackgroundMode( wxTRANSPARENT );
3351 dc.SetTextForeground( GetLabelTextColour() );
3352 dc.SetFont( GetLabelFont() );
3353
3354 dc.SetBackgroundMode( wxTRANSPARENT );
3355 dc.SetTextForeground( GetLabelTextColour() );
3356 dc.SetFont( GetLabelFont() );
3357
3358 int hAlign, vAlign;
3359 GetColLabelAlignment( &hAlign, &vAlign );
3360
3361 wxRect rect;
3362 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3363 rect.SetY( 2 );
3364 rect.SetWidth( m_colWidths[col] - 4 );
3365 rect.SetHeight( m_colLabelHeight - 4 );
3366 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
3367 }
3368
3369
3370 void wxGrid::DrawTextRectangle( wxDC& dc,
3371 const wxString& value,
3372 const wxRect& rect,
3373 int horizAlign,
3374 int vertAlign )
3375 {
3376 long textWidth, textHeight;
3377 long lineWidth, lineHeight;
3378 wxArrayString lines;
3379
3380 dc.SetClippingRegion( rect );
3381 StringToLines( value, lines );
3382 if ( lines.GetCount() )
3383 {
3384 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
3385 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
3386
3387 float x, y;
3388 switch ( horizAlign )
3389 {
3390 case wxRIGHT:
3391 x = rect.x + (rect.width - textWidth - 1);
3392 break;
3393
3394 case wxCENTRE:
3395 x = rect.x + ((rect.width - textWidth)/2);
3396 break;
3397
3398 case wxLEFT:
3399 default:
3400 x = rect.x + 1;
3401 break;
3402 }
3403
3404 switch ( vertAlign )
3405 {
3406 case wxBOTTOM:
3407 y = rect.y + (rect.height - textHeight - 1);
3408 break;
3409
3410 case wxCENTRE:
3411 y = rect.y + ((rect.height - textHeight)/2);
3412 break;
3413
3414 case wxTOP:
3415 default:
3416 y = rect.y + 1;
3417 break;
3418 }
3419
3420 for ( size_t i = 0; i < lines.GetCount(); i++ )
3421 {
3422 dc.DrawText( lines[i], (long)x, (long)y );
3423 y += lineHeight;
3424 }
3425 }
3426
3427 dc.DestroyClippingRegion();
3428 }
3429
3430
3431 // Split multi line text up into an array of strings. Any existing
3432 // contents of the string array are preserved.
3433 //
3434 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
3435 {
3436 int startPos = 0;
3437 int pos;
3438 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
3439 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
3440
3441 while ( startPos < (int)tVal.Length() )
3442 {
3443 pos = tVal.Mid(startPos).Find( eol );
3444 if ( pos < 0 )
3445 {
3446 break;
3447 }
3448 else if ( pos == 0 )
3449 {
3450 lines.Add( wxEmptyString );
3451 }
3452 else
3453 {
3454 lines.Add( value.Mid(startPos, pos) );
3455 }
3456 startPos += pos+1;
3457 }
3458 if ( startPos < (int)value.Length() )
3459 {
3460 lines.Add( value.Mid( startPos ) );
3461 }
3462 }
3463
3464
3465 void wxGrid::GetTextBoxSize( wxDC& dc,
3466 wxArrayString& lines,
3467 long *width, long *height )
3468 {
3469 long w = 0;
3470 long h = 0;
3471 long lineW, lineH;
3472
3473 size_t i;
3474 for ( i = 0; i < lines.GetCount(); i++ )
3475 {
3476 dc.GetTextExtent( lines[i], &lineW, &lineH );
3477 w = wxMax( w, lineW );
3478 h += lineH;
3479 }
3480
3481 *width = w;
3482 *height = h;
3483 }
3484
3485
3486 //
3487 // ------ Edit control functions
3488 //
3489
3490
3491 void wxGrid::EnableEditing( bool edit )
3492 {
3493 // TODO: improve this ?
3494 //
3495 if ( edit != m_editable )
3496 {
3497 m_editable = edit;
3498
3499 // TODO: extend this for other edit control types
3500 //
3501 if ( m_editCtrlType == wxGRID_TEXTCTRL )
3502 {
3503 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
3504 }
3505 }
3506 }
3507
3508
3509 #if 0 // disabled for the moment - the cell control is always active
3510 void wxGrid::EnableCellEditControl( bool enable )
3511 {
3512 if ( m_cellEditCtrl &&
3513 enable != m_cellEditCtrlEnabled )
3514 {
3515 m_cellEditCtrlEnabled = enable;
3516
3517 if ( m_cellEditCtrlEnabled )
3518 {
3519 SetEditControlValue();
3520 ShowCellEditControl();
3521 }
3522 else
3523 {
3524 HideCellEditControl();
3525 SaveEditControlValue();
3526 }
3527 }
3528 }
3529 #endif
3530
3531
3532 void wxGrid::ShowCellEditControl()
3533 {
3534 wxRect rect;
3535
3536 if ( IsCellEditControlEnabled() )
3537 {
3538 if ( !IsVisible( m_currentCellCoords ) )
3539 {
3540 return;
3541 }
3542 else
3543 {
3544 rect = CellToRect( m_currentCellCoords );
3545
3546 // convert to scrolled coords
3547 //
3548 int left, top, right, bottom;
3549 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
3550 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
3551
3552 int cw, ch;
3553 m_gridWin->GetClientSize( &cw, &ch );
3554
3555 // Make the edit control large enough to allow for internal margins
3556 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3557 //
3558 int extra;
3559 #if defined(__WXMOTIF__)
3560 if ( m_currentCellCoords.GetRow() == 0 ||
3561 m_currentCellCoords.GetCol() == 0 )
3562 {
3563 extra = 2;
3564 }
3565 else
3566 {
3567 extra = 4;
3568 }
3569 #else
3570 if ( m_currentCellCoords.GetRow() == 0 ||
3571 m_currentCellCoords.GetCol() == 0 )
3572 {
3573 extra = 1;
3574 }
3575 else
3576 {
3577 extra = 2;
3578 }
3579 #endif
3580
3581 #if defined(__WXGTK__)
3582 int top_diff = 0;
3583 int left_diff = 0;
3584 if (left != 0) left_diff++;
3585 if (top != 0) top_diff++;
3586 rect.SetLeft( left + left_diff );
3587 rect.SetTop( top + top_diff );
3588 rect.SetRight( rect.GetRight() - left_diff );
3589 rect.SetBottom( rect.GetBottom() - top_diff );
3590 #else
3591 rect.SetLeft( wxMax(0, left - extra) );
3592 rect.SetTop( wxMax(0, top - extra) );
3593 rect.SetRight( rect.GetRight() + 2*extra );
3594 rect.SetBottom( rect.GetBottom() + 2*extra );
3595 #endif
3596
3597 m_cellEditCtrl->SetSize( rect );
3598 m_cellEditCtrl->Show( TRUE );
3599
3600 switch ( m_editCtrlType )
3601 {
3602 case wxGRID_TEXTCTRL:
3603 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3604 break;
3605
3606 case wxGRID_CHECKBOX:
3607 // TODO: anything ???
3608 //
3609 break;
3610
3611 case wxGRID_CHOICE:
3612 // TODO: anything ???
3613 //
3614 break;
3615
3616 case wxGRID_COMBOBOX:
3617 // TODO: anything ???
3618 //
3619 break;
3620 }
3621
3622 m_cellEditCtrl->SetFocus();
3623 }
3624 }
3625 }
3626
3627
3628 void wxGrid::HideCellEditControl()
3629 {
3630 if ( IsCellEditControlEnabled() )
3631 {
3632 m_cellEditCtrl->Show( FALSE );
3633 }
3634 }
3635
3636
3637 void wxGrid::SetEditControlValue( const wxString& value )
3638 {
3639 if ( m_table )
3640 {
3641 wxString s;
3642 if ( !value )
3643 s = GetCellValue(m_currentCellCoords);
3644 else
3645 s = value;
3646
3647 if ( IsCellEditControlEnabled() )
3648 {
3649 switch ( m_editCtrlType )
3650 {
3651 case wxGRID_TEXTCTRL:
3652 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3653 break;
3654
3655 case wxGRID_CHECKBOX:
3656 // TODO: implement this
3657 //
3658 break;
3659
3660 case wxGRID_CHOICE:
3661 // TODO: implement this
3662 //
3663 break;
3664
3665 case wxGRID_COMBOBOX:
3666 // TODO: implement this
3667 //
3668 break;
3669 }
3670 }
3671 }
3672 }
3673
3674
3675 void wxGrid::SaveEditControlValue()
3676 {
3677 if ( m_table )
3678 {
3679 wxWindow *ctrl = (wxWindow *)NULL;
3680
3681 if ( IsCellEditControlEnabled() )
3682 {
3683 ctrl = m_cellEditCtrl;
3684 }
3685 else
3686 {
3687 return;
3688 }
3689
3690 bool valueChanged = FALSE;
3691
3692 switch ( m_editCtrlType )
3693 {
3694 case wxGRID_TEXTCTRL:
3695 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3696 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3697 SetCellValue( m_currentCellCoords,
3698 ((wxTextCtrl *) ctrl)->GetValue() );
3699 break;
3700
3701 case wxGRID_CHECKBOX:
3702 // TODO: implement this
3703 //
3704 break;
3705
3706 case wxGRID_CHOICE:
3707 // TODO: implement this
3708 //
3709 break;
3710
3711 case wxGRID_COMBOBOX:
3712 // TODO: implement this
3713 //
3714 break;
3715 }
3716
3717 if ( valueChanged )
3718 {
3719 SendEvent( EVT_GRID_CELL_CHANGE,
3720 m_currentCellCoords.GetRow(),
3721 m_currentCellCoords.GetCol() );
3722 }
3723 }
3724 }
3725
3726
3727 //
3728 // ------ Grid location functions
3729 // Note that all of these functions work with the logical coordinates of
3730 // grid cells and labels so you will need to convert from device
3731 // coordinates for mouse events etc.
3732 //
3733
3734 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
3735 {
3736 int row = YToRow(y);
3737 int col = XToCol(x);
3738
3739 if ( row == -1 || col == -1 )
3740 {
3741 coords = wxGridNoCellCoords;
3742 }
3743 else
3744 {
3745 coords.Set( row, col );
3746 }
3747 }
3748
3749
3750 int wxGrid::YToRow( int y )
3751 {
3752 int i;
3753
3754 for ( i = 0; i < m_numRows; i++ )
3755 {
3756 if ( y < m_rowBottoms[i] ) return i;
3757 }
3758
3759 return -1;
3760 }
3761
3762
3763 int wxGrid::XToCol( int x )
3764 {
3765 int i;
3766
3767 for ( i = 0; i < m_numCols; i++ )
3768 {
3769 if ( x < m_colRights[i] ) return i;
3770 }
3771
3772 return -1;
3773 }
3774
3775
3776 // return the row number that that the y coord is near the edge of, or
3777 // -1 if not near an edge
3778 //
3779 int wxGrid::YToEdgeOfRow( int y )
3780 {
3781 int i, d;
3782
3783 for ( i = 0; i < m_numRows; i++ )
3784 {
3785 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
3786 {
3787 d = abs( y - m_rowBottoms[i] );
3788 {
3789 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3790 }
3791 }
3792 }
3793
3794 return -1;
3795 }
3796
3797
3798 // return the col number that that the x coord is near the edge of, or
3799 // -1 if not near an edge
3800 //
3801 int wxGrid::XToEdgeOfCol( int x )
3802 {
3803 int i, d;
3804
3805 for ( i = 0; i < m_numCols; i++ )
3806 {
3807 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3808 {
3809 d = abs( x - m_colRights[i] );
3810 {
3811 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3812 }
3813 }
3814 }
3815
3816 return -1;
3817 }
3818
3819
3820 wxRect wxGrid::CellToRect( int row, int col )
3821 {
3822 wxRect rect( -1, -1, -1, -1 );
3823
3824 if ( row >= 0 && row < m_numRows &&
3825 col >= 0 && col < m_numCols )
3826 {
3827 rect.x = m_colRights[col] - m_colWidths[col];
3828 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3829 rect.width = m_colWidths[col];
3830 rect.height = m_rowHeights[ row ];
3831 }
3832
3833 return rect;
3834 }
3835
3836
3837 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3838 {
3839 // get the cell rectangle in logical coords
3840 //
3841 wxRect r( CellToRect( row, col ) );
3842
3843 // convert to device coords
3844 //
3845 int left, top, right, bottom;
3846 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3847 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3848
3849 // check against the client area of the grid window
3850 //
3851 int cw, ch;
3852 m_gridWin->GetClientSize( &cw, &ch );
3853
3854 if ( wholeCellVisible )
3855 {
3856 // is the cell wholly visible ?
3857 //
3858 return ( left >= 0 && right <= cw &&
3859 top >= 0 && bottom <= ch );
3860 }
3861 else
3862 {
3863 // is the cell partly visible ?
3864 //
3865 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3866 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3867 }
3868 }
3869
3870
3871 // make the specified cell location visible by doing a minimal amount
3872 // of scrolling
3873 //
3874 void wxGrid::MakeCellVisible( int row, int col )
3875 {
3876 int i;
3877 int xpos = -1, ypos = -1;
3878
3879 if ( row >= 0 && row < m_numRows &&
3880 col >= 0 && col < m_numCols )
3881 {
3882 // get the cell rectangle in logical coords
3883 //
3884 wxRect r( CellToRect( row, col ) );
3885
3886 // convert to device coords
3887 //
3888 int left, top, right, bottom;
3889 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3890 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3891
3892 int cw, ch;
3893 m_gridWin->GetClientSize( &cw, &ch );
3894
3895 if ( top < 0 )
3896 {
3897 ypos = r.GetTop();
3898 }
3899 else if ( bottom > ch )
3900 {
3901 int h = r.GetHeight();
3902 ypos = r.GetTop();
3903 for ( i = row-1; i >= 0; i-- )
3904 {
3905 if ( h + m_rowHeights[i] > ch ) break;
3906
3907 h += m_rowHeights[i];
3908 ypos -= m_rowHeights[i];
3909 }
3910
3911 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3912 // have rounding errors (this is important, because if we do, we
3913 // might not scroll at all and some cells won't be redrawn)
3914 ypos += GRID_SCROLL_LINE / 2;
3915 }
3916
3917 if ( left < 0 )
3918 {
3919 xpos = r.GetLeft();
3920 }
3921 else if ( right > cw )
3922 {
3923 int w = r.GetWidth();
3924 xpos = r.GetLeft();
3925 for ( i = col-1; i >= 0; i-- )
3926 {
3927 if ( w + m_colWidths[i] > cw ) break;
3928
3929 w += m_colWidths[i];
3930 xpos -= m_colWidths[i];
3931 }
3932
3933 // see comment for ypos above
3934 xpos += GRID_SCROLL_LINE / 2;
3935 }
3936
3937 if ( xpos != -1 || ypos != -1 )
3938 {
3939 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
3940 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
3941 Scroll( xpos, ypos );
3942 AdjustScrollbars();
3943 }
3944 }
3945 }
3946
3947
3948 //
3949 // ------ Grid cursor movement functions
3950 //
3951
3952 bool wxGrid::MoveCursorUp()
3953 {
3954 if ( m_currentCellCoords != wxGridNoCellCoords &&
3955 m_currentCellCoords.GetRow() > 0 )
3956 {
3957 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3958 m_currentCellCoords.GetCol() );
3959
3960 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3961 m_currentCellCoords.GetCol() );
3962
3963 return TRUE;
3964 }
3965
3966 return FALSE;
3967 }
3968
3969
3970 bool wxGrid::MoveCursorDown()
3971 {
3972 // TODO: allow for scrolling
3973 //
3974 if ( m_currentCellCoords != wxGridNoCellCoords &&
3975 m_currentCellCoords.GetRow() < m_numRows-1 )
3976 {
3977 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3978 m_currentCellCoords.GetCol() );
3979
3980 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3981 m_currentCellCoords.GetCol() );
3982
3983 return TRUE;
3984 }
3985
3986 return FALSE;
3987 }
3988
3989
3990 bool wxGrid::MoveCursorLeft()
3991 {
3992 if ( m_currentCellCoords != wxGridNoCellCoords &&
3993 m_currentCellCoords.GetCol() > 0 )
3994 {
3995 MakeCellVisible( m_currentCellCoords.GetRow(),
3996 m_currentCellCoords.GetCol() - 1 );
3997
3998 SetCurrentCell( m_currentCellCoords.GetRow(),
3999 m_currentCellCoords.GetCol() - 1 );
4000
4001 return TRUE;
4002 }
4003
4004 return FALSE;
4005 }
4006
4007
4008 bool wxGrid::MoveCursorRight()
4009 {
4010 if ( m_currentCellCoords != wxGridNoCellCoords &&
4011 m_currentCellCoords.GetCol() < m_numCols - 1 )
4012 {
4013 MakeCellVisible( m_currentCellCoords.GetRow(),
4014 m_currentCellCoords.GetCol() + 1 );
4015
4016 SetCurrentCell( m_currentCellCoords.GetRow(),
4017 m_currentCellCoords.GetCol() + 1 );
4018
4019 return TRUE;
4020 }
4021
4022 return FALSE;
4023 }
4024
4025
4026 bool wxGrid::MovePageUp()
4027 {
4028 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4029
4030 int row = m_currentCellCoords.GetRow();
4031 if ( row > 0 )
4032 {
4033 int cw, ch;
4034 m_gridWin->GetClientSize( &cw, &ch );
4035
4036 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4037 int newRow = YToRow( y - ch + 1 );
4038 if ( newRow == -1 )
4039 {
4040 newRow = 0;
4041 }
4042 else if ( newRow == row )
4043 {
4044 newRow = row - 1;
4045 }
4046
4047 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4048 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4049
4050 return TRUE;
4051 }
4052
4053 return FALSE;
4054 }
4055
4056 bool wxGrid::MovePageDown()
4057 {
4058 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4059
4060 int row = m_currentCellCoords.GetRow();
4061 if ( row < m_numRows )
4062 {
4063 int cw, ch;
4064 m_gridWin->GetClientSize( &cw, &ch );
4065
4066 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4067 int newRow = YToRow( y + ch );
4068 if ( newRow == -1 )
4069 {
4070 newRow = m_numRows - 1;
4071 }
4072 else if ( newRow == row )
4073 {
4074 newRow = row + 1;
4075 }
4076
4077 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4078 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4079
4080 return TRUE;
4081 }
4082
4083 return FALSE;
4084 }
4085
4086 bool wxGrid::MoveCursorUpBlock()
4087 {
4088 if ( m_table &&
4089 m_currentCellCoords != wxGridNoCellCoords &&
4090 m_currentCellCoords.GetRow() > 0 )
4091 {
4092 int row = m_currentCellCoords.GetRow();
4093 int col = m_currentCellCoords.GetCol();
4094
4095 if ( m_table->IsEmptyCell(row, col) )
4096 {
4097 // starting in an empty cell: find the next block of
4098 // non-empty cells
4099 //
4100 while ( row > 0 )
4101 {
4102 row-- ;
4103 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4104 }
4105 }
4106 else if ( m_table->IsEmptyCell(row-1, col) )
4107 {
4108 // starting at the top of a block: find the next block
4109 //
4110 row--;
4111 while ( row > 0 )
4112 {
4113 row-- ;
4114 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4115 }
4116 }
4117 else
4118 {
4119 // starting within a block: find the top of the block
4120 //
4121 while ( row > 0 )
4122 {
4123 row-- ;
4124 if ( m_table->IsEmptyCell(row, col) )
4125 {
4126 row++ ;
4127 break;
4128 }
4129 }
4130 }
4131
4132 MakeCellVisible( row, col );
4133 SetCurrentCell( row, col );
4134
4135 return TRUE;
4136 }
4137
4138 return FALSE;
4139 }
4140
4141 bool wxGrid::MoveCursorDownBlock()
4142 {
4143 if ( m_table &&
4144 m_currentCellCoords != wxGridNoCellCoords &&
4145 m_currentCellCoords.GetRow() < m_numRows-1 )
4146 {
4147 int row = m_currentCellCoords.GetRow();
4148 int col = m_currentCellCoords.GetCol();
4149
4150 if ( m_table->IsEmptyCell(row, col) )
4151 {
4152 // starting in an empty cell: find the next block of
4153 // non-empty cells
4154 //
4155 while ( row < m_numRows-1 )
4156 {
4157 row++ ;
4158 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4159 }
4160 }
4161 else if ( m_table->IsEmptyCell(row+1, col) )
4162 {
4163 // starting at the bottom of a block: find the next block
4164 //
4165 row++;
4166 while ( row < m_numRows-1 )
4167 {
4168 row++ ;
4169 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4170 }
4171 }
4172 else
4173 {
4174 // starting within a block: find the bottom of the block
4175 //
4176 while ( row < m_numRows-1 )
4177 {
4178 row++ ;
4179 if ( m_table->IsEmptyCell(row, col) )
4180 {
4181 row-- ;
4182 break;
4183 }
4184 }
4185 }
4186
4187 MakeCellVisible( row, col );
4188 SetCurrentCell( row, col );
4189
4190 return TRUE;
4191 }
4192
4193 return FALSE;
4194 }
4195
4196 bool wxGrid::MoveCursorLeftBlock()
4197 {
4198 if ( m_table &&
4199 m_currentCellCoords != wxGridNoCellCoords &&
4200 m_currentCellCoords.GetCol() > 0 )
4201 {
4202 int row = m_currentCellCoords.GetRow();
4203 int col = m_currentCellCoords.GetCol();
4204
4205 if ( m_table->IsEmptyCell(row, col) )
4206 {
4207 // starting in an empty cell: find the next block of
4208 // non-empty cells
4209 //
4210 while ( col > 0 )
4211 {
4212 col-- ;
4213 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4214 }
4215 }
4216 else if ( m_table->IsEmptyCell(row, col-1) )
4217 {
4218 // starting at the left of a block: find the next block
4219 //
4220 col--;
4221 while ( col > 0 )
4222 {
4223 col-- ;
4224 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4225 }
4226 }
4227 else
4228 {
4229 // starting within a block: find the left of the block
4230 //
4231 while ( col > 0 )
4232 {
4233 col-- ;
4234 if ( m_table->IsEmptyCell(row, col) )
4235 {
4236 col++ ;
4237 break;
4238 }
4239 }
4240 }
4241
4242 MakeCellVisible( row, col );
4243 SetCurrentCell( row, col );
4244
4245 return TRUE;
4246 }
4247
4248 return FALSE;
4249 }
4250
4251 bool wxGrid::MoveCursorRightBlock()
4252 {
4253 if ( m_table &&
4254 m_currentCellCoords != wxGridNoCellCoords &&
4255 m_currentCellCoords.GetCol() < m_numCols-1 )
4256 {
4257 int row = m_currentCellCoords.GetRow();
4258 int col = m_currentCellCoords.GetCol();
4259
4260 if ( m_table->IsEmptyCell(row, col) )
4261 {
4262 // starting in an empty cell: find the next block of
4263 // non-empty cells
4264 //
4265 while ( col < m_numCols-1 )
4266 {
4267 col++ ;
4268 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4269 }
4270 }
4271 else if ( m_table->IsEmptyCell(row, col+1) )
4272 {
4273 // starting at the right of a block: find the next block
4274 //
4275 col++;
4276 while ( col < m_numCols-1 )
4277 {
4278 col++ ;
4279 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4280 }
4281 }
4282 else
4283 {
4284 // starting within a block: find the right of the block
4285 //
4286 while ( col < m_numCols-1 )
4287 {
4288 col++ ;
4289 if ( m_table->IsEmptyCell(row, col) )
4290 {
4291 col-- ;
4292 break;
4293 }
4294 }
4295 }
4296
4297 MakeCellVisible( row, col );
4298 SetCurrentCell( row, col );
4299
4300 return TRUE;
4301 }
4302
4303 return FALSE;
4304 }
4305
4306
4307
4308 //
4309 // ------ Label values and formatting
4310 //
4311
4312 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4313 {
4314 *horiz = m_rowLabelHorizAlign;
4315 *vert = m_rowLabelVertAlign;
4316 }
4317
4318 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4319 {
4320 *horiz = m_colLabelHorizAlign;
4321 *vert = m_colLabelVertAlign;
4322 }
4323
4324 wxString wxGrid::GetRowLabelValue( int row )
4325 {
4326 if ( m_table )
4327 {
4328 return m_table->GetRowLabelValue( row );
4329 }
4330 else
4331 {
4332 wxString s;
4333 s << row;
4334 return s;
4335 }
4336 }
4337
4338 wxString wxGrid::GetColLabelValue( int col )
4339 {
4340 if ( m_table )
4341 {
4342 return m_table->GetColLabelValue( col );
4343 }
4344 else
4345 {
4346 wxString s;
4347 s << col;
4348 return s;
4349 }
4350 }
4351
4352
4353 void wxGrid::SetRowLabelSize( int width )
4354 {
4355 width = wxMax( width, 0 );
4356 if ( width != m_rowLabelWidth )
4357 {
4358 if ( width == 0 )
4359 {
4360 m_rowLabelWin->Show( FALSE );
4361 m_cornerLabelWin->Show( FALSE );
4362 }
4363 else if ( m_rowLabelWidth == 0 )
4364 {
4365 m_rowLabelWin->Show( TRUE );
4366 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
4367 }
4368
4369 m_rowLabelWidth = width;
4370 CalcWindowSizes();
4371 Refresh( TRUE );
4372 }
4373 }
4374
4375
4376 void wxGrid::SetColLabelSize( int height )
4377 {
4378 height = wxMax( height, 0 );
4379 if ( height != m_colLabelHeight )
4380 {
4381 if ( height == 0 )
4382 {
4383 m_colLabelWin->Show( FALSE );
4384 m_cornerLabelWin->Show( FALSE );
4385 }
4386 else if ( m_colLabelHeight == 0 )
4387 {
4388 m_colLabelWin->Show( TRUE );
4389 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
4390 }
4391
4392 m_colLabelHeight = height;
4393 CalcWindowSizes();
4394 Refresh( TRUE );
4395 }
4396 }
4397
4398
4399 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4400 {
4401 if ( m_labelBackgroundColour != colour )
4402 {
4403 m_labelBackgroundColour = colour;
4404 m_rowLabelWin->SetBackgroundColour( colour );
4405 m_colLabelWin->SetBackgroundColour( colour );
4406 m_cornerLabelWin->SetBackgroundColour( colour );
4407
4408 if ( !GetBatchCount() )
4409 {
4410 m_rowLabelWin->Refresh();
4411 m_colLabelWin->Refresh();
4412 m_cornerLabelWin->Refresh();
4413 }
4414 }
4415 }
4416
4417 void wxGrid::SetLabelTextColour( const wxColour& colour )
4418 {
4419 if ( m_labelTextColour != colour )
4420 {
4421 m_labelTextColour = colour;
4422 if ( !GetBatchCount() )
4423 {
4424 m_rowLabelWin->Refresh();
4425 m_colLabelWin->Refresh();
4426 }
4427 }
4428 }
4429
4430 void wxGrid::SetLabelFont( const wxFont& font )
4431 {
4432 m_labelFont = font;
4433 if ( !GetBatchCount() )
4434 {
4435 m_rowLabelWin->Refresh();
4436 m_colLabelWin->Refresh();
4437 }
4438 }
4439
4440 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
4441 {
4442 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4443 {
4444 m_rowLabelHorizAlign = horiz;
4445 }
4446
4447 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4448 {
4449 m_rowLabelVertAlign = vert;
4450 }
4451
4452 if ( !GetBatchCount() )
4453 {
4454 m_rowLabelWin->Refresh();
4455 }
4456 }
4457
4458 void wxGrid::SetColLabelAlignment( int horiz, int vert )
4459 {
4460 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4461 {
4462 m_colLabelHorizAlign = horiz;
4463 }
4464
4465 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4466 {
4467 m_colLabelVertAlign = vert;
4468 }
4469
4470 if ( !GetBatchCount() )
4471 {
4472 m_colLabelWin->Refresh();
4473 }
4474 }
4475
4476 void wxGrid::SetRowLabelValue( int row, const wxString& s )
4477 {
4478 if ( m_table )
4479 {
4480 m_table->SetRowLabelValue( row, s );
4481 if ( !GetBatchCount() )
4482 {
4483 wxRect rect = CellToRect( row, 0);
4484 if ( rect.height > 0 )
4485 {
4486 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
4487 rect.x = m_left;
4488 rect.width = m_rowLabelWidth;
4489 m_rowLabelWin->Refresh( TRUE, &rect );
4490 }
4491 }
4492 }
4493 }
4494
4495 void wxGrid::SetColLabelValue( int col, const wxString& s )
4496 {
4497 if ( m_table )
4498 {
4499 m_table->SetColLabelValue( col, s );
4500 if ( !GetBatchCount() )
4501 {
4502 wxRect rect = CellToRect( 0, col );
4503 if ( rect.width > 0 )
4504 {
4505 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
4506 rect.y = m_top;
4507 rect.height = m_colLabelHeight;
4508 m_colLabelWin->Refresh( TRUE, &rect );
4509 }
4510 }
4511 }
4512 }
4513
4514 void wxGrid::SetGridLineColour( const wxColour& colour )
4515 {
4516 if ( m_gridLineColour != colour )
4517 {
4518 m_gridLineColour = colour;
4519
4520 wxClientDC dc( m_gridWin );
4521 PrepareDC( dc );
4522 DrawAllGridLines( dc, wxRegion() );
4523 }
4524 }
4525
4526 void wxGrid::EnableGridLines( bool enable )
4527 {
4528 if ( enable != m_gridLinesEnabled )
4529 {
4530 m_gridLinesEnabled = enable;
4531
4532 if ( !GetBatchCount() )
4533 {
4534 if ( enable )
4535 {
4536 wxClientDC dc( m_gridWin );
4537 PrepareDC( dc );
4538 DrawAllGridLines( dc, wxRegion() );
4539 }
4540 else
4541 {
4542 m_gridWin->Refresh();
4543 }
4544 }
4545 }
4546 }
4547
4548
4549 int wxGrid::GetDefaultRowSize()
4550 {
4551 return m_defaultRowHeight;
4552 }
4553
4554 int wxGrid::GetRowSize( int row )
4555 {
4556 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
4557
4558 return m_rowHeights[row];
4559 }
4560
4561 int wxGrid::GetDefaultColSize()
4562 {
4563 return m_defaultColWidth;
4564 }
4565
4566 int wxGrid::GetColSize( int col )
4567 {
4568 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
4569
4570 return m_colWidths[col];
4571 }
4572
4573 // ============================================================================
4574 // access to the grid attributes: each of them has a default value in the grid
4575 // itself and may be overidden on a per-cell basis
4576 // ============================================================================
4577
4578 // ----------------------------------------------------------------------------
4579 // setting default attributes
4580 // ----------------------------------------------------------------------------
4581
4582 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
4583 {
4584 m_gridWin->SetBackgroundColour(col);
4585 }
4586
4587 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
4588 {
4589 m_gridWin->SetForegroundColour(col);
4590 }
4591
4592 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
4593 {
4594 m_defaultCellHAlign = horiz;
4595 m_defaultCellVAlign = vert;
4596 }
4597
4598 void wxGrid::SetDefaultCellFont( const wxFont& font )
4599 {
4600 m_defaultCellFont = font;
4601 }
4602
4603 // ----------------------------------------------------------------------------
4604 // access to the default attrbiutes
4605 // ----------------------------------------------------------------------------
4606
4607 wxColour wxGrid::GetDefaultCellBackgroundColour()
4608 {
4609 return m_gridWin->GetBackgroundColour();
4610 }
4611
4612 wxColour wxGrid::GetDefaultCellTextColour()
4613 {
4614 return m_gridWin->GetForegroundColour();
4615 }
4616
4617 wxFont wxGrid::GetDefaultCellFont()
4618 {
4619 return m_defaultCellFont;
4620 }
4621
4622 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
4623 {
4624 if ( horiz )
4625 *horiz = m_defaultCellHAlign;
4626 if ( vert )
4627 *vert = m_defaultCellVAlign;
4628 }
4629
4630 // ----------------------------------------------------------------------------
4631 // access to cell attributes
4632 // ----------------------------------------------------------------------------
4633
4634 // TODO VZ: we must cache the attr to allow only retrieveing it once!
4635
4636 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
4637 {
4638 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4639
4640 wxColour colour;
4641 if ( attr && attr->HasBackgroundColour() )
4642 colour = attr->GetBackgroundColour();
4643 else
4644 colour = GetDefaultCellBackgroundColour();
4645
4646 attr->SafeDecRef();
4647
4648 return colour;
4649 }
4650
4651 wxColour wxGrid::GetCellTextColour( int row, int col )
4652 {
4653 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4654
4655 wxColour colour;
4656 if ( attr && attr->HasTextColour() )
4657 colour = attr->GetTextColour();
4658 else
4659 colour = GetDefaultCellTextColour();
4660
4661 attr->SafeDecRef();
4662
4663 return colour;
4664 }
4665
4666 wxFont wxGrid::GetCellFont( int row, int col )
4667 {
4668 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4669
4670 wxFont font;
4671 if ( attr && attr->HasFont() )
4672 font = attr->GetFont();
4673 else
4674 font = GetDefaultCellFont();
4675
4676 attr->SafeDecRef();
4677
4678 return font;
4679 }
4680
4681 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
4682 {
4683 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4684
4685 if ( attr && attr->HasAlignment() )
4686 attr->GetAlignment(horiz, vert);
4687 else
4688 GetDefaultCellAlignment(horiz, vert);
4689
4690 attr->SafeDecRef();
4691 }
4692
4693 // ----------------------------------------------------------------------------
4694 // setting cell attributes: this is forwarded to the table
4695 // ----------------------------------------------------------------------------
4696
4697 bool wxGrid::CanHaveAttributes()
4698 {
4699 if ( !m_table )
4700 {
4701 return FALSE;
4702 }
4703
4704 if ( !m_table->GetAttrProvider() )
4705 {
4706 // use the default attr provider by default
4707 // (another choice would be to just return FALSE thus forcing the user
4708 // to it himself)
4709 m_table->SetAttrProvider(new wxGridCellAttrProvider);
4710 }
4711
4712 return TRUE;
4713 }
4714
4715 wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
4716 {
4717 wxGridCellAttr *attr = m_table->GetAttr(row, col);
4718 if ( !attr )
4719 {
4720 attr = new wxGridCellAttr;
4721
4722 // artificially inc the ref count to match DecRef() in caller
4723 attr->IncRef();
4724
4725 m_table->SetAttr(attr, row, col);
4726 }
4727
4728 return attr;
4729 }
4730
4731 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
4732 {
4733 if ( CanHaveAttributes() )
4734 {
4735 wxGridCellAttr *attr = GetCellAttr(row, col);
4736 attr->SetBackgroundColour(colour);
4737 attr->DecRef();
4738 }
4739 }
4740
4741 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
4742 {
4743 if ( CanHaveAttributes() )
4744 {
4745 wxGridCellAttr *attr = GetCellAttr(row, col);
4746 attr->SetTextColour(colour);
4747 attr->DecRef();
4748 }
4749 }
4750
4751 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
4752 {
4753 if ( CanHaveAttributes() )
4754 {
4755 wxGridCellAttr *attr = GetCellAttr(row, col);
4756 attr->SetFont(font);
4757 attr->DecRef();
4758 }
4759 }
4760
4761 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
4762 {
4763 if ( CanHaveAttributes() )
4764 {
4765 wxGridCellAttr *attr = GetCellAttr(row, col);
4766 attr->SetAlignment(horiz, vert);
4767 attr->DecRef();
4768 }
4769 }
4770
4771 // ----------------------------------------------------------------------------
4772 // row/col size
4773 // ----------------------------------------------------------------------------
4774
4775 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
4776 {
4777 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
4778
4779 if ( resizeExistingRows )
4780 {
4781 int row;
4782 int bottom = 0;
4783 for ( row = 0; row < m_numRows; row++ )
4784 {
4785 m_rowHeights[row] = m_defaultRowHeight;
4786 bottom += m_defaultRowHeight;
4787 m_rowBottoms[row] = bottom;
4788 }
4789 CalcDimensions();
4790 }
4791 }
4792
4793 void wxGrid::SetRowSize( int row, int height )
4794 {
4795 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
4796
4797 int i;
4798
4799 int h = wxMax( 0, height );
4800 int diff = h - m_rowHeights[row];
4801
4802 m_rowHeights[row] = h;
4803 for ( i = row; i < m_numRows; i++ )
4804 {
4805 m_rowBottoms[i] += diff;
4806 }
4807 CalcDimensions();
4808 }
4809
4810 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4811 {
4812 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4813
4814 if ( resizeExistingCols )
4815 {
4816 int col;
4817 int right = 0;
4818 for ( col = 0; col < m_numCols; col++ )
4819 {
4820 m_colWidths[col] = m_defaultColWidth;
4821 right += m_defaultColWidth;
4822 m_colRights[col] = right;
4823 }
4824 CalcDimensions();
4825 }
4826 }
4827
4828 void wxGrid::SetColSize( int col, int width )
4829 {
4830 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
4831
4832 int i;
4833
4834 int w = wxMax( 0, width );
4835 int diff = w - m_colWidths[col];
4836 m_colWidths[col] = w;
4837
4838 for ( i = col; i < m_numCols; i++ )
4839 {
4840 m_colRights[i] += diff;
4841 }
4842 CalcDimensions();
4843 }
4844
4845
4846 //
4847 // ------ cell value accessor functions
4848 //
4849
4850 void wxGrid::SetCellValue( int row, int col, const wxString& s )
4851 {
4852 if ( m_table )
4853 {
4854 m_table->SetValue( row, col, s.c_str() );
4855 if ( !GetBatchCount() )
4856 {
4857 wxClientDC dc( m_gridWin );
4858 PrepareDC( dc );
4859 DrawCell( dc, wxGridCellCoords(row, col) );
4860 }
4861
4862 #if 0 // TODO: edit in place
4863
4864 if ( m_currentCellCoords.GetRow() == row &&
4865 m_currentCellCoords.GetCol() == col )
4866 {
4867 SetEditControlValue( s );
4868 }
4869 #endif
4870
4871 }
4872 }
4873
4874
4875 //
4876 // ------ Block, row and col selection
4877 //
4878
4879 void wxGrid::SelectRow( int row, bool addToSelected )
4880 {
4881 wxRect r;
4882
4883 if ( IsSelection() && addToSelected )
4884 {
4885 wxRect rect[4];
4886 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4887 int i;
4888
4889 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4890 wxCoord oldTop = m_selectedTopLeft.GetRow();
4891 wxCoord oldRight = m_selectedBottomRight.GetCol();
4892 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4893
4894 if ( oldTop > row )
4895 {
4896 need_refresh[0] = TRUE;
4897 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
4898 wxGridCellCoords ( oldTop - 1,
4899 m_numCols - 1 ) );
4900 m_selectedTopLeft.SetRow( row );
4901 }
4902
4903 if ( oldLeft > 0 )
4904 {
4905 need_refresh[1] = TRUE;
4906 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
4907 wxGridCellCoords ( oldBottom,
4908 oldLeft - 1 ) );
4909
4910 m_selectedTopLeft.SetCol( 0 );
4911 }
4912
4913 if ( oldBottom < row )
4914 {
4915 need_refresh[2] = TRUE;
4916 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
4917 wxGridCellCoords ( row,
4918 m_numCols - 1 ) );
4919 m_selectedBottomRight.SetRow( row );
4920 }
4921
4922 if ( oldRight < m_numCols - 1 )
4923 {
4924 need_refresh[3] = TRUE;
4925 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
4926 oldRight + 1 ),
4927 wxGridCellCoords ( oldBottom,
4928 m_numCols - 1 ) );
4929 m_selectedBottomRight.SetCol( m_numCols - 1 );
4930 }
4931
4932 for (i = 0; i < 4; i++ )
4933 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4934 m_gridWin->Refresh( FALSE, &(rect[i]) );
4935 }
4936 else
4937 {
4938 r = SelectionToDeviceRect();
4939 ClearSelection();
4940 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4941
4942 m_selectedTopLeft.Set( row, 0 );
4943 m_selectedBottomRight.Set( row, m_numCols-1 );
4944 r = SelectionToDeviceRect();
4945 m_gridWin->Refresh( FALSE, &r );
4946 }
4947
4948 wxGridRangeSelectEvent gridEvt( GetId(),
4949 EVT_GRID_RANGE_SELECT,
4950 this,
4951 m_selectedTopLeft,
4952 m_selectedBottomRight );
4953
4954 GetEventHandler()->ProcessEvent(gridEvt);
4955 }
4956
4957
4958 void wxGrid::SelectCol( int col, bool addToSelected )
4959 {
4960 if ( IsSelection() && addToSelected )
4961 {
4962 wxRect rect[4];
4963 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4964 int i;
4965
4966 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4967 wxCoord oldTop = m_selectedTopLeft.GetRow();
4968 wxCoord oldRight = m_selectedBottomRight.GetCol();
4969 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4970
4971 if ( oldLeft > col )
4972 {
4973 need_refresh[0] = TRUE;
4974 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
4975 wxGridCellCoords ( m_numRows - 1,
4976 oldLeft - 1 ) );
4977 m_selectedTopLeft.SetCol( col );
4978 }
4979
4980 if ( oldTop > 0 )
4981 {
4982 need_refresh[1] = TRUE;
4983 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
4984 wxGridCellCoords ( oldTop - 1,
4985 oldRight ) );
4986 m_selectedTopLeft.SetRow( 0 );
4987 }
4988
4989 if ( oldRight < col )
4990 {
4991 need_refresh[2] = TRUE;
4992 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
4993 wxGridCellCoords ( m_numRows - 1,
4994 col ) );
4995 m_selectedBottomRight.SetCol( col );
4996 }
4997
4998 if ( oldBottom < m_numRows - 1 )
4999 {
5000 need_refresh[3] = TRUE;
5001 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
5002 oldLeft ),
5003 wxGridCellCoords ( m_numRows - 1,
5004 oldRight ) );
5005 m_selectedBottomRight.SetRow( m_numRows - 1 );
5006 }
5007
5008 for (i = 0; i < 4; i++ )
5009 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5010 m_gridWin->Refresh( FALSE, &(rect[i]) );
5011 }
5012 else
5013 {
5014 wxRect r;
5015
5016 r = SelectionToDeviceRect();
5017 ClearSelection();
5018 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
5019
5020 m_selectedTopLeft.Set( 0, col );
5021 m_selectedBottomRight.Set( m_numRows-1, col );
5022 r = SelectionToDeviceRect();
5023 m_gridWin->Refresh( FALSE, &r );
5024 }
5025
5026 wxGridRangeSelectEvent gridEvt( GetId(),
5027 EVT_GRID_RANGE_SELECT,
5028 this,
5029 m_selectedTopLeft,
5030 m_selectedBottomRight );
5031
5032 GetEventHandler()->ProcessEvent(gridEvt);
5033 }
5034
5035
5036 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
5037 {
5038 int temp;
5039 wxGridCellCoords updateTopLeft, updateBottomRight;
5040
5041 if ( topRow > bottomRow )
5042 {
5043 temp = topRow;
5044 topRow = bottomRow;
5045 bottomRow = temp;
5046 }
5047
5048 if ( leftCol > rightCol )
5049 {
5050 temp = leftCol;
5051 leftCol = rightCol;
5052 rightCol = temp;
5053 }
5054
5055 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5056 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5057
5058 if ( m_selectedTopLeft != updateTopLeft ||
5059 m_selectedBottomRight != updateBottomRight )
5060 {
5061 // Compute two optimal update rectangles:
5062 // Either one rectangle is a real subset of the
5063 // other, or they are (almost) disjoint!
5064 wxRect rect[4];
5065 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5066 int i;
5067
5068 // Store intermediate values
5069 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5070 wxCoord oldTop = m_selectedTopLeft.GetRow();
5071 wxCoord oldRight = m_selectedBottomRight.GetCol();
5072 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5073
5074 // Determine the outer/inner coordinates.
5075 if (oldLeft > leftCol)
5076 {
5077 temp = oldLeft;
5078 oldLeft = leftCol;
5079 leftCol = temp;
5080 }
5081 if (oldTop > topRow )
5082 {
5083 temp = oldTop;
5084 oldTop = topRow;
5085 topRow = temp;
5086 }
5087 if (oldRight < rightCol )
5088 {
5089 temp = oldRight;
5090 oldRight = rightCol;
5091 rightCol = temp;
5092 }
5093 if (oldBottom < bottomRow)
5094 {
5095 temp = oldBottom;
5096 oldBottom = bottomRow;
5097 bottomRow = temp;
5098 }
5099
5100 // Now, either the stuff marked old is the outer
5101 // rectangle or we don't have a situation where one
5102 // is contained in the other.
5103
5104 if ( oldLeft < leftCol )
5105 {
5106 need_refresh[0] = TRUE;
5107 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5108 oldLeft ),
5109 wxGridCellCoords ( oldBottom,
5110 leftCol - 1 ) );
5111 }
5112
5113 if ( oldTop < topRow )
5114 {
5115 need_refresh[1] = TRUE;
5116 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5117 leftCol ),
5118 wxGridCellCoords ( topRow - 1,
5119 rightCol ) );
5120 }
5121
5122 if ( oldRight > rightCol )
5123 {
5124 need_refresh[2] = TRUE;
5125 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5126 rightCol + 1 ),
5127 wxGridCellCoords ( oldBottom,
5128 oldRight ) );
5129 }
5130
5131 if ( oldBottom > bottomRow )
5132 {
5133 need_refresh[3] = TRUE;
5134 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5135 leftCol ),
5136 wxGridCellCoords ( oldBottom,
5137 rightCol ) );
5138 }
5139
5140
5141 // Change Selection
5142 m_selectedTopLeft = updateTopLeft;
5143 m_selectedBottomRight = updateBottomRight;
5144
5145 // various Refresh() calls
5146 for (i = 0; i < 4; i++ )
5147 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5148 m_gridWin->Refresh( FALSE, &(rect[i]) );
5149 }
5150
5151 // only generate an event if the block is not being selected by
5152 // dragging the mouse (in which case the event will be generated in
5153 // the mouse event handler)
5154 if ( !m_isDragging )
5155 {
5156 wxGridRangeSelectEvent gridEvt( GetId(),
5157 EVT_GRID_RANGE_SELECT,
5158 this,
5159 m_selectedTopLeft,
5160 m_selectedBottomRight );
5161
5162 GetEventHandler()->ProcessEvent(gridEvt);
5163 }
5164 }
5165
5166 void wxGrid::SelectAll()
5167 {
5168 m_selectedTopLeft.Set( 0, 0 );
5169 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
5170
5171 m_gridWin->Refresh();
5172 }
5173
5174
5175 void wxGrid::ClearSelection()
5176 {
5177 m_selectedTopLeft = wxGridNoCellCoords;
5178 m_selectedBottomRight = wxGridNoCellCoords;
5179 }
5180
5181
5182 // This function returns the rectangle that encloses the given block
5183 // in device coords clipped to the client size of the grid window.
5184 //
5185 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
5186 const wxGridCellCoords &bottomRight )
5187 {
5188 wxRect rect( wxGridNoCellRect );
5189 wxRect cellRect;
5190
5191 cellRect = CellToRect( topLeft );
5192 if ( cellRect != wxGridNoCellRect )
5193 {
5194 rect = cellRect;
5195 }
5196 else
5197 {
5198 rect = wxRect( 0, 0, 0, 0 );
5199 }
5200
5201 cellRect = CellToRect( bottomRight );
5202 if ( cellRect != wxGridNoCellRect )
5203 {
5204 rect += cellRect;
5205 }
5206 else
5207 {
5208 return wxGridNoCellRect;
5209 }
5210
5211 // convert to scrolled coords
5212 //
5213 int left, top, right, bottom;
5214 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
5215 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
5216
5217 int cw, ch;
5218 m_gridWin->GetClientSize( &cw, &ch );
5219
5220 rect.SetLeft( wxMax(0, left) );
5221 rect.SetTop( wxMax(0, top) );
5222 rect.SetRight( wxMin(cw, right) );
5223 rect.SetBottom( wxMin(ch, bottom) );
5224
5225 return rect;
5226 }
5227
5228
5229
5230 //
5231 // ------ Grid event classes
5232 //
5233
5234 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5235
5236 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5237 int row, int col, int x, int y,
5238 bool control, bool shift, bool alt, bool meta )
5239 : wxNotifyEvent( type, id )
5240 {
5241 m_row = row;
5242 m_col = col;
5243 m_x = x;
5244 m_y = y;
5245 m_control = control;
5246 m_shift = shift;
5247 m_alt = alt;
5248 m_meta = meta;
5249
5250 SetEventObject(obj);
5251 }
5252
5253
5254 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5255
5256 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5257 int rowOrCol, int x, int y,
5258 bool control, bool shift, bool alt, bool meta )
5259 : wxNotifyEvent( type, id )
5260 {
5261 m_rowOrCol = rowOrCol;
5262 m_x = x;
5263 m_y = y;
5264 m_control = control;
5265 m_shift = shift;
5266 m_alt = alt;
5267 m_meta = meta;
5268
5269 SetEventObject(obj);
5270 }
5271
5272
5273 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5274
5275 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
5276 const wxGridCellCoords& topLeft,
5277 const wxGridCellCoords& bottomRight,
5278 bool control, bool shift, bool alt, bool meta )
5279 : wxNotifyEvent( type, id )
5280 {
5281 m_topLeft = topLeft;
5282 m_bottomRight = bottomRight;
5283 m_control = control;
5284 m_shift = shift;
5285 m_alt = alt;
5286 m_meta = meta;
5287
5288 SetEventObject(obj);
5289 }
5290
5291
5292 #endif // ifndef wxUSE_NEW_GRID
5293