1 /////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/grid.cpp 
   3 // Purpose:     wxGrid and related classes 
   4 // Author:      Michael Bedward (based on code by Julian Smart, Robin Dunn) 
   5 // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios 
   8 // Copyright:   (c) Michael Bedward (mbedward@ozemail.com.au) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  15     - Replace use of wxINVERT with wxOverlay 
  16     - Make Begin/EndBatch() the same as the generic Freeze/Thaw() 
  17     - Review the column reordering code, it's a mess. 
  18     - Implement row reordering after dealing with the columns. 
  21 // For compilers that support precompilation, includes "wx/wx.h". 
  22 #include "wx/wxprec.h" 
  34     #include "wx/dcclient.h" 
  35     #include "wx/settings.h" 
  37     #include "wx/textctrl.h" 
  38     #include "wx/checkbox.h" 
  39     #include "wx/combobox.h" 
  40     #include "wx/valtext.h" 
  43     #include "wx/listbox.h" 
  46 #include "wx/textfile.h" 
  47 #include "wx/spinctrl.h" 
  48 #include "wx/tokenzr.h" 
  49 #include "wx/renderer.h" 
  50 #include "wx/headerctrl.h" 
  51 #include "wx/hashset.h" 
  53 #include "wx/generic/gridsel.h" 
  54 #include "wx/generic/gridctrl.h" 
  55 #include "wx/generic/grideditors.h" 
  56 #include "wx/generic/private/grid.h" 
  58 const char wxGridNameStr
[] = "grid"; 
  60 #if defined(__WXMOTIF__) 
  61     #define WXUNUSED_MOTIF(identifier)  WXUNUSED(identifier) 
  63     #define WXUNUSED_MOTIF(identifier)  identifier 
  66 #if defined(__WXGTK__) 
  67     #define WXUNUSED_GTK(identifier)    WXUNUSED(identifier) 
  69     #define WXUNUSED_GTK(identifier)    identifier 
  72 // Required for wxIs... functions 
  75 WX_DECLARE_HASH_SET_WITH_DECL_PTR(int, ::wxIntegerHash
, ::wxIntegerEqual
, 
  76                                   wxGridFixedIndicesSet
, class WXDLLIMPEXP_ADV
); 
  79 // ---------------------------------------------------------------------------- 
  81 // ---------------------------------------------------------------------------- 
  86 //#define DEBUG_ATTR_CACHE 
  87 #ifdef DEBUG_ATTR_CACHE 
  88     static size_t gs_nAttrCacheHits 
= 0; 
  89     static size_t gs_nAttrCacheMisses 
= 0; 
  92 // this struct simply combines together the default header renderers 
  94 // as the renderers ctors are trivial, there is no problem with making them 
  96 struct DefaultHeaderRenderers
 
  98     wxGridColumnHeaderRendererDefault colRenderer
; 
  99     wxGridRowHeaderRendererDefault rowRenderer
; 
 100     wxGridCornerHeaderRendererDefault cornerRenderer
; 
 101 } gs_defaultHeaderRenderers
; 
 103 } // anonymous namespace 
 105 // ---------------------------------------------------------------------------- 
 107 // ---------------------------------------------------------------------------- 
 109 wxGridCellCoords 
wxGridNoCellCoords( -1, -1 ); 
 110 wxRect 
wxGridNoCellRect( -1, -1, -1, -1 ); 
 116 const size_t GRID_SCROLL_LINE_X 
= 15; 
 117 const size_t GRID_SCROLL_LINE_Y 
= GRID_SCROLL_LINE_X
; 
 119 // the size of hash tables used a bit everywhere (the max number of elements 
 120 // in these hash tables is the number of rows/columns) 
 121 const int GRID_HASH_SIZE 
= 100; 
 123 // the minimal distance in pixels the mouse needs to move to start a drag 
 125 const int DRAG_SENSITIVITY 
= 3; 
 127 } // anonymous namespace 
 129 #include "wx/arrimpl.cpp" 
 131 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
) 
 132 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
) 
 134 // ---------------------------------------------------------------------------- 
 136 // ---------------------------------------------------------------------------- 
 138 wxDEFINE_EVENT( wxEVT_GRID_CELL_LEFT_CLICK
, wxGridEvent 
); 
 139 wxDEFINE_EVENT( wxEVT_GRID_CELL_RIGHT_CLICK
, wxGridEvent 
); 
 140 wxDEFINE_EVENT( wxEVT_GRID_CELL_LEFT_DCLICK
, wxGridEvent 
); 
 141 wxDEFINE_EVENT( wxEVT_GRID_CELL_RIGHT_DCLICK
, wxGridEvent 
); 
 142 wxDEFINE_EVENT( wxEVT_GRID_CELL_BEGIN_DRAG
, wxGridEvent 
); 
 143 wxDEFINE_EVENT( wxEVT_GRID_LABEL_LEFT_CLICK
, wxGridEvent 
); 
 144 wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_CLICK
, wxGridEvent 
); 
 145 wxDEFINE_EVENT( wxEVT_GRID_LABEL_LEFT_DCLICK
, wxGridEvent 
); 
 146 wxDEFINE_EVENT( wxEVT_GRID_LABEL_RIGHT_DCLICK
, wxGridEvent 
); 
 147 wxDEFINE_EVENT( wxEVT_GRID_ROW_SIZE
, wxGridSizeEvent 
); 
 148 wxDEFINE_EVENT( wxEVT_GRID_COL_SIZE
, wxGridSizeEvent 
); 
 149 wxDEFINE_EVENT( wxEVT_GRID_COL_MOVE
, wxGridEvent 
); 
 150 wxDEFINE_EVENT( wxEVT_GRID_COL_SORT
, wxGridEvent 
); 
 151 wxDEFINE_EVENT( wxEVT_GRID_RANGE_SELECT
, wxGridRangeSelectEvent 
); 
 152 wxDEFINE_EVENT( wxEVT_GRID_CELL_CHANGING
, wxGridEvent 
); 
 153 wxDEFINE_EVENT( wxEVT_GRID_CELL_CHANGED
, wxGridEvent 
); 
 154 wxDEFINE_EVENT( wxEVT_GRID_SELECT_CELL
, wxGridEvent 
); 
 155 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_SHOWN
, wxGridEvent 
); 
 156 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_HIDDEN
, wxGridEvent 
); 
 157 wxDEFINE_EVENT( wxEVT_GRID_EDITOR_CREATED
, wxGridEditorCreatedEvent 
); 
 159 // ---------------------------------------------------------------------------- 
 161 // ---------------------------------------------------------------------------- 
 166     // ensure that first is less or equal to second, swapping the values if 
 168     void EnsureFirstLessThanSecond(int& first
, int& second
) 
 170         if ( first 
> second 
) 
 171             wxSwap(first
, second
); 
 174 } // anonymous namespace 
 176 // ============================================================================ 
 178 // ============================================================================ 
 180 IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler
, wxEvtHandler
) 
 182 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler
, wxEvtHandler 
) 
 183     EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus 
) 
 184     EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown 
) 
 185     EVT_CHAR( wxGridCellEditorEvtHandler::OnChar 
) 
 188 BEGIN_EVENT_TABLE(wxGridHeaderCtrl
, wxHeaderCtrl
) 
 189     EVT_HEADER_CLICK(wxID_ANY
, wxGridHeaderCtrl::OnClick
) 
 190     EVT_HEADER_DCLICK(wxID_ANY
, wxGridHeaderCtrl::OnDoubleClick
) 
 191     EVT_HEADER_RIGHT_CLICK(wxID_ANY
, wxGridHeaderCtrl::OnRightClick
) 
 193     EVT_HEADER_BEGIN_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnBeginResize
) 
 194     EVT_HEADER_RESIZING(wxID_ANY
, wxGridHeaderCtrl::OnResizing
) 
 195     EVT_HEADER_END_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnEndResize
) 
 197     EVT_HEADER_BEGIN_REORDER(wxID_ANY
, wxGridHeaderCtrl::OnBeginReorder
) 
 198     EVT_HEADER_END_REORDER(wxID_ANY
, wxGridHeaderCtrl::OnEndReorder
) 
 201 wxGridOperations
& wxGridRowOperations::Dual() const 
 203     static wxGridColumnOperations s_colOper
; 
 208 wxGridOperations
& wxGridColumnOperations::Dual() const 
 210     static wxGridRowOperations s_rowOper
; 
 215 // ---------------------------------------------------------------------------- 
 216 // wxGridCellWorker is an (almost) empty common base class for 
 217 // wxGridCellRenderer and wxGridCellEditor managing ref counting 
 218 // ---------------------------------------------------------------------------- 
 220 void wxGridCellWorker::SetParameters(const wxString
& WXUNUSED(params
)) 
 225 wxGridCellWorker::~wxGridCellWorker() 
 229 // ---------------------------------------------------------------------------- 
 230 // wxGridHeaderLabelsRenderer and related classes 
 231 // ---------------------------------------------------------------------------- 
 233 void wxGridHeaderLabelsRenderer::DrawLabel(const wxGrid
& grid
, 
 235                                            const wxString
& value
, 
 239                                            int textOrientation
) const 
 241     dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
 242     dc
.SetTextForeground(grid
.GetLabelTextColour()); 
 243     dc
.SetFont(grid
.GetLabelFont()); 
 244     grid
.DrawTextRectangle(dc
, value
, rect
, horizAlign
, vertAlign
, textOrientation
); 
 248 void wxGridRowHeaderRendererDefault::DrawBorder(const wxGrid
& WXUNUSED(grid
), 
 252     dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
 253     dc
.DrawLine(rect
.GetRight(), rect
.GetTop(), 
 254                 rect
.GetRight(), rect
.GetBottom()); 
 255     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop(), 
 256                 rect
.GetLeft(), rect
.GetBottom()); 
 257     dc
.DrawLine(rect
.GetLeft(), rect
.GetBottom(), 
 258                 rect
.GetRight() + 1, rect
.GetBottom()); 
 260     dc
.SetPen(*wxWHITE_PEN
); 
 261     dc
.DrawLine(rect
.GetLeft() + 1, rect
.GetTop(), 
 262                 rect
.GetLeft() + 1, rect
.GetBottom()); 
 263     dc
.DrawLine(rect
.GetLeft() + 1, rect
.GetTop(), 
 264                 rect
.GetRight(), rect
.GetTop()); 
 269 void wxGridColumnHeaderRendererDefault::DrawBorder(const wxGrid
& WXUNUSED(grid
), 
 273     dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
 274     dc
.DrawLine(rect
.GetRight(), rect
.GetTop(), 
 275                 rect
.GetRight(), rect
.GetBottom()); 
 276     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop(), 
 277                 rect
.GetRight(), rect
.GetTop()); 
 278     dc
.DrawLine(rect
.GetLeft(), rect
.GetBottom(), 
 279                 rect
.GetRight() + 1, rect
.GetBottom()); 
 281     dc
.SetPen(*wxWHITE_PEN
); 
 282     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop() + 1, 
 283                 rect
.GetLeft(), rect
.GetBottom()); 
 284     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop() + 1, 
 285                 rect
.GetRight(), rect
.GetTop() + 1); 
 290 void wxGridCornerHeaderRendererDefault::DrawBorder(const wxGrid
& WXUNUSED(grid
), 
 294     dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
 295     dc
.DrawLine(rect
.GetRight() - 1, rect
.GetBottom() - 1, 
 296                 rect
.GetRight() - 1, rect
.GetTop()); 
 297     dc
.DrawLine(rect
.GetRight() - 1, rect
.GetBottom() - 1, 
 298                 rect
.GetLeft(), rect
.GetBottom() - 1); 
 299     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop(), 
 300                 rect
.GetRight(), rect
.GetTop()); 
 301     dc
.DrawLine(rect
.GetLeft(), rect
.GetTop(), 
 302                 rect
.GetLeft(), rect
.GetBottom()); 
 304     dc
.SetPen(*wxWHITE_PEN
); 
 305     dc
.DrawLine(rect
.GetLeft() + 1, rect
.GetTop() + 1, 
 306                 rect
.GetRight() - 1, rect
.GetTop() + 1); 
 307     dc
.DrawLine(rect
.GetLeft() + 1, rect
.GetTop() + 1, 
 308                 rect
.GetLeft() + 1, rect
.GetBottom() - 1); 
 313 // ---------------------------------------------------------------------------- 
 315 // ---------------------------------------------------------------------------- 
 317 void wxGridCellAttr::Init(wxGridCellAttr 
*attrDefault
) 
 319     m_isReadOnly 
= Unset
; 
 324     m_attrkind 
= wxGridCellAttr::Cell
; 
 326     m_sizeRows 
= m_sizeCols 
= 1; 
 327     m_overflow 
= UnsetOverflow
; 
 329     SetDefAttr(attrDefault
); 
 332 wxGridCellAttr 
*wxGridCellAttr::Clone() const 
 334     wxGridCellAttr 
*attr 
= new wxGridCellAttr(m_defGridAttr
); 
 336     if ( HasTextColour() ) 
 337         attr
->SetTextColour(GetTextColour()); 
 338     if ( HasBackgroundColour() ) 
 339         attr
->SetBackgroundColour(GetBackgroundColour()); 
 341         attr
->SetFont(GetFont()); 
 342     if ( HasAlignment() ) 
 343         attr
->SetAlignment(m_hAlign
, m_vAlign
); 
 345     attr
->SetSize( m_sizeRows
, m_sizeCols 
); 
 349         attr
->SetRenderer(m_renderer
); 
 350         m_renderer
->IncRef(); 
 354         attr
->SetEditor(m_editor
); 
 361     attr
->SetOverflow( m_overflow 
== Overflow 
); 
 362     attr
->SetKind( m_attrkind 
); 
 367 void wxGridCellAttr::MergeWith(wxGridCellAttr 
*mergefrom
) 
 369     if ( !HasTextColour() && mergefrom
->HasTextColour() ) 
 370         SetTextColour(mergefrom
->GetTextColour()); 
 371     if ( !HasBackgroundColour() && mergefrom
->HasBackgroundColour() ) 
 372         SetBackgroundColour(mergefrom
->GetBackgroundColour()); 
 373     if ( !HasFont() && mergefrom
->HasFont() ) 
 374         SetFont(mergefrom
->GetFont()); 
 375     if ( !HasAlignment() && mergefrom
->HasAlignment() ) 
 378         mergefrom
->GetAlignment( &hAlign
, &vAlign
); 
 379         SetAlignment(hAlign
, vAlign
); 
 381     if ( !HasSize() && mergefrom
->HasSize() ) 
 382         mergefrom
->GetSize( &m_sizeRows
, &m_sizeCols 
); 
 384     // Directly access member functions as GetRender/Editor don't just return 
 385     // m_renderer/m_editor 
 387     // Maybe add support for merge of Render and Editor? 
 388     if (!HasRenderer() && mergefrom
->HasRenderer() ) 
 390         m_renderer 
= mergefrom
->m_renderer
; 
 391         m_renderer
->IncRef(); 
 393     if ( !HasEditor() && mergefrom
->HasEditor() ) 
 395         m_editor 
=  mergefrom
->m_editor
; 
 398     if ( !HasReadWriteMode() && mergefrom
->HasReadWriteMode() ) 
 399         SetReadOnly(mergefrom
->IsReadOnly()); 
 401     if (!HasOverflowMode() && mergefrom
->HasOverflowMode() ) 
 402         SetOverflow(mergefrom
->GetOverflow()); 
 404     SetDefAttr(mergefrom
->m_defGridAttr
); 
 407 void wxGridCellAttr::SetSize(int num_rows
, int num_cols
) 
 409     // The size of a cell is normally 1,1 
 411     // If this cell is larger (2,2) then this is the top left cell 
 412     // the other cells that will be covered (lower right cells) must be 
 413     // set to negative or zero values such that 
 414     // row + num_rows of the covered cell points to the larger cell (this cell) 
 415     // same goes for the col + num_cols. 
 417     // Size of 0,0 is NOT valid, neither is <=0 and any positive value 
 419     wxASSERT_MSG( (!((num_rows 
> 0) && (num_cols 
<= 0)) || 
 420                   !((num_rows 
<= 0) && (num_cols 
> 0)) || 
 421                   !((num_rows 
== 0) && (num_cols 
== 0))), 
 422                   wxT("wxGridCellAttr::SetSize only takes two positive values or negative/zero values")); 
 424     m_sizeRows 
= num_rows
; 
 425     m_sizeCols 
= num_cols
; 
 428 const wxColour
& wxGridCellAttr::GetTextColour() const 
 434     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
 436         return m_defGridAttr
->GetTextColour(); 
 440         wxFAIL_MSG(wxT("Missing default cell attribute")); 
 445 const wxColour
& wxGridCellAttr::GetBackgroundColour() const 
 447     if (HasBackgroundColour()) 
 451     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
 453         return m_defGridAttr
->GetBackgroundColour(); 
 457         wxFAIL_MSG(wxT("Missing default cell attribute")); 
 462 const wxFont
& wxGridCellAttr::GetFont() const 
 468     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
 470         return m_defGridAttr
->GetFont(); 
 474         wxFAIL_MSG(wxT("Missing default cell attribute")); 
 479 void wxGridCellAttr::GetAlignment(int *hAlign
, int *vAlign
) const 
 488     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
 490         m_defGridAttr
->GetAlignment(hAlign
, vAlign
); 
 494         wxFAIL_MSG(wxT("Missing default cell attribute")); 
 498 void wxGridCellAttr::GetNonDefaultAlignment(int *hAlign
, int *vAlign
) const 
 500     if ( hAlign 
&& m_hAlign 
!= wxALIGN_INVALID 
) 
 503     if ( vAlign 
&& m_vAlign 
!= wxALIGN_INVALID 
) 
 507 void wxGridCellAttr::GetSize( int *num_rows
, int *num_cols 
) const 
 510         *num_rows 
= m_sizeRows
; 
 512         *num_cols 
= m_sizeCols
; 
 515 // GetRenderer and GetEditor use a slightly different decision path about 
 516 // which attribute to use.  If a non-default attr object has one then it is 
 517 // used, otherwise the default editor or renderer is fetched from the grid and 
 518 // used.  It should be the default for the data type of the cell.  If it is 
 519 // NULL (because the table has a type that the grid does not have in its 
 520 // registry), then the grid's default editor or renderer is used. 
 522 wxGridCellRenderer
* wxGridCellAttr::GetRenderer(const wxGrid
* grid
, int row
, int col
) const 
 524     wxGridCellRenderer 
*renderer 
= NULL
; 
 526     if ( m_renderer 
&& this != m_defGridAttr 
) 
 528         // use the cells renderer if it has one 
 529         renderer 
= m_renderer
; 
 532     else // no non-default cell renderer 
 534         // get default renderer for the data type 
 537             // GetDefaultRendererForCell() will do IncRef() for us 
 538             renderer 
= grid
->GetDefaultRendererForCell(row
, col
); 
 541         if ( renderer 
== NULL 
) 
 543             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
 545                 // if we still don't have one then use the grid default 
 546                 // (no need for IncRef() here neither) 
 547                 renderer 
= m_defGridAttr
->GetRenderer(NULL
, 0, 0); 
 549             else // default grid attr 
 551                 // use m_renderer which we had decided not to use initially 
 552                 renderer 
= m_renderer
; 
 559     // we're supposed to always find something 
 560     wxASSERT_MSG(renderer
, wxT("Missing default cell renderer")); 
 565 // same as above, except for s/renderer/editor/g 
 566 wxGridCellEditor
* wxGridCellAttr::GetEditor(const wxGrid
* grid
, int row
, int col
) const 
 568     wxGridCellEditor 
*editor 
= NULL
; 
 570     if ( m_editor 
&& this != m_defGridAttr 
) 
 572         // use the cells editor if it has one 
 576     else // no non default cell editor 
 578         // get default editor for the data type 
 581             // GetDefaultEditorForCell() will do IncRef() for us 
 582             editor 
= grid
->GetDefaultEditorForCell(row
, col
); 
 585         if ( editor 
== NULL 
) 
 587             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
 589                 // if we still don't have one then use the grid default 
 590                 // (no need for IncRef() here neither) 
 591                 editor 
= m_defGridAttr
->GetEditor(NULL
, 0, 0); 
 593             else // default grid attr 
 595                 // use m_editor which we had decided not to use initially 
 603     // we're supposed to always find something 
 604     wxASSERT_MSG(editor
, wxT("Missing default cell editor")); 
 609 // ---------------------------------------------------------------------------- 
 610 // wxGridCellAttrData 
 611 // ---------------------------------------------------------------------------- 
 613 void wxGridCellAttrData::SetAttr(wxGridCellAttr 
*attr
, int row
, int col
) 
 615     // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not 
 616     //       touch attribute's reference counting explicitly, since this 
 617     //       is managed by class wxGridCellWithAttr 
 618     int n 
= FindIndex(row
, col
); 
 619     if ( n 
== wxNOT_FOUND 
) 
 624             m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
)); 
 626         //else: nothing to do 
 628     else // we already have an attribute for this cell 
 632             // change the attribute 
 633             m_attrs
[(size_t)n
].ChangeAttr(attr
); 
 637             // remove this attribute 
 638             m_attrs
.RemoveAt((size_t)n
); 
 643 wxGridCellAttr 
*wxGridCellAttrData::GetAttr(int row
, int col
) const 
 645     wxGridCellAttr 
*attr 
= NULL
; 
 647     int n 
= FindIndex(row
, col
); 
 648     if ( n 
!= wxNOT_FOUND 
) 
 650         attr 
= m_attrs
[(size_t)n
].attr
; 
 657 void wxGridCellAttrData::UpdateAttrRows( size_t pos
, int numRows 
) 
 659     size_t count 
= m_attrs
.GetCount(); 
 660     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 662         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
 663         wxCoord row 
= coords
.GetRow(); 
 664         if ((size_t)row 
>= pos
) 
 668                 // If rows inserted, include row counter where necessary 
 669                 coords
.SetRow(row 
+ numRows
); 
 671             else if (numRows 
< 0) 
 673                 // If rows deleted ... 
 674                 if ((size_t)row 
>= pos 
- numRows
) 
 676                     // ...either decrement row counter (if row still exists)... 
 677                     coords
.SetRow(row 
+ numRows
); 
 681                     // ...or remove the attribute 
 691 void wxGridCellAttrData::UpdateAttrCols( size_t pos
, int numCols 
) 
 693     size_t count 
= m_attrs
.GetCount(); 
 694     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 696         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
 697         wxCoord col 
= coords
.GetCol(); 
 698         if ( (size_t)col 
>= pos 
) 
 702                 // If rows inserted, include row counter where necessary 
 703                 coords
.SetCol(col 
+ numCols
); 
 705             else if (numCols 
< 0) 
 707                 // If rows deleted ... 
 708                 if ((size_t)col 
>= pos 
- numCols
) 
 710                     // ...either decrement row counter (if row still exists)... 
 711                     coords
.SetCol(col 
+ numCols
); 
 715                     // ...or remove the attribute 
 725 int wxGridCellAttrData::FindIndex(int row
, int col
) const 
 727     size_t count 
= m_attrs
.GetCount(); 
 728     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 730         const wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
 731         if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) ) 
 740 // ---------------------------------------------------------------------------- 
 741 // wxGridRowOrColAttrData 
 742 // ---------------------------------------------------------------------------- 
 744 wxGridRowOrColAttrData::~wxGridRowOrColAttrData() 
 746     size_t count 
= m_attrs
.GetCount(); 
 747     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 749         m_attrs
[n
]->DecRef(); 
 753 wxGridCellAttr 
*wxGridRowOrColAttrData::GetAttr(int rowOrCol
) const 
 755     wxGridCellAttr 
*attr 
= NULL
; 
 757     int n 
= m_rowsOrCols
.Index(rowOrCol
); 
 758     if ( n 
!= wxNOT_FOUND 
) 
 760         attr 
= m_attrs
[(size_t)n
]; 
 767 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr 
*attr
, int rowOrCol
) 
 769     int i 
= m_rowsOrCols
.Index(rowOrCol
); 
 770     if ( i 
== wxNOT_FOUND 
) 
 774             // store the new attribute, taking its ownership 
 775             m_rowsOrCols
.Add(rowOrCol
); 
 780     else // we have an attribute for this row or column 
 782         size_t n 
= (size_t)i
; 
 784         // notice that this code works correctly even when the old attribute is 
 785         // the same as the new one: as we own of it, we must call DecRef() on 
 786         // it in any case and this won't result in destruction of the new 
 787         // attribute if it's the same as old one because it must have ref count 
 788         // of at least 2 to be passed to us while we keep a reference to it too 
 789         m_attrs
[n
]->DecRef(); 
 793             // replace the attribute with the new one 
 796         else // remove the attribute 
 798             m_rowsOrCols
.RemoveAt(n
); 
 804 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols 
) 
 806     size_t count 
= m_attrs
.GetCount(); 
 807     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 809         int & rowOrCol 
= m_rowsOrCols
[n
]; 
 810         if ( (size_t)rowOrCol 
>= pos 
) 
 812             if ( numRowsOrCols 
> 0 ) 
 814                 // If rows inserted, include row counter where necessary 
 815                 rowOrCol 
+= numRowsOrCols
; 
 817             else if ( numRowsOrCols 
< 0) 
 819                 // If rows deleted, either decrement row counter (if row still exists) 
 820                 if ((size_t)rowOrCol 
>= pos 
- numRowsOrCols
) 
 821                     rowOrCol 
+= numRowsOrCols
; 
 824                     m_rowsOrCols
.RemoveAt(n
); 
 825                     m_attrs
[n
]->DecRef(); 
 835 // ---------------------------------------------------------------------------- 
 836 // wxGridCellAttrProvider 
 837 // ---------------------------------------------------------------------------- 
 839 wxGridCellAttrProvider::wxGridCellAttrProvider() 
 844 wxGridCellAttrProvider::~wxGridCellAttrProvider() 
 849 void wxGridCellAttrProvider::InitData() 
 851     m_data 
= new wxGridCellAttrProviderData
; 
 854 wxGridCellAttr 
*wxGridCellAttrProvider::GetAttr(int row
, int col
, 
 855                                                 wxGridCellAttr::wxAttrKind  kind 
) const 
 857     wxGridCellAttr 
*attr 
= NULL
; 
 862             case (wxGridCellAttr::Any
): 
 863                 // Get cached merge attributes. 
 864                 // Currently not used as no cache implemented as not mutable 
 865                 // attr = m_data->m_mergeAttr.GetAttr(row, col); 
 868                     // Basically implement old version. 
 869                     // Also check merge cache, so we don't have to re-merge every time.. 
 870                     wxGridCellAttr 
*attrcell 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
 871                     wxGridCellAttr 
*attrrow 
= m_data
->m_rowAttrs
.GetAttr(row
); 
 872                     wxGridCellAttr 
*attrcol 
= m_data
->m_colAttrs
.GetAttr(col
); 
 874                     if ((attrcell 
!= attrrow
) && (attrrow 
!= attrcol
) && (attrcell 
!= attrcol
)) 
 876                         // Two or more are non NULL 
 877                         attr 
= new wxGridCellAttr
; 
 878                         attr
->SetKind(wxGridCellAttr::Merged
); 
 880                         // Order is important.. 
 883                             attr
->MergeWith(attrcell
); 
 888                             attr
->MergeWith(attrcol
); 
 893                             attr
->MergeWith(attrrow
); 
 897                         // store merge attr if cache implemented 
 899                         //m_data->m_mergeAttr.SetAttr(attr, row, col); 
 903                         // one or none is non null return it or null. 
 922             case (wxGridCellAttr::Cell
): 
 923                 attr 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
 926             case (wxGridCellAttr::Col
): 
 927                 attr 
= m_data
->m_colAttrs
.GetAttr(col
); 
 930             case (wxGridCellAttr::Row
): 
 931                 attr 
= m_data
->m_rowAttrs
.GetAttr(row
); 
 936                 // (wxGridCellAttr::Default): 
 937                 // (wxGridCellAttr::Merged): 
 945 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr 
*attr
, 
 951     m_data
->m_cellAttrs
.SetAttr(attr
, row
, col
); 
 954 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
 959     m_data
->m_rowAttrs
.SetAttr(attr
, row
); 
 962 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
 967     m_data
->m_colAttrs
.SetAttr(attr
, col
); 
 970 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos
, int numRows 
) 
 974         m_data
->m_cellAttrs
.UpdateAttrRows( pos
, numRows 
); 
 976         m_data
->m_rowAttrs
.UpdateAttrRowsOrCols( pos
, numRows 
); 
 980 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos
, int numCols 
) 
 984         m_data
->m_cellAttrs
.UpdateAttrCols( pos
, numCols 
); 
 986         m_data
->m_colAttrs
.UpdateAttrRowsOrCols( pos
, numCols 
); 
 990 const wxGridColumnHeaderRenderer
& 
 991 wxGridCellAttrProvider::GetColumnHeaderRenderer(int WXUNUSED(col
)) 
 993     return gs_defaultHeaderRenderers
.colRenderer
; 
 996 const wxGridRowHeaderRenderer
& 
 997 wxGridCellAttrProvider::GetRowHeaderRenderer(int WXUNUSED(row
)) 
 999     return gs_defaultHeaderRenderers
.rowRenderer
; 
1002 const wxGridCornerHeaderRenderer
& wxGridCellAttrProvider::GetCornerRenderer() 
1004     return gs_defaultHeaderRenderers
.cornerRenderer
; 
1007 // ---------------------------------------------------------------------------- 
1009 // ---------------------------------------------------------------------------- 
1011 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject 
) 
1013 wxGridTableBase::wxGridTableBase() 
1016     m_attrProvider 
= NULL
; 
1019 wxGridTableBase::~wxGridTableBase() 
1021     delete m_attrProvider
; 
1024 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider 
*attrProvider
) 
1026     delete m_attrProvider
; 
1027     m_attrProvider 
= attrProvider
; 
1030 bool wxGridTableBase::CanHaveAttributes() 
1032     if ( ! GetAttrProvider() ) 
1034         // use the default attr provider by default 
1035         SetAttrProvider(new wxGridCellAttrProvider
); 
1041 wxGridCellAttr 
*wxGridTableBase::GetAttr(int row
, int col
, wxGridCellAttr::wxAttrKind  kind
) 
1043     if ( m_attrProvider 
) 
1044         return m_attrProvider
->GetAttr(row
, col
, kind
); 
1049 void wxGridTableBase::SetAttr(wxGridCellAttr
* attr
, int row
, int col
) 
1051     if ( m_attrProvider 
) 
1054             attr
->SetKind(wxGridCellAttr::Cell
); 
1055         m_attrProvider
->SetAttr(attr
, row
, col
); 
1059         // as we take ownership of the pointer and don't store it, we must 
1065 void wxGridTableBase::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
1067     if ( m_attrProvider 
) 
1069         attr
->SetKind(wxGridCellAttr::Row
); 
1070         m_attrProvider
->SetRowAttr(attr
, row
); 
1074         // as we take ownership of the pointer and don't store it, we must 
1080 void wxGridTableBase::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
1082     if ( m_attrProvider 
) 
1084         attr
->SetKind(wxGridCellAttr::Col
); 
1085         m_attrProvider
->SetColAttr(attr
, col
); 
1089         // as we take ownership of the pointer and don't store it, we must 
1095 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos
), 
1096                                   size_t WXUNUSED(numRows
) ) 
1098     wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") ); 
1103 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows
) ) 
1105     wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function")); 
1110 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos
), 
1111                                   size_t WXUNUSED(numRows
) ) 
1113     wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function")); 
1118 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos
), 
1119                                   size_t WXUNUSED(numCols
) ) 
1121     wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function")); 
1126 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols
) ) 
1128     wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function")); 
1133 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos
), 
1134                                   size_t WXUNUSED(numCols
) ) 
1136     wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function")); 
1141 wxString 
wxGridTableBase::GetRowLabelValue( int row 
) 
1145     // RD: Starting the rows at zero confuses users, 
1146     // no matter how much it makes sense to us geeks. 
1152 wxString 
wxGridTableBase::GetColLabelValue( int col 
) 
1154     // default col labels are: 
1155     //   cols 0 to 25   : A-Z 
1156     //   cols 26 to 675 : AA-ZZ 
1161     for ( n 
= 1; ; n
++ ) 
1163         s 
+= (wxChar
) (wxT('A') + (wxChar
)(col 
% 26)); 
1169     // reverse the string... 
1171     for ( i 
= 0; i 
< n
; i
++ ) 
1179 wxString 
wxGridTableBase::GetTypeName( int WXUNUSED(row
), int WXUNUSED(col
) ) 
1181     return wxGRID_VALUE_STRING
; 
1184 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row
), int WXUNUSED(col
), 
1185                                      const wxString
& typeName 
) 
1187     return typeName 
== wxGRID_VALUE_STRING
; 
1190 bool wxGridTableBase::CanSetValueAs( int row
, int col
, const wxString
& typeName 
) 
1192     return CanGetValueAs(row
, col
, typeName
); 
1195 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
) ) 
1200 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
) ) 
1205 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
) ) 
1210 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
), 
1211                                       long WXUNUSED(value
) ) 
1215 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
), 
1216                                         double WXUNUSED(value
) ) 
1220 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
), 
1221                                       bool WXUNUSED(value
) ) 
1225 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
1226                                          const wxString
& WXUNUSED(typeName
) ) 
1231 void  wxGridTableBase::SetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
1232                                          const wxString
& WXUNUSED(typeName
), 
1233                                          void* WXUNUSED(value
) ) 
1237 ////////////////////////////////////////////////////////////////////// 
1239 // Message class for the grid table to send requests and notifications 
1243 wxGridTableMessage::wxGridTableMessage() 
1251 wxGridTableMessage::wxGridTableMessage( wxGridTableBase 
*table
, int id
, 
1252                                         int commandInt1
, int commandInt2 
) 
1256     m_comInt1 
= commandInt1
; 
1257     m_comInt2 
= commandInt2
; 
1260 ////////////////////////////////////////////////////////////////////// 
1262 // A basic grid table for string data. An object of this class will 
1263 // created by wxGrid if you don't specify an alternative table class. 
1266 WX_DEFINE_OBJARRAY(wxGridStringArray
) 
1268 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase 
) 
1270 wxGridStringTable::wxGridStringTable() 
1276 wxGridStringTable::wxGridStringTable( int numRows
, int numCols 
) 
1279     m_numCols 
= numCols
; 
1281     m_data
.Alloc( numRows 
); 
1284     sa
.Alloc( numCols 
); 
1285     sa
.Add( wxEmptyString
, numCols 
); 
1287     m_data
.Add( sa
, numRows 
); 
1290 wxString 
wxGridStringTable::GetValue( int row
, int col 
) 
1292     wxCHECK_MSG( (row 
>= 0 && row 
< GetNumberRows()) && 
1293                  (col 
>= 0 && col 
< GetNumberCols()), 
1295                  wxT("invalid row or column index in wxGridStringTable") ); 
1297     return m_data
[row
][col
]; 
1300 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& value 
) 
1302     wxCHECK_RET( (row 
>= 0 && row 
< GetNumberRows()) && 
1303                  (col 
>= 0 && col 
< GetNumberCols()), 
1304                  wxT("invalid row or column index in wxGridStringTable") ); 
1306     m_data
[row
][col
] = value
; 
1309 void wxGridStringTable::Clear() 
1312     int numRows
, numCols
; 
1314     numRows 
= m_data
.GetCount(); 
1317         numCols 
= m_data
[0].GetCount(); 
1319         for ( row 
= 0; row 
< numRows
; row
++ ) 
1321             for ( col 
= 0; col 
< numCols
; col
++ ) 
1323                 m_data
[row
][col
] = wxEmptyString
; 
1329 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows 
) 
1331     size_t curNumRows 
= m_data
.GetCount(); 
1332     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
1333                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
1335     if ( pos 
>= curNumRows 
) 
1337         return AppendRows( numRows 
); 
1341     sa
.Alloc( curNumCols 
); 
1342     sa
.Add( wxEmptyString
, curNumCols 
); 
1343     m_data
.Insert( sa
, pos
, numRows 
); 
1347         wxGridTableMessage 
msg( this, 
1348                                 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
, 
1352         GetView()->ProcessTableMessage( msg 
); 
1358 bool wxGridStringTable::AppendRows( size_t numRows 
) 
1360     size_t curNumRows 
= m_data
.GetCount(); 
1361     size_t curNumCols 
= ( curNumRows 
> 0 
1362                          ? m_data
[0].GetCount() 
1363                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
1366     if ( curNumCols 
> 0 ) 
1368         sa
.Alloc( curNumCols 
); 
1369         sa
.Add( wxEmptyString
, curNumCols 
); 
1372     m_data
.Add( sa
, numRows 
); 
1376         wxGridTableMessage 
msg( this, 
1377                                 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, 
1380         GetView()->ProcessTableMessage( msg 
); 
1386 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows 
) 
1388     size_t curNumRows 
= m_data
.GetCount(); 
1390     if ( pos 
>= curNumRows 
) 
1392         wxFAIL_MSG( wxString::Format
 
1394                         wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"), 
1396                         (unsigned long)numRows
, 
1397                         (unsigned long)curNumRows
 
1403     if ( numRows 
> curNumRows 
- pos 
) 
1405         numRows 
= curNumRows 
- pos
; 
1408     if ( numRows 
>= curNumRows 
) 
1414         m_data
.RemoveAt( pos
, numRows 
); 
1419         wxGridTableMessage 
msg( this, 
1420                                 wxGRIDTABLE_NOTIFY_ROWS_DELETED
, 
1424         GetView()->ProcessTableMessage( msg 
); 
1430 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols 
) 
1434     size_t curNumRows 
= m_data
.GetCount(); 
1435     size_t curNumCols 
= ( curNumRows 
> 0 
1436                          ? m_data
[0].GetCount() 
1437                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
1439     if ( pos 
>= curNumCols 
) 
1441         return AppendCols( numCols 
); 
1444     if ( !m_colLabels
.IsEmpty() ) 
1446         m_colLabels
.Insert( wxEmptyString
, pos
, numCols 
); 
1449         for ( i 
= pos
; i 
< pos 
+ numCols
; i
++ ) 
1450             m_colLabels
[i
] = wxGridTableBase::GetColLabelValue( i 
); 
1453     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
1455         for ( col 
= pos
; col 
< pos 
+ numCols
; col
++ ) 
1457             m_data
[row
].Insert( wxEmptyString
, col 
); 
1461     m_numCols 
+= numCols
; 
1465         wxGridTableMessage 
msg( this, 
1466                                 wxGRIDTABLE_NOTIFY_COLS_INSERTED
, 
1470         GetView()->ProcessTableMessage( msg 
); 
1476 bool wxGridStringTable::AppendCols( size_t numCols 
) 
1480     size_t curNumRows 
= m_data
.GetCount(); 
1482     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
1484         m_data
[row
].Add( wxEmptyString
, numCols 
); 
1487     m_numCols 
+= numCols
; 
1491         wxGridTableMessage 
msg( this, 
1492                                 wxGRIDTABLE_NOTIFY_COLS_APPENDED
, 
1495         GetView()->ProcessTableMessage( msg 
); 
1501 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols 
) 
1505     size_t curNumRows 
= m_data
.GetCount(); 
1506     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
1507                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
1509     if ( pos 
>= curNumCols 
) 
1511         wxFAIL_MSG( wxString::Format
 
1513                         wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"), 
1515                         (unsigned long)numCols
, 
1516                         (unsigned long)curNumCols
 
1523         colID 
= GetView()->GetColAt( pos 
); 
1527     if ( numCols 
> curNumCols 
- colID 
) 
1529         numCols 
= curNumCols 
- colID
; 
1532     if ( !m_colLabels
.IsEmpty() ) 
1534         // m_colLabels stores just as many elements as it needs, e.g. if only 
1535         // the label of the first column had been set it would have only one 
1536         // element and not numCols, so account for it 
1537         int numRemaining 
= m_colLabels
.size() - colID
; 
1538         if (numRemaining 
> 0) 
1539             m_colLabels
.RemoveAt( colID
, wxMin(numCols
, numRemaining
) ); 
1542     if ( numCols 
>= curNumCols 
) 
1544         for ( row 
= 0; row 
< curNumRows
; row
++ ) 
1546             m_data
[row
].Clear(); 
1551     else // something will be left 
1553         for ( row 
= 0; row 
< curNumRows
; row
++ ) 
1555             m_data
[row
].RemoveAt( colID
, numCols 
); 
1558         m_numCols 
-= numCols
; 
1563         wxGridTableMessage 
msg( this, 
1564                                 wxGRIDTABLE_NOTIFY_COLS_DELETED
, 
1568         GetView()->ProcessTableMessage( msg 
); 
1574 wxString 
wxGridStringTable::GetRowLabelValue( int row 
) 
1576     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
1578         // using default label 
1580         return wxGridTableBase::GetRowLabelValue( row 
); 
1584         return m_rowLabels
[row
]; 
1588 wxString 
wxGridStringTable::GetColLabelValue( int col 
) 
1590     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
1592         // using default label 
1594         return wxGridTableBase::GetColLabelValue( col 
); 
1598         return m_colLabels
[col
]; 
1602 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value 
) 
1604     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
1606         int n 
= m_rowLabels
.GetCount(); 
1609         for ( i 
= n
; i 
<= row
; i
++ ) 
1611             m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) ); 
1615     m_rowLabels
[row
] = value
; 
1618 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value 
) 
1620     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
1622         int n 
= m_colLabels
.GetCount(); 
1625         for ( i 
= n
; i 
<= col
; i
++ ) 
1627             m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) ); 
1631     m_colLabels
[col
] = value
; 
1635 ////////////////////////////////////////////////////////////////////// 
1636 ////////////////////////////////////////////////////////////////////// 
1638 BEGIN_EVENT_TABLE(wxGridSubwindow
, wxWindow
) 
1639     EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost
) 
1642 void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
1644     m_owner
->CancelMouseCapture(); 
1647 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxGridSubwindow 
) 
1648     EVT_PAINT( wxGridRowLabelWindow::OnPaint 
) 
1649     EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel 
) 
1650     EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent 
) 
1653 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1657     // NO - don't do this because it will set both the x and y origin 
1658     // coords to match the parent scrolled window and we just want to 
1659     // set the y coord  - MB 
1661     // m_owner->PrepareDC( dc ); 
1664     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
1665     wxPoint pt 
= dc
.GetDeviceOrigin(); 
1666     dc
.SetDeviceOrigin( pt
.x
, pt
.y
-y 
); 
1668     wxArrayInt rows 
= m_owner
->CalcRowLabelsExposed( GetUpdateRegion() ); 
1669     m_owner
->DrawRowLabels( dc
, rows 
); 
1672 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
1674     m_owner
->ProcessRowLabelMouseEvent( event 
); 
1677 void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
1679     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
1683 ////////////////////////////////////////////////////////////////////// 
1685 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxGridSubwindow 
) 
1686     EVT_PAINT( wxGridColLabelWindow::OnPaint 
) 
1687     EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel 
) 
1688     EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent 
) 
1691 void wxGridColLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1695     // NO - don't do this because it will set both the x and y origin 
1696     // coords to match the parent scrolled window and we just want to 
1697     // set the x coord  - MB 
1699     // m_owner->PrepareDC( dc ); 
1702     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
1703     wxPoint pt 
= dc
.GetDeviceOrigin(); 
1704     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
1705         dc
.SetDeviceOrigin( pt
.x
+x
, pt
.y 
); 
1707         dc
.SetDeviceOrigin( pt
.x
-x
, pt
.y 
); 
1709     wxArrayInt cols 
= m_owner
->CalcColLabelsExposed( GetUpdateRegion() ); 
1710     m_owner
->DrawColLabels( dc
, cols 
); 
1713 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
1715     m_owner
->ProcessColLabelMouseEvent( event 
); 
1718 void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
1720     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
1724 ////////////////////////////////////////////////////////////////////// 
1726 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxGridSubwindow 
) 
1727     EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel 
) 
1728     EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent 
) 
1729     EVT_PAINT( wxGridCornerLabelWindow::OnPaint 
) 
1732 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1736     m_owner
->DrawCornerLabel(dc
); 
1739 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
1741     m_owner
->ProcessCornerLabelMouseEvent( event 
); 
1744 void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
1746     if (!m_owner
->GetEventHandler()->ProcessEvent(event
)) 
1750 ////////////////////////////////////////////////////////////////////// 
1752 BEGIN_EVENT_TABLE( wxGridWindow
, wxGridSubwindow 
) 
1753     EVT_PAINT( wxGridWindow::OnPaint 
) 
1754     EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel 
) 
1755     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent 
) 
1756     EVT_KEY_DOWN( wxGridWindow::OnKeyDown 
) 
1757     EVT_KEY_UP( wxGridWindow::OnKeyUp 
) 
1758     EVT_CHAR( wxGridWindow::OnChar 
) 
1759     EVT_SET_FOCUS( wxGridWindow::OnFocus 
) 
1760     EVT_KILL_FOCUS( wxGridWindow::OnFocus 
) 
1761     EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground 
) 
1764 void wxGridWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
1766     wxPaintDC 
dc( this ); 
1767     m_owner
->PrepareDC( dc 
); 
1768     wxRegion reg 
= GetUpdateRegion(); 
1769     wxGridCellCoordsArray dirtyCells 
= m_owner
->CalcCellsExposed( reg 
); 
1770     m_owner
->DrawGridCellArea( dc
, dirtyCells 
); 
1772     m_owner
->DrawGridSpace( dc 
); 
1774     m_owner
->DrawAllGridLines( dc
, reg 
); 
1776     m_owner
->DrawHighlight( dc
, dirtyCells 
); 
1779 void wxGrid::Render( wxDC
& dc
, 
1780                      const wxPoint
& position
, 
1782                      const wxGridCellCoords
& topLeft
, 
1783                      const wxGridCellCoords
& bottomRight
, 
1786     wxCHECK_RET( bottomRight
.GetCol() < GetNumberCols(), 
1787                  "Invalid right column" ); 
1788     wxCHECK_RET( bottomRight
.GetRow() < GetNumberRows(), 
1789                  "Invalid bottom row" ); 
1791     // store user settings and reset later 
1793     // remove grid selection, don't paint selection colour 
1794     // unless we have wxGRID_DRAW_SELECTION 
1795     // block selections are the only ones catered for here 
1796     wxGridCellCoordsArray selectedCells
; 
1797     bool hasSelection 
= IsSelection(); 
1798     if ( hasSelection 
&& !( style 
& wxGRID_DRAW_SELECTION 
) ) 
1800         selectedCells 
= GetSelectionBlockTopLeft(); 
1801         // non block selections may not have a bottom right 
1802         if ( GetSelectionBlockBottomRight().size() ) 
1803             selectedCells
.Add( GetSelectionBlockBottomRight()[ 0 ] ); 
1808     // store user device origin 
1809     wxCoord userOriginX
, userOriginY
; 
1810     dc
.GetDeviceOrigin( &userOriginX
, &userOriginY 
); 
1813     double scaleUserX
, scaleUserY
; 
1814     dc
.GetUserScale( &scaleUserX
, &scaleUserY 
); 
1816     // set defaults if necessary 
1817     wxGridCellCoords 
leftTop( topLeft 
), rightBottom( bottomRight 
); 
1818     if ( leftTop
.GetCol() < 0 ) 
1820     if ( leftTop
.GetRow() < 0 ) 
1822     if ( rightBottom
.GetCol() < 0 ) 
1823         rightBottom
.SetCol(GetNumberCols() - 1); 
1824     if ( rightBottom
.GetRow() < 0 ) 
1825         rightBottom
.SetRow(GetNumberRows() - 1); 
1827     // get grid offset, size and cell parameters 
1828     wxPoint pointOffSet
; 
1830     wxGridCellCoordsArray renderCells
; 
1831     wxArrayInt arrayCols
; 
1832     wxArrayInt arrayRows
; 
1834     GetRenderSizes( leftTop
, rightBottom
, 
1835                     pointOffSet
, sizeGrid
, 
1837                     arrayCols
, arrayRows 
); 
1839     // add headers/labels to dimensions 
1840     if ( style 
& wxGRID_DRAW_ROWS_HEADER 
) 
1841         sizeGrid
.x 
+= GetRowLabelSize(); 
1842     if ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
1843         sizeGrid
.y 
+= GetColLabelSize(); 
1845     // get render start position in logical units 
1846     wxPoint positionRender 
= GetRenderPosition( dc
, position 
); 
1848     wxCoord originX 
= dc
.LogicalToDeviceX( positionRender
.x 
); 
1849     wxCoord originY 
= dc
.LogicalToDeviceY( positionRender
.y 
); 
1851     dc
.SetDeviceOrigin( originX
, originY 
); 
1853     SetRenderScale( dc
, positionRender
, size
, sizeGrid 
); 
1855     // draw row headers at specified origin 
1856     if ( GetRowLabelSize() > 0 && ( style 
& wxGRID_DRAW_ROWS_HEADER 
) ) 
1858         if ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
1860             DrawCornerLabel( dc 
); // do only if both col and row labels drawn 
1861             originY 
+= dc
.LogicalToDeviceYRel( GetColLabelSize() ); 
1864         originY 
-= dc
.LogicalToDeviceYRel( pointOffSet
.y 
); 
1865         dc
.SetDeviceOrigin( originX
, originY 
); 
1867         DrawRowLabels( dc
, arrayRows 
); 
1869         // reset for columns 
1870         if ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
1871             originY 
-= dc
.LogicalToDeviceYRel( GetColLabelSize() ); 
1873         originY 
+= dc
.LogicalToDeviceYRel( pointOffSet
.y 
); 
1874         // X offset so we don't overwrite row labels 
1875         originX 
+= dc
.LogicalToDeviceXRel( GetRowLabelSize() ); 
1878     // subtract col offset where startcol > 0 
1879     originX 
-= dc
.LogicalToDeviceXRel( pointOffSet
.x 
); 
1880     // no y offset for col labels, they are at the Y origin 
1882     // draw column labels 
1883     if ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
1885         dc
.SetDeviceOrigin( originX
, originY 
); 
1886         DrawColLabels( dc
, arrayCols 
); 
1887         // don't overwrite the labels, increment originY 
1888         originY 
+= dc
.LogicalToDeviceYRel( GetColLabelSize() ); 
1891     // set device origin to draw grid cells and lines 
1892     originY 
-= dc
.LogicalToDeviceYRel( pointOffSet
.y 
); 
1893     dc
.SetDeviceOrigin( originX
, originY 
); 
1895     // draw cell area background 
1896     dc
.SetBrush( GetDefaultCellBackgroundColour() ); 
1897     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1898     // subtract headers from grid area dimensions 
1899     wxSize 
sizeCells( sizeGrid 
); 
1900     if ( style 
& wxGRID_DRAW_ROWS_HEADER 
) 
1901         sizeCells
.x 
-= GetRowLabelSize(); 
1902     if ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
1903         sizeCells
.y 
-= GetColLabelSize(); 
1905     dc
.DrawRectangle( pointOffSet
, sizeCells 
); 
1908     DrawGridCellArea( dc
, renderCells 
); 
1911     if ( style 
& wxGRID_DRAW_CELL_LINES 
) 
1913         wxRegion 
regionClip( pointOffSet
.x
, pointOffSet
.y
, 
1914                              sizeCells
.x
, sizeCells
.y 
); 
1916         DrawRangeGridLines(dc
, regionClip
, renderCells
[0], renderCells
.Last()); 
1919     // draw render rectangle bounding lines 
1920     DoRenderBox( dc
, style
, 
1921                  pointOffSet
, sizeCells
, 
1922                  leftTop
, rightBottom 
); 
1924     // restore user setings 
1925     dc
.SetDeviceOrigin( userOriginX
, userOriginY 
); 
1926     dc
.SetUserScale( scaleUserX
, scaleUserY 
); 
1928     if ( selectedCells
.size() && !( style 
& wxGRID_DRAW_SELECTION 
) ) 
1930         SelectBlock( selectedCells
[ 0 ].GetRow(), 
1931                      selectedCells
[ 0 ].GetCol(), 
1932                      selectedCells
[ selectedCells
.size() -1 ].GetRow(), 
1933                      selectedCells
[ selectedCells
.size() -1 ].GetCol() ); 
1938 wxGrid::SetRenderScale(wxDC
& dc
, 
1939                        const wxPoint
& pos
, const wxSize
& size
, 
1940                        const wxSize
& sizeGrid 
) 
1942     double scaleX
, scaleY
; 
1945     if ( size
.GetWidth() != wxDefaultSize
.GetWidth() ) // size.x was specified 
1946         sizeTemp
.SetWidth( size
.GetWidth() ); 
1948         sizeTemp
.SetWidth( dc
.DeviceToLogicalXRel( dc
.GetSize().GetWidth() ) 
1951     if ( size
.GetHeight() != wxDefaultSize
.GetHeight() ) // size.y was specified 
1952         sizeTemp
.SetHeight( size
.GetHeight() ); 
1954         sizeTemp
.SetHeight( dc
.DeviceToLogicalYRel( dc
.GetSize().GetHeight() ) 
1957     scaleX 
= (double)( (double) sizeTemp
.GetWidth() / (double) sizeGrid
.GetWidth() ); 
1958     scaleY 
= (double)( (double) sizeTemp
.GetHeight() / (double) sizeGrid
.GetHeight() ); 
1960     dc
.SetUserScale( wxMin( scaleX
, scaleY
), wxMin( scaleX
, scaleY 
) ); 
1963 // get grid rendered size, origin offset and fill cell arrays 
1964 void wxGrid::GetRenderSizes( const wxGridCellCoords
& topLeft
, 
1965                              const wxGridCellCoords
& bottomRight
, 
1966                              wxPoint
& pointOffSet
, wxSize
& sizeGrid
, 
1967                              wxGridCellCoordsArray
& renderCells
, 
1968                              wxArrayInt
& arrayCols
, wxArrayInt
& arrayRows 
) 
1972     sizeGrid
.SetWidth( 0 ); 
1973     sizeGrid
.SetHeight( 0 ); 
1977     wxGridSizesInfo sizeinfo 
= GetColSizes(); 
1978     for ( col 
= 0; col 
<= bottomRight
.GetCol(); col
++ ) 
1980         if ( col 
< topLeft
.GetCol() ) 
1982             pointOffSet
.x 
+= sizeinfo
.GetSize( col 
); 
1986             for ( row 
= topLeft
.GetRow(); row 
<= bottomRight
.GetRow(); row
++ ) 
1988                 renderCells
.Add( wxGridCellCoords( row
, col 
)); 
1989                 arrayRows
.Add( row 
); // column labels rendered in DrawColLabels 
1991             arrayCols
.Add( col 
); // row labels rendered in DrawRowLabels 
1992             sizeGrid
.x 
+= sizeinfo
.GetSize( col 
); 
1996     sizeinfo 
= GetRowSizes(); 
1997     for ( row 
= 0; row 
<= bottomRight
.GetRow(); row
++ ) 
1999         if ( row 
< topLeft
.GetRow() ) 
2000             pointOffSet
.y 
+= sizeinfo
.GetSize( row 
); 
2002             sizeGrid
.y 
+= sizeinfo
.GetSize( row 
); 
2006 // get render start position 
2007 // if position not specified use dc draw extents MaxX and MaxY 
2008 wxPoint 
wxGrid::GetRenderPosition( wxDC
& dc
, const wxPoint
& position 
) 
2010     wxPoint 
positionRender( position 
); 
2012     if ( !positionRender
.IsFullySpecified() ) 
2014         if ( positionRender
.x 
== wxDefaultPosition
.x 
) 
2015             positionRender
.x 
= dc
.MaxX(); 
2017         if ( positionRender
.y 
== wxDefaultPosition
.y 
) 
2018             positionRender
.y 
= dc
.MaxY(); 
2021     return positionRender
; 
2024 // draw render rectangle bounding lines 
2025 // useful where there is multi cell row or col clipping and no cell border 
2026 void wxGrid::DoRenderBox( wxDC
& dc
, const int& style
, 
2027                           const wxPoint
& pointOffSet
, 
2028                           const wxSize
& sizeCells
, 
2029                           const wxGridCellCoords
& topLeft
, 
2030                           const wxGridCellCoords
& bottomRight 
) 
2032     if ( !( style 
& wxGRID_DRAW_BOX_RECT 
) ) 
2035     int bottom 
= pointOffSet
.y 
+ sizeCells
.GetY(), 
2036         right 
= pointOffSet
.x 
+ sizeCells
.GetX() - 1; 
2038     // horiz top line if we are not drawing column header/labels 
2039     if ( !( style 
& wxGRID_DRAW_COLS_HEADER 
) ) 
2041         int left 
= pointOffSet
.x
; 
2042         left 
+= ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
2043                      ? - GetRowLabelSize() : 0; 
2044         dc
.SetPen( GetRowGridLinePen( topLeft
.GetRow() ) ); 
2051     // horiz bottom line 
2052     dc
.SetPen( GetRowGridLinePen( bottomRight
.GetRow() ) ); 
2053     dc
.DrawLine( pointOffSet
.x
, bottom 
- 1, right
, bottom 
- 1 ); 
2055     // left vertical line if we are not drawing row header/labels 
2056     if ( !( style 
& wxGRID_DRAW_ROWS_HEADER 
) ) 
2058         int top 
= pointOffSet
.y
; 
2059         top 
+= ( style 
& wxGRID_DRAW_COLS_HEADER 
) 
2060                      ? - GetColLabelSize() : 0; 
2061         dc
.SetPen( GetColGridLinePen( topLeft
.GetCol() ) ); 
2062         dc
.DrawLine( pointOffSet
.x 
-1, 
2068     // right vertical line 
2069     dc
.SetPen( GetColGridLinePen( bottomRight
.GetCol() ) ); 
2070     dc
.DrawLine( right
, pointOffSet
.y
, right
, bottom 
- 1 ); 
2073 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
2075     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
2076     m_owner
->GetGridRowLabelWindow()->ScrollWindow( 0, dy
, rect 
); 
2077     m_owner
->GetGridColLabelWindow()->ScrollWindow( dx
, 0, rect 
); 
2080 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event 
) 
2082     if (event
.ButtonDown(wxMOUSE_BTN_LEFT
) && FindFocus() != this) 
2085     m_owner
->ProcessGridCellMouseEvent( event 
); 
2088 void wxGridWindow::OnMouseWheel( wxMouseEvent
& event 
) 
2090     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
2094 // This seems to be required for wxMotif/wxGTK otherwise the mouse 
2095 // cursor must be in the cell edit control to get key events 
2097 void wxGridWindow::OnKeyDown( wxKeyEvent
& event 
) 
2099     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
2103 void wxGridWindow::OnKeyUp( wxKeyEvent
& event 
) 
2105     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
2109 void wxGridWindow::OnChar( wxKeyEvent
& event 
) 
2111     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
2115 void wxGridWindow::OnEraseBackground( wxEraseEvent
& WXUNUSED(event
) ) 
2119 void wxGridWindow::OnFocus(wxFocusEvent
& event
) 
2121     // and if we have any selection, it has to be repainted, because it 
2122     // uses different colour when the grid is not focused: 
2123     if ( m_owner
->IsSelection() ) 
2129         // NB: Note that this code is in "else" branch only because the other 
2130         //     branch refreshes everything and so there's no point in calling 
2131         //     Refresh() again, *not* because it should only be done if 
2132         //     !IsSelection(). If the above code is ever optimized to refresh 
2133         //     only selected area, this needs to be moved out of the "else" 
2134         //     branch so that it's always executed. 
2136         // current cell cursor {dis,re}appears on focus change: 
2137         const wxGridCellCoords 
cursorCoords(m_owner
->GetGridCursorRow(), 
2138                                             m_owner
->GetGridCursorCol()); 
2139         const wxRect cursor 
= 
2140             m_owner
->BlockToDeviceRect(cursorCoords
, cursorCoords
); 
2141         Refresh(true, &cursor
); 
2144     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
2148 #define internalXToCol(x) XToCol(x, true) 
2149 #define internalYToRow(y) YToRow(y, true) 
2151 ///////////////////////////////////////////////////////////////////// 
2153 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow 
) 
2154     EVT_PAINT( wxGrid::OnPaint 
) 
2155     EVT_SIZE( wxGrid::OnSize 
) 
2156     EVT_KEY_DOWN( wxGrid::OnKeyDown 
) 
2157     EVT_KEY_UP( wxGrid::OnKeyUp 
) 
2158     EVT_CHAR ( wxGrid::OnChar 
) 
2159     EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground 
) 
2162 bool wxGrid::Create(wxWindow 
*parent
, wxWindowID id
, 
2163                           const wxPoint
& pos
, const wxSize
& size
, 
2164                           long style
, const wxString
& name
) 
2166     if (!wxScrolledWindow::Create(parent
, id
, pos
, size
, 
2167                                   style 
| wxWANTS_CHARS
, name
)) 
2170     m_colMinWidths 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
2171     m_rowMinHeights 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
2174     SetInitialSize(size
); 
2183         m_winCapture
->ReleaseMouse(); 
2185     // Ensure that the editor control is destroyed before the grid is, 
2186     // otherwise we crash later when the editor tries to do something with the 
2187     // half destroyed grid 
2188     HideCellEditControl(); 
2190     // Must do this or ~wxScrollHelper will pop the wrong event handler 
2191     SetTargetWindow(this); 
2193     wxSafeDecRef(m_defaultCellAttr
); 
2195 #ifdef DEBUG_ATTR_CACHE 
2196     size_t total 
= gs_nAttrCacheHits 
+ gs_nAttrCacheMisses
; 
2197     wxPrintf(wxT("wxGrid attribute cache statistics: " 
2198                 "total: %u, hits: %u (%u%%)\n"), 
2199              total
, gs_nAttrCacheHits
, 
2200              total 
? (gs_nAttrCacheHits
*100) / total 
: 0); 
2203     // if we own the table, just delete it, otherwise at least don't leave it 
2204     // with dangling view pointer 
2207     else if ( m_table 
&& m_table
->GetView() == this ) 
2208         m_table
->SetView(NULL
); 
2210     delete m_typeRegistry
; 
2213     delete m_setFixedRows
; 
2214     delete m_setFixedCols
; 
2218 // ----- internal init and update functions 
2221 // NOTE: If using the default visual attributes works everywhere then this can 
2222 // be removed as well as the #else cases below. 
2223 #define _USE_VISATTR 0 
2225 void wxGrid::Create() 
2227     // create the type registry 
2228     m_typeRegistry 
= new wxGridTypeRegistry
; 
2230     m_cellEditCtrlEnabled 
= false; 
2232     m_defaultCellAttr 
= new wxGridCellAttr(); 
2234     // Set default cell attributes 
2235     m_defaultCellAttr
->SetDefAttr(m_defaultCellAttr
); 
2236     m_defaultCellAttr
->SetKind(wxGridCellAttr::Default
); 
2237     m_defaultCellAttr
->SetFont(GetFont()); 
2238     m_defaultCellAttr
->SetAlignment(wxALIGN_LEFT
, wxALIGN_TOP
); 
2239     m_defaultCellAttr
->SetRenderer(new wxGridCellStringRenderer
); 
2240     m_defaultCellAttr
->SetEditor(new wxGridCellTextEditor
); 
2243     wxVisualAttributes gva 
= wxListBox::GetClassDefaultAttributes(); 
2244     wxVisualAttributes lva 
= wxPanel::GetClassDefaultAttributes(); 
2246     m_defaultCellAttr
->SetTextColour(gva
.colFg
); 
2247     m_defaultCellAttr
->SetBackgroundColour(gva
.colBg
); 
2250     m_defaultCellAttr
->SetTextColour( 
2251         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
2252     m_defaultCellAttr
->SetBackgroundColour( 
2253         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
2258     m_currentCellCoords 
= wxGridNoCellCoords
; 
2260     // subwindow components that make up the wxGrid 
2261     m_rowLabelWin 
= new wxGridRowLabelWindow(this); 
2262     CreateColumnWindow(); 
2263     m_cornerLabelWin 
= new wxGridCornerLabelWindow(this); 
2264     m_gridWin 
= new wxGridWindow( this ); 
2266     SetTargetWindow( m_gridWin 
); 
2269     wxColour gfg 
= gva
.colFg
; 
2270     wxColour gbg 
= gva
.colBg
; 
2271     wxColour lfg 
= lva
.colFg
; 
2272     wxColour lbg 
= lva
.colBg
; 
2274     wxColour gfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
2275     wxColour gbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
2276     wxColour lfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
2277     wxColour lbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
2280     m_cornerLabelWin
->SetOwnForegroundColour(lfg
); 
2281     m_cornerLabelWin
->SetOwnBackgroundColour(lbg
); 
2282     m_rowLabelWin
->SetOwnForegroundColour(lfg
); 
2283     m_rowLabelWin
->SetOwnBackgroundColour(lbg
); 
2284     m_colWindow
->SetOwnForegroundColour(lfg
); 
2285     m_colWindow
->SetOwnBackgroundColour(lbg
); 
2287     m_gridWin
->SetOwnForegroundColour(gfg
); 
2288     m_gridWin
->SetOwnBackgroundColour(gbg
); 
2290     m_labelBackgroundColour 
= m_rowLabelWin
->GetBackgroundColour(); 
2291     m_labelTextColour 
= m_rowLabelWin
->GetForegroundColour(); 
2293     // now that we have the grid window, use its font to compute the default 
2295     m_defaultRowHeight 
= m_gridWin
->GetCharHeight(); 
2296 #if defined(__WXMOTIF__) || defined(__WXGTK__)  // see also text ctrl sizing in ShowCellEditControl() 
2297     m_defaultRowHeight 
+= 8; 
2299     m_defaultRowHeight 
+= 4; 
2304 void wxGrid::CreateColumnWindow() 
2306     if ( m_useNativeHeader 
) 
2308         m_colWindow 
= new wxGridHeaderCtrl(this); 
2309         m_colLabelHeight 
= m_colWindow
->GetBestSize().y
; 
2311     else // draw labels ourselves 
2313         m_colWindow 
= new wxGridColLabelWindow(this); 
2314         m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
2318 bool wxGrid::CreateGrid( int numRows
, int numCols
, 
2319                          wxGridSelectionModes selmode 
) 
2321     wxCHECK_MSG( !m_created
, 
2323                  wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); 
2325     return SetTable(new wxGridStringTable(numRows
, numCols
), true, selmode
); 
2328 void wxGrid::SetSelectionMode(wxGridSelectionModes selmode
) 
2330     wxCHECK_RET( m_created
, 
2331                  wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); 
2333     m_selection
->SetSelectionMode( selmode 
); 
2336 wxGrid::wxGridSelectionModes 
wxGrid::GetSelectionMode() const 
2338     wxCHECK_MSG( m_created
, wxGridSelectCells
, 
2339                  wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") ); 
2341     return m_selection
->GetSelectionMode(); 
2345 wxGrid::SetTable(wxGridTableBase 
*table
, 
2347                  wxGrid::wxGridSelectionModes selmode 
) 
2349     bool checkSelection 
= false; 
2352         // stop all processing 
2357             m_table
->SetView(0); 
2363         wxDELETE(m_selection
); 
2368         checkSelection 
= true; 
2370         // kill row and column size arrays 
2371         m_colWidths
.Empty(); 
2372         m_colRights
.Empty(); 
2373         m_rowHeights
.Empty(); 
2374         m_rowBottoms
.Empty(); 
2379         m_numRows 
= table
->GetNumberRows(); 
2380         m_numCols 
= table
->GetNumberCols(); 
2382         if ( m_useNativeHeader 
) 
2383             GetGridColHeader()->SetColumnCount(m_numCols
); 
2386         m_table
->SetView( this ); 
2387         m_ownTable 
= takeOwnership
; 
2388         m_selection 
= new wxGridSelection( this, selmode 
); 
2391             // If the newly set table is smaller than the 
2392             // original one current cell and selection regions 
2393             // might be invalid, 
2394             m_selectedBlockCorner 
= wxGridNoCellCoords
; 
2395             m_currentCellCoords 
= 
2396               wxGridCellCoords(wxMin(m_numRows
, m_currentCellCoords
.GetRow()), 
2397                                wxMin(m_numCols
, m_currentCellCoords
.GetCol())); 
2398             if (m_selectedBlockTopLeft
.GetRow() >= m_numRows 
|| 
2399                 m_selectedBlockTopLeft
.GetCol() >= m_numCols
) 
2401                 m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
2402                 m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
2405                 m_selectedBlockBottomRight 
= 
2406                   wxGridCellCoords(wxMin(m_numRows
, 
2407                                          m_selectedBlockBottomRight
.GetRow()), 
2409                                          m_selectedBlockBottomRight
.GetCol())); 
2423     m_cornerLabelWin 
= NULL
; 
2424     m_rowLabelWin 
= NULL
; 
2432     m_defaultCellAttr 
= NULL
; 
2433     m_typeRegistry 
= NULL
; 
2434     m_winCapture 
= NULL
; 
2436     m_rowLabelWidth  
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
2437     m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
2440     m_setFixedCols 
= NULL
; 
2443     m_attrCache
.row 
= -1; 
2444     m_attrCache
.col 
= -1; 
2445     m_attrCache
.attr 
= NULL
; 
2447     m_labelFont 
= GetFont(); 
2448     m_labelFont
.SetWeight( wxBOLD 
); 
2450     m_rowLabelHorizAlign 
= wxALIGN_CENTRE
; 
2451     m_rowLabelVertAlign  
= wxALIGN_CENTRE
; 
2453     m_colLabelHorizAlign 
= wxALIGN_CENTRE
; 
2454     m_colLabelVertAlign  
= wxALIGN_CENTRE
; 
2455     m_colLabelTextOrientation 
= wxHORIZONTAL
; 
2457     m_defaultColWidth  
= WXGRID_DEFAULT_COL_WIDTH
; 
2458     m_defaultRowHeight 
= 0; // this will be initialized after creation 
2460     m_minAcceptableColWidth  
= WXGRID_MIN_COL_WIDTH
; 
2461     m_minAcceptableRowHeight 
= WXGRID_MIN_ROW_HEIGHT
; 
2463     m_gridLineColour 
= wxColour( 192,192,192 ); 
2464     m_gridLinesEnabled 
= true; 
2465     m_gridLinesClipHorz 
= 
2466     m_gridLinesClipVert 
= true; 
2467     m_cellHighlightColour 
= *wxBLACK
; 
2468     m_cellHighlightPenWidth 
= 2; 
2469     m_cellHighlightROPenWidth 
= 1; 
2471     m_canDragColMove 
= false; 
2473     m_cursorMode  
= WXGRID_CURSOR_SELECT_CELL
; 
2474     m_winCapture 
= NULL
; 
2475     m_canDragRowSize 
= true; 
2476     m_canDragColSize 
= true; 
2477     m_canDragGridSize 
= true; 
2478     m_canDragCell 
= false; 
2480     m_dragRowOrCol 
= -1; 
2481     m_isDragging 
= false; 
2482     m_startDragPos 
= wxDefaultPosition
; 
2484     m_sortCol 
= wxNOT_FOUND
; 
2485     m_sortIsAscending 
= true; 
2488     m_nativeColumnLabels 
= false; 
2490     m_waitForSlowClick 
= false; 
2492     m_rowResizeCursor 
= wxCursor( wxCURSOR_SIZENS 
); 
2493     m_colResizeCursor 
= wxCursor( wxCURSOR_SIZEWE 
); 
2495     m_currentCellCoords 
= wxGridNoCellCoords
; 
2497     m_selectedBlockTopLeft 
= 
2498     m_selectedBlockBottomRight 
= 
2499     m_selectedBlockCorner 
= wxGridNoCellCoords
; 
2501     m_selectionBackground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
2502     m_selectionForeground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
2504     m_editable 
= true;  // default for whole grid 
2506     m_inOnKeyDown 
= false; 
2512     // we can't call SetScrollRate() as the window isn't created yet but OTOH 
2513     // we don't need to call it neither as the scroll position is (0, 0) right 
2514     // now anyhow, so just set the parameters directly 
2515     m_xScrollPixelsPerLine 
= GRID_SCROLL_LINE_X
; 
2516     m_yScrollPixelsPerLine 
= GRID_SCROLL_LINE_Y
; 
2519 // ---------------------------------------------------------------------------- 
2520 // the idea is to call these functions only when necessary because they create 
2521 // quite big arrays which eat memory mostly unnecessary - in particular, if 
2522 // default widths/heights are used for all rows/columns, we may not use these 
2525 // with some extra code, it should be possible to only store the widths/heights 
2526 // different from default ones (resulting in space savings for huge grids) but 
2527 // this is not done currently 
2528 // ---------------------------------------------------------------------------- 
2530 void wxGrid::InitRowHeights() 
2532     m_rowHeights
.Empty(); 
2533     m_rowBottoms
.Empty(); 
2535     m_rowHeights
.Alloc( m_numRows 
); 
2536     m_rowBottoms
.Alloc( m_numRows 
); 
2538     m_rowHeights
.Add( m_defaultRowHeight
, m_numRows 
); 
2541     for ( int i 
= 0; i 
< m_numRows
; i
++ ) 
2543         rowBottom 
+= m_defaultRowHeight
; 
2544         m_rowBottoms
.Add( rowBottom 
); 
2548 void wxGrid::InitColWidths() 
2550     m_colWidths
.Empty(); 
2551     m_colRights
.Empty(); 
2553     m_colWidths
.Alloc( m_numCols 
); 
2554     m_colRights
.Alloc( m_numCols 
); 
2556     m_colWidths
.Add( m_defaultColWidth
, m_numCols 
); 
2558     for ( int i 
= 0; i 
< m_numCols
; i
++ ) 
2560         int colRight 
= ( GetColPos( i 
) + 1 ) * m_defaultColWidth
; 
2561         m_colRights
.Add( colRight 
); 
2565 int wxGrid::GetColWidth(int col
) const 
2567     return m_colWidths
.IsEmpty() ? m_defaultColWidth 
: m_colWidths
[col
]; 
2570 int wxGrid::GetColLeft(int col
) const 
2572     return m_colRights
.IsEmpty() ? GetColPos( col 
) * m_defaultColWidth
 
2573                                  : m_colRights
[col
] - m_colWidths
[col
]; 
2576 int wxGrid::GetColRight(int col
) const 
2578     return m_colRights
.IsEmpty() ? (GetColPos( col 
) + 1) * m_defaultColWidth
 
2582 int wxGrid::GetRowHeight(int row
) const 
2584     return m_rowHeights
.IsEmpty() ? m_defaultRowHeight 
: m_rowHeights
[row
]; 
2587 int wxGrid::GetRowTop(int row
) const 
2589     return m_rowBottoms
.IsEmpty() ? row 
* m_defaultRowHeight
 
2590                                   : m_rowBottoms
[row
] - m_rowHeights
[row
]; 
2593 int wxGrid::GetRowBottom(int row
) const 
2595     return m_rowBottoms
.IsEmpty() ? (row 
+ 1) * m_defaultRowHeight
 
2596                                   : m_rowBottoms
[row
]; 
2599 void wxGrid::CalcDimensions() 
2601     // compute the size of the scrollable area 
2602     int w 
= m_numCols 
> 0 ? GetColRight(GetColAt(m_numCols 
- 1)) : 0; 
2603     int h 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
2608     // take into account editor if shown 
2609     if ( IsCellEditControlShown() ) 
2612         int r 
= m_currentCellCoords
.GetRow(); 
2613         int c 
= m_currentCellCoords
.GetCol(); 
2614         int x 
= GetColLeft(c
); 
2615         int y 
= GetRowTop(r
); 
2617         // how big is the editor 
2618         wxGridCellAttr
* attr 
= GetCellAttr(r
, c
); 
2619         wxGridCellEditor
* editor 
= attr
->GetEditor(this, r
, c
); 
2620         editor
->GetControl()->GetSize(&w2
, &h2
); 
2631     // preserve (more or less) the previous position 
2633     GetViewStart( &x
, &y 
); 
2635     // ensure the position is valid for the new scroll ranges 
2637         x 
= wxMax( w 
- 1, 0 ); 
2639         y 
= wxMax( h 
- 1, 0 ); 
2641     // update the virtual size and refresh the scrollbars to reflect it 
2642     m_gridWin
->SetVirtualSize(w
, h
); 
2646     // if our OnSize() hadn't been called (it would if we have scrollbars), we 
2647     // still must reposition the children 
2651 wxSize 
wxGrid::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
2653     wxSize 
sizeGridWin(size
); 
2654     sizeGridWin
.x 
-= m_rowLabelWidth
; 
2655     sizeGridWin
.y 
-= m_colLabelHeight
; 
2660 void wxGrid::CalcWindowSizes() 
2662     // escape if the window is has not been fully created yet 
2664     if ( m_cornerLabelWin 
== NULL 
) 
2668     GetClientSize( &cw
, &ch 
); 
2670     // the grid may be too small to have enough space for the labels yet, don't 
2671     // size the windows to negative sizes in this case 
2672     int gw 
= cw 
- m_rowLabelWidth
; 
2673     int gh 
= ch 
- m_colLabelHeight
; 
2679     if ( m_cornerLabelWin 
&& m_cornerLabelWin
->IsShown() ) 
2680         m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight 
); 
2682     if ( m_colWindow 
&& m_colWindow
->IsShown() ) 
2683         m_colWindow
->SetSize( m_rowLabelWidth
, 0, gw
, m_colLabelHeight 
); 
2685     if ( m_rowLabelWin 
&& m_rowLabelWin
->IsShown() ) 
2686         m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, gh 
); 
2688     if ( m_gridWin 
&& m_gridWin
->IsShown() ) 
2689         m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, gw
, gh 
); 
2692 // this is called when the grid table sends a message 
2693 // to indicate that it has been redimensioned 
2695 bool wxGrid::Redimension( wxGridTableMessage
& msg 
) 
2698     bool result 
= false; 
2700     // Clear the attribute cache as the attribute might refer to a different 
2701     // cell than stored in the cache after adding/removing rows/columns. 
2704     // By the same reasoning, the editor should be dismissed if columns are 
2705     // added or removed. And for consistency, it should IMHO always be 
2706     // removed, not only if the cell "underneath" it actually changes. 
2707     // For now, I intentionally do not save the editor's content as the 
2708     // cell it might want to save that stuff to might no longer exist. 
2709     HideCellEditControl(); 
2711     switch ( msg
.GetId() ) 
2713         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
2715             size_t pos 
= msg
.GetCommandInt(); 
2716             int numRows 
= msg
.GetCommandInt2(); 
2718             m_numRows 
+= numRows
; 
2720             if ( !m_rowHeights
.IsEmpty() ) 
2722                 m_rowHeights
.Insert( m_defaultRowHeight
, pos
, numRows 
); 
2723                 m_rowBottoms
.Insert( 0, pos
, numRows 
); 
2727                     bottom 
= m_rowBottoms
[pos 
- 1]; 
2729                 for ( i 
= pos
; i 
< m_numRows
; i
++ ) 
2731                     bottom 
+= m_rowHeights
[i
]; 
2732                     m_rowBottoms
[i
] = bottom
; 
2736             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2738                 // if we have just inserted cols into an empty grid the current 
2739                 // cell will be undefined... 
2741                 SetCurrentCell( 0, 0 ); 
2745                 m_selection
->UpdateRows( pos
, numRows 
); 
2746             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
2748                 attrProvider
->UpdateAttrRows( pos
, numRows 
); 
2750             if ( !GetBatchCount() ) 
2753                 m_rowLabelWin
->Refresh(); 
2759         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
2761             int numRows 
= msg
.GetCommandInt(); 
2762             int oldNumRows 
= m_numRows
; 
2763             m_numRows 
+= numRows
; 
2765             if ( !m_rowHeights
.IsEmpty() ) 
2767                 m_rowHeights
.Add( m_defaultRowHeight
, numRows 
); 
2768                 m_rowBottoms
.Add( 0, numRows 
); 
2771                 if ( oldNumRows 
> 0 ) 
2772                     bottom 
= m_rowBottoms
[oldNumRows 
- 1]; 
2774                 for ( i 
= oldNumRows
; i 
< m_numRows
; i
++ ) 
2776                     bottom 
+= m_rowHeights
[i
]; 
2777                     m_rowBottoms
[i
] = bottom
; 
2781             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2783                 // if we have just inserted cols into an empty grid the current 
2784                 // cell will be undefined... 
2786                 SetCurrentCell( 0, 0 ); 
2789             if ( !GetBatchCount() ) 
2792                 m_rowLabelWin
->Refresh(); 
2798         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
2800             size_t pos 
= msg
.GetCommandInt(); 
2801             int numRows 
= msg
.GetCommandInt2(); 
2802             m_numRows 
-= numRows
; 
2804             if ( !m_rowHeights
.IsEmpty() ) 
2806                 m_rowHeights
.RemoveAt( pos
, numRows 
); 
2807                 m_rowBottoms
.RemoveAt( pos
, numRows 
); 
2810                 for ( i 
= 0; i 
< m_numRows
; i
++ ) 
2812                     h 
+= m_rowHeights
[i
]; 
2813                     m_rowBottoms
[i
] = h
; 
2819                 m_currentCellCoords 
= wxGridNoCellCoords
; 
2823                 if ( m_currentCellCoords
.GetRow() >= m_numRows 
) 
2824                     m_currentCellCoords
.Set( 0, 0 ); 
2828                 m_selection
->UpdateRows( pos
, -((int)numRows
) ); 
2829             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
2832                 attrProvider
->UpdateAttrRows( pos
, -((int)numRows
) ); 
2834 // ifdef'd out following patch from Paul Gammans 
2836                 // No need to touch column attributes, unless we 
2837                 // removed _all_ rows, in this case, we remove 
2838                 // all column attributes. 
2839                 // I hate to do this here, but the 
2840                 // needed data is not available inside UpdateAttrRows. 
2841                 if ( !GetNumberRows() ) 
2842                     attrProvider
->UpdateAttrCols( 0, -GetNumberCols() ); 
2846             if ( !GetBatchCount() ) 
2849                 m_rowLabelWin
->Refresh(); 
2855         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
2857             size_t pos 
= msg
.GetCommandInt(); 
2858             int numCols 
= msg
.GetCommandInt2(); 
2859             m_numCols 
+= numCols
; 
2861             if ( m_useNativeHeader 
) 
2862                 GetGridColHeader()->SetColumnCount(m_numCols
); 
2864             if ( !m_colAt
.IsEmpty() ) 
2866                 //Shift the column IDs 
2868                 for ( i 
= 0; i 
< m_numCols 
- numCols
; i
++ ) 
2870                     if ( m_colAt
[i
] >= (int)pos 
) 
2871                         m_colAt
[i
] += numCols
; 
2874                 m_colAt
.Insert( pos
, pos
, numCols 
); 
2876                 //Set the new columns' positions 
2877                 for ( i 
= pos 
+ 1; i 
< (int)pos 
+ numCols
; i
++ ) 
2883             if ( !m_colWidths
.IsEmpty() ) 
2885                 m_colWidths
.Insert( m_defaultColWidth
, pos
, numCols 
); 
2886                 m_colRights
.Insert( 0, pos
, numCols 
); 
2890                     right 
= m_colRights
[GetColAt( pos 
- 1 )]; 
2893                 for ( colPos 
= pos
; colPos 
< m_numCols
; colPos
++ ) 
2895                     i 
= GetColAt( colPos 
); 
2897                     right 
+= m_colWidths
[i
]; 
2898                     m_colRights
[i
] = right
; 
2902             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2904                 // if we have just inserted cols into an empty grid the current 
2905                 // cell will be undefined... 
2907                 SetCurrentCell( 0, 0 ); 
2911                 m_selection
->UpdateCols( pos
, numCols 
); 
2912             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
2914                 attrProvider
->UpdateAttrCols( pos
, numCols 
); 
2915             if ( !GetBatchCount() ) 
2918                 m_colWindow
->Refresh(); 
2924         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
2926             int numCols 
= msg
.GetCommandInt(); 
2927             int oldNumCols 
= m_numCols
; 
2928             m_numCols 
+= numCols
; 
2929             if ( m_useNativeHeader 
) 
2930                 GetGridColHeader()->SetColumnCount(m_numCols
); 
2932             if ( !m_colAt
.IsEmpty() ) 
2934                 m_colAt
.Add( 0, numCols 
); 
2936                 //Set the new columns' positions 
2938                 for ( i 
= oldNumCols
; i 
< m_numCols
; i
++ ) 
2944             if ( !m_colWidths
.IsEmpty() ) 
2946                 m_colWidths
.Add( m_defaultColWidth
, numCols 
); 
2947                 m_colRights
.Add( 0, numCols 
); 
2950                 if ( oldNumCols 
> 0 ) 
2951                     right 
= m_colRights
[GetColAt( oldNumCols 
- 1 )]; 
2954                 for ( colPos 
= oldNumCols
; colPos 
< m_numCols
; colPos
++ ) 
2956                     i 
= GetColAt( colPos 
); 
2958                     right 
+= m_colWidths
[i
]; 
2959                     m_colRights
[i
] = right
; 
2963             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
2965                 // if we have just inserted cols into an empty grid the current 
2966                 // cell will be undefined... 
2968                 SetCurrentCell( 0, 0 ); 
2970             if ( !GetBatchCount() ) 
2973                 m_colWindow
->Refresh(); 
2979         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
2981             size_t pos 
= msg
.GetCommandInt(); 
2982             int numCols 
= msg
.GetCommandInt2(); 
2983             m_numCols 
-= numCols
; 
2984             if ( m_useNativeHeader 
) 
2985                 GetGridColHeader()->SetColumnCount(m_numCols
); 
2987             if ( !m_colAt
.IsEmpty() ) 
2989                 int colID 
= GetColAt( pos 
); 
2991                 m_colAt
.RemoveAt( pos
, numCols 
); 
2993                 //Shift the column IDs 
2995                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
2997                     if ( m_colAt
[colPos
] > colID 
) 
2998                         m_colAt
[colPos
] -= numCols
; 
3002             if ( !m_colWidths
.IsEmpty() ) 
3004                 m_colWidths
.RemoveAt( pos
, numCols 
); 
3005                 m_colRights
.RemoveAt( pos
, numCols 
); 
3009                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
3011                     i 
= GetColAt( colPos 
); 
3013                     w 
+= m_colWidths
[i
]; 
3020                 m_currentCellCoords 
= wxGridNoCellCoords
; 
3024                 if ( m_currentCellCoords
.GetCol() >= m_numCols 
) 
3025                   m_currentCellCoords
.Set( 0, 0 ); 
3029                 m_selection
->UpdateCols( pos
, -((int)numCols
) ); 
3030             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
3033                 attrProvider
->UpdateAttrCols( pos
, -((int)numCols
) ); 
3035 // ifdef'd out following patch from Paul Gammans 
3037                 // No need to touch row attributes, unless we 
3038                 // removed _all_ columns, in this case, we remove 
3039                 // all row attributes. 
3040                 // I hate to do this here, but the 
3041                 // needed data is not available inside UpdateAttrCols. 
3042                 if ( !GetNumberCols() ) 
3043                     attrProvider
->UpdateAttrRows( 0, -GetNumberRows() ); 
3047             if ( !GetBatchCount() ) 
3050                 m_colWindow
->Refresh(); 
3057     if (result 
&& !GetBatchCount() ) 
3058         m_gridWin
->Refresh(); 
3063 wxArrayInt 
wxGrid::CalcRowLabelsExposed( const wxRegion
& reg 
) const 
3065     wxRegionIterator 
iter( reg 
); 
3068     wxArrayInt  rowlabels
; 
3075         // TODO: remove this when we can... 
3076         // There is a bug in wxMotif that gives garbage update 
3077         // rectangles if you jump-scroll a long way by clicking the 
3078         // scrollbar with middle button.  This is a work-around 
3080 #if defined(__WXMOTIF__) 
3082         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3083         if ( r
.GetTop() > ch 
) 
3085         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
3088         // logical bounds of update region 
3091         CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top 
); 
3092         CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom 
); 
3094         // find the row labels within these bounds 
3097         for ( row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
3099             if ( GetRowBottom(row
) < top 
) 
3102             if ( GetRowTop(row
) > bottom 
) 
3105             rowlabels
.Add( row 
); 
3114 wxArrayInt 
wxGrid::CalcColLabelsExposed( const wxRegion
& reg 
) const 
3116     wxRegionIterator 
iter( reg 
); 
3119     wxArrayInt colLabels
; 
3126         // TODO: remove this when we can... 
3127         // There is a bug in wxMotif that gives garbage update 
3128         // rectangles if you jump-scroll a long way by clicking the 
3129         // scrollbar with middle button.  This is a work-around 
3131 #if defined(__WXMOTIF__) 
3133         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3134         if ( r
.GetLeft() > cw 
) 
3136         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
3139         // logical bounds of update region 
3142         CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy 
); 
3143         CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy 
); 
3145         // find the cells within these bounds 
3149         for ( colPos 
= GetColPos( internalXToCol(left
) ); colPos 
< m_numCols
; colPos
++ ) 
3151             col 
= GetColAt( colPos 
); 
3153             if ( GetColRight(col
) < left 
) 
3156             if ( GetColLeft(col
) > right 
) 
3159             colLabels
.Add( col 
); 
3168 wxGridCellCoordsArray 
wxGrid::CalcCellsExposed( const wxRegion
& reg 
) const 
3172     wxGridCellCoordsArray  cellsExposed
; 
3174     int left
, top
, right
, bottom
; 
3175     for ( wxRegionIterator 
iter(reg
); iter
; ++iter 
) 
3179         // Skip 0-height cells, they're invisible anyhow, don't waste time 
3180         // getting their rectangles and so on. 
3181         if ( !r
.GetHeight() ) 
3184         // TODO: remove this when we can... 
3185         // There is a bug in wxMotif that gives garbage update 
3186         // rectangles if you jump-scroll a long way by clicking the 
3187         // scrollbar with middle button.  This is a work-around 
3189 #if defined(__WXMOTIF__) 
3191         m_gridWin
->GetClientSize( &cw
, &ch 
); 
3192         if ( r
.GetTop() > ch 
) r
.SetTop( 0 ); 
3193         if ( r
.GetLeft() > cw 
) r
.SetLeft( 0 ); 
3194         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
3195         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
3198         // logical bounds of update region 
3200         CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
3201         CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
3203         // find the cells within these bounds 
3205         for ( int row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
3207             if ( GetRowBottom(row
) <= top 
) 
3210             if ( GetRowTop(row
) > bottom 
) 
3213             // add all dirty cells in this row: notice that the columns which 
3214             // are dirty don't depend on the row so we compute them only once 
3215             // for the first dirty row and then reuse for all the next ones 
3218                 // do determine the dirty columns 
3219                 for ( int pos 
= XToPos(left
); pos 
<= XToPos(right
); pos
++ ) 
3220                     cols
.push_back(GetColAt(pos
)); 
3222                 // if there are no dirty columns at all, nothing to do 
3227             const size_t count 
= cols
.size(); 
3228             for ( size_t n 
= 0; n 
< count
; n
++ ) 
3229                 cellsExposed
.Add(wxGridCellCoords(row
, cols
[n
])); 
3233     return cellsExposed
; 
3237 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event 
) 
3240     wxPoint 
pos( event
.GetPosition() ); 
3241     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
3243     if ( event
.Dragging() ) 
3247             m_isDragging 
= true; 
3248             m_rowLabelWin
->CaptureMouse(); 
3251         if ( event
.LeftIsDown() ) 
3253             switch ( m_cursorMode 
) 
3255                 case WXGRID_CURSOR_RESIZE_ROW
: 
3257                     int cw
, ch
, left
, dummy
; 
3258                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
3259                     CalcUnscrolledPosition( 0, 0, &left
, &dummy 
); 
3261                     wxClientDC 
dc( m_gridWin 
); 
3264                                GetRowTop(m_dragRowOrCol
) + 
3265                                GetRowMinimalHeight(m_dragRowOrCol
) ); 
3266                     dc
.SetLogicalFunction(wxINVERT
); 
3267                     if ( m_dragLastPos 
>= 0 ) 
3269                         dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos 
); 
3271                     dc
.DrawLine( left
, y
, left
+cw
, y 
); 
3276                 case WXGRID_CURSOR_SELECT_ROW
: 
3278                     if ( (row 
= YToRow( y 
)) >= 0 ) 
3281                             m_selection
->SelectRow(row
, event
); 
3286                 // default label to suppress warnings about "enumeration value 
3287                 // 'xxx' not handled in switch 
3295     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
3300         if (m_rowLabelWin
->HasCapture()) 
3301             m_rowLabelWin
->ReleaseMouse(); 
3302         m_isDragging 
= false; 
3305     // ------------ Entering or leaving the window 
3307     if ( event
.Entering() || event
.Leaving() ) 
3309         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
3312     // ------------ Left button pressed 
3314     else if ( event
.LeftDown() ) 
3316         row 
= YToEdgeOfRow(y
); 
3317         if ( row 
!= wxNOT_FOUND 
&& CanDragRowSize(row
) ) 
3319             ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
); 
3321         else // not a request to start resizing 
3325                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event 
) ) 
3327                 if ( !event
.ShiftDown() && !event
.CmdDown() ) 
3331                     if ( event
.ShiftDown() ) 
3333                         m_selection
->SelectBlock
 
3335                                         m_currentCellCoords
.GetRow(), 0, 
3336                                         row
, GetNumberCols() - 1, 
3342                         m_selection
->SelectRow(row
, event
); 
3346                 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
); 
3351     // ------------ Left double click 
3353     else if (event
.LeftDClick() ) 
3355         row 
= YToEdgeOfRow(y
); 
3356         if ( row 
!= wxNOT_FOUND 
&& CanDragRowSize(row
) ) 
3358             // adjust row height depending on label text 
3360             // TODO: generate RESIZING event, see #10754 
3361             AutoSizeRowLabelSize( row 
); 
3363             SendGridSizeEvent(wxEVT_GRID_ROW_SIZE
, row
, -1, event
); 
3365             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
3368         else // not on row separator or it's not resizable 
3372                  !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event 
) ) 
3374                 // no default action at the moment 
3379     // ------------ Left button released 
3381     else if ( event
.LeftUp() ) 
3383         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
3384             DoEndDragResizeRow(event
); 
3386         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
3390     // ------------ Right button down 
3392     else if ( event
.RightDown() ) 
3396              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event 
) ) 
3398             // no default action at the moment 
3402     // ------------ Right double click 
3404     else if ( event
.RightDClick() ) 
3408              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event 
) ) 
3410             // no default action at the moment 
3414     // ------------ No buttons down and mouse moving 
3416     else if ( event
.Moving() ) 
3418         m_dragRowOrCol 
= YToEdgeOfRow( y 
); 
3419         if ( m_dragRowOrCol 
!= wxNOT_FOUND 
) 
3421             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
3423                 if ( CanDragRowSize(m_dragRowOrCol
) ) 
3424                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, false); 
3427         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
3429             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, false); 
3434 void wxGrid::UpdateColumnSortingIndicator(int col
) 
3436     wxCHECK_RET( col 
!= wxNOT_FOUND
, "invalid column index" ); 
3438     if ( m_useNativeHeader 
) 
3439         GetGridColHeader()->UpdateColumn(col
); 
3440     else if ( m_nativeColumnLabels 
) 
3441         m_colWindow
->Refresh(); 
3442     //else: sorting indicator display not yet implemented in grid version 
3445 void wxGrid::SetSortingColumn(int col
, bool ascending
) 
3447     if ( col 
== m_sortCol 
) 
3449         // we are already using this column for sorting (or not sorting at all) 
3450         // but we might still change the sorting order, check for it 
3451         if ( m_sortCol 
!= wxNOT_FOUND 
&& ascending 
!= m_sortIsAscending 
) 
3453             m_sortIsAscending 
= ascending
; 
3455             UpdateColumnSortingIndicator(m_sortCol
); 
3458     else // we're changing the column used for sorting 
3460         const int sortColOld 
= m_sortCol
; 
3462         // change it before updating the column as we want GetSortingColumn() 
3463         // to return the correct new value 
3466         if ( sortColOld 
!= wxNOT_FOUND 
) 
3467             UpdateColumnSortingIndicator(sortColOld
); 
3469         if ( m_sortCol 
!= wxNOT_FOUND 
) 
3471             m_sortIsAscending 
= ascending
; 
3472             UpdateColumnSortingIndicator(m_sortCol
); 
3477 void wxGrid::DoColHeaderClick(int col
) 
3479     // we consider that the grid was resorted if this event is processed and 
3481     if ( SendEvent(wxEVT_GRID_COL_SORT
, -1, col
) == 1 ) 
3483         SetSortingColumn(col
, IsSortingBy(col
) ? !m_sortIsAscending 
: true); 
3488 void wxGrid::DoStartResizeCol(int col
) 
3490     m_dragRowOrCol 
= col
; 
3492     DoUpdateResizeColWidth(GetColWidth(m_dragRowOrCol
)); 
3495 void wxGrid::DoUpdateResizeCol(int x
) 
3497     int cw
, ch
, dummy
, top
; 
3498     m_gridWin
->GetClientSize( &cw
, &ch 
); 
3499     CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
3501     wxClientDC 
dc( m_gridWin 
); 
3504     x 
= wxMax( x
, GetColLeft(m_dragRowOrCol
) + GetColMinimalWidth(m_dragRowOrCol
)); 
3505     dc
.SetLogicalFunction(wxINVERT
); 
3506     if ( m_dragLastPos 
>= 0 ) 
3508         dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top 
+ ch 
); 
3510     dc
.DrawLine( x
, top
, x
, top 
+ ch 
); 
3514 void wxGrid::DoUpdateResizeColWidth(int w
) 
3516     DoUpdateResizeCol(GetColLeft(m_dragRowOrCol
) + w
); 
3519 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event 
) 
3522     wxPoint 
pos( event
.GetPosition() ); 
3523     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
3525     int col 
= XToCol(x
); 
3526     if ( event
.Dragging() ) 
3530             m_isDragging 
= true; 
3531             GetColLabelWindow()->CaptureMouse(); 
3533             if ( m_cursorMode 
== WXGRID_CURSOR_MOVE_COL 
&& col 
!= -1 ) 
3534                 DoStartMoveCol(col
); 
3537         if ( event
.LeftIsDown() ) 
3539             switch ( m_cursorMode 
) 
3541                 case WXGRID_CURSOR_RESIZE_COL
: 
3542                 DoUpdateResizeCol(x
); 
3545                 case WXGRID_CURSOR_SELECT_COL
: 
3550                             m_selection
->SelectCol(col
, event
); 
3555                 case WXGRID_CURSOR_MOVE_COL
: 
3557                     int posNew 
= XToPos(x
); 
3558                     int colNew 
= GetColAt(posNew
); 
3560                     // determine the position of the drop marker 
3562                     if ( x 
>= GetColLeft(colNew
) + (GetColWidth(colNew
) / 2) ) 
3563                         markerX 
= GetColRight(colNew
); 
3565                         markerX 
= GetColLeft(colNew
); 
3567                     if ( markerX 
!= m_dragLastPos 
) 
3569                         wxClientDC 
dc( GetColLabelWindow() ); 
3573                         GetColLabelWindow()->GetClientSize( &cw
, &ch 
); 
3577                         //Clean up the last indicator 
3578                         if ( m_dragLastPos 
>= 0 ) 
3580                             wxPen 
pen( GetColLabelWindow()->GetBackgroundColour(), 2 ); 
3582                             dc
.DrawLine( m_dragLastPos 
+ 1, 0, m_dragLastPos 
+ 1, ch 
); 
3583                             dc
.SetPen(wxNullPen
); 
3585                             if ( XToCol( m_dragLastPos 
) != -1 ) 
3586                                 DrawColLabel( dc
, XToCol( m_dragLastPos 
) ); 
3589                         const wxColour 
*color
; 
3590                         //Moving to the same place? Don't draw a marker 
3591                         if ( colNew 
== m_dragRowOrCol 
) 
3592                             color 
= wxLIGHT_GREY
; 
3597                         wxPen 
pen( *color
, 2 ); 
3600                         dc
.DrawLine( markerX
, 0, markerX
, ch 
); 
3602                         dc
.SetPen(wxNullPen
); 
3604                         m_dragLastPos 
= markerX 
- 1; 
3609                 // default label to suppress warnings about "enumeration value 
3610                 // 'xxx' not handled in switch 
3618     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
3623         if (GetColLabelWindow()->HasCapture()) 
3624             GetColLabelWindow()->ReleaseMouse(); 
3625         m_isDragging 
= false; 
3628     // ------------ Entering or leaving the window 
3630     if ( event
.Entering() || event
.Leaving() ) 
3632         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
3635     // ------------ Left button pressed 
3637     else if ( event
.LeftDown() ) 
3639         int col 
= XToEdgeOfCol(x
); 
3640         if ( col 
!= wxNOT_FOUND 
&& CanDragColSize(col
) ) 
3642             ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow()); 
3644         else // not a request to start resizing 
3648                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event 
) ) 
3650                 if ( m_canDragColMove 
) 
3652                     //Show button as pressed 
3653                     wxClientDC 
dc( GetColLabelWindow() ); 
3654                     int colLeft 
= GetColLeft( col 
); 
3655                     int colRight 
= GetColRight( col 
) - 1; 
3656                     dc
.SetPen( wxPen( GetColLabelWindow()->GetBackgroundColour(), 1 ) ); 
3657                     dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight
-1 ); 
3658                     dc
.DrawLine( colLeft
, 1, colRight
, 1 ); 
3660                     ChangeCursorMode(WXGRID_CURSOR_MOVE_COL
, GetColLabelWindow()); 
3664                     if ( !event
.ShiftDown() && !event
.CmdDown() ) 
3668                         if ( event
.ShiftDown() ) 
3670                             m_selection
->SelectBlock
 
3672                                             0, m_currentCellCoords
.GetCol(), 
3673                                             GetNumberRows() - 1, col
, 
3679                             m_selection
->SelectCol(col
, event
); 
3683                     ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, GetColLabelWindow()); 
3689     // ------------ Left double click 
3691     if ( event
.LeftDClick() ) 
3693         const int colEdge 
= XToEdgeOfCol(x
); 
3694         if ( colEdge 
== -1 ) 
3697                  ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event 
) ) 
3699                 // no default action at the moment 
3704             // adjust column width depending on label text 
3706             // TODO: generate RESIZING event, see #10754 
3707             AutoSizeColLabelSize( colEdge 
); 
3709             SendGridSizeEvent(wxEVT_GRID_COL_SIZE
, -1, colEdge
, event
); 
3711             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
3716     // ------------ Left button released 
3718     else if ( event
.LeftUp() ) 
3720         switch ( m_cursorMode 
) 
3722             case WXGRID_CURSOR_RESIZE_COL
: 
3723                 DoEndDragResizeCol(event
); 
3726             case WXGRID_CURSOR_MOVE_COL
: 
3727                 if ( m_dragLastPos 
== -1 || col 
== m_dragRowOrCol 
) 
3729                     // the column didn't actually move anywhere 
3731                         DoColHeaderClick(col
); 
3732                     m_colWindow
->Refresh();   // "unpress" the column 
3736                     // get the position of the column we're over 
3737                     int pos 
= XToPos(x
); 
3739                     // we may need to adjust the drop position but don't bother 
3740                     // checking for it if we can't anyhow 
3743                         // also find the index of the column we're over: notice 
3744                         // that the existing "col" variable may be invalid but 
3745                         // we need a valid one here 
3746                         const int colValid 
= GetColAt(pos
); 
3748                         // if we're on the "near" (usually left but right in 
3749                         // RTL case) part of the column, the actual position we 
3750                         // should be placed in is actually the one before it 
3752                         const int middle 
= GetColLeft(colValid
) + 
3753                                                 GetColWidth(colValid
)/2; 
3754                         if ( GetLayoutDirection() == wxLayout_LeftToRight 
) 
3755                             onNearPart 
= (x 
<= middle
); 
3756                         else // wxLayout_RightToLeft 
3757                             onNearPart 
= (x 
> middle
); 
3767             case WXGRID_CURSOR_SELECT_COL
: 
3768             case WXGRID_CURSOR_SELECT_CELL
: 
3769             case WXGRID_CURSOR_RESIZE_ROW
: 
3770             case WXGRID_CURSOR_SELECT_ROW
: 
3772                     DoColHeaderClick(col
); 
3776         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
3780     // ------------ Right button down 
3782     else if ( event
.RightDown() ) 
3785              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event 
) ) 
3787             // no default action at the moment 
3791     // ------------ Right double click 
3793     else if ( event
.RightDClick() ) 
3796              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event 
) ) 
3798             // no default action at the moment 
3802     // ------------ No buttons down and mouse moving 
3804     else if ( event
.Moving() ) 
3806         m_dragRowOrCol 
= XToEdgeOfCol( x 
); 
3807         if ( m_dragRowOrCol 
>= 0 ) 
3809             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
3811                 if ( CanDragColSize(m_dragRowOrCol
) ) 
3812                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow(), false); 
3815         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
3817             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow(), false); 
3822 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event 
) 
3824     if ( event
.LeftDown() ) 
3826         // indicate corner label by having both row and 
3829         if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event 
) ) 
3834     else if ( event
.LeftDClick() ) 
3836         SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event 
); 
3838     else if ( event
.RightDown() ) 
3840         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event 
) ) 
3842             // no default action at the moment 
3845     else if ( event
.RightDClick() ) 
3847         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event 
) ) 
3849             // no default action at the moment 
3854 void wxGrid::CancelMouseCapture() 
3856     // cancel operation currently in progress, whatever it is 
3859         m_isDragging 
= false; 
3860         m_startDragPos 
= wxDefaultPosition
; 
3862         m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
3863         m_winCapture
->SetCursor( *wxSTANDARD_CURSOR 
); 
3864         m_winCapture 
= NULL
; 
3866         // remove traces of whatever we drew on screen 
3871 void wxGrid::ChangeCursorMode(CursorMode mode
, 
3876     static const wxChar 
*const cursorModes
[] = 
3886     wxLogTrace(wxT("grid"), 
3887                wxT("wxGrid cursor mode (mouse capture for %s): %s -> %s"), 
3888                win 
== m_colWindow 
? wxT("colLabelWin") 
3889                                   : win 
? wxT("rowLabelWin") 
3891                cursorModes
[m_cursorMode
], cursorModes
[mode
]); 
3892 #endif // wxUSE_LOG_TRACE 
3894     if ( mode 
== m_cursorMode 
&& 
3895          win 
== m_winCapture 
&& 
3896          captureMouse 
== (m_winCapture 
!= NULL
)) 
3901         // by default use the grid itself 
3907         m_winCapture
->ReleaseMouse(); 
3908         m_winCapture 
= NULL
; 
3911     m_cursorMode 
= mode
; 
3913     switch ( m_cursorMode 
) 
3915         case WXGRID_CURSOR_RESIZE_ROW
: 
3916             win
->SetCursor( m_rowResizeCursor 
); 
3919         case WXGRID_CURSOR_RESIZE_COL
: 
3920             win
->SetCursor( m_colResizeCursor 
); 
3923         case WXGRID_CURSOR_MOVE_COL
: 
3924             win
->SetCursor( wxCursor(wxCURSOR_HAND
) ); 
3928             win
->SetCursor( *wxSTANDARD_CURSOR 
); 
3932     // we need to capture mouse when resizing 
3933     bool resize 
= m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
|| 
3934                   m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL
; 
3936     if ( captureMouse 
&& resize 
) 
3938         win
->CaptureMouse(); 
3943 // ---------------------------------------------------------------------------- 
3944 // grid mouse event processing 
3945 // ---------------------------------------------------------------------------- 
3948 wxGrid::DoGridCellDrag(wxMouseEvent
& event
, 
3949                        const wxGridCellCoords
& coords
, 
3952     bool performDefault 
= true ; 
3954     if ( coords 
== wxGridNoCellCoords 
) 
3955         return performDefault
; // we're outside any valid cell 
3957     // Hide the edit control, so it won't interfere with drag-shrinking. 
3958     if ( IsCellEditControlShown() ) 
3960         HideCellEditControl(); 
3961         SaveEditControlValue(); 
3964     switch ( event
.GetModifiers() ) 
3967             if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
3968                 m_selectedBlockCorner 
= coords
; 
3969             UpdateBlockBeingSelected(m_selectedBlockCorner
, coords
); 
3973             if ( CanDragCell() ) 
3977                     if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
3978                         m_selectedBlockCorner 
= coords
; 
3980                     // if event is handled by user code, no further processing 
3981                     if ( SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG
, coords
, event
) != 0 ) 
3982                         performDefault 
= false; 
3984                     return performDefault
; 
3988             UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
3992             // we don't handle the other key modifiers 
3996     return performDefault
; 
3999 void wxGrid::DoGridLineDrag(wxMouseEvent
& event
, const wxGridOperations
& oper
) 
4001     wxClientDC 
dc(m_gridWin
); 
4003     dc
.SetLogicalFunction(wxINVERT
); 
4005     const wxRect 
rectWin(CalcUnscrolledPosition(wxPoint(0, 0)), 
4006                          m_gridWin
->GetClientSize()); 
4008     // erase the previously drawn line, if any 
4009     if ( m_dragLastPos 
>= 0 ) 
4010         oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
4012     // we need the vertical position for rows and horizontal for columns here 
4013     m_dragLastPos 
= oper
.Dual().Select(CalcUnscrolledPosition(event
.GetPosition())); 
4015     // don't allow resizing beneath the minimal size 
4016     const int posMin 
= oper
.GetLineStartPos(this, m_dragRowOrCol
) + 
4017                         oper
.GetMinimalLineSize(this, m_dragRowOrCol
); 
4018     if ( m_dragLastPos 
< posMin 
) 
4019         m_dragLastPos 
= posMin
; 
4021     // and draw it at the new position 
4022     oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
4025 void wxGrid::DoGridDragEvent(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
4027     if ( !m_isDragging 
) 
4029         // Don't start doing anything until the mouse has been dragged far 
4031         const wxPoint
& pt 
= event
.GetPosition(); 
4032         if ( m_startDragPos 
== wxDefaultPosition 
) 
4034             m_startDragPos 
= pt
; 
4038         if ( abs(m_startDragPos
.x 
- pt
.x
) <= DRAG_SENSITIVITY 
&& 
4039                 abs(m_startDragPos
.y 
- pt
.y
) <= DRAG_SENSITIVITY 
) 
4043     const bool isFirstDrag 
= !m_isDragging
; 
4044     m_isDragging 
= true; 
4046     switch ( m_cursorMode 
) 
4048         case WXGRID_CURSOR_SELECT_CELL
: 
4049             // no further handling if handled by user 
4050             if ( DoGridCellDrag(event
, coords
, isFirstDrag
) == false ) 
4054         case WXGRID_CURSOR_RESIZE_ROW
: 
4055             DoGridLineDrag(event
, wxGridRowOperations()); 
4058         case WXGRID_CURSOR_RESIZE_COL
: 
4059             DoGridLineDrag(event
, wxGridColumnOperations()); 
4068         wxASSERT_MSG( !m_winCapture
, "shouldn't capture the mouse twice" ); 
4070         m_winCapture 
= m_gridWin
; 
4071         m_winCapture
->CaptureMouse(); 
4076 wxGrid::DoGridCellLeftDown(wxMouseEvent
& event
, 
4077                            const wxGridCellCoords
& coords
, 
4080     if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK
, coords
, event
) ) 
4082         // event handled by user code, no need to do anything here 
4086     if ( !event
.CmdDown() ) 
4089     if ( event
.ShiftDown() ) 
4093             m_selection
->SelectBlock(m_currentCellCoords
, coords
, event
); 
4094             m_selectedBlockCorner 
= coords
; 
4097     else if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
4099         DisableCellEditControl(); 
4100         MakeCellVisible( coords 
); 
4102         if ( event
.CmdDown() ) 
4106                 m_selection
->ToggleCellSelection(coords
, event
); 
4109             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
4110             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
4111             m_selectedBlockCorner 
= coords
; 
4117                 // In row or column selection mode just clicking on the cell 
4118                 // should select the row or column containing it: this is more 
4119                 // convenient for the kinds of controls that use such selection 
4120                 // mode and is compatible with 2.8 behaviour (see #12062). 
4121                 switch ( m_selection
->GetSelectionMode() ) 
4123                     case wxGridSelectCells
: 
4124                     case wxGridSelectRowsOrColumns
: 
4125                         // nothing to do in these cases 
4128                     case wxGridSelectRows
: 
4129                         m_selection
->SelectRow(coords
.GetRow()); 
4132                     case wxGridSelectColumns
: 
4133                         m_selection
->SelectCol(coords
.GetCol()); 
4138             m_waitForSlowClick 
= m_currentCellCoords 
== coords 
&& 
4139                                         coords 
!= wxGridNoCellCoords
; 
4140             SetCurrentCell( coords 
); 
4146 wxGrid::DoGridCellLeftDClick(wxMouseEvent
& event
, 
4147                              const wxGridCellCoords
& coords
, 
4150     if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
4152         if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK
, coords
, event
) ) 
4154             // we want double click to select a cell and start editing 
4155             // (i.e. to behave in same way as sequence of two slow clicks): 
4156             m_waitForSlowClick 
= true; 
4162 wxGrid::DoGridCellLeftUp(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
4164     if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
4168             m_winCapture
->ReleaseMouse(); 
4169             m_winCapture 
= NULL
; 
4172         if ( coords 
== m_currentCellCoords 
&& m_waitForSlowClick 
&& CanEnableCellControl() ) 
4175             EnableCellEditControl(); 
4177             wxGridCellAttr 
*attr 
= GetCellAttr(coords
); 
4178             wxGridCellEditor 
*editor 
= attr
->GetEditor(this, coords
.GetRow(), coords
.GetCol()); 
4179             editor
->StartingClick(); 
4183             m_waitForSlowClick 
= false; 
4185         else if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
4186              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
4190                 m_selection
->SelectBlock( m_selectedBlockTopLeft
, 
4191                                           m_selectedBlockBottomRight
, 
4195             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
4196             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
4198             // Show the edit control, if it has been hidden for 
4200             ShowCellEditControl(); 
4203     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
4205         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
4206         DoEndDragResizeRow(event
); 
4208     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL 
) 
4210         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
4211         DoEndDragResizeCol(event
); 
4218 wxGrid::DoGridMouseMoveEvent(wxMouseEvent
& WXUNUSED(event
), 
4219                              const wxGridCellCoords
& coords
, 
4222     if ( coords
.GetRow() < 0 || coords
.GetCol() < 0 ) 
4224         // out of grid cell area 
4225         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
4229     int dragRow 
= YToEdgeOfRow( pos
.y 
); 
4230     int dragCol 
= XToEdgeOfCol( pos
.x 
); 
4232     // Dragging on the corner of a cell to resize in both 
4233     // directions is not implemented yet... 
4235     if ( dragRow 
>= 0 && dragCol 
>= 0 ) 
4237         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
4241     if ( dragRow 
>= 0 && CanDragGridSize() && CanDragRowSize(dragRow
) ) 
4243         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
4245             m_dragRowOrCol 
= dragRow
; 
4246             ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, NULL
, false); 
4249     // When using the native header window we can only resize the columns by 
4250     // dragging the dividers in it because we can't make it enter into the 
4251     // column resizing mode programmatically 
4252     else if ( dragCol 
>= 0 && !m_useNativeHeader 
&& 
4253                 CanDragGridSize() && CanDragColSize(dragCol
) ) 
4255         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
4257             m_dragRowOrCol 
= dragCol
; 
4258             ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, NULL
, false); 
4261     else // Neither on a row or col edge 
4263         if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
4265             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
4270 void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent
& event
) 
4272     if ( event
.Entering() || event
.Leaving() ) 
4274         // we don't care about these events but we must not reset m_isDragging 
4275         // if they happen so return before anything else is done 
4280     const wxPoint pos 
= CalcUnscrolledPosition(event
.GetPosition()); 
4282     // coordinates of the cell under mouse 
4283     wxGridCellCoords coords 
= XYToCell(pos
); 
4285     int cell_rows
, cell_cols
; 
4286     GetCellSize( coords
.GetRow(), coords
.GetCol(), &cell_rows
, &cell_cols 
); 
4287     if ( (cell_rows 
< 0) || (cell_cols 
< 0) ) 
4289         coords
.SetRow(coords
.GetRow() + cell_rows
); 
4290         coords
.SetCol(coords
.GetCol() + cell_cols
); 
4293     if ( event
.Dragging() ) 
4295         if ( event
.LeftIsDown() ) 
4296             DoGridDragEvent(event
, coords
); 
4302     m_isDragging 
= false; 
4303     m_startDragPos 
= wxDefaultPosition
; 
4305     // deal with various button presses 
4306     if ( event
.IsButton() ) 
4308         if ( coords 
!= wxGridNoCellCoords 
) 
4310             DisableCellEditControl(); 
4312             if ( event
.LeftDown() ) 
4313                 DoGridCellLeftDown(event
, coords
, pos
); 
4314             else if ( event
.LeftDClick() ) 
4315                 DoGridCellLeftDClick(event
, coords
, pos
); 
4316             else if ( event
.RightDown() ) 
4317                 SendEvent(wxEVT_GRID_CELL_RIGHT_CLICK
, coords
, event
); 
4318             else if ( event
.RightDClick() ) 
4319                 SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK
, coords
, event
); 
4322         // this one should be called even if we're not over any cell 
4323         if ( event
.LeftUp() ) 
4325             DoGridCellLeftUp(event
, coords
); 
4328     else if ( event
.Moving() ) 
4330         DoGridMouseMoveEvent(event
, coords
, pos
); 
4332     else // unknown mouse event? 
4338 // this function returns true only if the size really changed 
4339 bool wxGrid::DoEndDragResizeLine(const wxGridOperations
& oper
) 
4341     if ( m_dragLastPos 
== -1 ) 
4344     const wxGridOperations
& doper 
= oper
.Dual(); 
4346     const wxSize size 
= m_gridWin
->GetClientSize(); 
4348     const wxPoint ptOrigin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
4350     // erase the last line we drew 
4351     wxClientDC 
dc(m_gridWin
); 
4353     dc
.SetLogicalFunction(wxINVERT
); 
4355     const int posLineStart 
= oper
.Select(ptOrigin
); 
4356     const int posLineEnd 
= oper
.Select(ptOrigin
) + oper
.Select(size
); 
4358     oper
.DrawParallelLine(dc
, posLineStart
, posLineEnd
, m_dragLastPos
); 
4360     // temporarily hide the edit control before resizing 
4361     HideCellEditControl(); 
4362     SaveEditControlValue(); 
4364     // do resize the line 
4365     const int lineStart 
= oper
.GetLineStartPos(this, m_dragRowOrCol
); 
4366     const int lineSizeOld 
= oper
.GetLineSize(this, m_dragRowOrCol
); 
4367     oper
.SetLineSize(this, m_dragRowOrCol
, 
4368                      wxMax(m_dragLastPos 
- lineStart
, 
4369                            oper
.GetMinimalLineSize(this, m_dragRowOrCol
))); 
4371         sizeChanged 
= oper
.GetLineSize(this, m_dragRowOrCol
) != lineSizeOld
; 
4375     // refresh now if we're not frozen 
4376     if ( !GetBatchCount() ) 
4378         // we need to refresh everything beyond the resized line in the header 
4381         // get the position from which to refresh in the other direction 
4382         wxRect 
rect(CellToRect(oper
.MakeCoords(m_dragRowOrCol
, 0))); 
4383         rect
.SetPosition(CalcScrolledPosition(rect
.GetPosition())); 
4385         // we only need the ordinate (for rows) or abscissa (for columns) here, 
4386         // and need to cover the entire window in the other direction 
4387         oper
.Select(rect
) = 0; 
4389         wxRect 
rectHeader(rect
.GetPosition(), 
4392                                     oper
.GetHeaderWindowSize(this), 
4393                                     doper
.Select(size
) - doper
.Select(rect
) 
4396         oper
.GetHeaderWindow(this)->Refresh(true, &rectHeader
); 
4399         // also refresh the grid window: extend the rectangle 
4402             oper
.SelectSize(rect
) = oper
.Select(size
); 
4404             int subtractLines 
= 0; 
4405             const int lineStart 
= doper
.PosToLine(this, posLineStart
); 
4406             if ( lineStart 
>= 0 ) 
4408                 // ensure that if we have a multi-cell block we redraw all of 
4409                 // it by increasing the refresh area to cover it entirely if a 
4410                 // part of it is affected 
4411                 const int lineEnd 
= doper
.PosToLine(this, posLineEnd
, true); 
4412                 for ( int line 
= lineStart
; line 
< lineEnd
; line
++ ) 
4414                     int cellLines 
= oper
.Select( 
4415                         GetCellSize(oper
.MakeCoords(m_dragRowOrCol
, line
))); 
4416                     if ( cellLines 
< subtractLines 
) 
4417                         subtractLines 
= cellLines
; 
4422                 oper
.GetLineStartPos(this, m_dragRowOrCol 
+ subtractLines
); 
4423             startPos 
= doper
.CalcScrolledPosition(this, startPos
); 
4425             doper
.Select(rect
) = startPos
; 
4426             doper
.SelectSize(rect
) = doper
.Select(size
) - startPos
; 
4428             m_gridWin
->Refresh(false, &rect
); 
4432     // show the edit control back again 
4433     ShowCellEditControl(); 
4438 void wxGrid::DoEndDragResizeRow(const wxMouseEvent
& event
) 
4440     // TODO: generate RESIZING event, see #10754 
4442     if ( DoEndDragResizeLine(wxGridRowOperations()) ) 
4443         SendGridSizeEvent(wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event
); 
4446 void wxGrid::DoEndDragResizeCol(const wxMouseEvent
& event
) 
4448     // TODO: generate RESIZING event, see #10754 
4450     if ( DoEndDragResizeLine(wxGridColumnOperations()) ) 
4451         SendGridSizeEvent(wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event
); 
4454 void wxGrid::DoStartMoveCol(int col
) 
4456     m_dragRowOrCol 
= col
; 
4459 void wxGrid::DoEndMoveCol(int pos
) 
4461     wxASSERT_MSG( m_dragRowOrCol 
!= -1, "no matching DoStartMoveCol?" ); 
4463     if ( SendEvent(wxEVT_GRID_COL_MOVE
, -1, m_dragRowOrCol
) != -1 ) 
4464         SetColPos(m_dragRowOrCol
, pos
); 
4465     //else: vetoed by user 
4467     m_dragRowOrCol 
= -1; 
4470 void wxGrid::RefreshAfterColPosChange() 
4472     // recalculate the column rights as the column positions have changed, 
4473     // unless we calculate them dynamically because all columns widths are the 
4474     // same and it's easy to do 
4475     if ( !m_colWidths
.empty() ) 
4478         for ( int colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
4480             int colID 
= GetColAt( colPos 
); 
4482             colRight 
+= m_colWidths
[colID
]; 
4483             m_colRights
[colID
] = colRight
; 
4487     // and make the changes visible 
4488     if ( m_useNativeHeader 
) 
4490         if ( m_colAt
.empty() ) 
4491             GetGridColHeader()->ResetColumnsOrder(); 
4493             GetGridColHeader()->SetColumnsOrder(m_colAt
); 
4497         m_colWindow
->Refresh(); 
4499     m_gridWin
->Refresh(); 
4502 void wxGrid::SetColumnsOrder(const wxArrayInt
& order
) 
4506     RefreshAfterColPosChange(); 
4509 void wxGrid::SetColPos(int idx
, int pos
) 
4511     // we're going to need m_colAt now, initialize it if needed 
4512     if ( m_colAt
.empty() ) 
4514         m_colAt
.reserve(m_numCols
); 
4515         for ( int i 
= 0; i 
< m_numCols
; i
++ ) 
4516             m_colAt
.push_back(i
); 
4519     wxHeaderCtrl::MoveColumnInOrderArray(m_colAt
, idx
, pos
); 
4521     RefreshAfterColPosChange(); 
4524 void wxGrid::ResetColPos() 
4528     RefreshAfterColPosChange(); 
4531 void wxGrid::EnableDragColMove( bool enable 
) 
4533     if ( m_canDragColMove 
== enable 
) 
4536     if ( m_useNativeHeader 
) 
4538         // update all columns to make them [not] reorderable 
4539         GetGridColHeader()->SetColumnCount(m_numCols
); 
4542     m_canDragColMove 
= enable
; 
4544     // we use to call ResetColPos() from here if !enable but this doesn't seem 
4545     // right as it would mean there would be no way to "freeze" the current 
4546     // columns order by disabling moving them after putting them in the desired 
4547     // order, whereas now you can always call ResetColPos() manually if needed 
4552 // ------ interaction with data model 
4554 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg 
) 
4556     switch ( msg
.GetId() ) 
4558         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
: 
4559             return GetModelValues(); 
4561         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
: 
4562             return SetModelValues(); 
4564         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
4565         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
4566         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
4567         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
4568         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
4569         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
4570             return Redimension( msg 
); 
4577 // The behaviour of this function depends on the grid table class 
4578 // Clear() function. For the default wxGridStringTable class the 
4579 // behaviour is to replace all cell contents with wxEmptyString but 
4580 // not to change the number of rows or cols. 
4582 void wxGrid::ClearGrid() 
4586         if (IsCellEditControlEnabled()) 
4587             DisableCellEditControl(); 
4590         if (!GetBatchCount()) 
4591             m_gridWin
->Refresh(); 
4596 wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify
)(size_t, size_t), 
4597                       int pos
, int num
, bool WXUNUSED(updateLabels
) ) 
4599     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
4604     if ( IsCellEditControlEnabled() ) 
4605         DisableCellEditControl(); 
4607     return (m_table
->*funcModify
)(pos
, num
); 
4609     // the table will have sent the results of the insert row 
4610     // operation to this view object as a grid table message 
4614 wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend
)(size_t), 
4615                       int num
, bool WXUNUSED(updateLabels
)) 
4617     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
4622     return (m_table
->*funcAppend
)(num
); 
4625 // ---------------------------------------------------------------------------- 
4626 // event generation helpers 
4627 // ---------------------------------------------------------------------------- 
4630 wxGrid::SendGridSizeEvent(wxEventType type
, 
4632                       const wxMouseEvent
& mouseEv
) 
4634    int rowOrCol 
= row 
== -1 ? col 
: row
; 
4636    wxGridSizeEvent 
gridEvt( GetId(), 
4640            mouseEv
.GetX() + GetRowLabelSize(), 
4641            mouseEv
.GetY() + GetColLabelSize(), 
4644    GetEventHandler()->ProcessEvent(gridEvt
); 
4647 // Generate a grid event based on a mouse event and return: 
4648 //  -1 if the event was vetoed 
4649 //  +1 if the event was processed (but not vetoed) 
4650 //   0 if the event wasn't handled 
4652 wxGrid::SendEvent(const wxEventType type
, 
4654                   const wxMouseEvent
& mouseEv
) 
4656    bool claimed
, vetoed
; 
4658    if ( type 
== wxEVT_GRID_RANGE_SELECT 
) 
4660        // Right now, it should _never_ end up here! 
4661        wxGridRangeSelectEvent 
gridEvt( GetId(), 
4664                m_selectedBlockTopLeft
, 
4665                m_selectedBlockBottomRight
, 
4669        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
4670        vetoed 
= !gridEvt
.IsAllowed(); 
4672    else if ( type 
== wxEVT_GRID_LABEL_LEFT_CLICK 
|| 
4673              type 
== wxEVT_GRID_LABEL_LEFT_DCLICK 
|| 
4674              type 
== wxEVT_GRID_LABEL_RIGHT_CLICK 
|| 
4675              type 
== wxEVT_GRID_LABEL_RIGHT_DCLICK 
) 
4677        wxPoint pos 
= mouseEv
.GetPosition(); 
4679        if ( mouseEv
.GetEventObject() == GetGridRowLabelWindow() ) 
4680            pos
.y 
+= GetColLabelSize(); 
4681        if ( mouseEv
.GetEventObject() == GetGridColLabelWindow() ) 
4682            pos
.x 
+= GetRowLabelSize(); 
4684        wxGridEvent 
gridEvt( GetId(), 
4692        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
4693        vetoed 
= !gridEvt
.IsAllowed(); 
4697        wxGridEvent 
gridEvt( GetId(), 
4701                mouseEv
.GetX() + GetRowLabelSize(), 
4702                mouseEv
.GetY() + GetColLabelSize(), 
4706        if ( type 
== wxEVT_GRID_CELL_BEGIN_DRAG 
) 
4708            // by default the dragging is not supported, the user code must 
4709            // explicitly allow the event for it to take place 
4713        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
4714        vetoed 
= !gridEvt
.IsAllowed(); 
4717    // A Veto'd event may not be `claimed' so test this first 
4721    return claimed 
? 1 : 0; 
4724 // Generate a grid event of specified type, return value same as above 
4727 wxGrid::SendEvent(const wxEventType type
, int row
, int col
, const wxString
& s
) 
4729     wxGridEvent 
gridEvt( GetId(), type
, this, row
, col 
); 
4730     gridEvt
.SetString(s
); 
4732     const bool claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
4734     // A Veto'd event may not be `claimed' so test this first 
4735     if ( !gridEvt
.IsAllowed() ) 
4738     return claimed 
? 1 : 0; 
4741 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4743     // needed to prevent zillions of paint events on MSW 
4747 void wxGrid::Refresh(bool eraseb
, const wxRect
* rect
) 
4749     // Don't do anything if between Begin/EndBatch... 
4750     // EndBatch() will do all this on the last nested one anyway. 
4751     if ( m_created 
&& !GetBatchCount() ) 
4753         // Refresh to get correct scrolled position: 
4754         wxScrolledWindow::Refresh(eraseb
, rect
); 
4758             int rect_x
, rect_y
, rectWidth
, rectHeight
; 
4759             int width_label
, width_cell
, height_label
, height_cell
; 
4762             // Copy rectangle can get scroll offsets.. 
4763             rect_x 
= rect
->GetX(); 
4764             rect_y 
= rect
->GetY(); 
4765             rectWidth 
= rect
->GetWidth(); 
4766             rectHeight 
= rect
->GetHeight(); 
4768             width_label 
= m_rowLabelWidth 
- rect_x
; 
4769             if (width_label 
> rectWidth
) 
4770                 width_label 
= rectWidth
; 
4772             height_label 
= m_colLabelHeight 
- rect_y
; 
4773             if (height_label 
> rectHeight
) 
4774                 height_label 
= rectHeight
; 
4776             if (rect_x 
> m_rowLabelWidth
) 
4778                 x 
= rect_x 
- m_rowLabelWidth
; 
4779                 width_cell 
= rectWidth
; 
4784                 width_cell 
= rectWidth 
- (m_rowLabelWidth 
- rect_x
); 
4787             if (rect_y 
> m_colLabelHeight
) 
4789                 y 
= rect_y 
- m_colLabelHeight
; 
4790                 height_cell 
= rectHeight
; 
4795                 height_cell 
= rectHeight 
- (m_colLabelHeight 
- rect_y
); 
4798             // Paint corner label part intersecting rect. 
4799             if ( width_label 
> 0 && height_label 
> 0 ) 
4801                 wxRect 
anotherrect(rect_x
, rect_y
, width_label
, height_label
); 
4802                 m_cornerLabelWin
->Refresh(eraseb
, &anotherrect
); 
4805             // Paint col labels part intersecting rect. 
4806             if ( width_cell 
> 0 && height_label 
> 0 ) 
4808                 wxRect 
anotherrect(x
, rect_y
, width_cell
, height_label
); 
4809                 m_colWindow
->Refresh(eraseb
, &anotherrect
); 
4812             // Paint row labels part intersecting rect. 
4813             if ( width_label 
> 0 && height_cell 
> 0 ) 
4815                 wxRect 
anotherrect(rect_x
, y
, width_label
, height_cell
); 
4816                 m_rowLabelWin
->Refresh(eraseb
, &anotherrect
); 
4819             // Paint cell area part intersecting rect. 
4820             if ( width_cell 
> 0 && height_cell 
> 0 ) 
4822                 wxRect 
anotherrect(x
, y
, width_cell
, height_cell
); 
4823                 m_gridWin
->Refresh(eraseb
, &anotherrect
); 
4828             m_cornerLabelWin
->Refresh(eraseb
, NULL
); 
4829             m_colWindow
->Refresh(eraseb
, NULL
); 
4830             m_rowLabelWin
->Refresh(eraseb
, NULL
); 
4831             m_gridWin
->Refresh(eraseb
, NULL
); 
4836 void wxGrid::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
4838     if (m_targetWindow 
!= this) // check whether initialisation has been done 
4840         // reposition our children windows 
4845 void wxGrid::OnKeyDown( wxKeyEvent
& event 
) 
4847     if ( m_inOnKeyDown 
) 
4849         // shouldn't be here - we are going round in circles... 
4851         wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); 
4854     m_inOnKeyDown 
= true; 
4856     // propagate the event up and see if it gets processed 
4857     wxWindow 
*parent 
= GetParent(); 
4858     wxKeyEvent 
keyEvt( event 
); 
4859     keyEvt
.SetEventObject( parent 
); 
4861     if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt 
) ) 
4863         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
4865             if (event
.GetKeyCode() == WXK_RIGHT
) 
4866                 event
.m_keyCode 
= WXK_LEFT
; 
4867             else if (event
.GetKeyCode() == WXK_LEFT
) 
4868                 event
.m_keyCode 
= WXK_RIGHT
; 
4871         // try local handlers 
4872         switch ( event
.GetKeyCode() ) 
4875                 if ( event
.ControlDown() ) 
4876                     MoveCursorUpBlock( event
.ShiftDown() ); 
4878                     MoveCursorUp( event
.ShiftDown() ); 
4882                 if ( event
.ControlDown() ) 
4883                     MoveCursorDownBlock( event
.ShiftDown() ); 
4885                     MoveCursorDown( event
.ShiftDown() ); 
4889                 if ( event
.ControlDown() ) 
4890                     MoveCursorLeftBlock( event
.ShiftDown() ); 
4892                     MoveCursorLeft( event
.ShiftDown() ); 
4896                 if ( event
.ControlDown() ) 
4897                     MoveCursorRightBlock( event
.ShiftDown() ); 
4899                     MoveCursorRight( event
.ShiftDown() ); 
4903             case WXK_NUMPAD_ENTER
: 
4904                 if ( event
.ControlDown() ) 
4906                     event
.Skip();  // to let the edit control have the return 
4910                     if ( GetGridCursorRow() < GetNumberRows()-1 ) 
4912                         MoveCursorDown( event
.ShiftDown() ); 
4916                         // at the bottom of a column 
4917                         DisableCellEditControl(); 
4927                 if (event
.ShiftDown()) 
4929                     if ( GetGridCursorCol() > 0 ) 
4931                         MoveCursorLeft( false ); 
4936                         DisableCellEditControl(); 
4941                     if ( GetGridCursorCol() < GetNumberCols() - 1 ) 
4943                         MoveCursorRight( false ); 
4948                         DisableCellEditControl(); 
4954                 GoToCell(event
.ControlDown() ? 0 
4955                                              : m_currentCellCoords
.GetRow(), 
4960                 GoToCell(event
.ControlDown() ? m_numRows 
- 1 
4961                                              : m_currentCellCoords
.GetRow(), 
4974                 // Ctrl-Space selects the current column, Shift-Space -- the 
4975                 // current row and Ctrl-Shift-Space -- everything 
4976                 switch ( m_selection 
? event
.GetModifiers() : wxMOD_NONE 
) 
4979                         m_selection
->SelectCol(m_currentCellCoords
.GetCol()); 
4983                         m_selection
->SelectRow(m_currentCellCoords
.GetRow()); 
4986                     case wxMOD_CONTROL 
| wxMOD_SHIFT
: 
4987                         m_selection
->SelectBlock(0, 0, 
4988                                                  m_numRows 
- 1, m_numCols 
- 1); 
4992                         if ( !IsEditable() ) 
4994                             MoveCursorRight(false); 
4997                         //else: fall through 
5010     m_inOnKeyDown 
= false; 
5013 void wxGrid::OnKeyUp( wxKeyEvent
& event 
) 
5015     // try local handlers 
5017     if ( event
.GetKeyCode() == WXK_SHIFT 
) 
5019         if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
5020              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
5024                 m_selection
->SelectBlock( 
5025                     m_selectedBlockTopLeft
, 
5026                     m_selectedBlockBottomRight
, 
5031         m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
5032         m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
5033         m_selectedBlockCorner 
= wxGridNoCellCoords
; 
5037 void wxGrid::OnChar( wxKeyEvent
& event 
) 
5039     // is it possible to edit the current cell at all? 
5040     if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) 
5042         // yes, now check whether the cells editor accepts the key 
5043         int row 
= m_currentCellCoords
.GetRow(); 
5044         int col 
= m_currentCellCoords
.GetCol(); 
5045         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
5046         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
5048         // <F2> is special and will always start editing, for 
5049         // other keys - ask the editor itself 
5050         if ( (event
.GetKeyCode() == WXK_F2 
&& !event
.HasModifiers()) 
5051              || editor
->IsAcceptedKey(event
) ) 
5053             // ensure cell is visble 
5054             MakeCellVisible(row
, col
); 
5055             EnableCellEditControl(); 
5057             // a problem can arise if the cell is not completely 
5058             // visible (even after calling MakeCellVisible the 
5059             // control is not created and calling StartingKey will 
5061             if ( event
.GetKeyCode() != WXK_F2 
&& editor
->IsCreated() && m_cellEditCtrlEnabled 
) 
5062                 editor
->StartingKey(event
); 
5078 void wxGrid::OnEraseBackground(wxEraseEvent
&) 
5082 bool wxGrid::SetCurrentCell( const wxGridCellCoords
& coords 
) 
5084     if ( SendEvent(wxEVT_GRID_SELECT_CELL
, coords
) == -1 ) 
5086         // the event has been vetoed - do nothing 
5090 #if !defined(__WXMAC__) 
5091     wxClientDC 
dc( m_gridWin 
); 
5095     if ( m_currentCellCoords 
!= wxGridNoCellCoords 
) 
5097         DisableCellEditControl(); 
5099         if ( IsVisible( m_currentCellCoords
, false ) ) 
5102             r 
= BlockToDeviceRect( m_currentCellCoords
, m_currentCellCoords 
); 
5103             if ( !m_gridLinesEnabled 
) 
5111             wxGridCellCoordsArray cells 
= CalcCellsExposed( r 
); 
5113             // Otherwise refresh redraws the highlight! 
5114             m_currentCellCoords 
= coords
; 
5116 #if defined(__WXMAC__) 
5117             m_gridWin
->Refresh(true /*, & r */); 
5119             DrawGridCellArea( dc
, cells 
); 
5120             DrawAllGridLines( dc
, r 
); 
5125     m_currentCellCoords 
= coords
; 
5127     wxGridCellAttr 
*attr 
= GetCellAttr( coords 
); 
5128 #if !defined(__WXMAC__) 
5129     DrawCellHighlight( dc
, attr 
); 
5137 wxGrid::UpdateBlockBeingSelected(int topRow
, int leftCol
, 
5138                                  int bottomRow
, int rightCol
) 
5140     MakeCellVisible(m_selectedBlockCorner
); 
5141     m_selectedBlockCorner 
= wxGridCellCoords(bottomRow
, rightCol
); 
5145         switch ( m_selection
->GetSelectionMode() ) 
5148                 wxFAIL_MSG( "unknown selection mode" ); 
5151             case wxGridSelectCells
: 
5152                 // arbitrary blocks selection allowed so just use the cell 
5153                 // coordinates as is 
5156             case wxGridSelectRows
: 
5157                 // only full rows selection allowd, ensure that we do select 
5160                 rightCol 
= GetNumberCols() - 1; 
5163             case wxGridSelectColumns
: 
5164                 // same as above but for columns 
5166                 bottomRow 
= GetNumberRows() - 1; 
5169             case wxGridSelectRowsOrColumns
: 
5170                 // in this mode we can select only full rows or full columns so 
5171                 // it doesn't make sense to select blocks at all (and we can't 
5172                 // extend the block because there is no preferred direction, we 
5173                 // could only extend it to cover the entire grid but this is 
5179     EnsureFirstLessThanSecond(topRow
, bottomRow
); 
5180     EnsureFirstLessThanSecond(leftCol
, rightCol
); 
5182     wxGridCellCoords updateTopLeft 
= wxGridCellCoords(topRow
, leftCol
), 
5183                      updateBottomRight 
= wxGridCellCoords(bottomRow
, rightCol
); 
5185     // First the case that we selected a completely new area 
5186     if ( m_selectedBlockTopLeft 
== wxGridNoCellCoords 
|| 
5187          m_selectedBlockBottomRight 
== wxGridNoCellCoords 
) 
5190         rect 
= BlockToDeviceRect( wxGridCellCoords ( topRow
, leftCol 
), 
5191                                   wxGridCellCoords ( bottomRow
, rightCol 
) ); 
5192         m_gridWin
->Refresh( false, &rect 
); 
5195     // Now handle changing an existing selection area. 
5196     else if ( m_selectedBlockTopLeft 
!= updateTopLeft 
|| 
5197               m_selectedBlockBottomRight 
!= updateBottomRight 
) 
5199         // Compute two optimal update rectangles: 
5200         // Either one rectangle is a real subset of the 
5201         // other, or they are (almost) disjoint! 
5203         bool    need_refresh
[4]; 
5207         need_refresh
[3] = false; 
5210         // Store intermediate values 
5211         wxCoord oldLeft 
= m_selectedBlockTopLeft
.GetCol(); 
5212         wxCoord oldTop 
= m_selectedBlockTopLeft
.GetRow(); 
5213         wxCoord oldRight 
= m_selectedBlockBottomRight
.GetCol(); 
5214         wxCoord oldBottom 
= m_selectedBlockBottomRight
.GetRow(); 
5216         // Determine the outer/inner coordinates. 
5217         EnsureFirstLessThanSecond(oldLeft
, leftCol
); 
5218         EnsureFirstLessThanSecond(oldTop
, topRow
); 
5219         EnsureFirstLessThanSecond(rightCol
, oldRight
); 
5220         EnsureFirstLessThanSecond(bottomRow
, oldBottom
); 
5222         // Now, either the stuff marked old is the outer 
5223         // rectangle or we don't have a situation where one 
5224         // is contained in the other. 
5226         if ( oldLeft 
< leftCol 
) 
5228             // Refresh the newly selected or deselected 
5229             // area to the left of the old or new selection. 
5230             need_refresh
[0] = true; 
5231             rect
[0] = BlockToDeviceRect( 
5232                 wxGridCellCoords( oldTop
,  oldLeft 
), 
5233                 wxGridCellCoords( oldBottom
, leftCol 
- 1 ) ); 
5236         if ( oldTop 
< topRow 
) 
5238             // Refresh the newly selected or deselected 
5239             // area above the old or new selection. 
5240             need_refresh
[1] = true; 
5241             rect
[1] = BlockToDeviceRect( 
5242                 wxGridCellCoords( oldTop
, leftCol 
), 
5243                 wxGridCellCoords( topRow 
- 1, rightCol 
) ); 
5246         if ( oldRight 
> rightCol 
) 
5248             // Refresh the newly selected or deselected 
5249             // area to the right of the old or new selection. 
5250             need_refresh
[2] = true; 
5251             rect
[2] = BlockToDeviceRect( 
5252                 wxGridCellCoords( oldTop
, rightCol 
+ 1 ), 
5253                 wxGridCellCoords( oldBottom
, oldRight 
) ); 
5256         if ( oldBottom 
> bottomRow 
) 
5258             // Refresh the newly selected or deselected 
5259             // area below the old or new selection. 
5260             need_refresh
[3] = true; 
5261             rect
[3] = BlockToDeviceRect( 
5262                 wxGridCellCoords( bottomRow 
+ 1, leftCol 
), 
5263                 wxGridCellCoords( oldBottom
, rightCol 
) ); 
5266         // various Refresh() calls 
5267         for (i 
= 0; i 
< 4; i
++ ) 
5268             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
5269                 m_gridWin
->Refresh( false, &(rect
[i
]) ); 
5273     m_selectedBlockTopLeft 
= updateTopLeft
; 
5274     m_selectedBlockBottomRight 
= updateBottomRight
; 
5278 // ------ functions to get/send data (see also public functions) 
5281 bool wxGrid::GetModelValues() 
5283     // Hide the editor, so it won't hide a changed value. 
5284     HideCellEditControl(); 
5288         // all we need to do is repaint the grid 
5290         m_gridWin
->Refresh(); 
5297 bool wxGrid::SetModelValues() 
5301     // Disable the editor, so it won't hide a changed value. 
5302     // Do we also want to save the current value of the editor first? 
5304     DisableCellEditControl(); 
5308         for ( row 
= 0; row 
< m_numRows
; row
++ ) 
5310             for ( col 
= 0; col 
< m_numCols
; col
++ ) 
5312                 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) ); 
5322 // Note - this function only draws cells that are in the list of 
5323 // exposed cells (usually set from the update region by 
5324 // CalcExposedCells) 
5326 void wxGrid::DrawGridCellArea( wxDC
& dc
, const wxGridCellCoordsArray
& cells 
) 
5328     if ( !m_numRows 
|| !m_numCols 
) 
5331     int i
, numCells 
= cells
.GetCount(); 
5332     int row
, col
, cell_rows
, cell_cols
; 
5333     wxGridCellCoordsArray redrawCells
; 
5335     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
5337         row 
= cells
[i
].GetRow(); 
5338         col 
= cells
[i
].GetCol(); 
5339         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
5341         // If this cell is part of a multicell block, find owner for repaint 
5342         if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
5344             wxGridCellCoords 
cell( row 
+ cell_rows
, col 
+ cell_cols 
); 
5345             bool marked 
= false; 
5346             for ( int j 
= 0; j 
< numCells
; j
++ ) 
5348                 if ( cell 
== cells
[j
] ) 
5357                 int count 
= redrawCells
.GetCount(); 
5358                 for (int j 
= 0; j 
< count
; j
++) 
5360                     if ( cell 
== redrawCells
[j
] ) 
5368                     redrawCells
.Add( cell 
); 
5371             // don't bother drawing this cell 
5375         // If this cell is empty, find cell to left that might want to overflow 
5376         if (m_table 
&& m_table
->IsEmptyCell(row
, col
)) 
5378             for ( int l 
= 0; l 
< cell_rows
; l
++ ) 
5380                 // find a cell in this row to leave already marked for repaint 
5382                 for (int k 
= 0; k 
< int(redrawCells
.GetCount()); k
++) 
5383                     if ((redrawCells
[k
].GetCol() < left
) && 
5384                         (redrawCells
[k
].GetRow() == row
)) 
5386                         left 
= redrawCells
[k
].GetCol(); 
5390                     left 
= 0; // oh well 
5392                 for (int j 
= col 
- 1; j 
>= left
; j
--) 
5394                     if (!m_table
->IsEmptyCell(row 
+ l
, j
)) 
5396                         if (GetCellOverflow(row 
+ l
, j
)) 
5398                             wxGridCellCoords 
cell(row 
+ l
, j
); 
5399                             bool marked 
= false; 
5401                             for (int k 
= 0; k 
< numCells
; k
++) 
5403                                 if ( cell 
== cells
[k
] ) 
5412                                 int count 
= redrawCells
.GetCount(); 
5413                                 for (int k 
= 0; k 
< count
; k
++) 
5415                                     if ( cell 
== redrawCells
[k
] ) 
5422                                     redrawCells
.Add( cell 
); 
5431         DrawCell( dc
, cells
[i
] ); 
5434     numCells 
= redrawCells
.GetCount(); 
5436     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
5438         DrawCell( dc
, redrawCells
[i
] ); 
5442 void wxGrid::DrawGridSpace( wxDC
& dc 
) 
5445   m_gridWin
->GetClientSize( &cw
, &ch 
); 
5448   CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
5450   int rightCol 
= m_numCols 
> 0 ? GetColRight(GetColAt( m_numCols 
- 1 )) : 0; 
5451   int bottomRow 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
5453   if ( right 
> rightCol 
|| bottom 
> bottomRow 
) 
5456       CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
5458       dc
.SetBrush(GetDefaultCellBackgroundColour()); 
5459       dc
.SetPen( *wxTRANSPARENT_PEN 
); 
5461       if ( right 
> rightCol 
) 
5463           dc
.DrawRectangle( rightCol
, top
, right 
- rightCol
, ch 
); 
5466       if ( bottom 
> bottomRow 
) 
5468           dc
.DrawRectangle( left
, bottomRow
, cw
, bottom 
- bottomRow 
); 
5473 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
5475     int row 
= coords
.GetRow(); 
5476     int col 
= coords
.GetCol(); 
5478     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
5481     // we draw the cell border ourselves 
5482     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
5484     bool isCurrent 
= coords 
== m_currentCellCoords
; 
5486     wxRect rect 
= CellToRect( row
, col 
); 
5488     // if the editor is shown, we should use it and not the renderer 
5489     // Note: However, only if it is really _shown_, i.e. not hidden! 
5490     if ( isCurrent 
&& IsCellEditControlShown() ) 
5492         // NB: this "#if..." is temporary and fixes a problem where the 
5493         // edit control is erased by this code after being rendered. 
5494         // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered 
5495         // implicitly, causing this out-of order render. 
5496 #if !defined(__WXMAC__) 
5497         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
5498         editor
->PaintBackground(rect
, attr
); 
5504         // but all the rest is drawn by the cell renderer and hence may be customized 
5505         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
5506         renderer
->Draw(*this, *attr
, dc
, rect
, row
, col
, IsInSelection(coords
)); 
5513 void wxGrid::DrawCellHighlight( wxDC
& dc
, const wxGridCellAttr 
*attr 
) 
5515     // don't show highlight when the grid doesn't have focus 
5519     int row 
= m_currentCellCoords
.GetRow(); 
5520     int col 
= m_currentCellCoords
.GetCol(); 
5522     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
5525     wxRect rect 
= CellToRect(row
, col
); 
5527     // hmmm... what could we do here to show that the cell is disabled? 
5528     // for now, I just draw a thinner border than for the other ones, but 
5529     // it doesn't look really good 
5531     int penWidth 
= attr
->IsReadOnly() ? m_cellHighlightROPenWidth 
: m_cellHighlightPenWidth
; 
5535         // The center of the drawn line is where the position/width/height of 
5536         // the rectangle is actually at (on wxMSW at least), so the 
5537         // size of the rectangle is reduced to compensate for the thickness of 
5538         // the line. If this is too strange on non-wxMSW platforms then 
5539         // please #ifdef this appropriately. 
5540         rect
.x 
+= penWidth 
/ 2; 
5541         rect
.y 
+= penWidth 
/ 2; 
5542         rect
.width 
-= penWidth 
- 1; 
5543         rect
.height 
-= penWidth 
- 1; 
5545         // Now draw the rectangle 
5546         // use the cellHighlightColour if the cell is inside a selection, this 
5547         // will ensure the cell is always visible. 
5548         dc
.SetPen(wxPen(IsInSelection(row
,col
) ? m_selectionForeground
 
5549                                                : m_cellHighlightColour
, 
5551         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
5552         dc
.DrawRectangle(rect
); 
5556 wxPen 
wxGrid::GetDefaultGridLinePen() 
5558     return wxPen(GetGridLineColour()); 
5561 wxPen 
wxGrid::GetRowGridLinePen(int WXUNUSED(row
)) 
5563     return GetDefaultGridLinePen(); 
5566 wxPen 
wxGrid::GetColGridLinePen(int WXUNUSED(col
)) 
5568     return GetDefaultGridLinePen(); 
5571 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
5573     int row 
= coords
.GetRow(); 
5574     int col 
= coords
.GetCol(); 
5575     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
5579     wxRect rect 
= CellToRect( row
, col 
); 
5581     // right hand border 
5582     dc
.SetPen( GetColGridLinePen(col
) ); 
5583     dc
.DrawLine( rect
.x 
+ rect
.width
, rect
.y
, 
5584                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height 
+ 1 ); 
5587     dc
.SetPen( GetRowGridLinePen(row
) ); 
5588     dc
.DrawLine( rect
.x
, rect
.y 
+ rect
.height
, 
5589                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height
); 
5592 void wxGrid::DrawHighlight(wxDC
& dc
, const wxGridCellCoordsArray
& cells
) 
5594     // This if block was previously in wxGrid::OnPaint but that doesn't 
5595     // seem to get called under wxGTK - MB 
5597     if ( m_currentCellCoords 
== wxGridNoCellCoords 
&& 
5598          m_numRows 
&& m_numCols 
) 
5600         m_currentCellCoords
.Set(0, 0); 
5603     if ( IsCellEditControlShown() ) 
5605         // don't show highlight when the edit control is shown 
5609     // if the active cell was repainted, repaint its highlight too because it 
5610     // might have been damaged by the grid lines 
5611     size_t count 
= cells
.GetCount(); 
5612     for ( size_t n 
= 0; n 
< count
; n
++ ) 
5614         wxGridCellCoords cell 
= cells
[n
]; 
5616         // If we are using attributes, then we may have just exposed another 
5617         // cell in a partially-visible merged cluster of cells. If the "anchor" 
5618         // (upper left) cell of this merged cluster is the cell indicated by 
5619         // m_currentCellCoords, then we need to refresh the cell highlight even 
5620         // though the "anchor" itself is not part of our update segment. 
5621         if ( CanHaveAttributes() ) 
5625             GetCellSize(cell
.GetRow(), cell
.GetCol(), &rows
, &cols
); 
5628                 cell
.SetRow(cell
.GetRow() + rows
); 
5631                 cell
.SetCol(cell
.GetCol() + cols
); 
5634         if ( cell 
== m_currentCellCoords 
) 
5636             wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
5637             DrawCellHighlight(dc
, attr
); 
5645 // Used by wxGrid::Render() to draw the grid lines only for the cells in the 
5648 wxGrid::DrawRangeGridLines(wxDC
& dc
, 
5649                            const wxRegion
& reg
, 
5650                            const wxGridCellCoords
& topLeft
, 
5651                            const wxGridCellCoords
& bottomRight
) 
5653     if ( !m_gridLinesEnabled 
) 
5656     int top
, left
, width
, height
; 
5657     reg
.GetBox( left
, top
, width
, height 
); 
5659     // create a clipping region 
5660     wxRegion 
clippedcells( dc
.LogicalToDeviceX( left 
), 
5661                            dc
.LogicalToDeviceY( top 
), 
5662                            dc
.LogicalToDeviceXRel( width 
), 
5663                            dc
.LogicalToDeviceYRel( height 
) ); 
5665     // subtract multi cell span area from clipping region for lines 
5667     for ( int row 
= topLeft
.GetRow(); row 
<= bottomRight
.GetRow(); row
++ ) 
5669         for ( int col 
= topLeft
.GetCol(); col 
<= bottomRight
.GetCol(); col
++ ) 
5671             int cell_rows
, cell_cols
; 
5672             GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
5673             if ( cell_rows 
> 1 || cell_cols 
> 1 ) // multi cell 
5675                 rect 
= CellToRect( row
, col 
); 
5676                 // cater for scaling 
5677                 // device origin already set in ::Render() for x, y 
5678                 rect
.x 
= dc
.LogicalToDeviceX( rect
.x 
); 
5679                 rect
.y 
= dc
.LogicalToDeviceY( rect
.y 
); 
5680                 rect
.width 
= dc
.LogicalToDeviceXRel( rect
.width 
); 
5681                 rect
.height 
= dc
.LogicalToDeviceYRel( rect
.height 
) - 1; 
5682                 clippedcells
.Subtract( rect 
); 
5684             else if ( cell_rows 
< 0 || cell_cols 
< 0 ) // part of multicell 
5686                 rect 
= CellToRect( row 
+ cell_rows
, col 
+ cell_cols 
); 
5687                 rect
.x 
= dc
.LogicalToDeviceX( rect
.x 
); 
5688                 rect
.y 
= dc
.LogicalToDeviceY( rect
.y 
); 
5689                 rect
.width 
= dc
.LogicalToDeviceXRel( rect
.width 
); 
5690                 rect
.height 
= dc
.LogicalToDeviceYRel( rect
.height 
) - 1; 
5691                 clippedcells
.Subtract( rect 
); 
5696     dc
.SetDeviceClippingRegion( clippedcells 
); 
5699                     top
, left
, top 
+ height
, left 
+ width
, 
5700                     topLeft
.GetRow(), topLeft
.GetCol(), 
5701                     bottomRight
.GetRow(), bottomRight
.GetCol()); 
5703     dc
.DestroyClippingRegion(); 
5706 // This is used to redraw all grid lines e.g. when the grid line colour 
5709 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion 
& WXUNUSED(reg
) ) 
5711     if ( !m_gridLinesEnabled 
) 
5714     int top
, bottom
, left
, right
; 
5717     m_gridWin
->GetClientSize(&cw
, &ch
); 
5718     CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
5719     CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
5721     // avoid drawing grid lines past the last row and col 
5722     if ( m_gridLinesClipHorz 
) 
5727         const int lastColRight 
= GetColRight(GetColAt(m_numCols 
- 1)); 
5728         if ( right 
> lastColRight 
) 
5729             right 
= lastColRight
; 
5732     if ( m_gridLinesClipVert 
) 
5737         const int lastRowBottom 
= GetRowBottom(m_numRows 
- 1); 
5738         if ( bottom 
> lastRowBottom 
) 
5739             bottom 
= lastRowBottom
; 
5742     // no gridlines inside multicells, clip them out 
5743     int leftCol 
= GetColPos( internalXToCol(left
) ); 
5744     int topRow 
= internalYToRow(top
); 
5745     int rightCol 
= GetColPos( internalXToCol(right
) ); 
5746     int bottomRow 
= internalYToRow(bottom
); 
5748     wxRegion 
clippedcells(0, 0, cw
, ch
); 
5750     int cell_rows
, cell_cols
; 
5753     for ( int j 
= topRow
; j 
<= bottomRow
; j
++ ) 
5755         for ( int colPos 
= leftCol
; colPos 
<= rightCol
; colPos
++ ) 
5757             int i 
= GetColAt( colPos 
); 
5759             GetCellSize( j
, i
, &cell_rows
, &cell_cols 
); 
5760             if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
5762                 rect 
= CellToRect(j
,i
); 
5763                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
5764                 clippedcells
.Subtract(rect
); 
5766             else if ((cell_rows 
< 0) || (cell_cols 
< 0)) 
5768                 rect 
= CellToRect(j 
+ cell_rows
, i 
+ cell_cols
); 
5769                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
5770                 clippedcells
.Subtract(rect
); 
5775     dc
.SetDeviceClippingRegion( clippedcells 
); 
5778                     top
, left
, bottom
, right
, 
5779                     topRow
, leftCol
, m_numRows
, m_numCols
); 
5781     dc
.DestroyClippingRegion(); 
5785 wxGrid::DoDrawGridLines(wxDC
& dc
, 
5787                         int bottom
, int right
, 
5788                         int topRow
, int leftCol
, 
5789                         int bottomRow
, int rightCol
) 
5791     // horizontal grid lines 
5792     for ( int i 
= topRow
; i 
< bottomRow
; i
++ ) 
5794         int bot 
= GetRowBottom(i
) - 1; 
5801             dc
.SetPen( GetRowGridLinePen(i
) ); 
5802             dc
.DrawLine( left
, bot
, right
, bot 
); 
5806     // vertical grid lines 
5807     for ( int colPos 
= leftCol
; colPos 
< rightCol
; colPos
++ ) 
5809         int i 
= GetColAt( colPos 
); 
5811         int colRight 
= GetColRight(i
); 
5813         if (GetLayoutDirection() != wxLayout_RightToLeft
) 
5817         if ( colRight 
> right 
) 
5820         if ( colRight 
>= left 
) 
5822             dc
.SetPen( GetColGridLinePen(i
) ); 
5823             dc
.DrawLine( colRight
, top
, colRight
, bottom 
); 
5828 void wxGrid::DrawRowLabels( wxDC
& dc
, const wxArrayInt
& rows
) 
5833     const size_t numLabels 
= rows
.GetCount(); 
5834     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
5836         DrawRowLabel( dc
, rows
[i
] ); 
5840 void wxGrid::DrawRowLabel( wxDC
& dc
, int row 
) 
5842     if ( GetRowHeight(row
) <= 0 || m_rowLabelWidth 
<= 0 ) 
5845     wxGridCellAttrProvider 
* const 
5846         attrProvider 
= m_table 
? m_table
->GetAttrProvider() : NULL
; 
5848     // notice that an explicit static_cast is needed to avoid a compilation 
5849     // error with VC7.1 which, for some reason, tries to instantiate (abstract) 
5850     // wxGridRowHeaderRenderer class without it 
5851     const wxGridRowHeaderRenderer
& 
5852         rend 
= attrProvider 
? attrProvider
->GetRowHeaderRenderer(row
) 
5853                             : static_cast<const wxGridRowHeaderRenderer
&> 
5854                                 (gs_defaultHeaderRenderers
.rowRenderer
); 
5856     wxRect 
rect(0, GetRowTop(row
), m_rowLabelWidth
, GetRowHeight(row
)); 
5857     rend
.DrawBorder(*this, dc
, rect
); 
5860     GetRowLabelAlignment(&hAlign
, &vAlign
); 
5862     rend
.DrawLabel(*this, dc
, GetRowLabelValue(row
), 
5863                    rect
, hAlign
, vAlign
, wxHORIZONTAL
); 
5866 void wxGrid::UseNativeColHeader(bool native
) 
5868     if ( native 
== m_useNativeHeader 
) 
5872     m_useNativeHeader 
= native
; 
5874     CreateColumnWindow(); 
5876     if ( m_useNativeHeader 
) 
5877         GetGridColHeader()->SetColumnCount(m_numCols
); 
5881 void wxGrid::SetUseNativeColLabels( bool native 
) 
5883     wxASSERT_MSG( !m_useNativeHeader
, 
5884                   "doesn't make sense when using native header" ); 
5886     m_nativeColumnLabels 
= native
; 
5889         int height 
= wxRendererNative::Get().GetHeaderButtonHeight( this ); 
5890         SetColLabelSize( height 
); 
5893     GetColLabelWindow()->Refresh(); 
5894     m_cornerLabelWin
->Refresh(); 
5897 void wxGrid::DrawColLabels( wxDC
& dc
,const wxArrayInt
& cols 
) 
5902     const size_t numLabels 
= cols
.GetCount(); 
5903     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
5905         DrawColLabel( dc
, cols
[i
] ); 
5909 void wxGrid::DrawCornerLabel(wxDC
& dc
) 
5911     wxRect 
rect(wxSize(m_rowLabelWidth
, m_colLabelHeight
)); 
5913     if ( m_nativeColumnLabels 
) 
5917         wxRendererNative::Get().DrawHeaderButton(m_cornerLabelWin
, dc
, rect
, 0); 
5924         wxGridCellAttrProvider 
* const 
5925             attrProvider 
= m_table 
? m_table
->GetAttrProvider() : NULL
; 
5926         const wxGridCornerHeaderRenderer
& 
5927             rend 
= attrProvider 
? attrProvider
->GetCornerRenderer() 
5928                                 : static_cast<wxGridCornerHeaderRenderer
&> 
5929                                     (gs_defaultHeaderRenderers
.cornerRenderer
); 
5931         rend
.DrawBorder(*this, dc
, rect
); 
5935 void wxGrid::DrawColLabel(wxDC
& dc
, int col
) 
5937     if ( GetColWidth(col
) <= 0 || m_colLabelHeight 
<= 0 ) 
5940     int colLeft 
= GetColLeft(col
); 
5942     wxRect 
rect(colLeft
, 0, GetColWidth(col
), m_colLabelHeight
); 
5943     wxGridCellAttrProvider 
* const 
5944         attrProvider 
= m_table 
? m_table
->GetAttrProvider() : NULL
; 
5945     const wxGridColumnHeaderRenderer
& 
5946         rend 
= attrProvider 
? attrProvider
->GetColumnHeaderRenderer(col
) 
5947                             : static_cast<wxGridColumnHeaderRenderer
&> 
5948                                 (gs_defaultHeaderRenderers
.colRenderer
); 
5950     if ( m_nativeColumnLabels 
) 
5952         wxRendererNative::Get().DrawHeaderButton
 
5954                                     GetColLabelWindow(), 
5959                                         ? IsSortOrderAscending() 
5960                                             ? wxHDR_SORT_ICON_UP
 
5961                                             : wxHDR_SORT_ICON_DOWN
 
5962                                         : wxHDR_SORT_ICON_NONE
 
5968         // It is reported that we need to erase the background to avoid display 
5969         // artefacts, see #12055. 
5970         wxDCBrushChanger 
setBrush(dc
, m_colWindow
->GetBackgroundColour()); 
5971         dc
.DrawRectangle(rect
); 
5973         rend
.DrawBorder(*this, dc
, rect
); 
5977     GetColLabelAlignment(&hAlign
, &vAlign
); 
5978     const int orient 
= GetColLabelTextOrientation(); 
5980     rend
.DrawLabel(*this, dc
, GetColLabelValue(col
), rect
, hAlign
, vAlign
, orient
); 
5983 // TODO: these 2 functions should be replaced with wxDC::DrawLabel() to which 
5984 //       we just have to add textOrientation support 
5985 void wxGrid::DrawTextRectangle( wxDC
& dc
, 
5986                                 const wxString
& value
, 
5990                                 int textOrientation 
) const 
5992     wxArrayString lines
; 
5994     StringToLines( value
, lines 
); 
5996     DrawTextRectangle(dc
, lines
, rect
, horizAlign
, vertAlign
, textOrientation
); 
5999 void wxGrid::DrawTextRectangle(wxDC
& dc
, 
6000                                const wxArrayString
& lines
, 
6004                                int textOrientation
) const 
6006     if ( lines
.empty() ) 
6009     wxDCClipper 
clip(dc
, rect
); 
6014     if ( textOrientation 
== wxHORIZONTAL 
) 
6015         GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight 
); 
6017         GetTextBoxSize( dc
, lines
, &textHeight
, &textWidth 
); 
6021     switch ( vertAlign 
) 
6023         case wxALIGN_BOTTOM
: 
6024             if ( textOrientation 
== wxHORIZONTAL 
) 
6025                 y 
= rect
.y 
+ (rect
.height 
- textHeight 
- 1); 
6027                 x 
= rect
.x 
+ rect
.width 
- textWidth
; 
6030         case wxALIGN_CENTRE
: 
6031             if ( textOrientation 
== wxHORIZONTAL 
) 
6032                 y 
= rect
.y 
+ ((rect
.height 
- textHeight
) / 2); 
6034                 x 
= rect
.x 
+ ((rect
.width 
- textWidth
) / 2); 
6039             if ( textOrientation 
== wxHORIZONTAL 
) 
6046     // Align each line of a multi-line label 
6047     size_t nLines 
= lines
.GetCount(); 
6048     for ( size_t l 
= 0; l 
< nLines
; l
++ ) 
6050         const wxString
& line 
= lines
[l
]; 
6054             *(textOrientation 
== wxHORIZONTAL 
? &y 
: &x
) += dc
.GetCharHeight(); 
6058         wxCoord lineWidth 
= 0, 
6060         dc
.GetTextExtent(line
, &lineWidth
, &lineHeight
); 
6062         switch ( horizAlign 
) 
6065                 if ( textOrientation 
== wxHORIZONTAL 
) 
6066                     x 
= rect
.x 
+ (rect
.width 
- lineWidth 
- 1); 
6068                     y 
= rect
.y 
+ lineWidth 
+ 1; 
6071             case wxALIGN_CENTRE
: 
6072                 if ( textOrientation 
== wxHORIZONTAL 
) 
6073                     x 
= rect
.x 
+ ((rect
.width 
- lineWidth
) / 2); 
6075                     y 
= rect
.y 
+ rect
.height 
- ((rect
.height 
- lineWidth
) / 2); 
6080                 if ( textOrientation 
== wxHORIZONTAL 
) 
6083                     y 
= rect
.y 
+ rect
.height 
- 1; 
6087         if ( textOrientation 
== wxHORIZONTAL 
) 
6089             dc
.DrawText( line
, x
, y 
); 
6094             dc
.DrawRotatedText( line
, x
, y
, 90.0 ); 
6100 // Split multi-line text up into an array of strings. 
6101 // Any existing contents of the string array are preserved. 
6103 // TODO: refactor wxTextFile::Read() and reuse the same code from here 
6104 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines 
) const 
6108     wxString eol 
= wxTextFile::GetEOL( wxTextFileType_Unix 
); 
6109     wxString tVal 
= wxTextFile::Translate( value
, wxTextFileType_Unix 
); 
6111     while ( startPos 
< (int)tVal
.length() ) 
6113         pos 
= tVal
.Mid(startPos
).Find( eol 
); 
6118         else if ( pos 
== 0 ) 
6120             lines
.Add( wxEmptyString 
); 
6124             lines
.Add( tVal
.Mid(startPos
, pos
) ); 
6127         startPos 
+= pos 
+ 1; 
6130     if ( startPos 
< (int)tVal
.length() ) 
6132         lines
.Add( tVal
.Mid( startPos 
) ); 
6136 void wxGrid::GetTextBoxSize( const wxDC
& dc
, 
6137                              const wxArrayString
& lines
, 
6138                              long *width
, long *height 
) const 
6142     wxCoord lineW 
= 0, lineH 
= 0; 
6145     for ( i 
= 0; i 
< lines
.GetCount(); i
++ ) 
6147         dc
.GetTextExtent( lines
[i
], &lineW
, &lineH 
); 
6148         w 
= wxMax( w
, lineW 
); 
6157 // ------ Batch processing. 
6159 void wxGrid::EndBatch() 
6161     if ( m_batchCount 
> 0 ) 
6164         if ( !m_batchCount 
) 
6167             m_rowLabelWin
->Refresh(); 
6168             m_colWindow
->Refresh(); 
6169             m_cornerLabelWin
->Refresh(); 
6170             m_gridWin
->Refresh(); 
6175 // Use this, rather than wxWindow::Refresh(), to force an immediate 
6176 // repainting of the grid. Has no effect if you are already inside a 
6177 // BeginBatch / EndBatch block. 
6179 void wxGrid::ForceRefresh() 
6185 bool wxGrid::Enable(bool enable
) 
6187     if ( !wxScrolledWindow::Enable(enable
) ) 
6190     // redraw in the new state 
6191     m_gridWin
->Refresh(); 
6197 // ------ Edit control functions 
6200 void wxGrid::EnableEditing( bool edit 
) 
6202     if ( edit 
!= m_editable 
) 
6205             EnableCellEditControl(edit
); 
6210 void wxGrid::EnableCellEditControl( bool enable 
) 
6215     if ( enable 
!= m_cellEditCtrlEnabled 
) 
6219             if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN
) == -1 ) 
6222             // this should be checked by the caller! 
6223             wxASSERT_MSG( CanEnableCellControl(), wxT("can't enable editing for this cell!") ); 
6225             // do it before ShowCellEditControl() 
6226             m_cellEditCtrlEnabled 
= enable
; 
6228             ShowCellEditControl(); 
6232             SendEvent(wxEVT_GRID_EDITOR_HIDDEN
); 
6234             HideCellEditControl(); 
6235             SaveEditControlValue(); 
6237             // do it after HideCellEditControl() 
6238             m_cellEditCtrlEnabled 
= enable
; 
6243 bool wxGrid::IsCurrentCellReadOnly() const 
6246         attr 
= const_cast<wxGrid 
*>(this)->GetCellAttr(m_currentCellCoords
); 
6247     bool readonly 
= attr
->IsReadOnly(); 
6253 bool wxGrid::CanEnableCellControl() const 
6255     return m_editable 
&& (m_currentCellCoords 
!= wxGridNoCellCoords
) && 
6256         !IsCurrentCellReadOnly(); 
6259 bool wxGrid::IsCellEditControlEnabled() const 
6261     // the cell edit control might be disable for all cells or just for the 
6262     // current one if it's read only 
6263     return m_cellEditCtrlEnabled 
? !IsCurrentCellReadOnly() : false; 
6266 bool wxGrid::IsCellEditControlShown() const 
6268     bool isShown 
= false; 
6270     if ( m_cellEditCtrlEnabled 
) 
6272         int row 
= m_currentCellCoords
.GetRow(); 
6273         int col 
= m_currentCellCoords
.GetCol(); 
6274         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
6275         wxGridCellEditor
* editor 
= attr
->GetEditor((wxGrid
*) this, row
, col
); 
6280             if ( editor
->IsCreated() ) 
6282                 isShown 
= editor
->GetControl()->IsShown(); 
6292 void wxGrid::ShowCellEditControl() 
6294     if ( IsCellEditControlEnabled() ) 
6296         if ( !IsVisible( m_currentCellCoords
, false ) ) 
6298             m_cellEditCtrlEnabled 
= false; 
6303             wxRect rect 
= CellToRect( m_currentCellCoords 
); 
6304             int row 
= m_currentCellCoords
.GetRow(); 
6305             int col 
= m_currentCellCoords
.GetCol(); 
6307             // if this is part of a multicell, find owner (topleft) 
6308             int cell_rows
, cell_cols
; 
6309             GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
6310             if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
6314                 m_currentCellCoords
.SetRow( row 
); 
6315                 m_currentCellCoords
.SetCol( col 
); 
6318             // erase the highlight and the cell contents because the editor 
6319             // might not cover the entire cell 
6320             wxClientDC 
dc( m_gridWin 
); 
6322             wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
6323             dc
.SetBrush(wxBrush(attr
->GetBackgroundColour())); 
6324             dc
.SetPen(*wxTRANSPARENT_PEN
); 
6325             dc
.DrawRectangle(rect
); 
6327             // convert to scrolled coords 
6328             CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
6334             // cell is shifted by one pixel 
6335             // However, don't allow x or y to become negative 
6336             // since the SetSize() method interprets that as 
6343             wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
6344             if ( !editor
->IsCreated() ) 
6346                 editor
->Create(m_gridWin
, wxID_ANY
, 
6347                                new wxGridCellEditorEvtHandler(this, editor
)); 
6349                 wxGridEditorCreatedEvent 
evt(GetId(), 
6350                                              wxEVT_GRID_EDITOR_CREATED
, 
6354                                              editor
->GetControl()); 
6355                 GetEventHandler()->ProcessEvent(evt
); 
6358             // resize editor to overflow into righthand cells if allowed 
6359             int maxWidth 
= rect
.width
; 
6360             wxString value 
= GetCellValue(row
, col
); 
6361             if ( (value 
!= wxEmptyString
) && (attr
->GetOverflow()) ) 
6364                 GetTextExtent(value
, &maxWidth
, &y
, NULL
, NULL
, &attr
->GetFont()); 
6365                 if (maxWidth 
< rect
.width
) 
6366                     maxWidth 
= rect
.width
; 
6369             int client_right 
= m_gridWin
->GetClientSize().GetWidth(); 
6370             if (rect
.x 
+ maxWidth 
> client_right
) 
6371                 maxWidth 
= client_right 
- rect
.x
; 
6373             if ((maxWidth 
> rect
.width
) && (col 
< m_numCols
) && m_table
) 
6375                 GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
6376                 // may have changed earlier 
6377                 for (int i 
= col 
+ cell_cols
; i 
< m_numCols
; i
++) 
6380                     GetCellSize( row
, i
, &c_rows
, &c_cols 
); 
6382                     // looks weird going over a multicell 
6383                     if (m_table
->IsEmptyCell( row
, i 
) && 
6384                             (rect
.width 
< maxWidth
) && (c_rows 
== 1)) 
6386                         rect
.width 
+= GetColWidth( i 
); 
6392                 if (rect
.GetRight() > client_right
) 
6393                     rect
.SetRight( client_right 
- 1 ); 
6396             editor
->SetCellAttr( attr 
); 
6397             editor
->SetSize( rect 
); 
6399                 editor
->GetControl()->Move( 
6400                     editor
->GetControl()->GetPosition().x 
+ nXMove
, 
6401                     editor
->GetControl()->GetPosition().y 
); 
6402             editor
->Show( true, attr 
); 
6404             // recalc dimensions in case we need to 
6405             // expand the scrolled window to account for editor 
6408             editor
->BeginEdit(row
, col
, this); 
6409             editor
->SetCellAttr(NULL
); 
6417 void wxGrid::HideCellEditControl() 
6419     if ( IsCellEditControlEnabled() ) 
6421         int row 
= m_currentCellCoords
.GetRow(); 
6422         int col 
= m_currentCellCoords
.GetCol(); 
6424         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
6425         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
6426         const bool editorHadFocus 
= editor
->GetControl()->HasFocus(); 
6427         editor
->Show( false ); 
6431         // return the focus to the grid itself if the editor had it 
6433         // note that we must not do this unconditionally to avoid stealing 
6434         // focus from the window which just received it if we are hiding the 
6435         // editor precisely because we lost focus 
6436         if ( editorHadFocus 
) 
6437             m_gridWin
->SetFocus(); 
6439         // refresh whole row to the right 
6440         wxRect 
rect( CellToRect(row
, col
) ); 
6441         CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
6442         rect
.width 
= m_gridWin
->GetClientSize().GetWidth() - rect
.x
; 
6445         // ensure that the pixels under the focus ring get refreshed as well 
6446         rect
.Inflate(10, 10); 
6449         m_gridWin
->Refresh( false, &rect 
); 
6453 void wxGrid::SaveEditControlValue() 
6455     if ( IsCellEditControlEnabled() ) 
6457         int row 
= m_currentCellCoords
.GetRow(); 
6458         int col 
= m_currentCellCoords
.GetCol(); 
6460         wxString oldval 
= GetCellValue(row
, col
); 
6462         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
6463         wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
6466         bool changed 
= editor
->EndEdit(row
, col
, this, oldval
, &newval
); 
6468         if ( changed 
&& SendEvent(wxEVT_GRID_CELL_CHANGING
, newval
) != -1 ) 
6470             editor
->ApplyEdit(row
, col
, this); 
6472             // for compatibility reasons dating back to wx 2.8 when this event 
6473             // was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING 
6474             // didn't exist we allow vetoing this one too 
6475             if ( SendEvent(wxEVT_GRID_CELL_CHANGED
, oldval
) == -1 ) 
6477                 // Event has been vetoed, set the data back. 
6478                 SetCellValue(row
, col
, oldval
); 
6488 // ------ Grid location functions 
6489 //  Note that all of these functions work with the logical coordinates of 
6490 //  grid cells and labels so you will need to convert from device 
6491 //  coordinates for mouse events etc. 
6494 wxGridCellCoords 
wxGrid::XYToCell(int x
, int y
) const 
6496     int row 
= YToRow(y
); 
6497     int col 
= XToCol(x
); 
6499     return row 
== -1 || col 
== -1 ? wxGridNoCellCoords
 
6500                                   : wxGridCellCoords(row
, col
); 
6503 // compute row or column from some (unscrolled) coordinate value, using either 
6504 // m_defaultRowHeight/m_defaultColWidth or binary search on array of 
6505 // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used 
6507 int wxGrid::PosToLinePos(int coord
, 
6509                          const wxGridOperations
& oper
) const 
6511     const int numLines 
= oper
.GetNumberOfLines(this); 
6514         return clipToMinMax 
&& numLines 
> 0 ? 0 : wxNOT_FOUND
; 
6516     const int defaultLineSize 
= oper
.GetDefaultLineSize(this); 
6517     wxCHECK_MSG( defaultLineSize
, -1, "can't have 0 default line size" ); 
6519     int maxPos 
= coord 
/ defaultLineSize
, 
6522     // check for the simplest case: if we have no explicit line sizes 
6523     // configured, then we already know the line this position falls in 
6524     const wxArrayInt
& lineEnds 
= oper
.GetLineEnds(this); 
6525     if ( lineEnds
.empty() ) 
6527         if ( maxPos 
< numLines 
) 
6530         return clipToMinMax 
? numLines 
- 1 : -1; 
6534     // adjust maxPos before starting the binary search 
6535     if ( maxPos 
>= numLines 
) 
6537         maxPos 
= numLines  
- 1; 
6541         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos
)]) 
6544             const int minDist 
= oper
.GetMinimalAcceptableLineSize(this); 
6546                 maxPos 
= coord 
/ minDist
; 
6548                 maxPos 
= numLines 
- 1; 
6551         if ( maxPos 
>= numLines 
) 
6552             maxPos 
= numLines  
- 1; 
6555     // check if the position is beyond the last column 
6556     const int lineAtMaxPos 
= oper
.GetLineAt(this, maxPos
); 
6557     if ( coord 
>= lineEnds
[lineAtMaxPos
] ) 
6558         return clipToMinMax 
? maxPos 
: -1; 
6560     // or before the first one 
6561     const int lineAt0 
= oper
.GetLineAt(this, 0); 
6562     if ( coord 
< lineEnds
[lineAt0
] ) 
6566     // finally do perform the binary search 
6567     while ( minPos 
< maxPos 
) 
6569         wxCHECK_MSG( lineEnds
[oper
.GetLineAt(this, minPos
)] <= coord 
&& 
6570                         coord 
< lineEnds
[oper
.GetLineAt(this, maxPos
)], 
6572                      "wxGrid: internal error in PosToLinePos()" ); 
6574         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos 
- 1)] ) 
6579         const int median 
= minPos 
+ (maxPos 
- minPos 
+ 1) / 2; 
6580         if ( coord 
< lineEnds
[oper
.GetLineAt(this, median
)] ) 
6590 wxGrid::PosToLine(int coord
, 
6592                   const wxGridOperations
& oper
) const 
6594     int pos 
= PosToLinePos(coord
, clipToMinMax
, oper
); 
6596     return pos 
== wxNOT_FOUND 
? wxNOT_FOUND 
: oper
.GetLineAt(this, pos
); 
6599 int wxGrid::YToRow(int y
, bool clipToMinMax
) const 
6601     return PosToLine(y
, clipToMinMax
, wxGridRowOperations()); 
6604 int wxGrid::XToCol(int x
, bool clipToMinMax
) const 
6606     return PosToLine(x
, clipToMinMax
, wxGridColumnOperations()); 
6609 int wxGrid::XToPos(int x
) const 
6611     return PosToLinePos(x
, true /* clip */, wxGridColumnOperations()); 
6614 // return the row number such that the y coord is near the edge of, or -1 if 
6615 // not near an edge. 
6617 // notice that position can only possibly be near an edge if the row/column is 
6618 // large enough to still allow for an "inner" area that is _not_ near the edge 
6619 // (i.e., if the height/width is smaller than WXGRID_LABEL_EDGE_ZONE, pos will 
6620 // _never_ be considered to be near the edge). 
6621 int wxGrid::PosToEdgeOfLine(int pos
, const wxGridOperations
& oper
) const 
6623     const int line 
= oper
.PosToLine(this, pos
, true); 
6625     if ( oper
.GetLineSize(this, line
) > WXGRID_LABEL_EDGE_ZONE 
) 
6627         // We know that we are in this line, test whether we are close enough 
6628         // to start or end border, respectively. 
6629         if ( abs(oper
.GetLineEndPos(this, line
) - pos
) < WXGRID_LABEL_EDGE_ZONE 
) 
6631         else if ( line 
> 0 && 
6632                     pos 
- oper
.GetLineStartPos(this, 
6633                                                line
) < WXGRID_LABEL_EDGE_ZONE 
) 
6635             return oper
.GetLineBefore(this, line
); 
6642 int wxGrid::YToEdgeOfRow(int y
) const 
6644     return PosToEdgeOfLine(y
, wxGridRowOperations()); 
6647 int wxGrid::XToEdgeOfCol(int x
) const 
6649     return PosToEdgeOfLine(x
, wxGridColumnOperations()); 
6652 wxRect 
wxGrid::CellToRect( int row
, int col 
) const 
6654     wxRect 
rect( -1, -1, -1, -1 ); 
6656     if ( row 
>= 0 && row 
< m_numRows 
&& 
6657          col 
>= 0 && col 
< m_numCols 
) 
6659         int i
, cell_rows
, cell_cols
; 
6660         rect
.width 
= rect
.height 
= 0; 
6661         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
6662         // if negative then find multicell owner 
6667         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
6669         rect
.x 
= GetColLeft(col
); 
6670         rect
.y 
= GetRowTop(row
); 
6671         for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
6672             rect
.width 
+= GetColWidth(i
); 
6673         for (i
=row
; i 
< row 
+ cell_rows
; i
++) 
6674             rect
.height 
+= GetRowHeight(i
); 
6676         // if grid lines are enabled, then the area of the cell is a bit smaller 
6677         if (m_gridLinesEnabled
) 
6687 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible 
) const 
6689     // get the cell rectangle in logical coords 
6691     wxRect 
r( CellToRect( row
, col 
) ); 
6693     // convert to device coords 
6695     int left
, top
, right
, bottom
; 
6696     CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
6697     CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
6699     // check against the client area of the grid window 
6701     m_gridWin
->GetClientSize( &cw
, &ch 
); 
6703     if ( wholeCellVisible 
) 
6705         // is the cell wholly visible ? 
6706         return ( left 
>= 0 && right 
<= cw 
&& 
6707                  top 
>= 0 && bottom 
<= ch 
); 
6711         // is the cell partly visible ? 
6713         return ( ((left 
>= 0 && left 
< cw
) || (right 
> 0 && right 
<= cw
)) && 
6714                  ((top 
>= 0 && top 
< ch
) || (bottom 
> 0 && bottom 
<= ch
)) ); 
6718 // make the specified cell location visible by doing a minimal amount 
6721 void wxGrid::MakeCellVisible( int row
, int col 
) 
6724     int xpos 
= -1, ypos 
= -1; 
6726     if ( row 
>= 0 && row 
< m_numRows 
&& 
6727          col 
>= 0 && col 
< m_numCols 
) 
6729         // get the cell rectangle in logical coords 
6730         wxRect 
r( CellToRect( row
, col 
) ); 
6732         // convert to device coords 
6733         int left
, top
, right
, bottom
; 
6734         CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
6735         CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
6738         m_gridWin
->GetClientSize( &cw
, &ch 
); 
6744         else if ( bottom 
> ch 
) 
6746             int h 
= r
.GetHeight(); 
6748             for ( i 
= row 
- 1; i 
>= 0; i
-- ) 
6750                 int rowHeight 
= GetRowHeight(i
); 
6751                 if ( h 
+ rowHeight 
> ch 
) 
6758             // we divide it later by GRID_SCROLL_LINE, make sure that we don't 
6759             // have rounding errors (this is important, because if we do, 
6760             // we might not scroll at all and some cells won't be redrawn) 
6762             // Sometimes GRID_SCROLL_LINE / 2 is not enough, 
6763             // so just add a full scroll unit... 
6764             ypos 
+= m_yScrollPixelsPerLine
; 
6767         // special handling for wide cells - show always left part of the cell! 
6768         // Otherwise, e.g. when stepping from row to row, it would jump between 
6769         // left and right part of the cell on every step! 
6771         if ( left 
< 0 || (right 
- left
) >= cw 
) 
6775         else if ( right 
> cw 
) 
6777             // position the view so that the cell is on the right 
6779             CalcUnscrolledPosition(0, 0, &x0
, &y0
); 
6780             xpos 
= x0 
+ (right 
- cw
); 
6782             // see comment for ypos above 
6783             xpos 
+= m_xScrollPixelsPerLine
; 
6786         if ( xpos 
!= -1 || ypos 
!= -1 ) 
6789                 xpos 
/= m_xScrollPixelsPerLine
; 
6791                 ypos 
/= m_yScrollPixelsPerLine
; 
6792             Scroll( xpos
, ypos 
); 
6799 // ------ Grid cursor movement functions 
6803 wxGrid::DoMoveCursor(bool expandSelection
, 
6804                      const wxGridDirectionOperations
& diroper
) 
6806     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
6809     if ( expandSelection 
) 
6811         wxGridCellCoords coords 
= m_selectedBlockCorner
; 
6812         if ( coords 
== wxGridNoCellCoords 
) 
6813             coords 
= m_currentCellCoords
; 
6815         if ( diroper
.IsAtBoundary(coords
) ) 
6818         diroper
.Advance(coords
); 
6820         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
6822     else // don't expand selection 
6826         if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
6829         wxGridCellCoords coords 
= m_currentCellCoords
; 
6830         diroper
.Advance(coords
); 
6838 bool wxGrid::MoveCursorUp(bool expandSelection
) 
6840     return DoMoveCursor(expandSelection
, 
6841                         wxGridBackwardOperations(this, wxGridRowOperations())); 
6844 bool wxGrid::MoveCursorDown(bool expandSelection
) 
6846     return DoMoveCursor(expandSelection
, 
6847                         wxGridForwardOperations(this, wxGridRowOperations())); 
6850 bool wxGrid::MoveCursorLeft(bool expandSelection
) 
6852     return DoMoveCursor(expandSelection
, 
6853                         wxGridBackwardOperations(this, wxGridColumnOperations())); 
6856 bool wxGrid::MoveCursorRight(bool expandSelection
) 
6858     return DoMoveCursor(expandSelection
, 
6859                         wxGridForwardOperations(this, wxGridColumnOperations())); 
6862 bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations
& diroper
) 
6864     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
6867     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
6870     const int oldRow 
= m_currentCellCoords
.GetRow(); 
6871     int newRow 
= diroper
.MoveByPixelDistance(oldRow
, m_gridWin
->GetClientSize().y
); 
6872     if ( newRow 
== oldRow 
) 
6874         wxGridCellCoords 
coords(m_currentCellCoords
); 
6875         diroper
.Advance(coords
); 
6876         newRow 
= coords
.GetRow(); 
6879     GoToCell(newRow
, m_currentCellCoords
.GetCol()); 
6884 bool wxGrid::MovePageUp() 
6886     return DoMoveCursorByPage( 
6887                 wxGridBackwardOperations(this, wxGridRowOperations())); 
6890 bool wxGrid::MovePageDown() 
6892     return DoMoveCursorByPage( 
6893                 wxGridForwardOperations(this, wxGridRowOperations())); 
6896 // helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper 
6897 // until we find a non-empty cell or reach the grid end 
6899 wxGrid::AdvanceToNextNonEmpty(wxGridCellCoords
& coords
, 
6900                               const wxGridDirectionOperations
& diroper
) 
6902     while ( !diroper
.IsAtBoundary(coords
) ) 
6904         diroper
.Advance(coords
); 
6905         if ( !m_table
->IsEmpty(coords
) ) 
6911 wxGrid::DoMoveCursorByBlock(bool expandSelection
, 
6912                             const wxGridDirectionOperations
& diroper
) 
6914     if ( !m_table 
|| m_currentCellCoords 
== wxGridNoCellCoords 
) 
6917     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
6920     wxGridCellCoords 
coords(m_currentCellCoords
); 
6921     if ( m_table
->IsEmpty(coords
) ) 
6923         // we are in an empty cell: find the next block of non-empty cells 
6924         AdvanceToNextNonEmpty(coords
, diroper
); 
6926     else // current cell is not empty 
6928         diroper
.Advance(coords
); 
6929         if ( m_table
->IsEmpty(coords
) ) 
6931             // we started at the end of a block, find the next one 
6932             AdvanceToNextNonEmpty(coords
, diroper
); 
6934         else // we're in a middle of a block 
6936             // go to the end of it, i.e. find the last cell before the next 
6938             while ( !diroper
.IsAtBoundary(coords
) ) 
6940                 wxGridCellCoords 
coordsNext(coords
); 
6941                 diroper
.Advance(coordsNext
); 
6942                 if ( m_table
->IsEmpty(coordsNext
) ) 
6945                 coords 
= coordsNext
; 
6950     if ( expandSelection 
) 
6952         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
6963 bool wxGrid::MoveCursorUpBlock(bool expandSelection
) 
6965     return DoMoveCursorByBlock( 
6967                 wxGridBackwardOperations(this, wxGridRowOperations()) 
6971 bool wxGrid::MoveCursorDownBlock( bool expandSelection 
) 
6973     return DoMoveCursorByBlock( 
6975                 wxGridForwardOperations(this, wxGridRowOperations()) 
6979 bool wxGrid::MoveCursorLeftBlock( bool expandSelection 
) 
6981     return DoMoveCursorByBlock( 
6983                 wxGridBackwardOperations(this, wxGridColumnOperations()) 
6987 bool wxGrid::MoveCursorRightBlock( bool expandSelection 
) 
6989     return DoMoveCursorByBlock( 
6991                 wxGridForwardOperations(this, wxGridColumnOperations()) 
6996 // ------ Label values and formatting 
6999 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert 
) const 
7002         *horiz 
= m_rowLabelHorizAlign
; 
7004         *vert  
= m_rowLabelVertAlign
; 
7007 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert 
) const 
7010         *horiz 
= m_colLabelHorizAlign
; 
7012         *vert  
= m_colLabelVertAlign
; 
7015 int wxGrid::GetColLabelTextOrientation() const 
7017     return m_colLabelTextOrientation
; 
7020 wxString 
wxGrid::GetRowLabelValue( int row 
) const 
7024         return m_table
->GetRowLabelValue( row 
); 
7034 wxString 
wxGrid::GetColLabelValue( int col 
) const 
7038         return m_table
->GetColLabelValue( col 
); 
7048 void wxGrid::SetRowLabelSize( int width 
) 
7050     wxASSERT( width 
>= 0 || width 
== wxGRID_AUTOSIZE 
); 
7052     if ( width 
== wxGRID_AUTOSIZE 
) 
7054         width 
= CalcColOrRowLabelAreaMinSize(wxGRID_ROW
); 
7057     if ( width 
!= m_rowLabelWidth 
) 
7061             m_rowLabelWin
->Show( false ); 
7062             m_cornerLabelWin
->Show( false ); 
7064         else if ( m_rowLabelWidth 
== 0 ) 
7066             m_rowLabelWin
->Show( true ); 
7067             if ( m_colLabelHeight 
> 0 ) 
7068                 m_cornerLabelWin
->Show( true ); 
7071         m_rowLabelWidth 
= width
; 
7073         wxScrolledWindow::Refresh( true ); 
7077 void wxGrid::SetColLabelSize( int height 
) 
7079     wxASSERT( height 
>=0 || height 
== wxGRID_AUTOSIZE 
); 
7081     if ( height 
== wxGRID_AUTOSIZE 
) 
7083         height 
= CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN
); 
7086     if ( height 
!= m_colLabelHeight 
) 
7090             m_colWindow
->Show( false ); 
7091             m_cornerLabelWin
->Show( false ); 
7093         else if ( m_colLabelHeight 
== 0 ) 
7095             m_colWindow
->Show( true ); 
7096             if ( m_rowLabelWidth 
> 0 ) 
7097                 m_cornerLabelWin
->Show( true ); 
7100         m_colLabelHeight 
= height
; 
7102         wxScrolledWindow::Refresh( true ); 
7106 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour 
) 
7108     if ( m_labelBackgroundColour 
!= colour 
) 
7110         m_labelBackgroundColour 
= colour
; 
7111         m_rowLabelWin
->SetBackgroundColour( colour 
); 
7112         m_colWindow
->SetBackgroundColour( colour 
); 
7113         m_cornerLabelWin
->SetBackgroundColour( colour 
); 
7115         if ( !GetBatchCount() ) 
7117             m_rowLabelWin
->Refresh(); 
7118             m_colWindow
->Refresh(); 
7119             m_cornerLabelWin
->Refresh(); 
7124 void wxGrid::SetLabelTextColour( const wxColour
& colour 
) 
7126     if ( m_labelTextColour 
!= colour 
) 
7128         m_labelTextColour 
= colour
; 
7129         if ( !GetBatchCount() ) 
7131             m_rowLabelWin
->Refresh(); 
7132             m_colWindow
->Refresh(); 
7137 void wxGrid::SetLabelFont( const wxFont
& font 
) 
7140     if ( !GetBatchCount() ) 
7142         m_rowLabelWin
->Refresh(); 
7143         m_colWindow
->Refresh(); 
7147 void wxGrid::SetRowLabelAlignment( int horiz
, int vert 
) 
7149     // allow old (incorrect) defs to be used 
7152         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
7153         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
7154         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
7159         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
7160         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
7161         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
7164     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
7166         m_rowLabelHorizAlign 
= horiz
; 
7169     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
7171         m_rowLabelVertAlign 
= vert
; 
7174     if ( !GetBatchCount() ) 
7176         m_rowLabelWin
->Refresh(); 
7180 void wxGrid::SetColLabelAlignment( int horiz
, int vert 
) 
7182     // allow old (incorrect) defs to be used 
7185         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
7186         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
7187         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
7192         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
7193         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
7194         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
7197     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
7199         m_colLabelHorizAlign 
= horiz
; 
7202     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
7204         m_colLabelVertAlign 
= vert
; 
7207     if ( !GetBatchCount() ) 
7209         m_colWindow
->Refresh(); 
7213 // Note: under MSW, the default column label font must be changed because it 
7214 //       does not support vertical printing 
7216 // Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD); 
7217 //                      pGrid->SetLabelFont(font); 
7218 //                      pGrid->SetColLabelTextOrientation(wxVERTICAL); 
7220 void wxGrid::SetColLabelTextOrientation( int textOrientation 
) 
7222     if ( textOrientation 
== wxHORIZONTAL 
|| textOrientation 
== wxVERTICAL 
) 
7223         m_colLabelTextOrientation 
= textOrientation
; 
7225     if ( !GetBatchCount() ) 
7226         m_colWindow
->Refresh(); 
7229 void wxGrid::SetRowLabelValue( int row
, const wxString
& s 
) 
7233         m_table
->SetRowLabelValue( row
, s 
); 
7234         if ( !GetBatchCount() ) 
7236             wxRect rect 
= CellToRect( row
, 0 ); 
7237             if ( rect
.height 
> 0 ) 
7239                 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
); 
7241                 rect
.width 
= m_rowLabelWidth
; 
7242                 m_rowLabelWin
->Refresh( true, &rect 
); 
7248 void wxGrid::SetColLabelValue( int col
, const wxString
& s 
) 
7252         m_table
->SetColLabelValue( col
, s 
); 
7253         if ( !GetBatchCount() ) 
7255             if ( m_useNativeHeader 
) 
7257                 GetGridColHeader()->UpdateColumn(col
); 
7261                 wxRect rect 
= CellToRect( 0, col 
); 
7262                 if ( rect
.width 
> 0 ) 
7264                     CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
); 
7266                     rect
.height 
= m_colLabelHeight
; 
7267                     GetColLabelWindow()->Refresh( true, &rect 
); 
7274 void wxGrid::SetGridLineColour( const wxColour
& colour 
) 
7276     if ( m_gridLineColour 
!= colour 
) 
7278         m_gridLineColour 
= colour
; 
7280         if ( GridLinesEnabled() ) 
7285 void wxGrid::SetCellHighlightColour( const wxColour
& colour 
) 
7287     if ( m_cellHighlightColour 
!= colour 
) 
7289         m_cellHighlightColour 
= colour
; 
7291         wxClientDC 
dc( m_gridWin 
); 
7293         wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
7294         DrawCellHighlight(dc
, attr
); 
7299 void wxGrid::SetCellHighlightPenWidth(int width
) 
7301     if (m_cellHighlightPenWidth 
!= width
) 
7303         m_cellHighlightPenWidth 
= width
; 
7305         // Just redrawing the cell highlight is not enough since that won't 
7306         // make any visible change if the thickness is getting smaller. 
7307         int row 
= m_currentCellCoords
.GetRow(); 
7308         int col 
= m_currentCellCoords
.GetCol(); 
7309         if ( row 
== -1 || col 
== -1 || GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7312         wxRect rect 
= CellToRect(row
, col
); 
7313         m_gridWin
->Refresh(true, &rect
); 
7317 void wxGrid::SetCellHighlightROPenWidth(int width
) 
7319     if (m_cellHighlightROPenWidth 
!= width
) 
7321         m_cellHighlightROPenWidth 
= width
; 
7323         // Just redrawing the cell highlight is not enough since that won't 
7324         // make any visible change if the thickness is getting smaller. 
7325         int row 
= m_currentCellCoords
.GetRow(); 
7326         int col 
= m_currentCellCoords
.GetCol(); 
7327         if ( row 
== -1 || col 
== -1 || 
7328                 GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7331         wxRect rect 
= CellToRect(row
, col
); 
7332         m_gridWin
->Refresh(true, &rect
); 
7336 void wxGrid::RedrawGridLines() 
7338     // the lines will be redrawn when the window is thawn 
7339     if ( GetBatchCount() ) 
7342     if ( GridLinesEnabled() ) 
7344         wxClientDC 
dc( m_gridWin 
); 
7346         DrawAllGridLines( dc
, wxRegion() ); 
7348     else // remove the grid lines 
7350         m_gridWin
->Refresh(); 
7354 void wxGrid::EnableGridLines( bool enable 
) 
7356     if ( enable 
!= m_gridLinesEnabled 
) 
7358         m_gridLinesEnabled 
= enable
; 
7364 void wxGrid::DoClipGridLines(bool& var
, bool clip
) 
7370         if ( GridLinesEnabled() ) 
7375 int wxGrid::GetDefaultRowSize() const 
7377     return m_defaultRowHeight
; 
7380 int wxGrid::GetRowSize( int row 
) const 
7382     wxCHECK_MSG( row 
>= 0 && row 
< m_numRows
, 0, wxT("invalid row index") ); 
7384     return GetRowHeight(row
); 
7387 int wxGrid::GetDefaultColSize() const 
7389     return m_defaultColWidth
; 
7392 int wxGrid::GetColSize( int col 
) const 
7394     wxCHECK_MSG( col 
>= 0 && col 
< m_numCols
, 0, wxT("invalid column index") ); 
7396     return GetColWidth(col
); 
7399 // ============================================================================ 
7400 // access to the grid attributes: each of them has a default value in the grid 
7401 // itself and may be overidden on a per-cell basis 
7402 // ============================================================================ 
7404 // ---------------------------------------------------------------------------- 
7405 // setting default attributes 
7406 // ---------------------------------------------------------------------------- 
7408 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& col 
) 
7410     m_defaultCellAttr
->SetBackgroundColour(col
); 
7412     m_gridWin
->SetBackgroundColour(col
); 
7416 void wxGrid::SetDefaultCellTextColour( const wxColour
& col 
) 
7418     m_defaultCellAttr
->SetTextColour(col
); 
7421 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert 
) 
7423     m_defaultCellAttr
->SetAlignment(horiz
, vert
); 
7426 void wxGrid::SetDefaultCellOverflow( bool allow 
) 
7428     m_defaultCellAttr
->SetOverflow(allow
); 
7431 void wxGrid::SetDefaultCellFont( const wxFont
& font 
) 
7433     m_defaultCellAttr
->SetFont(font
); 
7436 // For editors and renderers the type registry takes precedence over the 
7437 // default attr, so we need to register the new editor/renderer for the string 
7438 // data type in order to make setting a default editor/renderer appear to 
7441 void wxGrid::SetDefaultRenderer(wxGridCellRenderer 
*renderer
) 
7443     RegisterDataType(wxGRID_VALUE_STRING
, 
7445                      GetDefaultEditorForType(wxGRID_VALUE_STRING
)); 
7448 void wxGrid::SetDefaultEditor(wxGridCellEditor 
*editor
) 
7450     RegisterDataType(wxGRID_VALUE_STRING
, 
7451                      GetDefaultRendererForType(wxGRID_VALUE_STRING
), 
7455 // ---------------------------------------------------------------------------- 
7456 // access to the default attributes 
7457 // ---------------------------------------------------------------------------- 
7459 wxColour 
wxGrid::GetDefaultCellBackgroundColour() const 
7461     return m_defaultCellAttr
->GetBackgroundColour(); 
7464 wxColour 
wxGrid::GetDefaultCellTextColour() const 
7466     return m_defaultCellAttr
->GetTextColour(); 
7469 wxFont 
wxGrid::GetDefaultCellFont() const 
7471     return m_defaultCellAttr
->GetFont(); 
7474 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert 
) const 
7476     m_defaultCellAttr
->GetAlignment(horiz
, vert
); 
7479 bool wxGrid::GetDefaultCellOverflow() const 
7481     return m_defaultCellAttr
->GetOverflow(); 
7484 wxGridCellRenderer 
*wxGrid::GetDefaultRenderer() const 
7486     return m_defaultCellAttr
->GetRenderer(NULL
, 0, 0); 
7489 wxGridCellEditor 
*wxGrid::GetDefaultEditor() const 
7491     return m_defaultCellAttr
->GetEditor(NULL
, 0, 0); 
7494 // ---------------------------------------------------------------------------- 
7495 // access to cell attributes 
7496 // ---------------------------------------------------------------------------- 
7498 wxColour 
wxGrid::GetCellBackgroundColour(int row
, int col
) const 
7500     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7501     wxColour colour 
= attr
->GetBackgroundColour(); 
7507 wxColour 
wxGrid::GetCellTextColour( int row
, int col 
) const 
7509     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7510     wxColour colour 
= attr
->GetTextColour(); 
7516 wxFont 
wxGrid::GetCellFont( int row
, int col 
) const 
7518     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7519     wxFont font 
= attr
->GetFont(); 
7525 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert 
) const 
7527     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7528     attr
->GetAlignment(horiz
, vert
); 
7532 bool wxGrid::GetCellOverflow( int row
, int col 
) const 
7534     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7535     bool allow 
= attr
->GetOverflow(); 
7542 wxGrid::GetCellSize( int row
, int col
, int *num_rows
, int *num_cols 
) const 
7544     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7545     attr
->GetSize( num_rows
, num_cols 
); 
7548     if ( *num_rows 
== 1 && *num_cols 
== 1 ) 
7549         return CellSpan_None
; // just a normal cell 
7551     if ( *num_rows 
< 0 || *num_cols 
< 0 ) 
7552         return CellSpan_Inside
; // covered by a multi-span cell 
7554     // this cell spans multiple cells to its right/bottom 
7555     return CellSpan_Main
; 
7558 wxGridCellRenderer
* wxGrid::GetCellRenderer(int row
, int col
) const 
7560     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
7561     wxGridCellRenderer
* renderer 
= attr
->GetRenderer(this, row
, col
); 
7567 wxGridCellEditor
* wxGrid::GetCellEditor(int row
, int col
) const 
7569     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
7570     wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
7576 bool wxGrid::IsReadOnly(int row
, int col
) const 
7578     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
7579     bool isReadOnly 
= attr
->IsReadOnly(); 
7585 // ---------------------------------------------------------------------------- 
7586 // attribute support: cache, automatic provider creation, ... 
7587 // ---------------------------------------------------------------------------- 
7589 bool wxGrid::CanHaveAttributes() const 
7596     return m_table
->CanHaveAttributes(); 
7599 void wxGrid::ClearAttrCache() 
7601     if ( m_attrCache
.row 
!= -1 ) 
7603         wxGridCellAttr 
*oldAttr 
= m_attrCache
.attr
; 
7604         m_attrCache
.attr 
= NULL
; 
7605         m_attrCache
.row 
= -1; 
7606         // wxSafeDecRec(...) might cause event processing that accesses 
7607         // the cached attribute, if one exists (e.g. by deleting the 
7608         // editor stored within the attribute). Therefore it is important 
7609         // to invalidate the cache  before calling wxSafeDecRef! 
7610         wxSafeDecRef(oldAttr
); 
7614 void wxGrid::RefreshAttr(int row
, int col
) 
7616     if ( m_attrCache
.row 
== row 
&& m_attrCache
.col 
== col 
) 
7621 void wxGrid::CacheAttr(int row
, int col
, wxGridCellAttr 
*attr
) const 
7625         wxGrid 
* const self 
= const_cast<wxGrid 
*>(this); 
7627         self
->ClearAttrCache(); 
7628         self
->m_attrCache
.row 
= row
; 
7629         self
->m_attrCache
.col 
= col
; 
7630         self
->m_attrCache
.attr 
= attr
; 
7635 bool wxGrid::LookupAttr(int row
, int col
, wxGridCellAttr 
**attr
) const 
7637     if ( row 
== m_attrCache
.row 
&& col 
== m_attrCache
.col 
) 
7639         *attr 
= m_attrCache
.attr
; 
7640         wxSafeIncRef(m_attrCache
.attr
); 
7642 #ifdef DEBUG_ATTR_CACHE 
7643         gs_nAttrCacheHits
++; 
7650 #ifdef DEBUG_ATTR_CACHE 
7651         gs_nAttrCacheMisses
++; 
7658 wxGridCellAttr 
*wxGrid::GetCellAttr(int row
, int col
) const 
7660     wxGridCellAttr 
*attr 
= NULL
; 
7661     // Additional test to avoid looking at the cache e.g. for 
7662     // wxNoCellCoords, as this will confuse memory management. 
7665         if ( !LookupAttr(row
, col
, &attr
) ) 
7667             attr 
= m_table 
? m_table
->GetAttr(row
, col
, wxGridCellAttr::Any
) 
7669             CacheAttr(row
, col
, attr
); 
7675         attr
->SetDefAttr(m_defaultCellAttr
); 
7679         attr 
= m_defaultCellAttr
; 
7686 wxGridCellAttr 
*wxGrid::GetOrCreateCellAttr(int row
, int col
) const 
7688     wxGridCellAttr 
*attr 
= NULL
; 
7689     bool canHave 
= ((wxGrid
*)this)->CanHaveAttributes(); 
7691     wxCHECK_MSG( canHave
, attr
, wxT("Cell attributes not allowed")); 
7692     wxCHECK_MSG( m_table
, attr
, wxT("must have a table") ); 
7694     attr 
= m_table
->GetAttr(row
, col
, wxGridCellAttr::Cell
); 
7697         attr 
= new wxGridCellAttr(m_defaultCellAttr
); 
7699         // artificially inc the ref count to match DecRef() in caller 
7701         m_table
->SetAttr(attr
, row
, col
); 
7707 // ---------------------------------------------------------------------------- 
7708 // setting column attributes (wrappers around SetColAttr) 
7709 // ---------------------------------------------------------------------------- 
7711 void wxGrid::SetColFormatBool(int col
) 
7713     SetColFormatCustom(col
, wxGRID_VALUE_BOOL
); 
7716 void wxGrid::SetColFormatNumber(int col
) 
7718     SetColFormatCustom(col
, wxGRID_VALUE_NUMBER
); 
7721 void wxGrid::SetColFormatFloat(int col
, int width
, int precision
) 
7723     wxString typeName 
= wxGRID_VALUE_FLOAT
; 
7724     if ( (width 
!= -1) || (precision 
!= -1) ) 
7726         typeName 
<< wxT(':') << width 
<< wxT(',') << precision
; 
7729     SetColFormatCustom(col
, typeName
); 
7732 void wxGrid::SetColFormatCustom(int col
, const wxString
& typeName
) 
7734     wxGridCellAttr 
*attr 
= m_table
->GetAttr(-1, col
, wxGridCellAttr::Col 
); 
7736         attr 
= new wxGridCellAttr
; 
7737     wxGridCellRenderer 
*renderer 
= GetDefaultRendererForType(typeName
); 
7738     attr
->SetRenderer(renderer
); 
7739     wxGridCellEditor 
*editor 
= GetDefaultEditorForType(typeName
); 
7740     attr
->SetEditor(editor
); 
7742     SetColAttr(col
, attr
); 
7746 // ---------------------------------------------------------------------------- 
7747 // setting cell attributes: this is forwarded to the table 
7748 // ---------------------------------------------------------------------------- 
7750 void wxGrid::SetAttr(int row
, int col
, wxGridCellAttr 
*attr
) 
7752     if ( CanHaveAttributes() ) 
7754         m_table
->SetAttr(attr
, row
, col
); 
7763 void wxGrid::SetRowAttr(int row
, wxGridCellAttr 
*attr
) 
7765     if ( CanHaveAttributes() ) 
7767         m_table
->SetRowAttr(attr
, row
); 
7776 void wxGrid::SetColAttr(int col
, wxGridCellAttr 
*attr
) 
7778     if ( CanHaveAttributes() ) 
7780         m_table
->SetColAttr(attr
, col
); 
7789 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour 
) 
7791     if ( CanHaveAttributes() ) 
7793         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7794         attr
->SetBackgroundColour(colour
); 
7799 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& colour 
) 
7801     if ( CanHaveAttributes() ) 
7803         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7804         attr
->SetTextColour(colour
); 
7809 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& font 
) 
7811     if ( CanHaveAttributes() ) 
7813         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7814         attr
->SetFont(font
); 
7819 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert 
) 
7821     if ( CanHaveAttributes() ) 
7823         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7824         attr
->SetAlignment(horiz
, vert
); 
7829 void wxGrid::SetCellOverflow( int row
, int col
, bool allow 
) 
7831     if ( CanHaveAttributes() ) 
7833         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7834         attr
->SetOverflow(allow
); 
7839 void wxGrid::SetCellSize( int row
, int col
, int num_rows
, int num_cols 
) 
7841     if ( CanHaveAttributes() ) 
7843         int cell_rows
, cell_cols
; 
7845         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7846         attr
->GetSize(&cell_rows
, &cell_cols
); 
7847         attr
->SetSize(num_rows
, num_cols
); 
7850         // Cannot set the size of a cell to 0 or negative values 
7851         // While it is perfectly legal to do that, this function cannot 
7852         // handle all the possibilies, do it by hand by getting the CellAttr. 
7853         // You can only set the size of a cell to 1,1 or greater with this fn 
7854         wxASSERT_MSG( !((cell_rows 
< 1) || (cell_cols 
< 1)), 
7855                       wxT("wxGrid::SetCellSize setting cell size that is already part of another cell")); 
7856         wxASSERT_MSG( !((num_rows 
< 1) || (num_cols 
< 1)), 
7857                       wxT("wxGrid::SetCellSize setting cell size to < 1")); 
7859         // if this was already a multicell then "turn off" the other cells first 
7860         if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
7863             for (j
=row
; j 
< row 
+ cell_rows
; j
++) 
7865                 for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
7867                     if ((i 
!= col
) || (j 
!= row
)) 
7869                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
7870                         attr_stub
->SetSize( 1, 1 ); 
7871                         attr_stub
->DecRef(); 
7877         // mark the cells that will be covered by this cell to 
7878         // negative or zero values to point back at this cell 
7879         if (((num_rows 
> 1) || (num_cols 
> 1)) && (num_rows 
>= 1) && (num_cols 
>= 1)) 
7882             for (j
=row
; j 
< row 
+ num_rows
; j
++) 
7884                 for (i
=col
; i 
< col 
+ num_cols
; i
++) 
7886                     if ((i 
!= col
) || (j 
!= row
)) 
7888                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
7889                         attr_stub
->SetSize( row 
- j
, col 
- i 
); 
7890                         attr_stub
->DecRef(); 
7898 void wxGrid::SetCellRenderer(int row
, int col
, wxGridCellRenderer 
*renderer
) 
7900     if ( CanHaveAttributes() ) 
7902         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7903         attr
->SetRenderer(renderer
); 
7908 void wxGrid::SetCellEditor(int row
, int col
, wxGridCellEditor
* editor
) 
7910     if ( CanHaveAttributes() ) 
7912         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7913         attr
->SetEditor(editor
); 
7918 void wxGrid::SetReadOnly(int row
, int col
, bool isReadOnly
) 
7920     if ( CanHaveAttributes() ) 
7922         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
7923         attr
->SetReadOnly(isReadOnly
); 
7928 // ---------------------------------------------------------------------------- 
7929 // Data type registration 
7930 // ---------------------------------------------------------------------------- 
7932 void wxGrid::RegisterDataType(const wxString
& typeName
, 
7933                               wxGridCellRenderer
* renderer
, 
7934                               wxGridCellEditor
* editor
) 
7936     m_typeRegistry
->RegisterDataType(typeName
, renderer
, editor
); 
7940 wxGridCellEditor 
* wxGrid::GetDefaultEditorForCell(int row
, int col
) const 
7942     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
7943     return GetDefaultEditorForType(typeName
); 
7946 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForCell(int row
, int col
) const 
7948     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
7949     return GetDefaultRendererForType(typeName
); 
7952 wxGridCellEditor 
* wxGrid::GetDefaultEditorForType(const wxString
& typeName
) const 
7954     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
7955     if ( index 
== wxNOT_FOUND 
) 
7957         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
7962     return m_typeRegistry
->GetEditor(index
); 
7965 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForType(const wxString
& typeName
) const 
7967     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
7968     if ( index 
== wxNOT_FOUND 
) 
7970         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
7975     return m_typeRegistry
->GetRenderer(index
); 
7978 // ---------------------------------------------------------------------------- 
7980 // ---------------------------------------------------------------------------- 
7982 void wxGrid::DoDisableLineResize(int line
, wxGridFixedIndicesSet 
*& setFixed
) 
7986         setFixed 
= new wxGridFixedIndicesSet
; 
7989     setFixed
->insert(line
); 
7993 wxGrid::DoCanResizeLine(int line
, const wxGridFixedIndicesSet 
*setFixed
) const 
7995     return !setFixed 
|| !setFixed
->count(line
); 
7998 void wxGrid::EnableDragRowSize( bool enable 
) 
8000     m_canDragRowSize 
= enable
; 
8003 void wxGrid::EnableDragColSize( bool enable 
) 
8005     m_canDragColSize 
= enable
; 
8008 void wxGrid::EnableDragGridSize( bool enable 
) 
8010     m_canDragGridSize 
= enable
; 
8013 void wxGrid::EnableDragCell( bool enable 
) 
8015     m_canDragCell 
= enable
; 
8018 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows 
) 
8020     m_defaultRowHeight 
= wxMax( height
, m_minAcceptableRowHeight 
); 
8022     if ( resizeExistingRows 
) 
8024         // since we are resizing all rows to the default row size, 
8025         // we can simply clear the row heights and row bottoms 
8026         // arrays (which also allows us to take advantage of 
8027         // some speed optimisations) 
8028         m_rowHeights
.Empty(); 
8029         m_rowBottoms
.Empty(); 
8030         if ( !GetBatchCount() ) 
8035 void wxGrid::SetRowSize( int row
, int height 
) 
8037     wxCHECK_RET( row 
>= 0 && row 
< m_numRows
, wxT("invalid row index") ); 
8039     // if < 0 then calculate new height from label 
8043         wxArrayString lines
; 
8044         wxClientDC 
dc(m_rowLabelWin
); 
8045         dc
.SetFont(GetLabelFont()); 
8046         StringToLines(GetRowLabelValue( row 
), lines
); 
8047         GetTextBoxSize( dc
, lines
, &w
, &h 
); 
8048         //check that it is not less than the minimal height 
8049         height 
= wxMax(h
, GetRowMinimalAcceptableHeight()); 
8052     // See comment in SetColSize 
8053     if ( height 
> 0 && height 
< GetRowMinimalAcceptableHeight()) 
8056     if ( m_rowHeights
.IsEmpty() ) 
8058         // need to really create the array 
8062     int h 
= wxMax( 0, height 
); 
8063     int diff 
= h 
- m_rowHeights
[row
]; 
8065     m_rowHeights
[row
] = h
; 
8066     for ( int i 
= row
; i 
< m_numRows
; i
++ ) 
8068         m_rowBottoms
[i
] += diff
; 
8071     if ( !GetBatchCount() ) 
8078 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols 
) 
8080     // we dont allow zero default column width 
8081     m_defaultColWidth 
= wxMax( wxMax( width
, m_minAcceptableColWidth 
), 1 ); 
8083     if ( resizeExistingCols 
) 
8085         // since we are resizing all columns to the default column size, 
8086         // we can simply clear the col widths and col rights 
8087         // arrays (which also allows us to take advantage of 
8088         // some speed optimisations) 
8089         m_colWidths
.Empty(); 
8090         m_colRights
.Empty(); 
8091         if ( !GetBatchCount() ) 
8096 void wxGrid::SetColSize( int col
, int width 
) 
8098     wxCHECK_RET( col 
>= 0 && col 
< m_numCols
, wxT("invalid column index") ); 
8100     // if < 0 then calculate new width from label 
8104         wxArrayString lines
; 
8105         wxClientDC 
dc(m_colWindow
); 
8106         dc
.SetFont(GetLabelFont()); 
8107         StringToLines(GetColLabelValue(col
), lines
); 
8108         if ( GetColLabelTextOrientation() == wxHORIZONTAL 
) 
8109             GetTextBoxSize( dc
, lines
, &w
, &h 
); 
8111             GetTextBoxSize( dc
, lines
, &h
, &w 
); 
8113         //check that it is not less than the minimal width 
8114         width 
= wxMax(width
, GetColMinimalAcceptableWidth()); 
8117     // we intentionally don't test whether the width is less than 
8118     // GetColMinimalWidth() here but we do compare it with 
8119     // GetColMinimalAcceptableWidth() as otherwise things currently break (see 
8120     // #651) -- and we also always allow the width of 0 as it has the special 
8121     // sense of hiding the column 
8122     if ( width 
> 0 && width 
< GetColMinimalAcceptableWidth() ) 
8125     if ( m_colWidths
.IsEmpty() ) 
8127         // need to really create the array 
8131     const int diff 
= width 
- m_colWidths
[col
]; 
8132     m_colWidths
[col
] = width
; 
8133     if ( m_useNativeHeader 
) 
8134         GetGridColHeader()->UpdateColumn(col
); 
8135     //else: will be refreshed when the header is redrawn 
8137     for ( int colPos 
= GetColPos(col
); colPos 
< m_numCols
; colPos
++ ) 
8139         m_colRights
[GetColAt(colPos
)] += diff
; 
8142     if ( !GetBatchCount() ) 
8149 void wxGrid::SetColMinimalWidth( int col
, int width 
) 
8151     if (width 
> GetColMinimalAcceptableWidth()) 
8153         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
8154         m_colMinWidths
[key
] = width
; 
8158 void wxGrid::SetRowMinimalHeight( int row
, int width 
) 
8160     if (width 
> GetRowMinimalAcceptableHeight()) 
8162         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
8163         m_rowMinHeights
[key
] = width
; 
8167 int wxGrid::GetColMinimalWidth(int col
) const 
8169     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
8170     wxLongToLongHashMap::const_iterator it 
= m_colMinWidths
.find(key
); 
8172     return it 
!= m_colMinWidths
.end() ? (int)it
->second 
: m_minAcceptableColWidth
; 
8175 int wxGrid::GetRowMinimalHeight(int row
) const 
8177     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
8178     wxLongToLongHashMap::const_iterator it 
= m_rowMinHeights
.find(key
); 
8180     return it 
!= m_rowMinHeights
.end() ? (int)it
->second 
: m_minAcceptableRowHeight
; 
8183 void wxGrid::SetColMinimalAcceptableWidth( int width 
) 
8185     // We do allow a width of 0 since this gives us 
8186     // an easy way to temporarily hiding columns. 
8188         m_minAcceptableColWidth 
= width
; 
8191 void wxGrid::SetRowMinimalAcceptableHeight( int height 
) 
8193     // We do allow a height of 0 since this gives us 
8194     // an easy way to temporarily hiding rows. 
8196         m_minAcceptableRowHeight 
= height
; 
8199 int  wxGrid::GetColMinimalAcceptableWidth() const 
8201     return m_minAcceptableColWidth
; 
8204 int  wxGrid::GetRowMinimalAcceptableHeight() const 
8206     return m_minAcceptableRowHeight
; 
8209 // ---------------------------------------------------------------------------- 
8211 // ---------------------------------------------------------------------------- 
8214 wxGrid::AutoSizeColOrRow(int colOrRow
, bool setAsMin
, wxGridDirection direction
) 
8216     const bool column 
= direction 
== wxGRID_COLUMN
; 
8218     wxClientDC 
dc(m_gridWin
); 
8220     // cancel editing of cell 
8221     HideCellEditControl(); 
8222     SaveEditControlValue(); 
8224     // initialize both of them just to avoid compiler warnings even if only 
8225     // really needs to be initialized here 
8239     wxCoord extent
, extentMax 
= 0; 
8240     int max 
= column 
? m_numRows 
: m_numCols
; 
8241     for ( int rowOrCol 
= 0; rowOrCol 
< max
; rowOrCol
++ ) 
8248         // we need to account for the cells spanning multiple columns/rows: 
8249         // while they may need a lot of space, they don't need all of it in 
8251         int numRows
, numCols
; 
8252         const CellSpan span 
= GetCellSize(row
, col
, &numRows
, &numCols
); 
8253         if ( span 
== CellSpan_Inside 
) 
8255             // we need to get the size of the main cell, not of a cell hidden 
8260             // get the size of the main cell too 
8261             GetCellSize(row
, col
, &numRows
, &numCols
); 
8264         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
8265         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
8268             wxSize size 
= renderer
->GetBestSize(*this, *attr
, dc
, row
, col
); 
8269             extent 
= column 
? size
.x 
: size
.y
; 
8271             if ( span 
!= CellSpan_None 
) 
8273                 // we spread the size of a spanning cell over all the cells it 
8274                 // covers evenly -- this is probably not ideal but we can't 
8275                 // really do much better here 
8277                 // notice that numCols and numRows are never 0 as they 
8278                 // correspond to the size of the main cell of the span and not 
8279                 // of the cell inside it 
8280                 extent 
/= column 
? numCols 
: numRows
; 
8283             if ( extent 
> extentMax 
) 
8292     // now also compare with the column label extent 
8294     dc
.SetFont( GetLabelFont() ); 
8298         dc
.GetMultiLineTextExtent( GetColLabelValue(col
), &w
, &h 
); 
8299         if ( GetColLabelTextOrientation() == wxVERTICAL 
) 
8303         dc
.GetMultiLineTextExtent( GetRowLabelValue(row
), &w
, &h 
); 
8305     extent 
= column 
? w 
: h
; 
8306     if ( extent 
> extentMax 
) 
8311         // empty column - give default extent (notice that if extentMax is less 
8312         // than default extent but != 0, it's OK) 
8313         extentMax 
= column 
? m_defaultColWidth 
: m_defaultRowHeight
; 
8318             // leave some space around text 
8326         // Ensure automatic width is not less than minimal width. See the 
8327         // comment in SetColSize() for explanation of why this isn't done 
8330             extentMax 
= wxMax(extentMax
, GetColMinimalWidth(col
)); 
8332         SetColSize( col
, extentMax 
); 
8333         if ( !GetBatchCount() ) 
8335             if ( m_useNativeHeader 
) 
8337                 GetGridColHeader()->UpdateColumn(col
); 
8342                 m_gridWin
->GetClientSize( &cw
, &ch 
); 
8343                 wxRect 
rect ( CellToRect( 0, col 
) ); 
8345                 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
); 
8346                 rect
.width 
= cw 
- rect
.x
; 
8347                 rect
.height 
= m_colLabelHeight
; 
8348                 GetColLabelWindow()->Refresh( true, &rect 
); 
8354         // Ensure automatic width is not less than minimal height. See the 
8355         // comment in SetColSize() for explanation of why this isn't done 
8358             extentMax 
= wxMax(extentMax
, GetRowMinimalHeight(row
)); 
8360         SetRowSize(row
, extentMax
); 
8361         if ( !GetBatchCount() ) 
8364             m_gridWin
->GetClientSize( &cw
, &ch 
); 
8365             wxRect 
rect( CellToRect( row
, 0 ) ); 
8367             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
8368             rect
.width 
= m_rowLabelWidth
; 
8369             rect
.height 
= ch 
- rect
.y
; 
8370             m_rowLabelWin
->Refresh( true, &rect 
); 
8377             SetColMinimalWidth(col
, extentMax
); 
8379             SetRowMinimalHeight(row
, extentMax
); 
8383 wxCoord 
wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction
) 
8385     // calculate size for the rows or columns? 
8386     const bool calcRows 
= direction 
== wxGRID_ROW
; 
8388     wxClientDC 
dc(calcRows 
? GetGridRowLabelWindow() 
8389                            : GetGridColLabelWindow()); 
8390     dc
.SetFont(GetLabelFont()); 
8392     // which dimension should we take into account for calculations? 
8394     // for columns, the text can be only horizontal so it's easy but for rows 
8395     // we also have to take into account the text orientation 
8397         useWidth 
= calcRows 
|| (GetColLabelTextOrientation() == wxVERTICAL
); 
8399     wxArrayString lines
; 
8400     wxCoord extentMax 
= 0; 
8402     const int numRowsOrCols 
= calcRows 
? m_numRows 
: m_numCols
; 
8403     for ( int rowOrCol 
= 0; rowOrCol 
< numRowsOrCols
; rowOrCol
++ ) 
8407         wxString label 
= calcRows 
? GetRowLabelValue(rowOrCol
) 
8408                                   : GetColLabelValue(rowOrCol
); 
8409         StringToLines(label
, lines
); 
8412         GetTextBoxSize(dc
, lines
, &w
, &h
); 
8414         const wxCoord extent 
= useWidth 
? w 
: h
; 
8415         if ( extent 
> extentMax 
) 
8421         // empty column - give default extent (notice that if extentMax is less 
8422         // than default extent but != 0, it's OK) 
8423         extentMax 
= calcRows 
? GetDefaultRowLabelSize() 
8424                              : GetDefaultColLabelSize(); 
8427     // leave some space around text (taken from AutoSizeColOrRow) 
8436 int wxGrid::SetOrCalcColumnSizes(bool calcOnly
, bool setAsMin
) 
8438     int width 
= m_rowLabelWidth
; 
8440     wxGridUpdateLocker locker
; 
8442         locker
.Create(this); 
8444     for ( int col 
= 0; col 
< m_numCols
; col
++ ) 
8447             AutoSizeColumn(col
, setAsMin
); 
8449         width 
+= GetColWidth(col
); 
8455 int wxGrid::SetOrCalcRowSizes(bool calcOnly
, bool setAsMin
) 
8457     int height 
= m_colLabelHeight
; 
8459     wxGridUpdateLocker locker
; 
8461         locker
.Create(this); 
8463     for ( int row 
= 0; row 
< m_numRows
; row
++ ) 
8466             AutoSizeRow(row
, setAsMin
); 
8468         height 
+= GetRowHeight(row
); 
8474 void wxGrid::AutoSize() 
8476     wxGridUpdateLocker 
locker(this); 
8478     wxSize 
size(SetOrCalcColumnSizes(false) - m_rowLabelWidth 
+ m_extraWidth
, 
8479                 SetOrCalcRowSizes(false) - m_colLabelHeight 
+ m_extraHeight
); 
8481     // we know that we're not going to have scrollbars so disable them now to 
8482     // avoid trouble in SetClientSize() which can otherwise set the correct 
8483     // client size but also leave space for (not needed any more) scrollbars 
8484     SetScrollbars(m_xScrollPixelsPerLine
, m_yScrollPixelsPerLine
, 
8487     SetClientSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
); 
8490 void wxGrid::AutoSizeRowLabelSize( int row 
) 
8492     // Hide the edit control, so it 
8493     // won't interfere with drag-shrinking. 
8494     if ( IsCellEditControlShown() ) 
8496         HideCellEditControl(); 
8497         SaveEditControlValue(); 
8500     // autosize row height depending on label text 
8501     SetRowSize(row
, -1); 
8505 void wxGrid::AutoSizeColLabelSize( int col 
) 
8507     // Hide the edit control, so it 
8508     // won't interfere with drag-shrinking. 
8509     if ( IsCellEditControlShown() ) 
8511         HideCellEditControl(); 
8512         SaveEditControlValue(); 
8515     // autosize column width depending on label text 
8516     SetColSize(col
, -1); 
8520 wxSize 
wxGrid::DoGetBestSize() const 
8522     wxGrid 
* const self 
= const_cast<wxGrid 
*>(this); 
8524     // we do the same as in AutoSize() here with the exception that we don't 
8525     // change the column/row sizes, only calculate them 
8526     wxSize 
size(self
->SetOrCalcColumnSizes(true) - m_rowLabelWidth 
+ m_extraWidth
, 
8527                 self
->SetOrCalcRowSizes(true) - m_colLabelHeight 
+ m_extraHeight
); 
8529     // NOTE: This size should be cached, but first we need to add calls to 
8530     // InvalidateBestSize everywhere that could change the results of this 
8532     // CacheBestSize(size); 
8534     return wxSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
) 
8535             + GetWindowBorderSize(); 
8543 #if WXWIN_COMPATIBILITY_2_8 
8544 wxPen
& wxGrid::GetDividerPen() const 
8548 #endif // WXWIN_COMPATIBILITY_2_8 
8550 // ---------------------------------------------------------------------------- 
8551 // cell value accessor functions 
8552 // ---------------------------------------------------------------------------- 
8554 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s 
) 
8558         m_table
->SetValue( row
, col
, s 
); 
8559         if ( !GetBatchCount() ) 
8562             wxRect 
rect( CellToRect( row
, col 
) ); 
8564             rect
.width 
= m_gridWin
->GetClientSize().GetWidth(); 
8565             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
8566             m_gridWin
->Refresh( false, &rect 
); 
8569         if ( m_currentCellCoords
.GetRow() == row 
&& 
8570              m_currentCellCoords
.GetCol() == col 
&& 
8571              IsCellEditControlShown()) 
8572              // Note: If we are using IsCellEditControlEnabled, 
8573              // this interacts badly with calling SetCellValue from 
8574              // an EVT_GRID_CELL_CHANGE handler. 
8576             HideCellEditControl(); 
8577             ShowCellEditControl(); // will reread data from table 
8582 // ---------------------------------------------------------------------------- 
8583 // block, row and column selection 
8584 // ---------------------------------------------------------------------------- 
8586 void wxGrid::SelectRow( int row
, bool addToSelected 
) 
8591     if ( !addToSelected 
) 
8594     m_selection
->SelectRow(row
); 
8597 void wxGrid::SelectCol( int col
, bool addToSelected 
) 
8602     if ( !addToSelected 
) 
8605     m_selection
->SelectCol(col
); 
8608 void wxGrid::SelectBlock(int topRow
, int leftCol
, int bottomRow
, int rightCol
, 
8614     if ( !addToSelected 
) 
8617     m_selection
->SelectBlock(topRow
, leftCol
, bottomRow
, rightCol
); 
8620 void wxGrid::SelectAll() 
8622     if ( m_numRows 
> 0 && m_numCols 
> 0 ) 
8625             m_selection
->SelectBlock( 0, 0, m_numRows 
- 1, m_numCols 
- 1 ); 
8629 // ---------------------------------------------------------------------------- 
8630 // cell, row and col deselection 
8631 // ---------------------------------------------------------------------------- 
8633 void wxGrid::DeselectLine(int line
, const wxGridOperations
& oper
) 
8638     const wxGridSelectionModes mode 
= m_selection
->GetSelectionMode(); 
8639     if ( mode 
== oper
.GetSelectionMode() || 
8640             mode 
== wxGrid::wxGridSelectRowsOrColumns 
) 
8642         const wxGridCellCoords 
c(oper
.MakeCoords(line
, 0)); 
8643         if ( m_selection
->IsInSelection(c
) ) 
8644             m_selection
->ToggleCellSelection(c
); 
8646     else if ( mode 
!= oper
.Dual().GetSelectionMode() ) 
8648         const int nOther 
= oper
.Dual().GetNumberOfLines(this); 
8649         for ( int i 
= 0; i 
< nOther
; i
++ ) 
8651             const wxGridCellCoords 
c(oper
.MakeCoords(line
, i
)); 
8652             if ( m_selection
->IsInSelection(c
) ) 
8653                 m_selection
->ToggleCellSelection(c
); 
8656     //else: can only select orthogonal lines so no lines in this direction 
8657     //      could have been selected anyhow 
8660 void wxGrid::DeselectRow(int row
) 
8662     DeselectLine(row
, wxGridRowOperations()); 
8665 void wxGrid::DeselectCol(int col
) 
8667     DeselectLine(col
, wxGridColumnOperations()); 
8670 void wxGrid::DeselectCell( int row
, int col 
) 
8672     if ( m_selection 
&& m_selection
->IsInSelection(row
, col
) ) 
8673         m_selection
->ToggleCellSelection(row
, col
); 
8676 bool wxGrid::IsSelection() const 
8678     return ( m_selection 
&& (m_selection
->IsSelection() || 
8679              ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
8680                m_selectedBlockBottomRight 
!= wxGridNoCellCoords
) ) ); 
8683 bool wxGrid::IsInSelection( int row
, int col 
) const 
8685     return ( m_selection 
&& (m_selection
->IsInSelection( row
, col 
) || 
8686              ( row 
>= m_selectedBlockTopLeft
.GetRow() && 
8687                col 
>= m_selectedBlockTopLeft
.GetCol() && 
8688                row 
<= m_selectedBlockBottomRight
.GetRow() && 
8689                col 
<= m_selectedBlockBottomRight
.GetCol() )) ); 
8692 wxGridCellCoordsArray 
wxGrid::GetSelectedCells() const 
8696         wxGridCellCoordsArray a
; 
8700     return m_selection
->m_cellSelection
; 
8703 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockTopLeft() const 
8707         wxGridCellCoordsArray a
; 
8711     return m_selection
->m_blockSelectionTopLeft
; 
8714 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockBottomRight() const 
8718         wxGridCellCoordsArray a
; 
8722     return m_selection
->m_blockSelectionBottomRight
; 
8725 wxArrayInt 
wxGrid::GetSelectedRows() const 
8733     return m_selection
->m_rowSelection
; 
8736 wxArrayInt 
wxGrid::GetSelectedCols() const 
8744     return m_selection
->m_colSelection
; 
8747 void wxGrid::ClearSelection() 
8749     wxRect r1 
= BlockToDeviceRect(m_selectedBlockTopLeft
, 
8750                                   m_selectedBlockBottomRight
); 
8751     wxRect r2 
= BlockToDeviceRect(m_currentCellCoords
, 
8752                                   m_selectedBlockCorner
); 
8754     m_selectedBlockTopLeft 
= 
8755     m_selectedBlockBottomRight 
= 
8756     m_selectedBlockCorner 
= wxGridNoCellCoords
; 
8758     if ( !r1
.IsEmpty() ) 
8759         RefreshRect(r1
, false); 
8760     if ( !r2
.IsEmpty() ) 
8761         RefreshRect(r2
, false); 
8764         m_selection
->ClearSelection(); 
8767 // This function returns the rectangle that encloses the given block 
8768 // in device coords clipped to the client size of the grid window. 
8770 wxRect 
wxGrid::BlockToDeviceRect( const wxGridCellCoords
& topLeft
, 
8771                                   const wxGridCellCoords
& bottomRight 
) const 
8774     wxRect tempCellRect 
= CellToRect(topLeft
); 
8775     if ( tempCellRect 
!= wxGridNoCellRect 
) 
8777         resultRect 
= tempCellRect
; 
8781         resultRect 
= wxRect(0, 0, 0, 0); 
8784     tempCellRect 
= CellToRect(bottomRight
); 
8785     if ( tempCellRect 
!= wxGridNoCellRect 
) 
8787         resultRect 
+= tempCellRect
; 
8791         // If both inputs were "wxGridNoCellRect," then there's nothing to do. 
8792         return wxGridNoCellRect
; 
8795     // Ensure that left/right and top/bottom pairs are in order. 
8796     int left 
= resultRect
.GetLeft(); 
8797     int top 
= resultRect
.GetTop(); 
8798     int right 
= resultRect
.GetRight(); 
8799     int bottom 
= resultRect
.GetBottom(); 
8801     int leftCol 
= topLeft
.GetCol(); 
8802     int topRow 
= topLeft
.GetRow(); 
8803     int rightCol 
= bottomRight
.GetCol(); 
8804     int bottomRow 
= bottomRight
.GetRow(); 
8828     // The following loop is ONLY necessary to detect and handle merged cells. 
8830     m_gridWin
->GetClientSize( &cw
, &ch 
); 
8832     // Get the origin coordinates: notice that they will be negative if the 
8833     // grid is scrolled downwards/to the right. 
8834     int gridOriginX 
= 0; 
8835     int gridOriginY 
= 0; 
8836     CalcScrolledPosition(gridOriginX
, gridOriginY
, &gridOriginX
, &gridOriginY
); 
8838     int onScreenLeftmostCol 
= internalXToCol(-gridOriginX
); 
8839     int onScreenUppermostRow 
= internalYToRow(-gridOriginY
); 
8841     int onScreenRightmostCol 
= internalXToCol(-gridOriginX 
+ cw
); 
8842     int onScreenBottommostRow 
= internalYToRow(-gridOriginY 
+ ch
); 
8844     // Bound our loop so that we only examine the portion of the selected block 
8845     // that is shown on screen. Therefore, we compare the Top-Left block values 
8846     // to the Top-Left screen values, and the Bottom-Right block values to the 
8847     // Bottom-Right screen values, choosing appropriately. 
8848     const int visibleTopRow 
= wxMax(topRow
, onScreenUppermostRow
); 
8849     const int visibleBottomRow 
= wxMin(bottomRow
, onScreenBottommostRow
); 
8850     const int visibleLeftCol 
= wxMax(leftCol
, onScreenLeftmostCol
); 
8851     const int visibleRightCol 
= wxMin(rightCol
, onScreenRightmostCol
); 
8853     for ( int j 
= visibleTopRow
; j 
<= visibleBottomRow
; j
++ ) 
8855         for ( int i 
= visibleLeftCol
; i 
<= visibleRightCol
; i
++ ) 
8857             if ( (j 
== visibleTopRow
) || (j 
== visibleBottomRow
) || 
8858                     (i 
== visibleLeftCol
) || (i 
== visibleRightCol
) ) 
8860                 tempCellRect 
= CellToRect( j
, i 
); 
8862                 if (tempCellRect
.x 
< left
) 
8863                     left 
= tempCellRect
.x
; 
8864                 if (tempCellRect
.y 
< top
) 
8865                     top 
= tempCellRect
.y
; 
8866                 if (tempCellRect
.x 
+ tempCellRect
.width 
> right
) 
8867                     right 
= tempCellRect
.x 
+ tempCellRect
.width
; 
8868                 if (tempCellRect
.y 
+ tempCellRect
.height 
> bottom
) 
8869                     bottom 
= tempCellRect
.y 
+ tempCellRect
.height
; 
8873                 i 
= visibleRightCol
; // jump over inner cells. 
8878     // Convert to scrolled coords 
8879     CalcScrolledPosition( left
, top
, &left
, &top 
); 
8880     CalcScrolledPosition( right
, bottom
, &right
, &bottom 
); 
8882     if (right 
< 0 || bottom 
< 0 || left 
> cw 
|| top 
> ch
) 
8883         return wxRect(0,0,0,0); 
8885     resultRect
.SetLeft( wxMax(0, left
) ); 
8886     resultRect
.SetTop( wxMax(0, top
) ); 
8887     resultRect
.SetRight( wxMin(cw
, right
) ); 
8888     resultRect
.SetBottom( wxMin(ch
, bottom
) ); 
8893 void wxGrid::DoSetSizes(const wxGridSizesInfo
& sizeInfo
, 
8894                         const wxGridOperations
& oper
) 
8897     oper
.SetDefaultLineSize(this, sizeInfo
.m_sizeDefault
, true); 
8898     const int numLines 
= oper
.GetNumberOfLines(this); 
8899     for ( int i 
= 0; i 
< numLines
; i
++ ) 
8901         int size 
= sizeInfo
.GetSize(i
); 
8902         if ( size 
!= sizeInfo
.m_sizeDefault
) 
8903             oper
.SetLineSize(this, i
, size
); 
8908 void wxGrid::SetColSizes(const wxGridSizesInfo
& sizeInfo
) 
8910     DoSetSizes(sizeInfo
, wxGridColumnOperations()); 
8913 void wxGrid::SetRowSizes(const wxGridSizesInfo
& sizeInfo
) 
8915     DoSetSizes(sizeInfo
, wxGridRowOperations()); 
8918 wxGridSizesInfo::wxGridSizesInfo(int defSize
, const wxArrayInt
& allSizes
) 
8920     m_sizeDefault 
= defSize
; 
8921     for ( size_t i 
= 0; i 
< allSizes
.size(); i
++ ) 
8923         if ( allSizes
[i
] != defSize 
) 
8924             m_customSizes
[i
] = allSizes
[i
]; 
8928 int wxGridSizesInfo::GetSize(unsigned pos
) const 
8930     wxUnsignedToIntHashMap::const_iterator it 
= m_customSizes
.find(pos
); 
8932     return it 
== m_customSizes
.end() ? m_sizeDefault 
: it
->second
; 
8935 // ---------------------------------------------------------------------------- 
8937 // ---------------------------------------------------------------------------- 
8939 #if wxUSE_DRAG_AND_DROP 
8941 // this allow setting drop target directly on wxGrid 
8942 void wxGrid::SetDropTarget(wxDropTarget 
*dropTarget
) 
8944     GetGridWindow()->SetDropTarget(dropTarget
); 
8947 #endif // wxUSE_DRAG_AND_DROP 
8949 // ---------------------------------------------------------------------------- 
8950 // grid event classes 
8951 // ---------------------------------------------------------------------------- 
8953 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxNotifyEvent 
) 
8955 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
, 
8956                           int row
, int col
, int x
, int y
, bool sel
, 
8957                           bool control
, bool shift
, bool alt
, bool meta 
) 
8958         : wxNotifyEvent( type
, id 
), 
8959           wxKeyboardState(control
, shift
, alt
, meta
) 
8961     Init(row
, col
, x
, y
, sel
); 
8963     SetEventObject(obj
); 
8966 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxNotifyEvent 
) 
8968 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
, 
8969                                   int rowOrCol
, int x
, int y
, 
8970                                   bool control
, bool shift
, bool alt
, bool meta 
) 
8971         : wxNotifyEvent( type
, id 
), 
8972           wxKeyboardState(control
, shift
, alt
, meta
) 
8974     Init(rowOrCol
, x
, y
); 
8976     SetEventObject(obj
); 
8980 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxNotifyEvent 
) 
8982 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
, 
8983                                                const wxGridCellCoords
& topLeft
, 
8984                                                const wxGridCellCoords
& bottomRight
, 
8985                                                bool sel
, bool control
, 
8986                                                bool shift
, bool alt
, bool meta 
) 
8987         : wxNotifyEvent( type
, id 
), 
8988           wxKeyboardState(control
, shift
, alt
, meta
) 
8990     Init(topLeft
, bottomRight
, sel
); 
8992     SetEventObject(obj
); 
8996 IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent
, wxCommandEvent
) 
8998 wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id
, wxEventType type
, 
8999                                                    wxObject
* obj
, int row
, 
9000                                                    int col
, wxControl
* ctrl
) 
9001     : wxCommandEvent(type
, id
) 
9003     SetEventObject(obj
); 
9010 // ---------------------------------------------------------------------------- 
9011 // wxGridTypeRegistry 
9012 // ---------------------------------------------------------------------------- 
9014 wxGridTypeRegistry::~wxGridTypeRegistry() 
9016     size_t count 
= m_typeinfo
.GetCount(); 
9017     for ( size_t i 
= 0; i 
< count
; i
++ ) 
9018         delete m_typeinfo
[i
]; 
9021 void wxGridTypeRegistry::RegisterDataType(const wxString
& typeName
, 
9022                                           wxGridCellRenderer
* renderer
, 
9023                                           wxGridCellEditor
* editor
) 
9025     wxGridDataTypeInfo
* info 
= new wxGridDataTypeInfo(typeName
, renderer
, editor
); 
9027     // is it already registered? 
9028     int loc 
= FindRegisteredDataType(typeName
); 
9029     if ( loc 
!= wxNOT_FOUND 
) 
9031         delete m_typeinfo
[loc
]; 
9032         m_typeinfo
[loc
] = info
; 
9036         m_typeinfo
.Add(info
); 
9040 int wxGridTypeRegistry::FindRegisteredDataType(const wxString
& typeName
) 
9042     size_t count 
= m_typeinfo
.GetCount(); 
9043     for ( size_t i 
= 0; i 
< count
; i
++ ) 
9045         if ( typeName 
== m_typeinfo
[i
]->m_typeName 
) 
9054 int wxGridTypeRegistry::FindDataType(const wxString
& typeName
) 
9056     int index 
= FindRegisteredDataType(typeName
); 
9057     if ( index 
== wxNOT_FOUND 
) 
9059         // check whether this is one of the standard ones, in which case 
9060         // register it "on the fly" 
9062         if ( typeName 
== wxGRID_VALUE_STRING 
) 
9064             RegisterDataType(wxGRID_VALUE_STRING
, 
9065                              new wxGridCellStringRenderer
, 
9066                              new wxGridCellTextEditor
); 
9069 #endif // wxUSE_TEXTCTRL 
9071         if ( typeName 
== wxGRID_VALUE_BOOL 
) 
9073             RegisterDataType(wxGRID_VALUE_BOOL
, 
9074                              new wxGridCellBoolRenderer
, 
9075                              new wxGridCellBoolEditor
); 
9078 #endif // wxUSE_CHECKBOX 
9080         if ( typeName 
== wxGRID_VALUE_NUMBER 
) 
9082             RegisterDataType(wxGRID_VALUE_NUMBER
, 
9083                              new wxGridCellNumberRenderer
, 
9084                              new wxGridCellNumberEditor
); 
9086         else if ( typeName 
== wxGRID_VALUE_FLOAT 
) 
9088             RegisterDataType(wxGRID_VALUE_FLOAT
, 
9089                              new wxGridCellFloatRenderer
, 
9090                              new wxGridCellFloatEditor
); 
9093 #endif // wxUSE_TEXTCTRL 
9095         if ( typeName 
== wxGRID_VALUE_CHOICE 
) 
9097             RegisterDataType(wxGRID_VALUE_CHOICE
, 
9098                              new wxGridCellStringRenderer
, 
9099                              new wxGridCellChoiceEditor
); 
9102 #endif // wxUSE_COMBOBOX 
9107         // we get here only if just added the entry for this type, so return 
9109         index 
= m_typeinfo
.GetCount() - 1; 
9115 int wxGridTypeRegistry::FindOrCloneDataType(const wxString
& typeName
) 
9117     int index 
= FindDataType(typeName
); 
9118     if ( index 
== wxNOT_FOUND 
) 
9120         // the first part of the typename is the "real" type, anything after ':' 
9121         // are the parameters for the renderer 
9122         index 
= FindDataType(typeName
.BeforeFirst(wxT(':'))); 
9123         if ( index 
== wxNOT_FOUND 
) 
9128         wxGridCellRenderer 
*renderer 
= GetRenderer(index
); 
9129         wxGridCellRenderer 
*rendererOld 
= renderer
; 
9130         renderer 
= renderer
->Clone(); 
9131         rendererOld
->DecRef(); 
9133         wxGridCellEditor 
*editor 
= GetEditor(index
); 
9134         wxGridCellEditor 
*editorOld 
= editor
; 
9135         editor 
= editor
->Clone(); 
9136         editorOld
->DecRef(); 
9138         // do it even if there are no parameters to reset them to defaults 
9139         wxString params 
= typeName
.AfterFirst(wxT(':')); 
9140         renderer
->SetParameters(params
); 
9141         editor
->SetParameters(params
); 
9143         // register the new typename 
9144         RegisterDataType(typeName
, renderer
, editor
); 
9146         // we just registered it, it's the last one 
9147         index 
= m_typeinfo
.GetCount() - 1; 
9153 wxGridCellRenderer
* wxGridTypeRegistry::GetRenderer(int index
) 
9155     wxGridCellRenderer
* renderer 
= m_typeinfo
[index
]->m_renderer
; 
9162 wxGridCellEditor
* wxGridTypeRegistry::GetEditor(int index
) 
9164     wxGridCellEditor
* editor 
= m_typeinfo
[index
]->m_editor
; 
9171 #endif // wxUSE_GRID