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"
36 // this include needs to be outside precomp for BCC
37 #include "wx/textfile.h"
39 #include "wx/generic/grid.h"
41 // ----------------------------------------------------------------------------
42 // array classes instantiation
43 // ----------------------------------------------------------------------------
45 struct wxGridCellWithAttr
47 wxGridCellWithAttr(int row
, int col
, wxGridCellAttr
*attr_
)
48 : coords(row
, col
), attr(attr_
)
57 wxGridCellCoords coords
;
61 WX_DECLARE_OBJARRAY(wxGridCellWithAttr
, wxGridCellWithAttrArray
);
63 #include "wx/arrimpl.cpp"
65 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
)
66 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
)
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 class WXDLLEXPORT wxGridRowLabelWindow
: public wxWindow
75 wxGridRowLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
76 wxGridRowLabelWindow( wxGrid
*parent
, wxWindowID id
,
77 const wxPoint
&pos
, const wxSize
&size
);
82 void OnPaint( wxPaintEvent
& event
);
83 void OnMouseEvent( wxMouseEvent
& event
);
84 void OnKeyDown( wxKeyEvent
& event
);
86 DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow
)
91 class WXDLLEXPORT wxGridColLabelWindow
: public wxWindow
94 wxGridColLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
95 wxGridColLabelWindow( wxGrid
*parent
, wxWindowID id
,
96 const wxPoint
&pos
, const wxSize
&size
);
101 void OnPaint( wxPaintEvent
&event
);
102 void OnMouseEvent( wxMouseEvent
& event
);
103 void OnKeyDown( wxKeyEvent
& event
);
105 DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow
)
106 DECLARE_EVENT_TABLE()
110 class WXDLLEXPORT wxGridCornerLabelWindow
: public wxWindow
113 wxGridCornerLabelWindow() { m_owner
= (wxGrid
*)NULL
; }
114 wxGridCornerLabelWindow( wxGrid
*parent
, wxWindowID id
,
115 const wxPoint
&pos
, const wxSize
&size
);
120 void OnMouseEvent( wxMouseEvent
& event
);
121 void OnKeyDown( wxKeyEvent
& event
);
122 void OnPaint( wxPaintEvent
& event
);
124 DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow
)
125 DECLARE_EVENT_TABLE()
128 class WXDLLEXPORT wxGridWindow
: public wxPanel
133 m_owner
= (wxGrid
*)NULL
;
134 m_rowLabelWin
= (wxGridRowLabelWindow
*)NULL
;
135 m_colLabelWin
= (wxGridColLabelWindow
*)NULL
;
138 wxGridWindow( wxGrid
*parent
,
139 wxGridRowLabelWindow
*rowLblWin
,
140 wxGridColLabelWindow
*colLblWin
,
141 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
);
144 void ScrollWindow( int dx
, int dy
, const wxRect
*rect
);
148 wxGridRowLabelWindow
*m_rowLabelWin
;
149 wxGridColLabelWindow
*m_colLabelWin
;
151 void OnPaint( wxPaintEvent
&event
);
152 void OnMouseEvent( wxMouseEvent
& event
);
153 void OnKeyDown( wxKeyEvent
& );
155 DECLARE_DYNAMIC_CLASS(wxGridWindow
)
156 DECLARE_EVENT_TABLE()
159 // the internal data representation used by wxGridCellAttrProvider
161 // TODO make it more efficient
162 class WXDLLEXPORT wxGridCellAttrProviderData
165 void SetAttr(wxGridCellAttr
*attr
, int row
, int col
);
166 wxGridCellAttr
*GetAttr(int row
, int col
) const;
169 // searches for the attr for given cell, returns wxNOT_FOUND if not found
170 int FindIndex(int row
, int col
) const;
172 wxGridCellWithAttrArray m_attrs
;
175 // ----------------------------------------------------------------------------
176 // conditional compilation
177 // ----------------------------------------------------------------------------
179 #ifndef WXGRID_DRAW_LINES
180 #define WXGRID_DRAW_LINES 1
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
187 //#define DEBUG_ATTR_CACHE
188 #ifdef DEBUG_ATTR_CACHE
189 static size_t gs_nAttrCacheHits
= 0;
190 static size_t gs_nAttrCacheMisses
= 0;
191 #endif // DEBUG_ATTR_CACHE
193 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
194 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
197 // TODO: fixed so far - make configurable later (and also different for x/y)
198 static const size_t GRID_SCROLL_LINE
= 10;
200 // ============================================================================
202 // ============================================================================
204 // ----------------------------------------------------------------------------
205 // wxGridCellRenderer
206 // ----------------------------------------------------------------------------
208 void wxGridCellRenderer
::Draw(wxGrid
& grid
,
214 dc
.SetBackgroundMode( wxSOLID
);
219 dc
.SetBrush( *wxBLACK_BRUSH
);
223 dc
.SetBrush( wxBrush(grid
.GetCellBackgroundColour(row
, col
), wxSOLID
) );
226 dc
.SetPen( *wxTRANSPARENT_PEN
);
228 dc
.DrawRectangle(rect
);
231 void wxGridCellStringRenderer
::Draw(wxGrid
& grid
,
233 const wxRect
& rectCell
,
237 wxGridCellRenderer
::Draw(grid
, dc
, rectCell
, row
, col
, isSelected
);
239 // now we only have to draw the text
240 dc
.SetBackgroundMode( wxTRANSPARENT
);
245 dc
.SetTextBackground( wxColour(0, 0, 0) );
246 dc
.SetTextForeground( wxColour(255, 255, 255) );
250 dc
.SetTextBackground( grid
.GetCellBackgroundColour(row
, col
) );
251 dc
.SetTextForeground( grid
.GetCellTextColour(row
, col
) );
253 dc
.SetFont( grid
.GetCellFont(row
, col
) );
256 grid
.GetCellAlignment(row
, col
, &hAlign
, &vAlign
);
258 wxRect rect
= rectCell
;
264 grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
),
265 rect
, hAlign
, vAlign
);
268 // ----------------------------------------------------------------------------
269 // wxGridCellAttrProviderData
270 // ----------------------------------------------------------------------------
272 void wxGridCellAttrProviderData
::SetAttr(wxGridCellAttr
*attr
,
275 int n
= FindIndex(row
, col
);
276 if ( n
== wxNOT_FOUND
)
279 m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
));
285 // change the attribute
286 m_attrs
[(size_t)n
].attr
= attr
;
290 // remove this attribute
291 m_attrs
.RemoveAt((size_t)n
);
296 wxGridCellAttr
*wxGridCellAttrProviderData
::GetAttr(int row
, int col
) const
298 wxGridCellAttr
*attr
= (wxGridCellAttr
*)NULL
;
300 int n
= FindIndex(row
, col
);
301 if ( n
!= wxNOT_FOUND
)
303 attr
= m_attrs
[(size_t)n
].attr
;
310 int wxGridCellAttrProviderData
::FindIndex(int row
, int col
) const
312 size_t count
= m_attrs
.GetCount();
313 for ( size_t n
= 0; n
< count
; n
++ )
315 const wxGridCellCoords
& coords
= m_attrs
[n
].coords
;
316 if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) )
325 // ----------------------------------------------------------------------------
326 // wxGridCellAttrProvider
327 // ----------------------------------------------------------------------------
329 wxGridCellAttrProvider
::wxGridCellAttrProvider()
331 m_data
= (wxGridCellAttrProviderData
*)NULL
;
334 wxGridCellAttrProvider
::~wxGridCellAttrProvider()
339 void wxGridCellAttrProvider
::InitData()
341 m_data
= new wxGridCellAttrProviderData
;
344 wxGridCellAttr
*wxGridCellAttrProvider
::GetAttr(int row
, int col
) const
346 return m_data ? m_data
->GetAttr(row
, col
) : (wxGridCellAttr
*)NULL
;
349 void wxGridCellAttrProvider
::SetAttr(wxGridCellAttr
*attr
,
355 m_data
->SetAttr(attr
, row
, col
);
358 //////////////////////////////////////////////////////////////////////
360 // Abstract base class for grid data (the model)
362 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
365 wxGridTableBase
::wxGridTableBase()
367 m_view
= (wxGrid
*) NULL
;
368 m_attrProvider
= (wxGridCellAttrProvider
*) NULL
;
371 wxGridTableBase
::~wxGridTableBase()
373 delete m_attrProvider
;
376 void wxGridTableBase
::SetAttrProvider(wxGridCellAttrProvider
*attrProvider
)
378 delete m_attrProvider
;
379 m_attrProvider
= attrProvider
;
382 wxGridCellAttr
*wxGridTableBase
::GetAttr(int row
, int col
)
384 if ( m_attrProvider
)
385 return m_attrProvider
->GetAttr(row
, col
);
387 return (wxGridCellAttr
*)NULL
;
390 void wxGridTableBase
::SetAttr(wxGridCellAttr
*attr
, int row
, int col
)
392 if ( m_attrProvider
)
394 m_attrProvider
->SetAttr(attr
, row
, col
);
398 // as we take ownership of the pointer and don't store it, we must
404 bool wxGridTableBase
::InsertRows( size_t pos
, size_t numRows
)
406 wxFAIL_MSG( wxT("Called grid table class function InsertRows\n"
407 "but your derived table class does not override this function") );
412 bool wxGridTableBase
::AppendRows( size_t numRows
)
414 wxFAIL_MSG( wxT("Called grid table class function AppendRows\n"
415 "but your derived table class does not override this function"));
420 bool wxGridTableBase
::DeleteRows( size_t pos
, size_t numRows
)
422 wxFAIL_MSG( wxT("Called grid table class function DeleteRows\n"
423 "but your derived table class does not override this function"));
428 bool wxGridTableBase
::InsertCols( size_t pos
, size_t numCols
)
430 wxFAIL_MSG( wxT("Called grid table class function InsertCols\n"
431 "but your derived table class does not override this function"));
436 bool wxGridTableBase
::AppendCols( size_t numCols
)
438 wxFAIL_MSG(wxT("Called grid table class function AppendCols\n"
439 "but your derived table class does not override this function"));
444 bool wxGridTableBase
::DeleteCols( size_t pos
, size_t numCols
)
446 wxFAIL_MSG( wxT("Called grid table class function DeleteCols\n"
447 "but your derived table class does not override this function"));
453 wxString wxGridTableBase
::GetRowLabelValue( int row
)
460 wxString wxGridTableBase
::GetColLabelValue( int col
)
462 // default col labels are:
463 // cols 0 to 25 : A-Z
464 // cols 26 to 675 : AA-ZZ
471 s
+= (_T('A') + (wxChar
)( col
%26 ));
473 if ( col
< 0 ) break;
476 // reverse the string...
478 for ( i
= 0; i
< n
; i
++ )
488 //////////////////////////////////////////////////////////////////////
490 // Message class for the grid table to send requests and notifications
494 wxGridTableMessage
::wxGridTableMessage()
496 m_table
= (wxGridTableBase
*) NULL
;
502 wxGridTableMessage
::wxGridTableMessage( wxGridTableBase
*table
, int id
,
503 int commandInt1
, int commandInt2
)
507 m_comInt1
= commandInt1
;
508 m_comInt2
= commandInt2
;
513 //////////////////////////////////////////////////////////////////////
515 // A basic grid table for string data. An object of this class will
516 // created by wxGrid if you don't specify an alternative table class.
519 WX_DEFINE_OBJARRAY(wxGridStringArray
)
521 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
523 wxGridStringTable
::wxGridStringTable()
528 wxGridStringTable
::wxGridStringTable( int numRows
, int numCols
)
533 m_data
.Alloc( numRows
);
537 for ( col
= 0; col
< numCols
; col
++ )
539 sa
.Add( wxEmptyString
);
542 for ( row
= 0; row
< numRows
; row
++ )
548 wxGridStringTable
::~wxGridStringTable()
552 long wxGridStringTable
::GetNumberRows()
554 return m_data
.GetCount();
557 long wxGridStringTable
::GetNumberCols()
559 if ( m_data
.GetCount() > 0 )
560 return m_data
[0].GetCount();
565 wxString wxGridStringTable
::GetValue( int row
, int col
)
567 // TODO: bounds checking
569 return m_data
[row
][col
];
572 void wxGridStringTable
::SetValue( int row
, int col
, const wxString
& s
)
574 // TODO: bounds checking
576 m_data
[row
][col
] = s
;
579 bool wxGridStringTable
::IsEmptyCell( int row
, int col
)
581 // TODO: bounds checking
583 return (m_data
[row
][col
] == wxEmptyString
);
587 void wxGridStringTable
::Clear()
590 int numRows
, numCols
;
592 numRows
= m_data
.GetCount();
595 numCols
= m_data
[0].GetCount();
597 for ( row
= 0; row
< numRows
; row
++ )
599 for ( col
= 0; col
< numCols
; col
++ )
601 m_data
[row
][col
] = wxEmptyString
;
608 bool wxGridStringTable
::InsertRows( size_t pos
, size_t numRows
)
612 size_t curNumRows
= m_data
.GetCount();
613 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
615 if ( pos
>= curNumRows
)
617 return AppendRows( numRows
);
621 sa
.Alloc( curNumCols
);
622 for ( col
= 0; col
< curNumCols
; col
++ )
624 sa
.Add( wxEmptyString
);
627 for ( row
= pos
; row
< pos
+ numRows
; row
++ )
629 m_data
.Insert( sa
, row
);
634 wxGridTableMessage
msg( this,
635 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
639 GetView()->ProcessTableMessage( msg
);
645 bool wxGridStringTable
::AppendRows( size_t numRows
)
649 size_t curNumRows
= m_data
.GetCount();
650 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
653 if ( curNumCols
> 0 )
655 sa
.Alloc( curNumCols
);
656 for ( col
= 0; col
< curNumCols
; col
++ )
658 sa
.Add( wxEmptyString
);
662 for ( row
= 0; row
< numRows
; row
++ )
669 wxGridTableMessage
msg( this,
670 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
673 GetView()->ProcessTableMessage( msg
);
679 bool wxGridStringTable
::DeleteRows( size_t pos
, size_t numRows
)
683 size_t curNumRows
= m_data
.GetCount();
685 if ( pos
>= curNumRows
)
688 errmsg
.Printf("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)\n"
689 "Pos value is invalid for present table with %d rows",
690 pos
, numRows
, curNumRows
);
691 wxFAIL_MSG( wxT(errmsg
) );
695 if ( numRows
> curNumRows
- pos
)
697 numRows
= curNumRows
- pos
;
700 if ( numRows
>= curNumRows
)
702 m_data
.Empty(); // don't release memory just yet
706 for ( n
= 0; n
< numRows
; n
++ )
708 m_data
.Remove( pos
);
714 wxGridTableMessage
msg( this,
715 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
719 GetView()->ProcessTableMessage( msg
);
725 bool wxGridStringTable
::InsertCols( size_t pos
, size_t numCols
)
729 size_t curNumRows
= m_data
.GetCount();
730 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
732 if ( pos
>= curNumCols
)
734 return AppendCols( numCols
);
737 for ( row
= 0; row
< curNumRows
; row
++ )
739 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
741 m_data
[row
].Insert( wxEmptyString
, col
);
747 wxGridTableMessage
msg( this,
748 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
752 GetView()->ProcessTableMessage( msg
);
758 bool wxGridStringTable
::AppendCols( size_t numCols
)
762 size_t curNumRows
= m_data
.GetCount();
765 // TODO: something better than this ?
767 wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\n"
768 "Call AppendRows() first") );
772 for ( row
= 0; row
< curNumRows
; row
++ )
774 for ( n
= 0; n
< numCols
; n
++ )
776 m_data
[row
].Add( wxEmptyString
);
782 wxGridTableMessage
msg( this,
783 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
786 GetView()->ProcessTableMessage( msg
);
792 bool wxGridStringTable
::DeleteCols( size_t pos
, size_t numCols
)
796 size_t curNumRows
= m_data
.GetCount();
797 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
799 if ( pos
>= curNumCols
)
802 errmsg
.Printf( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
803 "Pos value is invalid for present table with %d cols",
804 pos
, numCols
, curNumCols
);
805 wxFAIL_MSG( wxT( errmsg
) );
809 if ( numCols
> curNumCols
- pos
)
811 numCols
= curNumCols
- pos
;
814 for ( row
= 0; row
< curNumRows
; row
++ )
816 if ( numCols
>= curNumCols
)
822 for ( n
= 0; n
< numCols
; n
++ )
824 m_data
[row
].Remove( pos
);
831 wxGridTableMessage
msg( this,
832 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
836 GetView()->ProcessTableMessage( msg
);
842 wxString wxGridStringTable
::GetRowLabelValue( int row
)
844 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
846 // using default label
848 return wxGridTableBase
::GetRowLabelValue( row
);
852 return m_rowLabels
[ row
];
856 wxString wxGridStringTable
::GetColLabelValue( int col
)
858 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
860 // using default label
862 return wxGridTableBase
::GetColLabelValue( col
);
866 return m_colLabels
[ col
];
870 void wxGridStringTable
::SetRowLabelValue( int row
, const wxString
& value
)
872 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
874 int n
= m_rowLabels
.GetCount();
876 for ( i
= n
; i
<= row
; i
++ )
878 m_rowLabels
.Add( wxGridTableBase
::GetRowLabelValue(i
) );
882 m_rowLabels
[row
] = value
;
885 void wxGridStringTable
::SetColLabelValue( int col
, const wxString
& value
)
887 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
889 int n
= m_colLabels
.GetCount();
891 for ( i
= n
; i
<= col
; i
++ )
893 m_colLabels
.Add( wxGridTableBase
::GetColLabelValue(i
) );
897 m_colLabels
[col
] = value
;
903 //////////////////////////////////////////////////////////////////////
905 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl
, wxTextCtrl
)
907 BEGIN_EVENT_TABLE( wxGridTextCtrl
, wxTextCtrl
)
908 EVT_KEY_DOWN( wxGridTextCtrl
::OnKeyDown
)
912 wxGridTextCtrl
::wxGridTextCtrl( wxWindow
*par
,
916 const wxString
& value
,
920 : wxTextCtrl( par
, id
, value
, pos
, size
, style
)
923 m_isCellControl
= isCellControl
;
927 void wxGridTextCtrl
::OnKeyDown( wxKeyEvent
& event
)
929 switch ( event
.KeyCode() )
932 m_grid
->SetEditControlValue( startValue
);
933 SetInsertionPointEnd();
943 if ( m_isCellControl
)
945 // send the event to the parent grid, skipping the
946 // event if nothing happens
948 event
.Skip( m_grid
->ProcessEvent( event
) );
952 // default text control response within the top edit
960 if ( m_isCellControl
)
962 if ( !m_grid
->ProcessEvent( event
) )
964 #if defined(__WXMOTIF__) || defined(__WXGTK__)
965 // wxMotif needs a little extra help...
967 int pos
= GetInsertionPoint();
968 wxString
s( GetValue() );
969 s
= s
.Left(pos
) + "\n" + s
.Mid(pos
);
971 SetInsertionPoint( pos
);
973 // the other ports can handle a Return key press
983 if ( m_isCellControl
)
985 // send the event to the parent grid, skipping the
986 // event if nothing happens
988 event
.Skip( m_grid
->ProcessEvent( event
) );
992 // default text control response within the top edit
1004 void wxGridTextCtrl
::SetStartValue( const wxString
& s
)
1007 wxTextCtrl
::SetValue(s
);
1012 //////////////////////////////////////////////////////////////////////
1014 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow
)
1016 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxWindow
)
1017 EVT_PAINT( wxGridRowLabelWindow
::OnPaint
)
1018 EVT_MOUSE_EVENTS( wxGridRowLabelWindow
::OnMouseEvent
)
1019 EVT_KEY_DOWN( wxGridRowLabelWindow
::OnKeyDown
)
1022 wxGridRowLabelWindow
::wxGridRowLabelWindow( wxGrid
*parent
,
1024 const wxPoint
&pos
, const wxSize
&size
)
1025 : wxWindow( parent
, id
, pos
, size
)
1030 void wxGridRowLabelWindow
::OnPaint( wxPaintEvent
&event
)
1034 // NO - don't do this because it will set both the x and y origin
1035 // coords to match the parent scrolled window and we just want to
1036 // set the y coord - MB
1038 // m_owner->PrepareDC( dc );
1041 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
1042 dc
.SetDeviceOrigin( 0, -y
);
1044 m_owner
->CalcRowLabelsExposed( GetUpdateRegion() );
1045 m_owner
->DrawRowLabels( dc
);
1049 void wxGridRowLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
1051 m_owner
->ProcessRowLabelMouseEvent( event
);
1055 // This seems to be required for wxMotif otherwise the mouse
1056 // cursor must be in the cell edit control to get key events
1058 void wxGridRowLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
1060 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1065 //////////////////////////////////////////////////////////////////////
1067 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow
)
1069 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxWindow
)
1070 EVT_PAINT( wxGridColLabelWindow
::OnPaint
)
1071 EVT_MOUSE_EVENTS( wxGridColLabelWindow
::OnMouseEvent
)
1072 EVT_KEY_DOWN( wxGridColLabelWindow
::OnKeyDown
)
1075 wxGridColLabelWindow
::wxGridColLabelWindow( wxGrid
*parent
,
1077 const wxPoint
&pos
, const wxSize
&size
)
1078 : wxWindow( parent
, id
, pos
, size
)
1083 void wxGridColLabelWindow
::OnPaint( wxPaintEvent
&event
)
1087 // NO - don't do this because it will set both the x and y origin
1088 // coords to match the parent scrolled window and we just want to
1089 // set the x coord - MB
1091 // m_owner->PrepareDC( dc );
1094 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
1095 dc
.SetDeviceOrigin( -x
, 0 );
1097 m_owner
->CalcColLabelsExposed( GetUpdateRegion() );
1098 m_owner
->DrawColLabels( dc
);
1102 void wxGridColLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
1104 m_owner
->ProcessColLabelMouseEvent( event
);
1108 // This seems to be required for wxMotif otherwise the mouse
1109 // cursor must be in the cell edit control to get key events
1111 void wxGridColLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
1113 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1118 //////////////////////////////////////////////////////////////////////
1120 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow
)
1122 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxWindow
)
1123 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow
::OnMouseEvent
)
1124 EVT_PAINT( wxGridCornerLabelWindow
::OnPaint
)
1125 EVT_KEY_DOWN( wxGridCornerLabelWindow
::OnKeyDown
)
1128 wxGridCornerLabelWindow
::wxGridCornerLabelWindow( wxGrid
*parent
,
1130 const wxPoint
&pos
, const wxSize
&size
)
1131 : wxWindow( parent
, id
, pos
, size
)
1136 void wxGridCornerLabelWindow
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1140 int client_height
= 0;
1141 int client_width
= 0;
1142 GetClientSize( &client_width
, &client_height
);
1144 dc
.SetPen( *wxBLACK_PEN
);
1145 dc
.DrawLine( client_width
-1, client_height
-1, client_width
-1, 0 );
1146 dc
.DrawLine( client_width
-1, client_height
-1, 0, client_height
-1 );
1148 dc
.SetPen( *wxWHITE_PEN
);
1149 dc
.DrawLine( 0, 0, client_width
, 0 );
1150 dc
.DrawLine( 0, 0, 0, client_height
);
1154 void wxGridCornerLabelWindow
::OnMouseEvent( wxMouseEvent
& event
)
1156 m_owner
->ProcessCornerLabelMouseEvent( event
);
1160 // This seems to be required for wxMotif otherwise the mouse
1161 // cursor must be in the cell edit control to get key events
1163 void wxGridCornerLabelWindow
::OnKeyDown( wxKeyEvent
& event
)
1165 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1170 //////////////////////////////////////////////////////////////////////
1172 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxPanel
)
1174 BEGIN_EVENT_TABLE( wxGridWindow
, wxPanel
)
1175 EVT_PAINT( wxGridWindow
::OnPaint
)
1176 EVT_MOUSE_EVENTS( wxGridWindow
::OnMouseEvent
)
1177 EVT_KEY_DOWN( wxGridWindow
::OnKeyDown
)
1180 wxGridWindow
::wxGridWindow( wxGrid
*parent
,
1181 wxGridRowLabelWindow
*rowLblWin
,
1182 wxGridColLabelWindow
*colLblWin
,
1183 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
)
1184 : wxPanel( parent
, id
, pos
, size
, 0, "grid window" )
1187 m_rowLabelWin
= rowLblWin
;
1188 m_colLabelWin
= colLblWin
;
1190 SetBackgroundColour( "WHITE" );
1194 wxGridWindow
::~wxGridWindow()
1199 void wxGridWindow
::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
1201 wxPaintDC
dc( this );
1202 m_owner
->PrepareDC( dc
);
1203 wxRegion reg
= GetUpdateRegion();
1204 m_owner
->CalcCellsExposed( reg
);
1205 m_owner
->DrawGridCellArea( dc
);
1206 #if WXGRID_DRAW_LINES
1207 m_owner
->DrawAllGridLines( dc
, reg
);
1212 void wxGridWindow
::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
1214 wxPanel
::ScrollWindow( dx
, dy
, rect
);
1215 m_rowLabelWin
->ScrollWindow( 0, dy
, rect
);
1216 m_colLabelWin
->ScrollWindow( dx
, 0, rect
);
1220 void wxGridWindow
::OnMouseEvent( wxMouseEvent
& event
)
1222 m_owner
->ProcessGridCellMouseEvent( event
);
1226 // This seems to be required for wxMotif otherwise the mouse
1227 // cursor must be in the cell edit control to get key events
1229 void wxGridWindow
::OnKeyDown( wxKeyEvent
& event
)
1231 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
1236 //////////////////////////////////////////////////////////////////////
1238 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow
)
1240 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow
)
1241 EVT_PAINT( wxGrid
::OnPaint
)
1242 EVT_SIZE( wxGrid
::OnSize
)
1243 EVT_KEY_DOWN( wxGrid
::OnKeyDown
)
1246 wxGrid
::wxGrid( wxWindow
*parent
,
1251 const wxString
& name
)
1252 : wxScrolledWindow( parent
, id
, pos
, size
, style
, name
)
1262 #ifdef DEBUG_ATTR_CACHE
1263 size_t total
= gs_nAttrCacheHits
+ gs_nAttrCacheMisses
;
1264 wxPrintf(_T("wxGrid attribute cache statistics: "
1265 "total: %u, hits: %u (%u%%)\n"),
1266 total
, gs_nAttrCacheHits
,
1267 total ?
(gs_nAttrCacheHits
*100) / total
: 0);
1270 delete m_defaultRenderer
;
1276 // ----- internal init and update functions
1279 void wxGrid
::Create()
1281 m_created
= FALSE
; // set to TRUE by CreateGrid
1282 m_displayed
= FALSE
; // set to TRUE by OnPaint
1284 m_table
= (wxGridTableBase
*) NULL
;
1285 m_cellEditCtrl
= (wxWindow
*) NULL
;
1289 m_currentCellCoords
= wxGridNoCellCoords
;
1291 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
1292 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1294 m_cornerLabelWin
= new wxGridCornerLabelWindow( this,
1299 m_rowLabelWin
= new wxGridRowLabelWindow( this,
1304 m_colLabelWin
= new wxGridColLabelWindow( this,
1309 m_gridWin
= new wxGridWindow( this,
1316 SetTargetWindow( m_gridWin
);
1320 bool wxGrid
::CreateGrid( int numRows
, int numCols
)
1324 wxFAIL_MSG( wxT("wxGrid::CreateGrid called more than once") );
1329 m_numRows
= numRows
;
1330 m_numCols
= numCols
;
1332 m_table
= new wxGridStringTable( m_numRows
, m_numCols
);
1333 m_table
->SetView( this );
1346 if ( m_numRows
<= 0 )
1347 m_numRows
= WXGRID_DEFAULT_NUMBER_ROWS
;
1349 if ( m_numCols
<= 0 )
1350 m_numCols
= WXGRID_DEFAULT_NUMBER_COLS
;
1352 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
1353 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1355 if ( m_rowLabelWin
)
1357 m_labelBackgroundColour
= m_rowLabelWin
->GetBackgroundColour();
1361 m_labelBackgroundColour
= wxColour( _T("WHITE") );
1364 m_labelTextColour
= wxColour( _T("BLACK") );
1367 m_attrCache
.row
= -1;
1369 // TODO: something better than this ?
1371 m_labelFont
= this->GetFont();
1372 m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 );
1374 m_rowLabelHorizAlign
= wxLEFT
;
1375 m_rowLabelVertAlign
= wxCENTRE
;
1377 m_colLabelHorizAlign
= wxCENTRE
;
1378 m_colLabelVertAlign
= wxTOP
;
1380 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
1381 m_defaultRowHeight
= m_gridWin
->GetCharHeight();
1383 #if defined(__WXMOTIF__) || defined(__WXGTK__) // see also text ctrl sizing in ShowCellEditControl()
1384 m_defaultRowHeight
+= 8;
1386 m_defaultRowHeight
+= 4;
1389 m_rowHeights
.Alloc( m_numRows
);
1390 m_rowBottoms
.Alloc( m_numRows
);
1392 for ( i
= 0; i
< m_numRows
; i
++ )
1394 m_rowHeights
.Add( m_defaultRowHeight
);
1395 rowBottom
+= m_defaultRowHeight
;
1396 m_rowBottoms
.Add( rowBottom
);
1399 m_colWidths
.Alloc( m_numCols
);
1400 m_colRights
.Alloc( m_numCols
);
1402 for ( i
= 0; i
< m_numCols
; i
++ )
1404 m_colWidths
.Add( m_defaultColWidth
);
1405 colRight
+= m_defaultColWidth
;
1406 m_colRights
.Add( colRight
);
1409 // TODO: improve this by using wxSystemSettings?
1411 m_defaultCellFont
= GetFont();
1413 m_defaultCellHAlign
= wxLEFT
;
1414 m_defaultCellVAlign
= wxTOP
;
1416 m_defaultRenderer
= (wxGridCellRenderer
*)NULL
;
1418 m_gridLineColour
= wxColour( 128, 128, 255 );
1419 m_gridLinesEnabled
= TRUE
;
1421 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1422 m_winCapture
= (wxWindow
*)NULL
;
1424 m_dragRowOrCol
= -1;
1425 m_isDragging
= FALSE
;
1427 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
1428 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
1430 m_currentCellCoords
= wxGridNoCellCoords
;
1432 m_selectedTopLeft
= wxGridNoCellCoords
;
1433 m_selectedBottomRight
= wxGridNoCellCoords
;
1435 m_editable
= TRUE
; // default for whole grid
1437 m_inOnKeyDown
= FALSE
;
1440 // TODO: extend this to other types of controls
1442 m_cellEditCtrl
= new wxGridTextCtrl( m_gridWin
,
1449 #if defined(__WXMSW__)
1450 , wxTE_MULTILINE
| wxTE_NO_VSCROLL
1454 m_cellEditCtrl
->Show( FALSE
);
1455 m_cellEditCtrlEnabled
= TRUE
;
1456 m_editCtrlType
= wxGRID_TEXTCTRL
;
1460 void wxGrid
::CalcDimensions()
1463 GetClientSize( &cw
, &ch
);
1465 if ( m_numRows
> 0 && m_numCols
> 0 )
1467 int right
= m_colRights
[ m_numCols
-1 ] + 50;
1468 int bottom
= m_rowBottoms
[ m_numRows
-1 ] + 50;
1470 // TODO: restore the scroll position that we had before sizing
1473 GetViewStart( &x
, &y
);
1474 SetScrollbars( GRID_SCROLL_LINE
, GRID_SCROLL_LINE
,
1475 right
/GRID_SCROLL_LINE
, bottom
/GRID_SCROLL_LINE
,
1481 void wxGrid
::CalcWindowSizes()
1484 GetClientSize( &cw
, &ch
);
1486 if ( m_cornerLabelWin
->IsShown() )
1487 m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight
);
1489 if ( m_colLabelWin
->IsShown() )
1490 m_colLabelWin
->SetSize( m_rowLabelWidth
, 0, cw
-m_rowLabelWidth
, m_colLabelHeight
);
1492 if ( m_rowLabelWin
->IsShown() )
1493 m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, ch
-m_colLabelHeight
);
1495 if ( m_gridWin
->IsShown() )
1496 m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, cw
-m_rowLabelWidth
, ch
-m_colLabelHeight
);
1500 // this is called when the grid table sends a message to say that it
1501 // has been redimensioned
1503 bool wxGrid
::Redimension( wxGridTableMessage
& msg
)
1507 switch ( msg
.GetId() )
1509 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
1511 size_t pos
= msg
.GetCommandInt();
1512 int numRows
= msg
.GetCommandInt2();
1513 for ( i
= 0; i
< numRows
; i
++ )
1515 m_rowHeights
.Insert( m_defaultRowHeight
, pos
);
1516 m_rowBottoms
.Insert( 0, pos
);
1518 m_numRows
+= numRows
;
1521 if ( pos
> 0 ) bottom
= m_rowBottoms
[pos
-1];
1523 for ( i
= pos
; i
< m_numRows
; i
++ )
1525 bottom
+= m_rowHeights
[i
];
1526 m_rowBottoms
[i
] = bottom
;
1532 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
1534 int numRows
= msg
.GetCommandInt();
1535 for ( i
= 0; i
< numRows
; i
++ )
1537 m_rowHeights
.Add( m_defaultRowHeight
);
1538 m_rowBottoms
.Add( 0 );
1541 int oldNumRows
= m_numRows
;
1542 m_numRows
+= numRows
;
1545 if ( oldNumRows
> 0 ) bottom
= m_rowBottoms
[oldNumRows
-1];
1547 for ( i
= oldNumRows
; i
< m_numRows
; i
++ )
1549 bottom
+= m_rowHeights
[i
];
1550 m_rowBottoms
[i
] = bottom
;
1556 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
1558 size_t pos
= msg
.GetCommandInt();
1559 int numRows
= msg
.GetCommandInt2();
1560 for ( i
= 0; i
< numRows
; i
++ )
1562 m_rowHeights
.Remove( pos
);
1563 m_rowBottoms
.Remove( pos
);
1565 m_numRows
-= numRows
;
1570 m_colWidths
.Clear();
1571 m_colRights
.Clear();
1572 m_currentCellCoords
= wxGridNoCellCoords
;
1576 if ( m_currentCellCoords
.GetRow() >= m_numRows
)
1577 m_currentCellCoords
.Set( 0, 0 );
1580 for ( i
= 0; i
< m_numRows
; i
++ )
1582 h
+= m_rowHeights
[i
];
1583 m_rowBottoms
[i
] = h
;
1591 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
1593 size_t pos
= msg
.GetCommandInt();
1594 int numCols
= msg
.GetCommandInt2();
1595 for ( i
= 0; i
< numCols
; i
++ )
1597 m_colWidths
.Insert( m_defaultColWidth
, pos
);
1598 m_colRights
.Insert( 0, pos
);
1600 m_numCols
+= numCols
;
1603 if ( pos
> 0 ) right
= m_colRights
[pos
-1];
1605 for ( i
= pos
; i
< m_numCols
; i
++ )
1607 right
+= m_colWidths
[i
];
1608 m_colRights
[i
] = right
;
1614 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
1616 int numCols
= msg
.GetCommandInt();
1617 for ( i
= 0; i
< numCols
; i
++ )
1619 m_colWidths
.Add( m_defaultColWidth
);
1620 m_colRights
.Add( 0 );
1623 int oldNumCols
= m_numCols
;
1624 m_numCols
+= numCols
;
1627 if ( oldNumCols
> 0 ) right
= m_colRights
[oldNumCols
-1];
1629 for ( i
= oldNumCols
; i
< m_numCols
; i
++ )
1631 right
+= m_colWidths
[i
];
1632 m_colRights
[i
] = right
;
1638 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
1640 size_t pos
= msg
.GetCommandInt();
1641 int numCols
= msg
.GetCommandInt2();
1642 for ( i
= 0; i
< numCols
; i
++ )
1644 m_colWidths
.Remove( pos
);
1645 m_colRights
.Remove( pos
);
1647 m_numCols
-= numCols
;
1651 #if 0 // leave the row alone here so that AppendCols will work subsequently
1653 m_rowHeights
.Clear();
1654 m_rowBottoms
.Clear();
1656 m_currentCellCoords
= wxGridNoCellCoords
;
1660 if ( m_currentCellCoords
.GetCol() >= m_numCols
)
1661 m_currentCellCoords
.Set( 0, 0 );
1664 for ( i
= 0; i
< m_numCols
; i
++ )
1666 w
+= m_colWidths
[i
];
1679 void wxGrid
::CalcRowLabelsExposed( wxRegion
& reg
)
1681 wxRegionIterator
iter( reg
);
1684 m_rowLabelsExposed
.Empty();
1691 // TODO: remove this when we can...
1692 // There is a bug in wxMotif that gives garbage update
1693 // rectangles if you jump-scroll a long way by clicking the
1694 // scrollbar with middle button. This is a work-around
1696 #if defined(__WXMOTIF__)
1698 m_gridWin
->GetClientSize( &cw
, &ch
);
1699 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1700 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1703 // logical bounds of update region
1706 CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top
);
1707 CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom
);
1709 // find the row labels within these bounds
1713 for ( row
= 0; row
< m_numRows
; row
++ )
1715 if ( m_rowBottoms
[row
] < top
) continue;
1717 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1718 if ( rowTop
> bottom
) break;
1720 m_rowLabelsExposed
.Add( row
);
1728 void wxGrid
::CalcColLabelsExposed( wxRegion
& reg
)
1730 wxRegionIterator
iter( reg
);
1733 m_colLabelsExposed
.Empty();
1740 // TODO: remove this when we can...
1741 // There is a bug in wxMotif that gives garbage update
1742 // rectangles if you jump-scroll a long way by clicking the
1743 // scrollbar with middle button. This is a work-around
1745 #if defined(__WXMOTIF__)
1747 m_gridWin
->GetClientSize( &cw
, &ch
);
1748 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1749 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1752 // logical bounds of update region
1755 CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy
);
1756 CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy
);
1758 // find the cells within these bounds
1762 for ( col
= 0; col
< m_numCols
; col
++ )
1764 if ( m_colRights
[col
] < left
) continue;
1766 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1767 if ( colLeft
> right
) break;
1769 m_colLabelsExposed
.Add( col
);
1777 void wxGrid
::CalcCellsExposed( wxRegion
& reg
)
1779 wxRegionIterator
iter( reg
);
1782 m_cellsExposed
.Empty();
1783 m_rowsExposed
.Empty();
1784 m_colsExposed
.Empty();
1786 int left
, top
, right
, bottom
;
1791 // TODO: remove this when we can...
1792 // There is a bug in wxMotif that gives garbage update
1793 // rectangles if you jump-scroll a long way by clicking the
1794 // scrollbar with middle button. This is a work-around
1796 #if defined(__WXMOTIF__)
1798 m_gridWin
->GetClientSize( &cw
, &ch
);
1799 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1800 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1801 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1802 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1805 // logical bounds of update region
1807 CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
1808 CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
1810 // find the cells within these bounds
1813 int colLeft
, rowTop
;
1814 for ( row
= 0; row
< m_numRows
; row
++ )
1816 if ( m_rowBottoms
[row
] < top
) continue;
1818 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1819 if ( rowTop
> bottom
) break;
1821 m_rowsExposed
.Add( row
);
1823 for ( col
= 0; col
< m_numCols
; col
++ )
1825 if ( m_colRights
[col
] < left
) continue;
1827 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1828 if ( colLeft
> right
) break;
1830 if ( m_colsExposed
.Index( col
) == wxNOT_FOUND
) m_colsExposed
.Add( col
);
1831 m_cellsExposed
.Add( wxGridCellCoords( row
, col
) );
1840 void wxGrid
::ProcessRowLabelMouseEvent( wxMouseEvent
& event
)
1843 wxPoint
pos( event
.GetPosition() );
1844 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1846 if ( event
.Dragging() )
1848 m_isDragging
= TRUE
;
1850 if ( event
.LeftIsDown() )
1852 switch( m_cursorMode
)
1854 case WXGRID_CURSOR_RESIZE_ROW
:
1856 int cw
, ch
, left
, dummy
;
1857 m_gridWin
->GetClientSize( &cw
, &ch
);
1858 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
1860 wxClientDC
dc( m_gridWin
);
1862 dc
.SetLogicalFunction(wxINVERT
);
1863 if ( m_dragLastPos
>= 0 )
1865 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
1867 dc
.DrawLine( left
, y
, left
+cw
, y
);
1872 case WXGRID_CURSOR_SELECT_ROW
:
1873 if ( (row
= YToRow( y
)) >= 0 &&
1874 !IsInSelection( row
, 0 ) )
1876 SelectRow( row
, TRUE
);
1879 // default label to suppress warnings about "enumeration value
1880 // 'xxx' not handled in switch
1888 m_isDragging
= FALSE
;
1891 // ------------ Entering or leaving the window
1893 if ( event
.Entering() || event
.Leaving() )
1895 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
1899 // ------------ Left button pressed
1901 else if ( event
.LeftDown() )
1903 // don't send a label click event for a hit on the
1904 // edge of the row label - this is probably the user
1905 // wanting to resize the row
1907 if ( YToEdgeOfRow(y
) < 0 )
1911 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event
) )
1913 SelectRow( row
, event
.ShiftDown() );
1914 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
);
1919 // starting to drag-resize a row
1921 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
);
1926 // ------------ Left double click
1928 else if (event
.LeftDClick() )
1930 if ( YToEdgeOfRow(y
) < 0 )
1933 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event
);
1938 // ------------ Left button released
1940 else if ( event
.LeftUp() )
1942 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
1944 DoEndDragResizeRow();
1946 // Note: we are ending the event *after* doing
1947 // default processing in this case
1949 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
1952 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
);
1957 // ------------ Right button down
1959 else if ( event
.RightDown() )
1962 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event
) )
1964 // no default action at the moment
1969 // ------------ Right double click
1971 else if ( event
.RightDClick() )
1974 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event
) )
1976 // no default action at the moment
1981 // ------------ No buttons down and mouse moving
1983 else if ( event
.Moving() )
1985 m_dragRowOrCol
= YToEdgeOfRow( y
);
1986 if ( m_dragRowOrCol
>= 0 )
1988 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1990 // don't capture the mouse yet
1991 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, FALSE
);
1994 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1996 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, FALSE
);
2002 void wxGrid
::ProcessColLabelMouseEvent( wxMouseEvent
& event
)
2005 wxPoint
pos( event
.GetPosition() );
2006 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
2008 if ( event
.Dragging() )
2010 m_isDragging
= TRUE
;
2012 if ( event
.LeftIsDown() )
2014 switch( m_cursorMode
)
2016 case WXGRID_CURSOR_RESIZE_COL
:
2018 int cw
, ch
, dummy
, top
;
2019 m_gridWin
->GetClientSize( &cw
, &ch
);
2020 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
2022 wxClientDC
dc( m_gridWin
);
2024 dc
.SetLogicalFunction(wxINVERT
);
2025 if ( m_dragLastPos
>= 0 )
2027 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
2029 dc
.DrawLine( x
, top
, x
, top
+ch
);
2034 case WXGRID_CURSOR_SELECT_COL
:
2035 if ( (col
= XToCol( x
)) >= 0 &&
2036 !IsInSelection( 0, col
) )
2038 SelectCol( col
, TRUE
);
2041 // default label to suppress warnings about "enumeration value
2042 // 'xxx' not handled in switch
2050 m_isDragging
= FALSE
;
2053 // ------------ Entering or leaving the window
2055 if ( event
.Entering() || event
.Leaving() )
2057 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
);
2061 // ------------ Left button pressed
2063 else if ( event
.LeftDown() )
2065 // don't send a label click event for a hit on the
2066 // edge of the col label - this is probably the user
2067 // wanting to resize the col
2069 if ( XToEdgeOfCol(x
) < 0 )
2073 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event
) )
2075 SelectCol( col
, event
.ShiftDown() );
2076 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, m_colLabelWin
);
2081 // starting to drag-resize a col
2083 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
);
2088 // ------------ Left double click
2090 if ( event
.LeftDClick() )
2092 if ( XToEdgeOfCol(x
) < 0 )
2095 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event
);
2100 // ------------ Left button released
2102 else if ( event
.LeftUp() )
2104 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
2106 DoEndDragResizeCol();
2108 // Note: we are ending the event *after* doing
2109 // default processing in this case
2111 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
2114 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
);
2119 // ------------ Right button down
2121 else if ( event
.RightDown() )
2124 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event
) )
2126 // no default action at the moment
2131 // ------------ Right double click
2133 else if ( event
.RightDClick() )
2136 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event
) )
2138 // no default action at the moment
2143 // ------------ No buttons down and mouse moving
2145 else if ( event
.Moving() )
2147 m_dragRowOrCol
= XToEdgeOfCol( x
);
2148 if ( m_dragRowOrCol
>= 0 )
2150 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2152 // don't capture the cursor yet
2153 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
, FALSE
);
2156 else if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
2158 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
, FALSE
);
2164 void wxGrid
::ProcessCornerLabelMouseEvent( wxMouseEvent
& event
)
2166 if ( event
.LeftDown() )
2168 // indicate corner label by having both row and
2171 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event
) )
2177 else if ( event
.LeftDClick() )
2179 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event
);
2182 else if ( event
.RightDown() )
2184 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event
) )
2186 // no default action at the moment
2190 else if ( event
.RightDClick() )
2192 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event
) )
2194 // no default action at the moment
2199 void wxGrid
::ChangeCursorMode(CursorMode mode
,
2204 static const wxChar
*cursorModes
[] =
2213 wxLogTrace(_T("grid"),
2214 _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
2215 win
== m_colLabelWin ?
_T("colLabelWin")
2216 : win ?
_T("rowLabelWin")
2218 cursorModes
[m_cursorMode
], cursorModes
[mode
]);
2219 #endif // __WXDEBUG__
2221 if ( mode
== m_cursorMode
)
2226 // by default use the grid itself
2232 m_winCapture
->ReleaseMouse();
2233 m_winCapture
= (wxWindow
*)NULL
;
2236 m_cursorMode
= mode
;
2238 switch ( m_cursorMode
)
2240 case WXGRID_CURSOR_RESIZE_ROW
:
2241 win
->SetCursor( m_rowResizeCursor
);
2244 case WXGRID_CURSOR_RESIZE_COL
:
2245 win
->SetCursor( m_colResizeCursor
);
2249 win
->SetCursor( *wxSTANDARD_CURSOR
);
2252 // we need to capture mouse when resizing
2253 bool resize
= m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
||
2254 m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
;
2256 if ( captureMouse
&& resize
)
2258 win
->CaptureMouse();
2263 void wxGrid
::ProcessGridCellMouseEvent( wxMouseEvent
& event
)
2266 wxPoint
pos( event
.GetPosition() );
2267 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
2269 wxGridCellCoords coords
;
2270 XYToCell( x
, y
, coords
);
2272 if ( event
.Dragging() )
2274 m_isDragging
= TRUE
;
2275 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2277 // Hide the edit control, so it
2278 // won't interfer with drag-shrinking.
2279 if ( IsCellEditControlEnabled() )
2280 HideCellEditControl();
2281 if ( coords
!= wxGridNoCellCoords
)
2283 if ( !IsSelection() )
2285 SelectBlock( coords
, coords
);
2289 SelectBlock( m_currentCellCoords
, coords
);
2293 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
2295 int cw
, ch
, left
, dummy
;
2296 m_gridWin
->GetClientSize( &cw
, &ch
);
2297 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
2299 wxClientDC
dc( m_gridWin
);
2301 dc
.SetLogicalFunction(wxINVERT
);
2302 if ( m_dragLastPos
>= 0 )
2304 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
2306 dc
.DrawLine( left
, y
, left
+cw
, y
);
2309 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
2311 int cw
, ch
, dummy
, top
;
2312 m_gridWin
->GetClientSize( &cw
, &ch
);
2313 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
2315 wxClientDC
dc( m_gridWin
);
2317 dc
.SetLogicalFunction(wxINVERT
);
2318 if ( m_dragLastPos
>= 0 )
2320 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
2322 dc
.DrawLine( x
, top
, x
, top
+ch
);
2329 m_isDragging
= FALSE
;
2331 if ( coords
!= wxGridNoCellCoords
)
2333 // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
2334 // immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
2337 if ( event
.Entering() || event
.Leaving() )
2339 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
2340 m_gridWin
->SetCursor( *wxSTANDARD_CURSOR
);
2345 // ------------ Left button pressed
2347 if ( event
.LeftDown() )
2349 if ( event
.ShiftDown() )
2351 SelectBlock( m_currentCellCoords
, coords
);
2353 else if ( XToEdgeOfCol(x
) < 0 &&
2354 YToEdgeOfRow(y
) < 0 )
2356 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK
,
2361 MakeCellVisible( coords
);
2362 SetCurrentCell( coords
);
2368 // ------------ Left double click
2370 else if ( event
.LeftDClick() )
2372 if ( XToEdgeOfCol(x
) < 0 && YToEdgeOfRow(y
) < 0 )
2374 SendEvent( EVT_GRID_CELL_LEFT_DCLICK
,
2382 // ------------ Left button released
2384 else if ( event
.LeftUp() )
2386 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2388 if ( IsSelection() )
2390 SendEvent( EVT_GRID_RANGE_SELECT
, -1, -1, event
);
2393 // Show the edit control, if it has
2394 // been hidden for drag-shrinking.
2395 if ( IsCellEditControlEnabled() )
2396 ShowCellEditControl();
2398 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
2400 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
2401 DoEndDragResizeRow();
2403 // Note: we are ending the event *after* doing
2404 // default processing in this case
2406 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
2408 else if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
2410 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
2411 DoEndDragResizeCol();
2413 // Note: we are ending the event *after* doing
2414 // default processing in this case
2416 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
2423 // ------------ Right button down
2425 else if ( event
.RightDown() )
2427 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK
,
2432 // no default action at the moment
2437 // ------------ Right double click
2439 else if ( event
.RightDClick() )
2441 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK
,
2446 // no default action at the moment
2450 // ------------ Moving and no button action
2452 else if ( event
.Moving() && !event
.IsButton() )
2454 int dragRow
= YToEdgeOfRow( y
);
2455 int dragCol
= XToEdgeOfCol( x
);
2457 // Dragging on the corner of a cell to resize in both
2458 // directions is not implemented yet...
2460 if ( dragRow
>= 0 && dragCol
>= 0 )
2462 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
2468 m_dragRowOrCol
= dragRow
;
2470 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2472 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
);
2480 m_dragRowOrCol
= dragCol
;
2482 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
2484 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
);
2490 // Neither on a row or col edge
2492 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
2494 ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
);
2501 void wxGrid
::DoEndDragResizeRow()
2503 if ( m_dragLastPos
>= 0 )
2505 // erase the last line and resize the row
2507 int cw
, ch
, left
, dummy
;
2508 m_gridWin
->GetClientSize( &cw
, &ch
);
2509 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
2511 wxClientDC
dc( m_gridWin
);
2513 dc
.SetLogicalFunction( wxINVERT
);
2514 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
2515 HideCellEditControl();
2517 int rowTop
= m_rowBottoms
[m_dragRowOrCol
] - m_rowHeights
[m_dragRowOrCol
];
2518 SetRowSize( m_dragRowOrCol
,
2519 wxMax( m_dragLastPos
- rowTop
, WXGRID_MIN_ROW_HEIGHT
) );
2521 if ( !GetBatchCount() )
2523 // Only needed to get the correct rect.y:
2524 wxRect
rect ( CellToRect( m_dragRowOrCol
, 0 ) );
2526 CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
);
2527 rect
.width
= m_rowLabelWidth
;
2528 rect
.height
= ch
- rect
.y
;
2529 m_rowLabelWin
->Refresh( TRUE
, &rect
);
2531 m_gridWin
->Refresh( FALSE
, &rect
);
2534 ShowCellEditControl();
2539 void wxGrid
::DoEndDragResizeCol()
2541 if ( m_dragLastPos
>= 0 )
2543 // erase the last line and resize the col
2545 int cw
, ch
, dummy
, top
;
2546 m_gridWin
->GetClientSize( &cw
, &ch
);
2547 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
2549 wxClientDC
dc( m_gridWin
);
2551 dc
.SetLogicalFunction( wxINVERT
);
2552 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
2553 HideCellEditControl();
2555 int colLeft
= m_colRights
[m_dragRowOrCol
] - m_colWidths
[m_dragRowOrCol
];
2556 SetColSize( m_dragRowOrCol
,
2557 wxMax( m_dragLastPos
- colLeft
, WXGRID_MIN_COL_WIDTH
) );
2559 if ( !GetBatchCount() )
2561 // Only needed to get the correct rect.x:
2562 wxRect
rect ( CellToRect( 0, m_dragRowOrCol
) );
2564 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
);
2565 rect
.width
= cw
- rect
.x
;
2566 rect
.height
= m_colLabelHeight
;
2567 m_colLabelWin
->Refresh( TRUE
, &rect
);
2569 m_gridWin
->Refresh( FALSE
, &rect
);
2572 ShowCellEditControl();
2579 // ------ interaction with data model
2581 bool wxGrid
::ProcessTableMessage( wxGridTableMessage
& msg
)
2583 switch ( msg
.GetId() )
2585 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
2586 return GetModelValues();
2588 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
2589 return SetModelValues();
2591 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
2592 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
2593 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
2594 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
2595 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
2596 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
2597 return Redimension( msg
);
2606 // The behaviour of this function depends on the grid table class
2607 // Clear() function. For the default wxGridStringTable class the
2608 // behavious is to replace all cell contents with wxEmptyString but
2609 // not to change the number of rows or cols.
2611 void wxGrid
::ClearGrid()
2616 SetEditControlValue();
2617 if ( !GetBatchCount() ) m_gridWin
->Refresh();
2622 bool wxGrid
::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2624 // TODO: something with updateLabels flag
2628 wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2634 bool ok
= m_table
->InsertRows( pos
, numRows
);
2636 // the table will have sent the results of the insert row
2637 // operation to this view object as a grid table message
2641 if ( m_numCols
== 0 )
2643 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS
);
2645 // TODO: perhaps instead of appending the default number of cols
2646 // we should remember what the last non-zero number of cols was ?
2650 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2652 // if we have just inserted cols into an empty grid the current
2653 // cell will be undefined...
2655 SetCurrentCell( 0, 0 );
2659 if ( !GetBatchCount() ) Refresh();
2662 SetEditControlValue();
2672 bool wxGrid
::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) )
2674 // TODO: something with updateLabels flag
2678 wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2682 if ( m_table
&& m_table
->AppendRows( numRows
) )
2684 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2686 // if we have just inserted cols into an empty grid the current
2687 // cell will be undefined...
2689 SetCurrentCell( 0, 0 );
2692 // the table will have sent the results of the append row
2693 // operation to this view object as a grid table message
2696 if ( !GetBatchCount() ) Refresh();
2706 bool wxGrid
::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2708 // TODO: something with updateLabels flag
2712 wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2716 if ( m_table
&& m_table
->DeleteRows( pos
, numRows
) )
2718 // the table will have sent the results of the delete row
2719 // operation to this view object as a grid table message
2721 if ( m_numRows
> 0 )
2722 SetEditControlValue();
2724 HideCellEditControl();
2727 if ( !GetBatchCount() ) Refresh();
2737 bool wxGrid
::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2739 // TODO: something with updateLabels flag
2743 wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2749 HideCellEditControl();
2750 bool ok
= m_table
->InsertCols( pos
, numCols
);
2752 // the table will have sent the results of the insert col
2753 // operation to this view object as a grid table message
2757 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2759 // if we have just inserted cols into an empty grid the current
2760 // cell will be undefined...
2762 SetCurrentCell( 0, 0 );
2766 if ( !GetBatchCount() ) Refresh();
2769 SetEditControlValue();
2779 bool wxGrid
::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) )
2781 // TODO: something with updateLabels flag
2785 wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2789 if ( m_table
&& m_table
->AppendCols( numCols
) )
2791 // the table will have sent the results of the append col
2792 // operation to this view object as a grid table message
2794 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2796 // if we have just inserted cols into an empty grid the current
2797 // cell will be undefined...
2799 SetCurrentCell( 0, 0 );
2803 if ( !GetBatchCount() ) Refresh();
2813 bool wxGrid
::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2815 // TODO: something with updateLabels flag
2819 wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2823 if ( m_table
&& m_table
->DeleteCols( pos
, numCols
) )
2825 // the table will have sent the results of the delete col
2826 // operation to this view object as a grid table message
2828 if ( m_numCols
> 0 )
2829 SetEditControlValue();
2831 HideCellEditControl();
2834 if ( !GetBatchCount() ) Refresh();
2846 // ----- event handlers
2849 // Generate a grid event based on a mouse event and
2850 // return the result of ProcessEvent()
2852 bool wxGrid
::SendEvent( const wxEventType type
,
2854 wxMouseEvent
& mouseEv
)
2856 if ( type
== EVT_GRID_ROW_SIZE
||
2857 type
== EVT_GRID_COL_SIZE
)
2859 int rowOrCol
= (row
== -1 ? col
: row
);
2861 wxGridSizeEvent
gridEvt( GetId(),
2865 mouseEv
.GetX(), mouseEv
.GetY(),
2866 mouseEv
.ControlDown(),
2867 mouseEv
.ShiftDown(),
2869 mouseEv
.MetaDown() );
2871 return GetEventHandler()->ProcessEvent(gridEvt
);
2873 else if ( type
== EVT_GRID_RANGE_SELECT
)
2875 wxGridRangeSelectEvent
gridEvt( GetId(),
2879 m_selectedBottomRight
,
2880 mouseEv
.ControlDown(),
2881 mouseEv
.ShiftDown(),
2883 mouseEv
.MetaDown() );
2885 return GetEventHandler()->ProcessEvent(gridEvt
);
2889 wxGridEvent
gridEvt( GetId(),
2893 mouseEv
.GetX(), mouseEv
.GetY(),
2894 mouseEv
.ControlDown(),
2895 mouseEv
.ShiftDown(),
2897 mouseEv
.MetaDown() );
2899 return GetEventHandler()->ProcessEvent(gridEvt
);
2904 // Generate a grid event of specified type and return the result
2905 // of ProcessEvent().
2907 bool wxGrid
::SendEvent( const wxEventType type
,
2910 if ( type
== EVT_GRID_ROW_SIZE
||
2911 type
== EVT_GRID_COL_SIZE
)
2913 int rowOrCol
= (row
== -1 ? col
: row
);
2915 wxGridSizeEvent
gridEvt( GetId(),
2920 return GetEventHandler()->ProcessEvent(gridEvt
);
2924 wxGridEvent
gridEvt( GetId(),
2929 return GetEventHandler()->ProcessEvent(gridEvt
);
2934 void wxGrid
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
2936 wxPaintDC
dc( this );
2938 if ( m_currentCellCoords
== wxGridNoCellCoords
&&
2939 m_numRows
&& m_numCols
)
2941 m_currentCellCoords
.Set(0, 0);
2942 SetEditControlValue();
2943 ShowCellEditControl();
2950 // This is just here to make sure that CalcDimensions gets called when
2951 // the grid view is resized... then the size event is skipped to allow
2952 // the box sizers to handle everything
2954 void wxGrid
::OnSize( wxSizeEvent
& event
)
2961 void wxGrid
::OnKeyDown( wxKeyEvent
& event
)
2963 if ( m_inOnKeyDown
)
2965 // shouldn't be here - we are going round in circles...
2967 wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while alread active") );
2970 m_inOnKeyDown
= TRUE
;
2972 // propagate the event up and see if it gets processed
2974 wxWindow
*parent
= GetParent();
2975 wxKeyEvent
keyEvt( event
);
2976 keyEvt
.SetEventObject( parent
);
2978 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
2980 // try local handlers
2982 switch ( event
.KeyCode() )
2985 if ( event
.ControlDown() )
2987 MoveCursorUpBlock();
2996 if ( event
.ControlDown() )
2998 MoveCursorDownBlock();
3007 if ( event
.ControlDown() )
3009 MoveCursorLeftBlock();
3018 if ( event
.ControlDown() )
3020 MoveCursorRightBlock();
3029 if ( !IsEditable() )
3040 if ( event
.ControlDown() )
3042 event
.Skip(); // to let the edit control have the return
3051 if ( event
.ControlDown() )
3053 MakeCellVisible( 0, 0 );
3054 SetCurrentCell( 0, 0 );
3063 if ( event
.ControlDown() )
3065 MakeCellVisible( m_numRows
-1, m_numCols
-1 );
3066 SetCurrentCell( m_numRows
-1, m_numCols
-1 );
3083 // now try the cell edit control
3085 if ( IsCellEditControlEnabled() )
3087 event
.SetEventObject( m_cellEditCtrl
);
3088 m_cellEditCtrl
->GetEventHandler()->ProcessEvent( event
);
3094 m_inOnKeyDown
= FALSE
;
3098 void wxGrid
::SetCurrentCell( const wxGridCellCoords
& coords
)
3100 if ( SendEvent( EVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) )
3102 // the event has been intercepted - do nothing
3107 m_currentCellCoords
!= wxGridNoCellCoords
)
3109 HideCellEditControl();
3110 SaveEditControlValue();
3113 m_currentCellCoords
= coords
;
3115 SetEditControlValue();
3119 ShowCellEditControl();
3121 if ( IsSelection() )
3123 wxRect
r( SelectionToDeviceRect() );
3125 if ( !GetBatchCount() ) m_gridWin
->Refresh( FALSE
, &r
);
3132 // ------ functions to get/send data (see also public functions)
3135 bool wxGrid
::GetModelValues()
3139 // all we need to do is repaint the grid
3141 m_gridWin
->Refresh();
3149 bool wxGrid
::SetModelValues()
3155 for ( row
= 0; row
< m_numRows
; row
++ )
3157 for ( col
= 0; col
< m_numCols
; col
++ )
3159 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
3171 // Note - this function only draws cells that are in the list of
3172 // exposed cells (usually set from the update region by
3173 // CalcExposedCells)
3175 void wxGrid
::DrawGridCellArea( wxDC
& dc
)
3177 if ( !m_numRows
|| !m_numCols
) return;
3180 size_t numCells
= m_cellsExposed
.GetCount();
3182 for ( i
= 0; i
< numCells
; i
++ )
3184 DrawCell( dc
, m_cellsExposed
[i
] );
3189 void wxGrid
::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords
)
3191 int row
= coords
.GetRow();
3192 int col
= coords
.GetCol();
3194 if ( m_colWidths
[col
] <= 0 || m_rowHeights
[row
] <= 0 )
3197 // we draw the cell border ourselves
3198 #if !WXGRID_DRAW_LINES
3199 if ( m_gridLinesEnabled
)
3200 DrawCellBorder( dc
, coords
);
3203 // but all the rest is drawn by the cell renderer and hence may be
3205 wxGridCellRenderer
*renderer
= GetCellRenderer(row
, col
);
3207 rect
.x
= m_colRights
[col
] - m_colWidths
[col
] + 1;
3208 rect
.y
= m_rowBottoms
[row
] - m_rowHeights
[row
] + 1;
3209 rect
.width
= m_colWidths
[col
] - 1;
3210 rect
.height
= m_rowHeights
[row
] - 1;
3212 renderer
->Draw(*this, dc
, rect
, row
, col
, IsInSelection(coords
));
3215 void wxGrid
::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords
)
3217 if ( m_colWidths
[coords
.GetCol()] <=0 ||
3218 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
3220 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
3221 int row
= coords
.GetRow();
3222 int col
= coords
.GetCol();
3224 // right hand border
3226 dc
.DrawLine( m_colRights
[col
], m_rowBottoms
[row
] - m_rowHeights
[row
],
3227 m_colRights
[col
], m_rowBottoms
[row
] );
3231 dc
.DrawLine( m_colRights
[col
] - m_colWidths
[col
], m_rowBottoms
[row
],
3232 m_colRights
[col
], m_rowBottoms
[row
] );
3236 // TODO: remove this ???
3237 // This is used to redraw all grid lines e.g. when the grid line colour
3240 void wxGrid
::DrawAllGridLines( wxDC
& dc
, const wxRegion
& reg
)
3242 if ( !m_gridLinesEnabled
||
3244 !m_numCols
) return;
3246 int top
, bottom
, left
, right
;
3250 m_gridWin
->GetClientSize(&cw
, &ch
);
3252 // virtual coords of visible area
3254 CalcUnscrolledPosition( 0, 0, &left
, &top
);
3255 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
3259 reg
.GetBox(x
, y
, w
, h
);
3260 CalcUnscrolledPosition( x
, y
, &left
, &top
);
3261 CalcUnscrolledPosition( x
+ w
, y
+ h
, &right
, &bottom
);
3264 // avoid drawing grid lines past the last row and col
3266 right
= wxMin( right
, m_colRights
[m_numCols
-1] );
3267 bottom
= wxMin( bottom
, m_rowBottoms
[m_numRows
-1] );
3269 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
3271 // horizontal grid lines
3274 for ( i
= 0; i
< m_numRows
; i
++ )
3276 if ( m_rowBottoms
[i
] > bottom
)
3280 else if ( m_rowBottoms
[i
] >= top
)
3282 dc
.DrawLine( left
, m_rowBottoms
[i
], right
, m_rowBottoms
[i
] );
3287 // vertical grid lines
3289 for ( i
= 0; i
< m_numCols
; i
++ )
3291 if ( m_colRights
[i
] > right
)
3295 else if ( m_colRights
[i
] >= left
)
3297 dc
.DrawLine( m_colRights
[i
], top
, m_colRights
[i
], bottom
);
3303 void wxGrid
::DrawRowLabels( wxDC
& dc
)
3305 if ( !m_numRows
|| !m_numCols
) return;
3308 size_t numLabels
= m_rowLabelsExposed
.GetCount();
3310 for ( i
= 0; i
< numLabels
; i
++ )
3312 DrawRowLabel( dc
, m_rowLabelsExposed
[i
] );
3317 void wxGrid
::DrawRowLabel( wxDC
& dc
, int row
)
3319 if ( m_rowHeights
[row
] <= 0 ) return;
3321 int rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3323 dc
.SetPen( *wxBLACK_PEN
);
3324 dc
.DrawLine( m_rowLabelWidth
-1, rowTop
,
3325 m_rowLabelWidth
-1, m_rowBottoms
[row
]-1 );
3327 dc
.DrawLine( 0, m_rowBottoms
[row
]-1,
3328 m_rowLabelWidth
-1, m_rowBottoms
[row
]-1 );
3330 dc
.SetPen( *wxWHITE_PEN
);
3331 dc
.DrawLine( 0, rowTop
, 0, m_rowBottoms
[row
]-1 );
3332 dc
.DrawLine( 0, rowTop
, m_rowLabelWidth
-1, rowTop
);
3334 dc
.SetBackgroundMode( wxTRANSPARENT
);
3335 dc
.SetTextForeground( GetLabelTextColour() );
3336 dc
.SetFont( GetLabelFont() );
3339 GetRowLabelAlignment( &hAlign
, &vAlign
);
3343 rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 );
3344 rect
.SetWidth( m_rowLabelWidth
- 4 );
3345 rect
.SetHeight( m_rowHeights
[row
] - 4 );
3346 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect
, hAlign
, vAlign
);
3350 void wxGrid
::DrawColLabels( wxDC
& dc
)
3352 if ( !m_numRows
|| !m_numCols
) return;
3355 size_t numLabels
= m_colLabelsExposed
.GetCount();
3357 for ( i
= 0; i
< numLabels
; i
++ )
3359 DrawColLabel( dc
, m_colLabelsExposed
[i
] );
3364 void wxGrid
::DrawColLabel( wxDC
& dc
, int col
)
3366 if ( m_colWidths
[col
] <= 0 ) return;
3368 int colLeft
= m_colRights
[col
] - m_colWidths
[col
];
3370 dc
.SetPen( *wxBLACK_PEN
);
3371 dc
.DrawLine( m_colRights
[col
]-1, 0,
3372 m_colRights
[col
]-1, m_colLabelHeight
-1 );
3374 dc
.DrawLine( colLeft
, m_colLabelHeight
-1,
3375 m_colRights
[col
]-1, m_colLabelHeight
-1 );
3377 dc
.SetPen( *wxWHITE_PEN
);
3378 dc
.DrawLine( colLeft
, 0, colLeft
, m_colLabelHeight
-1 );
3379 dc
.DrawLine( colLeft
, 0, m_colRights
[col
]-1, 0 );
3381 dc
.SetBackgroundMode( wxTRANSPARENT
);
3382 dc
.SetTextForeground( GetLabelTextColour() );
3383 dc
.SetFont( GetLabelFont() );
3385 dc
.SetBackgroundMode( wxTRANSPARENT
);
3386 dc
.SetTextForeground( GetLabelTextColour() );
3387 dc
.SetFont( GetLabelFont() );
3390 GetColLabelAlignment( &hAlign
, &vAlign
);
3393 rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 );
3395 rect
.SetWidth( m_colWidths
[col
] - 4 );
3396 rect
.SetHeight( m_colLabelHeight
- 4 );
3397 DrawTextRectangle( dc
, GetColLabelValue( col
), rect
, hAlign
, vAlign
);
3401 void wxGrid
::DrawTextRectangle( wxDC
& dc
,
3402 const wxString
& value
,
3407 long textWidth
, textHeight
;
3408 long lineWidth
, lineHeight
;
3409 wxArrayString lines
;
3411 dc
.SetClippingRegion( rect
);
3412 StringToLines( value
, lines
);
3413 if ( lines
.GetCount() )
3415 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
3416 dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight
);
3419 switch ( horizAlign
)
3422 x
= rect
.x
+ (rect
.width
- textWidth
- 1);
3426 x
= rect
.x
+ ((rect
.width
- textWidth
)/2);
3435 switch ( vertAlign
)
3438 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
3442 y
= rect
.y
+ ((rect
.height
- textHeight
)/2);
3451 for ( size_t i
= 0; i
< lines
.GetCount(); i
++ )
3453 dc
.DrawText( lines
[i
], (long)x
, (long)y
);
3458 dc
.DestroyClippingRegion();
3462 // Split multi line text up into an array of strings. Any existing
3463 // contents of the string array are preserved.
3465 void wxGrid
::StringToLines( const wxString
& value
, wxArrayString
& lines
)
3469 wxString eol
= wxTextFile
::GetEOL( wxTextFileType_Unix
);
3470 wxString tVal
= wxTextFile
::Translate( value
, wxTextFileType_Unix
);
3472 while ( startPos
< (int)tVal
.Length() )
3474 pos
= tVal
.Mid(startPos
).Find( eol
);
3479 else if ( pos
== 0 )
3481 lines
.Add( wxEmptyString
);
3485 lines
.Add( value
.Mid(startPos
, pos
) );
3489 if ( startPos
< (int)value
.Length() )
3491 lines
.Add( value
.Mid( startPos
) );
3496 void wxGrid
::GetTextBoxSize( wxDC
& dc
,
3497 wxArrayString
& lines
,
3498 long *width
, long *height
)
3505 for ( i
= 0; i
< lines
.GetCount(); i
++ )
3507 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
3508 w
= wxMax( w
, lineW
);
3518 // ------ Edit control functions
3522 void wxGrid
::EnableEditing( bool edit
)
3524 // TODO: improve this ?
3526 if ( edit
!= m_editable
)
3530 // TODO: extend this for other edit control types
3532 if ( m_editCtrlType
== wxGRID_TEXTCTRL
)
3534 ((wxTextCtrl
*)m_cellEditCtrl
)->SetEditable( m_editable
);
3540 #if 0 // disabled for the moment - the cell control is always active
3541 void wxGrid
::EnableCellEditControl( bool enable
)
3543 if ( m_cellEditCtrl
&&
3544 enable
!= m_cellEditCtrlEnabled
)
3546 m_cellEditCtrlEnabled
= enable
;
3548 if ( m_cellEditCtrlEnabled
)
3550 SetEditControlValue();
3551 ShowCellEditControl();
3555 HideCellEditControl();
3556 SaveEditControlValue();
3563 void wxGrid
::ShowCellEditControl()
3567 if ( IsCellEditControlEnabled() )
3569 if ( !IsVisible( m_currentCellCoords
) )
3575 rect
= CellToRect( m_currentCellCoords
);
3577 // convert to scrolled coords
3579 int left
, top
, right
, bottom
;
3580 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
3581 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
3584 m_gridWin
->GetClientSize( &cw
, &ch
);
3586 // Make the edit control large enough to allow for internal margins
3587 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3590 #if defined(__WXMOTIF__)
3591 if ( m_currentCellCoords
.GetRow() == 0 ||
3592 m_currentCellCoords
.GetCol() == 0 )
3601 if ( m_currentCellCoords
.GetRow() == 0 ||
3602 m_currentCellCoords
.GetCol() == 0 )
3612 #if defined(__WXGTK__)
3615 if (left
!= 0) left_diff
++;
3616 if (top
!= 0) top_diff
++;
3617 rect
.SetLeft( left
+ left_diff
);
3618 rect
.SetTop( top
+ top_diff
);
3619 rect
.SetRight( rect
.GetRight() - left_diff
);
3620 rect
.SetBottom( rect
.GetBottom() - top_diff
);
3622 rect
.SetLeft( wxMax(0, left
- extra
) );
3623 rect
.SetTop( wxMax(0, top
- extra
) );
3624 rect
.SetRight( rect
.GetRight() + 2*extra
);
3625 rect
.SetBottom( rect
.GetBottom() + 2*extra
);
3628 m_cellEditCtrl
->SetSize( rect
);
3629 m_cellEditCtrl
->Show( TRUE
);
3631 switch ( m_editCtrlType
)
3633 case wxGRID_TEXTCTRL
:
3634 ((wxTextCtrl
*) m_cellEditCtrl
)->SetInsertionPointEnd();
3637 case wxGRID_CHECKBOX
:
3638 // TODO: anything ???
3643 // TODO: anything ???
3647 case wxGRID_COMBOBOX
:
3648 // TODO: anything ???
3653 m_cellEditCtrl
->SetFocus();
3659 void wxGrid
::HideCellEditControl()
3661 if ( IsCellEditControlEnabled() )
3663 m_cellEditCtrl
->Show( FALSE
);
3668 void wxGrid
::SetEditControlValue( const wxString
& value
)
3674 s
= GetCellValue(m_currentCellCoords
);
3678 if ( IsCellEditControlEnabled() )
3680 switch ( m_editCtrlType
)
3682 case wxGRID_TEXTCTRL
:
3683 ((wxGridTextCtrl
*)m_cellEditCtrl
)->SetStartValue(s
);
3686 case wxGRID_CHECKBOX
:
3687 // TODO: implement this
3692 // TODO: implement this
3696 case wxGRID_COMBOBOX
:
3697 // TODO: implement this
3706 void wxGrid
::SaveEditControlValue()
3710 wxWindow
*ctrl
= (wxWindow
*)NULL
;
3712 if ( IsCellEditControlEnabled() )
3714 ctrl
= m_cellEditCtrl
;
3721 bool valueChanged
= FALSE
;
3723 switch ( m_editCtrlType
)
3725 case wxGRID_TEXTCTRL
:
3726 valueChanged
= (((wxGridTextCtrl
*)ctrl
)->GetValue() !=
3727 ((wxGridTextCtrl
*)ctrl
)->GetStartValue());
3728 SetCellValue( m_currentCellCoords
,
3729 ((wxTextCtrl
*) ctrl
)->GetValue() );
3732 case wxGRID_CHECKBOX
:
3733 // TODO: implement this
3738 // TODO: implement this
3742 case wxGRID_COMBOBOX
:
3743 // TODO: implement this
3750 SendEvent( EVT_GRID_CELL_CHANGE
,
3751 m_currentCellCoords
.GetRow(),
3752 m_currentCellCoords
.GetCol() );
3759 // ------ Grid location functions
3760 // Note that all of these functions work with the logical coordinates of
3761 // grid cells and labels so you will need to convert from device
3762 // coordinates for mouse events etc.
3765 void wxGrid
::XYToCell( int x
, int y
, wxGridCellCoords
& coords
)
3767 int row
= YToRow(y
);
3768 int col
= XToCol(x
);
3770 if ( row
== -1 || col
== -1 )
3772 coords
= wxGridNoCellCoords
;
3776 coords
.Set( row
, col
);
3781 int wxGrid
::YToRow( int y
)
3785 for ( i
= 0; i
< m_numRows
; i
++ )
3787 if ( y
< m_rowBottoms
[i
] ) return i
;
3794 int wxGrid
::XToCol( int x
)
3798 for ( i
= 0; i
< m_numCols
; i
++ )
3800 if ( x
< m_colRights
[i
] ) return i
;
3807 // return the row number that that the y coord is near the edge of, or
3808 // -1 if not near an edge
3810 int wxGrid
::YToEdgeOfRow( int y
)
3814 for ( i
= 0; i
< m_numRows
; i
++ )
3816 if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3818 d
= abs( y
- m_rowBottoms
[i
] );
3820 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3829 // return the col number that that the x coord is near the edge of, or
3830 // -1 if not near an edge
3832 int wxGrid
::XToEdgeOfCol( int x
)
3836 for ( i
= 0; i
< m_numCols
; i
++ )
3838 if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3840 d
= abs( x
- m_colRights
[i
] );
3842 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3851 wxRect wxGrid
::CellToRect( int row
, int col
)
3853 wxRect
rect( -1, -1, -1, -1 );
3855 if ( row
>= 0 && row
< m_numRows
&&
3856 col
>= 0 && col
< m_numCols
)
3858 rect
.x
= m_colRights
[col
] - m_colWidths
[col
];
3859 rect
.y
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3860 rect
.width
= m_colWidths
[col
];
3861 rect
.height
= m_rowHeights
[ row
];
3868 bool wxGrid
::IsVisible( int row
, int col
, bool wholeCellVisible
)
3870 // get the cell rectangle in logical coords
3872 wxRect
r( CellToRect( row
, col
) );
3874 // convert to device coords
3876 int left
, top
, right
, bottom
;
3877 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3878 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3880 // check against the client area of the grid window
3883 m_gridWin
->GetClientSize( &cw
, &ch
);
3885 if ( wholeCellVisible
)
3887 // is the cell wholly visible ?
3889 return ( left
>= 0 && right
<= cw
&&
3890 top
>= 0 && bottom
<= ch
);
3894 // is the cell partly visible ?
3896 return ( ((left
>=0 && left
< cw
) || (right
> 0 && right
<= cw
)) &&
3897 ((top
>=0 && top
< ch
) || (bottom
> 0 && bottom
<= ch
)) );
3902 // make the specified cell location visible by doing a minimal amount
3905 void wxGrid
::MakeCellVisible( int row
, int col
)
3908 int xpos
= -1, ypos
= -1;
3910 if ( row
>= 0 && row
< m_numRows
&&
3911 col
>= 0 && col
< m_numCols
)
3913 // get the cell rectangle in logical coords
3915 wxRect
r( CellToRect( row
, col
) );
3917 // convert to device coords
3919 int left
, top
, right
, bottom
;
3920 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3921 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3924 m_gridWin
->GetClientSize( &cw
, &ch
);
3930 else if ( bottom
> ch
)
3932 int h
= r
.GetHeight();
3934 for ( i
= row
-1; i
>= 0; i
-- )
3936 if ( h
+ m_rowHeights
[i
] > ch
) break;
3938 h
+= m_rowHeights
[i
];
3939 ypos
-= m_rowHeights
[i
];
3942 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3943 // have rounding errors (this is important, because if we do, we
3944 // might not scroll at all and some cells won't be redrawn)
3945 ypos
+= GRID_SCROLL_LINE
/ 2;
3952 else if ( right
> cw
)
3954 int w
= r
.GetWidth();
3956 for ( i
= col
-1; i
>= 0; i
-- )
3958 if ( w
+ m_colWidths
[i
] > cw
) break;
3960 w
+= m_colWidths
[i
];
3961 xpos
-= m_colWidths
[i
];
3964 // see comment for ypos above
3965 xpos
+= GRID_SCROLL_LINE
/ 2;
3968 if ( xpos
!= -1 || ypos
!= -1 )
3970 if ( xpos
!= -1 ) xpos
/= GRID_SCROLL_LINE
;
3971 if ( ypos
!= -1 ) ypos
/= GRID_SCROLL_LINE
;
3972 Scroll( xpos
, ypos
);
3980 // ------ Grid cursor movement functions
3983 bool wxGrid
::MoveCursorUp()
3985 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3986 m_currentCellCoords
.GetRow() > 0 )
3988 MakeCellVisible( m_currentCellCoords
.GetRow() - 1,
3989 m_currentCellCoords
.GetCol() );
3991 SetCurrentCell( m_currentCellCoords
.GetRow() - 1,
3992 m_currentCellCoords
.GetCol() );
4001 bool wxGrid
::MoveCursorDown()
4003 // TODO: allow for scrolling
4005 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
4006 m_currentCellCoords
.GetRow() < m_numRows
-1 )
4008 MakeCellVisible( m_currentCellCoords
.GetRow() + 1,
4009 m_currentCellCoords
.GetCol() );
4011 SetCurrentCell( m_currentCellCoords
.GetRow() + 1,
4012 m_currentCellCoords
.GetCol() );
4021 bool wxGrid
::MoveCursorLeft()
4023 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
4024 m_currentCellCoords
.GetCol() > 0 )
4026 MakeCellVisible( m_currentCellCoords
.GetRow(),
4027 m_currentCellCoords
.GetCol() - 1 );
4029 SetCurrentCell( m_currentCellCoords
.GetRow(),
4030 m_currentCellCoords
.GetCol() - 1 );
4039 bool wxGrid
::MoveCursorRight()
4041 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
4042 m_currentCellCoords
.GetCol() < m_numCols
- 1 )
4044 MakeCellVisible( m_currentCellCoords
.GetRow(),
4045 m_currentCellCoords
.GetCol() + 1 );
4047 SetCurrentCell( m_currentCellCoords
.GetRow(),
4048 m_currentCellCoords
.GetCol() + 1 );
4057 bool wxGrid
::MovePageUp()
4059 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
4061 int row
= m_currentCellCoords
.GetRow();
4065 m_gridWin
->GetClientSize( &cw
, &ch
);
4067 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
4068 int newRow
= YToRow( y
- ch
+ 1 );
4073 else if ( newRow
== row
)
4078 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
4079 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
4087 bool wxGrid
::MovePageDown()
4089 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
4091 int row
= m_currentCellCoords
.GetRow();
4092 if ( row
< m_numRows
)
4095 m_gridWin
->GetClientSize( &cw
, &ch
);
4097 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
4098 int newRow
= YToRow( y
+ ch
);
4101 newRow
= m_numRows
- 1;
4103 else if ( newRow
== row
)
4108 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
4109 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
4117 bool wxGrid
::MoveCursorUpBlock()
4120 m_currentCellCoords
!= wxGridNoCellCoords
&&
4121 m_currentCellCoords
.GetRow() > 0 )
4123 int row
= m_currentCellCoords
.GetRow();
4124 int col
= m_currentCellCoords
.GetCol();
4126 if ( m_table
->IsEmptyCell(row
, col
) )
4128 // starting in an empty cell: find the next block of
4134 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4137 else if ( m_table
->IsEmptyCell(row
-1, col
) )
4139 // starting at the top of a block: find the next block
4145 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4150 // starting within a block: find the top of the block
4155 if ( m_table
->IsEmptyCell(row
, col
) )
4163 MakeCellVisible( row
, col
);
4164 SetCurrentCell( row
, col
);
4172 bool wxGrid
::MoveCursorDownBlock()
4175 m_currentCellCoords
!= wxGridNoCellCoords
&&
4176 m_currentCellCoords
.GetRow() < m_numRows
-1 )
4178 int row
= m_currentCellCoords
.GetRow();
4179 int col
= m_currentCellCoords
.GetCol();
4181 if ( m_table
->IsEmptyCell(row
, col
) )
4183 // starting in an empty cell: find the next block of
4186 while ( row
< m_numRows
-1 )
4189 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4192 else if ( m_table
->IsEmptyCell(row
+1, col
) )
4194 // starting at the bottom of a block: find the next block
4197 while ( row
< m_numRows
-1 )
4200 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4205 // starting within a block: find the bottom of the block
4207 while ( row
< m_numRows
-1 )
4210 if ( m_table
->IsEmptyCell(row
, col
) )
4218 MakeCellVisible( row
, col
);
4219 SetCurrentCell( row
, col
);
4227 bool wxGrid
::MoveCursorLeftBlock()
4230 m_currentCellCoords
!= wxGridNoCellCoords
&&
4231 m_currentCellCoords
.GetCol() > 0 )
4233 int row
= m_currentCellCoords
.GetRow();
4234 int col
= m_currentCellCoords
.GetCol();
4236 if ( m_table
->IsEmptyCell(row
, col
) )
4238 // starting in an empty cell: find the next block of
4244 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4247 else if ( m_table
->IsEmptyCell(row
, col
-1) )
4249 // starting at the left of a block: find the next block
4255 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4260 // starting within a block: find the left of the block
4265 if ( m_table
->IsEmptyCell(row
, col
) )
4273 MakeCellVisible( row
, col
);
4274 SetCurrentCell( row
, col
);
4282 bool wxGrid
::MoveCursorRightBlock()
4285 m_currentCellCoords
!= wxGridNoCellCoords
&&
4286 m_currentCellCoords
.GetCol() < m_numCols
-1 )
4288 int row
= m_currentCellCoords
.GetRow();
4289 int col
= m_currentCellCoords
.GetCol();
4291 if ( m_table
->IsEmptyCell(row
, col
) )
4293 // starting in an empty cell: find the next block of
4296 while ( col
< m_numCols
-1 )
4299 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4302 else if ( m_table
->IsEmptyCell(row
, col
+1) )
4304 // starting at the right of a block: find the next block
4307 while ( col
< m_numCols
-1 )
4310 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
4315 // starting within a block: find the right of the block
4317 while ( col
< m_numCols
-1 )
4320 if ( m_table
->IsEmptyCell(row
, col
) )
4328 MakeCellVisible( row
, col
);
4329 SetCurrentCell( row
, col
);
4340 // ------ Label values and formatting
4343 void wxGrid
::GetRowLabelAlignment( int *horiz
, int *vert
)
4345 *horiz
= m_rowLabelHorizAlign
;
4346 *vert
= m_rowLabelVertAlign
;
4349 void wxGrid
::GetColLabelAlignment( int *horiz
, int *vert
)
4351 *horiz
= m_colLabelHorizAlign
;
4352 *vert
= m_colLabelVertAlign
;
4355 wxString wxGrid
::GetRowLabelValue( int row
)
4359 return m_table
->GetRowLabelValue( row
);
4369 wxString wxGrid
::GetColLabelValue( int col
)
4373 return m_table
->GetColLabelValue( col
);
4384 void wxGrid
::SetRowLabelSize( int width
)
4386 width
= wxMax( width
, 0 );
4387 if ( width
!= m_rowLabelWidth
)
4391 m_rowLabelWin
->Show( FALSE
);
4392 m_cornerLabelWin
->Show( FALSE
);
4394 else if ( m_rowLabelWidth
== 0 )
4396 m_rowLabelWin
->Show( TRUE
);
4397 if ( m_colLabelHeight
> 0 ) m_cornerLabelWin
->Show( TRUE
);
4400 m_rowLabelWidth
= width
;
4407 void wxGrid
::SetColLabelSize( int height
)
4409 height
= wxMax( height
, 0 );
4410 if ( height
!= m_colLabelHeight
)
4414 m_colLabelWin
->Show( FALSE
);
4415 m_cornerLabelWin
->Show( FALSE
);
4417 else if ( m_colLabelHeight
== 0 )
4419 m_colLabelWin
->Show( TRUE
);
4420 if ( m_rowLabelWidth
> 0 ) m_cornerLabelWin
->Show( TRUE
);
4423 m_colLabelHeight
= height
;
4430 void wxGrid
::SetLabelBackgroundColour( const wxColour
& colour
)
4432 if ( m_labelBackgroundColour
!= colour
)
4434 m_labelBackgroundColour
= colour
;
4435 m_rowLabelWin
->SetBackgroundColour( colour
);
4436 m_colLabelWin
->SetBackgroundColour( colour
);
4437 m_cornerLabelWin
->SetBackgroundColour( colour
);
4439 if ( !GetBatchCount() )
4441 m_rowLabelWin
->Refresh();
4442 m_colLabelWin
->Refresh();
4443 m_cornerLabelWin
->Refresh();
4448 void wxGrid
::SetLabelTextColour( const wxColour
& colour
)
4450 if ( m_labelTextColour
!= colour
)
4452 m_labelTextColour
= colour
;
4453 if ( !GetBatchCount() )
4455 m_rowLabelWin
->Refresh();
4456 m_colLabelWin
->Refresh();
4461 void wxGrid
::SetLabelFont( const wxFont
& font
)
4464 if ( !GetBatchCount() )
4466 m_rowLabelWin
->Refresh();
4467 m_colLabelWin
->Refresh();
4471 void wxGrid
::SetRowLabelAlignment( int horiz
, int vert
)
4473 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
4475 m_rowLabelHorizAlign
= horiz
;
4478 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
4480 m_rowLabelVertAlign
= vert
;
4483 if ( !GetBatchCount() )
4485 m_rowLabelWin
->Refresh();
4489 void wxGrid
::SetColLabelAlignment( int horiz
, int vert
)
4491 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
4493 m_colLabelHorizAlign
= horiz
;
4496 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
4498 m_colLabelVertAlign
= vert
;
4501 if ( !GetBatchCount() )
4503 m_colLabelWin
->Refresh();
4507 void wxGrid
::SetRowLabelValue( int row
, const wxString
& s
)
4511 m_table
->SetRowLabelValue( row
, s
);
4512 if ( !GetBatchCount() )
4514 wxRect rect
= CellToRect( row
, 0);
4515 if ( rect
.height
> 0 )
4517 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
);
4519 rect
.width
= m_rowLabelWidth
;
4520 m_rowLabelWin
->Refresh( TRUE
, &rect
);
4526 void wxGrid
::SetColLabelValue( int col
, const wxString
& s
)
4530 m_table
->SetColLabelValue( col
, s
);
4531 if ( !GetBatchCount() )
4533 wxRect rect
= CellToRect( 0, col
);
4534 if ( rect
.width
> 0 )
4536 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
);
4538 rect
.height
= m_colLabelHeight
;
4539 m_colLabelWin
->Refresh( TRUE
, &rect
);
4545 void wxGrid
::SetGridLineColour( const wxColour
& colour
)
4547 if ( m_gridLineColour
!= colour
)
4549 m_gridLineColour
= colour
;
4551 wxClientDC
dc( m_gridWin
);
4553 DrawAllGridLines( dc
, wxRegion() );
4557 void wxGrid
::EnableGridLines( bool enable
)
4559 if ( enable
!= m_gridLinesEnabled
)
4561 m_gridLinesEnabled
= enable
;
4563 if ( !GetBatchCount() )
4567 wxClientDC
dc( m_gridWin
);
4569 DrawAllGridLines( dc
, wxRegion() );
4573 m_gridWin
->Refresh();
4580 int wxGrid
::GetDefaultRowSize()
4582 return m_defaultRowHeight
;
4585 int wxGrid
::GetRowSize( int row
)
4587 wxCHECK_MSG( row
>= 0 && row
< m_numRows
, 0, _T("invalid row index") );
4589 return m_rowHeights
[row
];
4592 int wxGrid
::GetDefaultColSize()
4594 return m_defaultColWidth
;
4597 int wxGrid
::GetColSize( int col
)
4599 wxCHECK_MSG( col
>= 0 && col
< m_numCols
, 0, _T("invalid column index") );
4601 return m_colWidths
[col
];
4604 // ============================================================================
4605 // access to the grid attributes: each of them has a default value in the grid
4606 // itself and may be overidden on a per-cell basis
4607 // ============================================================================
4609 // ----------------------------------------------------------------------------
4610 // setting default attributes
4611 // ----------------------------------------------------------------------------
4613 void wxGrid
::SetDefaultCellBackgroundColour( const wxColour
& col
)
4615 m_gridWin
->SetBackgroundColour(col
);
4618 void wxGrid
::SetDefaultCellTextColour( const wxColour
& col
)
4620 m_gridWin
->SetForegroundColour(col
);
4623 void wxGrid
::SetDefaultCellAlignment( int horiz
, int vert
)
4625 m_defaultCellHAlign
= horiz
;
4626 m_defaultCellVAlign
= vert
;
4629 void wxGrid
::SetDefaultCellFont( const wxFont
& font
)
4631 m_defaultCellFont
= font
;
4634 // ----------------------------------------------------------------------------
4635 // access to the default attrbiutes
4636 // ----------------------------------------------------------------------------
4638 wxColour wxGrid
::GetDefaultCellBackgroundColour()
4640 return m_gridWin
->GetBackgroundColour();
4643 wxColour wxGrid
::GetDefaultCellTextColour()
4645 return m_gridWin
->GetForegroundColour();
4648 wxFont wxGrid
::GetDefaultCellFont()
4650 return m_defaultCellFont
;
4653 void wxGrid
::GetDefaultCellAlignment( int *horiz
, int *vert
)
4656 *horiz
= m_defaultCellHAlign
;
4658 *vert
= m_defaultCellVAlign
;
4661 wxGridCellRenderer
*wxGrid
::GetCellRenderer(int row
, int col
)
4663 wxGridCellRenderer
*renderer
= (wxGridCellRenderer
*)NULL
;
4664 wxGridCellAttr
*attr
= m_table ? m_table
->GetAttr(row
, col
) : NULL
;
4667 renderer
= attr
->GetRenderer();
4674 if ( !m_defaultRenderer
)
4676 m_defaultRenderer
= new wxGridCellStringRenderer
;
4679 renderer
= m_defaultRenderer
;
4685 // ----------------------------------------------------------------------------
4686 // access to cell attributes
4687 // ----------------------------------------------------------------------------
4689 wxColour wxGrid
::GetCellBackgroundColour(int row
, int col
)
4691 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
4694 if ( attr
&& attr
->HasBackgroundColour() )
4695 colour
= attr
->GetBackgroundColour();
4697 colour
= GetDefaultCellBackgroundColour();
4704 wxColour wxGrid
::GetCellTextColour( int row
, int col
)
4706 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
4709 if ( attr
&& attr
->HasTextColour() )
4710 colour
= attr
->GetTextColour();
4712 colour
= GetDefaultCellTextColour();
4719 wxFont wxGrid
::GetCellFont( int row
, int col
)
4721 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
4724 if ( attr
&& attr
->HasFont() )
4725 font
= attr
->GetFont();
4727 font
= GetDefaultCellFont();
4734 void wxGrid
::GetCellAlignment( int row
, int col
, int *horiz
, int *vert
)
4736 wxGridCellAttr
*attr
= GetCellAttr(row
, col
);
4738 if ( attr
&& attr
->HasAlignment() )
4739 attr
->GetAlignment(horiz
, vert
);
4741 GetDefaultCellAlignment(horiz
, vert
);
4746 // ----------------------------------------------------------------------------
4747 // setting cell attributes: this is forwarded to the table
4748 // ----------------------------------------------------------------------------
4750 bool wxGrid
::CanHaveAttributes()
4757 if ( !m_table
->GetAttrProvider() )
4759 // use the default attr provider by default
4760 // (another choice would be to just return FALSE thus forcing the user
4762 m_table
->SetAttrProvider(new wxGridCellAttrProvider
);
4768 void wxGrid
::ClearAttrCache()
4770 if ( m_attrCache
.row
!= -1 )
4772 m_attrCache
.attr
->SafeDecRef();
4773 m_attrCache
.row
= -1;
4777 void wxGrid
::CacheAttr(int row
, int col
, wxGridCellAttr
*attr
) const
4779 wxGrid
*self
= (wxGrid
*)this; // const_cast
4781 self
->ClearAttrCache();
4782 self
->m_attrCache
.row
= row
;
4783 self
->m_attrCache
.col
= col
;
4784 self
->m_attrCache
.attr
= attr
;
4788 bool wxGrid
::LookupAttr(int row
, int col
, wxGridCellAttr
**attr
) const
4790 if ( row
== m_attrCache
.row
&& col
== m_attrCache
.col
)
4792 *attr
= m_attrCache
.attr
;
4793 (*attr
)->SafeIncRef();
4795 #ifdef DEBUG_ATTR_CACHE
4796 gs_nAttrCacheHits
++;
4803 #ifdef DEBUG_ATTR_CACHE
4804 gs_nAttrCacheMisses
++;
4810 wxGridCellAttr
*wxGrid
::GetCellAttr(int row
, int col
) const
4812 wxGridCellAttr
*attr
;
4813 if ( !LookupAttr(row
, col
, &attr
) )
4815 attr
= m_table ? m_table
->GetAttr(row
, col
) : (wxGridCellAttr
*)NULL
;
4816 CacheAttr(row
, col
, attr
);
4822 wxGridCellAttr
*wxGrid
::GetOrCreateCellAttr(int row
, int col
) const
4824 wxGridCellAttr
*attr
;
4825 if ( !LookupAttr(row
, col
, &attr
) || !attr
)
4827 wxASSERT_MSG( m_table
,
4828 _T("we may only be called if CanHaveAttributes() "
4829 "returned TRUE and then m_table should be !NULL") );
4831 attr
= m_table
->GetAttr(row
, col
);
4834 attr
= new wxGridCellAttr
;
4836 // artificially inc the ref count to match DecRef() in caller
4839 m_table
->SetAttr(attr
, row
, col
);
4842 CacheAttr(row
, col
, attr
);
4848 void wxGrid
::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour
)
4850 if ( CanHaveAttributes() )
4852 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
4853 attr
->SetBackgroundColour(colour
);
4858 void wxGrid
::SetCellTextColour( int row
, int col
, const wxColour
& colour
)
4860 if ( CanHaveAttributes() )
4862 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
4863 attr
->SetTextColour(colour
);
4868 void wxGrid
::SetCellFont( int row
, int col
, const wxFont
& font
)
4870 if ( CanHaveAttributes() )
4872 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
4873 attr
->SetFont(font
);
4878 void wxGrid
::SetCellAlignment( int row
, int col
, int horiz
, int vert
)
4880 if ( CanHaveAttributes() )
4882 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
4883 attr
->SetAlignment(horiz
, vert
);
4888 void wxGrid
::SetCellRenderer(int row
, int col
, wxGridCellRenderer
*renderer
)
4890 if ( CanHaveAttributes() )
4892 wxGridCellAttr
*attr
= GetOrCreateCellAttr(row
, col
);
4893 attr
->SetRenderer(renderer
);
4898 // ----------------------------------------------------------------------------
4900 // ----------------------------------------------------------------------------
4902 void wxGrid
::SetDefaultRowSize( int height
, bool resizeExistingRows
)
4904 m_defaultRowHeight
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT
);
4906 if ( resizeExistingRows
)
4910 for ( row
= 0; row
< m_numRows
; row
++ )
4912 m_rowHeights
[row
] = m_defaultRowHeight
;
4913 bottom
+= m_defaultRowHeight
;
4914 m_rowBottoms
[row
] = bottom
;
4920 void wxGrid
::SetRowSize( int row
, int height
)
4922 wxCHECK_RET( row
>= 0 && row
< m_numRows
, _T("invalid row index") );
4926 int h
= wxMax( 0, height
);
4927 int diff
= h
- m_rowHeights
[row
];
4929 m_rowHeights
[row
] = h
;
4930 for ( i
= row
; i
< m_numRows
; i
++ )
4932 m_rowBottoms
[i
] += diff
;
4937 void wxGrid
::SetDefaultColSize( int width
, bool resizeExistingCols
)
4939 m_defaultColWidth
= wxMax( width
, WXGRID_MIN_COL_WIDTH
);
4941 if ( resizeExistingCols
)
4945 for ( col
= 0; col
< m_numCols
; col
++ )
4947 m_colWidths
[col
] = m_defaultColWidth
;
4948 right
+= m_defaultColWidth
;
4949 m_colRights
[col
] = right
;
4955 void wxGrid
::SetColSize( int col
, int width
)
4957 wxCHECK_RET( col
>= 0 && col
< m_numCols
, _T("invalid column index") );
4961 int w
= wxMax( 0, width
);
4962 int diff
= w
- m_colWidths
[col
];
4963 m_colWidths
[col
] = w
;
4965 for ( i
= col
; i
< m_numCols
; i
++ )
4967 m_colRights
[i
] += diff
;
4974 // ------ cell value accessor functions
4977 void wxGrid
::SetCellValue( int row
, int col
, const wxString
& s
)
4981 m_table
->SetValue( row
, col
, s
.c_str() );
4982 if ( !GetBatchCount() )
4984 wxClientDC
dc( m_gridWin
);
4986 DrawCell( dc
, wxGridCellCoords(row
, col
) );
4989 #if 0 // TODO: edit in place
4991 if ( m_currentCellCoords
.GetRow() == row
&&
4992 m_currentCellCoords
.GetCol() == col
)
4994 SetEditControlValue( s
);
5003 // ------ Block, row and col selection
5006 void wxGrid
::SelectRow( int row
, bool addToSelected
)
5010 if ( IsSelection() && addToSelected
)
5013 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
5016 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
5017 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
5018 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
5019 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
5023 need_refresh
[0] = TRUE
;
5024 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( row
, 0 ),
5025 wxGridCellCoords ( oldTop
- 1,
5027 m_selectedTopLeft
.SetRow( row
);
5032 need_refresh
[1] = TRUE
;
5033 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 0 ),
5034 wxGridCellCoords ( oldBottom
,
5037 m_selectedTopLeft
.SetCol( 0 );
5040 if ( oldBottom
< row
)
5042 need_refresh
[2] = TRUE
;
5043 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1, 0 ),
5044 wxGridCellCoords ( row
,
5046 m_selectedBottomRight
.SetRow( row
);
5049 if ( oldRight
< m_numCols
- 1 )
5051 need_refresh
[3] = TRUE
;
5052 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
5054 wxGridCellCoords ( oldBottom
,
5056 m_selectedBottomRight
.SetCol( m_numCols
- 1 );
5059 for (i
= 0; i
< 4; i
++ )
5060 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
5061 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
5065 r
= SelectionToDeviceRect();
5067 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
5069 m_selectedTopLeft
.Set( row
, 0 );
5070 m_selectedBottomRight
.Set( row
, m_numCols
-1 );
5071 r
= SelectionToDeviceRect();
5072 m_gridWin
->Refresh( FALSE
, &r
);
5075 wxGridRangeSelectEvent
gridEvt( GetId(),
5076 EVT_GRID_RANGE_SELECT
,
5079 m_selectedBottomRight
);
5081 GetEventHandler()->ProcessEvent(gridEvt
);
5085 void wxGrid
::SelectCol( int col
, bool addToSelected
)
5087 if ( IsSelection() && addToSelected
)
5090 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
5093 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
5094 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
5095 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
5096 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
5098 if ( oldLeft
> col
)
5100 need_refresh
[0] = TRUE
;
5101 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col
),
5102 wxGridCellCoords ( m_numRows
- 1,
5104 m_selectedTopLeft
.SetCol( col
);
5109 need_refresh
[1] = TRUE
;
5110 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft
),
5111 wxGridCellCoords ( oldTop
- 1,
5113 m_selectedTopLeft
.SetRow( 0 );
5116 if ( oldRight
< col
)
5118 need_refresh
[2] = TRUE
;
5119 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight
+ 1 ),
5120 wxGridCellCoords ( m_numRows
- 1,
5122 m_selectedBottomRight
.SetCol( col
);
5125 if ( oldBottom
< m_numRows
- 1 )
5127 need_refresh
[3] = TRUE
;
5128 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom
+ 1,
5130 wxGridCellCoords ( m_numRows
- 1,
5132 m_selectedBottomRight
.SetRow( m_numRows
- 1 );
5135 for (i
= 0; i
< 4; i
++ )
5136 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
5137 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
5143 r
= SelectionToDeviceRect();
5145 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( FALSE
, &r
);
5147 m_selectedTopLeft
.Set( 0, col
);
5148 m_selectedBottomRight
.Set( m_numRows
-1, col
);
5149 r
= SelectionToDeviceRect();
5150 m_gridWin
->Refresh( FALSE
, &r
);
5153 wxGridRangeSelectEvent
gridEvt( GetId(),
5154 EVT_GRID_RANGE_SELECT
,
5157 m_selectedBottomRight
);
5159 GetEventHandler()->ProcessEvent(gridEvt
);
5163 void wxGrid
::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol
)
5166 wxGridCellCoords updateTopLeft
, updateBottomRight
;
5168 if ( topRow
> bottomRow
)
5175 if ( leftCol
> rightCol
)
5182 updateTopLeft
= wxGridCellCoords( topRow
, leftCol
);
5183 updateBottomRight
= wxGridCellCoords( bottomRow
, rightCol
);
5185 if ( m_selectedTopLeft
!= updateTopLeft
||
5186 m_selectedBottomRight
!= updateBottomRight
)
5188 // Compute two optimal update rectangles:
5189 // Either one rectangle is a real subset of the
5190 // other, or they are (almost) disjoint!
5192 bool need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE
};
5195 // Store intermediate values
5196 wxCoord oldLeft
= m_selectedTopLeft
.GetCol();
5197 wxCoord oldTop
= m_selectedTopLeft
.GetRow();
5198 wxCoord oldRight
= m_selectedBottomRight
.GetCol();
5199 wxCoord oldBottom
= m_selectedBottomRight
.GetRow();
5201 // Determine the outer/inner coordinates.
5202 if (oldLeft
> leftCol
)
5208 if (oldTop
> topRow
)
5214 if (oldRight
< rightCol
)
5217 oldRight
= rightCol
;
5220 if (oldBottom
< bottomRow
)
5223 oldBottom
= bottomRow
;
5227 // Now, either the stuff marked old is the outer
5228 // rectangle or we don't have a situation where one
5229 // is contained in the other.
5231 if ( oldLeft
< leftCol
)
5233 need_refresh
[0] = TRUE
;
5234 rect
[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
5236 wxGridCellCoords ( oldBottom
,
5240 if ( oldTop
< topRow
)
5242 need_refresh
[1] = TRUE
;
5243 rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
5245 wxGridCellCoords ( topRow
- 1,
5249 if ( oldRight
> rightCol
)
5251 need_refresh
[2] = TRUE
;
5252 rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop
,
5254 wxGridCellCoords ( oldBottom
,
5258 if ( oldBottom
> bottomRow
)
5260 need_refresh
[3] = TRUE
;
5261 rect
[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow
+ 1,
5263 wxGridCellCoords ( oldBottom
,
5269 m_selectedTopLeft
= updateTopLeft
;
5270 m_selectedBottomRight
= updateBottomRight
;
5272 // various Refresh() calls
5273 for (i
= 0; i
< 4; i
++ )
5274 if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect
)
5275 m_gridWin
->Refresh( FALSE
, &(rect
[i
]) );
5278 // only generate an event if the block is not being selected by
5279 // dragging the mouse (in which case the event will be generated in
5280 // the mouse event handler)
5281 if ( !m_isDragging
)
5283 wxGridRangeSelectEvent
gridEvt( GetId(),
5284 EVT_GRID_RANGE_SELECT
,
5287 m_selectedBottomRight
);
5289 GetEventHandler()->ProcessEvent(gridEvt
);
5293 void wxGrid
::SelectAll()
5295 m_selectedTopLeft
.Set( 0, 0 );
5296 m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 );
5298 m_gridWin
->Refresh();
5302 void wxGrid
::ClearSelection()
5304 m_selectedTopLeft
= wxGridNoCellCoords
;
5305 m_selectedBottomRight
= wxGridNoCellCoords
;
5309 // This function returns the rectangle that encloses the given block
5310 // in device coords clipped to the client size of the grid window.
5312 wxRect wxGrid
::BlockToDeviceRect( const wxGridCellCoords
&topLeft
,
5313 const wxGridCellCoords
&bottomRight
)
5315 wxRect
rect( wxGridNoCellRect
);
5318 cellRect
= CellToRect( topLeft
);
5319 if ( cellRect
!= wxGridNoCellRect
)
5325 rect
= wxRect( 0, 0, 0, 0 );
5328 cellRect
= CellToRect( bottomRight
);
5329 if ( cellRect
!= wxGridNoCellRect
)
5335 return wxGridNoCellRect
;
5338 // convert to scrolled coords
5340 int left
, top
, right
, bottom
;
5341 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
5342 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
5345 m_gridWin
->GetClientSize( &cw
, &ch
);
5347 rect
.SetLeft( wxMax(0, left
) );
5348 rect
.SetTop( wxMax(0, top
) );
5349 rect
.SetRight( wxMin(cw
, right
) );
5350 rect
.SetBottom( wxMin(ch
, bottom
) );
5358 // ------ Grid event classes
5361 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent
)
5363 wxGridEvent
::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
5364 int row
, int col
, int x
, int y
,
5365 bool control
, bool shift
, bool alt
, bool meta
)
5366 : wxNotifyEvent( type
, id
)
5372 m_control
= control
;
5377 SetEventObject(obj
);
5381 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent
)
5383 wxGridSizeEvent
::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
5384 int rowOrCol
, int x
, int y
,
5385 bool control
, bool shift
, bool alt
, bool meta
)
5386 : wxNotifyEvent( type
, id
)
5388 m_rowOrCol
= rowOrCol
;
5391 m_control
= control
;
5396 SetEventObject(obj
);
5400 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent
)
5402 wxGridRangeSelectEvent
::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
5403 const wxGridCellCoords
& topLeft
,
5404 const wxGridCellCoords
& bottomRight
,
5405 bool control
, bool shift
, bool alt
, bool meta
)
5406 : wxNotifyEvent( type
, id
)
5408 m_topLeft
= topLeft
;
5409 m_bottomRight
= bottomRight
;
5410 m_control
= control
;
5415 SetEventObject(obj
);
5419 #endif // ifndef wxUSE_NEW_GRID