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                   // Only needed to get the correct rect.y: 
1596                   wxRect 
rect ( CellToRect( m_dragRowOrCol
, 0 ) ); 
1598                   CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
1599                   rect
.width 
= m_rowLabelWidth
; 
1600                   rect
.height 
= ch 
- rect
.y
; 
1601                   m_rowLabelWin
->Refresh( TRUE
, &rect 
); 
1603                   m_gridWin
->Refresh( TRUE
, &rect 
); 
1606                 ShowCellEditControl(); 
1608                 // Note: we are ending the event *after* doing 
1609                 // default processing in this case 
1611                 SendEvent( EVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
1619     // ------------ Right button down 
1621     else if ( event
.RightDown() ) 
1624         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event 
) ) 
1626             // no default action at the moment 
1631     // ------------ Right double click 
1633     else if ( event
.RightDClick() ) 
1636         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event 
) ) 
1638             // no default action at the moment 
1643     // ------------ No buttons down and mouse moving 
1645     else if ( event
.Moving() ) 
1647         m_dragRowOrCol 
= YToEdgeOfRow( y 
); 
1648         if ( m_dragRowOrCol 
>= 0 ) 
1650             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1652                 m_cursorMode 
= WXGRID_CURSOR_RESIZE_ROW
; 
1653                 m_rowLabelWin
->SetCursor( m_rowResizeCursor 
); 
1658             if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
1660                 m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
1661                 m_rowLabelWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
1668 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event 
) 
1671     wxPoint 
pos( event
.GetPosition() ); 
1672     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
1674     if ( event
.Dragging() ) 
1676         m_isDragging 
= TRUE
; 
1678         if ( event
.LeftIsDown() ) 
1680             switch( m_cursorMode 
) 
1682                 case WXGRID_CURSOR_RESIZE_COL
: 
1684                     int cw
, ch
, dummy
, top
; 
1685                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
1686                     CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
1688                     wxClientDC 
dc( m_gridWin 
); 
1690                     dc
.SetLogicalFunction(wxINVERT
); 
1691                     if ( m_dragLastPos 
>= 0 ) 
1693                         dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch 
); 
1695                     dc
.DrawLine( x
, top
, x
, top
+ch 
); 
1700                 case WXGRID_CURSOR_SELECT_COL
: 
1702                     if ( (col 
= XToCol( x 
)) >= 0  && 
1703                          !IsInSelection( 0, col 
) ) 
1705                         SelectCol( col
, TRUE 
); 
1714     m_isDragging 
= FALSE
; 
1717     // ------------ Left button pressed 
1719     if ( event
.LeftDown() ) 
1721         // don't send a label click event for a hit on the 
1722         // edge of the col label - this is probably the user 
1723         // wanting to resize the col 
1725         if ( XToEdgeOfCol(x
) < 0 ) 
1729                  !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event 
) ) 
1731                 SelectCol( col
, event
.ShiftDown() ); 
1732                 m_cursorMode 
= WXGRID_CURSOR_SELECT_COL
; 
1737             // starting to drag-resize a col 
1739             m_colLabelWin
->CaptureMouse(); 
1744     // ------------ Left double click 
1746     if ( event
.LeftDClick() ) 
1748         if ( XToEdgeOfCol(x
) < 0 ) 
1751             SendEvent(  EVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event 
); 
1756     // ------------ Left button released 
1758     else if ( event
.LeftUp() ) 
1760         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL 
) 
1762             m_colLabelWin
->ReleaseMouse(); 
1764             if ( m_dragLastPos 
>= 0 ) 
1766                 // erase the last line and resize the col 
1768                 int cw
, ch
, dummy
, top
; 
1769                 m_gridWin
->GetClientSize( &cw
, &ch 
); 
1770                 CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
1772                 wxClientDC 
dc( m_gridWin 
); 
1774                 dc
.SetLogicalFunction( wxINVERT 
); 
1775                 dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top
+ch 
); 
1776                 HideCellEditControl(); 
1778                 int colLeft 
= m_colRights
[m_dragRowOrCol
] - m_colWidths
[m_dragRowOrCol
]; 
1779                 SetColSize( m_dragRowOrCol
, wxMax( x 
- colLeft
, WXGRID_MIN_COL_WIDTH 
) ); 
1781                 if ( !GetBatchCount() ) 
1783                   // Only needed to get the correct rect.x: 
1784                   wxRect 
rect ( CellToRect( 0, m_dragRowOrCol 
) ); 
1786                   CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
); 
1787                   rect
.width 
= cw 
- rect
.x
; 
1788                   rect
.height 
= m_colLabelHeight
; 
1789                   m_colLabelWin
->Refresh( TRUE
, &rect 
); 
1791                   m_gridWin
->Refresh( TRUE
, &rect 
); 
1794                 ShowCellEditControl(); 
1796                 // Note: we are ending the event *after* doing 
1797                 // default processing in this case 
1799                 SendEvent( EVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event 
); 
1807     // ------------ Right button down 
1809     else if ( event
.RightDown() ) 
1812         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event 
) ) 
1814             // no default action at the moment 
1819     // ------------ Right double click 
1821     else if ( event
.RightDClick() ) 
1824         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event 
) ) 
1826             // no default action at the moment 
1831     // ------------ No buttons down and mouse moving 
1833     else if ( event
.Moving() ) 
1835         m_dragRowOrCol 
= XToEdgeOfCol( x 
); 
1836         if ( m_dragRowOrCol 
>= 0 ) 
1838             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1840                 m_cursorMode 
= WXGRID_CURSOR_RESIZE_COL
; 
1841                 m_colLabelWin
->SetCursor( m_colResizeCursor 
); 
1846             if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
1848                 m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
1849                 m_colLabelWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
1856 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event 
) 
1858     if ( event
.LeftDown() ) 
1860         // indicate corner label by having both row and 
1863         if ( !SendEvent( EVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event 
) ) 
1869     else if ( event
.LeftDClick() ) 
1871         SendEvent( EVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event 
); 
1874     else if ( event
.RightDown() ) 
1876         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event 
) ) 
1878             // no default action at the moment 
1882     else if ( event
.RightDClick() ) 
1884         if ( !SendEvent( EVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event 
) ) 
1886             // no default action at the moment 
1892 void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent
& event 
) 
1895     wxPoint 
pos( event
.GetPosition() ); 
1896     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
1898     wxGridCellCoords coords
; 
1899     XYToCell( x
, y
, coords 
); 
1901     if ( event
.Dragging() ) 
1903         m_isDragging 
= TRUE
; 
1904         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1906             // Hide the edit control, so it 
1907             // won't interfer with drag-shrinking. 
1908             if ( IsCellEditControlEnabled() ) 
1909                 HideCellEditControl(); 
1910             if ( coords 
!= wxGridNoCellCoords 
) 
1912                 if ( !IsSelection() ) 
1914                     SelectBlock( coords
, coords 
); 
1918                     SelectBlock( m_currentCellCoords
, coords 
); 
1926     m_isDragging 
= FALSE
; 
1928     if ( coords 
!= wxGridNoCellCoords 
) 
1930         if ( event
.LeftDown() ) 
1932             if ( event
.ShiftDown() ) 
1934                 SelectBlock( m_currentCellCoords
, coords 
); 
1938                 if ( !SendEvent( EVT_GRID_CELL_LEFT_CLICK
, 
1943                     MakeCellVisible( coords 
); 
1944                     SetCurrentCell( coords 
); 
1950         // ------------ Left double click 
1952         else if ( event
.LeftDClick() ) 
1954             SendEvent( EVT_GRID_CELL_LEFT_DCLICK
, 
1961         // ------------ Left button released 
1963         else if ( event
.LeftUp() ) 
1965             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
1967                 if ( IsSelection() ) 
1969                     SendEvent( EVT_GRID_RANGE_SELECT
, -1, -1, event 
); 
1973             // Show the edit control, if it has 
1974             // been hidden for drag-shrinking. 
1975             if ( IsCellEditControlEnabled() ) 
1976                 ShowCellEditControl(); 
1982         // ------------ Right button down 
1984         else if ( event
.RightDown() ) 
1986             if ( !SendEvent( EVT_GRID_CELL_RIGHT_CLICK
, 
1991                 // no default action at the moment 
1996         // ------------ Right double click 
1998         else if ( event
.RightDClick() ) 
2000             if ( !SendEvent( EVT_GRID_CELL_RIGHT_DCLICK
, 
2005                 // no default action at the moment 
2013 // ------ interaction with data model 
2015 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg 
) 
2017     switch ( msg
.GetId() ) 
2019         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
: 
2020             return GetModelValues(); 
2022         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
: 
2023             return SetModelValues(); 
2025         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
2026         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
2027         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
2028         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
2029         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
2030         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
2031             return Redimension( msg 
); 
2040 // The behaviour of this function depends on the grid table class 
2041 // Clear() function.  For the default wxGridStringTable class the 
2042 // behavious is to replace all cell contents with wxEmptyString but 
2043 // not to change the number of rows or cols. 
2045 void wxGrid::ClearGrid() 
2050         SetEditControlValue(); 
2051         if ( !GetBatchCount() ) m_gridWin
->Refresh(); 
2056 bool wxGrid::InsertRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) ) 
2058     // TODO: something with updateLabels flag 
2062         wxLogError( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") ); 
2068         bool ok 
= m_table
->InsertRows( pos
, numRows 
); 
2070         // the table will have sent the results of the insert row 
2071         // operation to this view object as a grid table message 
2075             if ( m_numCols 
== 0 ) 
2077                 m_table
->AppendCols( WXGRID_DEFAULT_NUMBER_COLS 
); 
2079                 // TODO: perhaps instead of appending the default number of cols 
2080                 // we should remember what the last non-zero number of cols was ? 
2084             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2086                 // if we have just inserted cols into an empty grid the current 
2087                 // cell will be undefined... 
2089                 SetCurrentCell( 0, 0 ); 
2093             if ( !GetBatchCount() ) Refresh(); 
2096         SetEditControlValue(); 
2106 bool wxGrid::AppendRows( int numRows
, bool WXUNUSED(updateLabels
) ) 
2108     // TODO: something with updateLabels flag 
2112         wxLogError( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") ); 
2116     if ( m_table 
&& m_table
->AppendRows( numRows 
) ) 
2118         if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2120             // if we have just inserted cols into an empty grid the current 
2121             // cell will be undefined... 
2123             SetCurrentCell( 0, 0 ); 
2126         // the table will have sent the results of the append row 
2127         // operation to this view object as a grid table message 
2130         if ( !GetBatchCount() ) Refresh(); 
2140 bool wxGrid::DeleteRows( int pos
, int numRows
, bool WXUNUSED(updateLabels
) ) 
2142     // TODO: something with updateLabels flag 
2146         wxLogError( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") ); 
2150     if ( m_table 
&& m_table
->DeleteRows( pos
, numRows 
) ) 
2152         // the table will have sent the results of the delete row 
2153         // operation to this view object as a grid table message 
2155         if ( m_numRows 
> 0 ) 
2156             SetEditControlValue(); 
2158             HideCellEditControl(); 
2161         if ( !GetBatchCount() ) Refresh(); 
2171 bool wxGrid::InsertCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) ) 
2173     // TODO: something with updateLabels flag 
2177         wxLogError( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") ); 
2183         HideCellEditControl(); 
2184         bool ok 
= m_table
->InsertCols( pos
, numCols 
); 
2186         // the table will have sent the results of the insert col 
2187         // operation to this view object as a grid table message 
2191             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2193                 // if we have just inserted cols into an empty grid the current 
2194                 // cell will be undefined... 
2196                 SetCurrentCell( 0, 0 ); 
2200             if ( !GetBatchCount() ) Refresh(); 
2203         SetEditControlValue(); 
2213 bool wxGrid::AppendCols( int numCols
, bool WXUNUSED(updateLabels
) ) 
2215     // TODO: something with updateLabels flag 
2219         wxLogError( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") ); 
2223     if ( m_table 
&& m_table
->AppendCols( numCols 
) ) 
2225         // the table will have sent the results of the append col 
2226         // operation to this view object as a grid table message 
2228         if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2230             // if we have just inserted cols into an empty grid the current 
2231             // cell will be undefined... 
2233             SetCurrentCell( 0, 0 ); 
2237         if ( !GetBatchCount() ) Refresh(); 
2247 bool wxGrid::DeleteCols( int pos
, int numCols
, bool WXUNUSED(updateLabels
) ) 
2249     // TODO: something with updateLabels flag 
2253         wxLogError( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") ); 
2257     if ( m_table 
&& m_table
->DeleteCols( pos
, numCols 
) ) 
2259         // the table will have sent the results of the delete col 
2260         // operation to this view object as a grid table message 
2262         if ( m_numCols 
> 0 ) 
2263             SetEditControlValue(); 
2265             HideCellEditControl(); 
2268         if ( !GetBatchCount() ) Refresh(); 
2280 // ----- event handlers 
2283 // Generate a grid event based on a mouse event and 
2284 // return the result of ProcessEvent() 
2286 bool wxGrid::SendEvent( const wxEventType type
, 
2288                         wxMouseEvent
& mouseEv 
) 
2290     if ( type 
== EVT_GRID_ROW_SIZE 
|| 
2291          type 
== EVT_GRID_COL_SIZE 
) 
2293         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
2295         wxGridSizeEvent 
gridEvt( GetId(), 
2299                                  mouseEv
.GetX(), mouseEv
.GetY(), 
2300                                  mouseEv
.ControlDown(), 
2301                                  mouseEv
.ShiftDown(), 
2303                                  mouseEv
.MetaDown() ); 
2305         return GetEventHandler()->ProcessEvent(gridEvt
); 
2307     else if ( type 
== EVT_GRID_RANGE_SELECT 
) 
2309         wxGridRangeSelectEvent 
gridEvt( GetId(), 
2313                                         m_selectedBottomRight
, 
2314                                         mouseEv
.ControlDown(), 
2315                                         mouseEv
.ShiftDown(), 
2317                                         mouseEv
.MetaDown() ); 
2319         return GetEventHandler()->ProcessEvent(gridEvt
); 
2323         wxGridEvent 
gridEvt( GetId(), 
2327                              mouseEv
.GetX(), mouseEv
.GetY(), 
2328                              mouseEv
.ControlDown(), 
2329                              mouseEv
.ShiftDown(), 
2331                              mouseEv
.MetaDown() ); 
2333         return GetEventHandler()->ProcessEvent(gridEvt
); 
2338 // Generate a grid event of specified type and return the result 
2339 // of ProcessEvent(). 
2341 bool wxGrid::SendEvent( const wxEventType type
, 
2344     if ( type 
== EVT_GRID_ROW_SIZE 
|| 
2345          type 
== EVT_GRID_COL_SIZE 
) 
2347         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
2349         wxGridSizeEvent 
gridEvt( GetId(), 
2354         return GetEventHandler()->ProcessEvent(gridEvt
); 
2358         wxGridEvent 
gridEvt( GetId(), 
2363         return GetEventHandler()->ProcessEvent(gridEvt
); 
2368 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
2370     wxPaintDC 
dc( this ); 
2372     if ( m_currentCellCoords 
== wxGridNoCellCoords  
&& 
2373          m_numRows 
&& m_numCols 
) 
2375         m_currentCellCoords
.Set(0, 0); 
2376         SetEditControlValue(); 
2377         ShowCellEditControl(); 
2382 // This is just here to make sure that CalcDimensions gets called when 
2383 // the grid view is resized... then the size event is skipped to allow 
2384 // the box sizers to handle everything 
2386 void wxGrid::OnSize( wxSizeEvent
& event 
) 
2393 void wxGrid::OnKeyDown( wxKeyEvent
& event 
) 
2395     if ( m_inOnKeyDown 
) 
2397         // shouldn't be here - we are going round in circles... 
2399         wxLogFatalError( wxT("wxGrid::OnKeyDown called while alread active") ); 
2402     m_inOnKeyDown 
= TRUE
; 
2404     // propagate the event up and see if it gets processed 
2406     wxWindow 
*parent 
= GetParent(); 
2407     wxKeyEvent 
keyEvt( event 
); 
2408     keyEvt
.SetEventObject( parent 
); 
2410     if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt 
) ) 
2412         // try local handlers 
2414         switch ( event
.KeyCode() ) 
2417                 if ( event
.ControlDown() ) 
2419                     MoveCursorUpBlock(); 
2428                 if ( event
.ControlDown() ) 
2430                     MoveCursorDownBlock(); 
2439                 if ( event
.ControlDown() ) 
2441                     MoveCursorLeftBlock(); 
2450                 if ( event
.ControlDown() ) 
2452                     MoveCursorRightBlock(); 
2461                 if ( !IsEditable() ) 
2472                 if ( event
.ControlDown() ) 
2474                     event
.Skip();  // to let the edit control have the return 
2483                 if ( event
.ControlDown() ) 
2485                     MakeCellVisible( 0, 0 ); 
2486                     SetCurrentCell( 0, 0 ); 
2495                 if ( event
.ControlDown() ) 
2497                     MakeCellVisible( m_numRows
-1, m_numCols
-1 ); 
2498                     SetCurrentCell( m_numRows
-1, m_numCols
-1 ); 
2515                 // now try the cell edit control 
2517                 if ( IsCellEditControlEnabled() ) 
2519                     event
.SetEventObject( m_cellEditCtrl 
); 
2520                     m_cellEditCtrl
->GetEventHandler()->ProcessEvent( event 
); 
2526     m_inOnKeyDown 
= FALSE
; 
2530 void wxGrid::SetCurrentCell( const wxGridCellCoords
& coords 
) 
2532     if ( SendEvent( EVT_GRID_SELECT_CELL
, coords
.GetRow(), coords
.GetCol() ) ) 
2534         // the event has been intercepted - do nothing 
2538     wxClientDC 
dc( m_gridWin 
); 
2541     if ( m_currentCellCoords 
!= wxGridNoCellCoords 
) 
2543         HideCellEditControl(); 
2544         SaveEditControlValue(); 
2547     m_currentCellCoords 
= coords
; 
2549     SetEditControlValue(); 
2550     ShowCellEditControl(); 
2552     if ( IsSelection() ) 
2554         wxRect 
r( SelectionToDeviceRect() ); 
2556         if ( !GetBatchCount() ) m_gridWin
->Refresh( TRUE
, &r 
); 
2562 // ------ functions to get/send data (see also public functions) 
2565 bool wxGrid::GetModelValues() 
2569         // all we need to do is repaint the grid 
2571         m_gridWin
->Refresh(); 
2579 bool wxGrid::SetModelValues() 
2585         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
2587             for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
2589                 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) ); 
2601 // Note - this function only draws cells that are in the list of 
2602 // exposed cells (usually set from the update region by 
2603 // CalcExposedCells) 
2605 void wxGrid::DrawGridCellArea( wxDC
& dc 
) 
2607     if ( !m_numRows 
|| !m_numCols 
) return; 
2610     size_t numCells 
= m_cellsExposed
.GetCount(); 
2612     for ( i 
= 0;  i 
< numCells
;  i
++ ) 
2614         DrawCell( dc
, m_cellsExposed
[i
] ); 
2619 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2621     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2622          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2625     if ( m_gridLinesEnabled 
) 
2626         DrawCellBorder( dc
, coords 
); 
2629     DrawCellBackground( dc
, coords 
); 
2631     // TODO: separate functions here for different kinds of cells ? 
2634     DrawCellValue( dc
, coords 
); 
2638 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2640     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2641          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2643     dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) ); 
2644     int row 
= coords
.GetRow(); 
2645     int col 
= coords
.GetCol(); 
2647     // right hand border 
2649     dc
.DrawLine( m_colRights
[col
], m_rowBottoms
[row
] - m_rowHeights
[row
], 
2650                  m_colRights
[col
], m_rowBottoms
[row
] ); 
2654     dc
.DrawLine( m_colRights
[col
] - m_colWidths
[col
], m_rowBottoms
[row
], 
2655                  m_colRights
[col
], m_rowBottoms
[row
] ); 
2659 void wxGrid::DrawCellBackground( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2661     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2662          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2664     int row 
= coords
.GetRow(); 
2665     int col 
= coords
.GetCol(); 
2667     dc
.SetBackgroundMode( wxSOLID 
); 
2669     if ( IsInSelection( coords 
) ) 
2671         // TODO: improve this 
2673         dc
.SetBrush( *wxBLACK_BRUSH 
); 
2677         dc
.SetBrush( wxBrush(GetCellBackgroundColour(row
, col
), wxSOLID
) ); 
2680     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2682     dc
.DrawRectangle( m_colRights
[col
] - m_colWidths
[col
] + 1, 
2683                       m_rowBottoms
[row
] - m_rowHeights
[row
] + 1, 
2685                       m_rowHeights
[row
]-1 ); 
2689 void wxGrid::DrawCellValue( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
2691     if ( m_colWidths
[coords
.GetCol()] <=0  || 
2692          m_rowHeights
[coords
.GetRow()] <= 0 ) return; 
2694     int row 
= coords
.GetRow(); 
2695     int col 
= coords
.GetCol(); 
2697     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2699     if ( IsInSelection( row
, col 
) ) 
2701         // TODO: improve this 
2703         dc
.SetTextBackground( wxColour(0, 0, 0) ); 
2704         dc
.SetTextForeground( wxColour(255, 255, 255) ); 
2708         dc
.SetTextBackground( GetCellBackgroundColour(row
, col
) ); 
2709         dc
.SetTextForeground( GetCellTextColour(row
, col
) ); 
2711     dc
.SetFont( GetCellFont(row
, col
) ); 
2714     GetCellAlignment( row
, col
, &hAlign
, &vAlign 
); 
2717     rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 ); 
2718     rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 ); 
2719     rect
.SetWidth( m_colWidths
[col
] - 4 ); 
2720     rect
.SetHeight( m_rowHeights
[row
] - 4 ); 
2722     DrawTextRectangle( dc
, GetCellValue( row
, col 
), rect
, hAlign
, vAlign 
); 
2727 // TODO: remove this ??? 
2728 // This is used to redraw all grid lines e.g. when the grid line colour 
2731 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion 
& reg 
) 
2733     if ( !m_gridLinesEnabled 
|| 
2735          !m_numCols 
) return; 
2737     int top
, bottom
, left
, right
; 
2741       m_gridWin
->GetClientSize(&cw
, &ch
); 
2743       // virtual coords of visible area 
2745       CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
2746       CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
2750       reg
.GetBox(x
, y
, w
, h
); 
2751       CalcUnscrolledPosition( x
, y
, &left
, &top 
); 
2752       CalcUnscrolledPosition( x 
+ w
, y 
+ h
, &right
, &bottom 
); 
2755     dc
.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID
) ); 
2757     // horizontal grid lines 
2760     for ( i 
= 0; i 
<= m_numRows
; i
++ ) 
2762         if ( m_rowBottoms
[i
] > bottom 
) 
2766         else if ( m_rowBottoms
[i
] >= top 
) 
2768             dc
.DrawLine( left
, m_rowBottoms
[i
], right
, m_rowBottoms
[i
] ); 
2773     // vertical grid lines 
2775     for ( i 
= 0; i 
<= m_numCols
; i
++ ) 
2777         if ( m_colRights
[i
] > right 
) 
2781         else if ( m_colRights
[i
] >= left 
) 
2783             dc
.DrawLine( m_colRights
[i
], top
, m_colRights
[i
], bottom 
); 
2789 void wxGrid::DrawRowLabels( wxDC
& dc 
) 
2791     if ( !m_numRows 
|| !m_numCols 
) return; 
2794     size_t numLabels 
= m_rowLabelsExposed
.GetCount(); 
2796     for ( i 
= 0;  i 
< numLabels
;  i
++ ) 
2798         DrawRowLabel( dc
, m_rowLabelsExposed
[i
] ); 
2803 void wxGrid::DrawRowLabel( wxDC
& dc
, int row 
) 
2805     if ( m_rowHeights
[row
] <= 0 ) return; 
2807     // draw the label's horizontal border (the vertical border is 
2808     // provided by the cell area window margin) 
2810     dc
.SetPen( *wxBLACK_PEN 
); 
2812     dc
.DrawLine( 0, m_rowBottoms
[row
]+1, 
2813                  m_rowLabelWidth
, m_rowBottoms
[row
]+1 ); 
2815     dc
.SetPen( *wxWHITE_PEN 
); 
2817     dc
.DrawLine( 0, m_rowBottoms
[row
]+2, 
2818                  m_rowLabelWidth
, m_rowBottoms
[row
]+2 ); 
2820     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2821     dc
.SetTextForeground( GetLabelTextColour() ); 
2822     dc
.SetFont( GetLabelFont() ); 
2825     GetRowLabelAlignment( &hAlign
, &vAlign 
); 
2829     rect
.SetY( m_rowBottoms
[row
] - m_rowHeights
[row
] + 2 ); 
2830     rect
.SetWidth( m_rowLabelWidth 
- 4 ); 
2831     rect
.SetHeight( m_rowHeights
[row
] - 4 ); 
2832     DrawTextRectangle( dc
, GetRowLabelValue( row 
), rect
, hAlign
, vAlign 
); 
2836 void wxGrid::DrawColLabels( wxDC
& dc 
) 
2838     if ( !m_numRows 
|| !m_numCols 
) return; 
2841     size_t numLabels 
= m_colLabelsExposed
.GetCount(); 
2843     for ( i 
= 0;  i 
< numLabels
;  i
++ ) 
2845         DrawColLabel( dc
, m_colLabelsExposed
[i
] ); 
2850 void wxGrid::DrawColLabel( wxDC
& dc
, int col 
) 
2852     if ( m_colWidths
[col
] <= 0 ) return; 
2854     // draw the label's vertical border (the horizontal border is 
2855     // provided by the cell area window margin) 
2857     dc
.SetPen( *wxBLACK_PEN 
); 
2859     dc
.DrawLine( m_colRights
[col
]+1, 0, 
2860                  m_colRights
[col
]+1, m_colLabelHeight 
); 
2862     dc
.SetPen( *wxWHITE_PEN 
); 
2864     dc
.DrawLine( m_colRights
[col
]+2, 0, 
2865                  m_colRights
[col
]+2, m_colLabelHeight 
); 
2867     dc
.SetBackgroundMode( wxTRANSPARENT 
); 
2868     dc
.SetTextForeground( GetLabelTextColour() ); 
2869     dc
.SetFont( GetLabelFont() ); 
2872     GetColLabelAlignment( &hAlign
, &vAlign 
); 
2875     rect
.SetX( m_colRights
[col
] - m_colWidths
[col
] + 2 ); 
2877     rect
.SetWidth( m_colWidths
[col
] - 4 ); 
2878     rect
.SetHeight( m_colLabelHeight 
- 4 ); 
2879     DrawTextRectangle( dc
, GetColLabelValue( col 
), rect
, hAlign
, vAlign 
); 
2883 void wxGrid::DrawTextRectangle( wxDC
& dc
, 
2884                                 const wxString
& value
, 
2889     long textWidth
, textHeight
; 
2890     long lineWidth
, lineHeight
; 
2891     wxArrayString lines
; 
2893     dc
.SetClippingRegion( rect 
); 
2894     StringToLines( value
, lines 
); 
2895     if ( lines
.GetCount() ) 
2897         GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight 
); 
2898         dc
.GetTextExtent( lines
[0], &lineWidth
, &lineHeight 
); 
2901         switch ( horizAlign 
) 
2904                 x 
= rect
.x 
+ (rect
.width 
- textWidth 
- 1); 
2908                 x 
= rect
.x 
+ ((rect
.width 
- textWidth
)/2); 
2917         switch ( vertAlign 
) 
2920                 y 
= rect
.y 
+ (rect
.height 
- textHeight 
- 1); 
2924                 y 
= rect
.y 
+ ((rect
.height 
- textHeight
)/2); 
2933         for ( size_t i 
= 0;  i 
< lines
.GetCount();  i
++ ) 
2935             dc
.DrawText( lines
[i
], (long)x
, (long)y 
); 
2940     dc
.DestroyClippingRegion(); 
2944 // Split multi line text up into an array of strings.  Any existing 
2945 // contents of the string array are preserved. 
2947 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines 
) 
2949     // TODO: this won't work for WXMAC ? (lines end with '\r') 
2950     //       => use wxTextFile functions then (VZ) 
2953     while ( startPos 
< (int)value
.Length() ) 
2955         pos 
= value
.Mid(startPos
).Find( '\n' ); 
2960         else if ( pos 
== 0 ) 
2962             lines
.Add( wxEmptyString 
); 
2966             if ( value
[startPos
+pos
-1] == '\r' ) 
2968                 lines
.Add( value
.Mid(startPos
, pos
-1) ); 
2972                 lines
.Add( value
.Mid(startPos
, pos
) ); 
2977     if ( startPos 
< (int)value
.Length() ) 
2979         lines
.Add( value
.Mid( startPos 
) ); 
2984 void wxGrid::GetTextBoxSize( wxDC
& dc
, 
2985                              wxArrayString
& lines
, 
2986                              long *width
, long *height 
) 
2993     for ( i 
= 0;  i 
< lines
.GetCount();  i
++ ) 
2995         dc
.GetTextExtent( lines
[i
], &lineW
, &lineH 
); 
2996         w 
= wxMax( w
, lineW 
); 
3006 // ------ Edit control functions 
3010 void wxGrid::EnableEditing( bool edit 
) 
3012     // TODO: improve this ? 
3014     if ( edit 
!= m_editable 
) 
3018         // TODO: extend this for other edit control types 
3020         if ( m_editCtrlType 
== wxGRID_TEXTCTRL 
) 
3022             ((wxTextCtrl 
*)m_cellEditCtrl
)->SetEditable( m_editable 
); 
3028 #if 0  // disabled for the moment - the cell control is always active 
3029 void wxGrid::EnableCellEditControl( bool enable 
) 
3031     if ( m_cellEditCtrl 
&& 
3032          enable 
!= m_cellEditCtrlEnabled 
) 
3034         m_cellEditCtrlEnabled 
= enable
; 
3036         if ( m_cellEditCtrlEnabled 
) 
3038             SetEditControlValue(); 
3039             ShowCellEditControl(); 
3043             HideCellEditControl(); 
3044             SaveEditControlValue(); 
3051 void wxGrid::ShowCellEditControl() 
3055     if ( IsCellEditControlEnabled() ) 
3057         if ( !IsVisible( m_currentCellCoords 
) ) 
3063             rect 
= CellToRect( m_currentCellCoords 
); 
3065             // convert to scrolled coords 
3067             int left
, top
, right
, bottom
; 
3068             CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top 
); 
3069             CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom 
); 
3072             m_gridWin
->GetClientSize( &cw
, &ch 
); 
3074             // Make the edit control large enough to allow for internal margins 
3075             // TODO: remove this if the text ctrl sizing is improved esp. for unix 
3078 #if defined(__WXMOTIF__) 
3079             if ( m_currentCellCoords
.GetRow() == 0  || 
3080                  m_currentCellCoords
.GetCol() == 0 ) 
3089             if ( m_currentCellCoords
.GetRow() == 0  || 
3090                  m_currentCellCoords
.GetCol() == 0 ) 
3100 #if defined(__WXGTK__) 
3103             if (left 
!= 0) left_diff
++; 
3104             if (top 
!= 0) top_diff
++; 
3105             rect
.SetLeft( left 
+ left_diff 
); 
3106             rect
.SetTop( top 
+ top_diff 
); 
3107             rect
.SetRight( rect
.GetRight() - left_diff 
); 
3108             rect
.SetBottom( rect
.GetBottom() - top_diff 
); 
3110             rect
.SetLeft( wxMax(0, left 
- extra
) ); 
3111             rect
.SetTop( wxMax(0, top 
- extra
) ); 
3112             rect
.SetRight( rect
.GetRight() + 2*extra 
); 
3113             rect
.SetBottom( rect
.GetBottom() + 2*extra 
); 
3116             m_cellEditCtrl
->SetSize( rect 
); 
3117             m_cellEditCtrl
->Show( TRUE 
); 
3119             switch ( m_editCtrlType 
) 
3121                 case wxGRID_TEXTCTRL
: 
3122                     ((wxTextCtrl 
*) m_cellEditCtrl
)->SetInsertionPointEnd(); 
3125                 case wxGRID_CHECKBOX
: 
3126                     // TODO: anything ??? 
3131                     // TODO: anything ??? 
3135                 case wxGRID_COMBOBOX
: 
3136                     // TODO: anything ??? 
3141             m_cellEditCtrl
->SetFocus(); 
3147 void wxGrid::HideCellEditControl() 
3149     if ( IsCellEditControlEnabled() ) 
3151         m_cellEditCtrl
->Show( FALSE 
); 
3156 void wxGrid::SetEditControlValue( const wxString
& value 
) 
3162             s 
= GetCellValue(m_currentCellCoords
); 
3166         if ( IsCellEditControlEnabled() ) 
3168             switch ( m_editCtrlType 
) 
3170                 case wxGRID_TEXTCTRL
: 
3171                     ((wxGridTextCtrl 
*)m_cellEditCtrl
)->SetStartValue(s
); 
3174                 case wxGRID_CHECKBOX
: 
3175                     // TODO: implement this 
3180                     // TODO: implement this 
3184                 case wxGRID_COMBOBOX
: 
3185                     // TODO: implement this 
3194 void wxGrid::SaveEditControlValue() 
3198         wxWindow 
*ctrl 
= (wxWindow 
*)NULL
; 
3200         if ( IsCellEditControlEnabled() ) 
3202             ctrl 
= m_cellEditCtrl
; 
3209         bool valueChanged 
= FALSE
; 
3211         switch ( m_editCtrlType 
) 
3213             case wxGRID_TEXTCTRL
: 
3214                 valueChanged 
= (((wxGridTextCtrl 
*)ctrl
)->GetValue() != 
3215                                 ((wxGridTextCtrl 
*)ctrl
)->GetStartValue()); 
3216                 SetCellValue( m_currentCellCoords
, 
3217                               ((wxTextCtrl 
*) ctrl
)->GetValue() ); 
3220             case wxGRID_CHECKBOX
: 
3221                 // TODO: implement this 
3226                 // TODO: implement this 
3230             case wxGRID_COMBOBOX
: 
3231                 // TODO: implement this 
3238             SendEvent( EVT_GRID_CELL_CHANGE
, 
3239                        m_currentCellCoords
.GetRow(), 
3240                        m_currentCellCoords
.GetCol() ); 
3247 // ------ Grid location functions 
3248 //  Note that all of these functions work with the logical coordinates of 
3249 //  grid cells and labels so you will need to convert from device 
3250 //  coordinates for mouse events etc. 
3253 void wxGrid::XYToCell( int x
, int y
, wxGridCellCoords
& coords 
) 
3255     int row 
= YToRow(y
); 
3256     int col 
= XToCol(x
); 
3258     if ( row 
== -1  ||  col 
== -1 ) 
3260         coords 
= wxGridNoCellCoords
; 
3264         coords
.Set( row
, col 
); 
3269 int wxGrid::YToRow( int y 
) 
3273     for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
3275         if ( y 
< m_rowBottoms
[i
] ) return i
; 
3282 int wxGrid::XToCol( int x 
) 
3286     for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
3288         if ( x 
< m_colRights
[i
] ) return i
; 
3295 // return the row number that that the y coord is near the edge of, or 
3296 // -1 if not near an edge 
3298 int wxGrid::YToEdgeOfRow( int y 
) 
3302     for ( i 
= 0;  i 
< m_numRows
;  i
++ ) 
3304         if ( m_rowHeights
[i
] > WXGRID_LABEL_EDGE_ZONE 
) 
3306             d 
= abs( y 
- m_rowBottoms
[i
] ); 
3308                 if ( d 
< WXGRID_LABEL_EDGE_ZONE 
) return i
; 
3317 // return the col number that that the x coord is near the edge of, or 
3318 // -1 if not near an edge 
3320 int wxGrid::XToEdgeOfCol( int x 
) 
3324     for ( i 
= 0;  i 
< m_numCols
;  i
++ ) 
3326         if ( m_colWidths
[i
] > WXGRID_LABEL_EDGE_ZONE 
) 
3328             d 
= abs( x 
- m_colRights
[i
] ); 
3330                 if ( d 
< WXGRID_LABEL_EDGE_ZONE 
) return i
; 
3339 wxRect 
wxGrid::CellToRect( int row
, int col 
) 
3341     wxRect 
rect( -1, -1, -1, -1 ); 
3343     if ( row 
>= 0  &&  row 
< m_numRows  
&& 
3344          col 
>= 0  &&  col 
< m_numCols 
) 
3346         rect
.x 
= m_colRights
[col
] - m_colWidths
[col
]; 
3347         rect
.y 
= m_rowBottoms
[row
] - m_rowHeights
[row
]; 
3348         rect
.width 
= m_colWidths
[col
]; 
3349         rect
.height 
= m_rowHeights
[ row 
]; 
3356 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible 
) 
3358     // get the cell rectangle in logical coords 
3360     wxRect 
r( CellToRect( row
, col 
) ); 
3362     // convert to device coords 
3364     int left
, top
, right
, bottom
; 
3365     CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
3366     CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
3368     // check against the client area of the grid window 
3371     m_gridWin
->GetClientSize( &cw
, &ch 
); 
3373     if ( wholeCellVisible 
) 
3375         // is the cell wholly visible ? 
3377         return ( left 
>= 0  &&  right 
<= cw  
&& 
3378                  top 
>= 0  &&  bottom 
<= ch 
); 
3382         // is the cell partly visible ? 
3384         return ( ((left 
>=0 && left 
< cw
) || (right 
> 0 && right 
<= cw
))  && 
3385                  ((top 
>=0 && top 
< ch
) || (bottom 
> 0 && bottom 
<= ch
)) ); 
3390 // make the specified cell location visible by doing a minimal amount 
3393 void wxGrid::MakeCellVisible( int row
, int col 
) 
3396     int xpos 
= -1, ypos 
= -1; 
3398     if ( row 
>= 0  &&  row 
< m_numRows  
&& 
3399          col 
>= 0  &&  col 
< m_numCols 
) 
3401         // get the cell rectangle in logical coords 
3403         wxRect 
r( CellToRect( row
, col 
) ); 
3405         // convert to device coords 
3407         int left
, top
, right
, bottom
; 
3408         CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
3409         CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
3412         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3418         else if ( bottom 
> ch 
) 
3420             int h 
= r
.GetHeight(); 
3422             for ( i 
= row
-1;  i 
>= 0;  i
-- ) 
3424                 if ( h 
+ m_rowHeights
[i
] > ch 
) break; 
3426                 h 
+= m_rowHeights
[i
]; 
3427                 ypos 
-= m_rowHeights
[i
]; 
3430             // we divide it later by GRID_SCROLL_LINE, make sure that we don't 
3431             // have rounding errors (this is important, because if we do, we 
3432             // might not scroll at all and some cells won't be redrawn) 
3433             ypos 
+= GRID_SCROLL_LINE 
/ 2; 
3440         else if ( right 
> cw 
) 
3442             int w 
= r
.GetWidth(); 
3444             for ( i 
= col
-1;  i 
>= 0;  i
-- ) 
3446                 if ( w 
+ m_colWidths
[i
] > cw 
) break; 
3448                 w 
+= m_colWidths
[i
]; 
3449                 xpos 
-= m_colWidths
[i
]; 
3452             // see comment for ypos above 
3453             xpos 
+= GRID_SCROLL_LINE 
/ 2; 
3456         if ( xpos 
!= -1  ||  ypos 
!= -1 ) 
3458             if ( xpos 
!= -1 ) xpos 
/= GRID_SCROLL_LINE
; 
3459             if ( ypos 
!= -1 ) ypos 
/= GRID_SCROLL_LINE
; 
3460             Scroll( xpos
, ypos 
); 
3468 // ------ Grid cursor movement functions 
3471 bool wxGrid::MoveCursorUp() 
3473     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3474          m_currentCellCoords
.GetRow() > 0 ) 
3476         MakeCellVisible( m_currentCellCoords
.GetRow() - 1, 
3477                         m_currentCellCoords
.GetCol() ); 
3479         SetCurrentCell( m_currentCellCoords
.GetRow() - 1, 
3480                         m_currentCellCoords
.GetCol() ); 
3489 bool wxGrid::MoveCursorDown() 
3491     // TODO: allow for scrolling 
3493     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3494          m_currentCellCoords
.GetRow() < m_numRows
-1 ) 
3496         MakeCellVisible( m_currentCellCoords
.GetRow() + 1, 
3497                         m_currentCellCoords
.GetCol() ); 
3499         SetCurrentCell( m_currentCellCoords
.GetRow() + 1, 
3500                         m_currentCellCoords
.GetCol() ); 
3509 bool wxGrid::MoveCursorLeft() 
3511     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3512          m_currentCellCoords
.GetCol() > 0 ) 
3514         MakeCellVisible( m_currentCellCoords
.GetRow(), 
3515                         m_currentCellCoords
.GetCol() - 1 ); 
3517         SetCurrentCell( m_currentCellCoords
.GetRow(), 
3518                         m_currentCellCoords
.GetCol() - 1 ); 
3527 bool wxGrid::MoveCursorRight() 
3529     if ( m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3530          m_currentCellCoords
.GetCol() < m_numCols 
- 1 ) 
3532         MakeCellVisible( m_currentCellCoords
.GetRow(), 
3533                         m_currentCellCoords
.GetCol() + 1 ); 
3535         SetCurrentCell( m_currentCellCoords
.GetRow(), 
3536                         m_currentCellCoords
.GetCol() + 1 ); 
3545 bool wxGrid::MovePageUp() 
3547     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) return FALSE
; 
3549     int row 
= m_currentCellCoords
.GetRow(); 
3553         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3555         int y 
= m_rowBottoms
[ row 
] - m_rowHeights
[ row 
]; 
3556         int newRow 
= YToRow( y 
- ch 
+ 1 ); 
3561         else if ( newRow 
== row 
) 
3566         MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() ); 
3567         SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() ); 
3575 bool wxGrid::MovePageDown() 
3577     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) return FALSE
; 
3579     int row 
= m_currentCellCoords
.GetRow(); 
3580     if ( row 
< m_numRows 
) 
3583         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3585         int y 
= m_rowBottoms
[ row 
] - m_rowHeights
[ row 
]; 
3586         int newRow 
= YToRow( y 
+ ch 
); 
3589             newRow 
= m_numRows 
- 1; 
3591         else if ( newRow 
== row 
) 
3596         MakeCellVisible( newRow
, m_currentCellCoords
.GetCol() ); 
3597         SetCurrentCell( newRow
, m_currentCellCoords
.GetCol() ); 
3605 bool wxGrid::MoveCursorUpBlock() 
3608          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3609          m_currentCellCoords
.GetRow() > 0 ) 
3611         int row 
= m_currentCellCoords
.GetRow(); 
3612         int col 
= m_currentCellCoords
.GetCol(); 
3614         if ( m_table
->IsEmptyCell(row
, col
) ) 
3616             // starting in an empty cell: find the next block of 
3622                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3625         else if ( m_table
->IsEmptyCell(row
-1, col
) ) 
3627             // starting at the top of a block: find the next block 
3633                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3638             // starting within a block: find the top of the block 
3643                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3651         MakeCellVisible( row
, col 
); 
3652         SetCurrentCell( row
, col 
); 
3660 bool wxGrid::MoveCursorDownBlock() 
3663          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3664          m_currentCellCoords
.GetRow() < m_numRows
-1 ) 
3666         int row 
= m_currentCellCoords
.GetRow(); 
3667         int col 
= m_currentCellCoords
.GetCol(); 
3669         if ( m_table
->IsEmptyCell(row
, col
) ) 
3671             // starting in an empty cell: find the next block of 
3674             while ( row 
< m_numRows
-1 ) 
3677                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3680         else if ( m_table
->IsEmptyCell(row
+1, col
) ) 
3682             // starting at the bottom of a block: find the next block 
3685             while ( row 
< m_numRows
-1 ) 
3688                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3693             // starting within a block: find the bottom of the block 
3695             while ( row 
< m_numRows
-1 ) 
3698                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3706         MakeCellVisible( row
, col 
); 
3707         SetCurrentCell( row
, col 
); 
3715 bool wxGrid::MoveCursorLeftBlock() 
3718          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3719          m_currentCellCoords
.GetCol() > 0 ) 
3721         int row 
= m_currentCellCoords
.GetRow(); 
3722         int col 
= m_currentCellCoords
.GetCol(); 
3724         if ( m_table
->IsEmptyCell(row
, col
) ) 
3726             // starting in an empty cell: find the next block of 
3732                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3735         else if ( m_table
->IsEmptyCell(row
, col
-1) ) 
3737             // starting at the left of a block: find the next block 
3743                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3748             // starting within a block: find the left of the block 
3753                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3761         MakeCellVisible( row
, col 
); 
3762         SetCurrentCell( row
, col 
); 
3770 bool wxGrid::MoveCursorRightBlock() 
3773          m_currentCellCoords 
!= wxGridNoCellCoords  
&& 
3774          m_currentCellCoords
.GetCol() < m_numCols
-1 ) 
3776         int row 
= m_currentCellCoords
.GetRow(); 
3777         int col 
= m_currentCellCoords
.GetCol(); 
3779         if ( m_table
->IsEmptyCell(row
, col
) ) 
3781             // starting in an empty cell: find the next block of 
3784             while ( col 
< m_numCols
-1 ) 
3787                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3790         else if ( m_table
->IsEmptyCell(row
, col
+1) ) 
3792             // starting at the right of a block: find the next block 
3795             while ( col 
< m_numCols
-1 ) 
3798                 if ( !(m_table
->IsEmptyCell(row
, col
)) ) break; 
3803             // starting within a block: find the right of the block 
3805             while ( col 
< m_numCols
-1 ) 
3808                 if ( m_table
->IsEmptyCell(row
, col
) ) 
3816         MakeCellVisible( row
, col 
); 
3817         SetCurrentCell( row
, col 
); 
3828 // ------ Label values and formatting 
3831 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert 
) 
3833     *horiz 
= m_rowLabelHorizAlign
; 
3834     *vert  
= m_rowLabelVertAlign
; 
3837 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert 
) 
3839     *horiz 
= m_colLabelHorizAlign
; 
3840     *vert  
= m_colLabelVertAlign
; 
3843 wxString 
wxGrid::GetRowLabelValue( int row 
) 
3847         return m_table
->GetRowLabelValue( row 
); 
3857 wxString 
wxGrid::GetColLabelValue( int col 
) 
3861         return m_table
->GetColLabelValue( col 
); 
3871 void wxGrid::SetRowLabelSize( int width 
) 
3873     // TODO: how to do this with the box sizers ? 
3876 void wxGrid::SetColLabelSize( int height 
) 
3878     // TODO: how to do this with the box sizers ? 
3881 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour 
) 
3883     if ( m_labelBackgroundColour 
!= colour 
) 
3885         m_labelBackgroundColour 
= colour
; 
3886         m_rowLabelWin
->SetBackgroundColour( colour 
); 
3887         m_colLabelWin
->SetBackgroundColour( colour 
); 
3888         m_cornerLabelWin
->SetBackgroundColour( colour 
); 
3890         if ( !GetBatchCount() ) 
3892             m_rowLabelWin
->Refresh(); 
3893             m_colLabelWin
->Refresh(); 
3894             m_cornerLabelWin
->Refresh(); 
3899 void wxGrid::SetLabelTextColour( const wxColour
& colour 
) 
3901     if ( m_labelTextColour 
!= colour 
) 
3903         m_labelTextColour 
= colour
; 
3904         if ( !GetBatchCount() ) 
3906             m_rowLabelWin
->Refresh(); 
3907             m_colLabelWin
->Refresh(); 
3912 void wxGrid::SetLabelFont( const wxFont
& font 
) 
3915     if ( !GetBatchCount() ) 
3917         m_rowLabelWin
->Refresh(); 
3918         m_colLabelWin
->Refresh(); 
3922 void wxGrid::SetRowLabelAlignment( int horiz
, int vert 
) 
3924     if ( horiz 
== wxLEFT 
|| horiz 
== wxCENTRE 
|| horiz 
== wxRIGHT 
) 
3926         m_rowLabelHorizAlign 
= horiz
; 
3929     if ( vert 
== wxTOP 
|| vert 
== wxCENTRE 
|| vert 
== wxBOTTOM 
) 
3931         m_rowLabelVertAlign 
= vert
; 
3934     if ( !GetBatchCount() ) 
3936         m_rowLabelWin
->Refresh(); 
3940 void wxGrid::SetColLabelAlignment( int horiz
, int vert 
) 
3942     if ( horiz 
== wxLEFT 
|| horiz 
== wxCENTRE 
|| horiz 
== wxRIGHT 
) 
3944         m_colLabelHorizAlign 
= horiz
; 
3947     if ( vert 
== wxTOP 
|| vert 
== wxCENTRE 
|| vert 
== wxBOTTOM 
) 
3949         m_colLabelVertAlign 
= vert
; 
3952     if ( !GetBatchCount() ) 
3954         m_colLabelWin
->Refresh(); 
3958 void wxGrid::SetRowLabelValue( int row
, const wxString
& s 
) 
3962         m_table
->SetRowLabelValue( row
, s 
); 
3963         if ( !GetBatchCount() ) 
3965             wxRect rect 
= CellToRect( row
, 0); 
3966             if ( rect
.height 
> 0 ) 
3968                 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
); 
3970                 rect
.width 
= m_rowLabelWidth
; 
3971                 m_rowLabelWin
->Refresh( TRUE
, &rect 
); 
3977 void wxGrid::SetColLabelValue( int col
, const wxString
& s 
) 
3981         m_table
->SetColLabelValue( col
, s 
); 
3982         if ( !GetBatchCount() ) 
3984             wxRect rect 
= CellToRect( 0, col 
); 
3985             if ( rect
.width 
> 0 ) 
3987                 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
); 
3989                 rect
.height 
= m_colLabelHeight
; 
3990                 m_colLabelWin
->Refresh( TRUE
, &rect 
); 
3996 void wxGrid::SetGridLineColour( const wxColour
& colour 
) 
3998     if ( m_gridLineColour 
!= colour 
) 
4000         m_gridLineColour 
= colour
; 
4002         wxClientDC 
dc( m_gridWin 
); 
4004         DrawAllGridLines( dc 
); 
4008 void wxGrid::EnableGridLines( bool enable 
) 
4010     if ( enable 
!= m_gridLinesEnabled 
) 
4012         m_gridLinesEnabled 
= enable
; 
4014         if ( !GetBatchCount() ) 
4018                 wxClientDC 
dc( m_gridWin 
); 
4020                 DrawAllGridLines( dc 
); 
4024                 m_gridWin
->Refresh(); 
4031 int wxGrid::GetDefaultRowSize() 
4033     return m_defaultRowHeight
; 
4036 int wxGrid::GetRowSize( int row 
) 
4038     if ( row 
>= 0  &&  row 
< m_numRows 
) 
4039         return m_rowHeights
[row
]; 
4041         return 0;  // TODO: log an error here 
4044 int wxGrid::GetDefaultColSize() 
4046     return m_defaultColWidth
; 
4049 int wxGrid::GetColSize( int col 
) 
4051     if ( col 
>= 0  &&  col 
< m_numCols 
) 
4052         return m_colWidths
[col
]; 
4054         return 0;  // TODO: log an error here 
4057 wxColour 
wxGrid::GetDefaultCellBackgroundColour() 
4059     // TODO: replace this temp test code 
4061     return wxColour( 255, 255, 255 ); 
4064 wxColour 
wxGrid::GetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4066     // TODO: replace this temp test code 
4068     return wxColour( 255, 255, 255 ); 
4071 wxColour 
wxGrid::GetDefaultCellTextColour() 
4073     // TODO: replace this temp test code 
4075     return wxColour( 0, 0, 0 ); 
4078 wxColour 
wxGrid::GetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4080     // TODO: replace this temp test code 
4082     return wxColour( 0, 0, 0 ); 
4086 wxFont 
wxGrid::GetDefaultCellFont() 
4088     return m_defaultCellFont
; 
4091 wxFont 
wxGrid::GetCellFont( int WXUNUSED(row
), int WXUNUSED(col
) ) 
4093     // TODO: replace this temp test code 
4095     return m_defaultCellFont
; 
4098 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert 
) 
4100     // TODO: replace this temp test code 
4106 void wxGrid::GetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int *horiz
, int *vert 
) 
4108     // TODO: replace this temp test code 
4114 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows 
) 
4116     m_defaultRowHeight 
= wxMax( height
, WXGRID_MIN_ROW_HEIGHT 
); 
4118     if ( resizeExistingRows 
) 
4122         for ( row 
= 0;  row 
< m_numRows
;  row
++ ) 
4124             m_rowHeights
[row
] = m_defaultRowHeight
; 
4125             bottom 
+= m_defaultRowHeight
; 
4126             m_rowBottoms
[row
] = bottom
; 
4132 void wxGrid::SetRowSize( int row
, int height 
) 
4136     if ( row 
>= 0  &&  row 
< m_numRows 
) 
4138         int h 
= wxMax( 0, height 
); 
4139         int diff 
= h 
- m_rowHeights
[row
]; 
4141         m_rowHeights
[row
] = h
; 
4142         for ( i 
= row
;  i 
< m_numRows
;  i
++ ) 
4144             m_rowBottoms
[i
] += diff
; 
4148         // Note: we are ending the event *after* doing 
4149         // default processing in this case 
4151         SendEvent( EVT_GRID_ROW_SIZE
, 
4156         // TODO: log an error here 
4160 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols 
) 
4162     m_defaultColWidth 
= wxMax( width
, WXGRID_MIN_COL_WIDTH 
); 
4164     if ( resizeExistingCols 
) 
4168         for ( col 
= 0;  col 
< m_numCols
;  col
++ ) 
4170             m_colWidths
[col
] = m_defaultColWidth
; 
4171             right 
+= m_defaultColWidth
; 
4172             m_colRights
[col
] = right
; 
4178 void wxGrid::SetColSize( int col
, int width 
) 
4182     if ( col 
>= 0  &&  col 
< m_numCols 
) 
4184         int w 
= wxMax( 0, width 
); 
4185         int diff 
= w 
- m_colWidths
[col
]; 
4186         m_colWidths
[col
] = w
; 
4188         for ( i 
= col
;  i 
< m_numCols
;  i
++ ) 
4190             m_colRights
[i
] += diff
; 
4194         // Note: we are ending the event *after* doing 
4195         // default processing in this case 
4197         SendEvent( EVT_GRID_COL_SIZE
, 
4202         // TODO: log an error here 
4206 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& ) 
4208     // TODO: everything !!! 
4212 void wxGrid::SetCellBackgroundColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& ) 
4214     // TODO: everything !!! 
4218 void wxGrid::SetDefaultCellTextColour( const wxColour
& ) 
4220     // TODO: everything !!! 
4224 void wxGrid::SetCellTextColour( int WXUNUSED(row
), int WXUNUSED(col
), const wxColour
& ) 
4226     // TODO: everything !!! 
4230 void wxGrid::SetDefaultCellFont( const wxFont
& ) 
4232     // TODO: everything !!! 
4236 void wxGrid::SetCellFont( int WXUNUSED(row
), int WXUNUSED(col
), const wxFont
& ) 
4238     // TODO: everything !!! 
4242 void wxGrid::SetDefaultCellAlignment( int WXUNUSED(horiz
), int WXUNUSED(vert
) ) 
4244     // TODO: everything !!! 
4248 void wxGrid::SetCellAlignment( int WXUNUSED(row
), int WXUNUSED(col
), int WXUNUSED(horiz
), int WXUNUSED(vert
) ) 
4250     // TODO: everything !!! 
4257 // ------ cell value accessor functions 
4260 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s 
) 
4264         m_table
->SetValue( row
, col
, s
.c_str() ); 
4265         if ( !GetBatchCount() ) 
4267             wxClientDC 
dc( m_gridWin 
); 
4269             DrawCell( dc
, wxGridCellCoords(row
, col
) ); 
4272 #if 0  // TODO: edit in place 
4274         if ( m_currentCellCoords
.GetRow() == row 
&& 
4275              m_currentCellCoords
.GetCol() == col 
) 
4277             SetEditControlValue( s 
); 
4286 // ------ Block, row and col selection 
4289 void wxGrid::SelectRow( int row
, bool addToSelected 
) 
4293     if ( IsSelection() && addToSelected 
) 
4296         bool    need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE 
}; 
4299         wxCoord oldLeft   
= m_selectedTopLeft
.GetCol(); 
4300         wxCoord oldTop    
= m_selectedTopLeft
.GetRow(); 
4301         wxCoord oldRight  
= m_selectedBottomRight
.GetCol(); 
4302         wxCoord oldBottom 
= m_selectedBottomRight
.GetRow(); 
4306             need_refresh
[0] = TRUE
; 
4307             rect
[0] = BlockToDeviceRect( wxGridCellCoords ( row
, 0 ), 
4308                                          wxGridCellCoords ( oldTop 
- 1, 
4310             m_selectedTopLeft
.SetRow( row 
); 
4315             need_refresh
[1] = TRUE
; 
4316             rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 0 ), 
4317                                          wxGridCellCoords ( oldBottom
, 
4320             m_selectedTopLeft
.SetCol( 0 ); 
4323         if ( oldBottom 
< row 
) 
4325             need_refresh
[2] = TRUE
; 
4326             rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldBottom 
+ 1, 0 ), 
4327                                          wxGridCellCoords ( row
, 
4329             m_selectedBottomRight
.SetRow( row 
); 
4332         if ( oldRight 
< m_numCols 
- 1 ) 
4334             need_refresh
[3] = TRUE
; 
4335             rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldTop 
, 
4337                                          wxGridCellCoords ( oldBottom
, 
4339             m_selectedBottomRight
.SetCol( m_numCols 
- 1 ); 
4342         for (i 
= 0; i 
< 4; i
++ ) 
4343             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
4344                 m_gridWin
->Refresh( TRUE
, &(rect
[i
]) ); 
4348         r 
= SelectionToDeviceRect(); 
4350         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4352         m_selectedTopLeft
.Set( row
, 0 ); 
4353         m_selectedBottomRight
.Set( row
, m_numCols
-1 ); 
4354         r 
= SelectionToDeviceRect(); 
4355         m_gridWin
->Refresh( TRUE
, &r 
); 
4358     wxGridRangeSelectEvent 
gridEvt( GetId(), 
4359                                     EVT_GRID_RANGE_SELECT
, 
4362                                     m_selectedBottomRight 
); 
4364     GetEventHandler()->ProcessEvent(gridEvt
); 
4368 void wxGrid::SelectCol( int col
, bool addToSelected 
) 
4370     if ( IsSelection() && addToSelected 
) 
4373         bool    need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE 
}; 
4376         wxCoord oldLeft   
= m_selectedTopLeft
.GetCol(); 
4377         wxCoord oldTop    
= m_selectedTopLeft
.GetRow(); 
4378         wxCoord oldRight  
= m_selectedBottomRight
.GetCol(); 
4379         wxCoord oldBottom 
= m_selectedBottomRight
.GetRow(); 
4381         if ( oldLeft 
> col 
) 
4383             need_refresh
[0] = TRUE
; 
4384             rect
[0] = BlockToDeviceRect( wxGridCellCoords ( 0, col 
), 
4385                                          wxGridCellCoords ( m_numRows 
- 1,  
4387             m_selectedTopLeft
.SetCol( col 
); 
4392             need_refresh
[1] = TRUE
; 
4393             rect
[1] = BlockToDeviceRect( wxGridCellCoords ( 0, oldLeft 
), 
4394                                          wxGridCellCoords ( oldTop 
- 1,  
4396             m_selectedTopLeft
.SetRow( 0 ); 
4399         if ( oldRight 
< col 
) 
4401             need_refresh
[2] = TRUE
; 
4402             rect
[2] = BlockToDeviceRect( wxGridCellCoords ( 0, oldRight 
+ 1 ), 
4403                                          wxGridCellCoords ( m_numRows 
- 1, 
4405             m_selectedBottomRight
.SetCol( col 
); 
4408         if ( oldBottom 
< m_numRows 
- 1 ) 
4410             need_refresh
[3] = TRUE
; 
4411             rect
[3] = BlockToDeviceRect( wxGridCellCoords ( oldBottom 
+ 1, 
4413                                          wxGridCellCoords ( m_numRows 
- 1, 
4415             m_selectedBottomRight
.SetRow( m_numRows 
- 1 ); 
4418         for (i 
= 0; i 
< 4; i
++ ) 
4419             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
4420                 m_gridWin
->Refresh( TRUE
, &(rect
[i
]) ); 
4426         r 
= SelectionToDeviceRect(); 
4428         if ( r 
!= wxGridNoCellRect 
) m_gridWin
->Refresh( TRUE
, &r 
); 
4430         m_selectedTopLeft
.Set( 0, col 
); 
4431         m_selectedBottomRight
.Set( m_numRows
-1, col 
); 
4432         r 
= SelectionToDeviceRect(); 
4433         m_gridWin
->Refresh( TRUE
, &r 
); 
4436     wxGridRangeSelectEvent 
gridEvt( GetId(), 
4437                                     EVT_GRID_RANGE_SELECT
, 
4440                                     m_selectedBottomRight 
); 
4442     GetEventHandler()->ProcessEvent(gridEvt
); 
4446 void wxGrid::SelectBlock( int topRow
, int leftCol
, int bottomRow
, int rightCol 
) 
4449     wxGridCellCoords updateTopLeft
, updateBottomRight
; 
4451     if ( topRow 
> bottomRow 
) 
4458     if ( leftCol 
> rightCol 
) 
4465     updateTopLeft 
= wxGridCellCoords( topRow
, leftCol 
); 
4466     updateBottomRight 
= wxGridCellCoords( bottomRow
, rightCol 
); 
4468     if ( m_selectedTopLeft 
!= updateTopLeft 
|| 
4469          m_selectedBottomRight 
!= updateBottomRight 
) 
4471         // Compute two optimal update rectangles: 
4472         // Either one rectangle is a real subset of the 
4473         // other, or they are (almost) disjoint! 
4475         bool    need_refresh
[4] = { FALSE
, FALSE
, FALSE
, FALSE 
}; 
4478         // Store intermediate values 
4479         wxCoord oldLeft   
= m_selectedTopLeft
.GetCol(); 
4480         wxCoord oldTop    
= m_selectedTopLeft
.GetRow(); 
4481         wxCoord oldRight  
= m_selectedBottomRight
.GetCol(); 
4482         wxCoord oldBottom 
= m_selectedBottomRight
.GetRow(); 
4484         // Determine the outer/inner coordinates. 
4485         if (oldLeft 
> leftCol
) 
4491         if (oldTop 
> topRow 
) 
4497         if (oldRight 
< rightCol 
) 
4500             oldRight 
= rightCol
; 
4503         if (oldBottom 
< bottomRow
) 
4506             oldBottom 
= bottomRow
; 
4510         // Now, either the stuff marked old is the outer 
4511         // rectangle or we don't have a situation where one 
4512         // is contained in the other. 
4514         if ( oldLeft 
< leftCol 
) 
4516             need_refresh
[0] = TRUE
; 
4517             rect
[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 
4519                                          wxGridCellCoords ( oldBottom
,  
4523         if ( oldTop  
< topRow 
) 
4525             need_refresh
[1] = TRUE
; 
4526             rect
[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 
4528                                          wxGridCellCoords ( topRow 
- 1,  
4532         if ( oldRight 
> rightCol 
) 
4534             need_refresh
[2] = TRUE
; 
4535             rect
[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop
, 
4537                                          wxGridCellCoords ( oldBottom
, 
4541         if ( oldBottom 
> bottomRow 
) 
4543             need_refresh
[3] = TRUE
; 
4544             rect
[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow 
+ 1, 
4546                                          wxGridCellCoords ( oldBottom
, 
4552         m_selectedTopLeft 
= updateTopLeft
; 
4553         m_selectedBottomRight 
= updateBottomRight
; 
4555         // various Refresh() calls 
4556         for (i 
= 0; i 
< 4; i
++ ) 
4557             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
4558                 m_gridWin
->Refresh( TRUE
, &(rect
[i
]) ); 
4561     // only generate an event if the block is not being selected by 
4562     // dragging the mouse (in which case the event will be generated in 
4563     // the mouse event handler) 
4564     if ( !m_isDragging 
) 
4566         wxGridRangeSelectEvent 
gridEvt( GetId(), 
4567                                         EVT_GRID_RANGE_SELECT
, 
4570                                         m_selectedBottomRight 
); 
4572         GetEventHandler()->ProcessEvent(gridEvt
); 
4576 void wxGrid::SelectAll() 
4578     m_selectedTopLeft
.Set( 0, 0 ); 
4579     m_selectedBottomRight
.Set( m_numRows
-1, m_numCols
-1 ); 
4581     m_gridWin
->Refresh(); 
4585 void wxGrid::ClearSelection() 
4587     m_selectedTopLeft 
= wxGridNoCellCoords
; 
4588     m_selectedBottomRight 
= wxGridNoCellCoords
; 
4592 // This function returns the rectangle that encloses the given block 
4593 // in device coords clipped to the client size of the grid window. 
4595 wxRect 
wxGrid::BlockToDeviceRect( const wxGridCellCoords 
&topLeft
, 
4596                                   const wxGridCellCoords 
&bottomRight 
) 
4598     wxRect 
rect( wxGridNoCellRect 
); 
4601     cellRect 
= CellToRect( topLeft 
); 
4602     if ( cellRect 
!= wxGridNoCellRect 
) 
4608         rect 
= wxRect( 0, 0, 0, 0 ); 
4611     cellRect 
= CellToRect( bottomRight 
); 
4612     if ( cellRect 
!= wxGridNoCellRect 
) 
4618         return wxGridNoCellRect
; 
4621     // convert to scrolled coords 
4623     int left
, top
, right
, bottom
; 
4624     CalcScrolledPosition( rect
.GetLeft(), rect
.GetTop(), &left
, &top 
); 
4625     CalcScrolledPosition( rect
.GetRight(), rect
.GetBottom(), &right
, &bottom 
); 
4628     m_gridWin
->GetClientSize( &cw
, &ch 
); 
4630     rect
.SetLeft( wxMax(0, left
) ); 
4631     rect
.SetTop( wxMax(0, top
) ); 
4632     rect
.SetRight( wxMin(cw
, right
) ); 
4633     rect
.SetBottom( wxMin(ch
, bottom
) ); 
4641 // ------ Grid event classes 
4644 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxEvent 
) 
4646 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
, 
4647                           int row
, int col
, int x
, int y
, 
4648                           bool control
, bool shift
, bool alt
, bool meta 
) 
4649         : wxNotifyEvent( type
, id 
) 
4655     m_control 
= control
; 
4660     SetEventObject(obj
); 
4664 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxEvent 
) 
4666 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
, 
4667                                   int rowOrCol
, int x
, int y
, 
4668                                   bool control
, bool shift
, bool alt
, bool meta 
) 
4669         : wxNotifyEvent( type
, id 
) 
4671     m_rowOrCol 
= rowOrCol
; 
4674     m_control 
= control
; 
4679     SetEventObject(obj
); 
4683 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxEvent 
) 
4685 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
, 
4686                                                const wxGridCellCoords
& topLeft
, 
4687                                                const wxGridCellCoords
& bottomRight
, 
4688                                                bool control
, bool shift
, bool alt
, bool meta 
) 
4689         : wxNotifyEvent( type
, id 
) 
4691     m_topLeft     
= topLeft
; 
4692     m_bottomRight 
= bottomRight
; 
4693     m_control     
= control
; 
4698     SetEventObject(obj
); 
4702 #endif // ifndef wxUSE_NEW_GRID