removed debugging messages I just added by default
[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 wxLogTrace(_T("grid"),
2118 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
2119 win == m_colLabelWin ? _T("colLabelWin")
2120 : win ? _T("rowLabelWin")
2121 : _T("gridWin"),
2122 cursorModes[m_cursorMode], cursorModes[mode]);
2123 #endif // __WXDEBUG__
2124
2125 if ( mode == m_cursorMode )
2126 return;
2127
2128 if ( !win )
2129 {
2130 // by default use the grid itself
2131 win = m_gridWin;
2132 }
2133
2134 if ( m_winCapture )
2135 {
2136 m_winCapture->ReleaseMouse();
2137 m_winCapture = (wxWindow *)NULL;
2138 }
2139
2140 m_cursorMode = mode;
2141
2142 switch ( m_cursorMode )
2143 {
2144 case WXGRID_CURSOR_RESIZE_ROW:
2145 win->SetCursor( m_rowResizeCursor );
2146 break;
2147
2148 case WXGRID_CURSOR_RESIZE_COL:
2149 win->SetCursor( m_colResizeCursor );
2150 break;
2151
2152 default:
2153 win->SetCursor( *wxSTANDARD_CURSOR );
2154 }
2155
2156 // we need to capture mouse when resizing
2157 bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
2158 m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
2159
2160 if ( captureMouse && resize )
2161 {
2162 win->CaptureMouse();
2163 m_winCapture = win;
2164 }
2165 }
2166
2167 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
2168 {
2169 int x, y;
2170 wxPoint pos( event.GetPosition() );
2171 CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
2172
2173 wxGridCellCoords coords;
2174 XYToCell( x, y, coords );
2175
2176 if ( event.Dragging() )
2177 {
2178 m_isDragging = TRUE;
2179 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2180 {
2181 // Hide the edit control, so it
2182 // won't interfer with drag-shrinking.
2183 if ( IsCellEditControlEnabled() )
2184 HideCellEditControl();
2185 if ( coords != wxGridNoCellCoords )
2186 {
2187 if ( !IsSelection() )
2188 {
2189 SelectBlock( coords, coords );
2190 }
2191 else
2192 {
2193 SelectBlock( m_currentCellCoords, coords );
2194 }
2195 }
2196 }
2197 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2198 {
2199 int cw, ch, left, dummy;
2200 m_gridWin->GetClientSize( &cw, &ch );
2201 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2202
2203 wxClientDC dc( m_gridWin );
2204 PrepareDC( dc );
2205 dc.SetLogicalFunction(wxINVERT);
2206 if ( m_dragLastPos >= 0 )
2207 {
2208 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2209 }
2210 dc.DrawLine( left, y, left+cw, y );
2211 m_dragLastPos = y;
2212 }
2213 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2214 {
2215 int cw, ch, dummy, top;
2216 m_gridWin->GetClientSize( &cw, &ch );
2217 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2218
2219 wxClientDC dc( m_gridWin );
2220 PrepareDC( dc );
2221 dc.SetLogicalFunction(wxINVERT);
2222 if ( m_dragLastPos >= 0 )
2223 {
2224 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2225 }
2226 dc.DrawLine( x, top, x, top+ch );
2227 m_dragLastPos = x;
2228 }
2229
2230 return;
2231 }
2232
2233 m_isDragging = FALSE;
2234
2235 if ( coords != wxGridNoCellCoords )
2236 {
2237 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
2238 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
2239 // wxGTK
2240 #if 0
2241 if ( event.Entering() || event.Leaving() )
2242 {
2243 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2244 m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
2245 }
2246 else
2247 #endif // 0
2248
2249 // ------------ Left button pressed
2250 //
2251 if ( event.LeftDown() )
2252 {
2253 if ( event.ShiftDown() )
2254 {
2255 SelectBlock( m_currentCellCoords, coords );
2256 }
2257 else if ( XToEdgeOfCol(x) < 0 &&
2258 YToEdgeOfRow(y) < 0 )
2259 {
2260 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK,
2261 coords.GetRow(),
2262 coords.GetCol(),
2263 event ) )
2264 {
2265 MakeCellVisible( coords );
2266 SetCurrentCell( coords );
2267 }
2268 }
2269 }
2270
2271
2272 // ------------ Left double click
2273 //
2274 else if ( event.LeftDClick() )
2275 {
2276 if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
2277 {
2278 SendEvent( EVT_GRID_CELL_LEFT_DCLICK,
2279 coords.GetRow(),
2280 coords.GetCol(),
2281 event );
2282 }
2283 }
2284
2285
2286 // ------------ Left button released
2287 //
2288 else if ( event.LeftUp() )
2289 {
2290 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2291 {
2292 if ( IsSelection() )
2293 {
2294 SendEvent( EVT_GRID_RANGE_SELECT, -1, -1, event );
2295 }
2296
2297 // Show the edit control, if it has
2298 // been hidden for drag-shrinking.
2299 if ( IsCellEditControlEnabled() )
2300 ShowCellEditControl();
2301 }
2302 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
2303 {
2304 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2305 DoEndDragResizeRow();
2306
2307 // Note: we are ending the event *after* doing
2308 // default processing in this case
2309 //
2310 SendEvent( EVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
2311 }
2312 else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
2313 {
2314 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2315 DoEndDragResizeCol();
2316
2317 // Note: we are ending the event *after* doing
2318 // default processing in this case
2319 //
2320 SendEvent( EVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
2321 }
2322
2323 m_dragLastPos = -1;
2324 }
2325
2326
2327 // ------------ Right button down
2328 //
2329 else if ( event.RightDown() )
2330 {
2331 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK,
2332 coords.GetRow(),
2333 coords.GetCol(),
2334 event ) )
2335 {
2336 // no default action at the moment
2337 }
2338 }
2339
2340
2341 // ------------ Right double click
2342 //
2343 else if ( event.RightDClick() )
2344 {
2345 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK,
2346 coords.GetRow(),
2347 coords.GetCol(),
2348 event ) )
2349 {
2350 // no default action at the moment
2351 }
2352 }
2353
2354 // ------------ Moving and no button action
2355 //
2356 else if ( event.Moving() && !event.IsButton() )
2357 {
2358 int dragRow = YToEdgeOfRow( y );
2359 int dragCol = XToEdgeOfCol( x );
2360
2361 // Dragging on the corner of a cell to resize in both
2362 // directions is not implemented yet...
2363 //
2364 if ( dragRow >= 0 && dragCol >= 0 )
2365 {
2366 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2367 return;
2368 }
2369
2370 if ( dragRow >= 0 )
2371 {
2372 m_dragRowOrCol = dragRow;
2373
2374 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2375 {
2376 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
2377 }
2378
2379 return;
2380 }
2381
2382 if ( dragCol >= 0 )
2383 {
2384 m_dragRowOrCol = dragCol;
2385
2386 if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
2387 {
2388 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
2389 }
2390
2391 return;
2392 }
2393
2394 // Neither on a row or col edge
2395 //
2396 if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
2397 {
2398 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
2399 }
2400 }
2401 }
2402 }
2403
2404
2405 void wxGrid::DoEndDragResizeRow()
2406 {
2407 if ( m_dragLastPos >= 0 )
2408 {
2409 // erase the last line and resize the row
2410 //
2411 int cw, ch, left, dummy;
2412 m_gridWin->GetClientSize( &cw, &ch );
2413 CalcUnscrolledPosition( 0, 0, &left, &dummy );
2414
2415 wxClientDC dc( m_gridWin );
2416 PrepareDC( dc );
2417 dc.SetLogicalFunction( wxINVERT );
2418 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
2419 HideCellEditControl();
2420
2421 int rowTop = m_rowBottoms[m_dragRowOrCol] - m_rowHeights[m_dragRowOrCol];
2422 SetRowSize( m_dragRowOrCol,
2423 wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
2424
2425 if ( !GetBatchCount() )
2426 {
2427 // Only needed to get the correct rect.y:
2428 wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
2429 rect.x = 0;
2430 CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
2431 rect.width = m_rowLabelWidth;
2432 rect.height = ch - rect.y;
2433 m_rowLabelWin->Refresh( TRUE, &rect );
2434 rect.width = cw;
2435 m_gridWin->Refresh( FALSE, &rect );
2436 }
2437
2438 ShowCellEditControl();
2439 }
2440 }
2441
2442
2443 void wxGrid::DoEndDragResizeCol()
2444 {
2445 if ( m_dragLastPos >= 0 )
2446 {
2447 // erase the last line and resize the col
2448 //
2449 int cw, ch, dummy, top;
2450 m_gridWin->GetClientSize( &cw, &ch );
2451 CalcUnscrolledPosition( 0, 0, &dummy, &top );
2452
2453 wxClientDC dc( m_gridWin );
2454 PrepareDC( dc );
2455 dc.SetLogicalFunction( wxINVERT );
2456 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
2457 HideCellEditControl();
2458
2459 int colLeft = m_colRights[m_dragRowOrCol] - m_colWidths[m_dragRowOrCol];
2460 SetColSize( m_dragRowOrCol,
2461 wxMax( m_dragLastPos - colLeft, WXGRID_MIN_COL_WIDTH ) );
2462
2463 if ( !GetBatchCount() )
2464 {
2465 // Only needed to get the correct rect.x:
2466 wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
2467 rect.y = 0;
2468 CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
2469 rect.width = cw - rect.x;
2470 rect.height = m_colLabelHeight;
2471 m_colLabelWin->Refresh( TRUE, &rect );
2472 rect.height = ch;
2473 m_gridWin->Refresh( FALSE, &rect );
2474 }
2475
2476 ShowCellEditControl();
2477 }
2478 }
2479
2480
2481
2482 //
2483 // ------ interaction with data model
2484 //
2485 bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
2486 {
2487 switch ( msg.GetId() )
2488 {
2489 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
2490 return GetModelValues();
2491
2492 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
2493 return SetModelValues();
2494
2495 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
2496 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
2497 case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
2498 case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
2499 case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
2500 case wxGRIDTABLE_NOTIFY_COLS_DELETED:
2501 return Redimension( msg );
2502
2503 default:
2504 return FALSE;
2505 }
2506 }
2507
2508
2509
2510 // The behaviour of this function depends on the grid table class
2511 // Clear() function. For the default wxGridStringTable class the
2512 // behavious is to replace all cell contents with wxEmptyString but
2513 // not to change the number of rows or cols.
2514 //
2515 void wxGrid::ClearGrid()
2516 {
2517 if ( m_table )
2518 {
2519 m_table->Clear();
2520 SetEditControlValue();
2521 if ( !GetBatchCount() ) m_gridWin->Refresh();
2522 }
2523 }
2524
2525
2526 bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2527 {
2528 // TODO: something with updateLabels flag
2529
2530 if ( !m_created )
2531 {
2532 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2533 return FALSE;
2534 }
2535
2536 if ( m_table )
2537 {
2538 bool ok = m_table->InsertRows( pos, numRows );
2539
2540 // the table will have sent the results of the insert row
2541 // operation to this view object as a grid table message
2542 //
2543 if ( ok )
2544 {
2545 if ( m_numCols == 0 )
2546 {
2547 m_table->AppendCols( WXGRID_DEFAULT_NUMBER_COLS );
2548 //
2549 // TODO: perhaps instead of appending the default number of cols
2550 // we should remember what the last non-zero number of cols was ?
2551 //
2552 }
2553
2554 if ( m_currentCellCoords == wxGridNoCellCoords )
2555 {
2556 // if we have just inserted cols into an empty grid the current
2557 // cell will be undefined...
2558 //
2559 SetCurrentCell( 0, 0 );
2560 }
2561
2562 ClearSelection();
2563 if ( !GetBatchCount() ) Refresh();
2564 }
2565
2566 SetEditControlValue();
2567 return ok;
2568 }
2569 else
2570 {
2571 return FALSE;
2572 }
2573 }
2574
2575
2576 bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
2577 {
2578 // TODO: something with updateLabels flag
2579
2580 if ( !m_created )
2581 {
2582 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2583 return FALSE;
2584 }
2585
2586 if ( m_table && m_table->AppendRows( numRows ) )
2587 {
2588 if ( m_currentCellCoords == wxGridNoCellCoords )
2589 {
2590 // if we have just inserted cols into an empty grid the current
2591 // cell will be undefined...
2592 //
2593 SetCurrentCell( 0, 0 );
2594 }
2595
2596 // the table will have sent the results of the append row
2597 // operation to this view object as a grid table message
2598 //
2599 ClearSelection();
2600 if ( !GetBatchCount() ) Refresh();
2601 return TRUE;
2602 }
2603 else
2604 {
2605 return FALSE;
2606 }
2607 }
2608
2609
2610 bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
2611 {
2612 // TODO: something with updateLabels flag
2613
2614 if ( !m_created )
2615 {
2616 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2617 return FALSE;
2618 }
2619
2620 if ( m_table && m_table->DeleteRows( pos, numRows ) )
2621 {
2622 // the table will have sent the results of the delete row
2623 // operation to this view object as a grid table message
2624 //
2625 if ( m_numRows > 0 )
2626 SetEditControlValue();
2627 else
2628 HideCellEditControl();
2629
2630 ClearSelection();
2631 if ( !GetBatchCount() ) Refresh();
2632 return TRUE;
2633 }
2634 else
2635 {
2636 return FALSE;
2637 }
2638 }
2639
2640
2641 bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2642 {
2643 // TODO: something with updateLabels flag
2644
2645 if ( !m_created )
2646 {
2647 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2648 return FALSE;
2649 }
2650
2651 if ( m_table )
2652 {
2653 HideCellEditControl();
2654 bool ok = m_table->InsertCols( pos, numCols );
2655
2656 // the table will have sent the results of the insert col
2657 // operation to this view object as a grid table message
2658 //
2659 if ( ok )
2660 {
2661 if ( m_currentCellCoords == wxGridNoCellCoords )
2662 {
2663 // if we have just inserted cols into an empty grid the current
2664 // cell will be undefined...
2665 //
2666 SetCurrentCell( 0, 0 );
2667 }
2668
2669 ClearSelection();
2670 if ( !GetBatchCount() ) Refresh();
2671 }
2672
2673 SetEditControlValue();
2674 return ok;
2675 }
2676 else
2677 {
2678 return FALSE;
2679 }
2680 }
2681
2682
2683 bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
2684 {
2685 // TODO: something with updateLabels flag
2686
2687 if ( !m_created )
2688 {
2689 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2690 return FALSE;
2691 }
2692
2693 if ( m_table && m_table->AppendCols( numCols ) )
2694 {
2695 // the table will have sent the results of the append col
2696 // operation to this view object as a grid table message
2697 //
2698 if ( m_currentCellCoords == wxGridNoCellCoords )
2699 {
2700 // if we have just inserted cols into an empty grid the current
2701 // cell will be undefined...
2702 //
2703 SetCurrentCell( 0, 0 );
2704 }
2705
2706 ClearSelection();
2707 if ( !GetBatchCount() ) Refresh();
2708 return TRUE;
2709 }
2710 else
2711 {
2712 return FALSE;
2713 }
2714 }
2715
2716
2717 bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
2718 {
2719 // TODO: something with updateLabels flag
2720
2721 if ( !m_created )
2722 {
2723 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2724 return FALSE;
2725 }
2726
2727 if ( m_table && m_table->DeleteCols( pos, numCols ) )
2728 {
2729 // the table will have sent the results of the delete col
2730 // operation to this view object as a grid table message
2731 //
2732 if ( m_numCols > 0 )
2733 SetEditControlValue();
2734 else
2735 HideCellEditControl();
2736
2737 ClearSelection();
2738 if ( !GetBatchCount() ) Refresh();
2739 return TRUE;
2740 }
2741 else
2742 {
2743 return FALSE;
2744 }
2745 }
2746
2747
2748
2749 //
2750 // ----- event handlers
2751 //
2752
2753 // Generate a grid event based on a mouse event and
2754 // return the result of ProcessEvent()
2755 //
2756 bool wxGrid::SendEvent( const wxEventType type,
2757 int row, int col,
2758 wxMouseEvent& mouseEv )
2759 {
2760 if ( type == EVT_GRID_ROW_SIZE ||
2761 type == EVT_GRID_COL_SIZE )
2762 {
2763 int rowOrCol = (row == -1 ? col : row);
2764
2765 wxGridSizeEvent gridEvt( GetId(),
2766 type,
2767 this,
2768 rowOrCol,
2769 mouseEv.GetX(), mouseEv.GetY(),
2770 mouseEv.ControlDown(),
2771 mouseEv.ShiftDown(),
2772 mouseEv.AltDown(),
2773 mouseEv.MetaDown() );
2774
2775 return GetEventHandler()->ProcessEvent(gridEvt);
2776 }
2777 else if ( type == EVT_GRID_RANGE_SELECT )
2778 {
2779 wxGridRangeSelectEvent gridEvt( GetId(),
2780 type,
2781 this,
2782 m_selectedTopLeft,
2783 m_selectedBottomRight,
2784 mouseEv.ControlDown(),
2785 mouseEv.ShiftDown(),
2786 mouseEv.AltDown(),
2787 mouseEv.MetaDown() );
2788
2789 return GetEventHandler()->ProcessEvent(gridEvt);
2790 }
2791 else
2792 {
2793 wxGridEvent gridEvt( GetId(),
2794 type,
2795 this,
2796 row, col,
2797 mouseEv.GetX(), mouseEv.GetY(),
2798 mouseEv.ControlDown(),
2799 mouseEv.ShiftDown(),
2800 mouseEv.AltDown(),
2801 mouseEv.MetaDown() );
2802
2803 return GetEventHandler()->ProcessEvent(gridEvt);
2804 }
2805 }
2806
2807
2808 // Generate a grid event of specified type and return the result
2809 // of ProcessEvent().
2810 //
2811 bool wxGrid::SendEvent( const wxEventType type,
2812 int row, int col )
2813 {
2814 if ( type == EVT_GRID_ROW_SIZE ||
2815 type == EVT_GRID_COL_SIZE )
2816 {
2817 int rowOrCol = (row == -1 ? col : row);
2818
2819 wxGridSizeEvent gridEvt( GetId(),
2820 type,
2821 this,
2822 rowOrCol );
2823
2824 return GetEventHandler()->ProcessEvent(gridEvt);
2825 }
2826 else
2827 {
2828 wxGridEvent gridEvt( GetId(),
2829 type,
2830 this,
2831 row, col );
2832
2833 return GetEventHandler()->ProcessEvent(gridEvt);
2834 }
2835 }
2836
2837
2838 void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
2839 {
2840 wxPaintDC dc( this );
2841
2842 if ( m_currentCellCoords == wxGridNoCellCoords &&
2843 m_numRows && m_numCols )
2844 {
2845 m_currentCellCoords.Set(0, 0);
2846 SetEditControlValue();
2847 ShowCellEditControl();
2848 }
2849
2850 m_displayed = TRUE;
2851 }
2852
2853
2854 // This is just here to make sure that CalcDimensions gets called when
2855 // the grid view is resized... then the size event is skipped to allow
2856 // the box sizers to handle everything
2857 //
2858 void wxGrid::OnSize( wxSizeEvent& event )
2859 {
2860 CalcWindowSizes();
2861 CalcDimensions();
2862 }
2863
2864
2865 void wxGrid::OnKeyDown( wxKeyEvent& event )
2866 {
2867 if ( m_inOnKeyDown )
2868 {
2869 // shouldn't be here - we are going round in circles...
2870 //
2871 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
2872 }
2873
2874 m_inOnKeyDown = TRUE;
2875
2876 // propagate the event up and see if it gets processed
2877 //
2878 wxWindow *parent = GetParent();
2879 wxKeyEvent keyEvt( event );
2880 keyEvt.SetEventObject( parent );
2881
2882 if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
2883 {
2884 // try local handlers
2885 //
2886 switch ( event.KeyCode() )
2887 {
2888 case WXK_UP:
2889 if ( event.ControlDown() )
2890 {
2891 MoveCursorUpBlock();
2892 }
2893 else
2894 {
2895 MoveCursorUp();
2896 }
2897 break;
2898
2899 case WXK_DOWN:
2900 if ( event.ControlDown() )
2901 {
2902 MoveCursorDownBlock();
2903 }
2904 else
2905 {
2906 MoveCursorDown();
2907 }
2908 break;
2909
2910 case WXK_LEFT:
2911 if ( event.ControlDown() )
2912 {
2913 MoveCursorLeftBlock();
2914 }
2915 else
2916 {
2917 MoveCursorLeft();
2918 }
2919 break;
2920
2921 case WXK_RIGHT:
2922 if ( event.ControlDown() )
2923 {
2924 MoveCursorRightBlock();
2925 }
2926 else
2927 {
2928 MoveCursorRight();
2929 }
2930 break;
2931
2932 case WXK_SPACE:
2933 if ( !IsEditable() )
2934 {
2935 MoveCursorRight();
2936 }
2937 else
2938 {
2939 event.Skip();
2940 }
2941 break;
2942
2943 case WXK_RETURN:
2944 if ( event.ControlDown() )
2945 {
2946 event.Skip(); // to let the edit control have the return
2947 }
2948 else
2949 {
2950 MoveCursorDown();
2951 }
2952 break;
2953
2954 case WXK_HOME:
2955 if ( event.ControlDown() )
2956 {
2957 MakeCellVisible( 0, 0 );
2958 SetCurrentCell( 0, 0 );
2959 }
2960 else
2961 {
2962 event.Skip();
2963 }
2964 break;
2965
2966 case WXK_END:
2967 if ( event.ControlDown() )
2968 {
2969 MakeCellVisible( m_numRows-1, m_numCols-1 );
2970 SetCurrentCell( m_numRows-1, m_numCols-1 );
2971 }
2972 else
2973 {
2974 event.Skip();
2975 }
2976 break;
2977
2978 case WXK_PRIOR:
2979 MovePageUp();
2980 break;
2981
2982 case WXK_NEXT:
2983 MovePageDown();
2984 break;
2985
2986 default:
2987 // now try the cell edit control
2988 //
2989 if ( IsCellEditControlEnabled() )
2990 {
2991 event.SetEventObject( m_cellEditCtrl );
2992 m_cellEditCtrl->GetEventHandler()->ProcessEvent( event );
2993 }
2994 break;
2995 }
2996 }
2997
2998 m_inOnKeyDown = FALSE;
2999 }
3000
3001
3002 void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
3003 {
3004 if ( SendEvent( EVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
3005 {
3006 // the event has been intercepted - do nothing
3007 return;
3008 }
3009
3010 if ( m_displayed &&
3011 m_currentCellCoords != wxGridNoCellCoords )
3012 {
3013 HideCellEditControl();
3014 SaveEditControlValue();
3015 }
3016
3017 m_currentCellCoords = coords;
3018
3019 SetEditControlValue();
3020
3021 if ( m_displayed )
3022 {
3023 ShowCellEditControl();
3024
3025 if ( IsSelection() )
3026 {
3027 wxRect r( SelectionToDeviceRect() );
3028 ClearSelection();
3029 if ( !GetBatchCount() ) m_gridWin->Refresh( FALSE, &r );
3030 }
3031 }
3032 }
3033
3034
3035 //
3036 // ------ functions to get/send data (see also public functions)
3037 //
3038
3039 bool wxGrid::GetModelValues()
3040 {
3041 if ( m_table )
3042 {
3043 // all we need to do is repaint the grid
3044 //
3045 m_gridWin->Refresh();
3046 return TRUE;
3047 }
3048
3049 return FALSE;
3050 }
3051
3052
3053 bool wxGrid::SetModelValues()
3054 {
3055 int row, col;
3056
3057 if ( m_table )
3058 {
3059 for ( row = 0; row < m_numRows; row++ )
3060 {
3061 for ( col = 0; col < m_numCols; col++ )
3062 {
3063 m_table->SetValue( row, col, GetCellValue(row, col) );
3064 }
3065 }
3066
3067 return TRUE;
3068 }
3069
3070 return FALSE;
3071 }
3072
3073
3074
3075 // Note - this function only draws cells that are in the list of
3076 // exposed cells (usually set from the update region by
3077 // CalcExposedCells)
3078 //
3079 void wxGrid::DrawGridCellArea( wxDC& dc )
3080 {
3081 if ( !m_numRows || !m_numCols ) return;
3082
3083 size_t i;
3084 size_t numCells = m_cellsExposed.GetCount();
3085
3086 for ( i = 0; i < numCells; i++ )
3087 {
3088 DrawCell( dc, m_cellsExposed[i] );
3089 }
3090 }
3091
3092
3093 void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
3094 {
3095 if ( m_colWidths[coords.GetCol()] <=0 ||
3096 m_rowHeights[coords.GetRow()] <= 0 ) return;
3097
3098 #if !WXGRID_DRAW_LINES
3099 if ( m_gridLinesEnabled )
3100 DrawCellBorder( dc, coords );
3101 #endif
3102
3103 DrawCellBackground( dc, coords );
3104
3105 // TODO: separate functions here for different kinds of cells ?
3106 // e.g. text, image
3107 //
3108 DrawCellValue( dc, coords );
3109 }
3110
3111
3112 void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
3113 {
3114 if ( m_colWidths[coords.GetCol()] <=0 ||
3115 m_rowHeights[coords.GetRow()] <= 0 ) return;
3116
3117 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3118 int row = coords.GetRow();
3119 int col = coords.GetCol();
3120
3121 // right hand border
3122 //
3123 dc.DrawLine( m_colRights[col], m_rowBottoms[row] - m_rowHeights[row],
3124 m_colRights[col], m_rowBottoms[row] );
3125
3126 // bottom border
3127 //
3128 dc.DrawLine( m_colRights[col] - m_colWidths[col], m_rowBottoms[row],
3129 m_colRights[col], m_rowBottoms[row] );
3130 }
3131
3132
3133 void wxGrid::DrawCellBackground( wxDC& dc, const wxGridCellCoords& coords )
3134 {
3135 if ( m_colWidths[coords.GetCol()] <=0 ||
3136 m_rowHeights[coords.GetRow()] <= 0 ) return;
3137
3138 int row = coords.GetRow();
3139 int col = coords.GetCol();
3140
3141 dc.SetBackgroundMode( wxSOLID );
3142
3143 if ( IsInSelection( coords ) )
3144 {
3145 // TODO: improve this
3146 //
3147 dc.SetBrush( *wxBLACK_BRUSH );
3148 }
3149 else
3150 {
3151 dc.SetBrush( wxBrush(GetCellBackgroundColour(row, col), wxSOLID) );
3152 }
3153
3154 dc.SetPen( *wxTRANSPARENT_PEN );
3155
3156 dc.DrawRectangle( m_colRights[col] - m_colWidths[col] + 1,
3157 m_rowBottoms[row] - m_rowHeights[row] + 1,
3158 m_colWidths[col]-1,
3159 m_rowHeights[row]-1 );
3160 }
3161
3162
3163 void wxGrid::DrawCellValue( wxDC& dc, const wxGridCellCoords& coords )
3164 {
3165 if ( m_colWidths[coords.GetCol()] <=0 ||
3166 m_rowHeights[coords.GetRow()] <= 0 ) return;
3167
3168 int row = coords.GetRow();
3169 int col = coords.GetCol();
3170
3171 dc.SetBackgroundMode( wxTRANSPARENT );
3172
3173 if ( IsInSelection( row, col ) )
3174 {
3175 // TODO: improve this
3176 //
3177 dc.SetTextBackground( wxColour(0, 0, 0) );
3178 dc.SetTextForeground( wxColour(255, 255, 255) );
3179 }
3180 else
3181 {
3182 dc.SetTextBackground( GetCellBackgroundColour(row, col) );
3183 dc.SetTextForeground( GetCellTextColour(row, col) );
3184 }
3185 dc.SetFont( GetCellFont(row, col) );
3186
3187 int hAlign, vAlign;
3188 GetCellAlignment( row, col, &hAlign, &vAlign );
3189
3190 wxRect rect;
3191 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3192 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3193 rect.SetWidth( m_colWidths[col] - 4 );
3194 rect.SetHeight( m_rowHeights[row] - 4 );
3195
3196 DrawTextRectangle( dc, GetCellValue( row, col ), rect, hAlign, vAlign );
3197 }
3198
3199
3200
3201 // TODO: remove this ???
3202 // This is used to redraw all grid lines e.g. when the grid line colour
3203 // has been changed
3204 //
3205 void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & reg )
3206 {
3207 if ( !m_gridLinesEnabled ||
3208 !m_numRows ||
3209 !m_numCols ) return;
3210
3211 int top, bottom, left, right;
3212
3213 if (reg.IsEmpty()){
3214 int cw, ch;
3215 m_gridWin->GetClientSize(&cw, &ch);
3216
3217 // virtual coords of visible area
3218 //
3219 CalcUnscrolledPosition( 0, 0, &left, &top );
3220 CalcUnscrolledPosition( cw, ch, &right, &bottom );
3221 }
3222 else{
3223 wxCoord x, y, w, h;
3224 reg.GetBox(x, y, w, h);
3225 CalcUnscrolledPosition( x, y, &left, &top );
3226 CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
3227 }
3228
3229 // avoid drawing grid lines past the last row and col
3230 //
3231 right = wxMin( right, m_colRights[m_numCols-1] );
3232 bottom = wxMin( bottom, m_rowBottoms[m_numRows-1] );
3233
3234 dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
3235
3236 // horizontal grid lines
3237 //
3238 int i;
3239 for ( i = 0; i < m_numRows; i++ )
3240 {
3241 if ( m_rowBottoms[i] > bottom )
3242 {
3243 break;
3244 }
3245 else if ( m_rowBottoms[i] >= top )
3246 {
3247 dc.DrawLine( left, m_rowBottoms[i], right, m_rowBottoms[i] );
3248 }
3249 }
3250
3251
3252 // vertical grid lines
3253 //
3254 for ( i = 0; i < m_numCols; i++ )
3255 {
3256 if ( m_colRights[i] > right )
3257 {
3258 break;
3259 }
3260 else if ( m_colRights[i] >= left )
3261 {
3262 dc.DrawLine( m_colRights[i], top, m_colRights[i], bottom );
3263 }
3264 }
3265 }
3266
3267
3268 void wxGrid::DrawRowLabels( wxDC& dc )
3269 {
3270 if ( !m_numRows || !m_numCols ) return;
3271
3272 size_t i;
3273 size_t numLabels = m_rowLabelsExposed.GetCount();
3274
3275 for ( i = 0; i < numLabels; i++ )
3276 {
3277 DrawRowLabel( dc, m_rowLabelsExposed[i] );
3278 }
3279 }
3280
3281
3282 void wxGrid::DrawRowLabel( wxDC& dc, int row )
3283 {
3284 if ( m_rowHeights[row] <= 0 ) return;
3285
3286 int rowTop = m_rowBottoms[row] - m_rowHeights[row];
3287
3288 dc.SetPen( *wxBLACK_PEN );
3289 dc.DrawLine( m_rowLabelWidth-1, rowTop,
3290 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3291
3292 dc.DrawLine( 0, m_rowBottoms[row]-1,
3293 m_rowLabelWidth-1, m_rowBottoms[row]-1 );
3294
3295 dc.SetPen( *wxWHITE_PEN );
3296 dc.DrawLine( 0, rowTop, 0, m_rowBottoms[row]-1 );
3297 dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
3298
3299 dc.SetBackgroundMode( wxTRANSPARENT );
3300 dc.SetTextForeground( GetLabelTextColour() );
3301 dc.SetFont( GetLabelFont() );
3302
3303 int hAlign, vAlign;
3304 GetRowLabelAlignment( &hAlign, &vAlign );
3305
3306 wxRect rect;
3307 rect.SetX( 2 );
3308 rect.SetY( m_rowBottoms[row] - m_rowHeights[row] + 2 );
3309 rect.SetWidth( m_rowLabelWidth - 4 );
3310 rect.SetHeight( m_rowHeights[row] - 4 );
3311 DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
3312 }
3313
3314
3315 void wxGrid::DrawColLabels( wxDC& dc )
3316 {
3317 if ( !m_numRows || !m_numCols ) return;
3318
3319 size_t i;
3320 size_t numLabels = m_colLabelsExposed.GetCount();
3321
3322 for ( i = 0; i < numLabels; i++ )
3323 {
3324 DrawColLabel( dc, m_colLabelsExposed[i] );
3325 }
3326 }
3327
3328
3329 void wxGrid::DrawColLabel( wxDC& dc, int col )
3330 {
3331 if ( m_colWidths[col] <= 0 ) return;
3332
3333 int colLeft = m_colRights[col] - m_colWidths[col];
3334
3335 dc.SetPen( *wxBLACK_PEN );
3336 dc.DrawLine( m_colRights[col]-1, 0,
3337 m_colRights[col]-1, m_colLabelHeight-1 );
3338
3339 dc.DrawLine( colLeft, m_colLabelHeight-1,
3340 m_colRights[col]-1, m_colLabelHeight-1 );
3341
3342 dc.SetPen( *wxWHITE_PEN );
3343 dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
3344 dc.DrawLine( colLeft, 0, m_colRights[col]-1, 0 );
3345
3346 dc.SetBackgroundMode( wxTRANSPARENT );
3347 dc.SetTextForeground( GetLabelTextColour() );
3348 dc.SetFont( GetLabelFont() );
3349
3350 dc.SetBackgroundMode( wxTRANSPARENT );
3351 dc.SetTextForeground( GetLabelTextColour() );
3352 dc.SetFont( GetLabelFont() );
3353
3354 int hAlign, vAlign;
3355 GetColLabelAlignment( &hAlign, &vAlign );
3356
3357 wxRect rect;
3358 rect.SetX( m_colRights[col] - m_colWidths[col] + 2 );
3359 rect.SetY( 2 );
3360 rect.SetWidth( m_colWidths[col] - 4 );
3361 rect.SetHeight( m_colLabelHeight - 4 );
3362 DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
3363 }
3364
3365
3366 void wxGrid::DrawTextRectangle( wxDC& dc,
3367 const wxString& value,
3368 const wxRect& rect,
3369 int horizAlign,
3370 int vertAlign )
3371 {
3372 long textWidth, textHeight;
3373 long lineWidth, lineHeight;
3374 wxArrayString lines;
3375
3376 dc.SetClippingRegion( rect );
3377 StringToLines( value, lines );
3378 if ( lines.GetCount() )
3379 {
3380 GetTextBoxSize( dc, lines, &textWidth, &textHeight );
3381 dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
3382
3383 float x, y;
3384 switch ( horizAlign )
3385 {
3386 case wxRIGHT:
3387 x = rect.x + (rect.width - textWidth - 1);
3388 break;
3389
3390 case wxCENTRE:
3391 x = rect.x + ((rect.width - textWidth)/2);
3392 break;
3393
3394 case wxLEFT:
3395 default:
3396 x = rect.x + 1;
3397 break;
3398 }
3399
3400 switch ( vertAlign )
3401 {
3402 case wxBOTTOM:
3403 y = rect.y + (rect.height - textHeight - 1);
3404 break;
3405
3406 case wxCENTRE:
3407 y = rect.y + ((rect.height - textHeight)/2);
3408 break;
3409
3410 case wxTOP:
3411 default:
3412 y = rect.y + 1;
3413 break;
3414 }
3415
3416 for ( size_t i = 0; i < lines.GetCount(); i++ )
3417 {
3418 dc.DrawText( lines[i], (long)x, (long)y );
3419 y += lineHeight;
3420 }
3421 }
3422
3423 dc.DestroyClippingRegion();
3424 }
3425
3426
3427 // Split multi line text up into an array of strings. Any existing
3428 // contents of the string array are preserved.
3429 //
3430 void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
3431 {
3432 int startPos = 0;
3433 int pos;
3434 wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
3435 wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
3436
3437 while ( startPos < (int)tVal.Length() )
3438 {
3439 pos = tVal.Mid(startPos).Find( eol );
3440 if ( pos < 0 )
3441 {
3442 break;
3443 }
3444 else if ( pos == 0 )
3445 {
3446 lines.Add( wxEmptyString );
3447 }
3448 else
3449 {
3450 lines.Add( value.Mid(startPos, pos) );
3451 }
3452 startPos += pos+1;
3453 }
3454 if ( startPos < (int)value.Length() )
3455 {
3456 lines.Add( value.Mid( startPos ) );
3457 }
3458 }
3459
3460
3461 void wxGrid::GetTextBoxSize( wxDC& dc,
3462 wxArrayString& lines,
3463 long *width, long *height )
3464 {
3465 long w = 0;
3466 long h = 0;
3467 long lineW, lineH;
3468
3469 size_t i;
3470 for ( i = 0; i < lines.GetCount(); i++ )
3471 {
3472 dc.GetTextExtent( lines[i], &lineW, &lineH );
3473 w = wxMax( w, lineW );
3474 h += lineH;
3475 }
3476
3477 *width = w;
3478 *height = h;
3479 }
3480
3481
3482 //
3483 // ------ Edit control functions
3484 //
3485
3486
3487 void wxGrid::EnableEditing( bool edit )
3488 {
3489 // TODO: improve this ?
3490 //
3491 if ( edit != m_editable )
3492 {
3493 m_editable = edit;
3494
3495 // TODO: extend this for other edit control types
3496 //
3497 if ( m_editCtrlType == wxGRID_TEXTCTRL )
3498 {
3499 ((wxTextCtrl *)m_cellEditCtrl)->SetEditable( m_editable );
3500 }
3501 }
3502 }
3503
3504
3505 #if 0 // disabled for the moment - the cell control is always active
3506 void wxGrid::EnableCellEditControl( bool enable )
3507 {
3508 if ( m_cellEditCtrl &&
3509 enable != m_cellEditCtrlEnabled )
3510 {
3511 m_cellEditCtrlEnabled = enable;
3512
3513 if ( m_cellEditCtrlEnabled )
3514 {
3515 SetEditControlValue();
3516 ShowCellEditControl();
3517 }
3518 else
3519 {
3520 HideCellEditControl();
3521 SaveEditControlValue();
3522 }
3523 }
3524 }
3525 #endif
3526
3527
3528 void wxGrid::ShowCellEditControl()
3529 {
3530 wxRect rect;
3531
3532 if ( IsCellEditControlEnabled() )
3533 {
3534 if ( !IsVisible( m_currentCellCoords ) )
3535 {
3536 return;
3537 }
3538 else
3539 {
3540 rect = CellToRect( m_currentCellCoords );
3541
3542 // convert to scrolled coords
3543 //
3544 int left, top, right, bottom;
3545 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
3546 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
3547
3548 int cw, ch;
3549 m_gridWin->GetClientSize( &cw, &ch );
3550
3551 // Make the edit control large enough to allow for internal margins
3552 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3553 //
3554 int extra;
3555 #if defined(__WXMOTIF__)
3556 if ( m_currentCellCoords.GetRow() == 0 ||
3557 m_currentCellCoords.GetCol() == 0 )
3558 {
3559 extra = 2;
3560 }
3561 else
3562 {
3563 extra = 4;
3564 }
3565 #else
3566 if ( m_currentCellCoords.GetRow() == 0 ||
3567 m_currentCellCoords.GetCol() == 0 )
3568 {
3569 extra = 1;
3570 }
3571 else
3572 {
3573 extra = 2;
3574 }
3575 #endif
3576
3577 #if defined(__WXGTK__)
3578 int top_diff = 0;
3579 int left_diff = 0;
3580 if (left != 0) left_diff++;
3581 if (top != 0) top_diff++;
3582 rect.SetLeft( left + left_diff );
3583 rect.SetTop( top + top_diff );
3584 rect.SetRight( rect.GetRight() - left_diff );
3585 rect.SetBottom( rect.GetBottom() - top_diff );
3586 #else
3587 rect.SetLeft( wxMax(0, left - extra) );
3588 rect.SetTop( wxMax(0, top - extra) );
3589 rect.SetRight( rect.GetRight() + 2*extra );
3590 rect.SetBottom( rect.GetBottom() + 2*extra );
3591 #endif
3592
3593 m_cellEditCtrl->SetSize( rect );
3594 m_cellEditCtrl->Show( TRUE );
3595
3596 switch ( m_editCtrlType )
3597 {
3598 case wxGRID_TEXTCTRL:
3599 ((wxTextCtrl *) m_cellEditCtrl)->SetInsertionPointEnd();
3600 break;
3601
3602 case wxGRID_CHECKBOX:
3603 // TODO: anything ???
3604 //
3605 break;
3606
3607 case wxGRID_CHOICE:
3608 // TODO: anything ???
3609 //
3610 break;
3611
3612 case wxGRID_COMBOBOX:
3613 // TODO: anything ???
3614 //
3615 break;
3616 }
3617
3618 m_cellEditCtrl->SetFocus();
3619 }
3620 }
3621 }
3622
3623
3624 void wxGrid::HideCellEditControl()
3625 {
3626 if ( IsCellEditControlEnabled() )
3627 {
3628 m_cellEditCtrl->Show( FALSE );
3629 }
3630 }
3631
3632
3633 void wxGrid::SetEditControlValue( const wxString& value )
3634 {
3635 if ( m_table )
3636 {
3637 wxString s;
3638 if ( !value )
3639 s = GetCellValue(m_currentCellCoords);
3640 else
3641 s = value;
3642
3643 if ( IsCellEditControlEnabled() )
3644 {
3645 switch ( m_editCtrlType )
3646 {
3647 case wxGRID_TEXTCTRL:
3648 ((wxGridTextCtrl *)m_cellEditCtrl)->SetStartValue(s);
3649 break;
3650
3651 case wxGRID_CHECKBOX:
3652 // TODO: implement this
3653 //
3654 break;
3655
3656 case wxGRID_CHOICE:
3657 // TODO: implement this
3658 //
3659 break;
3660
3661 case wxGRID_COMBOBOX:
3662 // TODO: implement this
3663 //
3664 break;
3665 }
3666 }
3667 }
3668 }
3669
3670
3671 void wxGrid::SaveEditControlValue()
3672 {
3673 if ( m_table )
3674 {
3675 wxWindow *ctrl = (wxWindow *)NULL;
3676
3677 if ( IsCellEditControlEnabled() )
3678 {
3679 ctrl = m_cellEditCtrl;
3680 }
3681 else
3682 {
3683 return;
3684 }
3685
3686 bool valueChanged = FALSE;
3687
3688 switch ( m_editCtrlType )
3689 {
3690 case wxGRID_TEXTCTRL:
3691 valueChanged = (((wxGridTextCtrl *)ctrl)->GetValue() !=
3692 ((wxGridTextCtrl *)ctrl)->GetStartValue());
3693 SetCellValue( m_currentCellCoords,
3694 ((wxTextCtrl *) ctrl)->GetValue() );
3695 break;
3696
3697 case wxGRID_CHECKBOX:
3698 // TODO: implement this
3699 //
3700 break;
3701
3702 case wxGRID_CHOICE:
3703 // TODO: implement this
3704 //
3705 break;
3706
3707 case wxGRID_COMBOBOX:
3708 // TODO: implement this
3709 //
3710 break;
3711 }
3712
3713 if ( valueChanged )
3714 {
3715 SendEvent( EVT_GRID_CELL_CHANGE,
3716 m_currentCellCoords.GetRow(),
3717 m_currentCellCoords.GetCol() );
3718 }
3719 }
3720 }
3721
3722
3723 //
3724 // ------ Grid location functions
3725 // Note that all of these functions work with the logical coordinates of
3726 // grid cells and labels so you will need to convert from device
3727 // coordinates for mouse events etc.
3728 //
3729
3730 void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
3731 {
3732 int row = YToRow(y);
3733 int col = XToCol(x);
3734
3735 if ( row == -1 || col == -1 )
3736 {
3737 coords = wxGridNoCellCoords;
3738 }
3739 else
3740 {
3741 coords.Set( row, col );
3742 }
3743 }
3744
3745
3746 int wxGrid::YToRow( int y )
3747 {
3748 int i;
3749
3750 for ( i = 0; i < m_numRows; i++ )
3751 {
3752 if ( y < m_rowBottoms[i] ) return i;
3753 }
3754
3755 return -1;
3756 }
3757
3758
3759 int wxGrid::XToCol( int x )
3760 {
3761 int i;
3762
3763 for ( i = 0; i < m_numCols; i++ )
3764 {
3765 if ( x < m_colRights[i] ) return i;
3766 }
3767
3768 return -1;
3769 }
3770
3771
3772 // return the row number that that the y coord is near the edge of, or
3773 // -1 if not near an edge
3774 //
3775 int wxGrid::YToEdgeOfRow( int y )
3776 {
3777 int i, d;
3778
3779 for ( i = 0; i < m_numRows; i++ )
3780 {
3781 if ( m_rowHeights[i] > WXGRID_LABEL_EDGE_ZONE )
3782 {
3783 d = abs( y - m_rowBottoms[i] );
3784 {
3785 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3786 }
3787 }
3788 }
3789
3790 return -1;
3791 }
3792
3793
3794 // return the col number that that the x coord is near the edge of, or
3795 // -1 if not near an edge
3796 //
3797 int wxGrid::XToEdgeOfCol( int x )
3798 {
3799 int i, d;
3800
3801 for ( i = 0; i < m_numCols; i++ )
3802 {
3803 if ( m_colWidths[i] > WXGRID_LABEL_EDGE_ZONE )
3804 {
3805 d = abs( x - m_colRights[i] );
3806 {
3807 if ( d < WXGRID_LABEL_EDGE_ZONE ) return i;
3808 }
3809 }
3810 }
3811
3812 return -1;
3813 }
3814
3815
3816 wxRect wxGrid::CellToRect( int row, int col )
3817 {
3818 wxRect rect( -1, -1, -1, -1 );
3819
3820 if ( row >= 0 && row < m_numRows &&
3821 col >= 0 && col < m_numCols )
3822 {
3823 rect.x = m_colRights[col] - m_colWidths[col];
3824 rect.y = m_rowBottoms[row] - m_rowHeights[row];
3825 rect.width = m_colWidths[col];
3826 rect.height = m_rowHeights[ row ];
3827 }
3828
3829 return rect;
3830 }
3831
3832
3833 bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
3834 {
3835 // get the cell rectangle in logical coords
3836 //
3837 wxRect r( CellToRect( row, col ) );
3838
3839 // convert to device coords
3840 //
3841 int left, top, right, bottom;
3842 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3843 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3844
3845 // check against the client area of the grid window
3846 //
3847 int cw, ch;
3848 m_gridWin->GetClientSize( &cw, &ch );
3849
3850 if ( wholeCellVisible )
3851 {
3852 // is the cell wholly visible ?
3853 //
3854 return ( left >= 0 && right <= cw &&
3855 top >= 0 && bottom <= ch );
3856 }
3857 else
3858 {
3859 // is the cell partly visible ?
3860 //
3861 return ( ((left >=0 && left < cw) || (right > 0 && right <= cw)) &&
3862 ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
3863 }
3864 }
3865
3866
3867 // make the specified cell location visible by doing a minimal amount
3868 // of scrolling
3869 //
3870 void wxGrid::MakeCellVisible( int row, int col )
3871 {
3872 int i;
3873 int xpos = -1, ypos = -1;
3874
3875 if ( row >= 0 && row < m_numRows &&
3876 col >= 0 && col < m_numCols )
3877 {
3878 // get the cell rectangle in logical coords
3879 //
3880 wxRect r( CellToRect( row, col ) );
3881
3882 // convert to device coords
3883 //
3884 int left, top, right, bottom;
3885 CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
3886 CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
3887
3888 int cw, ch;
3889 m_gridWin->GetClientSize( &cw, &ch );
3890
3891 if ( top < 0 )
3892 {
3893 ypos = r.GetTop();
3894 }
3895 else if ( bottom > ch )
3896 {
3897 int h = r.GetHeight();
3898 ypos = r.GetTop();
3899 for ( i = row-1; i >= 0; i-- )
3900 {
3901 if ( h + m_rowHeights[i] > ch ) break;
3902
3903 h += m_rowHeights[i];
3904 ypos -= m_rowHeights[i];
3905 }
3906
3907 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3908 // have rounding errors (this is important, because if we do, we
3909 // might not scroll at all and some cells won't be redrawn)
3910 ypos += GRID_SCROLL_LINE / 2;
3911 }
3912
3913 if ( left < 0 )
3914 {
3915 xpos = r.GetLeft();
3916 }
3917 else if ( right > cw )
3918 {
3919 int w = r.GetWidth();
3920 xpos = r.GetLeft();
3921 for ( i = col-1; i >= 0; i-- )
3922 {
3923 if ( w + m_colWidths[i] > cw ) break;
3924
3925 w += m_colWidths[i];
3926 xpos -= m_colWidths[i];
3927 }
3928
3929 // see comment for ypos above
3930 xpos += GRID_SCROLL_LINE / 2;
3931 }
3932
3933 if ( xpos != -1 || ypos != -1 )
3934 {
3935 if ( xpos != -1 ) xpos /= GRID_SCROLL_LINE;
3936 if ( ypos != -1 ) ypos /= GRID_SCROLL_LINE;
3937 Scroll( xpos, ypos );
3938 AdjustScrollbars();
3939 }
3940 }
3941 }
3942
3943
3944 //
3945 // ------ Grid cursor movement functions
3946 //
3947
3948 bool wxGrid::MoveCursorUp()
3949 {
3950 if ( m_currentCellCoords != wxGridNoCellCoords &&
3951 m_currentCellCoords.GetRow() > 0 )
3952 {
3953 MakeCellVisible( m_currentCellCoords.GetRow() - 1,
3954 m_currentCellCoords.GetCol() );
3955
3956 SetCurrentCell( m_currentCellCoords.GetRow() - 1,
3957 m_currentCellCoords.GetCol() );
3958
3959 return TRUE;
3960 }
3961
3962 return FALSE;
3963 }
3964
3965
3966 bool wxGrid::MoveCursorDown()
3967 {
3968 // TODO: allow for scrolling
3969 //
3970 if ( m_currentCellCoords != wxGridNoCellCoords &&
3971 m_currentCellCoords.GetRow() < m_numRows-1 )
3972 {
3973 MakeCellVisible( m_currentCellCoords.GetRow() + 1,
3974 m_currentCellCoords.GetCol() );
3975
3976 SetCurrentCell( m_currentCellCoords.GetRow() + 1,
3977 m_currentCellCoords.GetCol() );
3978
3979 return TRUE;
3980 }
3981
3982 return FALSE;
3983 }
3984
3985
3986 bool wxGrid::MoveCursorLeft()
3987 {
3988 if ( m_currentCellCoords != wxGridNoCellCoords &&
3989 m_currentCellCoords.GetCol() > 0 )
3990 {
3991 MakeCellVisible( m_currentCellCoords.GetRow(),
3992 m_currentCellCoords.GetCol() - 1 );
3993
3994 SetCurrentCell( m_currentCellCoords.GetRow(),
3995 m_currentCellCoords.GetCol() - 1 );
3996
3997 return TRUE;
3998 }
3999
4000 return FALSE;
4001 }
4002
4003
4004 bool wxGrid::MoveCursorRight()
4005 {
4006 if ( m_currentCellCoords != wxGridNoCellCoords &&
4007 m_currentCellCoords.GetCol() < m_numCols - 1 )
4008 {
4009 MakeCellVisible( m_currentCellCoords.GetRow(),
4010 m_currentCellCoords.GetCol() + 1 );
4011
4012 SetCurrentCell( m_currentCellCoords.GetRow(),
4013 m_currentCellCoords.GetCol() + 1 );
4014
4015 return TRUE;
4016 }
4017
4018 return FALSE;
4019 }
4020
4021
4022 bool wxGrid::MovePageUp()
4023 {
4024 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4025
4026 int row = m_currentCellCoords.GetRow();
4027 if ( row > 0 )
4028 {
4029 int cw, ch;
4030 m_gridWin->GetClientSize( &cw, &ch );
4031
4032 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4033 int newRow = YToRow( y - ch + 1 );
4034 if ( newRow == -1 )
4035 {
4036 newRow = 0;
4037 }
4038 else if ( newRow == row )
4039 {
4040 newRow = row - 1;
4041 }
4042
4043 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4044 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4045
4046 return TRUE;
4047 }
4048
4049 return FALSE;
4050 }
4051
4052 bool wxGrid::MovePageDown()
4053 {
4054 if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
4055
4056 int row = m_currentCellCoords.GetRow();
4057 if ( row < m_numRows )
4058 {
4059 int cw, ch;
4060 m_gridWin->GetClientSize( &cw, &ch );
4061
4062 int y = m_rowBottoms[ row ] - m_rowHeights[ row ];
4063 int newRow = YToRow( y + ch );
4064 if ( newRow == -1 )
4065 {
4066 newRow = m_numRows - 1;
4067 }
4068 else if ( newRow == row )
4069 {
4070 newRow = row + 1;
4071 }
4072
4073 MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
4074 SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
4075
4076 return TRUE;
4077 }
4078
4079 return FALSE;
4080 }
4081
4082 bool wxGrid::MoveCursorUpBlock()
4083 {
4084 if ( m_table &&
4085 m_currentCellCoords != wxGridNoCellCoords &&
4086 m_currentCellCoords.GetRow() > 0 )
4087 {
4088 int row = m_currentCellCoords.GetRow();
4089 int col = m_currentCellCoords.GetCol();
4090
4091 if ( m_table->IsEmptyCell(row, col) )
4092 {
4093 // starting in an empty cell: find the next block of
4094 // non-empty cells
4095 //
4096 while ( row > 0 )
4097 {
4098 row-- ;
4099 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4100 }
4101 }
4102 else if ( m_table->IsEmptyCell(row-1, col) )
4103 {
4104 // starting at the top of a block: find the next block
4105 //
4106 row--;
4107 while ( row > 0 )
4108 {
4109 row-- ;
4110 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4111 }
4112 }
4113 else
4114 {
4115 // starting within a block: find the top of the block
4116 //
4117 while ( row > 0 )
4118 {
4119 row-- ;
4120 if ( m_table->IsEmptyCell(row, col) )
4121 {
4122 row++ ;
4123 break;
4124 }
4125 }
4126 }
4127
4128 MakeCellVisible( row, col );
4129 SetCurrentCell( row, col );
4130
4131 return TRUE;
4132 }
4133
4134 return FALSE;
4135 }
4136
4137 bool wxGrid::MoveCursorDownBlock()
4138 {
4139 if ( m_table &&
4140 m_currentCellCoords != wxGridNoCellCoords &&
4141 m_currentCellCoords.GetRow() < m_numRows-1 )
4142 {
4143 int row = m_currentCellCoords.GetRow();
4144 int col = m_currentCellCoords.GetCol();
4145
4146 if ( m_table->IsEmptyCell(row, col) )
4147 {
4148 // starting in an empty cell: find the next block of
4149 // non-empty cells
4150 //
4151 while ( row < m_numRows-1 )
4152 {
4153 row++ ;
4154 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4155 }
4156 }
4157 else if ( m_table->IsEmptyCell(row+1, col) )
4158 {
4159 // starting at the bottom of a block: find the next block
4160 //
4161 row++;
4162 while ( row < m_numRows-1 )
4163 {
4164 row++ ;
4165 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4166 }
4167 }
4168 else
4169 {
4170 // starting within a block: find the bottom of the block
4171 //
4172 while ( row < m_numRows-1 )
4173 {
4174 row++ ;
4175 if ( m_table->IsEmptyCell(row, col) )
4176 {
4177 row-- ;
4178 break;
4179 }
4180 }
4181 }
4182
4183 MakeCellVisible( row, col );
4184 SetCurrentCell( row, col );
4185
4186 return TRUE;
4187 }
4188
4189 return FALSE;
4190 }
4191
4192 bool wxGrid::MoveCursorLeftBlock()
4193 {
4194 if ( m_table &&
4195 m_currentCellCoords != wxGridNoCellCoords &&
4196 m_currentCellCoords.GetCol() > 0 )
4197 {
4198 int row = m_currentCellCoords.GetRow();
4199 int col = m_currentCellCoords.GetCol();
4200
4201 if ( m_table->IsEmptyCell(row, col) )
4202 {
4203 // starting in an empty cell: find the next block of
4204 // non-empty cells
4205 //
4206 while ( col > 0 )
4207 {
4208 col-- ;
4209 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4210 }
4211 }
4212 else if ( m_table->IsEmptyCell(row, col-1) )
4213 {
4214 // starting at the left of a block: find the next block
4215 //
4216 col--;
4217 while ( col > 0 )
4218 {
4219 col-- ;
4220 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4221 }
4222 }
4223 else
4224 {
4225 // starting within a block: find the left of the block
4226 //
4227 while ( col > 0 )
4228 {
4229 col-- ;
4230 if ( m_table->IsEmptyCell(row, col) )
4231 {
4232 col++ ;
4233 break;
4234 }
4235 }
4236 }
4237
4238 MakeCellVisible( row, col );
4239 SetCurrentCell( row, col );
4240
4241 return TRUE;
4242 }
4243
4244 return FALSE;
4245 }
4246
4247 bool wxGrid::MoveCursorRightBlock()
4248 {
4249 if ( m_table &&
4250 m_currentCellCoords != wxGridNoCellCoords &&
4251 m_currentCellCoords.GetCol() < m_numCols-1 )
4252 {
4253 int row = m_currentCellCoords.GetRow();
4254 int col = m_currentCellCoords.GetCol();
4255
4256 if ( m_table->IsEmptyCell(row, col) )
4257 {
4258 // starting in an empty cell: find the next block of
4259 // non-empty cells
4260 //
4261 while ( col < m_numCols-1 )
4262 {
4263 col++ ;
4264 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4265 }
4266 }
4267 else if ( m_table->IsEmptyCell(row, col+1) )
4268 {
4269 // starting at the right of a block: find the next block
4270 //
4271 col++;
4272 while ( col < m_numCols-1 )
4273 {
4274 col++ ;
4275 if ( !(m_table->IsEmptyCell(row, col)) ) break;
4276 }
4277 }
4278 else
4279 {
4280 // starting within a block: find the right of the block
4281 //
4282 while ( col < m_numCols-1 )
4283 {
4284 col++ ;
4285 if ( m_table->IsEmptyCell(row, col) )
4286 {
4287 col-- ;
4288 break;
4289 }
4290 }
4291 }
4292
4293 MakeCellVisible( row, col );
4294 SetCurrentCell( row, col );
4295
4296 return TRUE;
4297 }
4298
4299 return FALSE;
4300 }
4301
4302
4303
4304 //
4305 // ------ Label values and formatting
4306 //
4307
4308 void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
4309 {
4310 *horiz = m_rowLabelHorizAlign;
4311 *vert = m_rowLabelVertAlign;
4312 }
4313
4314 void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
4315 {
4316 *horiz = m_colLabelHorizAlign;
4317 *vert = m_colLabelVertAlign;
4318 }
4319
4320 wxString wxGrid::GetRowLabelValue( int row )
4321 {
4322 if ( m_table )
4323 {
4324 return m_table->GetRowLabelValue( row );
4325 }
4326 else
4327 {
4328 wxString s;
4329 s << row;
4330 return s;
4331 }
4332 }
4333
4334 wxString wxGrid::GetColLabelValue( int col )
4335 {
4336 if ( m_table )
4337 {
4338 return m_table->GetColLabelValue( col );
4339 }
4340 else
4341 {
4342 wxString s;
4343 s << col;
4344 return s;
4345 }
4346 }
4347
4348
4349 void wxGrid::SetRowLabelSize( int width )
4350 {
4351 width = wxMax( width, 0 );
4352 if ( width != m_rowLabelWidth )
4353 {
4354 if ( width == 0 )
4355 {
4356 m_rowLabelWin->Show( FALSE );
4357 m_cornerLabelWin->Show( FALSE );
4358 }
4359 else if ( m_rowLabelWidth == 0 )
4360 {
4361 m_rowLabelWin->Show( TRUE );
4362 if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
4363 }
4364
4365 m_rowLabelWidth = width;
4366 CalcWindowSizes();
4367 Refresh( TRUE );
4368 }
4369 }
4370
4371
4372 void wxGrid::SetColLabelSize( int height )
4373 {
4374 height = wxMax( height, 0 );
4375 if ( height != m_colLabelHeight )
4376 {
4377 if ( height == 0 )
4378 {
4379 m_colLabelWin->Show( FALSE );
4380 m_cornerLabelWin->Show( FALSE );
4381 }
4382 else if ( m_colLabelHeight == 0 )
4383 {
4384 m_colLabelWin->Show( TRUE );
4385 if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
4386 }
4387
4388 m_colLabelHeight = height;
4389 CalcWindowSizes();
4390 Refresh( TRUE );
4391 }
4392 }
4393
4394
4395 void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
4396 {
4397 if ( m_labelBackgroundColour != colour )
4398 {
4399 m_labelBackgroundColour = colour;
4400 m_rowLabelWin->SetBackgroundColour( colour );
4401 m_colLabelWin->SetBackgroundColour( colour );
4402 m_cornerLabelWin->SetBackgroundColour( colour );
4403
4404 if ( !GetBatchCount() )
4405 {
4406 m_rowLabelWin->Refresh();
4407 m_colLabelWin->Refresh();
4408 m_cornerLabelWin->Refresh();
4409 }
4410 }
4411 }
4412
4413 void wxGrid::SetLabelTextColour( const wxColour& colour )
4414 {
4415 if ( m_labelTextColour != colour )
4416 {
4417 m_labelTextColour = colour;
4418 if ( !GetBatchCount() )
4419 {
4420 m_rowLabelWin->Refresh();
4421 m_colLabelWin->Refresh();
4422 }
4423 }
4424 }
4425
4426 void wxGrid::SetLabelFont( const wxFont& font )
4427 {
4428 m_labelFont = font;
4429 if ( !GetBatchCount() )
4430 {
4431 m_rowLabelWin->Refresh();
4432 m_colLabelWin->Refresh();
4433 }
4434 }
4435
4436 void wxGrid::SetRowLabelAlignment( int horiz, int vert )
4437 {
4438 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4439 {
4440 m_rowLabelHorizAlign = horiz;
4441 }
4442
4443 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4444 {
4445 m_rowLabelVertAlign = vert;
4446 }
4447
4448 if ( !GetBatchCount() )
4449 {
4450 m_rowLabelWin->Refresh();
4451 }
4452 }
4453
4454 void wxGrid::SetColLabelAlignment( int horiz, int vert )
4455 {
4456 if ( horiz == wxLEFT || horiz == wxCENTRE || horiz == wxRIGHT )
4457 {
4458 m_colLabelHorizAlign = horiz;
4459 }
4460
4461 if ( vert == wxTOP || vert == wxCENTRE || vert == wxBOTTOM )
4462 {
4463 m_colLabelVertAlign = vert;
4464 }
4465
4466 if ( !GetBatchCount() )
4467 {
4468 m_colLabelWin->Refresh();
4469 }
4470 }
4471
4472 void wxGrid::SetRowLabelValue( int row, const wxString& s )
4473 {
4474 if ( m_table )
4475 {
4476 m_table->SetRowLabelValue( row, s );
4477 if ( !GetBatchCount() )
4478 {
4479 wxRect rect = CellToRect( row, 0);
4480 if ( rect.height > 0 )
4481 {
4482 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
4483 rect.x = m_left;
4484 rect.width = m_rowLabelWidth;
4485 m_rowLabelWin->Refresh( TRUE, &rect );
4486 }
4487 }
4488 }
4489 }
4490
4491 void wxGrid::SetColLabelValue( int col, const wxString& s )
4492 {
4493 if ( m_table )
4494 {
4495 m_table->SetColLabelValue( col, s );
4496 if ( !GetBatchCount() )
4497 {
4498 wxRect rect = CellToRect( 0, col );
4499 if ( rect.width > 0 )
4500 {
4501 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
4502 rect.y = m_top;
4503 rect.height = m_colLabelHeight;
4504 m_colLabelWin->Refresh( TRUE, &rect );
4505 }
4506 }
4507 }
4508 }
4509
4510 void wxGrid::SetGridLineColour( const wxColour& colour )
4511 {
4512 if ( m_gridLineColour != colour )
4513 {
4514 m_gridLineColour = colour;
4515
4516 wxClientDC dc( m_gridWin );
4517 PrepareDC( dc );
4518 DrawAllGridLines( dc, wxRegion() );
4519 }
4520 }
4521
4522 void wxGrid::EnableGridLines( bool enable )
4523 {
4524 if ( enable != m_gridLinesEnabled )
4525 {
4526 m_gridLinesEnabled = enable;
4527
4528 if ( !GetBatchCount() )
4529 {
4530 if ( enable )
4531 {
4532 wxClientDC dc( m_gridWin );
4533 PrepareDC( dc );
4534 DrawAllGridLines( dc, wxRegion() );
4535 }
4536 else
4537 {
4538 m_gridWin->Refresh();
4539 }
4540 }
4541 }
4542 }
4543
4544
4545 int wxGrid::GetDefaultRowSize()
4546 {
4547 return m_defaultRowHeight;
4548 }
4549
4550 int wxGrid::GetRowSize( int row )
4551 {
4552 wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
4553
4554 return m_rowHeights[row];
4555 }
4556
4557 int wxGrid::GetDefaultColSize()
4558 {
4559 return m_defaultColWidth;
4560 }
4561
4562 int wxGrid::GetColSize( int col )
4563 {
4564 wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
4565
4566 return m_colWidths[col];
4567 }
4568
4569 wxColour wxGrid::GetDefaultCellBackgroundColour()
4570 {
4571 return m_gridWin->GetBackgroundColour();
4572 }
4573
4574 // TODO VZ: this must be optimized to allow only retrieveing attr once!
4575
4576 wxColour wxGrid::GetCellBackgroundColour(int row, int col)
4577 {
4578 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4579
4580 wxColour colour;
4581 if ( attr && attr->HasBackgroundColour() )
4582 colour = attr->GetBackgroundColour();
4583 else
4584 colour = GetDefaultCellBackgroundColour();
4585
4586 delete attr;
4587
4588 return colour;
4589 }
4590
4591 wxColour wxGrid::GetDefaultCellTextColour()
4592 {
4593 return m_gridWin->GetForegroundColour();
4594 }
4595
4596 wxColour wxGrid::GetCellTextColour( int row, int col )
4597 {
4598 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4599
4600 wxColour colour;
4601 if ( attr && attr->HasTextColour() )
4602 colour = attr->GetTextColour();
4603 else
4604 colour = GetDefaultCellTextColour();
4605
4606 delete attr;
4607
4608 return colour;
4609 }
4610
4611
4612 wxFont wxGrid::GetDefaultCellFont()
4613 {
4614 return m_defaultCellFont;
4615 }
4616
4617 wxFont wxGrid::GetCellFont( int row, int col )
4618 {
4619 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4620
4621 wxFont font;
4622 if ( attr && attr->HasFont() )
4623 font = attr->GetFont();
4624 else
4625 font = GetDefaultCellFont();
4626
4627 delete attr;
4628
4629 return font;
4630 }
4631
4632 void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
4633 {
4634 if ( horiz )
4635 *horiz = m_defaultCellHAlign;
4636 if ( vert )
4637 *vert = m_defaultCellVAlign;
4638 }
4639
4640 void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
4641 {
4642 wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
4643
4644 if ( attr && attr->HasAlignment() )
4645 attr->GetAlignment(horiz, vert);
4646 else
4647 GetDefaultCellAlignment(horiz, vert);
4648
4649 delete attr;
4650 }
4651
4652 void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
4653 {
4654 m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
4655
4656 if ( resizeExistingRows )
4657 {
4658 int row;
4659 int bottom = 0;
4660 for ( row = 0; row < m_numRows; row++ )
4661 {
4662 m_rowHeights[row] = m_defaultRowHeight;
4663 bottom += m_defaultRowHeight;
4664 m_rowBottoms[row] = bottom;
4665 }
4666 CalcDimensions();
4667 }
4668 }
4669
4670 void wxGrid::SetRowSize( int row, int height )
4671 {
4672 wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
4673
4674 int i;
4675
4676 int h = wxMax( 0, height );
4677 int diff = h - m_rowHeights[row];
4678
4679 m_rowHeights[row] = h;
4680 for ( i = row; i < m_numRows; i++ )
4681 {
4682 m_rowBottoms[i] += diff;
4683 }
4684 CalcDimensions();
4685 }
4686
4687 void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
4688 {
4689 m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
4690
4691 if ( resizeExistingCols )
4692 {
4693 int col;
4694 int right = 0;
4695 for ( col = 0; col < m_numCols; col++ )
4696 {
4697 m_colWidths[col] = m_defaultColWidth;
4698 right += m_defaultColWidth;
4699 m_colRights[col] = right;
4700 }
4701 CalcDimensions();
4702 }
4703 }
4704
4705 void wxGrid::SetColSize( int col, int width )
4706 {
4707 wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
4708
4709 int i;
4710
4711 int w = wxMax( 0, width );
4712 int diff = w - m_colWidths[col];
4713 m_colWidths[col] = w;
4714
4715 for ( i = col; i < m_numCols; i++ )
4716 {
4717 m_colRights[i] += diff;
4718 }
4719 CalcDimensions();
4720 }
4721
4722 void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
4723 {
4724 m_gridWin->SetBackgroundColour(col);
4725 }
4726
4727 void wxGrid::SetDefaultCellTextColour( const wxColour& col )
4728 {
4729 m_gridWin->SetForegroundColour(col);
4730 }
4731
4732 void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
4733 {
4734 m_defaultCellHAlign = horiz;
4735 m_defaultCellVAlign = vert;
4736 }
4737
4738 bool wxGrid::CanHaveAttributes()
4739 {
4740 if ( !m_table )
4741 {
4742 return FALSE;
4743 }
4744
4745 if ( !m_table->GetAttrProvider() )
4746 {
4747 // use the default attr provider by default
4748 // (another choice would be to just return FALSE thus forcing the user
4749 // to it himself)
4750 m_table->SetAttrProvider(new wxGridCellAttrProvider);
4751 }
4752
4753 return TRUE;
4754 }
4755
4756 void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
4757 {
4758 if ( CanHaveAttributes() )
4759 {
4760 wxGridCellAttr *attr = new wxGridCellAttr;
4761 attr->SetBackgroundColour(colour);
4762
4763 m_table->SetAttr(attr, row, col);
4764 }
4765 }
4766
4767 void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
4768 {
4769 if ( CanHaveAttributes() )
4770 {
4771 wxGridCellAttr *attr = new wxGridCellAttr;
4772 attr->SetTextColour(colour);
4773
4774 m_table->SetAttr(attr, row, col);
4775 }
4776 }
4777
4778 void wxGrid::SetDefaultCellFont( const wxFont& font )
4779 {
4780 m_defaultCellFont = font;
4781 }
4782
4783 void wxGrid::SetCellFont( int row, int col, const wxFont& font )
4784 {
4785 if ( CanHaveAttributes() )
4786 {
4787 wxGridCellAttr *attr = new wxGridCellAttr;
4788 attr->SetFont(font);
4789
4790 m_table->SetAttr(attr, row, col);
4791 }
4792 }
4793
4794 void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
4795 {
4796 if ( CanHaveAttributes() )
4797 {
4798 wxGridCellAttr *attr = new wxGridCellAttr;
4799 attr->SetAlignment(horiz, vert);
4800
4801 m_table->SetAttr(attr, row, col);
4802 }
4803 }
4804
4805
4806
4807 //
4808 // ------ cell value accessor functions
4809 //
4810
4811 void wxGrid::SetCellValue( int row, int col, const wxString& s )
4812 {
4813 if ( m_table )
4814 {
4815 m_table->SetValue( row, col, s.c_str() );
4816 if ( !GetBatchCount() )
4817 {
4818 wxClientDC dc( m_gridWin );
4819 PrepareDC( dc );
4820 DrawCell( dc, wxGridCellCoords(row, col) );
4821 }
4822
4823 #if 0 // TODO: edit in place
4824
4825 if ( m_currentCellCoords.GetRow() == row &&
4826 m_currentCellCoords.GetCol() == col )
4827 {
4828 SetEditControlValue( s );
4829 }
4830 #endif
4831
4832 }
4833 }
4834
4835
4836 //
4837 // ------ Block, row and col selection
4838 //
4839
4840 void wxGrid::SelectRow( int row, bool addToSelected )
4841 {
4842 wxRect r;
4843
4844 if ( IsSelection() && addToSelected )
4845 {
4846 wxRect rect[4];
4847 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4848 int i;
4849
4850 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4851 wxCoord oldTop = m_selectedTopLeft.GetRow();
4852 wxCoord oldRight = m_selectedBottomRight.GetCol();
4853 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4854
4855 if ( oldTop > row )
4856 {
4857 need_refresh[0] = TRUE;
4858 rect[0] = BlockToDeviceRect( wxGridCellCoords ( row, 0 ),
4859 wxGridCellCoords ( oldTop - 1,
4860 m_numCols - 1 ) );
4861 m_selectedTopLeft.SetRow( row );
4862 }
4863
4864 if ( oldLeft > 0 )
4865 {
4866 need_refresh[1] = TRUE;
4867 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop, 0 ),
4868 wxGridCellCoords ( oldBottom,
4869 oldLeft - 1 ) );
4870
4871 m_selectedTopLeft.SetCol( 0 );
4872 }
4873
4874 if ( oldBottom < row )
4875 {
4876 need_refresh[2] = TRUE;
4877 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1, 0 ),
4878 wxGridCellCoords ( row,
4879 m_numCols - 1 ) );
4880 m_selectedBottomRight.SetRow( row );
4881 }
4882
4883 if ( oldRight < m_numCols - 1 )
4884 {
4885 need_refresh[3] = TRUE;
4886 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop ,
4887 oldRight + 1 ),
4888 wxGridCellCoords ( oldBottom,
4889 m_numCols - 1 ) );
4890 m_selectedBottomRight.SetCol( m_numCols - 1 );
4891 }
4892
4893 for (i = 0; i < 4; i++ )
4894 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4895 m_gridWin->Refresh( FALSE, &(rect[i]) );
4896 }
4897 else
4898 {
4899 r = SelectionToDeviceRect();
4900 ClearSelection();
4901 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4902
4903 m_selectedTopLeft.Set( row, 0 );
4904 m_selectedBottomRight.Set( row, m_numCols-1 );
4905 r = SelectionToDeviceRect();
4906 m_gridWin->Refresh( FALSE, &r );
4907 }
4908
4909 wxGridRangeSelectEvent gridEvt( GetId(),
4910 EVT_GRID_RANGE_SELECT,
4911 this,
4912 m_selectedTopLeft,
4913 m_selectedBottomRight );
4914
4915 GetEventHandler()->ProcessEvent(gridEvt);
4916 }
4917
4918
4919 void wxGrid::SelectCol( int col, bool addToSelected )
4920 {
4921 if ( IsSelection() && addToSelected )
4922 {
4923 wxRect rect[4];
4924 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
4925 int i;
4926
4927 wxCoord oldLeft = m_selectedTopLeft.GetCol();
4928 wxCoord oldTop = m_selectedTopLeft.GetRow();
4929 wxCoord oldRight = m_selectedBottomRight.GetCol();
4930 wxCoord oldBottom = m_selectedBottomRight.GetRow();
4931
4932 if ( oldLeft > col )
4933 {
4934 need_refresh[0] = TRUE;
4935 rect[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col ),
4936 wxGridCellCoords ( m_numRows - 1,
4937 oldLeft - 1 ) );
4938 m_selectedTopLeft.SetCol( col );
4939 }
4940
4941 if ( oldTop > 0 )
4942 {
4943 need_refresh[1] = TRUE;
4944 rect[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft ),
4945 wxGridCellCoords ( oldTop - 1,
4946 oldRight ) );
4947 m_selectedTopLeft.SetRow( 0 );
4948 }
4949
4950 if ( oldRight < col )
4951 {
4952 need_refresh[2] = TRUE;
4953 rect[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight + 1 ),
4954 wxGridCellCoords ( m_numRows - 1,
4955 col ) );
4956 m_selectedBottomRight.SetCol( col );
4957 }
4958
4959 if ( oldBottom < m_numRows - 1 )
4960 {
4961 need_refresh[3] = TRUE;
4962 rect[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom + 1,
4963 oldLeft ),
4964 wxGridCellCoords ( m_numRows - 1,
4965 oldRight ) );
4966 m_selectedBottomRight.SetRow( m_numRows - 1 );
4967 }
4968
4969 for (i = 0; i < 4; i++ )
4970 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
4971 m_gridWin->Refresh( FALSE, &(rect[i]) );
4972 }
4973 else
4974 {
4975 wxRect r;
4976
4977 r = SelectionToDeviceRect();
4978 ClearSelection();
4979 if ( r != wxGridNoCellRect ) m_gridWin->Refresh( FALSE, &r );
4980
4981 m_selectedTopLeft.Set( 0, col );
4982 m_selectedBottomRight.Set( m_numRows-1, col );
4983 r = SelectionToDeviceRect();
4984 m_gridWin->Refresh( FALSE, &r );
4985 }
4986
4987 wxGridRangeSelectEvent gridEvt( GetId(),
4988 EVT_GRID_RANGE_SELECT,
4989 this,
4990 m_selectedTopLeft,
4991 m_selectedBottomRight );
4992
4993 GetEventHandler()->ProcessEvent(gridEvt);
4994 }
4995
4996
4997 void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol )
4998 {
4999 int temp;
5000 wxGridCellCoords updateTopLeft, updateBottomRight;
5001
5002 if ( topRow > bottomRow )
5003 {
5004 temp = topRow;
5005 topRow = bottomRow;
5006 bottomRow = temp;
5007 }
5008
5009 if ( leftCol > rightCol )
5010 {
5011 temp = leftCol;
5012 leftCol = rightCol;
5013 rightCol = temp;
5014 }
5015
5016 updateTopLeft = wxGridCellCoords( topRow, leftCol );
5017 updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
5018
5019 if ( m_selectedTopLeft != updateTopLeft ||
5020 m_selectedBottomRight != updateBottomRight )
5021 {
5022 // Compute two optimal update rectangles:
5023 // Either one rectangle is a real subset of the
5024 // other, or they are (almost) disjoint!
5025 wxRect rect[4];
5026 bool need_refresh[4] = { FALSE, FALSE, FALSE, FALSE };
5027 int i;
5028
5029 // Store intermediate values
5030 wxCoord oldLeft = m_selectedTopLeft.GetCol();
5031 wxCoord oldTop = m_selectedTopLeft.GetRow();
5032 wxCoord oldRight = m_selectedBottomRight.GetCol();
5033 wxCoord oldBottom = m_selectedBottomRight.GetRow();
5034
5035 // Determine the outer/inner coordinates.
5036 if (oldLeft > leftCol)
5037 {
5038 temp = oldLeft;
5039 oldLeft = leftCol;
5040 leftCol = temp;
5041 }
5042 if (oldTop > topRow )
5043 {
5044 temp = oldTop;
5045 oldTop = topRow;
5046 topRow = temp;
5047 }
5048 if (oldRight < rightCol )
5049 {
5050 temp = oldRight;
5051 oldRight = rightCol;
5052 rightCol = temp;
5053 }
5054 if (oldBottom < bottomRow)
5055 {
5056 temp = oldBottom;
5057 oldBottom = bottomRow;
5058 bottomRow = temp;
5059 }
5060
5061 // Now, either the stuff marked old is the outer
5062 // rectangle or we don't have a situation where one
5063 // is contained in the other.
5064
5065 if ( oldLeft < leftCol )
5066 {
5067 need_refresh[0] = TRUE;
5068 rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5069 oldLeft ),
5070 wxGridCellCoords ( oldBottom,
5071 leftCol - 1 ) );
5072 }
5073
5074 if ( oldTop < topRow )
5075 {
5076 need_refresh[1] = TRUE;
5077 rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5078 leftCol ),
5079 wxGridCellCoords ( topRow - 1,
5080 rightCol ) );
5081 }
5082
5083 if ( oldRight > rightCol )
5084 {
5085 need_refresh[2] = TRUE;
5086 rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
5087 rightCol + 1 ),
5088 wxGridCellCoords ( oldBottom,
5089 oldRight ) );
5090 }
5091
5092 if ( oldBottom > bottomRow )
5093 {
5094 need_refresh[3] = TRUE;
5095 rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
5096 leftCol ),
5097 wxGridCellCoords ( oldBottom,
5098 rightCol ) );
5099 }
5100
5101
5102 // Change Selection
5103 m_selectedTopLeft = updateTopLeft;
5104 m_selectedBottomRight = updateBottomRight;
5105
5106 // various Refresh() calls
5107 for (i = 0; i < 4; i++ )
5108 if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
5109 m_gridWin->Refresh( FALSE, &(rect[i]) );
5110 }
5111
5112 // only generate an event if the block is not being selected by
5113 // dragging the mouse (in which case the event will be generated in
5114 // the mouse event handler)
5115 if ( !m_isDragging )
5116 {
5117 wxGridRangeSelectEvent gridEvt( GetId(),
5118 EVT_GRID_RANGE_SELECT,
5119 this,
5120 m_selectedTopLeft,
5121 m_selectedBottomRight );
5122
5123 GetEventHandler()->ProcessEvent(gridEvt);
5124 }
5125 }
5126
5127 void wxGrid::SelectAll()
5128 {
5129 m_selectedTopLeft.Set( 0, 0 );
5130 m_selectedBottomRight.Set( m_numRows-1, m_numCols-1 );
5131
5132 m_gridWin->Refresh();
5133 }
5134
5135
5136 void wxGrid::ClearSelection()
5137 {
5138 m_selectedTopLeft = wxGridNoCellCoords;
5139 m_selectedBottomRight = wxGridNoCellCoords;
5140 }
5141
5142
5143 // This function returns the rectangle that encloses the given block
5144 // in device coords clipped to the client size of the grid window.
5145 //
5146 wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
5147 const wxGridCellCoords &bottomRight )
5148 {
5149 wxRect rect( wxGridNoCellRect );
5150 wxRect cellRect;
5151
5152 cellRect = CellToRect( topLeft );
5153 if ( cellRect != wxGridNoCellRect )
5154 {
5155 rect = cellRect;
5156 }
5157 else
5158 {
5159 rect = wxRect( 0, 0, 0, 0 );
5160 }
5161
5162 cellRect = CellToRect( bottomRight );
5163 if ( cellRect != wxGridNoCellRect )
5164 {
5165 rect += cellRect;
5166 }
5167 else
5168 {
5169 return wxGridNoCellRect;
5170 }
5171
5172 // convert to scrolled coords
5173 //
5174 int left, top, right, bottom;
5175 CalcScrolledPosition( rect.GetLeft(), rect.GetTop(), &left, &top );
5176 CalcScrolledPosition( rect.GetRight(), rect.GetBottom(), &right, &bottom );
5177
5178 int cw, ch;
5179 m_gridWin->GetClientSize( &cw, &ch );
5180
5181 rect.SetLeft( wxMax(0, left) );
5182 rect.SetTop( wxMax(0, top) );
5183 rect.SetRight( wxMin(cw, right) );
5184 rect.SetBottom( wxMin(ch, bottom) );
5185
5186 return rect;
5187 }
5188
5189
5190
5191 //
5192 // ------ Grid event classes
5193 //
5194
5195 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxEvent )
5196
5197 wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
5198 int row, int col, int x, int y,
5199 bool control, bool shift, bool alt, bool meta )
5200 : wxNotifyEvent( type, id )
5201 {
5202 m_row = row;
5203 m_col = col;
5204 m_x = x;
5205 m_y = y;
5206 m_control = control;
5207 m_shift = shift;
5208 m_alt = alt;
5209 m_meta = meta;
5210
5211 SetEventObject(obj);
5212 }
5213
5214
5215 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxEvent )
5216
5217 wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
5218 int rowOrCol, int x, int y,
5219 bool control, bool shift, bool alt, bool meta )
5220 : wxNotifyEvent( type, id )
5221 {
5222 m_rowOrCol = rowOrCol;
5223 m_x = x;
5224 m_y = y;
5225 m_control = control;
5226 m_shift = shift;
5227 m_alt = alt;
5228 m_meta = meta;
5229
5230 SetEventObject(obj);
5231 }
5232
5233
5234 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxEvent )
5235
5236 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
5237 const wxGridCellCoords& topLeft,
5238 const wxGridCellCoords& bottomRight,
5239 bool control, bool shift, bool alt, bool meta )
5240 : wxNotifyEvent( type, id )
5241 {
5242 m_topLeft = topLeft;
5243 m_bottomRight = bottomRight;
5244 m_control = control;
5245 m_shift = shift;
5246 m_alt = alt;
5247 m_meta = meta;
5248
5249 SetEventObject(obj);
5250 }
5251
5252
5253 #endif // ifndef wxUSE_NEW_GRID
5254