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" 
  43 ////////////////////////////////////////////////////////////////////// 
  45 wxGridCellCoords 
wxGridNoCellCoords( -1, -1 ); 
  46 wxRect           
wxGridNoCellRect( -1, -1, -1, -1 ); 
  48 // this is a magic incantation which must be done! 
  49 #include "wx/arrimpl.cpp" 
  51 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
) 
  54 // TODO: fixed so far - make configurable later (and also different for x/y) 
  55 static const size_t GRID_SCROLL_LINE 
= 10; 
  57 ////////////////////////////////////////////////////////////////////// 
  59 // Abstract base class for grid data (the model) 
  61 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject 
) 
  64 wxGridTableBase::wxGridTableBase() 
  67     m_view 
= (wxGrid 
*) NULL
; 
  70 wxGridTableBase::~wxGridTableBase() 
  75 bool wxGridTableBase::InsertRows( size_t pos
, size_t numRows 
) 
  77     wxLogWarning( wxT("Called grid table class function InsertRows(pos=%d, N=%d)\n" 
  78                   "but your derived table class does not override this function"), 
  84 bool wxGridTableBase::AppendRows( size_t numRows 
) 
  86     wxLogWarning( wxT("Called grid table class function AppendRows(N=%d)\n" 
  87                   "but your derived table class does not override this function"), 
  93 bool wxGridTableBase::DeleteRows( size_t pos
, size_t numRows 
) 
  95     wxLogWarning( wxT("Called grid table class function DeleteRows(pos=%d, N=%d)\n" 
  96                   "but your derived table class does not override this function"), 
 102 bool wxGridTableBase::InsertCols( size_t pos
, size_t numCols 
) 
 104     wxLogWarning( wxT("Called grid table class function InsertCols(pos=%d, N=%d)\n" 
 105                   "but your derived table class does not override this function"), 
 111 bool wxGridTableBase::AppendCols( size_t numCols 
) 
 113     wxLogWarning( wxT("Called grid table class function AppendCols(N=%d)\n" 
 114                   "but your derived table class does not override this function"), 
 120 bool wxGridTableBase::DeleteCols( size_t pos
, size_t numCols 
) 
 122     wxLogWarning( wxT("Called grid table class function DeleteCols(pos=%d, N=%d)\n" 
 123                   "but your derived table class does not override this function"), 
 130 wxString 
wxGridTableBase::GetRowLabelValue( int row 
) 
 137 wxString 
wxGridTableBase::GetColLabelValue( int col 
) 
 139     // default col labels are: 
 140     //   cols 0 to 25   : A-Z 
 141     //   cols 26 to 675 : AA-ZZ 
 148         s 
+= (_T('A') + (wxChar
)( col%26 
)); 
 150         if ( col 
< 0 ) break; 
 153     // reverse the string... 
 155     for ( i 
= 0;  i 
< n
;  i
++ ) 
 165 ////////////////////////////////////////////////////////////////////// 
 167 // Message class for the grid table to send requests and notifications 
 171 wxGridTableMessage::wxGridTableMessage() 
 173     m_table 
= (wxGridTableBase 
*) NULL
; 
 179 wxGridTableMessage::wxGridTableMessage( wxGridTableBase 
*table
, int id
, 
 180                                         int commandInt1
, int commandInt2 
) 
 184     m_comInt1 
= commandInt1
; 
 185     m_comInt2 
= commandInt2
; 
 190 ////////////////////////////////////////////////////////////////////// 
 192 // A basic grid table for string data. An object of this class will 
 193 // created by wxGrid if you don't specify an alternative table class. 
 196 WX_DEFINE_OBJARRAY(wxGridStringArray
) 
 198 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase 
) 
 200 wxGridStringTable::wxGridStringTable() 
 205 wxGridStringTable::wxGridStringTable( int numRows
, int numCols 
) 
 210     m_data
.Alloc( numRows 
); 
 214     for ( col 
= 0;  col 
< numCols
;  col
++ ) 
 216         sa
.Add( wxEmptyString 
); 
 219     for ( row 
= 0;  row 
< numRows
;  row
++ ) 
 225 wxGridStringTable::~wxGridStringTable() 
 229 long wxGridStringTable::GetNumberRows() 
 231     return m_data
.GetCount(); 
 234 long wxGridStringTable::GetNumberCols() 
 236     if ( m_data
.GetCount() > 0 ) 
 237         return m_data
[0].GetCount(); 
 242 wxString 
wxGridStringTable::GetValue( int row
, int col 
) 
 244     // TODO: bounds checking 
 246     return m_data
[row
][col
]; 
 249 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& s 
) 
 251     // TODO: bounds checking 
 253     m_data
[row
][col
] = s
; 
 256 bool wxGridStringTable::IsEmptyCell( int row
, int col 
) 
 258     // TODO: bounds checking 
 260     return (m_data
[row
][col
] == wxEmptyString
); 
 264 void wxGridStringTable::Clear() 
 267     int numRows
, numCols
; 
 269     numRows 
= m_data
.GetCount(); 
 272         numCols 
= m_data
[0].GetCount(); 
 274         for ( row 
= 0;  row 
< numRows
;  row
++ ) 
 276             for ( col 
= 0;  col 
< numCols
;  col
++ ) 
 278                 m_data
[row
][col
] = wxEmptyString
; 
 285 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows 
) 
 289     size_t curNumRows 
= m_data
.GetCount(); 
 290     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 0 ); 
 292     if ( pos 
>= curNumRows 
) 
 294         return AppendRows( numRows 
); 
 298     sa
.Alloc( curNumCols 
); 
 299     for ( col 
= 0;  col 
< curNumCols
;  col
++ ) 
 301         sa
.Add( wxEmptyString 
); 
 304     for ( row 
= pos
;  row 
< pos 
+ numRows
;  row
++ ) 
 306         m_data
.Insert( sa
, row 
); 
 311         wxGridTableMessage 
msg( this, 
 312                                 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
, 
 316         GetView()->ProcessTableMessage( msg 
); 
 322 bool wxGridStringTable::AppendRows( size_t numRows 
) 
 326     size_t curNumRows 
= m_data
.GetCount(); 
 327     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 0 ); 
 330     if ( curNumCols 
> 0 ) 
 332         sa
.Alloc( curNumCols 
); 
 333         for ( col 
= 0;  col 
< curNumCols
;  col
++ ) 
 335             sa
.Add( wxEmptyString 
); 
 339     for ( row 
= 0;  row 
< numRows
;  row
++ ) 
 346         wxGridTableMessage 
msg( this, 
 347                                 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, 
 350         GetView()->ProcessTableMessage( msg 
); 
 356 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows 
) 
 360     size_t curNumRows 
= m_data
.GetCount(); 
 362     if ( pos 
>= curNumRows 
) 
 364         wxLogError( wxT("Called wxGridStringTable::DeleteRows(pos=%d, N=%d)...\n" 
 365                     "Pos value is invalid for present table with %d rows"), 
 366                     pos
, numRows
, curNumRows 
); 
 370     if ( numRows 
> curNumRows 
- pos 
) 
 372         numRows 
= curNumRows 
- pos
; 
 375     if ( numRows 
>= curNumRows 
) 
 377         m_data
.Empty();  // don't release memory just yet 
 381         for ( n 
= 0;  n 
< numRows
;  n
++ ) 
 383             m_data
.Remove( pos 
); 
 389         wxGridTableMessage 
msg( this, 
 390                                 wxGRIDTABLE_NOTIFY_ROWS_DELETED
, 
 394         GetView()->ProcessTableMessage( msg 
); 
 400 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols 
) 
 404     size_t curNumRows 
= m_data
.GetCount(); 
 405     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 0 ); 
 407     if ( pos 
>= curNumCols 
) 
 409         return AppendCols( numCols 
); 
 412     for ( row 
= 0;  row 
< curNumRows
;  row
++ ) 
 414         for ( col 
= pos
;  col 
< pos 
+ numCols
;  col
++ ) 
 416             m_data
[row
].Insert( wxEmptyString
, col 
); 
 422         wxGridTableMessage 
msg( this, 
 423                                 wxGRIDTABLE_NOTIFY_COLS_INSERTED
, 
 427         GetView()->ProcessTableMessage( msg 
); 
 433 bool wxGridStringTable::AppendCols( size_t numCols 
) 
 437     size_t curNumRows 
= m_data
.GetCount(); 
 440         // TODO: something better than this ? 
 442         wxLogError( wxT("Unable to append cols to a grid table with no rows.\n" 
 443                     "Call AppendRows() first") ); 
 447     for ( row 
= 0;  row 
< curNumRows
;  row
++ ) 
 449         for ( n 
= 0;  n 
< numCols
;  n
++ ) 
 451             m_data
[row
].Add( wxEmptyString 
); 
 457         wxGridTableMessage 
msg( this, 
 458                                 wxGRIDTABLE_NOTIFY_COLS_APPENDED
, 
 461         GetView()->ProcessTableMessage( msg 
); 
 467 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols 
) 
 471     size_t curNumRows 
= m_data
.GetCount(); 
 472     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 0 ); 
 474     if ( pos 
>= curNumCols 
) 
 476         wxLogError( wxT("Called wxGridStringTable::DeleteCols(pos=%d, N=%d)...\n" 
 477                     "Pos value is invalid for present table with %d cols"), 
 478                     pos
, numCols
, curNumCols 
); 
 482     if ( numCols 
> curNumCols 
- pos 
) 
 484         numCols 
= curNumCols 
- pos
; 
 487     for ( row 
= 0;  row 
< curNumRows
;  row
++ ) 
 489         if ( numCols 
>= curNumCols 
) 
 495             for ( n 
= 0;  n 
< numCols
;  n
++ ) 
 497                 m_data
[row
].Remove( pos 
); 
 504         wxGridTableMessage 
msg( this, 
 505                                 wxGRIDTABLE_NOTIFY_COLS_DELETED
, 
 509         GetView()->ProcessTableMessage( msg 
); 
 515 wxString 
wxGridStringTable::GetRowLabelValue( int row 
) 
 517     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
 519         // using default label 
 521         return wxGridTableBase::GetRowLabelValue( row 
); 
 525         return m_rowLabels
[ row 
]; 
 529 wxString 
wxGridStringTable::GetColLabelValue( int col 
) 
 531     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
 533         // using default label 
 535         return wxGridTableBase::GetColLabelValue( col 
); 
 539         return m_colLabels
[ col 
]; 
 543 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value 
) 
 545     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
 547         int n 
= m_rowLabels
.GetCount(); 
 549         for ( i 
= n
;  i 
<= row
;  i
++ ) 
 551             m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) ); 
 555     m_rowLabels
[row
] = value
; 
 558 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value 
) 
 560     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
 562         int n 
= m_colLabels
.GetCount(); 
 564         for ( i 
= n
;  i 
<= col
;  i
++ ) 
 566             m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) ); 
 570     m_colLabels
[col
] = value
; 
 576 ////////////////////////////////////////////////////////////////////// 
 578 IMPLEMENT_DYNAMIC_CLASS( wxGridTextCtrl
, wxTextCtrl 
) 
 580 BEGIN_EVENT_TABLE( wxGridTextCtrl
, wxTextCtrl 
) 
 581     EVT_KEY_DOWN( wxGridTextCtrl::OnKeyDown 
) 
 585 wxGridTextCtrl::wxGridTextCtrl( wxWindow 
*par
, 
 589                                 const wxString
& value
, 
 593         : wxTextCtrl( par
, id
, value
, pos
, size
, style 
) 
 596     m_isCellControl 
= isCellControl
; 
 600 void wxGridTextCtrl::OnKeyDown( wxKeyEvent
& event 
) 
 602     switch ( event
.KeyCode() ) 
 605             m_grid
->SetEditControlValue( startValue 
); 
 606             SetInsertionPointEnd(); 
 616             if ( m_isCellControl 
) 
 618                 // send the event to the parent grid, skipping the 
 619                 // event if nothing happens 
 621                 event
.Skip( m_grid
->ProcessEvent( event 
) ); 
 625                 // default text control response within the top edit 
 633             if ( m_isCellControl 
) 
 635                 if ( !m_grid
->ProcessEvent( event 
) ) 
 637 #if defined(__WXMOTIF__) || defined(__WXGTK__) 
 638                     // wxMotif needs a little extra help... 
 640                     int pos 
= GetInsertionPoint(); 
 641                     wxString 
s( GetValue() ); 
 642                     s 
= s
.Left(pos
) + "\n" + s
.Mid(pos
); 
 644                     SetInsertionPoint( pos 
); 
 646                     // the other ports can handle a Return key press 
 656             if ( m_isCellControl 
) 
 658                 // send the event to the parent grid, skipping the 
 659                 // event if nothing happens 
 661                 event
.Skip( m_grid
->ProcessEvent( event 
) ); 
 665                 // default text control response within the top edit 
 677 void wxGridTextCtrl::SetStartValue( const wxString
& s 
) 
 680     wxTextCtrl::SetValue(s
); 
 685 ////////////////////////////////////////////////////////////////////// 
 687 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow 
) 
 689 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxWindow 
) 
 690     EVT_PAINT( wxGridRowLabelWindow::OnPaint 
) 
 691     EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent 
) 
 692     EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown 
) 
 695 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid 
*parent
, 
 697                                             const wxPoint 
&pos
, const wxSize 
&size 
) 
 698   : wxWindow( parent
, id
, pos
, size 
) 
 703 void wxGridRowLabelWindow::OnPaint( wxPaintEvent 
&event 
) 
 707     // NO - don't do this because it will set both the x and y origin 
 708     // coords to match the parent scrolled window and we just want to 
 709     // set the y coord  - MB 
 711     // m_owner->PrepareDC( dc ); 
 714     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
 715     dc
.SetDeviceOrigin( 0, -y 
); 
 717     m_owner
->CalcRowLabelsExposed( GetUpdateRegion() ); 
 718     m_owner
->DrawRowLabels( dc 
); 
 722 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
 724     m_owner
->ProcessRowLabelMouseEvent( event 
); 
 728 // This seems to be required for wxMotif otherwise the mouse 
 729 // cursor must be in the cell edit control to get key events 
 731 void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent
& event 
) 
 733     if ( !m_owner
->ProcessEvent( event 
) ) event
.Skip(); 
 738 ////////////////////////////////////////////////////////////////////// 
 740 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow 
) 
 742 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxWindow 
) 
 743     EVT_PAINT( wxGridColLabelWindow::OnPaint 
) 
 744     EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent 
) 
 745     EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown 
) 
 748 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid 
*parent
, 
 750                                             const wxPoint 
&pos
, const wxSize 
&size 
) 
 751   : wxWindow( parent
, id
, pos
, size 
) 
 756 void wxGridColLabelWindow::OnPaint( wxPaintEvent 
&event 
) 
 760     // NO - don't do this because it will set both the x and y origin 
 761     // coords to match the parent scrolled window and we just want to 
 762     // set the x coord  - MB 
 764     // m_owner->PrepareDC( dc ); 
 767     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
 768     dc
.SetDeviceOrigin( -x
, 0 ); 
 770     m_owner
->CalcColLabelsExposed( GetUpdateRegion() ); 
 771     m_owner
->DrawColLabels( dc 
); 
 775 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
 777     m_owner
->ProcessColLabelMouseEvent( event 
); 
 781 // This seems to be required for wxMotif otherwise the mouse 
 782 // cursor must be in the cell edit control to get key events 
 784 void wxGridColLabelWindow::OnKeyDown( wxKeyEvent
& event 
) 
 786     if ( !m_owner
->ProcessEvent( event 
) ) event
.Skip(); 
 791 ////////////////////////////////////////////////////////////////////// 
 793 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow 
) 
 795 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxWindow 
) 
 796     EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent 
) 
 797     EVT_PAINT( wxGridCornerLabelWindow::OnPaint
) 
 798     EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown 
) 
 801 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid 
*parent
, 
 803                                                   const wxPoint 
&pos
, const wxSize 
&size 
) 
 804   : wxWindow( parent
, id
, pos
, size 
) 
 809 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
 813     int client_height 
= 0; 
 814     int client_width 
= 0; 
 815     GetClientSize( &client_width
, &client_height 
); 
 817     dc
.SetPen( *wxBLACK_PEN 
); 
 818     dc
.DrawLine( client_width
-1, client_height
-1, client_width
-1, 0 ); 
 819     dc
.DrawLine( client_width
-1, client_height
-1, 0, client_height
-1 ); 
 821     dc
.SetPen( *wxWHITE_PEN 
); 
 822     dc
.DrawLine( 0, 0, client_width
, 0 ); 
 823     dc
.DrawLine( 0, 0, 0, client_height 
); 
 827 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
 829     m_owner
->ProcessCornerLabelMouseEvent( event 
); 
 833 // This seems to be required for wxMotif otherwise the mouse 
 834 // cursor must be in the cell edit control to get key events 
 836 void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent
& event 
) 
 838     if ( !m_owner
->ProcessEvent( event 
) ) event
.Skip(); 
 843 ////////////////////////////////////////////////////////////////////// 
 845 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxPanel 
) 
 847 BEGIN_EVENT_TABLE( wxGridWindow
, wxPanel 
) 
 848     EVT_PAINT( wxGridWindow::OnPaint 
) 
 849     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent 
) 
 850     EVT_KEY_DOWN( wxGridWindow::OnKeyDown 
) 
 853 wxGridWindow::wxGridWindow( wxGrid 
*parent
, 
 854                             wxGridRowLabelWindow 
*rowLblWin
, 
 855                             wxGridColLabelWindow 
*colLblWin
, 
 856                             wxWindowID id
, const wxPoint 
&pos
, const wxSize 
&size 
) 
 857         : wxPanel( parent
, id
, pos
, size
, wxSUNKEN_BORDER
, "grid window" ) 
 860     m_rowLabelWin 
= rowLblWin
; 
 861     m_colLabelWin 
= colLblWin
; 
 863     SetBackgroundColour( "WHITE" ); 
 867 wxGridWindow::~wxGridWindow() 
 872 void wxGridWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
 874     wxPaintDC 
dc( this ); 
 875     m_owner
->PrepareDC( dc 
); 
 876     wxRegion reg 
= GetUpdateRegion(); 
 877     m_owner
->CalcCellsExposed( reg 
); 
 878     m_owner
->DrawGridCellArea( dc 
); 
 880     m_owner
->DrawAllGridLines( dc
, reg 
); 
 885 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
 887     wxPanel::ScrollWindow( dx
, dy
, rect 
); 
 888     m_rowLabelWin
->ScrollWindow( 0, dy
, rect 
); 
 889     m_colLabelWin
->ScrollWindow( dx
, 0, rect 
); 
 893 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event 
) 
 895     m_owner
->ProcessGridCellMouseEvent( event 
); 
 899 // This seems to be required for wxMotif otherwise the mouse 
 900 // cursor must be in the cell edit control to get key events 
 902 void wxGridWindow::OnKeyDown( wxKeyEvent
& event 
) 
 904     if ( !m_owner
->ProcessEvent( event 
) ) event
.Skip(); 
 909 ////////////////////////////////////////////////////////////////////// 
 911 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow 
) 
 913 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow 
) 
 914     EVT_PAINT( wxGrid::OnPaint 
) 
 915     EVT_SIZE( wxGrid::OnSize 
) 
 916     EVT_KEY_DOWN( wxGrid::OnKeyDown 
) 
 919 wxGrid::wxGrid( wxWindow 
*parent
, 
 924                  const wxString
& name 
) 
 925   : wxScrolledWindow( parent
, id
, pos
, size
, style
, name 
) 
 938 // ----- internal init and update functions 
 941 void wxGrid::Create() 
 943     int colLblH 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
 944     int rowLblW 
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
 946     m_rowLabelWin 
= new wxGridRowLabelWindow( this, 
 949                                               wxSize(rowLblW
,-1) ); 
 951     m_colLabelWin 
= new wxGridColLabelWindow( this, 
 954                                               wxSize(-1, colLblH 
) ); 
 956     m_cornerLabelWin 
= new wxGridCornerLabelWindow( this, 
 959                                                     wxSize(rowLblW
, colLblH 
) ); 
 961     m_gridWin 
= new wxGridWindow( this, 
 968     SetTargetWindow( m_gridWin 
); 
 970     m_mainSizer 
= new wxBoxSizer( wxVERTICAL 
); 
 972     m_topSizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 973     m_topSizer
->Add( m_cornerLabelWin
, 0 ); 
 974     m_topSizer
->Add( m_colLabelWin
, 1 ); 
 976     m_mainSizer
->Add( m_topSizer
, 0, wxEXPAND 
); 
 978     m_middleSizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 979     m_middleSizer
->Add( m_rowLabelWin
, 0, wxEXPAND 
); 
 980     m_middleSizer
->Add( m_gridWin
, 1, wxEXPAND 
); 
 982     m_mainSizer
->Add( m_middleSizer
, 1, wxEXPAND 
); 
 984     SetAutoLayout( TRUE 
); 
 985     SetSizer( m_mainSizer 
); 
 989 bool wxGrid::CreateGrid( int numRows
, int numCols 
) 
 993         wxLogError( wxT("wxGrid::CreateGrid(numRows, numCols) called more than once") ); 
1001         m_table 
= new wxGridStringTable( m_numRows
, m_numCols 
); 
1002         m_table
->SetView( this ); 
1015     if ( m_numRows 
<= 0 ) 
1016         m_numRows 
= WXGRID_DEFAULT_NUMBER_ROWS
; 
1018     if ( m_numCols 
<= 0 ) 
1019         m_numCols 
= WXGRID_DEFAULT_NUMBER_COLS
; 
1021     m_rowLabelWidth  
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
1022     m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
1024     if ( m_rowLabelWin 
) 
1026         m_labelBackgroundColour 
= m_rowLabelWin
->GetBackgroundColour(); 
1030         m_labelBackgroundColour 
= wxColour( _T("WHITE") ); 
1033     m_labelTextColour 
= wxColour( _T("BLACK") ); 
1035     // TODO: something better than this ? 
1037     m_labelFont 
= this->GetFont(); 
1038     m_labelFont
.SetWeight( m_labelFont
.GetWeight() + 2 ); 
1040     m_rowLabelHorizAlign 
= wxLEFT
; 
1041     m_rowLabelVertAlign  
= wxCENTRE
; 
1043     m_colLabelHorizAlign 
= wxCENTRE
; 
1044     m_colLabelVertAlign  
= wxTOP
; 
1046     m_defaultColWidth  
= WXGRID_DEFAULT_COL_WIDTH
; 
1047     m_defaultRowHeight 
= m_gridWin
->GetCharHeight(); 
1049 #if defined(__WXMOTIF__) || defined(__WXGTK__)  // see also text ctrl sizing in ShowCellEditControl() 
1050     m_defaultRowHeight 
+= 8; 
1052     m_defaultRowHeight 
+= 4; 
1055     m_rowHeights
.Alloc( m_numRows 
); 
1056     m_rowBottoms
.Alloc( m_numRows 
); 
1058     for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
1060         m_rowHeights
.Add( m_defaultRowHeight 
); 
1061         rowBottom 
+= m_defaultRowHeight
; 
1062         m_rowBottoms
.Add( rowBottom 
); 
1065     m_colWidths
.Alloc( m_numCols 
); 
1066     m_colRights
.Alloc( m_numCols 
); 
1068     for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
1070         m_colWidths
.Add( m_defaultColWidth 
); 
1071         colRight 
+= m_defaultColWidth
; 
1072         m_colRights
.Add( colRight 
); 
1075     // TODO: improve this ? 
1077     m_defaultCellFont 
= this->GetFont(); 
1079     m_gridLineColour 
= wxColour( 128, 128, 255 ); 
1080     m_gridLinesEnabled 
= TRUE
; 
1082     m_cursorMode  
= WXGRID_CURSOR_SELECT_CELL
; 
1084     m_dragRowOrCol 
= -1; 
1085     m_isDragging 
= FALSE
; 
1087     m_rowResizeCursor 
= wxCursor( wxCURSOR_SIZENS 
); 
1088     m_colResizeCursor 
= wxCursor( wxCURSOR_SIZEWE 
); 
1090     m_currentCellCoords 
= wxGridNoCellCoords
; 
1092     m_selectedTopLeft 
= wxGridNoCellCoords
; 
1093     m_selectedBottomRight 
= wxGridNoCellCoords
; 
1095     m_editable 
= TRUE
;  // default for whole grid 
1097     m_inOnKeyDown 
= FALSE
; 
1100     // TODO: extend this to other types of controls 
1102     m_cellEditCtrl 
= new wxGridTextCtrl( m_gridWin
, 
1109 #if defined(__WXMSW__) 
1110                                          , wxTE_MULTILINE 
| wxTE_NO_VSCROLL
 
1114     m_cellEditCtrl
->Show( FALSE 
); 
1115     m_cellEditCtrlEnabled 
= TRUE
; 
1116     m_editCtrlType 
= wxGRID_TEXTCTRL
; 
1120 void wxGrid::CalcDimensions() 
1123     GetClientSize( &cw
, &ch 
); 
1125     if ( m_numRows 
> 0  &&  m_numCols 
> 0 ) 
1127         int right 
= m_colRights
[ m_numCols
-1 ] + 20; 
1128         int bottom 
= m_rowBottoms
[ m_numRows
-1 ] + 20; 
1130         // TODO: restore the scroll position that we had before sizing 
1133         GetViewStart( &x
, &y 
); 
1134         SetScrollbars( GRID_SCROLL_LINE
, GRID_SCROLL_LINE
, 
1135                        right
/GRID_SCROLL_LINE
, bottom
/GRID_SCROLL_LINE
, 
1141 // this is called when the grid table sends a message to say that it 
1142 // has been redimensioned 
1144 bool wxGrid::Redimension( wxGridTableMessage
& msg 
) 
1148     switch ( msg
.GetId() ) 
1150         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
1152             size_t pos 
= msg
.GetCommandInt(); 
1153             int numRows 
= msg
.GetCommandInt2(); 
1154             for ( i 
= 0;  i 
< numRows
;  i
++ ) 
1156                 m_rowHeights
.Insert( m_defaultRowHeight
, pos 
); 
1157                 m_rowBottoms
.Insert( 0, pos 
); 
1159             m_numRows 
+= numRows
; 
1162             if ( pos 
> 0 ) bottom 
= m_rowBottoms
[pos
-1]; 
1164             for ( i 
= pos
;  i 
< m_numRows
;  i
++ ) 
1166                 bottom 
+= m_rowHeights
[i
]; 
1167                 m_rowBottoms
[i
] = bottom
; 
1173         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
1175             int numRows 
= msg
.GetCommandInt(); 
1176             for ( i 
= 0;  i 
< numRows
;  i
++ ) 
1178                 m_rowHeights
.Add( m_defaultRowHeight 
); 
1179                 m_rowBottoms
.Add( 0 ); 
1182             int oldNumRows 
= m_numRows
; 
1183             m_numRows 
+= numRows
; 
1186             if ( oldNumRows 
> 0 ) bottom 
= m_rowBottoms
[oldNumRows
-1]; 
1188             for ( i 
= oldNumRows
;  i 
< m_numRows
;  i
++ ) 
1190                 bottom 
+= m_rowHeights
[i
]; 
1191                 m_rowBottoms
[i
] = bottom
; 
1197         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
1199             size_t pos 
= msg
.GetCommandInt(); 
1200             int numRows 
= msg
.GetCommandInt2(); 
1201             for ( i 
= 0;  i 
< numRows
;  i
++ ) 
1203                 m_rowHeights
.Remove( pos 
); 
1204                 m_rowBottoms
.Remove( pos 
); 
1206             m_numRows 
-= numRows
; 
1211                 m_colWidths
.Clear(); 
1212                 m_colRights
.Clear(); 
1213                 m_currentCellCoords 
= wxGridNoCellCoords
; 
1217                 if ( m_currentCellCoords
.GetRow() >= m_numRows 
) 
1218                     m_currentCellCoords
.Set( 0, 0 ); 
1221                 for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
1223                     h 
+= m_rowHeights
[i
]; 
1224                     m_rowBottoms
[i
] = h
; 
1232         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
1234             size_t pos 
= msg
.GetCommandInt(); 
1235             int numCols 
= msg
.GetCommandInt2(); 
1236             for ( i 
= 0;  i 
< numCols
;  i
++ ) 
1238                 m_colWidths
.Insert( m_defaultColWidth
, pos 
); 
1239                 m_colRights
.Insert( 0, pos 
); 
1241             m_numCols 
+= numCols
; 
1244             if ( pos 
> 0 ) right 
= m_colRights
[pos
-1]; 
1246             for ( i 
= pos
;  i 
< m_numCols
;  i
++ ) 
1248                 right 
+= m_colWidths
[i
]; 
1249                 m_colRights
[i
] = right
; 
1255         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
1257             int numCols 
= msg
.GetCommandInt(); 
1258             for ( i 
= 0;  i 
< numCols
;  i
++ ) 
1260                 m_colWidths
.Add( m_defaultColWidth 
); 
1261                 m_colRights
.Add( 0 ); 
1264             int oldNumCols 
= m_numCols
; 
1265             m_numCols 
+= numCols
; 
1268             if ( oldNumCols 
> 0 ) right 
= m_colRights
[oldNumCols
-1]; 
1270             for ( i 
= oldNumCols
;  i 
< m_numCols
;  i
++ ) 
1272                 right 
+= m_colWidths
[i
]; 
1273                 m_colRights
[i
] = right
; 
1279         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
1281             size_t pos 
= msg
.GetCommandInt(); 
1282             int numCols 
= msg
.GetCommandInt2(); 
1283             for ( i 
= 0;  i 
< numCols
;  i
++ ) 
1285                 m_colWidths
.Remove( pos 
); 
1286                 m_colRights
.Remove( pos 
); 
1288             m_numCols 
-= numCols
; 
1292 #if 0  // leave the row alone here so that AppendCols will work subsequently 
1294                 m_rowHeights
.Clear(); 
1295                 m_rowBottoms
.Clear(); 
1297                 m_currentCellCoords 
= wxGridNoCellCoords
; 
1301                 if ( m_currentCellCoords
.GetCol() >= m_numCols 
) 
1302                     m_currentCellCoords
.Set( 0, 0 ); 
1305                 for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
1307                     w 
+= m_colWidths
[i
]; 
1320 void wxGrid::CalcRowLabelsExposed( wxRegion
& reg 
) 
1322     wxRegionIterator 
iter( reg 
); 
1325     m_rowLabelsExposed
.Empty(); 
1332         // TODO: remove this when we can... 
1333         // There is a bug in wxMotif that gives garbage update 
1334         // rectangles if you jump-scroll a long way by clicking the 
1335         // scrollbar with middle button.  This is a work-around 
1337 #if defined(__WXMOTIF__) 
1339         m_gridWin
->GetClientSize( &cw
, &ch 
); 
1340         if ( r
.GetTop() > ch 
) r
.SetTop( 0 ); 
1341         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
1344         // logical bounds of update region 
1347         CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top 
); 
1348         CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom 
); 
1350         // find the row labels within these bounds 
1354         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
1356             if ( m_rowBottoms
[row
] < top 
) continue; 
1358             rowTop 
= m_rowBottoms
[row
] - m_rowHeights
[row
]; 
1359             if ( rowTop 
> bottom 
) break; 
1361             m_rowLabelsExposed
.Add( row 
); 
1369 void wxGrid::CalcColLabelsExposed( wxRegion
& reg 
) 
1371     wxRegionIterator 
iter( reg 
); 
1374     m_colLabelsExposed
.Empty(); 
1381         // TODO: remove this when we can... 
1382         // There is a bug in wxMotif that gives garbage update 
1383         // rectangles if you jump-scroll a long way by clicking the 
1384         // scrollbar with middle button.  This is a work-around 
1386 #if defined(__WXMOTIF__) 
1388         m_gridWin
->GetClientSize( &cw
, &ch 
); 
1389         if ( r
.GetLeft() > cw 
) r
.SetLeft( 0 ); 
1390         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
1393         // logical bounds of update region 
1396         CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy 
); 
1397         CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy 
); 
1399         // find the cells within these bounds 
1403         for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
1405             if ( m_colRights
[col
] < left 
) continue; 
1407             colLeft 
= m_colRights
[col
] - m_colWidths
[col
]; 
1408             if ( colLeft 
> right 
) break; 
1410             m_colLabelsExposed
.Add( col 
); 
1418 void wxGrid::CalcCellsExposed( wxRegion
& reg 
) 
1420     wxRegionIterator 
iter( reg 
); 
1423     m_cellsExposed
.Empty(); 
1424     m_rowsExposed
.Empty(); 
1425     m_colsExposed
.Empty(); 
1427     int left
, top
, right
, bottom
; 
1432         // TODO: remove this when we can... 
1433         // There is a bug in wxMotif that gives garbage update 
1434         // rectangles if you jump-scroll a long way by clicking the 
1435         // scrollbar with middle button.  This is a work-around 
1437 #if defined(__WXMOTIF__) 
1439         m_gridWin
->GetClientSize( &cw
, &ch 
); 
1440         if ( r
.GetTop() > ch 
) r
.SetTop( 0 ); 
1441         if ( r
.GetLeft() > cw 
) r
.SetLeft( 0 ); 
1442         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
1443         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
1446         // logical bounds of update region 
1448         CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
1449         CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
1451         // find the cells within these bounds 
1454         int colLeft
, rowTop
; 
1455         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
1457             if ( m_rowBottoms
[row
] < top 
) continue; 
1459             rowTop 
= m_rowBottoms
[row
] - m_rowHeights
[row
]; 
1460             if ( rowTop 
> bottom 
) break; 
1462             m_rowsExposed
.Add( row 
); 
1464             for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
1466                 if ( m_colRights
[col
] < left 
) continue; 
1468                 colLeft 
= m_colRights
[col
] - m_colWidths
[col
]; 
1469                 if ( colLeft 
> right 
) break; 
1471                 if ( m_colsExposed
.Index( col 
) == wxNOT_FOUND 
) m_colsExposed
.Add( col 
); 
1472                 m_cellsExposed
.Add( wxGridCellCoords( row
, col 
) ); 
1481 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event 
) 
1484     wxPoint 
pos( event
.GetPosition() ); 
1485     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
1487     if ( event
.Dragging() ) 
1489         m_isDragging 
= TRUE
; 
1491         if ( event
.LeftIsDown() ) 
1493             switch( m_cursorMode 
) 
1495                 case WXGRID_CURSOR_RESIZE_ROW
: 
1497                     int cw
, ch
, left
, dummy
; 
1498                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
1499                     CalcUnscrolledPosition( 0, 0, &left
, &dummy 
); 
1501                     wxClientDC 
dc( m_gridWin 
); 
1503                     dc
.SetLogicalFunction(wxINVERT
); 
1504                     if ( m_dragLastPos 
>= 0 ) 
1506                         dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos 
); 
1508                     dc
.DrawLine( left
, y
, left
+cw
, y 
); 
1513                 case WXGRID_CURSOR_SELECT_ROW
: 
1515                     if ( (row 
= YToRow( y 
)) >= 0  && 
1516                          !IsInSelection( row
, 0 ) ) 
1518                         SelectRow( row
, TRUE 
); 
1527     m_isDragging 
= FALSE
; 
1530     // ------------ Left button pressed 
1532     if ( event
.LeftDown() ) 
1534         // don't send a label click event for a hit on the 
1535         // edge of the row label - this is probably the user 
1536         // wanting to resize the row 
1538         if ( YToEdgeOfRow(y
) < 0 ) 
1542                  !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event 
) ) 
1544                 SelectRow( row
, event
.ShiftDown() ); 
1545                 m_cursorMode 
= WXGRID_CURSOR_SELECT_ROW
; 
1550             // starting to drag-resize a row 
1552             m_rowLabelWin
->CaptureMouse(); 
1557     // ------------ Left double click 
1559     else if (event
.LeftDClick() ) 
1561         if ( YToEdgeOfRow(y
) < 0 ) 
1564             SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event 
); 
1569     // ------------ Left button released 
1571     else if ( event
.LeftUp() ) 
1573         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
1575             m_rowLabelWin
->ReleaseMouse(); 
1577             if ( m_dragLastPos 
>= 0 ) 
1579                 // erase the last line and resize the row 
1581                 int cw
, ch
, left
, dummy
; 
1582                 m_gridWin
->GetClientSize( &cw
, &ch 
); 
1583                 CalcUnscrolledPosition( 0, 0, &left
, &dummy 
); 
1585                 wxClientDC 
dc( m_gridWin 
); 
1587                 dc
.SetLogicalFunction( wxINVERT 
); 
1588                 dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos 
); 
1589                 HideCellEditControl(); 
1591                 int rowTop 
= m_rowBottoms
[m_dragRowOrCol
] - m_rowHeights
[m_dragRowOrCol
]; 
1592                 SetRowSize( m_dragRowOrCol
, wxMax( y 
- rowTop
, WXGRID_MIN_ROW_HEIGHT 
) ); 
1593                 if ( !GetBatchCount() ) 
1595                   // TODO: optimize this 
1596                   m_rowLabelWin
->Refresh(); 
1597                   m_gridWin
->Refresh(); 
1600                 ShowCellEditControl(); 
1602                 // Note: we are ending the event *after* doing 
1603                 // default processing in this case 
1605                 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
1613     // ------------ Right button down 
1615     else if ( event
.RightDown() ) 
1618         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event 
) ) 
1620             // no default action at the moment 
1625     // ------------ Right double click 
1627     else if ( event
.RightDClick() ) 
1630         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event 
) ) 
1632             // no default action at the moment 
1637     // ------------ No buttons down and mouse moving 
1639     else if ( event
.Moving() ) 
1641         m_dragRowOrCol 
= YToEdgeOfRow( y 
); 
1642         if ( m_dragRowOrCol 
>= 0 ) 
1644             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1646                 m_cursorMode 
= WXGRID_CURSOR_RESIZE_ROW
; 
1647                 m_rowLabelWin
->SetCursor( m_rowResizeCursor 
); 
1652             if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
1654                 m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
1655                 m_rowLabelWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
1662 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event 
) 
1665     wxPoint 
pos( event
.GetPosition() ); 
1666     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
1668     if ( event
.Dragging() ) 
1670         m_isDragging 
= TRUE
; 
1672         if ( event
.LeftIsDown() ) 
1674             switch( m_cursorMode 
) 
1676                 case WXGRID_CURSOR_RESIZE_COL
: 
1678                     int cw
, ch
, dummy
, top
; 
1679                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
1680                     CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
1682                     wxClientDC 
dc( m_gridWin 
); 
1684                     dc
.SetLogicalFunction(wxINVERT
); 
1685                     if ( m_dragLastPos 
>= 0 ) 
1687                         dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch 
); 
1689                     dc
.DrawLine( x
, top
, x
, top
+ch 
); 
1694                 case WXGRID_CURSOR_SELECT_COL
: 
1696                     if ( (col 
= XToCol( x 
)) >= 0  && 
1697                          !IsInSelection( 0, col 
) ) 
1699                         SelectCol( col
, TRUE 
); 
1708     m_isDragging 
= FALSE
; 
1711     // ------------ Left button pressed 
1713     if ( event
.LeftDown() ) 
1715         // don't send a label click event for a hit on the 
1716         // edge of the col label - this is probably the user 
1717         // wanting to resize the col 
1719         if ( XToEdgeOfCol(x
) < 0 ) 
1723                  !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event 
) ) 
1725                 SelectCol( col
, event
.ShiftDown() ); 
1726                 m_cursorMode 
= WXGRID_CURSOR_SELECT_COL
; 
1731             // starting to drag-resize a col 
1733             m_colLabelWin
->CaptureMouse(); 
1738     // ------------ Left double click 
1740     if ( event
.LeftDClick() ) 
1742         if ( XToEdgeOfCol(x
) < 0 ) 
1745             SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event 
); 
1750     // ------------ Left button released 
1752     else if ( event
.LeftUp() ) 
1754         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL 
) 
1756             m_colLabelWin
->ReleaseMouse(); 
1758             if ( m_dragLastPos 
>= 0 ) 
1760                 // erase the last line and resize the col 
1762                 int cw
, ch
, dummy
, top
; 
1763                 m_gridWin
->GetClientSize( &cw
, &ch 
); 
1764                 CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
1766                 wxClientDC 
dc( m_gridWin 
); 
1768                 dc
.SetLogicalFunction( wxINVERT 
); 
1769                 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch 
); 
1770                 HideCellEditControl(); 
1772                 int colLeft 
= m_colRights
[m_dragRowOrCol
] - m_colWidths
[m_dragRowOrCol
]; 
1773                 SetColSize( m_dragRowOrCol
, wxMax( x 
- colLeft
, WXGRID_MIN_COL_WIDTH 
) ); 
1775                 if ( !GetBatchCount() ) 
1777                   // TODO: optimize this 
1778                   m_colLabelWin
->Refresh(); 
1779                   m_gridWin
->Refresh(); 
1782                 ShowCellEditControl(); 
1784                 // Note: we are ending the event *after* doing 
1785                 // default processing in this case 
1787                 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event 
); 
1795     // ------------ Right button down 
1797     else if ( event
.RightDown() ) 
1800         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event 
) ) 
1802             // no default action at the moment 
1807     // ------------ Right double click 
1809     else if ( event
.RightDClick() ) 
1812         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event 
) ) 
1814             // no default action at the moment 
1819     // ------------ No buttons down and mouse moving 
1821     else if ( event
.Moving() ) 
1823         m_dragRowOrCol 
= XToEdgeOfCol( x 
); 
1824         if ( m_dragRowOrCol 
>= 0 ) 
1826             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1828                 m_cursorMode 
= WXGRID_CURSOR_RESIZE_COL
; 
1829                 m_colLabelWin
->SetCursor( m_colResizeCursor 
); 
1834             if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
1836                 m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
1837                 m_colLabelWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
1844 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event 
) 
1846     if ( event
.LeftDown() ) 
1848         // indicate corner label by having both row and 
1851         if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event 
) ) 
1857     else if ( event
.LeftDClick() ) 
1859         SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event 
); 
1862     else if ( event
.RightDown() ) 
1864         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event 
) ) 
1866             // no default action at the moment 
1870     else if ( event
.RightDClick() ) 
1872         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event 
) ) 
1874             // no default action at the moment 
1880 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent
& event 
) 
1883     wxPoint 
pos( event
.GetPosition() ); 
1884     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
1886     wxGridCellCoords coords
; 
1887     XYToCell( x
, y
, coords 
); 
1889     if ( event
.Dragging() ) 
1891         m_isDragging 
= TRUE
; 
1892         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1894             // Hide the edit control, so it 
1895             // won't interfer with drag-shrinking. 
1896             if ( IsCellEditControlEnabled() ) 
1897                 HideCellEditControl(); 
1898             if ( coords 
!= wxGridNoCellCoords 
) 
1900                 if ( !IsSelection() ) 
1902                     SelectBlock( coords
, coords 
); 
1906                     SelectBlock( m_currentCellCoords
, coords 
); 
1914     m_isDragging 
= FALSE
; 
1916     if ( coords 
!= wxGridNoCellCoords 
) 
1918         if ( event
.LeftDown() ) 
1920             if ( event
.ShiftDown() ) 
1922                 SelectBlock( m_currentCellCoords
, coords 
); 
1926                 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK
, 
1931                     MakeCellVisible( coords 
); 
1932                     SetCurrentCell( coords 
); 
1938         // ------------ Left double click 
1940         else if ( event
.LeftDClick() ) 
1942             SendEvent( EVT_GRID_CELL_LEFT_DCLICK
, 
1949         // ------------ Left button released 
1951         else if ( event
.LeftUp() ) 
1953             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1955                 if ( IsSelection() ) 
1957                     SendEvent( EVT_GRID_RANGE_SELECT
, -1, -1, event 
); 
1961             // Show the edit control, if it has 
1962             // been hidden for drag-shrinking. 
1963             if ( IsCellEditControlEnabled() ) 
1964                 ShowCellEditControl(); 
1970         // ------------ Right button down 
1972         else if ( event
.RightDown() ) 
1974             if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK
, 
1979                 // no default action at the moment 
1984         // ------------ Right double click 
1986         else if ( event
.RightDClick() ) 
1988             if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK
, 
1993                 // no default action at the moment 
2001 // ------ interaction with data model 
2003 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg 
) 
2005     switch ( msg
.GetId() ) 
2007         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
: 
2008             return GetModelValues(); 
2010         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
: 
2011             return SetModelValues(); 
2013         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
2014         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
2015         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
2016         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
2017         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
2018         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
2019             return Redimension( msg 
); 
2028 // The behaviour of this function depends on the grid table class 
2029 // Clear() function.  For the default wxGridStringTable class the 
2030 // behavious is to replace all cell contents with wxEmptyString but 
2031 // not to change the number of rows or cols. 
2033 void wxGrid::ClearGrid() 
2038         SetEditControlValue(); 
2039         if ( !GetBatchCount() ) m_gridWin
->Refresh(); 
2044 bool wxGrid::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) ) 
2046     // TODO: something with updateLabels flag 
2050         wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") ); 
2056         bool ok 
= m_table
->InsertRows( pos
, numRows 
); 
2058         // the table will have sent the results of the insert row 
2059         // operation to this view object as a grid table message 
2063             if ( m_numCols 
== 0 ) 
2065                 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS 
); 
2067                 // TODO: perhaps instead of appending the default number of cols 
2068                 // we should remember what the last non-zero number of cols was ? 
2072             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2074                 // if we have just inserted cols into an empty grid the current 
2075                 // cell will be undefined... 
2077                 SetCurrentCell( 0, 0 ); 
2081             if ( !GetBatchCount() ) Refresh(); 
2084         SetEditControlValue(); 
2094 bool wxGrid::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) ) 
2096     // TODO: something with updateLabels flag 
2100         wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") ); 
2104     if ( m_table 
&& m_table
->AppendRows( numRows 
) ) 
2106         if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2108             // if we have just inserted cols into an empty grid the current 
2109             // cell will be undefined... 
2111             SetCurrentCell( 0, 0 ); 
2114         // the table will have sent the results of the append row 
2115         // operation to this view object as a grid table message 
2118         if ( !GetBatchCount() ) Refresh(); 
2128 bool wxGrid::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) ) 
2130     // TODO: something with updateLabels flag 
2134         wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") ); 
2138     if ( m_table 
&& m_table
->DeleteRows( pos
, numRows 
) ) 
2140         // the table will have sent the results of the delete row 
2141         // operation to this view object as a grid table message 
2143         if ( m_numRows 
> 0 ) 
2144             SetEditControlValue(); 
2146             HideCellEditControl(); 
2149         if ( !GetBatchCount() ) Refresh(); 
2159 bool wxGrid::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) ) 
2161     // TODO: something with updateLabels flag 
2165         wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") ); 
2171         HideCellEditControl(); 
2172         bool ok 
= m_table
->InsertCols( pos
, numCols 
); 
2174         // the table will have sent the results of the insert col 
2175         // operation to this view object as a grid table message 
2179             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2181                 // if we have just inserted cols into an empty grid the current 
2182                 // cell will be undefined... 
2184                 SetCurrentCell( 0, 0 ); 
2188             if ( !GetBatchCount() ) Refresh(); 
2191         SetEditControlValue(); 
2201 bool wxGrid::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) ) 
2203     // TODO: something with updateLabels flag 
2207         wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") ); 
2211     if ( m_table 
&& m_table
->AppendCols( numCols 
) ) 
2213         // the table will have sent the results of the append col 
2214         // operation to this view object as a grid table message 
2216         if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2218             // if we have just inserted cols into an empty grid the current 
2219             // cell will be undefined... 
2221             SetCurrentCell( 0, 0 ); 
2225         if ( !GetBatchCount() ) Refresh(); 
2235 bool wxGrid::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) ) 
2237     // TODO: something with updateLabels flag 
2241         wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") ); 
2245     if ( m_table 
&& m_table
->DeleteCols( pos
, numCols 
) ) 
2247         // the table will have sent the results of the delete col 
2248         // operation to this view object as a grid table message 
2250         if ( m_numCols 
> 0 ) 
2251             SetEditControlValue(); 
2253             HideCellEditControl(); 
2256         if ( !GetBatchCount() ) Refresh(); 
2268 // ----- event handlers 
2271 // Generate a grid event based on a mouse event and 
2272 // return the result of ProcessEvent() 
2274 bool wxGrid::SendEvent( const wxEventType type
, 
2276                         wxMouseEvent
& mouseEv 
) 
2278     if ( type 
== EVT_GRID_ROW_SIZE 
|| 
2279          type 
== EVT_GRID_COL_SIZE 
) 
2281         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
2283         wxGridSizeEvent 
gridEvt( GetId(), 
2287                                  mouseEv
.GetX(), mouseEv
.GetY(), 
2288                                  mouseEv
.ControlDown(), 
2289                                  mouseEv
.ShiftDown(), 
2291                                  mouseEv
.MetaDown() ); 
2293         return GetEventHandler()->ProcessEvent(gridEvt
); 
2295     else if ( type 
== EVT_GRID_RANGE_SELECT 
) 
2297         wxGridRangeSelectEvent 
gridEvt( GetId(), 
2301                                         m_selectedBottomRight
, 
2302                                         mouseEv
.ControlDown(), 
2303                                         mouseEv
.ShiftDown(), 
2305                                         mouseEv
.MetaDown() ); 
2307         return GetEventHandler()->ProcessEvent(gridEvt
); 
2311         wxGridEvent 
gridEvt( GetId(), 
2315                              mouseEv
.GetX(), mouseEv
.GetY(), 
2316                              mouseEv
.ControlDown(), 
2317                              mouseEv
.ShiftDown(), 
2319                              mouseEv
.MetaDown() ); 
2321         return GetEventHandler()->ProcessEvent(gridEvt
); 
2326 // Generate a grid event of specified type and return the result 
2327 // of ProcessEvent(). 
2329 bool wxGrid::SendEvent( const wxEventType type
, 
2332     if ( type 
== EVT_GRID_ROW_SIZE 
|| 
2333          type 
== EVT_GRID_COL_SIZE 
) 
2335         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
2337         wxGridSizeEvent 
gridEvt( GetId(), 
2342         return GetEventHandler()->ProcessEvent(gridEvt
); 
2346         wxGridEvent 
gridEvt( GetId(), 
2351         return GetEventHandler()->ProcessEvent(gridEvt
); 
2356 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
2358     wxPaintDC 
dc( this ); 
2360     if ( m_currentCellCoords 
== wxGridNoCellCoords  
&& 
2361          m_numRows 
&& m_numCols 
) 
2363         m_currentCellCoords
.Set(0, 0); 
2364         SetEditControlValue(); 
2365         ShowCellEditControl(); 
2370 // This is just here to make sure that CalcDimensions gets called when 
2371 // the grid view is resized... then the size event is skipped to allow 
2372 // the box sizers to handle everything 
2374 void wxGrid::OnSize( wxSizeEvent
& event 
) 
2381 void wxGrid::OnKeyDown( wxKeyEvent
& event 
) 
2383     if ( m_inOnKeyDown 
) 
2385         // shouldn't be here - we are going round in circles... 
2387         wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") ); 
2390     m_inOnKeyDown 
= TRUE
; 
2392     // propagate the event up and see if it gets processed 
2394     wxWindow 
*parent 
= GetParent(); 
2395     wxKeyEvent 
keyEvt( event 
); 
2396     keyEvt
.SetEventObject( parent 
); 
2398     if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt 
) ) 
2400         // try local handlers 
2402         switch ( event
.KeyCode() ) 
2405                 if ( event
.ControlDown() ) 
2407                     MoveCursorUpBlock(); 
2416                 if ( event
.ControlDown() ) 
2418                     MoveCursorDownBlock(); 
2427                 if ( event
.ControlDown() ) 
2429                     MoveCursorLeftBlock(); 
2438                 if ( event
.ControlDown() ) 
2440                     MoveCursorRightBlock(); 
2449                 if ( !IsEditable() ) 
2460                 if ( event
.ControlDown() ) 
2462                     event
.Skip();  // to let the edit control have the return 
2471                 if ( event
.ControlDown() ) 
2473                     MakeCellVisible( 0, 0 ); 
2474                     SetCurrentCell( 0, 0 ); 
2483                 if ( event
.ControlDown() ) 
2485                     MakeCellVisible( m_numRows
-1, m_numCols
-1 ); 
2486                     SetCurrentCell( m_numRows
-1, m_numCols
-1 ); 
2503                 // now try the cell edit control 
2505                 if ( IsCellEditControlEnabled() ) 
2507                     event
.SetEventObject( m_cellEditCtrl 
); 
2508                     m_cellEditCtrl
->GetEventHandler()->ProcessEvent( event 
); 
2514     m_inOnKeyDown 
= FALSE
; 
2518 void wxGrid::SetCurrentCell( const wxGridCellCoords
& coords 
) 
2520     if ( SendEvent( EVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) ) 
2522         // the event has been intercepted - do nothing 
2526     wxClientDC 
dc( m_gridWin 
); 
2529     if ( m_currentCellCoords 
!= wxGridNoCellCoords 
) 
2531         HideCellEditControl(); 
2532         SaveEditControlValue(); 
2535     m_currentCellCoords 
= coords
; 
2537     SetEditControlValue(); 
2538     ShowCellEditControl(); 
2540     if ( IsSelection() ) 
2542         wxRect 
r( SelectionToDeviceRect() ); 
2544         if ( !GetBatchCount() ) m_gridWin
->Refresh( TRUE
, &r 
); 
2550 // ------ functions to get/send data (see also public functions) 
2553 bool wxGrid::GetModelValues() 
2557         // all we need to do is repaint the grid 
2559         m_gridWin
->Refresh(); 
2567 bool wxGrid::SetModelValues() 
2573         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
2575             for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
2577                 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) ); 
2589 // Note - this function only draws cells that are in the list of 
2590 // exposed cells (usually set from the update region by 
2591 // CalcExposedCells) 
2593 void wxGrid::DrawGridCellArea( wxDC
& dc 
) 
2595     if ( !m_numRows 
|| !m_numCols 
) return; 
2598     size_t numCells 
= m_cellsExposed
.GetCount(); 
2600     for ( i 
= 0;  i 
< numCells
;  i
++ ) 
2602         DrawCell( dc
, m_cellsExposed
[i
] ); 
2607 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2609     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2610          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2613     if ( m_gridLinesEnabled 
) 
2614         DrawCellBorder( dc
, coords 
); 
2617     DrawCellBackground( dc
, coords 
); 
2619     // TODO: separate functions here for different kinds of cells ? 
2622     DrawCellValue( dc
, coords 
); 
2626 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2628     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2629          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2631     dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) ); 
2632     int row 
= coords
.GetRow(); 
2633     int col 
= coords
.GetCol(); 
2635     // right hand border 
2637     dc
.DrawLine( m_colRights
[col
], m_rowBottoms
[row
] - m_rowHeights
[row
], 
2638                  m_colRights
[col
], m_rowBottoms
[row
] ); 
2642     dc
.DrawLine( m_colRights
[col
] - m_colWidths
[col
], m_rowBottoms
[row
], 
2643                  m_colRights
[col
], m_rowBottoms
[row
] ); 
2647 void wxGrid::DrawCellBackground( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2649     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2650          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2652     int row 
= coords
.GetRow(); 
2653     int col 
= coords
.GetCol(); 
2655     dc
.SetBackgroundMode( wxSOLID 
); 
2657     if ( IsInSelection( coords 
) ) 
2659         // TODO: improve this 
2661         dc
.SetBrush( *wxBLACK_BRUSH 
); 
2665         dc
.SetBrush( wxBrush(GetCellBackgroundColour(row
, col
), wxSOLID
) ); 
2668     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2670     dc
.DrawRectangle( m_colRights
[col
] - m_colWidths
[col
] + 1, 
2671                       m_rowBottoms
[row
] - m_rowHeights
[row
] + 1, 
2673                       m_rowHeights
[row
]-1 ); 
2677 void wxGrid::DrawCellValue( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2679     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2680          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2682     int row 
= coords
.GetRow(); 
2683     int col 
= coords
.GetCol(); 
2685     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2687     if ( IsInSelection( row
, col 
) ) 
2689         // TODO: improve this 
2691         dc
.SetTextBackground( wxColour(0, 0, 0) ); 
2692         dc
.SetTextForeground( wxColour(255, 255, 255) ); 
2696         dc
.SetTextBackground( GetCellBackgroundColour(row
, col
) ); 
2697         dc
.SetTextForeground( GetCellTextColour(row
, col
) ); 
2699     dc
.SetFont( GetCellFont(row
, col
) ); 
2702     GetCellAlignment( row
, col
, &hAlign
, &vAlign 
); 
2705     rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 ); 
2706     rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 ); 
2707     rect
.SetWidth( m_colWidths
[col
] - 4 ); 
2708     rect
.SetHeight( m_rowHeights
[row
] - 4 ); 
2710     DrawTextRectangle( dc
, GetCellValue( row
, col 
), rect
, hAlign
, vAlign 
); 
2715 // TODO: remove this ??? 
2716 // This is used to redraw all grid lines e.g. when the grid line colour 
2719 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion 
& reg 
) 
2721     if ( !m_gridLinesEnabled 
|| 
2723          !m_numCols 
) return; 
2725     int top
, bottom
, left
, right
; 
2729       m_gridWin
->GetClientSize(&cw
, &ch
); 
2731       // virtual coords of visible area 
2733       CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
2734       CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
2738       reg
.GetBox(x
, y
, w
, h
); 
2739       CalcUnscrolledPosition( x
, y
, &left
, &top 
); 
2740       CalcUnscrolledPosition( x 
+ w
, y 
+ h
, &right
, &bottom 
); 
2743     dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) ); 
2745     // horizontal grid lines 
2748     for ( i 
= 0; i 
<= m_numRows
; i
++ ) 
2750         if ( m_rowBottoms
[i
] > bottom 
) 
2754         else if ( m_rowBottoms
[i
] >= top 
) 
2756             dc
.DrawLine( left
, m_rowBottoms
[i
], right
, m_rowBottoms
[i
] ); 
2761     // vertical grid lines 
2763     for ( i 
= 0; i 
<= m_numCols
; i
++ ) 
2765         if ( m_colRights
[i
] > right 
) 
2769         else if ( m_colRights
[i
] >= left 
) 
2771             dc
.DrawLine( m_colRights
[i
], top
, m_colRights
[i
], bottom 
); 
2777 void wxGrid::DrawRowLabels( wxDC
& dc 
) 
2779     if ( !m_numRows 
|| !m_numCols 
) return; 
2782     size_t numLabels 
= m_rowLabelsExposed
.GetCount(); 
2784     for ( i 
= 0;  i 
< numLabels
;  i
++ ) 
2786         DrawRowLabel( dc
, m_rowLabelsExposed
[i
] ); 
2791 void wxGrid::DrawRowLabel( wxDC
& dc
, int row 
) 
2793     if ( m_rowHeights
[row
] <= 0 ) return; 
2795     // draw the label's horizontal border (the vertical border is 
2796     // provided by the cell area window margin) 
2798     dc
.SetPen( *wxBLACK_PEN 
); 
2800     dc
.DrawLine( 0, m_rowBottoms
[row
]+1, 
2801                  m_rowLabelWidth
, m_rowBottoms
[row
]+1 ); 
2803     dc
.SetPen( *wxWHITE_PEN 
); 
2805     dc
.DrawLine( 0, m_rowBottoms
[row
]+2, 
2806                  m_rowLabelWidth
, m_rowBottoms
[row
]+2 ); 
2808     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2809     dc
.SetTextForeground( GetLabelTextColour() ); 
2810     dc
.SetFont( GetLabelFont() ); 
2813     GetRowLabelAlignment( &hAlign
, &vAlign 
); 
2817     rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 ); 
2818     rect
.SetWidth( m_rowLabelWidth 
- 4 ); 
2819     rect
.SetHeight( m_rowHeights
[row
] - 4 ); 
2820     DrawTextRectangle( dc
, GetRowLabelValue( row 
), rect
, hAlign
, vAlign 
); 
2824 void wxGrid::DrawColLabels( wxDC
& dc 
) 
2826     if ( !m_numRows 
|| !m_numCols 
) return; 
2829     size_t numLabels 
= m_colLabelsExposed
.GetCount(); 
2831     for ( i 
= 0;  i 
< numLabels
;  i
++ ) 
2833         DrawColLabel( dc
, m_colLabelsExposed
[i
] ); 
2838 void wxGrid::DrawColLabel( wxDC
& dc
, int col 
) 
2840     if ( m_colWidths
[col
] <= 0 ) return; 
2842     // draw the label's vertical border (the horizontal border is 
2843     // provided by the cell area window margin) 
2845     dc
.SetPen( *wxBLACK_PEN 
); 
2847     dc
.DrawLine( m_colRights
[col
]+1, 0, 
2848                  m_colRights
[col
]+1, m_colLabelHeight 
); 
2850     dc
.SetPen( *wxWHITE_PEN 
); 
2852     dc
.DrawLine( m_colRights
[col
]+2, 0, 
2853                  m_colRights
[col
]+2, m_colLabelHeight 
); 
2855     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2856     dc
.SetTextForeground( GetLabelTextColour() ); 
2857     dc
.SetFont( GetLabelFont() ); 
2860     GetColLabelAlignment( &hAlign
, &vAlign 
); 
2863     rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 ); 
2865     rect
.SetWidth( m_colWidths
[col
] - 4 ); 
2866     rect
.SetHeight( m_colLabelHeight 
- 4 ); 
2867     DrawTextRectangle( dc
, GetColLabelValue( col 
), rect
, hAlign
, vAlign 
); 
2871 void wxGrid::DrawTextRectangle( wxDC
& dc
, 
2872                                 const wxString
& value
, 
2877     long textWidth
, textHeight
; 
2878     long lineWidth
, lineHeight
; 
2879     wxArrayString lines
; 
2881     dc
.SetClippingRegion( rect 
); 
2882     StringToLines( value
, lines 
); 
2883     if ( lines
.GetCount() ) 
2885         GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight 
); 
2886         dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight 
); 
2889         switch ( horizAlign 
) 
2892                 x 
= rect
.x 
+ (rect
.width 
- textWidth 
- 1); 
2896                 x 
= rect
.x 
+ ((rect
.width 
- textWidth
)/2); 
2905         switch ( vertAlign 
) 
2908                 y 
= rect
.y 
+ (rect
.height 
- textHeight 
- 1); 
2912                 y 
= rect
.y 
+ ((rect
.height 
- textHeight
)/2); 
2921         for ( size_t i 
= 0;  i 
< lines
.GetCount();  i
++ ) 
2923             dc
.DrawText( lines
[i
], (long)x
, (long)y 
); 
2928     dc
.DestroyClippingRegion(); 
2932 // Split multi line text up into an array of strings.  Any existing 
2933 // contents of the string array are preserved. 
2935 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines 
) 
2937     // TODO: this won't work for WXMAC ? (lines end with '\r') 
2938     //       => use wxTextFile functions then (VZ) 
2941     while ( startPos 
< (int)value
.Length() ) 
2943         pos 
= value
.Mid(startPos
).Find( '\n' ); 
2948         else if ( pos 
== 0 ) 
2950             lines
.Add( wxEmptyString 
); 
2954             if ( value
[startPos
+pos
-1] == '\r' ) 
2956                 lines
.Add( value
.Mid(startPos
, pos
-1) ); 
2960                 lines
.Add( value
.Mid(startPos
, pos
) ); 
2965     if ( startPos 
< (int)value
.Length() ) 
2967         lines
.Add( value
.Mid( startPos 
) ); 
2972 void wxGrid::GetTextBoxSize( wxDC
& dc
, 
2973                              wxArrayString
& lines
, 
2974                              long *width
, long *height 
) 
2981     for ( i 
= 0;  i 
< lines
.GetCount();  i
++ ) 
2983         dc
.GetTextExtent( lines
[i
], &lineW
, &lineH 
); 
2984         w 
= wxMax( w
, lineW 
); 
2994 // ------ Edit control functions 
2998 void wxGrid::EnableEditing( bool edit 
) 
3000     // TODO: improve this ? 
3002     if ( edit 
!= m_editable 
) 
3006         // TODO: extend this for other edit control types 
3008         if ( m_editCtrlType 
== wxGRID_TEXTCTRL 
) 
3010             ((wxTextCtrl 
*)m_cellEditCtrl
)->SetEditable( m_editable 
); 
3016 #if 0  // disabled for the moment - the cell control is always active 
3017 void wxGrid::EnableCellEditControl( bool enable 
) 
3019     if ( m_cellEditCtrl 
&& 
3020          enable 
!= m_cellEditCtrlEnabled 
) 
3022         m_cellEditCtrlEnabled 
= enable
; 
3024         if ( m_cellEditCtrlEnabled 
) 
3026             SetEditControlValue(); 
3027             ShowCellEditControl(); 
3031             HideCellEditControl(); 
3032             SaveEditControlValue(); 
3039 void wxGrid::ShowCellEditControl() 
3043     if ( IsCellEditControlEnabled() ) 
3045         if ( !IsVisible( m_currentCellCoords 
) ) 
3051             rect 
= CellToRect( m_currentCellCoords 
); 
3053             // convert to scrolled coords 
3055             int left
, top
, right
, bottom
; 
3056             CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top 
); 
3057             CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom 
); 
3060             m_gridWin
->GetClientSize( &cw
, &ch 
); 
3062             // Make the edit control large enough to allow for internal margins 
3063             // TODO: remove this if the text ctrl sizing is improved esp. for unix 
3066 #if defined(__WXMOTIF__) 
3067             if ( m_currentCellCoords
.GetRow() == 0  || 
3068                  m_currentCellCoords
.GetCol() == 0 ) 
3077             if ( m_currentCellCoords
.GetRow() == 0  || 
3078                  m_currentCellCoords
.GetCol() == 0 ) 
3088 #if defined(__WXGTK__) 
3091             if (left 
!= 0) left_diff
++; 
3092             if (top 
!= 0) top_diff
++; 
3093             rect
.SetLeft( left 
+ left_diff 
); 
3094             rect
.SetTop( top 
+ top_diff 
); 
3095             rect
.SetRight( rect
.GetRight() - left_diff 
); 
3096             rect
.SetBottom( rect
.GetBottom() - top_diff 
); 
3098             rect
.SetLeft( wxMax(0, left 
- extra
) ); 
3099             rect
.SetTop( wxMax(0, top 
- extra
) ); 
3100             rect
.SetRight( rect
.GetRight() + 2*extra 
); 
3101             rect
.SetBottom( rect
.GetBottom() + 2*extra 
); 
3104             m_cellEditCtrl
->SetSize( rect 
); 
3105             m_cellEditCtrl
->Show( TRUE 
); 
3107             switch ( m_editCtrlType 
) 
3109                 case wxGRID_TEXTCTRL
: 
3110                     ((wxTextCtrl 
*) m_cellEditCtrl
)->SetInsertionPointEnd(); 
3113                 case wxGRID_CHECKBOX
: 
3114                     // TODO: anything ??? 
3119                     // TODO: anything ??? 
3123                 case wxGRID_COMBOBOX
: 
3124                     // TODO: anything ??? 
3129             m_cellEditCtrl
->SetFocus(); 
3135 void wxGrid::HideCellEditControl() 
3137     if ( IsCellEditControlEnabled() ) 
3139         m_cellEditCtrl
->Show( FALSE 
); 
3144 void wxGrid::SetEditControlValue( const wxString
& value 
) 
3150             s 
= GetCellValue(m_currentCellCoords
); 
3154         if ( IsCellEditControlEnabled() ) 
3156             switch ( m_editCtrlType 
) 
3158                 case wxGRID_TEXTCTRL
: 
3159                     ((wxGridTextCtrl 
*)m_cellEditCtrl
)->SetStartValue(s
); 
3162                 case wxGRID_CHECKBOX
: 
3163                     // TODO: implement this 
3168                     // TODO: implement this 
3172                 case wxGRID_COMBOBOX
: 
3173                     // TODO: implement this 
3182 void wxGrid::SaveEditControlValue() 
3186         wxWindow 
*ctrl 
= (wxWindow 
*)NULL
; 
3188         if ( IsCellEditControlEnabled() ) 
3190             ctrl 
= m_cellEditCtrl
; 
3197         bool valueChanged 
= FALSE
; 
3199         switch ( m_editCtrlType 
) 
3201             case wxGRID_TEXTCTRL
: 
3202                 valueChanged 
= (((wxGridTextCtrl 
*)ctrl
)->GetValue() != 
3203                                 ((wxGridTextCtrl 
*)ctrl
)->GetStartValue()); 
3204                 SetCellValue( m_currentCellCoords
, 
3205                               ((wxTextCtrl 
*) ctrl
)->GetValue() ); 
3208             case wxGRID_CHECKBOX
: 
3209                 // TODO: implement this 
3214                 // TODO: implement this 
3218             case wxGRID_COMBOBOX
: 
3219                 // TODO: implement this 
3226             SendEvent( EVT_GRID_CELL_CHANGE
, 
3227                        m_currentCellCoords
.GetRow(), 
3228                        m_currentCellCoords
.GetCol() ); 
3235 // ------ Grid location functions 
3236 //  Note that all of these functions work with the logical coordinates of 
3237 //  grid cells and labels so you will need to convert from device 
3238 //  coordinates for mouse events etc. 
3241 void wxGrid::XYToCell( int x
, int y
, wxGridCellCoords
& coords 
) 
3243     int row 
= YToRow(y
); 
3244     int col 
= XToCol(x
); 
3246     if ( row 
== -1  ||  col 
== -1 ) 
3248         coords 
= wxGridNoCellCoords
; 
3252         coords
.Set( row
, col 
); 
3257 int wxGrid::YToRow( int y 
) 
3261     for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
3263         if ( y 
< m_rowBottoms
[i
] ) return i
; 
3270 int wxGrid::XToCol( int x 
) 
3274     for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
3276         if ( x 
< m_colRights
[i
] ) return i
; 
3283 // return the row number that that the y coord is near the edge of, or 
3284 // -1 if not near an edge 
3286 int wxGrid::YToEdgeOfRow( int y 
) 
3290     for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
3292         if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE 
) 
3294             d 
= abs( y 
- m_rowBottoms
[i
] ); 
3296                 if ( d 
< WXGRID_LABEL_EDGE_ZONE 
) return i
; 
3305 // return the col number that that the x coord is near the edge of, or 
3306 // -1 if not near an edge 
3308 int wxGrid::XToEdgeOfCol( int x 
) 
3312     for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
3314         if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE 
) 
3316             d 
= abs( x 
- m_colRights
[i
] ); 
3318                 if ( d 
< WXGRID_LABEL_EDGE_ZONE 
) return i
; 
3327 wxRect 
wxGrid::CellToRect( int row
, int col 
) 
3329     wxRect 
rect( -1, -1, -1, -1 ); 
3331     if ( row 
>= 0  &&  row 
< m_numRows  
&& 
3332          col 
>= 0  &&  col 
< m_numCols 
) 
3334         rect
.x 
= m_colRights
[col
] - m_colWidths
[col
]; 
3335         rect
.y 
= m_rowBottoms
[row
] - m_rowHeights
[row
]; 
3336         rect
.width 
= m_colWidths
[col
]; 
3337         rect
.height 
= m_rowHeights
[ row 
]; 
3344 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible 
) 
3346     // get the cell rectangle in logical coords 
3348     wxRect 
r( CellToRect( row
, col 
) ); 
3350     // convert to device coords 
3352     int left
, top
, right
, bottom
; 
3353     CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
3354     CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
3356     // check against the client area of the grid window 
3359     m_gridWin
->GetClientSize( &cw
, &ch 
); 
3361     if ( wholeCellVisible 
) 
3363         // is the cell wholly visible ? 
3365         return ( left 
>= 0  &&  right 
<= cw  
&& 
3366                  top 
>= 0  &&  bottom 
<= ch 
); 
3370         // is the cell partly visible ? 
3372         return ( ((left 
>=0 && left 
< cw
) || (right 
> 0 && right 
<= cw
))  && 
3373                  ((top 
>=0 && top 
< ch
) || (bottom 
> 0 && bottom 
<= ch
)) ); 
3378 // make the specified cell location visible by doing a minimal amount 
3381 void wxGrid::MakeCellVisible( int row
, int col 
) 
3384     int xpos 
= -1, ypos 
= -1; 
3386     if ( row 
>= 0  &&  row 
< m_numRows  
&& 
3387          col 
>= 0  &&  col 
< m_numCols 
) 
3389         // get the cell rectangle in logical coords 
3391         wxRect 
r( CellToRect( row
, col 
) ); 
3393         // convert to device coords 
3395         int left
, top
, right
, bottom
; 
3396         CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
3397         CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
3400         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3406         else if ( bottom 
> ch 
) 
3408             int h 
= r
.GetHeight(); 
3410             for ( i 
= row
-1;  i 
>= 0;  i
-- ) 
3412                 if ( h 
+ m_rowHeights
[i
] > ch 
) break; 
3414                 h 
+= m_rowHeights
[i
]; 
3415                 ypos 
-= m_rowHeights
[i
]; 
3418             // we divide it later by GRID_SCROLL_LINE, make sure that we don't 
3419             // have rounding errors (this is important, because if we do, we 
3420             // might not scroll at all and some cells won't be redrawn) 
3421             ypos 
+= GRID_SCROLL_LINE 
/ 2; 
3428         else if ( right 
> cw 
) 
3430             int w 
= r
.GetWidth(); 
3432             for ( i 
= col
-1;  i 
>= 0;  i
-- ) 
3434                 if ( w 
+ m_colWidths
[i
] > cw 
) break; 
3436                 w 
+= m_colWidths
[i
]; 
3437                 xpos 
-= m_colWidths
[i
]; 
3440             // see comment for ypos above 
3441             xpos 
+= GRID_SCROLL_LINE 
/ 2; 
3444         if ( xpos 
!= -1  ||  ypos 
!= -1 ) 
3446             if ( xpos 
!= -1 ) xpos 
/= GRID_SCROLL_LINE
; 
3447             if ( ypos 
!= -1 ) ypos 
/= GRID_SCROLL_LINE
; 
3448             Scroll( xpos
, ypos 
); 
3456 // ------ Grid cursor movement functions 
3459 bool wxGrid::MoveCursorUp() 
3461     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3462          m_currentCellCoords
.GetRow() > 0 ) 
3464         MakeCellVisible( m_currentCellCoords
.GetRow() - 1, 
3465                         m_currentCellCoords
.GetCol() ); 
3467         SetCurrentCell( m_currentCellCoords
.GetRow() - 1, 
3468                         m_currentCellCoords
.GetCol() ); 
3477 bool wxGrid::MoveCursorDown() 
3479     // TODO: allow for scrolling 
3481     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3482          m_currentCellCoords
.GetRow() < m_numRows
-1 ) 
3484         MakeCellVisible( m_currentCellCoords
.GetRow() + 1, 
3485                         m_currentCellCoords
.GetCol() ); 
3487         SetCurrentCell( m_currentCellCoords
.GetRow() + 1, 
3488                         m_currentCellCoords
.GetCol() ); 
3497 bool wxGrid::MoveCursorLeft() 
3499     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3500          m_currentCellCoords
.GetCol() > 0 ) 
3502         MakeCellVisible( m_currentCellCoords
.GetRow(), 
3503                         m_currentCellCoords
.GetCol() - 1 ); 
3505         SetCurrentCell( m_currentCellCoords
.GetRow(), 
3506                         m_currentCellCoords
.GetCol() - 1 ); 
3515 bool wxGrid::MoveCursorRight() 
3517     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3518          m_currentCellCoords
.GetCol() < m_numCols 
- 1 ) 
3520         MakeCellVisible( m_currentCellCoords
.GetRow(), 
3521                         m_currentCellCoords
.GetCol() + 1 ); 
3523         SetCurrentCell( m_currentCellCoords
.GetRow(), 
3524                         m_currentCellCoords
.GetCol() + 1 ); 
3533 bool wxGrid::MovePageUp() 
3535     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) return FALSE
; 
3537     int row 
= m_currentCellCoords
.GetRow(); 
3541         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3543         int y 
= m_rowBottoms
[ row 
] - m_rowHeights
[ row 
]; 
3544         int newRow 
= YToRow( y 
- ch 
+ 1 ); 
3549         else if ( newRow 
== row 
) 
3554         MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() ); 
3555         SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() ); 
3563 bool wxGrid::MovePageDown() 
3565     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) return FALSE
; 
3567     int row 
= m_currentCellCoords
.GetRow(); 
3568     if ( row 
< m_numRows 
) 
3571         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3573         int y 
= m_rowBottoms
[ row 
] - m_rowHeights
[ row 
]; 
3574         int newRow 
= YToRow( y 
+ ch 
); 
3577             newRow 
= m_numRows 
- 1; 
3579         else if ( newRow 
== row 
) 
3584         MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() ); 
3585         SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() ); 
3593 bool wxGrid::MoveCursorUpBlock() 
3596          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3597          m_currentCellCoords
.GetRow() > 0 ) 
3599         int row 
= m_currentCellCoords
.GetRow(); 
3600         int col 
= m_currentCellCoords
.GetCol(); 
3602         if ( m_table
->IsEmptyCell(row
, col
) ) 
3604             // starting in an empty cell: find the next block of 
3610                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3613         else if ( m_table
->IsEmptyCell(row
-1, col
) ) 
3615             // starting at the top of a block: find the next block 
3621                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3626             // starting within a block: find the top of the block 
3631                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3639         MakeCellVisible( row
, col 
); 
3640         SetCurrentCell( row
, col 
); 
3648 bool wxGrid::MoveCursorDownBlock() 
3651          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3652          m_currentCellCoords
.GetRow() < m_numRows
-1 ) 
3654         int row 
= m_currentCellCoords
.GetRow(); 
3655         int col 
= m_currentCellCoords
.GetCol(); 
3657         if ( m_table
->IsEmptyCell(row
, col
) ) 
3659             // starting in an empty cell: find the next block of 
3662             while ( row 
< m_numRows
-1 ) 
3665                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3668         else if ( m_table
->IsEmptyCell(row
+1, col
) ) 
3670             // starting at the bottom of a block: find the next block 
3673             while ( row 
< m_numRows
-1 ) 
3676                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3681             // starting within a block: find the bottom of the block 
3683             while ( row 
< m_numRows
-1 ) 
3686                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3694         MakeCellVisible( row
, col 
); 
3695         SetCurrentCell( row
, col 
); 
3703 bool wxGrid::MoveCursorLeftBlock() 
3706          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3707          m_currentCellCoords
.GetCol() > 0 ) 
3709         int row 
= m_currentCellCoords
.GetRow(); 
3710         int col 
= m_currentCellCoords
.GetCol(); 
3712         if ( m_table
->IsEmptyCell(row
, col
) ) 
3714             // starting in an empty cell: find the next block of 
3720                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3723         else if ( m_table
->IsEmptyCell(row
, col
-1) ) 
3725             // starting at the left of a block: find the next block 
3731                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3736             // starting within a block: find the left of the block 
3741                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3749         MakeCellVisible( row
, col 
); 
3750         SetCurrentCell( row
, col 
); 
3758 bool wxGrid::MoveCursorRightBlock() 
3761          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3762          m_currentCellCoords
.GetCol() < m_numCols
-1 ) 
3764         int row 
= m_currentCellCoords
.GetRow(); 
3765         int col 
= m_currentCellCoords
.GetCol(); 
3767         if ( m_table
->IsEmptyCell(row
, col
) ) 
3769             // starting in an empty cell: find the next block of 
3772             while ( col 
< m_numCols
-1 ) 
3775                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3778         else if ( m_table
->IsEmptyCell(row
, col
+1) ) 
3780             // starting at the right of a block: find the next block 
3783             while ( col 
< m_numCols
-1 ) 
3786                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3791             // starting within a block: find the right of the block 
3793             while ( col 
< m_numCols
-1 ) 
3796                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3804         MakeCellVisible( row
, col 
); 
3805         SetCurrentCell( row
, col 
); 
3816 // ------ Label values and formatting 
3819 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert 
) 
3821     *horiz 
= m_rowLabelHorizAlign
; 
3822     *vert  
= m_rowLabelVertAlign
; 
3825 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert 
) 
3827     *horiz 
= m_colLabelHorizAlign
; 
3828     *vert  
= m_colLabelVertAlign
; 
3831 wxString 
wxGrid::GetRowLabelValue( int row 
) 
3835         return m_table
->GetRowLabelValue( row 
); 
3845 wxString 
wxGrid::GetColLabelValue( int col 
) 
3849         return m_table
->GetColLabelValue( col 
); 
3859 void wxGrid::SetRowLabelSize( int width 
) 
3861     // TODO: how to do this with the box sizers ? 
3864 void wxGrid::SetColLabelSize( int height 
) 
3866     // TODO: how to do this with the box sizers ? 
3869 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour 
) 
3871     if ( m_labelBackgroundColour 
!= colour 
) 
3873         m_labelBackgroundColour 
= colour
; 
3874         m_rowLabelWin
->SetBackgroundColour( colour 
); 
3875         m_colLabelWin
->SetBackgroundColour( colour 
); 
3876         m_cornerLabelWin
->SetBackgroundColour( colour 
); 
3878         if ( !GetBatchCount() ) 
3880             m_rowLabelWin
->Refresh(); 
3881             m_colLabelWin
->Refresh(); 
3882             m_cornerLabelWin
->Refresh(); 
3887 void wxGrid::SetLabelTextColour( const wxColour
& colour 
) 
3889     if ( m_labelTextColour 
!= colour 
) 
3891         m_labelTextColour 
= colour
; 
3892         if ( !GetBatchCount() ) 
3894             m_rowLabelWin
->Refresh(); 
3895             m_colLabelWin
->Refresh(); 
3900 void wxGrid::SetLabelFont( const wxFont
& font 
) 
3903     if ( !GetBatchCount() ) 
3905         m_rowLabelWin
->Refresh(); 
3906         m_colLabelWin
->Refresh(); 
3910 void wxGrid::SetRowLabelAlignment( int horiz
, int vert 
) 
3912     if ( horiz 
== wxLEFT 
|| horiz 
== wxCENTRE 
|| horiz 
== wxRIGHT 
) 
3914         m_rowLabelHorizAlign 
= horiz
; 
3917     if ( vert 
== wxTOP 
|| vert 
== wxCENTRE 
|| vert 
== wxBOTTOM 
) 
3919         m_rowLabelVertAlign 
= vert
; 
3922     if ( !GetBatchCount() ) 
3924         m_rowLabelWin
->Refresh(); 
3925         m_colLabelWin
->Refresh(); 
3929 void wxGrid::SetColLabelAlignment( int horiz
, int vert 
) 
3931     if ( horiz 
== wxLEFT 
|| horiz 
== wxCENTRE 
|| horiz 
== wxRIGHT 
) 
3933         m_colLabelHorizAlign 
= horiz
; 
3936     if ( vert 
== wxTOP 
|| vert 
== wxCENTRE 
|| vert 
== wxBOTTOM 
) 
3938         m_colLabelVertAlign 
= vert
; 
3941     if ( !GetBatchCount() ) 
3943         m_rowLabelWin
->Refresh(); 
3944         m_colLabelWin
->Refresh(); 
3948 void wxGrid::SetRowLabelValue( int row
, const wxString
& s 
) 
3952         m_table
->SetRowLabelValue( row
, s 
); 
3953         if ( !GetBatchCount() ) 
3955             // TODO: Optimize this 
3957             m_rowLabelWin
->Refresh(); 
3962 void wxGrid::SetColLabelValue( int col
, const wxString
& s 
) 
3966         m_table
->SetColLabelValue( col
, s 
); 
3967         if ( !GetBatchCount() ) 
3969             // TODO: optimize this 
3971             m_colLabelWin
->Refresh(); 
3976 void wxGrid::SetGridLineColour( const wxColour
& colour 
) 
3978     if ( m_gridLineColour 
!= colour 
) 
3980         m_gridLineColour 
= colour
; 
3982         wxClientDC 
dc( m_gridWin 
); 
3984         DrawAllGridLines( dc 
); 
3988 void wxGrid::EnableGridLines( bool enable 
) 
3990     if ( enable 
!= m_gridLinesEnabled 
) 
3992         m_gridLinesEnabled 
= enable
; 
3994         if ( !GetBatchCount() ) 
3998                 wxClientDC 
dc( m_gridWin 
); 
4000                 DrawAllGridLines( dc 
); 
4004                 m_gridWin
->Refresh(); 
4011 int wxGrid::GetDefaultRowSize() 
4013     return m_defaultRowHeight
; 
4016 int wxGrid::GetRowSize( int row 
) 
4018     if ( row 
>= 0  &&  row 
< m_numRows 
) 
4019         return m_rowHeights
[row
]; 
4021         return 0;  // TODO: log an error here 
4024 int wxGrid::GetDefaultColSize() 
4026     return m_defaultColWidth
; 
4029 int wxGrid::GetColSize( int col 
) 
4031     if ( col 
>= 0  &&  col 
< m_numCols 
) 
4032         return m_colWidths
[col
]; 
4034         return 0;  // TODO: log an error here 
4037 wxColour 
wxGrid::GetDefaultCellBackgroundColour() 
4039     // TODO: replace this temp test code 
4041     return wxColour( 255, 255, 255 ); 
4044 wxColour 
wxGrid::GetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4046     // TODO: replace this temp test code 
4048     return wxColour( 255, 255, 255 ); 
4051 wxColour 
wxGrid::GetDefaultCellTextColour() 
4053     // TODO: replace this temp test code 
4055     return wxColour( 0, 0, 0 ); 
4058 wxColour 
wxGrid::GetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4060     // TODO: replace this temp test code 
4062     return wxColour( 0, 0, 0 ); 
4066 wxFont 
wxGrid::GetDefaultCellFont() 
4068     return m_defaultCellFont
; 
4071 wxFont 
wxGrid::GetCellFont( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4073     // TODO: replace this temp test code 
4075     return m_defaultCellFont
; 
4078 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert 
) 
4080     // TODO: replace this temp test code 
4086 void wxGrid::GetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int *horiz
, int *vert 
) 
4088     // TODO: replace this temp test code 
4094 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows 
) 
4096     m_defaultRowHeight 
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT 
); 
4098     if ( resizeExistingRows 
) 
4102         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
4104             m_rowHeights
[row
] = m_defaultRowHeight
; 
4105             bottom 
+= m_defaultRowHeight
; 
4106             m_rowBottoms
[row
] = bottom
; 
4112 void wxGrid::SetRowSize( int row
, int height 
) 
4116     if ( row 
>= 0  &&  row 
< m_numRows 
) 
4118         int h 
= wxMax( 0, height 
); 
4119         int diff 
= h 
- m_rowHeights
[row
]; 
4121         m_rowHeights
[row
] = h
; 
4122         for ( i 
= row
;  i 
< m_numRows
;  i
++ ) 
4124             m_rowBottoms
[i
] += diff
; 
4128         // Note: we are ending the event *after* doing 
4129         // default processing in this case 
4131         SendEvent( EVT_GRID_ROW_SIZE
, 
4136         // TODO: log an error here 
4140 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols 
) 
4142     m_defaultColWidth 
= wxMax( width
, WXGRID_MIN_COL_WIDTH 
); 
4144     if ( resizeExistingCols 
) 
4148         for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
4150             m_colWidths
[col
] = m_defaultColWidth
; 
4151             right 
+= m_defaultColWidth
; 
4152             m_colRights
[col
] = right
; 
4158 void wxGrid::SetColSize( int col
, int width 
) 
4162     if ( col 
>= 0  &&  col 
< m_numCols 
) 
4164         int w 
= wxMax( 0, width 
); 
4165         int diff 
= w 
- m_colWidths
[col
]; 
4166         m_colWidths
[col
] = w
; 
4168         for ( i 
= col
;  i 
< m_numCols
;  i
++ ) 
4170             m_colRights
[i
] += diff
; 
4174         // Note: we are ending the event *after* doing 
4175         // default processing in this case 
4177         SendEvent( EVT_GRID_COL_SIZE
, 
4182         // TODO: log an error here 
4186 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& ) 
4188     // TODO: everything !!! 
4192 void wxGrid::SetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& ) 
4194     // TODO: everything !!! 
4198 void wxGrid::SetDefaultCellTextColour( const wxColour
& ) 
4200     // TODO: everything !!! 
4204 void wxGrid::SetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& ) 
4206     // TODO: everything !!! 
4210 void wxGrid::SetDefaultCellFont( const wxFont
& ) 
4212     // TODO: everything !!! 
4216 void wxGrid::SetCellFont( int WXUNUSED(row
), int WXUNUSED(col
), const wxFont
& ) 
4218     // TODO: everything !!! 
4222 void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz
), int WXUNUSED(vert
) ) 
4224     // TODO: everything !!! 
4228 void wxGrid::SetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int WXUNUSED(horiz
), int WXUNUSED(vert
) ) 
4230     // TODO: everything !!! 
4237 // ------ cell value accessor functions 
4240 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s 
) 
4244         m_table
->SetValue( row
, col
, s
.c_str() ); 
4245         if ( !GetBatchCount() ) 
4247             wxClientDC 
dc( m_gridWin 
); 
4249             DrawCell( dc
, wxGridCellCoords(row
, col
) ); 
4252 #if 0  // TODO: edit in place 
4254         if ( m_currentCellCoords
.GetRow() == row 
&& 
4255              m_currentCellCoords
.GetCol() == col 
) 
4257             SetEditControlValue( s 
); 
4266 // ------ Block, row and col selection 
4269 void wxGrid::SelectRow( int row
, bool addToSelected 
) 
4273     if ( IsSelection() && addToSelected 
) 
4275         if ( m_selectedTopLeft
.GetRow() > row 
) 
4276             m_selectedTopLeft
.SetRow( row 
); 
4278         m_selectedTopLeft
.SetCol( 0 ); 
4280         if ( m_selectedBottomRight
.GetRow() < row 
) 
4281             m_selectedBottomRight
.SetRow( row 
); 
4283         m_selectedBottomRight
.SetCol( m_numCols 
- 1 ); 
4285         // TODO: optimize this so that we only refresh the newly 
4288         r 
= SelectionToDeviceRect(); 
4289         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4293         r 
= SelectionToDeviceRect(); 
4295         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4297         m_selectedTopLeft
.Set( row
, 0 ); 
4298         m_selectedBottomRight
.Set( row
, m_numCols
-1 ); 
4299         r 
= SelectionToDeviceRect(); 
4300         m_gridWin
->Refresh( TRUE
, &r 
); 
4303     wxGridRangeSelectEvent 
gridEvt( GetId(), 
4304                                     EVT_GRID_RANGE_SELECT
, 
4307                                     m_selectedBottomRight 
); 
4309     GetEventHandler()->ProcessEvent(gridEvt
); 
4313 void wxGrid::SelectCol( int col
, bool addToSelected 
) 
4317     if ( IsSelection() && addToSelected 
) 
4319         if ( m_selectedTopLeft
.GetCol() > col 
) 
4320             m_selectedTopLeft
.SetCol( col 
); 
4322         m_selectedTopLeft
.SetRow( 0 ); 
4324         if ( m_selectedBottomRight
.GetCol() < col 
) 
4325             m_selectedBottomRight
.SetCol( col 
); 
4327         m_selectedBottomRight
.SetRow( m_numRows 
- 1 ); 
4329         // TODO: optimize this so that we only refresh the newly 
4332         r 
= SelectionToDeviceRect(); 
4333         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4337         r 
= SelectionToDeviceRect(); 
4339         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4341         m_selectedTopLeft
.Set( 0, col 
); 
4342         m_selectedBottomRight
.Set( m_numRows
-1, col 
); 
4343         r 
= SelectionToDeviceRect(); 
4344         m_gridWin
->Refresh( TRUE
, &r 
); 
4347     wxGridRangeSelectEvent 
gridEvt( GetId(), 
4348                                     EVT_GRID_RANGE_SELECT
, 
4351                                     m_selectedBottomRight 
); 
4353     GetEventHandler()->ProcessEvent(gridEvt
); 
4357 void wxGrid::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol 
) 
4360     bool changed 
= FALSE
; 
4361     wxGridCellCoords updateTopLeft
, updateBottomRight
; 
4363     if ( topRow 
> bottomRow 
) 
4370     if ( leftCol 
> rightCol 
) 
4377     updateTopLeft 
= m_selectedTopLeft
; 
4378     if (m_selectedTopLeft 
!= wxGridCellCoords( topRow
, leftCol 
) ) 
4380         m_selectedTopLeft 
= wxGridCellCoords( topRow
, leftCol 
); 
4381         if (updateTopLeft 
== wxGridNoCellCoords
) 
4383             updateTopLeft 
= m_selectedTopLeft
; 
4387              if(updateTopLeft
.GetRow() > topRow
) 
4388                 updateTopLeft
.SetRow(topRow
); 
4389             if (updateTopLeft
.GetCol() > leftCol
) 
4390               updateTopLeft
.SetCol(leftCol
); 
4395     updateBottomRight 
= m_selectedBottomRight
; 
4396     if (m_selectedBottomRight 
!= wxGridCellCoords( bottomRow
, rightCol 
) ) 
4398         m_selectedBottomRight 
= wxGridCellCoords( bottomRow
, rightCol 
); 
4399         if (updateBottomRight 
== wxGridNoCellCoords
) 
4401             updateBottomRight 
= m_selectedBottomRight
; 
4405             if (updateBottomRight
.GetRow() < bottomRow
) 
4406                 updateBottomRight
.SetRow(bottomRow
); 
4407             if (updateBottomRight
.GetCol() < rightCol
) 
4408                 updateBottomRight
.SetCol(rightCol
); 
4415         wxRect 
r( BlockToDeviceRect( updateTopLeft
, updateBottomRight 
) ); 
4416         m_gridWin
->Refresh( TRUE
, &r 
); 
4419     // only generate an event if the block is not being selected by 
4420     // dragging the mouse (in which case the event will be generated in 
4421     // the mouse event handler) 
4422     if ( !m_isDragging 
) 
4424         wxGridRangeSelectEvent 
gridEvt( GetId(), 
4425                                         EVT_GRID_RANGE_SELECT
, 
4428                                         m_selectedBottomRight 
); 
4430         GetEventHandler()->ProcessEvent(gridEvt
); 
4434 void wxGrid::SelectAll() 
4436     m_selectedTopLeft
.Set( 0, 0 ); 
4437     m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 ); 
4439     m_gridWin
->Refresh(); 
4443 void wxGrid::ClearSelection() 
4445     m_selectedTopLeft 
= wxGridNoCellCoords
; 
4446     m_selectedBottomRight 
= wxGridNoCellCoords
; 
4450 // This function returns the rectangle that encloses the given block 
4451 // in device coords clipped to the client size of the grid window. 
4453 wxRect 
wxGrid::BlockToDeviceRect( const wxGridCellCoords 
&topLeft
, 
4454                                   const wxGridCellCoords 
&bottomRight 
) 
4456     wxRect 
rect( wxGridNoCellRect 
); 
4459     cellRect 
= CellToRect( topLeft 
); 
4460     if ( cellRect 
!= wxGridNoCellRect 
) 
4466         rect 
= wxRect( 0, 0, 0, 0 ); 
4469     cellRect 
= CellToRect( bottomRight 
); 
4470     if ( cellRect 
!= wxGridNoCellRect 
) 
4476         return wxGridNoCellRect
; 
4479     // convert to scrolled coords 
4481     int left
, top
, right
, bottom
; 
4482     CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top 
); 
4483     CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom 
); 
4486     m_gridWin
->GetClientSize( &cw
, &ch 
); 
4488     rect
.SetLeft( wxMax(0, left
) ); 
4489     rect
.SetTop( wxMax(0, top
) ); 
4490     rect
.SetRight( wxMin(cw
, right
) ); 
4491     rect
.SetBottom( wxMin(ch
, bottom
) ); 
4499 // ------ Grid event classes 
4502 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent 
) 
4504 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
, 
4505                           int row
, int col
, int x
, int y
, 
4506                           bool control
, bool shift
, bool alt
, bool meta 
) 
4507         : wxNotifyEvent( type
, id 
) 
4513     m_control 
= control
; 
4518     SetEventObject(obj
); 
4522 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent 
) 
4524 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
, 
4525                                   int rowOrCol
, int x
, int y
, 
4526                                   bool control
, bool shift
, bool alt
, bool meta 
) 
4527         : wxNotifyEvent( type
, id 
) 
4529     m_rowOrCol 
= rowOrCol
; 
4532     m_control 
= control
; 
4537     SetEventObject(obj
); 
4541 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent 
) 
4543 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
, 
4544                                                const wxGridCellCoords
& topLeft
, 
4545                                                const wxGridCellCoords
& bottomRight
, 
4546                                                bool control
, bool shift
, bool alt
, bool meta 
) 
4547         : wxNotifyEvent( type
, id 
) 
4549     m_topLeft     
= topLeft
; 
4550     m_bottomRight 
= bottomRight
; 
4551     m_control     
= control
; 
4556     SetEventObject(obj
); 
4560 #endif // ifndef wxUSE_NEW_GRID