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"
37 #include "wx/generic/grid.h"
39 //////////////////////////////////////////////////////////////////////
41 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
42 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
44 // this is a magic incantation which must be done!
45 #include "wx/arrimpl.cpp"
47 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
)
50 // TODO: fixed so far - make configurable later (and also different for x/y)
51 static const size_t GRID_SCROLL_LINE
= 10;
53 //////////////////////////////////////////////////////////////////////
55 // Abstract base class for grid data (the model)
57 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
60 wxGridTableBase::wxGridTableBase()
63 m_view
= (wxGrid
*) NULL
;
66 wxGridTableBase::~wxGridTableBase()
71 bool wxGridTableBase::InsertRows( size_t pos
, size_t numRows
)
73 wxLogWarning( wxT("Called grid table class function InsertRows(pos=%d, N=%d)\n"
74 "but your derived table class does not override this function"),
80 bool wxGridTableBase::AppendRows( size_t numRows
)
82 wxLogWarning( wxT("Called grid table class function AppendRows(N=%d)\n"
83 "but your derived table class does not override this function"),
89 bool wxGridTableBase::DeleteRows( size_t pos
, size_t numRows
)
91 wxLogWarning( wxT("Called grid table class function DeleteRows(pos=%d, N=%d)\n"
92 "but your derived table class does not override this function"),
98 bool wxGridTableBase::InsertCols( size_t pos
, size_t numCols
)
100 wxLogWarning( wxT("Called grid table class function InsertCols(pos=%d, N=%d)\n"
101 "but your derived table class does not override this function"),
107 bool wxGridTableBase::AppendCols( size_t numCols
)
109 wxLogWarning( wxT("Called grid table class function AppendCols(N=%d)\n"
110 "but your derived table class does not override this function"),
116 bool wxGridTableBase::DeleteCols( size_t pos
, size_t numCols
)
118 wxLogWarning( wxT("Called grid table class function DeleteCols(pos=%d, N=%d)\n"
119 "but your derived table class does not override this function"),
126 wxString
wxGridTableBase::GetRowLabelValue( int row
)
133 wxString
wxGridTableBase::GetColLabelValue( int col
)
135 // default col labels are:
136 // cols 0 to 25 : A-Z
137 // cols 26 to 675 : AA-ZZ
144 s
+= (_T('A') + (wxChar
)( col%26
));
146 if ( col
< 0 ) break;
149 // reverse the string...
151 for ( i
= 0; i
< n
; i
++ )
161 //////////////////////////////////////////////////////////////////////
163 // Message class for the grid table to send requests and notifications
167 wxGridTableMessage::wxGridTableMessage()
169 m_table
= (wxGridTableBase
*) NULL
;
175 wxGridTableMessage::wxGridTableMessage( wxGridTableBase
*table
, int id
,
176 int commandInt1
, int commandInt2
)
180 m_comInt1
= commandInt1
;
181 m_comInt2
= commandInt2
;
186 //////////////////////////////////////////////////////////////////////
188 // A basic grid table for string data. An object of this class will
189 // created by wxGrid if you don't specify an alternative table class.
192 WX_DEFINE_OBJARRAY(wxGridStringArray
)
194 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
196 wxGridStringTable::wxGridStringTable()
201 wxGridStringTable::wxGridStringTable( int numRows
, int numCols
)
206 m_data
.Alloc( numRows
);
210 for ( col
= 0; col
< numCols
; col
++ )
212 sa
.Add( wxEmptyString
);
215 for ( row
= 0; row
< numRows
; row
++ )
221 wxGridStringTable::~wxGridStringTable()
225 long wxGridStringTable::GetNumberRows()
227 return m_data
.GetCount();
230 long wxGridStringTable::GetNumberCols()
232 if ( m_data
.GetCount() > 0 )
233 return m_data
[0].GetCount();
238 wxString
wxGridStringTable::GetValue( int row
, int col
)
240 // TODO: bounds checking
242 return m_data
[row
][col
];
245 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& s
)
247 // TODO: bounds checking
249 m_data
[row
][col
] = s
;
252 bool wxGridStringTable::IsEmptyCell( int row
, int col
)
254 // TODO: bounds checking
256 return (m_data
[row
][col
] == wxEmptyString
);
260 void wxGridStringTable::Clear()
263 int numRows
, numCols
;
265 numRows
= m_data
.GetCount();
268 numCols
= m_data
[0].GetCount();
270 for ( row
= 0; row
< numRows
; row
++ )
272 for ( col
= 0; col
< numCols
; col
++ )
274 m_data
[row
][col
] = wxEmptyString
;
281 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows
)
285 size_t curNumRows
= m_data
.GetCount();
286 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
288 if ( pos
>= curNumRows
)
290 return AppendRows( numRows
);
294 sa
.Alloc( curNumCols
);
295 for ( col
= 0; col
< curNumCols
; col
++ )
297 sa
.Add( wxEmptyString
);
300 for ( row
= pos
; row
< pos
+ numRows
; row
++ )
302 m_data
.Insert( sa
, row
);
307 wxGridTableMessage
msg( this,
308 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
312 GetView()->ProcessTableMessage( msg
);
318 bool wxGridStringTable::AppendRows( size_t numRows
)
322 size_t curNumRows
= m_data
.GetCount();
323 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
326 if ( curNumCols
> 0 )
328 sa
.Alloc( curNumCols
);
329 for ( col
= 0; col
< curNumCols
; col
++ )
331 sa
.Add( wxEmptyString
);
335 for ( row
= 0; row
< numRows
; row
++ )
342 wxGridTableMessage
msg( this,
343 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
346 GetView()->ProcessTableMessage( msg
);
352 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows
)
356 size_t curNumRows
= m_data
.GetCount();
358 if ( pos
>= curNumRows
)
360 wxLogError( wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)...\n"
361 "Pos value is invalid for present table with %d rows"),
362 pos
, numRows
, curNumRows
);
366 if ( numRows
> curNumRows
- pos
)
368 numRows
= curNumRows
- pos
;
371 if ( numRows
>= curNumRows
)
373 m_data
.Empty(); // don't release memory just yet
377 for ( n
= 0; n
< numRows
; n
++ )
379 m_data
.Remove( pos
);
385 wxGridTableMessage
msg( this,
386 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
390 GetView()->ProcessTableMessage( msg
);
396 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols
)
400 size_t curNumRows
= m_data
.GetCount();
401 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
403 if ( pos
>= curNumCols
)
405 return AppendCols( numCols
);
408 for ( row
= 0; row
< curNumRows
; row
++ )
410 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
412 m_data
[row
].Insert( wxEmptyString
, col
);
418 wxGridTableMessage
msg( this,
419 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
423 GetView()->ProcessTableMessage( msg
);
429 bool wxGridStringTable::AppendCols( size_t numCols
)
433 size_t curNumRows
= m_data
.GetCount();
436 // TODO: something better than this ?
438 wxLogError( wxT("Unable to append cols to a grid table with no rows.\n"
439 "Call AppendRows() first") );
443 for ( row
= 0; row
< curNumRows
; row
++ )
445 for ( n
= 0; n
< numCols
; n
++ )
447 m_data
[row
].Add( wxEmptyString
);
453 wxGridTableMessage
msg( this,
454 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
457 GetView()->ProcessTableMessage( msg
);
463 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols
)
467 size_t curNumRows
= m_data
.GetCount();
468 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
470 if ( pos
>= curNumCols
)
472 wxLogError( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
473 "Pos value is invalid for present table with %d cols"),
474 pos
, numCols
, curNumCols
);
478 if ( numCols
> curNumCols
- pos
)
480 numCols
= curNumCols
- pos
;
483 for ( row
= 0; row
< curNumRows
; row
++ )
485 if ( numCols
>= curNumCols
)
491 for ( n
= 0; n
< numCols
; n
++ )
493 m_data
[row
].Remove( pos
);
500 wxGridTableMessage
msg( this,
501 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
505 GetView()->ProcessTableMessage( msg
);
511 wxString
wxGridStringTable::GetRowLabelValue( int row
)
513 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
515 // using default label
517 return wxGridTableBase::GetRowLabelValue( row
);
521 return m_rowLabels
[ row
];
525 wxString
wxGridStringTable::GetColLabelValue( int col
)
527 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
529 // using default label
531 return wxGridTableBase::GetColLabelValue( col
);
535 return m_colLabels
[ col
];
539 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value
)
541 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
543 int n
= m_rowLabels
.GetCount();
545 for ( i
= n
; i
<= row
; i
++ )
547 m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) );
551 m_rowLabels
[row
] = value
;
554 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value
)
556 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
558 int n
= m_colLabels
.GetCount();
560 for ( i
= n
; i
<= col
; i
++ )
562 m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) );
566 m_colLabels
[col
] = value
;
572 //////////////////////////////////////////////////////////////////////
574 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl
, wxTextCtrl
)
576 BEGIN_EVENT_TABLE( wxGridTextCtrl
, wxTextCtrl
)
577 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown
)
581 wxGridTextCtrl::wxGridTextCtrl( wxWindow
*par
,
585 const wxString
& value
,
589 : wxTextCtrl( par
, id
, value
, pos
, size
, style
)
592 m_isCellControl
= isCellControl
;
596 void wxGridTextCtrl::OnKeyDown( wxKeyEvent
& event
)
598 switch ( event
.KeyCode() )
601 m_grid
->SetEditControlValue( startValue
);
602 SetInsertionPointEnd();
611 if ( m_isCellControl
)
613 // send the event to the parent grid, skipping the
614 // event if nothing happens
616 event
.Skip( m_grid
->ProcessEvent( event
) );
620 // default text control response within the top edit
628 if ( m_isCellControl
)
630 if ( !m_grid
->ProcessEvent( event
) )
633 // wxMotif needs a little extra help...
635 int pos
= GetInsertionPoint();
636 wxString
s( GetValue() );
637 s
= s
.Left(pos
) + "\n" + s
.Mid(pos
);
639 SetInsertionPoint( pos
);
641 // the other ports can handle a Return key press
651 if ( m_isCellControl
)
653 // send the event to the parent grid, skipping the
654 // event if nothing happens
656 event
.Skip( m_grid
->ProcessEvent( event
) );
660 // default text control response within the top edit
672 void wxGridTextCtrl::SetStartValue( const wxString
& s
)
675 wxTextCtrl::SetValue(s
);
680 //////////////////////////////////////////////////////////////////////
682 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow
)
684 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxWindow
)
685 EVT_PAINT( wxGridRowLabelWindow::OnPaint
)
686 EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent
)
687 EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown
)
690 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid
*parent
,
692 const wxPoint
&pos
, const wxSize
&size
)
693 : wxWindow( parent
, id
, pos
, size
)
698 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
&event
)
702 // NO - don't do this because it will set both the x and y origin
703 // coords to match the parent scrolled window and we just want to
704 // set the y coord - MB
706 // m_owner->PrepareDC( dc );
709 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
710 dc
.SetDeviceOrigin( 0, -y
);
712 m_owner
->CalcRowLabelsExposed( GetUpdateRegion() );
713 m_owner
->DrawRowLabels( dc
);
717 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
719 m_owner
->ProcessRowLabelMouseEvent( event
);
723 // This seems to be required for wxMotif otherwise the mouse
724 // cursor must be in the cell edit control to get key events
726 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent
& event
)
728 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
733 //////////////////////////////////////////////////////////////////////
735 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow
)
737 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxWindow
)
738 EVT_PAINT( wxGridColLabelWindow::OnPaint
)
739 EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent
)
740 EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown
)
743 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid
*parent
,
745 const wxPoint
&pos
, const wxSize
&size
)
746 : wxWindow( parent
, id
, pos
, size
)
751 void wxGridColLabelWindow::OnPaint( wxPaintEvent
&event
)
755 // NO - don't do this because it will set both the x and y origin
756 // coords to match the parent scrolled window and we just want to
757 // set the x coord - MB
759 // m_owner->PrepareDC( dc );
762 m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y
);
763 dc
.SetDeviceOrigin( -x
, 0 );
765 m_owner
->CalcColLabelsExposed( GetUpdateRegion() );
766 m_owner
->DrawColLabels( dc
);
770 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
772 m_owner
->ProcessColLabelMouseEvent( event
);
776 // This seems to be required for wxMotif otherwise the mouse
777 // cursor must be in the cell edit control to get key events
779 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent
& event
)
781 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
786 //////////////////////////////////////////////////////////////////////
788 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow
)
790 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxWindow
)
791 EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent
)
792 EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown
)
795 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid
*parent
,
797 const wxPoint
&pos
, const wxSize
&size
)
798 : wxWindow( parent
, id
, pos
, size
, wxRAISED_BORDER
)
804 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event
)
806 m_owner
->ProcessCornerLabelMouseEvent( event
);
810 // This seems to be required for wxMotif otherwise the mouse
811 // cursor must be in the cell edit control to get key events
813 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent
& event
)
815 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
820 //////////////////////////////////////////////////////////////////////
822 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxPanel
)
824 BEGIN_EVENT_TABLE( wxGridWindow
, wxPanel
)
825 EVT_PAINT( wxGridWindow::OnPaint
)
826 EVT_SCROLLWIN( wxGridWindow::ScrollWindow
)
827 EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent
)
828 EVT_KEY_DOWN( wxGridWindow::OnKeyDown
)
831 wxGridWindow::wxGridWindow( wxGrid
*parent
,
832 wxGridRowLabelWindow
*rowLblWin
,
833 wxGridColLabelWindow
*colLblWin
,
834 wxWindowID id
, const wxPoint
&pos
, const wxSize
&size
)
835 : wxPanel( parent
, id
, pos
, size
, wxSUNKEN_BORDER
, "grid window" )
838 m_rowLabelWin
= rowLblWin
;
839 m_colLabelWin
= colLblWin
;
841 SetBackgroundColour( "WHITE" );
845 wxGridWindow::~wxGridWindow()
850 void wxGridWindow::OnPaint( wxPaintEvent
&WXUNUSED(event
) )
852 wxPaintDC
dc( this );
853 m_owner
->PrepareDC( dc
);
855 m_owner
->CalcCellsExposed( GetUpdateRegion() );
856 m_owner
->DrawGridCellArea( dc
);
860 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect
*rect
)
862 wxPanel::ScrollWindow( dx
, dy
, rect
);
863 m_rowLabelWin
->ScrollWindow( 0, dy
, rect
);
864 m_colLabelWin
->ScrollWindow( dx
, 0, rect
);
868 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event
)
870 m_owner
->ProcessGridCellMouseEvent( event
);
874 // This seems to be required for wxMotif otherwise the mouse
875 // cursor must be in the cell edit control to get key events
877 void wxGridWindow::OnKeyDown( wxKeyEvent
& event
)
879 if ( !m_owner
->ProcessEvent( event
) ) event
.Skip();
884 //////////////////////////////////////////////////////////////////////
886 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow
)
888 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow
)
889 EVT_PAINT( wxGrid::OnPaint
)
890 EVT_SIZE( wxGrid::OnSize
)
891 EVT_KEY_DOWN( wxGrid::OnKeyDown
)
894 wxGrid::wxGrid( wxWindow
*parent
,
899 const wxString
& name
)
900 : wxScrolledWindow( parent
, id
, pos
, size
, style
, name
)
913 // ----- internal init and update functions
916 void wxGrid::Create()
918 int colLblH
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
919 int rowLblW
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
921 m_rowLabelWin
= new wxGridRowLabelWindow( this,
924 wxSize(rowLblW
,-1) );
926 m_colLabelWin
= new wxGridColLabelWindow( this,
929 wxSize(-1, colLblH
) );
931 m_cornerLabelWin
= new wxGridCornerLabelWindow( this,
934 wxSize(rowLblW
, colLblH
) );
936 m_gridWin
= new wxGridWindow( this,
943 SetTargetWindow( m_gridWin
);
945 m_mainSizer
= new wxBoxSizer( wxVERTICAL
);
947 m_topSizer
= new wxBoxSizer( wxHORIZONTAL
);
948 m_topSizer
->Add( m_cornerLabelWin
, 0 );
949 m_topSizer
->Add( m_colLabelWin
, 1 );
951 m_mainSizer
->Add( m_topSizer
, 0, wxEXPAND
);
953 m_middleSizer
= new wxBoxSizer( wxHORIZONTAL
);
954 m_middleSizer
->Add( m_rowLabelWin
, 0, wxEXPAND
);
955 m_middleSizer
->Add( m_gridWin
, 1, wxEXPAND
);
957 m_mainSizer
->Add( m_middleSizer
, 1, wxEXPAND
);
959 SetAutoLayout( TRUE
);
960 SetSizer( m_mainSizer
);
964 bool wxGrid::CreateGrid( int numRows
, int numCols
)
968 wxLogError( wxT("wxGrid::CreateGrid(numRows, numCols) called more than once") );
976 m_table
= new wxGridStringTable( m_numRows
, m_numCols
);
977 m_table
->SetView( this );
990 if ( m_numRows
<= 0 )
991 m_numRows
= WXGRID_DEFAULT_NUMBER_ROWS
;
993 if ( m_numCols
<= 0 )
994 m_numCols
= WXGRID_DEFAULT_NUMBER_COLS
;
996 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
997 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
1001 m_labelBackgroundColour
= m_rowLabelWin
->GetBackgroundColour();
1005 m_labelBackgroundColour
= wxColour( _T("WHITE") );
1008 m_labelTextColour
= wxColour( _T("BLACK") );
1010 // TODO: something better than this ?
1012 m_labelFont
= this->GetFont();
1013 m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 );
1015 m_rowLabelHorizAlign
= wxLEFT
;
1016 m_rowLabelVertAlign
= wxCENTRE
;
1018 m_colLabelHorizAlign
= wxCENTRE
;
1019 m_colLabelVertAlign
= wxTOP
;
1021 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
1022 m_defaultRowHeight
= m_gridWin
->GetCharHeight();
1024 #if defined (__WXMOTIF__) // see also text ctrl sizing in ShowCellEditControl()
1025 m_defaultRowHeight
+= 8;
1027 m_defaultRowHeight
+= 4;
1030 m_rowHeights
.Alloc( m_numRows
);
1031 m_rowBottoms
.Alloc( m_numRows
);
1033 for ( i
= 0; i
< m_numRows
; i
++ )
1035 m_rowHeights
.Add( m_defaultRowHeight
);
1036 rowBottom
+= m_defaultRowHeight
;
1037 m_rowBottoms
.Add( rowBottom
);
1040 m_colWidths
.Alloc( m_numCols
);
1041 m_colRights
.Alloc( m_numCols
);
1043 for ( i
= 0; i
< m_numCols
; i
++ )
1045 m_colWidths
.Add( m_defaultColWidth
);
1046 colRight
+= m_defaultColWidth
;
1047 m_colRights
.Add( colRight
);
1050 // TODO: improve this ?
1052 m_defaultCellFont
= this->GetFont();
1054 m_gridLineColour
= wxColour( 128, 128, 255 );
1055 m_gridLinesEnabled
= TRUE
;
1057 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1059 m_dragRowOrCol
= -1;
1060 m_isDragging
= FALSE
;
1062 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
1063 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
1065 m_currentCellCoords
= wxGridNoCellCoords
;
1067 m_selectedTopLeft
= wxGridNoCellCoords
;
1068 m_selectedBottomRight
= wxGridNoCellCoords
;
1070 m_editable
= TRUE
; // default for whole grid
1072 m_inOnKeyDown
= FALSE
;
1075 // TODO: extend this to other types of controls
1077 m_cellEditCtrl
= new wxGridTextCtrl( m_gridWin
,
1085 , wxTE_MULTILINE
| wxTE_NO_VSCROLL
1089 m_cellEditCtrl
->Show( FALSE
);
1090 m_cellEditCtrlEnabled
= TRUE
;
1091 m_editCtrlType
= wxGRID_TEXTCTRL
;
1095 void wxGrid::CalcDimensions()
1098 GetClientSize( &cw
, &ch
);
1100 if ( m_numRows
> 0 && m_numCols
> 0 )
1102 int right
= m_colRights
[ m_numCols
-1 ] + 20;
1103 int bottom
= m_rowBottoms
[ m_numRows
-1 ] + 20;
1105 // TODO: restore the scroll position that we had before sizing
1108 GetViewStart( &x
, &y
);
1109 SetScrollbars( GRID_SCROLL_LINE
, GRID_SCROLL_LINE
,
1110 right
/GRID_SCROLL_LINE
, bottom
/GRID_SCROLL_LINE
,
1116 // this is called when the grid table sends a message to say that it
1117 // has been redimensioned
1119 bool wxGrid::Redimension( wxGridTableMessage
& msg
)
1123 switch ( msg
.GetId() )
1125 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
1127 size_t pos
= msg
.GetCommandInt();
1128 int numRows
= msg
.GetCommandInt2();
1129 for ( i
= 0; i
< numRows
; i
++ )
1131 m_rowHeights
.Insert( m_defaultRowHeight
, pos
);
1132 m_rowBottoms
.Insert( 0, pos
);
1134 m_numRows
+= numRows
;
1137 if ( pos
> 0 ) bottom
= m_rowBottoms
[pos
-1];
1139 for ( i
= pos
; i
< m_numRows
; i
++ )
1141 bottom
+= m_rowHeights
[i
];
1142 m_rowBottoms
[i
] = bottom
;
1148 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
1150 int numRows
= msg
.GetCommandInt();
1151 for ( i
= 0; i
< numRows
; i
++ )
1153 m_rowHeights
.Add( m_defaultRowHeight
);
1154 m_rowBottoms
.Add( 0 );
1157 int oldNumRows
= m_numRows
;
1158 m_numRows
+= numRows
;
1161 if ( oldNumRows
> 0 ) bottom
= m_rowBottoms
[oldNumRows
-1];
1163 for ( i
= oldNumRows
; i
< m_numRows
; i
++ )
1165 bottom
+= m_rowHeights
[i
];
1166 m_rowBottoms
[i
] = bottom
;
1172 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
1174 size_t pos
= msg
.GetCommandInt();
1175 int numRows
= msg
.GetCommandInt2();
1176 for ( i
= 0; i
< numRows
; i
++ )
1178 m_rowHeights
.Remove( pos
);
1179 m_rowBottoms
.Remove( pos
);
1181 m_numRows
-= numRows
;
1186 m_colWidths
.Clear();
1187 m_colRights
.Clear();
1188 m_currentCellCoords
= wxGridNoCellCoords
;
1192 if ( m_currentCellCoords
.GetRow() >= m_numRows
)
1193 m_currentCellCoords
.Set( 0, 0 );
1196 for ( i
= 0; i
< m_numRows
; i
++ )
1198 h
+= m_rowHeights
[i
];
1199 m_rowBottoms
[i
] = h
;
1207 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
1209 size_t pos
= msg
.GetCommandInt();
1210 int numCols
= msg
.GetCommandInt2();
1211 for ( i
= 0; i
< numCols
; i
++ )
1213 m_colWidths
.Insert( m_defaultColWidth
, pos
);
1214 m_colRights
.Insert( 0, pos
);
1216 m_numCols
+= numCols
;
1219 if ( pos
> 0 ) right
= m_colRights
[pos
-1];
1221 for ( i
= pos
; i
< m_numCols
; i
++ )
1223 right
+= m_colWidths
[i
];
1224 m_colRights
[i
] = right
;
1230 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
1232 int numCols
= msg
.GetCommandInt();
1233 for ( i
= 0; i
< numCols
; i
++ )
1235 m_colWidths
.Add( m_defaultColWidth
);
1236 m_colRights
.Add( 0 );
1239 int oldNumCols
= m_numCols
;
1240 m_numCols
+= numCols
;
1243 if ( oldNumCols
> 0 ) right
= m_colRights
[oldNumCols
-1];
1245 for ( i
= oldNumCols
; i
< m_numCols
; i
++ )
1247 right
+= m_colWidths
[i
];
1248 m_colRights
[i
] = right
;
1254 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
1256 size_t pos
= msg
.GetCommandInt();
1257 int numCols
= msg
.GetCommandInt2();
1258 for ( i
= 0; i
< numCols
; i
++ )
1260 m_colWidths
.Remove( pos
);
1261 m_colRights
.Remove( pos
);
1263 m_numCols
-= numCols
;
1267 #if 0 // leave the row alone here so that AppendCols will work subsequently
1269 m_rowHeights
.Clear();
1270 m_rowBottoms
.Clear();
1272 m_currentCellCoords
= wxGridNoCellCoords
;
1276 if ( m_currentCellCoords
.GetCol() >= m_numCols
)
1277 m_currentCellCoords
.Set( 0, 0 );
1280 for ( i
= 0; i
< m_numCols
; i
++ )
1282 w
+= m_colWidths
[i
];
1295 void wxGrid::CalcRowLabelsExposed( wxRegion
& reg
)
1297 wxRegionIterator
iter( reg
);
1300 m_rowLabelsExposed
.Empty();
1307 // TODO: remove this when we can...
1308 // There is a bug in wxMotif that gives garbage update
1309 // rectangles if you jump-scroll a long way by clicking the
1310 // scrollbar with middle button. This is a work-around
1312 #if defined(__WXMOTIF__)
1314 m_gridWin
->GetClientSize( &cw
, &ch
);
1315 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1316 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1319 // logical bounds of update region
1322 CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top
);
1323 CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom
);
1325 // find the row labels within these bounds
1329 for ( row
= 0; row
< m_numRows
; row
++ )
1331 if ( m_rowBottoms
[row
] < top
) continue;
1333 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1334 if ( rowTop
> bottom
) break;
1336 m_rowLabelsExposed
.Add( row
);
1344 void wxGrid::CalcColLabelsExposed( wxRegion
& reg
)
1346 wxRegionIterator
iter( reg
);
1349 m_colLabelsExposed
.Empty();
1356 // TODO: remove this when we can...
1357 // There is a bug in wxMotif that gives garbage update
1358 // rectangles if you jump-scroll a long way by clicking the
1359 // scrollbar with middle button. This is a work-around
1361 #if defined(__WXMOTIF__)
1363 m_gridWin
->GetClientSize( &cw
, &ch
);
1364 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1365 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1368 // logical bounds of update region
1371 CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy
);
1372 CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy
);
1374 // find the cells within these bounds
1378 for ( col
= 0; col
< m_numCols
; col
++ )
1380 if ( m_colRights
[col
] < left
) continue;
1382 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1383 if ( colLeft
> right
) break;
1385 m_colLabelsExposed
.Add( col
);
1393 void wxGrid::CalcCellsExposed( wxRegion
& reg
)
1395 wxRegionIterator
iter( reg
);
1398 m_cellsExposed
.Empty();
1399 m_rowsExposed
.Empty();
1400 m_colsExposed
.Empty();
1402 int left
, top
, right
, bottom
;
1407 // TODO: remove this when we can...
1408 // There is a bug in wxMotif that gives garbage update
1409 // rectangles if you jump-scroll a long way by clicking the
1410 // scrollbar with middle button. This is a work-around
1412 #if defined(__WXMOTIF__)
1414 m_gridWin
->GetClientSize( &cw
, &ch
);
1415 if ( r
.GetTop() > ch
) r
.SetTop( 0 );
1416 if ( r
.GetLeft() > cw
) r
.SetLeft( 0 );
1417 r
.SetRight( wxMin( r
.GetRight(), cw
) );
1418 r
.SetBottom( wxMin( r
.GetBottom(), ch
) );
1421 // logical bounds of update region
1423 CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
1424 CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
1426 // find the cells within these bounds
1429 int colLeft
, rowTop
;
1430 for ( row
= 0; row
< m_numRows
; row
++ )
1432 if ( m_rowBottoms
[row
] < top
) continue;
1434 rowTop
= m_rowBottoms
[row
] - m_rowHeights
[row
];
1435 if ( rowTop
> bottom
) break;
1437 m_rowsExposed
.Add( row
);
1439 for ( col
= 0; col
< m_numCols
; col
++ )
1441 if ( m_colRights
[col
] < left
) continue;
1443 colLeft
= m_colRights
[col
] - m_colWidths
[col
];
1444 if ( colLeft
> right
) break;
1446 if ( m_colsExposed
.Index( col
) == wxNOT_FOUND
) m_colsExposed
.Add( col
);
1447 m_cellsExposed
.Add( wxGridCellCoords( row
, col
) );
1456 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event
)
1459 wxPoint
pos( event
.GetPosition() );
1460 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1462 if ( event
.Dragging() )
1464 m_isDragging
= TRUE
;
1466 if ( event
.LeftIsDown() )
1468 switch( m_cursorMode
)
1470 case WXGRID_CURSOR_RESIZE_ROW
:
1472 int cw
, ch
, left
, dummy
;
1473 m_gridWin
->GetClientSize( &cw
, &ch
);
1474 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
1476 wxClientDC
dc( m_gridWin
);
1478 dc
.SetPen(*wxRED_PEN
); // FIXME should be bg col dependent
1479 dc
.SetLogicalFunction(wxXOR
);
1480 if ( m_dragLastPos
>= 0 )
1482 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
1484 dc
.DrawLine( left
, y
, left
+cw
, y
);
1489 case WXGRID_CURSOR_SELECT_ROW
:
1491 if ( (row
= YToRow( y
)) >= 0 &&
1492 !IsInSelection( row
, 0 ) )
1494 SelectRow( row
, TRUE
);
1503 m_isDragging
= FALSE
;
1506 // ------------ Left button pressed
1508 if ( event
.LeftDown() )
1510 // don't send a label click event for a hit on the
1511 // edge of the row label - this is probably the user
1512 // wanting to resize the row
1514 if ( YToEdgeOfRow(y
) < 0 )
1518 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event
) )
1520 SelectRow( row
, event
.ShiftDown() );
1521 m_cursorMode
= WXGRID_CURSOR_SELECT_ROW
;
1526 // starting to drag-resize a row
1528 m_rowLabelWin
->CaptureMouse();
1533 // ------------ Left double click
1535 else if (event
.LeftDClick() )
1537 if ( YToEdgeOfRow(y
) < 0 )
1540 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event
);
1545 // ------------ Left button released
1547 else if ( event
.LeftUp() )
1549 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_ROW
)
1551 m_rowLabelWin
->ReleaseMouse();
1553 if ( m_dragLastPos
>= 0 )
1555 // erase the last line and resize the row
1557 int cw
, ch
, left
, dummy
;
1558 m_gridWin
->GetClientSize( &cw
, &ch
);
1559 CalcUnscrolledPosition( 0, 0, &left
, &dummy
);
1561 wxClientDC
dc( m_gridWin
);
1563 dc
.SetLogicalFunction( wxINVERT
);
1564 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos
);
1565 HideCellEditControl();
1567 int rowTop
= m_rowBottoms
[m_dragRowOrCol
] - m_rowHeights
[m_dragRowOrCol
];
1568 SetRowSize( m_dragRowOrCol
, wxMax( y
- rowTop
, WXGRID_MIN_ROW_HEIGHT
) );
1569 if ( !GetBatchCount() )
1571 // TODO: optimize this
1572 m_rowLabelWin
->Refresh();
1573 m_gridWin
->Refresh();
1576 ShowCellEditControl();
1578 // Note: we are ending the event *after* doing
1579 // default processing in this case
1581 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
);
1589 // ------------ Right button down
1591 else if ( event
.RightDown() )
1594 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event
) )
1596 // no default action at the moment
1601 // ------------ Right double click
1603 else if ( event
.RightDClick() )
1606 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event
) )
1608 // no default action at the moment
1613 // ------------ No buttons down and mouse moving
1615 else if ( event
.Moving() )
1617 m_dragRowOrCol
= YToEdgeOfRow( y
);
1618 if ( m_dragRowOrCol
>= 0 )
1620 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1622 m_cursorMode
= WXGRID_CURSOR_RESIZE_ROW
;
1623 m_rowLabelWin
->SetCursor( m_rowResizeCursor
);
1628 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1630 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1631 m_rowLabelWin
->SetCursor( *wxSTANDARD_CURSOR
);
1638 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event
)
1641 wxPoint
pos( event
.GetPosition() );
1642 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1644 if ( event
.Dragging() )
1646 m_isDragging
= TRUE
;
1648 if ( event
.LeftIsDown() )
1650 switch( m_cursorMode
)
1652 case WXGRID_CURSOR_RESIZE_COL
:
1654 int cw
, ch
, dummy
, top
;
1655 m_gridWin
->GetClientSize( &cw
, &ch
);
1656 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
1658 wxClientDC
dc( m_gridWin
);
1660 dc
.SetPen(*wxRED_PEN
); // FIXME should be bg col dependent
1661 dc
.SetLogicalFunction(wxXOR
);
1662 if ( m_dragLastPos
>= 0 )
1664 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
1666 dc
.DrawLine( x
, top
, x
, top
+ch
);
1671 case WXGRID_CURSOR_SELECT_COL
:
1673 if ( (col
= XToCol( x
)) >= 0 &&
1674 !IsInSelection( 0, col
) )
1676 SelectCol( col
, TRUE
);
1685 m_isDragging
= FALSE
;
1688 // ------------ Left button pressed
1690 if ( event
.LeftDown() )
1692 // don't send a label click event for a hit on the
1693 // edge of the col label - this is probably the user
1694 // wanting to resize the col
1696 if ( XToEdgeOfCol(x
) < 0 )
1700 !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event
) )
1702 SelectCol( col
, event
.ShiftDown() );
1703 m_cursorMode
= WXGRID_CURSOR_SELECT_COL
;
1708 // starting to drag-resize a col
1710 m_colLabelWin
->CaptureMouse();
1715 // ------------ Left double click
1717 if ( event
.LeftDClick() )
1719 if ( XToEdgeOfCol(x
) < 0 )
1722 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event
);
1727 // ------------ Left button released
1729 else if ( event
.LeftUp() )
1731 if ( m_cursorMode
== WXGRID_CURSOR_RESIZE_COL
)
1733 m_colLabelWin
->ReleaseMouse();
1735 if ( m_dragLastPos
>= 0 )
1737 // erase the last line and resize the col
1739 int cw
, ch
, dummy
, top
;
1740 m_gridWin
->GetClientSize( &cw
, &ch
);
1741 CalcUnscrolledPosition( 0, 0, &dummy
, &top
);
1743 wxClientDC
dc( m_gridWin
);
1745 dc
.SetLogicalFunction( wxINVERT
);
1746 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch
);
1747 HideCellEditControl();
1749 int colLeft
= m_colRights
[m_dragRowOrCol
] - m_colWidths
[m_dragRowOrCol
];
1750 SetColSize( m_dragRowOrCol
, wxMax( x
- colLeft
, WXGRID_MIN_COL_WIDTH
) );
1752 if ( !GetBatchCount() )
1754 // TODO: optimize this
1755 m_colLabelWin
->Refresh();
1756 m_gridWin
->Refresh();
1759 ShowCellEditControl();
1761 // Note: we are ending the event *after* doing
1762 // default processing in this case
1764 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
);
1772 // ------------ Right button down
1774 else if ( event
.RightDown() )
1777 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event
) )
1779 // no default action at the moment
1784 // ------------ Right double click
1786 else if ( event
.RightDClick() )
1789 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event
) )
1791 // no default action at the moment
1796 // ------------ No buttons down and mouse moving
1798 else if ( event
.Moving() )
1800 m_dragRowOrCol
= XToEdgeOfCol( x
);
1801 if ( m_dragRowOrCol
>= 0 )
1803 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1805 m_cursorMode
= WXGRID_CURSOR_RESIZE_COL
;
1806 m_colLabelWin
->SetCursor( m_colResizeCursor
);
1811 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1813 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1814 m_colLabelWin
->SetCursor( *wxSTANDARD_CURSOR
);
1821 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event
)
1823 if ( event
.LeftDown() )
1825 // indicate corner label by having both row and
1828 if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event
) )
1834 else if ( event
.LeftDClick() )
1836 SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event
);
1839 else if ( event
.RightDown() )
1841 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event
) )
1843 // no default action at the moment
1847 else if ( event
.RightDClick() )
1849 if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event
) )
1851 // no default action at the moment
1857 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent
& event
)
1860 wxPoint
pos( event
.GetPosition() );
1861 CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y
);
1863 wxGridCellCoords coords
;
1864 XYToCell( x
, y
, coords
);
1866 if ( event
.Dragging() )
1868 m_isDragging
= TRUE
;
1869 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1871 // Hide the edit control, so it
1872 // won't interfer with drag-shrinking.
1873 if ( IsCellEditControlEnabled() )
1874 HideCellEditControl();
1875 if ( coords
!= wxGridNoCellCoords
)
1877 if ( !IsSelection() )
1879 SelectBlock( coords
, coords
);
1883 SelectBlock( m_currentCellCoords
, coords
);
1891 m_isDragging
= FALSE
;
1893 if ( coords
!= wxGridNoCellCoords
)
1895 if ( event
.LeftDown() )
1897 if ( event
.ShiftDown() )
1899 SelectBlock( m_currentCellCoords
, coords
);
1903 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK
,
1908 MakeCellVisible( coords
);
1909 SetCurrentCell( coords
);
1915 // ------------ Left double click
1917 else if ( event
.LeftDClick() )
1919 SendEvent( EVT_GRID_CELL_LEFT_DCLICK
,
1926 // ------------ Left button released
1928 else if ( event
.LeftUp() )
1930 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1932 if ( IsSelection() )
1934 SendEvent( EVT_GRID_RANGE_SELECT
, -1, -1, event
);
1938 // Show the edit control, if it has
1939 // been hidden for drag-shrinking.
1940 if ( IsCellEditControlEnabled() )
1941 ShowCellEditControl();
1947 // ------------ Right button down
1949 else if ( event
.RightDown() )
1951 if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK
,
1956 // no default action at the moment
1961 // ------------ Right double click
1963 else if ( event
.RightDClick() )
1965 if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK
,
1970 // no default action at the moment
1978 // ------ interaction with data model
1980 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg
)
1982 switch ( msg
.GetId() )
1984 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
1985 return GetModelValues();
1987 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
1988 return SetModelValues();
1990 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
1991 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
1992 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
1993 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
1994 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
1995 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
1996 return Redimension( msg
);
2005 // The behaviour of this function depends on the grid table class
2006 // Clear() function. For the default wxGridStringTable class the
2007 // behavious is to replace all cell contents with wxEmptyString but
2008 // not to change the number of rows or cols.
2010 void wxGrid::ClearGrid()
2015 SetEditControlValue();
2016 if ( !GetBatchCount() ) m_gridWin
->Refresh();
2021 bool wxGrid::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2023 // TODO: something with updateLabels flag
2027 wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
2033 bool ok
= m_table
->InsertRows( pos
, numRows
);
2035 // the table will have sent the results of the insert row
2036 // operation to this view object as a grid table message
2040 if ( m_numCols
== 0 )
2042 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS
);
2044 // TODO: perhaps instead of appending the default number of cols
2045 // we should remember what the last non-zero number of cols was ?
2049 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2051 // if we have just inserted cols into an empty grid the current
2052 // cell will be undefined...
2054 SetCurrentCell( 0, 0 );
2058 if ( !GetBatchCount() ) Refresh();
2061 SetEditControlValue();
2071 bool wxGrid::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) )
2073 // TODO: something with updateLabels flag
2077 wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
2081 if ( m_table
&& m_table
->AppendRows( numRows
) )
2083 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2085 // if we have just inserted cols into an empty grid the current
2086 // cell will be undefined...
2088 SetCurrentCell( 0, 0 );
2091 // the table will have sent the results of the append row
2092 // operation to this view object as a grid table message
2095 if ( !GetBatchCount() ) Refresh();
2105 bool wxGrid::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
2107 // TODO: something with updateLabels flag
2111 wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
2115 if ( m_table
&& m_table
->DeleteRows( pos
, numRows
) )
2117 // the table will have sent the results of the delete row
2118 // operation to this view object as a grid table message
2120 if ( m_numRows
> 0 )
2121 SetEditControlValue();
2123 HideCellEditControl();
2126 if ( !GetBatchCount() ) Refresh();
2136 bool wxGrid::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2138 // TODO: something with updateLabels flag
2142 wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
2148 HideCellEditControl();
2149 bool ok
= m_table
->InsertCols( pos
, numCols
);
2151 // the table will have sent the results of the insert col
2152 // operation to this view object as a grid table message
2156 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2158 // if we have just inserted cols into an empty grid the current
2159 // cell will be undefined...
2161 SetCurrentCell( 0, 0 );
2165 if ( !GetBatchCount() ) Refresh();
2168 SetEditControlValue();
2178 bool wxGrid::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) )
2180 // TODO: something with updateLabels flag
2184 wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
2188 if ( m_table
&& m_table
->AppendCols( numCols
) )
2190 // the table will have sent the results of the append col
2191 // operation to this view object as a grid table message
2193 if ( m_currentCellCoords
== wxGridNoCellCoords
)
2195 // if we have just inserted cols into an empty grid the current
2196 // cell will be undefined...
2198 SetCurrentCell( 0, 0 );
2202 if ( !GetBatchCount() ) Refresh();
2212 bool wxGrid::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
2214 // TODO: something with updateLabels flag
2218 wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
2222 if ( m_table
&& m_table
->DeleteCols( pos
, numCols
) )
2224 // the table will have sent the results of the delete col
2225 // operation to this view object as a grid table message
2227 if ( m_numCols
> 0 )
2228 SetEditControlValue();
2230 HideCellEditControl();
2233 if ( !GetBatchCount() ) Refresh();
2245 // ----- event handlers
2248 // Generate a grid event based on a mouse event and
2249 // return the result of ProcessEvent()
2251 bool wxGrid::SendEvent( const wxEventType type
,
2253 wxMouseEvent
& mouseEv
)
2255 if ( type
== EVT_GRID_ROW_SIZE
||
2256 type
== EVT_GRID_COL_SIZE
)
2258 int rowOrCol
= (row
== -1 ? col
: row
);
2260 wxGridSizeEvent
gridEvt( GetId(),
2264 mouseEv
.GetX(), mouseEv
.GetY(),
2265 mouseEv
.ControlDown(),
2266 mouseEv
.ShiftDown(),
2268 mouseEv
.MetaDown() );
2270 return GetEventHandler()->ProcessEvent(gridEvt
);
2272 else if ( type
== EVT_GRID_RANGE_SELECT
)
2274 wxGridRangeSelectEvent
gridEvt( GetId(),
2278 m_selectedBottomRight
,
2279 mouseEv
.ControlDown(),
2280 mouseEv
.ShiftDown(),
2282 mouseEv
.MetaDown() );
2284 return GetEventHandler()->ProcessEvent(gridEvt
);
2288 wxGridEvent
gridEvt( GetId(),
2292 mouseEv
.GetX(), mouseEv
.GetY(),
2293 mouseEv
.ControlDown(),
2294 mouseEv
.ShiftDown(),
2296 mouseEv
.MetaDown() );
2298 return GetEventHandler()->ProcessEvent(gridEvt
);
2303 // Generate a grid event of specified type and return the result
2304 // of ProcessEvent().
2306 bool wxGrid::SendEvent( const wxEventType type
,
2309 if ( type
== EVT_GRID_ROW_SIZE
||
2310 type
== EVT_GRID_COL_SIZE
)
2312 int rowOrCol
= (row
== -1 ? col
: row
);
2314 wxGridSizeEvent
gridEvt( GetId(),
2319 return GetEventHandler()->ProcessEvent(gridEvt
);
2323 wxGridEvent
gridEvt( GetId(),
2328 return GetEventHandler()->ProcessEvent(gridEvt
);
2333 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
2335 wxPaintDC
dc( this );
2337 if ( m_currentCellCoords
== wxGridNoCellCoords
&&
2338 m_numRows
&& m_numCols
)
2340 m_currentCellCoords
.Set(0, 0);
2341 SetEditControlValue();
2342 ShowCellEditControl();
2347 // This is just here to make sure that CalcDimensions gets called when
2348 // the grid view is resized... then the size event is skipped to allow
2349 // the box sizers to handle everything
2351 void wxGrid::OnSize( wxSizeEvent
& event
)
2358 void wxGrid::OnKeyDown( wxKeyEvent
& event
)
2360 if ( m_inOnKeyDown
)
2362 // shouldn't be here - we are going round in circles...
2364 wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") );
2367 m_inOnKeyDown
= TRUE
;
2369 // propagate the event up and see if it gets processed
2371 wxWindow
*parent
= GetParent();
2372 wxKeyEvent
keyEvt( event
);
2373 keyEvt
.SetEventObject( parent
);
2375 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
2377 // try local handlers
2379 switch ( event
.KeyCode() )
2382 if ( event
.ControlDown() )
2384 MoveCursorUpBlock();
2393 if ( event
.ControlDown() )
2395 MoveCursorDownBlock();
2404 if ( event
.ControlDown() )
2406 MoveCursorLeftBlock();
2415 if ( event
.ControlDown() )
2417 MoveCursorRightBlock();
2426 if ( event
.ControlDown() )
2428 event
.Skip(); // to let the edit control have the return
2437 if ( event
.ControlDown() )
2439 MakeCellVisible( 0, 0 );
2440 SetCurrentCell( 0, 0 );
2449 if ( event
.ControlDown() )
2451 MakeCellVisible( m_numRows
-1, m_numCols
-1 );
2452 SetCurrentCell( m_numRows
-1, m_numCols
-1 );
2469 // now try the cell edit control
2471 if ( IsCellEditControlEnabled() )
2473 event
.SetEventObject( m_cellEditCtrl
);
2474 m_cellEditCtrl
->GetEventHandler()->ProcessEvent( event
);
2480 m_inOnKeyDown
= FALSE
;
2484 void wxGrid::SetCurrentCell( const wxGridCellCoords
& coords
)
2486 if ( SendEvent( EVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) )
2488 // the event has been intercepted - do nothing
2492 wxClientDC
dc( m_gridWin
);
2495 if ( m_currentCellCoords
!= wxGridNoCellCoords
)
2497 HideCellEditControl();
2498 SaveEditControlValue();
2501 m_currentCellCoords
= coords
;
2503 SetEditControlValue();
2504 ShowCellEditControl();
2506 if ( IsSelection() )
2508 wxRect
r( SelectionToDeviceRect() );
2510 if ( !GetBatchCount() ) m_gridWin
->Refresh( TRUE
, &r
);
2516 // ------ functions to get/send data (see also public functions)
2519 bool wxGrid::GetModelValues()
2523 // all we need to do is repaint the grid
2525 m_gridWin
->Refresh();
2533 bool wxGrid::SetModelValues()
2539 for ( row
= 0; row
< m_numRows
; row
++ )
2541 for ( col
= 0; col
< m_numCols
; col
++ )
2543 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
2555 // Note - this function only draws cells that are in the list of
2556 // exposed cells (usually set from the update region by
2557 // CalcExposedCells)
2559 void wxGrid::DrawGridCellArea( wxDC
& dc
)
2561 if ( !m_numRows
|| !m_numCols
) return;
2564 size_t numCells
= m_cellsExposed
.GetCount();
2566 for ( i
= 0; i
< numCells
; i
++ )
2568 DrawCell( dc
, m_cellsExposed
[i
] );
2573 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords
)
2575 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2576 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2578 if ( m_gridLinesEnabled
)
2579 DrawCellBorder( dc
, coords
);
2581 DrawCellBackground( dc
, coords
);
2583 // TODO: separate functions here for different kinds of cells ?
2586 DrawCellValue( dc
, coords
);
2590 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords
)
2592 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2593 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2595 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
2596 int row
= coords
.GetRow();
2597 int col
= coords
.GetCol();
2599 // right hand border
2601 dc
.DrawLine( m_colRights
[col
], m_rowBottoms
[row
] - m_rowHeights
[row
],
2602 m_colRights
[col
], m_rowBottoms
[row
] );
2606 dc
.DrawLine( m_colRights
[col
] - m_colWidths
[col
], m_rowBottoms
[row
],
2607 m_colRights
[col
], m_rowBottoms
[row
] );
2611 void wxGrid::DrawCellBackground( wxDC
& dc
, const wxGridCellCoords
& coords
)
2613 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2614 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2616 int row
= coords
.GetRow();
2617 int col
= coords
.GetCol();
2619 dc
.SetBackgroundMode( wxSOLID
);
2621 if ( IsInSelection( coords
) )
2623 // TODO: improve this
2625 dc
.SetBrush( *wxBLACK_BRUSH
);
2629 dc
.SetBrush( wxBrush(GetCellBackgroundColour(row
, col
), wxSOLID
) );
2632 dc
.SetPen( *wxTRANSPARENT_PEN
);
2634 dc
.DrawRectangle( m_colRights
[col
] - m_colWidths
[col
] + 1,
2635 m_rowBottoms
[row
] - m_rowHeights
[row
] + 1,
2637 m_rowHeights
[row
]-1 );
2641 void wxGrid::DrawCellValue( wxDC
& dc
, const wxGridCellCoords
& coords
)
2643 if ( m_colWidths
[coords
.GetCol()] <=0 ||
2644 m_rowHeights
[coords
.GetRow()] <= 0 ) return;
2646 int row
= coords
.GetRow();
2647 int col
= coords
.GetCol();
2649 dc
.SetBackgroundMode( wxTRANSPARENT
);
2651 if ( IsInSelection( row
, col
) )
2653 // TODO: improve this
2655 dc
.SetTextBackground( wxColour(0, 0, 0) );
2656 dc
.SetTextForeground( wxColour(255, 255, 255) );
2660 dc
.SetTextBackground( GetCellBackgroundColour(row
, col
) );
2661 dc
.SetTextForeground( GetCellTextColour(row
, col
) );
2663 dc
.SetFont( GetCellFont(row
, col
) );
2666 GetCellAlignment( row
, col
, &hAlign
, &vAlign
);
2669 rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 );
2670 rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 );
2671 rect
.SetWidth( m_colWidths
[col
] - 4 );
2672 rect
.SetHeight( m_rowHeights
[row
] - 4 );
2674 DrawTextRectangle( dc
, GetCellValue( row
, col
), rect
, hAlign
, vAlign
);
2679 // TODO: remove this ???
2680 // This is used to redraw all grid lines e.g. when the grid line colour
2683 void wxGrid::DrawAllGridLines( wxDC
& dc
)
2685 if ( !m_gridLinesEnabled
||
2687 !m_numCols
) return;
2690 m_gridWin
->GetClientSize(&cw
, &ch
);
2692 // virtual coords of visible area
2694 int top
, bottom
, left
, right
;
2695 CalcUnscrolledPosition( 0, 0, &left
, &top
);
2696 CalcUnscrolledPosition( cw
, ch
, &right
, &bottom
);
2698 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
2700 // horizontal grid lines
2703 for ( i
= 0; i
<= m_numRows
; i
++ )
2705 if ( m_rowBottoms
[i
] > bottom
)
2709 else if ( m_rowBottoms
[i
] >= top
)
2711 dc
.DrawLine( left
, m_rowBottoms
[i
], right
, m_rowBottoms
[i
] );
2716 // vertical grid lines
2718 for ( i
= 0; i
<= m_numCols
; i
++ )
2720 if ( m_colRights
[i
] > right
)
2724 else if ( m_colRights
[i
] >= left
)
2726 dc
.DrawLine( m_colRights
[i
], top
, m_colRights
[i
], bottom
);
2732 void wxGrid::DrawRowLabels( wxDC
& dc
)
2734 if ( !m_numRows
|| !m_numCols
) return;
2737 size_t numLabels
= m_rowLabelsExposed
.GetCount();
2739 for ( i
= 0; i
< numLabels
; i
++ )
2741 DrawRowLabel( dc
, m_rowLabelsExposed
[i
] );
2746 void wxGrid::DrawRowLabel( wxDC
& dc
, int row
)
2748 if ( m_rowHeights
[row
] <= 0 ) return;
2750 // draw the label's horizontal border (the vertical border is
2751 // provided by the cell area window margin)
2753 dc
.SetPen( *wxBLACK_PEN
);
2755 dc
.DrawLine( 0, m_rowBottoms
[row
]+1,
2756 m_rowLabelWidth
, m_rowBottoms
[row
]+1 );
2758 dc
.SetPen( *wxWHITE_PEN
);
2760 dc
.DrawLine( 0, m_rowBottoms
[row
]+2,
2761 m_rowLabelWidth
, m_rowBottoms
[row
]+2 );
2763 dc
.SetBackgroundMode( wxTRANSPARENT
);
2764 dc
.SetTextForeground( GetLabelTextColour() );
2765 dc
.SetFont( GetLabelFont() );
2768 GetRowLabelAlignment( &hAlign
, &vAlign
);
2772 rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 );
2773 rect
.SetWidth( m_rowLabelWidth
- 4 );
2774 rect
.SetHeight( m_rowHeights
[row
] - 4 );
2775 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect
, hAlign
, vAlign
);
2779 void wxGrid::DrawColLabels( wxDC
& dc
)
2781 if ( !m_numRows
|| !m_numCols
) return;
2784 size_t numLabels
= m_colLabelsExposed
.GetCount();
2786 for ( i
= 0; i
< numLabels
; i
++ )
2788 DrawColLabel( dc
, m_colLabelsExposed
[i
] );
2793 void wxGrid::DrawColLabel( wxDC
& dc
, int col
)
2795 if ( m_colWidths
[col
] <= 0 ) return;
2797 // draw the label's vertical border (the horizontal border is
2798 // provided by the cell area window margin)
2800 dc
.SetPen( *wxBLACK_PEN
);
2802 dc
.DrawLine( m_colRights
[col
]+1, 0,
2803 m_colRights
[col
]+1, m_colLabelHeight
);
2805 dc
.SetPen( *wxWHITE_PEN
);
2807 dc
.DrawLine( m_colRights
[col
]+2, 0,
2808 m_colRights
[col
]+2, m_colLabelHeight
);
2810 dc
.SetBackgroundMode( wxTRANSPARENT
);
2811 dc
.SetTextForeground( GetLabelTextColour() );
2812 dc
.SetFont( GetLabelFont() );
2815 GetColLabelAlignment( &hAlign
, &vAlign
);
2818 rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 );
2820 rect
.SetWidth( m_colWidths
[col
] - 4 );
2821 rect
.SetHeight( m_colLabelHeight
- 4 );
2822 DrawTextRectangle( dc
, GetColLabelValue( col
), rect
, hAlign
, vAlign
);
2826 void wxGrid::DrawTextRectangle( wxDC
& dc
,
2827 const wxString
& value
,
2832 long textWidth
, textHeight
;
2833 long lineWidth
, lineHeight
;
2834 wxArrayString lines
;
2836 dc
.SetClippingRegion( rect
);
2837 StringToLines( value
, lines
);
2838 if ( lines
.GetCount() )
2840 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
2841 dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight
);
2844 switch ( horizAlign
)
2847 x
= rect
.x
+ (rect
.width
- textWidth
- 1);
2851 x
= rect
.x
+ ((rect
.width
- textWidth
)/2);
2860 switch ( vertAlign
)
2863 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
2867 y
= rect
.y
+ ((rect
.height
- textHeight
)/2);
2876 for ( size_t i
= 0; i
< lines
.GetCount(); i
++ )
2878 dc
.DrawText( lines
[i
], (long)x
, (long)y
);
2883 dc
.DestroyClippingRegion();
2887 // Split multi line text up into an array of strings. Any existing
2888 // contents of the string array are preserved.
2890 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines
)
2892 // TODO: this won't work for WXMAC ? (lines end with '\r')
2893 // => use wxTextFile functions then (VZ)
2896 while ( startPos
< (int)value
.Length() )
2898 pos
= value
.Mid(startPos
).Find( '\n' );
2903 else if ( pos
== 0 )
2905 lines
.Add( wxEmptyString
);
2909 if ( value
[startPos
+pos
-1] == '\r' )
2911 lines
.Add( value
.Mid(startPos
, pos
-1) );
2915 lines
.Add( value
.Mid(startPos
, pos
) );
2920 if ( startPos
< (int)value
.Length() )
2922 lines
.Add( value
.Mid( startPos
) );
2927 void wxGrid::GetTextBoxSize( wxDC
& dc
,
2928 wxArrayString
& lines
,
2929 long *width
, long *height
)
2936 for ( i
= 0; i
< lines
.GetCount(); i
++ )
2938 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
2939 w
= wxMax( w
, lineW
);
2949 // ------ Edit control functions
2953 void wxGrid::EnableEditing( bool edit
)
2955 // TODO: improve this ?
2957 if ( edit
!= m_editable
)
2961 // TODO: extend this for other edit control types
2963 if ( m_editCtrlType
== wxGRID_TEXTCTRL
)
2965 ((wxTextCtrl
*)m_cellEditCtrl
)->SetEditable( m_editable
);
2971 #if 0 // disabled for the moment - the cell control is always active
2972 void wxGrid::EnableCellEditControl( bool enable
)
2974 if ( m_cellEditCtrl
&&
2975 enable
!= m_cellEditCtrlEnabled
)
2977 m_cellEditCtrlEnabled
= enable
;
2979 if ( m_cellEditCtrlEnabled
)
2981 SetEditControlValue();
2982 ShowCellEditControl();
2986 HideCellEditControl();
2987 SaveEditControlValue();
2994 void wxGrid::ShowCellEditControl()
2998 if ( IsCellEditControlEnabled() )
3000 if ( !IsVisible( m_currentCellCoords
) )
3006 rect
= CellToRect( m_currentCellCoords
);
3008 // convert to scrolled coords
3010 int left
, top
, right
, bottom
;
3011 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
3012 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
3015 m_gridWin
->GetClientSize( &cw
, &ch
);
3017 // Make the edit control large enough to allow for internal margins
3018 // TODO: remove this if the text ctrl sizing is improved esp. for unix
3021 #if defined (__WXMOTIF__)
3022 if ( m_currentCellCoords
.GetRow() == 0 ||
3023 m_currentCellCoords
.GetCol() == 0 )
3032 if ( m_currentCellCoords
.GetRow() == 0 ||
3033 m_currentCellCoords
.GetCol() == 0 )
3042 rect
.SetLeft( wxMax(0, left
- extra
) );
3043 rect
.SetTop( wxMax(0, top
- extra
) );
3044 rect
.SetRight( rect
.GetRight() + 2*extra
);
3045 rect
.SetBottom( rect
.GetBottom() + 2*extra
);
3048 m_cellEditCtrl
->SetSize( rect
);
3049 m_cellEditCtrl
->Show( TRUE
);
3051 switch ( m_editCtrlType
)
3053 case wxGRID_TEXTCTRL
:
3054 ((wxTextCtrl
*) m_cellEditCtrl
)->SetInsertionPointEnd();
3057 case wxGRID_CHECKBOX
:
3058 // TODO: anything ???
3063 // TODO: anything ???
3067 case wxGRID_COMBOBOX
:
3068 // TODO: anything ???
3073 m_cellEditCtrl
->SetFocus();
3079 void wxGrid::HideCellEditControl()
3081 if ( IsCellEditControlEnabled() )
3083 m_cellEditCtrl
->Show( FALSE
);
3088 void wxGrid::SetEditControlValue( const wxString
& value
)
3094 s
= GetCellValue(m_currentCellCoords
);
3098 if ( IsCellEditControlEnabled() )
3100 switch ( m_editCtrlType
)
3102 case wxGRID_TEXTCTRL
:
3103 ((wxGridTextCtrl
*)m_cellEditCtrl
)->SetStartValue(s
);
3106 case wxGRID_CHECKBOX
:
3107 // TODO: implement this
3112 // TODO: implement this
3116 case wxGRID_COMBOBOX
:
3117 // TODO: implement this
3126 void wxGrid::SaveEditControlValue()
3130 wxWindow
*ctrl
= (wxWindow
*)NULL
;
3132 if ( IsCellEditControlEnabled() )
3134 ctrl
= m_cellEditCtrl
;
3141 bool valueChanged
= FALSE
;
3143 switch ( m_editCtrlType
)
3145 case wxGRID_TEXTCTRL
:
3146 valueChanged
= (((wxGridTextCtrl
*)ctrl
)->GetValue() !=
3147 ((wxGridTextCtrl
*)ctrl
)->GetStartValue());
3148 SetCellValue( m_currentCellCoords
,
3149 ((wxTextCtrl
*) ctrl
)->GetValue() );
3152 case wxGRID_CHECKBOX
:
3153 // TODO: implement this
3158 // TODO: implement this
3162 case wxGRID_COMBOBOX
:
3163 // TODO: implement this
3170 SendEvent( EVT_GRID_CELL_CHANGE
,
3171 m_currentCellCoords
.GetRow(),
3172 m_currentCellCoords
.GetCol() );
3179 // ------ Grid location functions
3180 // Note that all of these functions work with the logical coordinates of
3181 // grid cells and labels so you will need to convert from device
3182 // coordinates for mouse events etc.
3185 void wxGrid::XYToCell( int x
, int y
, wxGridCellCoords
& coords
)
3187 int row
= YToRow(y
);
3188 int col
= XToCol(x
);
3190 if ( row
== -1 || col
== -1 )
3192 coords
= wxGridNoCellCoords
;
3196 coords
.Set( row
, col
);
3201 int wxGrid::YToRow( int y
)
3205 for ( i
= 0; i
< m_numRows
; i
++ )
3207 if ( y
< m_rowBottoms
[i
] ) return i
;
3214 int wxGrid::XToCol( int x
)
3218 for ( i
= 0; i
< m_numCols
; i
++ )
3220 if ( x
< m_colRights
[i
] ) return i
;
3227 // return the row number that that the y coord is near the edge of, or
3228 // -1 if not near an edge
3230 int wxGrid::YToEdgeOfRow( int y
)
3234 for ( i
= 0; i
< m_numRows
; i
++ )
3236 if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3238 d
= abs( y
- m_rowBottoms
[i
] );
3240 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3249 // return the col number that that the x coord is near the edge of, or
3250 // -1 if not near an edge
3252 int wxGrid::XToEdgeOfCol( int x
)
3256 for ( i
= 0; i
< m_numCols
; i
++ )
3258 if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE
)
3260 d
= abs( x
- m_colRights
[i
] );
3262 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
3271 wxRect
wxGrid::CellToRect( int row
, int col
)
3273 wxRect
rect( -1, -1, -1, -1 );
3275 if ( row
>= 0 && row
< m_numRows
&&
3276 col
>= 0 && col
< m_numCols
)
3278 rect
.x
= m_colRights
[col
] - m_colWidths
[col
];
3279 rect
.y
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3280 rect
.width
= m_colWidths
[col
];
3281 rect
.height
= m_rowHeights
[ row
];
3288 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible
)
3290 // get the cell rectangle in logical coords
3292 wxRect
r( CellToRect( row
, col
) );
3294 // convert to device coords
3296 int left
, top
, right
, bottom
;
3297 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3298 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3300 // check against the client area of the grid window
3303 m_gridWin
->GetClientSize( &cw
, &ch
);
3305 if ( wholeCellVisible
)
3307 // is the cell wholly visible ?
3309 return ( left
>= 0 && right
<= cw
&&
3310 top
>= 0 && bottom
<= ch
);
3314 // is the cell partly visible ?
3316 return ( ((left
>=0 && left
< cw
) || (right
> 0 && right
<= cw
)) &&
3317 ((top
>=0 && top
< ch
) || (bottom
> 0 && bottom
<= ch
)) );
3322 // make the specified cell location visible by doing a minimal amount
3325 void wxGrid::MakeCellVisible( int row
, int col
)
3328 int xpos
= -1, ypos
= -1;
3330 if ( row
>= 0 && row
< m_numRows
&&
3331 col
>= 0 && col
< m_numCols
)
3333 // get the cell rectangle in logical coords
3335 wxRect
r( CellToRect( row
, col
) );
3337 // convert to device coords
3339 int left
, top
, right
, bottom
;
3340 CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top
);
3341 CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom
);
3344 m_gridWin
->GetClientSize( &cw
, &ch
);
3350 else if ( bottom
> ch
)
3352 int h
= r
.GetHeight();
3354 for ( i
= row
-1; i
>= 0; i
-- )
3356 if ( h
+ m_rowHeights
[i
] > ch
) break;
3358 h
+= m_rowHeights
[i
];
3359 ypos
-= m_rowHeights
[i
];
3362 // we divide it later by GRID_SCROLL_LINE, make sure that we don't
3363 // have rounding errors (this is important, because if we do, we
3364 // might not scroll at all and some cells won't be redrawn)
3365 ypos
+= GRID_SCROLL_LINE
/ 2;
3372 else if ( right
> cw
)
3374 int w
= r
.GetWidth();
3376 for ( i
= col
-1; i
>= 0; i
-- )
3378 if ( w
+ m_colWidths
[i
] > cw
) break;
3380 w
+= m_colWidths
[i
];
3381 xpos
-= m_colWidths
[i
];
3384 // see comment for ypos above
3385 xpos
+= GRID_SCROLL_LINE
/ 2;
3388 if ( xpos
!= -1 || ypos
!= -1 )
3390 if ( xpos
!= -1 ) xpos
/= GRID_SCROLL_LINE
;
3391 if ( ypos
!= -1 ) ypos
/= GRID_SCROLL_LINE
;
3392 Scroll( xpos
, ypos
);
3400 // ------ Grid cursor movement functions
3403 bool wxGrid::MoveCursorUp()
3405 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3406 m_currentCellCoords
.GetRow() > 0 )
3408 MakeCellVisible( m_currentCellCoords
.GetRow() - 1,
3409 m_currentCellCoords
.GetCol() );
3411 SetCurrentCell( m_currentCellCoords
.GetRow() - 1,
3412 m_currentCellCoords
.GetCol() );
3421 bool wxGrid::MoveCursorDown()
3423 // TODO: allow for scrolling
3425 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3426 m_currentCellCoords
.GetRow() < m_numRows
-1 )
3428 MakeCellVisible( m_currentCellCoords
.GetRow() + 1,
3429 m_currentCellCoords
.GetCol() );
3431 SetCurrentCell( m_currentCellCoords
.GetRow() + 1,
3432 m_currentCellCoords
.GetCol() );
3441 bool wxGrid::MoveCursorLeft()
3443 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3444 m_currentCellCoords
.GetCol() > 0 )
3446 MakeCellVisible( m_currentCellCoords
.GetRow(),
3447 m_currentCellCoords
.GetCol() - 1 );
3449 SetCurrentCell( m_currentCellCoords
.GetRow(),
3450 m_currentCellCoords
.GetCol() - 1 );
3459 bool wxGrid::MoveCursorRight()
3461 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
3462 m_currentCellCoords
.GetCol() < m_numCols
- 1 )
3464 MakeCellVisible( m_currentCellCoords
.GetRow(),
3465 m_currentCellCoords
.GetCol() + 1 );
3467 SetCurrentCell( m_currentCellCoords
.GetRow(),
3468 m_currentCellCoords
.GetCol() + 1 );
3477 bool wxGrid::MovePageUp()
3479 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
3481 int row
= m_currentCellCoords
.GetRow();
3485 m_gridWin
->GetClientSize( &cw
, &ch
);
3487 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
3488 int newRow
= YToRow( y
- ch
+ 1 );
3493 else if ( newRow
== row
)
3498 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
3499 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
3507 bool wxGrid::MovePageDown()
3509 if ( m_currentCellCoords
== wxGridNoCellCoords
) return FALSE
;
3511 int row
= m_currentCellCoords
.GetRow();
3512 if ( row
< m_numRows
)
3515 m_gridWin
->GetClientSize( &cw
, &ch
);
3517 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
3518 int newRow
= YToRow( y
+ ch
);
3521 newRow
= m_numRows
- 1;
3523 else if ( newRow
== row
)
3528 MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() );
3529 SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() );
3537 bool wxGrid::MoveCursorUpBlock()
3540 m_currentCellCoords
!= wxGridNoCellCoords
&&
3541 m_currentCellCoords
.GetRow() > 0 )
3543 int row
= m_currentCellCoords
.GetRow();
3544 int col
= m_currentCellCoords
.GetCol();
3546 if ( m_table
->IsEmptyCell(row
, col
) )
3548 // starting in an empty cell: find the next block of
3554 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3557 else if ( m_table
->IsEmptyCell(row
-1, col
) )
3559 // starting at the top of a block: find the next block
3565 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3570 // starting within a block: find the top of the block
3575 if ( m_table
->IsEmptyCell(row
, col
) )
3583 MakeCellVisible( row
, col
);
3584 SetCurrentCell( row
, col
);
3592 bool wxGrid::MoveCursorDownBlock()
3595 m_currentCellCoords
!= wxGridNoCellCoords
&&
3596 m_currentCellCoords
.GetRow() < m_numRows
-1 )
3598 int row
= m_currentCellCoords
.GetRow();
3599 int col
= m_currentCellCoords
.GetCol();
3601 if ( m_table
->IsEmptyCell(row
, col
) )
3603 // starting in an empty cell: find the next block of
3606 while ( row
< m_numRows
-1 )
3609 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3612 else if ( m_table
->IsEmptyCell(row
+1, col
) )
3614 // starting at the bottom of a block: find the next block
3617 while ( row
< m_numRows
-1 )
3620 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3625 // starting within a block: find the bottom of the block
3627 while ( row
< m_numRows
-1 )
3630 if ( m_table
->IsEmptyCell(row
, col
) )
3638 MakeCellVisible( row
, col
);
3639 SetCurrentCell( row
, col
);
3647 bool wxGrid::MoveCursorLeftBlock()
3650 m_currentCellCoords
!= wxGridNoCellCoords
&&
3651 m_currentCellCoords
.GetCol() > 0 )
3653 int row
= m_currentCellCoords
.GetRow();
3654 int col
= m_currentCellCoords
.GetCol();
3656 if ( m_table
->IsEmptyCell(row
, col
) )
3658 // starting in an empty cell: find the next block of
3664 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3667 else if ( m_table
->IsEmptyCell(row
, col
-1) )
3669 // starting at the left of a block: find the next block
3675 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3680 // starting within a block: find the left of the block
3685 if ( m_table
->IsEmptyCell(row
, col
) )
3693 MakeCellVisible( row
, col
);
3694 SetCurrentCell( row
, col
);
3702 bool wxGrid::MoveCursorRightBlock()
3705 m_currentCellCoords
!= wxGridNoCellCoords
&&
3706 m_currentCellCoords
.GetCol() < m_numCols
-1 )
3708 int row
= m_currentCellCoords
.GetRow();
3709 int col
= m_currentCellCoords
.GetCol();
3711 if ( m_table
->IsEmptyCell(row
, col
) )
3713 // starting in an empty cell: find the next block of
3716 while ( col
< m_numCols
-1 )
3719 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3722 else if ( m_table
->IsEmptyCell(row
, col
+1) )
3724 // starting at the right of a block: find the next block
3727 while ( col
< m_numCols
-1 )
3730 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
3735 // starting within a block: find the right of the block
3737 while ( col
< m_numCols
-1 )
3740 if ( m_table
->IsEmptyCell(row
, col
) )
3748 MakeCellVisible( row
, col
);
3749 SetCurrentCell( row
, col
);
3760 // ------ Label values and formatting
3763 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert
)
3765 *horiz
= m_rowLabelHorizAlign
;
3766 *vert
= m_rowLabelVertAlign
;
3769 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert
)
3771 *horiz
= m_colLabelHorizAlign
;
3772 *vert
= m_colLabelVertAlign
;
3775 wxString
wxGrid::GetRowLabelValue( int row
)
3779 return m_table
->GetRowLabelValue( row
);
3789 wxString
wxGrid::GetColLabelValue( int col
)
3793 return m_table
->GetColLabelValue( col
);
3803 void wxGrid::SetRowLabelSize( int width
)
3805 // TODO: how to do this with the box sizers ?
3808 void wxGrid::SetColLabelSize( int height
)
3810 // TODO: how to do this with the box sizers ?
3813 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour
)
3815 if ( m_labelBackgroundColour
!= colour
)
3817 m_labelBackgroundColour
= colour
;
3818 m_rowLabelWin
->SetBackgroundColour( colour
);
3819 m_colLabelWin
->SetBackgroundColour( colour
);
3820 m_cornerLabelWin
->SetBackgroundColour( colour
);
3822 if ( !GetBatchCount() )
3824 m_rowLabelWin
->Refresh();
3825 m_colLabelWin
->Refresh();
3826 m_cornerLabelWin
->Refresh();
3831 void wxGrid::SetLabelTextColour( const wxColour
& colour
)
3833 if ( m_labelTextColour
!= colour
)
3835 m_labelTextColour
= colour
;
3836 if ( !GetBatchCount() )
3838 m_rowLabelWin
->Refresh();
3839 m_colLabelWin
->Refresh();
3844 void wxGrid::SetLabelFont( const wxFont
& font
)
3847 if ( !GetBatchCount() )
3849 m_rowLabelWin
->Refresh();
3850 m_colLabelWin
->Refresh();
3854 void wxGrid::SetRowLabelAlignment( int horiz
, int vert
)
3856 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
3858 m_rowLabelHorizAlign
= horiz
;
3861 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
3863 m_rowLabelVertAlign
= vert
;
3866 if ( !GetBatchCount() )
3868 m_rowLabelWin
->Refresh();
3869 m_colLabelWin
->Refresh();
3873 void wxGrid::SetColLabelAlignment( int horiz
, int vert
)
3875 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
3877 m_colLabelHorizAlign
= horiz
;
3880 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
3882 m_colLabelVertAlign
= vert
;
3885 if ( !GetBatchCount() )
3887 m_rowLabelWin
->Refresh();
3888 m_colLabelWin
->Refresh();
3892 void wxGrid::SetRowLabelValue( int row
, const wxString
& s
)
3896 m_table
->SetRowLabelValue( row
, s
);
3897 if ( !GetBatchCount() )
3899 // TODO: Optimize this
3901 m_rowLabelWin
->Refresh();
3906 void wxGrid::SetColLabelValue( int col
, const wxString
& s
)
3910 m_table
->SetColLabelValue( col
, s
);
3911 if ( !GetBatchCount() )
3913 // TODO: optimize this
3915 m_colLabelWin
->Refresh();
3920 void wxGrid::SetGridLineColour( const wxColour
& colour
)
3922 if ( m_gridLineColour
!= colour
)
3924 m_gridLineColour
= colour
;
3926 wxClientDC
dc( m_gridWin
);
3928 DrawAllGridLines( dc
);
3932 void wxGrid::EnableGridLines( bool enable
)
3934 if ( enable
!= m_gridLinesEnabled
)
3936 m_gridLinesEnabled
= enable
;
3938 if ( !GetBatchCount() )
3942 wxClientDC
dc( m_gridWin
);
3944 DrawAllGridLines( dc
);
3948 m_gridWin
->Refresh();
3955 int wxGrid::GetDefaultRowSize()
3957 return m_defaultRowHeight
;
3960 int wxGrid::GetRowSize( int row
)
3962 if ( row
>= 0 && row
< m_numRows
)
3963 return m_rowHeights
[row
];
3965 return 0; // TODO: log an error here
3968 int wxGrid::GetDefaultColSize()
3970 return m_defaultColWidth
;
3973 int wxGrid::GetColSize( int col
)
3975 if ( col
>= 0 && col
< m_numCols
)
3976 return m_colWidths
[col
];
3978 return 0; // TODO: log an error here
3981 wxColour
wxGrid::GetDefaultCellBackgroundColour()
3983 // TODO: replace this temp test code
3985 return wxColour( 255, 255, 255 );
3988 wxColour
wxGrid::GetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
) )
3990 // TODO: replace this temp test code
3992 return wxColour( 255, 255, 255 );
3995 wxColour
wxGrid::GetDefaultCellTextColour()
3997 // TODO: replace this temp test code
3999 return wxColour( 0, 0, 0 );
4002 wxColour
wxGrid::GetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
) )
4004 // TODO: replace this temp test code
4006 return wxColour( 0, 0, 0 );
4010 wxFont
wxGrid::GetDefaultCellFont()
4012 return m_defaultCellFont
;
4015 wxFont
wxGrid::GetCellFont( int WXUNUSED(row
), int WXUNUSED(col
) )
4017 // TODO: replace this temp test code
4019 return m_defaultCellFont
;
4022 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert
)
4024 // TODO: replace this temp test code
4030 void wxGrid::GetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int *horiz
, int *vert
)
4032 // TODO: replace this temp test code
4038 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows
)
4040 m_defaultRowHeight
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT
);
4042 if ( resizeExistingRows
)
4046 for ( row
= 0; row
< m_numRows
; row
++ )
4048 m_rowHeights
[row
] = m_defaultRowHeight
;
4049 bottom
+= m_defaultRowHeight
;
4050 m_rowBottoms
[row
] = bottom
;
4056 void wxGrid::SetRowSize( int row
, int height
)
4060 if ( row
>= 0 && row
< m_numRows
)
4062 int h
= wxMax( 0, height
);
4063 int diff
= h
- m_rowHeights
[row
];
4065 m_rowHeights
[row
] = h
;
4066 for ( i
= row
; i
< m_numRows
; i
++ )
4068 m_rowBottoms
[i
] += diff
;
4072 // Note: we are ending the event *after* doing
4073 // default processing in this case
4075 SendEvent( EVT_GRID_ROW_SIZE
,
4080 // TODO: log an error here
4084 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols
)
4086 m_defaultColWidth
= wxMax( width
, WXGRID_MIN_COL_WIDTH
);
4088 if ( resizeExistingCols
)
4092 for ( col
= 0; col
< m_numCols
; col
++ )
4094 m_colWidths
[col
] = m_defaultColWidth
;
4095 right
+= m_defaultColWidth
;
4096 m_colRights
[col
] = right
;
4102 void wxGrid::SetColSize( int col
, int width
)
4106 if ( col
>= 0 && col
< m_numCols
)
4108 int w
= wxMax( 0, width
);
4109 int diff
= w
- m_colWidths
[col
];
4110 m_colWidths
[col
] = w
;
4112 for ( i
= col
; i
< m_numCols
; i
++ )
4114 m_colRights
[i
] += diff
;
4118 // Note: we are ending the event *after* doing
4119 // default processing in this case
4121 SendEvent( EVT_GRID_COL_SIZE
,
4126 // TODO: log an error here
4130 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& )
4132 // TODO: everything !!!
4136 void wxGrid::SetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& )
4138 // TODO: everything !!!
4142 void wxGrid::SetDefaultCellTextColour( const wxColour
& )
4144 // TODO: everything !!!
4148 void wxGrid::SetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& )
4150 // TODO: everything !!!
4154 void wxGrid::SetDefaultCellFont( const wxFont
& )
4156 // TODO: everything !!!
4160 void wxGrid::SetCellFont( int WXUNUSED(row
), int WXUNUSED(col
), const wxFont
& )
4162 // TODO: everything !!!
4166 void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz
), int WXUNUSED(vert
) )
4168 // TODO: everything !!!
4172 void wxGrid::SetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int WXUNUSED(horiz
), int WXUNUSED(vert
) )
4174 // TODO: everything !!!
4181 // ------ cell value accessor functions
4184 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s
)
4188 m_table
->SetValue( row
, col
, s
.c_str() );
4189 if ( !GetBatchCount() )
4191 wxClientDC
dc( m_gridWin
);
4193 DrawCell( dc
, wxGridCellCoords(row
, col
) );
4196 #if 0 // TODO: edit in place
4198 if ( m_currentCellCoords
.GetRow() == row
&&
4199 m_currentCellCoords
.GetCol() == col
)
4201 SetEditControlValue( s
);
4210 // ------ Block, row and col selection
4213 void wxGrid::SelectRow( int row
, bool addToSelected
)
4217 if ( IsSelection() && addToSelected
)
4219 if ( m_selectedTopLeft
.GetRow() > row
)
4220 m_selectedTopLeft
.SetRow( row
);
4222 m_selectedTopLeft
.SetCol( 0 );
4224 if ( m_selectedBottomRight
.GetRow() < row
)
4225 m_selectedBottomRight
.SetRow( row
);
4227 m_selectedBottomRight
.SetCol( m_numCols
- 1 );
4229 // TODO: optimize this so that we only refresh the newly
4232 r
= SelectionToDeviceRect();
4233 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( TRUE
, &r
);
4237 r
= SelectionToDeviceRect();
4239 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( TRUE
, &r
);
4241 m_selectedTopLeft
.Set( row
, 0 );
4242 m_selectedBottomRight
.Set( row
, m_numCols
-1 );
4243 r
= SelectionToDeviceRect();
4244 m_gridWin
->Refresh( TRUE
, &r
);
4247 wxGridRangeSelectEvent
gridEvt( GetId(),
4248 EVT_GRID_RANGE_SELECT
,
4251 m_selectedBottomRight
);
4253 GetEventHandler()->ProcessEvent(gridEvt
);
4257 void wxGrid::SelectCol( int col
, bool addToSelected
)
4261 if ( IsSelection() && addToSelected
)
4263 if ( m_selectedTopLeft
.GetCol() > col
)
4264 m_selectedTopLeft
.SetCol( col
);
4266 m_selectedTopLeft
.SetRow( 0 );
4268 if ( m_selectedBottomRight
.GetCol() < col
)
4269 m_selectedBottomRight
.SetCol( col
);
4271 m_selectedBottomRight
.SetRow( m_numRows
- 1 );
4273 // TODO: optimize this so that we only refresh the newly
4276 r
= SelectionToDeviceRect();
4277 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( TRUE
, &r
);
4281 r
= SelectionToDeviceRect();
4283 if ( r
!= wxGridNoCellRect
) m_gridWin
->Refresh( TRUE
, &r
);
4285 m_selectedTopLeft
.Set( 0, col
);
4286 m_selectedBottomRight
.Set( m_numRows
-1, col
);
4287 r
= SelectionToDeviceRect();
4288 m_gridWin
->Refresh( TRUE
, &r
);
4291 wxGridRangeSelectEvent
gridEvt( GetId(),
4292 EVT_GRID_RANGE_SELECT
,
4295 m_selectedBottomRight
);
4297 GetEventHandler()->ProcessEvent(gridEvt
);
4301 void wxGrid::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol
)
4304 bool changed
= false;
4305 wxGridCellCoords updateTopLeft
, updateBottomRight
;
4307 if ( topRow
> bottomRow
)
4314 if ( leftCol
> rightCol
)
4321 updateTopLeft
= m_selectedTopLeft
;
4322 if (m_selectedTopLeft
!= wxGridCellCoords( topRow
, leftCol
) )
4324 m_selectedTopLeft
= wxGridCellCoords( topRow
, leftCol
);
4325 if (updateTopLeft
== wxGridNoCellCoords
)
4327 updateTopLeft
= m_selectedTopLeft
;
4331 if(updateTopLeft
.GetRow() > topRow
)
4332 updateTopLeft
.SetRow(topRow
);
4333 if (updateTopLeft
.GetCol() > leftCol
)
4334 updateTopLeft
.SetCol(leftCol
);
4339 updateBottomRight
= m_selectedBottomRight
;
4340 if (m_selectedBottomRight
!= wxGridCellCoords( bottomRow
, rightCol
) )
4342 m_selectedBottomRight
= wxGridCellCoords( bottomRow
, rightCol
);
4343 if (updateBottomRight
== wxGridNoCellCoords
)
4345 updateBottomRight
= m_selectedBottomRight
;
4349 if (updateBottomRight
.GetRow() < bottomRow
)
4350 updateBottomRight
.SetRow(bottomRow
);
4351 if (updateBottomRight
.GetCol() < rightCol
)
4352 updateBottomRight
.SetCol(rightCol
);
4359 wxRect
r( BlockToDeviceRect( updateTopLeft
, updateBottomRight
) );
4360 m_gridWin
->Refresh( TRUE
, &r
);
4363 // only generate an event if the block is not being selected by
4364 // dragging the mouse (in which case the event will be generated in
4365 // the mouse event handler)
4366 if ( !m_isDragging
)
4368 wxGridRangeSelectEvent
gridEvt( GetId(),
4369 EVT_GRID_RANGE_SELECT
,
4372 m_selectedBottomRight
);
4374 GetEventHandler()->ProcessEvent(gridEvt
);
4378 void wxGrid::SelectAll()
4380 m_selectedTopLeft
.Set( 0, 0 );
4381 m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 );
4383 m_gridWin
->Refresh();
4387 void wxGrid::ClearSelection()
4389 m_selectedTopLeft
= wxGridNoCellCoords
;
4390 m_selectedBottomRight
= wxGridNoCellCoords
;
4394 // This function returns the rectangle that encloses the given block
4395 // in device coords clipped to the client size of the grid window.
4397 wxRect
wxGrid::BlockToDeviceRect( const wxGridCellCoords
&topLeft
,
4398 const wxGridCellCoords
&bottomRight
)
4400 wxRect
rect( wxGridNoCellRect
);
4403 cellRect
= CellToRect( topLeft
);
4404 if ( cellRect
!= wxGridNoCellRect
)
4410 rect
= wxRect( 0, 0, 0, 0 );
4413 cellRect
= CellToRect( bottomRight
);
4414 if ( cellRect
!= wxGridNoCellRect
)
4420 return wxGridNoCellRect
;
4423 // convert to scrolled coords
4425 int left
, top
, right
, bottom
;
4426 CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top
);
4427 CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom
);
4430 m_gridWin
->GetClientSize( &cw
, &ch
);
4432 rect
.SetLeft( wxMax(0, left
) );
4433 rect
.SetTop( wxMax(0, top
) );
4434 rect
.SetRight( wxMin(cw
, right
) );
4435 rect
.SetBottom( wxMin(ch
, bottom
) );
4443 // ------ Grid event classes
4446 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent
)
4448 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
4449 int row
, int col
, int x
, int y
,
4450 bool control
, bool shift
, bool alt
, bool meta
)
4451 : wxNotifyEvent( type
, id
)
4457 m_control
= control
;
4462 SetEventObject(obj
);
4466 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent
)
4468 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
4469 int rowOrCol
, int x
, int y
,
4470 bool control
, bool shift
, bool alt
, bool meta
)
4471 : wxNotifyEvent( type
, id
)
4473 m_rowOrCol
= rowOrCol
;
4476 m_control
= control
;
4481 SetEventObject(obj
);
4485 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent
)
4487 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
4488 const wxGridCellCoords
& topLeft
,
4489 const wxGridCellCoords
& bottomRight
,
4490 bool control
, bool shift
, bool alt
, bool meta
)
4491 : wxNotifyEvent( type
, id
)
4493 m_topLeft
= topLeft
;
4494 m_bottomRight
= bottomRight
;
4495 m_control
= control
;
4500 SetEventObject(obj
);
4504 #endif // ifndef wxUSE_NEW_GRID