1 /////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/grid.cpp 
   3 // Purpose:     wxGrid and related classes 
   4 // Author:      Michael Bedward (based on code by Julian Smart, Robin Dunn) 
   5 // Modified by: Robin Dunn, Vadim Zeitlin, Santiago Palacios 
   8 // Copyright:   (c) Michael Bedward (mbedward@ozemail.com.au) 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  15     - Replace use of wxINVERT with wxOverlay 
  16     - Make Begin/EndBatch() the same as the generic Freeze/Thaw() 
  17     - Review the column reordering code, it's a mess. 
  18     - Implement row reordering after dealing with the columns. 
  21 // For compilers that support precompilation, includes "wx/wx.h". 
  22 #include "wx/wxprec.h" 
  34     #include "wx/dcclient.h" 
  35     #include "wx/settings.h" 
  37     #include "wx/textctrl.h" 
  38     #include "wx/checkbox.h" 
  39     #include "wx/combobox.h" 
  40     #include "wx/valtext.h" 
  43     #include "wx/listbox.h" 
  46 #include "wx/textfile.h" 
  47 #include "wx/spinctrl.h" 
  48 #include "wx/tokenzr.h" 
  49 #include "wx/renderer.h" 
  50 #include "wx/headerctrl.h" 
  52 #include "wx/generic/gridsel.h" 
  54 const char wxGridNameStr
[] = "grid"; 
  56 #if defined(__WXMOTIF__) 
  57     #define WXUNUSED_MOTIF(identifier)  WXUNUSED(identifier) 
  59     #define WXUNUSED_MOTIF(identifier)  identifier 
  62 #if defined(__WXGTK__) 
  63     #define WXUNUSED_GTK(identifier)    WXUNUSED(identifier) 
  65     #define WXUNUSED_GTK(identifier)    identifier 
  68 // Required for wxIs... functions 
  71 // ---------------------------------------------------------------------------- 
  73 // ---------------------------------------------------------------------------- 
  75 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridCellAttr 
*, wxArrayAttrs
, 
  76                                  class WXDLLIMPEXP_ADV
); 
  78 struct wxGridCellWithAttr
 
  80     wxGridCellWithAttr(int row
, int col
, wxGridCellAttr 
*attr_
) 
  81         : coords(row
, col
), attr(attr_
) 
  86     wxGridCellWithAttr(const wxGridCellWithAttr
& other
) 
  87         : coords(other
.coords
), 
  93     wxGridCellWithAttr
& operator=(const wxGridCellWithAttr
& other
) 
  95         coords 
= other
.coords
; 
  96         if (attr 
!= other
.attr
) 
 105     void ChangeAttr(wxGridCellAttr
* new_attr
) 
 107         if (attr 
!= new_attr
) 
 109             // "Delete" (i.e. DecRef) the old attribute. 
 112             // Take ownership of the new attribute, i.e. no IncRef. 
 116     ~wxGridCellWithAttr() 
 121     wxGridCellCoords coords
; 
 122     wxGridCellAttr  
*attr
; 
 125 WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellWithAttr
, wxGridCellWithAttrArray
, 
 126                               class WXDLLIMPEXP_ADV
); 
 128 #include "wx/arrimpl.cpp" 
 130 WX_DEFINE_OBJARRAY(wxGridCellCoordsArray
) 
 131 WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray
) 
 133 // ---------------------------------------------------------------------------- 
 135 // ---------------------------------------------------------------------------- 
 137 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK
) 
 138 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK
) 
 139 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK
) 
 140 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK
) 
 141 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_BEGIN_DRAG
) 
 142 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK
) 
 143 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK
) 
 144 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK
) 
 145 DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK
) 
 146 DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE
) 
 147 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE
) 
 148 DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE
) 
 149 DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT
) 
 150 DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE
) 
 151 DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL
) 
 152 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN
) 
 153 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN
) 
 154 DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED
) 
 156 // ---------------------------------------------------------------------------- 
 158 // ---------------------------------------------------------------------------- 
 160 // header column providing access to the column information stored in wxGrid 
 161 // via wxHeaderColumn interface 
 162 class wxGridHeaderColumn 
: public wxHeaderColumn
 
 165     wxGridHeaderColumn(wxGrid 
*grid
, int col
) 
 171     virtual wxString 
GetTitle() const { return m_grid
->GetColLabelValue(m_col
); } 
 172     virtual wxBitmap 
GetBitmap() const { return wxNullBitmap
; } 
 173     virtual int GetWidth() const { return m_grid
->GetColSize(m_col
); } 
 174     virtual int GetMinWidth() const { return 0; } 
 175     virtual wxAlignment 
GetAlignment() const 
 179         m_grid
->GetColLabelAlignment(&horz
, &vert
); 
 181         return static_cast<wxAlignment
>(horz
); 
 184     virtual int GetFlags() const 
 187         if ( m_grid
->CanDragColSize() ) 
 188             flags 
|= wxCOL_RESIZABLE
; 
 189         if ( m_grid
->CanDragColMove() ) 
 190             flags 
|= wxCOL_REORDERABLE
; 
 195     // TODO: currently there is no support for sorting 
 196     virtual bool IsSortKey() const { return false; } 
 197     virtual bool IsSortOrderAscending() const { return false; } 
 200     wxGrid 
* const m_grid
; 
 204 // header control retreiving column information from the grid 
 205 class wxGridHeaderCtrl 
: public wxHeaderCtrl
 
 208     wxGridHeaderCtrl(wxGrid 
*owner
) 
 209         : wxHeaderCtrl(owner
, 
 213                        owner
->CanDragColMove() ? wxHD_DRAGDROP 
: 0) 
 218     virtual wxHeaderColumn
& GetColumn(unsigned int idx
) 
 220         return m_columns
[idx
]; 
 224     wxGrid 
*GetOwner() const { return static_cast<wxGrid 
*>(GetParent()); } 
 226     // override the base class method to update our m_columns array 
 227     virtual void OnColumnCountChanging(unsigned int count
) 
 229         const unsigned countOld 
= m_columns
.size(); 
 230         if ( count 
< countOld 
) 
 232             // just discard the columns which don't exist any more (notice that 
 233             // we can't use resize() here as it would require the vector 
 234             // value_type, i.e. wxGridHeaderColumn to be default constructible, 
 236             m_columns
.erase(m_columns
.begin() + count
, m_columns
.end()); 
 238         else // new columns added 
 240             // add columns for the new elements 
 241             for ( unsigned n 
= countOld
; n 
< count
; n
++ ) 
 242                 m_columns
.push_back(wxGridHeaderColumn(GetOwner(), n
)); 
 246     // override to implement column auto sizing 
 247     virtual bool UpdateColumnWidthToFit(unsigned int idx
, int widthTitle
) 
 249         GetOwner()->SetColSize(idx
, widthTitle
); 
 255     // event handlers forwarding wxHeaderCtrl events to wxGrid 
 256     void OnBeginResize(wxHeaderCtrlEvent
& event
) 
 258         GetOwner()->DoStartResizeCol(event
.GetColumn()); 
 263     void OnResizing(wxHeaderCtrlEvent
& event
) 
 265         GetOwner()->DoUpdateResizeColWidth(event
.GetWidth()); 
 268     void OnEndResize(wxHeaderCtrlEvent
& event
) 
 270         GetOwner()->DoEndDragResizeCol(); 
 275     void OnEndReorder(wxHeaderCtrlEvent
& event
) 
 277         event
.Skip(); // TODO: position it at event.GetNewOrder() 
 280     wxVector
<wxGridHeaderColumn
> m_columns
; 
 282     DECLARE_EVENT_TABLE() 
 283     DECLARE_NO_COPY_CLASS(wxGridHeaderCtrl
) 
 286 BEGIN_EVENT_TABLE(wxGridHeaderCtrl
, wxHeaderCtrl
) 
 287     EVT_HEADER_BEGIN_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnBeginResize
) 
 288     EVT_HEADER_RESIZING(wxID_ANY
, wxGridHeaderCtrl::OnResizing
) 
 289     EVT_HEADER_END_RESIZE(wxID_ANY
, wxGridHeaderCtrl::OnEndResize
) 
 291     EVT_HEADER_END_REORDER(wxID_ANY
, wxGridHeaderCtrl::OnEndReorder
) 
 294 // common base class for various grid subwindows 
 295 class WXDLLIMPEXP_ADV wxGridSubwindow 
: public wxWindow
 
 298     wxGridSubwindow(wxGrid 
*owner
, 
 299                     int additionalStyle 
= 0, 
 300                     const wxString
& name 
= wxPanelNameStr
) 
 301         : wxWindow(owner
, wxID_ANY
, 
 302                    wxDefaultPosition
, wxDefaultSize
, 
 303                    wxBORDER_NONE 
| additionalStyle
, 
 309     virtual bool AcceptsFocus() const { return false; } 
 311     wxGrid 
*GetOwner() { return m_owner
; } 
 314     void OnMouseCaptureLost(wxMouseCaptureLostEvent
& event
); 
 318     DECLARE_EVENT_TABLE() 
 319     DECLARE_NO_COPY_CLASS(wxGridSubwindow
) 
 322 class WXDLLIMPEXP_ADV wxGridRowLabelWindow 
: public wxGridSubwindow
 
 325     wxGridRowLabelWindow(wxGrid 
*parent
) 
 326       : wxGridSubwindow(parent
) 
 332     void OnPaint( wxPaintEvent
& event 
); 
 333     void OnMouseEvent( wxMouseEvent
& event 
); 
 334     void OnMouseWheel( wxMouseEvent
& event 
); 
 336     DECLARE_EVENT_TABLE() 
 337     DECLARE_NO_COPY_CLASS(wxGridRowLabelWindow
) 
 341 class WXDLLIMPEXP_ADV wxGridColLabelWindow 
: public wxGridSubwindow
 
 344     wxGridColLabelWindow(wxGrid 
*parent
) 
 345         : wxGridSubwindow(parent
) 
 351     void OnPaint( wxPaintEvent
& event 
); 
 352     void OnMouseEvent( wxMouseEvent
& event 
); 
 353     void OnMouseWheel( wxMouseEvent
& event 
); 
 355     DECLARE_EVENT_TABLE() 
 356     DECLARE_NO_COPY_CLASS(wxGridColLabelWindow
) 
 360 class WXDLLIMPEXP_ADV wxGridCornerLabelWindow 
: public wxGridSubwindow
 
 363     wxGridCornerLabelWindow(wxGrid 
*parent
) 
 364         : wxGridSubwindow(parent
) 
 369     void OnMouseEvent( wxMouseEvent
& event 
); 
 370     void OnMouseWheel( wxMouseEvent
& event 
); 
 371     void OnPaint( wxPaintEvent
& event 
); 
 373     DECLARE_EVENT_TABLE() 
 374     DECLARE_NO_COPY_CLASS(wxGridCornerLabelWindow
) 
 377 class WXDLLIMPEXP_ADV wxGridWindow 
: public wxGridSubwindow
 
 380     wxGridWindow(wxGrid 
*parent
) 
 381         : wxGridSubwindow(parent
, 
 382                           wxWANTS_CHARS 
| wxCLIP_CHILDREN
, 
 388     virtual void ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
); 
 390     virtual bool AcceptsFocus() const { return true; } 
 393     void OnPaint( wxPaintEvent 
&event 
); 
 394     void OnMouseWheel( wxMouseEvent
& event 
); 
 395     void OnMouseEvent( wxMouseEvent
& event 
); 
 396     void OnKeyDown( wxKeyEvent
& ); 
 397     void OnKeyUp( wxKeyEvent
& ); 
 398     void OnChar( wxKeyEvent
& ); 
 399     void OnEraseBackground( wxEraseEvent
& ); 
 400     void OnFocus( wxFocusEvent
& ); 
 402     DECLARE_EVENT_TABLE() 
 403     DECLARE_NO_COPY_CLASS(wxGridWindow
) 
 407 class wxGridCellEditorEvtHandler 
: public wxEvtHandler
 
 410     wxGridCellEditorEvtHandler(wxGrid
* grid
, wxGridCellEditor
* editor
) 
 417     void OnKillFocus(wxFocusEvent
& event
); 
 418     void OnKeyDown(wxKeyEvent
& event
); 
 419     void OnChar(wxKeyEvent
& event
); 
 421     void SetInSetFocus(bool inSetFocus
) { m_inSetFocus 
= inSetFocus
; } 
 425     wxGridCellEditor   
*m_editor
; 
 427     // Work around the fact that a focus kill event can be sent to 
 428     // a combobox within a set focus event. 
 431     DECLARE_EVENT_TABLE() 
 432     DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler
) 
 433     DECLARE_NO_COPY_CLASS(wxGridCellEditorEvtHandler
) 
 437 IMPLEMENT_ABSTRACT_CLASS(wxGridCellEditorEvtHandler
, wxEvtHandler
) 
 439 BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler
, wxEvtHandler 
) 
 440     EVT_KILL_FOCUS( wxGridCellEditorEvtHandler::OnKillFocus 
) 
 441     EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown 
) 
 442     EVT_CHAR( wxGridCellEditorEvtHandler::OnChar 
) 
 446 // ---------------------------------------------------------------------------- 
 447 // the internal data representation used by wxGridCellAttrProvider 
 448 // ---------------------------------------------------------------------------- 
 450 // this class stores attributes set for cells 
 451 class WXDLLIMPEXP_ADV wxGridCellAttrData
 
 454     void SetAttr(wxGridCellAttr 
*attr
, int row
, int col
); 
 455     wxGridCellAttr 
*GetAttr(int row
, int col
) const; 
 456     void UpdateAttrRows( size_t pos
, int numRows 
); 
 457     void UpdateAttrCols( size_t pos
, int numCols 
); 
 460     // searches for the attr for given cell, returns wxNOT_FOUND if not found 
 461     int FindIndex(int row
, int col
) const; 
 463     wxGridCellWithAttrArray m_attrs
; 
 466 // this class stores attributes set for rows or columns 
 467 class WXDLLIMPEXP_ADV wxGridRowOrColAttrData
 
 470     // empty ctor to suppress warnings 
 471     wxGridRowOrColAttrData() {} 
 472     ~wxGridRowOrColAttrData(); 
 474     void SetAttr(wxGridCellAttr 
*attr
, int rowOrCol
); 
 475     wxGridCellAttr 
*GetAttr(int rowOrCol
) const; 
 476     void UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols 
); 
 479     wxArrayInt m_rowsOrCols
; 
 480     wxArrayAttrs m_attrs
; 
 483 // NB: this is just a wrapper around 3 objects: one which stores cell 
 484 //     attributes, and 2 others for row/col ones 
 485 class WXDLLIMPEXP_ADV wxGridCellAttrProviderData
 
 488     wxGridCellAttrData m_cellAttrs
; 
 489     wxGridRowOrColAttrData m_rowAttrs
, 
 494 // ---------------------------------------------------------------------------- 
 495 // data structures used for the data type registry 
 496 // ---------------------------------------------------------------------------- 
 498 struct wxGridDataTypeInfo
 
 500     wxGridDataTypeInfo(const wxString
& typeName
, 
 501                        wxGridCellRenderer
* renderer
, 
 502                        wxGridCellEditor
* editor
) 
 503         : m_typeName(typeName
), m_renderer(renderer
), m_editor(editor
) 
 506     ~wxGridDataTypeInfo() 
 508         wxSafeDecRef(m_renderer
); 
 509         wxSafeDecRef(m_editor
); 
 513     wxGridCellRenderer
* m_renderer
; 
 514     wxGridCellEditor
*   m_editor
; 
 516     DECLARE_NO_COPY_CLASS(wxGridDataTypeInfo
) 
 520 WX_DEFINE_ARRAY_WITH_DECL_PTR(wxGridDataTypeInfo
*, wxGridDataTypeInfoArray
, 
 521                                  class WXDLLIMPEXP_ADV
); 
 524 class WXDLLIMPEXP_ADV wxGridTypeRegistry
 
 527     wxGridTypeRegistry() {} 
 528     ~wxGridTypeRegistry(); 
 530     void RegisterDataType(const wxString
& typeName
, 
 531                      wxGridCellRenderer
* renderer
, 
 532                      wxGridCellEditor
* editor
); 
 534     // find one of already registered data types 
 535     int FindRegisteredDataType(const wxString
& typeName
); 
 537     // try to FindRegisteredDataType(), if this fails and typeName is one of 
 538     // standard typenames, register it and return its index 
 539     int FindDataType(const wxString
& typeName
); 
 541     // try to FindDataType(), if it fails see if it is not one of already 
 542     // registered data types with some params in which case clone the 
 543     // registered data type and set params for it 
 544     int FindOrCloneDataType(const wxString
& typeName
); 
 546     wxGridCellRenderer
* GetRenderer(int index
); 
 547     wxGridCellEditor
*   GetEditor(int index
); 
 550     wxGridDataTypeInfoArray m_typeinfo
; 
 553 // ---------------------------------------------------------------------------- 
 554 // operations classes abstracting the difference between operating on rows and 
 556 // ---------------------------------------------------------------------------- 
 558 // This class allows to write a function only once because by using its methods 
 559 // it will apply to both columns and rows. 
 561 // This is an abstract interface definition, the two concrete implementations 
 562 // below should be used when working with rows and columns respectively. 
 563 class wxGridOperations
 
 566     // Returns the operations in the other direction, i.e. wxGridRowOperations 
 567     // if this object is a wxGridColumnOperations and vice versa. 
 568     virtual wxGridOperations
& Dual() const = 0; 
 570     // Return the number of rows or columns. 
 571     virtual int GetNumberOfLines(const wxGrid 
*grid
) const = 0; 
 573     // Return the selection mode which allows selecting rows or columns. 
 574     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const = 0; 
 576     // Make a wxGridCellCoords from the given components: thisDir is row or 
 577     // column and otherDir is column or row 
 578     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const = 0; 
 580     // Calculate the scrolled position of the given abscissa or ordinate. 
 581     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const = 0; 
 583     // Selects the horizontal or vertical component from the given object. 
 584     virtual int Select(const wxGridCellCoords
& coords
) const = 0; 
 585     virtual int Select(const wxPoint
& pt
) const = 0; 
 586     virtual int Select(const wxSize
& sz
) const = 0; 
 587     virtual int Select(const wxRect
& r
) const = 0; 
 588     virtual int& Select(wxRect
& r
) const = 0; 
 590     // Returns width or height of the rectangle 
 591     virtual int& SelectSize(wxRect
& r
) const = 0; 
 593     // Make a wxSize such that Select() applied to it returns first component 
 594     virtual wxSize 
MakeSize(int first
, int second
) const = 0; 
 596     // Sets the row or column component of the given cell coordinates 
 597     virtual void Set(wxGridCellCoords
& coords
, int line
) const = 0; 
 600     // Draws a line parallel to the row or column, i.e. horizontal or vertical: 
 601     // pos is the horizontal or vertical position of the line and start and end 
 602     // are the coordinates of the line extremities in the other direction 
 604         DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const = 0; 
 606     // Draw a horizontal or vertical line across the given rectangle 
 607     // (this is implemented in terms of above and uses Select() to extract 
 608     // start and end from the given rectangle) 
 609     void DrawParallelLineInRect(wxDC
& dc
, const wxRect
& rect
, int pos
) const 
 611         const int posStart 
= Select(rect
.GetPosition()); 
 612         DrawParallelLine(dc
, posStart
, posStart 
+ Select(rect
.GetSize()), pos
); 
 616     // Return the row or column at the given pixel coordinate. 
 618         PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const = 0; 
 620     // Get the top/left position, in pixels, of the given row or column 
 621     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const = 0; 
 623     // Get the bottom/right position, in pixels, of the given row or column 
 624     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const = 0; 
 626     // Get the height/width of the given row/column 
 627     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const = 0; 
 629     // Get wxGrid::m_rowBottoms/m_colRights array 
 630     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const = 0; 
 632     // Get default height row height or column width 
 633     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const = 0; 
 635     // Return the minimal acceptable row height or column width 
 636     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const = 0; 
 638     // Return the minimal row height or column width 
 639     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const = 0; 
 641     // Set the row height or column width 
 642     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const = 0; 
 644     // True if rows/columns can be resized by user 
 645     virtual bool CanResizeLines(const wxGrid 
*grid
) const = 0; 
 648     // Return the index of the line at the given position 
 650     // NB: currently this is always identity for the rows as reordering is only 
 651     //     implemented for the lines 
 652     virtual int GetLineAt(const wxGrid 
*grid
, int line
) const = 0; 
 655     // Get the row or column label window 
 656     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const = 0; 
 658     // Get the width or height of the row or column label window 
 659     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const = 0; 
 662     // This class is never used polymorphically but give it a virtual dtor 
 663     // anyhow to suppress g++ complaints about it 
 664     virtual ~wxGridOperations() { } 
 667 class wxGridRowOperations 
: public wxGridOperations
 
 670     virtual wxGridOperations
& Dual() const; 
 672     virtual int GetNumberOfLines(const wxGrid 
*grid
) const 
 673         { return grid
->GetNumberRows(); } 
 675     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const 
 676         { return wxGrid::wxGridSelectRows
; } 
 678     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const 
 679         { return wxGridCellCoords(thisDir
, otherDir
); } 
 681     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const 
 682         { return grid
->CalcScrolledPosition(wxPoint(pos
, 0)).x
; } 
 684     virtual int Select(const wxGridCellCoords
& c
) const { return c
.GetRow(); } 
 685     virtual int Select(const wxPoint
& pt
) const { return pt
.x
; } 
 686     virtual int Select(const wxSize
& sz
) const { return sz
.x
; } 
 687     virtual int Select(const wxRect
& r
) const { return r
.x
; } 
 688     virtual int& Select(wxRect
& r
) const { return r
.x
; } 
 689     virtual int& SelectSize(wxRect
& r
) const { return r
.width
; } 
 690     virtual wxSize 
MakeSize(int first
, int second
) const 
 691         { return wxSize(first
, second
); } 
 692     virtual void Set(wxGridCellCoords
& coords
, int line
) const 
 693         { coords
.SetRow(line
); } 
 695     virtual void DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const 
 696         { dc
.DrawLine(start
, pos
, end
, pos
); } 
 698     virtual int PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const 
 699         { return grid
->YToRow(pos
, clip
); } 
 700     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const 
 701         { return grid
->GetRowTop(line
); } 
 702     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const 
 703         { return grid
->GetRowBottom(line
); } 
 704     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const 
 705         { return grid
->GetRowHeight(line
); } 
 706     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const 
 707         { return grid
->m_rowBottoms
; } 
 708     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const 
 709         { return grid
->GetDefaultRowSize(); } 
 710     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const 
 711         { return grid
->GetRowMinimalAcceptableHeight(); } 
 712     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const 
 713         { return grid
->GetRowMinimalHeight(line
); } 
 714     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const 
 715         { grid
->SetRowSize(line
, size
); } 
 716     virtual bool CanResizeLines(const wxGrid 
*grid
) const 
 717         { return grid
->CanDragRowSize(); } 
 719     virtual int GetLineAt(const wxGrid 
* WXUNUSED(grid
), int line
) const 
 720         { return line
; } // TODO: implement row reordering 
 722     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const 
 723         { return grid
->GetGridRowLabelWindow(); } 
 724     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const 
 725         { return grid
->GetRowLabelSize(); } 
 728 class wxGridColumnOperations 
: public wxGridOperations
 
 731     virtual wxGridOperations
& Dual() const; 
 733     virtual int GetNumberOfLines(const wxGrid 
*grid
) const 
 734         { return grid
->GetNumberCols(); } 
 736     virtual wxGrid::wxGridSelectionModes 
GetSelectionMode() const 
 737         { return wxGrid::wxGridSelectColumns
; } 
 739     virtual wxGridCellCoords 
MakeCoords(int thisDir
, int otherDir
) const 
 740         { return wxGridCellCoords(otherDir
, thisDir
); } 
 742     virtual int CalcScrolledPosition(wxGrid 
*grid
, int pos
) const 
 743         { return grid
->CalcScrolledPosition(wxPoint(0, pos
)).y
; } 
 745     virtual int Select(const wxGridCellCoords
& c
) const { return c
.GetCol(); } 
 746     virtual int Select(const wxPoint
& pt
) const { return pt
.y
; } 
 747     virtual int Select(const wxSize
& sz
) const { return sz
.y
; } 
 748     virtual int Select(const wxRect
& r
) const { return r
.y
; } 
 749     virtual int& Select(wxRect
& r
) const { return r
.y
; } 
 750     virtual int& SelectSize(wxRect
& r
) const { return r
.height
; } 
 751     virtual wxSize 
MakeSize(int first
, int second
) const 
 752         { return wxSize(second
, first
); } 
 753     virtual void Set(wxGridCellCoords
& coords
, int line
) const 
 754         { coords
.SetCol(line
); } 
 756     virtual void DrawParallelLine(wxDC
& dc
, int start
, int end
, int pos
) const 
 757         { dc
.DrawLine(pos
, start
, pos
, end
); } 
 759     virtual int PosToLine(const wxGrid 
*grid
, int pos
, bool clip 
= false) const 
 760         { return grid
->XToCol(pos
, clip
); } 
 761     virtual int GetLineStartPos(const wxGrid 
*grid
, int line
) const 
 762         { return grid
->GetColLeft(line
); } 
 763     virtual int GetLineEndPos(const wxGrid 
*grid
, int line
) const 
 764         { return grid
->GetColRight(line
); } 
 765     virtual int GetLineSize(const wxGrid 
*grid
, int line
) const 
 766         { return grid
->GetColWidth(line
); } 
 767     virtual const wxArrayInt
& GetLineEnds(const wxGrid 
*grid
) const 
 768         { return grid
->m_colRights
; } 
 769     virtual int GetDefaultLineSize(const wxGrid 
*grid
) const 
 770         { return grid
->GetDefaultColSize(); } 
 771     virtual int GetMinimalAcceptableLineSize(const wxGrid 
*grid
) const 
 772         { return grid
->GetColMinimalAcceptableWidth(); } 
 773     virtual int GetMinimalLineSize(const wxGrid 
*grid
, int line
) const 
 774         { return grid
->GetColMinimalWidth(line
); } 
 775     virtual void SetLineSize(wxGrid 
*grid
, int line
, int size
) const 
 776         { grid
->SetColSize(line
, size
); } 
 777     virtual bool CanResizeLines(const wxGrid 
*grid
) const 
 778         { return grid
->CanDragColSize(); } 
 780     virtual int GetLineAt(const wxGrid 
*grid
, int line
) const 
 781         { return grid
->GetColAt(line
); } 
 783     virtual wxWindow 
*GetHeaderWindow(wxGrid 
*grid
) const 
 784         { return grid
->GetGridColLabelWindow(); } 
 785     virtual int GetHeaderWindowSize(wxGrid 
*grid
) const 
 786         { return grid
->GetColLabelSize(); } 
 789 wxGridOperations
& wxGridRowOperations::Dual() const 
 791     static wxGridColumnOperations s_colOper
; 
 796 wxGridOperations
& wxGridColumnOperations::Dual() const 
 798     static wxGridRowOperations s_rowOper
; 
 803 // This class abstracts the difference between operations going forward 
 804 // (down/right) and backward (up/left) and allows to use the same code for 
 805 // functions which differ only in the direction of grid traversal 
 807 // Like wxGridOperations it's an ABC with two concrete subclasses below. Unlike 
 808 // it, this is a normal object and not just a function dispatch table and has a 
 811 // Note: the explanation of this discrepancy is the existence of (very useful) 
 812 // Dual() method in wxGridOperations which forces us to make wxGridOperations a 
 813 // function dispatcher only. 
 814 class wxGridDirectionOperations
 
 817     // The oper parameter to ctor selects whether we work with rows or columns 
 818     wxGridDirectionOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 824     // Check if the component of this point in our direction is at the 
 825     // boundary, i.e. is the first/last row/column 
 826     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const = 0; 
 828     // Increment the component of this point in our direction 
 829     virtual void Advance(wxGridCellCoords
& coords
) const = 0; 
 831     // Find the line at the given distance, in pixels, away from this one 
 832     // (this uses clipping, i.e. anything after the last line is counted as the 
 833     // last one and anything before the first one as 0) 
 834     virtual int MoveByPixelDistance(int line
, int distance
) const = 0; 
 836     // This class is never used polymorphically but give it a virtual dtor 
 837     // anyhow to suppress g++ complaints about it 
 838     virtual ~wxGridDirectionOperations() { } 
 841     wxGrid 
* const m_grid
; 
 842     const wxGridOperations
& m_oper
; 
 845 class wxGridBackwardOperations 
: public wxGridDirectionOperations
 
 848     wxGridBackwardOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 849         : wxGridDirectionOperations(grid
, oper
) 
 853     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const 
 855         wxASSERT_MSG( m_oper
.Select(coords
) >= 0, "invalid row/column" ); 
 857         return m_oper
.Select(coords
) == 0; 
 860     virtual void Advance(wxGridCellCoords
& coords
) const 
 862         wxASSERT( !IsAtBoundary(coords
) ); 
 864         m_oper
.Set(coords
, m_oper
.Select(coords
) - 1); 
 867     virtual int MoveByPixelDistance(int line
, int distance
) const 
 869         int pos 
= m_oper
.GetLineStartPos(m_grid
, line
); 
 870         return m_oper
.PosToLine(m_grid
, pos 
- distance 
+ 1, true); 
 874 class wxGridForwardOperations 
: public wxGridDirectionOperations
 
 877     wxGridForwardOperations(wxGrid 
*grid
, const wxGridOperations
& oper
) 
 878         : wxGridDirectionOperations(grid
, oper
), 
 879           m_numLines(oper
.GetNumberOfLines(grid
)) 
 883     virtual bool IsAtBoundary(const wxGridCellCoords
& coords
) const 
 885         wxASSERT_MSG( m_oper
.Select(coords
) < m_numLines
, "invalid row/column" ); 
 887         return m_oper
.Select(coords
) == m_numLines 
- 1; 
 890     virtual void Advance(wxGridCellCoords
& coords
) const 
 892         wxASSERT( !IsAtBoundary(coords
) ); 
 894         m_oper
.Set(coords
, m_oper
.Select(coords
) + 1); 
 897     virtual int MoveByPixelDistance(int line
, int distance
) const 
 899         int pos 
= m_oper
.GetLineStartPos(m_grid
, line
); 
 900         return m_oper
.PosToLine(m_grid
, pos 
+ distance
, true); 
 904     const int m_numLines
; 
 907 // ---------------------------------------------------------------------------- 
 909 // ---------------------------------------------------------------------------- 
 911 //#define DEBUG_ATTR_CACHE 
 912 #ifdef DEBUG_ATTR_CACHE 
 913     static size_t gs_nAttrCacheHits 
= 0; 
 914     static size_t gs_nAttrCacheMisses 
= 0; 
 917 // ---------------------------------------------------------------------------- 
 919 // ---------------------------------------------------------------------------- 
 921 wxGridCellCoords 
wxGridNoCellCoords( -1, -1 ); 
 922 wxRect 
wxGridNoCellRect( -1, -1, -1, -1 ); 
 928 const size_t GRID_SCROLL_LINE_X 
= 15; 
 929 const size_t GRID_SCROLL_LINE_Y 
= GRID_SCROLL_LINE_X
; 
 931 // the size of hash tables used a bit everywhere (the max number of elements 
 932 // in these hash tables is the number of rows/columns) 
 933 const int GRID_HASH_SIZE 
= 100; 
 935 // the minimal distance in pixels the mouse needs to move to start a drag 
 937 const int DRAG_SENSITIVITY 
= 3; 
 939 } // anonymous namespace 
 941 // ---------------------------------------------------------------------------- 
 943 // ---------------------------------------------------------------------------- 
 948 // ensure that first is less or equal to second, swapping the values if 
 950 void EnsureFirstLessThanSecond(int& first
, int& second
) 
 952     if ( first 
> second 
) 
 953         wxSwap(first
, second
); 
 956 } // anonymous namespace 
 958 // ============================================================================ 
 960 // ============================================================================ 
 962 // ---------------------------------------------------------------------------- 
 964 // ---------------------------------------------------------------------------- 
 966 wxGridCellEditor::wxGridCellEditor() 
 972 wxGridCellEditor::~wxGridCellEditor() 
 977 void wxGridCellEditor::Create(wxWindow
* WXUNUSED(parent
), 
 978                               wxWindowID 
WXUNUSED(id
), 
 979                               wxEvtHandler
* evtHandler
) 
 982         m_control
->PushEventHandler(evtHandler
); 
 985 void wxGridCellEditor::PaintBackground(const wxRect
& rectCell
, 
 986                                        wxGridCellAttr 
*attr
) 
 988     // erase the background because we might not fill the cell 
 989     wxClientDC 
dc(m_control
->GetParent()); 
 990     wxGridWindow
* gridWindow 
= wxDynamicCast(m_control
->GetParent(), wxGridWindow
); 
 992         gridWindow
->GetOwner()->PrepareDC(dc
); 
 994     dc
.SetPen(*wxTRANSPARENT_PEN
); 
 995     dc
.SetBrush(wxBrush(attr
->GetBackgroundColour())); 
 996     dc
.DrawRectangle(rectCell
); 
 998     // redraw the control we just painted over 
 999     m_control
->Refresh(); 
1002 void wxGridCellEditor::Destroy() 
1006         m_control
->PopEventHandler( true /* delete it*/ ); 
1008         m_control
->Destroy(); 
1013 void wxGridCellEditor::Show(bool show
, wxGridCellAttr 
*attr
) 
1015     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1017     m_control
->Show(show
); 
1021         // set the colours/fonts if we have any 
1024             m_colFgOld 
= m_control
->GetForegroundColour(); 
1025             m_control
->SetForegroundColour(attr
->GetTextColour()); 
1027             m_colBgOld 
= m_control
->GetBackgroundColour(); 
1028             m_control
->SetBackgroundColour(attr
->GetBackgroundColour()); 
1030 // Workaround for GTK+1 font setting problem on some platforms 
1031 #if !defined(__WXGTK__) || defined(__WXGTK20__) 
1032             m_fontOld 
= m_control
->GetFont(); 
1033             m_control
->SetFont(attr
->GetFont()); 
1036             // can't do anything more in the base class version, the other 
1037             // attributes may only be used by the derived classes 
1042         // restore the standard colours fonts 
1043         if ( m_colFgOld
.Ok() ) 
1045             m_control
->SetForegroundColour(m_colFgOld
); 
1046             m_colFgOld 
= wxNullColour
; 
1049         if ( m_colBgOld
.Ok() ) 
1051             m_control
->SetBackgroundColour(m_colBgOld
); 
1052             m_colBgOld 
= wxNullColour
; 
1055 // Workaround for GTK+1 font setting problem on some platforms 
1056 #if !defined(__WXGTK__) || defined(__WXGTK20__) 
1057         if ( m_fontOld
.Ok() ) 
1059             m_control
->SetFont(m_fontOld
); 
1060             m_fontOld 
= wxNullFont
; 
1066 void wxGridCellEditor::SetSize(const wxRect
& rect
) 
1068     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1070     m_control
->SetSize(rect
, wxSIZE_ALLOW_MINUS_ONE
); 
1073 void wxGridCellEditor::HandleReturn(wxKeyEvent
& event
) 
1078 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1080     bool ctrl 
= event
.ControlDown(); 
1081     bool alt  
= event
.AltDown(); 
1084     // On the Mac the Alt key is more like shift and is used for entry of 
1085     // valid characters, so check for Ctrl and Meta instead. 
1086     alt 
= event
.MetaDown(); 
1089     // Assume it's not a valid char if ctrl or alt is down, but if both are 
1090     // down then it may be because of an AltGr key combination, so let them 
1091     // through in that case. 
1092     if ((ctrl 
|| alt
) && !(ctrl 
&& alt
)) 
1096     // if the unicode key code is not really a unicode character (it may 
1097     // be a function key or etc., the platforms appear to always give us a 
1098     // small value in this case) then fallback to the ASCII key code but 
1099     // don't do anything for function keys or etc. 
1100     if ( event
.GetUnicodeKey() > 127 && event
.GetKeyCode() > 127 ) 
1103     if ( event
.GetKeyCode() > 255 ) 
1110 void wxGridCellEditor::StartingKey(wxKeyEvent
& event
) 
1115 void wxGridCellEditor::StartingClick() 
1121 // ---------------------------------------------------------------------------- 
1122 // wxGridCellTextEditor 
1123 // ---------------------------------------------------------------------------- 
1125 wxGridCellTextEditor::wxGridCellTextEditor() 
1130 void wxGridCellTextEditor::Create(wxWindow
* parent
, 
1132                                   wxEvtHandler
* evtHandler
) 
1134     DoCreate(parent
, id
, evtHandler
); 
1137 void wxGridCellTextEditor::DoCreate(wxWindow
* parent
, 
1139                                     wxEvtHandler
* evtHandler
, 
1142     style 
|= wxTE_PROCESS_ENTER 
| wxTE_PROCESS_TAB 
| wxNO_BORDER
; 
1144     m_control 
= new wxTextCtrl(parent
, id
, wxEmptyString
, 
1145                                wxDefaultPosition
, wxDefaultSize
, 
1148     // set max length allowed in the textctrl, if the parameter was set 
1149     if ( m_maxChars 
!= 0 ) 
1151         Text()->SetMaxLength(m_maxChars
); 
1154     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1157 void wxGridCellTextEditor::PaintBackground(const wxRect
& WXUNUSED(rectCell
), 
1158                                            wxGridCellAttr 
* WXUNUSED(attr
)) 
1160     // as we fill the entire client area, 
1161     // don't do anything here to minimize flicker 
1164 void wxGridCellTextEditor::SetSize(const wxRect
& rectOrig
) 
1166     wxRect 
rect(rectOrig
); 
1168     // Make the edit control large enough to allow for internal margins 
1170     // TODO: remove this if the text ctrl sizing is improved esp. for unix 
1172 #if defined(__WXGTK__) 
1180 #elif defined(__WXMSW__) 
1194     int extra_x 
= ( rect
.x 
> 2 ) ? 2 : 1; 
1195     int extra_y 
= ( rect
.y 
> 2 ) ? 2 : 1; 
1197     #if defined(__WXMOTIF__) 
1202     rect
.SetLeft( wxMax(0, rect
.x 
- extra_x
) ); 
1203     rect
.SetTop( wxMax(0, rect
.y 
- extra_y
) ); 
1204     rect
.SetRight( rect
.GetRight() + 2 * extra_x 
); 
1205     rect
.SetBottom( rect
.GetBottom() + 2 * extra_y 
); 
1208     wxGridCellEditor::SetSize(rect
); 
1211 void wxGridCellTextEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1213     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1215     m_startValue 
= grid
->GetTable()->GetValue(row
, col
); 
1217     DoBeginEdit(m_startValue
); 
1220 void wxGridCellTextEditor::DoBeginEdit(const wxString
& startValue
) 
1222     Text()->SetValue(startValue
); 
1223     Text()->SetInsertionPointEnd(); 
1224     Text()->SetSelection(-1, -1); 
1228 bool wxGridCellTextEditor::EndEdit(int row
, int col
, wxGrid
* grid
) 
1230     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1232     bool changed 
= false; 
1233     wxString value 
= Text()->GetValue(); 
1234     if (value 
!= m_startValue
) 
1238         grid
->GetTable()->SetValue(row
, col
, value
); 
1240     m_startValue 
= wxEmptyString
; 
1242     // No point in setting the text of the hidden control 
1243     //Text()->SetValue(m_startValue); 
1248 void wxGridCellTextEditor::Reset() 
1250     wxASSERT_MSG(m_control
, wxT("The wxGridCellEditor must be created first!")); 
1252     DoReset(m_startValue
); 
1255 void wxGridCellTextEditor::DoReset(const wxString
& startValue
) 
1257     Text()->SetValue(startValue
); 
1258     Text()->SetInsertionPointEnd(); 
1261 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1263     return wxGridCellEditor::IsAcceptedKey(event
); 
1266 void wxGridCellTextEditor::StartingKey(wxKeyEvent
& event
) 
1268     // Since this is now happening in the EVT_CHAR event EmulateKeyPress is no 
1269     // longer an appropriate way to get the character into the text control. 
1270     // Do it ourselves instead.  We know that if we get this far that we have 
1271     // a valid character, so not a whole lot of testing needs to be done. 
1273     wxTextCtrl
* tc 
= Text(); 
1278     ch 
= event
.GetUnicodeKey(); 
1280         ch 
= (wxChar
)event
.GetKeyCode(); 
1282     ch 
= (wxChar
)event
.GetKeyCode(); 
1288             // delete the character at the cursor 
1289             pos 
= tc
->GetInsertionPoint(); 
1290             if (pos 
< tc
->GetLastPosition()) 
1291                 tc
->Remove(pos
, pos 
+ 1); 
1295             // delete the character before the cursor 
1296             pos 
= tc
->GetInsertionPoint(); 
1298                 tc
->Remove(pos 
- 1, pos
); 
1307 void wxGridCellTextEditor::HandleReturn( wxKeyEvent
& 
1308                                          WXUNUSED_GTK(WXUNUSED_MOTIF(event
)) ) 
1310 #if defined(__WXMOTIF__) || defined(__WXGTK__) 
1311     // wxMotif needs a little extra help... 
1312     size_t pos 
= (size_t)( Text()->GetInsertionPoint() ); 
1313     wxString 
s( Text()->GetValue() ); 
1314     s 
= s
.Left(pos
) + wxT("\n") + s
.Mid(pos
); 
1315     Text()->SetValue(s
); 
1316     Text()->SetInsertionPoint( pos 
); 
1318     // the other ports can handle a Return key press 
1324 void wxGridCellTextEditor::SetParameters(const wxString
& params
) 
1334         if ( params
.ToLong(&tmp
) ) 
1336             m_maxChars 
= (size_t)tmp
; 
1340             wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params
.c_str() ); 
1345 // return the value in the text control 
1346 wxString 
wxGridCellTextEditor::GetValue() const 
1348     return Text()->GetValue(); 
1351 // ---------------------------------------------------------------------------- 
1352 // wxGridCellNumberEditor 
1353 // ---------------------------------------------------------------------------- 
1355 wxGridCellNumberEditor::wxGridCellNumberEditor(int min
, int max
) 
1361 void wxGridCellNumberEditor::Create(wxWindow
* parent
, 
1363                                     wxEvtHandler
* evtHandler
) 
1368         // create a spin ctrl 
1369         m_control 
= new wxSpinCtrl(parent
, wxID_ANY
, wxEmptyString
, 
1370                                    wxDefaultPosition
, wxDefaultSize
, 
1374         wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1379         // just a text control 
1380         wxGridCellTextEditor::Create(parent
, id
, evtHandler
); 
1382 #if wxUSE_VALIDATORS 
1383         Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
)); 
1388 void wxGridCellNumberEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1390     // first get the value 
1391     wxGridTableBase 
*table 
= grid
->GetTable(); 
1392     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
1394         m_valueOld 
= table
->GetValueAsLong(row
, col
); 
1399         wxString sValue 
= table
->GetValue(row
, col
); 
1400         if (! sValue
.ToLong(&m_valueOld
) && ! sValue
.empty()) 
1402             wxFAIL_MSG( _T("this cell doesn't have numeric value") ); 
1410         Spin()->SetValue((int)m_valueOld
); 
1416         DoBeginEdit(GetString()); 
1420 bool wxGridCellNumberEditor::EndEdit(int row
, int col
, 
1429         value 
= Spin()->GetValue(); 
1430         if ( value 
== m_valueOld 
) 
1433         text
.Printf(wxT("%ld"), value
); 
1435     else // using unconstrained input 
1436 #endif // wxUSE_SPINCTRL 
1438         const wxString 
textOld(grid
->GetCellValue(row
, col
)); 
1439         text 
= Text()->GetValue(); 
1442             if ( textOld
.empty() ) 
1445         else // non-empty text now (maybe 0) 
1447             if ( !text
.ToLong(&value
) ) 
1450             // if value == m_valueOld == 0 but old text was "" and new one is 
1451             // "0" something still did change 
1452             if ( value 
== m_valueOld 
&& (value 
|| !textOld
.empty()) ) 
1457     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1458     if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
1459         table
->SetValueAsLong(row
, col
, value
); 
1461         table
->SetValue(row
, col
, text
); 
1466 void wxGridCellNumberEditor::Reset() 
1471         Spin()->SetValue((int)m_valueOld
); 
1476         DoReset(GetString()); 
1480 bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1482     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1484         int keycode 
= event
.GetKeyCode(); 
1485         if ( (keycode 
< 128) && 
1486              (wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-')) 
1495 void wxGridCellNumberEditor::StartingKey(wxKeyEvent
& event
) 
1497     int keycode 
= event
.GetKeyCode(); 
1500         if ( wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-') 
1502             wxGridCellTextEditor::StartingKey(event
); 
1504             // skip Skip() below 
1511         if ( wxIsdigit(keycode
) ) 
1513             wxSpinCtrl
* spin 
= (wxSpinCtrl
*)m_control
; 
1514             spin
->SetValue(keycode 
- '0'); 
1515             spin
->SetSelection(1,1); 
1524 void wxGridCellNumberEditor::SetParameters(const wxString
& params
) 
1535         if ( params
.BeforeFirst(_T(',')).ToLong(&tmp
) ) 
1539             if ( params
.AfterFirst(_T(',')).ToLong(&tmp
) ) 
1543                 // skip the error message below 
1548         wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params
.c_str()); 
1552 // return the value in the spin control if it is there (the text control otherwise) 
1553 wxString 
wxGridCellNumberEditor::GetValue() const 
1560         long value 
= Spin()->GetValue(); 
1561         s
.Printf(wxT("%ld"), value
); 
1566         s 
= Text()->GetValue(); 
1572 // ---------------------------------------------------------------------------- 
1573 // wxGridCellFloatEditor 
1574 // ---------------------------------------------------------------------------- 
1576 wxGridCellFloatEditor::wxGridCellFloatEditor(int width
, int precision
) 
1579     m_precision 
= precision
; 
1582 void wxGridCellFloatEditor::Create(wxWindow
* parent
, 
1584                                    wxEvtHandler
* evtHandler
) 
1586     wxGridCellTextEditor::Create(parent
, id
, evtHandler
); 
1588 #if wxUSE_VALIDATORS 
1589     Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC
)); 
1593 void wxGridCellFloatEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1595     // first get the value 
1596     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1597     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
1599         m_valueOld 
= table
->GetValueAsDouble(row
, col
); 
1605         const wxString value 
= table
->GetValue(row
, col
); 
1606         if ( !value
.empty() ) 
1608             if ( !value
.ToDouble(&m_valueOld
) ) 
1610                 wxFAIL_MSG( _T("this cell doesn't have float value") ); 
1616     DoBeginEdit(GetString()); 
1619 bool wxGridCellFloatEditor::EndEdit(int row
, int col
, wxGrid
* grid
) 
1621     const wxString 
text(Text()->GetValue()), 
1622                    textOld(grid
->GetCellValue(row
, col
)); 
1625     if ( !text
.empty() ) 
1627         if ( !text
.ToDouble(&value
) ) 
1630     else // new value is empty string 
1632         if ( textOld
.empty() ) 
1633             return false;           // nothing changed 
1638     // the test for empty strings ensures that we don't skip the value setting 
1639     // when "" is replaced by "0" or vice versa as "" numeric value is also 0. 
1640     if ( wxIsSameDouble(value
, m_valueOld
) && !text
.empty() && !textOld
.empty() ) 
1641         return false;           // nothing changed 
1643     wxGridTableBase 
* const table 
= grid
->GetTable(); 
1645     if ( table
->CanSetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
1646         table
->SetValueAsDouble(row
, col
, value
); 
1648         table
->SetValue(row
, col
, text
); 
1653 void wxGridCellFloatEditor::Reset() 
1655     DoReset(GetString()); 
1658 void wxGridCellFloatEditor::StartingKey(wxKeyEvent
& event
) 
1660     int keycode 
= event
.GetKeyCode(); 
1662     tmpbuf
[0] = (char) keycode
; 
1664     wxString 
strbuf(tmpbuf
, *wxConvCurrent
); 
1667     bool is_decimal_point 
= ( strbuf 
== 
1668        wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
) ); 
1670     bool is_decimal_point 
= ( strbuf 
== _T(".") ); 
1673     if ( wxIsdigit(keycode
) || keycode 
== '+' || keycode 
== '-' 
1674          || is_decimal_point 
) 
1676         wxGridCellTextEditor::StartingKey(event
); 
1678         // skip Skip() below 
1685 void wxGridCellFloatEditor::SetParameters(const wxString
& params
) 
1696         if ( params
.BeforeFirst(_T(',')).ToLong(&tmp
) ) 
1700             if ( params
.AfterFirst(_T(',')).ToLong(&tmp
) ) 
1702                 m_precision 
= (int)tmp
; 
1704                 // skip the error message below 
1709         wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params
.c_str()); 
1713 wxString 
wxGridCellFloatEditor::GetString() const 
1716     if ( m_precision 
== -1 && m_width 
!= -1) 
1718         // default precision 
1719         fmt
.Printf(_T("%%%d.f"), m_width
); 
1721     else if ( m_precision 
!= -1 && m_width 
== -1) 
1724         fmt
.Printf(_T("%%.%df"), m_precision
); 
1726     else if ( m_precision 
!= -1 && m_width 
!= -1 ) 
1728         fmt
.Printf(_T("%%%d.%df"), m_width
, m_precision
); 
1732         // default width/precision 
1736     return wxString::Format(fmt
, m_valueOld
); 
1739 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1741     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1743         const int keycode 
= event
.GetKeyCode(); 
1744         if ( isascii(keycode
) ) 
1747             tmpbuf
[0] = (char) keycode
; 
1749             wxString 
strbuf(tmpbuf
, *wxConvCurrent
); 
1752             const wxString decimalPoint 
= 
1753                 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT
, wxLOCALE_CAT_NUMBER
); 
1755             const wxString 
decimalPoint(_T('.')); 
1758             // accept digits, 'e' as in '1e+6', also '-', '+', and '.' 
1759             if ( wxIsdigit(keycode
) || 
1760                     tolower(keycode
) == 'e' || 
1761                         keycode 
== decimalPoint 
|| 
1773 #endif // wxUSE_TEXTCTRL 
1777 // ---------------------------------------------------------------------------- 
1778 // wxGridCellBoolEditor 
1779 // ---------------------------------------------------------------------------- 
1781 // the default values for GetValue() 
1782 wxString 
wxGridCellBoolEditor::ms_stringValues
[2] = { _T(""), _T("1") }; 
1784 void wxGridCellBoolEditor::Create(wxWindow
* parent
, 
1786                                   wxEvtHandler
* evtHandler
) 
1788     m_control 
= new wxCheckBox(parent
, id
, wxEmptyString
, 
1789                                wxDefaultPosition
, wxDefaultSize
, 
1792     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
1795 void wxGridCellBoolEditor::SetSize(const wxRect
& r
) 
1797     bool resize 
= false; 
1798     wxSize size 
= m_control
->GetSize(); 
1799     wxCoord minSize 
= wxMin(r
.width
, r
.height
); 
1801     // check if the checkbox is not too big/small for this cell 
1802     wxSize sizeBest 
= m_control
->GetBestSize(); 
1803     if ( !(size 
== sizeBest
) ) 
1805         // reset to default size if it had been made smaller 
1811     if ( size
.x 
>= minSize 
|| size
.y 
>= minSize 
) 
1813         // leave 1 pixel margin 
1814         size
.x 
= size
.y 
= minSize 
- 2; 
1821         m_control
->SetSize(size
); 
1824     // position it in the centre of the rectangle (TODO: support alignment?) 
1826 #if defined(__WXGTK__) || defined (__WXMOTIF__) 
1827     // the checkbox without label still has some space to the right in wxGTK, 
1828     // so shift it to the right 
1830 #elif defined(__WXMSW__) 
1831     // here too, but in other way 
1836     int hAlign 
= wxALIGN_CENTRE
; 
1837     int vAlign 
= wxALIGN_CENTRE
; 
1839         GetCellAttr()->GetAlignment(& hAlign
, & vAlign
); 
1842     if (hAlign 
== wxALIGN_LEFT
) 
1850         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1852     else if (hAlign 
== wxALIGN_RIGHT
) 
1854         x 
= r
.x 
+ r
.width 
- size
.x 
- 2; 
1855         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1857     else if (hAlign 
== wxALIGN_CENTRE
) 
1859         x 
= r
.x 
+ r
.width 
/ 2 - size
.x 
/ 2; 
1860         y 
= r
.y 
+ r
.height 
/ 2 - size
.y 
/ 2; 
1863     m_control
->Move(x
, y
); 
1866 void wxGridCellBoolEditor::Show(bool show
, wxGridCellAttr 
*attr
) 
1868     m_control
->Show(show
); 
1872         wxColour colBg 
= attr 
? attr
->GetBackgroundColour() : *wxLIGHT_GREY
; 
1873         CBox()->SetBackgroundColour(colBg
); 
1877 void wxGridCellBoolEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
1879     wxASSERT_MSG(m_control
, 
1880                  wxT("The wxGridCellEditor must be created first!")); 
1882     if (grid
->GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
)) 
1884         m_startValue 
= grid
->GetTable()->GetValueAsBool(row
, col
); 
1888         wxString 
cellval( grid
->GetTable()->GetValue(row
, col
) ); 
1890         if ( cellval 
== ms_stringValues
[false] ) 
1891             m_startValue 
= false; 
1892         else if ( cellval 
== ms_stringValues
[true] ) 
1893             m_startValue 
= true; 
1896             // do not try to be smart here and convert it to true or false 
1897             // because we'll still overwrite it with something different and 
1898             // this risks to be very surprising for the user code, let them 
1900             wxFAIL_MSG( _T("invalid value for a cell with bool editor!") ); 
1904     CBox()->SetValue(m_startValue
); 
1908 bool wxGridCellBoolEditor::EndEdit(int row
, int col
, 
1911     wxASSERT_MSG(m_control
, 
1912                  wxT("The wxGridCellEditor must be created first!")); 
1914     bool changed 
= false; 
1915     bool value 
= CBox()->GetValue(); 
1916     if ( value 
!= m_startValue 
) 
1921         wxGridTableBase 
* const table 
= grid
->GetTable(); 
1922         if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
) ) 
1923             table
->SetValueAsBool(row
, col
, value
); 
1925             table
->SetValue(row
, col
, GetValue()); 
1931 void wxGridCellBoolEditor::Reset() 
1933     wxASSERT_MSG(m_control
, 
1934                  wxT("The wxGridCellEditor must be created first!")); 
1936     CBox()->SetValue(m_startValue
); 
1939 void wxGridCellBoolEditor::StartingClick() 
1941     CBox()->SetValue(!CBox()->GetValue()); 
1944 bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent
& event
) 
1946     if ( wxGridCellEditor::IsAcceptedKey(event
) ) 
1948         int keycode 
= event
.GetKeyCode(); 
1961 void wxGridCellBoolEditor::StartingKey(wxKeyEvent
& event
) 
1963     int keycode 
= event
.GetKeyCode(); 
1967             CBox()->SetValue(!CBox()->GetValue()); 
1971             CBox()->SetValue(true); 
1975             CBox()->SetValue(false); 
1980 wxString 
wxGridCellBoolEditor::GetValue() const 
1982   return ms_stringValues
[CBox()->GetValue()]; 
1986 wxGridCellBoolEditor::UseStringValues(const wxString
& valueTrue
, 
1987                                       const wxString
& valueFalse
) 
1989     ms_stringValues
[false] = valueFalse
; 
1990     ms_stringValues
[true] = valueTrue
; 
1994 wxGridCellBoolEditor::IsTrueValue(const wxString
& value
) 
1996     return value 
== ms_stringValues
[true]; 
1999 #endif // wxUSE_CHECKBOX 
2003 // ---------------------------------------------------------------------------- 
2004 // wxGridCellChoiceEditor 
2005 // ---------------------------------------------------------------------------- 
2007 wxGridCellChoiceEditor::wxGridCellChoiceEditor(const wxArrayString
& choices
, 
2009     : m_choices(choices
), 
2010       m_allowOthers(allowOthers
) { } 
2012 wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count
, 
2013                                                const wxString choices
[], 
2015                       : m_allowOthers(allowOthers
) 
2019         m_choices
.Alloc(count
); 
2020         for ( size_t n 
= 0; n 
< count
; n
++ ) 
2022             m_choices
.Add(choices
[n
]); 
2027 wxGridCellEditor 
*wxGridCellChoiceEditor::Clone() const 
2029     wxGridCellChoiceEditor 
*editor 
= new wxGridCellChoiceEditor
; 
2030     editor
->m_allowOthers 
= m_allowOthers
; 
2031     editor
->m_choices 
= m_choices
; 
2036 void wxGridCellChoiceEditor::Create(wxWindow
* parent
, 
2038                                     wxEvtHandler
* evtHandler
) 
2040     int style 
= wxTE_PROCESS_ENTER 
| 
2044     if ( !m_allowOthers 
) 
2045         style 
|= wxCB_READONLY
; 
2046     m_control 
= new wxComboBox(parent
, id
, wxEmptyString
, 
2047                                wxDefaultPosition
, wxDefaultSize
, 
2051     wxGridCellEditor::Create(parent
, id
, evtHandler
); 
2054 void wxGridCellChoiceEditor::PaintBackground(const wxRect
& rectCell
, 
2055                                              wxGridCellAttr 
* attr
) 
2057     // as we fill the entire client area, don't do anything here to minimize 
2060     // TODO: It doesn't actually fill the client area since the height of a 
2061     // combo always defaults to the standard.  Until someone has time to 
2062     // figure out the right rectangle to paint, just do it the normal way. 
2063     wxGridCellEditor::PaintBackground(rectCell
, attr
); 
2066 void wxGridCellChoiceEditor::BeginEdit(int row
, int col
, wxGrid
* grid
) 
2068     wxASSERT_MSG(m_control
, 
2069                  wxT("The wxGridCellEditor must be created first!")); 
2071     wxGridCellEditorEvtHandler
* evtHandler 
= NULL
; 
2073         evtHandler 
= wxDynamicCast(m_control
->GetEventHandler(), wxGridCellEditorEvtHandler
); 
2075     // Don't immediately end if we get a kill focus event within BeginEdit 
2077         evtHandler
->SetInSetFocus(true); 
2079     m_startValue 
= grid
->GetTable()->GetValue(row
, col
); 
2081     Reset(); // this updates combo box to correspond to m_startValue 
2083     Combo()->SetFocus(); 
2087         // When dropping down the menu, a kill focus event 
2088         // happens after this point, so we can't reset the flag yet. 
2089 #if !defined(__WXGTK20__) 
2090         evtHandler
->SetInSetFocus(false); 
2095 bool wxGridCellChoiceEditor::EndEdit(int row
, int col
, 
2098     wxString value 
= Combo()->GetValue(); 
2099     if ( value 
== m_startValue 
) 
2102     grid
->GetTable()->SetValue(row
, col
, value
); 
2107 void wxGridCellChoiceEditor::Reset() 
2111         Combo()->SetValue(m_startValue
); 
2112         Combo()->SetInsertionPointEnd(); 
2114     else // the combobox is read-only 
2116         // find the right position, or default to the first if not found 
2117         int pos 
= Combo()->FindString(m_startValue
); 
2118         if (pos 
== wxNOT_FOUND
) 
2120         Combo()->SetSelection(pos
); 
2124 void wxGridCellChoiceEditor::SetParameters(const wxString
& params
) 
2134     wxStringTokenizer 
tk(params
, _T(',')); 
2135     while ( tk
.HasMoreTokens() ) 
2137         m_choices
.Add(tk
.GetNextToken()); 
2141 // return the value in the text control 
2142 wxString 
wxGridCellChoiceEditor::GetValue() const 
2144   return Combo()->GetValue(); 
2147 #endif // wxUSE_COMBOBOX 
2149 // ---------------------------------------------------------------------------- 
2150 // wxGridCellEditorEvtHandler 
2151 // ---------------------------------------------------------------------------- 
2153 void wxGridCellEditorEvtHandler::OnKillFocus(wxFocusEvent
& event
) 
2155     // Don't disable the cell if we're just starting to edit it 
2160     m_grid
->DisableCellEditControl(); 
2165 void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent
& event
) 
2167     switch ( event
.GetKeyCode() ) 
2171             m_grid
->DisableCellEditControl(); 
2175             m_grid
->GetEventHandler()->ProcessEvent( event 
); 
2179         case WXK_NUMPAD_ENTER
: 
2180             if (!m_grid
->GetEventHandler()->ProcessEvent(event
)) 
2181                 m_editor
->HandleReturn(event
); 
2190 void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent
& event
) 
2192     int row 
= m_grid
->GetGridCursorRow(); 
2193     int col 
= m_grid
->GetGridCursorCol(); 
2194     wxRect rect 
= m_grid
->CellToRect( row
, col 
); 
2196     m_grid
->GetGridWindow()->GetClientSize( &cw
, &ch 
); 
2198     // if cell width is smaller than grid client area, cell is wholly visible 
2199     bool wholeCellVisible 
= (rect
.GetWidth() < cw
); 
2201     switch ( event
.GetKeyCode() ) 
2206         case WXK_NUMPAD_ENTER
: 
2211             if ( wholeCellVisible 
) 
2213                 // no special processing needed... 
2218             // do special processing for partly visible cell... 
2220             // get the widths of all cells previous to this one 
2222             for ( int i 
= 0; i 
< col
; i
++ ) 
2224                 colXPos 
+= m_grid
->GetColSize(i
); 
2227             int xUnit 
= 1, yUnit 
= 1; 
2228             m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
); 
2231                 m_grid
->Scroll(colXPos 
/ xUnit 
- 1, m_grid
->GetScrollPos(wxVERTICAL
)); 
2235                 m_grid
->Scroll(colXPos 
/ xUnit
, m_grid
->GetScrollPos(wxVERTICAL
)); 
2243             if ( wholeCellVisible 
) 
2245                 // no special processing needed... 
2250             // do special processing for partly visible cell... 
2253             wxString value 
= m_grid
->GetCellValue(row
, col
); 
2254             if ( wxEmptyString 
!= value 
) 
2256                 // get width of cell CONTENTS (text) 
2258                 wxFont font 
= m_grid
->GetCellFont(row
, col
); 
2259                 m_grid
->GetTextExtent(value
, &textWidth
, &y
, NULL
, NULL
, &font
); 
2261                 // try to RIGHT align the text by scrolling 
2262                 int client_right 
= m_grid
->GetGridWindow()->GetClientSize().GetWidth(); 
2264                 // (m_grid->GetScrollLineX()*2) is a factor for not scrolling to far, 
2265                 // otherwise the last part of the cell content might be hidden below the scroll bar 
2266                 // FIXME: maybe there is a more suitable correction? 
2267                 textWidth 
-= (client_right 
- (m_grid
->GetScrollLineX() * 2)); 
2268                 if ( textWidth 
< 0 ) 
2274             // get the widths of all cells previous to this one 
2276             for ( int i 
= 0; i 
< col
; i
++ ) 
2278                 colXPos 
+= m_grid
->GetColSize(i
); 
2281             // and add the (modified) text width of the cell contents 
2282             // as we'd like to see the last part of the cell contents 
2283             colXPos 
+= textWidth
; 
2285             int xUnit 
= 1, yUnit 
= 1; 
2286             m_grid
->GetScrollPixelsPerUnit(&xUnit
, &yUnit
); 
2287             m_grid
->Scroll(colXPos 
/ xUnit 
- 1, m_grid
->GetScrollPos(wxVERTICAL
)); 
2298 // ---------------------------------------------------------------------------- 
2299 // wxGridCellWorker is an (almost) empty common base class for 
2300 // wxGridCellRenderer and wxGridCellEditor managing ref counting 
2301 // ---------------------------------------------------------------------------- 
2303 void wxGridCellWorker::SetParameters(const wxString
& WXUNUSED(params
)) 
2308 wxGridCellWorker::~wxGridCellWorker() 
2312 // ============================================================================ 
2314 // ============================================================================ 
2316 // ---------------------------------------------------------------------------- 
2317 // wxGridCellRenderer 
2318 // ---------------------------------------------------------------------------- 
2320 void wxGridCellRenderer::Draw(wxGrid
& grid
, 
2321                               wxGridCellAttr
& attr
, 
2324                               int WXUNUSED(row
), int WXUNUSED(col
), 
2327     dc
.SetBackgroundMode( wxBRUSHSTYLE_SOLID 
); 
2330     if ( grid
.IsEnabled() ) 
2334             if ( grid
.HasFocus() ) 
2335                 clr 
= grid
.GetSelectionBackground(); 
2337                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
2341             clr 
= attr
.GetBackgroundColour(); 
2344     else // grey out fields if the grid is disabled 
2346         clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
); 
2350     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2351     dc
.DrawRectangle(rect
); 
2354 // ---------------------------------------------------------------------------- 
2355 // wxGridCellStringRenderer 
2356 // ---------------------------------------------------------------------------- 
2358 void wxGridCellStringRenderer::SetTextColoursAndFont(const wxGrid
& grid
, 
2359                                                      const wxGridCellAttr
& attr
, 
2363     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
2365     // TODO some special colours for attr.IsReadOnly() case? 
2367     // different coloured text when the grid is disabled 
2368     if ( grid
.IsEnabled() ) 
2373             if ( grid
.HasFocus() ) 
2374                 clr 
= grid
.GetSelectionBackground(); 
2376                 clr 
= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW
); 
2377             dc
.SetTextBackground( clr 
); 
2378             dc
.SetTextForeground( grid
.GetSelectionForeground() ); 
2382             dc
.SetTextBackground( attr
.GetBackgroundColour() ); 
2383             dc
.SetTextForeground( attr
.GetTextColour() ); 
2388         dc
.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)); 
2389         dc
.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT
)); 
2392     dc
.SetFont( attr
.GetFont() ); 
2395 wxSize 
wxGridCellStringRenderer::DoGetBestSize(const wxGridCellAttr
& attr
, 
2397                                                const wxString
& text
) 
2399     wxCoord x 
= 0, y 
= 0, max_x 
= 0; 
2400     dc
.SetFont(attr
.GetFont()); 
2401     wxStringTokenizer 
tk(text
, _T('\n')); 
2402     while ( tk
.HasMoreTokens() ) 
2404         dc
.GetTextExtent(tk
.GetNextToken(), &x
, &y
); 
2405         max_x 
= wxMax(max_x
, x
); 
2408     y 
*= 1 + text
.Freq(wxT('\n')); // multiply by the number of lines. 
2410     return wxSize(max_x
, y
); 
2413 wxSize 
wxGridCellStringRenderer::GetBestSize(wxGrid
& grid
, 
2414                                              wxGridCellAttr
& attr
, 
2418     return DoGetBestSize(attr
, dc
, grid
.GetCellValue(row
, col
)); 
2421 void wxGridCellStringRenderer::Draw(wxGrid
& grid
, 
2422                                     wxGridCellAttr
& attr
, 
2424                                     const wxRect
& rectCell
, 
2428     wxRect rect 
= rectCell
; 
2431     // erase only this cells background, overflow cells should have been erased 
2432     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2435     attr
.GetAlignment(&hAlign
, &vAlign
); 
2437     int overflowCols 
= 0; 
2439     if (attr
.GetOverflow()) 
2441         int cols 
= grid
.GetNumberCols(); 
2442         int best_width 
= GetBestSize(grid
,attr
,dc
,row
,col
).GetWidth(); 
2443         int cell_rows
, cell_cols
; 
2444         attr
.GetSize( &cell_rows
, &cell_cols 
); // shouldn't get here if <= 0 
2445         if ((best_width 
> rectCell
.width
) && (col 
< cols
) && grid
.GetTable()) 
2447             int i
, c_cols
, c_rows
; 
2448             for (i 
= col
+cell_cols
; i 
< cols
; i
++) 
2450                 bool is_empty 
= true; 
2451                 for (int j
=row
; j 
< row 
+ cell_rows
; j
++) 
2453                     // check w/ anchor cell for multicell block 
2454                     grid
.GetCellSize(j
, i
, &c_rows
, &c_cols
); 
2457                     if (!grid
.GetTable()->IsEmptyCell(j 
+ c_rows
, i
)) 
2466                     rect
.width 
+= grid
.GetColSize(i
); 
2474                 if (rect
.width 
>= best_width
) 
2478             overflowCols 
= i 
- col 
- cell_cols 
+ 1; 
2479             if (overflowCols 
>= cols
) 
2480                 overflowCols 
= cols 
- 1; 
2483         if (overflowCols 
> 0) // redraw overflow cells w/ proper hilight 
2485             hAlign 
= wxALIGN_LEFT
; // if oveflowed then it's left aligned 
2487             clip
.x 
+= rectCell
.width
; 
2488             // draw each overflow cell individually 
2489             int col_end 
= col 
+ cell_cols 
+ overflowCols
; 
2490             if (col_end 
>= grid
.GetNumberCols()) 
2491                 col_end 
= grid
.GetNumberCols() - 1; 
2492             for (int i 
= col 
+ cell_cols
; i 
<= col_end
; i
++) 
2494                 clip
.width 
= grid
.GetColSize(i
) - 1; 
2495                 dc
.DestroyClippingRegion(); 
2496                 dc
.SetClippingRegion(clip
); 
2498                 SetTextColoursAndFont(grid
, attr
, dc
, 
2499                         grid
.IsInSelection(row
,i
)); 
2501                 grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
2502                         rect
, hAlign
, vAlign
); 
2503                 clip
.x 
+= grid
.GetColSize(i
) - 1; 
2509             dc
.DestroyClippingRegion(); 
2513     // now we only have to draw the text 
2514     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2516     grid
.DrawTextRectangle(dc
, grid
.GetCellValue(row
, col
), 
2517                            rect
, hAlign
, vAlign
); 
2520 // ---------------------------------------------------------------------------- 
2521 // wxGridCellNumberRenderer 
2522 // ---------------------------------------------------------------------------- 
2524 wxString 
wxGridCellNumberRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
2526     wxGridTableBase 
*table 
= grid
.GetTable(); 
2528     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_NUMBER
) ) 
2530         text
.Printf(_T("%ld"), table
->GetValueAsLong(row
, col
)); 
2534         text 
= table
->GetValue(row
, col
); 
2540 void wxGridCellNumberRenderer::Draw(wxGrid
& grid
, 
2541                                     wxGridCellAttr
& attr
, 
2543                                     const wxRect
& rectCell
, 
2547     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2549     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2551     // draw the text right aligned by default 
2553     attr
.GetAlignment(&hAlign
, &vAlign
); 
2554     hAlign 
= wxALIGN_RIGHT
; 
2556     wxRect rect 
= rectCell
; 
2559     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
2562 wxSize 
wxGridCellNumberRenderer::GetBestSize(wxGrid
& grid
, 
2563                                              wxGridCellAttr
& attr
, 
2567     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
2570 // ---------------------------------------------------------------------------- 
2571 // wxGridCellFloatRenderer 
2572 // ---------------------------------------------------------------------------- 
2574 wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width
, int precision
) 
2577     SetPrecision(precision
); 
2580 wxGridCellRenderer 
*wxGridCellFloatRenderer::Clone() const 
2582     wxGridCellFloatRenderer 
*renderer 
= new wxGridCellFloatRenderer
; 
2583     renderer
->m_width 
= m_width
; 
2584     renderer
->m_precision 
= m_precision
; 
2585     renderer
->m_format 
= m_format
; 
2590 wxString 
wxGridCellFloatRenderer::GetString(const wxGrid
& grid
, int row
, int col
) 
2592     wxGridTableBase 
*table 
= grid
.GetTable(); 
2597     if ( table
->CanGetValueAs(row
, col
, wxGRID_VALUE_FLOAT
) ) 
2599         val 
= table
->GetValueAsDouble(row
, col
); 
2604         text 
= table
->GetValue(row
, col
); 
2605         hasDouble 
= text
.ToDouble(&val
); 
2612             if ( m_width 
== -1 ) 
2614                 if ( m_precision 
== -1 ) 
2616                     // default width/precision 
2617                     m_format 
= _T("%f"); 
2621                     m_format
.Printf(_T("%%.%df"), m_precision
); 
2624             else if ( m_precision 
== -1 ) 
2626                 // default precision 
2627                 m_format
.Printf(_T("%%%d.f"), m_width
); 
2631                 m_format
.Printf(_T("%%%d.%df"), m_width
, m_precision
); 
2635         text
.Printf(m_format
, val
); 
2638     //else: text already contains the string 
2643 void wxGridCellFloatRenderer::Draw(wxGrid
& grid
, 
2644                                    wxGridCellAttr
& attr
, 
2646                                    const wxRect
& rectCell
, 
2650     wxGridCellRenderer::Draw(grid
, attr
, dc
, rectCell
, row
, col
, isSelected
); 
2652     SetTextColoursAndFont(grid
, attr
, dc
, isSelected
); 
2654     // draw the text right aligned by default 
2656     attr
.GetAlignment(&hAlign
, &vAlign
); 
2657     hAlign 
= wxALIGN_RIGHT
; 
2659     wxRect rect 
= rectCell
; 
2662     grid
.DrawTextRectangle(dc
, GetString(grid
, row
, col
), rect
, hAlign
, vAlign
); 
2665 wxSize 
wxGridCellFloatRenderer::GetBestSize(wxGrid
& grid
, 
2666                                             wxGridCellAttr
& attr
, 
2670     return DoGetBestSize(attr
, dc
, GetString(grid
, row
, col
)); 
2673 void wxGridCellFloatRenderer::SetParameters(const wxString
& params
) 
2677         // reset to defaults 
2683         wxString tmp 
= params
.BeforeFirst(_T(',')); 
2687             if ( tmp
.ToLong(&width
) ) 
2689                 SetWidth((int)width
); 
2693                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params
.c_str()); 
2697         tmp 
= params
.AfterFirst(_T(',')); 
2701             if ( tmp
.ToLong(&precision
) ) 
2703                 SetPrecision((int)precision
); 
2707                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params
.c_str()); 
2713 // ---------------------------------------------------------------------------- 
2714 // wxGridCellBoolRenderer 
2715 // ---------------------------------------------------------------------------- 
2717 wxSize 
wxGridCellBoolRenderer::ms_sizeCheckMark
; 
2719 // FIXME these checkbox size calculations are really ugly... 
2721 // between checkmark and box 
2722 static const wxCoord wxGRID_CHECKMARK_MARGIN 
= 2; 
2724 wxSize 
wxGridCellBoolRenderer::GetBestSize(wxGrid
& grid
, 
2725                                            wxGridCellAttr
& WXUNUSED(attr
), 
2730     // compute it only once (no locks for MT safeness in GUI thread...) 
2731     if ( !ms_sizeCheckMark
.x 
) 
2733         // get checkbox size 
2734         wxCheckBox 
*checkbox 
= new wxCheckBox(&grid
, wxID_ANY
, wxEmptyString
); 
2735         wxSize size 
= checkbox
->GetBestSize(); 
2736         wxCoord checkSize 
= size
.y 
+ 2 * wxGRID_CHECKMARK_MARGIN
; 
2738 #if defined(__WXMOTIF__) 
2739         checkSize 
-= size
.y 
/ 2; 
2744         ms_sizeCheckMark
.x 
= ms_sizeCheckMark
.y 
= checkSize
; 
2747     return ms_sizeCheckMark
; 
2750 void wxGridCellBoolRenderer::Draw(wxGrid
& grid
, 
2751                                   wxGridCellAttr
& attr
, 
2757     wxGridCellRenderer::Draw(grid
, attr
, dc
, rect
, row
, col
, isSelected
); 
2759     // draw a check mark in the centre (ignoring alignment - TODO) 
2760     wxSize size 
= GetBestSize(grid
, attr
, dc
, row
, col
); 
2762     // don't draw outside the cell 
2763     wxCoord minSize 
= wxMin(rect
.width
, rect
.height
); 
2764     if ( size
.x 
>= minSize 
|| size
.y 
>= minSize 
) 
2766         // and even leave (at least) 1 pixel margin 
2767         size
.x 
= size
.y 
= minSize
; 
2770     // draw a border around checkmark 
2772     attr
.GetAlignment(&hAlign
, &vAlign
); 
2775     if (hAlign 
== wxALIGN_CENTRE
) 
2777         rectBorder
.x 
= rect
.x 
+ rect
.width 
/ 2 - size
.x 
/ 2; 
2778         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2779         rectBorder
.width 
= size
.x
; 
2780         rectBorder
.height 
= size
.y
; 
2782     else if (hAlign 
== wxALIGN_LEFT
) 
2784         rectBorder
.x 
= rect
.x 
+ 2; 
2785         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2786         rectBorder
.width 
= size
.x
; 
2787         rectBorder
.height 
= size
.y
; 
2789     else if (hAlign 
== wxALIGN_RIGHT
) 
2791         rectBorder
.x 
= rect
.x 
+ rect
.width 
- size
.x 
- 2; 
2792         rectBorder
.y 
= rect
.y 
+ rect
.height 
/ 2 - size
.y 
/ 2; 
2793         rectBorder
.width 
= size
.x
; 
2794         rectBorder
.height 
= size
.y
; 
2798     if ( grid
.GetTable()->CanGetValueAs(row
, col
, wxGRID_VALUE_BOOL
) ) 
2800         value 
= grid
.GetTable()->GetValueAsBool(row
, col
); 
2804         wxString 
cellval( grid
.GetTable()->GetValue(row
, col
) ); 
2805         value 
= wxGridCellBoolEditor::IsTrueValue(cellval
); 
2810         flags 
|= wxCONTROL_CHECKED
; 
2812     wxRendererNative::Get().DrawCheckBox( &grid
, dc
, rectBorder
, flags 
); 
2815 // ---------------------------------------------------------------------------- 
2817 // ---------------------------------------------------------------------------- 
2819 void wxGridCellAttr::Init(wxGridCellAttr 
*attrDefault
) 
2823     m_isReadOnly 
= Unset
; 
2828     m_attrkind 
= wxGridCellAttr::Cell
; 
2830     m_sizeRows 
= m_sizeCols 
= 1; 
2831     m_overflow 
= UnsetOverflow
; 
2833     SetDefAttr(attrDefault
); 
2836 wxGridCellAttr 
*wxGridCellAttr::Clone() const 
2838     wxGridCellAttr 
*attr 
= new wxGridCellAttr(m_defGridAttr
); 
2840     if ( HasTextColour() ) 
2841         attr
->SetTextColour(GetTextColour()); 
2842     if ( HasBackgroundColour() ) 
2843         attr
->SetBackgroundColour(GetBackgroundColour()); 
2845         attr
->SetFont(GetFont()); 
2846     if ( HasAlignment() ) 
2847         attr
->SetAlignment(m_hAlign
, m_vAlign
); 
2849     attr
->SetSize( m_sizeRows
, m_sizeCols 
); 
2853         attr
->SetRenderer(m_renderer
); 
2854         m_renderer
->IncRef(); 
2858         attr
->SetEditor(m_editor
); 
2863         attr
->SetReadOnly(); 
2865     attr
->SetOverflow( m_overflow 
== Overflow 
); 
2866     attr
->SetKind( m_attrkind 
); 
2871 void wxGridCellAttr::MergeWith(wxGridCellAttr 
*mergefrom
) 
2873     if ( !HasTextColour() && mergefrom
->HasTextColour() ) 
2874         SetTextColour(mergefrom
->GetTextColour()); 
2875     if ( !HasBackgroundColour() && mergefrom
->HasBackgroundColour() ) 
2876         SetBackgroundColour(mergefrom
->GetBackgroundColour()); 
2877     if ( !HasFont() && mergefrom
->HasFont() ) 
2878         SetFont(mergefrom
->GetFont()); 
2879     if ( !HasAlignment() && mergefrom
->HasAlignment() ) 
2882         mergefrom
->GetAlignment( &hAlign
, &vAlign
); 
2883         SetAlignment(hAlign
, vAlign
); 
2885     if ( !HasSize() && mergefrom
->HasSize() ) 
2886         mergefrom
->GetSize( &m_sizeRows
, &m_sizeCols 
); 
2888     // Directly access member functions as GetRender/Editor don't just return 
2889     // m_renderer/m_editor 
2891     // Maybe add support for merge of Render and Editor? 
2892     if (!HasRenderer() && mergefrom
->HasRenderer() ) 
2894         m_renderer 
= mergefrom
->m_renderer
; 
2895         m_renderer
->IncRef(); 
2897     if ( !HasEditor() && mergefrom
->HasEditor() ) 
2899         m_editor 
=  mergefrom
->m_editor
; 
2902     if ( !HasReadWriteMode() && mergefrom
->HasReadWriteMode() ) 
2903         SetReadOnly(mergefrom
->IsReadOnly()); 
2905     if (!HasOverflowMode() && mergefrom
->HasOverflowMode() ) 
2906         SetOverflow(mergefrom
->GetOverflow()); 
2908     SetDefAttr(mergefrom
->m_defGridAttr
); 
2911 void wxGridCellAttr::SetSize(int num_rows
, int num_cols
) 
2913     // The size of a cell is normally 1,1 
2915     // If this cell is larger (2,2) then this is the top left cell 
2916     // the other cells that will be covered (lower right cells) must be 
2917     // set to negative or zero values such that 
2918     // row + num_rows of the covered cell points to the larger cell (this cell) 
2919     // same goes for the col + num_cols. 
2921     // Size of 0,0 is NOT valid, neither is <=0 and any positive value 
2923     wxASSERT_MSG( (!((num_rows 
> 0) && (num_cols 
<= 0)) || 
2924                   !((num_rows 
<= 0) && (num_cols 
> 0)) || 
2925                   !((num_rows 
== 0) && (num_cols 
== 0))), 
2926                   wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values")); 
2928     m_sizeRows 
= num_rows
; 
2929     m_sizeCols 
= num_cols
; 
2932 const wxColour
& wxGridCellAttr::GetTextColour() const 
2934     if (HasTextColour()) 
2938     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2940         return m_defGridAttr
->GetTextColour(); 
2944         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2945         return wxNullColour
; 
2949 const wxColour
& wxGridCellAttr::GetBackgroundColour() const 
2951     if (HasBackgroundColour()) 
2955     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2957         return m_defGridAttr
->GetBackgroundColour(); 
2961         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2962         return wxNullColour
; 
2966 const wxFont
& wxGridCellAttr::GetFont() const 
2972     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2974         return m_defGridAttr
->GetFont(); 
2978         wxFAIL_MSG(wxT("Missing default cell attribute")); 
2983 void wxGridCellAttr::GetAlignment(int *hAlign
, int *vAlign
) const 
2992     else if (m_defGridAttr 
&& m_defGridAttr 
!= this) 
2994         m_defGridAttr
->GetAlignment(hAlign
, vAlign
); 
2998         wxFAIL_MSG(wxT("Missing default cell attribute")); 
3002 void wxGridCellAttr::GetSize( int *num_rows
, int *num_cols 
) const 
3005         *num_rows 
= m_sizeRows
; 
3007         *num_cols 
= m_sizeCols
; 
3010 // GetRenderer and GetEditor use a slightly different decision path about 
3011 // which attribute to use.  If a non-default attr object has one then it is 
3012 // used, otherwise the default editor or renderer is fetched from the grid and 
3013 // used.  It should be the default for the data type of the cell.  If it is 
3014 // NULL (because the table has a type that the grid does not have in its 
3015 // registry), then the grid's default editor or renderer is used. 
3017 wxGridCellRenderer
* wxGridCellAttr::GetRenderer(const wxGrid
* grid
, int row
, int col
) const 
3019     wxGridCellRenderer 
*renderer 
= NULL
; 
3021     if ( m_renderer 
&& this != m_defGridAttr 
) 
3023         // use the cells renderer if it has one 
3024         renderer 
= m_renderer
; 
3027     else // no non-default cell renderer 
3029         // get default renderer for the data type 
3032             // GetDefaultRendererForCell() will do IncRef() for us 
3033             renderer 
= grid
->GetDefaultRendererForCell(row
, col
); 
3036         if ( renderer 
== NULL 
) 
3038             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
3040                 // if we still don't have one then use the grid default 
3041                 // (no need for IncRef() here neither) 
3042                 renderer 
= m_defGridAttr
->GetRenderer(NULL
, 0, 0); 
3044             else // default grid attr 
3046                 // use m_renderer which we had decided not to use initially 
3047                 renderer 
= m_renderer
; 
3054     // we're supposed to always find something 
3055     wxASSERT_MSG(renderer
, wxT("Missing default cell renderer")); 
3060 // same as above, except for s/renderer/editor/g 
3061 wxGridCellEditor
* wxGridCellAttr::GetEditor(const wxGrid
* grid
, int row
, int col
) const 
3063     wxGridCellEditor 
*editor 
= NULL
; 
3065     if ( m_editor 
&& this != m_defGridAttr 
) 
3067         // use the cells editor if it has one 
3071     else // no non default cell editor 
3073         // get default editor for the data type 
3076             // GetDefaultEditorForCell() will do IncRef() for us 
3077             editor 
= grid
->GetDefaultEditorForCell(row
, col
); 
3080         if ( editor 
== NULL 
) 
3082             if ( (m_defGridAttr 
!= NULL
) && (m_defGridAttr 
!= this) ) 
3084                 // if we still don't have one then use the grid default 
3085                 // (no need for IncRef() here neither) 
3086                 editor 
= m_defGridAttr
->GetEditor(NULL
, 0, 0); 
3088             else // default grid attr 
3090                 // use m_editor which we had decided not to use initially 
3098     // we're supposed to always find something 
3099     wxASSERT_MSG(editor
, wxT("Missing default cell editor")); 
3104 // ---------------------------------------------------------------------------- 
3105 // wxGridCellAttrData 
3106 // ---------------------------------------------------------------------------- 
3108 void wxGridCellAttrData::SetAttr(wxGridCellAttr 
*attr
, int row
, int col
) 
3110     // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not 
3111     //       touch attribute's reference counting explicitly, since this 
3112     //       is managed by class wxGridCellWithAttr 
3113     int n 
= FindIndex(row
, col
); 
3114     if ( n 
== wxNOT_FOUND 
) 
3118             // add the attribute 
3119             m_attrs
.Add(new wxGridCellWithAttr(row
, col
, attr
)); 
3121         //else: nothing to do 
3123     else // we already have an attribute for this cell 
3127             // change the attribute 
3128             m_attrs
[(size_t)n
].ChangeAttr(attr
); 
3132             // remove this attribute 
3133             m_attrs
.RemoveAt((size_t)n
); 
3138 wxGridCellAttr 
*wxGridCellAttrData::GetAttr(int row
, int col
) const 
3140     wxGridCellAttr 
*attr 
= NULL
; 
3142     int n 
= FindIndex(row
, col
); 
3143     if ( n 
!= wxNOT_FOUND 
) 
3145         attr 
= m_attrs
[(size_t)n
].attr
; 
3152 void wxGridCellAttrData::UpdateAttrRows( size_t pos
, int numRows 
) 
3154     size_t count 
= m_attrs
.GetCount(); 
3155     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3157         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3158         wxCoord row 
= coords
.GetRow(); 
3159         if ((size_t)row 
>= pos
) 
3163                 // If rows inserted, include row counter where necessary 
3164                 coords
.SetRow(row 
+ numRows
); 
3166             else if (numRows 
< 0) 
3168                 // If rows deleted ... 
3169                 if ((size_t)row 
>= pos 
- numRows
) 
3171                     // ...either decrement row counter (if row still exists)... 
3172                     coords
.SetRow(row 
+ numRows
); 
3176                     // ...or remove the attribute 
3177                     m_attrs
.RemoveAt(n
); 
3186 void wxGridCellAttrData::UpdateAttrCols( size_t pos
, int numCols 
) 
3188     size_t count 
= m_attrs
.GetCount(); 
3189     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3191         wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3192         wxCoord col 
= coords
.GetCol(); 
3193         if ( (size_t)col 
>= pos 
) 
3197                 // If rows inserted, include row counter where necessary 
3198                 coords
.SetCol(col 
+ numCols
); 
3200             else if (numCols 
< 0) 
3202                 // If rows deleted ... 
3203                 if ((size_t)col 
>= pos 
- numCols
) 
3205                     // ...either decrement row counter (if row still exists)... 
3206                     coords
.SetCol(col 
+ numCols
); 
3210                     // ...or remove the attribute 
3211                     m_attrs
.RemoveAt(n
); 
3220 int wxGridCellAttrData::FindIndex(int row
, int col
) const 
3222     size_t count 
= m_attrs
.GetCount(); 
3223     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3225         const wxGridCellCoords
& coords 
= m_attrs
[n
].coords
; 
3226         if ( (coords
.GetRow() == row
) && (coords
.GetCol() == col
) ) 
3235 // ---------------------------------------------------------------------------- 
3236 // wxGridRowOrColAttrData 
3237 // ---------------------------------------------------------------------------- 
3239 wxGridRowOrColAttrData::~wxGridRowOrColAttrData() 
3241     size_t count 
= m_attrs
.GetCount(); 
3242     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3244         m_attrs
[n
]->DecRef(); 
3248 wxGridCellAttr 
*wxGridRowOrColAttrData::GetAttr(int rowOrCol
) const 
3250     wxGridCellAttr 
*attr 
= NULL
; 
3252     int n 
= m_rowsOrCols
.Index(rowOrCol
); 
3253     if ( n 
!= wxNOT_FOUND 
) 
3255         attr 
= m_attrs
[(size_t)n
]; 
3262 void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr 
*attr
, int rowOrCol
) 
3264     int i 
= m_rowsOrCols
.Index(rowOrCol
); 
3265     if ( i 
== wxNOT_FOUND 
) 
3269             // add the attribute - no need to do anything to reference count 
3270             //                     since we take ownership of the attribute. 
3271             m_rowsOrCols
.Add(rowOrCol
); 
3274         // nothing to remove 
3278         size_t n 
= (size_t)i
; 
3279         if ( m_attrs
[n
] == attr 
) 
3284             // change the attribute, handling reference count manually, 
3285             //                       taking ownership of the new attribute. 
3286             m_attrs
[n
]->DecRef(); 
3291             // remove this attribute, handling reference count manually 
3292             m_attrs
[n
]->DecRef(); 
3293             m_rowsOrCols
.RemoveAt(n
); 
3294             m_attrs
.RemoveAt(n
); 
3299 void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos
, int numRowsOrCols 
) 
3301     size_t count 
= m_attrs
.GetCount(); 
3302     for ( size_t n 
= 0; n 
< count
; n
++ ) 
3304         int & rowOrCol 
= m_rowsOrCols
[n
]; 
3305         if ( (size_t)rowOrCol 
>= pos 
) 
3307             if ( numRowsOrCols 
> 0 ) 
3309                 // If rows inserted, include row counter where necessary 
3310                 rowOrCol 
+= numRowsOrCols
; 
3312             else if ( numRowsOrCols 
< 0) 
3314                 // If rows deleted, either decrement row counter (if row still exists) 
3315                 if ((size_t)rowOrCol 
>= pos 
- numRowsOrCols
) 
3316                     rowOrCol 
+= numRowsOrCols
; 
3319                     m_rowsOrCols
.RemoveAt(n
); 
3320                     m_attrs
[n
]->DecRef(); 
3321                     m_attrs
.RemoveAt(n
); 
3330 // ---------------------------------------------------------------------------- 
3331 // wxGridCellAttrProvider 
3332 // ---------------------------------------------------------------------------- 
3334 wxGridCellAttrProvider::wxGridCellAttrProvider() 
3339 wxGridCellAttrProvider::~wxGridCellAttrProvider() 
3344 void wxGridCellAttrProvider::InitData() 
3346     m_data 
= new wxGridCellAttrProviderData
; 
3349 wxGridCellAttr 
*wxGridCellAttrProvider::GetAttr(int row
, int col
, 
3350                                                 wxGridCellAttr::wxAttrKind  kind 
) const 
3352     wxGridCellAttr 
*attr 
= NULL
; 
3357             case (wxGridCellAttr::Any
): 
3358                 // Get cached merge attributes. 
3359                 // Currently not used as no cache implemented as not mutable 
3360                 // attr = m_data->m_mergeAttr.GetAttr(row, col); 
3363                     // Basically implement old version. 
3364                     // Also check merge cache, so we don't have to re-merge every time.. 
3365                     wxGridCellAttr 
*attrcell 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
3366                     wxGridCellAttr 
*attrrow 
= m_data
->m_rowAttrs
.GetAttr(row
); 
3367                     wxGridCellAttr 
*attrcol 
= m_data
->m_colAttrs
.GetAttr(col
); 
3369                     if ((attrcell 
!= attrrow
) && (attrrow 
!= attrcol
) && (attrcell 
!= attrcol
)) 
3371                         // Two or more are non NULL 
3372                         attr 
= new wxGridCellAttr
; 
3373                         attr
->SetKind(wxGridCellAttr::Merged
); 
3375                         // Order is important.. 
3378                             attr
->MergeWith(attrcell
); 
3383                             attr
->MergeWith(attrcol
); 
3388                             attr
->MergeWith(attrrow
); 
3392                         // store merge attr if cache implemented 
3394                         //m_data->m_mergeAttr.SetAttr(attr, row, col); 
3398                         // one or none is non null return it or null. 
3417             case (wxGridCellAttr::Cell
): 
3418                 attr 
= m_data
->m_cellAttrs
.GetAttr(row
, col
); 
3421             case (wxGridCellAttr::Col
): 
3422                 attr 
= m_data
->m_colAttrs
.GetAttr(col
); 
3425             case (wxGridCellAttr::Row
): 
3426                 attr 
= m_data
->m_rowAttrs
.GetAttr(row
); 
3431                 // (wxGridCellAttr::Default): 
3432                 // (wxGridCellAttr::Merged): 
3440 void wxGridCellAttrProvider::SetAttr(wxGridCellAttr 
*attr
, 
3446     m_data
->m_cellAttrs
.SetAttr(attr
, row
, col
); 
3449 void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
3454     m_data
->m_rowAttrs
.SetAttr(attr
, row
); 
3457 void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
3462     m_data
->m_colAttrs
.SetAttr(attr
, col
); 
3465 void wxGridCellAttrProvider::UpdateAttrRows( size_t pos
, int numRows 
) 
3469         m_data
->m_cellAttrs
.UpdateAttrRows( pos
, numRows 
); 
3471         m_data
->m_rowAttrs
.UpdateAttrRowsOrCols( pos
, numRows 
); 
3475 void wxGridCellAttrProvider::UpdateAttrCols( size_t pos
, int numCols 
) 
3479         m_data
->m_cellAttrs
.UpdateAttrCols( pos
, numCols 
); 
3481         m_data
->m_colAttrs
.UpdateAttrRowsOrCols( pos
, numCols 
); 
3485 // ---------------------------------------------------------------------------- 
3486 // wxGridTypeRegistry 
3487 // ---------------------------------------------------------------------------- 
3489 wxGridTypeRegistry::~wxGridTypeRegistry() 
3491     size_t count 
= m_typeinfo
.GetCount(); 
3492     for ( size_t i 
= 0; i 
< count
; i
++ ) 
3493         delete m_typeinfo
[i
]; 
3496 void wxGridTypeRegistry::RegisterDataType(const wxString
& typeName
, 
3497                                           wxGridCellRenderer
* renderer
, 
3498                                           wxGridCellEditor
* editor
) 
3500     wxGridDataTypeInfo
* info 
= new wxGridDataTypeInfo(typeName
, renderer
, editor
); 
3502     // is it already registered? 
3503     int loc 
= FindRegisteredDataType(typeName
); 
3504     if ( loc 
!= wxNOT_FOUND 
) 
3506         delete m_typeinfo
[loc
]; 
3507         m_typeinfo
[loc
] = info
; 
3511         m_typeinfo
.Add(info
); 
3515 int wxGridTypeRegistry::FindRegisteredDataType(const wxString
& typeName
) 
3517     size_t count 
= m_typeinfo
.GetCount(); 
3518     for ( size_t i 
= 0; i 
< count
; i
++ ) 
3520         if ( typeName 
== m_typeinfo
[i
]->m_typeName 
) 
3529 int wxGridTypeRegistry::FindDataType(const wxString
& typeName
) 
3531     int index 
= FindRegisteredDataType(typeName
); 
3532     if ( index 
== wxNOT_FOUND 
) 
3534         // check whether this is one of the standard ones, in which case 
3535         // register it "on the fly" 
3537         if ( typeName 
== wxGRID_VALUE_STRING 
) 
3539             RegisterDataType(wxGRID_VALUE_STRING
, 
3540                              new wxGridCellStringRenderer
, 
3541                              new wxGridCellTextEditor
); 
3544 #endif // wxUSE_TEXTCTRL 
3546         if ( typeName 
== wxGRID_VALUE_BOOL 
) 
3548             RegisterDataType(wxGRID_VALUE_BOOL
, 
3549                              new wxGridCellBoolRenderer
, 
3550                              new wxGridCellBoolEditor
); 
3553 #endif // wxUSE_CHECKBOX 
3555         if ( typeName 
== wxGRID_VALUE_NUMBER 
) 
3557             RegisterDataType(wxGRID_VALUE_NUMBER
, 
3558                              new wxGridCellNumberRenderer
, 
3559                              new wxGridCellNumberEditor
); 
3561         else if ( typeName 
== wxGRID_VALUE_FLOAT 
) 
3563             RegisterDataType(wxGRID_VALUE_FLOAT
, 
3564                              new wxGridCellFloatRenderer
, 
3565                              new wxGridCellFloatEditor
); 
3568 #endif // wxUSE_TEXTCTRL 
3570         if ( typeName 
== wxGRID_VALUE_CHOICE 
) 
3572             RegisterDataType(wxGRID_VALUE_CHOICE
, 
3573                              new wxGridCellStringRenderer
, 
3574                              new wxGridCellChoiceEditor
); 
3577 #endif // wxUSE_COMBOBOX 
3582         // we get here only if just added the entry for this type, so return 
3584         index 
= m_typeinfo
.GetCount() - 1; 
3590 int wxGridTypeRegistry::FindOrCloneDataType(const wxString
& typeName
) 
3592     int index 
= FindDataType(typeName
); 
3593     if ( index 
== wxNOT_FOUND 
) 
3595         // the first part of the typename is the "real" type, anything after ':' 
3596         // are the parameters for the renderer 
3597         index 
= FindDataType(typeName
.BeforeFirst(_T(':'))); 
3598         if ( index 
== wxNOT_FOUND 
) 
3603         wxGridCellRenderer 
*renderer 
= GetRenderer(index
); 
3604         wxGridCellRenderer 
*rendererOld 
= renderer
; 
3605         renderer 
= renderer
->Clone(); 
3606         rendererOld
->DecRef(); 
3608         wxGridCellEditor 
*editor 
= GetEditor(index
); 
3609         wxGridCellEditor 
*editorOld 
= editor
; 
3610         editor 
= editor
->Clone(); 
3611         editorOld
->DecRef(); 
3613         // do it even if there are no parameters to reset them to defaults 
3614         wxString params 
= typeName
.AfterFirst(_T(':')); 
3615         renderer
->SetParameters(params
); 
3616         editor
->SetParameters(params
); 
3618         // register the new typename 
3619         RegisterDataType(typeName
, renderer
, editor
); 
3621         // we just registered it, it's the last one 
3622         index 
= m_typeinfo
.GetCount() - 1; 
3628 wxGridCellRenderer
* wxGridTypeRegistry::GetRenderer(int index
) 
3630     wxGridCellRenderer
* renderer 
= m_typeinfo
[index
]->m_renderer
; 
3637 wxGridCellEditor
* wxGridTypeRegistry::GetEditor(int index
) 
3639     wxGridCellEditor
* editor 
= m_typeinfo
[index
]->m_editor
; 
3646 // ---------------------------------------------------------------------------- 
3648 // ---------------------------------------------------------------------------- 
3650 IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase
, wxObject 
) 
3652 wxGridTableBase::wxGridTableBase() 
3655     m_attrProvider 
= NULL
; 
3658 wxGridTableBase::~wxGridTableBase() 
3660     delete m_attrProvider
; 
3663 void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider 
*attrProvider
) 
3665     delete m_attrProvider
; 
3666     m_attrProvider 
= attrProvider
; 
3669 bool wxGridTableBase::CanHaveAttributes() 
3671     if ( ! GetAttrProvider() ) 
3673         // use the default attr provider by default 
3674         SetAttrProvider(new wxGridCellAttrProvider
); 
3680 wxGridCellAttr 
*wxGridTableBase::GetAttr(int row
, int col
, wxGridCellAttr::wxAttrKind  kind
) 
3682     if ( m_attrProvider 
) 
3683         return m_attrProvider
->GetAttr(row
, col
, kind
); 
3688 void wxGridTableBase::SetAttr(wxGridCellAttr
* attr
, int row
, int col
) 
3690     if ( m_attrProvider 
) 
3693             attr
->SetKind(wxGridCellAttr::Cell
); 
3694         m_attrProvider
->SetAttr(attr
, row
, col
); 
3698         // as we take ownership of the pointer and don't store it, we must 
3704 void wxGridTableBase::SetRowAttr(wxGridCellAttr 
*attr
, int row
) 
3706     if ( m_attrProvider 
) 
3708         attr
->SetKind(wxGridCellAttr::Row
); 
3709         m_attrProvider
->SetRowAttr(attr
, row
); 
3713         // as we take ownership of the pointer and don't store it, we must 
3719 void wxGridTableBase::SetColAttr(wxGridCellAttr 
*attr
, int col
) 
3721     if ( m_attrProvider 
) 
3723         attr
->SetKind(wxGridCellAttr::Col
); 
3724         m_attrProvider
->SetColAttr(attr
, col
); 
3728         // as we take ownership of the pointer and don't store it, we must 
3734 bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos
), 
3735                                   size_t WXUNUSED(numRows
) ) 
3737     wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") ); 
3742 bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows
) ) 
3744     wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function")); 
3749 bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos
), 
3750                                   size_t WXUNUSED(numRows
) ) 
3752     wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function")); 
3757 bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos
), 
3758                                   size_t WXUNUSED(numCols
) ) 
3760     wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function")); 
3765 bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols
) ) 
3767     wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function")); 
3772 bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos
), 
3773                                   size_t WXUNUSED(numCols
) ) 
3775     wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function")); 
3780 wxString 
wxGridTableBase::GetRowLabelValue( int row 
) 
3784     // RD: Starting the rows at zero confuses users, 
3785     // no matter how much it makes sense to us geeks. 
3791 wxString 
wxGridTableBase::GetColLabelValue( int col 
) 
3793     // default col labels are: 
3794     //   cols 0 to 25   : A-Z 
3795     //   cols 26 to 675 : AA-ZZ 
3800     for ( n 
= 1; ; n
++ ) 
3802         s 
+= (wxChar
) (_T('A') + (wxChar
)(col 
% 26)); 
3808     // reverse the string... 
3810     for ( i 
= 0; i 
< n
; i
++ ) 
3818 wxString 
wxGridTableBase::GetTypeName( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3820     return wxGRID_VALUE_STRING
; 
3823 bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row
), int WXUNUSED(col
), 
3824                                      const wxString
& typeName 
) 
3826     return typeName 
== wxGRID_VALUE_STRING
; 
3829 bool wxGridTableBase::CanSetValueAs( int row
, int col
, const wxString
& typeName 
) 
3831     return CanGetValueAs(row
, col
, typeName
); 
3834 long wxGridTableBase::GetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3839 double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3844 bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
) ) 
3849 void wxGridTableBase::SetValueAsLong( int WXUNUSED(row
), int WXUNUSED(col
), 
3850                                       long WXUNUSED(value
) ) 
3854 void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row
), int WXUNUSED(col
), 
3855                                         double WXUNUSED(value
) ) 
3859 void wxGridTableBase::SetValueAsBool( int WXUNUSED(row
), int WXUNUSED(col
), 
3860                                       bool WXUNUSED(value
) ) 
3864 void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
3865                                          const wxString
& WXUNUSED(typeName
) ) 
3870 void  wxGridTableBase::SetValueAsCustom( int WXUNUSED(row
), int WXUNUSED(col
), 
3871                                          const wxString
& WXUNUSED(typeName
), 
3872                                          void* WXUNUSED(value
) ) 
3876 ////////////////////////////////////////////////////////////////////// 
3878 // Message class for the grid table to send requests and notifications 
3882 wxGridTableMessage::wxGridTableMessage() 
3890 wxGridTableMessage::wxGridTableMessage( wxGridTableBase 
*table
, int id
, 
3891                                         int commandInt1
, int commandInt2 
) 
3895     m_comInt1 
= commandInt1
; 
3896     m_comInt2 
= commandInt2
; 
3899 ////////////////////////////////////////////////////////////////////// 
3901 // A basic grid table for string data. An object of this class will 
3902 // created by wxGrid if you don't specify an alternative table class. 
3905 WX_DEFINE_OBJARRAY(wxGridStringArray
) 
3907 IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable
, wxGridTableBase 
) 
3909 wxGridStringTable::wxGridStringTable() 
3914 wxGridStringTable::wxGridStringTable( int numRows
, int numCols 
) 
3917     m_data
.Alloc( numRows 
); 
3920     sa
.Alloc( numCols 
); 
3921     sa
.Add( wxEmptyString
, numCols 
); 
3923     m_data
.Add( sa
, numRows 
); 
3926 wxGridStringTable::~wxGridStringTable() 
3930 int wxGridStringTable::GetNumberRows() 
3932     return m_data
.GetCount(); 
3935 int wxGridStringTable::GetNumberCols() 
3937     if ( m_data
.GetCount() > 0 ) 
3938         return m_data
[0].GetCount(); 
3943 wxString 
wxGridStringTable::GetValue( int row
, int col 
) 
3945     wxCHECK_MSG( (row 
< GetNumberRows()) && (col 
< GetNumberCols()), 
3947                  _T("invalid row or column index in wxGridStringTable") ); 
3949     return m_data
[row
][col
]; 
3952 void wxGridStringTable::SetValue( int row
, int col
, const wxString
& value 
) 
3954     wxCHECK_RET( (row 
< GetNumberRows()) && (col 
< GetNumberCols()), 
3955                  _T("invalid row or column index in wxGridStringTable") ); 
3957     m_data
[row
][col
] = value
; 
3960 void wxGridStringTable::Clear() 
3963     int numRows
, numCols
; 
3965     numRows 
= m_data
.GetCount(); 
3968         numCols 
= m_data
[0].GetCount(); 
3970         for ( row 
= 0; row 
< numRows
; row
++ ) 
3972             for ( col 
= 0; col 
< numCols
; col
++ ) 
3974                 m_data
[row
][col
] = wxEmptyString
; 
3980 bool wxGridStringTable::InsertRows( size_t pos
, size_t numRows 
) 
3982     size_t curNumRows 
= m_data
.GetCount(); 
3983     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
3984                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
3986     if ( pos 
>= curNumRows 
) 
3988         return AppendRows( numRows 
); 
3992     sa
.Alloc( curNumCols 
); 
3993     sa
.Add( wxEmptyString
, curNumCols 
); 
3994     m_data
.Insert( sa
, pos
, numRows 
); 
3998         wxGridTableMessage 
msg( this, 
3999                                 wxGRIDTABLE_NOTIFY_ROWS_INSERTED
, 
4003         GetView()->ProcessTableMessage( msg 
); 
4009 bool wxGridStringTable::AppendRows( size_t numRows 
) 
4011     size_t curNumRows 
= m_data
.GetCount(); 
4012     size_t curNumCols 
= ( curNumRows 
> 0 
4013                          ? m_data
[0].GetCount() 
4014                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
4017     if ( curNumCols 
> 0 ) 
4019         sa
.Alloc( curNumCols 
); 
4020         sa
.Add( wxEmptyString
, curNumCols 
); 
4023     m_data
.Add( sa
, numRows 
); 
4027         wxGridTableMessage 
msg( this, 
4028                                 wxGRIDTABLE_NOTIFY_ROWS_APPENDED
, 
4031         GetView()->ProcessTableMessage( msg 
); 
4037 bool wxGridStringTable::DeleteRows( size_t pos
, size_t numRows 
) 
4039     size_t curNumRows 
= m_data
.GetCount(); 
4041     if ( pos 
>= curNumRows 
) 
4043         wxFAIL_MSG( wxString::Format
 
4045                         wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"), 
4047                         (unsigned long)numRows
, 
4048                         (unsigned long)curNumRows
 
4054     if ( numRows 
> curNumRows 
- pos 
) 
4056         numRows 
= curNumRows 
- pos
; 
4059     if ( numRows 
>= curNumRows 
) 
4065         m_data
.RemoveAt( pos
, numRows 
); 
4070         wxGridTableMessage 
msg( this, 
4071                                 wxGRIDTABLE_NOTIFY_ROWS_DELETED
, 
4075         GetView()->ProcessTableMessage( msg 
); 
4081 bool wxGridStringTable::InsertCols( size_t pos
, size_t numCols 
) 
4085     size_t curNumRows 
= m_data
.GetCount(); 
4086     size_t curNumCols 
= ( curNumRows 
> 0 
4087                          ? m_data
[0].GetCount() 
4088                          : ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
4090     if ( pos 
>= curNumCols 
) 
4092         return AppendCols( numCols 
); 
4095     if ( !m_colLabels
.IsEmpty() ) 
4097         m_colLabels
.Insert( wxEmptyString
, pos
, numCols 
); 
4100         for ( i 
= pos
; i 
< pos 
+ numCols
; i
++ ) 
4101             m_colLabels
[i
] = wxGridTableBase::GetColLabelValue( i 
); 
4104     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
4106         for ( col 
= pos
; col 
< pos 
+ numCols
; col
++ ) 
4108             m_data
[row
].Insert( wxEmptyString
, col 
); 
4114         wxGridTableMessage 
msg( this, 
4115                                 wxGRIDTABLE_NOTIFY_COLS_INSERTED
, 
4119         GetView()->ProcessTableMessage( msg 
); 
4125 bool wxGridStringTable::AppendCols( size_t numCols 
) 
4129     size_t curNumRows 
= m_data
.GetCount(); 
4131     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
4133         m_data
[row
].Add( wxEmptyString
, numCols 
); 
4138         wxGridTableMessage 
msg( this, 
4139                                 wxGRIDTABLE_NOTIFY_COLS_APPENDED
, 
4142         GetView()->ProcessTableMessage( msg 
); 
4148 bool wxGridStringTable::DeleteCols( size_t pos
, size_t numCols 
) 
4152     size_t curNumRows 
= m_data
.GetCount(); 
4153     size_t curNumCols 
= ( curNumRows 
> 0 ? m_data
[0].GetCount() : 
4154                           ( GetView() ? GetView()->GetNumberCols() : 0 ) ); 
4156     if ( pos 
>= curNumCols 
) 
4158         wxFAIL_MSG( wxString::Format
 
4160                         wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"), 
4162                         (unsigned long)numCols
, 
4163                         (unsigned long)curNumCols
 
4170         colID 
= GetView()->GetColAt( pos 
); 
4174     if ( numCols 
> curNumCols 
- colID 
) 
4176         numCols 
= curNumCols 
- colID
; 
4179     if ( !m_colLabels
.IsEmpty() ) 
4181         // m_colLabels stores just as many elements as it needs, e.g. if only 
4182         // the label of the first column had been set it would have only one 
4183         // element and not numCols, so account for it 
4184         int nToRm 
= m_colLabels
.size() - colID
; 
4186             m_colLabels
.RemoveAt( colID
, nToRm 
); 
4189     for ( row 
= 0; row 
< curNumRows
; row
++ ) 
4191         if ( numCols 
>= curNumCols 
) 
4193             m_data
[row
].Clear(); 
4197             m_data
[row
].RemoveAt( colID
, numCols 
); 
4203         wxGridTableMessage 
msg( this, 
4204                                 wxGRIDTABLE_NOTIFY_COLS_DELETED
, 
4208         GetView()->ProcessTableMessage( msg 
); 
4214 wxString 
wxGridStringTable::GetRowLabelValue( int row 
) 
4216     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
4218         // using default label 
4220         return wxGridTableBase::GetRowLabelValue( row 
); 
4224         return m_rowLabels
[row
]; 
4228 wxString 
wxGridStringTable::GetColLabelValue( int col 
) 
4230     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
4232         // using default label 
4234         return wxGridTableBase::GetColLabelValue( col 
); 
4238         return m_colLabels
[col
]; 
4242 void wxGridStringTable::SetRowLabelValue( int row
, const wxString
& value 
) 
4244     if ( row 
> (int)(m_rowLabels
.GetCount()) - 1 ) 
4246         int n 
= m_rowLabels
.GetCount(); 
4249         for ( i 
= n
; i 
<= row
; i
++ ) 
4251             m_rowLabels
.Add( wxGridTableBase::GetRowLabelValue(i
) ); 
4255     m_rowLabels
[row
] = value
; 
4258 void wxGridStringTable::SetColLabelValue( int col
, const wxString
& value 
) 
4260     if ( col 
> (int)(m_colLabels
.GetCount()) - 1 ) 
4262         int n 
= m_colLabels
.GetCount(); 
4265         for ( i 
= n
; i 
<= col
; i
++ ) 
4267             m_colLabels
.Add( wxGridTableBase::GetColLabelValue(i
) ); 
4271     m_colLabels
[col
] = value
; 
4275 ////////////////////////////////////////////////////////////////////// 
4276 ////////////////////////////////////////////////////////////////////// 
4278 BEGIN_EVENT_TABLE(wxGridSubwindow
, wxWindow
) 
4279     EVT_MOUSE_CAPTURE_LOST(wxGridSubwindow::OnMouseCaptureLost
) 
4282 void wxGridSubwindow::OnMouseCaptureLost(wxMouseCaptureLostEvent
& WXUNUSED(event
)) 
4284     m_owner
->CancelMouseCapture(); 
4287 BEGIN_EVENT_TABLE( wxGridRowLabelWindow
, wxGridSubwindow 
) 
4288     EVT_PAINT( wxGridRowLabelWindow::OnPaint 
) 
4289     EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel 
) 
4290     EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent 
) 
4293 void wxGridRowLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4297     // NO - don't do this because it will set both the x and y origin 
4298     // coords to match the parent scrolled window and we just want to 
4299     // set the y coord  - MB 
4301     // m_owner->PrepareDC( dc ); 
4304     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
4305     wxPoint pt 
= dc
.GetDeviceOrigin(); 
4306     dc
.SetDeviceOrigin( pt
.x
, pt
.y
-y 
); 
4308     wxArrayInt rows 
= m_owner
->CalcRowLabelsExposed( GetUpdateRegion() ); 
4309     m_owner
->DrawRowLabels( dc
, rows 
); 
4312 void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4314     m_owner
->ProcessRowLabelMouseEvent( event 
); 
4317 void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4319     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
4323 ////////////////////////////////////////////////////////////////////// 
4325 BEGIN_EVENT_TABLE( wxGridColLabelWindow
, wxGridSubwindow 
) 
4326     EVT_PAINT( wxGridColLabelWindow::OnPaint 
) 
4327     EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel 
) 
4328     EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent 
) 
4331 void wxGridColLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4335     // NO - don't do this because it will set both the x and y origin 
4336     // coords to match the parent scrolled window and we just want to 
4337     // set the x coord  - MB 
4339     // m_owner->PrepareDC( dc ); 
4342     m_owner
->CalcUnscrolledPosition( 0, 0, &x
, &y 
); 
4343     wxPoint pt 
= dc
.GetDeviceOrigin(); 
4344     if (GetLayoutDirection() == wxLayout_RightToLeft
) 
4345         dc
.SetDeviceOrigin( pt
.x
+x
, pt
.y 
); 
4347         dc
.SetDeviceOrigin( pt
.x
-x
, pt
.y 
); 
4349     wxArrayInt cols 
= m_owner
->CalcColLabelsExposed( GetUpdateRegion() ); 
4350     m_owner
->DrawColLabels( dc
, cols 
); 
4353 void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4355     m_owner
->ProcessColLabelMouseEvent( event 
); 
4358 void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4360     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
4364 ////////////////////////////////////////////////////////////////////// 
4366 BEGIN_EVENT_TABLE( wxGridCornerLabelWindow
, wxGridSubwindow 
) 
4367     EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel 
) 
4368     EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent 
) 
4369     EVT_PAINT( wxGridCornerLabelWindow::OnPaint 
) 
4372 void wxGridCornerLabelWindow::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
4376     m_owner
->DrawCornerLabel(dc
); 
4379 void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4381     m_owner
->ProcessCornerLabelMouseEvent( event 
); 
4384 void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4386     if (!m_owner
->GetEventHandler()->ProcessEvent(event
)) 
4390 ////////////////////////////////////////////////////////////////////// 
4392 BEGIN_EVENT_TABLE( wxGridWindow
, wxGridSubwindow 
) 
4393     EVT_PAINT( wxGridWindow::OnPaint 
) 
4394     EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel 
) 
4395     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent 
) 
4396     EVT_KEY_DOWN( wxGridWindow::OnKeyDown 
) 
4397     EVT_KEY_UP( wxGridWindow::OnKeyUp 
) 
4398     EVT_CHAR( wxGridWindow::OnChar 
) 
4399     EVT_SET_FOCUS( wxGridWindow::OnFocus 
) 
4400     EVT_KILL_FOCUS( wxGridWindow::OnFocus 
) 
4401     EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground 
) 
4404 void wxGridWindow::OnPaint( wxPaintEvent 
&WXUNUSED(event
) ) 
4406     wxPaintDC 
dc( this ); 
4407     m_owner
->PrepareDC( dc 
); 
4408     wxRegion reg 
= GetUpdateRegion(); 
4409     wxGridCellCoordsArray dirtyCells 
= m_owner
->CalcCellsExposed( reg 
); 
4410     m_owner
->DrawGridCellArea( dc
, dirtyCells 
); 
4412     m_owner
->DrawGridSpace( dc 
); 
4414     m_owner
->DrawAllGridLines( dc
, reg 
); 
4416     m_owner
->DrawHighlight( dc
, dirtyCells 
); 
4419 void wxGridWindow::ScrollWindow( int dx
, int dy
, const wxRect 
*rect 
) 
4421     wxWindow::ScrollWindow( dx
, dy
, rect 
); 
4422     m_owner
->GetGridRowLabelWindow()->ScrollWindow( 0, dy
, rect 
); 
4423     m_owner
->GetGridColLabelWindow()->ScrollWindow( dx
, 0, rect 
); 
4426 void wxGridWindow::OnMouseEvent( wxMouseEvent
& event 
) 
4428     if (event
.ButtonDown(wxMOUSE_BTN_LEFT
) && FindFocus() != this) 
4431     m_owner
->ProcessGridCellMouseEvent( event 
); 
4434 void wxGridWindow::OnMouseWheel( wxMouseEvent
& event 
) 
4436     if (!m_owner
->GetEventHandler()->ProcessEvent( event 
)) 
4440 // This seems to be required for wxMotif/wxGTK otherwise the mouse 
4441 // cursor must be in the cell edit control to get key events 
4443 void wxGridWindow::OnKeyDown( wxKeyEvent
& event 
) 
4445     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4449 void wxGridWindow::OnKeyUp( wxKeyEvent
& event 
) 
4451     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4455 void wxGridWindow::OnChar( wxKeyEvent
& event 
) 
4457     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4461 void wxGridWindow::OnEraseBackground( wxEraseEvent
& WXUNUSED(event
) ) 
4465 void wxGridWindow::OnFocus(wxFocusEvent
& event
) 
4467     // and if we have any selection, it has to be repainted, because it 
4468     // uses different colour when the grid is not focused: 
4469     if ( m_owner
->IsSelection() ) 
4475         // NB: Note that this code is in "else" branch only because the other 
4476         //     branch refreshes everything and so there's no point in calling 
4477         //     Refresh() again, *not* because it should only be done if 
4478         //     !IsSelection(). If the above code is ever optimized to refresh 
4479         //     only selected area, this needs to be moved out of the "else" 
4480         //     branch so that it's always executed. 
4482         // current cell cursor {dis,re}appears on focus change: 
4483         const wxGridCellCoords 
cursorCoords(m_owner
->GetGridCursorRow(), 
4484                                             m_owner
->GetGridCursorCol()); 
4485         const wxRect cursor 
= 
4486             m_owner
->BlockToDeviceRect(cursorCoords
, cursorCoords
); 
4487         Refresh(true, &cursor
); 
4490     if ( !m_owner
->GetEventHandler()->ProcessEvent( event 
) ) 
4494 #define internalXToCol(x) XToCol(x, true) 
4495 #define internalYToRow(y) YToRow(y, true) 
4497 ///////////////////////////////////////////////////////////////////// 
4499 #if wxUSE_EXTENDED_RTTI 
4500 WX_DEFINE_FLAGS( wxGridStyle 
) 
4502 wxBEGIN_FLAGS( wxGridStyle 
) 
4503     // new style border flags, we put them first to 
4504     // use them for streaming out 
4505     wxFLAGS_MEMBER(wxBORDER_SIMPLE
) 
4506     wxFLAGS_MEMBER(wxBORDER_SUNKEN
) 
4507     wxFLAGS_MEMBER(wxBORDER_DOUBLE
) 
4508     wxFLAGS_MEMBER(wxBORDER_RAISED
) 
4509     wxFLAGS_MEMBER(wxBORDER_STATIC
) 
4510     wxFLAGS_MEMBER(wxBORDER_NONE
) 
4512     // old style border flags 
4513     wxFLAGS_MEMBER(wxSIMPLE_BORDER
) 
4514     wxFLAGS_MEMBER(wxSUNKEN_BORDER
) 
4515     wxFLAGS_MEMBER(wxDOUBLE_BORDER
) 
4516     wxFLAGS_MEMBER(wxRAISED_BORDER
) 
4517     wxFLAGS_MEMBER(wxSTATIC_BORDER
) 
4518     wxFLAGS_MEMBER(wxBORDER
) 
4520     // standard window styles 
4521     wxFLAGS_MEMBER(wxTAB_TRAVERSAL
) 
4522     wxFLAGS_MEMBER(wxCLIP_CHILDREN
) 
4523     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
) 
4524     wxFLAGS_MEMBER(wxWANTS_CHARS
) 
4525     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
) 
4526     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
) 
4527     wxFLAGS_MEMBER(wxVSCROLL
) 
4528     wxFLAGS_MEMBER(wxHSCROLL
) 
4530 wxEND_FLAGS( wxGridStyle 
) 
4532 IMPLEMENT_DYNAMIC_CLASS_XTI(wxGrid
, wxScrolledWindow
,"wx/grid.h") 
4534 wxBEGIN_PROPERTIES_TABLE(wxGrid
) 
4535     wxHIDE_PROPERTY( Children 
) 
4536     wxPROPERTY_FLAGS( WindowStyle 
, wxGridStyle 
, long , SetWindowStyleFlag 
, GetWindowStyleFlag 
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
4537 wxEND_PROPERTIES_TABLE() 
4539 wxBEGIN_HANDLERS_TABLE(wxGrid
) 
4540 wxEND_HANDLERS_TABLE() 
4542 wxCONSTRUCTOR_5( wxGrid 
, wxWindow
* , Parent 
, wxWindowID 
, Id 
, wxPoint 
, Position 
, wxSize 
, Size 
, long , WindowStyle 
) 
4545  TODO : Expose more information of a list's layout, etc. via appropriate objects (e.g., NotebookPageInfo) 
4548 IMPLEMENT_DYNAMIC_CLASS( wxGrid
, wxScrolledWindow 
) 
4551 BEGIN_EVENT_TABLE( wxGrid
, wxScrolledWindow 
) 
4552     EVT_PAINT( wxGrid::OnPaint 
) 
4553     EVT_SIZE( wxGrid::OnSize 
) 
4554     EVT_KEY_DOWN( wxGrid::OnKeyDown 
) 
4555     EVT_KEY_UP( wxGrid::OnKeyUp 
) 
4556     EVT_CHAR ( wxGrid::OnChar 
) 
4557     EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground 
) 
4560 bool wxGrid::Create(wxWindow 
*parent
, wxWindowID id
, 
4561                           const wxPoint
& pos
, const wxSize
& size
, 
4562                           long style
, const wxString
& name
) 
4564     if (!wxScrolledWindow::Create(parent
, id
, pos
, size
, 
4565                                   style 
| wxWANTS_CHARS
, name
)) 
4568     m_colMinWidths 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
4569     m_rowMinHeights 
= wxLongToLongHashMap(GRID_HASH_SIZE
); 
4572     SetInitialSize(size
); 
4573     SetScrollRate(m_scrollLineX
, m_scrollLineY
); 
4582         m_winCapture
->ReleaseMouse(); 
4584     // Ensure that the editor control is destroyed before the grid is, 
4585     // otherwise we crash later when the editor tries to do something with the 
4586     // half destroyed grid 
4587     HideCellEditControl(); 
4589     // Must do this or ~wxScrollHelper will pop the wrong event handler 
4590     SetTargetWindow(this); 
4592     wxSafeDecRef(m_defaultCellAttr
); 
4594 #ifdef DEBUG_ATTR_CACHE 
4595     size_t total 
= gs_nAttrCacheHits 
+ gs_nAttrCacheMisses
; 
4596     wxPrintf(_T("wxGrid attribute cache statistics: " 
4597                 "total: %u, hits: %u (%u%%)\n"), 
4598              total
, gs_nAttrCacheHits
, 
4599              total 
? (gs_nAttrCacheHits
*100) / total 
: 0); 
4602     // if we own the table, just delete it, otherwise at least don't leave it 
4603     // with dangling view pointer 
4606     else if ( m_table 
&& m_table
->GetView() == this ) 
4607         m_table
->SetView(NULL
); 
4609     delete m_typeRegistry
; 
4614 // ----- internal init and update functions 
4617 // NOTE: If using the default visual attributes works everywhere then this can 
4618 // be removed as well as the #else cases below. 
4619 #define _USE_VISATTR 0 
4621 void wxGrid::Create() 
4623     // create the type registry 
4624     m_typeRegistry 
= new wxGridTypeRegistry
; 
4626     m_cellEditCtrlEnabled 
= false; 
4628     m_defaultCellAttr 
= new wxGridCellAttr(); 
4630     // Set default cell attributes 
4631     m_defaultCellAttr
->SetDefAttr(m_defaultCellAttr
); 
4632     m_defaultCellAttr
->SetKind(wxGridCellAttr::Default
); 
4633     m_defaultCellAttr
->SetFont(GetFont()); 
4634     m_defaultCellAttr
->SetAlignment(wxALIGN_LEFT
, wxALIGN_TOP
); 
4635     m_defaultCellAttr
->SetRenderer(new wxGridCellStringRenderer
); 
4636     m_defaultCellAttr
->SetEditor(new wxGridCellTextEditor
); 
4639     wxVisualAttributes gva 
= wxListBox::GetClassDefaultAttributes(); 
4640     wxVisualAttributes lva 
= wxPanel::GetClassDefaultAttributes(); 
4642     m_defaultCellAttr
->SetTextColour(gva
.colFg
); 
4643     m_defaultCellAttr
->SetBackgroundColour(gva
.colBg
); 
4646     m_defaultCellAttr
->SetTextColour( 
4647         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT
)); 
4648     m_defaultCellAttr
->SetBackgroundColour( 
4649         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
)); 
4654     m_currentCellCoords 
= wxGridNoCellCoords
; 
4656     // subwindow components that make up the wxGrid 
4657     m_rowLabelWin 
= new wxGridRowLabelWindow(this); 
4658     CreateColumnWindow(); 
4659     m_cornerLabelWin 
= new wxGridCornerLabelWindow(this); 
4660     m_gridWin 
= new wxGridWindow( this ); 
4662     SetTargetWindow( m_gridWin 
); 
4665     wxColour gfg 
= gva
.colFg
; 
4666     wxColour gbg 
= gva
.colBg
; 
4667     wxColour lfg 
= lva
.colFg
; 
4668     wxColour lbg 
= lva
.colBg
; 
4670     wxColour gfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
4671     wxColour gbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
4672     wxColour lfg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
4673     wxColour lbg 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
4676     m_cornerLabelWin
->SetOwnForegroundColour(lfg
); 
4677     m_cornerLabelWin
->SetOwnBackgroundColour(lbg
); 
4678     m_rowLabelWin
->SetOwnForegroundColour(lfg
); 
4679     m_rowLabelWin
->SetOwnBackgroundColour(lbg
); 
4680     m_colWindow
->SetOwnForegroundColour(lfg
); 
4681     m_colWindow
->SetOwnBackgroundColour(lbg
); 
4683     m_gridWin
->SetOwnForegroundColour(gfg
); 
4684     m_gridWin
->SetOwnBackgroundColour(gbg
); 
4686     m_labelBackgroundColour 
= m_rowLabelWin
->GetBackgroundColour(); 
4687     m_labelTextColour 
= m_rowLabelWin
->GetForegroundColour(); 
4689     // now that we have the grid window, use its font to compute the default 
4691     m_defaultRowHeight 
= m_gridWin
->GetCharHeight(); 
4692 #if defined(__WXMOTIF__) || defined(__WXGTK__)  // see also text ctrl sizing in ShowCellEditControl() 
4693     m_defaultRowHeight 
+= 8; 
4695     m_defaultRowHeight 
+= 4; 
4700 void wxGrid::CreateColumnWindow() 
4702     if ( m_useNativeHeader 
) 
4704         m_colWindow 
= new wxGridHeaderCtrl(this); 
4705         m_colLabelHeight 
= m_colWindow
->GetBestSize().y
; 
4707     else // draw labels ourselves 
4709         m_colWindow 
= new wxGridColLabelWindow(this); 
4710         m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
4714 bool wxGrid::CreateGrid( int numRows
, int numCols
, 
4715                          wxGridSelectionModes selmode 
) 
4717     wxCHECK_MSG( !m_created
, 
4719                  wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") ); 
4721     return SetTable(new wxGridStringTable(numRows
, numCols
), true, selmode
); 
4724 void wxGrid::SetSelectionMode(wxGridSelectionModes selmode
) 
4726     wxCHECK_RET( m_created
, 
4727                  wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") ); 
4729     m_selection
->SetSelectionMode( selmode 
); 
4732 wxGrid::wxGridSelectionModes 
wxGrid::GetSelectionMode() const 
4734     wxCHECK_MSG( m_created
, wxGridSelectCells
, 
4735                  wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") ); 
4737     return m_selection
->GetSelectionMode(); 
4741 wxGrid::SetTable(wxGridTableBase 
*table
, 
4743                  wxGrid::wxGridSelectionModes selmode 
) 
4745     bool checkSelection 
= false; 
4748         // stop all processing 
4753             m_table
->SetView(0); 
4765         checkSelection 
= true; 
4767         // kill row and column size arrays 
4768         m_colWidths
.Empty(); 
4769         m_colRights
.Empty(); 
4770         m_rowHeights
.Empty(); 
4771         m_rowBottoms
.Empty(); 
4776         m_numRows 
= table
->GetNumberRows(); 
4777         m_numCols 
= table
->GetNumberCols(); 
4779         if ( m_useNativeHeader 
) 
4780             GetColHeader()->SetColumnCount(m_numCols
); 
4783         m_table
->SetView( this ); 
4784         m_ownTable 
= takeOwnership
; 
4785         m_selection 
= new wxGridSelection( this, selmode 
); 
4788             // If the newly set table is smaller than the 
4789             // original one current cell and selection regions 
4790             // might be invalid, 
4791             m_selectedBlockCorner 
= wxGridNoCellCoords
; 
4792             m_currentCellCoords 
= 
4793               wxGridCellCoords(wxMin(m_numRows
, m_currentCellCoords
.GetRow()), 
4794                                wxMin(m_numCols
, m_currentCellCoords
.GetCol())); 
4795             if (m_selectedBlockTopLeft
.GetRow() >= m_numRows 
|| 
4796                 m_selectedBlockTopLeft
.GetCol() >= m_numCols
) 
4798                 m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
4799                 m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
4802                 m_selectedBlockBottomRight 
= 
4803                   wxGridCellCoords(wxMin(m_numRows
, 
4804                                          m_selectedBlockBottomRight
.GetRow()), 
4806                                          m_selectedBlockBottomRight
.GetCol())); 
4820     m_cornerLabelWin 
= NULL
; 
4821     m_rowLabelWin 
= NULL
; 
4829     m_defaultCellAttr 
= NULL
; 
4830     m_typeRegistry 
= NULL
; 
4831     m_winCapture 
= NULL
; 
4833     m_rowLabelWidth  
= WXGRID_DEFAULT_ROW_LABEL_WIDTH
; 
4834     m_colLabelHeight 
= WXGRID_DEFAULT_COL_LABEL_HEIGHT
; 
4837     m_attrCache
.row 
= -1; 
4838     m_attrCache
.col 
= -1; 
4839     m_attrCache
.attr 
= NULL
; 
4841     m_labelFont 
= GetFont(); 
4842     m_labelFont
.SetWeight( wxBOLD 
); 
4844     m_rowLabelHorizAlign 
= wxALIGN_CENTRE
; 
4845     m_rowLabelVertAlign  
= wxALIGN_CENTRE
; 
4847     m_colLabelHorizAlign 
= wxALIGN_CENTRE
; 
4848     m_colLabelVertAlign  
= wxALIGN_CENTRE
; 
4849     m_colLabelTextOrientation 
= wxHORIZONTAL
; 
4851     m_defaultColWidth  
= WXGRID_DEFAULT_COL_WIDTH
; 
4852     m_defaultRowHeight 
= 0; // this will be initialized after creation 
4854     m_minAcceptableColWidth  
= WXGRID_MIN_COL_WIDTH
; 
4855     m_minAcceptableRowHeight 
= WXGRID_MIN_ROW_HEIGHT
; 
4857     m_gridLineColour 
= wxColour( 192,192,192 ); 
4858     m_gridLinesEnabled 
= true; 
4859     m_gridLinesClipHorz 
= 
4860     m_gridLinesClipVert 
= true; 
4861     m_cellHighlightColour 
= *wxBLACK
; 
4862     m_cellHighlightPenWidth 
= 2; 
4863     m_cellHighlightROPenWidth 
= 1; 
4865     m_canDragColMove 
= false; 
4867     m_cursorMode  
= WXGRID_CURSOR_SELECT_CELL
; 
4868     m_winCapture 
= NULL
; 
4869     m_canDragRowSize 
= true; 
4870     m_canDragColSize 
= true; 
4871     m_canDragGridSize 
= true; 
4872     m_canDragCell 
= false; 
4874     m_dragRowOrCol 
= -1; 
4875     m_isDragging 
= false; 
4876     m_startDragPos 
= wxDefaultPosition
; 
4879     m_nativeColumnLabels 
= false; 
4881     m_waitForSlowClick 
= false; 
4883     m_rowResizeCursor 
= wxCursor( wxCURSOR_SIZENS 
); 
4884     m_colResizeCursor 
= wxCursor( wxCURSOR_SIZEWE 
); 
4886     m_currentCellCoords 
= wxGridNoCellCoords
; 
4888     m_selectedBlockTopLeft 
= 
4889     m_selectedBlockBottomRight 
= 
4890     m_selectedBlockCorner 
= wxGridNoCellCoords
; 
4892     m_selectionBackground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
4893     m_selectionForeground 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
); 
4895     m_editable 
= true;  // default for whole grid 
4897     m_inOnKeyDown 
= false; 
4903     m_scrollLineX 
= GRID_SCROLL_LINE_X
; 
4904     m_scrollLineY 
= GRID_SCROLL_LINE_Y
; 
4907 // ---------------------------------------------------------------------------- 
4908 // the idea is to call these functions only when necessary because they create 
4909 // quite big arrays which eat memory mostly unnecessary - in particular, if 
4910 // default widths/heights are used for all rows/columns, we may not use these 
4913 // with some extra code, it should be possible to only store the widths/heights 
4914 // different from default ones (resulting in space savings for huge grids) but 
4915 // this is not done currently 
4916 // ---------------------------------------------------------------------------- 
4918 void wxGrid::InitRowHeights() 
4920     m_rowHeights
.Empty(); 
4921     m_rowBottoms
.Empty(); 
4923     m_rowHeights
.Alloc( m_numRows 
); 
4924     m_rowBottoms
.Alloc( m_numRows 
); 
4926     m_rowHeights
.Add( m_defaultRowHeight
, m_numRows 
); 
4929     for ( int i 
= 0; i 
< m_numRows
; i
++ ) 
4931         rowBottom 
+= m_defaultRowHeight
; 
4932         m_rowBottoms
.Add( rowBottom 
); 
4936 void wxGrid::InitColWidths() 
4938     m_colWidths
.Empty(); 
4939     m_colRights
.Empty(); 
4941     m_colWidths
.Alloc( m_numCols 
); 
4942     m_colRights
.Alloc( m_numCols 
); 
4944     m_colWidths
.Add( m_defaultColWidth
, m_numCols 
); 
4946     for ( int i 
= 0; i 
< m_numCols
; i
++ ) 
4948         int colRight 
= ( GetColPos( i 
) + 1 ) * m_defaultColWidth
; 
4949         m_colRights
.Add( colRight 
); 
4953 int wxGrid::GetColWidth(int col
) const 
4955     return m_colWidths
.IsEmpty() ? m_defaultColWidth 
: m_colWidths
[col
]; 
4958 int wxGrid::GetColLeft(int col
) const 
4960     return m_colRights
.IsEmpty() ? GetColPos( col 
) * m_defaultColWidth
 
4961                                  : m_colRights
[col
] - m_colWidths
[col
]; 
4964 int wxGrid::GetColRight(int col
) const 
4966     return m_colRights
.IsEmpty() ? (GetColPos( col 
) + 1) * m_defaultColWidth
 
4970 int wxGrid::GetRowHeight(int row
) const 
4972     return m_rowHeights
.IsEmpty() ? m_defaultRowHeight 
: m_rowHeights
[row
]; 
4975 int wxGrid::GetRowTop(int row
) const 
4977     return m_rowBottoms
.IsEmpty() ? row 
* m_defaultRowHeight
 
4978                                   : m_rowBottoms
[row
] - m_rowHeights
[row
]; 
4981 int wxGrid::GetRowBottom(int row
) const 
4983     return m_rowBottoms
.IsEmpty() ? (row 
+ 1) * m_defaultRowHeight
 
4984                                   : m_rowBottoms
[row
]; 
4987 void wxGrid::CalcDimensions() 
4989     // compute the size of the scrollable area 
4990     int w 
= m_numCols 
> 0 ? GetColRight(GetColAt(m_numCols 
- 1)) : 0; 
4991     int h 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
4996     // take into account editor if shown 
4997     if ( IsCellEditControlShown() ) 
5000         int r 
= m_currentCellCoords
.GetRow(); 
5001         int c 
= m_currentCellCoords
.GetCol(); 
5002         int x 
= GetColLeft(c
); 
5003         int y 
= GetRowTop(r
); 
5005         // how big is the editor 
5006         wxGridCellAttr
* attr 
= GetCellAttr(r
, c
); 
5007         wxGridCellEditor
* editor 
= attr
->GetEditor(this, r
, c
); 
5008         editor
->GetControl()->GetSize(&w2
, &h2
); 
5019     // preserve (more or less) the previous position 
5021     GetViewStart( &x
, &y 
); 
5023     // ensure the position is valid for the new scroll ranges 
5025         x 
= wxMax( w 
- 1, 0 ); 
5027         y 
= wxMax( h 
- 1, 0 ); 
5029     // update the virtual size and refresh the scrollbars to reflect it 
5030     m_gridWin
->SetVirtualSize(w
, h
); 
5034     // if our OnSize() hadn't been called (it would if we have scrollbars), we 
5035     // still must reposition the children 
5039 wxSize 
wxGrid::GetSizeAvailableForScrollTarget(const wxSize
& size
) 
5041     wxSize 
sizeGridWin(size
); 
5042     sizeGridWin
.x 
-= m_rowLabelWidth
; 
5043     sizeGridWin
.y 
-= m_colLabelHeight
; 
5048 void wxGrid::CalcWindowSizes() 
5050     // escape if the window is has not been fully created yet 
5052     if ( m_cornerLabelWin 
== NULL 
) 
5056     GetClientSize( &cw
, &ch 
); 
5058     // the grid may be too small to have enough space for the labels yet, don't 
5059     // size the windows to negative sizes in this case 
5060     int gw 
= cw 
- m_rowLabelWidth
; 
5061     int gh 
= ch 
- m_colLabelHeight
; 
5067     if ( m_cornerLabelWin 
&& m_cornerLabelWin
->IsShown() ) 
5068         m_cornerLabelWin
->SetSize( 0, 0, m_rowLabelWidth
, m_colLabelHeight 
); 
5070     if ( m_colWindow 
&& m_colWindow
->IsShown() ) 
5071         m_colWindow
->SetSize( m_rowLabelWidth
, 0, gw
, m_colLabelHeight 
); 
5073     if ( m_rowLabelWin 
&& m_rowLabelWin
->IsShown() ) 
5074         m_rowLabelWin
->SetSize( 0, m_colLabelHeight
, m_rowLabelWidth
, gh 
); 
5076     if ( m_gridWin 
&& m_gridWin
->IsShown() ) 
5077         m_gridWin
->SetSize( m_rowLabelWidth
, m_colLabelHeight
, gw
, gh 
); 
5080 // this is called when the grid table sends a message 
5081 // to indicate that it has been redimensioned 
5083 bool wxGrid::Redimension( wxGridTableMessage
& msg 
) 
5086     bool result 
= false; 
5088     // Clear the attribute cache as the attribute might refer to a different 
5089     // cell than stored in the cache after adding/removing rows/columns. 
5092     // By the same reasoning, the editor should be dismissed if columns are 
5093     // added or removed. And for consistency, it should IMHO always be 
5094     // removed, not only if the cell "underneath" it actually changes. 
5095     // For now, I intentionally do not save the editor's content as the 
5096     // cell it might want to save that stuff to might no longer exist. 
5097     HideCellEditControl(); 
5100     // if we were using the default widths/heights so far, we must change them 
5102     if ( m_colWidths
.IsEmpty() ) 
5107     if ( m_rowHeights
.IsEmpty() ) 
5113     switch ( msg
.GetId() ) 
5115         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
5117             size_t pos 
= msg
.GetCommandInt(); 
5118             int numRows 
= msg
.GetCommandInt2(); 
5120             m_numRows 
+= numRows
; 
5122             if ( !m_rowHeights
.IsEmpty() ) 
5124                 m_rowHeights
.Insert( m_defaultRowHeight
, pos
, numRows 
); 
5125                 m_rowBottoms
.Insert( 0, pos
, numRows 
); 
5129                     bottom 
= m_rowBottoms
[pos 
- 1]; 
5131                 for ( i 
= pos
; i 
< m_numRows
; i
++ ) 
5133                     bottom 
+= m_rowHeights
[i
]; 
5134                     m_rowBottoms
[i
] = bottom
; 
5138             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5140                 // if we have just inserted cols into an empty grid the current 
5141                 // cell will be undefined... 
5143                 SetCurrentCell( 0, 0 ); 
5147                 m_selection
->UpdateRows( pos
, numRows 
); 
5148             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5150                 attrProvider
->UpdateAttrRows( pos
, numRows 
); 
5152             if ( !GetBatchCount() ) 
5155                 m_rowLabelWin
->Refresh(); 
5161         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
5163             int numRows 
= msg
.GetCommandInt(); 
5164             int oldNumRows 
= m_numRows
; 
5165             m_numRows 
+= numRows
; 
5167             if ( !m_rowHeights
.IsEmpty() ) 
5169                 m_rowHeights
.Add( m_defaultRowHeight
, numRows 
); 
5170                 m_rowBottoms
.Add( 0, numRows 
); 
5173                 if ( oldNumRows 
> 0 ) 
5174                     bottom 
= m_rowBottoms
[oldNumRows 
- 1]; 
5176                 for ( i 
= oldNumRows
; i 
< m_numRows
; i
++ ) 
5178                     bottom 
+= m_rowHeights
[i
]; 
5179                     m_rowBottoms
[i
] = bottom
; 
5183             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5185                 // if we have just inserted cols into an empty grid the current 
5186                 // cell will be undefined... 
5188                 SetCurrentCell( 0, 0 ); 
5191             if ( !GetBatchCount() ) 
5194                 m_rowLabelWin
->Refresh(); 
5200         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
5202             size_t pos 
= msg
.GetCommandInt(); 
5203             int numRows 
= msg
.GetCommandInt2(); 
5204             m_numRows 
-= numRows
; 
5206             if ( !m_rowHeights
.IsEmpty() ) 
5208                 m_rowHeights
.RemoveAt( pos
, numRows 
); 
5209                 m_rowBottoms
.RemoveAt( pos
, numRows 
); 
5212                 for ( i 
= 0; i 
< m_numRows
; i
++ ) 
5214                     h 
+= m_rowHeights
[i
]; 
5215                     m_rowBottoms
[i
] = h
; 
5221                 m_currentCellCoords 
= wxGridNoCellCoords
; 
5225                 if ( m_currentCellCoords
.GetRow() >= m_numRows 
) 
5226                     m_currentCellCoords
.Set( 0, 0 ); 
5230                 m_selection
->UpdateRows( pos
, -((int)numRows
) ); 
5231             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5234                 attrProvider
->UpdateAttrRows( pos
, -((int)numRows
) ); 
5236 // ifdef'd out following patch from Paul Gammans 
5238                 // No need to touch column attributes, unless we 
5239                 // removed _all_ rows, in this case, we remove 
5240                 // all column attributes. 
5241                 // I hate to do this here, but the 
5242                 // needed data is not available inside UpdateAttrRows. 
5243                 if ( !GetNumberRows() ) 
5244                     attrProvider
->UpdateAttrCols( 0, -GetNumberCols() ); 
5248             if ( !GetBatchCount() ) 
5251                 m_rowLabelWin
->Refresh(); 
5257         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
5259             size_t pos 
= msg
.GetCommandInt(); 
5260             int numCols 
= msg
.GetCommandInt2(); 
5261             m_numCols 
+= numCols
; 
5263             if ( m_useNativeHeader 
) 
5264                 GetColHeader()->SetColumnCount(m_numCols
); 
5266             if ( !m_colAt
.IsEmpty() ) 
5268                 //Shift the column IDs 
5270                 for ( i 
= 0; i 
< m_numCols 
- numCols
; i
++ ) 
5272                     if ( m_colAt
[i
] >= (int)pos 
) 
5273                         m_colAt
[i
] += numCols
; 
5276                 m_colAt
.Insert( pos
, pos
, numCols 
); 
5278                 //Set the new columns' positions 
5279                 for ( i 
= pos 
+ 1; i 
< (int)pos 
+ numCols
; i
++ ) 
5285             if ( !m_colWidths
.IsEmpty() ) 
5287                 m_colWidths
.Insert( m_defaultColWidth
, pos
, numCols 
); 
5288                 m_colRights
.Insert( 0, pos
, numCols 
); 
5292                     right 
= m_colRights
[GetColAt( pos 
- 1 )]; 
5295                 for ( colPos 
= pos
; colPos 
< m_numCols
; colPos
++ ) 
5297                     i 
= GetColAt( colPos 
); 
5299                     right 
+= m_colWidths
[i
]; 
5300                     m_colRights
[i
] = right
; 
5304             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5306                 // if we have just inserted cols into an empty grid the current 
5307                 // cell will be undefined... 
5309                 SetCurrentCell( 0, 0 ); 
5313                 m_selection
->UpdateCols( pos
, numCols 
); 
5314             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5316                 attrProvider
->UpdateAttrCols( pos
, numCols 
); 
5317             if ( !GetBatchCount() ) 
5320                 m_colWindow
->Refresh(); 
5326         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
5328             int numCols 
= msg
.GetCommandInt(); 
5329             int oldNumCols 
= m_numCols
; 
5330             m_numCols 
+= numCols
; 
5331             if ( m_useNativeHeader 
) 
5332                 GetColHeader()->SetColumnCount(m_numCols
); 
5334             if ( !m_colAt
.IsEmpty() ) 
5336                 m_colAt
.Add( 0, numCols 
); 
5338                 //Set the new columns' positions 
5340                 for ( i 
= oldNumCols
; i 
< m_numCols
; i
++ ) 
5346             if ( !m_colWidths
.IsEmpty() ) 
5348                 m_colWidths
.Add( m_defaultColWidth
, numCols 
); 
5349                 m_colRights
.Add( 0, numCols 
); 
5352                 if ( oldNumCols 
> 0 ) 
5353                     right 
= m_colRights
[GetColAt( oldNumCols 
- 1 )]; 
5356                 for ( colPos 
= oldNumCols
; colPos 
< m_numCols
; colPos
++ ) 
5358                     i 
= GetColAt( colPos 
); 
5360                     right 
+= m_colWidths
[i
]; 
5361                     m_colRights
[i
] = right
; 
5365             if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
5367                 // if we have just inserted cols into an empty grid the current 
5368                 // cell will be undefined... 
5370                 SetCurrentCell( 0, 0 ); 
5372             if ( !GetBatchCount() ) 
5375                 m_colWindow
->Refresh(); 
5381         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
5383             size_t pos 
= msg
.GetCommandInt(); 
5384             int numCols 
= msg
.GetCommandInt2(); 
5385             m_numCols 
-= numCols
; 
5386             if ( m_useNativeHeader 
) 
5387                 GetColHeader()->SetColumnCount(m_numCols
); 
5389             if ( !m_colAt
.IsEmpty() ) 
5391                 int colID 
= GetColAt( pos 
); 
5393                 m_colAt
.RemoveAt( pos
, numCols 
); 
5395                 //Shift the column IDs 
5397                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
5399                     if ( m_colAt
[colPos
] > colID 
) 
5400                         m_colAt
[colPos
] -= numCols
; 
5404             if ( !m_colWidths
.IsEmpty() ) 
5406                 m_colWidths
.RemoveAt( pos
, numCols 
); 
5407                 m_colRights
.RemoveAt( pos
, numCols 
); 
5411                 for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
5413                     i 
= GetColAt( colPos 
); 
5415                     w 
+= m_colWidths
[i
]; 
5422                 m_currentCellCoords 
= wxGridNoCellCoords
; 
5426                 if ( m_currentCellCoords
.GetCol() >= m_numCols 
) 
5427                   m_currentCellCoords
.Set( 0, 0 ); 
5431                 m_selection
->UpdateCols( pos
, -((int)numCols
) ); 
5432             wxGridCellAttrProvider 
* attrProvider 
= m_table
->GetAttrProvider(); 
5435                 attrProvider
->UpdateAttrCols( pos
, -((int)numCols
) ); 
5437 // ifdef'd out following patch from Paul Gammans 
5439                 // No need to touch row attributes, unless we 
5440                 // removed _all_ columns, in this case, we remove 
5441                 // all row attributes. 
5442                 // I hate to do this here, but the 
5443                 // needed data is not available inside UpdateAttrCols. 
5444                 if ( !GetNumberCols() ) 
5445                     attrProvider
->UpdateAttrRows( 0, -GetNumberRows() ); 
5449             if ( !GetBatchCount() ) 
5452                 m_colWindow
->Refresh(); 
5459     if (result 
&& !GetBatchCount() ) 
5460         m_gridWin
->Refresh(); 
5465 wxArrayInt 
wxGrid::CalcRowLabelsExposed( const wxRegion
& reg 
) const 
5467     wxRegionIterator 
iter( reg 
); 
5470     wxArrayInt  rowlabels
; 
5477         // TODO: remove this when we can... 
5478         // There is a bug in wxMotif that gives garbage update 
5479         // rectangles if you jump-scroll a long way by clicking the 
5480         // scrollbar with middle button.  This is a work-around 
5482 #if defined(__WXMOTIF__) 
5484         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5485         if ( r
.GetTop() > ch 
) 
5487         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
5490         // logical bounds of update region 
5493         CalcUnscrolledPosition( 0, r
.GetTop(), &dummy
, &top 
); 
5494         CalcUnscrolledPosition( 0, r
.GetBottom(), &dummy
, &bottom 
); 
5496         // find the row labels within these bounds 
5499         for ( row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
5501             if ( GetRowBottom(row
) < top 
) 
5504             if ( GetRowTop(row
) > bottom 
) 
5507             rowlabels
.Add( row 
); 
5516 wxArrayInt 
wxGrid::CalcColLabelsExposed( const wxRegion
& reg 
) const 
5518     wxRegionIterator 
iter( reg 
); 
5521     wxArrayInt colLabels
; 
5528         // TODO: remove this when we can... 
5529         // There is a bug in wxMotif that gives garbage update 
5530         // rectangles if you jump-scroll a long way by clicking the 
5531         // scrollbar with middle button.  This is a work-around 
5533 #if defined(__WXMOTIF__) 
5535         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5536         if ( r
.GetLeft() > cw 
) 
5538         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
5541         // logical bounds of update region 
5544         CalcUnscrolledPosition( r
.GetLeft(), 0, &left
, &dummy 
); 
5545         CalcUnscrolledPosition( r
.GetRight(), 0, &right
, &dummy 
); 
5547         // find the cells within these bounds 
5551         for ( colPos 
= GetColPos( internalXToCol(left
) ); colPos 
< m_numCols
; colPos
++ ) 
5553             col 
= GetColAt( colPos 
); 
5555             if ( GetColRight(col
) < left 
) 
5558             if ( GetColLeft(col
) > right 
) 
5561             colLabels
.Add( col 
); 
5570 wxGridCellCoordsArray 
wxGrid::CalcCellsExposed( const wxRegion
& reg 
) const 
5572     wxRegionIterator 
iter( reg 
); 
5575     wxGridCellCoordsArray  cellsExposed
; 
5577     int left
, top
, right
, bottom
; 
5582         // TODO: remove this when we can... 
5583         // There is a bug in wxMotif that gives garbage update 
5584         // rectangles if you jump-scroll a long way by clicking the 
5585         // scrollbar with middle button.  This is a work-around 
5587 #if defined(__WXMOTIF__) 
5589         m_gridWin
->GetClientSize( &cw
, &ch 
); 
5590         if ( r
.GetTop() > ch 
) r
.SetTop( 0 ); 
5591         if ( r
.GetLeft() > cw 
) r
.SetLeft( 0 ); 
5592         r
.SetRight( wxMin( r
.GetRight(), cw 
) ); 
5593         r
.SetBottom( wxMin( r
.GetBottom(), ch 
) ); 
5596         // logical bounds of update region 
5598         CalcUnscrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
5599         CalcUnscrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
5601         // find the cells within these bounds 
5604         for ( row 
= internalYToRow(top
); row 
< m_numRows
; row
++ ) 
5606             if ( GetRowBottom(row
) <= top 
) 
5609             if ( GetRowTop(row
) > bottom 
) 
5613             for ( colPos 
= GetColPos( internalXToCol(left
) ); colPos 
< m_numCols
; colPos
++ ) 
5615                 col 
= GetColAt( colPos 
); 
5617                 if ( GetColRight(col
) <= left 
) 
5620                 if ( GetColLeft(col
) > right 
) 
5623                 cellsExposed
.Add( wxGridCellCoords( row
, col 
) ); 
5630     return cellsExposed
; 
5634 void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent
& event 
) 
5637     wxPoint 
pos( event
.GetPosition() ); 
5638     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
5640     if ( event
.Dragging() ) 
5644             m_isDragging 
= true; 
5645             m_rowLabelWin
->CaptureMouse(); 
5648         if ( event
.LeftIsDown() ) 
5650             switch ( m_cursorMode 
) 
5652                 case WXGRID_CURSOR_RESIZE_ROW
: 
5654                     int cw
, ch
, left
, dummy
; 
5655                     m_gridWin
->GetClientSize( &cw
, &ch 
); 
5656                     CalcUnscrolledPosition( 0, 0, &left
, &dummy 
); 
5658                     wxClientDC 
dc( m_gridWin 
); 
5661                                GetRowTop(m_dragRowOrCol
) + 
5662                                GetRowMinimalHeight(m_dragRowOrCol
) ); 
5663                     dc
.SetLogicalFunction(wxINVERT
); 
5664                     if ( m_dragLastPos 
>= 0 ) 
5666                         dc
.DrawLine( left
, m_dragLastPos
, left
+cw
, m_dragLastPos 
); 
5668                     dc
.DrawLine( left
, y
, left
+cw
, y 
); 
5673                 case WXGRID_CURSOR_SELECT_ROW
: 
5675                     if ( (row 
= YToRow( y 
)) >= 0 ) 
5678                             m_selection
->SelectRow(row
, event
); 
5683                 // default label to suppress warnings about "enumeration value 
5684                 // 'xxx' not handled in switch 
5692     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
5697         if (m_rowLabelWin
->HasCapture()) 
5698             m_rowLabelWin
->ReleaseMouse(); 
5699         m_isDragging 
= false; 
5702     // ------------ Entering or leaving the window 
5704     if ( event
.Entering() || event
.Leaving() ) 
5706         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
5709     // ------------ Left button pressed 
5711     else if ( event
.LeftDown() ) 
5713         // don't send a label click event for a hit on the 
5714         // edge of the row label - this is probably the user 
5715         // wanting to resize the row 
5717         if ( YToEdgeOfRow(y
) < 0 ) 
5721                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, row
, -1, event 
) ) 
5723                 if ( !event
.ShiftDown() && !event
.CmdDown() ) 
5727                     if ( event
.ShiftDown() ) 
5729                         m_selection
->SelectBlock
 
5731                                         m_currentCellCoords
.GetRow(), 0, 
5732                                         row
, GetNumberCols() - 1, 
5738                         m_selection
->SelectRow(row
, event
); 
5742                 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW
, m_rowLabelWin
); 
5747             // starting to drag-resize a row 
5748             if ( CanDragRowSize() ) 
5749                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
); 
5753     // ------------ Left double click 
5755     else if (event
.LeftDClick() ) 
5757         row 
= YToEdgeOfRow(y
); 
5762                  !SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, row
, -1, event 
) ) 
5764                 // no default action at the moment 
5769             // adjust row height depending on label text 
5770             AutoSizeRowLabelSize( row 
); 
5772             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
5777     // ------------ Left button released 
5779     else if ( event
.LeftUp() ) 
5781         if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
5783             DoEndDragResizeRow(); 
5785             // Note: we are ending the event *after* doing 
5786             // default processing in this case 
5788             SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
5791         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
); 
5795     // ------------ Right button down 
5797     else if ( event
.RightDown() ) 
5801              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, row
, -1, event 
) ) 
5803             // no default action at the moment 
5807     // ------------ Right double click 
5809     else if ( event
.RightDClick() ) 
5813              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, row
, -1, event 
) ) 
5815             // no default action at the moment 
5819     // ------------ No buttons down and mouse moving 
5821     else if ( event
.Moving() ) 
5823         m_dragRowOrCol 
= YToEdgeOfRow( y 
); 
5824         if ( m_dragRowOrCol 
>= 0 ) 
5826             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
5828                 // don't capture the mouse yet 
5829                 if ( CanDragRowSize() ) 
5830                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, m_rowLabelWin
, false); 
5833         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
5835             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, m_rowLabelWin
, false); 
5840 void wxGrid::DoStartResizeCol(int col
) 
5842     m_dragRowOrCol 
= col
; 
5844     DoUpdateResizeColWidth(GetColWidth(m_dragRowOrCol
)); 
5847 void wxGrid::DoUpdateResizeCol(int x
) 
5849     int cw
, ch
, dummy
, top
; 
5850     m_gridWin
->GetClientSize( &cw
, &ch 
); 
5851     CalcUnscrolledPosition( 0, 0, &dummy
, &top 
); 
5853     wxClientDC 
dc( m_gridWin 
); 
5856     x 
= wxMax( x
, GetColLeft(m_dragRowOrCol
) + GetColMinimalWidth(m_dragRowOrCol
)); 
5857     dc
.SetLogicalFunction(wxINVERT
); 
5858     if ( m_dragLastPos 
>= 0 ) 
5860         dc
.DrawLine( m_dragLastPos
, top
, m_dragLastPos
, top 
+ ch 
); 
5862     dc
.DrawLine( x
, top
, x
, top 
+ ch 
); 
5866 void wxGrid::DoUpdateResizeColWidth(int w
) 
5868     DoUpdateResizeCol(GetColLeft(m_dragRowOrCol
) + w
); 
5871 void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent
& event 
) 
5874     wxPoint 
pos( event
.GetPosition() ); 
5875     CalcUnscrolledPosition( pos
.x
, pos
.y
, &x
, &y 
); 
5877     if ( event
.Dragging() ) 
5881             m_isDragging 
= true; 
5882             GetColLabelWindow()->CaptureMouse(); 
5884             if ( m_cursorMode 
== WXGRID_CURSOR_MOVE_COL 
) 
5885                 m_dragRowOrCol 
= XToCol( x 
); 
5888         if ( event
.LeftIsDown() ) 
5890             switch ( m_cursorMode 
) 
5892                 case WXGRID_CURSOR_RESIZE_COL
: 
5893                 DoUpdateResizeCol(x
); 
5896                 case WXGRID_CURSOR_SELECT_COL
: 
5898                     if ( (col 
= XToCol( x 
)) >= 0 ) 
5901                             m_selection
->SelectCol(col
, event
); 
5906                 case WXGRID_CURSOR_MOVE_COL
: 
5909                         m_moveToCol 
= GetColAt( 0 ); 
5911                         m_moveToCol 
= XToCol( x 
); 
5915                     if ( m_moveToCol 
< 0 ) 
5916                         markerX 
= GetColRight( GetColAt( m_numCols 
- 1 ) ); 
5917                     else if ( x 
>= (GetColLeft( m_moveToCol 
) + (GetColWidth(m_moveToCol
) / 2)) ) 
5919                         m_moveToCol 
= GetColAt( GetColPos( m_moveToCol 
) + 1 ); 
5920                         if ( m_moveToCol 
< 0 ) 
5921                             markerX 
= GetColRight( GetColAt( m_numCols 
- 1 ) ); 
5923                             markerX 
= GetColLeft( m_moveToCol 
); 
5926                         markerX 
= GetColLeft( m_moveToCol 
); 
5928                     if ( markerX 
!= m_dragLastPos 
) 
5930                         wxClientDC 
dc( GetColLabelWindow() ); 
5934                         GetColLabelWindow()->GetClientSize( &cw
, &ch 
); 
5938                         //Clean up the last indicator 
5939                         if ( m_dragLastPos 
>= 0 ) 
5941                             wxPen 
pen( GetColLabelWindow()->GetBackgroundColour(), 2 ); 
5943                             dc
.DrawLine( m_dragLastPos 
+ 1, 0, m_dragLastPos 
+ 1, ch 
); 
5944                             dc
.SetPen(wxNullPen
); 
5946                             if ( XToCol( m_dragLastPos 
) != -1 ) 
5947                                 DrawColLabel( dc
, XToCol( m_dragLastPos 
) ); 
5950                         const wxColour 
*color
; 
5951                         //Moving to the same place? Don't draw a marker 
5952                         if ( (m_moveToCol 
== m_dragRowOrCol
) 
5953                           || (GetColPos( m_moveToCol 
) == GetColPos( m_dragRowOrCol 
) + 1) 
5954                           || (m_moveToCol 
< 0 && m_dragRowOrCol 
== GetColAt( m_numCols 
- 1 ))) 
5955                             color 
= wxLIGHT_GREY
; 
5960                         wxPen 
pen( *color
, 2 ); 
5963                         dc
.DrawLine( markerX
, 0, markerX
, ch 
); 
5965                         dc
.SetPen(wxNullPen
); 
5967                         m_dragLastPos 
= markerX 
- 1; 
5972                 // default label to suppress warnings about "enumeration value 
5973                 // 'xxx' not handled in switch 
5981     if ( m_isDragging 
&& (event
.Entering() || event
.Leaving()) ) 
5986         if (GetColLabelWindow()->HasCapture()) 
5987             GetColLabelWindow()->ReleaseMouse(); 
5988         m_isDragging 
= false; 
5991     // ------------ Entering or leaving the window 
5993     if ( event
.Entering() || event
.Leaving() ) 
5995         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
5998     // ------------ Left button pressed 
6000     else if ( event
.LeftDown() ) 
6002         // don't send a label click event for a hit on the 
6003         // edge of the col label - this is probably the user 
6004         // wanting to resize the col 
6006         if ( XToEdgeOfCol(x
) < 0 ) 
6010                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, col
, event 
) ) 
6012                 if ( m_canDragColMove 
) 
6014                     //Show button as pressed 
6015                     wxClientDC 
dc( GetColLabelWindow() ); 
6016                     int colLeft 
= GetColLeft( col 
); 
6017                     int colRight 
= GetColRight( col 
) - 1; 
6018                     dc
.SetPen( wxPen( GetColLabelWindow()->GetBackgroundColour(), 1 ) ); 
6019                     dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight
-1 ); 
6020                     dc
.DrawLine( colLeft
, 1, colRight
, 1 ); 
6022                     ChangeCursorMode(WXGRID_CURSOR_MOVE_COL
, GetColLabelWindow()); 
6026                     if ( !event
.ShiftDown() && !event
.CmdDown() ) 
6030                         if ( event
.ShiftDown() ) 
6032                             m_selection
->SelectBlock
 
6034                                             0, m_currentCellCoords
.GetCol(), 
6035                                             GetNumberRows() - 1, col
, 
6041                             m_selection
->SelectCol(col
, event
); 
6045                     ChangeCursorMode(WXGRID_CURSOR_SELECT_COL
, GetColLabelWindow()); 
6051             // starting to drag-resize a col 
6053             if ( CanDragColSize() ) 
6054                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow()); 
6058     // ------------ Left double click 
6060     if ( event
.LeftDClick() ) 
6062         col 
= XToEdgeOfCol(x
); 
6067                  ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, col
, event 
) ) 
6069                 // no default action at the moment 
6074             // adjust column width depending on label text 
6075             AutoSizeColLabelSize( col 
); 
6077             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
6082     // ------------ Left button released 
6084     else if ( event
.LeftUp() ) 
6086         switch ( m_cursorMode 
) 
6088             case WXGRID_CURSOR_RESIZE_COL
: 
6089                 DoEndDragResizeCol(); 
6092             case WXGRID_CURSOR_MOVE_COL
: 
6095                 SendEvent( wxEVT_GRID_COL_MOVE
, -1, m_dragRowOrCol
, event 
); 
6098             case WXGRID_CURSOR_SELECT_COL
: 
6099             case WXGRID_CURSOR_SELECT_CELL
: 
6100             case WXGRID_CURSOR_RESIZE_ROW
: 
6101             case WXGRID_CURSOR_SELECT_ROW
: 
6102                 // nothing to do (?) 
6106         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow()); 
6110     // ------------ Right button down 
6112     else if ( event
.RightDown() ) 
6116              !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, col
, event 
) ) 
6118             // no default action at the moment 
6122     // ------------ Right double click 
6124     else if ( event
.RightDClick() ) 
6128              !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, col
, event 
) ) 
6130             // no default action at the moment 
6134     // ------------ No buttons down and mouse moving 
6136     else if ( event
.Moving() ) 
6138         m_dragRowOrCol 
= XToEdgeOfCol( x 
); 
6139         if ( m_dragRowOrCol 
>= 0 ) 
6141             if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6143                 // don't capture the cursor yet 
6144                 if ( CanDragColSize() ) 
6145                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, GetColLabelWindow(), false); 
6148         else if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
6150             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
, GetColLabelWindow(), false); 
6155 void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent
& event 
) 
6157     if ( event
.LeftDown() ) 
6159         // indicate corner label by having both row and 
6162         if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK
, -1, -1, event 
) ) 
6167     else if ( event
.LeftDClick() ) 
6169         SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK
, -1, -1, event 
); 
6171     else if ( event
.RightDown() ) 
6173         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK
, -1, -1, event 
) ) 
6175             // no default action at the moment 
6178     else if ( event
.RightDClick() ) 
6180         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK
, -1, -1, event 
) ) 
6182             // no default action at the moment 
6187 void wxGrid::CancelMouseCapture() 
6189     // cancel operation currently in progress, whatever it is 
6192         m_isDragging 
= false; 
6193         m_startDragPos 
= wxDefaultPosition
; 
6195         m_cursorMode 
= WXGRID_CURSOR_SELECT_CELL
; 
6196         m_winCapture
->SetCursor( *wxSTANDARD_CURSOR 
); 
6197         m_winCapture 
= NULL
; 
6199         // remove traces of whatever we drew on screen 
6204 void wxGrid::ChangeCursorMode(CursorMode mode
, 
6209     static const wxChar 
*cursorModes
[] = 
6219     wxLogTrace(_T("grid"), 
6220                _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"), 
6221                win 
== m_colWindow 
? _T("colLabelWin") 
6222                                   : win 
? _T("rowLabelWin") 
6224                cursorModes
[m_cursorMode
], cursorModes
[mode
]); 
6227     if ( mode 
== m_cursorMode 
&& 
6228          win 
== m_winCapture 
&& 
6229          captureMouse 
== (m_winCapture 
!= NULL
)) 
6234         // by default use the grid itself 
6240         m_winCapture
->ReleaseMouse(); 
6241         m_winCapture 
= NULL
; 
6244     m_cursorMode 
= mode
; 
6246     switch ( m_cursorMode 
) 
6248         case WXGRID_CURSOR_RESIZE_ROW
: 
6249             win
->SetCursor( m_rowResizeCursor 
); 
6252         case WXGRID_CURSOR_RESIZE_COL
: 
6253             win
->SetCursor( m_colResizeCursor 
); 
6256         case WXGRID_CURSOR_MOVE_COL
: 
6257             win
->SetCursor( wxCursor(wxCURSOR_HAND
) ); 
6261             win
->SetCursor( *wxSTANDARD_CURSOR 
); 
6265     // we need to capture mouse when resizing 
6266     bool resize 
= m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
|| 
6267                   m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL
; 
6269     if ( captureMouse 
&& resize 
) 
6271         win
->CaptureMouse(); 
6276 // ---------------------------------------------------------------------------- 
6277 // grid mouse event processing 
6278 // ---------------------------------------------------------------------------- 
6281 wxGrid::DoGridCellDrag(wxMouseEvent
& event
, 
6282                        const wxGridCellCoords
& coords
, 
6285     if ( coords 
== wxGridNoCellCoords 
) 
6286         return; // we're outside any valid cell 
6288     // Hide the edit control, so it won't interfere with drag-shrinking. 
6289     if ( IsCellEditControlShown() ) 
6291         HideCellEditControl(); 
6292         SaveEditControlValue(); 
6295     switch ( event
.GetModifiers() ) 
6298             if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
6299                 m_selectedBlockCorner 
= coords
; 
6300             UpdateBlockBeingSelected(m_selectedBlockCorner
, coords
); 
6304             if ( CanDragCell() ) 
6308                     if ( m_selectedBlockCorner 
== wxGridNoCellCoords
) 
6309                         m_selectedBlockCorner 
= coords
; 
6311                     SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG
, coords
, event
); 
6316             UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
6320             // we don't handle the other key modifiers 
6325 void wxGrid::DoGridLineDrag(wxMouseEvent
& event
, const wxGridOperations
& oper
) 
6327     wxClientDC 
dc(m_gridWin
); 
6329     dc
.SetLogicalFunction(wxINVERT
); 
6331     const wxRect 
rectWin(CalcUnscrolledPosition(wxPoint(0, 0)), 
6332                          m_gridWin
->GetClientSize()); 
6334     // erase the previously drawn line, if any 
6335     if ( m_dragLastPos 
>= 0 ) 
6336         oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
6338     // we need the vertical position for rows and horizontal for columns here 
6339     m_dragLastPos 
= oper
.Dual().Select(CalcUnscrolledPosition(event
.GetPosition())); 
6341     // don't allow resizing beneath the minimal size 
6342     const int posMin 
= oper
.GetLineStartPos(this, m_dragRowOrCol
) + 
6343                         oper
.GetMinimalLineSize(this, m_dragRowOrCol
); 
6344     if ( m_dragLastPos 
< posMin 
) 
6345         m_dragLastPos 
= posMin
; 
6347     // and draw it at the new position 
6348     oper
.DrawParallelLineInRect(dc
, rectWin
, m_dragLastPos
); 
6351 void wxGrid::DoGridDragEvent(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
6353     if ( !m_isDragging 
) 
6355         // Don't start doing anything until the mouse has been dragged far 
6357         const wxPoint
& pt 
= event
.GetPosition(); 
6358         if ( m_startDragPos 
== wxDefaultPosition 
) 
6360             m_startDragPos 
= pt
; 
6364         if ( abs(m_startDragPos
.x 
- pt
.x
) <= DRAG_SENSITIVITY 
&& 
6365                 abs(m_startDragPos
.y 
- pt
.y
) <= DRAG_SENSITIVITY 
) 
6369     const bool isFirstDrag 
= !m_isDragging
; 
6370     m_isDragging 
= true; 
6372     switch ( m_cursorMode 
) 
6374         case WXGRID_CURSOR_SELECT_CELL
: 
6375             DoGridCellDrag(event
, coords
, isFirstDrag
); 
6378         case WXGRID_CURSOR_RESIZE_ROW
: 
6379             DoGridLineDrag(event
, wxGridRowOperations()); 
6382         case WXGRID_CURSOR_RESIZE_COL
: 
6383             DoGridLineDrag(event
, wxGridColumnOperations()); 
6392         m_winCapture 
= m_gridWin
; 
6393         m_winCapture
->CaptureMouse(); 
6398 wxGrid::DoGridCellLeftDown(wxMouseEvent
& event
, 
6399                            const wxGridCellCoords
& coords
, 
6402     if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK
, coords
, event
) ) 
6404         // event handled by user code, no need to do anything here 
6408     if ( !event
.CmdDown() ) 
6411     if ( event
.ShiftDown() ) 
6415             m_selection
->SelectBlock(m_currentCellCoords
, coords
, event
); 
6416             m_selectedBlockCorner 
= coords
; 
6419     else if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
6421         DisableCellEditControl(); 
6422         MakeCellVisible( coords 
); 
6424         if ( event
.CmdDown() ) 
6428                 m_selection
->ToggleCellSelection(coords
, event
); 
6431             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
6432             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
6433             m_selectedBlockCorner 
= coords
; 
6437             m_waitForSlowClick 
= m_currentCellCoords 
== coords 
&& 
6438                                         coords 
!= wxGridNoCellCoords
; 
6439             SetCurrentCell( coords 
); 
6445 wxGrid::DoGridCellLeftDClick(wxMouseEvent
& event
, 
6446                              const wxGridCellCoords
& coords
, 
6449     if ( XToEdgeOfCol(pos
.x
) < 0 && YToEdgeOfRow(pos
.y
) < 0 ) 
6451         if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK
, coords
, event
) ) 
6453             // we want double click to select a cell and start editing 
6454             // (i.e. to behave in same way as sequence of two slow clicks): 
6455             m_waitForSlowClick 
= true; 
6461 wxGrid::DoGridCellLeftUp(wxMouseEvent
& event
, const wxGridCellCoords
& coords
) 
6463     if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6467             m_winCapture
->ReleaseMouse(); 
6468             m_winCapture 
= NULL
; 
6471         if ( coords 
== m_currentCellCoords 
&& m_waitForSlowClick 
&& CanEnableCellControl() ) 
6474             EnableCellEditControl(); 
6476             wxGridCellAttr 
*attr 
= GetCellAttr(coords
); 
6477             wxGridCellEditor 
*editor 
= attr
->GetEditor(this, coords
.GetRow(), coords
.GetCol()); 
6478             editor
->StartingClick(); 
6482             m_waitForSlowClick 
= false; 
6484         else if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
6485              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
6489                 m_selection
->SelectBlock( m_selectedBlockTopLeft
, 
6490                                           m_selectedBlockBottomRight
, 
6494             m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
6495             m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
6497             // Show the edit control, if it has been hidden for 
6499             ShowCellEditControl(); 
6502     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_ROW 
) 
6504         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6505         DoEndDragResizeRow(); 
6507         // Note: we are ending the event *after* doing 
6508         // default processing in this case 
6510         SendEvent( wxEVT_GRID_ROW_SIZE
, m_dragRowOrCol
, -1, event 
); 
6512     else if ( m_cursorMode 
== WXGRID_CURSOR_RESIZE_COL 
) 
6514         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6515         DoEndDragResizeCol(); 
6522 wxGrid::DoGridMouseMoveEvent(wxMouseEvent
& WXUNUSED(event
), 
6523                              const wxGridCellCoords
& coords
, 
6526     if ( coords
.GetRow() < 0 || coords
.GetCol() < 0 ) 
6528         // out of grid cell area 
6529         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6533     int dragRow 
= YToEdgeOfRow( pos
.y 
); 
6534     int dragCol 
= XToEdgeOfCol( pos
.x 
); 
6536     // Dragging on the corner of a cell to resize in both 
6537     // directions is not implemented yet... 
6539     if ( dragRow 
>= 0 && dragCol 
>= 0 ) 
6541         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6547         m_dragRowOrCol 
= dragRow
; 
6549         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6551             if ( CanDragRowSize() && CanDragGridSize() ) 
6552                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW
, NULL
, false); 
6555     // When using the native header window we can only resize the columns by 
6556     // dragging the dividers in it because we can't make it enter into the 
6557     // column resizing mode programmatically 
6558     else if ( dragCol 
>= 0 && !m_useNativeHeader 
) 
6560         m_dragRowOrCol 
= dragCol
; 
6562         if ( m_cursorMode 
== WXGRID_CURSOR_SELECT_CELL 
) 
6564             if ( CanDragColSize() && CanDragGridSize() ) 
6565                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL
, NULL
, false); 
6568     else // Neither on a row or col edge 
6570         if ( m_cursorMode 
!= WXGRID_CURSOR_SELECT_CELL 
) 
6572             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6577 void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent
& event
) 
6579     const wxPoint pos 
= CalcUnscrolledPosition(event
.GetPosition()); 
6581     // coordinates of the cell under mouse 
6582     wxGridCellCoords coords 
= XYToCell(pos
); 
6584     int cell_rows
, cell_cols
; 
6585     GetCellSize( coords
.GetRow(), coords
.GetCol(), &cell_rows
, &cell_cols 
); 
6586     if ( (cell_rows 
< 0) || (cell_cols 
< 0) ) 
6588         coords
.SetRow(coords
.GetRow() + cell_rows
); 
6589         coords
.SetCol(coords
.GetCol() + cell_cols
); 
6592     if ( event
.Dragging() ) 
6594         if ( event
.LeftIsDown() ) 
6595             DoGridDragEvent(event
, coords
); 
6601     m_isDragging 
= false; 
6602     m_startDragPos 
= wxDefaultPosition
; 
6604     // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL 
6605     //     immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under 
6608     if ( event
.Entering() || event
.Leaving() ) 
6610         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL
); 
6611         m_gridWin
->SetCursor( *wxSTANDARD_CURSOR 
); 
6615     // deal with various button presses 
6616     if ( event
.IsButton() ) 
6618         if ( coords 
!= wxGridNoCellCoords 
) 
6620             DisableCellEditControl(); 
6622             if ( event
.LeftDown() ) 
6623                 DoGridCellLeftDown(event
, coords
, pos
); 
6624             else if ( event
.LeftDClick() ) 
6625                 DoGridCellLeftDClick(event
, coords
, pos
); 
6626             else if ( event
.RightDown() ) 
6627                 SendEvent(wxEVT_GRID_CELL_RIGHT_CLICK
, coords
, event
); 
6628             else if ( event
.RightDClick() ) 
6629                 SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK
, coords
, event
); 
6632         // this one should be called even if we're not over any cell 
6633         if ( event
.LeftUp() ) 
6635             DoGridCellLeftUp(event
, coords
); 
6638     else if ( event
.Moving() ) 
6640         DoGridMouseMoveEvent(event
, coords
, pos
); 
6642     else // unknown mouse event? 
6648 void wxGrid::DoEndDragResizeLine(const wxGridOperations
& oper
) 
6650     if ( m_dragLastPos 
== -1 ) 
6653     const wxGridOperations
& doper 
= oper
.Dual(); 
6655     const wxSize size 
= m_gridWin
->GetClientSize(); 
6657     const wxPoint ptOrigin 
= CalcUnscrolledPosition(wxPoint(0, 0)); 
6659     // erase the last line we drew 
6660     wxClientDC 
dc(m_gridWin
); 
6662     dc
.SetLogicalFunction(wxINVERT
); 
6664     const int posLineStart 
= oper
.Select(ptOrigin
); 
6665     const int posLineEnd 
= oper
.Select(ptOrigin
) + oper
.Select(size
); 
6667     oper
.DrawParallelLine(dc
, posLineStart
, posLineEnd
, m_dragLastPos
); 
6669     // temporarily hide the edit control before resizing 
6670     HideCellEditControl(); 
6671     SaveEditControlValue(); 
6673     // do resize the line 
6674     const int lineStart 
= oper
.GetLineStartPos(this, m_dragRowOrCol
); 
6675     oper
.SetLineSize(this, m_dragRowOrCol
, 
6676                      wxMax(m_dragLastPos 
- lineStart
, 
6677                            oper
.GetMinimalLineSize(this, m_dragRowOrCol
))); 
6681     // refresh now if we're not frozen 
6682     if ( !GetBatchCount() ) 
6684         // we need to refresh everything beyond the resized line in the header 
6687         // get the position from which to refresh in the other direction 
6688         wxRect 
rect(CellToRect(oper
.MakeCoords(m_dragRowOrCol
, 0))); 
6689         rect
.SetPosition(CalcScrolledPosition(rect
.GetPosition())); 
6691         // we only need the ordinate (for rows) or abscissa (for columns) here, 
6692         // and need to cover the entire window in the other direction 
6693         oper
.Select(rect
) = 0; 
6695         wxRect 
rectHeader(rect
.GetPosition(), 
6698                                     oper
.GetHeaderWindowSize(this), 
6699                                     doper
.Select(size
) - doper
.Select(rect
) 
6702         oper
.GetHeaderWindow(this)->Refresh(true, &rectHeader
); 
6705         // also refresh the grid window: extend the rectangle 
6708             oper
.SelectSize(rect
) = oper
.Select(size
); 
6710             int subtractLines 
= 0; 
6711             const int lineStart 
= oper
.PosToLine(this, posLineStart
); 
6712             if ( lineStart 
>= 0 ) 
6714                 // ensure that if we have a multi-cell block we redraw all of 
6715                 // it by increasing the refresh area to cover it entirely if a 
6716                 // part of it is affected 
6717                 const int lineEnd 
= oper
.PosToLine(this, posLineEnd
, true); 
6718                 for ( int line 
= lineStart
; line 
< lineEnd
; line
++ ) 
6720                     int cellLines 
= oper
.Select( 
6721                         GetCellSize(oper
.MakeCoords(m_dragRowOrCol
, line
))); 
6722                     if ( cellLines 
< subtractLines 
) 
6723                         subtractLines 
= cellLines
; 
6728                 oper
.GetLineStartPos(this, m_dragRowOrCol 
+ subtractLines
); 
6729             startPos 
= doper
.CalcScrolledPosition(this, startPos
); 
6731             doper
.Select(rect
) = startPos
; 
6732             doper
.SelectSize(rect
) = doper
.Select(size
) - startPos
; 
6734             m_gridWin
->Refresh(false, &rect
); 
6738     // show the edit control back again 
6739     ShowCellEditControl(); 
6742 void wxGrid::DoEndDragResizeRow() 
6744     DoEndDragResizeLine(wxGridRowOperations()); 
6747 void wxGrid::DoEndDragResizeCol(wxMouseEvent 
*event
) 
6749     DoEndDragResizeLine(wxGridColumnOperations()); 
6751     // Note: we are ending the event *after* doing 
6752     // default processing in this case 
6755         SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol
, *event 
); 
6757         SendEvent( wxEVT_GRID_COL_SIZE
, -1, m_dragRowOrCol 
); 
6760 void wxGrid::DoEndDragMoveCol() 
6762     //The user clicked on the column but didn't actually drag 
6763     if ( m_dragLastPos 
< 0 ) 
6765         m_colWindow
->Refresh();   //Do this to "unpress" the column 
6770     if ( m_moveToCol 
== -1 ) 
6771         newPos 
= m_numCols 
- 1; 
6774         newPos 
= GetColPos( m_moveToCol 
); 
6775         if ( newPos 
> GetColPos( m_dragRowOrCol 
) ) 
6779     SetColPos( m_dragRowOrCol
, newPos 
); 
6782 void wxGrid::SetColPos(int idx
, int pos
) 
6784     // we're going to need m_colAt now, initialize it if needed 
6785     if ( m_colAt
.empty() ) 
6787         m_colAt
.reserve(m_numCols
); 
6788         for ( int i 
= 0; i 
< m_numCols
; i
++ ) 
6789             m_colAt
.push_back(i
); 
6792     wxHeaderCtrl::MoveColumnInOrderArray(m_colAt
, idx
, pos
); 
6794     // also recalculate the column rights 
6795     if ( !m_colWidths
.IsEmpty() ) 
6799         for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
6801             int colID 
= GetColAt( colPos 
); 
6803             colRight 
+= m_colWidths
[colID
]; 
6804             m_colRights
[colID
] = colRight
; 
6808     // and make the changes visible 
6809     if ( m_useNativeHeader 
) 
6810         GetColHeader()->SetColumnsOrder(m_colAt
); 
6812         m_colWindow
->Refresh(); 
6813     m_gridWin
->Refresh(); 
6818 void wxGrid::EnableDragColMove( bool enable 
) 
6820     if ( m_canDragColMove 
== enable 
) 
6823     m_canDragColMove 
= enable
; 
6825     if ( !m_canDragColMove 
) 
6829         //Recalculate the column rights 
6830         if ( !m_colWidths
.IsEmpty() ) 
6834             for ( colPos 
= 0; colPos 
< m_numCols
; colPos
++ ) 
6836                 colRight 
+= m_colWidths
[colPos
]; 
6837                 m_colRights
[colPos
] = colRight
; 
6841         m_colWindow
->Refresh(); 
6842         m_gridWin
->Refresh(); 
6848 // ------ interaction with data model 
6850 bool wxGrid::ProcessTableMessage( wxGridTableMessage
& msg 
) 
6852     switch ( msg
.GetId() ) 
6854         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES
: 
6855             return GetModelValues(); 
6857         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES
: 
6858             return SetModelValues(); 
6860         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED
: 
6861         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED
: 
6862         case wxGRIDTABLE_NOTIFY_ROWS_DELETED
: 
6863         case wxGRIDTABLE_NOTIFY_COLS_INSERTED
: 
6864         case wxGRIDTABLE_NOTIFY_COLS_APPENDED
: 
6865         case wxGRIDTABLE_NOTIFY_COLS_DELETED
: 
6866             return Redimension( msg 
); 
6873 // The behaviour of this function depends on the grid table class 
6874 // Clear() function. For the default wxGridStringTable class the 
6875 // behaviour is to replace all cell contents with wxEmptyString but 
6876 // not to change the number of rows or cols. 
6878 void wxGrid::ClearGrid() 
6882         if (IsCellEditControlEnabled()) 
6883             DisableCellEditControl(); 
6886         if (!GetBatchCount()) 
6887             m_gridWin
->Refresh(); 
6892 wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify
)(size_t, size_t), 
6893                       int pos
, int num
, bool WXUNUSED(updateLabels
) ) 
6895     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
6900     if ( IsCellEditControlEnabled() ) 
6901         DisableCellEditControl(); 
6903     return (m_table
->*funcModify
)(pos
, num
); 
6905     // the table will have sent the results of the insert row 
6906     // operation to this view object as a grid table message 
6910 wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend
)(size_t), 
6911                       int num
, bool WXUNUSED(updateLabels
)) 
6913     wxCHECK_MSG( m_created
, false, "must finish creating the grid first" ); 
6918     return (m_table
->*funcAppend
)(num
); 
6922 // ----- event handlers 
6925 // Generate a grid event based on a mouse event and return: 
6926 //  -1 if the event was vetoed 
6927 //  +1 if the event was processed (but not vetoed) 
6928 //   0 if the event wasn't handled 
6930 wxGrid::SendEvent(const wxEventType type
, 
6932                   wxMouseEvent
& mouseEv
) 
6934    bool claimed
, vetoed
; 
6936    if ( type 
== wxEVT_GRID_ROW_SIZE 
|| type 
== wxEVT_GRID_COL_SIZE 
) 
6938        int rowOrCol 
= (row 
== -1 ? col 
: row
); 
6940        wxGridSizeEvent 
gridEvt( GetId(), 
6944                mouseEv
.GetX() + GetRowLabelSize(), 
6945                mouseEv
.GetY() + GetColLabelSize(), 
6948        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6949        vetoed 
= !gridEvt
.IsAllowed(); 
6951    else if ( type 
== wxEVT_GRID_RANGE_SELECT 
) 
6953        // Right now, it should _never_ end up here! 
6954        wxGridRangeSelectEvent 
gridEvt( GetId(), 
6957                m_selectedBlockTopLeft
, 
6958                m_selectedBlockBottomRight
, 
6962        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6963        vetoed 
= !gridEvt
.IsAllowed(); 
6965    else if ( type 
== wxEVT_GRID_LABEL_LEFT_CLICK 
|| 
6966              type 
== wxEVT_GRID_LABEL_LEFT_DCLICK 
|| 
6967              type 
== wxEVT_GRID_LABEL_RIGHT_CLICK 
|| 
6968              type 
== wxEVT_GRID_LABEL_RIGHT_DCLICK 
) 
6970        wxPoint pos 
= mouseEv
.GetPosition(); 
6972        if ( mouseEv
.GetEventObject() == GetGridRowLabelWindow() ) 
6973            pos
.y 
+= GetColLabelSize(); 
6974        if ( mouseEv
.GetEventObject() == GetGridColLabelWindow() ) 
6975            pos
.x 
+= GetRowLabelSize(); 
6977        wxGridEvent 
gridEvt( GetId(), 
6985        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6986        vetoed 
= !gridEvt
.IsAllowed(); 
6990        wxGridEvent 
gridEvt( GetId(), 
6994                mouseEv
.GetX() + GetRowLabelSize(), 
6995                mouseEv
.GetY() + GetColLabelSize(), 
6998        claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
6999        vetoed 
= !gridEvt
.IsAllowed(); 
7002    // A Veto'd event may not be `claimed' so test this first 
7006    return claimed 
? 1 : 0; 
7009 // Generate a grid event of specified type, return value same as above 
7011 int wxGrid::SendEvent(const wxEventType type
, int row
, int col
) 
7013    bool claimed
, vetoed
; 
7015     if ( type 
== wxEVT_GRID_ROW_SIZE 
|| type 
== wxEVT_GRID_COL_SIZE 
) 
7017         int rowOrCol 
= (row 
== -1 ? col 
: row
); 
7019         wxGridSizeEvent 
gridEvt( GetId(), type
, this, rowOrCol 
); 
7021         claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
7022         vetoed  
= !gridEvt
.IsAllowed(); 
7026         wxGridEvent 
gridEvt( GetId(), type
, this, row
, col 
); 
7028         claimed 
= GetEventHandler()->ProcessEvent(gridEvt
); 
7029         vetoed  
= !gridEvt
.IsAllowed(); 
7032     // A Veto'd event may not be `claimed' so test this first 
7036     return claimed 
? 1 : 0; 
7039 void wxGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
7041     // needed to prevent zillions of paint events on MSW 
7045 void wxGrid::Refresh(bool eraseb
, const wxRect
* rect
) 
7047     // Don't do anything if between Begin/EndBatch... 
7048     // EndBatch() will do all this on the last nested one anyway. 
7049     if ( m_created 
&& !GetBatchCount() ) 
7051         // Refresh to get correct scrolled position: 
7052         wxScrolledWindow::Refresh(eraseb
, rect
); 
7056             int rect_x
, rect_y
, rectWidth
, rectHeight
; 
7057             int width_label
, width_cell
, height_label
, height_cell
; 
7060             // Copy rectangle can get scroll offsets.. 
7061             rect_x 
= rect
->GetX(); 
7062             rect_y 
= rect
->GetY(); 
7063             rectWidth 
= rect
->GetWidth(); 
7064             rectHeight 
= rect
->GetHeight(); 
7066             width_label 
= m_rowLabelWidth 
- rect_x
; 
7067             if (width_label 
> rectWidth
) 
7068                 width_label 
= rectWidth
; 
7070             height_label 
= m_colLabelHeight 
- rect_y
; 
7071             if (height_label 
> rectHeight
) 
7072                 height_label 
= rectHeight
; 
7074             if (rect_x 
> m_rowLabelWidth
) 
7076                 x 
= rect_x 
- m_rowLabelWidth
; 
7077                 width_cell 
= rectWidth
; 
7082                 width_cell 
= rectWidth 
- (m_rowLabelWidth 
- rect_x
); 
7085             if (rect_y 
> m_colLabelHeight
) 
7087                 y 
= rect_y 
- m_colLabelHeight
; 
7088                 height_cell 
= rectHeight
; 
7093                 height_cell 
= rectHeight 
- (m_colLabelHeight 
- rect_y
); 
7096             // Paint corner label part intersecting rect. 
7097             if ( width_label 
> 0 && height_label 
> 0 ) 
7099                 wxRect 
anotherrect(rect_x
, rect_y
, width_label
, height_label
); 
7100                 m_cornerLabelWin
->Refresh(eraseb
, &anotherrect
); 
7103             // Paint col labels part intersecting rect. 
7104             if ( width_cell 
> 0 && height_label 
> 0 ) 
7106                 wxRect 
anotherrect(x
, rect_y
, width_cell
, height_label
); 
7107                 m_colWindow
->Refresh(eraseb
, &anotherrect
); 
7110             // Paint row labels part intersecting rect. 
7111             if ( width_label 
> 0 && height_cell 
> 0 ) 
7113                 wxRect 
anotherrect(rect_x
, y
, width_label
, height_cell
); 
7114                 m_rowLabelWin
->Refresh(eraseb
, &anotherrect
); 
7117             // Paint cell area part intersecting rect. 
7118             if ( width_cell 
> 0 && height_cell 
> 0 ) 
7120                 wxRect 
anotherrect(x
, y
, width_cell
, height_cell
); 
7121                 m_gridWin
->Refresh(eraseb
, &anotherrect
); 
7126             m_cornerLabelWin
->Refresh(eraseb
, NULL
); 
7127             m_colWindow
->Refresh(eraseb
, NULL
); 
7128             m_rowLabelWin
->Refresh(eraseb
, NULL
); 
7129             m_gridWin
->Refresh(eraseb
, NULL
); 
7134 void wxGrid::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
7136     if (m_targetWindow 
!= this) // check whether initialisation has been done 
7138         // reposition our children windows 
7143 void wxGrid::OnKeyDown( wxKeyEvent
& event 
) 
7145     if ( m_inOnKeyDown 
) 
7147         // shouldn't be here - we are going round in circles... 
7149         wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") ); 
7152     m_inOnKeyDown 
= true; 
7154     // propagate the event up and see if it gets processed 
7155     wxWindow 
*parent 
= GetParent(); 
7156     wxKeyEvent 
keyEvt( event 
); 
7157     keyEvt
.SetEventObject( parent 
); 
7159     if ( !parent
->GetEventHandler()->ProcessEvent( keyEvt 
) ) 
7161         if (GetLayoutDirection() == wxLayout_RightToLeft
) 
7163             if (event
.GetKeyCode() == WXK_RIGHT
) 
7164                 event
.m_keyCode 
= WXK_LEFT
; 
7165             else if (event
.GetKeyCode() == WXK_LEFT
) 
7166                 event
.m_keyCode 
= WXK_RIGHT
; 
7169         // try local handlers 
7170         switch ( event
.GetKeyCode() ) 
7173                 if ( event
.ControlDown() ) 
7174                     MoveCursorUpBlock( event
.ShiftDown() ); 
7176                     MoveCursorUp( event
.ShiftDown() ); 
7180                 if ( event
.ControlDown() ) 
7181                     MoveCursorDownBlock( event
.ShiftDown() ); 
7183                     MoveCursorDown( event
.ShiftDown() ); 
7187                 if ( event
.ControlDown() ) 
7188                     MoveCursorLeftBlock( event
.ShiftDown() ); 
7190                     MoveCursorLeft( event
.ShiftDown() ); 
7194                 if ( event
.ControlDown() ) 
7195                     MoveCursorRightBlock( event
.ShiftDown() ); 
7197                     MoveCursorRight( event
.ShiftDown() ); 
7201             case WXK_NUMPAD_ENTER
: 
7202                 if ( event
.ControlDown() ) 
7204                     event
.Skip();  // to let the edit control have the return 
7208                     if ( GetGridCursorRow() < GetNumberRows()-1 ) 
7210                         MoveCursorDown( event
.ShiftDown() ); 
7214                         // at the bottom of a column 
7215                         DisableCellEditControl(); 
7225                 if (event
.ShiftDown()) 
7227                     if ( GetGridCursorCol() > 0 ) 
7229                         MoveCursorLeft( false ); 
7234                         DisableCellEditControl(); 
7239                     if ( GetGridCursorCol() < GetNumberCols() - 1 ) 
7241                         MoveCursorRight( false ); 
7246                         DisableCellEditControl(); 
7252                 if ( event
.ControlDown() ) 
7263                 if ( event
.ControlDown() ) 
7265                     GoToCell(m_numRows 
- 1, m_numCols 
- 1); 
7282                 // Ctrl-Space selects the current column, Shift-Space -- the 
7283                 // current row and Ctrl-Shift-Space -- everything 
7284                 switch ( m_selection 
? event
.GetModifiers() : wxMOD_NONE 
) 
7287                         m_selection
->SelectCol(m_currentCellCoords
.GetCol()); 
7291                         m_selection
->SelectRow(m_currentCellCoords
.GetRow()); 
7294                     case wxMOD_CONTROL 
| wxMOD_SHIFT
: 
7295                         m_selection
->SelectBlock(0, 0, 
7296                                                  m_numRows 
- 1, m_numCols 
- 1); 
7300                         if ( !IsEditable() ) 
7302                             MoveCursorRight(false); 
7305                         //else: fall through 
7318     m_inOnKeyDown 
= false; 
7321 void wxGrid::OnKeyUp( wxKeyEvent
& event 
) 
7323     // try local handlers 
7325     if ( event
.GetKeyCode() == WXK_SHIFT 
) 
7327         if ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
7328              m_selectedBlockBottomRight 
!= wxGridNoCellCoords 
) 
7332                 m_selection
->SelectBlock( 
7333                     m_selectedBlockTopLeft
, 
7334                     m_selectedBlockBottomRight
, 
7339         m_selectedBlockTopLeft 
= wxGridNoCellCoords
; 
7340         m_selectedBlockBottomRight 
= wxGridNoCellCoords
; 
7341         m_selectedBlockCorner 
= wxGridNoCellCoords
; 
7345 void wxGrid::OnChar( wxKeyEvent
& event 
) 
7347     // is it possible to edit the current cell at all? 
7348     if ( !IsCellEditControlEnabled() && CanEnableCellControl() ) 
7350         // yes, now check whether the cells editor accepts the key 
7351         int row 
= m_currentCellCoords
.GetRow(); 
7352         int col 
= m_currentCellCoords
.GetCol(); 
7353         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
7354         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
7356         // <F2> is special and will always start editing, for 
7357         // other keys - ask the editor itself 
7358         if ( (event
.GetKeyCode() == WXK_F2 
&& !event
.HasModifiers()) 
7359              || editor
->IsAcceptedKey(event
) ) 
7361             // ensure cell is visble 
7362             MakeCellVisible(row
, col
); 
7363             EnableCellEditControl(); 
7365             // a problem can arise if the cell is not completely 
7366             // visible (even after calling MakeCellVisible the 
7367             // control is not created and calling StartingKey will 
7369             if ( event
.GetKeyCode() != WXK_F2 
&& editor
->IsCreated() && m_cellEditCtrlEnabled 
) 
7370                 editor
->StartingKey(event
); 
7386 void wxGrid::OnEraseBackground(wxEraseEvent
&) 
7390 bool wxGrid::SetCurrentCell( const wxGridCellCoords
& coords 
) 
7392     if ( SendEvent(wxEVT_GRID_SELECT_CELL
, coords
) == -1 ) 
7394         // the event has been vetoed - do nothing 
7398 #if !defined(__WXMAC__) 
7399     wxClientDC 
dc( m_gridWin 
); 
7403     if ( m_currentCellCoords 
!= wxGridNoCellCoords 
) 
7405         DisableCellEditControl(); 
7407         if ( IsVisible( m_currentCellCoords
, false ) ) 
7410             r 
= BlockToDeviceRect( m_currentCellCoords
, m_currentCellCoords 
); 
7411             if ( !m_gridLinesEnabled 
) 
7419             wxGridCellCoordsArray cells 
= CalcCellsExposed( r 
); 
7421             // Otherwise refresh redraws the highlight! 
7422             m_currentCellCoords 
= coords
; 
7424 #if defined(__WXMAC__) 
7425             m_gridWin
->Refresh(true /*, & r */); 
7427             DrawGridCellArea( dc
, cells 
); 
7428             DrawAllGridLines( dc
, r 
); 
7433     m_currentCellCoords 
= coords
; 
7435     wxGridCellAttr 
*attr 
= GetCellAttr( coords 
); 
7436 #if !defined(__WXMAC__) 
7437     DrawCellHighlight( dc
, attr 
); 
7445 wxGrid::UpdateBlockBeingSelected(int topRow
, int leftCol
, 
7446                                  int bottomRow
, int rightCol
) 
7450         switch ( m_selection
->GetSelectionMode() ) 
7453                 wxFAIL_MSG( "unknown selection mode" ); 
7456             case wxGridSelectCells
: 
7457                 // arbitrary blocks selection allowed so just use the cell 
7458                 // coordinates as is 
7461             case wxGridSelectRows
: 
7462                 // only full rows selection allowd, ensure that we do select 
7465                 rightCol 
= GetNumberCols() - 1; 
7468             case wxGridSelectColumns
: 
7469                 // same as above but for columns 
7471                 bottomRow 
= GetNumberRows() - 1; 
7474             case wxGridSelectRowsOrColumns
: 
7475                 // in this mode we can select only full rows or full columns so 
7476                 // it doesn't make sense to select blocks at all (and we can't 
7477                 // extend the block because there is no preferred direction, we 
7478                 // could only extend it to cover the entire grid but this is 
7484     m_selectedBlockCorner 
= wxGridCellCoords(bottomRow
, rightCol
); 
7485     MakeCellVisible(m_selectedBlockCorner
); 
7487     EnsureFirstLessThanSecond(topRow
, bottomRow
); 
7488     EnsureFirstLessThanSecond(leftCol
, rightCol
); 
7490     wxGridCellCoords updateTopLeft 
= wxGridCellCoords(topRow
, leftCol
), 
7491                      updateBottomRight 
= wxGridCellCoords(bottomRow
, rightCol
); 
7493     // First the case that we selected a completely new area 
7494     if ( m_selectedBlockTopLeft 
== wxGridNoCellCoords 
|| 
7495          m_selectedBlockBottomRight 
== wxGridNoCellCoords 
) 
7498         rect 
= BlockToDeviceRect( wxGridCellCoords ( topRow
, leftCol 
), 
7499                                   wxGridCellCoords ( bottomRow
, rightCol 
) ); 
7500         m_gridWin
->Refresh( false, &rect 
); 
7503     // Now handle changing an existing selection area. 
7504     else if ( m_selectedBlockTopLeft 
!= updateTopLeft 
|| 
7505               m_selectedBlockBottomRight 
!= updateBottomRight 
) 
7507         // Compute two optimal update rectangles: 
7508         // Either one rectangle is a real subset of the 
7509         // other, or they are (almost) disjoint! 
7511         bool    need_refresh
[4]; 
7515         need_refresh
[3] = false; 
7518         // Store intermediate values 
7519         wxCoord oldLeft 
= m_selectedBlockTopLeft
.GetCol(); 
7520         wxCoord oldTop 
= m_selectedBlockTopLeft
.GetRow(); 
7521         wxCoord oldRight 
= m_selectedBlockBottomRight
.GetCol(); 
7522         wxCoord oldBottom 
= m_selectedBlockBottomRight
.GetRow(); 
7524         // Determine the outer/inner coordinates. 
7525         EnsureFirstLessThanSecond(oldLeft
, leftCol
); 
7526         EnsureFirstLessThanSecond(oldTop
, topRow
); 
7527         EnsureFirstLessThanSecond(rightCol
, oldRight
); 
7528         EnsureFirstLessThanSecond(bottomRow
, oldBottom
); 
7530         // Now, either the stuff marked old is the outer 
7531         // rectangle or we don't have a situation where one 
7532         // is contained in the other. 
7534         if ( oldLeft 
< leftCol 
) 
7536             // Refresh the newly selected or deselected 
7537             // area to the left of the old or new selection. 
7538             need_refresh
[0] = true; 
7539             rect
[0] = BlockToDeviceRect( 
7540                 wxGridCellCoords( oldTop
,  oldLeft 
), 
7541                 wxGridCellCoords( oldBottom
, leftCol 
- 1 ) ); 
7544         if ( oldTop 
< topRow 
) 
7546             // Refresh the newly selected or deselected 
7547             // area above the old or new selection. 
7548             need_refresh
[1] = true; 
7549             rect
[1] = BlockToDeviceRect( 
7550                 wxGridCellCoords( oldTop
, leftCol 
), 
7551                 wxGridCellCoords( topRow 
- 1, rightCol 
) ); 
7554         if ( oldRight 
> rightCol 
) 
7556             // Refresh the newly selected or deselected 
7557             // area to the right of the old or new selection. 
7558             need_refresh
[2] = true; 
7559             rect
[2] = BlockToDeviceRect( 
7560                 wxGridCellCoords( oldTop
, rightCol 
+ 1 ), 
7561                 wxGridCellCoords( oldBottom
, oldRight 
) ); 
7564         if ( oldBottom 
> bottomRow 
) 
7566             // Refresh the newly selected or deselected 
7567             // area below the old or new selection. 
7568             need_refresh
[3] = true; 
7569             rect
[3] = BlockToDeviceRect( 
7570                 wxGridCellCoords( bottomRow 
+ 1, leftCol 
), 
7571                 wxGridCellCoords( oldBottom
, rightCol 
) ); 
7574         // various Refresh() calls 
7575         for (i 
= 0; i 
< 4; i
++ ) 
7576             if ( need_refresh
[i
] && rect
[i
] != wxGridNoCellRect 
) 
7577                 m_gridWin
->Refresh( false, &(rect
[i
]) ); 
7581     m_selectedBlockTopLeft 
= updateTopLeft
; 
7582     m_selectedBlockBottomRight 
= updateBottomRight
; 
7586 // ------ functions to get/send data (see also public functions) 
7589 bool wxGrid::GetModelValues() 
7591     // Hide the editor, so it won't hide a changed value. 
7592     HideCellEditControl(); 
7596         // all we need to do is repaint the grid 
7598         m_gridWin
->Refresh(); 
7605 bool wxGrid::SetModelValues() 
7609     // Disable the editor, so it won't hide a changed value. 
7610     // Do we also want to save the current value of the editor first? 
7612     DisableCellEditControl(); 
7616         for ( row 
= 0; row 
< m_numRows
; row
++ ) 
7618             for ( col 
= 0; col 
< m_numCols
; col
++ ) 
7620                 m_table
->SetValue( row
, col
, GetCellValue(row
, col
) ); 
7630 // Note - this function only draws cells that are in the list of 
7631 // exposed cells (usually set from the update region by 
7632 // CalcExposedCells) 
7634 void wxGrid::DrawGridCellArea( wxDC
& dc
, const wxGridCellCoordsArray
& cells 
) 
7636     if ( !m_numRows 
|| !m_numCols 
) 
7639     int i
, numCells 
= cells
.GetCount(); 
7640     int row
, col
, cell_rows
, cell_cols
; 
7641     wxGridCellCoordsArray redrawCells
; 
7643     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
7645         row 
= cells
[i
].GetRow(); 
7646         col 
= cells
[i
].GetCol(); 
7647         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
7649         // If this cell is part of a multicell block, find owner for repaint 
7650         if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
7652             wxGridCellCoords 
cell( row 
+ cell_rows
, col 
+ cell_cols 
); 
7653             bool marked 
= false; 
7654             for ( int j 
= 0; j 
< numCells
; j
++ ) 
7656                 if ( cell 
== cells
[j
] ) 
7665                 int count 
= redrawCells
.GetCount(); 
7666                 for (int j 
= 0; j 
< count
; j
++) 
7668                     if ( cell 
== redrawCells
[j
] ) 
7676                     redrawCells
.Add( cell 
); 
7679             // don't bother drawing this cell 
7683         // If this cell is empty, find cell to left that might want to overflow 
7684         if (m_table 
&& m_table
->IsEmptyCell(row
, col
)) 
7686             for ( int l 
= 0; l 
< cell_rows
; l
++ ) 
7688                 // find a cell in this row to leave already marked for repaint 
7690                 for (int k 
= 0; k 
< int(redrawCells
.GetCount()); k
++) 
7691                     if ((redrawCells
[k
].GetCol() < left
) && 
7692                         (redrawCells
[k
].GetRow() == row
)) 
7694                         left 
= redrawCells
[k
].GetCol(); 
7698                     left 
= 0; // oh well 
7700                 for (int j 
= col 
- 1; j 
>= left
; j
--) 
7702                     if (!m_table
->IsEmptyCell(row 
+ l
, j
)) 
7704                         if (GetCellOverflow(row 
+ l
, j
)) 
7706                             wxGridCellCoords 
cell(row 
+ l
, j
); 
7707                             bool marked 
= false; 
7709                             for (int k 
= 0; k 
< numCells
; k
++) 
7711                                 if ( cell 
== cells
[k
] ) 
7720                                 int count 
= redrawCells
.GetCount(); 
7721                                 for (int k 
= 0; k 
< count
; k
++) 
7723                                     if ( cell 
== redrawCells
[k
] ) 
7730                                     redrawCells
.Add( cell 
); 
7739         DrawCell( dc
, cells
[i
] ); 
7742     numCells 
= redrawCells
.GetCount(); 
7744     for ( i 
= numCells 
- 1; i 
>= 0; i
-- ) 
7746         DrawCell( dc
, redrawCells
[i
] ); 
7750 void wxGrid::DrawGridSpace( wxDC
& dc 
) 
7753   m_gridWin
->GetClientSize( &cw
, &ch 
); 
7756   CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
7758   int rightCol 
= m_numCols 
> 0 ? GetColRight(GetColAt( m_numCols 
- 1 )) : 0; 
7759   int bottomRow 
= m_numRows 
> 0 ? GetRowBottom(m_numRows 
- 1) : 0; 
7761   if ( right 
> rightCol 
|| bottom 
> bottomRow 
) 
7764       CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
7766       dc
.SetBrush(GetDefaultCellBackgroundColour()); 
7767       dc
.SetPen( *wxTRANSPARENT_PEN 
); 
7769       if ( right 
> rightCol 
) 
7771           dc
.DrawRectangle( rightCol
, top
, right 
- rightCol
, ch 
); 
7774       if ( bottom 
> bottomRow 
) 
7776           dc
.DrawRectangle( left
, bottomRow
, cw
, bottom 
- bottomRow 
); 
7781 void wxGrid::DrawCell( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
7783     int row 
= coords
.GetRow(); 
7784     int col 
= coords
.GetCol(); 
7786     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7789     // we draw the cell border ourselves 
7790     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
7792     bool isCurrent 
= coords 
== m_currentCellCoords
; 
7794     wxRect rect 
= CellToRect( row
, col 
); 
7796     // if the editor is shown, we should use it and not the renderer 
7797     // Note: However, only if it is really _shown_, i.e. not hidden! 
7798     if ( isCurrent 
&& IsCellEditControlShown() ) 
7800         // NB: this "#if..." is temporary and fixes a problem where the 
7801         // edit control is erased by this code after being rendered. 
7802         // On wxMac (QD build only), the cell editor is a wxTextCntl and is rendered 
7803         // implicitly, causing this out-of order render. 
7804 #if !defined(__WXMAC__) 
7805         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
7806         editor
->PaintBackground(rect
, attr
); 
7812         // but all the rest is drawn by the cell renderer and hence may be customized 
7813         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
7814         renderer
->Draw(*this, *attr
, dc
, rect
, row
, col
, IsInSelection(coords
)); 
7821 void wxGrid::DrawCellHighlight( wxDC
& dc
, const wxGridCellAttr 
*attr 
) 
7823     // don't show highlight when the grid doesn't have focus 
7827     int row 
= m_currentCellCoords
.GetRow(); 
7828     int col 
= m_currentCellCoords
.GetCol(); 
7830     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7833     wxRect rect 
= CellToRect(row
, col
); 
7835     // hmmm... what could we do here to show that the cell is disabled? 
7836     // for now, I just draw a thinner border than for the other ones, but 
7837     // it doesn't look really good 
7839     int penWidth 
= attr
->IsReadOnly() ? m_cellHighlightROPenWidth 
: m_cellHighlightPenWidth
; 
7843         // The center of the drawn line is where the position/width/height of 
7844         // the rectangle is actually at (on wxMSW at least), so the 
7845         // size of the rectangle is reduced to compensate for the thickness of 
7846         // the line. If this is too strange on non-wxMSW platforms then 
7847         // please #ifdef this appropriately. 
7848         rect
.x 
+= penWidth 
/ 2; 
7849         rect
.y 
+= penWidth 
/ 2; 
7850         rect
.width 
-= penWidth 
- 1; 
7851         rect
.height 
-= penWidth 
- 1; 
7853         // Now draw the rectangle 
7854         // use the cellHighlightColour if the cell is inside a selection, this 
7855         // will ensure the cell is always visible. 
7856         dc
.SetPen(wxPen(IsInSelection(row
,col
) ? m_selectionForeground
 
7857                                                : m_cellHighlightColour
, 
7859         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
7860         dc
.DrawRectangle(rect
); 
7864 wxPen 
wxGrid::GetDefaultGridLinePen() 
7866     return wxPen(GetGridLineColour()); 
7869 wxPen 
wxGrid::GetRowGridLinePen(int WXUNUSED(row
)) 
7871     return GetDefaultGridLinePen(); 
7874 wxPen 
wxGrid::GetColGridLinePen(int WXUNUSED(col
)) 
7876     return GetDefaultGridLinePen(); 
7879 void wxGrid::DrawCellBorder( wxDC
& dc
, const wxGridCellCoords
& coords 
) 
7881     int row 
= coords
.GetRow(); 
7882     int col 
= coords
.GetCol(); 
7883     if ( GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
7887     wxRect rect 
= CellToRect( row
, col 
); 
7889     // right hand border 
7890     dc
.SetPen( GetColGridLinePen(col
) ); 
7891     dc
.DrawLine( rect
.x 
+ rect
.width
, rect
.y
, 
7892                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height 
+ 1 ); 
7895     dc
.SetPen( GetRowGridLinePen(row
) ); 
7896     dc
.DrawLine( rect
.x
, rect
.y 
+ rect
.height
, 
7897                  rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height
); 
7900 void wxGrid::DrawHighlight(wxDC
& dc
, const wxGridCellCoordsArray
& cells
) 
7902     // This if block was previously in wxGrid::OnPaint but that doesn't 
7903     // seem to get called under wxGTK - MB 
7905     if ( m_currentCellCoords 
== wxGridNoCellCoords 
&& 
7906          m_numRows 
&& m_numCols 
) 
7908         m_currentCellCoords
.Set(0, 0); 
7911     if ( IsCellEditControlShown() ) 
7913         // don't show highlight when the edit control is shown 
7917     // if the active cell was repainted, repaint its highlight too because it 
7918     // might have been damaged by the grid lines 
7919     size_t count 
= cells
.GetCount(); 
7920     for ( size_t n 
= 0; n 
< count
; n
++ ) 
7922         wxGridCellCoords cell 
= cells
[n
]; 
7924         // If we are using attributes, then we may have just exposed another 
7925         // cell in a partially-visible merged cluster of cells. If the "anchor" 
7926         // (upper left) cell of this merged cluster is the cell indicated by 
7927         // m_currentCellCoords, then we need to refresh the cell highlight even 
7928         // though the "anchor" itself is not part of our update segment. 
7929         if ( CanHaveAttributes() ) 
7933             GetCellSize(cell
.GetRow(), cell
.GetCol(), &rows
, &cols
); 
7936                 cell
.SetRow(cell
.GetRow() + rows
); 
7939                 cell
.SetCol(cell
.GetCol() + cols
); 
7942         if ( cell 
== m_currentCellCoords 
) 
7944             wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
7945             DrawCellHighlight(dc
, attr
); 
7953 // This is used to redraw all grid lines e.g. when the grid line colour 
7956 void wxGrid::DrawAllGridLines( wxDC
& dc
, const wxRegion 
& WXUNUSED(reg
) ) 
7958     if ( !m_gridLinesEnabled 
) 
7961     int top
, bottom
, left
, right
; 
7964     m_gridWin
->GetClientSize(&cw
, &ch
); 
7965     CalcUnscrolledPosition( 0, 0, &left
, &top 
); 
7966     CalcUnscrolledPosition( cw
, ch
, &right
, &bottom 
); 
7968     // avoid drawing grid lines past the last row and col 
7969     if ( m_gridLinesClipHorz 
) 
7974         const int lastColRight 
= GetColRight(GetColAt(m_numCols 
- 1)); 
7975         if ( right 
> lastColRight 
) 
7976             right 
= lastColRight
; 
7979     if ( m_gridLinesClipVert 
) 
7984         const int lastRowBottom 
= GetRowBottom(m_numRows 
- 1); 
7985         if ( bottom 
> lastRowBottom 
) 
7986             bottom 
= lastRowBottom
; 
7989     // no gridlines inside multicells, clip them out 
7990     int leftCol 
= GetColPos( internalXToCol(left
) ); 
7991     int topRow 
= internalYToRow(top
); 
7992     int rightCol 
= GetColPos( internalXToCol(right
) ); 
7993     int bottomRow 
= internalYToRow(bottom
); 
7995     wxRegion 
clippedcells(0, 0, cw
, ch
); 
7997     int cell_rows
, cell_cols
; 
8000     for ( int j 
= topRow
; j 
<= bottomRow
; j
++ ) 
8002         for ( int colPos 
= leftCol
; colPos 
<= rightCol
; colPos
++ ) 
8004             int i 
= GetColAt( colPos 
); 
8006             GetCellSize( j
, i
, &cell_rows
, &cell_cols 
); 
8007             if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
8009                 rect 
= CellToRect(j
,i
); 
8010                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8011                 clippedcells
.Subtract(rect
); 
8013             else if ((cell_rows 
< 0) || (cell_cols 
< 0)) 
8015                 rect 
= CellToRect(j 
+ cell_rows
, i 
+ cell_cols
); 
8016                 CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8017                 clippedcells
.Subtract(rect
); 
8022     dc
.SetDeviceClippingRegion( clippedcells 
); 
8025     // horizontal grid lines 
8026     for ( int i 
= internalYToRow(top
); i 
< m_numRows
; i
++ ) 
8028         int bot 
= GetRowBottom(i
) - 1; 
8035             dc
.SetPen( GetRowGridLinePen(i
) ); 
8036             dc
.DrawLine( left
, bot
, right
, bot 
); 
8040     // vertical grid lines 
8041     for ( int colPos 
= leftCol
; colPos 
< m_numCols
; colPos
++ ) 
8043         int i 
= GetColAt( colPos 
); 
8045         int colRight 
= GetColRight(i
); 
8047         if (GetLayoutDirection() != wxLayout_RightToLeft
) 
8051         if ( colRight 
> right 
) 
8054         if ( colRight 
>= left 
) 
8056             dc
.SetPen( GetColGridLinePen(i
) ); 
8057             dc
.DrawLine( colRight
, top
, colRight
, bottom 
); 
8061     dc
.DestroyClippingRegion(); 
8064 void wxGrid::DrawRowLabels( wxDC
& dc
, const wxArrayInt
& rows
) 
8069     const size_t numLabels 
= rows
.GetCount(); 
8070     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
8072         DrawRowLabel( dc
, rows
[i
] ); 
8076 void wxGrid::DrawRowLabel( wxDC
& dc
, int row 
) 
8078     if ( GetRowHeight(row
) <= 0 || m_rowLabelWidth 
<= 0 ) 
8083     int rowTop 
= GetRowTop(row
), 
8084         rowBottom 
= GetRowBottom(row
) - 1; 
8086     dc
.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8087     dc
.DrawLine( m_rowLabelWidth 
- 1, rowTop
, m_rowLabelWidth 
- 1, rowBottom 
); 
8088     dc
.DrawLine( 0, rowTop
, 0, rowBottom 
); 
8089     dc
.DrawLine( 0, rowBottom
, m_rowLabelWidth
, rowBottom 
); 
8091     dc
.SetPen( *wxWHITE_PEN 
); 
8092     dc
.DrawLine( 1, rowTop
, 1, rowBottom 
); 
8093     dc
.DrawLine( 1, rowTop
, m_rowLabelWidth 
- 1, rowTop 
); 
8095     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
8096     dc
.SetTextForeground( GetLabelTextColour() ); 
8097     dc
.SetFont( GetLabelFont() ); 
8100     GetRowLabelAlignment( &hAlign
, &vAlign 
); 
8103     rect
.SetY( GetRowTop(row
) + 2 ); 
8104     rect
.SetWidth( m_rowLabelWidth 
- 4 ); 
8105     rect
.SetHeight( GetRowHeight(row
) - 4 ); 
8106     DrawTextRectangle( dc
, GetRowLabelValue( row 
), rect
, hAlign
, vAlign 
); 
8109 void wxGrid::UseNativeColHeader(bool native
) 
8111     if ( native 
== m_useNativeHeader 
) 
8115     m_useNativeHeader 
= native
; 
8117     CreateColumnWindow(); 
8119     if ( m_useNativeHeader 
) 
8120         GetColHeader()->SetColumnCount(m_numCols
); 
8124 void wxGrid::SetUseNativeColLabels( bool native 
) 
8126     wxASSERT_MSG( !m_useNativeHeader
, 
8127                   "doesn't make sense when using native header" ); 
8129     m_nativeColumnLabels 
= native
; 
8132         int height 
= wxRendererNative::Get().GetHeaderButtonHeight( this ); 
8133         SetColLabelSize( height 
); 
8136     GetColLabelWindow()->Refresh(); 
8137     m_cornerLabelWin
->Refresh(); 
8140 void wxGrid::DrawColLabels( wxDC
& dc
,const wxArrayInt
& cols 
) 
8145     const size_t numLabels 
= cols
.GetCount(); 
8146     for ( size_t i 
= 0; i 
< numLabels
; i
++ ) 
8148         DrawColLabel( dc
, cols
[i
] ); 
8152 void wxGrid::DrawCornerLabel(wxDC
& dc
) 
8154     if ( m_nativeColumnLabels 
) 
8156         wxRect 
rect(wxSize(m_rowLabelWidth
, m_colLabelHeight
)); 
8159         wxRendererNative::Get().DrawHeaderButton(m_cornerLabelWin
, dc
, rect
, 0); 
8163         dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8164         dc
.DrawLine( m_rowLabelWidth 
- 1, m_colLabelHeight 
- 1, 
8165                      m_rowLabelWidth 
- 1, 0 ); 
8166         dc
.DrawLine( m_rowLabelWidth 
- 1, m_colLabelHeight 
- 1, 
8167                      0, m_colLabelHeight 
- 1 ); 
8168         dc
.DrawLine( 0, 0, m_rowLabelWidth
, 0 ); 
8169         dc
.DrawLine( 0, 0, 0, m_colLabelHeight 
); 
8171         dc
.SetPen( *wxWHITE_PEN 
); 
8172         dc
.DrawLine( 1, 1, m_rowLabelWidth 
- 1, 1 ); 
8173         dc
.DrawLine( 1, 1, 1, m_colLabelHeight 
- 1 ); 
8177 void wxGrid::DrawColLabel(wxDC
& dc
, int col
) 
8179     if ( GetColWidth(col
) <= 0 || m_colLabelHeight 
<= 0 ) 
8182     int colLeft 
= GetColLeft(col
); 
8184     wxRect 
rect(colLeft
, 0, GetColWidth(col
), m_colLabelHeight
); 
8186     if ( m_nativeColumnLabels 
) 
8188         wxRendererNative::Get().DrawHeaderButton(GetColLabelWindow(), dc
, rect
, 0); 
8192         int colRight 
= GetColRight(col
) - 1; 
8194         dc
.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
))); 
8195         dc
.DrawLine( colRight
, 0, 
8196                      colRight
, m_colLabelHeight 
- 1 ); 
8197         dc
.DrawLine( colLeft
, 0, 
8199         dc
.DrawLine( colLeft
, m_colLabelHeight 
- 1, 
8200                      colRight 
+ 1, m_colLabelHeight 
- 1 ); 
8202         dc
.SetPen( *wxWHITE_PEN 
); 
8203         dc
.DrawLine( colLeft
, 1, colLeft
, m_colLabelHeight 
- 1 ); 
8204         dc
.DrawLine( colLeft
, 1, colRight
, 1 ); 
8207     dc
.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT 
); 
8208     dc
.SetTextForeground( GetLabelTextColour() ); 
8209     dc
.SetFont( GetLabelFont() ); 
8212     GetColLabelAlignment( &hAlign
, &vAlign 
); 
8213     const int orient 
= GetColLabelTextOrientation(); 
8216     DrawTextRectangle(dc
, GetColLabelValue(col
), rect
, hAlign
, vAlign
, orient
); 
8219 // TODO: these 2 functions should be replaced with wxDC::DrawLabel() to which 
8220 //       we just have to add textOrientation support 
8221 void wxGrid::DrawTextRectangle( wxDC
& dc
, 
8222                                 const wxString
& value
, 
8226                                 int textOrientation 
) 
8228     wxArrayString lines
; 
8230     StringToLines( value
, lines 
); 
8232     DrawTextRectangle(dc
, lines
, rect
, horizAlign
, vertAlign
, textOrientation
); 
8235 void wxGrid::DrawTextRectangle(wxDC
& dc
, 
8236                                const wxArrayString
& lines
, 
8240                                int textOrientation
) 
8242     if ( lines
.empty() ) 
8245     wxDCClipper 
clip(dc
, rect
); 
8250     if ( textOrientation 
== wxHORIZONTAL 
) 
8251         GetTextBoxSize( dc
, lines
, &textWidth
, &textHeight 
); 
8253         GetTextBoxSize( dc
, lines
, &textHeight
, &textWidth 
); 
8257     switch ( vertAlign 
) 
8259         case wxALIGN_BOTTOM
: 
8260             if ( textOrientation 
== wxHORIZONTAL 
) 
8261                 y 
= rect
.y 
+ (rect
.height 
- textHeight 
- 1); 
8263                 x 
= rect
.x 
+ rect
.width 
- textWidth
; 
8266         case wxALIGN_CENTRE
: 
8267             if ( textOrientation 
== wxHORIZONTAL 
) 
8268                 y 
= rect
.y 
+ ((rect
.height 
- textHeight
) / 2); 
8270                 x 
= rect
.x 
+ ((rect
.width 
- textWidth
) / 2); 
8275             if ( textOrientation 
== wxHORIZONTAL 
) 
8282     // Align each line of a multi-line label 
8283     size_t nLines 
= lines
.GetCount(); 
8284     for ( size_t l 
= 0; l 
< nLines
; l
++ ) 
8286         const wxString
& line 
= lines
[l
]; 
8290             *(textOrientation 
== wxHORIZONTAL 
? &y 
: &x
) += dc
.GetCharHeight(); 
8294         wxCoord lineWidth 
= 0, 
8296         dc
.GetTextExtent(line
, &lineWidth
, &lineHeight
); 
8298         switch ( horizAlign 
) 
8301                 if ( textOrientation 
== wxHORIZONTAL 
) 
8302                     x 
= rect
.x 
+ (rect
.width 
- lineWidth 
- 1); 
8304                     y 
= rect
.y 
+ lineWidth 
+ 1; 
8307             case wxALIGN_CENTRE
: 
8308                 if ( textOrientation 
== wxHORIZONTAL 
) 
8309                     x 
= rect
.x 
+ ((rect
.width 
- lineWidth
) / 2); 
8311                     y 
= rect
.y 
+ rect
.height 
- ((rect
.height 
- lineWidth
) / 2); 
8316                 if ( textOrientation 
== wxHORIZONTAL 
) 
8319                     y 
= rect
.y 
+ rect
.height 
- 1; 
8323         if ( textOrientation 
== wxHORIZONTAL 
) 
8325             dc
.DrawText( line
, x
, y 
); 
8330             dc
.DrawRotatedText( line
, x
, y
, 90.0 ); 
8336 // Split multi-line text up into an array of strings. 
8337 // Any existing contents of the string array are preserved. 
8339 // TODO: refactor wxTextFile::Read() and reuse the same code from here 
8340 void wxGrid::StringToLines( const wxString
& value
, wxArrayString
& lines 
) const 
8344     wxString eol 
= wxTextFile::GetEOL( wxTextFileType_Unix 
); 
8345     wxString tVal 
= wxTextFile::Translate( value
, wxTextFileType_Unix 
); 
8347     while ( startPos 
< (int)tVal
.length() ) 
8349         pos 
= tVal
.Mid(startPos
).Find( eol 
); 
8354         else if ( pos 
== 0 ) 
8356             lines
.Add( wxEmptyString 
); 
8360             lines
.Add( tVal
.Mid(startPos
, pos
) ); 
8363         startPos 
+= pos 
+ 1; 
8366     if ( startPos 
< (int)tVal
.length() ) 
8368         lines
.Add( tVal
.Mid( startPos 
) ); 
8372 void wxGrid::GetTextBoxSize( const wxDC
& dc
, 
8373                              const wxArrayString
& lines
, 
8374                              long *width
, long *height 
) const 
8378     wxCoord lineW 
= 0, lineH 
= 0; 
8381     for ( i 
= 0; i 
< lines
.GetCount(); i
++ ) 
8383         dc
.GetTextExtent( lines
[i
], &lineW
, &lineH 
); 
8384         w 
= wxMax( w
, lineW 
); 
8393 // ------ Batch processing. 
8395 void wxGrid::EndBatch() 
8397     if ( m_batchCount 
> 0 ) 
8400         if ( !m_batchCount 
) 
8403             m_rowLabelWin
->Refresh(); 
8404             m_colWindow
->Refresh(); 
8405             m_cornerLabelWin
->Refresh(); 
8406             m_gridWin
->Refresh(); 
8411 // Use this, rather than wxWindow::Refresh(), to force an immediate 
8412 // repainting of the grid. Has no effect if you are already inside a 
8413 // BeginBatch / EndBatch block. 
8415 void wxGrid::ForceRefresh() 
8421 bool wxGrid::Enable(bool enable
) 
8423     if ( !wxScrolledWindow::Enable(enable
) ) 
8426     // redraw in the new state 
8427     m_gridWin
->Refresh(); 
8433 // ------ Edit control functions 
8436 void wxGrid::EnableEditing( bool edit 
) 
8438     if ( edit 
!= m_editable 
) 
8441             EnableCellEditControl(edit
); 
8446 void wxGrid::EnableCellEditControl( bool enable 
) 
8451     if ( enable 
!= m_cellEditCtrlEnabled 
) 
8455             if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN
) == -1 ) 
8458             // this should be checked by the caller! 
8459             wxASSERT_MSG( CanEnableCellControl(), _T("can't enable editing for this cell!") ); 
8461             // do it before ShowCellEditControl() 
8462             m_cellEditCtrlEnabled 
= enable
; 
8464             ShowCellEditControl(); 
8468             //FIXME:add veto support 
8469             SendEvent(wxEVT_GRID_EDITOR_HIDDEN
); 
8471             HideCellEditControl(); 
8472             SaveEditControlValue(); 
8474             // do it after HideCellEditControl() 
8475             m_cellEditCtrlEnabled 
= enable
; 
8480 bool wxGrid::IsCurrentCellReadOnly() const 
8483     wxGridCellAttr
* attr 
= ((wxGrid 
*)this)->GetCellAttr(m_currentCellCoords
); 
8484     bool readonly 
= attr
->IsReadOnly(); 
8490 bool wxGrid::CanEnableCellControl() const 
8492     return m_editable 
&& (m_currentCellCoords 
!= wxGridNoCellCoords
) && 
8493         !IsCurrentCellReadOnly(); 
8496 bool wxGrid::IsCellEditControlEnabled() const 
8498     // the cell edit control might be disable for all cells or just for the 
8499     // current one if it's read only 
8500     return m_cellEditCtrlEnabled 
? !IsCurrentCellReadOnly() : false; 
8503 bool wxGrid::IsCellEditControlShown() const 
8505     bool isShown 
= false; 
8507     if ( m_cellEditCtrlEnabled 
) 
8509         int row 
= m_currentCellCoords
.GetRow(); 
8510         int col 
= m_currentCellCoords
.GetCol(); 
8511         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8512         wxGridCellEditor
* editor 
= attr
->GetEditor((wxGrid
*) this, row
, col
); 
8517             if ( editor
->IsCreated() ) 
8519                 isShown 
= editor
->GetControl()->IsShown(); 
8529 void wxGrid::ShowCellEditControl() 
8531     if ( IsCellEditControlEnabled() ) 
8533         if ( !IsVisible( m_currentCellCoords
, false ) ) 
8535             m_cellEditCtrlEnabled 
= false; 
8540             wxRect rect 
= CellToRect( m_currentCellCoords 
); 
8541             int row 
= m_currentCellCoords
.GetRow(); 
8542             int col 
= m_currentCellCoords
.GetCol(); 
8544             // if this is part of a multicell, find owner (topleft) 
8545             int cell_rows
, cell_cols
; 
8546             GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8547             if ( cell_rows 
<= 0 || cell_cols 
<= 0 ) 
8551                 m_currentCellCoords
.SetRow( row 
); 
8552                 m_currentCellCoords
.SetCol( col 
); 
8555             // erase the highlight and the cell contents because the editor 
8556             // might not cover the entire cell 
8557             wxClientDC 
dc( m_gridWin 
); 
8559             wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8560             dc
.SetBrush(wxBrush(attr
->GetBackgroundColour())); 
8561             dc
.SetPen(*wxTRANSPARENT_PEN
); 
8562             dc
.DrawRectangle(rect
); 
8564             // convert to scrolled coords 
8565             CalcScrolledPosition( rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8571             // cell is shifted by one pixel 
8572             // However, don't allow x or y to become negative 
8573             // since the SetSize() method interprets that as 
8580             wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
8581             if ( !editor
->IsCreated() ) 
8583                 editor
->Create(m_gridWin
, wxID_ANY
, 
8584                                new wxGridCellEditorEvtHandler(this, editor
)); 
8586                 wxGridEditorCreatedEvent 
evt(GetId(), 
8587                                              wxEVT_GRID_EDITOR_CREATED
, 
8591                                              editor
->GetControl()); 
8592                 GetEventHandler()->ProcessEvent(evt
); 
8595             // resize editor to overflow into righthand cells if allowed 
8596             int maxWidth 
= rect
.width
; 
8597             wxString value 
= GetCellValue(row
, col
); 
8598             if ( (value 
!= wxEmptyString
) && (attr
->GetOverflow()) ) 
8601                 GetTextExtent(value
, &maxWidth
, &y
, NULL
, NULL
, &attr
->GetFont()); 
8602                 if (maxWidth 
< rect
.width
) 
8603                     maxWidth 
= rect
.width
; 
8606             int client_right 
= m_gridWin
->GetClientSize().GetWidth(); 
8607             if (rect
.x 
+ maxWidth 
> client_right
) 
8608                 maxWidth 
= client_right 
- rect
.x
; 
8610             if ((maxWidth 
> rect
.width
) && (col 
< m_numCols
) && m_table
) 
8612                 GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8613                 // may have changed earlier 
8614                 for (int i 
= col 
+ cell_cols
; i 
< m_numCols
; i
++) 
8617                     GetCellSize( row
, i
, &c_rows
, &c_cols 
); 
8619                     // looks weird going over a multicell 
8620                     if (m_table
->IsEmptyCell( row
, i 
) && 
8621                             (rect
.width 
< maxWidth
) && (c_rows 
== 1)) 
8623                         rect
.width 
+= GetColWidth( i 
); 
8629                 if (rect
.GetRight() > client_right
) 
8630                     rect
.SetRight( client_right 
- 1 ); 
8633             editor
->SetCellAttr( attr 
); 
8634             editor
->SetSize( rect 
); 
8636                 editor
->GetControl()->Move( 
8637                     editor
->GetControl()->GetPosition().x 
+ nXMove
, 
8638                     editor
->GetControl()->GetPosition().y 
); 
8639             editor
->Show( true, attr 
); 
8641             // recalc dimensions in case we need to 
8642             // expand the scrolled window to account for editor 
8645             editor
->BeginEdit(row
, col
, this); 
8646             editor
->SetCellAttr(NULL
); 
8654 void wxGrid::HideCellEditControl() 
8656     if ( IsCellEditControlEnabled() ) 
8658         int row 
= m_currentCellCoords
.GetRow(); 
8659         int col 
= m_currentCellCoords
.GetCol(); 
8661         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
8662         wxGridCellEditor 
*editor 
= attr
->GetEditor(this, row
, col
); 
8663         const bool editorHadFocus 
= editor
->GetControl()->HasFocus(); 
8664         editor
->Show( false ); 
8668         // return the focus to the grid itself if the editor had it 
8670         // note that we must not do this unconditionally to avoid stealing 
8671         // focus from the window which just received it if we are hiding the 
8672         // editor precisely because we lost focus 
8673         if ( editorHadFocus 
) 
8674             m_gridWin
->SetFocus(); 
8676         // refresh whole row to the right 
8677         wxRect 
rect( CellToRect(row
, col
) ); 
8678         CalcScrolledPosition(rect
.x
, rect
.y
, &rect
.x
, &rect
.y 
); 
8679         rect
.width 
= m_gridWin
->GetClientSize().GetWidth() - rect
.x
; 
8682         // ensure that the pixels under the focus ring get refreshed as well 
8683         rect
.Inflate(10, 10); 
8686         m_gridWin
->Refresh( false, &rect 
); 
8690 void wxGrid::SaveEditControlValue() 
8692     if ( IsCellEditControlEnabled() ) 
8694         int row 
= m_currentCellCoords
.GetRow(); 
8695         int col 
= m_currentCellCoords
.GetCol(); 
8697         wxString oldval 
= GetCellValue(row
, col
); 
8699         wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
8700         wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
8701         bool changed 
= editor
->EndEdit(row
, col
, this); 
8708             if ( SendEvent(wxEVT_GRID_CELL_CHANGE
) == -1 ) 
8710                 // Event has been vetoed, set the data back. 
8711                 SetCellValue(row
, col
, oldval
); 
8718 // ------ Grid location functions 
8719 //  Note that all of these functions work with the logical coordinates of 
8720 //  grid cells and labels so you will need to convert from device 
8721 //  coordinates for mouse events etc. 
8724 wxGridCellCoords 
wxGrid::XYToCell(int x
, int y
) const 
8726     int row 
= YToRow(y
); 
8727     int col 
= XToCol(x
); 
8729     return row 
== -1 || col 
== -1 ? wxGridNoCellCoords
 
8730                                   : wxGridCellCoords(row
, col
); 
8733 // compute row or column from some (unscrolled) coordinate value, using either 
8734 // m_defaultRowHeight/m_defaultColWidth or binary search on array of 
8735 // m_rowBottoms/m_colRights to do it quickly (linear search shouldn't be used 
8738 wxGrid::PosToLine(int coord
, 
8740                   const wxGridOperations
& oper
) const 
8742     const int numLines 
= oper
.GetNumberOfLines(this); 
8745         return clipToMinMax 
&& numLines 
> 0 ? oper
.GetLineAt(this, 0) : -1; 
8747     const int defaultLineSize 
= oper
.GetDefaultLineSize(this); 
8748     wxCHECK_MSG( defaultLineSize
, -1, "can't have 0 default line size" ); 
8750     int maxPos 
= coord 
/ defaultLineSize
, 
8753     // check for the simplest case: if we have no explicit line sizes 
8754     // configured, then we already know the line this position falls in 
8755     const wxArrayInt
& lineEnds 
= oper
.GetLineEnds(this); 
8756     if ( lineEnds
.empty() ) 
8758         if ( maxPos 
< numLines 
) 
8761         return clipToMinMax 
? numLines 
- 1 : -1; 
8765     // adjust maxPos before starting the binary search 
8766     if ( maxPos 
>= numLines 
) 
8768         maxPos 
= numLines  
- 1; 
8772         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos
)]) 
8775             const int minDist 
= oper
.GetMinimalAcceptableLineSize(this); 
8777                 maxPos 
= coord 
/ minDist
; 
8779                 maxPos 
= numLines 
- 1; 
8782         if ( maxPos 
>= numLines 
) 
8783             maxPos 
= numLines  
- 1; 
8786     // check if the position is beyond the last column 
8787     const int lineAtMaxPos 
= oper
.GetLineAt(this, maxPos
); 
8788     if ( coord 
>= lineEnds
[lineAtMaxPos
] ) 
8789         return clipToMinMax 
? lineAtMaxPos 
: -1; 
8791     // or before the first one 
8792     const int lineAt0 
= oper
.GetLineAt(this, 0); 
8793     if ( coord 
< lineEnds
[lineAt0
] ) 
8797     // finally do perform the binary search 
8798     while ( minPos 
< maxPos 
) 
8800         wxCHECK_MSG( lineEnds
[oper
.GetLineAt(this, minPos
)] <= coord 
&& 
8801                         coord 
< lineEnds
[oper
.GetLineAt(this, maxPos
)], 
8803                      "wxGrid: internal error in PosToLine()" ); 
8805         if ( coord 
>= lineEnds
[oper
.GetLineAt(this, maxPos 
- 1)] ) 
8806             return oper
.GetLineAt(this, maxPos
); 
8810         const int median 
= minPos 
+ (maxPos 
- minPos 
+ 1) / 2; 
8811         if ( coord 
< lineEnds
[oper
.GetLineAt(this, median
)] ) 
8817     return oper
.GetLineAt(this, maxPos
); 
8820 int wxGrid::YToRow(int y
, bool clipToMinMax
) const 
8822     return PosToLine(y
, clipToMinMax
, wxGridRowOperations()); 
8825 int wxGrid::XToCol(int x
, bool clipToMinMax
) const 
8827     return PosToLine(x
, clipToMinMax
, wxGridColumnOperations()); 
8830 // return the row number that that the y coord is near the edge of, or -1 if 
8831 // not near an edge. 
8833 // coords can only possibly be near an edge if 
8834 //    (a) the row/column is large enough to still allow for an "inner" area 
8835 //        that is _not_ near the edge (i.e., if the height/width is smaller 
8836 //        than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be 
8839 //    (b) resizing rows/columns (the thing for which edge detection is 
8840 //        relevant at all) is enabled. 
8842 int wxGrid::PosToEdgeOfLine(int pos
, const wxGridOperations
& oper
) const 
8844     if ( !oper
.CanResizeLines(this) ) 
8847     const int line 
= oper
.PosToLine(this, pos
, true); 
8849     if ( oper
.GetLineSize(this, line
) > WXGRID_LABEL_EDGE_ZONE 
) 
8851         // We know that we are in this line, test whether we are close enough 
8852         // to start or end border, respectively. 
8853         if ( abs(oper
.GetLineEndPos(this, line
) - pos
) < WXGRID_LABEL_EDGE_ZONE 
) 
8855         else if ( line 
> 0 && 
8856                     pos 
- oper
.GetLineStartPos(this, 
8857                                                line
) < WXGRID_LABEL_EDGE_ZONE 
) 
8864 int wxGrid::YToEdgeOfRow(int y
) const 
8866     return PosToEdgeOfLine(y
, wxGridRowOperations()); 
8869 int wxGrid::XToEdgeOfCol(int x
) const 
8871     return PosToEdgeOfLine(x
, wxGridColumnOperations()); 
8874 wxRect 
wxGrid::CellToRect( int row
, int col 
) const 
8876     wxRect 
rect( -1, -1, -1, -1 ); 
8878     if ( row 
>= 0 && row 
< m_numRows 
&& 
8879          col 
>= 0 && col 
< m_numCols 
) 
8881         int i
, cell_rows
, cell_cols
; 
8882         rect
.width 
= rect
.height 
= 0; 
8883         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8884         // if negative then find multicell owner 
8889         GetCellSize( row
, col
, &cell_rows
, &cell_cols 
); 
8891         rect
.x 
= GetColLeft(col
); 
8892         rect
.y 
= GetRowTop(row
); 
8893         for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
8894             rect
.width 
+= GetColWidth(i
); 
8895         for (i
=row
; i 
< row 
+ cell_rows
; i
++) 
8896             rect
.height 
+= GetRowHeight(i
); 
8899     // if grid lines are enabled, then the area of the cell is a bit smaller 
8900     if (m_gridLinesEnabled
) 
8909 bool wxGrid::IsVisible( int row
, int col
, bool wholeCellVisible 
) const 
8911     // get the cell rectangle in logical coords 
8913     wxRect 
r( CellToRect( row
, col 
) ); 
8915     // convert to device coords 
8917     int left
, top
, right
, bottom
; 
8918     CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
8919     CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
8921     // check against the client area of the grid window 
8923     m_gridWin
->GetClientSize( &cw
, &ch 
); 
8925     if ( wholeCellVisible 
) 
8927         // is the cell wholly visible ? 
8928         return ( left 
>= 0 && right 
<= cw 
&& 
8929                  top 
>= 0 && bottom 
<= ch 
); 
8933         // is the cell partly visible ? 
8935         return ( ((left 
>= 0 && left 
< cw
) || (right 
> 0 && right 
<= cw
)) && 
8936                  ((top 
>= 0 && top 
< ch
) || (bottom 
> 0 && bottom 
<= ch
)) ); 
8940 // make the specified cell location visible by doing a minimal amount 
8943 void wxGrid::MakeCellVisible( int row
, int col 
) 
8946     int xpos 
= -1, ypos 
= -1; 
8948     if ( row 
>= 0 && row 
< m_numRows 
&& 
8949          col 
>= 0 && col 
< m_numCols 
) 
8951         // get the cell rectangle in logical coords 
8952         wxRect 
r( CellToRect( row
, col 
) ); 
8954         // convert to device coords 
8955         int left
, top
, right
, bottom
; 
8956         CalcScrolledPosition( r
.GetLeft(), r
.GetTop(), &left
, &top 
); 
8957         CalcScrolledPosition( r
.GetRight(), r
.GetBottom(), &right
, &bottom 
); 
8960         m_gridWin
->GetClientSize( &cw
, &ch 
); 
8966         else if ( bottom 
> ch 
) 
8968             int h 
= r
.GetHeight(); 
8970             for ( i 
= row 
- 1; i 
>= 0; i
-- ) 
8972                 int rowHeight 
= GetRowHeight(i
); 
8973                 if ( h 
+ rowHeight 
> ch 
) 
8980             // we divide it later by GRID_SCROLL_LINE, make sure that we don't 
8981             // have rounding errors (this is important, because if we do, 
8982             // we might not scroll at all and some cells won't be redrawn) 
8984             // Sometimes GRID_SCROLL_LINE / 2 is not enough, 
8985             // so just add a full scroll unit... 
8986             ypos 
+= m_scrollLineY
; 
8989         // special handling for wide cells - show always left part of the cell! 
8990         // Otherwise, e.g. when stepping from row to row, it would jump between 
8991         // left and right part of the cell on every step! 
8993         if ( left 
< 0 || (right 
- left
) >= cw 
) 
8997         else if ( right 
> cw 
) 
8999             // position the view so that the cell is on the right 
9001             CalcUnscrolledPosition(0, 0, &x0
, &y0
); 
9002             xpos 
= x0 
+ (right 
- cw
); 
9004             // see comment for ypos above 
9005             xpos 
+= m_scrollLineX
; 
9008         if ( xpos 
!= -1 || ypos 
!= -1 ) 
9011                 xpos 
/= m_scrollLineX
; 
9013                 ypos 
/= m_scrollLineY
; 
9014             Scroll( xpos
, ypos 
); 
9021 // ------ Grid cursor movement functions 
9025 wxGrid::DoMoveCursor(bool expandSelection
, 
9026                      const wxGridDirectionOperations
& diroper
) 
9028     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
9031     if ( expandSelection 
) 
9033         wxGridCellCoords coords 
= m_selectedBlockCorner
; 
9034         if ( coords 
== wxGridNoCellCoords 
) 
9035             coords 
= m_currentCellCoords
; 
9037         if ( diroper
.IsAtBoundary(coords
) ) 
9040         diroper
.Advance(coords
); 
9042         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
9044     else // don't expand selection 
9048         if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
9051         wxGridCellCoords coords 
= m_currentCellCoords
; 
9052         diroper
.Advance(coords
); 
9060 bool wxGrid::MoveCursorUp(bool expandSelection
) 
9062     return DoMoveCursor(expandSelection
, 
9063                         wxGridBackwardOperations(this, wxGridRowOperations())); 
9066 bool wxGrid::MoveCursorDown(bool expandSelection
) 
9068     return DoMoveCursor(expandSelection
, 
9069                         wxGridForwardOperations(this, wxGridRowOperations())); 
9072 bool wxGrid::MoveCursorLeft(bool expandSelection
) 
9074     return DoMoveCursor(expandSelection
, 
9075                         wxGridBackwardOperations(this, wxGridColumnOperations())); 
9078 bool wxGrid::MoveCursorRight(bool expandSelection
) 
9080     return DoMoveCursor(expandSelection
, 
9081                         wxGridForwardOperations(this, wxGridColumnOperations())); 
9084 bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations
& diroper
) 
9086     if ( m_currentCellCoords 
== wxGridNoCellCoords 
) 
9089     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
9092     const int oldRow 
= m_currentCellCoords
.GetRow(); 
9093     int newRow 
= diroper
.MoveByPixelDistance(oldRow
, m_gridWin
->GetClientSize().y
); 
9094     if ( newRow 
== oldRow 
) 
9096         wxGridCellCoords 
coords(m_currentCellCoords
); 
9097         diroper
.Advance(coords
); 
9098         newRow 
= coords
.GetRow(); 
9101     GoToCell(newRow
, m_currentCellCoords
.GetCol()); 
9106 bool wxGrid::MovePageUp() 
9108     return DoMoveCursorByPage( 
9109                 wxGridBackwardOperations(this, wxGridRowOperations())); 
9112 bool wxGrid::MovePageDown() 
9114     return DoMoveCursorByPage( 
9115                 wxGridForwardOperations(this, wxGridRowOperations())); 
9118 // helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper 
9119 // until we find a non-empty cell or reach the grid end 
9121 wxGrid::AdvanceToNextNonEmpty(wxGridCellCoords
& coords
, 
9122                               const wxGridDirectionOperations
& diroper
) 
9124     while ( !diroper
.IsAtBoundary(coords
) ) 
9126         diroper
.Advance(coords
); 
9127         if ( !m_table
->IsEmpty(coords
) ) 
9133 wxGrid::DoMoveCursorByBlock(bool expandSelection
, 
9134                             const wxGridDirectionOperations
& diroper
) 
9136     if ( !m_table 
|| m_currentCellCoords 
== wxGridNoCellCoords 
) 
9139     if ( diroper
.IsAtBoundary(m_currentCellCoords
) ) 
9142     wxGridCellCoords 
coords(m_currentCellCoords
); 
9143     if ( m_table
->IsEmpty(coords
) ) 
9145         // we are in an empty cell: find the next block of non-empty cells 
9146         AdvanceToNextNonEmpty(coords
, diroper
); 
9148     else // current cell is not empty 
9150         diroper
.Advance(coords
); 
9151         if ( m_table
->IsEmpty(coords
) ) 
9153             // we started at the end of a block, find the next one 
9154             AdvanceToNextNonEmpty(coords
, diroper
); 
9156         else // we're in a middle of a block 
9158             // go to the end of it, i.e. find the last cell before the next 
9160             while ( !diroper
.IsAtBoundary(coords
) ) 
9162                 wxGridCellCoords 
coordsNext(coords
); 
9163                 diroper
.Advance(coordsNext
); 
9164                 if ( m_table
->IsEmpty(coordsNext
) ) 
9167                 coords 
= coordsNext
; 
9172     if ( expandSelection 
) 
9174         UpdateBlockBeingSelected(m_currentCellCoords
, coords
); 
9185 bool wxGrid::MoveCursorUpBlock(bool expandSelection
) 
9187     return DoMoveCursorByBlock( 
9189                 wxGridBackwardOperations(this, wxGridRowOperations()) 
9193 bool wxGrid::MoveCursorDownBlock( bool expandSelection 
) 
9195     return DoMoveCursorByBlock( 
9197                 wxGridForwardOperations(this, wxGridRowOperations()) 
9201 bool wxGrid::MoveCursorLeftBlock( bool expandSelection 
) 
9203     return DoMoveCursorByBlock( 
9205                 wxGridBackwardOperations(this, wxGridColumnOperations()) 
9209 bool wxGrid::MoveCursorRightBlock( bool expandSelection 
) 
9211     return DoMoveCursorByBlock( 
9213                 wxGridForwardOperations(this, wxGridColumnOperations()) 
9218 // ------ Label values and formatting 
9221 void wxGrid::GetRowLabelAlignment( int *horiz
, int *vert 
) const 
9224         *horiz 
= m_rowLabelHorizAlign
; 
9226         *vert  
= m_rowLabelVertAlign
; 
9229 void wxGrid::GetColLabelAlignment( int *horiz
, int *vert 
) const 
9232         *horiz 
= m_colLabelHorizAlign
; 
9234         *vert  
= m_colLabelVertAlign
; 
9237 int wxGrid::GetColLabelTextOrientation() const 
9239     return m_colLabelTextOrientation
; 
9242 wxString 
wxGrid::GetRowLabelValue( int row 
) const 
9246         return m_table
->GetRowLabelValue( row 
); 
9256 wxString 
wxGrid::GetColLabelValue( int col 
) const 
9260         return m_table
->GetColLabelValue( col 
); 
9270 void wxGrid::SetRowLabelSize( int width 
) 
9272     wxASSERT( width 
>= 0 || width 
== wxGRID_AUTOSIZE 
); 
9274     if ( width 
== wxGRID_AUTOSIZE 
) 
9276         width 
= CalcColOrRowLabelAreaMinSize(wxGRID_ROW
); 
9279     if ( width 
!= m_rowLabelWidth 
) 
9283             m_rowLabelWin
->Show( false ); 
9284             m_cornerLabelWin
->Show( false ); 
9286         else if ( m_rowLabelWidth 
== 0 ) 
9288             m_rowLabelWin
->Show( true ); 
9289             if ( m_colLabelHeight 
> 0 ) 
9290                 m_cornerLabelWin
->Show( true ); 
9293         m_rowLabelWidth 
= width
; 
9295         wxScrolledWindow::Refresh( true ); 
9299 void wxGrid::SetColLabelSize( int height 
) 
9301     wxASSERT( height 
>=0 || height 
== wxGRID_AUTOSIZE 
); 
9303     if ( height 
== wxGRID_AUTOSIZE 
) 
9305         height 
= CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN
); 
9308     if ( height 
!= m_colLabelHeight 
) 
9312             m_colWindow
->Show( false ); 
9313             m_cornerLabelWin
->Show( false ); 
9315         else if ( m_colLabelHeight 
== 0 ) 
9317             m_colWindow
->Show( true ); 
9318             if ( m_rowLabelWidth 
> 0 ) 
9319                 m_cornerLabelWin
->Show( true ); 
9322         m_colLabelHeight 
= height
; 
9324         wxScrolledWindow::Refresh( true ); 
9328 void wxGrid::SetLabelBackgroundColour( const wxColour
& colour 
) 
9330     if ( m_labelBackgroundColour 
!= colour 
) 
9332         m_labelBackgroundColour 
= colour
; 
9333         m_rowLabelWin
->SetBackgroundColour( colour 
); 
9334         m_colWindow
->SetBackgroundColour( colour 
); 
9335         m_cornerLabelWin
->SetBackgroundColour( colour 
); 
9337         if ( !GetBatchCount() ) 
9339             m_rowLabelWin
->Refresh(); 
9340             m_colWindow
->Refresh(); 
9341             m_cornerLabelWin
->Refresh(); 
9346 void wxGrid::SetLabelTextColour( const wxColour
& colour 
) 
9348     if ( m_labelTextColour 
!= colour 
) 
9350         m_labelTextColour 
= colour
; 
9351         if ( !GetBatchCount() ) 
9353             m_rowLabelWin
->Refresh(); 
9354             m_colWindow
->Refresh(); 
9359 void wxGrid::SetLabelFont( const wxFont
& font 
) 
9362     if ( !GetBatchCount() ) 
9364         m_rowLabelWin
->Refresh(); 
9365         m_colWindow
->Refresh(); 
9369 void wxGrid::SetRowLabelAlignment( int horiz
, int vert 
) 
9371     // allow old (incorrect) defs to be used 
9374         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
9375         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
9376         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
9381         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
9382         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
9383         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
9386     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
9388         m_rowLabelHorizAlign 
= horiz
; 
9391     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
9393         m_rowLabelVertAlign 
= vert
; 
9396     if ( !GetBatchCount() ) 
9398         m_rowLabelWin
->Refresh(); 
9402 void wxGrid::SetColLabelAlignment( int horiz
, int vert 
) 
9404     // allow old (incorrect) defs to be used 
9407         case wxLEFT
:   horiz 
= wxALIGN_LEFT
; break; 
9408         case wxRIGHT
:  horiz 
= wxALIGN_RIGHT
; break; 
9409         case wxCENTRE
: horiz 
= wxALIGN_CENTRE
; break; 
9414         case wxTOP
:    vert 
= wxALIGN_TOP
;    break; 
9415         case wxBOTTOM
: vert 
= wxALIGN_BOTTOM
; break; 
9416         case wxCENTRE
: vert 
= wxALIGN_CENTRE
; break; 
9419     if ( horiz 
== wxALIGN_LEFT 
|| horiz 
== wxALIGN_CENTRE 
|| horiz 
== wxALIGN_RIGHT 
) 
9421         m_colLabelHorizAlign 
= horiz
; 
9424     if ( vert 
== wxALIGN_TOP 
|| vert 
== wxALIGN_CENTRE 
|| vert 
== wxALIGN_BOTTOM 
) 
9426         m_colLabelVertAlign 
= vert
; 
9429     if ( !GetBatchCount() ) 
9431         m_colWindow
->Refresh(); 
9435 // Note: under MSW, the default column label font must be changed because it 
9436 //       does not support vertical printing 
9438 // Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD); 
9439 //                      pGrid->SetLabelFont(font); 
9440 //                      pGrid->SetColLabelTextOrientation(wxVERTICAL); 
9442 void wxGrid::SetColLabelTextOrientation( int textOrientation 
) 
9444     if ( textOrientation 
== wxHORIZONTAL 
|| textOrientation 
== wxVERTICAL 
) 
9445         m_colLabelTextOrientation 
= textOrientation
; 
9447     if ( !GetBatchCount() ) 
9448         m_colWindow
->Refresh(); 
9451 void wxGrid::SetRowLabelValue( int row
, const wxString
& s 
) 
9455         m_table
->SetRowLabelValue( row
, s 
); 
9456         if ( !GetBatchCount() ) 
9458             wxRect rect 
= CellToRect( row
, 0 ); 
9459             if ( rect
.height 
> 0 ) 
9461                 CalcScrolledPosition(0, rect
.y
, &rect
.x
, &rect
.y
); 
9463                 rect
.width 
= m_rowLabelWidth
; 
9464                 m_rowLabelWin
->Refresh( true, &rect 
); 
9470 void wxGrid::SetColLabelValue( int col
, const wxString
& s 
) 
9474         m_table
->SetColLabelValue( col
, s 
); 
9475         if ( !GetBatchCount() ) 
9477             if ( m_useNativeHeader 
) 
9479                 GetColHeader()->UpdateColumn(col
); 
9483                 wxRect rect 
= CellToRect( 0, col 
); 
9484                 if ( rect
.width 
> 0 ) 
9486                     CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &rect
.y
); 
9488                     rect
.height 
= m_colLabelHeight
; 
9489                     GetColLabelWindow()->Refresh( true, &rect 
); 
9496 void wxGrid::SetGridLineColour( const wxColour
& colour 
) 
9498     if ( m_gridLineColour 
!= colour 
) 
9500         m_gridLineColour 
= colour
; 
9502         if ( GridLinesEnabled() ) 
9507 void wxGrid::SetCellHighlightColour( const wxColour
& colour 
) 
9509     if ( m_cellHighlightColour 
!= colour 
) 
9511         m_cellHighlightColour 
= colour
; 
9513         wxClientDC 
dc( m_gridWin 
); 
9515         wxGridCellAttr
* attr 
= GetCellAttr(m_currentCellCoords
); 
9516         DrawCellHighlight(dc
, attr
); 
9521 void wxGrid::SetCellHighlightPenWidth(int width
) 
9523     if (m_cellHighlightPenWidth 
!= width
) 
9525         m_cellHighlightPenWidth 
= width
; 
9527         // Just redrawing the cell highlight is not enough since that won't 
9528         // make any visible change if the the thickness is getting smaller. 
9529         int row 
= m_currentCellCoords
.GetRow(); 
9530         int col 
= m_currentCellCoords
.GetCol(); 
9531         if ( row 
== -1 || col 
== -1 || GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
9534         wxRect rect 
= CellToRect(row
, col
); 
9535         m_gridWin
->Refresh(true, &rect
); 
9539 void wxGrid::SetCellHighlightROPenWidth(int width
) 
9541     if (m_cellHighlightROPenWidth 
!= width
) 
9543         m_cellHighlightROPenWidth 
= width
; 
9545         // Just redrawing the cell highlight is not enough since that won't 
9546         // make any visible change if the the thickness is getting smaller. 
9547         int row 
= m_currentCellCoords
.GetRow(); 
9548         int col 
= m_currentCellCoords
.GetCol(); 
9549         if ( row 
== -1 || col 
== -1 || 
9550                 GetColWidth(col
) <= 0 || GetRowHeight(row
) <= 0 ) 
9553         wxRect rect 
= CellToRect(row
, col
); 
9554         m_gridWin
->Refresh(true, &rect
); 
9558 void wxGrid::RedrawGridLines() 
9560     // the lines will be redrawn when the window is thawn 
9561     if ( GetBatchCount() ) 
9564     if ( GridLinesEnabled() ) 
9566         wxClientDC 
dc( m_gridWin 
); 
9568         DrawAllGridLines( dc
, wxRegion() ); 
9570     else // remove the grid lines 
9572         m_gridWin
->Refresh(); 
9576 void wxGrid::EnableGridLines( bool enable 
) 
9578     if ( enable 
!= m_gridLinesEnabled 
) 
9580         m_gridLinesEnabled 
= enable
; 
9586 void wxGrid::DoClipGridLines(bool& var
, bool clip
) 
9592         if ( GridLinesEnabled() ) 
9597 int wxGrid::GetDefaultRowSize() const 
9599     return m_defaultRowHeight
; 
9602 int wxGrid::GetRowSize( int row 
) const 
9604     wxCHECK_MSG( row 
>= 0 && row 
< m_numRows
, 0, _T("invalid row index") ); 
9606     return GetRowHeight(row
); 
9609 int wxGrid::GetDefaultColSize() const 
9611     return m_defaultColWidth
; 
9614 int wxGrid::GetColSize( int col 
) const 
9616     wxCHECK_MSG( col 
>= 0 && col 
< m_numCols
, 0, _T("invalid column index") ); 
9618     return GetColWidth(col
); 
9621 // ============================================================================ 
9622 // access to the grid attributes: each of them has a default value in the grid 
9623 // itself and may be overidden on a per-cell basis 
9624 // ============================================================================ 
9626 // ---------------------------------------------------------------------------- 
9627 // setting default attributes 
9628 // ---------------------------------------------------------------------------- 
9630 void wxGrid::SetDefaultCellBackgroundColour( const wxColour
& col 
) 
9632     m_defaultCellAttr
->SetBackgroundColour(col
); 
9634     m_gridWin
->SetBackgroundColour(col
); 
9638 void wxGrid::SetDefaultCellTextColour( const wxColour
& col 
) 
9640     m_defaultCellAttr
->SetTextColour(col
); 
9643 void wxGrid::SetDefaultCellAlignment( int horiz
, int vert 
) 
9645     m_defaultCellAttr
->SetAlignment(horiz
, vert
); 
9648 void wxGrid::SetDefaultCellOverflow( bool allow 
) 
9650     m_defaultCellAttr
->SetOverflow(allow
); 
9653 void wxGrid::SetDefaultCellFont( const wxFont
& font 
) 
9655     m_defaultCellAttr
->SetFont(font
); 
9658 // For editors and renderers the type registry takes precedence over the 
9659 // default attr, so we need to register the new editor/renderer for the string 
9660 // data type in order to make setting a default editor/renderer appear to 
9663 void wxGrid::SetDefaultRenderer(wxGridCellRenderer 
*renderer
) 
9665     RegisterDataType(wxGRID_VALUE_STRING
, 
9667                      GetDefaultEditorForType(wxGRID_VALUE_STRING
)); 
9670 void wxGrid::SetDefaultEditor(wxGridCellEditor 
*editor
) 
9672     RegisterDataType(wxGRID_VALUE_STRING
, 
9673                      GetDefaultRendererForType(wxGRID_VALUE_STRING
), 
9677 // ---------------------------------------------------------------------------- 
9678 // access to the default attributes 
9679 // ---------------------------------------------------------------------------- 
9681 wxColour 
wxGrid::GetDefaultCellBackgroundColour() const 
9683     return m_defaultCellAttr
->GetBackgroundColour(); 
9686 wxColour 
wxGrid::GetDefaultCellTextColour() const 
9688     return m_defaultCellAttr
->GetTextColour(); 
9691 wxFont 
wxGrid::GetDefaultCellFont() const 
9693     return m_defaultCellAttr
->GetFont(); 
9696 void wxGrid::GetDefaultCellAlignment( int *horiz
, int *vert 
) const 
9698     m_defaultCellAttr
->GetAlignment(horiz
, vert
); 
9701 bool wxGrid::GetDefaultCellOverflow() const 
9703     return m_defaultCellAttr
->GetOverflow(); 
9706 wxGridCellRenderer 
*wxGrid::GetDefaultRenderer() const 
9708     return m_defaultCellAttr
->GetRenderer(NULL
, 0, 0); 
9711 wxGridCellEditor 
*wxGrid::GetDefaultEditor() const 
9713     return m_defaultCellAttr
->GetEditor(NULL
, 0, 0); 
9716 // ---------------------------------------------------------------------------- 
9717 // access to cell attributes 
9718 // ---------------------------------------------------------------------------- 
9720 wxColour 
wxGrid::GetCellBackgroundColour(int row
, int col
) const 
9722     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9723     wxColour colour 
= attr
->GetBackgroundColour(); 
9729 wxColour 
wxGrid::GetCellTextColour( int row
, int col 
) const 
9731     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9732     wxColour colour 
= attr
->GetTextColour(); 
9738 wxFont 
wxGrid::GetCellFont( int row
, int col 
) const 
9740     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9741     wxFont font 
= attr
->GetFont(); 
9747 void wxGrid::GetCellAlignment( int row
, int col
, int *horiz
, int *vert 
) const 
9749     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9750     attr
->GetAlignment(horiz
, vert
); 
9754 bool wxGrid::GetCellOverflow( int row
, int col 
) const 
9756     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9757     bool allow 
= attr
->GetOverflow(); 
9763 void wxGrid::GetCellSize( int row
, int col
, int *num_rows
, int *num_cols 
) const 
9765     wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
9766     attr
->GetSize( num_rows
, num_cols 
); 
9770 wxGridCellRenderer
* wxGrid::GetCellRenderer(int row
, int col
) const 
9772     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9773     wxGridCellRenderer
* renderer 
= attr
->GetRenderer(this, row
, col
); 
9779 wxGridCellEditor
* wxGrid::GetCellEditor(int row
, int col
) const 
9781     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9782     wxGridCellEditor
* editor 
= attr
->GetEditor(this, row
, col
); 
9788 bool wxGrid::IsReadOnly(int row
, int col
) const 
9790     wxGridCellAttr
* attr 
= GetCellAttr(row
, col
); 
9791     bool isReadOnly 
= attr
->IsReadOnly(); 
9797 // ---------------------------------------------------------------------------- 
9798 // attribute support: cache, automatic provider creation, ... 
9799 // ---------------------------------------------------------------------------- 
9801 bool wxGrid::CanHaveAttributes() const 
9808     return m_table
->CanHaveAttributes(); 
9811 void wxGrid::ClearAttrCache() 
9813     if ( m_attrCache
.row 
!= -1 ) 
9815         wxGridCellAttr 
*oldAttr 
= m_attrCache
.attr
; 
9816         m_attrCache
.attr 
= NULL
; 
9817         m_attrCache
.row 
= -1; 
9818         // wxSafeDecRec(...) might cause event processing that accesses 
9819         // the cached attribute, if one exists (e.g. by deleting the 
9820         // editor stored within the attribute). Therefore it is important 
9821         // to invalidate the cache  before calling wxSafeDecRef! 
9822         wxSafeDecRef(oldAttr
); 
9826 void wxGrid::CacheAttr(int row
, int col
, wxGridCellAttr 
*attr
) const 
9830         wxGrid 
*self 
= (wxGrid 
*)this;  // const_cast 
9832         self
->ClearAttrCache(); 
9833         self
->m_attrCache
.row 
= row
; 
9834         self
->m_attrCache
.col 
= col
; 
9835         self
->m_attrCache
.attr 
= attr
; 
9840 bool wxGrid::LookupAttr(int row
, int col
, wxGridCellAttr 
**attr
) const 
9842     if ( row 
== m_attrCache
.row 
&& col 
== m_attrCache
.col 
) 
9844         *attr 
= m_attrCache
.attr
; 
9845         wxSafeIncRef(m_attrCache
.attr
); 
9847 #ifdef DEBUG_ATTR_CACHE 
9848         gs_nAttrCacheHits
++; 
9855 #ifdef DEBUG_ATTR_CACHE 
9856         gs_nAttrCacheMisses
++; 
9863 wxGridCellAttr 
*wxGrid::GetCellAttr(int row
, int col
) const 
9865     wxGridCellAttr 
*attr 
= NULL
; 
9866     // Additional test to avoid looking at the cache e.g. for 
9867     // wxNoCellCoords, as this will confuse memory management. 
9870         if ( !LookupAttr(row
, col
, &attr
) ) 
9872             attr 
= m_table 
? m_table
->GetAttr(row
, col
, wxGridCellAttr::Any
) 
9874             CacheAttr(row
, col
, attr
); 
9880         attr
->SetDefAttr(m_defaultCellAttr
); 
9884         attr 
= m_defaultCellAttr
; 
9891 wxGridCellAttr 
*wxGrid::GetOrCreateCellAttr(int row
, int col
) const 
9893     wxGridCellAttr 
*attr 
= NULL
; 
9894     bool canHave 
= ((wxGrid
*)this)->CanHaveAttributes(); 
9896     wxCHECK_MSG( canHave
, attr
, _T("Cell attributes not allowed")); 
9897     wxCHECK_MSG( m_table
, attr
, _T("must have a table") ); 
9899     attr 
= m_table
->GetAttr(row
, col
, wxGridCellAttr::Cell
); 
9902         attr 
= new wxGridCellAttr(m_defaultCellAttr
); 
9904         // artificially inc the ref count to match DecRef() in caller 
9906         m_table
->SetAttr(attr
, row
, col
); 
9912 // ---------------------------------------------------------------------------- 
9913 // setting column attributes (wrappers around SetColAttr) 
9914 // ---------------------------------------------------------------------------- 
9916 void wxGrid::SetColFormatBool(int col
) 
9918     SetColFormatCustom(col
, wxGRID_VALUE_BOOL
); 
9921 void wxGrid::SetColFormatNumber(int col
) 
9923     SetColFormatCustom(col
, wxGRID_VALUE_NUMBER
); 
9926 void wxGrid::SetColFormatFloat(int col
, int width
, int precision
) 
9928     wxString typeName 
= wxGRID_VALUE_FLOAT
; 
9929     if ( (width 
!= -1) || (precision 
!= -1) ) 
9931         typeName 
<< _T(':') << width 
<< _T(',') << precision
; 
9934     SetColFormatCustom(col
, typeName
); 
9937 void wxGrid::SetColFormatCustom(int col
, const wxString
& typeName
) 
9939     wxGridCellAttr 
*attr 
= m_table
->GetAttr(-1, col
, wxGridCellAttr::Col 
); 
9941         attr 
= new wxGridCellAttr
; 
9942     wxGridCellRenderer 
*renderer 
= GetDefaultRendererForType(typeName
); 
9943     attr
->SetRenderer(renderer
); 
9944     wxGridCellEditor 
*editor 
= GetDefaultEditorForType(typeName
); 
9945     attr
->SetEditor(editor
); 
9947     SetColAttr(col
, attr
); 
9951 // ---------------------------------------------------------------------------- 
9952 // setting cell attributes: this is forwarded to the table 
9953 // ---------------------------------------------------------------------------- 
9955 void wxGrid::SetAttr(int row
, int col
, wxGridCellAttr 
*attr
) 
9957     if ( CanHaveAttributes() ) 
9959         m_table
->SetAttr(attr
, row
, col
); 
9968 void wxGrid::SetRowAttr(int row
, wxGridCellAttr 
*attr
) 
9970     if ( CanHaveAttributes() ) 
9972         m_table
->SetRowAttr(attr
, row
); 
9981 void wxGrid::SetColAttr(int col
, wxGridCellAttr 
*attr
) 
9983     if ( CanHaveAttributes() ) 
9985         m_table
->SetColAttr(attr
, col
); 
9994 void wxGrid::SetCellBackgroundColour( int row
, int col
, const wxColour
& colour 
) 
9996     if ( CanHaveAttributes() ) 
9998         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
9999         attr
->SetBackgroundColour(colour
); 
10004 void wxGrid::SetCellTextColour( int row
, int col
, const wxColour
& colour 
) 
10006     if ( CanHaveAttributes() ) 
10008         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10009         attr
->SetTextColour(colour
); 
10014 void wxGrid::SetCellFont( int row
, int col
, const wxFont
& font 
) 
10016     if ( CanHaveAttributes() ) 
10018         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10019         attr
->SetFont(font
); 
10024 void wxGrid::SetCellAlignment( int row
, int col
, int horiz
, int vert 
) 
10026     if ( CanHaveAttributes() ) 
10028         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10029         attr
->SetAlignment(horiz
, vert
); 
10034 void wxGrid::SetCellOverflow( int row
, int col
, bool allow 
) 
10036     if ( CanHaveAttributes() ) 
10038         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10039         attr
->SetOverflow(allow
); 
10044 void wxGrid::SetCellSize( int row
, int col
, int num_rows
, int num_cols 
) 
10046     if ( CanHaveAttributes() ) 
10048         int cell_rows
, cell_cols
; 
10050         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10051         attr
->GetSize(&cell_rows
, &cell_cols
); 
10052         attr
->SetSize(num_rows
, num_cols
); 
10055         // Cannot set the size of a cell to 0 or negative values 
10056         // While it is perfectly legal to do that, this function cannot 
10057         // handle all the possibilies, do it by hand by getting the CellAttr. 
10058         // You can only set the size of a cell to 1,1 or greater with this fn 
10059         wxASSERT_MSG( !((cell_rows 
< 1) || (cell_cols 
< 1)), 
10060                       wxT("wxGrid::SetCellSize setting cell size that is already part of another cell")); 
10061         wxASSERT_MSG( !((num_rows 
< 1) || (num_cols 
< 1)), 
10062                       wxT("wxGrid::SetCellSize setting cell size to < 1")); 
10064         // if this was already a multicell then "turn off" the other cells first 
10065         if ((cell_rows 
> 1) || (cell_cols 
> 1)) 
10068             for (j
=row
; j 
< row 
+ cell_rows
; j
++) 
10070                 for (i
=col
; i 
< col 
+ cell_cols
; i
++) 
10072                     if ((i 
!= col
) || (j 
!= row
)) 
10074                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
10075                         attr_stub
->SetSize( 1, 1 ); 
10076                         attr_stub
->DecRef(); 
10082         // mark the cells that will be covered by this cell to 
10083         // negative or zero values to point back at this cell 
10084         if (((num_rows 
> 1) || (num_cols 
> 1)) && (num_rows 
>= 1) && (num_cols 
>= 1)) 
10087             for (j
=row
; j 
< row 
+ num_rows
; j
++) 
10089                 for (i
=col
; i 
< col 
+ num_cols
; i
++) 
10091                     if ((i 
!= col
) || (j 
!= row
)) 
10093                         wxGridCellAttr 
*attr_stub 
= GetOrCreateCellAttr(j
, i
); 
10094                         attr_stub
->SetSize( row 
- j
, col 
- i 
); 
10095                         attr_stub
->DecRef(); 
10103 void wxGrid::SetCellRenderer(int row
, int col
, wxGridCellRenderer 
*renderer
) 
10105     if ( CanHaveAttributes() ) 
10107         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10108         attr
->SetRenderer(renderer
); 
10113 void wxGrid::SetCellEditor(int row
, int col
, wxGridCellEditor
* editor
) 
10115     if ( CanHaveAttributes() ) 
10117         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10118         attr
->SetEditor(editor
); 
10123 void wxGrid::SetReadOnly(int row
, int col
, bool isReadOnly
) 
10125     if ( CanHaveAttributes() ) 
10127         wxGridCellAttr 
*attr 
= GetOrCreateCellAttr(row
, col
); 
10128         attr
->SetReadOnly(isReadOnly
); 
10133 // ---------------------------------------------------------------------------- 
10134 // Data type registration 
10135 // ---------------------------------------------------------------------------- 
10137 void wxGrid::RegisterDataType(const wxString
& typeName
, 
10138                               wxGridCellRenderer
* renderer
, 
10139                               wxGridCellEditor
* editor
) 
10141     m_typeRegistry
->RegisterDataType(typeName
, renderer
, editor
); 
10145 wxGridCellEditor 
* wxGrid::GetDefaultEditorForCell(int row
, int col
) const 
10147     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
10148     return GetDefaultEditorForType(typeName
); 
10151 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForCell(int row
, int col
) const 
10153     wxString typeName 
= m_table
->GetTypeName(row
, col
); 
10154     return GetDefaultRendererForType(typeName
); 
10157 wxGridCellEditor 
* wxGrid::GetDefaultEditorForType(const wxString
& typeName
) const 
10159     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
10160     if ( index 
== wxNOT_FOUND 
) 
10162         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
10167     return m_typeRegistry
->GetEditor(index
); 
10170 wxGridCellRenderer 
* wxGrid::GetDefaultRendererForType(const wxString
& typeName
) const 
10172     int index 
= m_typeRegistry
->FindOrCloneDataType(typeName
); 
10173     if ( index 
== wxNOT_FOUND 
) 
10175         wxFAIL_MSG(wxString::Format(wxT("Unknown data type name [%s]"), typeName
.c_str())); 
10180     return m_typeRegistry
->GetRenderer(index
); 
10183 // ---------------------------------------------------------------------------- 
10185 // ---------------------------------------------------------------------------- 
10187 void wxGrid::EnableDragRowSize( bool enable 
) 
10189     m_canDragRowSize 
= enable
; 
10192 void wxGrid::EnableDragColSize( bool enable 
) 
10194     m_canDragColSize 
= enable
; 
10197 void wxGrid::EnableDragGridSize( bool enable 
) 
10199     m_canDragGridSize 
= enable
; 
10202 void wxGrid::EnableDragCell( bool enable 
) 
10204     m_canDragCell 
= enable
; 
10207 void wxGrid::SetDefaultRowSize( int height
, bool resizeExistingRows 
) 
10209     m_defaultRowHeight 
= wxMax( height
, m_minAcceptableRowHeight 
); 
10211     if ( resizeExistingRows 
) 
10213         // since we are resizing all rows to the default row size, 
10214         // we can simply clear the row heights and row bottoms 
10215         // arrays (which also allows us to take advantage of 
10216         // some speed optimisations) 
10217         m_rowHeights
.Empty(); 
10218         m_rowBottoms
.Empty(); 
10219         if ( !GetBatchCount() ) 
10224 void wxGrid::SetRowSize( int row
, int height 
) 
10226     wxCHECK_RET( row 
>= 0 && row 
< m_numRows
, _T("invalid row index") ); 
10228     // if < 0 then calculate new height from label 
10232         wxArrayString lines
; 
10233         wxClientDC 
dc(m_rowLabelWin
); 
10234         dc
.SetFont(GetLabelFont()); 
10235         StringToLines(GetRowLabelValue( row 
), lines
); 
10236         GetTextBoxSize( dc
, lines
, &w
, &h 
); 
10237         //check that it is not less than the minimal height 
10238         height 
= wxMax(h
, GetRowMinimalAcceptableHeight()); 
10241     // See comment in SetColSize 
10242     if ( height 
< GetRowMinimalAcceptableHeight()) 
10245     if ( m_rowHeights
.IsEmpty() ) 
10247         // need to really create the array 
10251     int h 
= wxMax( 0, height 
); 
10252     int diff 
= h 
- m_rowHeights
[row
]; 
10254     m_rowHeights
[row
] = h
; 
10255     for ( int i 
= row
; i 
< m_numRows
; i
++ ) 
10257         m_rowBottoms
[i
] += diff
; 
10260     if ( !GetBatchCount() ) 
10264 void wxGrid::SetDefaultColSize( int width
, bool resizeExistingCols 
) 
10266     // we dont allow zero default column width 
10267     m_defaultColWidth 
= wxMax( wxMax( width
, m_minAcceptableColWidth 
), 1 ); 
10269     if ( resizeExistingCols 
) 
10271         // since we are resizing all columns to the default column size, 
10272         // we can simply clear the col widths and col rights 
10273         // arrays (which also allows us to take advantage of 
10274         // some speed optimisations) 
10275         m_colWidths
.Empty(); 
10276         m_colRights
.Empty(); 
10277         if ( !GetBatchCount() ) 
10282 void wxGrid::SetColSize( int col
, int width 
) 
10284     wxCHECK_RET( col 
>= 0 && col 
< m_numCols
, _T("invalid column index") ); 
10286     // if < 0 then calculate new width from label 
10290         wxArrayString lines
; 
10291         wxClientDC 
dc(m_colWindow
); 
10292         dc
.SetFont(GetLabelFont()); 
10293         StringToLines(GetColLabelValue(col
), lines
); 
10294         if ( GetColLabelTextOrientation() == wxHORIZONTAL 
) 
10295             GetTextBoxSize( dc
, lines
, &w
, &h 
); 
10297             GetTextBoxSize( dc
, lines
, &h
, &w 
); 
10299         //check that it is not less than the minimal width 
10300         width 
= wxMax(width
, GetColMinimalAcceptableWidth()); 
10303     // should we check that it's bigger than GetColMinimalWidth(col) here? 
10305     // No, because it is reasonable to assume the library user know's 
10306     // what he is doing. However we should test against the weaker 
10307     // constraint of minimalAcceptableWidth, as this breaks rendering 
10309     // This test then fixes sf.net bug #645734 
10311     if ( width 
< GetColMinimalAcceptableWidth() ) 
10314     if ( m_colWidths
.IsEmpty() ) 
10316         // need to really create the array 
10320     int w 
= wxMax( 0, width 
); 
10321     int diff 
= w 
- m_colWidths
[col
]; 
10322     m_colWidths
[col
] = w
; 
10324     for ( int colPos 
= GetColPos(col
); colPos 
< m_numCols
; colPos
++ ) 
10326         m_colRights
[GetColAt(colPos
)] += diff
; 
10329     if ( !GetBatchCount() ) 
10336 void wxGrid::SetColMinimalWidth( int col
, int width 
) 
10338     if (width 
> GetColMinimalAcceptableWidth()) 
10340         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
10341         m_colMinWidths
[key
] = width
; 
10345 void wxGrid::SetRowMinimalHeight( int row
, int width 
) 
10347     if (width 
> GetRowMinimalAcceptableHeight()) 
10349         wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
10350         m_rowMinHeights
[key
] = width
; 
10354 int wxGrid::GetColMinimalWidth(int col
) const 
10356     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)col
; 
10357     wxLongToLongHashMap::const_iterator it 
= m_colMinWidths
.find(key
); 
10359     return it 
!= m_colMinWidths
.end() ? (int)it
->second 
: m_minAcceptableColWidth
; 
10362 int wxGrid::GetRowMinimalHeight(int row
) const 
10364     wxLongToLongHashMap::key_type key 
= (wxLongToLongHashMap::key_type
)row
; 
10365     wxLongToLongHashMap::const_iterator it 
= m_rowMinHeights
.find(key
); 
10367     return it 
!= m_rowMinHeights
.end() ? (int)it
->second 
: m_minAcceptableRowHeight
; 
10370 void wxGrid::SetColMinimalAcceptableWidth( int width 
) 
10372     // We do allow a width of 0 since this gives us 
10373     // an easy way to temporarily hiding columns. 
10375         m_minAcceptableColWidth 
= width
; 
10378 void wxGrid::SetRowMinimalAcceptableHeight( int height 
) 
10380     // We do allow a height of 0 since this gives us 
10381     // an easy way to temporarily hiding rows. 
10383         m_minAcceptableRowHeight 
= height
; 
10386 int  wxGrid::GetColMinimalAcceptableWidth() const 
10388     return m_minAcceptableColWidth
; 
10391 int  wxGrid::GetRowMinimalAcceptableHeight() const 
10393     return m_minAcceptableRowHeight
; 
10396 // ---------------------------------------------------------------------------- 
10398 // ---------------------------------------------------------------------------- 
10401 wxGrid::AutoSizeColOrRow(int colOrRow
, bool setAsMin
, wxGridDirection direction
) 
10403     const bool column 
= direction 
== wxGRID_COLUMN
; 
10405     wxClientDC 
dc(m_gridWin
); 
10407     // cancel editing of cell 
10408     HideCellEditControl(); 
10409     SaveEditControlValue(); 
10411     // init both of them to avoid compiler warnings, even if we only need one 
10419     wxCoord extent
, extentMax 
= 0; 
10420     int max 
= column 
? m_numRows 
: m_numCols
; 
10421     for ( int rowOrCol 
= 0; rowOrCol 
< max
; rowOrCol
++ ) 
10428         wxGridCellAttr 
*attr 
= GetCellAttr(row
, col
); 
10429         wxGridCellRenderer 
*renderer 
= attr
->GetRenderer(this, row
, col
); 
10432             wxSize size 
= renderer
->GetBestSize(*this, *attr
, dc
, row
, col
); 
10433             extent 
= column 
? size
.x 
: size
.y
; 
10434             if ( extent 
> extentMax 
) 
10435                 extentMax 
= extent
; 
10437             renderer
->DecRef(); 
10443     // now also compare with the column label extent 
10445     dc
.SetFont( GetLabelFont() ); 
10449         dc
.GetMultiLineTextExtent( GetColLabelValue(col
), &w
, &h 
); 
10450         if ( GetColLabelTextOrientation() == wxVERTICAL 
) 
10454         dc
.GetMultiLineTextExtent( GetRowLabelValue(row
), &w
, &h 
); 
10456     extent 
= column 
? w 
: h
; 
10457     if ( extent 
> extentMax 
) 
10458         extentMax 
= extent
; 
10462         // empty column - give default extent (notice that if extentMax is less 
10463         // than default extent but != 0, it's OK) 
10464         extentMax 
= column 
? m_defaultColWidth 
: m_defaultRowHeight
; 
10469             // leave some space around text 
10477         // Ensure automatic width is not less than minimal width. See the 
10478         // comment in SetColSize() for explanation of why this isn't done 
10479         // in SetColSize(). 
10481             extentMax 
= wxMax(extentMax
, GetColMinimalWidth(col
)); 
10483         SetColSize( col
, extentMax 
); 
10484         if ( !GetBatchCount() ) 
10486             if ( m_useNativeHeader 
) 
10488                 GetColHeader()->UpdateColumn(col
); 
10493                 m_gridWin
->GetClientSize( &cw
, &ch 
); 
10494                 wxRect 
rect ( CellToRect( 0, col 
) ); 
10496                 CalcScrolledPosition(rect
.x
, 0, &rect
.x
, &dummy
); 
10497                 rect
.width 
= cw 
- rect
.x
; 
10498                 rect
.height 
= m_colLabelHeight
; 
10499                 GetColLabelWindow()->Refresh( true, &rect 
); 
10505         // Ensure automatic width is not less than minimal height. See the 
10506         // comment in SetColSize() for explanation of why this isn't done 
10507         // in SetRowSize(). 
10509             extentMax 
= wxMax(extentMax
, GetRowMinimalHeight(row
)); 
10511         SetRowSize(row
, extentMax
); 
10512         if ( !GetBatchCount() ) 
10515             m_gridWin
->GetClientSize( &cw
, &ch 
); 
10516             wxRect 
rect( CellToRect( row
, 0 ) ); 
10518             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
10519             rect
.width 
= m_rowLabelWidth
; 
10520             rect
.height 
= ch 
- rect
.y
; 
10521             m_rowLabelWin
->Refresh( true, &rect 
); 
10528             SetColMinimalWidth(col
, extentMax
); 
10530             SetRowMinimalHeight(row
, extentMax
); 
10534 wxCoord 
wxGrid::CalcColOrRowLabelAreaMinSize(wxGridDirection direction
) 
10536     // calculate size for the rows or columns? 
10537     const bool calcRows 
= direction 
== wxGRID_ROW
; 
10539     wxClientDC 
dc(calcRows 
? GetGridRowLabelWindow() 
10540                            : GetGridColLabelWindow()); 
10541     dc
.SetFont(GetLabelFont()); 
10543     // which dimension should we take into account for calculations? 
10545     // for columns, the text can be only horizontal so it's easy but for rows 
10546     // we also have to take into account the text orientation 
10548         useWidth 
= calcRows 
|| (GetColLabelTextOrientation() == wxVERTICAL
); 
10550     wxArrayString lines
; 
10551     wxCoord extentMax 
= 0; 
10553     const int numRowsOrCols 
= calcRows 
? m_numRows 
: m_numCols
; 
10554     for ( int rowOrCol 
= 0; rowOrCol 
< numRowsOrCols
; rowOrCol
++ ) 
10558         wxString label 
= calcRows 
? GetRowLabelValue(rowOrCol
) 
10559                                   : GetColLabelValue(rowOrCol
); 
10560         StringToLines(label
, lines
); 
10563         GetTextBoxSize(dc
, lines
, &w
, &h
); 
10565         const wxCoord extent 
= useWidth 
? w 
: h
; 
10566         if ( extent 
> extentMax 
) 
10567             extentMax 
= extent
; 
10572         // empty column - give default extent (notice that if extentMax is less 
10573         // than default extent but != 0, it's OK) 
10574         extentMax 
= calcRows 
? GetDefaultRowLabelSize() 
10575                              : GetDefaultColLabelSize(); 
10578     // leave some space around text (taken from AutoSizeColOrRow) 
10587 int wxGrid::SetOrCalcColumnSizes(bool calcOnly
, bool setAsMin
) 
10589     int width 
= m_rowLabelWidth
; 
10591     wxGridUpdateLocker locker
; 
10593         locker
.Create(this); 
10595     for ( int col 
= 0; col 
< m_numCols
; col
++ ) 
10598             AutoSizeColumn(col
, setAsMin
); 
10600         width 
+= GetColWidth(col
); 
10606 int wxGrid::SetOrCalcRowSizes(bool calcOnly
, bool setAsMin
) 
10608     int height 
= m_colLabelHeight
; 
10610     wxGridUpdateLocker locker
; 
10612         locker
.Create(this); 
10614     for ( int row 
= 0; row 
< m_numRows
; row
++ ) 
10617             AutoSizeRow(row
, setAsMin
); 
10619         height 
+= GetRowHeight(row
); 
10625 void wxGrid::AutoSize() 
10627     wxGridUpdateLocker 
locker(this); 
10629     wxSize 
size(SetOrCalcColumnSizes(false) - m_rowLabelWidth 
+ m_extraWidth
, 
10630                 SetOrCalcRowSizes(false) - m_colLabelHeight 
+ m_extraHeight
); 
10632     // we know that we're not going to have scrollbars so disable them now to 
10633     // avoid trouble in SetClientSize() which can otherwise set the correct 
10634     // client size but also leave space for (not needed any more) scrollbars 
10635     SetScrollbars(0, 0, 0, 0, 0, 0, true); 
10637     // restore the scroll rate parameters overwritten by SetScrollbars() 
10638     SetScrollRate(m_scrollLineX
, m_scrollLineY
); 
10640     SetClientSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
); 
10643 void wxGrid::AutoSizeRowLabelSize( int row 
) 
10645     // Hide the edit control, so it 
10646     // won't interfere with drag-shrinking. 
10647     if ( IsCellEditControlShown() ) 
10649         HideCellEditControl(); 
10650         SaveEditControlValue(); 
10653     // autosize row height depending on label text 
10654     SetRowSize(row
, -1); 
10658 void wxGrid::AutoSizeColLabelSize( int col 
) 
10660     // Hide the edit control, so it 
10661     // won't interfere with drag-shrinking. 
10662     if ( IsCellEditControlShown() ) 
10664         HideCellEditControl(); 
10665         SaveEditControlValue(); 
10668     // autosize column width depending on label text 
10669     SetColSize(col
, -1); 
10673 wxSize 
wxGrid::DoGetBestSize() const 
10675     wxGrid 
*self 
= (wxGrid 
*)this;  // const_cast 
10677     // we do the same as in AutoSize() here with the exception that we don't 
10678     // change the column/row sizes, only calculate them 
10679     wxSize 
size(self
->SetOrCalcColumnSizes(true) - m_rowLabelWidth 
+ m_extraWidth
, 
10680                 self
->SetOrCalcRowSizes(true) - m_colLabelHeight 
+ m_extraHeight
); 
10682     // NOTE: This size should be cached, but first we need to add calls to 
10683     // InvalidateBestSize everywhere that could change the results of this 
10685     // CacheBestSize(size); 
10687     return wxSize(size
.x 
+ m_rowLabelWidth
, size
.y 
+ m_colLabelHeight
) 
10688             + GetWindowBorderSize(); 
10696 wxPen
& wxGrid::GetDividerPen() const 
10701 // ---------------------------------------------------------------------------- 
10702 // cell value accessor functions 
10703 // ---------------------------------------------------------------------------- 
10705 void wxGrid::SetCellValue( int row
, int col
, const wxString
& s 
) 
10709         m_table
->SetValue( row
, col
, s 
); 
10710         if ( !GetBatchCount() ) 
10713             wxRect 
rect( CellToRect( row
, col 
) ); 
10715             rect
.width 
= m_gridWin
->GetClientSize().GetWidth(); 
10716             CalcScrolledPosition(0, rect
.y
, &dummy
, &rect
.y
); 
10717             m_gridWin
->Refresh( false, &rect 
); 
10720         if ( m_currentCellCoords
.GetRow() == row 
&& 
10721              m_currentCellCoords
.GetCol() == col 
&& 
10722              IsCellEditControlShown()) 
10723              // Note: If we are using IsCellEditControlEnabled, 
10724              // this interacts badly with calling SetCellValue from 
10725              // an EVT_GRID_CELL_CHANGE handler. 
10727             HideCellEditControl(); 
10728             ShowCellEditControl(); // will reread data from table 
10733 // ---------------------------------------------------------------------------- 
10734 // block, row and column selection 
10735 // ---------------------------------------------------------------------------- 
10737 void wxGrid::SelectRow( int row
, bool addToSelected 
) 
10739     if ( !m_selection 
) 
10742     if ( !addToSelected 
) 
10745     m_selection
->SelectRow(row
); 
10748 void wxGrid::SelectCol( int col
, bool addToSelected 
) 
10750     if ( !m_selection 
) 
10753     if ( !addToSelected 
) 
10756     m_selection
->SelectCol(col
); 
10759 void wxGrid::SelectBlock(int topRow
, int leftCol
, int bottomRow
, int rightCol
, 
10760                          bool addToSelected
) 
10762     if ( !m_selection 
) 
10765     if ( !addToSelected 
) 
10768     m_selection
->SelectBlock(topRow
, leftCol
, bottomRow
, rightCol
); 
10771 void wxGrid::SelectAll() 
10773     if ( m_numRows 
> 0 && m_numCols 
> 0 ) 
10776             m_selection
->SelectBlock( 0, 0, m_numRows 
- 1, m_numCols 
- 1 ); 
10780 // ---------------------------------------------------------------------------- 
10781 // cell, row and col deselection 
10782 // ---------------------------------------------------------------------------- 
10784 void wxGrid::DeselectLine(int line
, const wxGridOperations
& oper
) 
10786     if ( !m_selection 
) 
10789     const wxGridSelectionModes mode 
= m_selection
->GetSelectionMode(); 
10790     if ( mode 
== oper
.GetSelectionMode() ) 
10792         const wxGridCellCoords 
c(oper
.MakeCoords(line
, 0)); 
10793         if ( m_selection
->IsInSelection(c
) ) 
10794             m_selection
->ToggleCellSelection(c
); 
10796     else if ( mode 
!= oper
.Dual().GetSelectionMode() ) 
10798         const int nOther 
= oper
.Dual().GetNumberOfLines(this); 
10799         for ( int i 
= 0; i 
< nOther
; i
++ ) 
10801             const wxGridCellCoords 
c(oper
.MakeCoords(line
, i
)); 
10802             if ( m_selection
->IsInSelection(c
) ) 
10803                 m_selection
->ToggleCellSelection(c
); 
10806     //else: can only select orthogonal lines so no lines in this direction 
10807     //      could have been selected anyhow 
10810 void wxGrid::DeselectRow(int row
) 
10812     DeselectLine(row
, wxGridRowOperations()); 
10815 void wxGrid::DeselectCol(int col
) 
10817     DeselectLine(col
, wxGridColumnOperations()); 
10820 void wxGrid::DeselectCell( int row
, int col 
) 
10822     if ( m_selection 
&& m_selection
->IsInSelection(row
, col
) ) 
10823         m_selection
->ToggleCellSelection(row
, col
); 
10826 bool wxGrid::IsSelection() const 
10828     return ( m_selection 
&& (m_selection
->IsSelection() || 
10829              ( m_selectedBlockTopLeft 
!= wxGridNoCellCoords 
&& 
10830                m_selectedBlockBottomRight 
!= wxGridNoCellCoords
) ) ); 
10833 bool wxGrid::IsInSelection( int row
, int col 
) const 
10835     return ( m_selection 
&& (m_selection
->IsInSelection( row
, col 
) || 
10836              ( row 
>= m_selectedBlockTopLeft
.GetRow() && 
10837                col 
>= m_selectedBlockTopLeft
.GetCol() && 
10838                row 
<= m_selectedBlockBottomRight
.GetRow() && 
10839                col 
<= m_selectedBlockBottomRight
.GetCol() )) ); 
10842 wxGridCellCoordsArray 
wxGrid::GetSelectedCells() const 
10846         wxGridCellCoordsArray a
; 
10850     return m_selection
->m_cellSelection
; 
10853 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockTopLeft() const 
10857         wxGridCellCoordsArray a
; 
10861     return m_selection
->m_blockSelectionTopLeft
; 
10864 wxGridCellCoordsArray 
wxGrid::GetSelectionBlockBottomRight() const 
10868         wxGridCellCoordsArray a
; 
10872     return m_selection
->m_blockSelectionBottomRight
; 
10875 wxArrayInt 
wxGrid::GetSelectedRows() const 
10883     return m_selection
->m_rowSelection
; 
10886 wxArrayInt 
wxGrid::GetSelectedCols() const 
10894     return m_selection
->m_colSelection
; 
10897 void wxGrid::ClearSelection() 
10899     wxRect r1 
= BlockToDeviceRect(m_selectedBlockTopLeft
, 
10900                                   m_selectedBlockBottomRight
); 
10901     wxRect r2 
= BlockToDeviceRect(m_currentCellCoords
, 
10902                                   m_selectedBlockCorner
); 
10904     m_selectedBlockTopLeft 
= 
10905     m_selectedBlockBottomRight 
= 
10906     m_selectedBlockCorner 
= wxGridNoCellCoords
; 
10908     Refresh( false, &r1 
); 
10909     Refresh( false, &r2 
); 
10912         m_selection
->ClearSelection(); 
10915 // This function returns the rectangle that encloses the given block 
10916 // in device coords clipped to the client size of the grid window. 
10918 wxRect 
wxGrid::BlockToDeviceRect( const wxGridCellCoords
& topLeft
, 
10919                                   const wxGridCellCoords
& bottomRight 
) const 
10922     wxRect tempCellRect 
= CellToRect(topLeft
); 
10923     if ( tempCellRect 
!= wxGridNoCellRect 
) 
10925         resultRect 
= tempCellRect
; 
10929         resultRect 
= wxRect(0, 0, 0, 0); 
10932     tempCellRect 
= CellToRect(bottomRight
); 
10933     if ( tempCellRect 
!= wxGridNoCellRect 
) 
10935         resultRect 
+= tempCellRect
; 
10939         // If both inputs were "wxGridNoCellRect," then there's nothing to do. 
10940         return wxGridNoCellRect
; 
10943     // Ensure that left/right and top/bottom pairs are in order. 
10944     int left 
= resultRect
.GetLeft(); 
10945     int top 
= resultRect
.GetTop(); 
10946     int right 
= resultRect
.GetRight(); 
10947     int bottom 
= resultRect
.GetBottom(); 
10949     int leftCol 
= topLeft
.GetCol(); 
10950     int topRow 
= topLeft
.GetRow(); 
10951     int rightCol 
= bottomRight
.GetCol(); 
10952     int bottomRow 
= bottomRight
.GetRow(); 
10961         leftCol 
= rightCol
; 
10972         topRow 
= bottomRow
; 
10976     // The following loop is ONLY necessary to detect and handle merged cells. 
10978     m_gridWin
->GetClientSize( &cw
, &ch 
); 
10980     // Get the origin coordinates: notice that they will be negative if the 
10981     // grid is scrolled downwards/to the right. 
10982     int gridOriginX 
= 0; 
10983     int gridOriginY 
= 0; 
10984     CalcScrolledPosition(gridOriginX
, gridOriginY
, &gridOriginX
, &gridOriginY
); 
10986     int onScreenLeftmostCol 
= internalXToCol(-gridOriginX
); 
10987     int onScreenUppermostRow 
= internalYToRow(-gridOriginY
); 
10989     int onScreenRightmostCol 
= internalXToCol(-gridOriginX 
+ cw
); 
10990     int onScreenBottommostRow 
= internalYToRow(-gridOriginY 
+ ch
); 
10992     // Bound our loop so that we only examine the portion of the selected block 
10993     // that is shown on screen. Therefore, we compare the Top-Left block values 
10994     // to the Top-Left screen values, and the Bottom-Right block values to the 
10995     // Bottom-Right screen values, choosing appropriately. 
10996     const int visibleTopRow 
= wxMax(topRow
, onScreenUppermostRow
); 
10997     const int visibleBottomRow 
= wxMin(bottomRow
, onScreenBottommostRow
); 
10998     const int visibleLeftCol 
= wxMax(leftCol
, onScreenLeftmostCol
); 
10999     const int visibleRightCol 
= wxMin(rightCol
, onScreenRightmostCol
); 
11001     for ( int j 
= visibleTopRow
; j 
<= visibleBottomRow
; j
++ ) 
11003         for ( int i 
= visibleLeftCol
; i 
<= visibleRightCol
; i
++ ) 
11005             if ( (j 
== visibleTopRow
) || (j 
== visibleBottomRow
) || 
11006                     (i 
== visibleLeftCol
) || (i 
== visibleRightCol
) ) 
11008                 tempCellRect 
= CellToRect( j
, i 
); 
11010                 if (tempCellRect
.x 
< left
) 
11011                     left 
= tempCellRect
.x
; 
11012                 if (tempCellRect
.y 
< top
) 
11013                     top 
= tempCellRect
.y
; 
11014                 if (tempCellRect
.x 
+ tempCellRect
.width 
> right
) 
11015                     right 
= tempCellRect
.x 
+ tempCellRect
.width
; 
11016                 if (tempCellRect
.y 
+ tempCellRect
.height 
> bottom
) 
11017                     bottom 
= tempCellRect
.y 
+ tempCellRect
.height
; 
11021                 i 
= visibleRightCol
; // jump over inner cells. 
11026     // Convert to scrolled coords 
11027     CalcScrolledPosition( left
, top
, &left
, &top 
); 
11028     CalcScrolledPosition( right
, bottom
, &right
, &bottom 
); 
11030     if (right 
< 0 || bottom 
< 0 || left 
> cw 
|| top 
> ch
) 
11031         return wxRect(0,0,0,0); 
11033     resultRect
.SetLeft( wxMax(0, left
) ); 
11034     resultRect
.SetTop( wxMax(0, top
) ); 
11035     resultRect
.SetRight( wxMin(cw
, right
) ); 
11036     resultRect
.SetBottom( wxMin(ch
, bottom
) ); 
11041 // ---------------------------------------------------------------------------- 
11043 // ---------------------------------------------------------------------------- 
11045 #if wxUSE_DRAG_AND_DROP 
11047 // this allow setting drop target directly on wxGrid 
11048 void wxGrid::SetDropTarget(wxDropTarget 
*dropTarget
) 
11050     GetGridWindow()->SetDropTarget(dropTarget
); 
11053 #endif // wxUSE_DRAG_AND_DROP 
11055 // ---------------------------------------------------------------------------- 
11056 // grid event classes 
11057 // ---------------------------------------------------------------------------- 
11059 IMPLEMENT_DYNAMIC_CLASS( wxGridEvent
, wxNotifyEvent 
) 
11061 wxGridEvent::wxGridEvent( int id
, wxEventType type
, wxObject
* obj
, 
11062                           int row
, int col
, int x
, int y
, bool sel
, 
11063                           bool control
, bool shift
, bool alt
, bool meta 
) 
11064         : wxNotifyEvent( type
, id 
), 
11065           wxKeyboardState(control
, shift
, alt
, meta
) 
11067     Init(row
, col
, x
, y
, sel
); 
11069     SetEventObject(obj
); 
11072 IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent
, wxNotifyEvent 
) 
11074 wxGridSizeEvent::wxGridSizeEvent( int id
, wxEventType type
, wxObject
* obj
, 
11075                                   int rowOrCol
, int x
, int y
, 
11076                                   bool control
, bool shift
, bool alt
, bool meta 
) 
11077         : wxNotifyEvent( type
, id 
), 
11078           wxKeyboardState(control
, shift
, alt
, meta
) 
11080     Init(rowOrCol
, x
, y
); 
11082     SetEventObject(obj
); 
11086 IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent
, wxNotifyEvent 
) 
11088 wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id
, wxEventType type
, wxObject
* obj
, 
11089                                                const wxGridCellCoords
& topLeft
, 
11090                                                const wxGridCellCoords
& bottomRight
, 
11091                                                bool sel
, bool control
, 
11092                                                bool shift
, bool alt
, bool meta 
) 
11093         : wxNotifyEvent( type
, id 
), 
11094           wxKeyboardState(control
, shift
, alt
, meta
) 
11096     Init(topLeft
, bottomRight
, sel
); 
11098     SetEventObject(obj
); 
11102 IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent
, wxCommandEvent
) 
11104 wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id
, wxEventType type
, 
11105                                                    wxObject
* obj
, int row
, 
11106                                                    int col
, wxControl
* ctrl
) 
11107     : wxCommandEvent(type
, id
) 
11109     SetEventObject(obj
); 
11115 #endif // wxUSE_GRID