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