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" 
  51 #include "wx/generic/gridsel.h" 
  53 const char wxGridNameStr
[] = "grid"; 
  55 #if defined(__WXMOTIF__) 
  56     #define WXUNUSED_MOTIF(identifier)  WXUNUSED(identifier) 
  58     #define WXUNUSED_MOTIF(identifier)  identifier 
  61 #if defined(__WXGTK__) 
  62     #define WXUNUSED_GTK(identifier)    WXUNUSED(identifier) 
  64     #define WXUNUSED_GTK(identifier)    identifier 
  67 // Required for wxIs... functions 
  70 // ---------------------------------------------------------------------------- 
  72 // ---------------------------------------------------------------------------- 
  74 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr 
*, wxArrayAttrs
, 
  75                                  class WXDLLIMPEXP_ADV
); 
  77 struct wxGridCellWithAttr
 
  79     wxGridCellWithAttr(int row
, int col
, wxGridCellAttr 
*attr_
) 
  80         : coords(row
, col
), attr(attr_
) 
  85     wxGridCellWithAttr(const wxGridCellWithAttr
& other
) 
  86         : coords(other
.coords
), 
  92     wxGridCellWithAttr
& operator=(const wxGridCellWithAttr
& other
) 
  94         coords 
= other
.coords
; 
  95         if (attr 
!= other
.attr
) 
 104     void ChangeAttr(wxGridCellAttr
* new_attr
) 
 106         if (attr 
!= new_attr
) 
 108             // "Delete" (i.e. DecRef) the old attribute. 
 111             // Take ownership of the new attribute, i.e. no IncRef. 
 115     ~wxGridCellWithAttr() 
 120     wxGridCellCoords coords
; 
 121     wxGridCellAttr  
*attr
; 
 124 WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr
, wxGridCellWithAttrArray
, 
 125                               class WXDLLIMPEXP_ADV
); 
 127 #include "wx/arrimpl.cpp" 
 129 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
) 
 130 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
) 
 132 // ---------------------------------------------------------------------------- 
 134 // ---------------------------------------------------------------------------- 
 136 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK
) 
 137 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK
) 
 138 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK
) 
 139 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK
) 
 140 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG
) 
 141 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK
) 
 142 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK
) 
 143 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK
) 
 144 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK
) 
 145 DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE
) 
 146 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE
) 
 147 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE
) 
 148 DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT
) 
 149 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE
) 
 150 DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL
) 
 151 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN
) 
 152 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN
) 
 153 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED
) 
 155 // ---------------------------------------------------------------------------- 
 157 // ---------------------------------------------------------------------------- 
 159 // common base class for various grid subwindows 
 160 class WXDLLIMPEXP_ADV wxGridSubwindow 
: public wxWindow
 
 163     wxGridSubwindow() { m_owner 
= NULL
; } 
 164     wxGridSubwindow(wxGrid 
*owner
, 
 168                     int additionalStyle 
= 0, 
 169                     const wxString
& name 
= wxPanelNameStr
) 
 170         : wxWindow(owner
, id
, pos
, size
, 
 171                    wxBORDER_NONE 
| additionalStyle
, 
 177     virtual bool AcceptsFocus() const { return false; } 
 179     wxGrid 
*GetOwner() { return m_owner
; } 
 182     void OnMouseCaptureLost(wxMouseCaptureLostEvent
& event
); 
 186     DECLARE_EVENT_TABLE() 
 187     DECLARE_NO_COPY_CLASS(wxGridSubwindow
) 
 190 class WXDLLIMPEXP_ADV wxGridRowLabelWindow 
: public wxGridSubwindow
 
 193     wxGridRowLabelWindow() { } 
 194     wxGridRowLabelWindow( wxGrid 
*parent
, wxWindowID id
, 
 195                           const wxPoint 
&pos
, const wxSize 
&size 
); 
 198     void OnPaint( wxPaintEvent
& event 
); 
 199     void OnMouseEvent( wxMouseEvent
& event 
); 
 200     void OnMouseWheel( wxMouseEvent
& event 
); 
 202     DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow
) 
 203     DECLARE_EVENT_TABLE() 
 204     DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow
) 
 208 class WXDLLIMPEXP_ADV wxGridColLabelWindow 
: public wxGridSubwindow
 
 211     wxGridColLabelWindow() { } 
 212     wxGridColLabelWindow( wxGrid 
*parent
, wxWindowID id
, 
 213                           const wxPoint 
&pos
, const wxSize 
&size 
); 
 216     void OnPaint( wxPaintEvent
& event 
); 
 217     void OnMouseEvent( wxMouseEvent
& event 
); 
 218     void OnMouseWheel( wxMouseEvent
& event 
); 
 220     DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow
) 
 221     DECLARE_EVENT_TABLE() 
 222     DECLARE_NO_COPY_CLASS(wxGridColLabelWindow
) 
 226 class WXDLLIMPEXP_ADV wxGridCornerLabelWindow 
: public wxGridSubwindow
 
 229     wxGridCornerLabelWindow() { } 
 230     wxGridCornerLabelWindow( wxGrid 
*parent
, wxWindowID id
, 
 231                              const wxPoint 
&pos
, const wxSize 
&size 
); 
 234     void OnMouseEvent( wxMouseEvent
& event 
); 
 235     void OnMouseWheel( wxMouseEvent
& event 
); 
 236     void OnPaint( wxPaintEvent
& event 
); 
 238     DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow
) 
 239     DECLARE_EVENT_TABLE() 
 240     DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow
) 
 243 class WXDLLIMPEXP_ADV wxGridWindow 
: public wxGridSubwindow
 
 248         m_rowLabelWin 
= NULL
; 
 249         m_colLabelWin 
= NULL
; 
 252     wxGridWindow( wxGrid 
*parent
, 
 253                   wxGridRowLabelWindow 
*rowLblWin
, 
 254                   wxGridColLabelWindow 
*colLblWin
, 
 255                   wxWindowID id
, const wxPoint 
&pos
, const wxSize 
&size 
); 
 257     void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
); 
 259     virtual bool AcceptsFocus() const { return true; } 
 262     wxGridRowLabelWindow     
*m_rowLabelWin
; 
 263     wxGridColLabelWindow     
*m_colLabelWin
; 
 265     void OnPaint( wxPaintEvent 
&event 
); 
 266     void OnMouseWheel( wxMouseEvent
& event 
); 
 267     void OnMouseEvent( wxMouseEvent
& event 
); 
 268     void OnKeyDown( wxKeyEvent
& ); 
 269     void OnKeyUp( wxKeyEvent
& ); 
 270     void OnChar( wxKeyEvent
& ); 
 271     void OnEraseBackground( wxEraseEvent
& ); 
 272     void OnFocus( wxFocusEvent
& ); 
 274     DECLARE_DYNAMIC_CLASS(wxGridWindow
) 
 275     DECLARE_EVENT_TABLE() 
 276     DECLARE_NO_COPY_CLASS(wxGridWindow
) 
 280 class wxGridCellEditorEvtHandler 
: public wxEvtHandler
 
 283     wxGridCellEditorEvtHandler(wxGrid
* grid
, wxGridCellEditor
* editor
) 
 290     void OnKillFocus(wxFocusEvent
& event
); 
 291     void OnKeyDown(wxKeyEvent
& event
); 
 292     void OnChar(wxKeyEvent
& event
); 
 294     void SetInSetFocus(bool inSetFocus
) { m_inSetFocus 
= inSetFocus
; } 
 298     wxGridCellEditor   
*m_editor
; 
 300     // Work around the fact that a focus kill event can be sent to 
 301     // a combobox within a set focus event. 
 304     DECLARE_EVENT_TABLE() 
 305     DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler
) 
 306     DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler
) 
 310 IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler
, wxEvtHandler
) 
 312 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler
, wxEvtHandler 
) 
 313     EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus 
) 
 314     EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown 
) 
 315     EVT_CHAR( wxGridCellEditorEvtHandler::OnChar 
) 
 319 // ---------------------------------------------------------------------------- 
 320 // the internal data representation used by wxGridCellAttrProvider 
 321 // ---------------------------------------------------------------------------- 
 323 // this class stores attributes set for cells 
 324 class WXDLLIMPEXP_ADV wxGridCellAttrData
 
 327     void SetAttr(wxGridCellAttr 
*attr
, int row
, int col
); 
 328     wxGridCellAttr 
*GetAttr(int row
, int col
) const; 
 329     void UpdateAttrRows( size_t pos
, int numRows 
); 
 330     void UpdateAttrCols( size_t pos
, int numCols 
); 
 333     // searches for the attr for given cell, returns wxNOT_FOUND if not found 
 334     int FindIndex(int row
, int col
) const; 
 336     wxGridCellWithAttrArray m_attrs
; 
 339 // this class stores attributes set for rows or columns 
 340 class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
 
 343     // empty ctor to suppress warnings 
 344     wxGridRowOrColAttrData() {} 
 345     ~wxGridRowOrColAttrData(); 
 347     void SetAttr(wxGridCellAttr 
*attr
, int rowOrCol
); 
 348     wxGridCellAttr 
*GetAttr(int rowOrCol
) const; 
 349     void UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols 
); 
 352     wxArrayInt m_rowsOrCols
; 
 353     wxArrayAttrs m_attrs
; 
 356 // NB: this is just a wrapper around 3 objects: one which stores cell 
 357 //     attributes, and 2 others for row/col ones 
 358 class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
 
 361     wxGridCellAttrData m_cellAttrs
; 
 362     wxGridRowOrColAttrData m_rowAttrs
, 
 367 // ---------------------------------------------------------------------------- 
 368 // data structures used for the data type registry 
 369 // ---------------------------------------------------------------------------- 
 371 struct wxGridDataTypeInfo
 
 373     wxGridDataTypeInfo(const wxString
& typeName
, 
 374                        wxGridCellRenderer
* renderer
, 
 375                        wxGridCellEditor
* editor
) 
 376         : m_typeName(typeName
), m_renderer(renderer
), m_editor(editor
) 
 379     ~wxGridDataTypeInfo() 
 381         wxSafeDecRef(m_renderer
); 
 382         wxSafeDecRef(m_editor
); 
 386     wxGridCellRenderer
* m_renderer
; 
 387     wxGridCellEditor
*   m_editor
; 
 389     DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo
) 
 393 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo
*, wxGridDataTypeInfoArray
, 
 394                                  class WXDLLIMPEXP_ADV
); 
 397 class WXDLLIMPEXP_ADV wxGridTypeRegistry
 
 400     wxGridTypeRegistry() {} 
 401     ~wxGridTypeRegistry(); 
 403     void RegisterDataType(const wxString
& typeName
, 
 404                      wxGridCellRenderer
* renderer
, 
 405                      wxGridCellEditor
* editor
); 
 407     // find one of already registered data types 
 408     int FindRegisteredDataType(const wxString
& typeName
); 
 410     // try to FindRegisteredDataType(), if this fails and typeName is one of 
 411     // standard typenames, register it and return its index 
 412     int FindDataType(const wxString
& typeName
); 
 414     // try to FindDataType(), if it fails see if it is not one of already 
 415     // registered data types with some params in which case clone the 
 416     // registered data type and set params for it 
 417     int FindOrCloneDataType(const wxString
& typeName
); 
 419     wxGridCellRenderer
* GetRenderer(int index
); 
 420     wxGridCellEditor
*   GetEditor(int index
); 
 423     wxGridDataTypeInfoArray m_typeinfo
; 
 426 // ---------------------------------------------------------------------------- 
 427 // operations classes abstracting the difference between operating on rows and 
 429 // ---------------------------------------------------------------------------- 
 431 // This class allows to write a function only once because by using its methods 
 432 // it will apply to both columns and rows. 
 434 // This is an abstract interface definition, the two concrete implementations 
 435 // below should be used when working with rows and columns respectively. 
 436 class wxGridOperations
 
 439     // Returns the operations in the other direction, i.e. wxGridRowOperations 
 440     // if this object is a wxGridColumnOperations and vice versa. 
 441     virtual wxGridOperations
& Dual() const = 0; 
 443     // Return the number of rows or columns. 
 444     virtual int GetNumberOfLines(const wxGrid 
*grid
) const = 0; 
 446     // Return the selection mode which allows selecting rows or columns. 
 447     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const = 0; 
 449     // Make a wxGridCellCoords from the given components: thisDir is row or 
 450     // column and otherDir is column or row 
 451     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const = 0; 
 453     // Calculate the scrolled position of the given abscissa or ordinate. 
 454     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const = 0; 
 456     // Selects the horizontal or vertical component from the given object. 
 457     virtual int Select(const wxGridCellCoords
& coords
) const = 0; 
 458     virtual int Select(const wxPoint
& pt
) const = 0; 
 459     virtual int Select(const wxSize
& sz
) const = 0; 
 460     virtual int Select(const wxRect
& r
) const = 0; 
 461     virtual int& Select(wxRect
& r
) const = 0; 
 463     // Returns width or height of the rectangle 
 464     virtual int& SelectSize(wxRect
& r
) const = 0; 
 466     // Make a wxSize such that Select() applied to it returns first component 
 467     virtual wxSize 
MakeSize(int first
, int second
) const = 0; 
 469     // Sets the row or column component of the given cell coordinates 
 470     virtual void Set(wxGridCellCoords
& coords
, int line
) const = 0; 
 473     // Draws a line parallel to the row or column, i.e. horizontal or vertical: 
 474     // pos is the horizontal or vertical position of the line and start and end 
 475     // are the coordinates of the line extremities in the other direction 
 477         DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const = 0; 
 479     // Draw a horizontal or vertical line across the given rectangle 
 480     // (this is implemented in terms of above and uses Select() to extract 
 481     // start and end from the given rectangle) 
 482     void DrawParallelLineInRect(wxDC
& dc
, const wxRect
& rect
, int pos
) const 
 484         const int posStart 
= Select(rect
.GetPosition()); 
 485         DrawParallelLine(dc
, posStart
, posStart 
+ Select(rect
.GetSize()), pos
); 
 489     // Return the row or column at the given pixel coordinate. 
 491         PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const = 0; 
 493     // Get the top/left position, in pixels, of the given row or column 
 494     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const = 0; 
 496     // Get the bottom/right position, in pixels, of the given row or column 
 497     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const = 0; 
 499     // Get the height/width of the given row/column 
 500     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const = 0; 
 502     // Get wxGrid::m_rowBottoms/m_colRights array 
 503     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const = 0; 
 505     // Get default height row height or column width 
 506     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const = 0; 
 508     // Return the minimal acceptable row height or column width 
 509     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const = 0; 
 511     // Return the minimal row height or column width 
 512     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const = 0; 
 514     // Set the row height or column width 
 515     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const = 0; 
 517     // True if rows/columns can be resized by user 
 518     virtual bool CanResizeLines(const wxGrid 
*grid
) const = 0; 
 521     // Return the index of the line at the given position 
 523     // NB: currently this is always identity for the rows as reordering is only 
 524     //     implemented for the lines 
 525     virtual int GetLineAt(const wxGrid 
*grid
, int line
) const = 0; 
 528     // Get the row or column label window 
 529     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const = 0; 
 531     // Get the width or height of the row or column label window 
 532     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const = 0; 
 535     // This class is never used polymorphically but give it a virtual dtor 
 536     // anyhow to suppress g++ complaints about it 
 537     virtual ~wxGridOperations() { } 
 540 class wxGridRowOperations 
: public wxGridOperations
 
 543     virtual wxGridOperations
& Dual() const; 
 545     virtual int GetNumberOfLines(const wxGrid 
*grid
) const 
 546         { return grid
->GetNumberRows(); } 
 548     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const 
 549         { return wxGrid::wxGridSelectRows
; } 
 551     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const 
 552         { return wxGridCellCoords(thisDir
, otherDir
); } 
 554     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const 
 555         { return grid
->CalcScrolledPosition(wxPoint(pos
, 0)).x
; } 
 557     virtual int Select(const wxGridCellCoords
& c
) const { return c
.GetRow(); } 
 558     virtual int Select(const wxPoint
& pt
) const { return pt
.x
; } 
 559     virtual int Select(const wxSize
& sz
) const { return sz
.x
; } 
 560     virtual int Select(const wxRect
& r
) const { return r
.x
; } 
 561     virtual int& Select(wxRect
& r
) const { return r
.x
; } 
 562     virtual int& SelectSize(wxRect
& r
) const { return r
.width
; } 
 563     virtual wxSize 
MakeSize(int first
, int second
) const 
 564         { return wxSize(first
, second
); } 
 565     virtual void Set(wxGridCellCoords
& coords
, int line
) const 
 566         { coords
.SetRow(line
); } 
 568     virtual void DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const 
 569         { dc
.DrawLine(start
, pos
, end
, pos
); } 
 571     virtual int PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const 
 572         { return grid
->YToRow(pos
, clip
); } 
 573     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const 
 574         { return grid
->GetRowTop(line
); } 
 575     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const 
 576         { return grid
->GetRowBottom(line
); } 
 577     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const 
 578         { return grid
->GetRowHeight(line
); } 
 579     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const 
 580         { return grid
->m_rowBottoms
; } 
 581     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const 
 582         { return grid
->GetDefaultRowSize(); } 
 583     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const 
 584         { return grid
->GetRowMinimalAcceptableHeight(); } 
 585     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const 
 586         { return grid
->GetRowMinimalHeight(line
); } 
 587     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const 
 588         { grid
->SetRowSize(line
, size
); } 
 589     virtual bool CanResizeLines(const wxGrid 
*grid
) const 
 590         { return grid
->CanDragRowSize(); } 
 592     virtual int GetLineAt(const wxGrid 
* WXUNUSED(grid
), int line
) const 
 593         { return line
; } // TODO: implement row reordering 
 595     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const 
 596         { return grid
->GetGridRowLabelWindow(); } 
 597     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const 
 598         { return grid
->GetRowLabelSize(); } 
 601 class wxGridColumnOperations 
: public wxGridOperations
 
 604     virtual wxGridOperations
& Dual() const; 
 606     virtual int GetNumberOfLines(const wxGrid 
*grid
) const 
 607         { return grid
->GetNumberCols(); } 
 609     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const 
 610         { return wxGrid::wxGridSelectColumns
; } 
 612     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const 
 613         { return wxGridCellCoords(otherDir
, thisDir
); } 
 615     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const 
 616         { return grid
->CalcScrolledPosition(wxPoint(0, pos
)).y
; } 
 618     virtual int Select(const wxGridCellCoords
& c
) const { return c
.GetCol(); } 
 619     virtual int Select(const wxPoint
& pt
) const { return pt
.y
; } 
 620     virtual int Select(const wxSize
& sz
) const { return sz
.y
; } 
 621     virtual int Select(const wxRect
& r
) const { return r
.y
; } 
 622     virtual int& Select(wxRect
& r
) const { return r
.y
; } 
 623     virtual int& SelectSize(wxRect
& r
) const { return r
.height
; } 
 624     virtual wxSize 
MakeSize(int first
, int second
) const 
 625         { return wxSize(second
, first
); } 
 626     virtual void Set(wxGridCellCoords
& coords
, int line
) const 
 627         { coords
.SetCol(line
); } 
 629     virtual void DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const 
 630         { dc
.DrawLine(pos
, start
, pos
, end
); } 
 632     virtual int PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const 
 633         { return grid
->XToCol(pos
, clip
); } 
 634     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const 
 635         { return grid
->GetColLeft(line
); } 
 636     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const 
 637         { return grid
->GetColRight(line
); } 
 638     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const 
 639         { return grid
->GetColWidth(line
); } 
 640     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const 
 641         { return grid
->m_colRights
; } 
 642     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const 
 643         { return grid
->GetDefaultColSize(); } 
 644     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const 
 645         { return grid
->GetColMinimalAcceptableWidth(); } 
 646     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const 
 647         { return grid
->GetColMinimalWidth(line
); } 
 648     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const 
 649         { grid
->SetColSize(line
, size
); } 
 650     virtual bool CanResizeLines(const wxGrid 
*grid
) const 
 651         { return grid
->CanDragColSize(); } 
 653     virtual int GetLineAt(const wxGrid 
*grid
, int line
) const 
 654         { return grid
->GetColAt(line
); } 
 656     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const 
 657         { return grid
->GetGridColLabelWindow(); } 
 658     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const 
 659         { return grid
->GetColLabelSize(); } 
 662 wxGridOperations
& wxGridRowOperations::Dual() const 
 664     static wxGridColumnOperations s_colOper
; 
 669 wxGridOperations
& wxGridColumnOperations::Dual() const 
 671     static wxGridRowOperations s_rowOper
; 
 676 // This class abstracts the difference between operations going forward 
 677 // (down/right) and backward (up/left) and allows to use the same code for 
 678 // functions which differ only in the direction of grid traversal 
 680 // Like wxGridOperations it's an ABC with two concrete subclasses below. Unlike 
 681 // it, this is a normal object and not just a function dispatch table and has a 
 684 // Note: the explanation of this discrepancy is the existence of (very useful) 
 685 // Dual() method in wxGridOperations which forces us to make wxGridOperations a 
 686 // function dispatcher only. 
 687 class wxGridDirectionOperations
 
 690     // The oper parameter to ctor selects whether we work with rows or columns 
 691     wxGridDirectionOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 697     // Check if the component of this point in our direction is at the 
 698     // boundary, i.e. is the first/last row/column 
 699     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const = 0; 
 701     // Increment the component of this point in our direction 
 702     virtual void Advance(wxGridCellCoords
& coords
) const = 0; 
 704     // Find the line at the given distance, in pixels, away from this one 
 705     // (this uses clipping, i.e. anything after the last line is counted as the 
 706     // last one and anything before the first one as 0) 
 707     virtual int MoveByPixelDistance(int line
, int distance
) const = 0; 
 709     // This class is never used polymorphically but give it a virtual dtor 
 710     // anyhow to suppress g++ complaints about it 
 711     virtual ~wxGridDirectionOperations() { } 
 714     wxGrid 
* const m_grid
; 
 715     const wxGridOperations
& m_oper
; 
 718 class wxGridBackwardOperations 
: public wxGridDirectionOperations
 
 721     wxGridBackwardOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 722         : wxGridDirectionOperations(grid
, oper
) 
 726     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const 
 728         wxASSERT_MSG( m_oper
.Select(coords
) >= 0, "invalid row/column" ); 
 730         return m_oper
.Select(coords
) == 0; 
 733     virtual void Advance(wxGridCellCoords
& coords
) const 
 735         wxASSERT( !IsAtBoundary(coords
) ); 
 737         m_oper
.Set(coords
, m_oper
.Select(coords
) - 1); 
 740     virtual int MoveByPixelDistance(int line
, int distance
) const 
 742         int pos 
= m_oper
.GetLineStartPos(m_grid
, line
); 
 743         return m_oper
.PosToLine(m_grid
, pos 
- distance 
+ 1, true); 
 747 class wxGridForwardOperations 
: public wxGridDirectionOperations
 
 750     wxGridForwardOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 751         : wxGridDirectionOperations(grid
, oper
), 
 752           m_numLines(oper
.GetNumberOfLines(grid
)) 
 756     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const 
 758         wxASSERT_MSG( m_oper
.Select(coords
) < m_numLines
, "invalid row/column" ); 
 760         return m_oper
.Select(coords
) == m_numLines 
- 1; 
 763     virtual void Advance(wxGridCellCoords
& coords
) const 
 765         wxASSERT( !IsAtBoundary(coords
) ); 
 767         m_oper
.Set(coords
, m_oper
.Select(coords
) + 1); 
 770     virtual int MoveByPixelDistance(int line
, int distance
) const 
 772         int pos 
= m_oper
.GetLineStartPos(m_grid
, line
); 
 773         return m_oper
.PosToLine(m_grid
, pos 
+ distance
, true); 
 777     const int m_numLines
; 
 780 // ---------------------------------------------------------------------------- 
 782 // ---------------------------------------------------------------------------- 
 784 //#define DEBUG_ATTR_CACHE 
 785 #ifdef DEBUG_ATTR_CACHE 
 786     static size_t gs_nAttrCacheHits 
= 0; 
 787     static size_t gs_nAttrCacheMisses 
= 0; 
 790 // ---------------------------------------------------------------------------- 
 792 // ---------------------------------------------------------------------------- 
 794 wxGridCellCoords 
wxGridNoCellCoords( -1, -1 ); 
 795 wxRect 
wxGridNoCellRect( -1, -1, -1, -1 ); 
 801 const size_t GRID_SCROLL_LINE_X 
= 15; 
 802 const size_t GRID_SCROLL_LINE_Y 
= GRID_SCROLL_LINE_X
; 
 804 // the size of hash tables used a bit everywhere (the max number of elements 
 805 // in these hash tables is the number of rows/columns) 
 806 const int GRID_HASH_SIZE 
= 100; 
 808 // the minimal distance in pixels the mouse needs to move to start a drag 
 810 const int DRAG_SENSITIVITY 
= 3; 
 812 } // anonymous namespace 
 814 // ---------------------------------------------------------------------------- 
 816 // ---------------------------------------------------------------------------- 
 821 // ensure that first is less or equal to second, swapping the values if 
 823 void EnsureFirstLessThanSecond(int& first
, int& second
) 
 825     if ( first 
> second 
) 
 826         wxSwap(first
, second
); 
 829 } // anonymous namespace 
 831 // ============================================================================ 
 833 // ============================================================================ 
 835 // ---------------------------------------------------------------------------- 
 837 // ---------------------------------------------------------------------------- 
 839 wxGridCellEditor::wxGridCellEditor() 
 845 wxGridCellEditor::~wxGridCellEditor() 
 850 void wxGridCellEditor::Create(wxWindow
* WXUNUSED(parent
), 
 851                               wxWindowID 
WXUNUSED(id
), 
 852                               wxEvtHandler
* evtHandler
) 
 855         m_control
->PushEventHandler(evtHandler
); 
 858 void wxGridCellEditor::PaintBackground(const wxRect
& rectCell
, 
 859                                        wxGridCellAttr 
*attr
) 
 861     // erase the background because we might not fill the cell 
 862     wxClientDC 
dc(m_control
->GetParent()); 
 863     wxGridWindow
* gridWindow 
= wxDynamicCast(m_control
->GetParent(), wxGridWindow
); 
 865         gridWindow
->GetOwner()->PrepareDC(dc
); 
 867     dc
.SetPen(*wxTRANSPARENT_PEN
); 
 868     dc
.SetBrush(wxBrush(attr
->GetBackgroundColour())); 
 869     dc
.DrawRectangle(rectCell
); 
 871     // redraw the control we just painted over 
 872     m_control
->Refresh(); 
 875 void wxGridCellEditor::Destroy() 
 879         m_control
->PopEventHandler( true /* delete it*/ ); 
 881         m_control
->Destroy(); 
 886 void wxGridCellEditor::Show(bool show
, wxGridCellAttr 
*attr
) 
 888     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
 890     m_control
->Show(show
); 
 894         // set the colours/fonts if we have any 
 897             m_colFgOld 
= m_control
->GetForegroundColour(); 
 898             m_control
->SetForegroundColour(attr
->GetTextColour()); 
 900             m_colBgOld 
= m_control
->GetBackgroundColour(); 
 901             m_control
->SetBackgroundColour(attr
->GetBackgroundColour()); 
 903 // Workaround for GTK+1 font setting problem on some platforms 
 904 #if !defined(__WXGTK__) || defined(__WXGTK20__) 
 905             m_fontOld 
= m_control
->GetFont(); 
 906             m_control
->SetFont(attr
->GetFont()); 
 909             // can't do anything more in the base class version, the other 
 910             // attributes may only be used by the derived classes 
 915         // restore the standard colours fonts 
 916         if ( m_colFgOld
.Ok() ) 
 918             m_control
->SetForegroundColour(m_colFgOld
); 
 919             m_colFgOld 
= wxNullColour
; 
 922         if ( m_colBgOld
.Ok() ) 
 924             m_control
->SetBackgroundColour(m_colBgOld
); 
 925             m_colBgOld 
= wxNullColour
; 
 928 // Workaround for GTK+1 font setting problem on some platforms 
 929 #if !defined(__WXGTK__) || defined(__WXGTK20__) 
 930         if ( m_fontOld
.Ok() ) 
 932             m_control
->SetFont(m_fontOld
); 
 933             m_fontOld 
= wxNullFont
; 
 939 void wxGridCellEditor::SetSize(const wxRect
& rect
) 
 941     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
 943     m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
); 
 946 void wxGridCellEditor::HandleReturn(wxKeyEvent
& event
) 
 951 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent
& event
) 
 953     bool ctrl 
= event
.ControlDown(); 
 954     bool alt  
= event
.AltDown(); 
 957     // On the Mac the Alt key is more like shift and is used for entry of 
 958     // valid characters, so check for Ctrl and Meta instead. 
 959     alt 
= event
.MetaDown(); 
 962     // Assume it's not a valid char if ctrl or alt is down, but if both are 
 963     // down then it may be because of an AltGr key combination, so let them 
 964     // through in that case. 
 965     if ((ctrl 
|| alt
) && !(ctrl 
&& alt
)) 
 969     // if the unicode key code is not really a unicode character (it may 
 970     // be a function key or etc., the platforms appear to always give us a 
 971     // small value in this case) then fallback to the ASCII key code but 
 972     // don't do anything for function keys or etc. 
 973     if ( event
.GetUnicodeKey() > 127 && event
.GetKeyCode() > 127 ) 
 976     if ( event
.GetKeyCode() > 255 ) 
 983 void wxGridCellEditor::StartingKey(wxKeyEvent
& event
) 
 988 void wxGridCellEditor::StartingClick() 
 994 // ---------------------------------------------------------------------------- 
 995 // wxGridCellTextEditor 
 996 // ---------------------------------------------------------------------------- 
 998 wxGridCellTextEditor::wxGridCellTextEditor() 
1003 void wxGridCellTextEditor::Create(wxWindow
* parent
, 
1005                                   wxEvtHandler
* evtHandler
) 
1007     DoCreate(parent
, id
, evtHandler
); 
1010 void wxGridCellTextEditor::DoCreate(wxWindow
* parent
, 
1012                                     wxEvtHandler
* evtHandler
, 
1015     style 
|= wxTE_PROCESS_ENTER 
| wxTE_PROCESS_TAB 
| wxNO_BORDER
; 
1017     m_control 
= new wxTextCtrl(parent
, id
, wxEmptyString
, 
1018                                wxDefaultPosition
, wxDefaultSize
, 
1021     // set max length allowed in the textctrl, if the parameter was set 
1022     if ( m_maxChars 
!= 0 ) 
1024         Text()->SetMaxLength(m_maxChars
); 
1027     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1030 void wxGridCellTextEditor::PaintBackground(const wxRect
& WXUNUSED(rectCell
), 
1031                                            wxGridCellAttr 
* WXUNUSED(attr
)) 
1033     // as we fill the entire client area, 
1034     // don't do anything here to minimize flicker 
1037 void wxGridCellTextEditor::SetSize(const wxRect
& rectOrig
) 
1039     wxRect 
rect(rectOrig
); 
1041     // Make the edit control large enough to allow for internal margins 
1043     // TODO: remove this if the text ctrl sizing is improved esp. for unix 
1045 #if defined(__WXGTK__) 
1053 #elif defined(__WXMSW__) 
1067     int extra_x 
= ( rect
.x 
> 2 ) ? 2 : 1; 
1068     int extra_y 
= ( rect
.y 
> 2 ) ? 2 : 1; 
1070     #if defined(__WXMOTIF__) 
1075     rect
.SetLeft( wxMax(0, rect
.x 
- extra_x
) ); 
1076     rect
.SetTop( wxMax(0, rect
.y 
- extra_y
) ); 
1077     rect
.SetRight( rect
.GetRight() + 2 * extra_x 
); 
1078     rect
.SetBottom( rect
.GetBottom() + 2 * extra_y 
); 
1081     wxGridCellEditor::SetSize(rect
); 
1084 void wxGridCellTextEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1086     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1088     m_startValue 
= grid
->GetTable()->GetValue(row
, col
); 
1090     DoBeginEdit(m_startValue
); 
1093 void wxGridCellTextEditor::DoBeginEdit(const wxString
& startValue
) 
1095     Text()->SetValue(startValue
); 
1096     Text()->SetInsertionPointEnd(); 
1097     Text()->SetSelection(-1, -1); 
1101 bool wxGridCellTextEditor::EndEdit(int row
, int col
, wxGrid
* grid
) 
1103     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1105     bool changed 
= false; 
1106     wxString value 
= Text()->GetValue(); 
1107     if (value 
!= m_startValue
) 
1111         grid
->GetTable()->SetValue(row
, col
, value
); 
1113     m_startValue 
= wxEmptyString
; 
1115     // No point in setting the text of the hidden control 
1116     //Text()->SetValue(m_startValue); 
1121 void wxGridCellTextEditor::Reset() 
1123     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1125     DoReset(m_startValue
); 
1128 void wxGridCellTextEditor::DoReset(const wxString
& startValue
) 
1130     Text()->SetValue(startValue
); 
1131     Text()->SetInsertionPointEnd(); 
1134 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1136     return wxGridCellEditor::IsAcceptedKey(event
); 
1139 void wxGridCellTextEditor::StartingKey(wxKeyEvent
& event
) 
1141     // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no 
1142     // longer an appropriate way to get the character into the text control. 
1143     // Do it ourselves instead.  We know that if we get this far that we have 
1144     // a valid character, so not a whole lot of testing needs to be done. 
1146     wxTextCtrl
* tc 
= Text(); 
1151     ch 
= event
.GetUnicodeKey(); 
1153         ch 
= (wxChar
)event
.GetKeyCode(); 
1155     ch 
= (wxChar
)event
.GetKeyCode(); 
1161             // delete the character at the cursor 
1162             pos 
= tc
->GetInsertionPoint(); 
1163             if (pos 
< tc
->GetLastPosition()) 
1164                 tc
->Remove(pos
, pos 
+ 1); 
1168             // delete the character before the cursor 
1169             pos 
= tc
->GetInsertionPoint(); 
1171                 tc
->Remove(pos 
- 1, pos
); 
1180 void wxGridCellTextEditor::HandleReturn( wxKeyEvent
& 
1181                                          WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) ) 
1183 #if defined(__WXMOTIF__) || defined(__WXGTK__) 
1184     // wxMotif needs a little extra help... 
1185     size_t pos 
= (size_t)( Text()->GetInsertionPoint() ); 
1186     wxString 
s( Text()->GetValue() ); 
1187     s 
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
); 
1188     Text()->SetValue(s
); 
1189     Text()->SetInsertionPoint( pos 
); 
1191     // the other ports can handle a Return key press 
1197 void wxGridCellTextEditor::SetParameters(const wxString
& params
) 
1207         if ( params
.ToLong(&tmp
) ) 
1209             m_maxChars 
= (size_t)tmp
; 
1213             wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() ); 
1218 // return the value in the text control 
1219 wxString 
wxGridCellTextEditor::GetValue() const 
1221     return Text()->GetValue(); 
1224 // ---------------------------------------------------------------------------- 
1225 // wxGridCellNumberEditor 
1226 // ---------------------------------------------------------------------------- 
1228 wxGridCellNumberEditor::wxGridCellNumberEditor(int min
, int max
) 
1234 void wxGridCellNumberEditor::Create(wxWindow
* parent
, 
1236                                     wxEvtHandler
* evtHandler
) 
1241         // create a spin ctrl 
1242         m_control 
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
, 
1243                                    wxDefaultPosition
, wxDefaultSize
, 
1247         wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1252         // just a text control 
1253         wxGridCellTextEditor::Create(parent
, id
, evtHandler
); 
1255 #if wxUSE_VALIDATORS 
1256         Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
)); 
1261 void wxGridCellNumberEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1263     // first get the value 
1264     wxGridTableBase 
*table 
= grid
->GetTable(); 
1265     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
1267         m_valueOld 
= table
->GetValueAsLong(row
, col
); 
1272         wxString sValue 
= table
->GetValue(row
, col
); 
1273         if (! sValue
.ToLong(&m_valueOld
) && ! sValue
.empty()) 
1275             wxFAIL_MSG( _T("this cell doesn't have numeric value") ); 
1283         Spin()->SetValue((int)m_valueOld
); 
1289         DoBeginEdit(GetString()); 
1293 bool wxGridCellNumberEditor::EndEdit(int row
, int col
, 
1302         value 
= Spin()->GetValue(); 
1303         if ( value 
== m_valueOld 
) 
1306         text
.Printf(wxT("%ld"), value
); 
1308     else // using unconstrained input 
1309 #endif // wxUSE_SPINCTRL 
1311         const wxString 
textOld(grid
->GetCellValue(row
, col
)); 
1312         text 
= Text()->GetValue(); 
1315             if ( textOld
.empty() ) 
1318         else // non-empty text now (maybe 0) 
1320             if ( !text
.ToLong(&value
) ) 
1323             // if value == m_valueOld == 0 but old text was "" and new one is 
1324             // "0" something still did change 
1325             if ( value 
== m_valueOld 
&& (value 
|| !textOld
.empty()) ) 
1330     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1331     if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
1332         table
->SetValueAsLong(row
, col
, value
); 
1334         table
->SetValue(row
, col
, text
); 
1339 void wxGridCellNumberEditor::Reset() 
1344         Spin()->SetValue((int)m_valueOld
); 
1349         DoReset(GetString()); 
1353 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1355     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1357         int keycode 
= event
.GetKeyCode(); 
1358         if ( (keycode 
< 128) && 
1359              (wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-')) 
1368 void wxGridCellNumberEditor::StartingKey(wxKeyEvent
& event
) 
1370     int keycode 
= event
.GetKeyCode(); 
1373         if ( wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-') 
1375             wxGridCellTextEditor::StartingKey(event
); 
1377             // skip Skip() below 
1384         if ( wxIsdigit(keycode
) ) 
1386             wxSpinCtrl
* spin 
= (wxSpinCtrl
*)m_control
; 
1387             spin
->SetValue(keycode 
- '0'); 
1388             spin
->SetSelection(1,1); 
1397 void wxGridCellNumberEditor::SetParameters(const wxString
& params
) 
1408         if ( params
.BeforeFirst(_T(',')).ToLong(&tmp
) ) 
1412             if ( params
.AfterFirst(_T(',')).ToLong(&tmp
) ) 
1416                 // skip the error message below 
1421         wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str()); 
1425 // return the value in the spin control if it is there (the text control otherwise) 
1426 wxString 
wxGridCellNumberEditor::GetValue() const 
1433         long value 
= Spin()->GetValue(); 
1434         s
.Printf(wxT("%ld"), value
); 
1439         s 
= Text()->GetValue(); 
1445 // ---------------------------------------------------------------------------- 
1446 // wxGridCellFloatEditor 
1447 // ---------------------------------------------------------------------------- 
1449 wxGridCellFloatEditor::wxGridCellFloatEditor(int width
, int precision
) 
1452     m_precision 
= precision
; 
1455 void wxGridCellFloatEditor::Create(wxWindow
* parent
, 
1457                                    wxEvtHandler
* evtHandler
) 
1459     wxGridCellTextEditor::Create(parent
, id
, evtHandler
); 
1461 #if wxUSE_VALIDATORS 
1462     Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
)); 
1466 void wxGridCellFloatEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1468     // first get the value 
1469     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1470     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
1472         m_valueOld 
= table
->GetValueAsDouble(row
, col
); 
1478         const wxString value 
= table
->GetValue(row
, col
); 
1479         if ( !value
.empty() ) 
1481             if ( !value
.ToDouble(&m_valueOld
) ) 
1483                 wxFAIL_MSG( _T("this cell doesn't have float value") ); 
1489     DoBeginEdit(GetString()); 
1492 bool wxGridCellFloatEditor::EndEdit(int row
, int col
, wxGrid
* grid
) 
1494     const wxString 
text(Text()->GetValue()), 
1495                    textOld(grid
->GetCellValue(row
, col
)); 
1498     if ( !text
.empty() ) 
1500         if ( !text
.ToDouble(&value
) ) 
1503     else // new value is empty string 
1505         if ( textOld
.empty() ) 
1506             return false;           // nothing changed 
1511     // the test for empty strings ensures that we don't skip the value setting 
1512     // when "" is replaced by "0" or vice versa as "" numeric value is also 0. 
1513     if ( wxIsSameDouble(value
, m_valueOld
) && !text
.empty() && !textOld
.empty() ) 
1514         return false;           // nothing changed 
1516     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1518     if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
1519         table
->SetValueAsDouble(row
, col
, value
); 
1521         table
->SetValue(row
, col
, text
); 
1526 void wxGridCellFloatEditor::Reset() 
1528     DoReset(GetString()); 
1531 void wxGridCellFloatEditor::StartingKey(wxKeyEvent
& event
) 
1533     int keycode 
= event
.GetKeyCode(); 
1535     tmpbuf
[0] = (char) keycode
; 
1537     wxString 
strbuf(tmpbuf
, *wxConvCurrent
); 
1540     bool is_decimal_point 
= ( strbuf 
== 
1541        wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) ); 
1543     bool is_decimal_point 
= ( strbuf 
== _T(".") ); 
1546     if ( wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-' 
1547          || is_decimal_point 
) 
1549         wxGridCellTextEditor::StartingKey(event
); 
1551         // skip Skip() below 
1558 void wxGridCellFloatEditor::SetParameters(const wxString
& params
) 
1569         if ( params
.BeforeFirst(_T(',')).ToLong(&tmp
) ) 
1573             if ( params
.AfterFirst(_T(',')).ToLong(&tmp
) ) 
1575                 m_precision 
= (int)tmp
; 
1577                 // skip the error message below 
1582         wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params
.c_str()); 
1586 wxString 
wxGridCellFloatEditor::GetString() const 
1589     if ( m_precision 
== -1 && m_width 
!= -1) 
1591         // default precision 
1592         fmt
.Printf(_T("%%%d.f"), m_width
); 
1594     else if ( m_precision 
!= -1 && m_width 
== -1) 
1597         fmt
.Printf(_T("%%.%df"), m_precision
); 
1599     else if ( m_precision 
!= -1 && m_width 
!= -1 ) 
1601         fmt
.Printf(_T("%%%d.%df"), m_width
, m_precision
); 
1605         // default width/precision 
1609     return wxString::Format(fmt
, m_valueOld
); 
1612 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1614     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1616         const int keycode 
= event
.GetKeyCode(); 
1617         if ( isascii(keycode
) ) 
1620             tmpbuf
[0] = (char) keycode
; 
1622             wxString 
strbuf(tmpbuf
, *wxConvCurrent
); 
1625             const wxString decimalPoint 
= 
1626                 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
); 
1628             const wxString 
decimalPoint(_T('.')); 
1631             // accept digits, 'e' as in '1e+6', also '-', '+', and '.' 
1632             if ( wxIsdigit(keycode
) || 
1633                     tolower(keycode
) == 'e' || 
1634                         keycode 
== decimalPoint 
|| 
1646 #endif // wxUSE_TEXTCTRL 
1650 // ---------------------------------------------------------------------------- 
1651 // wxGridCellBoolEditor 
1652 // ---------------------------------------------------------------------------- 
1654 // the default values for GetValue() 
1655 wxString 
wxGridCellBoolEditor::ms_stringValues
[2] = { _T(""), _T("1") }; 
1657 void wxGridCellBoolEditor::Create(wxWindow
* parent
, 
1659                                   wxEvtHandler
* evtHandler
) 
1661     m_control 
= new wxCheckBox(parent
, id
, wxEmptyString
, 
1662                                wxDefaultPosition
, wxDefaultSize
, 
1665     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1668 void wxGridCellBoolEditor::SetSize(const wxRect
& r
) 
1670     bool resize 
= false; 
1671     wxSize size 
= m_control
->GetSize(); 
1672     wxCoord minSize 
= wxMin(r
.width
, r
.height
); 
1674     // check if the checkbox is not too big/small for this cell 
1675     wxSize sizeBest 
= m_control
->GetBestSize(); 
1676     if ( !(size 
== sizeBest
) ) 
1678         // reset to default size if it had been made smaller 
1684     if ( size
.x 
>= minSize 
|| size
.y 
>= minSize 
) 
1686         // leave 1 pixel margin 
1687         size
.x 
= size
.y 
= minSize 
- 2; 
1694         m_control
->SetSize(size
); 
1697     // position it in the centre of the rectangle (TODO: support alignment?) 
1699 #if defined(__WXGTK__) || defined (__WXMOTIF__) 
1700     // the checkbox without label still has some space to the right in wxGTK, 
1701     // so shift it to the right 
1703 #elif defined(__WXMSW__) 
1704     // here too, but in other way 
1709     int hAlign 
= wxALIGN_CENTRE
; 
1710     int vAlign 
= wxALIGN_CENTRE
; 
1712         GetCellAttr()->GetAlignment(& hAlign
, & vAlign
); 
1715     if (hAlign 
== wxALIGN_LEFT
) 
1723         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1725     else if (hAlign 
== wxALIGN_RIGHT
) 
1727         x 
= r
.x 
+ r
.width 
- size
.x 
- 2; 
1728         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1730     else if (hAlign 
== wxALIGN_CENTRE
) 
1732         x 
= r
.x 
+ r
.width 
/ 2 - size
.x 
/ 2; 
1733         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1736     m_control
->Move(x
, y
); 
1739 void wxGridCellBoolEditor::Show(bool show
, wxGridCellAttr 
*attr
) 
1741     m_control
->Show(show
); 
1745         wxColour colBg 
= attr 
? attr
->GetBackgroundColour() : *wxLIGHT_GREY
; 
1746         CBox()->SetBackgroundColour(colBg
); 
1750 void wxGridCellBoolEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1752     wxASSERT_MSG(m_control
, 
1753                  wxT("The wxGridCellEditor must be created first!")); 
1755     if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
)) 
1757         m_startValue 
= grid
->GetTable()->GetValueAsBool(row
, col
); 
1761         wxString 
cellval( grid
->GetTable()->GetValue(row
, col
) ); 
1763         if ( cellval 
== ms_stringValues
[false] ) 
1764             m_startValue 
= false; 
1765         else if ( cellval 
== ms_stringValues
[true] ) 
1766             m_startValue 
= true; 
1769             // do not try to be smart here and convert it to true or false 
1770             // because we'll still overwrite it with something different and 
1771             // this risks to be very surprising for the user code, let them 
1773             wxFAIL_MSG( _T("invalid value for a cell with bool editor!") ); 
1777     CBox()->SetValue(m_startValue
); 
1781 bool wxGridCellBoolEditor::EndEdit(int row
, int col
, 
1784     wxASSERT_MSG(m_control
, 
1785                  wxT("The wxGridCellEditor must be created first!")); 
1787     bool changed 
= false; 
1788     bool value 
= CBox()->GetValue(); 
1789     if ( value 
!= m_startValue 
) 
1794         wxGridTableBase 
* const table 
= grid
->GetTable(); 
1795         if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
) ) 
1796             table
->SetValueAsBool(row
, col
, value
); 
1798             table
->SetValue(row
, col
, GetValue()); 
1804 void wxGridCellBoolEditor::Reset() 
1806     wxASSERT_MSG(m_control
, 
1807                  wxT("The wxGridCellEditor must be created first!")); 
1809     CBox()->SetValue(m_startValue
); 
1812 void wxGridCellBoolEditor::StartingClick() 
1814     CBox()->SetValue(!CBox()->GetValue()); 
1817 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1819     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1821         int keycode 
= event
.GetKeyCode(); 
1834 void wxGridCellBoolEditor::StartingKey(wxKeyEvent
& event
) 
1836     int keycode 
= event
.GetKeyCode(); 
1840             CBox()->SetValue(!CBox()->GetValue()); 
1844             CBox()->SetValue(true); 
1848             CBox()->SetValue(false); 
1853 wxString 
wxGridCellBoolEditor::GetValue() const 
1855   return ms_stringValues
[CBox()->GetValue()]; 
1859 wxGridCellBoolEditor::UseStringValues(const wxString
& valueTrue
, 
1860                                       const wxString
& valueFalse
) 
1862     ms_stringValues
[false] = valueFalse
; 
1863     ms_stringValues
[true] = valueTrue
; 
1867 wxGridCellBoolEditor::IsTrueValue(const wxString
& value
) 
1869     return value 
== ms_stringValues
[true]; 
1872 #endif // wxUSE_CHECKBOX 
1876 // ---------------------------------------------------------------------------- 
1877 // wxGridCellChoiceEditor 
1878 // ---------------------------------------------------------------------------- 
1880 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString
& choices
, 
1882     : m_choices(choices
), 
1883       m_allowOthers(allowOthers
) { } 
1885 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count
, 
1886                                                const wxString choices
[], 
1888                       : m_allowOthers(allowOthers
) 
1892         m_choices
.Alloc(count
); 
1893         for ( size_t n 
= 0; n 
< count
; n
++ ) 
1895             m_choices
.Add(choices
[n
]); 
1900 wxGridCellEditor 
*wxGridCellChoiceEditor::Clone() const 
1902     wxGridCellChoiceEditor 
*editor 
= new wxGridCellChoiceEditor
; 
1903     editor
->m_allowOthers 
= m_allowOthers
; 
1904     editor
->m_choices 
= m_choices
; 
1909 void wxGridCellChoiceEditor::Create(wxWindow
* parent
, 
1911                                     wxEvtHandler
* evtHandler
) 
1913     int style 
= wxTE_PROCESS_ENTER 
| 
1917     if ( !m_allowOthers 
) 
1918         style 
|= wxCB_READONLY
; 
1919     m_control 
= new wxComboBox(parent
, id
, wxEmptyString
, 
1920                                wxDefaultPosition
, wxDefaultSize
, 
1924     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1927 void wxGridCellChoiceEditor::PaintBackground(const wxRect
& rectCell
, 
1928                                              wxGridCellAttr 
* attr
) 
1930     // as we fill the entire client area, don't do anything here to minimize 
1933     // TODO: It doesn't actually fill the client area since the height of a 
1934     // combo always defaults to the standard.  Until someone has time to 
1935     // figure out the right rectangle to paint, just do it the normal way. 
1936     wxGridCellEditor::PaintBackground(rectCell
, attr
); 
1939 void wxGridCellChoiceEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1941     wxASSERT_MSG(m_control
, 
1942                  wxT("The wxGridCellEditor must be created first!")); 
1944     wxGridCellEditorEvtHandler
* evtHandler 
= NULL
; 
1946         evtHandler 
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
); 
1948     // Don't immediately end if we get a kill focus event within BeginEdit 
1950         evtHandler
->SetInSetFocus(true); 
1952     m_startValue 
= grid
->GetTable()->GetValue(row
, col
); 
1954     Reset(); // this updates combo box to correspond to m_startValue 
1956     Combo()->SetFocus(); 
1960         // When dropping down the menu, a kill focus event 
1961         // happens after this point, so we can't reset the flag yet. 
1962 #if !defined(__WXGTK20__) 
1963         evtHandler
->SetInSetFocus(false); 
1968 bool wxGridCellChoiceEditor::EndEdit(int row
, int col
, 
1971     wxString value 
= Combo()->GetValue(); 
1972     if ( value 
== m_startValue 
) 
1975     grid
->GetTable()->SetValue(row
, col
, value
); 
1980 void wxGridCellChoiceEditor::Reset() 
1984         Combo()->SetValue(m_startValue
); 
1985         Combo()->SetInsertionPointEnd(); 
1987     else // the combobox is read-only 
1989         // find the right position, or default to the first if not found 
1990         int pos 
= Combo()->FindString(m_startValue
); 
1991         if (pos 
== wxNOT_FOUND
) 
1993         Combo()->SetSelection(pos
); 
1997 void wxGridCellChoiceEditor::SetParameters(const wxString
& params
) 
2007     wxStringTokenizer 
tk(params
, _T(',')); 
2008     while ( tk
.HasMoreTokens() ) 
2010         m_choices
.Add(tk
.GetNextToken()); 
2014 // return the value in the text control 
2015 wxString 
wxGridCellChoiceEditor::GetValue() const 
2017   return Combo()->GetValue(); 
2020 #endif // wxUSE_COMBOBOX 
2022 // ---------------------------------------------------------------------------- 
2023 // wxGridCellEditorEvtHandler 
2024 // ---------------------------------------------------------------------------- 
2026 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent
& event
) 
2028     // Don't disable the cell if we're just starting to edit it 
2033     m_grid
->DisableCellEditControl(); 
2038 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent
& event
) 
2040     switch ( event
.GetKeyCode() ) 
2044             m_grid
->DisableCellEditControl(); 
2048             m_grid
->GetEventHandler()->ProcessEvent( event 
); 
2052         case WXK_NUMPAD_ENTER
: 
2053             if (!m_grid
->GetEventHandler()->ProcessEvent(event
)) 
2054                 m_editor
->HandleReturn(event
); 
2063 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent
& event
) 
2065     int row 
= m_grid
->GetGridCursorRow(); 
2066     int col 
= m_grid
->GetGridCursorCol(); 
2067     wxRect rect 
= m_grid
->CellToRect( row
, col 
); 
2069     m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch 
); 
2071     // if cell width is smaller than grid client area, cell is wholly visible 
2072     bool wholeCellVisible 
= (rect
.GetWidth() < cw
); 
2074     switch ( event
.GetKeyCode() ) 
2079         case WXK_NUMPAD_ENTER
: 
2084             if ( wholeCellVisible 
) 
2086                 // no special processing needed... 
2091             // do special processing for partly visible cell... 
2093             // get the widths of all cells previous to this one 
2095             for ( int i 
= 0; i 
< col
; i
++ ) 
2097                 colXPos 
+= m_grid
->GetColSize(i
); 
2100             int xUnit 
= 1, yUnit 
= 1; 
2101             m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
); 
2104                 m_grid
->Scroll(colXPos 
/ xUnit 
- 1, m_grid
->GetScrollPos(wxVERTICAL
)); 
2108                 m_grid
->Scroll(colXPos 
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
)); 
2116             if ( wholeCellVisible 
) 
2118                 // no special processing needed... 
2123             // do special processing for partly visible cell... 
2126             wxString value 
= m_grid
->GetCellValue(row
, col
); 
2127             if ( wxEmptyString 
!= value 
) 
2129                 // get width of cell CONTENTS (text) 
2131                 wxFont font 
= m_grid
->GetCellFont(row
, col
); 
2132                 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
); 
2134                 // try to RIGHT align the text by scrolling 
2135                 int client_right 
= m_grid
->GetGridWindow()->GetClientSize().GetWidth(); 
2137                 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far, 
2138                 // otherwise the last part of the cell content might be hidden below the scroll bar 
2139                 // FIXME: maybe there is a more suitable correction? 
2140                 textWidth 
-= (client_right 
- (m_grid
->GetScrollLineX() * 2)); 
2141                 if ( textWidth 
< 0 ) 
2147             // get the widths of all cells previous to this one 
2149             for ( int i 
= 0; i 
< col
; i
++ ) 
2151                 colXPos 
+= m_grid
->GetColSize(i
); 
2154             // and add the (modified) text width of the cell contents 
2155             // as we'd like to see the last part of the cell contents 
2156             colXPos 
+= textWidth
; 
2158             int xUnit 
= 1, yUnit 
= 1; 
2159             m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
); 
2160             m_grid
->Scroll(colXPos 
/ xUnit 
- 1, m_grid
->GetScrollPos(wxVERTICAL
)); 
2171 // ---------------------------------------------------------------------------- 
2172 // wxGridCellWorker is an (almost) empty common base class for 
2173 // wxGridCellRenderer and wxGridCellEditor managing ref counting 
2174 // ---------------------------------------------------------------------------- 
2176 void wxGridCellWorker::SetParameters(const wxString
& WXUNUSED(params
)) 
2181 wxGridCellWorker::~wxGridCellWorker() 
2185 // ============================================================================ 
2187 // ============================================================================ 
2189 // ---------------------------------------------------------------------------- 
2190 // wxGridCellRenderer 
2191 // ---------------------------------------------------------------------------- 
2193 void wxGridCellRenderer::Draw(wxGrid
& grid
, 
2194                               wxGridCellAttr
& attr
, 
2197                               int WXUNUSED(row
), int WXUNUSED(col
), 
2200     dc
.SetBackgroundMode( wxBRUSHSTYLE_SOLID 
); 
2203     if ( grid
.IsEnabled() ) 
2207             if ( grid
.HasFocus() ) 
2208                 clr 
= grid
.GetSelectionBackground(); 
2210                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
2214             clr 
= attr
.GetBackgroundColour(); 
2217     else // grey out fields if the grid is disabled 
2219         clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
2223     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2224     dc
.DrawRectangle(rect
); 
2227 // ---------------------------------------------------------------------------- 
2228 // wxGridCellStringRenderer 
2229 // ---------------------------------------------------------------------------- 
2231 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid
& grid
, 
2232                                                      const wxGridCellAttr
& attr
, 
2236     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
2238     // TODO some special colours for attr.IsReadOnly() case? 
2240     // different coloured text when the grid is disabled 
2241     if ( grid
.IsEnabled() ) 
2246             if ( grid
.HasFocus() ) 
2247                 clr 
= grid
.GetSelectionBackground(); 
2249                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
2250             dc
.SetTextBackground( clr 
); 
2251             dc
.SetTextForeground( grid
.GetSelectionForeground() ); 
2255             dc
.SetTextBackground( attr
.GetBackgroundColour() ); 
2256             dc
.SetTextForeground( attr
.GetTextColour() ); 
2261         dc
.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
2262         dc
.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
)); 
2265     dc
.SetFont( attr
.GetFont() ); 
2268 wxSize 
wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr
& attr
, 
2270                                                const wxString
& text
) 
2272     wxCoord x 
= 0, y 
= 0, max_x 
= 0; 
2273     dc
.SetFont(attr
.GetFont()); 
2274     wxStringTokenizer 
tk(text
, _T('\n')); 
2275     while ( tk
.HasMoreTokens() ) 
2277         dc
.GetTextExtent(tk
.GetNextToken(), &x
, &y
); 
2278         max_x 
= wxMax(max_x
, x
); 
2281     y 
*= 1 + text
.Freq(wxT('\n')); // multiply by the number of lines. 
2283     return wxSize(max_x
, y
); 
2286 wxSize 
wxGridCellStringRenderer::GetBestSize(wxGrid
& grid
, 
2287                                              wxGridCellAttr
& attr
, 
2291     return DoGetBestSize(attr
, dc
, grid
.GetCellValue(row
, col
)); 
2294 void wxGridCellStringRenderer::Draw(wxGrid
& grid
, 
2295                                     wxGridCellAttr
& attr
, 
2297                                     const wxRect
& rectCell
, 
2301     wxRect rect 
= rectCell
; 
2304     // erase only this cells background, overflow cells should have been erased 
2305     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2308     attr
.GetAlignment(&hAlign
, &vAlign
); 
2310     int overflowCols 
= 0; 
2312     if (attr
.GetOverflow()) 
2314         int cols 
= grid
.GetNumberCols(); 
2315         int best_width 
= GetBestSize(grid
,attr
,dc
,row
,col
).GetWidth(); 
2316         int cell_rows
, cell_cols
; 
2317         attr
.GetSize( &cell_rows
, &cell_cols 
); // shouldn't get here if <= 0 
2318         if ((best_width 
> rectCell
.width
) && (col 
< cols
) && grid
.GetTable()) 
2320             int i
, c_cols
, c_rows
; 
2321             for (i 
= col
+cell_cols
; i 
< cols
; i
++) 
2323                 bool is_empty 
= true; 
2324                 for (int j
=row
; j 
< row 
+ cell_rows
; j
++) 
2326                     // check w/ anchor cell for multicell block 
2327                     grid
.GetCellSize(j
, i
, &c_rows
, &c_cols
); 
2330                     if (!grid
.GetTable()->IsEmptyCell(j 
+ c_rows
, i
)) 
2339                     rect
.width 
+= grid
.GetColSize(i
); 
2347                 if (rect
.width 
>= best_width
) 
2351             overflowCols 
= i 
- col 
- cell_cols 
+ 1; 
2352             if (overflowCols 
>= cols
) 
2353                 overflowCols 
= cols 
- 1; 
2356         if (overflowCols 
> 0) // redraw overflow cells w/ proper hilight 
2358             hAlign 
= wxALIGN_LEFT
; // if oveflowed then it's left aligned 
2360             clip
.x 
+= rectCell
.width
; 
2361             // draw each overflow cell individually 
2362             int col_end 
= col 
+ cell_cols 
+ overflowCols
; 
2363             if (col_end 
>= grid
.GetNumberCols()) 
2364                 col_end 
= grid
.GetNumberCols() - 1; 
2365             for (int i 
= col 
+ cell_cols
; i 
<= col_end
; i
++) 
2367                 clip
.width 
= grid
.GetColSize(i
) - 1; 
2368                 dc
.DestroyClippingRegion(); 
2369                 dc
.SetClippingRegion(clip
); 
2371                 SetTextColoursAndFont(grid
, attr
, dc
, 
2372                         grid
.IsInSelection(row
,i
)); 
2374                 grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
2375                         rect
, hAlign
, vAlign
); 
2376                 clip
.x 
+= grid
.GetColSize(i
) - 1; 
2382             dc
.DestroyClippingRegion(); 
2386     // now we only have to draw the text 
2387     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2389     grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
2390                            rect
, hAlign
, vAlign
); 
2393 // ---------------------------------------------------------------------------- 
2394 // wxGridCellNumberRenderer 
2395 // ---------------------------------------------------------------------------- 
2397 wxString 
wxGridCellNumberRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
2399     wxGridTableBase 
*table 
= grid
.GetTable(); 
2401     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
2403         text
.Printf(_T("%ld"), table
->GetValueAsLong(row
, col
)); 
2407         text 
= table
->GetValue(row
, col
); 
2413 void wxGridCellNumberRenderer::Draw(wxGrid
& grid
, 
2414                                     wxGridCellAttr
& attr
, 
2416                                     const wxRect
& rectCell
, 
2420     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2422     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2424     // draw the text right aligned by default 
2426     attr
.GetAlignment(&hAlign
, &vAlign
); 
2427     hAlign 
= wxALIGN_RIGHT
; 
2429     wxRect rect 
= rectCell
; 
2432     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
2435 wxSize 
wxGridCellNumberRenderer::GetBestSize(wxGrid
& grid
, 
2436                                              wxGridCellAttr
& attr
, 
2440     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
2443 // ---------------------------------------------------------------------------- 
2444 // wxGridCellFloatRenderer 
2445 // ---------------------------------------------------------------------------- 
2447 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width
, int precision
) 
2450     SetPrecision(precision
); 
2453 wxGridCellRenderer 
*wxGridCellFloatRenderer::Clone() const 
2455     wxGridCellFloatRenderer 
*renderer 
= new wxGridCellFloatRenderer
; 
2456     renderer
->m_width 
= m_width
; 
2457     renderer
->m_precision 
= m_precision
; 
2458     renderer
->m_format 
= m_format
; 
2463 wxString 
wxGridCellFloatRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
2465     wxGridTableBase 
*table 
= grid
.GetTable(); 
2470     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
2472         val 
= table
->GetValueAsDouble(row
, col
); 
2477         text 
= table
->GetValue(row
, col
); 
2478         hasDouble 
= text
.ToDouble(&val
); 
2485             if ( m_width 
== -1 ) 
2487                 if ( m_precision 
== -1 ) 
2489                     // default width/precision 
2490                     m_format 
= _T("%f"); 
2494                     m_format
.Printf(_T("%%.%df"), m_precision
); 
2497             else if ( m_precision 
== -1 ) 
2499                 // default precision 
2500                 m_format
.Printf(_T("%%%d.f"), m_width
); 
2504                 m_format
.Printf(_T("%%%d.%df"), m_width
, m_precision
); 
2508         text
.Printf(m_format
, val
); 
2511     //else: text already contains the string 
2516 void wxGridCellFloatRenderer::Draw(wxGrid
& grid
, 
2517                                    wxGridCellAttr
& attr
, 
2519                                    const wxRect
& rectCell
, 
2523     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2525     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2527     // draw the text right aligned by default 
2529     attr
.GetAlignment(&hAlign
, &vAlign
); 
2530     hAlign 
= wxALIGN_RIGHT
; 
2532     wxRect rect 
= rectCell
; 
2535     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
2538 wxSize 
wxGridCellFloatRenderer::GetBestSize(wxGrid
& grid
, 
2539                                             wxGridCellAttr
& attr
, 
2543     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
2546 void wxGridCellFloatRenderer::SetParameters(const wxString
& params
) 
2550         // reset to defaults 
2556         wxString tmp 
= params
.BeforeFirst(_T(',')); 
2560             if ( tmp
.ToLong(&width
) ) 
2562                 SetWidth((int)width
); 
2566                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str()); 
2570         tmp 
= params
.AfterFirst(_T(',')); 
2574             if ( tmp
.ToLong(&precision
) ) 
2576                 SetPrecision((int)precision
); 
2580                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str()); 
2586 // ---------------------------------------------------------------------------- 
2587 // wxGridCellBoolRenderer 
2588 // ---------------------------------------------------------------------------- 
2590 wxSize 
wxGridCellBoolRenderer::ms_sizeCheckMark
; 
2592 // FIXME these checkbox size calculations are really ugly... 
2594 // between checkmark and box 
2595 static const wxCoord wxGRID_CHECKMARK_MARGIN 
= 2; 
2597 wxSize 
wxGridCellBoolRenderer::GetBestSize(wxGrid
& grid
, 
2598                                            wxGridCellAttr
& WXUNUSED(attr
), 
2603     // compute it only once (no locks for MT safeness in GUI thread...) 
2604     if ( !ms_sizeCheckMark
.x 
) 
2606         // get checkbox size 
2607         wxCheckBox 
*checkbox 
= new wxCheckBox(&grid
, wxID_ANY
, wxEmptyString
); 
2608         wxSize size 
= checkbox
->GetBestSize(); 
2609         wxCoord checkSize 
= size
.y 
+ 2 * wxGRID_CHECKMARK_MARGIN
; 
2611 #if defined(__WXMOTIF__) 
2612         checkSize 
-= size
.y 
/ 2; 
2617         ms_sizeCheckMark
.x 
= ms_sizeCheckMark
.y 
= checkSize
; 
2620     return ms_sizeCheckMark
; 
2623 void wxGridCellBoolRenderer::Draw(wxGrid
& grid
, 
2624                                   wxGridCellAttr
& attr
, 
2630     wxGridCellRenderer::Draw(grid
, attr
, dc
, rect
, row
, col
, isSelected
); 
2632     // draw a check mark in the centre (ignoring alignment - TODO) 
2633     wxSize size 
= GetBestSize(grid
, attr
, dc
, row
, col
); 
2635     // don't draw outside the cell 
2636     wxCoord minSize 
= wxMin(rect
.width
, rect
.height
); 
2637     if ( size
.x 
>= minSize 
|| size
.y 
>= minSize 
) 
2639         // and even leave (at least) 1 pixel margin 
2640         size
.x 
= size
.y 
= minSize
; 
2643     // draw a border around checkmark 
2645     attr
.GetAlignment(&hAlign
, &vAlign
); 
2648     if (hAlign 
== wxALIGN_CENTRE
) 
2650         rectBorder
.x 
= rect
.x 
+ rect
.width 
/ 2 - size
.x 
/ 2; 
2651         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2652         rectBorder
.width 
= size
.x
; 
2653         rectBorder
.height 
= size
.y
; 
2655     else if (hAlign 
== wxALIGN_LEFT
) 
2657         rectBorder
.x 
= rect
.x 
+ 2; 
2658         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2659         rectBorder
.width 
= size
.x
; 
2660         rectBorder
.height 
= size
.y
; 
2662     else if (hAlign 
== wxALIGN_RIGHT
) 
2664         rectBorder
.x 
= rect
.x 
+ rect
.width 
- size
.x 
- 2; 
2665         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2666         rectBorder
.width 
= size
.x
; 
2667         rectBorder
.height 
= size
.y
; 
2671     if ( grid
.GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
) ) 
2673         value 
= grid
.GetTable()->GetValueAsBool(row
, col
); 
2677         wxString 
cellval( grid
.GetTable()->GetValue(row
, col
) ); 
2678         value 
= wxGridCellBoolEditor::IsTrueValue(cellval
); 
2683         flags 
|= wxCONTROL_CHECKED
; 
2685     wxRendererNative::Get().DrawCheckBox( &grid
, dc
, rectBorder
, flags 
); 
2688 // ---------------------------------------------------------------------------- 
2690 // ---------------------------------------------------------------------------- 
2692 void wxGridCellAttr::Init(wxGridCellAttr 
*attrDefault
) 
2696     m_isReadOnly 
= Unset
; 
2701     m_attrkind 
= wxGridCellAttr::Cell
; 
2703     m_sizeRows 
= m_sizeCols 
= 1; 
2704     m_overflow 
= UnsetOverflow
; 
2706     SetDefAttr(attrDefault
); 
2709 wxGridCellAttr 
*wxGridCellAttr::Clone() const 
2711     wxGridCellAttr 
*attr 
= new wxGridCellAttr(m_defGridAttr
); 
2713     if ( HasTextColour() ) 
2714         attr
->SetTextColour(GetTextColour()); 
2715     if ( HasBackgroundColour() ) 
2716         attr
->SetBackgroundColour(GetBackgroundColour()); 
2718         attr
->SetFont(GetFont()); 
2719     if ( HasAlignment() ) 
2720         attr
->SetAlignment(m_hAlign
, m_vAlign
); 
2722     attr
->SetSize( m_sizeRows
, m_sizeCols 
); 
2726         attr
->SetRenderer(m_renderer
); 
2727         m_renderer
->IncRef(); 
2731         attr
->SetEditor(m_editor
); 
2736         attr
->SetReadOnly(); 
2738     attr
->SetOverflow( m_overflow 
== Overflow 
); 
2739     attr
->SetKind( m_attrkind 
); 
2744 void wxGridCellAttr::MergeWith(wxGridCellAttr 
*mergefrom
) 
2746     if ( !HasTextColour() && mergefrom
->HasTextColour() ) 
2747         SetTextColour(mergefrom
->GetTextColour()); 
2748     if ( !HasBackgroundColour() && mergefrom
->HasBackgroundColour() ) 
2749         SetBackgroundColour(mergefrom
->GetBackgroundColour()); 
2750     if ( !HasFont() && mergefrom
->HasFont() ) 
2751         SetFont(mergefrom
->GetFont()); 
2752     if ( !HasAlignment() && mergefrom
->HasAlignment() ) 
2755         mergefrom
->GetAlignment( &hAlign
, &vAlign
); 
2756         SetAlignment(hAlign
, vAlign
); 
2758     if ( !HasSize() && mergefrom
->HasSize() ) 
2759         mergefrom
->GetSize( &m_sizeRows
, &m_sizeCols 
); 
2761     // Directly access member functions as GetRender/Editor don't just return 
2762     // m_renderer/m_editor 
2764     // Maybe add support for merge of Render and Editor? 
2765     if (!HasRenderer() && mergefrom
->HasRenderer() ) 
2767         m_renderer 
= mergefrom
->m_renderer
; 
2768         m_renderer
->IncRef(); 
2770     if ( !HasEditor() && mergefrom
->HasEditor() ) 
2772         m_editor 
=  mergefrom
->m_editor
; 
2775     if ( !HasReadWriteMode() && mergefrom
->HasReadWriteMode() ) 
2776         SetReadOnly(mergefrom
->IsReadOnly()); 
2778     if (!HasOverflowMode() && mergefrom
->HasOverflowMode() ) 
2779         SetOverflow(mergefrom
->GetOverflow()); 
2781     SetDefAttr(mergefrom
->m_defGridAttr
); 
2784 void wxGridCellAttr::SetSize(int num_rows
, int num_cols
) 
2786     // The size of a cell is normally 1,1 
2788     // If this cell is larger (2,2) then this is the top left cell 
2789     // the other cells that will be covered (lower right cells) must be 
2790     // set to negative or zero values such that 
2791     // row + num_rows of the covered cell points to the larger cell (this cell) 
2792     // same goes for the col + num_cols. 
2794     // Size of 0,0 is NOT valid, neither is <=0 and any positive value 
2796     wxASSERT_MSG( (!((num_rows 
> 0) && (num_cols 
<= 0)) || 
2797                   !((num_rows 
<= 0) && (num_cols 
> 0)) || 
2798                   !((num_rows 
== 0) && (num_cols 
== 0))), 
2799                   wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values")); 
2801     m_sizeRows 
= num_rows
; 
2802     m_sizeCols 
= num_cols
; 
2805 const wxColour
& wxGridCellAttr::GetTextColour() const 
2807     if (HasTextColour()) 
2811     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2813         return m_defGridAttr
->GetTextColour(); 
2817         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2818         return wxNullColour
; 
2822 const wxColour
& wxGridCellAttr::GetBackgroundColour() const 
2824     if (HasBackgroundColour()) 
2828     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2830         return m_defGridAttr
->GetBackgroundColour(); 
2834         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2835         return wxNullColour
; 
2839 const wxFont
& wxGridCellAttr::GetFont() const 
2845     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2847         return m_defGridAttr
->GetFont(); 
2851         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2856 void wxGridCellAttr::GetAlignment(int *hAlign
, int *vAlign
) const 
2865     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2867         m_defGridAttr
->GetAlignment(hAlign
, vAlign
); 
2871         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2875 void wxGridCellAttr::GetSize( int *num_rows
, int *num_cols 
) const 
2878         *num_rows 
= m_sizeRows
; 
2880         *num_cols 
= m_sizeCols
; 
2883 // GetRenderer and GetEditor use a slightly different decision path about 
2884 // which attribute to use.  If a non-default attr object has one then it is 
2885 // used, otherwise the default editor or renderer is fetched from the grid and 
2886 // used.  It should be the default for the data type of the cell.  If it is 
2887 // NULL (because the table has a type that the grid does not have in its 
2888 // registry), then the grid's default editor or renderer is used. 
2890 wxGridCellRenderer
* wxGridCellAttr::GetRenderer(const wxGrid
* grid
, int row
, int col
) const 
2892     wxGridCellRenderer 
*renderer 
= NULL
; 
2894     if ( m_renderer 
&& this != m_defGridAttr 
) 
2896         // use the cells renderer if it has one 
2897         renderer 
= m_renderer
; 
2900     else // no non-default cell renderer 
2902         // get default renderer for the data type 
2905             // GetDefaultRendererForCell() will do IncRef() for us 
2906             renderer 
= grid
->GetDefaultRendererForCell(row
, col
); 
2909         if ( renderer 
== NULL 
) 
2911             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
2913                 // if we still don't have one then use the grid default 
2914                 // (no need for IncRef() here neither) 
2915                 renderer 
= m_defGridAttr
->GetRenderer(NULL
, 0, 0); 
2917             else // default grid attr 
2919                 // use m_renderer which we had decided not to use initially 
2920                 renderer 
= m_renderer
; 
2927     // we're supposed to always find something 
2928     wxASSERT_MSG(renderer
, wxT("Missing default cell renderer")); 
2933 // same as above, except for s/renderer/editor/g 
2934 wxGridCellEditor
* wxGridCellAttr::GetEditor(const wxGrid
* grid
, int row
, int col
) const 
2936     wxGridCellEditor 
*editor 
= NULL
; 
2938     if ( m_editor 
&& this != m_defGridAttr 
) 
2940         // use the cells editor if it has one 
2944     else // no non default cell editor 
2946         // get default editor for the data type 
2949             // GetDefaultEditorForCell() will do IncRef() for us 
2950             editor 
= grid
->GetDefaultEditorForCell(row
, col
); 
2953         if ( editor 
== NULL 
) 
2955             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
2957                 // if we still don't have one then use the grid default 
2958                 // (no need for IncRef() here neither) 
2959                 editor 
= m_defGridAttr
->GetEditor(NULL
, 0, 0); 
2961             else // default grid attr 
2963                 // use m_editor which we had decided not to use initially 
2971     // we're supposed to always find something 
2972     wxASSERT_MSG(editor
, wxT("Missing default cell editor")); 
2977 // ---------------------------------------------------------------------------- 
2978 // wxGridCellAttrData 
2979 // ---------------------------------------------------------------------------- 
2981 void wxGridCellAttrData::SetAttr(wxGridCellAttr 
*attr
, int row
, int col
) 
2983     // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not 
2984     //       touch attribute's reference counting explicitly, since this 
2985     //       is managed by class wxGridCellWithAttr 
2986     int n 
= FindIndex(row
, col
); 
2987     if ( n 
== wxNOT_FOUND 
) 
2991             // add the attribute 
2992             m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
)); 
2994         //else: nothing to do 
2996     else // we already have an attribute for this cell 
3000             // change the attribute 
3001             m_attrs
[(size_t)n
].ChangeAttr(attr
); 
3005             // remove this attribute 
3006             m_attrs
.RemoveAt((size_t)n
); 
3011 wxGridCellAttr 
*wxGridCellAttrData::GetAttr(int row
, int col
) const 
3013     wxGridCellAttr 
*attr 
= NULL
; 
3015     int n 
= FindIndex(row
, col
); 
3016     if ( n 
!= wxNOT_FOUND 
) 
3018         attr 
= m_attrs
[(size_t)n
].attr
; 
3025 void wxGridCellAttrData::UpdateAttrRows( size_t pos
, int numRows 
) 
3027     size_t count 
= m_attrs
.GetCount(); 
3028     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3030         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3031         wxCoord row 
= coords
.GetRow(); 
3032         if ((size_t)row 
>= pos
) 
3036                 // If rows inserted, include row counter where necessary 
3037                 coords
.SetRow(row 
+ numRows
); 
3039             else if (numRows 
< 0) 
3041                 // If rows deleted ... 
3042                 if ((size_t)row 
>= pos 
- numRows
) 
3044                     // ...either decrement row counter (if row still exists)... 
3045                     coords
.SetRow(row 
+ numRows
); 
3049                     // ...or remove the attribute 
3050                     m_attrs
.RemoveAt(n
); 
3059 void wxGridCellAttrData::UpdateAttrCols( size_t pos
, int numCols 
) 
3061     size_t count 
= m_attrs
.GetCount(); 
3062     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3064         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3065         wxCoord col 
= coords
.GetCol(); 
3066         if ( (size_t)col 
>= pos 
) 
3070                 // If rows inserted, include row counter where necessary 
3071                 coords
.SetCol(col 
+ numCols
); 
3073             else if (numCols 
< 0) 
3075                 // If rows deleted ... 
3076                 if ((size_t)col 
>= pos 
- numCols
) 
3078                     // ...either decrement row counter (if row still exists)... 
3079                     coords
.SetCol(col 
+ numCols
); 
3083                     // ...or remove the attribute 
3084                     m_attrs
.RemoveAt(n
); 
3093 int wxGridCellAttrData::FindIndex(int row
, int col
) const 
3095     size_t count 
= m_attrs
.GetCount(); 
3096     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3098         const wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3099         if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) ) 
3108 // ---------------------------------------------------------------------------- 
3109 // wxGridRowOrColAttrData 
3110 // ---------------------------------------------------------------------------- 
3112 wxGridRowOrColAttrData::~wxGridRowOrColAttrData() 
3114     size_t count 
= m_attrs
.GetCount(); 
3115     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3117         m_attrs
[n
]->DecRef(); 
3121 wxGridCellAttr 
*wxGridRowOrColAttrData::GetAttr(int rowOrCol
) const 
3123     wxGridCellAttr 
*attr 
= NULL
; 
3125     int n 
= m_rowsOrCols
.Index(rowOrCol
); 
3126     if ( n 
!= wxNOT_FOUND 
) 
3128         attr 
= m_attrs
[(size_t)n
]; 
3135 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr 
*attr
, int rowOrCol
) 
3137     int i 
= m_rowsOrCols
.Index(rowOrCol
); 
3138     if ( i 
== wxNOT_FOUND 
) 
3142             // add the attribute - no need to do anything to reference count 
3143             //                     since we take ownership of the attribute. 
3144             m_rowsOrCols
.Add(rowOrCol
); 
3147         // nothing to remove 
3151         size_t n 
= (size_t)i
; 
3152         if ( m_attrs
[n
] == attr 
) 
3157             // change the attribute, handling reference count manually, 
3158             //                       taking ownership of the new attribute. 
3159             m_attrs
[n
]->DecRef(); 
3164             // remove this attribute, handling reference count manually 
3165             m_attrs
[n
]->DecRef(); 
3166             m_rowsOrCols
.RemoveAt(n
); 
3167             m_attrs
.RemoveAt(n
); 
3172 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols 
) 
3174     size_t count 
= m_attrs
.GetCount(); 
3175     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3177         int & rowOrCol 
= m_rowsOrCols
[n
]; 
3178         if ( (size_t)rowOrCol 
>= pos 
) 
3180             if ( numRowsOrCols 
> 0 ) 
3182                 // If rows inserted, include row counter where necessary 
3183                 rowOrCol 
+= numRowsOrCols
; 
3185             else if ( numRowsOrCols 
< 0) 
3187                 // If rows deleted, either decrement row counter (if row still exists) 
3188                 if ((size_t)rowOrCol 
>= pos 
- numRowsOrCols
) 
3189                     rowOrCol 
+= numRowsOrCols
; 
3192                     m_rowsOrCols
.RemoveAt(n
); 
3193                     m_attrs
[n
]->DecRef(); 
3194                     m_attrs
.RemoveAt(n
); 
3203 // ---------------------------------------------------------------------------- 
3204 // wxGridCellAttrProvider 
3205 // ---------------------------------------------------------------------------- 
3207 wxGridCellAttrProvider::wxGridCellAttrProvider() 
3212 wxGridCellAttrProvider::~wxGridCellAttrProvider() 
3217 void wxGridCellAttrProvider::InitData() 
3219     m_data 
= new wxGridCellAttrProviderData
; 
3222 wxGridCellAttr 
*wxGridCellAttrProvider::GetAttr(int row
, int col
, 
3223                                                 wxGridCellAttr::wxAttrKind  kind 
) const 
3225     wxGridCellAttr 
*attr 
= NULL
; 
3230             case (wxGridCellAttr::Any
): 
3231                 // Get cached merge attributes. 
3232                 // Currently not used as no cache implemented as not mutable 
3233                 // attr = m_data->m_mergeAttr.GetAttr(row, col); 
3236                     // Basically implement old version. 
3237                     // Also check merge cache, so we don't have to re-merge every time.. 
3238                     wxGridCellAttr 
*attrcell 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
3239                     wxGridCellAttr 
*attrrow 
= m_data
->m_rowAttrs
.GetAttr(row
); 
3240                     wxGridCellAttr 
*attrcol 
= m_data
->m_colAttrs
.GetAttr(col
); 
3242                     if ((attrcell 
!= attrrow
) && (attrrow 
!= attrcol
) && (attrcell 
!= attrcol
)) 
3244                         // Two or more are non NULL 
3245                         attr 
= new wxGridCellAttr
; 
3246                         attr
->SetKind(wxGridCellAttr::Merged
); 
3248                         // Order is important.. 
3251                             attr
->MergeWith(attrcell
); 
3256                             attr
->MergeWith(attrcol
); 
3261                             attr
->MergeWith(attrrow
); 
3265                         // store merge attr if cache implemented 
3267                         //m_data->m_mergeAttr.SetAttr(attr, row, col); 
3271                         // one or none is non null return it or null. 
3290             case (wxGridCellAttr::Cell
): 
3291                 attr 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
3294             case (wxGridCellAttr::Col
): 
3295                 attr 
= m_data
->m_colAttrs
.GetAttr(col
); 
3298             case (wxGridCellAttr::Row
): 
3299                 attr 
= m_data
->m_rowAttrs
.GetAttr(row
); 
3304                 // (wxGridCellAttr::Default): 
3305                 // (wxGridCellAttr::Merged): 
3313 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr 
*attr
, 
3319     m_data
->m_cellAttrs
.SetAttr(attr
, row
, col
); 
3322 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
3327     m_data
->m_rowAttrs
.SetAttr(attr
, row
); 
3330 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
3335     m_data
->m_colAttrs
.SetAttr(attr
, col
); 
3338 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos
, int numRows 
) 
3342         m_data
->m_cellAttrs
.UpdateAttrRows( pos
, numRows 
); 
3344         m_data
->m_rowAttrs
.UpdateAttrRowsOrCols( pos
, numRows 
); 
3348 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos
, int numCols 
) 
3352         m_data
->m_cellAttrs
.UpdateAttrCols( pos
, numCols 
); 
3354         m_data
->m_colAttrs
.UpdateAttrRowsOrCols( pos
, numCols 
); 
3358 // ---------------------------------------------------------------------------- 
3359 // wxGridTypeRegistry 
3360 // ---------------------------------------------------------------------------- 
3362 wxGridTypeRegistry::~wxGridTypeRegistry() 
3364     size_t count 
= m_typeinfo
.GetCount(); 
3365     for ( size_t i 
= 0; i 
< count
; i
++ ) 
3366         delete m_typeinfo
[i
]; 
3369 void wxGridTypeRegistry::RegisterDataType(const wxString
& typeName
, 
3370                                           wxGridCellRenderer
* renderer
, 
3371                                           wxGridCellEditor
* editor
) 
3373     wxGridDataTypeInfo
* info 
= new wxGridDataTypeInfo(typeName
, renderer
, editor
); 
3375     // is it already registered? 
3376     int loc 
= FindRegisteredDataType(typeName
); 
3377     if ( loc 
!= wxNOT_FOUND 
) 
3379         delete m_typeinfo
[loc
]; 
3380         m_typeinfo
[loc
] = info
; 
3384         m_typeinfo
.Add(info
); 
3388 int wxGridTypeRegistry::FindRegisteredDataType(const wxString
& typeName
) 
3390     size_t count 
= m_typeinfo
.GetCount(); 
3391     for ( size_t i 
= 0; i 
< count
; i
++ ) 
3393         if ( typeName 
== m_typeinfo
[i
]->m_typeName 
) 
3402 int wxGridTypeRegistry::FindDataType(const wxString
& typeName
) 
3404     int index 
= FindRegisteredDataType(typeName
); 
3405     if ( index 
== wxNOT_FOUND 
) 
3407         // check whether this is one of the standard ones, in which case 
3408         // register it "on the fly" 
3410         if ( typeName 
== wxGRID_VALUE_STRING 
) 
3412             RegisterDataType(wxGRID_VALUE_STRING
, 
3413                              new wxGridCellStringRenderer
, 
3414                              new wxGridCellTextEditor
); 
3417 #endif // wxUSE_TEXTCTRL 
3419         if ( typeName 
== wxGRID_VALUE_BOOL 
) 
3421             RegisterDataType(wxGRID_VALUE_BOOL
, 
3422                              new wxGridCellBoolRenderer
, 
3423                              new wxGridCellBoolEditor
); 
3426 #endif // wxUSE_CHECKBOX 
3428         if ( typeName 
== wxGRID_VALUE_NUMBER 
) 
3430             RegisterDataType(wxGRID_VALUE_NUMBER
, 
3431                              new wxGridCellNumberRenderer
, 
3432                              new wxGridCellNumberEditor
); 
3434         else if ( typeName 
== wxGRID_VALUE_FLOAT 
) 
3436             RegisterDataType(wxGRID_VALUE_FLOAT
, 
3437                              new wxGridCellFloatRenderer
, 
3438                              new wxGridCellFloatEditor
); 
3441 #endif // wxUSE_TEXTCTRL 
3443         if ( typeName 
== wxGRID_VALUE_CHOICE 
) 
3445             RegisterDataType(wxGRID_VALUE_CHOICE
, 
3446                              new wxGridCellStringRenderer
, 
3447                              new wxGridCellChoiceEditor
); 
3450 #endif // wxUSE_COMBOBOX 
3455         // we get here only if just added the entry for this type, so return 
3457         index 
= m_typeinfo
.GetCount() - 1; 
3463 int wxGridTypeRegistry::FindOrCloneDataType(const wxString
& typeName
) 
3465     int index 
= FindDataType(typeName
); 
3466     if ( index 
== wxNOT_FOUND 
) 
3468         // the first part of the typename is the "real" type, anything after ':' 
3469         // are the parameters for the renderer 
3470         index 
= FindDataType(typeName
.BeforeFirst(_T(':'))); 
3471         if ( index 
== wxNOT_FOUND 
) 
3476         wxGridCellRenderer 
*renderer 
= GetRenderer(index
); 
3477         wxGridCellRenderer 
*rendererOld 
= renderer
; 
3478         renderer 
= renderer
->Clone(); 
3479         rendererOld
->DecRef(); 
3481         wxGridCellEditor 
*editor 
= GetEditor(index
); 
3482         wxGridCellEditor 
*editorOld 
= editor
; 
3483         editor 
= editor
->Clone(); 
3484         editorOld
->DecRef(); 
3486         // do it even if there are no parameters to reset them to defaults 
3487         wxString params 
= typeName
.AfterFirst(_T(':')); 
3488         renderer
->SetParameters(params
); 
3489         editor
->SetParameters(params
); 
3491         // register the new typename 
3492         RegisterDataType(typeName
, renderer
, editor
); 
3494         // we just registered it, it's the last one 
3495         index 
= m_typeinfo
.GetCount() - 1; 
3501 wxGridCellRenderer
* wxGridTypeRegistry::GetRenderer(int index
) 
3503     wxGridCellRenderer
* renderer 
= m_typeinfo
[index
]->m_renderer
; 
3510 wxGridCellEditor
* wxGridTypeRegistry::GetEditor(int index
) 
3512     wxGridCellEditor
* editor 
= m_typeinfo
[index
]->m_editor
; 
3519 // ---------------------------------------------------------------------------- 
3521 // ---------------------------------------------------------------------------- 
3523 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject 
) 
3525 wxGridTableBase::wxGridTableBase() 
3528     m_attrProvider 
= NULL
; 
3531 wxGridTableBase::~wxGridTableBase() 
3533     delete m_attrProvider
; 
3536 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider 
*attrProvider
) 
3538     delete m_attrProvider
; 
3539     m_attrProvider 
= attrProvider
; 
3542 bool wxGridTableBase::CanHaveAttributes() 
3544     if ( ! GetAttrProvider() ) 
3546         // use the default attr provider by default 
3547         SetAttrProvider(new wxGridCellAttrProvider
); 
3553 wxGridCellAttr 
*wxGridTableBase::GetAttr(int row
, int col
, wxGridCellAttr::wxAttrKind  kind
) 
3555     if ( m_attrProvider 
) 
3556         return m_attrProvider
->GetAttr(row
, col
, kind
); 
3561 void wxGridTableBase::SetAttr(wxGridCellAttr
* attr
, int row
, int col
) 
3563     if ( m_attrProvider 
) 
3566             attr
->SetKind(wxGridCellAttr::Cell
); 
3567         m_attrProvider
->SetAttr(attr
, row
, col
); 
3571         // as we take ownership of the pointer and don't store it, we must 
3577 void wxGridTableBase::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
3579     if ( m_attrProvider 
) 
3581         attr
->SetKind(wxGridCellAttr::Row
); 
3582         m_attrProvider
->SetRowAttr(attr
, row
); 
3586         // as we take ownership of the pointer and don't store it, we must 
3592 void wxGridTableBase::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
3594     if ( m_attrProvider 
) 
3596         attr
->SetKind(wxGridCellAttr::Col
); 
3597         m_attrProvider
->SetColAttr(attr
, col
); 
3601         // as we take ownership of the pointer and don't store it, we must 
3607 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos
), 
3608                                   size_t WXUNUSED(numRows
) ) 
3610     wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") ); 
3615 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows
) ) 
3617     wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function")); 
3622 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos
), 
3623                                   size_t WXUNUSED(numRows
) ) 
3625     wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function")); 
3630 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos
), 
3631                                   size_t WXUNUSED(numCols
) ) 
3633     wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function")); 
3638 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols
) ) 
3640     wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function")); 
3645 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos
), 
3646                                   size_t WXUNUSED(numCols
) ) 
3648     wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function")); 
3653 wxString 
wxGridTableBase::GetRowLabelValue( int row 
) 
3657     // RD: Starting the rows at zero confuses users, 
3658     // no matter how much it makes sense to us geeks. 
3664 wxString 
wxGridTableBase::GetColLabelValue( int col 
) 
3666     // default col labels are: 
3667     //   cols 0 to 25   : A-Z 
3668     //   cols 26 to 675 : AA-ZZ 
3673     for ( n 
= 1; ; n
++ ) 
3675         s 
+= (wxChar
) (_T('A') + (wxChar
)(col 
% 26)); 
3681     // reverse the string... 
3683     for ( i 
= 0; i 
< n
; i
++ ) 
3691 wxString 
wxGridTableBase::GetTypeName( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3693     return wxGRID_VALUE_STRING
; 
3696 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row
), int WXUNUSED(col
), 
3697                                      const wxString
& typeName 
) 
3699     return typeName 
== wxGRID_VALUE_STRING
; 
3702 bool wxGridTableBase::CanSetValueAs( int row
, int col
, const wxString
& typeName 
) 
3704     return CanGetValueAs(row
, col
, typeName
); 
3707 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3712 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3717 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3722 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
), 
3723                                       long WXUNUSED(value
) ) 
3727 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
), 
3728                                         double WXUNUSED(value
) ) 
3732 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
), 
3733                                       bool WXUNUSED(value
) ) 
3737 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
3738                                          const wxString
& WXUNUSED(typeName
) ) 
3743 void  wxGridTableBase::SetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
3744                                          const wxString
& WXUNUSED(typeName
), 
3745                                          void* WXUNUSED(value
) ) 
3749 ////////////////////////////////////////////////////////////////////// 
3751 // Message class for the grid table to send requests and notifications 
3755 wxGridTableMessage::wxGridTableMessage() 
3763 wxGridTableMessage::wxGridTableMessage( wxGridTableBase 
*table
, int id
, 
3764                                         int commandInt1
, int commandInt2 
) 
3768     m_comInt1 
= commandInt1
; 
3769     m_comInt2 
= commandInt2
; 
3772 ////////////////////////////////////////////////////////////////////// 
3774 // A basic grid table for string data. An object of this class will 
3775 // created by wxGrid if you don't specify an alternative table class. 
3778 WX_DEFINE_OBJARRAY(wxGridStringArray
) 
3780 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase 
) 
3782 wxGridStringTable::wxGridStringTable() 
3787 wxGridStringTable::wxGridStringTable( int numRows
, int numCols 
) 
3790     m_data
.Alloc( numRows 
); 
3793     sa
.Alloc( numCols 
); 
3794     sa
.Add( wxEmptyString
, numCols 
); 
3796     m_data
.Add( sa
, numRows 
); 
3799 wxGridStringTable::~wxGridStringTable() 
3803 int wxGridStringTable::GetNumberRows() 
3805     return m_data
.GetCount(); 
3808 int wxGridStringTable::GetNumberCols() 
3810     if ( m_data
.GetCount() > 0 ) 
3811         return m_data
[0].GetCount(); 
3816 wxString 
wxGridStringTable::GetValue( int row
, int col 
) 
3818     wxCHECK_MSG( (row 
< GetNumberRows()) && (col 
< GetNumberCols()), 
3820                  _T("invalid row or column index in wxGridStringTable") ); 
3822     return m_data
[row
][col
]; 
3825 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& value 
) 
3827     wxCHECK_RET( (row 
< GetNumberRows()) && (col 
< GetNumberCols()), 
3828                  _T("invalid row or column index in wxGridStringTable") ); 
3830     m_data
[row
][col
] = value
; 
3833 bool wxGridStringTable::IsEmptyCell( int row
, int col 
) 
3835     wxCHECK_MSG( (row 
< GetNumberRows()) && (col 
< GetNumberCols()), 
3837                   _T("invalid row or column index in wxGridStringTable") ); 
3839     return (m_data
[row
][col
] == wxEmptyString
); 
3842 void wxGridStringTable::Clear() 
3845     int numRows
, numCols
; 
3847     numRows 
= m_data
.GetCount(); 
3850         numCols 
= m_data
[0].GetCount(); 
3852         for ( row 
= 0; row 
< numRows
; row
++ ) 
3854             for ( col 
= 0; col 
< numCols
; col
++ ) 
3856                 m_data
[row
][col
] = wxEmptyString
; 
3862 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows 
) 
3864     size_t curNumRows 
= m_data
.GetCount(); 
3865     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
3866                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
3868     if ( pos 
>= curNumRows 
) 
3870         return AppendRows( numRows 
); 
3874     sa
.Alloc( curNumCols 
); 
3875     sa
.Add( wxEmptyString
, curNumCols 
); 
3876     m_data
.Insert( sa
, pos
, numRows 
); 
3880         wxGridTableMessage 
msg( this, 
3881                                 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
, 
3885         GetView()->ProcessTableMessage( msg 
); 
3891 bool wxGridStringTable::AppendRows( size_t numRows 
) 
3893     size_t curNumRows 
= m_data
.GetCount(); 
3894     size_t curNumCols 
= ( curNumRows 
> 0 
3895                          ? m_data
[0].GetCount() 
3896                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
3899     if ( curNumCols 
> 0 ) 
3901         sa
.Alloc( curNumCols 
); 
3902         sa
.Add( wxEmptyString
, curNumCols 
); 
3905     m_data
.Add( sa
, numRows 
); 
3909         wxGridTableMessage 
msg( this, 
3910                                 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, 
3913         GetView()->ProcessTableMessage( msg 
); 
3919 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows 
) 
3921     size_t curNumRows 
= m_data
.GetCount(); 
3923     if ( pos 
>= curNumRows 
) 
3925         wxFAIL_MSG( wxString::Format
 
3927                         wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"), 
3929                         (unsigned long)numRows
, 
3930                         (unsigned long)curNumRows
 
3936     if ( numRows 
> curNumRows 
- pos 
) 
3938         numRows 
= curNumRows 
- pos
; 
3941     if ( numRows 
>= curNumRows 
) 
3947         m_data
.RemoveAt( pos
, numRows 
); 
3952         wxGridTableMessage 
msg( this, 
3953                                 wxGRIDTABLE_NOTIFY_ROWS_DELETED
, 
3957         GetView()->ProcessTableMessage( msg 
); 
3963 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols 
) 
3967     size_t curNumRows 
= m_data
.GetCount(); 
3968     size_t curNumCols 
= ( curNumRows 
> 0 
3969                          ? m_data
[0].GetCount() 
3970                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
3972     if ( pos 
>= curNumCols 
) 
3974         return AppendCols( numCols 
); 
3977     if ( !m_colLabels
.IsEmpty() ) 
3979         m_colLabels
.Insert( wxEmptyString
, pos
, numCols 
); 
3982         for ( i 
= pos
; i 
< pos 
+ numCols
; i
++ ) 
3983             m_colLabels
[i
] = wxGridTableBase::GetColLabelValue( i 
); 
3986     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
3988         for ( col 
= pos
; col 
< pos 
+ numCols
; col
++ ) 
3990             m_data
[row
].Insert( wxEmptyString
, col 
); 
3996         wxGridTableMessage 
msg( this, 
3997                                 wxGRIDTABLE_NOTIFY_COLS_INSERTED
, 
4001         GetView()->ProcessTableMessage( msg 
); 
4007 bool wxGridStringTable::AppendCols( size_t numCols 
) 
4011     size_t curNumRows 
= m_data
.GetCount(); 
4013     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
4015         m_data
[row
].Add( wxEmptyString
, numCols 
); 
4020         wxGridTableMessage 
msg( this, 
4021                                 wxGRIDTABLE_NOTIFY_COLS_APPENDED
, 
4024         GetView()->ProcessTableMessage( msg 
); 
4030 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols 
) 
4034     size_t curNumRows 
= m_data
.GetCount(); 
4035     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
4036                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
4038     if ( pos 
>= curNumCols 
) 
4040         wxFAIL_MSG( wxString::Format
 
4042                         wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"), 
4044                         (unsigned long)numCols
, 
4045                         (unsigned long)curNumCols
 
4052         colID 
= GetView()->GetColAt( pos 
); 
4056     if ( numCols 
> curNumCols 
- colID 
) 
4058         numCols 
= curNumCols 
- colID
; 
4061     if ( !m_colLabels
.IsEmpty() ) 
4063         // m_colLabels stores just as many elements as it needs, e.g. if only 
4064         // the label of the first column had been set it would have only one 
4065         // element and not numCols, so account for it 
4066         int nToRm 
= m_colLabels
.size() - colID
; 
4068             m_colLabels
.RemoveAt( colID
, nToRm 
); 
4071     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
4073         if ( numCols 
>= curNumCols 
) 
4075             m_data
[row
].Clear(); 
4079             m_data
[row
].RemoveAt( colID
, numCols 
); 
4085         wxGridTableMessage 
msg( this, 
4086                                 wxGRIDTABLE_NOTIFY_COLS_DELETED
, 
4090         GetView()->ProcessTableMessage( msg 
); 
4096 wxString 
wxGridStringTable::GetRowLabelValue( int row 
) 
4098     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
4100         // using default label 
4102         return wxGridTableBase::GetRowLabelValue( row 
); 
4106         return m_rowLabels
[row
]; 
4110 wxString 
wxGridStringTable::GetColLabelValue( int col 
) 
4112     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
4114         // using default label 
4116         return wxGridTableBase::GetColLabelValue( col 
); 
4120         return m_colLabels
[col
]; 
4124 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value 
) 
4126     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
4128         int n 
= m_rowLabels
.GetCount(); 
4131         for ( i 
= n
; i 
<= row
; i
++ ) 
4133             m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) ); 
4137     m_rowLabels
[row
] = value
; 
4140 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value 
) 
4142     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
4144         int n 
= m_colLabels
.GetCount(); 
4147         for ( i 
= n
; i 
<= col
; i
++ ) 
4149             m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) ); 
4153     m_colLabels
[col
] = value
; 
4157 ////////////////////////////////////////////////////////////////////// 
4158 ////////////////////////////////////////////////////////////////////// 
4160 BEGIN_EVENT_TABLE(wxGridSubwindow
, wxWindow
) 
4161     EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost
) 
4164 void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
4166     m_owner
->CancelMouseCapture(); 
4169 IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow
, wxWindow 
) 
4171 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxGridSubwindow 
) 
4172     EVT_PAINT( wxGridRowLabelWindow::OnPaint 
) 
4173     EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel 
) 
4174     EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent 
) 
4177 wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid 
*parent
, 
4179                                             const wxPoint 
&pos
, const wxSize 
&size 
) 
4180   : wxGridSubwindow(parent
, id
, pos
, size
) 
4185 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4189     // NO - don't do this because it will set both the x and y origin 
4190     // coords to match the parent scrolled window and we just want to 
4191     // set the y coord  - MB 
4193     // m_owner->PrepareDC( dc ); 
4196     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
4197     wxPoint pt 
= dc
.GetDeviceOrigin(); 
4198     dc
.SetDeviceOrigin( pt
.x
, pt
.y
-y 
); 
4200     wxArrayInt rows 
= m_owner
->CalcRowLabelsExposed( GetUpdateRegion() ); 
4201     m_owner
->DrawRowLabels( dc
, rows 
); 
4204 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4206     m_owner
->ProcessRowLabelMouseEvent( event 
); 
4209 void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4211     m_owner
->GetEventHandler()->ProcessEvent( event 
); 
4214 ////////////////////////////////////////////////////////////////////// 
4216 IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow
, wxWindow 
) 
4218 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxGridSubwindow 
) 
4219     EVT_PAINT( wxGridColLabelWindow::OnPaint 
) 
4220     EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel 
) 
4221     EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent 
) 
4224 wxGridColLabelWindow::wxGridColLabelWindow( wxGrid 
*parent
, 
4226                                             const wxPoint 
&pos
, const wxSize 
&size 
) 
4227   : wxGridSubwindow(parent
, id
, pos
, size
) 
4232 void wxGridColLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4236     // NO - don't do this because it will set both the x and y origin 
4237     // coords to match the parent scrolled window and we just want to 
4238     // set the x coord  - MB 
4240     // m_owner->PrepareDC( dc ); 
4243     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
4244     wxPoint pt 
= dc
.GetDeviceOrigin(); 
4245     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
4246         dc
.SetDeviceOrigin( pt
.x
+x
, pt
.y 
); 
4248         dc
.SetDeviceOrigin( pt
.x
-x
, pt
.y 
); 
4250     wxArrayInt cols 
= m_owner
->CalcColLabelsExposed( GetUpdateRegion() ); 
4251     m_owner
->DrawColLabels( dc
, cols 
); 
4254 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4256     m_owner
->ProcessColLabelMouseEvent( event 
); 
4259 void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4261     m_owner
->GetEventHandler()->ProcessEvent( event 
); 
4264 ////////////////////////////////////////////////////////////////////// 
4266 IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow
, wxWindow 
) 
4268 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxGridSubwindow 
) 
4269     EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel 
) 
4270     EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent 
) 
4271     EVT_PAINT( wxGridCornerLabelWindow::OnPaint 
) 
4274 wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid 
*parent
, 
4277                                                   const wxSize
& size 
) 
4278   : wxGridSubwindow(parent
, id
, pos
, size
) 
4283 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4287     m_owner
->DrawCornerLabel(dc
); 
4290 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4292     m_owner
->ProcessCornerLabelMouseEvent( event 
); 
4295 void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4297     m_owner
->GetEventHandler()->ProcessEvent(event
); 
4300 ////////////////////////////////////////////////////////////////////// 
4302 IMPLEMENT_DYNAMIC_CLASS( wxGridWindow
, wxWindow 
) 
4304 BEGIN_EVENT_TABLE( wxGridWindow
, wxGridSubwindow 
) 
4305     EVT_PAINT( wxGridWindow::OnPaint 
) 
4306     EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel 
) 
4307     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent 
) 
4308     EVT_KEY_DOWN( wxGridWindow::OnKeyDown 
) 
4309     EVT_KEY_UP( wxGridWindow::OnKeyUp 
) 
4310     EVT_CHAR( wxGridWindow::OnChar 
) 
4311     EVT_SET_FOCUS( wxGridWindow::OnFocus 
) 
4312     EVT_KILL_FOCUS( wxGridWindow::OnFocus 
) 
4313     EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground 
) 
4316 wxGridWindow::wxGridWindow( wxGrid 
*parent
, 
4317                             wxGridRowLabelWindow 
*rowLblWin
, 
4318                             wxGridColLabelWindow 
*colLblWin
, 
4321                             const wxSize 
&size 
) 
4322             : wxGridSubwindow(parent
, id
, pos
, size
, 
4323                               wxWANTS_CHARS 
| wxCLIP_CHILDREN
, 
4324                               wxT("grid window") ) 
4327     m_rowLabelWin 
= rowLblWin
; 
4328     m_colLabelWin 
= colLblWin
; 
4331 void wxGridWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
4333     wxPaintDC 
dc( this ); 
4334     m_owner
->PrepareDC( dc 
); 
4335     wxRegion reg 
= GetUpdateRegion(); 
4336     wxGridCellCoordsArray dirtyCells 
= m_owner
->CalcCellsExposed( reg 
); 
4337     m_owner
->DrawGridCellArea( dc
, dirtyCells 
); 
4339     m_owner
->DrawGridSpace( dc 
); 
4341     m_owner
->DrawAllGridLines( dc
, reg 
); 
4343     m_owner
->DrawHighlight( dc
, dirtyCells 
); 
4346 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
4348     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
4349     m_rowLabelWin
->ScrollWindow( 0, dy
, rect 
); 
4350     m_colLabelWin
->ScrollWindow( dx
, 0, rect 
); 
4353 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4355     if (event
.ButtonDown(wxMOUSE_BTN_LEFT
) && FindFocus() != this) 
4358     m_owner
->ProcessGridCellMouseEvent( event 
); 
4361 void wxGridWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4363     m_owner
->GetEventHandler()->ProcessEvent( event 
); 
4366 // This seems to be required for wxMotif/wxGTK otherwise the mouse 
4367 // cursor must be in the cell edit control to get key events 
4369 void wxGridWindow::OnKeyDown( wxKeyEvent
& event 
) 
4371     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4375 void wxGridWindow::OnKeyUp( wxKeyEvent
& event 
) 
4377     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4381 void wxGridWindow::OnChar( wxKeyEvent
& event 
) 
4383     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4387 void wxGridWindow::OnEraseBackground( wxEraseEvent
& WXUNUSED(event
) ) 
4391 void wxGridWindow::OnFocus(wxFocusEvent
& event
) 
4393     // and if we have any selection, it has to be repainted, because it 
4394     // uses different colour when the grid is not focused: 
4395     if ( m_owner
->IsSelection() ) 
4401         // NB: Note that this code is in "else" branch only because the other 
4402         //     branch refreshes everything and so there's no point in calling 
4403         //     Refresh() again, *not* because it should only be done if 
4404         //     !IsSelection(). If the above code is ever optimized to refresh 
4405         //     only selected area, this needs to be moved out of the "else" 
4406         //     branch so that it's always executed. 
4408         // current cell cursor {dis,re}appears on focus change: 
4409         const wxGridCellCoords 
cursorCoords(m_owner
->GetGridCursorRow(), 
4410                                             m_owner
->GetGridCursorCol()); 
4411         const wxRect cursor 
= 
4412             m_owner
->BlockToDeviceRect(cursorCoords
, cursorCoords
); 
4413         Refresh(true, &cursor
); 
4416     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4420 #define internalXToCol(x) XToCol(x, true) 
4421 #define internalYToRow(y) YToRow(y, true) 
4423 ///////////////////////////////////////////////////////////////////// 
4425 #if wxUSE_EXTENDED_RTTI 
4426 WX_DEFINE_FLAGS( wxGridStyle 
) 
4428 wxBEGIN_FLAGS( wxGridStyle 
) 
4429     // new style border flags, we put them first to 
4430     // use them for streaming out 
4431     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
4432     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
4433     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
4434     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
4435     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
4436     wxFLAGS_MEMBER(wxBORDER_NONE
) 
4438     // old style border flags 
4439     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
4440     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
4441     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
4442     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
4443     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
4444     wxFLAGS_MEMBER(wxBORDER
) 
4446     // standard window styles 
4447     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
4448     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
4449     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
4450     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
4451     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
4452     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
) 
4453     wxFLAGS_MEMBER(wxVSCROLL
) 
4454     wxFLAGS_MEMBER(wxHSCROLL
) 
4456 wxEND_FLAGS( wxGridStyle 
) 
4458 IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid
, wxScrolledWindow
,"wx/grid.h") 
4460 wxBEGIN_PROPERTIES_TABLE(wxGrid
) 
4461     wxHIDE_PROPERTY( Children 
) 
4462     wxPROPERTY_FLAGS( WindowStyle 
, wxGridStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
4463 wxEND_PROPERTIES_TABLE() 
4465 wxBEGIN_HANDLERS_TABLE(wxGrid
) 
4466 wxEND_HANDLERS_TABLE() 
4468 wxCONSTRUCTOR_5( wxGrid 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle 
) 
4471  TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo) 
4474 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow 
) 
4477 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow 
) 
4478     EVT_PAINT( wxGrid::OnPaint 
) 
4479     EVT_SIZE( wxGrid::OnSize 
) 
4480     EVT_KEY_DOWN( wxGrid::OnKeyDown 
) 
4481     EVT_KEY_UP( wxGrid::OnKeyUp 
) 
4482     EVT_CHAR ( wxGrid::OnChar 
) 
4483     EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground 
) 
4491 wxGrid::wxGrid( wxWindow 
*parent
, 
4496                  const wxString
& name 
) 
4499     Create(parent
, id
, pos
, size
, style
, name
); 
4502 bool wxGrid::Create(wxWindow 
*parent
, wxWindowID id
, 
4503                           const wxPoint
& pos
, const wxSize
& size
, 
4504                           long style
, const wxString
& name
) 
4506     if (!wxScrolledWindow::Create(parent
, id
, pos
, size
, 
4507                                   style 
| wxWANTS_CHARS
, name
)) 
4510     m_colMinWidths 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
4511     m_rowMinHeights 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
4514     SetInitialSize(size
); 
4515     SetScrollRate(m_scrollLineX
, m_scrollLineY
); 
4523     // Ensure that the editor control is destroyed before the grid is, 
4524     // otherwise we crash later when the editor tries to do something with the 
4525     // half destroyed grid 
4526     HideCellEditControl(); 
4528     // Must do this or ~wxScrollHelper will pop the wrong event handler 
4529     SetTargetWindow(this); 
4531     wxSafeDecRef(m_defaultCellAttr
); 
4533 #ifdef DEBUG_ATTR_CACHE 
4534     size_t total 
= gs_nAttrCacheHits 
+ gs_nAttrCacheMisses
; 
4535     wxPrintf(_T("wxGrid attribute cache statistics: " 
4536                 "total: %u, hits: %u (%u%%)\n"), 
4537              total
, gs_nAttrCacheHits
, 
4538              total 
? (gs_nAttrCacheHits
*100) / total 
: 0); 
4541     // if we own the table, just delete it, otherwise at least don't leave it 
4542     // with dangling view pointer 
4545     else if ( m_table 
&& m_table
->GetView() == this ) 
4546         m_table
->SetView(NULL
); 
4548     delete m_typeRegistry
; 
4553 // ----- internal init and update functions 
4556 // NOTE: If using the default visual attributes works everywhere then this can 
4557 // be removed as well as the #else cases below. 
4558 #define _USE_VISATTR 0 
4560 void wxGrid::Create() 
4562     // create the type registry 
4563     m_typeRegistry 
= new wxGridTypeRegistry
; 
4565     m_cellEditCtrlEnabled 
= false; 
4567     m_defaultCellAttr 
= new wxGridCellAttr(); 
4569     // Set default cell attributes 
4570     m_defaultCellAttr
->SetDefAttr(m_defaultCellAttr
); 
4571     m_defaultCellAttr
->SetKind(wxGridCellAttr::Default
); 
4572     m_defaultCellAttr
->SetFont(GetFont()); 
4573     m_defaultCellAttr
->SetAlignment(wxALIGN_LEFT
, wxALIGN_TOP
); 
4574     m_defaultCellAttr
->SetRenderer(new wxGridCellStringRenderer
); 
4575     m_defaultCellAttr
->SetEditor(new wxGridCellTextEditor
); 
4578     wxVisualAttributes gva 
= wxListBox::GetClassDefaultAttributes(); 
4579     wxVisualAttributes lva 
= wxPanel::GetClassDefaultAttributes(); 
4581     m_defaultCellAttr
->SetTextColour(gva
.colFg
); 
4582     m_defaultCellAttr
->SetBackgroundColour(gva
.colBg
); 
4585     m_defaultCellAttr
->SetTextColour( 
4586         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
4587     m_defaultCellAttr
->SetBackgroundColour( 
4588         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
4593     m_currentCellCoords 
= wxGridNoCellCoords
; 
4595     m_rowLabelWidth 
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
4596     m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
4598     // subwindow components that make up the wxGrid 
4599     m_rowLabelWin 
= new wxGridRowLabelWindow( this, 
4604     m_colLabelWin 
= new wxGridColLabelWindow( this, 
4609     m_cornerLabelWin 
= new wxGridCornerLabelWindow( this, 
4614     m_gridWin 
= new wxGridWindow( this, 
4621     SetTargetWindow( m_gridWin 
); 
4624     wxColour gfg 
= gva
.colFg
; 
4625     wxColour gbg 
= gva
.colBg
; 
4626     wxColour lfg 
= lva
.colFg
; 
4627     wxColour lbg 
= lva
.colBg
; 
4629     wxColour gfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
4630     wxColour gbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
4631     wxColour lfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
4632     wxColour lbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
4635     m_cornerLabelWin
->SetOwnForegroundColour(lfg
); 
4636     m_cornerLabelWin
->SetOwnBackgroundColour(lbg
); 
4637     m_rowLabelWin
->SetOwnForegroundColour(lfg
); 
4638     m_rowLabelWin
->SetOwnBackgroundColour(lbg
); 
4639     m_colLabelWin
->SetOwnForegroundColour(lfg
); 
4640     m_colLabelWin
->SetOwnBackgroundColour(lbg
); 
4642     m_gridWin
->SetOwnForegroundColour(gfg
); 
4643     m_gridWin
->SetOwnBackgroundColour(gbg
); 
4648 bool wxGrid::CreateGrid( int numRows
, int numCols
, 
4649                          wxGridSelectionModes selmode 
) 
4651     wxCHECK_MSG( !m_created
, 
4653                  wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); 
4655     return SetTable(new wxGridStringTable(numRows
, numCols
), true, selmode
); 
4658 void wxGrid::SetSelectionMode(wxGridSelectionModes selmode
) 
4660     wxCHECK_RET( m_created
, 
4661                  wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); 
4663     m_selection
->SetSelectionMode( selmode 
); 
4666 wxGrid::wxGridSelectionModes 
wxGrid::GetSelectionMode() const 
4668     wxCHECK_MSG( m_created
, wxGridSelectCells
, 
4669                  wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") ); 
4671     return m_selection
->GetSelectionMode(); 
4675 wxGrid::SetTable(wxGridTableBase 
*table
, 
4677                  wxGrid::wxGridSelectionModes selmode 
) 
4679     bool checkSelection 
= false; 
4682         // stop all processing 
4687             m_table
->SetView(0); 
4699         checkSelection 
= true; 
4701         // kill row and column size arrays 
4702         m_colWidths
.Empty(); 
4703         m_colRights
.Empty(); 
4704         m_rowHeights
.Empty(); 
4705         m_rowBottoms
.Empty(); 
4710         m_numRows 
= table
->GetNumberRows(); 
4711         m_numCols 
= table
->GetNumberCols(); 
4714         m_table
->SetView( this ); 
4715         m_ownTable 
= takeOwnership
; 
4716         m_selection 
= new wxGridSelection( this, selmode 
); 
4719             // If the newly set table is smaller than the 
4720             // original one current cell and selection regions 
4721             // might be invalid, 
4722             m_selectedBlockCorner 
= wxGridNoCellCoords
; 
4723             m_currentCellCoords 
= 
4724               wxGridCellCoords(wxMin(m_numRows
, m_currentCellCoords
.GetRow()), 
4725                                wxMin(m_numCols
, m_currentCellCoords
.GetCol())); 
4726             if (m_selectedBlockTopLeft
.GetRow() >= m_numRows 
|| 
4727                 m_selectedBlockTopLeft
.GetCol() >= m_numCols
) 
4729                 m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
4730                 m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
4733                 m_selectedBlockBottomRight 
= 
4734                   wxGridCellCoords(wxMin(m_numRows
, 
4735                                          m_selectedBlockBottomRight
.GetRow()), 
4737                                          m_selectedBlockBottomRight
.GetCol())); 
4747 void wxGrid::InitVars() 
4751     m_cornerLabelWin 
= NULL
; 
4752     m_rowLabelWin 
= NULL
; 
4753     m_colLabelWin 
= NULL
; 
4760     m_defaultCellAttr 
= NULL
; 
4761     m_typeRegistry 
= NULL
; 
4762     m_winCapture 
= NULL
; 
4767     m_rowLabelWidth  
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
4768     m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
4770     if ( m_rowLabelWin 
) 
4772         m_labelBackgroundColour 
= m_rowLabelWin
->GetBackgroundColour(); 
4776         m_labelBackgroundColour 
= *wxWHITE
; 
4779     m_labelTextColour 
= *wxBLACK
; 
4782     m_attrCache
.row 
= -1; 
4783     m_attrCache
.col 
= -1; 
4784     m_attrCache
.attr 
= NULL
; 
4786     m_labelFont 
= GetFont(); 
4787     m_labelFont
.SetWeight( wxBOLD 
); 
4789     m_rowLabelHorizAlign 
= wxALIGN_CENTRE
; 
4790     m_rowLabelVertAlign  
= wxALIGN_CENTRE
; 
4792     m_colLabelHorizAlign 
= wxALIGN_CENTRE
; 
4793     m_colLabelVertAlign  
= wxALIGN_CENTRE
; 
4794     m_colLabelTextOrientation 
= wxHORIZONTAL
; 
4796     m_defaultColWidth  
= WXGRID_DEFAULT_COL_WIDTH
; 
4797     m_defaultRowHeight 
= m_gridWin
->GetCharHeight(); 
4799     m_minAcceptableColWidth  
= WXGRID_MIN_COL_WIDTH
; 
4800     m_minAcceptableRowHeight 
= WXGRID_MIN_ROW_HEIGHT
; 
4802 #if defined(__WXMOTIF__) || defined(__WXGTK__)  // see also text ctrl sizing in ShowCellEditControl() 
4803     m_defaultRowHeight 
+= 8; 
4805     m_defaultRowHeight 
+= 4; 
4808     m_gridLineColour 
= wxColour( 192,192,192 ); 
4809     m_gridLinesEnabled 
= true; 
4810     m_gridLinesClipHorz 
= 
4811     m_gridLinesClipVert 
= true; 
4812     m_cellHighlightColour 
= *wxBLACK
; 
4813     m_cellHighlightPenWidth 
= 2; 
4814     m_cellHighlightROPenWidth 
= 1; 
4816     m_canDragColMove 
= false; 
4818     m_cursorMode  
= WXGRID_CURSOR_SELECT_CELL
; 
4819     m_winCapture 
= NULL
; 
4820     m_canDragRowSize 
= true; 
4821     m_canDragColSize 
= true; 
4822     m_canDragGridSize 
= true; 
4823     m_canDragCell 
= false; 
4825     m_dragRowOrCol 
= -1; 
4826     m_isDragging 
= false; 
4827     m_startDragPos 
= wxDefaultPosition
; 
4828     m_nativeColumnLabels 
= false; 
4830     m_waitForSlowClick 
= false; 
4832     m_rowResizeCursor 
= wxCursor( wxCURSOR_SIZENS 
); 
4833     m_colResizeCursor 
= wxCursor( wxCURSOR_SIZEWE 
); 
4835     m_currentCellCoords 
= wxGridNoCellCoords
; 
4839     m_selectionBackground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
4840     m_selectionForeground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
4842     m_editable 
= true;  // default for whole grid 
4844     m_inOnKeyDown 
= false; 
4850     m_scrollLineX 
= GRID_SCROLL_LINE_X
; 
4851     m_scrollLineY 
= GRID_SCROLL_LINE_Y
; 
4854 // ---------------------------------------------------------------------------- 
4855 // the idea is to call these functions only when necessary because they create 
4856 // quite big arrays which eat memory mostly unnecessary - in particular, if 
4857 // default widths/heights are used for all rows/columns, we may not use these 
4860 // with some extra code, it should be possible to only store the widths/heights 
4861 // different from default ones (resulting in space savings for huge grids) but 
4862 // this is not done currently 
4863 // ---------------------------------------------------------------------------- 
4865 void wxGrid::InitRowHeights() 
4867     m_rowHeights
.Empty(); 
4868     m_rowBottoms
.Empty(); 
4870     m_rowHeights
.Alloc( m_numRows 
); 
4871     m_rowBottoms
.Alloc( m_numRows 
); 
4873     m_rowHeights
.Add( m_defaultRowHeight
, m_numRows 
); 
4876     for ( int i 
= 0; i 
< m_numRows
; i
++ ) 
4878         rowBottom 
+= m_defaultRowHeight
; 
4879         m_rowBottoms
.Add( rowBottom 
); 
4883 void wxGrid::InitColWidths() 
4885     m_colWidths
.Empty(); 
4886     m_colRights
.Empty(); 
4888     m_colWidths
.Alloc( m_numCols 
); 
4889     m_colRights
.Alloc( m_numCols 
); 
4891     m_colWidths
.Add( m_defaultColWidth
, m_numCols 
); 
4893     for ( int i 
= 0; i 
< m_numCols
; i
++ ) 
4895         int colRight 
= ( GetColPos( i 
) + 1 ) * m_defaultColWidth
; 
4896         m_colRights
.Add( colRight 
); 
4900 int wxGrid::GetColWidth(int col
) const 
4902     return m_colWidths
.IsEmpty() ? m_defaultColWidth 
: m_colWidths
[col
]; 
4905 int wxGrid::GetColLeft(int col
) const 
4907     return m_colRights
.IsEmpty() ? GetColPos( col 
) * m_defaultColWidth
 
4908                                  : m_colRights
[col
] - m_colWidths
[col
]; 
4911 int wxGrid::GetColRight(int col
) const 
4913     return m_colRights
.IsEmpty() ? (GetColPos( col 
) + 1) * m_defaultColWidth
 
4917 int wxGrid::GetRowHeight(int row
) const 
4919     return m_rowHeights
.IsEmpty() ? m_defaultRowHeight 
: m_rowHeights
[row
]; 
4922 int wxGrid::GetRowTop(int row
) const 
4924     return m_rowBottoms
.IsEmpty() ? row 
* m_defaultRowHeight
 
4925                                   : m_rowBottoms
[row
] - m_rowHeights
[row
]; 
4928 int wxGrid::GetRowBottom(int row
) const 
4930     return m_rowBottoms
.IsEmpty() ? (row 
+ 1) * m_defaultRowHeight
 
4931                                   : m_rowBottoms
[row
]; 
4934 void wxGrid::CalcDimensions() 
4936     // compute the size of the scrollable area 
4937     int w 
= m_numCols 
> 0 ? GetColRight(GetColAt(m_numCols 
- 1)) : 0; 
4938     int h 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
4943     // take into account editor if shown 
4944     if ( IsCellEditControlShown() ) 
4947         int r 
= m_currentCellCoords
.GetRow(); 
4948         int c 
= m_currentCellCoords
.GetCol(); 
4949         int x 
= GetColLeft(c
); 
4950         int y 
= GetRowTop(r
); 
4952         // how big is the editor 
4953         wxGridCellAttr
* attr 
= GetCellAttr(r
, c
); 
4954         wxGridCellEditor
* editor 
= attr
->GetEditor(this, r
, c
); 
4955         editor
->GetControl()->GetSize(&w2
, &h2
); 
4966     // preserve (more or less) the previous position 
4968     GetViewStart( &x
, &y 
); 
4970     // ensure the position is valid for the new scroll ranges 
4972         x 
= wxMax( w 
- 1, 0 ); 
4974         y 
= wxMax( h 
- 1, 0 ); 
4976     // update the virtual size and refresh the scrollbars to reflect it 
4977     m_gridWin
->SetVirtualSize(w
, h
); 
4981     // if our OnSize() hadn't been called (it would if we have scrollbars), we 
4982     // still must reposition the children 
4986 wxSize 
wxGrid::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
4988     wxSize 
sizeGridWin(size
); 
4989     sizeGridWin
.x 
-= m_rowLabelWidth
; 
4990     sizeGridWin
.y 
-= m_colLabelHeight
; 
4995 void wxGrid::CalcWindowSizes() 
4997     // escape if the window is has not been fully created yet 
4999     if ( m_cornerLabelWin 
== NULL 
) 
5003     GetClientSize( &cw
, &ch 
); 
5005     // the grid may be too small to have enough space for the labels yet, don't 
5006     // size the windows to negative sizes in this case 
5007     int gw 
= cw 
- m_rowLabelWidth
; 
5008     int gh 
= ch 
- m_colLabelHeight
; 
5014     if ( m_cornerLabelWin 
&& m_cornerLabelWin
->IsShown() ) 
5015         m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight 
); 
5017     if ( m_colLabelWin 
&& m_colLabelWin
->IsShown() ) 
5018         m_colLabelWin
->SetSize( m_rowLabelWidth
, 0, gw
, m_colLabelHeight 
); 
5020     if ( m_rowLabelWin 
&& m_rowLabelWin
->IsShown() ) 
5021         m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, gh 
); 
5023     if ( m_gridWin 
&& m_gridWin
->IsShown() ) 
5024         m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, gw
, gh 
); 
5027 // this is called when the grid table sends a message 
5028 // to indicate that it has been redimensioned 
5030 bool wxGrid::Redimension( wxGridTableMessage
& msg 
) 
5033     bool result 
= false; 
5035     // Clear the attribute cache as the attribute might refer to a different 
5036     // cell than stored in the cache after adding/removing rows/columns. 
5039     // By the same reasoning, the editor should be dismissed if columns are 
5040     // added or removed. And for consistency, it should IMHO always be 
5041     // removed, not only if the cell "underneath" it actually changes. 
5042     // For now, I intentionally do not save the editor's content as the 
5043     // cell it might want to save that stuff to might no longer exist. 
5044     HideCellEditControl(); 
5047     // if we were using the default widths/heights so far, we must change them 
5049     if ( m_colWidths
.IsEmpty() ) 
5054     if ( m_rowHeights
.IsEmpty() ) 
5060     switch ( msg
.GetId() ) 
5062         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
5064             size_t pos 
= msg
.GetCommandInt(); 
5065             int numRows 
= msg
.GetCommandInt2(); 
5067             m_numRows 
+= numRows
; 
5069             if ( !m_rowHeights
.IsEmpty() ) 
5071                 m_rowHeights
.Insert( m_defaultRowHeight
, pos
, numRows 
); 
5072                 m_rowBottoms
.Insert( 0, pos
, numRows 
); 
5076                     bottom 
= m_rowBottoms
[pos 
- 1]; 
5078                 for ( i 
= pos
; i 
< m_numRows
; i
++ ) 
5080                     bottom 
+= m_rowHeights
[i
]; 
5081                     m_rowBottoms
[i
] = bottom
; 
5085             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5087                 // if we have just inserted cols into an empty grid the current 
5088                 // cell will be undefined... 
5090                 SetCurrentCell( 0, 0 ); 
5094                 m_selection
->UpdateRows( pos
, numRows 
); 
5095             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5097                 attrProvider
->UpdateAttrRows( pos
, numRows 
); 
5099             if ( !GetBatchCount() ) 
5102                 m_rowLabelWin
->Refresh(); 
5108         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
5110             int numRows 
= msg
.GetCommandInt(); 
5111             int oldNumRows 
= m_numRows
; 
5112             m_numRows 
+= numRows
; 
5114             if ( !m_rowHeights
.IsEmpty() ) 
5116                 m_rowHeights
.Add( m_defaultRowHeight
, numRows 
); 
5117                 m_rowBottoms
.Add( 0, numRows 
); 
5120                 if ( oldNumRows 
> 0 ) 
5121                     bottom 
= m_rowBottoms
[oldNumRows 
- 1]; 
5123                 for ( i 
= oldNumRows
; i 
< m_numRows
; i
++ ) 
5125                     bottom 
+= m_rowHeights
[i
]; 
5126                     m_rowBottoms
[i
] = bottom
; 
5130             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5132                 // if we have just inserted cols into an empty grid the current 
5133                 // cell will be undefined... 
5135                 SetCurrentCell( 0, 0 ); 
5138             if ( !GetBatchCount() ) 
5141                 m_rowLabelWin
->Refresh(); 
5147         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
5149             size_t pos 
= msg
.GetCommandInt(); 
5150             int numRows 
= msg
.GetCommandInt2(); 
5151             m_numRows 
-= numRows
; 
5153             if ( !m_rowHeights
.IsEmpty() ) 
5155                 m_rowHeights
.RemoveAt( pos
, numRows 
); 
5156                 m_rowBottoms
.RemoveAt( pos
, numRows 
); 
5159                 for ( i 
= 0; i 
< m_numRows
; i
++ ) 
5161                     h 
+= m_rowHeights
[i
]; 
5162                     m_rowBottoms
[i
] = h
; 
5168                 m_currentCellCoords 
= wxGridNoCellCoords
; 
5172                 if ( m_currentCellCoords
.GetRow() >= m_numRows 
) 
5173                     m_currentCellCoords
.Set( 0, 0 ); 
5177                 m_selection
->UpdateRows( pos
, -((int)numRows
) ); 
5178             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5181                 attrProvider
->UpdateAttrRows( pos
, -((int)numRows
) ); 
5183 // ifdef'd out following patch from Paul Gammans 
5185                 // No need to touch column attributes, unless we 
5186                 // removed _all_ rows, in this case, we remove 
5187                 // all column attributes. 
5188                 // I hate to do this here, but the 
5189                 // needed data is not available inside UpdateAttrRows. 
5190                 if ( !GetNumberRows() ) 
5191                     attrProvider
->UpdateAttrCols( 0, -GetNumberCols() ); 
5195             if ( !GetBatchCount() ) 
5198                 m_rowLabelWin
->Refresh(); 
5204         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
5206             size_t pos 
= msg
.GetCommandInt(); 
5207             int numCols 
= msg
.GetCommandInt2(); 
5208             m_numCols 
+= numCols
; 
5210             if ( !m_colAt
.IsEmpty() ) 
5212                 //Shift the column IDs 
5214                 for ( i 
= 0; i 
< m_numCols 
- numCols
; i
++ ) 
5216                     if ( m_colAt
[i
] >= (int)pos 
) 
5217                         m_colAt
[i
] += numCols
; 
5220                 m_colAt
.Insert( pos
, pos
, numCols 
); 
5222                 //Set the new columns' positions 
5223                 for ( i 
= pos 
+ 1; i 
< (int)pos 
+ numCols
; i
++ ) 
5229             if ( !m_colWidths
.IsEmpty() ) 
5231                 m_colWidths
.Insert( m_defaultColWidth
, pos
, numCols 
); 
5232                 m_colRights
.Insert( 0, pos
, numCols 
); 
5236                     right 
= m_colRights
[GetColAt( pos 
- 1 )]; 
5239                 for ( colPos 
= pos
; colPos 
< m_numCols
; colPos
++ ) 
5241                     i 
= GetColAt( colPos 
); 
5243                     right 
+= m_colWidths
[i
]; 
5244                     m_colRights
[i
] = right
; 
5248             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5250                 // if we have just inserted cols into an empty grid the current 
5251                 // cell will be undefined... 
5253                 SetCurrentCell( 0, 0 ); 
5257                 m_selection
->UpdateCols( pos
, numCols 
); 
5258             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5260                 attrProvider
->UpdateAttrCols( pos
, numCols 
); 
5261             if ( !GetBatchCount() ) 
5264                 m_colLabelWin
->Refresh(); 
5270         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
5272             int numCols 
= msg
.GetCommandInt(); 
5273             int oldNumCols 
= m_numCols
; 
5274             m_numCols 
+= numCols
; 
5276             if ( !m_colAt
.IsEmpty() ) 
5278                 m_colAt
.Add( 0, numCols 
); 
5280                 //Set the new columns' positions 
5282                 for ( i 
= oldNumCols
; i 
< m_numCols
; i
++ ) 
5288             if ( !m_colWidths
.IsEmpty() ) 
5290                 m_colWidths
.Add( m_defaultColWidth
, numCols 
); 
5291                 m_colRights
.Add( 0, numCols 
); 
5294                 if ( oldNumCols 
> 0 ) 
5295                     right 
= m_colRights
[GetColAt( oldNumCols 
- 1 )]; 
5298                 for ( colPos 
= oldNumCols
; colPos 
< m_numCols
; colPos
++ ) 
5300                     i 
= GetColAt( colPos 
); 
5302                     right 
+= m_colWidths
[i
]; 
5303                     m_colRights
[i
] = right
; 
5307             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5309                 // if we have just inserted cols into an empty grid the current 
5310                 // cell will be undefined... 
5312                 SetCurrentCell( 0, 0 ); 
5314             if ( !GetBatchCount() ) 
5317                 m_colLabelWin
->Refresh(); 
5323         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
5325             size_t pos 
= msg
.GetCommandInt(); 
5326             int numCols 
= msg
.GetCommandInt2(); 
5327             m_numCols 
-= numCols
; 
5329             if ( !m_colAt
.IsEmpty() ) 
5331                 int colID 
= GetColAt( pos 
); 
5333                 m_colAt
.RemoveAt( pos
, numCols 
); 
5335                 //Shift the column IDs 
5337                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
5339                     if ( m_colAt
[colPos
] > colID 
) 
5340                         m_colAt
[colPos
] -= numCols
; 
5344             if ( !m_colWidths
.IsEmpty() ) 
5346                 m_colWidths
.RemoveAt( pos
, numCols 
); 
5347                 m_colRights
.RemoveAt( pos
, numCols 
); 
5351                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
5353                     i 
= GetColAt( colPos 
); 
5355                     w 
+= m_colWidths
[i
]; 
5362                 m_currentCellCoords 
= wxGridNoCellCoords
; 
5366                 if ( m_currentCellCoords
.GetCol() >= m_numCols 
) 
5367                   m_currentCellCoords
.Set( 0, 0 ); 
5371                 m_selection
->UpdateCols( pos
, -((int)numCols
) ); 
5372             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5375                 attrProvider
->UpdateAttrCols( pos
, -((int)numCols
) ); 
5377 // ifdef'd out following patch from Paul Gammans 
5379                 // No need to touch row attributes, unless we 
5380                 // removed _all_ columns, in this case, we remove 
5381                 // all row attributes. 
5382                 // I hate to do this here, but the 
5383                 // needed data is not available inside UpdateAttrCols. 
5384                 if ( !GetNumberCols() ) 
5385                     attrProvider
->UpdateAttrRows( 0, -GetNumberRows() ); 
5389             if ( !GetBatchCount() ) 
5392                 m_colLabelWin
->Refresh(); 
5399     if (result 
&& !GetBatchCount() ) 
5400         m_gridWin
->Refresh(); 
5405 wxArrayInt 
wxGrid::CalcRowLabelsExposed( const wxRegion
& reg 
) const 
5407     wxRegionIterator 
iter( reg 
); 
5410     wxArrayInt  rowlabels
; 
5417         // TODO: remove this when we can... 
5418         // There is a bug in wxMotif that gives garbage update 
5419         // rectangles if you jump-scroll a long way by clicking the 
5420         // scrollbar with middle button.  This is a work-around 
5422 #if defined(__WXMOTIF__) 
5424         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5425         if ( r
.GetTop() > ch 
) 
5427         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
5430         // logical bounds of update region 
5433         CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top 
); 
5434         CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom 
); 
5436         // find the row labels within these bounds 
5439         for ( row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
5441             if ( GetRowBottom(row
) < top 
) 
5444             if ( GetRowTop(row
) > bottom 
) 
5447             rowlabels
.Add( row 
); 
5456 wxArrayInt 
wxGrid::CalcColLabelsExposed( const wxRegion
& reg 
) const 
5458     wxRegionIterator 
iter( reg 
); 
5461     wxArrayInt colLabels
; 
5468         // TODO: remove this when we can... 
5469         // There is a bug in wxMotif that gives garbage update 
5470         // rectangles if you jump-scroll a long way by clicking the 
5471         // scrollbar with middle button.  This is a work-around 
5473 #if defined(__WXMOTIF__) 
5475         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5476         if ( r
.GetLeft() > cw 
) 
5478         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
5481         // logical bounds of update region 
5484         CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy 
); 
5485         CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy 
); 
5487         // find the cells within these bounds 
5491         for ( colPos 
= GetColPos( internalXToCol(left
) ); colPos 
< m_numCols
; colPos
++ ) 
5493             col 
= GetColAt( colPos 
); 
5495             if ( GetColRight(col
) < left 
) 
5498             if ( GetColLeft(col
) > right 
) 
5501             colLabels
.Add( col 
); 
5510 wxGridCellCoordsArray 
wxGrid::CalcCellsExposed( const wxRegion
& reg 
) const 
5512     wxRegionIterator 
iter( reg 
); 
5515     wxGridCellCoordsArray  cellsExposed
; 
5517     int left
, top
, right
, bottom
; 
5522         // TODO: remove this when we can... 
5523         // There is a bug in wxMotif that gives garbage update 
5524         // rectangles if you jump-scroll a long way by clicking the 
5525         // scrollbar with middle button.  This is a work-around 
5527 #if defined(__WXMOTIF__) 
5529         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5530         if ( r
.GetTop() > ch 
) r
.SetTop( 0 ); 
5531         if ( r
.GetLeft() > cw 
) r
.SetLeft( 0 ); 
5532         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
5533         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
5536         // logical bounds of update region 
5538         CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
5539         CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
5541         // find the cells within these bounds 
5544         for ( row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
5546             if ( GetRowBottom(row
) <= top 
) 
5549             if ( GetRowTop(row
) > bottom 
) 
5553             for ( colPos 
= GetColPos( internalXToCol(left
) ); colPos 
< m_numCols
; colPos
++ ) 
5555                 col 
= GetColAt( colPos 
); 
5557                 if ( GetColRight(col
) <= left 
) 
5560                 if ( GetColLeft(col
) > right 
) 
5563                 cellsExposed
.Add( wxGridCellCoords( row
, col 
) ); 
5570     return cellsExposed
; 
5574 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event 
) 
5577     wxPoint 
pos( event
.GetPosition() ); 
5578     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
5580     if ( event
.Dragging() ) 
5584             m_isDragging 
= true; 
5585             m_rowLabelWin
->CaptureMouse(); 
5588         if ( event
.LeftIsDown() ) 
5590             switch ( m_cursorMode 
) 
5592                 case WXGRID_CURSOR_RESIZE_ROW
: 
5594                     int cw
, ch
, left
, dummy
; 
5595                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
5596                     CalcUnscrolledPosition( 0, 0, &left
, &dummy 
); 
5598                     wxClientDC 
dc( m_gridWin 
); 
5601                                GetRowTop(m_dragRowOrCol
) + 
5602                                GetRowMinimalHeight(m_dragRowOrCol
) ); 
5603                     dc
.SetLogicalFunction(wxINVERT
); 
5604                     if ( m_dragLastPos 
>= 0 ) 
5606                         dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos 
); 
5608                     dc
.DrawLine( left
, y
, left
+cw
, y 
); 
5613                 case WXGRID_CURSOR_SELECT_ROW
: 
5615                     if ( (row 
= YToRow( y 
)) >= 0 ) 
5618                             m_selection
->SelectRow(row
, event
); 
5623                 // default label to suppress warnings about "enumeration value 
5624                 // 'xxx' not handled in switch 
5632     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
5637         if (m_rowLabelWin
->HasCapture()) 
5638             m_rowLabelWin
->ReleaseMouse(); 
5639         m_isDragging 
= false; 
5642     // ------------ Entering or leaving the window 
5644     if ( event
.Entering() || event
.Leaving() ) 
5646         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
5649     // ------------ Left button pressed 
5651     else if ( event
.LeftDown() ) 
5653         // don't send a label click event for a hit on the 
5654         // edge of the row label - this is probably the user 
5655         // wanting to resize the row 
5657         if ( YToEdgeOfRow(y
) < 0 ) 
5661                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event 
) ) 
5663                 if ( !event
.ShiftDown() && !event
.CmdDown() ) 
5667                     if ( event
.ShiftDown() ) 
5669                         m_selection
->SelectBlock
 
5671                                         m_currentCellCoords
.GetRow(), 0, 
5672                                         row
, GetNumberCols() - 1, 
5678                         m_selection
->SelectRow(row
, event
); 
5682                 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
); 
5687             // starting to drag-resize a row 
5688             if ( CanDragRowSize() ) 
5689                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
); 
5693     // ------------ Left double click 
5695     else if (event
.LeftDClick() ) 
5697         row 
= YToEdgeOfRow(y
); 
5702                  !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event 
) ) 
5704                 // no default action at the moment 
5709             // adjust row height depending on label text 
5710             AutoSizeRowLabelSize( row 
); 
5712             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
); 
5717     // ------------ Left button released 
5719     else if ( event
.LeftUp() ) 
5721         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
5723             DoEndDragResizeRow(); 
5725             // Note: we are ending the event *after* doing 
5726             // default processing in this case 
5728             SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
5731         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
5735     // ------------ Right button down 
5737     else if ( event
.RightDown() ) 
5741              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event 
) ) 
5743             // no default action at the moment 
5747     // ------------ Right double click 
5749     else if ( event
.RightDClick() ) 
5753              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event 
) ) 
5755             // no default action at the moment 
5759     // ------------ No buttons down and mouse moving 
5761     else if ( event
.Moving() ) 
5763         m_dragRowOrCol 
= YToEdgeOfRow( y 
); 
5764         if ( m_dragRowOrCol 
>= 0 ) 
5766             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
5768                 // don't capture the mouse yet 
5769                 if ( CanDragRowSize() ) 
5770                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, false); 
5773         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
5775             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, false); 
5780 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event 
) 
5783     wxPoint 
pos( event
.GetPosition() ); 
5784     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
5786     if ( event
.Dragging() ) 
5790             m_isDragging 
= true; 
5791             m_colLabelWin
->CaptureMouse(); 
5793             if ( m_cursorMode 
== WXGRID_CURSOR_MOVE_COL 
) 
5794                 m_dragRowOrCol 
= XToCol( x 
); 
5797         if ( event
.LeftIsDown() ) 
5799             switch ( m_cursorMode 
) 
5801                 case WXGRID_CURSOR_RESIZE_COL
: 
5803                     int cw
, ch
, dummy
, top
; 
5804                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
5805                     CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
5807                     wxClientDC 
dc( m_gridWin 
); 
5810                     x 
= wxMax( x
, GetColLeft(m_dragRowOrCol
) + 
5811                                   GetColMinimalWidth(m_dragRowOrCol
)); 
5812                     dc
.SetLogicalFunction(wxINVERT
); 
5813                     if ( m_dragLastPos 
>= 0 ) 
5815                         dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top 
+ ch 
); 
5817                     dc
.DrawLine( x
, top
, x
, top 
+ ch 
); 
5822                 case WXGRID_CURSOR_SELECT_COL
: 
5824                     if ( (col 
= XToCol( x 
)) >= 0 ) 
5827                             m_selection
->SelectCol(col
, event
); 
5832                 case WXGRID_CURSOR_MOVE_COL
: 
5835                         m_moveToCol 
= GetColAt( 0 ); 
5837                         m_moveToCol 
= XToCol( x 
); 
5841                     if ( m_moveToCol 
< 0 ) 
5842                         markerX 
= GetColRight( GetColAt( m_numCols 
- 1 ) ); 
5843                     else if ( x 
>= (GetColLeft( m_moveToCol 
) + (GetColWidth(m_moveToCol
) / 2)) ) 
5845                         m_moveToCol 
= GetColAt( GetColPos( m_moveToCol 
) + 1 ); 
5846                         if ( m_moveToCol 
< 0 ) 
5847                             markerX 
= GetColRight( GetColAt( m_numCols 
- 1 ) ); 
5849                             markerX 
= GetColLeft( m_moveToCol 
); 
5852                         markerX 
= GetColLeft( m_moveToCol 
); 
5854                     if ( markerX 
!= m_dragLastPos 
) 
5856                         wxClientDC 
dc( m_colLabelWin 
); 
5860                         m_colLabelWin
->GetClientSize( &cw
, &ch 
); 
5864                         //Clean up the last indicator 
5865                         if ( m_dragLastPos 
>= 0 ) 
5867                             wxPen 
pen( m_colLabelWin
->GetBackgroundColour(), 2 ); 
5869                             dc
.DrawLine( m_dragLastPos 
+ 1, 0, m_dragLastPos 
+ 1, ch 
); 
5870                             dc
.SetPen(wxNullPen
); 
5872                             if ( XToCol( m_dragLastPos 
) != -1 ) 
5873                                 DrawColLabel( dc
, XToCol( m_dragLastPos 
) ); 
5876                         const wxColour 
*color
; 
5877                         //Moving to the same place? Don't draw a marker 
5878                         if ( (m_moveToCol 
== m_dragRowOrCol
) 
5879                           || (GetColPos( m_moveToCol 
) == GetColPos( m_dragRowOrCol 
) + 1) 
5880                           || (m_moveToCol 
< 0 && m_dragRowOrCol 
== GetColAt( m_numCols 
- 1 ))) 
5881                             color 
= wxLIGHT_GREY
; 
5886                         wxPen 
pen( *color
, 2 ); 
5889                         dc
.DrawLine( markerX
, 0, markerX
, ch 
); 
5891                         dc
.SetPen(wxNullPen
); 
5893                         m_dragLastPos 
= markerX 
- 1; 
5898                 // default label to suppress warnings about "enumeration value 
5899                 // 'xxx' not handled in switch 
5907     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
5912         if (m_colLabelWin
->HasCapture()) 
5913             m_colLabelWin
->ReleaseMouse(); 
5914         m_isDragging 
= false; 
5917     // ------------ Entering or leaving the window 
5919     if ( event
.Entering() || event
.Leaving() ) 
5921         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
); 
5924     // ------------ Left button pressed 
5926     else if ( event
.LeftDown() ) 
5928         // don't send a label click event for a hit on the 
5929         // edge of the col label - this is probably the user 
5930         // wanting to resize the col 
5932         if ( XToEdgeOfCol(x
) < 0 ) 
5936                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event 
) ) 
5938                 if ( m_canDragColMove 
) 
5940                     //Show button as pressed 
5941                     wxClientDC 
dc( m_colLabelWin 
); 
5942                     int colLeft 
= GetColLeft( col 
); 
5943                     int colRight 
= GetColRight( col 
) - 1; 
5944                     dc
.SetPen( wxPen( m_colLabelWin
->GetBackgroundColour(), 1 ) ); 
5945                     dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight
-1 ); 
5946                     dc
.DrawLine( colLeft
, 1, colRight
, 1 ); 
5948                     ChangeCursorMode(WXGRID_CURSOR_MOVE_COL
, m_colLabelWin
); 
5952                     if ( !event
.ShiftDown() && !event
.CmdDown() ) 
5956                         if ( event
.ShiftDown() ) 
5958                             m_selection
->SelectBlock
 
5960                                             0, m_currentCellCoords
.GetCol(), 
5961                                             GetNumberRows() - 1, col
, 
5967                             m_selection
->SelectCol(col
, event
); 
5971                     ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, m_colLabelWin
); 
5977             // starting to drag-resize a col 
5979             if ( CanDragColSize() ) 
5980                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
); 
5984     // ------------ Left double click 
5986     if ( event
.LeftDClick() ) 
5988         col 
= XToEdgeOfCol(x
); 
5993                  ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event 
) ) 
5995                 // no default action at the moment 
6000             // adjust column width depending on label text 
6001             AutoSizeColLabelSize( col 
); 
6003             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
); 
6008     // ------------ Left button released 
6010     else if ( event
.LeftUp() ) 
6012         switch ( m_cursorMode 
) 
6014             case WXGRID_CURSOR_RESIZE_COL
: 
6015                 DoEndDragResizeCol(); 
6017                 // Note: we are ending the event *after* doing 
6018                 // default processing in this case 
6020                 SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event 
); 
6023             case WXGRID_CURSOR_MOVE_COL
: 
6026                 SendEvent( wxEVT_GRID_COL_MOVE
, -1, m_dragRowOrCol
, event 
); 
6029             case WXGRID_CURSOR_SELECT_COL
: 
6030             case WXGRID_CURSOR_SELECT_CELL
: 
6031             case WXGRID_CURSOR_RESIZE_ROW
: 
6032             case WXGRID_CURSOR_SELECT_ROW
: 
6033                 // nothing to do (?) 
6037         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
); 
6041     // ------------ Right button down 
6043     else if ( event
.RightDown() ) 
6047              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event 
) ) 
6049             // no default action at the moment 
6053     // ------------ Right double click 
6055     else if ( event
.RightDClick() ) 
6059              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event 
) ) 
6061             // no default action at the moment 
6065     // ------------ No buttons down and mouse moving 
6067     else if ( event
.Moving() ) 
6069         m_dragRowOrCol 
= XToEdgeOfCol( x 
); 
6070         if ( m_dragRowOrCol 
>= 0 ) 
6072             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6074                 // don't capture the cursor yet 
6075                 if ( CanDragColSize() ) 
6076                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, m_colLabelWin
, false); 
6079         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
6081             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_colLabelWin
, false); 
6086 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event 
) 
6088     if ( event
.LeftDown() ) 
6090         // indicate corner label by having both row and 
6093         if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event 
) ) 
6098     else if ( event
.LeftDClick() ) 
6100         SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event 
); 
6102     else if ( event
.RightDown() ) 
6104         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event 
) ) 
6106             // no default action at the moment 
6109     else if ( event
.RightDClick() ) 
6111         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event 
) ) 
6113             // no default action at the moment 
6118 void wxGrid::CancelMouseCapture() 
6120     // cancel operation currently in progress, whatever it is 
6123         m_isDragging 
= false; 
6124         m_startDragPos 
= wxDefaultPosition
; 
6126         m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
6127         m_winCapture
->SetCursor( *wxSTANDARD_CURSOR 
); 
6128         m_winCapture 
= NULL
; 
6130         // remove traces of whatever we drew on screen 
6135 void wxGrid::ChangeCursorMode(CursorMode mode
, 
6140     static const wxChar 
*cursorModes
[] = 
6150     wxLogTrace(_T("grid"), 
6151                _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"), 
6152                win 
== m_colLabelWin 
? _T("colLabelWin") 
6153                                     : win 
? _T("rowLabelWin") 
6155                cursorModes
[m_cursorMode
], cursorModes
[mode
]); 
6158     if ( mode 
== m_cursorMode 
&& 
6159          win 
== m_winCapture 
&& 
6160          captureMouse 
== (m_winCapture 
!= NULL
)) 
6165         // by default use the grid itself 
6171         if (m_winCapture
->HasCapture()) 
6172             m_winCapture
->ReleaseMouse(); 
6173         m_winCapture 
= NULL
; 
6176     m_cursorMode 
= mode
; 
6178     switch ( m_cursorMode 
) 
6180         case WXGRID_CURSOR_RESIZE_ROW
: 
6181             win
->SetCursor( m_rowResizeCursor 
); 
6184         case WXGRID_CURSOR_RESIZE_COL
: 
6185             win
->SetCursor( m_colResizeCursor 
); 
6188         case WXGRID_CURSOR_MOVE_COL
: 
6189             win
->SetCursor( wxCursor(wxCURSOR_HAND
) ); 
6193             win
->SetCursor( *wxSTANDARD_CURSOR 
); 
6197     // we need to capture mouse when resizing 
6198     bool resize 
= m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
|| 
6199                   m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL
; 
6201     if ( captureMouse 
&& resize 
) 
6203         win
->CaptureMouse(); 
6208 // ---------------------------------------------------------------------------- 
6209 // grid mouse event processing 
6210 // ---------------------------------------------------------------------------- 
6213 wxGrid::DoGridCellDrag(wxMouseEvent
& event
, 
6214                        const wxGridCellCoords
& coords
, 
6217     if ( coords 
== wxGridNoCellCoords 
) 
6218         return; // we're outside any valid cell 
6220     // Hide the edit control, so it won't interfere with drag-shrinking. 
6221     if ( IsCellEditControlShown() ) 
6223         HideCellEditControl(); 
6224         SaveEditControlValue(); 
6227     switch ( event
.GetModifiers() ) 
6230             if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
6231                 m_selectedBlockCorner 
= coords
; 
6232             UpdateBlockBeingSelected(m_selectedBlockCorner
, coords
); 
6236             if ( CanDragCell() ) 
6240                     if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
6241                         m_selectedBlockCorner 
= coords
; 
6243                     SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG
, coords
, event
); 
6248             UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
6252             // we don't handle the other key modifiers 
6257 void wxGrid::DoGridLineDrag(wxMouseEvent
& event
, const wxGridOperations
& oper
) 
6259     wxClientDC 
dc(m_gridWin
); 
6261     dc
.SetLogicalFunction(wxINVERT
); 
6263     const wxRect 
rectWin(CalcUnscrolledPosition(wxPoint(0, 0)), 
6264                          m_gridWin
->GetClientSize()); 
6266     // erase the previously drawn line, if any 
6267     if ( m_dragLastPos 
>= 0 ) 
6268         oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
6270     // we need the vertical position for rows and horizontal for columns here 
6271     m_dragLastPos 
= oper
.Dual().Select(CalcUnscrolledPosition(event
.GetPosition())); 
6273     // don't allow resizing beneath the minimal size 
6274     const int posMin 
= oper
.GetLineStartPos(this, m_dragRowOrCol
) + 
6275                         oper
.GetMinimalLineSize(this, m_dragRowOrCol
); 
6276     if ( m_dragLastPos 
< posMin 
) 
6277         m_dragLastPos 
= posMin
; 
6279     // and draw it at the new position 
6280     oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
6283 void wxGrid::DoGridDragEvent(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
6285     if ( !m_isDragging 
) 
6287         // Don't start doing anything until the mouse has been dragged far 
6289         const wxPoint
& pt 
= event
.GetPosition(); 
6290         if ( m_startDragPos 
== wxDefaultPosition 
) 
6292             m_startDragPos 
= pt
; 
6296         if ( abs(m_startDragPos
.x 
- pt
.x
) <= DRAG_SENSITIVITY 
&& 
6297                 abs(m_startDragPos
.y 
- pt
.y
) <= DRAG_SENSITIVITY 
) 
6301     const bool isFirstDrag 
= !m_isDragging
; 
6302     m_isDragging 
= true; 
6304     switch ( m_cursorMode 
) 
6306         case WXGRID_CURSOR_SELECT_CELL
: 
6307             DoGridCellDrag(event
, coords
, isFirstDrag
); 
6310         case WXGRID_CURSOR_RESIZE_ROW
: 
6311             DoGridLineDrag(event
, wxGridRowOperations()); 
6314         case WXGRID_CURSOR_RESIZE_COL
: 
6315             DoGridLineDrag(event
, wxGridColumnOperations()); 
6324         m_winCapture 
= m_gridWin
; 
6325         m_winCapture
->CaptureMouse(); 
6330 wxGrid::DoGridCellLeftDown(wxMouseEvent
& event
, 
6331                            const wxGridCellCoords
& coords
, 
6334     if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK
, coords
, event
) ) 
6336         // event handled by user code, no need to do anything here 
6340     if ( !event
.CmdDown() ) 
6343     if ( event
.ShiftDown() ) 
6347             m_selection
->SelectBlock(m_currentCellCoords
, coords
, event
); 
6348             m_selectedBlockCorner 
= coords
; 
6351     else if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
6353         DisableCellEditControl(); 
6354         MakeCellVisible( coords 
); 
6356         if ( event
.CmdDown() ) 
6360                 m_selection
->ToggleCellSelection(coords
, event
); 
6363             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
6364             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
6365             m_selectedBlockCorner 
= coords
; 
6369             m_waitForSlowClick 
= m_currentCellCoords 
== coords 
&& 
6370                                         coords 
!= wxGridNoCellCoords
; 
6371             SetCurrentCell( coords 
); 
6377 wxGrid::DoGridCellLeftDClick(wxMouseEvent
& event
, 
6378                              const wxGridCellCoords
& coords
, 
6381     if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
6383         if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK
, coords
, event
) ) 
6385             // we want double click to select a cell and start editing 
6386             // (i.e. to behave in same way as sequence of two slow clicks): 
6387             m_waitForSlowClick 
= true; 
6393 wxGrid::DoGridCellLeftUp(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
6395     if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6399             if (m_winCapture
->HasCapture()) 
6400                 m_winCapture
->ReleaseMouse(); 
6401             m_winCapture 
= NULL
; 
6404         if ( coords 
== m_currentCellCoords 
&& m_waitForSlowClick 
&& CanEnableCellControl() ) 
6407             EnableCellEditControl(); 
6409             wxGridCellAttr 
*attr 
= GetCellAttr(coords
); 
6410             wxGridCellEditor 
*editor 
= attr
->GetEditor(this, coords
.GetRow(), coords
.GetCol()); 
6411             editor
->StartingClick(); 
6415             m_waitForSlowClick 
= false; 
6417         else if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
6418              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
6422                 m_selection
->SelectBlock( m_selectedBlockTopLeft
, 
6423                                           m_selectedBlockBottomRight
, 
6427             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
6428             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
6430             // Show the edit control, if it has been hidden for 
6432             ShowCellEditControl(); 
6435     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
6437         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6438         DoEndDragResizeRow(); 
6440         // Note: we are ending the event *after* doing 
6441         // default processing in this case 
6443         SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
6445     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL 
) 
6447         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6448         DoEndDragResizeCol(); 
6450         // Note: we are ending the event *after* doing 
6451         // default processing in this case 
6453         SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, event 
); 
6460 wxGrid::DoGridMouseMoveEvent(wxMouseEvent
& WXUNUSED(event
), 
6461                              const wxGridCellCoords
& coords
, 
6464     if ( coords
.GetRow() < 0 || coords
.GetCol() < 0 ) 
6466         // out of grid cell area 
6467         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6471     int dragRow 
= YToEdgeOfRow( pos
.y 
); 
6472     int dragCol 
= XToEdgeOfCol( pos
.x 
); 
6474     // Dragging on the corner of a cell to resize in both 
6475     // directions is not implemented yet... 
6477     if ( dragRow 
>= 0 && dragCol 
>= 0 ) 
6479         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6485         m_dragRowOrCol 
= dragRow
; 
6487         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6489             if ( CanDragRowSize() && CanDragGridSize() ) 
6490                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, NULL
, false); 
6493     else if ( dragCol 
>= 0 ) 
6495         m_dragRowOrCol 
= dragCol
; 
6497         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6499             if ( CanDragColSize() && CanDragGridSize() ) 
6500                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, NULL
, false); 
6503     else // Neither on a row or col edge 
6505         if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
6507             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6512 void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent
& event
) 
6514     const wxPoint pos 
= CalcUnscrolledPosition(event
.GetPosition()); 
6516     // coordinates of the cell under mouse 
6517     wxGridCellCoords coords 
= XYToCell(pos
); 
6519     int cell_rows
, cell_cols
; 
6520     GetCellSize( coords
.GetRow(), coords
.GetCol(), &cell_rows
, &cell_cols 
); 
6521     if ( (cell_rows 
< 0) || (cell_cols 
< 0) ) 
6523         coords
.SetRow(coords
.GetRow() + cell_rows
); 
6524         coords
.SetCol(coords
.GetCol() + cell_cols
); 
6527     if ( event
.Dragging() ) 
6529         if ( event
.LeftIsDown() ) 
6530             DoGridDragEvent(event
, coords
); 
6536     m_isDragging 
= false; 
6537     m_startDragPos 
= wxDefaultPosition
; 
6539     // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL 
6540     //     immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under 
6543     if ( event
.Entering() || event
.Leaving() ) 
6545         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6546         m_gridWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
6550     // deal with various button presses 
6551     if ( event
.IsButton() ) 
6553         if ( coords 
!= wxGridNoCellCoords 
) 
6555             DisableCellEditControl(); 
6557             if ( event
.LeftDown() ) 
6558                 DoGridCellLeftDown(event
, coords
, pos
); 
6559             else if ( event
.LeftDClick() ) 
6560                 DoGridCellLeftDClick(event
, coords
, pos
); 
6561             else if ( event
.RightDown() ) 
6562                 SendEvent(wxEVT_GRID_CELL_RIGHT_CLICK
, coords
, event
); 
6563             else if ( event
.RightDClick() ) 
6564                 SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK
, coords
, event
); 
6567         // this one should be called even if we're not over any cell 
6568         if ( event
.LeftUp() ) 
6570             DoGridCellLeftUp(event
, coords
); 
6573     else if ( event
.Moving() ) 
6575         DoGridMouseMoveEvent(event
, coords
, pos
); 
6577     else // unknown mouse event? 
6583 void wxGrid::DoEndDragResizeLine(const wxGridOperations
& oper
) 
6585     if ( m_dragLastPos 
== -1 ) 
6588     const wxGridOperations
& doper 
= oper
.Dual(); 
6590     const wxSize size 
= m_gridWin
->GetClientSize(); 
6592     const wxPoint ptOrigin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
6594     // erase the last line we drew 
6595     wxClientDC 
dc(m_gridWin
); 
6597     dc
.SetLogicalFunction(wxINVERT
); 
6599     const int posLineStart 
= oper
.Select(ptOrigin
); 
6600     const int posLineEnd 
= oper
.Select(ptOrigin
) + oper
.Select(size
); 
6602     oper
.DrawParallelLine(dc
, posLineStart
, posLineEnd
, m_dragLastPos
); 
6604     // temporarily hide the edit control before resizing 
6605     HideCellEditControl(); 
6606     SaveEditControlValue(); 
6608     // do resize the line 
6609     const int lineStart 
= oper
.GetLineStartPos(this, m_dragRowOrCol
); 
6610     oper
.SetLineSize(this, m_dragRowOrCol
, 
6611                      wxMax(m_dragLastPos 
- lineStart
, 
6612                            oper
.GetMinimalLineSize(this, m_dragRowOrCol
))); 
6614     // refresh now if we're not frozen 
6615     if ( !GetBatchCount() ) 
6617         // we need to refresh everything beyond the resized line in the header 
6620         // get the position from which to refresh in the other direction 
6621         wxRect 
rect(CellToRect(oper
.MakeCoords(m_dragRowOrCol
, 0))); 
6622         rect
.SetPosition(CalcScrolledPosition(rect
.GetPosition())); 
6624         // we only need the ordinate (for rows) or abscissa (for columns) here, 
6625         // and need to cover the entire window in the other direction 
6626         oper
.Select(rect
) = 0; 
6628         wxRect 
rectHeader(rect
.GetPosition(), 
6631                                     oper
.GetHeaderWindowSize(this), 
6632                                     doper
.Select(size
) - doper
.Select(rect
) 
6635         oper
.GetHeaderWindow(this)->Refresh(true, &rectHeader
); 
6638         // also refresh the grid window: extend the rectangle 
6641             oper
.SelectSize(rect
) = oper
.Select(size
); 
6643             int subtractLines 
= 0; 
6644             const int lineStart 
= oper
.PosToLine(this, posLineStart
); 
6645             if ( lineStart 
>= 0 ) 
6647                 // ensure that if we have a multi-cell block we redraw all of 
6648                 // it by increasing the refresh area to cover it entirely if a 
6649                 // part of it is affected 
6650                 const int lineEnd 
= oper
.PosToLine(this, posLineEnd
, true); 
6651                 for ( int line 
= lineStart
; line 
< lineEnd
; line
++ ) 
6653                     int cellLines 
= oper
.Select( 
6654                         GetCellSize(oper
.MakeCoords(m_dragRowOrCol
, line
))); 
6655                     if ( cellLines 
< subtractLines 
) 
6656                         subtractLines 
= cellLines
; 
6661                 oper
.GetLineStartPos(this, m_dragRowOrCol 
+ subtractLines
); 
6662             startPos 
= doper
.CalcScrolledPosition(this, startPos
); 
6664             doper
.Select(rect
) = startPos
; 
6665             doper
.SelectSize(rect
) = doper
.Select(size
) - startPos
; 
6667             m_gridWin
->Refresh(false, &rect
); 
6671     // show the edit control back again 
6672     ShowCellEditControl(); 
6675 void wxGrid::DoEndDragResizeRow() 
6677     DoEndDragResizeLine(wxGridRowOperations()); 
6680 void wxGrid::DoEndDragResizeCol() 
6682     DoEndDragResizeLine(wxGridColumnOperations()); 
6685 void wxGrid::DoEndDragMoveCol() 
6687     //The user clicked on the column but didn't actually drag 
6688     if ( m_dragLastPos 
< 0 ) 
6690         m_colLabelWin
->Refresh();   //Do this to "unpress" the column 
6695     if ( m_moveToCol 
== -1 ) 
6696         newPos 
= m_numCols 
- 1; 
6699         newPos 
= GetColPos( m_moveToCol 
); 
6700         if ( newPos 
> GetColPos( m_dragRowOrCol 
) ) 
6704     SetColPos( m_dragRowOrCol
, newPos 
); 
6707 void wxGrid::SetColPos( int colID
, int newPos 
) 
6709     if ( m_colAt
.IsEmpty() ) 
6711         m_colAt
.Alloc( m_numCols 
); 
6714         for ( i 
= 0; i 
< m_numCols
; i
++ ) 
6720     int oldPos 
= GetColPos( colID 
); 
6722     //Reshuffle the m_colAt array 
6723     if ( newPos 
> oldPos 
) 
6726         for ( i 
= oldPos
; i 
< newPos
; i
++ ) 
6728             m_colAt
[i
] = m_colAt
[i
+1]; 
6734         for ( i 
= oldPos
; i 
> newPos
; i
-- ) 
6736             m_colAt
[i
] = m_colAt
[i
-1]; 
6740     m_colAt
[newPos
] = colID
; 
6742     //Recalculate the column rights 
6743     if ( !m_colWidths
.IsEmpty() ) 
6747         for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
6749             int colID 
= GetColAt( colPos 
); 
6751             colRight 
+= m_colWidths
[colID
]; 
6752             m_colRights
[colID
] = colRight
; 
6756     m_colLabelWin
->Refresh(); 
6757     m_gridWin
->Refresh(); 
6762 void wxGrid::EnableDragColMove( bool enable 
) 
6764     if ( m_canDragColMove 
== enable 
) 
6767     m_canDragColMove 
= enable
; 
6769     if ( !m_canDragColMove 
) 
6773         //Recalculate the column rights 
6774         if ( !m_colWidths
.IsEmpty() ) 
6778             for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
6780                 colRight 
+= m_colWidths
[colPos
]; 
6781                 m_colRights
[colPos
] = colRight
; 
6785         m_colLabelWin
->Refresh(); 
6786         m_gridWin
->Refresh(); 
6792 // ------ interaction with data model 
6794 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg 
) 
6796     switch ( msg
.GetId() ) 
6798         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
: 
6799             return GetModelValues(); 
6801         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
: 
6802             return SetModelValues(); 
6804         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
6805         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
6806         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
6807         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
6808         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
6809         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
6810             return Redimension( msg 
); 
6817 // The behaviour of this function depends on the grid table class 
6818 // Clear() function. For the default wxGridStringTable class the 
6819 // behaviour is to replace all cell contents with wxEmptyString but 
6820 // not to change the number of rows or cols. 
6822 void wxGrid::ClearGrid() 
6826         if (IsCellEditControlEnabled()) 
6827             DisableCellEditControl(); 
6830         if (!GetBatchCount()) 
6831             m_gridWin
->Refresh(); 
6836 wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify
)(size_t, size_t), 
6837                       int pos
, int num
, bool WXUNUSED(updateLabels
) ) 
6839     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
6844     if ( IsCellEditControlEnabled() ) 
6845         DisableCellEditControl(); 
6847     return (m_table
->*funcModify
)(pos
, num
); 
6849     // the table will have sent the results of the insert row 
6850     // operation to this view object as a grid table message 
6854 wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend
)(size_t), 
6855                       int num
, bool WXUNUSED(updateLabels
)) 
6857     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
6862     return (m_table
->*funcAppend
)(num
); 
6866 // ----- event handlers 
6869 // Generate a grid event based on a mouse event and return: 
6870 //  -1 if the event was vetoed 
6871 //  +1 if the event was processed (but not vetoed) 
6872 //   0 if the event wasn't handled 
6874 wxGrid::SendEvent(const wxEventType type
, 
6876                   wxMouseEvent
& mouseEv
) 
6878    bool claimed
, vetoed
; 
6880    if ( type 
== wxEVT_GRID_ROW_SIZE 
|| type 
== wxEVT_GRID_COL_SIZE 
) 
6882        int rowOrCol 
= (row 
== -1 ? col 
: row
); 
6884        wxGridSizeEvent 
gridEvt( GetId(), 
6888                mouseEv
.GetX() + GetRowLabelSize(), 
6889                mouseEv
.GetY() + GetColLabelSize(), 
6892        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6893        vetoed 
= !gridEvt
.IsAllowed(); 
6895    else if ( type 
== wxEVT_GRID_RANGE_SELECT 
) 
6897        // Right now, it should _never_ end up here! 
6898        wxGridRangeSelectEvent 
gridEvt( GetId(), 
6901                m_selectedBlockTopLeft
, 
6902                m_selectedBlockBottomRight
, 
6906        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6907        vetoed 
= !gridEvt
.IsAllowed(); 
6909    else if ( type 
== wxEVT_GRID_LABEL_LEFT_CLICK 
|| 
6910              type 
== wxEVT_GRID_LABEL_LEFT_DCLICK 
|| 
6911              type 
== wxEVT_GRID_LABEL_RIGHT_CLICK 
|| 
6912              type 
== wxEVT_GRID_LABEL_RIGHT_DCLICK 
) 
6914        wxPoint pos 
= mouseEv
.GetPosition(); 
6916        if ( mouseEv
.GetEventObject() == GetGridRowLabelWindow() ) 
6917            pos
.y 
+= GetColLabelSize(); 
6918        if ( mouseEv
.GetEventObject() == GetGridColLabelWindow() ) 
6919            pos
.x 
+= GetRowLabelSize(); 
6921        wxGridEvent 
gridEvt( GetId(), 
6929        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6930        vetoed 
= !gridEvt
.IsAllowed(); 
6934        wxGridEvent 
gridEvt( GetId(), 
6938                mouseEv
.GetX() + GetRowLabelSize(), 
6939                mouseEv
.GetY() + GetColLabelSize(), 
6942        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6943        vetoed 
= !gridEvt
.IsAllowed(); 
6946    // A Veto'd event may not be `claimed' so test this first 
6950    return claimed 
? 1 : 0; 
6953 // Generate a grid event of specified type, return value same as above 
6955 int wxGrid::SendEvent(const wxEventType type
, int row
, int col
) 
6957    bool claimed
, vetoed
; 
6959     if ( type 
== wxEVT_GRID_ROW_SIZE 
|| type 
== wxEVT_GRID_COL_SIZE 
) 
6961         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
6963         wxGridSizeEvent 
gridEvt( GetId(), type
, this, rowOrCol 
); 
6965         claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6966         vetoed  
= !gridEvt
.IsAllowed(); 
6970         wxGridEvent 
gridEvt( GetId(), type
, this, row
, col 
); 
6972         claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6973         vetoed  
= !gridEvt
.IsAllowed(); 
6976     // A Veto'd event may not be `claimed' so test this first 
6980     return claimed 
? 1 : 0; 
6983 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
6985     // needed to prevent zillions of paint events on MSW 
6989 void wxGrid::Refresh(bool eraseb
, const wxRect
* rect
) 
6991     // Don't do anything if between Begin/EndBatch... 
6992     // EndBatch() will do all this on the last nested one anyway. 
6993     if ( m_created 
&& !GetBatchCount() ) 
6995         // Refresh to get correct scrolled position: 
6996         wxScrolledWindow::Refresh(eraseb
, rect
); 
7000             int rect_x
, rect_y
, rectWidth
, rectHeight
; 
7001             int width_label
, width_cell
, height_label
, height_cell
; 
7004             // Copy rectangle can get scroll offsets.. 
7005             rect_x 
= rect
->GetX(); 
7006             rect_y 
= rect
->GetY(); 
7007             rectWidth 
= rect
->GetWidth(); 
7008             rectHeight 
= rect
->GetHeight(); 
7010             width_label 
= m_rowLabelWidth 
- rect_x
; 
7011             if (width_label 
> rectWidth
) 
7012                 width_label 
= rectWidth
; 
7014             height_label 
= m_colLabelHeight 
- rect_y
; 
7015             if (height_label 
> rectHeight
) 
7016                 height_label 
= rectHeight
; 
7018             if (rect_x 
> m_rowLabelWidth
) 
7020                 x 
= rect_x 
- m_rowLabelWidth
; 
7021                 width_cell 
= rectWidth
; 
7026                 width_cell 
= rectWidth 
- (m_rowLabelWidth 
- rect_x
); 
7029             if (rect_y 
> m_colLabelHeight
) 
7031                 y 
= rect_y 
- m_colLabelHeight
; 
7032                 height_cell 
= rectHeight
; 
7037                 height_cell 
= rectHeight 
- (m_colLabelHeight 
- rect_y
); 
7040             // Paint corner label part intersecting rect. 
7041             if ( width_label 
> 0 && height_label 
> 0 ) 
7043                 wxRect 
anotherrect(rect_x
, rect_y
, width_label
, height_label
); 
7044                 m_cornerLabelWin
->Refresh(eraseb
, &anotherrect
); 
7047             // Paint col labels part intersecting rect. 
7048             if ( width_cell 
> 0 && height_label 
> 0 ) 
7050                 wxRect 
anotherrect(x
, rect_y
, width_cell
, height_label
); 
7051                 m_colLabelWin
->Refresh(eraseb
, &anotherrect
); 
7054             // Paint row labels part intersecting rect. 
7055             if ( width_label 
> 0 && height_cell 
> 0 ) 
7057                 wxRect 
anotherrect(rect_x
, y
, width_label
, height_cell
); 
7058                 m_rowLabelWin
->Refresh(eraseb
, &anotherrect
); 
7061             // Paint cell area part intersecting rect. 
7062             if ( width_cell 
> 0 && height_cell 
> 0 ) 
7064                 wxRect 
anotherrect(x
, y
, width_cell
, height_cell
); 
7065                 m_gridWin
->Refresh(eraseb
, &anotherrect
); 
7070             m_cornerLabelWin
->Refresh(eraseb
, NULL
); 
7071             m_colLabelWin
->Refresh(eraseb
, NULL
); 
7072             m_rowLabelWin
->Refresh(eraseb
, NULL
); 
7073             m_gridWin
->Refresh(eraseb
, NULL
); 
7078 void wxGrid::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
7080     if (m_targetWindow 
!= this) // check whether initialisation has been done 
7082         // reposition our children windows 
7087 void wxGrid::OnKeyDown( wxKeyEvent
& event 
) 
7089     if ( m_inOnKeyDown 
) 
7091         // shouldn't be here - we are going round in circles... 
7093         wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); 
7096     m_inOnKeyDown 
= true; 
7098     // propagate the event up and see if it gets processed 
7099     wxWindow 
*parent 
= GetParent(); 
7100     wxKeyEvent 
keyEvt( event 
); 
7101     keyEvt
.SetEventObject( parent 
); 
7103     if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt 
) ) 
7105         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
7107             if (event
.GetKeyCode() == WXK_RIGHT
) 
7108                 event
.m_keyCode 
= WXK_LEFT
; 
7109             else if (event
.GetKeyCode() == WXK_LEFT
) 
7110                 event
.m_keyCode 
= WXK_RIGHT
; 
7113         // try local handlers 
7114         switch ( event
.GetKeyCode() ) 
7117                 if ( event
.ControlDown() ) 
7118                     MoveCursorUpBlock( event
.ShiftDown() ); 
7120                     MoveCursorUp( event
.ShiftDown() ); 
7124                 if ( event
.ControlDown() ) 
7125                     MoveCursorDownBlock( event
.ShiftDown() ); 
7127                     MoveCursorDown( event
.ShiftDown() ); 
7131                 if ( event
.ControlDown() ) 
7132                     MoveCursorLeftBlock( event
.ShiftDown() ); 
7134                     MoveCursorLeft( event
.ShiftDown() ); 
7138                 if ( event
.ControlDown() ) 
7139                     MoveCursorRightBlock( event
.ShiftDown() ); 
7141                     MoveCursorRight( event
.ShiftDown() ); 
7145             case WXK_NUMPAD_ENTER
: 
7146                 if ( event
.ControlDown() ) 
7148                     event
.Skip();  // to let the edit control have the return 
7152                     if ( GetGridCursorRow() < GetNumberRows()-1 ) 
7154                         MoveCursorDown( event
.ShiftDown() ); 
7158                         // at the bottom of a column 
7159                         DisableCellEditControl(); 
7169                 if (event
.ShiftDown()) 
7171                     if ( GetGridCursorCol() > 0 ) 
7173                         MoveCursorLeft( false ); 
7178                         DisableCellEditControl(); 
7183                     if ( GetGridCursorCol() < GetNumberCols() - 1 ) 
7185                         MoveCursorRight( false ); 
7190                         DisableCellEditControl(); 
7196                 if ( event
.ControlDown() ) 
7207                 if ( event
.ControlDown() ) 
7209                     GoToCell(m_numRows 
- 1, m_numCols 
- 1); 
7226                 // Ctrl-Space selects the current column, Shift-Space -- the 
7227                 // current row and Ctrl-Shift-Space -- everything 
7228                 switch ( m_selection 
? event
.GetModifiers() : wxMOD_NONE 
) 
7231                         m_selection
->SelectCol(m_currentCellCoords
.GetCol()); 
7235                         m_selection
->SelectRow(m_currentCellCoords
.GetRow()); 
7238                     case wxMOD_CONTROL 
| wxMOD_SHIFT
: 
7239                         m_selection
->SelectBlock(0, 0, 
7240                                                  m_numRows 
- 1, m_numCols 
- 1); 
7244                         if ( !IsEditable() ) 
7246                             MoveCursorRight(false); 
7249                         //else: fall through 
7262     m_inOnKeyDown 
= false; 
7265 void wxGrid::OnKeyUp( wxKeyEvent
& event 
) 
7267     // try local handlers 
7269     if ( event
.GetKeyCode() == WXK_SHIFT 
) 
7271         if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
7272              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
7276                 m_selection
->SelectBlock( 
7277                     m_selectedBlockTopLeft
, 
7278                     m_selectedBlockBottomRight
, 
7283         m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
7284         m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
7285         m_selectedBlockCorner 
= wxGridNoCellCoords
; 
7289 void wxGrid::OnChar( wxKeyEvent
& event 
) 
7291     // is it possible to edit the current cell at all? 
7292     if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) 
7294         // yes, now check whether the cells editor accepts the key 
7295         int row 
= m_currentCellCoords
.GetRow(); 
7296         int col 
= m_currentCellCoords
.GetCol(); 
7297         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7298         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
7300         // <F2> is special and will always start editing, for 
7301         // other keys - ask the editor itself 
7302         if ( (event
.GetKeyCode() == WXK_F2 
&& !event
.HasModifiers()) 
7303              || editor
->IsAcceptedKey(event
) ) 
7305             // ensure cell is visble 
7306             MakeCellVisible(row
, col
); 
7307             EnableCellEditControl(); 
7309             // a problem can arise if the cell is not completely 
7310             // visible (even after calling MakeCellVisible the 
7311             // control is not created and calling StartingKey will 
7313             if ( event
.GetKeyCode() != WXK_F2 
&& editor
->IsCreated() && m_cellEditCtrlEnabled 
) 
7314                 editor
->StartingKey(event
); 
7330 void wxGrid::OnEraseBackground(wxEraseEvent
&) 
7334 bool wxGrid::SetCurrentCell( const wxGridCellCoords
& coords 
) 
7336     if ( SendEvent(wxEVT_GRID_SELECT_CELL
, coords
) == -1 ) 
7338         // the event has been vetoed - do nothing 
7342 #if !defined(__WXMAC__) 
7343     wxClientDC 
dc( m_gridWin 
); 
7347     if ( m_currentCellCoords 
!= wxGridNoCellCoords 
) 
7349         DisableCellEditControl(); 
7351         if ( IsVisible( m_currentCellCoords
, false ) ) 
7354             r 
= BlockToDeviceRect( m_currentCellCoords
, m_currentCellCoords 
); 
7355             if ( !m_gridLinesEnabled 
) 
7363             wxGridCellCoordsArray cells 
= CalcCellsExposed( r 
); 
7365             // Otherwise refresh redraws the highlight! 
7366             m_currentCellCoords 
= coords
; 
7368 #if defined(__WXMAC__) 
7369             m_gridWin
->Refresh(true /*, & r */); 
7371             DrawGridCellArea( dc
, cells 
); 
7372             DrawAllGridLines( dc
, r 
); 
7377     m_currentCellCoords 
= coords
; 
7379     wxGridCellAttr 
*attr 
= GetCellAttr( coords 
); 
7380 #if !defined(__WXMAC__) 
7381     DrawCellHighlight( dc
, attr 
); 
7389 wxGrid::UpdateBlockBeingSelected(int topRow
, int leftCol
, 
7390                                  int bottomRow
, int rightCol
) 
7394         switch ( m_selection
->GetSelectionMode() ) 
7397                 wxFAIL_MSG( "unknown selection mode" ); 
7400             case wxGridSelectCells
: 
7401                 // arbitrary blocks selection allowed so just use the cell 
7402                 // coordinates as is 
7405             case wxGridSelectRows
: 
7406                 // only full rows selection allowd, ensure that we do select 
7409                 rightCol 
= GetNumberCols() - 1; 
7412             case wxGridSelectColumns
: 
7413                 // same as above but for columns 
7415                 bottomRow 
= GetNumberRows() - 1; 
7418             case wxGridSelectRowsOrColumns
: 
7419                 // in this mode we can select only full rows or full columns so 
7420                 // it doesn't make sense to select blocks at all (and we can't 
7421                 // extend the block because there is no preferred direction, we 
7422                 // could only extend it to cover the entire grid but this is 
7428     m_selectedBlockCorner 
= wxGridCellCoords(bottomRow
, rightCol
); 
7429     MakeCellVisible(m_selectedBlockCorner
); 
7431     EnsureFirstLessThanSecond(topRow
, bottomRow
); 
7432     EnsureFirstLessThanSecond(leftCol
, rightCol
); 
7434     wxGridCellCoords updateTopLeft 
= wxGridCellCoords(topRow
, leftCol
), 
7435                      updateBottomRight 
= wxGridCellCoords(bottomRow
, rightCol
); 
7437     // First the case that we selected a completely new area 
7438     if ( m_selectedBlockTopLeft 
== wxGridNoCellCoords 
|| 
7439          m_selectedBlockBottomRight 
== wxGridNoCellCoords 
) 
7442         rect 
= BlockToDeviceRect( wxGridCellCoords ( topRow
, leftCol 
), 
7443                                   wxGridCellCoords ( bottomRow
, rightCol 
) ); 
7444         m_gridWin
->Refresh( false, &rect 
); 
7447     // Now handle changing an existing selection area. 
7448     else if ( m_selectedBlockTopLeft 
!= updateTopLeft 
|| 
7449               m_selectedBlockBottomRight 
!= updateBottomRight 
) 
7451         // Compute two optimal update rectangles: 
7452         // Either one rectangle is a real subset of the 
7453         // other, or they are (almost) disjoint! 
7455         bool    need_refresh
[4]; 
7459         need_refresh
[3] = false; 
7462         // Store intermediate values 
7463         wxCoord oldLeft 
= m_selectedBlockTopLeft
.GetCol(); 
7464         wxCoord oldTop 
= m_selectedBlockTopLeft
.GetRow(); 
7465         wxCoord oldRight 
= m_selectedBlockBottomRight
.GetCol(); 
7466         wxCoord oldBottom 
= m_selectedBlockBottomRight
.GetRow(); 
7468         // Determine the outer/inner coordinates. 
7469         EnsureFirstLessThanSecond(oldLeft
, leftCol
); 
7470         EnsureFirstLessThanSecond(oldTop
, topRow
); 
7471         EnsureFirstLessThanSecond(rightCol
, oldRight
); 
7472         EnsureFirstLessThanSecond(bottomRow
, oldBottom
); 
7474         // Now, either the stuff marked old is the outer 
7475         // rectangle or we don't have a situation where one 
7476         // is contained in the other. 
7478         if ( oldLeft 
< leftCol 
) 
7480             // Refresh the newly selected or deselected 
7481             // area to the left of the old or new selection. 
7482             need_refresh
[0] = true; 
7483             rect
[0] = BlockToDeviceRect( 
7484                 wxGridCellCoords( oldTop
,  oldLeft 
), 
7485                 wxGridCellCoords( oldBottom
, leftCol 
- 1 ) ); 
7488         if ( oldTop 
< topRow 
) 
7490             // Refresh the newly selected or deselected 
7491             // area above the old or new selection. 
7492             need_refresh
[1] = true; 
7493             rect
[1] = BlockToDeviceRect( 
7494                 wxGridCellCoords( oldTop
, leftCol 
), 
7495                 wxGridCellCoords( topRow 
- 1, rightCol 
) ); 
7498         if ( oldRight 
> rightCol 
) 
7500             // Refresh the newly selected or deselected 
7501             // area to the right of the old or new selection. 
7502             need_refresh
[2] = true; 
7503             rect
[2] = BlockToDeviceRect( 
7504                 wxGridCellCoords( oldTop
, rightCol 
+ 1 ), 
7505                 wxGridCellCoords( oldBottom
, oldRight 
) ); 
7508         if ( oldBottom 
> bottomRow 
) 
7510             // Refresh the newly selected or deselected 
7511             // area below the old or new selection. 
7512             need_refresh
[3] = true; 
7513             rect
[3] = BlockToDeviceRect( 
7514                 wxGridCellCoords( bottomRow 
+ 1, leftCol 
), 
7515                 wxGridCellCoords( oldBottom
, rightCol 
) ); 
7518         // various Refresh() calls 
7519         for (i 
= 0; i 
< 4; i
++ ) 
7520             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
7521                 m_gridWin
->Refresh( false, &(rect
[i
]) ); 
7525     m_selectedBlockTopLeft 
= updateTopLeft
; 
7526     m_selectedBlockBottomRight 
= updateBottomRight
; 
7530 // ------ functions to get/send data (see also public functions) 
7533 bool wxGrid::GetModelValues() 
7535     // Hide the editor, so it won't hide a changed value. 
7536     HideCellEditControl(); 
7540         // all we need to do is repaint the grid 
7542         m_gridWin
->Refresh(); 
7549 bool wxGrid::SetModelValues() 
7553     // Disable the editor, so it won't hide a changed value. 
7554     // Do we also want to save the current value of the editor first? 
7556     DisableCellEditControl(); 
7560         for ( row 
= 0; row 
< m_numRows
; row
++ ) 
7562             for ( col 
= 0; col 
< m_numCols
; col
++ ) 
7564                 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) ); 
7574 // Note - this function only draws cells that are in the list of 
7575 // exposed cells (usually set from the update region by 
7576 // CalcExposedCells) 
7578 void wxGrid::DrawGridCellArea( wxDC
& dc
, const wxGridCellCoordsArray
& cells 
) 
7580     if ( !m_numRows 
|| !m_numCols 
) 
7583     int i
, numCells 
= cells
.GetCount(); 
7584     int row
, col
, cell_rows
, cell_cols
; 
7585     wxGridCellCoordsArray redrawCells
; 
7587     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
7589         row 
= cells
[i
].GetRow(); 
7590         col 
= cells
[i
].GetCol(); 
7591         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
7593         // If this cell is part of a multicell block, find owner for repaint 
7594         if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
7596             wxGridCellCoords 
cell( row 
+ cell_rows
, col 
+ cell_cols 
); 
7597             bool marked 
= false; 
7598             for ( int j 
= 0; j 
< numCells
; j
++ ) 
7600                 if ( cell 
== cells
[j
] ) 
7609                 int count 
= redrawCells
.GetCount(); 
7610                 for (int j 
= 0; j 
< count
; j
++) 
7612                     if ( cell 
== redrawCells
[j
] ) 
7620                     redrawCells
.Add( cell 
); 
7623             // don't bother drawing this cell 
7627         // If this cell is empty, find cell to left that might want to overflow 
7628         if (m_table 
&& m_table
->IsEmptyCell(row
, col
)) 
7630             for ( int l 
= 0; l 
< cell_rows
; l
++ ) 
7632                 // find a cell in this row to leave already marked for repaint 
7634                 for (int k 
= 0; k 
< int(redrawCells
.GetCount()); k
++) 
7635                     if ((redrawCells
[k
].GetCol() < left
) && 
7636                         (redrawCells
[k
].GetRow() == row
)) 
7638                         left 
= redrawCells
[k
].GetCol(); 
7642                     left 
= 0; // oh well 
7644                 for (int j 
= col 
- 1; j 
>= left
; j
--) 
7646                     if (!m_table
->IsEmptyCell(row 
+ l
, j
)) 
7648                         if (GetCellOverflow(row 
+ l
, j
)) 
7650                             wxGridCellCoords 
cell(row 
+ l
, j
); 
7651                             bool marked 
= false; 
7653                             for (int k 
= 0; k 
< numCells
; k
++) 
7655                                 if ( cell 
== cells
[k
] ) 
7664                                 int count 
= redrawCells
.GetCount(); 
7665                                 for (int k 
= 0; k 
< count
; k
++) 
7667                                     if ( cell 
== redrawCells
[k
] ) 
7674                                     redrawCells
.Add( cell 
); 
7683         DrawCell( dc
, cells
[i
] ); 
7686     numCells 
= redrawCells
.GetCount(); 
7688     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
7690         DrawCell( dc
, redrawCells
[i
] ); 
7694 void wxGrid::DrawGridSpace( wxDC
& dc 
) 
7697   m_gridWin
->GetClientSize( &cw
, &ch 
); 
7700   CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
7702   int rightCol 
= m_numCols 
> 0 ? GetColRight(GetColAt( m_numCols 
- 1 )) : 0; 
7703   int bottomRow 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
7705   if ( right 
> rightCol 
|| bottom 
> bottomRow 
) 
7708       CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
7710       dc
.SetBrush(GetDefaultCellBackgroundColour()); 
7711       dc
.SetPen( *wxTRANSPARENT_PEN 
); 
7713       if ( right 
> rightCol 
) 
7715           dc
.DrawRectangle( rightCol
, top
, right 
- rightCol
, ch 
); 
7718       if ( bottom 
> bottomRow 
) 
7720           dc
.DrawRectangle( left
, bottomRow
, cw
, bottom 
- bottomRow 
); 
7725 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
7727     int row 
= coords
.GetRow(); 
7728     int col 
= coords
.GetCol(); 
7730     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7733     // we draw the cell border ourselves 
7734     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
7736     bool isCurrent 
= coords 
== m_currentCellCoords
; 
7738     wxRect rect 
= CellToRect( row
, col 
); 
7740     // if the editor is shown, we should use it and not the renderer 
7741     // Note: However, only if it is really _shown_, i.e. not hidden! 
7742     if ( isCurrent 
&& IsCellEditControlShown() ) 
7744         // NB: this "#if..." is temporary and fixes a problem where the 
7745         // edit control is erased by this code after being rendered. 
7746         // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered 
7747         // implicitly, causing this out-of order render. 
7748 #if !defined(__WXMAC__) 
7749         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
7750         editor
->PaintBackground(rect
, attr
); 
7756         // but all the rest is drawn by the cell renderer and hence may be customized 
7757         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
7758         renderer
->Draw(*this, *attr
, dc
, rect
, row
, col
, IsInSelection(coords
)); 
7765 void wxGrid::DrawCellHighlight( wxDC
& dc
, const wxGridCellAttr 
*attr 
) 
7767     // don't show highlight when the grid doesn't have focus 
7771     int row 
= m_currentCellCoords
.GetRow(); 
7772     int col 
= m_currentCellCoords
.GetCol(); 
7774     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7777     wxRect rect 
= CellToRect(row
, col
); 
7779     // hmmm... what could we do here to show that the cell is disabled? 
7780     // for now, I just draw a thinner border than for the other ones, but 
7781     // it doesn't look really good 
7783     int penWidth 
= attr
->IsReadOnly() ? m_cellHighlightROPenWidth 
: m_cellHighlightPenWidth
; 
7787         // The center of the drawn line is where the position/width/height of 
7788         // the rectangle is actually at (on wxMSW at least), so the 
7789         // size of the rectangle is reduced to compensate for the thickness of 
7790         // the line. If this is too strange on non-wxMSW platforms then 
7791         // please #ifdef this appropriately. 
7792         rect
.x 
+= penWidth 
/ 2; 
7793         rect
.y 
+= penWidth 
/ 2; 
7794         rect
.width 
-= penWidth 
- 1; 
7795         rect
.height 
-= penWidth 
- 1; 
7797         // Now draw the rectangle 
7798         // use the cellHighlightColour if the cell is inside a selection, this 
7799         // will ensure the cell is always visible. 
7800         dc
.SetPen(wxPen(IsInSelection(row
,col
) ? m_selectionForeground
 
7801                                                : m_cellHighlightColour
, 
7803         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
7804         dc
.DrawRectangle(rect
); 
7808 wxPen 
wxGrid::GetDefaultGridLinePen() 
7810     return wxPen(GetGridLineColour()); 
7813 wxPen 
wxGrid::GetRowGridLinePen(int WXUNUSED(row
)) 
7815     return GetDefaultGridLinePen(); 
7818 wxPen 
wxGrid::GetColGridLinePen(int WXUNUSED(col
)) 
7820     return GetDefaultGridLinePen(); 
7823 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
7825     int row 
= coords
.GetRow(); 
7826     int col 
= coords
.GetCol(); 
7827     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7831     wxRect rect 
= CellToRect( row
, col 
); 
7833     // right hand border 
7834     dc
.SetPen( GetColGridLinePen(col
) ); 
7835     dc
.DrawLine( rect
.x 
+ rect
.width
, rect
.y
, 
7836                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height 
+ 1 ); 
7839     dc
.SetPen( GetRowGridLinePen(row
) ); 
7840     dc
.DrawLine( rect
.x
, rect
.y 
+ rect
.height
, 
7841                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height
); 
7844 void wxGrid::DrawHighlight(wxDC
& dc
, const wxGridCellCoordsArray
& cells
) 
7846     // This if block was previously in wxGrid::OnPaint but that doesn't 
7847     // seem to get called under wxGTK - MB 
7849     if ( m_currentCellCoords 
== wxGridNoCellCoords 
&& 
7850          m_numRows 
&& m_numCols 
) 
7852         m_currentCellCoords
.Set(0, 0); 
7855     if ( IsCellEditControlShown() ) 
7857         // don't show highlight when the edit control is shown 
7861     // if the active cell was repainted, repaint its highlight too because it 
7862     // might have been damaged by the grid lines 
7863     size_t count 
= cells
.GetCount(); 
7864     for ( size_t n 
= 0; n 
< count
; n
++ ) 
7866         wxGridCellCoords cell 
= cells
[n
]; 
7868         // If we are using attributes, then we may have just exposed another 
7869         // cell in a partially-visible merged cluster of cells. If the "anchor" 
7870         // (upper left) cell of this merged cluster is the cell indicated by 
7871         // m_currentCellCoords, then we need to refresh the cell highlight even 
7872         // though the "anchor" itself is not part of our update segment. 
7873         if ( CanHaveAttributes() ) 
7877             GetCellSize(cell
.GetRow(), cell
.GetCol(), &rows
, &cols
); 
7880                 cell
.SetRow(cell
.GetRow() + rows
); 
7883                 cell
.SetCol(cell
.GetCol() + cols
); 
7886         if ( cell 
== m_currentCellCoords 
) 
7888             wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
7889             DrawCellHighlight(dc
, attr
); 
7897 // This is used to redraw all grid lines e.g. when the grid line colour 
7900 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion 
& WXUNUSED(reg
) ) 
7902     if ( !m_gridLinesEnabled 
) 
7905     int top
, bottom
, left
, right
; 
7908     m_gridWin
->GetClientSize(&cw
, &ch
); 
7909     CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
7910     CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
7912     // avoid drawing grid lines past the last row and col 
7913     if ( m_gridLinesClipHorz 
) 
7918         const int lastColRight 
= GetColRight(GetColAt(m_numCols 
- 1)); 
7919         if ( right 
> lastColRight 
) 
7920             right 
= lastColRight
; 
7923     if ( m_gridLinesClipVert 
) 
7928         const int lastRowBottom 
= GetRowBottom(m_numRows 
- 1); 
7929         if ( bottom 
> lastRowBottom 
) 
7930             bottom 
= lastRowBottom
; 
7933     // no gridlines inside multicells, clip them out 
7934     int leftCol 
= GetColPos( internalXToCol(left
) ); 
7935     int topRow 
= internalYToRow(top
); 
7936     int rightCol 
= GetColPos( internalXToCol(right
) ); 
7937     int bottomRow 
= internalYToRow(bottom
); 
7939     wxRegion 
clippedcells(0, 0, cw
, ch
); 
7941     int cell_rows
, cell_cols
; 
7944     for ( int j 
= topRow
; j 
<= bottomRow
; j
++ ) 
7946         for ( int colPos 
= leftCol
; colPos 
<= rightCol
; colPos
++ ) 
7948             int i 
= GetColAt( colPos 
); 
7950             GetCellSize( j
, i
, &cell_rows
, &cell_cols 
); 
7951             if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
7953                 rect 
= CellToRect(j
,i
); 
7954                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
7955                 clippedcells
.Subtract(rect
); 
7957             else if ((cell_rows 
< 0) || (cell_cols 
< 0)) 
7959                 rect 
= CellToRect(j 
+ cell_rows
, i 
+ cell_cols
); 
7960                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
7961                 clippedcells
.Subtract(rect
); 
7966     dc
.SetDeviceClippingRegion( clippedcells 
); 
7969     // horizontal grid lines 
7970     for ( int i 
= internalYToRow(top
); i 
< m_numRows
; i
++ ) 
7972         int bot 
= GetRowBottom(i
) - 1; 
7979             dc
.SetPen( GetRowGridLinePen(i
) ); 
7980             dc
.DrawLine( left
, bot
, right
, bot 
); 
7984     // vertical grid lines 
7985     for ( int colPos 
= leftCol
; colPos 
< m_numCols
; colPos
++ ) 
7987         int i 
= GetColAt( colPos 
); 
7989         int colRight 
= GetColRight(i
); 
7991         if (GetLayoutDirection() != wxLayout_RightToLeft
) 
7995         if ( colRight 
> right 
) 
7998         if ( colRight 
>= left 
) 
8000             dc
.SetPen( GetColGridLinePen(i
) ); 
8001             dc
.DrawLine( colRight
, top
, colRight
, bottom 
); 
8005     dc
.DestroyClippingRegion(); 
8008 void wxGrid::DrawRowLabels( wxDC
& dc
, const wxArrayInt
& rows
) 
8013     const size_t numLabels 
= rows
.GetCount(); 
8014     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
8016         DrawRowLabel( dc
, rows
[i
] ); 
8020 void wxGrid::DrawRowLabel( wxDC
& dc
, int row 
) 
8022     if ( GetRowHeight(row
) <= 0 || m_rowLabelWidth 
<= 0 ) 
8027     int rowTop 
= GetRowTop(row
), 
8028         rowBottom 
= GetRowBottom(row
) - 1; 
8030     dc
.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8031     dc
.DrawLine( m_rowLabelWidth 
- 1, rowTop
, m_rowLabelWidth 
- 1, rowBottom 
); 
8032     dc
.DrawLine( 0, rowTop
, 0, rowBottom 
); 
8033     dc
.DrawLine( 0, rowBottom
, m_rowLabelWidth
, rowBottom 
); 
8035     dc
.SetPen( *wxWHITE_PEN 
); 
8036     dc
.DrawLine( 1, rowTop
, 1, rowBottom 
); 
8037     dc
.DrawLine( 1, rowTop
, m_rowLabelWidth 
- 1, rowTop 
); 
8039     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
8040     dc
.SetTextForeground( GetLabelTextColour() ); 
8041     dc
.SetFont( GetLabelFont() ); 
8044     GetRowLabelAlignment( &hAlign
, &vAlign 
); 
8047     rect
.SetY( GetRowTop(row
) + 2 ); 
8048     rect
.SetWidth( m_rowLabelWidth 
- 4 ); 
8049     rect
.SetHeight( GetRowHeight(row
) - 4 ); 
8050     DrawTextRectangle( dc
, GetRowLabelValue( row 
), rect
, hAlign
, vAlign 
); 
8053 void wxGrid::SetUseNativeColLabels( bool native 
) 
8055     m_nativeColumnLabels 
= native
; 
8058         int height 
= wxRendererNative::Get().GetHeaderButtonHeight( this ); 
8059         SetColLabelSize( height 
); 
8062     m_colLabelWin
->Refresh(); 
8063     m_cornerLabelWin
->Refresh(); 
8066 void wxGrid::DrawColLabels( wxDC
& dc
,const wxArrayInt
& cols 
) 
8071     const size_t numLabels 
= cols
.GetCount(); 
8072     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
8074         DrawColLabel( dc
, cols
[i
] ); 
8078 void wxGrid::DrawCornerLabel(wxDC
& dc
) 
8080     if ( m_nativeColumnLabels 
) 
8082         wxRect 
rect(wxSize(m_rowLabelWidth
, m_colLabelHeight
)); 
8085         wxRendererNative::Get().DrawHeaderButton(m_cornerLabelWin
, dc
, rect
, 0); 
8089         dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8090         dc
.DrawLine( m_rowLabelWidth 
- 1, m_colLabelHeight 
- 1, 
8091                      m_rowLabelWidth 
- 1, 0 ); 
8092         dc
.DrawLine( m_rowLabelWidth 
- 1, m_colLabelHeight 
- 1, 
8093                      0, m_colLabelHeight 
- 1 ); 
8094         dc
.DrawLine( 0, 0, m_rowLabelWidth
, 0 ); 
8095         dc
.DrawLine( 0, 0, 0, m_colLabelHeight 
); 
8097         dc
.SetPen( *wxWHITE_PEN 
); 
8098         dc
.DrawLine( 1, 1, m_rowLabelWidth 
- 1, 1 ); 
8099         dc
.DrawLine( 1, 1, 1, m_colLabelHeight 
- 1 ); 
8103 void wxGrid::DrawColLabel(wxDC
& dc
, int col
) 
8105     if ( GetColWidth(col
) <= 0 || m_colLabelHeight 
<= 0 ) 
8108     int colLeft 
= GetColLeft(col
); 
8110     wxRect 
rect(colLeft
, 0, GetColWidth(col
), m_colLabelHeight
); 
8112     if ( m_nativeColumnLabels 
) 
8114         wxRendererNative::Get().DrawHeaderButton(m_colLabelWin
, dc
, rect
, 0); 
8118         int colRight 
= GetColRight(col
) - 1; 
8120         dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8121         dc
.DrawLine( colRight
, 0, 
8122                      colRight
, m_colLabelHeight 
- 1 ); 
8123         dc
.DrawLine( colLeft
, 0, 
8125         dc
.DrawLine( colLeft
, m_colLabelHeight 
- 1, 
8126                      colRight 
+ 1, m_colLabelHeight 
- 1 ); 
8128         dc
.SetPen( *wxWHITE_PEN 
); 
8129         dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight 
- 1 ); 
8130         dc
.DrawLine( colLeft
, 1, colRight
, 1 ); 
8133     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
8134     dc
.SetTextForeground( GetLabelTextColour() ); 
8135     dc
.SetFont( GetLabelFont() ); 
8138     GetColLabelAlignment( &hAlign
, &vAlign 
); 
8139     const int orient 
= GetColLabelTextOrientation(); 
8142     DrawTextRectangle(dc
, GetColLabelValue(col
), rect
, hAlign
, vAlign
, orient
); 
8145 // TODO: these 2 functions should be replaced with wxDC::DrawLabel() to which 
8146 //       we just have to add textOrientation support 
8147 void wxGrid::DrawTextRectangle( wxDC
& dc
, 
8148                                 const wxString
& value
, 
8152                                 int textOrientation 
) 
8154     wxArrayString lines
; 
8156     StringToLines( value
, lines 
); 
8158     DrawTextRectangle(dc
, lines
, rect
, horizAlign
, vertAlign
, textOrientation
); 
8161 void wxGrid::DrawTextRectangle(wxDC
& dc
, 
8162                                const wxArrayString
& lines
, 
8166                                int textOrientation
) 
8168     if ( lines
.empty() ) 
8171     wxDCClipper 
clip(dc
, rect
); 
8176     if ( textOrientation 
== wxHORIZONTAL 
) 
8177         GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight 
); 
8179         GetTextBoxSize( dc
, lines
, &textHeight
, &textWidth 
); 
8183     switch ( vertAlign 
) 
8185         case wxALIGN_BOTTOM
: 
8186             if ( textOrientation 
== wxHORIZONTAL 
) 
8187                 y 
= rect
.y 
+ (rect
.height 
- textHeight 
- 1); 
8189                 x 
= rect
.x 
+ rect
.width 
- textWidth
; 
8192         case wxALIGN_CENTRE
: 
8193             if ( textOrientation 
== wxHORIZONTAL 
) 
8194                 y 
= rect
.y 
+ ((rect
.height 
- textHeight
) / 2); 
8196                 x 
= rect
.x 
+ ((rect
.width 
- textWidth
) / 2); 
8201             if ( textOrientation 
== wxHORIZONTAL 
) 
8208     // Align each line of a multi-line label 
8209     size_t nLines 
= lines
.GetCount(); 
8210     for ( size_t l 
= 0; l 
< nLines
; l
++ ) 
8212         const wxString
& line 
= lines
[l
]; 
8216             *(textOrientation 
== wxHORIZONTAL 
? &y 
: &x
) += dc
.GetCharHeight(); 
8220         wxCoord lineWidth 
= 0, 
8222         dc
.GetTextExtent(line
, &lineWidth
, &lineHeight
); 
8224         switch ( horizAlign 
) 
8227                 if ( textOrientation 
== wxHORIZONTAL 
) 
8228                     x 
= rect
.x 
+ (rect
.width 
- lineWidth 
- 1); 
8230                     y 
= rect
.y 
+ lineWidth 
+ 1; 
8233             case wxALIGN_CENTRE
: 
8234                 if ( textOrientation 
== wxHORIZONTAL 
) 
8235                     x 
= rect
.x 
+ ((rect
.width 
- lineWidth
) / 2); 
8237                     y 
= rect
.y 
+ rect
.height 
- ((rect
.height 
- lineWidth
) / 2); 
8242                 if ( textOrientation 
== wxHORIZONTAL 
) 
8245                     y 
= rect
.y 
+ rect
.height 
- 1; 
8249         if ( textOrientation 
== wxHORIZONTAL 
) 
8251             dc
.DrawText( line
, x
, y 
); 
8256             dc
.DrawRotatedText( line
, x
, y
, 90.0 ); 
8262 // Split multi-line text up into an array of strings. 
8263 // Any existing contents of the string array are preserved. 
8265 // TODO: refactor wxTextFile::Read() and reuse the same code from here 
8266 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines 
) const 
8270     wxString eol 
= wxTextFile::GetEOL( wxTextFileType_Unix 
); 
8271     wxString tVal 
= wxTextFile::Translate( value
, wxTextFileType_Unix 
); 
8273     while ( startPos 
< (int)tVal
.length() ) 
8275         pos 
= tVal
.Mid(startPos
).Find( eol 
); 
8280         else if ( pos 
== 0 ) 
8282             lines
.Add( wxEmptyString 
); 
8286             lines
.Add( tVal
.Mid(startPos
, pos
) ); 
8289         startPos 
+= pos 
+ 1; 
8292     if ( startPos 
< (int)tVal
.length() ) 
8294         lines
.Add( tVal
.Mid( startPos 
) ); 
8298 void wxGrid::GetTextBoxSize( const wxDC
& dc
, 
8299                              const wxArrayString
& lines
, 
8300                              long *width
, long *height 
) const 
8304     wxCoord lineW 
= 0, lineH 
= 0; 
8307     for ( i 
= 0; i 
< lines
.GetCount(); i
++ ) 
8309         dc
.GetTextExtent( lines
[i
], &lineW
, &lineH 
); 
8310         w 
= wxMax( w
, lineW 
); 
8319 // ------ Batch processing. 
8321 void wxGrid::EndBatch() 
8323     if ( m_batchCount 
> 0 ) 
8326         if ( !m_batchCount 
) 
8329             m_rowLabelWin
->Refresh(); 
8330             m_colLabelWin
->Refresh(); 
8331             m_cornerLabelWin
->Refresh(); 
8332             m_gridWin
->Refresh(); 
8337 // Use this, rather than wxWindow::Refresh(), to force an immediate 
8338 // repainting of the grid. Has no effect if you are already inside a 
8339 // BeginBatch / EndBatch block. 
8341 void wxGrid::ForceRefresh() 
8347 bool wxGrid::Enable(bool enable
) 
8349     if ( !wxScrolledWindow::Enable(enable
) ) 
8352     // redraw in the new state 
8353     m_gridWin
->Refresh(); 
8359 // ------ Edit control functions 
8362 void wxGrid::EnableEditing( bool edit 
) 
8364     if ( edit 
!= m_editable 
) 
8367             EnableCellEditControl(edit
); 
8372 void wxGrid::EnableCellEditControl( bool enable 
) 
8377     if ( enable 
!= m_cellEditCtrlEnabled 
) 
8381             if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN
) == -1 ) 
8384             // this should be checked by the caller! 
8385             wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); 
8387             // do it before ShowCellEditControl() 
8388             m_cellEditCtrlEnabled 
= enable
; 
8390             ShowCellEditControl(); 
8394             //FIXME:add veto support 
8395             SendEvent(wxEVT_GRID_EDITOR_HIDDEN
); 
8397             HideCellEditControl(); 
8398             SaveEditControlValue(); 
8400             // do it after HideCellEditControl() 
8401             m_cellEditCtrlEnabled 
= enable
; 
8406 bool wxGrid::IsCurrentCellReadOnly() const 
8409     wxGridCellAttr
* attr 
= ((wxGrid 
*)this)->GetCellAttr(m_currentCellCoords
); 
8410     bool readonly 
= attr
->IsReadOnly(); 
8416 bool wxGrid::CanEnableCellControl() const 
8418     return m_editable 
&& (m_currentCellCoords 
!= wxGridNoCellCoords
) && 
8419         !IsCurrentCellReadOnly(); 
8422 bool wxGrid::IsCellEditControlEnabled() const 
8424     // the cell edit control might be disable for all cells or just for the 
8425     // current one if it's read only 
8426     return m_cellEditCtrlEnabled 
? !IsCurrentCellReadOnly() : false; 
8429 bool wxGrid::IsCellEditControlShown() const 
8431     bool isShown 
= false; 
8433     if ( m_cellEditCtrlEnabled 
) 
8435         int row 
= m_currentCellCoords
.GetRow(); 
8436         int col 
= m_currentCellCoords
.GetCol(); 
8437         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8438         wxGridCellEditor
* editor 
= attr
->GetEditor((wxGrid
*) this, row
, col
); 
8443             if ( editor
->IsCreated() ) 
8445                 isShown 
= editor
->GetControl()->IsShown(); 
8455 void wxGrid::ShowCellEditControl() 
8457     if ( IsCellEditControlEnabled() ) 
8459         if ( !IsVisible( m_currentCellCoords
, false ) ) 
8461             m_cellEditCtrlEnabled 
= false; 
8466             wxRect rect 
= CellToRect( m_currentCellCoords 
); 
8467             int row 
= m_currentCellCoords
.GetRow(); 
8468             int col 
= m_currentCellCoords
.GetCol(); 
8470             // if this is part of a multicell, find owner (topleft) 
8471             int cell_rows
, cell_cols
; 
8472             GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8473             if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
8477                 m_currentCellCoords
.SetRow( row 
); 
8478                 m_currentCellCoords
.SetCol( col 
); 
8481             // erase the highlight and the cell contents because the editor 
8482             // might not cover the entire cell 
8483             wxClientDC 
dc( m_gridWin 
); 
8485             wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8486             dc
.SetBrush(wxBrush(attr
->GetBackgroundColour())); 
8487             dc
.SetPen(*wxTRANSPARENT_PEN
); 
8488             dc
.DrawRectangle(rect
); 
8490             // convert to scrolled coords 
8491             CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8497             // cell is shifted by one pixel 
8498             // However, don't allow x or y to become negative 
8499             // since the SetSize() method interprets that as 
8506             wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
8507             if ( !editor
->IsCreated() ) 
8509                 editor
->Create(m_gridWin
, wxID_ANY
, 
8510                                new wxGridCellEditorEvtHandler(this, editor
)); 
8512                 wxGridEditorCreatedEvent 
evt(GetId(), 
8513                                              wxEVT_GRID_EDITOR_CREATED
, 
8517                                              editor
->GetControl()); 
8518                 GetEventHandler()->ProcessEvent(evt
); 
8521             // resize editor to overflow into righthand cells if allowed 
8522             int maxWidth 
= rect
.width
; 
8523             wxString value 
= GetCellValue(row
, col
); 
8524             if ( (value 
!= wxEmptyString
) && (attr
->GetOverflow()) ) 
8527                 GetTextExtent(value
, &maxWidth
, &y
, NULL
, NULL
, &attr
->GetFont()); 
8528                 if (maxWidth 
< rect
.width
) 
8529                     maxWidth 
= rect
.width
; 
8532             int client_right 
= m_gridWin
->GetClientSize().GetWidth(); 
8533             if (rect
.x 
+ maxWidth 
> client_right
) 
8534                 maxWidth 
= client_right 
- rect
.x
; 
8536             if ((maxWidth 
> rect
.width
) && (col 
< m_numCols
) && m_table
) 
8538                 GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8539                 // may have changed earlier 
8540                 for (int i 
= col 
+ cell_cols
; i 
< m_numCols
; i
++) 
8543                     GetCellSize( row
, i
, &c_rows
, &c_cols 
); 
8545                     // looks weird going over a multicell 
8546                     if (m_table
->IsEmptyCell( row
, i 
) && 
8547                             (rect
.width 
< maxWidth
) && (c_rows 
== 1)) 
8549                         rect
.width 
+= GetColWidth( i 
); 
8555                 if (rect
.GetRight() > client_right
) 
8556                     rect
.SetRight( client_right 
- 1 ); 
8559             editor
->SetCellAttr( attr 
); 
8560             editor
->SetSize( rect 
); 
8562                 editor
->GetControl()->Move( 
8563                     editor
->GetControl()->GetPosition().x 
+ nXMove
, 
8564                     editor
->GetControl()->GetPosition().y 
); 
8565             editor
->Show( true, attr 
); 
8567             // recalc dimensions in case we need to 
8568             // expand the scrolled window to account for editor 
8571             editor
->BeginEdit(row
, col
, this); 
8572             editor
->SetCellAttr(NULL
); 
8580 void wxGrid::HideCellEditControl() 
8582     if ( IsCellEditControlEnabled() ) 
8584         int row 
= m_currentCellCoords
.GetRow(); 
8585         int col 
= m_currentCellCoords
.GetCol(); 
8587         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
8588         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
8589         const bool editorHadFocus 
= editor
->GetControl()->HasFocus(); 
8590         editor
->Show( false ); 
8594         // return the focus to the grid itself if the editor had it 
8596         // note that we must not do this unconditionally to avoid stealing 
8597         // focus from the window which just received it if we are hiding the 
8598         // editor precisely because we lost focus 
8599         if ( editorHadFocus 
) 
8600             m_gridWin
->SetFocus(); 
8602         // refresh whole row to the right 
8603         wxRect 
rect( CellToRect(row
, col
) ); 
8604         CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8605         rect
.width 
= m_gridWin
->GetClientSize().GetWidth() - rect
.x
; 
8608         // ensure that the pixels under the focus ring get refreshed as well 
8609         rect
.Inflate(10, 10); 
8612         m_gridWin
->Refresh( false, &rect 
); 
8616 void wxGrid::SaveEditControlValue() 
8618     if ( IsCellEditControlEnabled() ) 
8620         int row 
= m_currentCellCoords
.GetRow(); 
8621         int col 
= m_currentCellCoords
.GetCol(); 
8623         wxString oldval 
= GetCellValue(row
, col
); 
8625         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8626         wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
8627         bool changed 
= editor
->EndEdit(row
, col
, this); 
8634             if ( SendEvent(wxEVT_GRID_CELL_CHANGE
) == -1 ) 
8636                 // Event has been vetoed, set the data back. 
8637                 SetCellValue(row
, col
, oldval
); 
8644 // ------ Grid location functions 
8645 //  Note that all of these functions work with the logical coordinates of 
8646 //  grid cells and labels so you will need to convert from device 
8647 //  coordinates for mouse events etc. 
8650 wxGridCellCoords 
wxGrid::XYToCell(int x
, int y
) const 
8652     int row 
= YToRow(y
); 
8653     int col 
= XToCol(x
); 
8655     return row 
== -1 || col 
== -1 ? wxGridNoCellCoords
 
8656                                   : wxGridCellCoords(row
, col
); 
8659 // compute row or column from some (unscrolled) coordinate value, using either 
8660 // m_defaultRowHeight/m_defaultColWidth or binary search on array of 
8661 // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used 
8664 wxGrid::PosToLine(int coord
, 
8666                   const wxGridOperations
& oper
) const 
8668     const int numLines 
= oper
.GetNumberOfLines(this); 
8671         return clipToMinMax 
&& numLines 
> 0 ? oper
.GetLineAt(this, 0) : -1; 
8673     const int defaultLineSize 
= oper
.GetDefaultLineSize(this); 
8674     wxCHECK_MSG( defaultLineSize
, -1, "can't have 0 default line size" ); 
8676     int maxPos 
= coord 
/ defaultLineSize
, 
8679     // check for the simplest case: if we have no explicit line sizes 
8680     // configured, then we already know the line this position falls in 
8681     const wxArrayInt
& lineEnds 
= oper
.GetLineEnds(this); 
8682     if ( lineEnds
.empty() ) 
8684         if ( maxPos 
< numLines 
) 
8687         return clipToMinMax 
? numLines 
- 1 : -1; 
8691     // adjust maxPos before starting the binary search 
8692     if ( maxPos 
>= numLines 
) 
8694         maxPos 
= numLines  
- 1; 
8698         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos
)]) 
8701             const int minDist 
= oper
.GetMinimalAcceptableLineSize(this); 
8703                 maxPos 
= coord 
/ minDist
; 
8705                 maxPos 
= numLines 
- 1; 
8708         if ( maxPos 
>= numLines 
) 
8709             maxPos 
= numLines  
- 1; 
8712     // check if the position is beyond the last column 
8713     const int lineAtMaxPos 
= oper
.GetLineAt(this, maxPos
); 
8714     if ( coord 
>= lineEnds
[lineAtMaxPos
] ) 
8715         return clipToMinMax 
? lineAtMaxPos 
: -1; 
8717     // or before the first one 
8718     const int lineAt0 
= oper
.GetLineAt(this, 0); 
8719     if ( coord 
< lineEnds
[lineAt0
] ) 
8723     // finally do perform the binary search 
8724     while ( minPos 
< maxPos 
) 
8726         wxCHECK_MSG( lineEnds
[oper
.GetLineAt(this, minPos
)] <= coord 
&& 
8727                         coord 
< lineEnds
[oper
.GetLineAt(this, maxPos
)], 
8729                      "wxGrid: internal error in PosToLine()" ); 
8731         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos 
- 1)] ) 
8732             return oper
.GetLineAt(this, maxPos
); 
8736         const int median 
= minPos 
+ (maxPos 
- minPos 
+ 1) / 2; 
8737         if ( coord 
< lineEnds
[oper
.GetLineAt(this, median
)] ) 
8743     return oper
.GetLineAt(this, maxPos
); 
8746 int wxGrid::YToRow(int y
, bool clipToMinMax
) const 
8748     return PosToLine(y
, clipToMinMax
, wxGridRowOperations()); 
8751 int wxGrid::XToCol(int x
, bool clipToMinMax
) const 
8753     return PosToLine(x
, clipToMinMax
, wxGridColumnOperations()); 
8756 // return the row number that that the y coord is near the edge of, or -1 if 
8757 // not near an edge. 
8759 // coords can only possibly be near an edge if 
8760 //    (a) the row/column is large enough to still allow for an "inner" area 
8761 //        that is _not_ near the edge (i.e., if the height/width is smaller 
8762 //        than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be 
8765 //    (b) resizing rows/columns (the thing for which edge detection is 
8766 //        relevant at all) is enabled. 
8768 int wxGrid::PosToEdgeOfLine(int pos
, const wxGridOperations
& oper
) const 
8770     if ( !oper
.CanResizeLines(this) ) 
8773     const int line 
= oper
.PosToLine(this, pos
, true); 
8775     if ( oper
.GetLineSize(this, line
) > WXGRID_LABEL_EDGE_ZONE 
) 
8777         // We know that we are in this line, test whether we are close enough 
8778         // to start or end border, respectively. 
8779         if ( abs(oper
.GetLineEndPos(this, line
) - pos
) < WXGRID_LABEL_EDGE_ZONE 
) 
8781         else if ( line 
> 0 && 
8782                     pos 
- oper
.GetLineStartPos(this, 
8783                                                line
) < WXGRID_LABEL_EDGE_ZONE 
) 
8790 int wxGrid::YToEdgeOfRow(int y
) const 
8792     return PosToEdgeOfLine(y
, wxGridRowOperations()); 
8795 int wxGrid::XToEdgeOfCol(int x
) const 
8797     return PosToEdgeOfLine(x
, wxGridColumnOperations()); 
8800 wxRect 
wxGrid::CellToRect( int row
, int col 
) const 
8802     wxRect 
rect( -1, -1, -1, -1 ); 
8804     if ( row 
>= 0 && row 
< m_numRows 
&& 
8805          col 
>= 0 && col 
< m_numCols 
) 
8807         int i
, cell_rows
, cell_cols
; 
8808         rect
.width 
= rect
.height 
= 0; 
8809         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8810         // if negative then find multicell owner 
8815         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8817         rect
.x 
= GetColLeft(col
); 
8818         rect
.y 
= GetRowTop(row
); 
8819         for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
8820             rect
.width 
+= GetColWidth(i
); 
8821         for (i
=row
; i 
< row 
+ cell_rows
; i
++) 
8822             rect
.height 
+= GetRowHeight(i
); 
8825     // if grid lines are enabled, then the area of the cell is a bit smaller 
8826     if (m_gridLinesEnabled
) 
8835 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible 
) const 
8837     // get the cell rectangle in logical coords 
8839     wxRect 
r( CellToRect( row
, col 
) ); 
8841     // convert to device coords 
8843     int left
, top
, right
, bottom
; 
8844     CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
8845     CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
8847     // check against the client area of the grid window 
8849     m_gridWin
->GetClientSize( &cw
, &ch 
); 
8851     if ( wholeCellVisible 
) 
8853         // is the cell wholly visible ? 
8854         return ( left 
>= 0 && right 
<= cw 
&& 
8855                  top 
>= 0 && bottom 
<= ch 
); 
8859         // is the cell partly visible ? 
8861         return ( ((left 
>= 0 && left 
< cw
) || (right 
> 0 && right 
<= cw
)) && 
8862                  ((top 
>= 0 && top 
< ch
) || (bottom 
> 0 && bottom 
<= ch
)) ); 
8866 // make the specified cell location visible by doing a minimal amount 
8869 void wxGrid::MakeCellVisible( int row
, int col 
) 
8872     int xpos 
= -1, ypos 
= -1; 
8874     if ( row 
>= 0 && row 
< m_numRows 
&& 
8875          col 
>= 0 && col 
< m_numCols 
) 
8877         // get the cell rectangle in logical coords 
8878         wxRect 
r( CellToRect( row
, col 
) ); 
8880         // convert to device coords 
8881         int left
, top
, right
, bottom
; 
8882         CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
8883         CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
8886         m_gridWin
->GetClientSize( &cw
, &ch 
); 
8892         else if ( bottom 
> ch 
) 
8894             int h 
= r
.GetHeight(); 
8896             for ( i 
= row 
- 1; i 
>= 0; i
-- ) 
8898                 int rowHeight 
= GetRowHeight(i
); 
8899                 if ( h 
+ rowHeight 
> ch 
) 
8906             // we divide it later by GRID_SCROLL_LINE, make sure that we don't 
8907             // have rounding errors (this is important, because if we do, 
8908             // we might not scroll at all and some cells won't be redrawn) 
8910             // Sometimes GRID_SCROLL_LINE / 2 is not enough, 
8911             // so just add a full scroll unit... 
8912             ypos 
+= m_scrollLineY
; 
8915         // special handling for wide cells - show always left part of the cell! 
8916         // Otherwise, e.g. when stepping from row to row, it would jump between 
8917         // left and right part of the cell on every step! 
8919         if ( left 
< 0 || (right 
- left
) >= cw 
) 
8923         else if ( right 
> cw 
) 
8925             // position the view so that the cell is on the right 
8927             CalcUnscrolledPosition(0, 0, &x0
, &y0
); 
8928             xpos 
= x0 
+ (right 
- cw
); 
8930             // see comment for ypos above 
8931             xpos 
+= m_scrollLineX
; 
8934         if ( xpos 
!= -1 || ypos 
!= -1 ) 
8937                 xpos 
/= m_scrollLineX
; 
8939                 ypos 
/= m_scrollLineY
; 
8940             Scroll( xpos
, ypos 
); 
8947 // ------ Grid cursor movement functions 
8951 wxGrid::DoMoveCursor(bool expandSelection
, 
8952                      const wxGridDirectionOperations
& diroper
) 
8954     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
8957     if ( expandSelection 
) 
8959         wxGridCellCoords coords 
= m_selectedBlockCorner
; 
8960         if ( coords 
== wxGridNoCellCoords 
) 
8961             coords 
= m_currentCellCoords
; 
8963         if ( diroper
.IsAtBoundary(coords
) ) 
8966         diroper
.Advance(coords
); 
8968         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
8970     else // don't expand selection 
8974         if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
8977         wxGridCellCoords coords 
= m_currentCellCoords
; 
8978         diroper
.Advance(coords
); 
8986 bool wxGrid::MoveCursorUp(bool expandSelection
) 
8988     return DoMoveCursor(expandSelection
, 
8989                         wxGridBackwardOperations(this, wxGridRowOperations())); 
8992 bool wxGrid::MoveCursorDown(bool expandSelection
) 
8994     return DoMoveCursor(expandSelection
, 
8995                         wxGridForwardOperations(this, wxGridRowOperations())); 
8998 bool wxGrid::MoveCursorLeft(bool expandSelection
) 
9000     return DoMoveCursor(expandSelection
, 
9001                         wxGridBackwardOperations(this, wxGridColumnOperations())); 
9004 bool wxGrid::MoveCursorRight(bool expandSelection
) 
9006     return DoMoveCursor(expandSelection
, 
9007                         wxGridForwardOperations(this, wxGridColumnOperations())); 
9010 bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations
& diroper
) 
9012     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
9015     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
9018     const int oldRow 
= m_currentCellCoords
.GetRow(); 
9019     int newRow 
= diroper
.MoveByPixelDistance(oldRow
, m_gridWin
->GetClientSize().y
); 
9020     if ( newRow 
== oldRow 
) 
9022         wxGridCellCoords 
coords(m_currentCellCoords
); 
9023         diroper
.Advance(coords
); 
9024         newRow 
= coords
.GetRow(); 
9027     GoToCell(newRow
, m_currentCellCoords
.GetCol()); 
9032 bool wxGrid::MovePageUp() 
9034     return DoMoveCursorByPage( 
9035                 wxGridBackwardOperations(this, wxGridRowOperations())); 
9038 bool wxGrid::MovePageDown() 
9040     return DoMoveCursorByPage( 
9041                 wxGridForwardOperations(this, wxGridColumnOperations())); 
9044 // helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper 
9045 // until we find a non-empty cell or reach the grid end 
9047 wxGrid::AdvanceToNextNonEmpty(wxGridCellCoords
& coords
, 
9048                               const wxGridDirectionOperations
& diroper
) 
9050     while ( !diroper
.IsAtBoundary(coords
) ) 
9052         diroper
.Advance(coords
); 
9053         if ( !m_table
->IsEmpty(coords
) ) 
9059 wxGrid::DoMoveCursorByBlock(bool expandSelection
, 
9060                             const wxGridDirectionOperations
& diroper
) 
9062     if ( !m_table 
|| m_currentCellCoords 
== wxGridNoCellCoords 
) 
9065     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
9068     wxGridCellCoords 
coords(m_currentCellCoords
); 
9069     if ( m_table
->IsEmpty(coords
) ) 
9071         // we are in an empty cell: find the next block of non-empty cells 
9072         AdvanceToNextNonEmpty(coords
, diroper
); 
9074     else // current cell is not empty 
9076         diroper
.Advance(coords
); 
9077         if ( m_table
->IsEmpty(coords
) ) 
9079             // we started at the end of a block, find the next one 
9080             AdvanceToNextNonEmpty(coords
, diroper
); 
9082         else // we're in a middle of a block 
9084             // go to the end of it, i.e. find the last cell before the next 
9086             while ( !diroper
.IsAtBoundary(coords
) ) 
9088                 wxGridCellCoords 
coordsNext(coords
); 
9089                 diroper
.Advance(coordsNext
); 
9090                 if ( m_table
->IsEmpty(coordsNext
) ) 
9093                 coords 
= coordsNext
; 
9098     if ( expandSelection 
) 
9100         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
9111 bool wxGrid::MoveCursorUpBlock(bool expandSelection
) 
9113     return DoMoveCursorByBlock( 
9115                 wxGridBackwardOperations(this, wxGridRowOperations()) 
9119 bool wxGrid::MoveCursorDownBlock( bool expandSelection 
) 
9121     return DoMoveCursorByBlock( 
9123                 wxGridForwardOperations(this, wxGridRowOperations()) 
9127 bool wxGrid::MoveCursorLeftBlock( bool expandSelection 
) 
9129     return DoMoveCursorByBlock( 
9131                 wxGridBackwardOperations(this, wxGridColumnOperations()) 
9135 bool wxGrid::MoveCursorRightBlock( bool expandSelection 
) 
9137     return DoMoveCursorByBlock( 
9139                 wxGridForwardOperations(this, wxGridColumnOperations()) 
9144 // ------ Label values and formatting 
9147 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert 
) const 
9150         *horiz 
= m_rowLabelHorizAlign
; 
9152         *vert  
= m_rowLabelVertAlign
; 
9155 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert 
) const 
9158         *horiz 
= m_colLabelHorizAlign
; 
9160         *vert  
= m_colLabelVertAlign
; 
9163 int wxGrid::GetColLabelTextOrientation() const 
9165     return m_colLabelTextOrientation
; 
9168 wxString 
wxGrid::GetRowLabelValue( int row 
) const 
9172         return m_table
->GetRowLabelValue( row 
); 
9182 wxString 
wxGrid::GetColLabelValue( int col 
) const 
9186         return m_table
->GetColLabelValue( col 
); 
9196 void wxGrid::SetRowLabelSize( int width 
) 
9198     wxASSERT( width 
>= 0 || width 
== wxGRID_AUTOSIZE 
); 
9200     if ( width 
== wxGRID_AUTOSIZE 
) 
9202         width 
= CalcColOrRowLabelAreaMinSize(wxGRID_ROW
); 
9205     if ( width 
!= m_rowLabelWidth 
) 
9209             m_rowLabelWin
->Show( false ); 
9210             m_cornerLabelWin
->Show( false ); 
9212         else if ( m_rowLabelWidth 
== 0 ) 
9214             m_rowLabelWin
->Show( true ); 
9215             if ( m_colLabelHeight 
> 0 ) 
9216                 m_cornerLabelWin
->Show( true ); 
9219         m_rowLabelWidth 
= width
; 
9221         wxScrolledWindow::Refresh( true ); 
9225 void wxGrid::SetColLabelSize( int height 
) 
9227     wxASSERT( height 
>=0 || height 
== wxGRID_AUTOSIZE 
); 
9229     if ( height 
== wxGRID_AUTOSIZE 
) 
9231         height 
= CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN
); 
9234     if ( height 
!= m_colLabelHeight 
) 
9238             m_colLabelWin
->Show( false ); 
9239             m_cornerLabelWin
->Show( false ); 
9241         else if ( m_colLabelHeight 
== 0 ) 
9243             m_colLabelWin
->Show( true ); 
9244             if ( m_rowLabelWidth 
> 0 ) 
9245                 m_cornerLabelWin
->Show( true ); 
9248         m_colLabelHeight 
= height
; 
9250         wxScrolledWindow::Refresh( true ); 
9254 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour 
) 
9256     if ( m_labelBackgroundColour 
!= colour 
) 
9258         m_labelBackgroundColour 
= colour
; 
9259         m_rowLabelWin
->SetBackgroundColour( colour 
); 
9260         m_colLabelWin
->SetBackgroundColour( colour 
); 
9261         m_cornerLabelWin
->SetBackgroundColour( colour 
); 
9263         if ( !GetBatchCount() ) 
9265             m_rowLabelWin
->Refresh(); 
9266             m_colLabelWin
->Refresh(); 
9267             m_cornerLabelWin
->Refresh(); 
9272 void wxGrid::SetLabelTextColour( const wxColour
& colour 
) 
9274     if ( m_labelTextColour 
!= colour 
) 
9276         m_labelTextColour 
= colour
; 
9277         if ( !GetBatchCount() ) 
9279             m_rowLabelWin
->Refresh(); 
9280             m_colLabelWin
->Refresh(); 
9285 void wxGrid::SetLabelFont( const wxFont
& font 
) 
9288     if ( !GetBatchCount() ) 
9290         m_rowLabelWin
->Refresh(); 
9291         m_colLabelWin
->Refresh(); 
9295 void wxGrid::SetRowLabelAlignment( int horiz
, int vert 
) 
9297     // allow old (incorrect) defs to be used 
9300         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
9301         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
9302         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
9307         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
9308         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
9309         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
9312     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
9314         m_rowLabelHorizAlign 
= horiz
; 
9317     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
9319         m_rowLabelVertAlign 
= vert
; 
9322     if ( !GetBatchCount() ) 
9324         m_rowLabelWin
->Refresh(); 
9328 void wxGrid::SetColLabelAlignment( int horiz
, int vert 
) 
9330     // allow old (incorrect) defs to be used 
9333         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
9334         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
9335         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
9340         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
9341         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
9342         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
9345     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
9347         m_colLabelHorizAlign 
= horiz
; 
9350     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
9352         m_colLabelVertAlign 
= vert
; 
9355     if ( !GetBatchCount() ) 
9357         m_colLabelWin
->Refresh(); 
9361 // Note: under MSW, the default column label font must be changed because it 
9362 //       does not support vertical printing 
9364 // Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD); 
9365 //                      pGrid->SetLabelFont(font); 
9366 //                      pGrid->SetColLabelTextOrientation(wxVERTICAL); 
9368 void wxGrid::SetColLabelTextOrientation( int textOrientation 
) 
9370     if ( textOrientation 
== wxHORIZONTAL 
|| textOrientation 
== wxVERTICAL 
) 
9371         m_colLabelTextOrientation 
= textOrientation
; 
9373     if ( !GetBatchCount() ) 
9374         m_colLabelWin
->Refresh(); 
9377 void wxGrid::SetRowLabelValue( int row
, const wxString
& s 
) 
9381         m_table
->SetRowLabelValue( row
, s 
); 
9382         if ( !GetBatchCount() ) 
9384             wxRect rect 
= CellToRect( row
, 0 ); 
9385             if ( rect
.height 
> 0 ) 
9387                 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
); 
9389                 rect
.width 
= m_rowLabelWidth
; 
9390                 m_rowLabelWin
->Refresh( true, &rect 
); 
9396 void wxGrid::SetColLabelValue( int col
, const wxString
& s 
) 
9400         m_table
->SetColLabelValue( col
, s 
); 
9401         if ( !GetBatchCount() ) 
9403             wxRect rect 
= CellToRect( 0, col 
); 
9404             if ( rect
.width 
> 0 ) 
9406                 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
); 
9408                 rect
.height 
= m_colLabelHeight
; 
9409                 m_colLabelWin
->Refresh( true, &rect 
); 
9415 void wxGrid::SetGridLineColour( const wxColour
& colour 
) 
9417     if ( m_gridLineColour 
!= colour 
) 
9419         m_gridLineColour 
= colour
; 
9421         if ( GridLinesEnabled() ) 
9426 void wxGrid::SetCellHighlightColour( const wxColour
& colour 
) 
9428     if ( m_cellHighlightColour 
!= colour 
) 
9430         m_cellHighlightColour 
= colour
; 
9432         wxClientDC 
dc( m_gridWin 
); 
9434         wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
9435         DrawCellHighlight(dc
, attr
); 
9440 void wxGrid::SetCellHighlightPenWidth(int width
) 
9442     if (m_cellHighlightPenWidth 
!= width
) 
9444         m_cellHighlightPenWidth 
= width
; 
9446         // Just redrawing the cell highlight is not enough since that won't 
9447         // make any visible change if the the thickness is getting smaller. 
9448         int row 
= m_currentCellCoords
.GetRow(); 
9449         int col 
= m_currentCellCoords
.GetCol(); 
9450         if ( row 
== -1 || col 
== -1 || GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
9453         wxRect rect 
= CellToRect(row
, col
); 
9454         m_gridWin
->Refresh(true, &rect
); 
9458 void wxGrid::SetCellHighlightROPenWidth(int width
) 
9460     if (m_cellHighlightROPenWidth 
!= width
) 
9462         m_cellHighlightROPenWidth 
= width
; 
9464         // Just redrawing the cell highlight is not enough since that won't 
9465         // make any visible change if the the thickness is getting smaller. 
9466         int row 
= m_currentCellCoords
.GetRow(); 
9467         int col 
= m_currentCellCoords
.GetCol(); 
9468         if ( row 
== -1 || col 
== -1 || 
9469                 GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
9472         wxRect rect 
= CellToRect(row
, col
); 
9473         m_gridWin
->Refresh(true, &rect
); 
9477 void wxGrid::RedrawGridLines() 
9479     // the lines will be redrawn when the window is thawn 
9480     if ( GetBatchCount() ) 
9483     if ( GridLinesEnabled() ) 
9485         wxClientDC 
dc( m_gridWin 
); 
9487         DrawAllGridLines( dc
, wxRegion() ); 
9489     else // remove the grid lines 
9491         m_gridWin
->Refresh(); 
9495 void wxGrid::EnableGridLines( bool enable 
) 
9497     if ( enable 
!= m_gridLinesEnabled 
) 
9499         m_gridLinesEnabled 
= enable
; 
9505 void wxGrid::DoClipGridLines(bool& var
, bool clip
) 
9511         if ( GridLinesEnabled() ) 
9516 int wxGrid::GetDefaultRowSize() const 
9518     return m_defaultRowHeight
; 
9521 int wxGrid::GetRowSize( int row 
) const 
9523     wxCHECK_MSG( row 
>= 0 && row 
< m_numRows
, 0, _T("invalid row index") ); 
9525     return GetRowHeight(row
); 
9528 int wxGrid::GetDefaultColSize() const 
9530     return m_defaultColWidth
; 
9533 int wxGrid::GetColSize( int col 
) const 
9535     wxCHECK_MSG( col 
>= 0 && col 
< m_numCols
, 0, _T("invalid column index") ); 
9537     return GetColWidth(col
); 
9540 // ============================================================================ 
9541 // access to the grid attributes: each of them has a default value in the grid 
9542 // itself and may be overidden on a per-cell basis 
9543 // ============================================================================ 
9545 // ---------------------------------------------------------------------------- 
9546 // setting default attributes 
9547 // ---------------------------------------------------------------------------- 
9549 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& col 
) 
9551     m_defaultCellAttr
->SetBackgroundColour(col
); 
9553     m_gridWin
->SetBackgroundColour(col
); 
9557 void wxGrid::SetDefaultCellTextColour( const wxColour
& col 
) 
9559     m_defaultCellAttr
->SetTextColour(col
); 
9562 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert 
) 
9564     m_defaultCellAttr
->SetAlignment(horiz
, vert
); 
9567 void wxGrid::SetDefaultCellOverflow( bool allow 
) 
9569     m_defaultCellAttr
->SetOverflow(allow
); 
9572 void wxGrid::SetDefaultCellFont( const wxFont
& font 
) 
9574     m_defaultCellAttr
->SetFont(font
); 
9577 // For editors and renderers the type registry takes precedence over the 
9578 // default attr, so we need to register the new editor/renderer for the string 
9579 // data type in order to make setting a default editor/renderer appear to 
9582 void wxGrid::SetDefaultRenderer(wxGridCellRenderer 
*renderer
) 
9584     RegisterDataType(wxGRID_VALUE_STRING
, 
9586                      GetDefaultEditorForType(wxGRID_VALUE_STRING
)); 
9589 void wxGrid::SetDefaultEditor(wxGridCellEditor 
*editor
) 
9591     RegisterDataType(wxGRID_VALUE_STRING
, 
9592                      GetDefaultRendererForType(wxGRID_VALUE_STRING
), 
9596 // ---------------------------------------------------------------------------- 
9597 // access to the default attributes 
9598 // ---------------------------------------------------------------------------- 
9600 wxColour 
wxGrid::GetDefaultCellBackgroundColour() const 
9602     return m_defaultCellAttr
->GetBackgroundColour(); 
9605 wxColour 
wxGrid::GetDefaultCellTextColour() const 
9607     return m_defaultCellAttr
->GetTextColour(); 
9610 wxFont 
wxGrid::GetDefaultCellFont() const 
9612     return m_defaultCellAttr
->GetFont(); 
9615 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert 
) const 
9617     m_defaultCellAttr
->GetAlignment(horiz
, vert
); 
9620 bool wxGrid::GetDefaultCellOverflow() const 
9622     return m_defaultCellAttr
->GetOverflow(); 
9625 wxGridCellRenderer 
*wxGrid::GetDefaultRenderer() const 
9627     return m_defaultCellAttr
->GetRenderer(NULL
, 0, 0); 
9630 wxGridCellEditor 
*wxGrid::GetDefaultEditor() const 
9632     return m_defaultCellAttr
->GetEditor(NULL
, 0, 0); 
9635 // ---------------------------------------------------------------------------- 
9636 // access to cell attributes 
9637 // ---------------------------------------------------------------------------- 
9639 wxColour 
wxGrid::GetCellBackgroundColour(int row
, int col
) const 
9641     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9642     wxColour colour 
= attr
->GetBackgroundColour(); 
9648 wxColour 
wxGrid::GetCellTextColour( int row
, int col 
) const 
9650     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9651     wxColour colour 
= attr
->GetTextColour(); 
9657 wxFont 
wxGrid::GetCellFont( int row
, int col 
) const 
9659     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9660     wxFont font 
= attr
->GetFont(); 
9666 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert 
) const 
9668     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9669     attr
->GetAlignment(horiz
, vert
); 
9673 bool wxGrid::GetCellOverflow( int row
, int col 
) const 
9675     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9676     bool allow 
= attr
->GetOverflow(); 
9682 void wxGrid::GetCellSize( int row
, int col
, int *num_rows
, int *num_cols 
) const 
9684     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9685     attr
->GetSize( num_rows
, num_cols 
); 
9689 wxGridCellRenderer
* wxGrid::GetCellRenderer(int row
, int col
) const 
9691     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9692     wxGridCellRenderer
* renderer 
= attr
->GetRenderer(this, row
, col
); 
9698 wxGridCellEditor
* wxGrid::GetCellEditor(int row
, int col
) const 
9700     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9701     wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
9707 bool wxGrid::IsReadOnly(int row
, int col
) const 
9709     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9710     bool isReadOnly 
= attr
->IsReadOnly(); 
9716 // ---------------------------------------------------------------------------- 
9717 // attribute support: cache, automatic provider creation, ... 
9718 // ---------------------------------------------------------------------------- 
9720 bool wxGrid::CanHaveAttributes() const 
9727     return m_table
->CanHaveAttributes(); 
9730 void wxGrid::ClearAttrCache() 
9732     if ( m_attrCache
.row 
!= -1 ) 
9734         wxGridCellAttr 
*oldAttr 
= m_attrCache
.attr
; 
9735         m_attrCache
.attr 
= NULL
; 
9736         m_attrCache
.row 
= -1; 
9737         // wxSafeDecRec(...) might cause event processing that accesses 
9738         // the cached attribute, if one exists (e.g. by deleting the 
9739         // editor stored within the attribute). Therefore it is important 
9740         // to invalidate the cache  before calling wxSafeDecRef! 
9741         wxSafeDecRef(oldAttr
); 
9745 void wxGrid::CacheAttr(int row
, int col
, wxGridCellAttr 
*attr
) const 
9749         wxGrid 
*self 
= (wxGrid 
*)this;  // const_cast 
9751         self
->ClearAttrCache(); 
9752         self
->m_attrCache
.row 
= row
; 
9753         self
->m_attrCache
.col 
= col
; 
9754         self
->m_attrCache
.attr 
= attr
; 
9759 bool wxGrid::LookupAttr(int row
, int col
, wxGridCellAttr 
**attr
) const 
9761     if ( row 
== m_attrCache
.row 
&& col 
== m_attrCache
.col 
) 
9763         *attr 
= m_attrCache
.attr
; 
9764         wxSafeIncRef(m_attrCache
.attr
); 
9766 #ifdef DEBUG_ATTR_CACHE 
9767         gs_nAttrCacheHits
++; 
9774 #ifdef DEBUG_ATTR_CACHE 
9775         gs_nAttrCacheMisses
++; 
9782 wxGridCellAttr 
*wxGrid::GetCellAttr(int row
, int col
) const 
9784     wxGridCellAttr 
*attr 
= NULL
; 
9785     // Additional test to avoid looking at the cache e.g. for 
9786     // wxNoCellCoords, as this will confuse memory management. 
9789         if ( !LookupAttr(row
, col
, &attr
) ) 
9791             attr 
= m_table 
? m_table
->GetAttr(row
, col
, wxGridCellAttr::Any
) 
9793             CacheAttr(row
, col
, attr
); 
9799         attr
->SetDefAttr(m_defaultCellAttr
); 
9803         attr 
= m_defaultCellAttr
; 
9810 wxGridCellAttr 
*wxGrid::GetOrCreateCellAttr(int row
, int col
) const 
9812     wxGridCellAttr 
*attr 
= NULL
; 
9813     bool canHave 
= ((wxGrid
*)this)->CanHaveAttributes(); 
9815     wxCHECK_MSG( canHave
, attr
, _T("Cell attributes not allowed")); 
9816     wxCHECK_MSG( m_table
, attr
, _T("must have a table") ); 
9818     attr 
= m_table
->GetAttr(row
, col
, wxGridCellAttr::Cell
); 
9821         attr 
= new wxGridCellAttr(m_defaultCellAttr
); 
9823         // artificially inc the ref count to match DecRef() in caller 
9825         m_table
->SetAttr(attr
, row
, col
); 
9831 // ---------------------------------------------------------------------------- 
9832 // setting column attributes (wrappers around SetColAttr) 
9833 // ---------------------------------------------------------------------------- 
9835 void wxGrid::SetColFormatBool(int col
) 
9837     SetColFormatCustom(col
, wxGRID_VALUE_BOOL
); 
9840 void wxGrid::SetColFormatNumber(int col
) 
9842     SetColFormatCustom(col
, wxGRID_VALUE_NUMBER
); 
9845 void wxGrid::SetColFormatFloat(int col
, int width
, int precision
) 
9847     wxString typeName 
= wxGRID_VALUE_FLOAT
; 
9848     if ( (width 
!= -1) || (precision 
!= -1) ) 
9850         typeName 
<< _T(':') << width 
<< _T(',') << precision
; 
9853     SetColFormatCustom(col
, typeName
); 
9856 void wxGrid::SetColFormatCustom(int col
, const wxString
& typeName
) 
9858     wxGridCellAttr 
*attr 
= m_table
->GetAttr(-1, col
, wxGridCellAttr::Col 
); 
9860         attr 
= new wxGridCellAttr
; 
9861     wxGridCellRenderer 
*renderer 
= GetDefaultRendererForType(typeName
); 
9862     attr
->SetRenderer(renderer
); 
9863     wxGridCellEditor 
*editor 
= GetDefaultEditorForType(typeName
); 
9864     attr
->SetEditor(editor
); 
9866     SetColAttr(col
, attr
); 
9870 // ---------------------------------------------------------------------------- 
9871 // setting cell attributes: this is forwarded to the table 
9872 // ---------------------------------------------------------------------------- 
9874 void wxGrid::SetAttr(int row
, int col
, wxGridCellAttr 
*attr
) 
9876     if ( CanHaveAttributes() ) 
9878         m_table
->SetAttr(attr
, row
, col
); 
9887 void wxGrid::SetRowAttr(int row
, wxGridCellAttr 
*attr
) 
9889     if ( CanHaveAttributes() ) 
9891         m_table
->SetRowAttr(attr
, row
); 
9900 void wxGrid::SetColAttr(int col
, wxGridCellAttr 
*attr
) 
9902     if ( CanHaveAttributes() ) 
9904         m_table
->SetColAttr(attr
, col
); 
9913 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour 
) 
9915     if ( CanHaveAttributes() ) 
9917         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9918         attr
->SetBackgroundColour(colour
); 
9923 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& colour 
) 
9925     if ( CanHaveAttributes() ) 
9927         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9928         attr
->SetTextColour(colour
); 
9933 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& font 
) 
9935     if ( CanHaveAttributes() ) 
9937         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9938         attr
->SetFont(font
); 
9943 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert 
) 
9945     if ( CanHaveAttributes() ) 
9947         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9948         attr
->SetAlignment(horiz
, vert
); 
9953 void wxGrid::SetCellOverflow( int row
, int col
, bool allow 
) 
9955     if ( CanHaveAttributes() ) 
9957         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9958         attr
->SetOverflow(allow
); 
9963 void wxGrid::SetCellSize( int row
, int col
, int num_rows
, int num_cols 
) 
9965     if ( CanHaveAttributes() ) 
9967         int cell_rows
, cell_cols
; 
9969         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9970         attr
->GetSize(&cell_rows
, &cell_cols
); 
9971         attr
->SetSize(num_rows
, num_cols
); 
9974         // Cannot set the size of a cell to 0 or negative values 
9975         // While it is perfectly legal to do that, this function cannot 
9976         // handle all the possibilies, do it by hand by getting the CellAttr. 
9977         // You can only set the size of a cell to 1,1 or greater with this fn 
9978         wxASSERT_MSG( !((cell_rows 
< 1) || (cell_cols 
< 1)), 
9979                       wxT("wxGrid::SetCellSize setting cell size that is already part of another cell")); 
9980         wxASSERT_MSG( !((num_rows 
< 1) || (num_cols 
< 1)), 
9981                       wxT("wxGrid::SetCellSize setting cell size to < 1")); 
9983         // if this was already a multicell then "turn off" the other cells first 
9984         if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
9987             for (j
=row
; j 
< row 
+ cell_rows
; j
++) 
9989                 for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
9991                     if ((i 
!= col
) || (j 
!= row
)) 
9993                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
9994                         attr_stub
->SetSize( 1, 1 ); 
9995                         attr_stub
->DecRef(); 
10001         // mark the cells that will be covered by this cell to 
10002         // negative or zero values to point back at this cell 
10003         if (((num_rows 
> 1) || (num_cols 
> 1)) && (num_rows 
>= 1) && (num_cols 
>= 1)) 
10006             for (j
=row
; j 
< row 
+ num_rows
; j
++) 
10008                 for (i
=col
; i 
< col 
+ num_cols
; i
++) 
10010                     if ((i 
!= col
) || (j 
!= row
)) 
10012                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
10013                         attr_stub
->SetSize( row 
- j
, col 
- i 
); 
10014                         attr_stub
->DecRef(); 
10022 void wxGrid::SetCellRenderer(int row
, int col
, wxGridCellRenderer 
*renderer
) 
10024     if ( CanHaveAttributes() ) 
10026         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10027         attr
->SetRenderer(renderer
); 
10032 void wxGrid::SetCellEditor(int row
, int col
, wxGridCellEditor
* editor
) 
10034     if ( CanHaveAttributes() ) 
10036         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10037         attr
->SetEditor(editor
); 
10042 void wxGrid::SetReadOnly(int row
, int col
, bool isReadOnly
) 
10044     if ( CanHaveAttributes() ) 
10046         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10047         attr
->SetReadOnly(isReadOnly
); 
10052 // ---------------------------------------------------------------------------- 
10053 // Data type registration 
10054 // ---------------------------------------------------------------------------- 
10056 void wxGrid::RegisterDataType(const wxString
& typeName
, 
10057                               wxGridCellRenderer
* renderer
, 
10058                               wxGridCellEditor
* editor
) 
10060     m_typeRegistry
->RegisterDataType(typeName
, renderer
, editor
); 
10064 wxGridCellEditor 
* wxGrid::GetDefaultEditorForCell(int row
, int col
) const 
10066     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
10067     return GetDefaultEditorForType(typeName
); 
10070 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForCell(int row
, int col
) const 
10072     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
10073     return GetDefaultRendererForType(typeName
); 
10076 wxGridCellEditor 
* wxGrid::GetDefaultEditorForType(const wxString
& typeName
) const 
10078     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
10079     if ( index 
== wxNOT_FOUND 
) 
10081         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
10086     return m_typeRegistry
->GetEditor(index
); 
10089 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForType(const wxString
& typeName
) const 
10091     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
10092     if ( index 
== wxNOT_FOUND 
) 
10094         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
10099     return m_typeRegistry
->GetRenderer(index
); 
10102 // ---------------------------------------------------------------------------- 
10104 // ---------------------------------------------------------------------------- 
10106 void wxGrid::EnableDragRowSize( bool enable 
) 
10108     m_canDragRowSize 
= enable
; 
10111 void wxGrid::EnableDragColSize( bool enable 
) 
10113     m_canDragColSize 
= enable
; 
10116 void wxGrid::EnableDragGridSize( bool enable 
) 
10118     m_canDragGridSize 
= enable
; 
10121 void wxGrid::EnableDragCell( bool enable 
) 
10123     m_canDragCell 
= enable
; 
10126 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows 
) 
10128     m_defaultRowHeight 
= wxMax( height
, m_minAcceptableRowHeight 
); 
10130     if ( resizeExistingRows 
) 
10132         // since we are resizing all rows to the default row size, 
10133         // we can simply clear the row heights and row bottoms 
10134         // arrays (which also allows us to take advantage of 
10135         // some speed optimisations) 
10136         m_rowHeights
.Empty(); 
10137         m_rowBottoms
.Empty(); 
10138         if ( !GetBatchCount() ) 
10143 void wxGrid::SetRowSize( int row
, int height 
) 
10145     wxCHECK_RET( row 
>= 0 && row 
< m_numRows
, _T("invalid row index") ); 
10147     // if < 0 then calculate new height from label 
10151         wxArrayString lines
; 
10152         wxClientDC 
dc(m_rowLabelWin
); 
10153         dc
.SetFont(GetLabelFont()); 
10154         StringToLines(GetRowLabelValue( row 
), lines
); 
10155         GetTextBoxSize( dc
, lines
, &w
, &h 
); 
10156         //check that it is not less than the minimal height 
10157         height 
= wxMax(h
, GetRowMinimalAcceptableHeight()); 
10160     // See comment in SetColSize 
10161     if ( height 
< GetRowMinimalAcceptableHeight()) 
10164     if ( m_rowHeights
.IsEmpty() ) 
10166         // need to really create the array 
10170     int h 
= wxMax( 0, height 
); 
10171     int diff 
= h 
- m_rowHeights
[row
]; 
10173     m_rowHeights
[row
] = h
; 
10174     for ( int i 
= row
; i 
< m_numRows
; i
++ ) 
10176         m_rowBottoms
[i
] += diff
; 
10179     if ( !GetBatchCount() ) 
10183 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols 
) 
10185     // we dont allow zero default column width 
10186     m_defaultColWidth 
= wxMax( wxMax( width
, m_minAcceptableColWidth 
), 1 ); 
10188     if ( resizeExistingCols 
) 
10190         // since we are resizing all columns to the default column size, 
10191         // we can simply clear the col widths and col rights 
10192         // arrays (which also allows us to take advantage of 
10193         // some speed optimisations) 
10194         m_colWidths
.Empty(); 
10195         m_colRights
.Empty(); 
10196         if ( !GetBatchCount() ) 
10201 void wxGrid::SetColSize( int col
, int width 
) 
10203     wxCHECK_RET( col 
>= 0 && col 
< m_numCols
, _T("invalid column index") ); 
10205     // if < 0 then calculate new width from label 
10209         wxArrayString lines
; 
10210         wxClientDC 
dc(m_colLabelWin
); 
10211         dc
.SetFont(GetLabelFont()); 
10212         StringToLines(GetColLabelValue(col
), lines
); 
10213         if ( GetColLabelTextOrientation() == wxHORIZONTAL 
) 
10214             GetTextBoxSize( dc
, lines
, &w
, &h 
); 
10216             GetTextBoxSize( dc
, lines
, &h
, &w 
); 
10218         //check that it is not less than the minimal width 
10219         width 
= wxMax(width
, GetColMinimalAcceptableWidth()); 
10222     // should we check that it's bigger than GetColMinimalWidth(col) here? 
10224     // No, because it is reasonable to assume the library user know's 
10225     // what he is doing. However we should test against the weaker 
10226     // constraint of minimalAcceptableWidth, as this breaks rendering 
10228     // This test then fixes sf.net bug #645734 
10230     if ( width 
< GetColMinimalAcceptableWidth() ) 
10233     if ( m_colWidths
.IsEmpty() ) 
10235         // need to really create the array 
10239     int w 
= wxMax( 0, width 
); 
10240     int diff 
= w 
- m_colWidths
[col
]; 
10241     m_colWidths
[col
] = w
; 
10243     for ( int colPos 
= GetColPos(col
); colPos 
< m_numCols
; colPos
++ ) 
10245         m_colRights
[GetColAt(colPos
)] += diff
; 
10248     if ( !GetBatchCount() ) 
10252 void wxGrid::SetColMinimalWidth( int col
, int width 
) 
10254     if (width 
> GetColMinimalAcceptableWidth()) 
10256         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
10257         m_colMinWidths
[key
] = width
; 
10261 void wxGrid::SetRowMinimalHeight( int row
, int width 
) 
10263     if (width 
> GetRowMinimalAcceptableHeight()) 
10265         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
10266         m_rowMinHeights
[key
] = width
; 
10270 int wxGrid::GetColMinimalWidth(int col
) const 
10272     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
10273     wxLongToLongHashMap::const_iterator it 
= m_colMinWidths
.find(key
); 
10275     return it 
!= m_colMinWidths
.end() ? (int)it
->second 
: m_minAcceptableColWidth
; 
10278 int wxGrid::GetRowMinimalHeight(int row
) const 
10280     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
10281     wxLongToLongHashMap::const_iterator it 
= m_rowMinHeights
.find(key
); 
10283     return it 
!= m_rowMinHeights
.end() ? (int)it
->second 
: m_minAcceptableRowHeight
; 
10286 void wxGrid::SetColMinimalAcceptableWidth( int width 
) 
10288     // We do allow a width of 0 since this gives us 
10289     // an easy way to temporarily hiding columns. 
10291         m_minAcceptableColWidth 
= width
; 
10294 void wxGrid::SetRowMinimalAcceptableHeight( int height 
) 
10296     // We do allow a height of 0 since this gives us 
10297     // an easy way to temporarily hiding rows. 
10299         m_minAcceptableRowHeight 
= height
; 
10302 int  wxGrid::GetColMinimalAcceptableWidth() const 
10304     return m_minAcceptableColWidth
; 
10307 int  wxGrid::GetRowMinimalAcceptableHeight() const 
10309     return m_minAcceptableRowHeight
; 
10312 // ---------------------------------------------------------------------------- 
10314 // ---------------------------------------------------------------------------- 
10317 wxGrid::AutoSizeColOrRow(int colOrRow
, bool setAsMin
, wxGridDirection direction
) 
10319     const bool column 
= direction 
== wxGRID_COLUMN
; 
10321     wxClientDC 
dc(m_gridWin
); 
10323     // cancel editing of cell 
10324     HideCellEditControl(); 
10325     SaveEditControlValue(); 
10327     // init both of them to avoid compiler warnings, even if we only need one 
10335     wxCoord extent
, extentMax 
= 0; 
10336     int max 
= column 
? m_numRows 
: m_numCols
; 
10337     for ( int rowOrCol 
= 0; rowOrCol 
< max
; rowOrCol
++ ) 
10344         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
10345         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
10348             wxSize size 
= renderer
->GetBestSize(*this, *attr
, dc
, row
, col
); 
10349             extent 
= column 
? size
.x 
: size
.y
; 
10350             if ( extent 
> extentMax 
) 
10351                 extentMax 
= extent
; 
10353             renderer
->DecRef(); 
10359     // now also compare with the column label extent 
10361     dc
.SetFont( GetLabelFont() ); 
10365         dc
.GetMultiLineTextExtent( GetColLabelValue(col
), &w
, &h 
); 
10366         if ( GetColLabelTextOrientation() == wxVERTICAL 
) 
10370         dc
.GetMultiLineTextExtent( GetRowLabelValue(row
), &w
, &h 
); 
10372     extent 
= column 
? w 
: h
; 
10373     if ( extent 
> extentMax 
) 
10374         extentMax 
= extent
; 
10378         // empty column - give default extent (notice that if extentMax is less 
10379         // than default extent but != 0, it's OK) 
10380         extentMax 
= column 
? m_defaultColWidth 
: m_defaultRowHeight
; 
10385             // leave some space around text 
10393         // Ensure automatic width is not less than minimal width. See the 
10394         // comment in SetColSize() for explanation of why this isn't done 
10395         // in SetColSize(). 
10397             extentMax 
= wxMax(extentMax
, GetColMinimalWidth(col
)); 
10399         SetColSize( col
, extentMax 
); 
10400         if ( !GetBatchCount() ) 
10403             m_gridWin
->GetClientSize( &cw
, &ch 
); 
10404             wxRect 
rect ( CellToRect( 0, col 
) ); 
10406             CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
); 
10407             rect
.width 
= cw 
- rect
.x
; 
10408             rect
.height 
= m_colLabelHeight
; 
10409             m_colLabelWin
->Refresh( true, &rect 
); 
10414         // Ensure automatic width is not less than minimal height. See the 
10415         // comment in SetColSize() for explanation of why this isn't done 
10416         // in SetRowSize(). 
10418             extentMax 
= wxMax(extentMax
, GetRowMinimalHeight(row
)); 
10420         SetRowSize(row
, extentMax
); 
10421         if ( !GetBatchCount() ) 
10424             m_gridWin
->GetClientSize( &cw
, &ch 
); 
10425             wxRect 
rect( CellToRect( row
, 0 ) ); 
10427             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
10428             rect
.width 
= m_rowLabelWidth
; 
10429             rect
.height 
= ch 
- rect
.y
; 
10430             m_rowLabelWin
->Refresh( true, &rect 
); 
10437             SetColMinimalWidth(col
, extentMax
); 
10439             SetRowMinimalHeight(row
, extentMax
); 
10443 wxCoord 
wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction
) 
10445     // calculate size for the rows or columns? 
10446     const bool calcRows 
= direction 
== wxGRID_ROW
; 
10448     wxClientDC 
dc(calcRows 
? GetGridRowLabelWindow() 
10449                            : GetGridColLabelWindow()); 
10450     dc
.SetFont(GetLabelFont()); 
10452     // which dimension should we take into account for calculations? 
10454     // for columns, the text can be only horizontal so it's easy but for rows 
10455     // we also have to take into account the text orientation 
10457         useWidth 
= calcRows 
|| (GetColLabelTextOrientation() == wxVERTICAL
); 
10459     wxArrayString lines
; 
10460     wxCoord extentMax 
= 0; 
10462     const int numRowsOrCols 
= calcRows 
? m_numRows 
: m_numCols
; 
10463     for ( int rowOrCol 
= 0; rowOrCol 
< numRowsOrCols
; rowOrCol
++ ) 
10467         wxString label 
= calcRows 
? GetRowLabelValue(rowOrCol
) 
10468                                   : GetColLabelValue(rowOrCol
); 
10469         StringToLines(label
, lines
); 
10472         GetTextBoxSize(dc
, lines
, &w
, &h
); 
10474         const wxCoord extent 
= useWidth 
? w 
: h
; 
10475         if ( extent 
> extentMax 
) 
10476             extentMax 
= extent
; 
10481         // empty column - give default extent (notice that if extentMax is less 
10482         // than default extent but != 0, it's OK) 
10483         extentMax 
= calcRows 
? GetDefaultRowLabelSize() 
10484                              : GetDefaultColLabelSize(); 
10487     // leave some space around text (taken from AutoSizeColOrRow) 
10496 int wxGrid::SetOrCalcColumnSizes(bool calcOnly
, bool setAsMin
) 
10498     int width 
= m_rowLabelWidth
; 
10500     wxGridUpdateLocker locker
; 
10502         locker
.Create(this); 
10504     for ( int col 
= 0; col 
< m_numCols
; col
++ ) 
10507             AutoSizeColumn(col
, setAsMin
); 
10509         width 
+= GetColWidth(col
); 
10515 int wxGrid::SetOrCalcRowSizes(bool calcOnly
, bool setAsMin
) 
10517     int height 
= m_colLabelHeight
; 
10519     wxGridUpdateLocker locker
; 
10521         locker
.Create(this); 
10523     for ( int row 
= 0; row 
< m_numRows
; row
++ ) 
10526             AutoSizeRow(row
, setAsMin
); 
10528         height 
+= GetRowHeight(row
); 
10534 void wxGrid::AutoSize() 
10536     wxGridUpdateLocker 
locker(this); 
10538     wxSize 
size(SetOrCalcColumnSizes(false) - m_rowLabelWidth 
+ m_extraWidth
, 
10539                 SetOrCalcRowSizes(false) - m_colLabelHeight 
+ m_extraHeight
); 
10541     // we know that we're not going to have scrollbars so disable them now to 
10542     // avoid trouble in SetClientSize() which can otherwise set the correct 
10543     // client size but also leave space for (not needed any more) scrollbars 
10544     SetScrollbars(0, 0, 0, 0, 0, 0, true); 
10546     // restore the scroll rate parameters overwritten by SetScrollbars() 
10547     SetScrollRate(m_scrollLineX
, m_scrollLineY
); 
10549     SetClientSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
); 
10552 void wxGrid::AutoSizeRowLabelSize( int row 
) 
10554     // Hide the edit control, so it 
10555     // won't interfere with drag-shrinking. 
10556     if ( IsCellEditControlShown() ) 
10558         HideCellEditControl(); 
10559         SaveEditControlValue(); 
10562     // autosize row height depending on label text 
10563     SetRowSize(row
, -1); 
10567 void wxGrid::AutoSizeColLabelSize( int col 
) 
10569     // Hide the edit control, so it 
10570     // won't interfere with drag-shrinking. 
10571     if ( IsCellEditControlShown() ) 
10573         HideCellEditControl(); 
10574         SaveEditControlValue(); 
10577     // autosize column width depending on label text 
10578     SetColSize(col
, -1); 
10582 wxSize 
wxGrid::DoGetBestSize() const 
10584     wxGrid 
*self 
= (wxGrid 
*)this;  // const_cast 
10586     // we do the same as in AutoSize() here with the exception that we don't 
10587     // change the column/row sizes, only calculate them 
10588     wxSize 
size(self
->SetOrCalcColumnSizes(true) - m_rowLabelWidth 
+ m_extraWidth
, 
10589                 self
->SetOrCalcRowSizes(true) - m_colLabelHeight 
+ m_extraHeight
); 
10591     // NOTE: This size should be cached, but first we need to add calls to 
10592     // InvalidateBestSize everywhere that could change the results of this 
10594     // CacheBestSize(size); 
10596     return wxSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
) 
10597             + GetWindowBorderSize(); 
10605 wxPen
& wxGrid::GetDividerPen() const 
10610 // ---------------------------------------------------------------------------- 
10611 // cell value accessor functions 
10612 // ---------------------------------------------------------------------------- 
10614 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s 
) 
10618         m_table
->SetValue( row
, col
, s 
); 
10619         if ( !GetBatchCount() ) 
10622             wxRect 
rect( CellToRect( row
, col 
) ); 
10624             rect
.width 
= m_gridWin
->GetClientSize().GetWidth(); 
10625             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
10626             m_gridWin
->Refresh( false, &rect 
); 
10629         if ( m_currentCellCoords
.GetRow() == row 
&& 
10630              m_currentCellCoords
.GetCol() == col 
&& 
10631              IsCellEditControlShown()) 
10632              // Note: If we are using IsCellEditControlEnabled, 
10633              // this interacts badly with calling SetCellValue from 
10634              // an EVT_GRID_CELL_CHANGE handler. 
10636             HideCellEditControl(); 
10637             ShowCellEditControl(); // will reread data from table 
10642 // ---------------------------------------------------------------------------- 
10643 // block, row and column selection 
10644 // ---------------------------------------------------------------------------- 
10646 void wxGrid::SelectRow( int row
, bool addToSelected 
) 
10648     if ( !m_selection 
) 
10651     if ( !addToSelected 
) 
10654     m_selection
->SelectRow(row
); 
10657 void wxGrid::SelectCol( int col
, bool addToSelected 
) 
10659     if ( !m_selection 
) 
10662     if ( !addToSelected 
) 
10665     m_selection
->SelectCol(col
); 
10668 void wxGrid::SelectBlock(int topRow
, int leftCol
, int bottomRow
, int rightCol
, 
10669                          bool addToSelected
) 
10671     if ( !m_selection 
) 
10674     if ( !addToSelected 
) 
10677     m_selection
->SelectBlock(topRow
, leftCol
, bottomRow
, rightCol
); 
10680 void wxGrid::SelectAll() 
10682     if ( m_numRows 
> 0 && m_numCols 
> 0 ) 
10685             m_selection
->SelectBlock( 0, 0, m_numRows 
- 1, m_numCols 
- 1 ); 
10689 // ---------------------------------------------------------------------------- 
10690 // cell, row and col deselection 
10691 // ---------------------------------------------------------------------------- 
10693 void wxGrid::DeselectLine(int line
, const wxGridOperations
& oper
) 
10695     if ( !m_selection 
) 
10698     const wxGridSelectionModes mode 
= m_selection
->GetSelectionMode(); 
10699     if ( mode 
== oper
.GetSelectionMode() ) 
10701         const wxGridCellCoords 
c(oper
.MakeCoords(line
, 0)); 
10702         if ( m_selection
->IsInSelection(c
) ) 
10703             m_selection
->ToggleCellSelection(c
); 
10705     else if ( mode 
!= oper
.Dual().GetSelectionMode() ) 
10707         const int nOther 
= oper
.Dual().GetNumberOfLines(this); 
10708         for ( int i 
= 0; i 
< nOther
; i
++ ) 
10710             const wxGridCellCoords 
c(oper
.MakeCoords(line
, i
)); 
10711             if ( m_selection
->IsInSelection(c
) ) 
10712                 m_selection
->ToggleCellSelection(c
); 
10715     //else: can only select orthogonal lines so no lines in this direction 
10716     //      could have been selected anyhow 
10719 void wxGrid::DeselectRow(int row
) 
10721     DeselectLine(row
, wxGridRowOperations()); 
10724 void wxGrid::DeselectCol(int col
) 
10726     DeselectLine(col
, wxGridColumnOperations()); 
10729 void wxGrid::DeselectCell( int row
, int col 
) 
10731     if ( m_selection 
&& m_selection
->IsInSelection(row
, col
) ) 
10732         m_selection
->ToggleCellSelection(row
, col
); 
10735 bool wxGrid::IsSelection() const 
10737     return ( m_selection 
&& (m_selection
->IsSelection() || 
10738              ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
10739                m_selectedBlockBottomRight 
!= wxGridNoCellCoords
) ) ); 
10742 bool wxGrid::IsInSelection( int row
, int col 
) const 
10744     return ( m_selection 
&& (m_selection
->IsInSelection( row
, col 
) || 
10745              ( row 
>= m_selectedBlockTopLeft
.GetRow() && 
10746                col 
>= m_selectedBlockTopLeft
.GetCol() && 
10747                row 
<= m_selectedBlockBottomRight
.GetRow() && 
10748                col 
<= m_selectedBlockBottomRight
.GetCol() )) ); 
10751 wxGridCellCoordsArray 
wxGrid::GetSelectedCells() const 
10755         wxGridCellCoordsArray a
; 
10759     return m_selection
->m_cellSelection
; 
10762 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockTopLeft() const 
10766         wxGridCellCoordsArray a
; 
10770     return m_selection
->m_blockSelectionTopLeft
; 
10773 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockBottomRight() const 
10777         wxGridCellCoordsArray a
; 
10781     return m_selection
->m_blockSelectionBottomRight
; 
10784 wxArrayInt 
wxGrid::GetSelectedRows() const 
10792     return m_selection
->m_rowSelection
; 
10795 wxArrayInt 
wxGrid::GetSelectedCols() const 
10803     return m_selection
->m_colSelection
; 
10806 void wxGrid::ClearSelection() 
10808     wxRect r1 
= BlockToDeviceRect(m_selectedBlockTopLeft
, 
10809                                   m_selectedBlockBottomRight
); 
10810     wxRect r2 
= BlockToDeviceRect(m_currentCellCoords
, 
10811                                   m_selectedBlockCorner
); 
10813     m_selectedBlockTopLeft 
= 
10814     m_selectedBlockBottomRight 
= 
10815     m_selectedBlockCorner 
= wxGridNoCellCoords
; 
10817     Refresh( false, &r1 
); 
10818     Refresh( false, &r2 
); 
10821         m_selection
->ClearSelection(); 
10824 // This function returns the rectangle that encloses the given block 
10825 // in device coords clipped to the client size of the grid window. 
10827 wxRect 
wxGrid::BlockToDeviceRect( const wxGridCellCoords
& topLeft
, 
10828                                   const wxGridCellCoords
& bottomRight 
) const 
10831     wxRect tempCellRect 
= CellToRect(topLeft
); 
10832     if ( tempCellRect 
!= wxGridNoCellRect 
) 
10834         resultRect 
= tempCellRect
; 
10838         resultRect 
= wxRect(0, 0, 0, 0); 
10841     tempCellRect 
= CellToRect(bottomRight
); 
10842     if ( tempCellRect 
!= wxGridNoCellRect 
) 
10844         resultRect 
+= tempCellRect
; 
10848         // If both inputs were "wxGridNoCellRect," then there's nothing to do. 
10849         return wxGridNoCellRect
; 
10852     // Ensure that left/right and top/bottom pairs are in order. 
10853     int left 
= resultRect
.GetLeft(); 
10854     int top 
= resultRect
.GetTop(); 
10855     int right 
= resultRect
.GetRight(); 
10856     int bottom 
= resultRect
.GetBottom(); 
10858     int leftCol 
= topLeft
.GetCol(); 
10859     int topRow 
= topLeft
.GetRow(); 
10860     int rightCol 
= bottomRight
.GetCol(); 
10861     int bottomRow 
= bottomRight
.GetRow(); 
10870         leftCol 
= rightCol
; 
10881         topRow 
= bottomRow
; 
10885     // The following loop is ONLY necessary to detect and handle merged cells. 
10887     m_gridWin
->GetClientSize( &cw
, &ch 
); 
10889     // Get the origin coordinates: notice that they will be negative if the 
10890     // grid is scrolled downwards/to the right. 
10891     int gridOriginX 
= 0; 
10892     int gridOriginY 
= 0; 
10893     CalcScrolledPosition(gridOriginX
, gridOriginY
, &gridOriginX
, &gridOriginY
); 
10895     int onScreenLeftmostCol 
= internalXToCol(-gridOriginX
); 
10896     int onScreenUppermostRow 
= internalYToRow(-gridOriginY
); 
10898     int onScreenRightmostCol 
= internalXToCol(-gridOriginX 
+ cw
); 
10899     int onScreenBottommostRow 
= internalYToRow(-gridOriginY 
+ ch
); 
10901     // Bound our loop so that we only examine the portion of the selected block 
10902     // that is shown on screen. Therefore, we compare the Top-Left block values 
10903     // to the Top-Left screen values, and the Bottom-Right block values to the 
10904     // Bottom-Right screen values, choosing appropriately. 
10905     const int visibleTopRow 
= wxMax(topRow
, onScreenUppermostRow
); 
10906     const int visibleBottomRow 
= wxMin(bottomRow
, onScreenBottommostRow
); 
10907     const int visibleLeftCol 
= wxMax(leftCol
, onScreenLeftmostCol
); 
10908     const int visibleRightCol 
= wxMin(rightCol
, onScreenRightmostCol
); 
10910     for ( int j 
= visibleTopRow
; j 
<= visibleBottomRow
; j
++ ) 
10912         for ( int i 
= visibleLeftCol
; i 
<= visibleRightCol
; i
++ ) 
10914             if ( (j 
== visibleTopRow
) || (j 
== visibleBottomRow
) || 
10915                     (i 
== visibleLeftCol
) || (i 
== visibleRightCol
) ) 
10917                 tempCellRect 
= CellToRect( j
, i 
); 
10919                 if (tempCellRect
.x 
< left
) 
10920                     left 
= tempCellRect
.x
; 
10921                 if (tempCellRect
.y 
< top
) 
10922                     top 
= tempCellRect
.y
; 
10923                 if (tempCellRect
.x 
+ tempCellRect
.width 
> right
) 
10924                     right 
= tempCellRect
.x 
+ tempCellRect
.width
; 
10925                 if (tempCellRect
.y 
+ tempCellRect
.height 
> bottom
) 
10926                     bottom 
= tempCellRect
.y 
+ tempCellRect
.height
; 
10930                 i 
= visibleRightCol
; // jump over inner cells. 
10935     // Convert to scrolled coords 
10936     CalcScrolledPosition( left
, top
, &left
, &top 
); 
10937     CalcScrolledPosition( right
, bottom
, &right
, &bottom 
); 
10939     if (right 
< 0 || bottom 
< 0 || left 
> cw 
|| top 
> ch
) 
10940         return wxRect(0,0,0,0); 
10942     resultRect
.SetLeft( wxMax(0, left
) ); 
10943     resultRect
.SetTop( wxMax(0, top
) ); 
10944     resultRect
.SetRight( wxMin(cw
, right
) ); 
10945     resultRect
.SetBottom( wxMin(ch
, bottom
) ); 
10950 // ---------------------------------------------------------------------------- 
10952 // ---------------------------------------------------------------------------- 
10954 #if wxUSE_DRAG_AND_DROP 
10956 // this allow setting drop target directly on wxGrid 
10957 void wxGrid::SetDropTarget(wxDropTarget 
*dropTarget
) 
10959     GetGridWindow()->SetDropTarget(dropTarget
); 
10962 #endif // wxUSE_DRAG_AND_DROP 
10964 // ---------------------------------------------------------------------------- 
10965 // grid event classes 
10966 // ---------------------------------------------------------------------------- 
10968 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxNotifyEvent 
) 
10970 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
, 
10971                           int row
, int col
, int x
, int y
, bool sel
, 
10972                           bool control
, bool shift
, bool alt
, bool meta 
) 
10973         : wxNotifyEvent( type
, id 
), 
10974           wxKeyboardState(control
, shift
, alt
, meta
) 
10976     Init(row
, col
, x
, y
, sel
); 
10978     SetEventObject(obj
); 
10981 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxNotifyEvent 
) 
10983 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
, 
10984                                   int rowOrCol
, int x
, int y
, 
10985                                   bool control
, bool shift
, bool alt
, bool meta 
) 
10986         : wxNotifyEvent( type
, id 
), 
10987           wxKeyboardState(control
, shift
, alt
, meta
) 
10989     Init(rowOrCol
, x
, y
); 
10991     SetEventObject(obj
); 
10995 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxNotifyEvent 
) 
10997 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
, 
10998                                                const wxGridCellCoords
& topLeft
, 
10999                                                const wxGridCellCoords
& bottomRight
, 
11000                                                bool sel
, bool control
, 
11001                                                bool shift
, bool alt
, bool meta 
) 
11002         : wxNotifyEvent( type
, id 
), 
11003           wxKeyboardState(control
, shift
, alt
, meta
) 
11005     Init(topLeft
, bottomRight
, sel
); 
11007     SetEventObject(obj
); 
11011 IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent
, wxCommandEvent
) 
11013 wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id
, wxEventType type
, 
11014                                                    wxObject
* obj
, int row
, 
11015                                                    int col
, wxControl
* ctrl
) 
11016     : wxCommandEvent(type
, id
) 
11018     SetEventObject(obj
); 
11024 #endif // wxUSE_GRID