1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxGrid and related classes
4 // Author: Michael Bedward (based on code by Julian Smart, Robin Dunn)
8 // Copyright: (c) Michael Bedward (mbedward@ozemail.com.au)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "grid.h"
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
25 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
35 #include "wx/layout.h"
38 #include "wx/generic/grid.h"
40 // ----------------------------------------------------------------------------
41 // array classes instantiation
42 // ----------------------------------------------------------------------------
44 struct wxGridCellWithAttr
46 wxGridCellWithAttr(int row
, int col
, const wxGridCellAttr
*pAttr
)
47 : coords(row
, col
), attr(*pAttr
)
51 wxGridCellCoords coords
;
55 WX_DECLARE_OBJARRAY(wxGridCellWithAttr
, wxGridCellWithAttrArray
);
57 #include "wx/arrimpl.cpp"
59 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
)
60 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
)
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 class WXDLLEXPORT wxGridRowLabelWindow
: public wxWindow
69 wxGridRowLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
70 wxGridRowLabelWindow( wxGrid
*parent
, wxWindowID id
,
71 const wxPoint
&pos
, const wxSize
&size
);
76 void OnPaint( wxPaintEvent
& event
);
77 void OnMouseEvent( wxMouseEvent
& event
);
78 void OnKeyDown( wxKeyEvent
& event
);
80 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow
)
85 class WXDLLEXPORT wxGridColLabelWindow
: public wxWindow
88 wxGridColLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
89 wxGridColLabelWindow( wxGrid
*parent
, wxWindowID id
,
90 const wxPoint
&pos
, const wxSize
&size
);
95 void OnPaint( wxPaintEvent
&event
);
96 void OnMouseEvent( wxMouseEvent
& event
);
97 void OnKeyDown( wxKeyEvent
& event
);
99 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow
)
100 DECLARE_EVENT_TABLE()
104 class WXDLLEXPORT wxGridCornerLabelWindow
: public wxWindow
107 wxGridCornerLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
108 wxGridCornerLabelWindow( wxGrid
*parent
, wxWindowID id
,
109 const wxPoint
&pos
, const wxSize
&size
);
114 void OnMouseEvent( wxMouseEvent
& event
);
115 void OnKeyDown( wxKeyEvent
& event
);
116 void OnPaint( wxPaintEvent
& event
);
118 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow
)
119 DECLARE_EVENT_TABLE()
122 class WXDLLEXPORT wxGridWindow
: public wxPanel
127 m_owner
= (wxGrid
*)NULL
;
128 m_rowLabelWin
= (wxGridRowLabelWindow
*)NULL
;
129 m_colLabelWin
= (wxGridColLabelWindow
*)NULL
;
132 wxGridWindow( wxGrid
*parent
,
133 wxGridRowLabelWindow
*rowLblWin
,
134 wxGridColLabelWindow
*colLblWin
,
135 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
);
138 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
142 wxGridRowLabelWindow
*m_rowLabelWin
;
143 wxGridColLabelWindow
*m_colLabelWin
;
145 void OnPaint( wxPaintEvent
&event
);
146 void OnMouseEvent( wxMouseEvent
& event
);
147 void OnKeyDown( wxKeyEvent
& );
149 DECLARE_DYNAMIC_CLASS(wxGridWindow
)
150 DECLARE_EVENT_TABLE()
153 // the internal data representation used by wxGridCellAttrProvider
155 // TODO make it more efficient
156 class WXDLLEXPORT wxGridCellAttrProviderData
159 void SetAttr(const wxGridCellAttr
*attr
, int row
, int col
);
160 wxGridCellAttr
*GetAttr(int row
, int col
) const;
163 // searches for the attr for given cell, returns wxNOT_FOUND if not found
164 int FindIndex(int row
, int col
) const;
166 wxGridCellWithAttrArray m_attrs
;
169 // ----------------------------------------------------------------------------
170 // conditional compilation
171 // ----------------------------------------------------------------------------
173 #ifndef WXGRID_DRAW_LINES
174 #define WXGRID_DRAW_LINES 1
177 //////////////////////////////////////////////////////////////////////
179 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
180 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
183 // TODO: fixed so far - make configurable later (and also different for x/y)
184 static const size_t GRID_SCROLL_LINE
= 10;
186 // ----------------------------------------------------------------------------
187 // wxGridCellAttrProviderData
188 // ----------------------------------------------------------------------------
190 void wxGridCellAttrProviderData::SetAttr(const wxGridCellAttr
*attr
,
193 int n
= FindIndex(row
, col
);
194 if ( n
== wxNOT_FOUND
)
197 m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
));
203 // change the attribute
204 m_attrs
[(size_t)n
].attr
= *attr
;
208 // remove this attribute
209 m_attrs
.RemoveAt((size_t)n
);
216 wxGridCellAttr
*wxGridCellAttrProviderData::GetAttr(int row
, int col
) const
218 wxGridCellAttr
*attr
= (wxGridCellAttr
*)NULL
;
220 int n
= FindIndex(row
, col
);
221 if ( n
!= wxNOT_FOUND
)
223 attr
= new wxGridCellAttr(m_attrs
[(size_t)n
].attr
);
229 int wxGridCellAttrProviderData::FindIndex(int row
, int col
) const
231 size_t count
= m_attrs
.GetCount();
232 for ( size_t n
= 0; n
< count
; n
++ )
234 const wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
235 if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) )
244 // ----------------------------------------------------------------------------
245 // wxGridCellAttrProvider
246 // ----------------------------------------------------------------------------
248 wxGridCellAttrProvider::wxGridCellAttrProvider()
250 m_data
= (wxGridCellAttrProviderData
*)NULL
;
253 wxGridCellAttrProvider::~wxGridCellAttrProvider()
258 void wxGridCellAttrProvider::InitData()
260 m_data
= new wxGridCellAttrProviderData
;
263 wxGridCellAttr
*wxGridCellAttrProvider::GetAttr(int row
, int col
) const
265 return m_data
? m_data
->GetAttr(row
, col
) : (wxGridCellAttr
*)NULL
;
268 void wxGridCellAttrProvider::SetAttr(const wxGridCellAttr
*attr
,
274 m_data
->SetAttr(attr
, row
, col
);
277 //////////////////////////////////////////////////////////////////////
279 // Abstract base class for grid data (the model)
281 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
284 wxGridTableBase::wxGridTableBase()
286 m_view
= (wxGrid
*) NULL
;
287 m_attrProvider
= (wxGridCellAttrProvider
*) NULL
;
290 wxGridTableBase::~wxGridTableBase()
292 delete m_attrProvider
;
295 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider
*attrProvider
)
297 delete m_attrProvider
;
298 m_attrProvider
= attrProvider
;
301 wxGridCellAttr
*wxGridTableBase::GetAttr(int row
, int col
)
303 if ( m_attrProvider
)
304 return m_attrProvider
->GetAttr(row
, col
);
306 return (wxGridCellAttr
*)NULL
;
309 void wxGridTableBase::SetAttr(const wxGridCellAttr
*attr
, int row
, int col
)
311 if ( m_attrProvider
)
313 m_attrProvider
->SetAttr(attr
, row
, col
);
317 // as we take ownership of the pointer and don't store it, we must
323 bool wxGridTableBase::InsertRows( size_t pos
, size_t numRows
)
325 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
326 "but your derived table class does not override this function") );
331 bool wxGridTableBase::AppendRows( size_t numRows
)
333 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
334 "but your derived table class does not override this function"));
339 bool wxGridTableBase::DeleteRows( size_t pos
, size_t numRows
)
341 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
342 "but your derived table class does not override this function"));
347 bool wxGridTableBase::InsertCols( size_t pos
, size_t numCols
)
349 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
350 "but your derived table class does not override this function"));
355 bool wxGridTableBase::AppendCols( size_t numCols
)
357 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
358 "but your derived table class does not override this function"));
363 bool wxGridTableBase::DeleteCols( size_t pos
, size_t numCols
)
365 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
366 "but your derived table class does not override this function"));
372 wxString
wxGridTableBase::GetRowLabelValue( int row
)
379 wxString
wxGridTableBase::GetColLabelValue( int col
)
381 // default col labels are:
382 // cols 0 to 25 : A-Z
383 // cols 26 to 675 : AA-ZZ
390 s
+= (_T('A') + (wxChar
)( col%26
));
392 if ( col
< 0 ) break;
395 // reverse the string...
397 for ( i
= 0; i
< n
; i
++ )
407 //////////////////////////////////////////////////////////////////////
409 // Message class for the grid table to send requests and notifications
413 wxGridTableMessage::wxGridTableMessage()
415 m_table
= (wxGridTableBase
*) NULL
;
421 wxGridTableMessage::wxGridTableMessage( wxGridTableBase
*table
, int id
,
422 int commandInt1
, int commandInt2
)
426 m_comInt1
= commandInt1
;
427 m_comInt2
= commandInt2
;
432 //////////////////////////////////////////////////////////////////////
434 // A basic grid table for string data. An object of this class will
435 // created by wxGrid if you don't specify an alternative table class.
438 WX_DEFINE_OBJARRAY(wxGridStringArray
)
440 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
442 wxGridStringTable::wxGridStringTable()
447 wxGridStringTable::wxGridStringTable( int numRows
, int numCols
)
452 m_data
.Alloc( numRows
);
456 for ( col
= 0; col
< numCols
; col
++ )
458 sa
.Add( wxEmptyString
);
461 for ( row
= 0; row
< numRows
; row
++ )
467 wxGridStringTable::~wxGridStringTable()
471 long wxGridStringTable::GetNumberRows()
473 return m_data
.GetCount();
476 long wxGridStringTable::GetNumberCols()
478 if ( m_data
.GetCount() > 0 )
479 return m_data
[0].GetCount();
484 wxString
wxGridStringTable::GetValue( int row
, int col
)
486 // TODO: bounds checking
488 return m_data
[row
][col
];
491 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& s
)
493 // TODO: bounds checking
495 m_data
[row
][col
] = s
;
498 bool wxGridStringTable::IsEmptyCell( int row
, int col
)
500 // TODO: bounds checking
502 return (m_data
[row
][col
] == wxEmptyString
);
506 void wxGridStringTable::Clear()
509 int numRows
, numCols
;
511 numRows
= m_data
.GetCount();
514 numCols
= m_data
[0].GetCount();
516 for ( row
= 0; row
< numRows
; row
++ )
518 for ( col
= 0; col
< numCols
; col
++ )
520 m_data
[row
][col
] = wxEmptyString
;
527 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows
)
531 size_t curNumRows
= m_data
.GetCount();
532 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
534 if ( pos
>= curNumRows
)
536 return AppendRows( numRows
);
540 sa
.Alloc( curNumCols
);
541 for ( col
= 0; col
< curNumCols
; col
++ )
543 sa
.Add( wxEmptyString
);
546 for ( row
= pos
; row
< pos
+ numRows
; row
++ )
548 m_data
.Insert( sa
, row
);
553 wxGridTableMessage
msg( this,
554 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
558 GetView()->ProcessTableMessage( msg
);
564 bool wxGridStringTable::AppendRows( size_t numRows
)
568 size_t curNumRows
= m_data
.GetCount();
569 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
572 if ( curNumCols
> 0 )
574 sa
.Alloc( curNumCols
);
575 for ( col
= 0; col
< curNumCols
; col
++ )
577 sa
.Add( wxEmptyString
);
581 for ( row
= 0; row
< numRows
; row
++ )
588 wxGridTableMessage
msg( this,
589 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
592 GetView()->ProcessTableMessage( msg
);
598 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows
)
602 size_t curNumRows
= m_data
.GetCount();
604 if ( pos
>= curNumRows
)
607 errmsg
.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
608 "Pos value is invalid for present table with %d rows",
609 pos
, numRows
, curNumRows
);
610 wxFAIL_MSG( wxT(errmsg
) );
614 if ( numRows
> curNumRows
- pos
)
616 numRows
= curNumRows
- pos
;
619 if ( numRows
>= curNumRows
)
621 m_data
.Empty(); // don't release memory just yet
625 for ( n
= 0; n
< numRows
; n
++ )
627 m_data
.Remove( pos
);
633 wxGridTableMessage
msg( this,
634 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
638 GetView()->ProcessTableMessage( msg
);
644 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols
)
648 size_t curNumRows
= m_data
.GetCount();
649 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
651 if ( pos
>= curNumCols
)
653 return AppendCols( numCols
);
656 for ( row
= 0; row
< curNumRows
; row
++ )
658 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
660 m_data
[row
].Insert( wxEmptyString
, col
);
666 wxGridTableMessage
msg( this,
667 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
671 GetView()->ProcessTableMessage( msg
);
677 bool wxGridStringTable::AppendCols( size_t numCols
)
681 size_t curNumRows
= m_data
.GetCount();
684 // TODO: something better than this ?
686 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
687 "Call AppendRows() first") );
691 for ( row
= 0; row
< curNumRows
; row
++ )
693 for ( n
= 0; n
< numCols
; n
++ )
695 m_data
[row
].Add( wxEmptyString
);
701 wxGridTableMessage
msg( this,
702 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
705 GetView()->ProcessTableMessage( msg
);
711 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols
)
715 size_t curNumRows
= m_data
.GetCount();
716 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
718 if ( pos
>= curNumCols
)
721 errmsg
.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
722 "Pos value is invalid for present table with %d cols",
723 pos
, numCols
, curNumCols
);
724 wxFAIL_MSG( wxT( errmsg
) );
728 if ( numCols
> curNumCols
- pos
)
730 numCols
= curNumCols
- pos
;
733 for ( row
= 0; row
< curNumRows
; row
++ )
735 if ( numCols
>= curNumCols
)
741 for ( n
= 0; n
< numCols
; n
++ )
743 m_data
[row
].Remove( pos
);
750 wxGridTableMessage
msg( this,
751 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
755 GetView()->ProcessTableMessage( msg
);
761 wxString
wxGridStringTable::GetRowLabelValue( int row
)
763 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
765 // using default label
767 return wxGridTableBase::GetRowLabelValue( row
);
771 return m_rowLabels
[ row
];
775 wxString
wxGridStringTable::GetColLabelValue( int col
)
777 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
779 // using default label
781 return wxGridTableBase::GetColLabelValue( col
);
785 return m_colLabels
[ col
];
789 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value
)
791 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
793 int n
= m_rowLabels
.GetCount();
795 for ( i
= n
; i
<= row
; i
++ )
797 m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) );
801 m_rowLabels
[row
] = value
;
804 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value
)
806 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
808 int n
= m_colLabels
.GetCount();
810 for ( i
= n
; i
<= col
; i
++ )
812 m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) );
816 m_colLabels
[col
] = value
;
822 //////////////////////////////////////////////////////////////////////
824 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl
, wxTextCtrl
)
826 BEGIN_EVENT_TABLE( wxGridTextCtrl
, wxTextCtrl
)
827 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown
)
831 wxGridTextCtrl::wxGridTextCtrl( wxWindow
*par
,
835 const wxString
& value
,
839 : wxTextCtrl( par
, id
, value
, pos
, size
, style
)
842 m_isCellControl
= isCellControl
;
846 void wxGridTextCtrl::OnKeyDown( wxKeyEvent
& event
)
848 switch ( event
.KeyCode() )
851 m_grid
->SetEditControlValue( startValue
);
852 SetInsertionPointEnd();
862 if ( m_isCellControl
)
864 // send the event to the parent grid, skipping the
865 // event if nothing happens
867 event
.Skip( m_grid
->ProcessEvent( event
) );
871 // default text control response within the top edit
879 if ( m_isCellControl
)
881 if ( !m_grid
->ProcessEvent( event
) )
883 #if defined(__WXMOTIF__) || defined(__WXGTK__)
884 // wxMotif needs a little extra help...
886 int pos
= GetInsertionPoint();
887 wxString
s( GetValue() );
888 s
= s
.Left(pos
) + "\n" + s
.Mid(pos
);
890 SetInsertionPoint( pos
);
892 // the other ports can handle a Return key press
902 if ( m_isCellControl
)
904 // send the event to the parent grid, skipping the
905 // event if nothing happens
907 event
.Skip( m_grid
->ProcessEvent( event
) );
911 // default text control response within the top edit
923 void wxGridTextCtrl::SetStartValue( const wxString
& s
)
926 wxTextCtrl::SetValue(s
);
931 //////////////////////////////////////////////////////////////////////
933 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow
)
935 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxWindow
)
936 EVT_PAINT( wxGridRowLabelWindow::OnPaint
)
937 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent
)
938 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown
)
941 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid
*parent
,
943 const wxPoint
&pos
, const wxSize
&size
)
944 : wxWindow( parent
, id
, pos
, size
)
949 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
&event
)
953 // NO - don't do this because it will set both the x and y origin
954 // coords to match the parent scrolled window and we just want to
955 // set the y coord - MB
957 // m_owner->PrepareDC( dc );
960 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
961 dc
.SetDeviceOrigin( 0, -y
);
963 m_owner
->CalcRowLabelsExposed( GetUpdateRegion() );
964 m_owner
->DrawRowLabels( dc
);
968 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
970 m_owner
->ProcessRowLabelMouseEvent( event
);
974 // This seems to be required for wxMotif otherwise the mouse
975 // cursor must be in the cell edit control to get key events
977 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent
& event
)
979 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
984 //////////////////////////////////////////////////////////////////////
986 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow
)
988 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxWindow
)
989 EVT_PAINT( wxGridColLabelWindow::OnPaint
)
990 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent
)
991 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown
)
994 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid
*parent
,
996 const wxPoint
&pos
, const wxSize
&size
)
997 : wxWindow( parent
, id
, pos
, size
)
1002 void wxGridColLabelWindow::OnPaint( wxPaintEvent
&event
)
1006 // NO - don't do this because it will set both the x and y origin
1007 // coords to match the parent scrolled window and we just want to
1008 // set the x coord - MB
1010 // m_owner->PrepareDC( dc );
1013 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
1014 dc
.SetDeviceOrigin( -x
, 0 );
1016 m_owner
->CalcColLabelsExposed( GetUpdateRegion() );
1017 m_owner
->DrawColLabels( dc
);
1021 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
1023 m_owner
->ProcessColLabelMouseEvent( event
);
1027 // This seems to be required for wxMotif otherwise the mouse
1028 // cursor must be in the cell edit control to get key events
1030 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent
& event
)
1032 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1037 //////////////////////////////////////////////////////////////////////
1039 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow
)
1041 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxWindow
)
1042 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent
)
1043 EVT_PAINT( wxGridCornerLabelWindow::OnPaint
)
1044 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown
)
1047 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid
*parent
,
1049 const wxPoint
&pos
, const wxSize
&size
)
1050 : wxWindow( parent
, id
, pos
, size
)
1055 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1059 int client_height
= 0;
1060 int client_width
= 0;
1061 GetClientSize( &client_width
, &client_height
);
1063 dc
.SetPen( *wxBLACK_PEN
);
1064 dc
.DrawLine( client_width
-1, client_height
-1, client_width
-1, 0 );
1065 dc
.DrawLine( client_width
-1, client_height
-1, 0, client_height
-1 );
1067 dc
.SetPen( *wxWHITE_PEN
);
1068 dc
.DrawLine( 0, 0, client_width
, 0 );
1069 dc
.DrawLine( 0, 0, 0, client_height
);
1073 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
1075 m_owner
->ProcessCornerLabelMouseEvent( event
);
1079 // This seems to be required for wxMotif otherwise the mouse
1080 // cursor must be in the cell edit control to get key events
1082 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent
& event
)
1084 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1089 //////////////////////////////////////////////////////////////////////
1091 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxPanel
)
1093 BEGIN_EVENT_TABLE( wxGridWindow
, wxPanel
)
1094 EVT_PAINT( wxGridWindow::OnPaint
)
1095 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent
)
1096 EVT_KEY_DOWN( wxGridWindow::OnKeyDown
)
1099 wxGridWindow::wxGridWindow( wxGrid
*parent
,
1100 wxGridRowLabelWindow
*rowLblWin
,
1101 wxGridColLabelWindow
*colLblWin
,
1102 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
)
1103 : wxPanel( parent
, id
, pos
, size
, 0, "grid window" )
1106 m_rowLabelWin
= rowLblWin
;
1107 m_colLabelWin
= colLblWin
;
1109 SetBackgroundColour( "WHITE" );
1113 wxGridWindow::~wxGridWindow()
1118 void wxGridWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1120 wxPaintDC
dc( this );
1121 m_owner
->PrepareDC( dc
);
1122 wxRegion reg
= GetUpdateRegion();
1123 m_owner
->CalcCellsExposed( reg
);
1124 m_owner
->DrawGridCellArea( dc
);
1125 #if WXGRID_DRAW_LINES
1126 m_owner
->DrawAllGridLines( dc
, reg
);
1131 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1133 wxPanel::ScrollWindow( dx
, dy
, rect
);
1134 m_rowLabelWin
->ScrollWindow( 0, dy
, rect
);
1135 m_colLabelWin
->ScrollWindow( dx
, 0, rect
);
1139 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event
)
1141 m_owner
->ProcessGridCellMouseEvent( event
);
1145 // This seems to be required for wxMotif otherwise the mouse
1146 // cursor must be in the cell edit control to get key events
1148 void wxGridWindow::OnKeyDown( wxKeyEvent
& event
)
1150 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1155 //////////////////////////////////////////////////////////////////////
1157 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow
)
1159 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow
)
1160 EVT_PAINT( wxGrid::OnPaint
)
1161 EVT_SIZE( wxGrid::OnSize
)
1162 EVT_KEY_DOWN( wxGrid::OnKeyDown
)
1165 wxGrid::wxGrid( wxWindow
*parent
,
1170 const wxString
& name
)
1171 : wxScrolledWindow( parent
, id
, pos
, size
, style
, name
)
1184 // ----- internal init and update functions
1187 void wxGrid::Create()
1189 m_created
= FALSE
; // set to TRUE by CreateGrid
1190 m_displayed
= FALSE
; // set to TRUE by OnPaint
1192 m_table
= (wxGridTableBase
*) NULL
;
1193 m_cellEditCtrl
= (wxWindow
*) NULL
;
1197 m_currentCellCoords
= wxGridNoCellCoords
;
1199 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
1200 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1202 m_cornerLabelWin
= new wxGridCornerLabelWindow( this,
1207 m_rowLabelWin
= new wxGridRowLabelWindow( this,
1212 m_colLabelWin
= new wxGridColLabelWindow( this,
1217 m_gridWin
= new wxGridWindow( this,
1224 SetTargetWindow( m_gridWin
);
1228 bool wxGrid::CreateGrid( int numRows
, int numCols
)
1232 wxFAIL_MSG( wxT("wxGrid::CreateGrid called more than once") );
1237 m_numRows
= numRows
;
1238 m_numCols
= numCols
;
1240 m_table
= new wxGridStringTable( m_numRows
, m_numCols
);
1241 m_table
->SetView( this );
1254 if ( m_numRows
<= 0 )
1255 m_numRows
= WXGRID_DEFAULT_NUMBER_ROWS
;
1257 if ( m_numCols
<= 0 )
1258 m_numCols
= WXGRID_DEFAULT_NUMBER_COLS
;
1260 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
1261 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1263 if ( m_rowLabelWin
)
1265 m_labelBackgroundColour
= m_rowLabelWin
->GetBackgroundColour();
1269 m_labelBackgroundColour
= wxColour( _T("WHITE") );
1272 m_labelTextColour
= wxColour( _T("BLACK") );
1274 // TODO: something better than this ?
1276 m_labelFont
= this->GetFont();
1277 m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 );
1279 m_rowLabelHorizAlign
= wxLEFT
;
1280 m_rowLabelVertAlign
= wxCENTRE
;
1282 m_colLabelHorizAlign
= wxCENTRE
;
1283 m_colLabelVertAlign
= wxTOP
;
1285 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
1286 m_defaultRowHeight
= m_gridWin
->GetCharHeight();
1288 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1289 m_defaultRowHeight
+= 8;
1291 m_defaultRowHeight
+= 4;
1294 m_rowHeights
.Alloc( m_numRows
);
1295 m_rowBottoms
.Alloc( m_numRows
);
1297 for ( i
= 0; i
< m_numRows
; i
++ )
1299 m_rowHeights
.Add( m_defaultRowHeight
);
1300 rowBottom
+= m_defaultRowHeight
;
1301 m_rowBottoms
.Add( rowBottom
);
1304 m_colWidths
.Alloc( m_numCols
);
1305 m_colRights
.Alloc( m_numCols
);
1307 for ( i
= 0; i
< m_numCols
; i
++ )
1309 m_colWidths
.Add( m_defaultColWidth
);
1310 colRight
+= m_defaultColWidth
;
1311 m_colRights
.Add( colRight
);
1314 // TODO: improve this by using wxSystemSettings?
1316 m_defaultCellFont
= GetFont();
1318 m_defaultCellHAlign
= wxLEFT
;
1319 m_defaultCellVAlign
= wxTOP
;
1321 m_gridLineColour
= wxColour( 128, 128, 255 );
1322 m_gridLinesEnabled
= TRUE
;
1324 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1326 m_dragRowOrCol
= -1;
1327 m_isDragging
= FALSE
;
1329 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
1330 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
1332 m_currentCellCoords
= wxGridNoCellCoords
;
1334 m_selectedTopLeft
= wxGridNoCellCoords
;
1335 m_selectedBottomRight
= wxGridNoCellCoords
;
1337 m_editable
= TRUE
; // default for whole grid
1339 m_inOnKeyDown
= FALSE
;
1342 // TODO: extend this to other types of controls
1344 m_cellEditCtrl
= new wxGridTextCtrl( m_gridWin
,
1351 #if defined(__WXMSW__)
1352 , wxTE_MULTILINE
| wxTE_NO_VSCROLL
1356 m_cellEditCtrl
->Show( FALSE
);
1357 m_cellEditCtrlEnabled
= TRUE
;
1358 m_editCtrlType
= wxGRID_TEXTCTRL
;
1362 void wxGrid::CalcDimensions()
1365 GetClientSize( &cw
, &ch
);
1367 if ( m_numRows
> 0 && m_numCols
> 0 )
1369 int right
= m_colRights
[ m_numCols
-1 ] + 50;
1370 int bottom
= m_rowBottoms
[ m_numRows
-1 ] + 50;
1372 // TODO: restore the scroll position that we had before sizing
1375 GetViewStart( &x
, &y
);
1376 SetScrollbars( GRID_SCROLL_LINE
, GRID_SCROLL_LINE
,
1377 right
/GRID_SCROLL_LINE
, bottom
/GRID_SCROLL_LINE
,
1383 void wxGrid::CalcWindowSizes()
1386 GetClientSize( &cw
, &ch
);
1388 if ( m_cornerLabelWin
->IsShown() )
1389 m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight
);
1391 if ( m_colLabelWin
->IsShown() )
1392 m_colLabelWin
->SetSize( m_rowLabelWidth
, 0, cw
-m_rowLabelWidth
, m_colLabelHeight
);
1394 if ( m_rowLabelWin
->IsShown() )
1395 m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, ch
-m_colLabelHeight
);
1397 if ( m_gridWin
->IsShown() )
1398 m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, cw
-m_rowLabelWidth
, ch
-m_colLabelHeight
);
1402 // this is called when the grid table sends a message to say that it
1403 // has been redimensioned
1405 bool wxGrid::Redimension( wxGridTableMessage
& msg
)
1409 switch ( msg
.GetId() )
1411 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
1413 size_t pos
= msg
.GetCommandInt();
1414 int numRows
= msg
.GetCommandInt2();
1415 for ( i
= 0; i
< numRows
; i
++ )
1417 m_rowHeights
.Insert( m_defaultRowHeight
, pos
);
1418 m_rowBottoms
.Insert( 0, pos
);
1420 m_numRows
+= numRows
;
1423 if ( pos
> 0 ) bottom
= m_rowBottoms
[pos
-1];
1425 for ( i
= pos
; i
< m_numRows
; i
++ )
1427 bottom
+= m_rowHeights
[i
];
1428 m_rowBottoms
[i
] = bottom
;
1434 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
1436 int numRows
= msg
.GetCommandInt();
1437 for ( i
= 0; i
< numRows
; i
++ )
1439 m_rowHeights
.Add( m_defaultRowHeight
);
1440 m_rowBottoms
.Add( 0 );
1443 int oldNumRows
= m_numRows
;
1444 m_numRows
+= numRows
;
1447 if ( oldNumRows
> 0 ) bottom
= m_rowBottoms
[oldNumRows
-1];
1449 for ( i
= oldNumRows
; i
< m_numRows
; i
++ )
1451 bottom
+= m_rowHeights
[i
];
1452 m_rowBottoms
[i
] = bottom
;
1458 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
1460 size_t pos
= msg
.GetCommandInt();
1461 int numRows
= msg
.GetCommandInt2();
1462 for ( i
= 0; i
< numRows
; i
++ )
1464 m_rowHeights
.Remove( pos
);
1465 m_rowBottoms
.Remove( pos
);
1467 m_numRows
-= numRows
;
1472 m_colWidths
.Clear();
1473 m_colRights
.Clear();
1474 m_currentCellCoords
= wxGridNoCellCoords
;
1478 if ( m_currentCellCoords
.GetRow() >= m_numRows
)
1479 m_currentCellCoords
.Set( 0, 0 );
1482 for ( i
= 0; i
< m_numRows
; i
++ )
1484 h
+= m_rowHeights
[i
];
1485 m_rowBottoms
[i
] = h
;
1493 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
1495 size_t pos
= msg
.GetCommandInt();
1496 int numCols
= msg
.GetCommandInt2();
1497 for ( i
= 0; i
< numCols
; i
++ )
1499 m_colWidths
.Insert( m_defaultColWidth
, pos
);
1500 m_colRights
.Insert( 0, pos
);
1502 m_numCols
+= numCols
;
1505 if ( pos
> 0 ) right
= m_colRights
[pos
-1];
1507 for ( i
= pos
; i
< m_numCols
; i
++ )
1509 right
+= m_colWidths
[i
];
1510 m_colRights
[i
] = right
;
1516 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
1518 int numCols
= msg
.GetCommandInt();
1519 for ( i
= 0; i
< numCols
; i
++ )
1521 m_colWidths
.Add( m_defaultColWidth
);
1522 m_colRights
.Add( 0 );
1525 int oldNumCols
= m_numCols
;
1526 m_numCols
+= numCols
;
1529 if ( oldNumCols
> 0 ) right
= m_colRights
[oldNumCols
-1];
1531 for ( i
= oldNumCols
; i
< m_numCols
; i
++ )
1533 right
+= m_colWidths
[i
];
1534 m_colRights
[i
] = right
;
1540 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
1542 size_t pos
= msg
.GetCommandInt();
1543 int numCols
= msg
.GetCommandInt2();
1544 for ( i
= 0; i
< numCols
; i
++ )
1546 m_colWidths
.Remove( pos
);
1547 m_colRights
.Remove( pos
);
1549 m_numCols
-= numCols
;
1553 #if 0 // leave the row alone here so that AppendCols will work subsequently
1555 m_rowHeights
.Clear();
1556 m_rowBottoms
.Clear();
1558 m_currentCellCoords
= wxGridNoCellCoords
;
1562 if ( m_currentCellCoords
.GetCol() >= m_numCols
)
1563 m_currentCellCoords
.Set( 0, 0 );
1566 for ( i
= 0; i
< m_numCols
; i
++ )
1568 w
+= m_colWidths
[i
];
1581 void wxGrid::CalcRowLabelsExposed( wxRegion
& reg
)
1583 wxRegionIterator
iter( reg
);
1586 m_rowLabelsExposed
.Empty();
1593 // TODO: remove this when we can...
1594 // There is a bug in wxMotif that gives garbage update
1595 // rectangles if you jump-scroll a long way by clicking the
1596 // scrollbar with middle button. This is a work-around
1598 #if defined(__WXMOTIF__)
1600 m_gridWin
->GetClientSize( &cw
, &ch
);
1601 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1602 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1605 // logical bounds of update region
1608 CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top
);
1609 CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom
);
1611 // find the row labels within these bounds
1615 for ( row
= 0; row
< m_numRows
; row
++ )
1617 if ( m_rowBottoms
[row
] < top
) continue;
1619 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1620 if ( rowTop
> bottom
) break;
1622 m_rowLabelsExposed
.Add( row
);
1630 void wxGrid::CalcColLabelsExposed( wxRegion
& reg
)
1632 wxRegionIterator
iter( reg
);
1635 m_colLabelsExposed
.Empty();
1642 // TODO: remove this when we can...
1643 // There is a bug in wxMotif that gives garbage update
1644 // rectangles if you jump-scroll a long way by clicking the
1645 // scrollbar with middle button. This is a work-around
1647 #if defined(__WXMOTIF__)
1649 m_gridWin
->GetClientSize( &cw
, &ch
);
1650 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1651 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1654 // logical bounds of update region
1657 CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy
);
1658 CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy
);
1660 // find the cells within these bounds
1664 for ( col
= 0; col
< m_numCols
; col
++ )
1666 if ( m_colRights
[col
] < left
) continue;
1668 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1669 if ( colLeft
> right
) break;
1671 m_colLabelsExposed
.Add( col
);
1679 void wxGrid::CalcCellsExposed( wxRegion
& reg
)
1681 wxRegionIterator
iter( reg
);
1684 m_cellsExposed
.Empty();
1685 m_rowsExposed
.Empty();
1686 m_colsExposed
.Empty();
1688 int left
, top
, right
, bottom
;
1693 // TODO: remove this when we can...
1694 // There is a bug in wxMotif that gives garbage update
1695 // rectangles if you jump-scroll a long way by clicking the
1696 // scrollbar with middle button. This is a work-around
1698 #if defined(__WXMOTIF__)
1700 m_gridWin
->GetClientSize( &cw
, &ch
);
1701 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1702 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1703 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1704 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1707 // logical bounds of update region
1709 CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
1710 CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
1712 // find the cells within these bounds
1715 int colLeft
, rowTop
;
1716 for ( row
= 0; row
< m_numRows
; row
++ )
1718 if ( m_rowBottoms
[row
] < top
) continue;
1720 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1721 if ( rowTop
> bottom
) break;
1723 m_rowsExposed
.Add( row
);
1725 for ( col
= 0; col
< m_numCols
; col
++ )
1727 if ( m_colRights
[col
] < left
) continue;
1729 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1730 if ( colLeft
> right
) break;
1732 if ( m_colsExposed
.Index( col
) == wxNOT_FOUND
) m_colsExposed
.Add( col
);
1733 m_cellsExposed
.Add( wxGridCellCoords( row
, col
) );
1742 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event
)
1745 wxPoint
pos( event
.GetPosition() );
1746 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1748 if ( event
.Dragging() )
1750 m_isDragging
= TRUE
;
1752 if ( event
.LeftIsDown() )
1754 switch( m_cursorMode
)
1756 case WXGRID_CURSOR_RESIZE_ROW
:
1758 int cw
, ch
, left
, dummy
;
1759 m_gridWin
->GetClientSize( &cw
, &ch
);
1760 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
1762 wxClientDC
dc( m_gridWin
);
1764 dc
.SetLogicalFunction(wxINVERT
);
1765 if ( m_dragLastPos
>= 0 )
1767 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
1769 dc
.DrawLine( left
, y
, left
+cw
, y
);
1774 case WXGRID_CURSOR_SELECT_ROW
:
1776 if ( (row
= YToRow( y
)) >= 0 &&
1777 !IsInSelection( row
, 0 ) )
1779 SelectRow( row
, TRUE
);
1788 m_isDragging
= FALSE
;
1791 // ------------ Left button pressed
1793 if ( event
.LeftDown() )
1795 // don't send a label click event for a hit on the
1796 // edge of the row label - this is probably the user
1797 // wanting to resize the row
1799 if ( YToEdgeOfRow(y
) < 0 )
1803 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event
) )
1805 SelectRow( row
, event
.ShiftDown() );
1806 m_cursorMode
= WXGRID_CURSOR_SELECT_ROW
;
1811 // starting to drag-resize a row
1813 m_rowLabelWin
->CaptureMouse();
1818 // ------------ Left double click
1820 else if (event
.LeftDClick() )
1822 if ( YToEdgeOfRow(y
) < 0 )
1825 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event
);
1830 // ------------ Left button released
1832 else if ( event
.LeftUp() )
1834 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
1836 m_rowLabelWin
->ReleaseMouse();
1838 if ( m_dragLastPos
>= 0 )
1840 // erase the last line and resize the row
1842 int cw
, ch
, left
, dummy
;
1843 m_gridWin
->GetClientSize( &cw
, &ch
);
1844 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
1846 wxClientDC
dc( m_gridWin
);
1848 dc
.SetLogicalFunction( wxINVERT
);
1849 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
1850 HideCellEditControl();
1852 int rowTop
= m_rowBottoms
[m_dragRowOrCol
] - m_rowHeights
[m_dragRowOrCol
];
1853 SetRowSize( m_dragRowOrCol
, wxMax( y
- rowTop
, WXGRID_MIN_ROW_HEIGHT
) );
1854 if ( !GetBatchCount() )
1856 // Only needed to get the correct rect.y:
1857 wxRect
rect ( CellToRect( m_dragRowOrCol
, 0 ) );
1859 CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
);
1860 rect
.width
= m_rowLabelWidth
;
1861 rect
.height
= ch
- rect
.y
;
1862 m_rowLabelWin
->Refresh( TRUE
, &rect
);
1864 m_gridWin
->Refresh( FALSE
, &rect
);
1867 ShowCellEditControl();
1869 // Note: we are ending the event *after* doing
1870 // default processing in this case
1872 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
1876 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1881 // ------------ Right button down
1883 else if ( event
.RightDown() )
1886 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event
) )
1888 // no default action at the moment
1893 // ------------ Right double click
1895 else if ( event
.RightDClick() )
1898 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event
) )
1900 // no default action at the moment
1905 // ------------ No buttons down and mouse moving
1907 else if ( event
.Moving() )
1909 m_dragRowOrCol
= YToEdgeOfRow( y
);
1910 if ( m_dragRowOrCol
>= 0 )
1912 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1914 m_cursorMode
= WXGRID_CURSOR_RESIZE_ROW
;
1915 m_rowLabelWin
->SetCursor( m_rowResizeCursor
);
1920 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1921 if ( m_rowLabelWin
->GetCursor() == m_rowResizeCursor
)
1922 m_rowLabelWin
->SetCursor( *wxSTANDARD_CURSOR
);
1928 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event
)
1931 wxPoint
pos( event
.GetPosition() );
1932 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1934 if ( event
.Dragging() )
1936 m_isDragging
= TRUE
;
1938 if ( event
.LeftIsDown() )
1940 switch( m_cursorMode
)
1942 case WXGRID_CURSOR_RESIZE_COL
:
1944 int cw
, ch
, dummy
, top
;
1945 m_gridWin
->GetClientSize( &cw
, &ch
);
1946 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
1948 wxClientDC
dc( m_gridWin
);
1950 dc
.SetLogicalFunction(wxINVERT
);
1951 if ( m_dragLastPos
>= 0 )
1953 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
1955 dc
.DrawLine( x
, top
, x
, top
+ch
);
1960 case WXGRID_CURSOR_SELECT_COL
:
1962 if ( (col
= XToCol( x
)) >= 0 &&
1963 !IsInSelection( 0, col
) )
1965 SelectCol( col
, TRUE
);
1974 m_isDragging
= FALSE
;
1977 // ------------ Left button pressed
1979 if ( event
.LeftDown() )
1981 // don't send a label click event for a hit on the
1982 // edge of the col label - this is probably the user
1983 // wanting to resize the col
1985 if ( XToEdgeOfCol(x
) < 0 )
1989 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event
) )
1991 SelectCol( col
, event
.ShiftDown() );
1992 m_cursorMode
= WXGRID_CURSOR_SELECT_COL
;
1997 // starting to drag-resize a col
1999 m_colLabelWin
->CaptureMouse();
2004 // ------------ Left double click
2006 if ( event
.LeftDClick() )
2008 if ( XToEdgeOfCol(x
) < 0 )
2011 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event
);
2016 // ------------ Left button released
2018 else if ( event
.LeftUp() )
2020 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
2022 m_colLabelWin
->ReleaseMouse();
2024 if ( m_dragLastPos
>= 0 )
2026 // erase the last line and resize the col
2028 int cw
, ch
, dummy
, top
;
2029 m_gridWin
->GetClientSize( &cw
, &ch
);
2030 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
2032 wxClientDC
dc( m_gridWin
);
2034 dc
.SetLogicalFunction( wxINVERT
);
2035 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
2036 HideCellEditControl();
2038 int colLeft
= m_colRights
[m_dragRowOrCol
] - m_colWidths
[m_dragRowOrCol
];
2039 SetColSize( m_dragRowOrCol
, wxMax( x
- colLeft
, WXGRID_MIN_COL_WIDTH
) );
2041 if ( !GetBatchCount() )
2043 // Only needed to get the correct rect.x:
2044 wxRect
rect ( CellToRect( 0, m_dragRowOrCol
) );
2046 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
);
2047 rect
.width
= cw
- rect
.x
;
2048 rect
.height
= m_colLabelHeight
;
2049 m_colLabelWin
->Refresh( TRUE
, &rect
);
2051 m_gridWin
->Refresh( FALSE
, &rect
);
2054 ShowCellEditControl();
2056 // Note: we are ending the event *after* doing
2057 // default processing in this case
2059 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
2063 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
2068 // ------------ Right button down
2070 else if ( event
.RightDown() )
2073 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event
) )
2075 // no default action at the moment
2080 // ------------ Right double click
2082 else if ( event
.RightDClick() )
2085 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event
) )
2087 // no default action at the moment
2092 // ------------ No buttons down and mouse moving
2094 else if ( event
.Moving() )
2096 m_dragRowOrCol
= XToEdgeOfCol( x
);
2097 if ( m_dragRowOrCol
>= 0 )
2099 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2101 m_cursorMode
= WXGRID_CURSOR_RESIZE_COL
;
2102 m_colLabelWin
->SetCursor( m_colResizeCursor
);
2107 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
2108 if ( m_colLabelWin
->GetCursor() == m_colResizeCursor
)
2109 m_colLabelWin
->SetCursor( *wxSTANDARD_CURSOR
);
2115 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event
)
2117 if ( event
.LeftDown() )
2119 // indicate corner label by having both row and
2122 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event
) )
2128 else if ( event
.LeftDClick() )
2130 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event
);
2133 else if ( event
.RightDown() )
2135 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event
) )
2137 // no default action at the moment
2141 else if ( event
.RightDClick() )
2143 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event
) )
2145 // no default action at the moment
2151 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent
& event
)
2154 wxPoint
pos( event
.GetPosition() );
2155 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
2157 wxGridCellCoords coords
;
2158 XYToCell( x
, y
, coords
);
2160 if ( event
.Dragging() )
2162 m_isDragging
= TRUE
;
2163 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2165 // Hide the edit control, so it
2166 // won't interfer with drag-shrinking.
2167 if ( IsCellEditControlEnabled() )
2168 HideCellEditControl();
2169 if ( coords
!= wxGridNoCellCoords
)
2171 if ( !IsSelection() )
2173 SelectBlock( coords
, coords
);
2177 SelectBlock( m_currentCellCoords
, coords
);
2185 m_isDragging
= FALSE
;
2187 if ( coords
!= wxGridNoCellCoords
)
2189 if ( event
.LeftDown() )
2191 if ( event
.ShiftDown() )
2193 SelectBlock( m_currentCellCoords
, coords
);
2197 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK
,
2202 MakeCellVisible( coords
);
2203 SetCurrentCell( coords
);
2209 // ------------ Left double click
2211 else if ( event
.LeftDClick() )
2213 SendEvent( EVT_GRID_CELL_LEFT_DCLICK
,
2220 // ------------ Left button released
2222 else if ( event
.LeftUp() )
2224 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2226 if ( IsSelection() )
2228 SendEvent( EVT_GRID_RANGE_SELECT
, -1, -1, event
);
2232 // Show the edit control, if it has
2233 // been hidden for drag-shrinking.
2234 if ( IsCellEditControlEnabled() )
2235 ShowCellEditControl();
2241 // ------------ Right button down
2243 else if ( event
.RightDown() )
2245 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK
,
2250 // no default action at the moment
2255 // ------------ Right double click
2257 else if ( event
.RightDClick() )
2259 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK
,
2264 // no default action at the moment
2268 // ------------ Moving and no button action
2270 else if ( event
.Moving() && !event
.IsButton() )
2272 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
2279 // ------ interaction with data model
2281 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg
)
2283 switch ( msg
.GetId() )
2285 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
2286 return GetModelValues();
2288 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
2289 return SetModelValues();
2291 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
2292 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
2293 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
2294 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
2295 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
2296 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
2297 return Redimension( msg
);
2306 // The behaviour of this function depends on the grid table class
2307 // Clear() function. For the default wxGridStringTable class the
2308 // behavious is to replace all cell contents with wxEmptyString but
2309 // not to change the number of rows or cols.
2311 void wxGrid::ClearGrid()
2316 SetEditControlValue();
2317 if ( !GetBatchCount() ) m_gridWin
->Refresh();
2322 bool wxGrid::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2324 // TODO: something with updateLabels flag
2328 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2334 bool ok
= m_table
->InsertRows( pos
, numRows
);
2336 // the table will have sent the results of the insert row
2337 // operation to this view object as a grid table message
2341 if ( m_numCols
== 0 )
2343 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS
);
2345 // TODO: perhaps instead of appending the default number of cols
2346 // we should remember what the last non-zero number of cols was ?
2350 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2352 // if we have just inserted cols into an empty grid the current
2353 // cell will be undefined...
2355 SetCurrentCell( 0, 0 );
2359 if ( !GetBatchCount() ) Refresh();
2362 SetEditControlValue();
2372 bool wxGrid::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) )
2374 // TODO: something with updateLabels flag
2378 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2382 if ( m_table
&& m_table
->AppendRows( numRows
) )
2384 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2386 // if we have just inserted cols into an empty grid the current
2387 // cell will be undefined...
2389 SetCurrentCell( 0, 0 );
2392 // the table will have sent the results of the append row
2393 // operation to this view object as a grid table message
2396 if ( !GetBatchCount() ) Refresh();
2406 bool wxGrid::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2408 // TODO: something with updateLabels flag
2412 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2416 if ( m_table
&& m_table
->DeleteRows( pos
, numRows
) )
2418 // the table will have sent the results of the delete row
2419 // operation to this view object as a grid table message
2421 if ( m_numRows
> 0 )
2422 SetEditControlValue();
2424 HideCellEditControl();
2427 if ( !GetBatchCount() ) Refresh();
2437 bool wxGrid::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2439 // TODO: something with updateLabels flag
2443 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2449 HideCellEditControl();
2450 bool ok
= m_table
->InsertCols( pos
, numCols
);
2452 // the table will have sent the results of the insert col
2453 // operation to this view object as a grid table message
2457 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2459 // if we have just inserted cols into an empty grid the current
2460 // cell will be undefined...
2462 SetCurrentCell( 0, 0 );
2466 if ( !GetBatchCount() ) Refresh();
2469 SetEditControlValue();
2479 bool wxGrid::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) )
2481 // TODO: something with updateLabels flag
2485 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2489 if ( m_table
&& m_table
->AppendCols( numCols
) )
2491 // the table will have sent the results of the append col
2492 // operation to this view object as a grid table message
2494 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2496 // if we have just inserted cols into an empty grid the current
2497 // cell will be undefined...
2499 SetCurrentCell( 0, 0 );
2503 if ( !GetBatchCount() ) Refresh();
2513 bool wxGrid::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2515 // TODO: something with updateLabels flag
2519 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2523 if ( m_table
&& m_table
->DeleteCols( pos
, numCols
) )
2525 // the table will have sent the results of the delete col
2526 // operation to this view object as a grid table message
2528 if ( m_numCols
> 0 )
2529 SetEditControlValue();
2531 HideCellEditControl();
2534 if ( !GetBatchCount() ) Refresh();
2546 // ----- event handlers
2549 // Generate a grid event based on a mouse event and
2550 // return the result of ProcessEvent()
2552 bool wxGrid::SendEvent( const wxEventType type
,
2554 wxMouseEvent
& mouseEv
)
2556 if ( type
== EVT_GRID_ROW_SIZE
||
2557 type
== EVT_GRID_COL_SIZE
)
2559 int rowOrCol
= (row
== -1 ? col
: row
);
2561 wxGridSizeEvent
gridEvt( GetId(),
2565 mouseEv
.GetX(), mouseEv
.GetY(),
2566 mouseEv
.ControlDown(),
2567 mouseEv
.ShiftDown(),
2569 mouseEv
.MetaDown() );
2571 return GetEventHandler()->ProcessEvent(gridEvt
);
2573 else if ( type
== EVT_GRID_RANGE_SELECT
)
2575 wxGridRangeSelectEvent
gridEvt( GetId(),
2579 m_selectedBottomRight
,
2580 mouseEv
.ControlDown(),
2581 mouseEv
.ShiftDown(),
2583 mouseEv
.MetaDown() );
2585 return GetEventHandler()->ProcessEvent(gridEvt
);
2589 wxGridEvent
gridEvt( GetId(),
2593 mouseEv
.GetX(), mouseEv
.GetY(),
2594 mouseEv
.ControlDown(),
2595 mouseEv
.ShiftDown(),
2597 mouseEv
.MetaDown() );
2599 return GetEventHandler()->ProcessEvent(gridEvt
);
2604 // Generate a grid event of specified type and return the result
2605 // of ProcessEvent().
2607 bool wxGrid::SendEvent( const wxEventType type
,
2610 if ( type
== EVT_GRID_ROW_SIZE
||
2611 type
== EVT_GRID_COL_SIZE
)
2613 int rowOrCol
= (row
== -1 ? col
: row
);
2615 wxGridSizeEvent
gridEvt( GetId(),
2620 return GetEventHandler()->ProcessEvent(gridEvt
);
2624 wxGridEvent
gridEvt( GetId(),
2629 return GetEventHandler()->ProcessEvent(gridEvt
);
2634 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
2636 wxPaintDC
dc( this );
2638 if ( m_currentCellCoords
== wxGridNoCellCoords
&&
2639 m_numRows
&& m_numCols
)
2641 m_currentCellCoords
.Set(0, 0);
2642 SetEditControlValue();
2643 ShowCellEditControl();
2650 // This is just here to make sure that CalcDimensions gets called when
2651 // the grid view is resized... then the size event is skipped to allow
2652 // the box sizers to handle everything
2654 void wxGrid::OnSize( wxSizeEvent
& event
)
2661 void wxGrid::OnKeyDown( wxKeyEvent
& event
)
2663 if ( m_inOnKeyDown
)
2665 // shouldn't be here - we are going round in circles...
2667 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
2670 m_inOnKeyDown
= TRUE
;
2672 // propagate the event up and see if it gets processed
2674 wxWindow
*parent
= GetParent();
2675 wxKeyEvent
keyEvt( event
);
2676 keyEvt
.SetEventObject( parent
);
2678 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
2680 // try local handlers
2682 switch ( event
.KeyCode() )
2685 if ( event
.ControlDown() )
2687 MoveCursorUpBlock();
2696 if ( event
.ControlDown() )
2698 MoveCursorDownBlock();
2707 if ( event
.ControlDown() )
2709 MoveCursorLeftBlock();
2718 if ( event
.ControlDown() )
2720 MoveCursorRightBlock();
2729 if ( !IsEditable() )
2740 if ( event
.ControlDown() )
2742 event
.Skip(); // to let the edit control have the return
2751 if ( event
.ControlDown() )
2753 MakeCellVisible( 0, 0 );
2754 SetCurrentCell( 0, 0 );
2763 if ( event
.ControlDown() )
2765 MakeCellVisible( m_numRows
-1, m_numCols
-1 );
2766 SetCurrentCell( m_numRows
-1, m_numCols
-1 );
2783 // now try the cell edit control
2785 if ( IsCellEditControlEnabled() )
2787 event
.SetEventObject( m_cellEditCtrl
);
2788 m_cellEditCtrl
->GetEventHandler()->ProcessEvent( event
);
2794 m_inOnKeyDown
= FALSE
;
2798 void wxGrid::SetCurrentCell( const wxGridCellCoords
& coords
)
2800 if ( SendEvent( EVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) )
2802 // the event has been intercepted - do nothing
2807 m_currentCellCoords
!= wxGridNoCellCoords
)
2809 HideCellEditControl();
2810 SaveEditControlValue();
2813 m_currentCellCoords
= coords
;
2815 SetEditControlValue();
2819 ShowCellEditControl();
2821 if ( IsSelection() )
2823 wxRect
r( SelectionToDeviceRect() );
2825 if ( !GetBatchCount() ) m_gridWin
->Refresh( FALSE
, &r
);
2832 // ------ functions to get/send data (see also public functions)
2835 bool wxGrid::GetModelValues()
2839 // all we need to do is repaint the grid
2841 m_gridWin
->Refresh();
2849 bool wxGrid::SetModelValues()
2855 for ( row
= 0; row
< m_numRows
; row
++ )
2857 for ( col
= 0; col
< m_numCols
; col
++ )
2859 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
2871 // Note - this function only draws cells that are in the list of
2872 // exposed cells (usually set from the update region by
2873 // CalcExposedCells)
2875 void wxGrid::DrawGridCellArea( wxDC
& dc
)
2877 if ( !m_numRows
|| !m_numCols
) return;
2880 size_t numCells
= m_cellsExposed
.GetCount();
2882 for ( i
= 0; i
< numCells
; i
++ )
2884 DrawCell( dc
, m_cellsExposed
[i
] );
2889 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords
)
2891 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2892 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2894 #if !WXGRID_DRAW_LINES
2895 if ( m_gridLinesEnabled
)
2896 DrawCellBorder( dc
, coords
);
2899 DrawCellBackground( dc
, coords
);
2901 // TODO: separate functions here for different kinds of cells ?
2904 DrawCellValue( dc
, coords
);
2908 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords
)
2910 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2911 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2913 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
2914 int row
= coords
.GetRow();
2915 int col
= coords
.GetCol();
2917 // right hand border
2919 dc
.DrawLine( m_colRights
[col
], m_rowBottoms
[row
] - m_rowHeights
[row
],
2920 m_colRights
[col
], m_rowBottoms
[row
] );
2924 dc
.DrawLine( m_colRights
[col
] - m_colWidths
[col
], m_rowBottoms
[row
],
2925 m_colRights
[col
], m_rowBottoms
[row
] );
2929 void wxGrid::DrawCellBackground( wxDC
& dc
, const wxGridCellCoords
& coords
)
2931 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2932 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2934 int row
= coords
.GetRow();
2935 int col
= coords
.GetCol();
2937 dc
.SetBackgroundMode( wxSOLID
);
2939 if ( IsInSelection( coords
) )
2941 // TODO: improve this
2943 dc
.SetBrush( *wxBLACK_BRUSH
);
2947 dc
.SetBrush( wxBrush(GetCellBackgroundColour(row
, col
), wxSOLID
) );
2950 dc
.SetPen( *wxTRANSPARENT_PEN
);
2952 dc
.DrawRectangle( m_colRights
[col
] - m_colWidths
[col
] + 1,
2953 m_rowBottoms
[row
] - m_rowHeights
[row
] + 1,
2955 m_rowHeights
[row
]-1 );
2959 void wxGrid::DrawCellValue( wxDC
& dc
, const wxGridCellCoords
& coords
)
2961 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2962 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2964 int row
= coords
.GetRow();
2965 int col
= coords
.GetCol();
2967 dc
.SetBackgroundMode( wxTRANSPARENT
);
2969 if ( IsInSelection( row
, col
) )
2971 // TODO: improve this
2973 dc
.SetTextBackground( wxColour(0, 0, 0) );
2974 dc
.SetTextForeground( wxColour(255, 255, 255) );
2978 dc
.SetTextBackground( GetCellBackgroundColour(row
, col
) );
2979 dc
.SetTextForeground( GetCellTextColour(row
, col
) );
2981 dc
.SetFont( GetCellFont(row
, col
) );
2984 GetCellAlignment( row
, col
, &hAlign
, &vAlign
);
2987 rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 );
2988 rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 );
2989 rect
.SetWidth( m_colWidths
[col
] - 4 );
2990 rect
.SetHeight( m_rowHeights
[row
] - 4 );
2992 DrawTextRectangle( dc
, GetCellValue( row
, col
), rect
, hAlign
, vAlign
);
2997 // TODO: remove this ???
2998 // This is used to redraw all grid lines e.g. when the grid line colour
3001 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion
& reg
)
3003 if ( !m_gridLinesEnabled
||
3005 !m_numCols
) return;
3007 int top
, bottom
, left
, right
;
3011 m_gridWin
->GetClientSize(&cw
, &ch
);
3013 // virtual coords of visible area
3015 CalcUnscrolledPosition( 0, 0, &left
, &top
);
3016 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
3020 reg
.GetBox(x
, y
, w
, h
);
3021 CalcUnscrolledPosition( x
, y
, &left
, &top
);
3022 CalcUnscrolledPosition( x
+ w
, y
+ h
, &right
, &bottom
);
3025 // avoid drawing grid lines past the last row and col
3027 right
= wxMin( right
, m_colRights
[m_numCols
-1] );
3028 bottom
= wxMin( bottom
, m_rowBottoms
[m_numRows
-1] );
3030 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
3032 // horizontal grid lines
3035 for ( i
= 0; i
< m_numRows
; i
++ )
3037 if ( m_rowBottoms
[i
] > bottom
)
3041 else if ( m_rowBottoms
[i
] >= top
)
3043 dc
.DrawLine( left
, m_rowBottoms
[i
], right
, m_rowBottoms
[i
] );
3048 // vertical grid lines
3050 for ( i
= 0; i
< m_numCols
; i
++ )
3052 if ( m_colRights
[i
] > right
)
3056 else if ( m_colRights
[i
] >= left
)
3058 dc
.DrawLine( m_colRights
[i
], top
, m_colRights
[i
], bottom
);
3064 void wxGrid::DrawRowLabels( wxDC
& dc
)
3066 if ( !m_numRows
|| !m_numCols
) return;
3069 size_t numLabels
= m_rowLabelsExposed
.GetCount();
3071 for ( i
= 0; i
< numLabels
; i
++ )
3073 DrawRowLabel( dc
, m_rowLabelsExposed
[i
] );
3078 void wxGrid::DrawRowLabel( wxDC
& dc
, int row
)
3080 if ( m_rowHeights
[row
] <= 0 ) return;
3082 int rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3084 dc
.SetPen( *wxBLACK_PEN
);
3085 dc
.DrawLine( m_rowLabelWidth
-1, rowTop
,
3086 m_rowLabelWidth
-1, m_rowBottoms
[row
]-1 );
3088 dc
.DrawLine( 0, m_rowBottoms
[row
]-1,
3089 m_rowLabelWidth
-1, m_rowBottoms
[row
]-1 );
3091 dc
.SetPen( *wxWHITE_PEN
);
3092 dc
.DrawLine( 0, rowTop
, 0, m_rowBottoms
[row
]-1 );
3093 dc
.DrawLine( 0, rowTop
, m_rowLabelWidth
-1, rowTop
);
3095 dc
.SetBackgroundMode( wxTRANSPARENT
);
3096 dc
.SetTextForeground( GetLabelTextColour() );
3097 dc
.SetFont( GetLabelFont() );
3100 GetRowLabelAlignment( &hAlign
, &vAlign
);
3104 rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 );
3105 rect
.SetWidth( m_rowLabelWidth
- 4 );
3106 rect
.SetHeight( m_rowHeights
[row
] - 4 );
3107 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect
, hAlign
, vAlign
);
3111 void wxGrid::DrawColLabels( wxDC
& dc
)
3113 if ( !m_numRows
|| !m_numCols
) return;
3116 size_t numLabels
= m_colLabelsExposed
.GetCount();
3118 for ( i
= 0; i
< numLabels
; i
++ )
3120 DrawColLabel( dc
, m_colLabelsExposed
[i
] );
3125 void wxGrid::DrawColLabel( wxDC
& dc
, int col
)
3127 if ( m_colWidths
[col
] <= 0 ) return;
3129 int colLeft
= m_colRights
[col
] - m_colWidths
[col
];
3131 dc
.SetPen( *wxBLACK_PEN
);
3132 dc
.DrawLine( m_colRights
[col
]-1, 0,
3133 m_colRights
[col
]-1, m_colLabelHeight
-1 );
3135 dc
.DrawLine( colLeft
, m_colLabelHeight
-1,
3136 m_colRights
[col
]-1, m_colLabelHeight
-1 );
3138 dc
.SetPen( *wxWHITE_PEN
);
3139 dc
.DrawLine( colLeft
, 0, colLeft
, m_colLabelHeight
-1 );
3140 dc
.DrawLine( colLeft
, 0, m_colRights
[col
]-1, 0 );
3142 dc
.SetBackgroundMode( wxTRANSPARENT
);
3143 dc
.SetTextForeground( GetLabelTextColour() );
3144 dc
.SetFont( GetLabelFont() );
3146 dc
.SetBackgroundMode( wxTRANSPARENT
);
3147 dc
.SetTextForeground( GetLabelTextColour() );
3148 dc
.SetFont( GetLabelFont() );
3151 GetColLabelAlignment( &hAlign
, &vAlign
);
3154 rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 );
3156 rect
.SetWidth( m_colWidths
[col
] - 4 );
3157 rect
.SetHeight( m_colLabelHeight
- 4 );
3158 DrawTextRectangle( dc
, GetColLabelValue( col
), rect
, hAlign
, vAlign
);
3162 void wxGrid::DrawTextRectangle( wxDC
& dc
,
3163 const wxString
& value
,
3168 long textWidth
, textHeight
;
3169 long lineWidth
, lineHeight
;
3170 wxArrayString lines
;
3172 dc
.SetClippingRegion( rect
);
3173 StringToLines( value
, lines
);
3174 if ( lines
.GetCount() )
3176 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
3177 dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight
);
3180 switch ( horizAlign
)
3183 x
= rect
.x
+ (rect
.width
- textWidth
- 1);
3187 x
= rect
.x
+ ((rect
.width
- textWidth
)/2);
3196 switch ( vertAlign
)
3199 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
3203 y
= rect
.y
+ ((rect
.height
- textHeight
)/2);
3212 for ( size_t i
= 0; i
< lines
.GetCount(); i
++ )
3214 dc
.DrawText( lines
[i
], (long)x
, (long)y
);
3219 dc
.DestroyClippingRegion();
3223 // Split multi line text up into an array of strings. Any existing
3224 // contents of the string array are preserved.
3226 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines
)
3228 // TODO: this won't work for WXMAC ? (lines end with '\r')
3229 // => use wxTextFile functions then (VZ)
3232 while ( startPos
< (int)value
.Length() )
3234 pos
= value
.Mid(startPos
).Find( '\n' );
3239 else if ( pos
== 0 )
3241 lines
.Add( wxEmptyString
);
3245 if ( value
[startPos
+pos
-1] == '\r' )
3247 lines
.Add( value
.Mid(startPos
, pos
-1) );
3251 lines
.Add( value
.Mid(startPos
, pos
) );
3256 if ( startPos
< (int)value
.Length() )
3258 lines
.Add( value
.Mid( startPos
) );
3263 void wxGrid::GetTextBoxSize( wxDC
& dc
,
3264 wxArrayString
& lines
,
3265 long *width
, long *height
)
3272 for ( i
= 0; i
< lines
.GetCount(); i
++ )
3274 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
3275 w
= wxMax( w
, lineW
);
3285 // ------ Edit control functions
3289 void wxGrid::EnableEditing( bool edit
)
3291 // TODO: improve this ?
3293 if ( edit
!= m_editable
)
3297 // TODO: extend this for other edit control types
3299 if ( m_editCtrlType
== wxGRID_TEXTCTRL
)
3301 ((wxTextCtrl
*)m_cellEditCtrl
)->SetEditable( m_editable
);
3307 #if 0 // disabled for the moment - the cell control is always active
3308 void wxGrid::EnableCellEditControl( bool enable
)
3310 if ( m_cellEditCtrl
&&
3311 enable
!= m_cellEditCtrlEnabled
)
3313 m_cellEditCtrlEnabled
= enable
;
3315 if ( m_cellEditCtrlEnabled
)
3317 SetEditControlValue();
3318 ShowCellEditControl();
3322 HideCellEditControl();
3323 SaveEditControlValue();
3330 void wxGrid::ShowCellEditControl()
3334 if ( IsCellEditControlEnabled() )
3336 if ( !IsVisible( m_currentCellCoords
) )
3342 rect
= CellToRect( m_currentCellCoords
);
3344 // convert to scrolled coords
3346 int left
, top
, right
, bottom
;
3347 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
3348 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
3351 m_gridWin
->GetClientSize( &cw
, &ch
);
3353 // Make the edit control large enough to allow for internal margins
3354 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3357 #if defined(__WXMOTIF__)
3358 if ( m_currentCellCoords
.GetRow() == 0 ||
3359 m_currentCellCoords
.GetCol() == 0 )
3368 if ( m_currentCellCoords
.GetRow() == 0 ||
3369 m_currentCellCoords
.GetCol() == 0 )
3379 #if defined(__WXGTK__)
3382 if (left
!= 0) left_diff
++;
3383 if (top
!= 0) top_diff
++;
3384 rect
.SetLeft( left
+ left_diff
);
3385 rect
.SetTop( top
+ top_diff
);
3386 rect
.SetRight( rect
.GetRight() - left_diff
);
3387 rect
.SetBottom( rect
.GetBottom() - top_diff
);
3389 rect
.SetLeft( wxMax(0, left
- extra
) );
3390 rect
.SetTop( wxMax(0, top
- extra
) );
3391 rect
.SetRight( rect
.GetRight() + 2*extra
);
3392 rect
.SetBottom( rect
.GetBottom() + 2*extra
);
3395 m_cellEditCtrl
->SetSize( rect
);
3396 m_cellEditCtrl
->Show( TRUE
);
3398 switch ( m_editCtrlType
)
3400 case wxGRID_TEXTCTRL
:
3401 ((wxTextCtrl
*) m_cellEditCtrl
)->SetInsertionPointEnd();
3404 case wxGRID_CHECKBOX
:
3405 // TODO: anything ???
3410 // TODO: anything ???
3414 case wxGRID_COMBOBOX
:
3415 // TODO: anything ???
3420 m_cellEditCtrl
->SetFocus();
3426 void wxGrid::HideCellEditControl()
3428 if ( IsCellEditControlEnabled() )
3430 m_cellEditCtrl
->Show( FALSE
);
3435 void wxGrid::SetEditControlValue( const wxString
& value
)
3441 s
= GetCellValue(m_currentCellCoords
);
3445 if ( IsCellEditControlEnabled() )
3447 switch ( m_editCtrlType
)
3449 case wxGRID_TEXTCTRL
:
3450 ((wxGridTextCtrl
*)m_cellEditCtrl
)->SetStartValue(s
);
3453 case wxGRID_CHECKBOX
:
3454 // TODO: implement this
3459 // TODO: implement this
3463 case wxGRID_COMBOBOX
:
3464 // TODO: implement this
3473 void wxGrid::SaveEditControlValue()
3477 wxWindow
*ctrl
= (wxWindow
*)NULL
;
3479 if ( IsCellEditControlEnabled() )
3481 ctrl
= m_cellEditCtrl
;
3488 bool valueChanged
= FALSE
;
3490 switch ( m_editCtrlType
)
3492 case wxGRID_TEXTCTRL
:
3493 valueChanged
= (((wxGridTextCtrl
*)ctrl
)->GetValue() !=
3494 ((wxGridTextCtrl
*)ctrl
)->GetStartValue());
3495 SetCellValue( m_currentCellCoords
,
3496 ((wxTextCtrl
*) ctrl
)->GetValue() );
3499 case wxGRID_CHECKBOX
:
3500 // TODO: implement this
3505 // TODO: implement this
3509 case wxGRID_COMBOBOX
:
3510 // TODO: implement this
3517 SendEvent( EVT_GRID_CELL_CHANGE
,
3518 m_currentCellCoords
.GetRow(),
3519 m_currentCellCoords
.GetCol() );
3526 // ------ Grid location functions
3527 // Note that all of these functions work with the logical coordinates of
3528 // grid cells and labels so you will need to convert from device
3529 // coordinates for mouse events etc.
3532 void wxGrid::XYToCell( int x
, int y
, wxGridCellCoords
& coords
)
3534 int row
= YToRow(y
);
3535 int col
= XToCol(x
);
3537 if ( row
== -1 || col
== -1 )
3539 coords
= wxGridNoCellCoords
;
3543 coords
.Set( row
, col
);
3548 int wxGrid::YToRow( int y
)
3552 for ( i
= 0; i
< m_numRows
; i
++ )
3554 if ( y
< m_rowBottoms
[i
] ) return i
;
3561 int wxGrid::XToCol( int x
)
3565 for ( i
= 0; i
< m_numCols
; i
++ )
3567 if ( x
< m_colRights
[i
] ) return i
;
3574 // return the row number that that the y coord is near the edge of, or
3575 // -1 if not near an edge
3577 int wxGrid::YToEdgeOfRow( int y
)
3581 for ( i
= 0; i
< m_numRows
; i
++ )
3583 if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3585 d
= abs( y
- m_rowBottoms
[i
] );
3587 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3596 // return the col number that that the x coord is near the edge of, or
3597 // -1 if not near an edge
3599 int wxGrid::XToEdgeOfCol( int x
)
3603 for ( i
= 0; i
< m_numCols
; i
++ )
3605 if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3607 d
= abs( x
- m_colRights
[i
] );
3609 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3618 wxRect
wxGrid::CellToRect( int row
, int col
)
3620 wxRect
rect( -1, -1, -1, -1 );
3622 if ( row
>= 0 && row
< m_numRows
&&
3623 col
>= 0 && col
< m_numCols
)
3625 rect
.x
= m_colRights
[col
] - m_colWidths
[col
];
3626 rect
.y
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3627 rect
.width
= m_colWidths
[col
];
3628 rect
.height
= m_rowHeights
[ row
];
3635 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible
)
3637 // get the cell rectangle in logical coords
3639 wxRect
r( CellToRect( row
, col
) );
3641 // convert to device coords
3643 int left
, top
, right
, bottom
;
3644 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3645 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3647 // check against the client area of the grid window
3650 m_gridWin
->GetClientSize( &cw
, &ch
);
3652 if ( wholeCellVisible
)
3654 // is the cell wholly visible ?
3656 return ( left
>= 0 && right
<= cw
&&
3657 top
>= 0 && bottom
<= ch
);
3661 // is the cell partly visible ?
3663 return ( ((left
>=0 && left
< cw
) || (right
> 0 && right
<= cw
)) &&
3664 ((top
>=0 && top
< ch
) || (bottom
> 0 && bottom
<= ch
)) );
3669 // make the specified cell location visible by doing a minimal amount
3672 void wxGrid::MakeCellVisible( int row
, int col
)
3675 int xpos
= -1, ypos
= -1;
3677 if ( row
>= 0 && row
< m_numRows
&&
3678 col
>= 0 && col
< m_numCols
)
3680 // get the cell rectangle in logical coords
3682 wxRect
r( CellToRect( row
, col
) );
3684 // convert to device coords
3686 int left
, top
, right
, bottom
;
3687 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3688 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3691 m_gridWin
->GetClientSize( &cw
, &ch
);
3697 else if ( bottom
> ch
)
3699 int h
= r
.GetHeight();
3701 for ( i
= row
-1; i
>= 0; i
-- )
3703 if ( h
+ m_rowHeights
[i
] > ch
) break;
3705 h
+= m_rowHeights
[i
];
3706 ypos
-= m_rowHeights
[i
];
3709 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3710 // have rounding errors (this is important, because if we do, we
3711 // might not scroll at all and some cells won't be redrawn)
3712 ypos
+= GRID_SCROLL_LINE
/ 2;
3719 else if ( right
> cw
)
3721 int w
= r
.GetWidth();
3723 for ( i
= col
-1; i
>= 0; i
-- )
3725 if ( w
+ m_colWidths
[i
] > cw
) break;
3727 w
+= m_colWidths
[i
];
3728 xpos
-= m_colWidths
[i
];
3731 // see comment for ypos above
3732 xpos
+= GRID_SCROLL_LINE
/ 2;
3735 if ( xpos
!= -1 || ypos
!= -1 )
3737 if ( xpos
!= -1 ) xpos
/= GRID_SCROLL_LINE
;
3738 if ( ypos
!= -1 ) ypos
/= GRID_SCROLL_LINE
;
3739 Scroll( xpos
, ypos
);
3747 // ------ Grid cursor movement functions
3750 bool wxGrid::MoveCursorUp()
3752 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3753 m_currentCellCoords
.GetRow() > 0 )
3755 MakeCellVisible( m_currentCellCoords
.GetRow() - 1,
3756 m_currentCellCoords
.GetCol() );
3758 SetCurrentCell( m_currentCellCoords
.GetRow() - 1,
3759 m_currentCellCoords
.GetCol() );
3768 bool wxGrid::MoveCursorDown()
3770 // TODO: allow for scrolling
3772 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3773 m_currentCellCoords
.GetRow() < m_numRows
-1 )
3775 MakeCellVisible( m_currentCellCoords
.GetRow() + 1,
3776 m_currentCellCoords
.GetCol() );
3778 SetCurrentCell( m_currentCellCoords
.GetRow() + 1,
3779 m_currentCellCoords
.GetCol() );
3788 bool wxGrid::MoveCursorLeft()
3790 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3791 m_currentCellCoords
.GetCol() > 0 )
3793 MakeCellVisible( m_currentCellCoords
.GetRow(),
3794 m_currentCellCoords
.GetCol() - 1 );
3796 SetCurrentCell( m_currentCellCoords
.GetRow(),
3797 m_currentCellCoords
.GetCol() - 1 );
3806 bool wxGrid::MoveCursorRight()
3808 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3809 m_currentCellCoords
.GetCol() < m_numCols
- 1 )
3811 MakeCellVisible( m_currentCellCoords
.GetRow(),
3812 m_currentCellCoords
.GetCol() + 1 );
3814 SetCurrentCell( m_currentCellCoords
.GetRow(),
3815 m_currentCellCoords
.GetCol() + 1 );
3824 bool wxGrid::MovePageUp()
3826 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
3828 int row
= m_currentCellCoords
.GetRow();
3832 m_gridWin
->GetClientSize( &cw
, &ch
);
3834 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
3835 int newRow
= YToRow( y
- ch
+ 1 );
3840 else if ( newRow
== row
)
3845 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
3846 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
3854 bool wxGrid::MovePageDown()
3856 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
3858 int row
= m_currentCellCoords
.GetRow();
3859 if ( row
< m_numRows
)
3862 m_gridWin
->GetClientSize( &cw
, &ch
);
3864 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
3865 int newRow
= YToRow( y
+ ch
);
3868 newRow
= m_numRows
- 1;
3870 else if ( newRow
== row
)
3875 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
3876 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
3884 bool wxGrid::MoveCursorUpBlock()
3887 m_currentCellCoords
!= wxGridNoCellCoords
&&
3888 m_currentCellCoords
.GetRow() > 0 )
3890 int row
= m_currentCellCoords
.GetRow();
3891 int col
= m_currentCellCoords
.GetCol();
3893 if ( m_table
->IsEmptyCell(row
, col
) )
3895 // starting in an empty cell: find the next block of
3901 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3904 else if ( m_table
->IsEmptyCell(row
-1, col
) )
3906 // starting at the top of a block: find the next block
3912 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3917 // starting within a block: find the top of the block
3922 if ( m_table
->IsEmptyCell(row
, col
) )
3930 MakeCellVisible( row
, col
);
3931 SetCurrentCell( row
, col
);
3939 bool wxGrid::MoveCursorDownBlock()
3942 m_currentCellCoords
!= wxGridNoCellCoords
&&
3943 m_currentCellCoords
.GetRow() < m_numRows
-1 )
3945 int row
= m_currentCellCoords
.GetRow();
3946 int col
= m_currentCellCoords
.GetCol();
3948 if ( m_table
->IsEmptyCell(row
, col
) )
3950 // starting in an empty cell: find the next block of
3953 while ( row
< m_numRows
-1 )
3956 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3959 else if ( m_table
->IsEmptyCell(row
+1, col
) )
3961 // starting at the bottom of a block: find the next block
3964 while ( row
< m_numRows
-1 )
3967 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3972 // starting within a block: find the bottom of the block
3974 while ( row
< m_numRows
-1 )
3977 if ( m_table
->IsEmptyCell(row
, col
) )
3985 MakeCellVisible( row
, col
);
3986 SetCurrentCell( row
, col
);
3994 bool wxGrid::MoveCursorLeftBlock()
3997 m_currentCellCoords
!= wxGridNoCellCoords
&&
3998 m_currentCellCoords
.GetCol() > 0 )
4000 int row
= m_currentCellCoords
.GetRow();
4001 int col
= m_currentCellCoords
.GetCol();
4003 if ( m_table
->IsEmptyCell(row
, col
) )
4005 // starting in an empty cell: find the next block of
4011 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4014 else if ( m_table
->IsEmptyCell(row
, col
-1) )
4016 // starting at the left of a block: find the next block
4022 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4027 // starting within a block: find the left of the block
4032 if ( m_table
->IsEmptyCell(row
, col
) )
4040 MakeCellVisible( row
, col
);
4041 SetCurrentCell( row
, col
);
4049 bool wxGrid::MoveCursorRightBlock()
4052 m_currentCellCoords
!= wxGridNoCellCoords
&&
4053 m_currentCellCoords
.GetCol() < m_numCols
-1 )
4055 int row
= m_currentCellCoords
.GetRow();
4056 int col
= m_currentCellCoords
.GetCol();
4058 if ( m_table
->IsEmptyCell(row
, col
) )
4060 // starting in an empty cell: find the next block of
4063 while ( col
< m_numCols
-1 )
4066 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4069 else if ( m_table
->IsEmptyCell(row
, col
+1) )
4071 // starting at the right of a block: find the next block
4074 while ( col
< m_numCols
-1 )
4077 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4082 // starting within a block: find the right of the block
4084 while ( col
< m_numCols
-1 )
4087 if ( m_table
->IsEmptyCell(row
, col
) )
4095 MakeCellVisible( row
, col
);
4096 SetCurrentCell( row
, col
);
4107 // ------ Label values and formatting
4110 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert
)
4112 *horiz
= m_rowLabelHorizAlign
;
4113 *vert
= m_rowLabelVertAlign
;
4116 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert
)
4118 *horiz
= m_colLabelHorizAlign
;
4119 *vert
= m_colLabelVertAlign
;
4122 wxString
wxGrid::GetRowLabelValue( int row
)
4126 return m_table
->GetRowLabelValue( row
);
4136 wxString
wxGrid::GetColLabelValue( int col
)
4140 return m_table
->GetColLabelValue( col
);
4151 void wxGrid::SetRowLabelSize( int width
)
4153 width
= wxMax( width
, 0 );
4154 if ( width
!= m_rowLabelWidth
)
4158 m_rowLabelWin
->Show( FALSE
);
4159 m_cornerLabelWin
->Show( FALSE
);
4161 else if ( m_rowLabelWidth
== 0 )
4163 m_rowLabelWin
->Show( TRUE
);
4164 if ( m_colLabelHeight
> 0 ) m_cornerLabelWin
->Show( TRUE
);
4167 m_rowLabelWidth
= width
;
4174 void wxGrid::SetColLabelSize( int height
)
4176 height
= wxMax( height
, 0 );
4177 if ( height
!= m_colLabelHeight
)
4181 m_colLabelWin
->Show( FALSE
);
4182 m_cornerLabelWin
->Show( FALSE
);
4184 else if ( m_colLabelHeight
== 0 )
4186 m_colLabelWin
->Show( TRUE
);
4187 if ( m_rowLabelWidth
> 0 ) m_cornerLabelWin
->Show( TRUE
);
4190 m_colLabelHeight
= height
;
4197 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour
)
4199 if ( m_labelBackgroundColour
!= colour
)
4201 m_labelBackgroundColour
= colour
;
4202 m_rowLabelWin
->SetBackgroundColour( colour
);
4203 m_colLabelWin
->SetBackgroundColour( colour
);
4204 m_cornerLabelWin
->SetBackgroundColour( colour
);
4206 if ( !GetBatchCount() )
4208 m_rowLabelWin
->Refresh();
4209 m_colLabelWin
->Refresh();
4210 m_cornerLabelWin
->Refresh();
4215 void wxGrid::SetLabelTextColour( const wxColour
& colour
)
4217 if ( m_labelTextColour
!= colour
)
4219 m_labelTextColour
= colour
;
4220 if ( !GetBatchCount() )
4222 m_rowLabelWin
->Refresh();
4223 m_colLabelWin
->Refresh();
4228 void wxGrid::SetLabelFont( const wxFont
& font
)
4231 if ( !GetBatchCount() )
4233 m_rowLabelWin
->Refresh();
4234 m_colLabelWin
->Refresh();
4238 void wxGrid::SetRowLabelAlignment( int horiz
, int vert
)
4240 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
4242 m_rowLabelHorizAlign
= horiz
;
4245 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
4247 m_rowLabelVertAlign
= vert
;
4250 if ( !GetBatchCount() )
4252 m_rowLabelWin
->Refresh();
4256 void wxGrid::SetColLabelAlignment( int horiz
, int vert
)
4258 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
4260 m_colLabelHorizAlign
= horiz
;
4263 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
4265 m_colLabelVertAlign
= vert
;
4268 if ( !GetBatchCount() )
4270 m_colLabelWin
->Refresh();
4274 void wxGrid::SetRowLabelValue( int row
, const wxString
& s
)
4278 m_table
->SetRowLabelValue( row
, s
);
4279 if ( !GetBatchCount() )
4281 wxRect rect
= CellToRect( row
, 0);
4282 if ( rect
.height
> 0 )
4284 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
);
4286 rect
.width
= m_rowLabelWidth
;
4287 m_rowLabelWin
->Refresh( TRUE
, &rect
);
4293 void wxGrid::SetColLabelValue( int col
, const wxString
& s
)
4297 m_table
->SetColLabelValue( col
, s
);
4298 if ( !GetBatchCount() )
4300 wxRect rect
= CellToRect( 0, col
);
4301 if ( rect
.width
> 0 )
4303 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
);
4305 rect
.height
= m_colLabelHeight
;
4306 m_colLabelWin
->Refresh( TRUE
, &rect
);
4312 void wxGrid::SetGridLineColour( const wxColour
& colour
)
4314 if ( m_gridLineColour
!= colour
)
4316 m_gridLineColour
= colour
;
4318 wxClientDC
dc( m_gridWin
);
4320 DrawAllGridLines( dc
, wxRegion() );
4324 void wxGrid::EnableGridLines( bool enable
)
4326 if ( enable
!= m_gridLinesEnabled
)
4328 m_gridLinesEnabled
= enable
;
4330 if ( !GetBatchCount() )
4334 wxClientDC
dc( m_gridWin
);
4336 DrawAllGridLines( dc
, wxRegion() );
4340 m_gridWin
->Refresh();
4347 int wxGrid::GetDefaultRowSize()
4349 return m_defaultRowHeight
;
4352 int wxGrid::GetRowSize( int row
)
4354 wxCHECK_MSG( row
>= 0 && row
< m_numRows
, 0, _T("invalid row index") );
4356 return m_rowHeights
[row
];
4359 int wxGrid::GetDefaultColSize()
4361 return m_defaultColWidth
;
4364 int wxGrid::GetColSize( int col
)
4366 wxCHECK_MSG( col
>= 0 && col
< m_numCols
, 0, _T("invalid column index") );
4368 return m_colWidths
[col
];
4371 wxColour
wxGrid::GetDefaultCellBackgroundColour()
4373 return GetBackgroundColour();
4376 // TODO VZ: this must be optimized to allow only retrieveing attr once!
4378 wxColour
wxGrid::GetCellBackgroundColour(int row
, int col
)
4380 wxGridCellAttr
*attr
= m_table
? m_table
->GetAttr(row
, col
) : NULL
;
4383 if ( attr
&& attr
->HasBackgroundColour() )
4384 colour
= attr
->GetBackgroundColour();
4386 colour
= GetDefaultCellBackgroundColour();
4393 wxColour
wxGrid::GetDefaultCellTextColour()
4395 return GetForegroundColour();
4398 wxColour
wxGrid::GetCellTextColour( int row
, int col
)
4400 wxGridCellAttr
*attr
= m_table
? m_table
->GetAttr(row
, col
) : NULL
;
4403 if ( attr
&& attr
->HasTextColour() )
4404 colour
= attr
->GetTextColour();
4406 colour
= GetDefaultCellTextColour();
4414 wxFont
wxGrid::GetDefaultCellFont()
4416 return m_defaultCellFont
;
4419 wxFont
wxGrid::GetCellFont( int row
, int col
)
4421 wxGridCellAttr
*attr
= m_table
? m_table
->GetAttr(row
, col
) : NULL
;
4424 if ( attr
&& attr
->HasFont() )
4425 font
= attr
->GetFont();
4427 font
= GetDefaultCellFont();
4434 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert
)
4437 *horiz
= m_defaultCellHAlign
;
4439 *vert
= m_defaultCellVAlign
;
4442 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert
)
4444 wxGridCellAttr
*attr
= m_table
? m_table
->GetAttr(row
, col
) : NULL
;
4446 if ( attr
&& attr
->HasAlignment() )
4447 attr
->GetAlignment(horiz
, vert
);
4449 GetDefaultCellAlignment(horiz
, vert
);
4454 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows
)
4456 m_defaultRowHeight
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT
);
4458 if ( resizeExistingRows
)
4462 for ( row
= 0; row
< m_numRows
; row
++ )
4464 m_rowHeights
[row
] = m_defaultRowHeight
;
4465 bottom
+= m_defaultRowHeight
;
4466 m_rowBottoms
[row
] = bottom
;
4472 void wxGrid::SetRowSize( int row
, int height
)
4474 wxCHECK_RET( row
>= 0 && row
< m_numRows
, _T("invalid row index") );
4478 int h
= wxMax( 0, height
);
4479 int diff
= h
- m_rowHeights
[row
];
4481 m_rowHeights
[row
] = h
;
4482 for ( i
= row
; i
< m_numRows
; i
++ )
4484 m_rowBottoms
[i
] += diff
;
4488 // Note: we are ending the event *after* doing
4489 // default processing in this case
4491 SendEvent( EVT_GRID_ROW_SIZE
,
4495 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols
)
4497 m_defaultColWidth
= wxMax( width
, WXGRID_MIN_COL_WIDTH
);
4499 if ( resizeExistingCols
)
4503 for ( col
= 0; col
< m_numCols
; col
++ )
4505 m_colWidths
[col
] = m_defaultColWidth
;
4506 right
+= m_defaultColWidth
;
4507 m_colRights
[col
] = right
;
4513 void wxGrid::SetColSize( int col
, int width
)
4515 wxCHECK_RET( col
>= 0 && col
< m_numCols
, _T("invalid column index") );
4519 int w
= wxMax( 0, width
);
4520 int diff
= w
- m_colWidths
[col
];
4521 m_colWidths
[col
] = w
;
4523 for ( i
= col
; i
< m_numCols
; i
++ )
4525 m_colRights
[i
] += diff
;
4529 // Note: we are ending the event *after* doing
4530 // default processing in this case
4532 SendEvent( EVT_GRID_COL_SIZE
,
4536 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& col
)
4538 SetBackgroundColour(col
);
4541 void wxGrid::SetDefaultCellTextColour( const wxColour
& col
)
4543 SetForegroundColour(col
);
4546 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert
)
4548 m_defaultCellHAlign
= horiz
;
4549 m_defaultCellVAlign
= vert
;
4552 bool wxGrid::CanHaveAttributes()
4559 if ( !m_table
->GetAttrProvider() )
4561 // use the default attr provider by default
4562 // (another choice would be to just return FALSE thus forcing the user
4564 m_table
->SetAttrProvider(new wxGridCellAttrProvider
);
4570 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour
)
4572 if ( CanHaveAttributes() )
4574 wxGridCellAttr
*attr
= new wxGridCellAttr
;
4575 attr
->SetBackgroundColour(colour
);
4577 m_table
->SetAttr(attr
, row
, col
);
4581 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& colour
)
4583 if ( CanHaveAttributes() )
4585 wxGridCellAttr
*attr
= new wxGridCellAttr
;
4586 attr
->SetTextColour(colour
);
4588 m_table
->SetAttr(attr
, row
, col
);
4592 void wxGrid::SetDefaultCellFont( const wxFont
& font
)
4594 m_defaultCellFont
= font
;
4597 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& font
)
4599 if ( CanHaveAttributes() )
4601 wxGridCellAttr
*attr
= new wxGridCellAttr
;
4602 attr
->SetFont(font
);
4604 m_table
->SetAttr(attr
, row
, col
);
4608 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert
)
4610 if ( CanHaveAttributes() )
4612 wxGridCellAttr
*attr
= new wxGridCellAttr
;
4613 attr
->SetAlignment(horiz
, vert
);
4615 m_table
->SetAttr(attr
, row
, col
);
4622 // ------ cell value accessor functions
4625 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s
)
4629 m_table
->SetValue( row
, col
, s
.c_str() );
4630 if ( !GetBatchCount() )
4632 wxClientDC
dc( m_gridWin
);
4634 DrawCell( dc
, wxGridCellCoords(row
, col
) );
4637 #if 0 // TODO: edit in place
4639 if ( m_currentCellCoords
.GetRow() == row
&&
4640 m_currentCellCoords
.GetCol() == col
)
4642 SetEditControlValue( s
);
4651 // ------ Block, row and col selection
4654 void wxGrid::SelectRow( int row
, bool addToSelected
)
4658 if ( IsSelection() && addToSelected
)
4661 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
4664 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
4665 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
4666 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
4667 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
4671 need_refresh
[0] = TRUE
;
4672 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( row
, 0 ),
4673 wxGridCellCoords ( oldTop
- 1,
4675 m_selectedTopLeft
.SetRow( row
);
4680 need_refresh
[1] = TRUE
;
4681 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 0 ),
4682 wxGridCellCoords ( oldBottom
,
4685 m_selectedTopLeft
.SetCol( 0 );
4688 if ( oldBottom
< row
)
4690 need_refresh
[2] = TRUE
;
4691 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1, 0 ),
4692 wxGridCellCoords ( row
,
4694 m_selectedBottomRight
.SetRow( row
);
4697 if ( oldRight
< m_numCols
- 1 )
4699 need_refresh
[3] = TRUE
;
4700 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
4702 wxGridCellCoords ( oldBottom
,
4704 m_selectedBottomRight
.SetCol( m_numCols
- 1 );
4707 for (i
= 0; i
< 4; i
++ )
4708 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
4709 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
4713 r
= SelectionToDeviceRect();
4715 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
4717 m_selectedTopLeft
.Set( row
, 0 );
4718 m_selectedBottomRight
.Set( row
, m_numCols
-1 );
4719 r
= SelectionToDeviceRect();
4720 m_gridWin
->Refresh( FALSE
, &r
);
4723 wxGridRangeSelectEvent
gridEvt( GetId(),
4724 EVT_GRID_RANGE_SELECT
,
4727 m_selectedBottomRight
);
4729 GetEventHandler()->ProcessEvent(gridEvt
);
4733 void wxGrid::SelectCol( int col
, bool addToSelected
)
4735 if ( IsSelection() && addToSelected
)
4738 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
4741 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
4742 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
4743 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
4744 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
4746 if ( oldLeft
> col
)
4748 need_refresh
[0] = TRUE
;
4749 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col
),
4750 wxGridCellCoords ( m_numRows
- 1,
4752 m_selectedTopLeft
.SetCol( col
);
4757 need_refresh
[1] = TRUE
;
4758 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft
),
4759 wxGridCellCoords ( oldTop
- 1,
4761 m_selectedTopLeft
.SetRow( 0 );
4764 if ( oldRight
< col
)
4766 need_refresh
[2] = TRUE
;
4767 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight
+ 1 ),
4768 wxGridCellCoords ( m_numRows
- 1,
4770 m_selectedBottomRight
.SetCol( col
);
4773 if ( oldBottom
< m_numRows
- 1 )
4775 need_refresh
[3] = TRUE
;
4776 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1,
4778 wxGridCellCoords ( m_numRows
- 1,
4780 m_selectedBottomRight
.SetRow( m_numRows
- 1 );
4783 for (i
= 0; i
< 4; i
++ )
4784 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
4785 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
4791 r
= SelectionToDeviceRect();
4793 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
4795 m_selectedTopLeft
.Set( 0, col
);
4796 m_selectedBottomRight
.Set( m_numRows
-1, col
);
4797 r
= SelectionToDeviceRect();
4798 m_gridWin
->Refresh( FALSE
, &r
);
4801 wxGridRangeSelectEvent
gridEvt( GetId(),
4802 EVT_GRID_RANGE_SELECT
,
4805 m_selectedBottomRight
);
4807 GetEventHandler()->ProcessEvent(gridEvt
);
4811 void wxGrid::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol
)
4814 wxGridCellCoords updateTopLeft
, updateBottomRight
;
4816 if ( topRow
> bottomRow
)
4823 if ( leftCol
> rightCol
)
4830 updateTopLeft
= wxGridCellCoords( topRow
, leftCol
);
4831 updateBottomRight
= wxGridCellCoords( bottomRow
, rightCol
);
4833 if ( m_selectedTopLeft
!= updateTopLeft
||
4834 m_selectedBottomRight
!= updateBottomRight
)
4836 // Compute two optimal update rectangles:
4837 // Either one rectangle is a real subset of the
4838 // other, or they are (almost) disjoint!
4840 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
4843 // Store intermediate values
4844 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
4845 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
4846 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
4847 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
4849 // Determine the outer/inner coordinates.
4850 if (oldLeft
> leftCol
)
4856 if (oldTop
> topRow
)
4862 if (oldRight
< rightCol
)
4865 oldRight
= rightCol
;
4868 if (oldBottom
< bottomRow
)
4871 oldBottom
= bottomRow
;
4875 // Now, either the stuff marked old is the outer
4876 // rectangle or we don't have a situation where one
4877 // is contained in the other.
4879 if ( oldLeft
< leftCol
)
4881 need_refresh
[0] = TRUE
;
4882 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
4884 wxGridCellCoords ( oldBottom
,
4888 if ( oldTop
< topRow
)
4890 need_refresh
[1] = TRUE
;
4891 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
4893 wxGridCellCoords ( topRow
- 1,
4897 if ( oldRight
> rightCol
)
4899 need_refresh
[2] = TRUE
;
4900 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
4902 wxGridCellCoords ( oldBottom
,
4906 if ( oldBottom
> bottomRow
)
4908 need_refresh
[3] = TRUE
;
4909 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow
+ 1,
4911 wxGridCellCoords ( oldBottom
,
4917 m_selectedTopLeft
= updateTopLeft
;
4918 m_selectedBottomRight
= updateBottomRight
;
4920 // various Refresh() calls
4921 for (i
= 0; i
< 4; i
++ )
4922 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
4923 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
4926 // only generate an event if the block is not being selected by
4927 // dragging the mouse (in which case the event will be generated in
4928 // the mouse event handler)
4929 if ( !m_isDragging
)
4931 wxGridRangeSelectEvent
gridEvt( GetId(),
4932 EVT_GRID_RANGE_SELECT
,
4935 m_selectedBottomRight
);
4937 GetEventHandler()->ProcessEvent(gridEvt
);
4941 void wxGrid::SelectAll()
4943 m_selectedTopLeft
.Set( 0, 0 );
4944 m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 );
4946 m_gridWin
->Refresh();
4950 void wxGrid::ClearSelection()
4952 m_selectedTopLeft
= wxGridNoCellCoords
;
4953 m_selectedBottomRight
= wxGridNoCellCoords
;
4957 // This function returns the rectangle that encloses the given block
4958 // in device coords clipped to the client size of the grid window.
4960 wxRect
wxGrid::BlockToDeviceRect( const wxGridCellCoords
&topLeft
,
4961 const wxGridCellCoords
&bottomRight
)
4963 wxRect
rect( wxGridNoCellRect
);
4966 cellRect
= CellToRect( topLeft
);
4967 if ( cellRect
!= wxGridNoCellRect
)
4973 rect
= wxRect( 0, 0, 0, 0 );
4976 cellRect
= CellToRect( bottomRight
);
4977 if ( cellRect
!= wxGridNoCellRect
)
4983 return wxGridNoCellRect
;
4986 // convert to scrolled coords
4988 int left
, top
, right
, bottom
;
4989 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
4990 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
4993 m_gridWin
->GetClientSize( &cw
, &ch
);
4995 rect
.SetLeft( wxMax(0, left
) );
4996 rect
.SetTop( wxMax(0, top
) );
4997 rect
.SetRight( wxMin(cw
, right
) );
4998 rect
.SetBottom( wxMin(ch
, bottom
) );
5006 // ------ Grid event classes
5009 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent
)
5011 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
5012 int row
, int col
, int x
, int y
,
5013 bool control
, bool shift
, bool alt
, bool meta
)
5014 : wxNotifyEvent( type
, id
)
5020 m_control
= control
;
5025 SetEventObject(obj
);
5029 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent
)
5031 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
5032 int rowOrCol
, int x
, int y
,
5033 bool control
, bool shift
, bool alt
, bool meta
)
5034 : wxNotifyEvent( type
, id
)
5036 m_rowOrCol
= rowOrCol
;
5039 m_control
= control
;
5044 SetEventObject(obj
);
5048 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent
)
5050 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
5051 const wxGridCellCoords
& topLeft
,
5052 const wxGridCellCoords
& bottomRight
,
5053 bool control
, bool shift
, bool alt
, bool meta
)
5054 : wxNotifyEvent( type
, id
)
5056 m_topLeft
= topLeft
;
5057 m_bottomRight
= bottomRight
;
5058 m_control
= control
;
5063 SetEventObject(obj
);
5067 #endif // ifndef wxUSE_NEW_GRID