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