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 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
17 #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
22 #pragma implementation "grid.h"
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
37 #include "wx/generic/grid.h"
40 //////////////////////////////////////////////////////////////////////
42 wxGridCellCoords
wxGridNoCellCoords( -1, -1 );
43 wxRect
wxGridNoCellRect( -1, -1, -1, -1 );
47 //////////////////////////////////////////////////////////////////////
49 // Abstract base class for grid data (the model)
51 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject
)
54 wxGridTableBase::wxGridTableBase()
57 m_view
= (wxGrid
*) NULL
;
60 wxGridTableBase::~wxGridTableBase()
65 bool wxGridTableBase::InsertRows( size_t pos
, size_t numRows
)
67 wxLogWarning( "Called grid table class function InsertRows(pos=%d, N=%d)\n"
68 "but your derived table class does not override this function",
74 bool wxGridTableBase::AppendRows( size_t numRows
)
76 wxLogWarning( "Called grid table class function AppendRows(N=%d)\n"
77 "but your derived table class does not override this function",
83 bool wxGridTableBase::DeleteRows( size_t pos
, size_t numRows
)
85 wxLogWarning( "Called grid table class function DeleteRows(pos=%d, N=%d)\n"
86 "but your derived table class does not override this function",
92 bool wxGridTableBase::InsertCols( size_t pos
, size_t numCols
)
94 wxLogWarning( "Called grid table class function InsertCols(pos=%d, N=%d)\n"
95 "but your derived table class does not override this function",
101 bool wxGridTableBase::AppendCols( size_t numCols
)
103 wxLogWarning( "Called grid table class function AppendCols(N=%d)\n"
104 "but your derived table class does not override this function",
110 bool wxGridTableBase::DeleteCols( size_t pos
, size_t numCols
)
112 wxLogWarning( "Called grid table class function DeleteCols(pos=%d, N=%d)\n"
113 "but your derived table class does not override this function",
120 wxString
wxGridTableBase::GetRowLabelValue( int row
)
127 wxString
wxGridTableBase::GetColLabelValue( int col
)
129 // default col labels are:
130 // cols 0 to 25 : A-Z
131 // cols 26 to 675 : AA-ZZ
138 s
+= ('A' + (char)( col%26
));
140 if ( col
< 0 ) break;
143 // reverse the string...
145 for ( i
= 0; i
< n
; i
++ )
155 //////////////////////////////////////////////////////////////////////
157 // Message class for the grid table to send requests and notifications
161 wxGridTableMessage::wxGridTableMessage()
163 m_table
= (wxGridTableBase
*) NULL
;
169 wxGridTableMessage::wxGridTableMessage( wxGridTableBase
*table
, int id
,
170 int commandInt1
, int commandInt2
)
174 m_comInt1
= commandInt1
;
175 m_comInt2
= commandInt2
;
180 //////////////////////////////////////////////////////////////////////
182 // A basic grid table for string data. An object of this class will
183 // created by wxGrid if you don't specify an alternative table class.
187 // this is a magic incantation which must be done!
188 #include <wx/arrimpl.cpp>
190 WX_DEFINE_OBJARRAY(wxGridStringArray
);
192 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase
)
194 wxGridStringTable::wxGridStringTable()
199 wxGridStringTable::wxGridStringTable( int numRows
, int numCols
)
204 m_data
.Alloc( numRows
);
208 for ( col
= 0; col
< numCols
; col
++ )
210 sa
.Add( wxEmptyString
);
213 for ( row
= 0; row
< numRows
; row
++ )
219 wxGridStringTable::~wxGridStringTable()
223 long wxGridStringTable::GetNumberRows()
225 return m_data
.GetCount();
228 long wxGridStringTable::GetNumberCols()
230 if ( m_data
.GetCount() > 0 )
231 return m_data
[0].GetCount();
236 wxString
wxGridStringTable::GetValue( int row
, int col
)
238 // TODO: bounds checking
240 return m_data
[row
][col
];
243 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& s
)
245 // TODO: bounds checking
247 m_data
[row
][col
] = s
;
250 bool wxGridStringTable::IsEmptyCell( int row
, int col
)
252 // TODO: bounds checking
254 return (m_data
[row
][col
] == wxEmptyString
);
258 void wxGridStringTable::Clear()
261 int numRows
, numCols
;
263 numRows
= m_data
.GetCount();
266 numCols
= m_data
[0].GetCount();
268 for ( row
= 0; row
< numRows
; row
++ )
270 for ( col
= 0; col
< numCols
; col
++ )
272 m_data
[row
][col
] = wxEmptyString
;
279 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows
)
283 size_t curNumRows
= m_data
.GetCount();
284 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
286 if ( pos
>= curNumRows
)
288 return AppendRows( numRows
);
292 sa
.Alloc( curNumCols
);
293 for ( col
= 0; col
< curNumCols
; col
++ )
295 sa
.Add( wxEmptyString
);
298 for ( row
= pos
; row
< pos
+ numRows
; row
++ )
300 m_data
.Insert( sa
, row
);
305 wxGridTableMessage
msg( this,
306 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
,
310 GetView()->ProcessTableMessage( msg
);
316 bool wxGridStringTable::AppendRows( size_t numRows
)
320 size_t curNumRows
= m_data
.GetCount();
321 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
324 if ( curNumCols
> 0 )
326 sa
.Alloc( curNumCols
);
327 for ( col
= 0; col
< curNumCols
; col
++ )
329 sa
.Add( wxEmptyString
);
333 for ( row
= 0; row
< numRows
; row
++ )
340 wxGridTableMessage
msg( this,
341 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
,
344 GetView()->ProcessTableMessage( msg
);
350 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows
)
354 size_t curNumRows
= m_data
.GetCount();
356 if ( pos
>= curNumRows
)
358 wxLogError( "Called wxGridStringTable::DeleteRows(pos=%d, N=%d)...\n"
359 "Pos value is invalid for present table with %d rows",
360 pos
, numRows
, curNumRows
);
364 if ( numRows
> curNumRows
- pos
)
366 numRows
= curNumRows
- pos
;
369 if ( numRows
>= curNumRows
)
371 m_data
.Empty(); // don't release memory just yet
375 for ( n
= 0; n
< numRows
; n
++ )
377 m_data
.Remove( pos
);
383 wxGridTableMessage
msg( this,
384 wxGRIDTABLE_NOTIFY_ROWS_DELETED
,
388 GetView()->ProcessTableMessage( msg
);
394 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols
)
398 size_t curNumRows
= m_data
.GetCount();
399 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
401 if ( pos
>= curNumCols
)
403 return AppendCols( numCols
);
406 for ( row
= 0; row
< curNumRows
; row
++ )
408 for ( col
= pos
; col
< pos
+ numCols
; col
++ )
410 m_data
[row
].Insert( wxEmptyString
, col
);
416 wxGridTableMessage
msg( this,
417 wxGRIDTABLE_NOTIFY_COLS_INSERTED
,
421 GetView()->ProcessTableMessage( msg
);
427 bool wxGridStringTable::AppendCols( size_t numCols
)
431 size_t curNumRows
= m_data
.GetCount();
434 // TODO: something better than this ?
436 wxLogError( "Unable to append cols to a grid table with no rows.\n"
437 "Call AppendRows() first" );
441 for ( row
= 0; row
< curNumRows
; row
++ )
443 for ( n
= 0; n
< numCols
; n
++ )
445 m_data
[row
].Add( wxEmptyString
);
451 wxGridTableMessage
msg( this,
452 wxGRIDTABLE_NOTIFY_COLS_APPENDED
,
455 GetView()->ProcessTableMessage( msg
);
461 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols
)
465 size_t curNumRows
= m_data
.GetCount();
466 size_t curNumCols
= ( curNumRows
> 0 ? m_data
[0].GetCount() : 0 );
468 if ( pos
>= curNumCols
)
470 wxLogError( "Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n"
471 "Pos value is invalid for present table with %d cols",
472 pos
, numCols
, curNumCols
);
476 if ( numCols
> curNumCols
- pos
)
478 numCols
= curNumCols
- pos
;
481 for ( row
= 0; row
< curNumRows
; row
++ )
483 if ( numCols
>= curNumCols
)
489 for ( n
= 0; n
< numCols
; n
++ )
491 m_data
[row
].Remove( pos
);
498 wxGridTableMessage
msg( this,
499 wxGRIDTABLE_NOTIFY_COLS_DELETED
,
503 GetView()->ProcessTableMessage( msg
);
509 wxString
wxGridStringTable::GetRowLabelValue( int row
)
511 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
513 // using default label
515 return wxGridTableBase::GetRowLabelValue( row
);
519 return m_rowLabels
[ row
];
523 wxString
wxGridStringTable::GetColLabelValue( int col
)
525 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
527 // using default label
529 return wxGridTableBase::GetColLabelValue( col
);
533 return m_colLabels
[ col
];
537 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value
)
539 if ( row
> (int)(m_rowLabels
.GetCount()) - 1 )
541 int n
= m_rowLabels
.GetCount();
543 for ( i
= n
; i
<= row
; i
++ )
545 m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) );
549 m_rowLabels
[row
] = value
;
552 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value
)
554 if ( col
> (int)(m_colLabels
.GetCount()) - 1 )
556 int n
= m_colLabels
.GetCount();
558 for ( i
= n
; i
<= col
; i
++ )
560 m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) );
564 m_colLabels
[col
] = value
;
570 //////////////////////////////////////////////////////////////////////
572 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl
, wxTextCtrl
)
574 BEGIN_EVENT_TABLE( wxGridTextCtrl
, wxTextCtrl
)
575 EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown
)
579 wxGridTextCtrl::wxGridTextCtrl( wxWindow
*par
,
582 const wxString
& value
,
586 : wxTextCtrl( par
, id
, value
, pos
, size
, style
)
588 m_isCellControl
= isCellControl
;
592 void wxGridTextCtrl::OnKeyDown( wxKeyEvent
& ev
)
594 switch ( ev
.KeyCode() )
597 ((wxGrid
*)GetParent())->SetEditControlValue( startValue
);
598 SetInsertionPointEnd();
606 if ( m_isCellControl
)
608 // send the event to the parent grid, skipping the
609 // event if nothing happens
611 ev
.Skip( !GetParent()->ProcessEvent( ev
) );
615 // default text control response within the top edit
624 if ( m_isCellControl
)
626 // send the event to the parent grid, skipping the
627 // event if nothing happens
629 ev
.Skip( !GetParent()->ProcessEvent( ev
) );
633 // default text control response within the top edit
645 void wxGridTextCtrl::SetStartValue( const wxString
& s
)
648 wxTextCtrl::SetValue( s
.c_str() );
652 //////////////////////////////////////////////////////////////////////
654 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxPanel
)
657 BEGIN_EVENT_TABLE( wxGrid
, wxPanel
)
658 EVT_PAINT( wxGrid::OnPaint
)
659 EVT_SIZE( wxGrid::OnSize
)
660 EVT_MOUSE_EVENTS( wxGrid::OnMouse
)
661 EVT_KEY_DOWN( wxGrid::OnKeyDown
)
662 EVT_TEXT( wxGRID_CELLCTRL
, wxGrid::OnText
)
663 EVT_TEXT( wxGRID_TOPCTRL
, wxGrid::OnText
)
664 EVT_COMMAND_SCROLL( wxGRID_HORIZSCROLL
, wxGrid::OnGridScroll
)
665 EVT_COMMAND_SCROLL( wxGRID_VERTSCROLL
, wxGrid::OnGridScroll
)
676 // ----- internal init and update functions
679 void wxGrid::Create()
681 m_table
= (wxGridTableBase
*) NULL
;
682 m_topEditCtrl
= (wxWindow
*) NULL
;
683 m_cellEditCtrl
= (wxWindow
*) NULL
;
684 m_horizScrollBar
= (wxScrollBar
*) NULL
;
685 m_vertScrollBar
= (wxScrollBar
*) NULL
;
699 // TODO: perhaps have a style flag for control panel
701 m_topEditCtrlEnabled
= FALSE
;
702 m_topEditCtrl
= new wxGridTextCtrl( this,
707 wxSize(WXGRID_DEFAULT_TOPEDIT_WIDTH
,
708 WXGRID_DEFAULT_TOPEDIT_HEIGHT
),
710 m_topEditCtrl
->Show( FALSE
);
712 if ( m_numRows
<= 0 )
713 m_numRows
= WXGRID_DEFAULT_NUMBER_ROWS
;
715 if ( m_numCols
<= 0 )
716 m_numCols
= WXGRID_DEFAULT_NUMBER_COLS
;
718 m_rowLabelWidth
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
;
719 m_colLabelHeight
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
;
721 // default labels are pale grey with black text
723 m_labelBackgroundColour
= wxColour( 192, 192, 192 );
724 m_labelTextColour
= wxColour( 0, 0, 0 );
726 // TODO: something better than this ?
728 m_labelFont
= this->GetFont();
729 m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 );
731 m_rowLabelHorizAlign
= wxLEFT
;
732 m_rowLabelVertAlign
= wxCENTRE
;
734 m_colLabelHorizAlign
= wxCENTRE
;
735 m_colLabelVertAlign
= wxTOP
;
737 m_defaultRowHeight
= WXGRID_DEFAULT_ROW_HEIGHT
;
738 m_defaultColWidth
= WXGRID_DEFAULT_COL_WIDTH
;
740 m_rowHeights
.Alloc( m_numRows
);
741 m_rowBottoms
.Alloc( m_numRows
);
742 for ( i
= 0; i
< m_numRows
; i
++ )
744 m_rowHeights
.Add( m_defaultRowHeight
);
745 m_rowBottoms
.Add( 0 ); // set by CalcDimensions()
748 m_colWidths
.Alloc( m_numCols
);
749 m_colRights
.Alloc( m_numRows
);
750 for ( i
= 0; i
< m_numCols
; i
++ )
752 m_colWidths
.Add( m_defaultColWidth
);
753 m_colRights
.Add( 0 ); // set by CalcDimensions()
756 // TODO: improve this ?
758 m_defaultCellFont
= this->GetFont();
760 m_gridLineColour
= wxColour( 0, 0, 255 );
761 m_gridLinesEnabled
= TRUE
;
763 m_scrollBarWidth
= WXGRID_DEFAULT_SCROLLBAR_WIDTH
;
765 m_horizScrollBar
= new wxScrollBar( this,
771 m_vertScrollBar
= new wxScrollBar( this,
778 m_wholeColsVisible
= 0;
779 m_wholeRowsVisible
= 0;
782 m_inOnKeyDown
= FALSE
;
785 m_cursorMode
= WXGRID_CURSOR_DEFAULT
;
788 m_isDragging
= FALSE
;
790 m_rowResizeCursor
= wxCursor( wxCURSOR_SIZENS
);
791 m_colResizeCursor
= wxCursor( wxCURSOR_SIZEWE
);
793 m_currentCellCoords
= wxGridNoCellCoords
;
794 m_currentCellHighlighted
= FALSE
;
796 m_selectedTopLeft
= wxGridNoCellCoords
;
797 m_selectedBottomRight
= wxGridNoCellCoords
;
799 m_editable
= TRUE
; // default for whole grid
801 // TODO: extend this to other types of controls
803 m_cellEditCtrl
= new wxGridTextCtrl( this,
811 | wxTE_MULTILINE
| wxTE_NO_VSCROLL
815 m_cellEditCtrl
->Show( FALSE
);
816 m_cellEditCtrlEnabled
= TRUE
;
817 m_editCtrlType
= wxGRID_TEXTCTRL
;
819 // Not really needed here, it gets called by OnSize()
825 void wxGrid::CalcDimensions()
829 if ( IsTopEditControlEnabled() )
832 m_topEditCtrl
->GetSize( &ctrlW
, &ctrlH
);
841 int bottom
= m_top
+ m_colLabelHeight
;
842 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
844 bottom
+= m_rowHeights
[i
];
845 m_rowBottoms
[i
] = bottom
;
848 int right
= m_left
+ m_rowLabelWidth
;
849 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
851 right
+= m_colWidths
[i
];
852 m_colRights
[i
] = right
;
855 // adjust the scroll bars
859 GetClientSize(&cw
, &ch
);
861 // begin by assuming that we don't need either scroll bar
863 int vertScrollBarWidth
= 0;
864 int horizScrollBarHeight
= 0;
866 // Each scroll bar needs to eventually know if the other one is
867 // required in deciding whether or not it is also required - hence
868 // this loop. A bit inelegant but simple and it works.
871 for ( check
= 0; check
< 2; check
++ )
873 if ( m_numRows
> 0 &&
874 m_rowBottoms
[m_numRows
-1] + horizScrollBarHeight
> ch
)
876 vertScrollBarWidth
= m_scrollBarWidth
;
878 m_wholeRowsVisible
= 0;
879 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
881 // A partial row doesn't count, we still have to scroll to
882 // see the rest of it
883 if ( m_rowBottoms
[i
] + horizScrollBarHeight
> ch
) break;
885 m_wholeRowsVisible
++ ;
890 m_wholeRowsVisible
= m_numRows
- m_scrollPosY
;
893 vertScrollBarWidth
= m_scrollBarWidth
;
899 m_colRights
[m_numCols
-1] + vertScrollBarWidth
> cw
)
901 horizScrollBarHeight
= m_scrollBarWidth
;
903 m_wholeColsVisible
= 0;
904 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
906 // A partial col doesn't count, we still have to scroll to
907 // see the rest of it
908 if ( m_colRights
[i
] + vertScrollBarWidth
> cw
) break;
910 m_wholeColsVisible
++ ;
915 // we can see the right-most column
917 m_wholeColsVisible
= m_numCols
- m_scrollPosX
;
920 horizScrollBarHeight
= m_scrollBarWidth
;
926 if ( m_vertScrollBar
)
928 if ( !vertScrollBarWidth
)
930 m_vertScrollBar
->Show(FALSE
);
934 m_vertScrollBar
->Show(TRUE
);
935 m_vertScrollBar
->SetScrollbar(
937 wxMax(m_wholeRowsVisible
, 1),
938 (m_wholeRowsVisible
== 0 ? 1 : m_numRows
),
939 wxMax(m_wholeRowsVisible
, 1) );
941 m_vertScrollBar
->SetSize( cw
- m_scrollBarWidth
,
944 ch
- m_top
- horizScrollBarHeight
);
948 if ( m_horizScrollBar
)
950 if ( !horizScrollBarHeight
)
952 m_horizScrollBar
->Show(FALSE
);
956 m_horizScrollBar
->Show(TRUE
);
958 m_horizScrollBar
->SetScrollbar(
960 wxMax(m_wholeColsVisible
, 1),
961 (m_wholeColsVisible
== 0) ? 1 : m_numCols
,
962 wxMax(m_wholeColsVisible
, 1) );
964 m_horizScrollBar
->SetSize( m_left
,
965 ch
- m_scrollBarWidth
,
966 cw
- m_left
- vertScrollBarWidth
,
971 m_bottom
= m_right
= 0;
974 m_bottom
= wxMin( m_rowBottoms
[m_numRows
-1],
975 ch
- horizScrollBarHeight
);
979 m_right
= wxMin( m_colRights
[m_numCols
-1],
980 cw
- vertScrollBarWidth
);
985 bool wxGrid::IsOnScreen()
988 GetClientSize( &cw
, &ch
);
993 // this is called when the grid table sends a message to say that it
994 // has been redimensioned
996 bool wxGrid::Redimension( wxGridTableMessage
& msg
)
1000 switch ( msg
.GetId() )
1002 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
1004 size_t pos
= msg
.GetCommandInt();
1005 int numRows
= msg
.GetCommandInt2();
1006 for ( i
= 0; i
< numRows
; i
++ )
1008 m_rowHeights
.Insert( m_defaultRowHeight
, pos
);
1009 m_rowBottoms
.Insert( 0, pos
);
1011 m_numRows
+= numRows
;
1016 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
1018 int numRows
= msg
.GetCommandInt();
1019 for ( i
= 0; i
< numRows
; i
++ )
1021 m_rowHeights
.Add( m_defaultRowHeight
);
1022 m_rowBottoms
.Add( 0 );
1024 m_numRows
+= numRows
;
1029 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
1031 size_t pos
= msg
.GetCommandInt();
1032 int numRows
= msg
.GetCommandInt2();
1033 for ( i
= 0; i
< numRows
; i
++ )
1035 m_rowHeights
.Remove( pos
);
1036 m_rowBottoms
.Remove( pos
);
1038 m_numRows
-= numRows
;
1040 // TODO: improve these adjustments...
1042 if ( m_scrollPosY
>= m_numRows
)
1048 m_colWidths
.Clear();
1049 m_colRights
.Clear();
1050 m_currentCellCoords
= wxGridNoCellCoords
;
1052 else if ( m_currentCellCoords
.GetRow() >= m_numRows
)
1054 m_currentCellCoords
.Set( 0, 0 );
1060 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
1062 size_t pos
= msg
.GetCommandInt();
1063 int numCols
= msg
.GetCommandInt2();
1064 for ( i
= 0; i
< numCols
; i
++ )
1066 m_colWidths
.Insert( m_defaultColWidth
, pos
);
1067 m_colRights
.Insert( 0, pos
);
1069 m_numCols
+= numCols
;
1074 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
1076 int numCols
= msg
.GetCommandInt();
1077 for ( i
= 0; i
< numCols
; i
++ )
1079 m_colWidths
.Add( m_defaultColWidth
);
1080 m_colRights
.Add( 0 );
1082 m_numCols
+= numCols
;
1087 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
1089 size_t pos
= msg
.GetCommandInt();
1090 int numCols
= msg
.GetCommandInt2();
1091 for ( i
= 0; i
< numCols
; i
++ )
1093 m_colWidths
.Remove( pos
);
1094 m_colRights
.Remove( pos
);
1096 m_numCols
-= numCols
;
1098 // TODO: improve these adjustments...
1100 if ( m_scrollPosX
>= m_numCols
)
1105 #if 0 // leave the row alone here so that AppendCols will work subsequently
1107 m_rowHeights
.Clear();
1108 m_rowBottoms
.Clear();
1110 m_currentCellCoords
= wxGridNoCellCoords
;
1112 else if ( m_currentCellCoords
.GetCol() >= m_numCols
)
1114 m_currentCellCoords
.Set( 0, 0 );
1126 // ----- event handlers
1129 // Generate a grid event based on a mouse event and
1130 // return the result of ProcessEvent()
1132 bool wxGrid::SendEvent( const wxEventType type
,
1134 wxMouseEvent
& mouseEv
)
1136 if ( type
== EVT_WXGRID_ROW_SIZE
||
1137 type
== EVT_WXGRID_COL_SIZE
)
1139 int rowOrCol
= (row
== -1 ? col
: row
);
1141 wxGridSizeEvent
gridEvt( GetId(),
1145 mouseEv
.GetX(), mouseEv
.GetY(),
1146 mouseEv
.ControlDown(),
1147 mouseEv
.ShiftDown(),
1149 mouseEv
.MetaDown() );
1151 return GetEventHandler()->ProcessEvent(gridEvt
);
1153 else if ( type
== EVT_WXGRID_RANGE_SELECT
)
1155 wxGridRangeSelectEvent
gridEvt( GetId(),
1159 m_selectedBottomRight
,
1160 mouseEv
.ControlDown(),
1161 mouseEv
.ShiftDown(),
1163 mouseEv
.MetaDown() );
1165 return GetEventHandler()->ProcessEvent(gridEvt
);
1169 wxGridEvent
gridEvt( GetId(),
1173 mouseEv
.GetX(), mouseEv
.GetY(),
1174 mouseEv
.ControlDown(),
1175 mouseEv
.ShiftDown(),
1177 mouseEv
.MetaDown() );
1179 return GetEventHandler()->ProcessEvent(gridEvt
);
1184 // Generate a grid event of specified type and return the result
1185 // of ProcessEvent().
1187 bool wxGrid::SendEvent( const wxEventType type
,
1190 if ( type
== EVT_WXGRID_ROW_SIZE
||
1191 type
== EVT_WXGRID_COL_SIZE
)
1193 int rowOrCol
= (row
== -1 ? col
: row
);
1195 wxGridSizeEvent
gridEvt( GetId(),
1200 return GetEventHandler()->ProcessEvent(gridEvt
);
1204 wxGridEvent
gridEvt( GetId(),
1209 return GetEventHandler()->ProcessEvent(gridEvt
);
1214 void wxGrid::OnPaint( wxPaintEvent
& ev
)
1216 wxPaintDC
dc( this );
1218 if ( !m_batchCount
)
1220 // define a clipping region to avoid painting over the scroll bars
1223 if ( m_vertScrollBar
&& m_vertScrollBar
->IsShown() )
1224 vs
= m_scrollBarWidth
;
1227 if ( m_horizScrollBar
&& m_horizScrollBar
->IsShown() )
1228 hs
= m_scrollBarWidth
;
1231 GetClientSize( &cw
, &ch
);
1232 dc
.SetClippingRegion( 0, 0, cw
- vs
, ch
- hs
);
1234 HideCurrentCellHighlight( dc
);
1236 DrawLabelAreas( dc
);
1237 DrawColLabels( dc
);
1238 DrawRowLabels( dc
);
1240 DrawGridLines( dc
);
1243 // TODO: something more elegant than this...
1247 if ( m_currentCellCoords
== wxGridNoCellCoords
)
1248 m_currentCellCoords
.Set(0, 0);
1250 SetEditControlValue();
1251 ShowCellEditControl();
1252 m_firstPaint
= FALSE
;
1255 ShowCurrentCellHighlight( dc
);
1257 dc
.DestroyClippingRegion();
1262 void wxGrid::OnSize( wxSizeEvent
& ev
)
1268 void wxGrid::OnMouse( wxMouseEvent
& ev
)
1274 // ------------------------------------------------------------
1278 if ( ev
.Dragging() )
1280 m_isDragging
= TRUE
;
1282 if ( ev
.LeftIsDown() )
1284 switch( m_cursorMode
)
1286 case WXGRID_CURSOR_SELECT_CELL
:
1288 wxGridCellCoords cellCoords
;
1289 XYToCell( x
, y
, cellCoords
);
1290 if ( cellCoords
!= wxGridNoCellCoords
)
1292 if ( !IsSelection() )
1294 SelectBlock( cellCoords
, cellCoords
);
1296 else if ( !IsInSelection( cellCoords
) )
1298 SelectBlock( m_currentCellCoords
, cellCoords
);
1304 case WXGRID_CURSOR_RESIZE_ROW
:
1306 wxClientDC
dc(this);
1307 dc
.SetLogicalFunction(wxXOR
);
1308 if ( m_dragLastPos
>= 0 )
1310 dc
.DrawLine( m_left
, m_dragLastPos
,
1311 m_right
, m_dragLastPos
);
1313 dc
.DrawLine( m_left
, ev
.GetY(),
1314 m_right
, ev
.GetY());
1316 m_dragLastPos
= ev
.GetY();
1320 case WXGRID_CURSOR_RESIZE_COL
:
1322 wxClientDC
dc(this);
1323 dc
.SetLogicalFunction(wxINVERT
);
1324 if ( m_dragLastPos
>= 0 )
1326 dc
.DrawLine( m_dragLastPos
, m_top
,
1327 m_dragLastPos
, m_bottom
);
1329 dc
.DrawLine( ev
.GetX(), m_top
,
1330 ev
.GetX(), m_bottom
);
1332 m_dragLastPos
= ev
.GetX();
1336 case WXGRID_CURSOR_SELECT_ROW
:
1338 if ( (row
= YToRow( y
)) >= 0 &&
1339 !IsInSelection( row
, 0 ) )
1341 SelectRow( row
, TRUE
);
1346 case WXGRID_CURSOR_SELECT_COL
:
1348 if ( (col
= XToCol( x
)) >= 0 &&
1349 !IsInSelection( 0, col
) )
1351 SelectCol( col
, TRUE
);
1360 m_isDragging
= FALSE
;
1362 // ------------------------------------------------------------
1364 // Left mouse button down
1366 if ( ev
.LeftDown() )
1370 wxGridCellCoords cellCoords
;
1372 switch( XYToArea( x
, y
) )
1374 case WXGRID_ROWLABEL
:
1376 // don't send a label click event for a hit on the
1377 // edge of the row label - this is probably the user
1378 // wanting to resize the row
1380 if ( YToEdgeOfRow(y
) < 0 )
1383 if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK
, row
, col
, ev
) )
1385 SelectRow( row
, ev
.ShiftDown() );
1386 m_cursorMode
= WXGRID_CURSOR_SELECT_ROW
;
1392 case WXGRID_COLLABEL
:
1394 // don't send a label click event for a hit on the
1395 // edge of the col label - this is probably the user
1396 // wanting to resize the col
1398 if ( XToEdgeOfCol(x
) < 0 )
1401 if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK
, row
, col
, ev
) )
1403 SelectCol( col
, ev
.ShiftDown() );
1404 m_cursorMode
= WXGRID_CURSOR_SELECT_COL
;
1410 case WXGRID_CORNERLABEL
:
1412 // leave both row and col as -1
1414 if ( !SendEvent( EVT_WXGRID_LABEL_LEFT_CLICK
, row
, col
, ev
) )
1423 XYToCell( x
, y
, cellCoords
);
1424 if ( !SendEvent( EVT_WXGRID_CELL_LEFT_CLICK
,
1425 cellCoords
.GetRow(),
1426 cellCoords
.GetCol(),
1429 MakeCellVisible( cellCoords
);
1430 SelectCell( cellCoords
);
1437 wxLogMessage( "outside grid area" );
1442 // ------------------------------------------------------------
1444 // Left mouse button double click
1446 else if ( ev
.LeftDClick() )
1450 wxGridCellCoords cellCoords
;
1452 switch( XYToArea( x
, y
) )
1454 case WXGRID_ROWLABEL
:
1456 // don't send a label click event for a hit on the
1457 // edge of the row label - this is probably the user
1458 // wanting to resize the row
1460 if ( YToEdgeOfRow(y
) < 0 )
1463 SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK
, row
, col
, ev
);
1468 case WXGRID_COLLABEL
:
1470 // don't send a label click event for a hit on the
1471 // edge of the col label - this is probably the user
1472 // wanting to resize the col
1474 if ( XToEdgeOfCol(x
) < 0 )
1477 SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK
, row
, col
, ev
);
1482 case WXGRID_CORNERLABEL
:
1484 // leave both row and col as -1
1486 SendEvent( EVT_WXGRID_LABEL_LEFT_DCLICK
, row
, col
, ev
);
1492 XYToCell( x
, y
, cellCoords
);
1493 SendEvent( EVT_WXGRID_CELL_LEFT_DCLICK
,
1494 cellCoords
.GetRow(),
1495 cellCoords
.GetCol(),
1502 wxLogMessage( "outside grid area" );
1507 // ------------------------------------------------------------
1509 // Left mouse button released
1511 else if ( ev
.LeftUp() )
1513 switch ( m_cursorMode
)
1515 case WXGRID_CURSOR_RESIZE_ROW
:
1517 if ( m_dragLastPos
>= 0 )
1519 // erase the last line and resize the row
1521 wxClientDC
dc( this );
1522 dc
.SetLogicalFunction( wxINVERT
);
1523 dc
.DrawLine( m_left
, m_dragLastPos
,
1524 m_right
, m_dragLastPos
);
1525 HideCellEditControl();
1526 int top
= m_top
+ m_colLabelHeight
;
1527 if ( m_dragRowOrCol
> 0 )
1528 top
= m_rowBottoms
[m_dragRowOrCol
-1];
1529 m_rowHeights
[m_dragRowOrCol
] = wxMax( ev
.GetY() - top
,
1530 WXGRID_MIN_ROW_HEIGHT
);
1532 ShowCellEditControl();
1535 // Note: we are ending the event *after* doing
1536 // default processing in this case
1538 SendEvent( EVT_WXGRID_ROW_SIZE
, m_dragRowOrCol
, -1, ev
);
1543 case WXGRID_CURSOR_RESIZE_COL
:
1545 if ( m_dragLastPos
>= 0 )
1547 // erase the last line and resize the col
1549 wxClientDC
dc( this );
1550 dc
.SetLogicalFunction( wxINVERT
);
1551 dc
.DrawLine( m_left
, m_dragLastPos
,
1552 m_right
, m_dragLastPos
);
1553 HideCellEditControl();
1554 int left
= m_left
+ m_rowLabelWidth
;
1555 if ( m_dragRowOrCol
> 0 )
1556 left
= m_colRights
[m_dragRowOrCol
-1];
1557 m_colWidths
[m_dragRowOrCol
] = wxMax( ev
.GetX() - left
,
1558 WXGRID_MIN_COL_WIDTH
);
1560 ShowCellEditControl();
1563 // Note: we are ending the event *after* doing
1564 // default processing in this case
1566 SendEvent( EVT_WXGRID_COL_SIZE
, -1, m_dragRowOrCol
, ev
);
1571 case WXGRID_CURSOR_SELECT_CELL
:
1573 if ( IsSelection() )
1575 // Note: we are ending the event *after* doing
1576 // default processing in this case
1578 SendEvent( EVT_WXGRID_RANGE_SELECT
, -1, -1, ev
);
1586 // ------------------------------------------------------------
1588 // Right mouse button down
1590 else if ( ev
.RightDown() )
1594 wxGridCellCoords cellCoords
;
1596 switch( XYToArea( x
, y
) )
1599 case WXGRID_ROWLABEL
:
1602 if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK
, row
, col
, ev
) )
1604 // TODO: default processing ?
1609 case WXGRID_COLLABEL
:
1612 if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK
, row
, col
, ev
) )
1614 // TODO: default processing ?
1619 case WXGRID_CORNERLABEL
:
1621 // leave both row and col as -1
1623 if ( !SendEvent( EVT_WXGRID_LABEL_RIGHT_CLICK
, row
, col
, ev
) )
1625 // TODO: default processing ?
1632 XYToCell( x
, y
, cellCoords
);
1633 if ( !SendEvent( EVT_WXGRID_CELL_RIGHT_CLICK
,
1634 cellCoords
.GetRow(),
1635 cellCoords
.GetCol(),
1638 // TODO: default processing ?
1645 wxLogMessage( "outside grid area" );
1650 // ------------------------------------------------------------
1652 // Right mouse button double click
1654 else if ( ev
.RightDClick() )
1658 wxGridCellCoords cellCoords
;
1660 switch( XYToArea( x
, y
) )
1663 case WXGRID_ROWLABEL
:
1666 SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK
, row
, col
, ev
);
1670 case WXGRID_COLLABEL
:
1673 SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK
, row
, col
, ev
);
1677 case WXGRID_CORNERLABEL
:
1679 // leave both row and col as -1
1681 SendEvent( EVT_WXGRID_LABEL_RIGHT_DCLICK
, row
, col
, ev
);
1687 XYToCell( x
, y
, cellCoords
);
1688 SendEvent( EVT_WXGRID_CELL_RIGHT_DCLICK
,
1689 cellCoords
.GetRow(),
1690 cellCoords
.GetCol(),
1697 wxLogMessage( "outside grid area" );
1702 // ------------------------------------------------------------
1704 // No buttons down and mouse moving
1706 else if ( ev
.Moving() )
1708 switch( XYToArea( x
, y
) )
1710 case WXGRID_ROWLABEL
:
1712 m_dragRowOrCol
= YToEdgeOfRow( y
);
1713 if ( m_dragRowOrCol
>= 0 )
1715 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1717 m_cursorMode
= WXGRID_CURSOR_RESIZE_ROW
;
1718 SetCursor( m_rowResizeCursor
);
1723 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1725 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1726 SetCursor( *wxSTANDARD_CURSOR
);
1732 case WXGRID_COLLABEL
:
1734 m_dragRowOrCol
= XToEdgeOfCol( x
);
1735 if ( m_dragRowOrCol
>= 0 )
1737 if ( m_cursorMode
== WXGRID_CURSOR_SELECT_CELL
)
1739 m_cursorMode
= WXGRID_CURSOR_RESIZE_COL
;
1740 SetCursor( m_colResizeCursor
);
1745 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1747 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1748 SetCursor( *wxSTANDARD_CURSOR
);
1756 if ( m_cursorMode
!= WXGRID_CURSOR_SELECT_CELL
)
1758 m_cursorMode
= WXGRID_CURSOR_SELECT_CELL
;
1759 SetCursor( *wxSTANDARD_CURSOR
);
1768 void wxGrid::OnKeyDown( wxKeyEvent
& ev
)
1770 if ( m_inOnKeyDown
)
1772 // shouldn't be here - we are going round in circles...
1774 wxLogFatalError( "wxGrid::OnKeyDown called while alread active" );
1777 m_inOnKeyDown
= TRUE
;
1779 // propagate the event up and see if it gets processed
1781 wxWindow
*parent
= GetParent();
1782 wxKeyEvent
keyEvt( ev
);
1783 keyEvt
.SetEventObject( parent
);
1785 if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt
) )
1787 // try local handlers
1789 switch ( ev
.KeyCode() )
1792 if ( ev
.ControlDown() )
1794 MoveCursorUpBlock();
1803 if ( ev
.ControlDown() )
1805 MoveCursorDownBlock();
1814 if ( ev
.ControlDown() )
1816 MoveCursorLeftBlock();
1825 if ( ev
.ControlDown() )
1827 MoveCursorRightBlock();
1840 if ( ev
.ControlDown() )
1842 MakeCellVisible( 0, 0 );
1852 if ( ev
.ControlDown() )
1854 MakeCellVisible( m_numRows
-1, m_numCols
-1 );
1855 SelectCell( m_numRows
-1, m_numCols
-1 );
1872 // now try the cell edit control
1874 if ( IsCellEditControlEnabled() )
1876 ev
.SetEventObject( m_cellEditCtrl
);
1877 m_cellEditCtrl
->GetEventHandler()->ProcessEvent( ev
);
1883 m_inOnKeyDown
= FALSE
;
1887 // Text updated in an edit control - either a text control or a
1890 void wxGrid::OnText( wxKeyEvent
& ev
)
1895 wxWindow
*ctrl
= (wxWindow
*)ev
.GetEventObject();
1897 if ( ctrl
== m_cellEditCtrl
&&
1898 IsTopEditControlEnabled() )
1900 // set the value of the top edit control
1902 switch ( m_editCtrlType
)
1904 case wxGRID_TEXTCTRL
:
1905 ((wxTextCtrl
*)m_topEditCtrl
)->
1906 SetValue(((wxTextCtrl
*)ctrl
)->GetValue());
1909 case wxGRID_COMBOBOX
:
1910 ((wxComboBox
*)m_topEditCtrl
)->
1911 SetValue(((wxComboBox
*)ctrl
)->GetValue());
1915 else if ( ctrl
== m_topEditCtrl
&&
1916 IsCellEditControlEnabled() )
1918 switch ( m_editCtrlType
)
1920 case wxGRID_TEXTCTRL
:
1921 ((wxTextCtrl
*)m_cellEditCtrl
)->
1922 SetValue(((wxTextCtrl
*)ctrl
)->GetValue());
1925 case wxGRID_COMBOBOX
:
1926 ((wxComboBox
*)m_cellEditCtrl
)->
1927 SetValue(((wxComboBox
*)ctrl
)->GetValue());
1936 void wxGrid::OnGridScroll( wxScrollEvent
& ev
)
1938 // propagate the event up and see if it gets processed
1940 wxWindow
*parent
= GetParent();
1941 wxScrollEvent
scrollEvt( ev
);
1942 if (parent
->GetEventHandler()->ProcessEvent( scrollEvt
)) return;
1944 HideCellEditControl();
1946 if ( ev
.GetEventObject() == m_horizScrollBar
)
1948 if ( ev
.GetPosition() != m_scrollPosX
)
1950 SetHorizontalScrollPos( ev
.GetPosition() );
1955 if ( ev
.GetPosition() != m_scrollPosY
)
1957 SetVerticalScrollPos( ev
.GetPosition() );
1961 ShowCellEditControl();
1965 void wxGrid::SelectCell( const wxGridCellCoords
& coords
)
1967 wxClientDC
dc( this );
1969 if ( m_currentCellCoords
!= wxGridNoCellCoords
)
1971 HideCurrentCellHighlight( dc
);
1972 HideCellEditControl();
1973 SaveEditControlValue();
1976 m_currentCellCoords
= coords
;
1978 SetEditControlValue();
1981 ShowCellEditControl();
1982 ShowCurrentCellHighlight( dc
);
1985 if ( IsSelection() )
1988 if ( !GetBatchCount() ) Refresh();
1993 void wxGrid::ShowCellEditControl()
1997 if ( IsCellEditControlEnabled() )
1999 if ( !IsVisible( m_currentCellCoords
) )
2005 rect
= CellToRect( m_currentCellCoords
);
2007 m_cellEditCtrl
->SetSize( rect
);
2008 m_cellEditCtrl
->Show( TRUE
);
2010 switch ( m_editCtrlType
)
2012 case wxGRID_TEXTCTRL
:
2013 ((wxTextCtrl
*) m_cellEditCtrl
)->SetInsertionPointEnd();
2016 case wxGRID_CHECKBOX
:
2017 // TODO: anything ???
2022 // TODO: anything ???
2026 case wxGRID_COMBOBOX
:
2027 // TODO: anything ???
2032 m_cellEditCtrl
->SetFocus();
2038 void wxGrid::HideCellEditControl()
2040 if ( IsCellEditControlEnabled() )
2042 m_cellEditCtrl
->Show( FALSE
);
2046 void wxGrid::SetEditControlValue( const wxString
& value
)
2051 s
= ( value
== wxEmptyString
? GetCellValue(m_currentCellCoords
) : value
);
2053 if ( IsTopEditControlEnabled() )
2055 switch ( m_editCtrlType
)
2057 case wxGRID_TEXTCTRL
:
2058 ((wxGridTextCtrl
*)m_topEditCtrl
)->SetStartValue(s
);
2061 case wxGRID_CHECKBOX
:
2062 // TODO: implement this
2067 // TODO: implement this
2071 case wxGRID_COMBOBOX
:
2072 // TODO: implement this
2078 if ( IsCellEditControlEnabled() )
2080 switch ( m_editCtrlType
)
2082 case wxGRID_TEXTCTRL
:
2083 ((wxGridTextCtrl
*)m_cellEditCtrl
)->SetStartValue(s
);
2086 case wxGRID_CHECKBOX
:
2087 // TODO: implement this
2092 // TODO: implement this
2096 case wxGRID_COMBOBOX
:
2097 // TODO: implement this
2105 void wxGrid::SaveEditControlValue()
2109 wxWindow
*ctrl
= (wxWindow
*)NULL
;
2111 if ( IsCellEditControlEnabled() )
2113 ctrl
= m_cellEditCtrl
;
2115 else if ( IsTopEditControlEnabled() )
2117 ctrl
= m_topEditCtrl
;
2124 bool valueChanged
= FALSE
;
2126 switch ( m_editCtrlType
)
2128 case wxGRID_TEXTCTRL
:
2129 valueChanged
= (((wxGridTextCtrl
*)ctrl
)->GetValue() !=
2130 ((wxGridTextCtrl
*)ctrl
)->GetStartValue());
2131 SetCellValue( m_currentCellCoords
,
2132 ((wxTextCtrl
*) ctrl
)->GetValue() );
2135 case wxGRID_CHECKBOX
:
2136 // TODO: implement this
2141 // TODO: implement this
2145 case wxGRID_COMBOBOX
:
2146 // TODO: implement this
2153 SendEvent( EVT_WXGRID_CELL_CHANGE
,
2154 m_currentCellCoords
.GetRow(),
2155 m_currentCellCoords
.GetCol() );
2161 int wxGrid::XYToArea( int x
, int y
)
2163 if ( x
> m_left
&& x
< m_right
&&
2164 y
> m_top
&& y
< m_bottom
)
2166 if ( y
< m_top
+ m_colLabelHeight
)
2168 if ( x
> m_left
+ m_rowLabelWidth
)
2170 return WXGRID_COLLABEL
;
2174 return WXGRID_CORNERLABEL
;
2177 else if ( x
<= m_left
+ m_rowLabelWidth
)
2179 return WXGRID_ROWLABEL
;
2187 return WXGRID_NOAREA
;
2191 void wxGrid::XYToCell( int x
, int y
, wxGridCellCoords
& coords
)
2193 coords
.SetRow( YToRow(y
) );
2194 coords
.SetCol( XToCol(x
) );
2198 int wxGrid::YToRow( int y
)
2202 if ( y
> m_top
+ m_colLabelHeight
)
2204 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
2206 if ( y
< m_rowBottoms
[i
] )
2217 int wxGrid::XToCol( int x
)
2221 if ( x
> m_left
+ m_rowLabelWidth
)
2223 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
2225 if ( x
< m_colRights
[i
] )
2236 // return the row number that that the y coord is near the edge of, or
2237 // -1 if not near an edge
2239 int wxGrid::YToEdgeOfRow( int y
)
2243 if ( y
> m_top
+ m_colLabelHeight
)
2245 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
2247 if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE
)
2249 d
= abs( y
- m_rowBottoms
[i
] );
2251 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
2262 // return the col number that that the x coord is near the edge of, or
2263 // -1 if not near an edge
2265 int wxGrid::XToEdgeOfCol( int x
)
2269 if ( x
> m_left
+ m_rowLabelWidth
)
2271 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
2273 if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE
)
2275 d
= abs( x
- m_colRights
[i
] );
2277 if ( d
< WXGRID_LABEL_EDGE_ZONE
) return i
;
2288 wxRect
wxGrid::CellToRect( int row
, int col
)
2290 wxRect
rect( -1, -1, -1, -1 );
2292 if ( row
>= m_scrollPosY
&& col
>= m_scrollPosX
)
2294 rect
.x
= m_colRights
[col
] - m_colWidths
[col
];
2295 rect
.y
= m_rowBottoms
[row
] - m_rowHeights
[row
];
2296 rect
.width
= m_colWidths
[col
];
2297 rect
.height
= m_rowHeights
[ row
];
2304 bool wxGrid::MoveCursorUp()
2306 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2307 m_currentCellCoords
.GetRow() > 0 )
2309 SelectCell( m_currentCellCoords
.GetRow() - 1,
2310 m_currentCellCoords
.GetCol() );
2312 if ( !IsVisible( m_currentCellCoords
) )
2313 MakeCellVisible( m_currentCellCoords
);
2321 bool wxGrid::MoveCursorDown()
2323 // TODO: allow for scrolling
2325 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2326 m_currentCellCoords
.GetRow() < m_numRows
-1 )
2328 SelectCell( m_currentCellCoords
.GetRow() + 1,
2329 m_currentCellCoords
.GetCol() );
2331 if ( !IsVisible( m_currentCellCoords
) )
2332 MakeCellVisible( m_currentCellCoords
);
2340 bool wxGrid::MoveCursorLeft()
2342 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2343 m_currentCellCoords
.GetCol() > 0 )
2345 SelectCell( m_currentCellCoords
.GetRow(),
2346 m_currentCellCoords
.GetCol() - 1 );
2348 if ( !IsVisible( m_currentCellCoords
) )
2349 MakeCellVisible( m_currentCellCoords
);
2357 bool wxGrid::MoveCursorRight()
2359 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2360 m_currentCellCoords
.GetCol() < m_numCols
- 1 )
2362 SelectCell( m_currentCellCoords
.GetRow(),
2363 m_currentCellCoords
.GetCol() + 1 );
2365 if ( !IsVisible( m_currentCellCoords
) )
2366 MakeCellVisible( m_currentCellCoords
);
2374 bool wxGrid::MovePageUp()
2376 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2379 int row
= m_currentCellCoords
.GetRow();
2380 int y
= m_rowBottoms
[ row
] - m_rowHeights
[ row
];
2383 if ( y
+ m_rowHeights
[row
-1] > m_bottom
) break;
2384 y
+= m_rowHeights
[ --row
];
2386 SetVerticalScrollPos( row
);
2388 SelectCell( row
, m_currentCellCoords
.GetCol() );
2395 bool wxGrid::MovePageDown()
2397 if ( m_currentCellCoords
!= wxGridNoCellCoords
&&
2398 m_scrollPosY
+ m_wholeRowsVisible
< m_numRows
)
2400 if ( m_wholeRowsVisible
> 0 )
2402 SetVerticalScrollPos( m_scrollPosY
+ m_wholeRowsVisible
);
2404 else if ( m_scrollPosY
< m_numRows
- 1 )
2406 SetVerticalScrollPos( m_scrollPosY
+ 1 );
2413 // m_scrollPosY will have been updated
2415 SelectCell( m_scrollPosY
, m_currentCellCoords
.GetCol() );
2422 bool wxGrid::MoveCursorUpBlock()
2425 m_currentCellCoords
!= wxGridNoCellCoords
&&
2426 m_currentCellCoords
.GetRow() > 0 )
2428 int row
= m_currentCellCoords
.GetRow();
2429 int col
= m_currentCellCoords
.GetCol();
2431 if ( m_table
->IsEmptyCell(row
, col
) )
2433 // starting in an empty cell: find the next block of
2439 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2442 else if ( m_table
->IsEmptyCell(row
-1, col
) )
2444 // starting at the top of a block: find the next block
2450 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2455 // starting within a block: find the top of the block
2460 if ( m_table
->IsEmptyCell(row
, col
) )
2468 SelectCell( row
, col
);
2470 if ( !IsVisible( m_currentCellCoords
) )
2471 MakeCellVisible( m_currentCellCoords
);
2479 bool wxGrid::MoveCursorDownBlock()
2482 m_currentCellCoords
!= wxGridNoCellCoords
&&
2483 m_currentCellCoords
.GetRow() < m_numRows
-1 )
2485 int row
= m_currentCellCoords
.GetRow();
2486 int col
= m_currentCellCoords
.GetCol();
2488 if ( m_table
->IsEmptyCell(row
, col
) )
2490 // starting in an empty cell: find the next block of
2493 while ( row
< m_numRows
-1 )
2496 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2499 else if ( m_table
->IsEmptyCell(row
+1, col
) )
2501 // starting at the bottom of a block: find the next block
2504 while ( row
< m_numRows
-1 )
2507 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2512 // starting within a block: find the bottom of the block
2514 while ( row
< m_numRows
-1 )
2517 if ( m_table
->IsEmptyCell(row
, col
) )
2525 SelectCell( row
, col
);
2527 if ( !IsVisible( m_currentCellCoords
) )
2528 MakeCellVisible( m_currentCellCoords
);
2536 bool wxGrid::MoveCursorLeftBlock()
2539 m_currentCellCoords
!= wxGridNoCellCoords
&&
2540 m_currentCellCoords
.GetCol() > 0 )
2542 int row
= m_currentCellCoords
.GetRow();
2543 int col
= m_currentCellCoords
.GetCol();
2545 if ( m_table
->IsEmptyCell(row
, col
) )
2547 // starting in an empty cell: find the next block of
2553 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2556 else if ( m_table
->IsEmptyCell(row
, col
-1) )
2558 // starting at the left of a block: find the next block
2564 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2569 // starting within a block: find the left of the block
2574 if ( m_table
->IsEmptyCell(row
, col
) )
2582 SelectCell( row
, col
);
2584 if ( !IsVisible( m_currentCellCoords
) )
2585 MakeCellVisible( m_currentCellCoords
);
2593 bool wxGrid::MoveCursorRightBlock()
2596 m_currentCellCoords
!= wxGridNoCellCoords
&&
2597 m_currentCellCoords
.GetCol() < m_numCols
-1 )
2599 int row
= m_currentCellCoords
.GetRow();
2600 int col
= m_currentCellCoords
.GetCol();
2602 if ( m_table
->IsEmptyCell(row
, col
) )
2604 // starting in an empty cell: find the next block of
2607 while ( col
< m_numCols
-1 )
2610 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2613 else if ( m_table
->IsEmptyCell(row
, col
+1) )
2615 // starting at the right of a block: find the next block
2618 while ( col
< m_numCols
-1 )
2621 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break;
2626 // starting within a block: find the right of the block
2628 while ( col
< m_numCols
-1 )
2631 if ( m_table
->IsEmptyCell(row
, col
) )
2639 SelectCell( row
, col
);
2641 if ( !IsVisible( m_currentCellCoords
) )
2642 MakeCellVisible( m_currentCellCoords
);
2653 // ----- grid drawing functions
2656 void wxGrid::DrawLabelAreas( wxDC
& dc
)
2659 GetClientSize(&cw
, &ch
);
2661 dc
.SetPen(*wxTRANSPARENT_PEN
);
2662 dc
.SetBrush( wxBrush(GetLabelBackgroundColour(), wxSOLID
) );
2664 dc
.DrawRectangle( m_left
, m_top
,
2665 cw
- m_left
, m_colLabelHeight
);
2667 dc
.DrawRectangle( m_left
, m_top
,
2668 m_rowLabelWidth
, ch
- m_top
);
2672 void wxGrid::DrawColLabels( wxDC
& dc
)
2675 GetClientSize(&cw
, &ch
);
2677 if (m_colLabelHeight
== 0) return;
2679 DrawColLabelBorders( dc
);
2683 rect
.height
= m_colLabelHeight
- 1;
2685 int labelLeft
= m_left
+ m_rowLabelWidth
;
2688 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
2690 if ( labelLeft
> cw
) break;
2692 rect
.x
= 1 + labelLeft
;
2693 rect
.width
= m_colWidths
[i
];
2694 DrawColLabel( dc
, rect
, i
);
2696 labelLeft
+= m_colWidths
[i
];
2701 void wxGrid::DrawColLabelBorders( wxDC
& dc
)
2703 if ( m_colLabelHeight
<= 0 ) return;
2707 GetClientSize( &cw
, &ch
);
2709 dc
.SetPen( *wxBLACK_PEN
);
2713 dc
.DrawLine( m_left
, m_top
, cw
, m_top
);
2715 dc
.DrawLine( m_left
, m_top
+ m_colLabelHeight
,
2716 cw
, m_top
+ m_colLabelHeight
);
2720 int colLeft
= m_left
+ m_rowLabelWidth
;
2721 for ( i
= m_scrollPosX
; i
<= m_numCols
; i
++ )
2723 if (colLeft
> cw
) break;
2725 dc
.DrawLine( colLeft
, m_top
,
2726 colLeft
, m_top
+ m_colLabelHeight
);
2728 if ( i
< m_numCols
) colLeft
+= m_colWidths
[i
];
2731 // Draw white highlights for a 3d effect
2733 dc
.SetPen( *wxWHITE_PEN
);
2735 colLeft
= m_left
+ m_rowLabelWidth
;
2736 for ( i
= m_scrollPosX
; i
< m_numCols
; i
++ )
2738 if (colLeft
> cw
) break;
2740 dc
.DrawLine(colLeft
+ 1, m_top
+ 1,
2741 colLeft
+ m_colWidths
[i
], m_top
+ 1);
2743 dc
.DrawLine(colLeft
+ 1, m_top
+ 1,
2744 colLeft
+ 1, m_top
+ m_colLabelHeight
);
2746 colLeft
+= m_colWidths
[i
];
2751 void wxGrid::DrawColLabel( wxDC
& dc
, const wxRect
& rect
, int col
)
2760 dc
.SetBackgroundMode( wxTRANSPARENT
);
2761 dc
.SetTextBackground( GetLabelBackgroundColour() );
2762 dc
.SetTextForeground( GetLabelTextColour() );
2763 dc
.SetFont( GetLabelFont() );
2766 GetColLabelAlignment( &hAlign
, &vAlign
);
2767 DrawTextRectangle( dc
, GetColLabelValue( col
), rect2
, hAlign
, vAlign
);
2771 void wxGrid::DrawRowLabels( wxDC
& dc
)
2774 GetClientSize(&cw
, &ch
);
2776 if (m_rowLabelWidth
== 0) return;
2778 DrawRowLabelBorders( dc
);
2781 rect
.x
= m_left
+ 1;
2782 rect
.width
= m_rowLabelWidth
- 1;
2784 int labelTop
= m_top
+ m_colLabelHeight
;
2787 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
2789 if ( labelTop
> ch
) break;
2791 rect
.y
= 1 + labelTop
;
2792 rect
.height
= m_rowHeights
[i
];
2793 DrawRowLabel( dc
, rect
, i
);
2795 labelTop
+= m_rowHeights
[i
];
2800 void wxGrid::DrawRowLabelBorders( wxDC
& dc
)
2802 if ( m_rowLabelWidth
<= 0 ) return;
2806 GetClientSize( &cw
, &ch
);
2808 dc
.SetPen( *wxBLACK_PEN
);
2812 dc
.DrawLine( m_left
, m_top
, m_left
, ch
);
2814 dc
.DrawLine( m_left
+ m_rowLabelWidth
, m_top
,
2815 m_left
+ m_rowLabelWidth
, ch
);
2819 int rowTop
= m_top
+ m_colLabelHeight
;
2820 for ( i
= m_scrollPosY
; i
<= m_numRows
; i
++ )
2822 if ( rowTop
> ch
) break;
2824 dc
.DrawLine( m_left
, rowTop
,
2825 m_left
+ m_rowLabelWidth
, rowTop
);
2827 if ( i
< m_numRows
) rowTop
+= m_rowHeights
[i
];
2830 // Draw white highlights for a 3d effect
2832 dc
.SetPen( *wxWHITE_PEN
);
2834 rowTop
= m_top
+ m_colLabelHeight
;
2835 for ( i
= m_scrollPosY
; i
< m_numRows
; i
++ )
2837 if ( rowTop
> ch
) break;
2839 dc
.DrawLine( m_left
+ 1, rowTop
+ 1,
2840 m_left
+ m_rowLabelWidth
, rowTop
+ 1 );
2842 dc
.DrawLine( m_left
+ 1, rowTop
+ 1,
2843 m_left
+ 1, rowTop
+ m_rowHeights
[i
] );
2845 rowTop
+= m_rowHeights
[i
];
2850 void wxGrid::DrawRowLabel( wxDC
& dc
, const wxRect
& rect
, int row
)
2859 dc
.SetBackgroundMode( wxTRANSPARENT
);
2860 dc
.SetTextBackground( GetLabelBackgroundColour() );
2861 dc
.SetTextForeground( GetLabelTextColour() );
2862 dc
.SetFont( GetLabelFont() );
2865 GetRowLabelAlignment( &hAlign
, &vAlign
);
2866 DrawTextRectangle( dc
, GetRowLabelValue( row
), rect2
, hAlign
, vAlign
);
2870 void wxGrid::DrawCellArea( wxDC
& dc
)
2873 GetClientSize(&cw
, &ch
);
2875 dc
.SetPen( *wxTRANSPARENT_PEN
);
2876 dc
.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID
) );
2878 int left
= m_left
+ m_rowLabelWidth
+ 1;
2879 int top
= m_top
+ m_colLabelHeight
+ 1;
2881 dc
.DrawRectangle( left
, top
, cw
- left
, ch
- top
);
2885 void wxGrid::DrawGridLines( wxDC
& dc
)
2887 if ( !m_gridLinesEnabled
|| !m_numRows
|| !m_numCols
) return;
2891 GetClientSize(&cw
, &ch
);
2893 dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) );
2895 // horizontal grid lines
2897 int rowTop
= m_top
+ m_colLabelHeight
+ m_rowHeights
[m_scrollPosY
];
2898 for ( i
= m_scrollPosY
+ 1; i
<= m_numRows
; i
++ )
2900 if ( rowTop
> ch
) break;
2902 dc
.DrawLine( m_left
+ m_rowLabelWidth
+ 1, rowTop
,
2905 if ( i
< m_numRows
) rowTop
+= m_rowHeights
[i
];
2909 // vertical grid lines
2911 int colLeft
= m_left
+ m_rowLabelWidth
+ m_colWidths
[m_scrollPosX
];
2912 for ( i
= m_scrollPosX
+ 1; i
<= m_numCols
; i
++ )
2914 if ( colLeft
> cw
) break;
2916 dc
.DrawLine( colLeft
, m_top
+ m_colLabelHeight
+ 1,
2917 colLeft
, m_bottom
);
2919 if ( i
< m_numCols
) colLeft
+= m_colWidths
[i
];
2924 void wxGrid::DrawCells( wxDC
& dc
)
2926 if ( !m_numRows
|| !m_numCols
) return;
2931 GetClientSize( &cw
, &ch
);
2937 rect
.y
= m_top
+ m_colLabelHeight
;
2938 for ( row
= m_scrollPosY
; row
< m_numRows
; row
++ )
2940 if ( rect
.y
> ch
) break;
2942 rect
.height
= m_rowHeights
[ row
];
2943 rect
.x
= m_left
+ m_rowLabelWidth
;
2945 for ( col
= m_scrollPosX
; col
< m_numCols
; col
++ )
2947 if ( rect
.x
> cw
) break;
2949 rect
.width
= m_colWidths
[col
];
2950 DrawCellBackground( dc
, rect
, row
, col
);
2951 DrawCellValue( dc
, rect
, row
, col
);
2952 rect
.x
+= rect
.width
;
2954 rect
.y
+= rect
.height
;
2960 void wxGrid::DrawCellBackground( wxDC
& dc
, const wxRect
& rect
, int row
, int col
)
2969 dc
.SetBackgroundMode( wxSOLID
);
2971 if ( IsInSelection( row
, col
) )
2973 // TODO: improve this
2975 dc
.SetBrush( *wxBLACK_BRUSH
);
2979 dc
.SetBrush( wxBrush(GetCellBackgroundColour(row
, col
), wxSOLID
) );
2981 dc
.SetPen( *wxTRANSPARENT_PEN
);
2982 dc
.DrawRectangle( rect2
);
2986 void wxGrid::DrawCellValue( wxDC
& dc
, const wxRect
& rect
, int row
, int col
)
2995 dc
.SetBackgroundMode( wxTRANSPARENT
);
2997 if ( IsInSelection( row
, col
) )
2999 // TODO: improve this
3001 dc
.SetTextBackground( wxColour(0, 0, 0) );
3002 dc
.SetTextForeground( wxColour(255, 255, 255) );
3006 dc
.SetTextBackground( GetCellBackgroundColour(row
, col
) );
3007 dc
.SetTextForeground( GetCellTextColour(row
, col
) );
3009 dc
.SetFont( GetCellFont(row
, col
) );
3012 GetCellAlignment( row
, col
, &hAlign
, &vAlign
);
3013 DrawTextRectangle( dc
, GetCellValue( row
, col
), rect2
, hAlign
, vAlign
);
3017 void wxGrid::DrawCellHighlight( wxDC
& dc
, int row
, int col
)
3019 // TODO: bounds checking on row, col ?
3022 if ( row
>= m_scrollPosY
&& col
>= m_scrollPosX
)
3027 GetClientSize( &cw
, &ch
);
3029 x
= m_colRights
[col
] - m_colWidths
[col
];
3030 if ( x
>= cw
) return;
3032 y
= m_rowBottoms
[row
] - m_rowHeights
[row
];
3033 if ( y
>= ch
) return;
3035 dc
.SetLogicalFunction( wxXOR
);
3036 dc
.SetPen( wxPen(GetCellHighlightColour(), 2, wxSOLID
) );
3037 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
3039 dc
.DrawRectangle( x
, y
,
3040 m_colWidths
[col
] + 2,
3041 m_rowHeights
[row
] + 2 );
3043 dc
.SetLogicalFunction( wxCOPY
);
3048 // This function is handy when you just want to update one or a few
3049 // cells. For example, it is used by SetCellValue()
3051 void wxGrid::DrawCell( int row
, int col
)
3053 if ( !GetBatchCount() )
3055 if ( !IsVisible( wxGridCellCoords(row
, col
) ) ) return;
3058 GetClientSize( &cw
, &ch
);
3060 wxRect
rect( CellToRect( row
, col
) );
3064 wxClientDC
dc( this );
3065 DrawCellBackground( dc
, rect
, row
, col
);
3066 DrawCellValue( dc
, rect
, row
, col
);
3072 // this is just to make other code more obvious
3074 void wxGrid::HideCurrentCellHighlight( wxDC
& dc
)
3076 if ( m_currentCellHighlighted
&&
3077 m_currentCellCoords
!= wxGridNoCellCoords
)
3079 DrawCellHighlight( dc
, m_currentCellCoords
);
3080 m_currentCellHighlighted
= FALSE
;
3085 // this is just to make other code more obvious
3087 void wxGrid::ShowCurrentCellHighlight( wxDC
& dc
)
3089 if ( !m_currentCellHighlighted
&&
3090 m_currentCellCoords
!= wxGridNoCellCoords
)
3092 DrawCellHighlight( dc
, m_currentCellCoords
);
3093 m_currentCellHighlighted
= TRUE
;
3098 void wxGrid::DrawTextRectangle( wxDC
& dc
,
3099 const wxString
& value
,
3104 long textWidth
, textHeight
;
3105 long lineWidth
, lineHeight
;
3106 wxArrayString lines
;
3108 // see if we are already clipping
3111 dc
.GetClippingBox( clipRect
);
3113 bool alreadyClipping
= TRUE
;
3114 wxRect intersectRect
;
3116 if ( clipRect
.x
== 0 && clipRect
.y
== 0 &&
3117 clipRect
.width
== 0 && clipRect
.height
== 0)
3119 alreadyClipping
= FALSE
;
3120 intersectRect
= rect
;
3124 // Find the intersection of the clipping rectangle and our
3127 wxRegion
region( rect
);
3128 region
.Intersect( clipRect
);
3129 if ( region
.IsEmpty() )
3135 intersectRect
= region
.GetBox();
3138 if ( alreadyClipping
) dc
.DestroyClippingRegion();
3140 dc
.SetClippingRegion( intersectRect
);
3142 StringToLines( value
, lines
);
3143 if ( lines
.GetCount() )
3145 GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight
);
3146 dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight
);
3149 switch ( horizAlign
)
3152 x
= rect
.x
+ (rect
.width
- textWidth
- 1.0);
3156 x
= rect
.x
+ ((rect
.width
- textWidth
)/2.0);
3165 switch ( vertAlign
)
3168 y
= rect
.y
+ (rect
.height
- textHeight
- 1);
3172 y
= rect
.y
+ ((rect
.height
- textHeight
)/2.0);
3181 for ( size_t i
= 0; i
< lines
.GetCount(); i
++ )
3183 dc
.DrawText( lines
[i
], (long)x
, (long)y
);
3188 dc
.DestroyClippingRegion();
3189 if (alreadyClipping
) dc
.SetClippingRegion( clipRect
);
3193 // Split multi line text up into an array of strings. Any existing
3194 // contents of the string array are preserved.
3196 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines
)
3198 // TODO: this won't work for WXMAC ? (lines end with '\r')
3199 // => use wxTextFile functions then (VZ)
3202 while ( startPos
< (int)value
.Length() )
3204 pos
= value
.Mid(startPos
).Find( '\n' );
3209 else if ( pos
== 0 )
3211 lines
.Add( wxEmptyString
);
3215 if ( value
[startPos
+pos
-1] == '\r' )
3217 lines
.Add( value
.Mid(startPos
, pos
-1) );
3221 lines
.Add( value
.Mid(startPos
, pos
) );
3226 if ( startPos
< (int)value
.Length() )
3228 lines
.Add( value
.Mid( startPos
) );
3233 void wxGrid::GetTextBoxSize( wxDC
& dc
,
3234 wxArrayString
& lines
,
3235 long *width
, long *height
)
3242 for ( i
= 0; i
< lines
.GetCount(); i
++ )
3244 dc
.GetTextExtent( lines
[i
], &lineW
, &lineH
);
3245 w
= wxMax( w
, lineW
);
3255 // ------ functions to get/send data (see also public functions)
3258 bool wxGrid::GetModelValues()
3262 // all we need to do is repaint the grid
3272 bool wxGrid::SetModelValues()
3278 for ( row
= m_scrollPosY
; row
< m_numRows
; row
++ )
3280 for ( col
= m_scrollPosX
; col
< m_numCols
; col
++ )
3282 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) );
3294 // ------ public functions
3297 bool wxGrid::CreateGrid( int numRows
, int numCols
)
3301 wxLogError( "wxGrid::CreateGrid(numRows, numCols) called more than once" );
3306 m_numRows
= numRows
;
3307 m_numCols
= numCols
;
3309 m_table
= new wxGridStringTable( m_numRows
, m_numCols
);
3310 m_table
->SetView( this );
3319 // The behaviour of this function depends on the grid table class
3320 // Clear() function. For the default wxGridStringTable class the
3321 // behavious is to replace all cell contents with wxEmptyString but
3322 // not to change the number of rows or cols.
3324 void wxGrid::ClearGrid()
3329 SetEditControlValue();
3330 if ( !GetBatchCount() ) Refresh();
3335 bool wxGrid::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
3337 // TODO: something with updateLabels flag
3341 wxLogError( "Called wxGrid::InsertRows() before calling CreateGrid()" );
3347 bool ok
= m_table
->InsertRows( pos
, numRows
);
3349 // the table will have sent the results of the insert row
3350 // operation to this view object as a grid table message
3354 if ( !GetBatchCount() ) Refresh();
3356 SetEditControlValue();
3365 bool wxGrid::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) )
3367 // TODO: something with updateLabels flag
3371 wxLogError( "Called wxGrid::AppendRows() before calling CreateGrid()" );
3375 if ( m_table
&& m_table
->AppendRows( numRows
) )
3377 // the table will have sent the results of the append row
3378 // operation to this view object as a grid table message
3380 if ( !GetBatchCount() ) Refresh();
3389 bool wxGrid::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) )
3391 // TODO: something with updateLabels flag
3395 wxLogError( "Called wxGrid::DeleteRows() before calling CreateGrid()" );
3399 if ( m_table
&& m_table
->DeleteRows( pos
, numRows
) )
3401 // the table will have sent the results of the delete row
3402 // operation to this view object as a grid table message
3404 if ( m_numRows
> 0 )
3405 SetEditControlValue();
3407 HideCellEditControl();
3409 if ( !GetBatchCount() ) Refresh();
3418 bool wxGrid::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
3420 // TODO: something with updateLabels flag
3424 wxLogError( "Called wxGrid::InsertCols() before calling CreateGrid()" );
3430 HideCellEditControl();
3431 bool ok
= m_table
->InsertCols( pos
, numCols
);
3434 // the table will have sent the results of the insert col
3435 // operation to this view object as a grid table message
3437 if ( !GetBatchCount() ) Refresh();
3439 SetEditControlValue();
3448 bool wxGrid::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) )
3450 // TODO: something with updateLabels flag
3454 wxLogError( "Called wxGrid::AppendCols() before calling CreateGrid()" );
3458 if ( m_table
&& m_table
->AppendCols( numCols
) )
3460 // the table will have sent the results of the append col
3461 // operation to this view object as a grid table message
3463 if ( !GetBatchCount() ) Refresh();
3472 bool wxGrid::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) )
3474 // TODO: something with updateLabels flag
3478 wxLogError( "Called wxGrid::DeleteCols() before calling CreateGrid()" );
3482 if ( m_table
&& m_table
->DeleteCols( pos
, numCols
) )
3484 // the table will have sent the results of the delete col
3485 // operation to this view object as a grid table message
3487 if ( m_numCols
> 0 )
3488 SetEditControlValue();
3490 HideCellEditControl();
3492 if ( !GetBatchCount() ) Refresh();
3504 // ------ control panel and cell edit control
3507 void wxGrid::EnableEditing( bool edit
)
3509 // TODO: improve this ?
3511 if ( edit
!= m_editable
)
3514 if ( !m_editable
) HideCellEditControl();
3515 m_topEditCtrlEnabled
= m_editable
;
3516 m_cellEditCtrlEnabled
= m_editable
;
3517 if ( !m_editable
) ShowCellEditControl();
3522 void wxGrid::EnableTopEditControl( bool enable
)
3524 if ( enable
!= m_topEditCtrlEnabled
)
3526 HideCellEditControl();
3527 m_topEditCtrlEnabled
= enable
;
3529 m_topEditCtrl
->Show( enable
);
3531 if ( m_currentCellCoords
!= wxGridNoCellCoords
)
3532 SetEditControlValue();
3534 ShowCellEditControl();
3535 if ( !GetBatchCount() ) Refresh();
3539 void wxGrid::EnableCellEditControl( bool enable
)
3541 if ( m_cellEditCtrl
&&
3542 enable
!= m_cellEditCtrlEnabled
)
3544 HideCellEditControl();
3545 SaveEditControlValue();
3547 m_cellEditCtrlEnabled
= enable
;
3549 SetEditControlValue();
3550 ShowCellEditControl();
3556 // ------ grid formatting functions
3559 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert
)
3561 *horiz
= m_rowLabelHorizAlign
;
3562 *vert
= m_rowLabelVertAlign
;
3565 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert
)
3567 *horiz
= m_colLabelHorizAlign
;
3568 *vert
= m_colLabelVertAlign
;
3571 wxString
wxGrid::GetRowLabelValue( int row
)
3575 return m_table
->GetRowLabelValue( row
);
3585 wxString
wxGrid::GetColLabelValue( int col
)
3589 return m_table
->GetColLabelValue( col
);
3599 void wxGrid::SetRowLabelSize( int width
)
3601 m_rowLabelWidth
= wxMax( 0, width
);
3603 ShowCellEditControl();
3604 if ( !GetBatchCount() ) Refresh();
3607 void wxGrid::SetColLabelSize( int height
)
3609 m_colLabelHeight
= wxMax( 0, height
);
3611 ShowCellEditControl();
3612 if ( !GetBatchCount() ) Refresh();
3615 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour
)
3617 m_labelBackgroundColour
= colour
;
3618 if ( !GetBatchCount() ) Refresh();
3621 void wxGrid::SetLabelTextColour( const wxColour
& colour
)
3623 m_labelTextColour
= colour
;
3624 if ( !GetBatchCount() ) Refresh();
3627 void wxGrid::SetLabelFont( const wxFont
& font
)
3630 if ( !GetBatchCount() ) Refresh();
3633 void wxGrid::SetRowLabelAlignment( int horiz
, int vert
)
3635 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
3637 m_rowLabelHorizAlign
= horiz
;
3640 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
3642 m_rowLabelVertAlign
= vert
;
3645 if ( !GetBatchCount() ) Refresh();
3648 void wxGrid::SetColLabelAlignment( int horiz
, int vert
)
3650 if ( horiz
== wxLEFT
|| horiz
== wxCENTRE
|| horiz
== wxRIGHT
)
3652 m_colLabelHorizAlign
= horiz
;
3655 if ( vert
== wxTOP
|| vert
== wxCENTRE
|| vert
== wxBOTTOM
)
3657 m_colLabelVertAlign
= vert
;
3660 if ( !GetBatchCount() ) Refresh();
3663 void wxGrid::SetRowLabelValue( int row
, const wxString
& s
)
3667 m_table
->SetRowLabelValue( row
, s
);
3668 if ( !GetBatchCount() ) Refresh();
3672 void wxGrid::SetColLabelValue( int col
, const wxString
& s
)
3676 m_table
->SetColLabelValue( col
, s
);
3677 if ( !GetBatchCount() ) Refresh();
3681 void wxGrid::SetGridLineColour( const wxColour
& colour
)
3683 m_gridLineColour
= colour
;
3685 wxClientDC
dc( this );
3686 DrawGridLines( dc
);
3689 void wxGrid::EnableGridLines( bool enable
)
3691 if ( enable
!= m_gridLinesEnabled
)
3693 m_gridLinesEnabled
= enable
;
3694 if ( !GetBatchCount() ) Refresh();
3699 int wxGrid::GetDefaultRowSize()
3701 return m_defaultRowHeight
;
3704 int wxGrid::GetRowSize( int row
)
3706 if ( row
>= 0 && row
< m_numRows
)
3707 return m_rowHeights
[row
];
3709 return 0; // TODO: log an error here
3712 int wxGrid::GetDefaultColSize()
3714 return m_defaultColWidth
;
3717 int wxGrid::GetColSize( int col
)
3719 if ( col
>= 0 && col
< m_numCols
)
3720 return m_colWidths
[col
];
3722 return 0; // TODO: log an error here
3725 wxColour
wxGrid::GetDefaultCellBackgroundColour()
3727 // TODO: replace this temp test code
3729 return wxColour( 255, 255, 255 );
3732 wxColour
wxGrid::GetCellBackgroundColour( int row
, int col
)
3734 // TODO: replace this temp test code
3736 return wxColour( 255, 255, 255 );
3739 wxColour
wxGrid::GetDefaultCellTextColour()
3741 // TODO: replace this temp test code
3743 return wxColour( 0, 0, 0 );
3746 wxColour
wxGrid::GetCellTextColour( int row
, int col
)
3748 // TODO: replace this temp test code
3750 return wxColour( 0, 0, 0 );
3754 wxColour
wxGrid::GetCellHighlightColour()
3756 // TODO: replace this temp test code
3758 return wxColour( 0, 0, 0 );
3762 wxFont
wxGrid::GetDefaultCellFont()
3764 return m_defaultCellFont
;
3767 wxFont
wxGrid::GetCellFont( int row
, int col
)
3769 // TODO: replace this temp test code
3771 return m_defaultCellFont
;
3774 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert
)
3776 // TODO: replace this temp test code
3782 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert
)
3784 // TODO: replace this temp test code
3790 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows
)
3792 m_defaultRowHeight
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT
);
3794 if ( resizeExistingRows
)
3796 // TODO: what do we do about events here ?
3797 // Generate an event for each resize ?
3800 for ( row
= 0; row
< m_numRows
; row
++ )
3802 m_rowHeights
[row
] = m_defaultRowHeight
;
3805 if ( !GetBatchCount() ) Refresh();
3809 void wxGrid::SetRowSize( int row
, int height
)
3811 if ( row
>= 0 && row
< m_numRows
)
3813 m_rowHeights
[row
] = wxMax( 0, height
);
3815 if ( !GetBatchCount() ) Refresh();
3817 // Note: we are ending the event *after* doing
3818 // default processing in this case
3820 SendEvent( EVT_WXGRID_ROW_SIZE
,
3825 // TODO: log an error here
3829 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols
)
3831 m_defaultColWidth
= wxMax( width
, WXGRID_MIN_COL_WIDTH
);
3833 if ( resizeExistingCols
)
3835 // TODO: what do we do about events here ?
3836 // Generate an event for each resize ?
3839 for ( col
= 0; col
< m_numCols
; col
++ )
3841 m_colWidths
[col
] = m_defaultColWidth
;
3844 if ( !GetBatchCount() ) Refresh();
3848 void wxGrid::SetColSize( int col
, int width
)
3850 if ( col
>= 0 && col
< m_numCols
)
3852 m_colWidths
[col
] = wxMax( 0, width
);
3854 if ( !GetBatchCount() ) Refresh();
3856 // Note: we are ending the event *after* doing
3857 // default processing in this case
3859 SendEvent( EVT_WXGRID_COL_SIZE
,
3864 // TODO: log an error here
3868 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& )
3870 // TODO: everything !!!
3874 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& )
3876 // TODO: everything !!!
3880 void wxGrid::SetDefaultCellTextColour( const wxColour
& )
3882 // TODO: everything !!!
3886 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& )
3888 // TODO: everything !!!
3892 void wxGrid::SetCellHighlightColour( const wxColour
& )
3894 // TODO: everything !!!
3898 void wxGrid::SetDefaultCellFont( const wxFont
& )
3900 // TODO: everything !!!
3904 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& )
3906 // TODO: everything !!!
3910 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert
)
3912 // TODO: everything !!!
3916 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert
)
3918 // TODO: everything !!!
3924 // ------ cell value accessor functions
3927 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s
)
3931 m_table
->SetValue( row
, col
, s
.c_str() );
3932 DrawCell( row
, col
);
3933 if ( m_currentCellCoords
.GetRow() == row
&&
3934 m_currentCellCoords
.GetCol() == col
)
3936 SetEditControlValue( s
);
3944 // ------ interaction with data model
3946 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg
)
3948 switch ( msg
.GetId() )
3950 case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
:
3951 return GetModelValues();
3953 case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
:
3954 return SetModelValues();
3956 case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
:
3957 case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
:
3958 case wxGRIDTABLE_NOTIFY_ROWS_DELETED
:
3959 case wxGRIDTABLE_NOTIFY_COLS_INSERTED
:
3960 case wxGRIDTABLE_NOTIFY_COLS_APPENDED
:
3961 case wxGRIDTABLE_NOTIFY_COLS_DELETED
:
3962 return Redimension( msg
);
3971 // ------ Grid location functions
3973 // (see also inline functions in grid.h)
3976 // check to see if a cell location is wholly visible
3978 bool wxGrid::IsVisible( const wxGridCellCoords
& coords
)
3980 return ( coords
.GetRow() >= m_scrollPosY
&&
3981 coords
.GetRow() < m_scrollPosY
+ m_wholeRowsVisible
&&
3982 coords
.GetCol() >= m_scrollPosX
&&
3983 coords
.GetCol() < m_scrollPosX
+ m_wholeColsVisible
);
3987 // make the specified cell location visible by doing a minimal amount
3990 void wxGrid::MakeCellVisible( int row
, int col
)
3992 int lastX
= m_scrollPosX
;
3993 int lastY
= m_scrollPosY
;
3995 if ( row
>= 0 && row
< m_numRows
&&
3996 col
>= 0 && col
< m_numCols
)
3998 if ( row
< m_scrollPosY
)
4000 SetVerticalScrollPos( row
);
4002 else if ( row
>= m_scrollPosY
+ m_wholeRowsVisible
)
4005 int h
= m_rowBottoms
[row
];
4006 for ( i
= m_scrollPosY
; i
< m_numRows
&& h
> m_bottom
; i
++ )
4008 h
-= m_rowHeights
[i
];
4010 SetVerticalScrollPos( i
);
4013 if ( col
< m_scrollPosX
)
4015 SetHorizontalScrollPos( col
);
4017 else if ( col
>= m_scrollPosX
+ m_wholeColsVisible
)
4020 int w
= m_colRights
[col
];
4021 for ( i
= m_scrollPosX
; i
< m_numCols
&& w
> m_right
; i
++ )
4023 w
-= m_colWidths
[i
];
4025 SetHorizontalScrollPos( i
);
4028 if ( m_scrollPosX
!= lastX
|| m_scrollPosY
!= lastY
)
4030 // The cell was not visible before but not it is
4032 ShowCellEditControl();
4037 // TODO: log an error
4042 void wxGrid::SetVerticalScrollPos( int topMostRow
)
4044 if ( m_vertScrollBar
&& topMostRow
!= m_scrollPosY
)
4046 m_scrollPosY
= topMostRow
;
4054 void wxGrid::SetHorizontalScrollPos( int leftMostCol
)
4056 if ( m_horizScrollBar
&& leftMostCol
!= m_scrollPosX
)
4058 m_scrollPosX
= leftMostCol
;
4067 // ------ block, row and col selection
4070 void wxGrid::SelectRow( int row
, bool addToSelected
)
4072 if ( IsSelection() && addToSelected
)
4074 if ( m_selectedTopLeft
.GetRow() > row
)
4075 m_selectedTopLeft
.SetRow( row
);
4077 m_selectedTopLeft
.SetCol( 0 );
4079 if ( m_selectedBottomRight
.GetRow() < row
)
4080 m_selectedBottomRight
.SetRow( row
);
4082 m_selectedBottomRight
.SetCol( m_numCols
- 1 );
4087 m_selectedTopLeft
.Set( row
, 0 );
4088 m_selectedBottomRight
.Set( row
, m_numCols
-1 );
4091 if ( !GetBatchCount() )
4093 wxRect
rect( SelectionToRect() );
4094 if ( rect
!= wxGridNoCellRect
) Refresh( TRUE
, &rect
);
4097 wxGridRangeSelectEvent
gridEvt( GetId(),
4098 EVT_WXGRID_RANGE_SELECT
,
4101 m_selectedBottomRight
);
4103 GetEventHandler()->ProcessEvent(gridEvt
);
4107 void wxGrid::SelectCol( int col
, bool addToSelected
)
4109 if ( addToSelected
&& m_selectedTopLeft
!= wxGridNoCellCoords
)
4111 if ( m_selectedTopLeft
.GetCol() > col
)
4112 m_selectedTopLeft
.SetCol( col
);
4114 m_selectedTopLeft
.SetRow( 0 );
4116 if ( m_selectedBottomRight
.GetCol() < col
)
4117 m_selectedBottomRight
.SetCol( col
);
4119 m_selectedBottomRight
.SetRow( m_numRows
- 1 );
4124 m_selectedTopLeft
.Set( 0, col
);
4125 m_selectedBottomRight
.Set( m_numRows
-1, col
);
4128 if ( !GetBatchCount() )
4130 wxRect
rect( SelectionToRect() );
4131 if ( rect
!= wxGridNoCellRect
) Refresh( TRUE
, &rect
);
4134 wxGridRangeSelectEvent
gridEvt( GetId(),
4135 EVT_WXGRID_RANGE_SELECT
,
4138 m_selectedBottomRight
);
4140 GetEventHandler()->ProcessEvent(gridEvt
);
4144 void wxGrid::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol
)
4148 if ( topRow
> bottomRow
)
4155 if ( leftCol
> rightCol
)
4162 m_selectedTopLeft
.Set( topRow
, leftCol
);
4163 m_selectedBottomRight
.Set( bottomRow
, rightCol
);
4165 if ( !GetBatchCount() )
4167 wxRect
rect( SelectionToRect() );
4168 if ( rect
!= wxGridNoCellRect
) Refresh( TRUE
, &rect
);
4171 // only generate an event if the block is not being selected by
4172 // dragging the mouse (in which case the event will be generated in
4174 if ( !m_isDragging
)
4176 wxGridRangeSelectEvent
gridEvt( GetId(),
4177 EVT_WXGRID_RANGE_SELECT
,
4180 m_selectedBottomRight
);
4182 GetEventHandler()->ProcessEvent(gridEvt
);
4186 void wxGrid::SelectAll()
4188 m_selectedTopLeft
.Set( 0, 0 );
4189 m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 );
4191 if ( !GetBatchCount() ) Refresh();
4195 void wxGrid::ClearSelection()
4197 if ( IsSelection() )
4199 wxRect
rect( SelectionToRect() );
4200 if ( rect
!= wxGridNoCellRect
)
4202 Refresh( TRUE
, &rect
);
4205 m_selectedTopLeft
= wxGridNoCellCoords
;
4206 m_selectedBottomRight
= wxGridNoCellCoords
;
4211 wxRect
wxGrid::SelectionToRect()
4216 if ( IsSelection() )
4218 cellRect
= CellToRect( m_selectedTopLeft
);
4219 if ( cellRect
!= wxGridNoCellRect
)
4225 rect
= wxRect( m_left
, m_top
, 0, 0 );
4228 cellRect
= CellToRect( m_selectedBottomRight
);
4229 if ( cellRect
!= wxGridNoCellRect
)
4235 return wxGridNoCellRect
;
4246 // ------ Grid event classes
4249 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent
)
4251 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
,
4252 int row
, int col
, int x
, int y
,
4253 bool control
, bool shift
, bool alt
, bool meta
)
4254 : wxNotifyEvent( type
, id
)
4260 m_control
= control
;
4265 SetEventObject(obj
);
4269 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent
)
4271 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
,
4272 int rowOrCol
, int x
, int y
,
4273 bool control
, bool shift
, bool alt
, bool meta
)
4274 : wxNotifyEvent( type
, id
)
4276 m_rowOrCol
= rowOrCol
;
4279 m_control
= control
;
4284 SetEventObject(obj
);
4288 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent
)
4290 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
,
4291 const wxGridCellCoords
& topLeft
,
4292 const wxGridCellCoords
& bottomRight
,
4293 bool control
, bool shift
, bool alt
, bool meta
)
4294 : wxNotifyEvent( type
, id
)
4296 m_topLeft
= topLeft
;
4297 m_bottomRight
= bottomRight
;
4298 m_control
= control
;
4303 SetEventObject(obj
);
4307 #endif // ifndef wxUSE_NEW_GRID