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