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