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