home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / grid.cpp < prev    next >
C/C++ Source or Header  |  2003-01-04  |  285KB  |  9,835 lines

  1. ///////////////////////////////////////////////////////////////////////////
  2. // Name:        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
  6. // Created:     1/08/1999
  7. // RCS-ID:      $Id: grid.cpp,v 1.231.2.10 2003/01/04 03:54:17 RD Exp $
  8. // Copyright:   (c) Michael Bedward (mbedward@ozemail.com.au)
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "grid.h"
  22. #endif
  23.  
  24. // For compilers that support precompilatixon, includes "wx/wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #include "wx/defs.h"
  28.  
  29. #ifdef __BORLANDC__
  30.     #pragma hdrstop
  31. #endif
  32.  
  33. #if wxUSE_GRID
  34.  
  35. #if !defined(wxUSE_NEW_GRID) || !(wxUSE_NEW_GRID)
  36.     #include "gridg.cpp"
  37. #else // wxUSE_NEW_GRID
  38.  
  39. #ifndef WX_PRECOMP
  40.     #include "wx/utils.h"
  41.     #include "wx/dcclient.h"
  42.     #include "wx/settings.h"
  43.     #include "wx/log.h"
  44.     #include "wx/textctrl.h"
  45.     #include "wx/checkbox.h"
  46.     #include "wx/combobox.h"
  47.     #include "wx/valtext.h"
  48. #endif
  49.  
  50. #include "wx/textfile.h"
  51. #include "wx/spinctrl.h"
  52. #include "wx/tokenzr.h"
  53.  
  54. #include "wx/grid.h"
  55. #include "wx/generic/gridsel.h"
  56.  
  57. #if defined(__WXMOTIF__)
  58.     #define WXUNUSED_MOTIF(identifier)  WXUNUSED(identifier)
  59. #else
  60.     #define WXUNUSED_MOTIF(identifier)  identifier
  61. #endif
  62.  
  63. #if defined(__WXGTK__)
  64.     #define WXUNUSED_GTK(identifier)    WXUNUSED(identifier)
  65. #else
  66.     #define WXUNUSED_GTK(identifier)    identifier
  67. #endif
  68.  
  69. // Required for wxIs... functions
  70. #include <ctype.h>
  71.  
  72. // ----------------------------------------------------------------------------
  73. // array classes
  74. // ----------------------------------------------------------------------------
  75.  
  76. WX_DEFINE_EXPORTED_ARRAY(wxGridCellAttr *, wxArrayAttrs);
  77.  
  78. struct wxGridCellWithAttr
  79. {
  80.     wxGridCellWithAttr(int row, int col, wxGridCellAttr *attr_)
  81.         : coords(row, col), attr(attr_)
  82.     {
  83.     }
  84.  
  85.     ~wxGridCellWithAttr()
  86.     {
  87.         attr->DecRef();
  88.     }
  89.  
  90.     wxGridCellCoords coords;
  91.     wxGridCellAttr  *attr;
  92. };
  93.  
  94. WX_DECLARE_EXPORTED_OBJARRAY(wxGridCellWithAttr, wxGridCellWithAttrArray);
  95.  
  96. #include "wx/arrimpl.cpp"
  97.  
  98. WX_DEFINE_OBJARRAY(wxGridCellCoordsArray)
  99. WX_DEFINE_OBJARRAY(wxGridCellWithAttrArray)
  100.  
  101. // ----------------------------------------------------------------------------
  102. // events
  103. // ----------------------------------------------------------------------------
  104.  
  105. DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_CLICK)
  106. DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_CLICK)
  107. DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_LEFT_DCLICK)
  108. DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_RIGHT_DCLICK)
  109. DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_CLICK)
  110. DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_CLICK)
  111. DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_LEFT_DCLICK)
  112. DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK)
  113. DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE)
  114. DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE)
  115. DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT)
  116. DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE)
  117. DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL)
  118. DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN)
  119. DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN)
  120. DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_CREATED)
  121.  
  122. // ----------------------------------------------------------------------------
  123. // private classes
  124. // ----------------------------------------------------------------------------
  125.  
  126. class WXDLLEXPORT wxGridRowLabelWindow : public wxWindow
  127. {
  128. public:
  129.     wxGridRowLabelWindow() { m_owner = (wxGrid *)NULL; }
  130.     wxGridRowLabelWindow( wxGrid *parent, wxWindowID id,
  131.                           const wxPoint &pos, const wxSize &size );
  132.  
  133. private:
  134.     wxGrid   *m_owner;
  135.  
  136.     void OnPaint( wxPaintEvent& event );
  137.     void OnMouseEvent( wxMouseEvent& event );
  138.     void OnMouseWheel( wxMouseEvent& event );
  139.     void OnKeyDown( wxKeyEvent& event );
  140.     void OnKeyUp( wxKeyEvent& );
  141.  
  142.     DECLARE_DYNAMIC_CLASS(wxGridRowLabelWindow)
  143.     DECLARE_EVENT_TABLE()
  144. };
  145.  
  146.  
  147. class WXDLLEXPORT wxGridColLabelWindow : public wxWindow
  148. {
  149. public:
  150.     wxGridColLabelWindow() { m_owner = (wxGrid *)NULL; }
  151.     wxGridColLabelWindow( wxGrid *parent, wxWindowID id,
  152.                           const wxPoint &pos, const wxSize &size );
  153.  
  154. private:
  155.     wxGrid   *m_owner;
  156.  
  157.     void OnPaint( wxPaintEvent &event );
  158.     void OnMouseEvent( wxMouseEvent& event );
  159.     void OnMouseWheel( wxMouseEvent& event );
  160.     void OnKeyDown( wxKeyEvent& event );
  161.     void OnKeyUp( wxKeyEvent& );
  162.  
  163.     DECLARE_DYNAMIC_CLASS(wxGridColLabelWindow)
  164.     DECLARE_EVENT_TABLE()
  165. };
  166.  
  167.  
  168. class WXDLLEXPORT wxGridCornerLabelWindow : public wxWindow
  169. {
  170. public:
  171.     wxGridCornerLabelWindow() { m_owner = (wxGrid *)NULL; }
  172.     wxGridCornerLabelWindow( wxGrid *parent, wxWindowID id,
  173.                              const wxPoint &pos, const wxSize &size );
  174.  
  175. private:
  176.     wxGrid *m_owner;
  177.  
  178.     void OnMouseEvent( wxMouseEvent& event );
  179.     void OnMouseWheel( wxMouseEvent& event );
  180.     void OnKeyDown( wxKeyEvent& event );
  181.     void OnKeyUp( wxKeyEvent& );
  182.     void OnPaint( wxPaintEvent& event );
  183.  
  184.     DECLARE_DYNAMIC_CLASS(wxGridCornerLabelWindow)
  185.     DECLARE_EVENT_TABLE()
  186. };
  187.  
  188. class WXDLLEXPORT wxGridWindow : public wxWindow
  189. {
  190. public:
  191.     wxGridWindow()
  192.     {
  193.         m_owner = (wxGrid *)NULL;
  194.         m_rowLabelWin = (wxGridRowLabelWindow *)NULL;
  195.         m_colLabelWin = (wxGridColLabelWindow *)NULL;
  196.     }
  197.  
  198.     wxGridWindow( wxGrid *parent,
  199.                   wxGridRowLabelWindow *rowLblWin,
  200.                   wxGridColLabelWindow *colLblWin,
  201.                   wxWindowID id, const wxPoint &pos, const wxSize &size );
  202.     ~wxGridWindow();
  203.  
  204.     void ScrollWindow( int dx, int dy, const wxRect *rect );
  205.  
  206.     wxGrid* GetOwner() { return m_owner; }
  207.  
  208. private:
  209.     wxGrid                   *m_owner;
  210.     wxGridRowLabelWindow     *m_rowLabelWin;
  211.     wxGridColLabelWindow     *m_colLabelWin;
  212.  
  213.     void OnPaint( wxPaintEvent &event );
  214.     void OnMouseWheel( wxMouseEvent& event );
  215.     void OnMouseEvent( wxMouseEvent& event );
  216.     void OnKeyDown( wxKeyEvent& );
  217.     void OnKeyUp( wxKeyEvent& );
  218.     void OnEraseBackground( wxEraseEvent& );
  219.  
  220.  
  221.     DECLARE_DYNAMIC_CLASS(wxGridWindow)
  222.     DECLARE_EVENT_TABLE()
  223. };
  224.  
  225.  
  226.  
  227. class wxGridCellEditorEvtHandler : public wxEvtHandler
  228. {
  229. public:
  230.     wxGridCellEditorEvtHandler()
  231.         : m_grid(0), m_editor(0)
  232.         { }
  233.     wxGridCellEditorEvtHandler(wxGrid* grid, wxGridCellEditor* editor)
  234.         : m_grid(grid), m_editor(editor)
  235.         { }
  236.  
  237.     void OnKeyDown(wxKeyEvent& event);
  238.     void OnChar(wxKeyEvent& event);
  239.  
  240. private:
  241.     wxGrid*             m_grid;
  242.     wxGridCellEditor*   m_editor;
  243.     DECLARE_DYNAMIC_CLASS(wxGridCellEditorEvtHandler)
  244.     DECLARE_EVENT_TABLE()
  245. };
  246.  
  247.  
  248. IMPLEMENT_DYNAMIC_CLASS( wxGridCellEditorEvtHandler, wxEvtHandler )
  249. BEGIN_EVENT_TABLE( wxGridCellEditorEvtHandler, wxEvtHandler )
  250.     EVT_KEY_DOWN( wxGridCellEditorEvtHandler::OnKeyDown )
  251.     EVT_CHAR( wxGridCellEditorEvtHandler::OnChar )
  252. END_EVENT_TABLE()
  253.  
  254.  
  255.  
  256. // ----------------------------------------------------------------------------
  257. // the internal data representation used by wxGridCellAttrProvider
  258. // ----------------------------------------------------------------------------
  259.  
  260. // this class stores attributes set for cells
  261. class WXDLLEXPORT wxGridCellAttrData
  262. {
  263. public:
  264.     void SetAttr(wxGridCellAttr *attr, int row, int col);
  265.     wxGridCellAttr *GetAttr(int row, int col) const;
  266.     void UpdateAttrRows( size_t pos, int numRows );
  267.     void UpdateAttrCols( size_t pos, int numCols );
  268.  
  269. private:
  270.     // searches for the attr for given cell, returns wxNOT_FOUND if not found
  271.     int FindIndex(int row, int col) const;
  272.  
  273.     wxGridCellWithAttrArray m_attrs;
  274. };
  275.  
  276. // this class stores attributes set for rows or columns
  277. class WXDLLEXPORT wxGridRowOrColAttrData
  278. {
  279. public:
  280.     // empty ctor to suppress warnings
  281.     wxGridRowOrColAttrData() { }
  282.     ~wxGridRowOrColAttrData();
  283.  
  284.     void SetAttr(wxGridCellAttr *attr, int rowOrCol);
  285.     wxGridCellAttr *GetAttr(int rowOrCol) const;
  286.     void UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols );
  287.  
  288. private:
  289.     wxArrayInt m_rowsOrCols;
  290.     wxArrayAttrs m_attrs;
  291. };
  292.  
  293. // NB: this is just a wrapper around 3 objects: one which stores cell
  294. //     attributes, and 2 others for row/col ones
  295. class WXDLLEXPORT wxGridCellAttrProviderData
  296. {
  297. public:
  298.     wxGridCellAttrData m_cellAttrs;
  299.     wxGridRowOrColAttrData m_rowAttrs,
  300.                            m_colAttrs;
  301. };
  302.  
  303.  
  304. // ----------------------------------------------------------------------------
  305. // data structures used for the data type registry
  306. // ----------------------------------------------------------------------------
  307.  
  308. struct wxGridDataTypeInfo
  309. {
  310.     wxGridDataTypeInfo(const wxString& typeName,
  311.                        wxGridCellRenderer* renderer,
  312.                        wxGridCellEditor* editor)
  313.         : m_typeName(typeName), m_renderer(renderer), m_editor(editor)
  314.         { }
  315.  
  316.     ~wxGridDataTypeInfo()
  317.     {
  318.         wxSafeDecRef(m_renderer);
  319.         wxSafeDecRef(m_editor);
  320.     }
  321.  
  322.     wxString            m_typeName;
  323.     wxGridCellRenderer* m_renderer;
  324.     wxGridCellEditor*   m_editor;
  325. };
  326.  
  327.  
  328. WX_DEFINE_EXPORTED_ARRAY(wxGridDataTypeInfo*, wxGridDataTypeInfoArray);
  329.  
  330.  
  331. class WXDLLEXPORT wxGridTypeRegistry
  332. {
  333. public:
  334.   wxGridTypeRegistry() {}
  335.     ~wxGridTypeRegistry();
  336.  
  337.     void RegisterDataType(const wxString& typeName,
  338.                      wxGridCellRenderer* renderer,
  339.                      wxGridCellEditor* editor);
  340.  
  341.     // find one of already registered data types
  342.     int FindRegisteredDataType(const wxString& typeName);
  343.  
  344.     // try to FindRegisteredDataType(), if this fails and typeName is one of
  345.     // standard typenames, register it and return its index
  346.     int FindDataType(const wxString& typeName);
  347.  
  348.     // try to FindDataType(), if it fails see if it is not one of already
  349.     // registered data types with some params in which case clone the
  350.     // registered data type and set params for it
  351.     int FindOrCloneDataType(const wxString& typeName);
  352.  
  353.     wxGridCellRenderer* GetRenderer(int index);
  354.     wxGridCellEditor*   GetEditor(int index);
  355.  
  356. private:
  357.     wxGridDataTypeInfoArray m_typeinfo;
  358. };
  359.  
  360. // ----------------------------------------------------------------------------
  361. // conditional compilation
  362. // ----------------------------------------------------------------------------
  363.  
  364. #ifndef WXGRID_DRAW_LINES
  365. #define WXGRID_DRAW_LINES 1
  366. #endif
  367.  
  368. // ----------------------------------------------------------------------------
  369. // globals
  370. // ----------------------------------------------------------------------------
  371.  
  372. //#define DEBUG_ATTR_CACHE
  373. #ifdef DEBUG_ATTR_CACHE
  374.     static size_t gs_nAttrCacheHits = 0;
  375.     static size_t gs_nAttrCacheMisses = 0;
  376. #endif // DEBUG_ATTR_CACHE
  377.  
  378. // ----------------------------------------------------------------------------
  379. // constants
  380. // ----------------------------------------------------------------------------
  381.  
  382. wxGridCellCoords wxGridNoCellCoords( -1, -1 );
  383. wxRect           wxGridNoCellRect( -1, -1, -1, -1 );
  384.  
  385. // scroll line size
  386. // TODO: this doesn't work at all, grid cells have different sizes and approx
  387. //       calculations don't work as because of the size mismatch scrollbars
  388. //       sometimes fail to be shown when they should be or vice versa
  389. //
  390. //       The scroll bars may be a little flakey once in a while, but that is
  391. //       surely much less horrible than having scroll lines of only 1!!!
  392. //       -- Robin
  393. //
  394. //       Well, it's still seriously broken so it might be better but needs
  395. //       fixing anyhow
  396. //       -- Vadim
  397. static const size_t GRID_SCROLL_LINE_X = 15;  // 1;
  398. static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
  399.  
  400. // the size of hash tables used a bit everywhere (the max number of elements
  401. // in these hash tables is the number of rows/columns)
  402. static const int GRID_HASH_SIZE = 100;
  403.  
  404. // ----------------------------------------------------------------------------
  405. // private functions
  406. // ----------------------------------------------------------------------------
  407.  
  408. static inline int GetScrollX(int x)
  409. {
  410.     return (x + GRID_SCROLL_LINE_X - 1) / GRID_SCROLL_LINE_X;
  411. }
  412.  
  413. static inline int GetScrollY(int y)
  414. {
  415.     return (y + GRID_SCROLL_LINE_Y - 1) / GRID_SCROLL_LINE_Y;
  416. }
  417.  
  418. // ============================================================================
  419. // implementation
  420. // ============================================================================
  421.  
  422. // ----------------------------------------------------------------------------
  423. // wxGridCellEditor
  424. // ----------------------------------------------------------------------------
  425.  
  426. wxGridCellEditor::wxGridCellEditor()
  427. {
  428.     m_control = NULL;
  429.     m_attr = NULL;
  430. }
  431.  
  432.  
  433. wxGridCellEditor::~wxGridCellEditor()
  434. {
  435.     Destroy();
  436. }
  437.  
  438. void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
  439.                               wxWindowID WXUNUSED(id),
  440.                               wxEvtHandler* evtHandler)
  441. {
  442.     if ( evtHandler )
  443.         m_control->PushEventHandler(evtHandler);
  444. }
  445.  
  446. void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
  447.                                        wxGridCellAttr *attr)
  448. {
  449.     // erase the background because we might not fill the cell
  450.     wxClientDC dc(m_control->GetParent());
  451.     wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
  452.     if (gridWindow)
  453.         gridWindow->GetOwner()->PrepareDC(dc);
  454.     dc.SetPen(*wxTRANSPARENT_PEN);
  455.     dc.SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
  456.     dc.DrawRectangle(rectCell);
  457.  
  458.     // redraw the control we just painted over
  459.     m_control->Refresh();
  460. }
  461.  
  462. void wxGridCellEditor::Destroy()
  463. {
  464.     if (m_control)
  465.     {
  466.         m_control->PopEventHandler(TRUE /* delete it*/);
  467.  
  468.         m_control->Destroy();
  469.         m_control = NULL;
  470.     }
  471. }
  472.  
  473. void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
  474. {
  475.     wxASSERT_MSG(m_control,
  476.                  wxT("The wxGridCellEditor must be Created first!"));
  477.     m_control->Show(show);
  478.  
  479.     if ( show )
  480.     {
  481.         // set the colours/fonts if we have any
  482.         if ( attr )
  483.         {
  484.             m_colFgOld = m_control->GetForegroundColour();
  485.             m_control->SetForegroundColour(attr->GetTextColour());
  486.  
  487.             m_colBgOld = m_control->GetBackgroundColour();
  488.             m_control->SetBackgroundColour(attr->GetBackgroundColour());
  489.  
  490.             m_fontOld = m_control->GetFont();
  491.             m_control->SetFont(attr->GetFont());
  492.  
  493.             // can't do anything more in the base class version, the other
  494.             // attributes may only be used by the derived classes
  495.         }
  496.     }
  497.     else
  498.     {
  499.         // restore the standard colours fonts
  500.         if ( m_colFgOld.Ok() )
  501.         {
  502.             m_control->SetForegroundColour(m_colFgOld);
  503.             m_colFgOld = wxNullColour;
  504.         }
  505.  
  506.         if ( m_colBgOld.Ok() )
  507.         {
  508.             m_control->SetBackgroundColour(m_colBgOld);
  509.             m_colBgOld = wxNullColour;
  510.         }
  511.  
  512.         if ( m_fontOld.Ok() )
  513.         {
  514.             m_control->SetFont(m_fontOld);
  515.             m_fontOld = wxNullFont;
  516.         }
  517.     }
  518. }
  519.  
  520. void wxGridCellEditor::SetSize(const wxRect& rect)
  521. {
  522.     wxASSERT_MSG(m_control,
  523.                  wxT("The wxGridCellEditor must be Created first!"));
  524.     m_control->SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
  525. }
  526.  
  527. void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
  528. {
  529.     event.Skip();
  530. }
  531.  
  532. bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
  533. {
  534.     // accept the simple key presses, not anything with Ctrl/Alt/Meta
  535.     return !(event.ControlDown() || event.AltDown());
  536. }
  537.  
  538. void wxGridCellEditor::StartingKey(wxKeyEvent& event)
  539. {
  540.     event.Skip();
  541. }
  542.  
  543. void wxGridCellEditor::StartingClick()
  544. {
  545. }
  546.  
  547. #if wxUSE_TEXTCTRL
  548.  
  549. // ----------------------------------------------------------------------------
  550. // wxGridCellTextEditor
  551. // ----------------------------------------------------------------------------
  552.  
  553. wxGridCellTextEditor::wxGridCellTextEditor()
  554. {
  555.     m_maxChars = 0;
  556. }
  557.  
  558. void wxGridCellTextEditor::Create(wxWindow* parent,
  559.                                   wxWindowID id,
  560.                                   wxEvtHandler* evtHandler)
  561. {
  562.     m_control = new wxTextCtrl(parent, id, wxEmptyString,
  563.                                wxDefaultPosition, wxDefaultSize
  564. #if defined(__WXMSW__)
  565.                                , wxTE_PROCESS_TAB | wxTE_MULTILINE |
  566.                                  wxTE_NO_VSCROLL | wxTE_AUTO_SCROLL
  567. #endif
  568.                               );
  569.  
  570.     // TODO: use m_maxChars
  571.  
  572.     wxGridCellEditor::Create(parent, id, evtHandler);
  573. }
  574.  
  575. void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
  576.                                            wxGridCellAttr * WXUNUSED(attr))
  577. {
  578.     // as we fill the entire client area, don't do anything here to minimize
  579.     // flicker
  580. }
  581.  
  582. void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
  583. {
  584.     wxRect rect(rectOrig);
  585.  
  586.     // Make the edit control large enough to allow for internal
  587.     // margins
  588.     //
  589.     // TODO: remove this if the text ctrl sizing is improved esp. for
  590.     // unix
  591.     //
  592. #if defined(__WXGTK__)
  593.     if (rect.x != 0)
  594.     {
  595.         rect.x += 1;
  596.         rect.y += 1;
  597.         rect.width -= 1;
  598.         rect.height -= 1;
  599.     }
  600. #else // !GTK
  601.     int extra_x = ( rect.x > 2 )? 2 : 1;
  602.  
  603. // MB: treat MSW separately here otherwise the caret doesn't show
  604. // when the editor is in the first row.
  605. #if defined(__WXMSW__)
  606.     int extra_y = 2;
  607. #else
  608.     int extra_y = ( rect.y > 2 )? 2 : 1;
  609. #endif // MSW
  610.  
  611. #if defined(__WXMOTIF__)
  612.     extra_x *= 2;
  613.     extra_y *= 2;
  614. #endif
  615.     rect.SetLeft( wxMax(0, rect.x - extra_x) );
  616.     rect.SetTop( wxMax(0, rect.y - extra_y) );
  617.     rect.SetRight( rect.GetRight() + 2*extra_x );
  618.     rect.SetBottom( rect.GetBottom() + 2*extra_y );
  619. #endif // GTK/!GTK
  620.  
  621.     wxGridCellEditor::SetSize(rect);
  622. }
  623.  
  624. void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid)
  625. {
  626.     wxASSERT_MSG(m_control,
  627.                  wxT("The wxGridCellEditor must be Created first!"));
  628.  
  629.     m_startValue = grid->GetTable()->GetValue(row, col);
  630.  
  631.     DoBeginEdit(m_startValue);
  632. }
  633.  
  634. void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
  635. {
  636.     Text()->SetValue(startValue);
  637.     Text()->SetInsertionPointEnd();
  638.     Text()->SetSelection(-1,-1);
  639.     Text()->SetFocus();
  640. }
  641.  
  642. bool wxGridCellTextEditor::EndEdit(int row, int col,
  643.                                    wxGrid* grid)
  644. {
  645.     wxASSERT_MSG(m_control,
  646.                  wxT("The wxGridCellEditor must be Created first!"));
  647.  
  648.     bool changed = FALSE;
  649.     wxString value = Text()->GetValue();
  650.     if (value != m_startValue)
  651.         changed = TRUE;
  652.  
  653.     if (changed)
  654.         grid->GetTable()->SetValue(row, col, value);
  655.  
  656.     m_startValue = wxEmptyString;
  657.     Text()->SetValue(m_startValue);
  658.  
  659.     return changed;
  660. }
  661.  
  662.  
  663. void wxGridCellTextEditor::Reset()
  664. {
  665.     wxASSERT_MSG(m_control,
  666.                  wxT("The wxGridCellEditor must be Created first!"));
  667.  
  668.     DoReset(m_startValue);
  669. }
  670.  
  671. void wxGridCellTextEditor::DoReset(const wxString& startValue)
  672. {
  673.     Text()->SetValue(startValue);
  674.     Text()->SetInsertionPointEnd();
  675. }
  676.  
  677. bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
  678. {
  679.     if ( wxGridCellEditor::IsAcceptedKey(event) )
  680.     {
  681.         int keycode = event.GetKeyCode();
  682.         switch ( keycode )
  683.         {
  684.             case WXK_NUMPAD0:
  685.             case WXK_NUMPAD1:
  686.             case WXK_NUMPAD2:
  687.             case WXK_NUMPAD3:
  688.             case WXK_NUMPAD4:
  689.             case WXK_NUMPAD5:
  690.             case WXK_NUMPAD6:
  691.             case WXK_NUMPAD7:
  692.             case WXK_NUMPAD8:
  693.             case WXK_NUMPAD9:
  694.             case WXK_MULTIPLY:
  695.             case WXK_NUMPAD_MULTIPLY:
  696.             case WXK_ADD:
  697.             case WXK_NUMPAD_ADD:
  698.             case WXK_SUBTRACT:
  699.             case WXK_NUMPAD_SUBTRACT:
  700.             case WXK_DECIMAL:
  701.             case WXK_NUMPAD_DECIMAL:
  702.             case WXK_DIVIDE:
  703.             case WXK_NUMPAD_DIVIDE:
  704.                 return TRUE;
  705.  
  706.             default:
  707.                 // accept 8 bit chars too if isprint() agrees
  708.                 if ( (keycode < 255) && (isprint(keycode)) )
  709.                     return TRUE;
  710.         }
  711.     }
  712.  
  713.     return FALSE;
  714. }
  715.  
  716. void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
  717. {
  718.     if ( !Text()->EmulateKeyPress(event) )
  719.     {
  720.         event.Skip();
  721.     }
  722. }
  723.  
  724. void wxGridCellTextEditor::HandleReturn( wxKeyEvent&
  725.                                          WXUNUSED_GTK(WXUNUSED_MOTIF(event)) )
  726. {
  727. #if defined(__WXMOTIF__) || defined(__WXGTK__)
  728.     // wxMotif needs a little extra help...
  729.     size_t pos = (size_t)( Text()->GetInsertionPoint() );
  730.     wxString s( Text()->GetValue() );
  731.     s = s.Left(pos) + wxT("\n") + s.Mid(pos);
  732.     Text()->SetValue(s);
  733.     Text()->SetInsertionPoint( pos );
  734. #else
  735.     // the other ports can handle a Return key press
  736.     //
  737.     event.Skip();
  738. #endif
  739. }
  740.  
  741. void wxGridCellTextEditor::SetParameters(const wxString& params)
  742. {
  743.     if ( !params )
  744.     {
  745.         // reset to default
  746.         m_maxChars = 0;
  747.     }
  748.     else
  749.     {
  750.         long tmp;
  751.         if ( !params.ToLong(&tmp) )
  752.         {
  753.             wxLogDebug(_T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str());
  754.         }
  755.         else
  756.         {
  757.             m_maxChars = (size_t)tmp;
  758.         }
  759.     }
  760. }
  761.  
  762. // ----------------------------------------------------------------------------
  763. // wxGridCellNumberEditor
  764. // ----------------------------------------------------------------------------
  765.  
  766. wxGridCellNumberEditor::wxGridCellNumberEditor(int min, int max)
  767. {
  768.     m_min = min;
  769.     m_max = max;
  770. }
  771.  
  772. void wxGridCellNumberEditor::Create(wxWindow* parent,
  773.                                     wxWindowID id,
  774.                                     wxEvtHandler* evtHandler)
  775. {
  776.     if ( HasRange() )
  777.     {
  778.         // create a spin ctrl
  779.         m_control = new wxSpinCtrl(parent, -1, wxEmptyString,
  780.                                    wxDefaultPosition, wxDefaultSize,
  781.                                    wxSP_ARROW_KEYS,
  782.                                    m_min, m_max);
  783.  
  784.         wxGridCellEditor::Create(parent, id, evtHandler);
  785.     }
  786.     else
  787.     {
  788.         // just a text control
  789.         wxGridCellTextEditor::Create(parent, id, evtHandler);
  790.  
  791. #if wxUSE_VALIDATORS
  792.         Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
  793. #endif // wxUSE_VALIDATORS
  794.     }
  795. }
  796.  
  797. void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
  798. {
  799.     // first get the value
  800.     wxGridTableBase *table = grid->GetTable();
  801.     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
  802.     {
  803.         m_valueOld = table->GetValueAsLong(row, col);
  804.     }
  805.     else
  806.     {
  807.         m_valueOld = 0;
  808.         wxString sValue = table->GetValue(row, col);
  809.         if (! sValue.ToLong(&m_valueOld) && ! sValue.IsEmpty())
  810.         {
  811.             wxFAIL_MSG( _T("this cell doesn't have numeric value") );
  812.             return;
  813.         }
  814.     }
  815.  
  816.     if ( HasRange() )
  817.     {
  818.         Spin()->SetValue((int)m_valueOld);
  819.         Spin()->SetFocus();
  820.     }
  821.     else
  822.     {
  823.         DoBeginEdit(GetString());
  824.     }
  825. }
  826.  
  827. bool wxGridCellNumberEditor::EndEdit(int row, int col,
  828.                                      wxGrid* grid)
  829. {
  830.     bool changed;
  831.     long value = 0;
  832.     wxString text;
  833.  
  834.     if ( HasRange() )
  835.     {
  836.         value = Spin()->GetValue();
  837.         changed = value != m_valueOld;
  838.         if (changed)
  839.             text = wxString::Format(wxT("%ld"), value);
  840.     }
  841.     else
  842.     {
  843.         text = Text()->GetValue();
  844.         changed = (text.IsEmpty() || text.ToLong(&value)) && (value != m_valueOld);
  845.     }
  846.  
  847.     if ( changed )
  848.     {
  849.         if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER))
  850.             grid->GetTable()->SetValueAsLong(row, col, value);
  851.         else
  852.             grid->GetTable()->SetValue(row, col, text);
  853.     }
  854.  
  855.     return changed;
  856. }
  857.  
  858. void wxGridCellNumberEditor::Reset()
  859. {
  860.     if ( HasRange() )
  861.     {
  862.         Spin()->SetValue((int)m_valueOld);
  863.     }
  864.     else
  865.     {
  866.         DoReset(GetString());
  867.     }
  868. }
  869.  
  870. bool wxGridCellNumberEditor::IsAcceptedKey(wxKeyEvent& event)
  871. {
  872.     if ( wxGridCellEditor::IsAcceptedKey(event) )
  873.     {
  874.         int keycode = event.GetKeyCode();
  875.         switch ( keycode )
  876.         {
  877.             case WXK_NUMPAD0:
  878.             case WXK_NUMPAD1:
  879.             case WXK_NUMPAD2:
  880.             case WXK_NUMPAD3:
  881.             case WXK_NUMPAD4:
  882.             case WXK_NUMPAD5:
  883.             case WXK_NUMPAD6:
  884.             case WXK_NUMPAD7:
  885.             case WXK_NUMPAD8:
  886.             case WXK_NUMPAD9:
  887.             case WXK_ADD:
  888.             case WXK_NUMPAD_ADD:
  889.             case WXK_SUBTRACT:
  890.             case WXK_NUMPAD_SUBTRACT:
  891.             case WXK_UP:
  892.             case WXK_DOWN:
  893.                 return TRUE;
  894.  
  895.             default:
  896.                 if ( (keycode < 128) && isdigit(keycode) )
  897.                     return TRUE;
  898.         }
  899.     }
  900.  
  901.     return FALSE;
  902. }
  903.  
  904. void wxGridCellNumberEditor::StartingKey(wxKeyEvent& event)
  905. {
  906.     if ( !HasRange() )
  907.     {
  908.         int keycode = (int) event.KeyCode();
  909.         if ( isdigit(keycode) || keycode == '+' || keycode == '-'
  910.             || keycode ==  WXK_NUMPAD0
  911.             || keycode ==  WXK_NUMPAD1
  912.             || keycode ==  WXK_NUMPAD2
  913.             || keycode ==  WXK_NUMPAD3
  914.             || keycode ==  WXK_NUMPAD4
  915.             || keycode ==  WXK_NUMPAD5
  916.             || keycode ==  WXK_NUMPAD6
  917.             || keycode ==  WXK_NUMPAD7
  918.             || keycode ==  WXK_NUMPAD8
  919.             || keycode ==  WXK_NUMPAD9
  920.             || keycode ==  WXK_ADD
  921.             || keycode ==  WXK_NUMPAD_ADD
  922.             || keycode ==  WXK_SUBTRACT
  923.             || keycode ==  WXK_NUMPAD_SUBTRACT)
  924.         {
  925.             wxGridCellTextEditor::StartingKey(event);
  926.  
  927.             // skip Skip() below
  928.             return;
  929.         }
  930.     }
  931.  
  932.     event.Skip();
  933. }
  934.  
  935. void wxGridCellNumberEditor::SetParameters(const wxString& params)
  936. {
  937.     if ( !params )
  938.     {
  939.         // reset to default
  940.         m_min =
  941.         m_max = -1;
  942.     }
  943.     else
  944.     {
  945.         long tmp;
  946.         if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
  947.         {
  948.             m_min = (int)tmp;
  949.  
  950.             if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
  951.             {
  952.                 m_max = (int)tmp;
  953.  
  954.                 // skip the error message below
  955.                 return;
  956.             }
  957.         }
  958.  
  959.         wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
  960.     }
  961. }
  962.  
  963. // ----------------------------------------------------------------------------
  964. // wxGridCellFloatEditor
  965. // ----------------------------------------------------------------------------
  966.  
  967. wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
  968. {
  969.     m_width = width;
  970.     m_precision = precision;
  971. }
  972.  
  973. void wxGridCellFloatEditor::Create(wxWindow* parent,
  974.                                    wxWindowID id,
  975.                                    wxEvtHandler* evtHandler)
  976. {
  977.     wxGridCellTextEditor::Create(parent, id, evtHandler);
  978.  
  979. #if wxUSE_VALIDATORS
  980.     Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
  981. #endif // wxUSE_VALIDATORS
  982. }
  983.  
  984. void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
  985. {
  986.     // first get the value
  987.     wxGridTableBase *table = grid->GetTable();
  988.     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
  989.     {
  990.         m_valueOld = table->GetValueAsDouble(row, col);
  991.     }
  992.     else
  993.     {
  994.         m_valueOld = 0.0;
  995.         wxString sValue = table->GetValue(row, col);
  996.         if (! sValue.ToDouble(&m_valueOld) && ! sValue.IsEmpty())
  997.         {
  998.             wxFAIL_MSG( _T("this cell doesn't have float value") );
  999.             return;
  1000.         }
  1001.     }
  1002.  
  1003.     DoBeginEdit(GetString());
  1004. }
  1005.  
  1006. bool wxGridCellFloatEditor::EndEdit(int row, int col,
  1007.                                      wxGrid* grid)
  1008. {
  1009.     double value = 0.0;
  1010.     wxString text(Text()->GetValue());
  1011.  
  1012.     if ( (text.IsEmpty() || text.ToDouble(&value)) && (value != m_valueOld) )
  1013.     {
  1014.         if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT))
  1015.             grid->GetTable()->SetValueAsDouble(row, col, value);
  1016.         else
  1017.             grid->GetTable()->SetValue(row, col, text);
  1018.  
  1019.         return TRUE;
  1020.     }
  1021.     return FALSE;
  1022. }
  1023.  
  1024. void wxGridCellFloatEditor::Reset()
  1025. {
  1026.     DoReset(GetString());
  1027. }
  1028.  
  1029. void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
  1030. {
  1031.     int keycode = (int)event.KeyCode();
  1032.         if ( isdigit(keycode) || keycode == '+' || keycode == '-' || keycode == '.'
  1033.             || keycode ==  WXK_NUMPAD0
  1034.             || keycode ==  WXK_NUMPAD1
  1035.             || keycode ==  WXK_NUMPAD2
  1036.             || keycode ==  WXK_NUMPAD3
  1037.             || keycode ==  WXK_NUMPAD4
  1038.             || keycode ==  WXK_NUMPAD5
  1039.             || keycode ==  WXK_NUMPAD6
  1040.             || keycode ==  WXK_NUMPAD7
  1041.             || keycode ==  WXK_NUMPAD8
  1042.             || keycode ==  WXK_NUMPAD9
  1043.             || keycode ==  WXK_ADD
  1044.             || keycode ==  WXK_NUMPAD_ADD
  1045.             || keycode ==  WXK_SUBTRACT
  1046.             || keycode ==  WXK_NUMPAD_SUBTRACT)
  1047.     {
  1048.         wxGridCellTextEditor::StartingKey(event);
  1049.  
  1050.         // skip Skip() below
  1051.         return;
  1052.     }
  1053.  
  1054.     event.Skip();
  1055. }
  1056.  
  1057. void wxGridCellFloatEditor::SetParameters(const wxString& params)
  1058. {
  1059.     if ( !params )
  1060.     {
  1061.         // reset to default
  1062.         m_width =
  1063.         m_precision = -1;
  1064.     }
  1065.     else
  1066.     {
  1067.         long tmp;
  1068.         if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
  1069.         {
  1070.             m_width = (int)tmp;
  1071.  
  1072.             if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
  1073.             {
  1074.                 m_precision = (int)tmp;
  1075.  
  1076.                 // skip the error message below
  1077.                 return;
  1078.             }
  1079.         }
  1080.  
  1081.         wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
  1082.     }
  1083. }
  1084.  
  1085. wxString wxGridCellFloatEditor::GetString() const
  1086. {
  1087.     wxString fmt;
  1088.     if ( m_width == -1 )
  1089.     {
  1090.         // default width/precision
  1091.         fmt = _T("%f");
  1092.     }
  1093.     else if ( m_precision == -1 )
  1094.     {
  1095.         // default precision
  1096.         fmt.Printf(_T("%%%d.f"), m_width);
  1097.     }
  1098.     else
  1099.     {
  1100.         fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
  1101.     }
  1102.  
  1103.     return wxString::Format(fmt, m_valueOld);
  1104. }
  1105.  
  1106. bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
  1107. {
  1108.     if ( wxGridCellEditor::IsAcceptedKey(event) )
  1109.     {
  1110.         int keycode = event.GetKeyCode();
  1111.         switch ( keycode )
  1112.         {
  1113.             case WXK_NUMPAD0:
  1114.             case WXK_NUMPAD1:
  1115.             case WXK_NUMPAD2:
  1116.             case WXK_NUMPAD3:
  1117.             case WXK_NUMPAD4:
  1118.             case WXK_NUMPAD5:
  1119.             case WXK_NUMPAD6:
  1120.             case WXK_NUMPAD7:
  1121.             case WXK_NUMPAD8:
  1122.             case WXK_NUMPAD9:
  1123.             case WXK_ADD:
  1124.             case WXK_NUMPAD_ADD:
  1125.             case WXK_SUBTRACT:
  1126.             case WXK_NUMPAD_SUBTRACT:
  1127.             case WXK_DECIMAL:
  1128.             case WXK_NUMPAD_DECIMAL:
  1129.                 return TRUE;
  1130.  
  1131.             default:
  1132.                 // additionally accept 'e' as in '1e+6'
  1133.                 if ( (keycode < 128) &&
  1134.                      (isdigit(keycode) || tolower(keycode) == 'e') )
  1135.                     return TRUE;
  1136.         }
  1137.     }
  1138.  
  1139.     return FALSE;
  1140. }
  1141.  
  1142. #endif // wxUSE_TEXTCTRL
  1143.  
  1144. #if wxUSE_CHECKBOX
  1145.  
  1146. // ----------------------------------------------------------------------------
  1147. // wxGridCellBoolEditor
  1148. // ----------------------------------------------------------------------------
  1149.  
  1150. void wxGridCellBoolEditor::Create(wxWindow* parent,
  1151.                                   wxWindowID id,
  1152.                                   wxEvtHandler* evtHandler)
  1153. {
  1154.     m_control = new wxCheckBox(parent, id, wxEmptyString,
  1155.                                wxDefaultPosition, wxDefaultSize,
  1156.                                wxNO_BORDER);
  1157.  
  1158.     wxGridCellEditor::Create(parent, id, evtHandler);
  1159. }
  1160.  
  1161. void wxGridCellBoolEditor::SetSize(const wxRect& r)
  1162. {
  1163.     bool resize = FALSE;
  1164.     wxSize size = m_control->GetSize();
  1165.     wxCoord minSize = wxMin(r.width, r.height);
  1166.  
  1167.     // check if the checkbox is not too big/small for this cell
  1168.     wxSize sizeBest = m_control->GetBestSize();
  1169.     if ( !(size == sizeBest) )
  1170.     {
  1171.         // reset to default size if it had been made smaller
  1172.         size = sizeBest;
  1173.  
  1174.         resize = TRUE;
  1175.     }
  1176.  
  1177.     if ( size.x >= minSize || size.y >= minSize )
  1178.     {
  1179.         // leave 1 pixel margin
  1180.         size.x = size.y = minSize - 2;
  1181.  
  1182.         resize = TRUE;
  1183.     }
  1184.  
  1185.     if ( resize )
  1186.     {
  1187.         m_control->SetSize(size);
  1188.     }
  1189.  
  1190.     // position it in the centre of the rectangle (TODO: support alignment?)
  1191.  
  1192. #if defined(__WXGTK__) || defined (__WXMOTIF__)
  1193.     // the checkbox without label still has some space to the right in wxGTK,
  1194.     // so shift it to the right
  1195.     size.x -= 8;
  1196. #elif defined(__WXMSW__)
  1197.     // here too, but in other way
  1198.     size.x += 1;
  1199.     size.y -= 2;
  1200. #endif
  1201.  
  1202.     int hAlign = wxALIGN_CENTRE;
  1203.     int vAlign = wxALIGN_CENTRE;
  1204.     if (GetCellAttr())
  1205.         GetCellAttr()->GetAlignment(& hAlign, & vAlign);
  1206.  
  1207.     int x = 0, y = 0;
  1208.     if (hAlign == wxALIGN_LEFT)
  1209.     {
  1210.         x = r.x + 2;
  1211. #ifdef __WXMSW__
  1212.         x += 2;
  1213. #endif
  1214.         y = r.y + r.height/2 - size.y/2;
  1215.     }
  1216.     else if (hAlign == wxALIGN_RIGHT)
  1217.     {
  1218.         x = r.x + r.width - size.x - 2;
  1219.         y = r.y + r.height/2 - size.y/2;
  1220.     }
  1221.     else if (hAlign == wxALIGN_CENTRE)
  1222.     {
  1223.         x = r.x + r.width/2 - size.x/2;
  1224.         y = r.y + r.height/2 - size.y/2;
  1225.     }
  1226.     m_control->Move(x, y);
  1227. }
  1228.  
  1229. void wxGridCellBoolEditor::Show(bool show, wxGridCellAttr *attr)
  1230. {
  1231.     m_control->Show(show);
  1232.  
  1233.     if ( show )
  1234.     {
  1235.         wxColour colBg = attr ? attr->GetBackgroundColour() : *wxLIGHT_GREY;
  1236.         CBox()->SetBackgroundColour(colBg);
  1237.     }
  1238. }
  1239.  
  1240. void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
  1241. {
  1242.     wxASSERT_MSG(m_control,
  1243.                  wxT("The wxGridCellEditor must be Created first!"));
  1244.  
  1245.     if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
  1246.         m_startValue = grid->GetTable()->GetValueAsBool(row, col);
  1247.     else
  1248.     {
  1249.         wxString cellval( grid->GetTable()->GetValue(row, col) );
  1250.         m_startValue = !( !cellval || (cellval == wxT("0")) );
  1251.     }
  1252.     CBox()->SetValue(m_startValue);
  1253.     CBox()->SetFocus();
  1254. }
  1255.  
  1256. bool wxGridCellBoolEditor::EndEdit(int row, int col,
  1257.                                    wxGrid* grid)
  1258. {
  1259.     wxASSERT_MSG(m_control,
  1260.                  wxT("The wxGridCellEditor must be Created first!"));
  1261.  
  1262.     bool changed = FALSE;
  1263.     bool value = CBox()->GetValue();
  1264.     if ( value != m_startValue )
  1265.         changed = TRUE;
  1266.  
  1267.     if ( changed )
  1268.     {
  1269.         if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL))
  1270.             grid->GetTable()->SetValueAsBool(row, col, value);
  1271.         else
  1272.             grid->GetTable()->SetValue(row, col, value ? _T("1") : wxEmptyString);
  1273.     }
  1274.  
  1275.     return changed;
  1276. }
  1277.  
  1278. void wxGridCellBoolEditor::Reset()
  1279. {
  1280.     wxASSERT_MSG(m_control,
  1281.                  wxT("The wxGridCellEditor must be Created first!"));
  1282.  
  1283.     CBox()->SetValue(m_startValue);
  1284. }
  1285.  
  1286. void wxGridCellBoolEditor::StartingClick()
  1287. {
  1288.     CBox()->SetValue(!CBox()->GetValue());
  1289. }
  1290.  
  1291. bool wxGridCellBoolEditor::IsAcceptedKey(wxKeyEvent& event)
  1292. {
  1293.     if ( wxGridCellEditor::IsAcceptedKey(event) )
  1294.     {
  1295.         int keycode = event.GetKeyCode();
  1296.         switch ( keycode )
  1297.         {
  1298.             case WXK_MULTIPLY:
  1299.             case WXK_NUMPAD_MULTIPLY:
  1300.             case WXK_ADD:
  1301.             case WXK_NUMPAD_ADD:
  1302.             case WXK_SUBTRACT:
  1303.             case WXK_NUMPAD_SUBTRACT:
  1304.             case WXK_SPACE:
  1305.             case '+':
  1306.             case '-':
  1307.                 return TRUE;
  1308.         }
  1309.     }
  1310.  
  1311.     return FALSE;
  1312. }
  1313.  
  1314. #endif // wxUSE_CHECKBOX
  1315.  
  1316. #if wxUSE_COMBOBOX
  1317.  
  1318. // ----------------------------------------------------------------------------
  1319. // wxGridCellChoiceEditor
  1320. // ----------------------------------------------------------------------------
  1321.  
  1322. wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t count,
  1323.                                                const wxString choices[],
  1324.                                                bool allowOthers)
  1325.                       : m_allowOthers(allowOthers)
  1326. {
  1327.     if ( count )
  1328.     {
  1329.         m_choices.Alloc(count);
  1330.         for ( size_t n = 0; n < count; n++ )
  1331.         {
  1332.             m_choices.Add(choices[n]);
  1333.         }
  1334.     }
  1335. }
  1336.  
  1337. wxGridCellEditor *wxGridCellChoiceEditor::Clone() const
  1338. {
  1339.     wxGridCellChoiceEditor *editor = new wxGridCellChoiceEditor;
  1340.     editor->m_allowOthers = m_allowOthers;
  1341.     editor->m_choices = m_choices;
  1342.  
  1343.     return editor;
  1344. }
  1345.  
  1346. void wxGridCellChoiceEditor::Create(wxWindow* parent,
  1347.                                     wxWindowID id,
  1348.                                     wxEvtHandler* evtHandler)
  1349. {
  1350.     size_t count = m_choices.GetCount();
  1351.     wxString *choices = new wxString[count];
  1352.     for ( size_t n = 0; n < count; n++ )
  1353.     {
  1354.         choices[n] = m_choices[n];
  1355.     }
  1356.  
  1357.     m_control = new wxComboBox(parent, id, wxEmptyString,
  1358.                                wxDefaultPosition, wxDefaultSize,
  1359.                                count, choices,
  1360.                                m_allowOthers ? 0 : wxCB_READONLY);
  1361.  
  1362.     delete [] choices;
  1363.  
  1364.     wxGridCellEditor::Create(parent, id, evtHandler);
  1365. }
  1366.  
  1367. void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
  1368.                                              wxGridCellAttr * attr)
  1369. {
  1370.     // as we fill the entire client area, don't do anything here to minimize
  1371.     // flicker
  1372.  
  1373.     // TODO: It doesn't actually fill the client area since the height of a
  1374.     // combo always defaults to the standard...  Until someone has time to
  1375.     // figure out the right rectangle to paint, just do it the normal way...
  1376.     wxGridCellEditor::PaintBackground(rectCell, attr);
  1377. }
  1378.  
  1379. void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
  1380. {
  1381.     wxASSERT_MSG(m_control,
  1382.                  wxT("The wxGridCellEditor must be Created first!"));
  1383.  
  1384.     m_startValue = grid->GetTable()->GetValue(row, col);
  1385.  
  1386.     if (m_allowOthers)
  1387.         Combo()->SetValue(m_startValue);
  1388.     else
  1389.     {
  1390.         // find the right position, or default to the first if not found
  1391.         int pos = Combo()->FindString(m_startValue);
  1392.         if (pos == -1)
  1393.             pos = 0;
  1394.         Combo()->SetSelection(pos);
  1395.     }
  1396.     Combo()->SetInsertionPointEnd();
  1397.     Combo()->SetFocus();
  1398. }
  1399.  
  1400. bool wxGridCellChoiceEditor::EndEdit(int row, int col,
  1401.                                      wxGrid* grid)
  1402. {
  1403.     wxString value = Combo()->GetValue();
  1404.     bool changed = value != m_startValue;
  1405.  
  1406.     if ( changed )
  1407.         grid->GetTable()->SetValue(row, col, value);
  1408.  
  1409.     m_startValue = wxEmptyString;
  1410.     if (m_allowOthers)
  1411.         Combo()->SetValue(m_startValue);
  1412.     else
  1413.         Combo()->SetSelection(0);
  1414.  
  1415.     return changed;
  1416. }
  1417.  
  1418. void wxGridCellChoiceEditor::Reset()
  1419. {
  1420.     Combo()->SetValue(m_startValue);
  1421.     Combo()->SetInsertionPointEnd();
  1422. }
  1423.  
  1424. void wxGridCellChoiceEditor::SetParameters(const wxString& params)
  1425. {
  1426.     if ( !params )
  1427.     {
  1428.         // what can we do?
  1429.         return;
  1430.     }
  1431.  
  1432.     m_choices.Empty();
  1433.  
  1434.     wxStringTokenizer tk(params, _T(','));
  1435.     while ( tk.HasMoreTokens() )
  1436.     {
  1437.         m_choices.Add(tk.GetNextToken());
  1438.     }
  1439. }
  1440.  
  1441. #endif // wxUSE_COMBOBOX
  1442.  
  1443. // ----------------------------------------------------------------------------
  1444. // wxGridCellEditorEvtHandler
  1445. // ----------------------------------------------------------------------------
  1446.  
  1447. void wxGridCellEditorEvtHandler::OnKeyDown(wxKeyEvent& event)
  1448. {
  1449.     switch ( event.KeyCode() )
  1450.     {
  1451.         case WXK_ESCAPE:
  1452.             m_editor->Reset();
  1453.             m_grid->DisableCellEditControl();
  1454.             break;
  1455.  
  1456.         case WXK_TAB:
  1457.             m_grid->GetEventHandler()->ProcessEvent( event );
  1458.             break;
  1459.  
  1460.         case WXK_RETURN:
  1461.         case WXK_NUMPAD_ENTER:
  1462.             if (!m_grid->GetEventHandler()->ProcessEvent(event))
  1463.                 m_editor->HandleReturn(event);
  1464.             break;
  1465.  
  1466.  
  1467.         default:
  1468.             event.Skip();
  1469.     }
  1470. }
  1471.  
  1472. void wxGridCellEditorEvtHandler::OnChar(wxKeyEvent& event)
  1473. {
  1474.     switch ( event.KeyCode() )
  1475.     {
  1476.         case WXK_ESCAPE:
  1477.         case WXK_TAB:
  1478.         case WXK_RETURN:
  1479.         case WXK_NUMPAD_ENTER:
  1480.             break;
  1481.  
  1482.         default:
  1483.             event.Skip();
  1484.     }
  1485. }
  1486.  
  1487. // ----------------------------------------------------------------------------
  1488. // wxGridCellWorker is an (almost) empty common base class for
  1489. // wxGridCellRenderer and wxGridCellEditor managing ref counting
  1490. // ----------------------------------------------------------------------------
  1491.  
  1492. void wxGridCellWorker::SetParameters(const wxString& WXUNUSED(params))
  1493. {
  1494.     // nothing to do
  1495. }
  1496.  
  1497. wxGridCellWorker::~wxGridCellWorker()
  1498. {
  1499. }
  1500.  
  1501. // ============================================================================
  1502. // renderer classes
  1503. // ============================================================================
  1504.  
  1505. // ----------------------------------------------------------------------------
  1506. // wxGridCellRenderer
  1507. // ----------------------------------------------------------------------------
  1508.  
  1509. void wxGridCellRenderer::Draw(wxGrid& grid,
  1510.                               wxGridCellAttr& attr,
  1511.                               wxDC& dc,
  1512.                               const wxRect& rect,
  1513.                               int WXUNUSED(row), int WXUNUSED(col),
  1514.                               bool isSelected)
  1515. {
  1516.     dc.SetBackgroundMode( wxSOLID );
  1517.  
  1518.     // grey out fields if the grid is disabled
  1519.     if( grid.IsEnabled() )
  1520.     {
  1521.       if ( isSelected )
  1522.       {
  1523.           dc.SetBrush( wxBrush(grid.GetSelectionBackground(), wxSOLID) );
  1524.       }
  1525.       else
  1526.       {
  1527.           dc.SetBrush( wxBrush(attr.GetBackgroundColour(), wxSOLID) );
  1528.       }
  1529.     }
  1530.     else
  1531.     {
  1532.       dc.SetBrush(wxBrush(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE), wxSOLID));
  1533.     }
  1534.  
  1535.     dc.SetPen( *wxTRANSPARENT_PEN );
  1536.     dc.DrawRectangle(rect);
  1537. }
  1538.  
  1539. // ----------------------------------------------------------------------------
  1540. // wxGridCellStringRenderer
  1541. // ----------------------------------------------------------------------------
  1542.  
  1543. void wxGridCellStringRenderer::SetTextColoursAndFont(wxGrid& grid,
  1544.                                                      wxGridCellAttr& attr,
  1545.                                                      wxDC& dc,
  1546.                                                      bool isSelected)
  1547. {
  1548.     dc.SetBackgroundMode( wxTRANSPARENT );
  1549.  
  1550.     // TODO some special colours for attr.IsReadOnly() case?
  1551.  
  1552.     if ( isSelected )
  1553.     {
  1554.         dc.SetTextBackground( grid.GetSelectionBackground() );
  1555.         dc.SetTextForeground( grid.GetSelectionForeground() );
  1556.     }
  1557.     else
  1558.     {
  1559.         dc.SetTextBackground( attr.GetBackgroundColour() );
  1560.         dc.SetTextForeground( attr.GetTextColour() );
  1561.     }
  1562.  
  1563.     dc.SetFont( attr.GetFont() );
  1564. }
  1565.  
  1566. wxSize wxGridCellStringRenderer::DoGetBestSize(wxGridCellAttr& attr,
  1567.                                                wxDC& dc,
  1568.                                                const wxString& text)
  1569. {
  1570.     wxCoord x = 0, y = 0, max_x = 0;
  1571.     dc.SetFont(attr.GetFont());
  1572.     wxStringTokenizer tk(text, _T('\n'));
  1573.     while ( tk.HasMoreTokens() )
  1574.     {
  1575.         dc.GetTextExtent(tk.GetNextToken(), &x, &y);
  1576.         max_x = wxMax(max_x, x);
  1577.     }
  1578.  
  1579.     y *= 1 + text.Freq(wxT('\n')); // multiply by the number of lines.
  1580.  
  1581.     return wxSize(max_x, y);
  1582. }
  1583.  
  1584. wxSize wxGridCellStringRenderer::GetBestSize(wxGrid& grid,
  1585.                                              wxGridCellAttr& attr,
  1586.                                              wxDC& dc,
  1587.                                              int row, int col)
  1588. {
  1589.     return DoGetBestSize(attr, dc, grid.GetCellValue(row, col));
  1590. }
  1591.  
  1592. void wxGridCellStringRenderer::Draw(wxGrid& grid,
  1593.                                     wxGridCellAttr& attr,
  1594.                                     wxDC& dc,
  1595.                                     const wxRect& rectCell,
  1596.                                     int row, int col,
  1597.                                     bool isSelected)
  1598. {
  1599.     wxRect rect = rectCell;
  1600.     rect.Inflate(-1);
  1601.  
  1602.     // erase only this cells background, overflow cells should have been erased
  1603.     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
  1604.  
  1605.     int hAlign, vAlign;
  1606.     attr.GetAlignment(&hAlign, &vAlign);
  1607.  
  1608.     int overflowCols = 0;
  1609.  
  1610.     if (attr.GetOverflow())
  1611.     {
  1612.         int cols = grid.GetNumberCols();
  1613.         int best_width = GetBestSize(grid,attr,dc,row,col).GetWidth();
  1614.         int cell_rows, cell_cols;
  1615.         attr.GetSize( &cell_rows, &cell_cols ); // shouldn't get here if <=0
  1616.         if ((best_width > rectCell.width) && (col < cols) && grid.GetTable())
  1617.         {
  1618.             int i, c_cols, c_rows;
  1619.             for (i = col+cell_cols; i < cols; i++)
  1620.             {
  1621.                 bool is_empty = TRUE;
  1622.                 for (int j=row; j<row+cell_rows; j++)
  1623.                 {
  1624.                     // check w/ anchor cell for multicell block
  1625.                     grid.GetCellSize(j, i, &c_rows, &c_cols);
  1626.                     if (c_rows > 0) c_rows = 0;
  1627.                     if (!grid.GetTable()->IsEmptyCell(j+c_rows, i))
  1628.                     {
  1629.                         is_empty = FALSE;
  1630.                        break;
  1631.                     }
  1632.                 }
  1633.                 if (is_empty)
  1634.                     rect.width += grid.GetColSize(i);
  1635.                 else
  1636.                 {
  1637.                     i--;
  1638.                     break;
  1639.                 }
  1640.                 if (rect.width >= best_width) break;
  1641.             }
  1642.             overflowCols = i - col - cell_cols + 1;
  1643.             if (overflowCols >= cols) overflowCols = cols - 1;
  1644.         }
  1645.  
  1646.         if (overflowCols > 0) // redraw overflow cells w/ proper hilight
  1647.         {
  1648.             hAlign = wxALIGN_LEFT; // if oveflowed then it's left aligned
  1649.             wxRect clip = rect;
  1650.             clip.x += rectCell.width;
  1651.             // draw each overflow cell individually
  1652.             int col_end = col+cell_cols+overflowCols;
  1653.             if (col_end >= grid.GetNumberCols())
  1654.                 col_end = grid.GetNumberCols() - 1;
  1655.             for (int i = col+cell_cols; i <= col_end; i++)
  1656.             {
  1657.                 clip.width = grid.GetColSize(i) - 1;
  1658.                 dc.DestroyClippingRegion();
  1659.                 dc.SetClippingRegion(clip);
  1660.  
  1661.                 SetTextColoursAndFont(grid, attr, dc,
  1662.                         grid.IsInSelection(row,i));
  1663.  
  1664.                 grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
  1665.                         rect, hAlign, vAlign);
  1666.                 clip.x += grid.GetColSize(i) - 1;
  1667.             }
  1668.  
  1669.             rect = rectCell;
  1670.             rect.Inflate(-1);
  1671.             rect.width++;
  1672.             dc.DestroyClippingRegion();
  1673.         }
  1674.     }
  1675.  
  1676.     // now we only have to draw the text
  1677.     SetTextColoursAndFont(grid, attr, dc, isSelected);
  1678.  
  1679.     grid.DrawTextRectangle(dc, grid.GetCellValue(row, col),
  1680.                            rect, hAlign, vAlign);
  1681. }
  1682.  
  1683. // ----------------------------------------------------------------------------
  1684. // wxGridCellNumberRenderer
  1685. // ----------------------------------------------------------------------------
  1686.  
  1687. wxString wxGridCellNumberRenderer::GetString(wxGrid& grid, int row, int col)
  1688. {
  1689.     wxGridTableBase *table = grid.GetTable();
  1690.     wxString text;
  1691.     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
  1692.     {
  1693.         text.Printf(_T("%ld"), table->GetValueAsLong(row, col));
  1694.     }
  1695.     else
  1696.     {
  1697.         text = table->GetValue(row, col);
  1698.     }
  1699.  
  1700.     return text;
  1701. }
  1702.  
  1703. void wxGridCellNumberRenderer::Draw(wxGrid& grid,
  1704.                                     wxGridCellAttr& attr,
  1705.                                     wxDC& dc,
  1706.                                     const wxRect& rectCell,
  1707.                                     int row, int col,
  1708.                                     bool isSelected)
  1709. {
  1710.     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
  1711.  
  1712.     SetTextColoursAndFont(grid, attr, dc, isSelected);
  1713.  
  1714.     // draw the text right aligned by default
  1715.     int hAlign, vAlign;
  1716.     attr.GetAlignment(&hAlign, &vAlign);
  1717.     hAlign = wxALIGN_RIGHT;
  1718.  
  1719.     wxRect rect = rectCell;
  1720.     rect.Inflate(-1);
  1721.  
  1722.     grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
  1723. }
  1724.  
  1725. wxSize wxGridCellNumberRenderer::GetBestSize(wxGrid& grid,
  1726.                                              wxGridCellAttr& attr,
  1727.                                              wxDC& dc,
  1728.                                              int row, int col)
  1729. {
  1730.     return DoGetBestSize(attr, dc, GetString(grid, row, col));
  1731. }
  1732.  
  1733. // ----------------------------------------------------------------------------
  1734. // wxGridCellFloatRenderer
  1735. // ----------------------------------------------------------------------------
  1736.  
  1737. wxGridCellFloatRenderer::wxGridCellFloatRenderer(int width, int precision)
  1738. {
  1739.     SetWidth(width);
  1740.     SetPrecision(precision);
  1741. }
  1742.  
  1743. wxGridCellRenderer *wxGridCellFloatRenderer::Clone() const
  1744. {
  1745.     wxGridCellFloatRenderer *renderer = new wxGridCellFloatRenderer;
  1746.     renderer->m_width = m_width;
  1747.     renderer->m_precision = m_precision;
  1748.     renderer->m_format = m_format;
  1749.  
  1750.     return renderer;
  1751. }
  1752.  
  1753. wxString wxGridCellFloatRenderer::GetString(wxGrid& grid, int row, int col)
  1754. {
  1755.     wxGridTableBase *table = grid.GetTable();
  1756.  
  1757.     bool hasDouble;
  1758.     double val;
  1759.     wxString text;
  1760.     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) )
  1761.     {
  1762.         val = table->GetValueAsDouble(row, col);
  1763.         hasDouble = TRUE;
  1764.     }
  1765.     else
  1766.     {
  1767.         text = table->GetValue(row, col);
  1768.         hasDouble = text.ToDouble(&val);
  1769.     }
  1770.  
  1771.     if ( hasDouble )
  1772.     {
  1773.         if ( !m_format )
  1774.         {
  1775.             if ( m_width == -1 )
  1776.             {
  1777.                 if ( m_precision == -1 )
  1778.                 {
  1779.                     // default width/precision
  1780.                     m_format = _T("%f");
  1781.                 }
  1782.                 else
  1783.                 {
  1784.                     m_format.Printf(_T("%%.%df"), m_precision);
  1785.                 }
  1786.             }
  1787.             else if ( m_precision == -1 )
  1788.             {
  1789.                 // default precision
  1790.                 m_format.Printf(_T("%%%d.f"), m_width);
  1791.             }
  1792.             else
  1793.             {
  1794.                 m_format.Printf(_T("%%%d.%df"), m_width, m_precision);
  1795.             }
  1796.         }
  1797.  
  1798.         text.Printf(m_format, val);
  1799.  
  1800.     }
  1801.     //else: text already contains the string
  1802.  
  1803.     return text;
  1804. }
  1805.  
  1806. void wxGridCellFloatRenderer::Draw(wxGrid& grid,
  1807.                                    wxGridCellAttr& attr,
  1808.                                    wxDC& dc,
  1809.                                    const wxRect& rectCell,
  1810.                                    int row, int col,
  1811.                                    bool isSelected)
  1812. {
  1813.     wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
  1814.  
  1815.     SetTextColoursAndFont(grid, attr, dc, isSelected);
  1816.  
  1817.     // draw the text right aligned by default
  1818.     int hAlign, vAlign;
  1819.     attr.GetAlignment(&hAlign, &vAlign);
  1820.     hAlign = wxALIGN_RIGHT;
  1821.  
  1822.     wxRect rect = rectCell;
  1823.     rect.Inflate(-1);
  1824.  
  1825.     grid.DrawTextRectangle(dc, GetString(grid, row, col), rect, hAlign, vAlign);
  1826. }
  1827.  
  1828. wxSize wxGridCellFloatRenderer::GetBestSize(wxGrid& grid,
  1829.                                             wxGridCellAttr& attr,
  1830.                                             wxDC& dc,
  1831.                                             int row, int col)
  1832. {
  1833.     return DoGetBestSize(attr, dc, GetString(grid, row, col));
  1834. }
  1835.  
  1836. void wxGridCellFloatRenderer::SetParameters(const wxString& params)
  1837. {
  1838.     if ( !params )
  1839.     {
  1840.         // reset to defaults
  1841.         SetWidth(-1);
  1842.         SetPrecision(-1);
  1843.     }
  1844.     else
  1845.     {
  1846.         wxString tmp = params.BeforeFirst(_T(','));
  1847.         if ( !!tmp )
  1848.         {
  1849.             long width;
  1850.             if ( tmp.ToLong(&width) )
  1851.             {
  1852.                 SetWidth((int)width);
  1853.             }
  1854.             else
  1855.             {
  1856.                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
  1857.             }
  1858.  
  1859.         }
  1860.                 tmp = params.AfterFirst(_T(','));
  1861.                 if ( !!tmp )
  1862.                 {
  1863.                     long precision;
  1864.             if ( tmp.ToLong(&precision) )
  1865.                     {
  1866.                 SetPrecision((int)precision);
  1867.                     }
  1868.                     else
  1869.                     {
  1870.                 wxLogDebug(_T("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
  1871.         }
  1872.  
  1873.         }
  1874.     }
  1875. }
  1876.  
  1877.  
  1878. // ----------------------------------------------------------------------------
  1879. // wxGridCellBoolRenderer
  1880. // ----------------------------------------------------------------------------
  1881.  
  1882. wxSize wxGridCellBoolRenderer::ms_sizeCheckMark;
  1883.  
  1884. // FIXME these checkbox size calculations are really ugly...
  1885.  
  1886. // between checkmark and box
  1887. static const wxCoord wxGRID_CHECKMARK_MARGIN = 2;
  1888.  
  1889. wxSize wxGridCellBoolRenderer::GetBestSize(wxGrid& grid,
  1890.                                            wxGridCellAttr& WXUNUSED(attr),
  1891.                                            wxDC& WXUNUSED(dc),
  1892.                                            int WXUNUSED(row),
  1893.                                            int WXUNUSED(col))
  1894. {
  1895.     // compute it only once (no locks for MT safeness in GUI thread...)
  1896.     if ( !ms_sizeCheckMark.x )
  1897.     {
  1898.         // get checkbox size
  1899.         wxCoord checkSize = 0;
  1900.         wxCheckBox *checkbox = new wxCheckBox(&grid, -1, wxEmptyString);
  1901.         wxSize size = checkbox->GetBestSize();
  1902.         checkSize = size.y + 2*wxGRID_CHECKMARK_MARGIN;
  1903.  
  1904.         // FIXME wxGTK::wxCheckBox::GetBestSize() gives "wrong" result
  1905. #if defined(__WXGTK__) || defined(__WXMOTIF__)
  1906.         checkSize -= size.y / 2;
  1907. #endif
  1908.  
  1909.         delete checkbox;
  1910.  
  1911.         ms_sizeCheckMark.x = ms_sizeCheckMark.y = checkSize;
  1912.     }
  1913.  
  1914.     return ms_sizeCheckMark;
  1915. }
  1916.  
  1917. void wxGridCellBoolRenderer::Draw(wxGrid& grid,
  1918.                                   wxGridCellAttr& attr,
  1919.                                   wxDC& dc,
  1920.                                   const wxRect& rect,
  1921.                                   int row, int col,
  1922.                                   bool isSelected)
  1923. {
  1924.     wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
  1925.  
  1926.     // draw a check mark in the centre (ignoring alignment - TODO)
  1927.     wxSize size = GetBestSize(grid, attr, dc, row, col);
  1928.  
  1929.     // don't draw outside the cell
  1930.     wxCoord minSize = wxMin(rect.width, rect.height);
  1931.     if ( size.x >= minSize || size.y >= minSize )
  1932.     {
  1933.         // and even leave (at least) 1 pixel margin
  1934.         size.x = size.y = minSize - 2;
  1935.     }
  1936.  
  1937.     // draw a border around checkmark
  1938.     int vAlign, hAlign;
  1939.     attr.GetAlignment(& hAlign, &vAlign);
  1940.  
  1941.     wxRect rectBorder;
  1942.     if (hAlign == wxALIGN_CENTRE)
  1943.     {
  1944.         rectBorder.x = rect.x + rect.width/2 - size.x/2;
  1945.         rectBorder.y = rect.y + rect.height/2 - size.y/2;
  1946.         rectBorder.width = size.x;
  1947.         rectBorder.height = size.y;
  1948.     }
  1949.     else if (hAlign == wxALIGN_LEFT)
  1950.     {
  1951.         rectBorder.x = rect.x + 2;
  1952.         rectBorder.y = rect.y + rect.height/2 - size.y/2;
  1953.         rectBorder.width = size.x;
  1954.         rectBorder.height = size.y;
  1955.     }
  1956.     else if (hAlign == wxALIGN_RIGHT)
  1957.     {
  1958.         rectBorder.x = rect.x + rect.width - size.x - 2;
  1959.         rectBorder.y = rect.y + rect.height/2 - size.y/2;
  1960.         rectBorder.width = size.x;
  1961.         rectBorder.height = size.y;
  1962.     }
  1963.  
  1964.     bool value;
  1965.     if ( grid.GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) )
  1966.         value = grid.GetTable()->GetValueAsBool(row, col);
  1967.     else
  1968.     {
  1969.         wxString cellval( grid.GetTable()->GetValue(row, col) );
  1970.         value = !( !cellval || (cellval == wxT("0")) );
  1971.     }
  1972.  
  1973.     if ( value )
  1974.     {
  1975.         wxRect rectMark = rectBorder;
  1976. #ifdef __WXMSW__
  1977.         // MSW DrawCheckMark() is weird (and should probably be changed...)
  1978.         rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN/2);
  1979.         rectMark.x++;
  1980.         rectMark.y++;
  1981. #else // !MSW
  1982.         rectMark.Inflate(-wxGRID_CHECKMARK_MARGIN);
  1983. #endif // MSW/!MSW
  1984.  
  1985.         dc.SetTextForeground(attr.GetTextColour());
  1986.         dc.DrawCheckMark(rectMark);
  1987.     }
  1988.  
  1989.     dc.SetBrush(*wxTRANSPARENT_BRUSH);
  1990.     dc.SetPen(wxPen(attr.GetTextColour(), 1, wxSOLID));
  1991.     dc.DrawRectangle(rectBorder);
  1992. }
  1993.  
  1994. // ----------------------------------------------------------------------------
  1995. // wxGridCellAttr
  1996. // ----------------------------------------------------------------------------
  1997.  
  1998. void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
  1999. {
  2000.     m_nRef = 1;
  2001.  
  2002.     m_isReadOnly = Unset;
  2003.  
  2004.     m_renderer = NULL;
  2005.     m_editor = NULL;
  2006.  
  2007.     m_attrkind = wxGridCellAttr::Cell;
  2008.  
  2009.     m_sizeRows = m_sizeCols = 1;
  2010.     m_overflow = TRUE;
  2011.  
  2012.     SetDefAttr(attrDefault);
  2013. }
  2014.  
  2015. wxGridCellAttr *wxGridCellAttr::Clone() const
  2016. {
  2017.     wxGridCellAttr *attr = new wxGridCellAttr(m_defGridAttr);
  2018.  
  2019.     if ( HasTextColour() )
  2020.         attr->SetTextColour(GetTextColour());
  2021.     if ( HasBackgroundColour() )
  2022.         attr->SetBackgroundColour(GetBackgroundColour());
  2023.     if ( HasFont() )
  2024.         attr->SetFont(GetFont());
  2025.     if ( HasAlignment() )
  2026.         attr->SetAlignment(m_hAlign, m_vAlign);
  2027.  
  2028.     attr->SetSize( m_sizeRows, m_sizeCols );
  2029.  
  2030.     if ( m_renderer )
  2031.     {
  2032.         attr->SetRenderer(m_renderer);
  2033.         m_renderer->IncRef();
  2034.     }
  2035.     if ( m_editor )
  2036.     {
  2037.         attr->SetEditor(m_editor);
  2038.         m_editor->IncRef();
  2039.     }
  2040.  
  2041.     if ( IsReadOnly() )
  2042.         attr->SetReadOnly();
  2043.  
  2044.     attr->SetKind( m_attrkind );
  2045.  
  2046.     return attr;
  2047. }
  2048.  
  2049. void wxGridCellAttr::MergeWith(wxGridCellAttr *mergefrom)
  2050. {
  2051.     if ( !HasTextColour() && mergefrom->HasTextColour() )
  2052.         SetTextColour(mergefrom->GetTextColour());
  2053.     if ( !HasBackgroundColour() && mergefrom->HasBackgroundColour() )
  2054.         SetBackgroundColour(mergefrom->GetBackgroundColour());
  2055.     if ( !HasFont() && mergefrom->HasFont() )
  2056.         SetFont(mergefrom->GetFont());
  2057.     if ( !HasAlignment() && mergefrom->HasAlignment() ){
  2058.         int hAlign, vAlign;
  2059.         mergefrom->GetAlignment( &hAlign, &vAlign);
  2060.         SetAlignment(hAlign, vAlign);
  2061.     }
  2062.  
  2063.     mergefrom->GetSize( &m_sizeRows, &m_sizeCols );
  2064.  
  2065.     // Directly access member functions as GetRender/Editor don't just return
  2066.     // m_renderer/m_editor
  2067.     //
  2068.     // Maybe add support for merge of Render and Editor?
  2069.     if (!HasRenderer() && mergefrom->HasRenderer() )
  2070.     {
  2071.         m_renderer = mergefrom->m_renderer;
  2072.         m_renderer->IncRef();
  2073.     }
  2074.     if ( !HasEditor() && mergefrom->HasEditor() )
  2075.     {
  2076.         m_editor =  mergefrom->m_editor;
  2077.         m_editor->IncRef();
  2078.     }
  2079.     if ( !HasReadWriteMode()  && mergefrom->HasReadWriteMode() )
  2080.         SetReadOnly(mergefrom->IsReadOnly());
  2081.  
  2082.     SetDefAttr(mergefrom->m_defGridAttr);
  2083. }
  2084.  
  2085. void wxGridCellAttr::SetSize(int num_rows, int num_cols)
  2086. {
  2087.     // The size of a cell is normally 1,1
  2088.  
  2089.     // If this cell is larger (2,2) then this is the top left cell
  2090.     // the other cells that will be covered (lower right cells) must be
  2091.     // set to negative or zero values such that
  2092.     // row + num_rows of the covered cell points to the larger cell (this cell)
  2093.     // same goes for the col + num_cols.
  2094.  
  2095.     // Size of 0,0 is NOT valid, neither is <=0 and any positive value
  2096.  
  2097.     wxASSERT_MSG( (!((num_rows>0)&&(num_cols<=0)) ||
  2098.                   !((num_rows<=0)&&(num_cols>0)) ||
  2099.                   !((num_rows==0)&&(num_cols==0))),
  2100.                   wxT("wxGridCellAttr::SetSize only takes two postive values or negative/zero values"));
  2101.  
  2102.     m_sizeRows = num_rows;
  2103.     m_sizeCols = num_cols;
  2104. }
  2105.  
  2106. const wxColour& wxGridCellAttr::GetTextColour() const
  2107. {
  2108.     if (HasTextColour())
  2109.     {
  2110.         return m_colText;
  2111.     }
  2112.     else if (m_defGridAttr && m_defGridAttr != this)
  2113.     {
  2114.         return m_defGridAttr->GetTextColour();
  2115.     }
  2116.     else
  2117.     {
  2118.         wxFAIL_MSG(wxT("Missing default cell attribute"));
  2119.         return wxNullColour;
  2120.     }
  2121. }
  2122.  
  2123.  
  2124. const wxColour& wxGridCellAttr::GetBackgroundColour() const
  2125. {
  2126.     if (HasBackgroundColour())
  2127.         return m_colBack;
  2128.     else if (m_defGridAttr && m_defGridAttr != this)
  2129.         return m_defGridAttr->GetBackgroundColour();
  2130.     else
  2131.     {
  2132.         wxFAIL_MSG(wxT("Missing default cell attribute"));
  2133.         return wxNullColour;
  2134.     }
  2135. }
  2136.  
  2137.  
  2138. const wxFont& wxGridCellAttr::GetFont() const
  2139. {
  2140.     if (HasFont())
  2141.         return m_font;
  2142.     else if (m_defGridAttr && m_defGridAttr != this)
  2143.         return m_defGridAttr->GetFont();
  2144.     else
  2145.     {
  2146.         wxFAIL_MSG(wxT("Missing default cell attribute"));
  2147.         return wxNullFont;
  2148.     }
  2149. }
  2150.  
  2151.  
  2152. void wxGridCellAttr::GetAlignment(int *hAlign, int *vAlign) const
  2153. {
  2154.     if (HasAlignment())
  2155.     {
  2156.         if ( hAlign ) *hAlign = m_hAlign;
  2157.         if ( vAlign ) *vAlign = m_vAlign;
  2158.     }
  2159.     else if (m_defGridAttr && m_defGridAttr != this)
  2160.         m_defGridAttr->GetAlignment(hAlign, vAlign);
  2161.     else
  2162.     {
  2163.         wxFAIL_MSG(wxT("Missing default cell attribute"));
  2164.     }
  2165. }
  2166.  
  2167. void wxGridCellAttr::GetSize( int *num_rows, int *num_cols ) const
  2168. {
  2169.     if ( num_rows ) *num_rows = m_sizeRows;
  2170.     if ( num_cols ) *num_cols = m_sizeCols;
  2171. }
  2172.  
  2173. // GetRenderer and GetEditor use a slightly different decision path about
  2174. // which attribute to use.  If a non-default attr object has one then it is
  2175. // used, otherwise the default editor or renderer is fetched from the grid and
  2176. // used.  It should be the default for the data type of the cell.  If it is
  2177. // NULL (because the table has a type that the grid does not have in its
  2178. // registry,) then the grid's default editor or renderer is used.
  2179.  
  2180. wxGridCellRenderer* wxGridCellAttr::GetRenderer(wxGrid* grid, int row, int col) const
  2181. {
  2182.     wxGridCellRenderer *renderer;
  2183.  
  2184.     if ( m_renderer && this != m_defGridAttr )
  2185.     {
  2186.         // use the cells renderer if it has one
  2187.         renderer = m_renderer;
  2188.         renderer->IncRef();
  2189.     }
  2190.     else // no non default cell renderer
  2191.     {
  2192.         // get default renderer for the data type
  2193.         if ( grid )
  2194.         {
  2195.             // GetDefaultRendererForCell() will do IncRef() for us
  2196.             renderer = grid->GetDefaultRendererForCell(row, col);
  2197.         }
  2198.         else
  2199.         {
  2200.             renderer = NULL;
  2201.         }
  2202.  
  2203.         if ( !renderer )
  2204.         {
  2205.             if (m_defGridAttr &&  this != m_defGridAttr )
  2206.             {
  2207.                 // if we still don't have one then use the grid default
  2208.                 // (no need for IncRef() here neither)
  2209.                 renderer = m_defGridAttr->GetRenderer(NULL, 0, 0);
  2210.             }
  2211.             else // default grid attr
  2212.             {
  2213.                 // use m_renderer which we had decided not to use initially
  2214.                 renderer = m_renderer;
  2215.                 if ( renderer )
  2216.                     renderer->IncRef();
  2217.             }
  2218.         }
  2219.     }
  2220.  
  2221.     // we're supposed to always find something
  2222.     wxASSERT_MSG(renderer, wxT("Missing default cell renderer"));
  2223.  
  2224.     return renderer;
  2225. }
  2226.  
  2227. // same as above, except for s/renderer/editor/g
  2228. wxGridCellEditor* wxGridCellAttr::GetEditor(wxGrid* grid, int row, int col) const
  2229. {
  2230.     wxGridCellEditor *editor;
  2231.  
  2232.     if ( m_editor && this != m_defGridAttr )
  2233.     {
  2234.         // use the cells editor if it has one
  2235.         editor = m_editor;
  2236.         editor->IncRef();
  2237.     }
  2238.     else // no non default cell editor
  2239.     {
  2240.         // get default editor for the data type
  2241.         if ( grid )
  2242.         {
  2243.             // GetDefaultEditorForCell() will do IncRef() for us
  2244.             editor = grid->GetDefaultEditorForCell(row, col);
  2245.         }
  2246.         else
  2247.         {
  2248.             editor = NULL;
  2249.         }
  2250.  
  2251.         if ( !editor )
  2252.         {
  2253.             if ( m_defGridAttr && this != m_defGridAttr )
  2254.             {
  2255.                 // if we still don't have one then use the grid default
  2256.                 // (no need for IncRef() here neither)
  2257.                 editor = m_defGridAttr->GetEditor(NULL, 0, 0);
  2258.             }
  2259.             else // default grid attr
  2260.             {
  2261.                 // use m_editor which we had decided not to use initially
  2262.                 editor = m_editor;
  2263.                 if ( editor )
  2264.                     editor->IncRef();
  2265.             }
  2266.         }
  2267.     }
  2268.  
  2269.     // we're supposed to always find something
  2270.     wxASSERT_MSG(editor, wxT("Missing default cell editor"));
  2271.  
  2272.     return editor;
  2273. }
  2274.  
  2275. // ----------------------------------------------------------------------------
  2276. // wxGridCellAttrData
  2277. // ----------------------------------------------------------------------------
  2278.  
  2279. void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col)
  2280. {
  2281.     int n = FindIndex(row, col);
  2282.     if ( n == wxNOT_FOUND )
  2283.     {
  2284.         // add the attribute
  2285.         m_attrs.Add(new wxGridCellWithAttr(row, col, attr));
  2286.     }
  2287.     else
  2288.     {
  2289.         // free the old attribute
  2290.         m_attrs[(size_t)n].attr->DecRef();
  2291.  
  2292.         if ( attr )
  2293.         {
  2294.             // change the attribute
  2295.             m_attrs[(size_t)n].attr = attr;
  2296.         }
  2297.         else
  2298.         {
  2299.             // remove this attribute
  2300.             m_attrs.RemoveAt((size_t)n);
  2301.         }
  2302.     }
  2303. }
  2304.  
  2305. wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const
  2306. {
  2307.     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
  2308.  
  2309.     int n = FindIndex(row, col);
  2310.     if ( n != wxNOT_FOUND )
  2311.     {
  2312.         attr = m_attrs[(size_t)n].attr;
  2313.         attr->IncRef();
  2314.     }
  2315.  
  2316.     return attr;
  2317. }
  2318.  
  2319. void wxGridCellAttrData::UpdateAttrRows( size_t pos, int numRows )
  2320. {
  2321.     size_t count = m_attrs.GetCount();
  2322.     for ( size_t n = 0; n < count; n++ )
  2323.     {
  2324.         wxGridCellCoords& coords = m_attrs[n].coords;
  2325.         wxCoord row = coords.GetRow();
  2326.         if ((size_t)row >= pos)
  2327.         {
  2328.             if (numRows > 0)
  2329.             {
  2330.                 // If rows inserted, include row counter where necessary
  2331.                 coords.SetRow(row + numRows);
  2332.             }
  2333.             else if (numRows < 0)
  2334.             {
  2335.                 // If rows deleted ...
  2336.                 if ((size_t)row >= pos - numRows)
  2337.                 {
  2338.                     // ...either decrement row counter (if row still exists)...
  2339.                     coords.SetRow(row + numRows);
  2340.                 }
  2341.                 else
  2342.                 {
  2343.                     // ...or remove the attribute
  2344.                     m_attrs.RemoveAt((size_t)n);
  2345.                     n--; count--;
  2346.                 }
  2347.             }
  2348.         }
  2349.     }
  2350. }
  2351.  
  2352. void wxGridCellAttrData::UpdateAttrCols( size_t pos, int numCols )
  2353. {
  2354.     size_t count = m_attrs.GetCount();
  2355.     for ( size_t n = 0; n < count; n++ )
  2356.     {
  2357.         wxGridCellCoords& coords = m_attrs[n].coords;
  2358.         wxCoord col = coords.GetCol();
  2359.         if ( (size_t)col >= pos )
  2360.         {
  2361.             if ( numCols > 0 )
  2362.             {
  2363.                 // If rows inserted, include row counter where necessary
  2364.                 coords.SetCol(col + numCols);
  2365.             }
  2366.             else if (numCols < 0)
  2367.             {
  2368.                 // If rows deleted ...
  2369.                 if ((size_t)col >= pos - numCols)
  2370.                 {
  2371.                     // ...either decrement row counter (if row still exists)...
  2372.                     coords.SetCol(col + numCols);
  2373.                 }
  2374.                 else
  2375.                 {
  2376.                     // ...or remove the attribute
  2377.                     m_attrs.RemoveAt((size_t)n);
  2378.                     n--; count--;
  2379.                 }
  2380.             }
  2381.         }
  2382.     }
  2383. }
  2384.  
  2385. int wxGridCellAttrData::FindIndex(int row, int col) const
  2386. {
  2387.     size_t count = m_attrs.GetCount();
  2388.     for ( size_t n = 0; n < count; n++ )
  2389.     {
  2390.         const wxGridCellCoords& coords = m_attrs[n].coords;
  2391.         if ( (coords.GetRow() == row) && (coords.GetCol() == col) )
  2392.         {
  2393.             return n;
  2394.         }
  2395.     }
  2396.  
  2397.     return wxNOT_FOUND;
  2398. }
  2399.  
  2400. // ----------------------------------------------------------------------------
  2401. // wxGridRowOrColAttrData
  2402. // ----------------------------------------------------------------------------
  2403.  
  2404. wxGridRowOrColAttrData::~wxGridRowOrColAttrData()
  2405. {
  2406.     size_t count = m_attrs.Count();
  2407.     for ( size_t n = 0; n < count; n++ )
  2408.     {
  2409.         m_attrs[n]->DecRef();
  2410.     }
  2411. }
  2412.  
  2413. wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const
  2414. {
  2415.     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
  2416.  
  2417.     int n = m_rowsOrCols.Index(rowOrCol);
  2418.     if ( n != wxNOT_FOUND )
  2419.     {
  2420.         attr = m_attrs[(size_t)n];
  2421.         attr->IncRef();
  2422.     }
  2423.  
  2424.     return attr;
  2425. }
  2426.  
  2427. void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
  2428. {
  2429.     int i = m_rowsOrCols.Index(rowOrCol);
  2430.     if ( i == wxNOT_FOUND )
  2431.     {
  2432.         // add the attribute
  2433.         m_rowsOrCols.Add(rowOrCol);
  2434.         m_attrs.Add(attr);
  2435.     }
  2436.     else
  2437.     {
  2438.         size_t n = (size_t)i;
  2439.         if ( attr )
  2440.         {
  2441.             // change the attribute
  2442.             m_attrs[n]->DecRef();
  2443.             m_attrs[n] = attr;
  2444.         }
  2445.         else
  2446.         {
  2447.             // remove this attribute
  2448.             m_attrs[n]->DecRef();
  2449.             m_rowsOrCols.RemoveAt(n);
  2450.             m_attrs.RemoveAt(n);
  2451.         }
  2452.     }
  2453. }
  2454.  
  2455. void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols )
  2456. {
  2457.     size_t count = m_attrs.GetCount();
  2458.     for ( size_t n = 0; n < count; n++ )
  2459.     {
  2460.         int & rowOrCol = m_rowsOrCols[n];
  2461.         if ( (size_t)rowOrCol >= pos )
  2462.         {
  2463.             if ( numRowsOrCols > 0 )
  2464.             {
  2465.                 // If rows inserted, include row counter where necessary
  2466.                 rowOrCol += numRowsOrCols;
  2467.             }
  2468.             else if ( numRowsOrCols < 0)
  2469.             {
  2470.                 // If rows deleted, either decrement row counter (if row still exists)
  2471.                 if ((size_t)rowOrCol >= pos - numRowsOrCols)
  2472.                     rowOrCol += numRowsOrCols;
  2473.                 else
  2474.                 {
  2475.                     m_rowsOrCols.RemoveAt((size_t)n);
  2476.                     m_attrs.RemoveAt((size_t)n);
  2477.                     n--; count--;
  2478.                 }
  2479.             }
  2480.         }
  2481.     }
  2482. }
  2483.  
  2484. // ----------------------------------------------------------------------------
  2485. // wxGridCellAttrProvider
  2486. // ----------------------------------------------------------------------------
  2487.  
  2488. wxGridCellAttrProvider::wxGridCellAttrProvider()
  2489. {
  2490.     m_data = (wxGridCellAttrProviderData *)NULL;
  2491. }
  2492.  
  2493. wxGridCellAttrProvider::~wxGridCellAttrProvider()
  2494. {
  2495.     delete m_data;
  2496. }
  2497.  
  2498. void wxGridCellAttrProvider::InitData()
  2499. {
  2500.     m_data = new wxGridCellAttrProviderData;
  2501. }
  2502.  
  2503. wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col,
  2504.                                                 wxGridCellAttr::wxAttrKind  kind ) const
  2505. {
  2506.     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
  2507.     if ( m_data )
  2508.     {
  2509.         switch(kind)
  2510.         {
  2511.             case (wxGridCellAttr::Any):
  2512.                 //Get cached merge attributes.
  2513.                 // Currenlty not used as no cache implemented as not mutiable
  2514.                 // attr = m_data->m_mergeAttr.GetAttr(row, col);
  2515.                 if(!attr)
  2516.                 {
  2517.                     //Basicaly implement old version.
  2518.                     //Also check merge cache, so we don't have to re-merge every time..
  2519.                     wxGridCellAttr *attrcell = (wxGridCellAttr *)NULL,
  2520.                                    *attrrow = (wxGridCellAttr *)NULL,
  2521.                                    *attrcol = (wxGridCellAttr *)NULL;
  2522.  
  2523.                     attrcell = m_data->m_cellAttrs.GetAttr(row, col);
  2524.                     attrcol = m_data->m_colAttrs.GetAttr(col);
  2525.                     attrrow = m_data->m_rowAttrs.GetAttr(row);
  2526.  
  2527.                     if((attrcell != attrrow) && (attrrow !=attrcol) && (attrcell != attrcol)){
  2528.                         // Two or move are non NULL
  2529.                         attr = new wxGridCellAttr;
  2530.                         attr->SetKind(wxGridCellAttr::Merged);
  2531.  
  2532.                         //Order important..
  2533.                         if(attrcell){
  2534.                             attr->MergeWith(attrcell);
  2535.                             attrcell->DecRef();
  2536.                         }
  2537.                         if(attrcol){
  2538.                             attr->MergeWith(attrcol);
  2539.                             attrcol->DecRef();
  2540.                         }
  2541.                         if(attrrow){
  2542.                             attr->MergeWith(attrrow);
  2543.                             attrrow->DecRef();
  2544.                         }
  2545.                         //store merge attr if cache implemented
  2546.                         //attr->IncRef();
  2547.                         //m_data->m_mergeAttr.SetAttr(attr, row, col);
  2548.                     }
  2549.                     else
  2550.         {
  2551.                         // one or none is non null return it or null.
  2552.                         if(attrrow) attr = attrrow;
  2553.                         if(attrcol) attr = attrcol;
  2554.                         if(attrcell) attr = attrcell;
  2555.                     }
  2556.                 }
  2557.             break;
  2558.             case (wxGridCellAttr::Cell):
  2559.                 attr = m_data->m_cellAttrs.GetAttr(row, col);
  2560.             break;
  2561.             case (wxGridCellAttr::Col):
  2562.                  attr = m_data->m_colAttrs.GetAttr(col);
  2563.             break;
  2564.             case (wxGridCellAttr::Row):
  2565.             attr = m_data->m_rowAttrs.GetAttr(row);
  2566.             break;
  2567.             default:
  2568.                 // unused as yet...
  2569.                 // (wxGridCellAttr::Default):
  2570.                 // (wxGridCellAttr::Merged):
  2571.             break;
  2572.         }
  2573.     }
  2574.     return attr;
  2575. }
  2576.  
  2577. void wxGridCellAttrProvider::SetAttr(wxGridCellAttr *attr,
  2578.                                      int row, int col)
  2579. {
  2580.     if ( !m_data )
  2581.         InitData();
  2582.  
  2583.     m_data->m_cellAttrs.SetAttr(attr, row, col);
  2584. }
  2585.  
  2586. void wxGridCellAttrProvider::SetRowAttr(wxGridCellAttr *attr, int row)
  2587. {
  2588.     if ( !m_data )
  2589.         InitData();
  2590.  
  2591.     m_data->m_rowAttrs.SetAttr(attr, row);
  2592. }
  2593.  
  2594. void wxGridCellAttrProvider::SetColAttr(wxGridCellAttr *attr, int col)
  2595. {
  2596.     if ( !m_data )
  2597.         InitData();
  2598.  
  2599.     m_data->m_colAttrs.SetAttr(attr, col);
  2600. }
  2601.  
  2602. void wxGridCellAttrProvider::UpdateAttrRows( size_t pos, int numRows )
  2603. {
  2604.     if ( m_data )
  2605.     {
  2606.         m_data->m_cellAttrs.UpdateAttrRows( pos, numRows );
  2607.  
  2608.         m_data->m_rowAttrs.UpdateAttrRowsOrCols( pos, numRows );
  2609.     }
  2610. }
  2611.  
  2612. void wxGridCellAttrProvider::UpdateAttrCols( size_t pos, int numCols )
  2613. {
  2614.     if ( m_data )
  2615.     {
  2616.         m_data->m_cellAttrs.UpdateAttrCols( pos, numCols );
  2617.  
  2618.         m_data->m_colAttrs.UpdateAttrRowsOrCols( pos, numCols );
  2619.     }
  2620. }
  2621.  
  2622. // ----------------------------------------------------------------------------
  2623. // wxGridTypeRegistry
  2624. // ----------------------------------------------------------------------------
  2625.  
  2626. wxGridTypeRegistry::~wxGridTypeRegistry()
  2627. {
  2628.     size_t count = m_typeinfo.Count();
  2629.     for ( size_t i = 0; i < count; i++ )
  2630.         delete m_typeinfo[i];
  2631. }
  2632.  
  2633.  
  2634. void wxGridTypeRegistry::RegisterDataType(const wxString& typeName,
  2635.                                           wxGridCellRenderer* renderer,
  2636.                                           wxGridCellEditor* editor)
  2637. {
  2638.     wxGridDataTypeInfo* info = new wxGridDataTypeInfo(typeName, renderer, editor);
  2639.  
  2640.     // is it already registered?
  2641.     int loc = FindRegisteredDataType(typeName);
  2642.     if ( loc != wxNOT_FOUND )
  2643.     {
  2644.         delete m_typeinfo[loc];
  2645.         m_typeinfo[loc] = info;
  2646.     }
  2647.     else
  2648.     {
  2649.         m_typeinfo.Add(info);
  2650.     }
  2651. }
  2652.  
  2653. int wxGridTypeRegistry::FindRegisteredDataType(const wxString& typeName)
  2654. {
  2655.     size_t count = m_typeinfo.GetCount();
  2656.     for ( size_t i = 0; i < count; i++ )
  2657.     {
  2658.         if ( typeName == m_typeinfo[i]->m_typeName )
  2659.         {
  2660.             return i;
  2661.         }
  2662.     }
  2663.  
  2664.     return wxNOT_FOUND;
  2665. }
  2666.  
  2667. int wxGridTypeRegistry::FindDataType(const wxString& typeName)
  2668. {
  2669.     int index = FindRegisteredDataType(typeName);
  2670.     if ( index == wxNOT_FOUND )
  2671.     {
  2672.         // check whether this is one of the standard ones, in which case
  2673.         // register it "on the fly"
  2674. #if wxUSE_TEXTCTRL
  2675.         if ( typeName == wxGRID_VALUE_STRING )
  2676.         {
  2677.             RegisterDataType(wxGRID_VALUE_STRING,
  2678.                              new wxGridCellStringRenderer,
  2679.                              new wxGridCellTextEditor);
  2680.         } else
  2681. #endif // wxUSE_TEXTCTRL
  2682. #if wxUSE_CHECKBOX
  2683.         if ( typeName == wxGRID_VALUE_BOOL )
  2684.         {
  2685.             RegisterDataType(wxGRID_VALUE_BOOL,
  2686.                              new wxGridCellBoolRenderer,
  2687.                              new wxGridCellBoolEditor);
  2688.         } else
  2689. #endif // wxUSE_CHECKBOX
  2690. #if wxUSE_TEXTCTRL
  2691.         if ( typeName == wxGRID_VALUE_NUMBER )
  2692.         {
  2693.             RegisterDataType(wxGRID_VALUE_NUMBER,
  2694.                              new wxGridCellNumberRenderer,
  2695.                              new wxGridCellNumberEditor);
  2696.         }
  2697.         else if ( typeName == wxGRID_VALUE_FLOAT )
  2698.         {
  2699.             RegisterDataType(wxGRID_VALUE_FLOAT,
  2700.                              new wxGridCellFloatRenderer,
  2701.                              new wxGridCellFloatEditor);
  2702.         } else
  2703. #endif // wxUSE_TEXTCTRL
  2704. #if wxUSE_COMBOBOX
  2705.         if ( typeName == wxGRID_VALUE_CHOICE )
  2706.         {
  2707.             RegisterDataType(wxGRID_VALUE_CHOICE,
  2708.                              new wxGridCellStringRenderer,
  2709.                              new wxGridCellChoiceEditor);
  2710.         } else
  2711. #endif // wxUSE_COMBOBOX
  2712.         {
  2713.             return wxNOT_FOUND;
  2714.         }
  2715.  
  2716.         // we get here only if just added the entry for this type, so return
  2717.         // the last index
  2718.         index = m_typeinfo.GetCount() - 1;
  2719.     }
  2720.  
  2721.     return index;
  2722. }
  2723.  
  2724. int wxGridTypeRegistry::FindOrCloneDataType(const wxString& typeName)
  2725. {
  2726.     int index = FindDataType(typeName);
  2727.     if ( index == wxNOT_FOUND )
  2728.     {
  2729.         // the first part of the typename is the "real" type, anything after ':'
  2730.         // are the parameters for the renderer
  2731.         index = FindDataType(typeName.BeforeFirst(_T(':')));
  2732.         if ( index == wxNOT_FOUND )
  2733.         {
  2734.             return wxNOT_FOUND;
  2735.         }
  2736.  
  2737.         wxGridCellRenderer *renderer = GetRenderer(index);
  2738.         wxGridCellRenderer *rendererOld = renderer;
  2739.         renderer = renderer->Clone();
  2740.         rendererOld->DecRef();
  2741.  
  2742.         wxGridCellEditor *editor = GetEditor(index);
  2743.         wxGridCellEditor *editorOld = editor;
  2744.         editor = editor->Clone();
  2745.         editorOld->DecRef();
  2746.  
  2747.         // do it even if there are no parameters to reset them to defaults
  2748.         wxString params = typeName.AfterFirst(_T(':'));
  2749.         renderer->SetParameters(params);
  2750.         editor->SetParameters(params);
  2751.  
  2752.         // register the new typename
  2753.         RegisterDataType(typeName, renderer, editor);
  2754.  
  2755.         // we just registered it, it's the last one
  2756.         index = m_typeinfo.GetCount() - 1;
  2757.     }
  2758.  
  2759.     return index;
  2760. }
  2761.  
  2762. wxGridCellRenderer* wxGridTypeRegistry::GetRenderer(int index)
  2763. {
  2764.     wxGridCellRenderer* renderer = m_typeinfo[index]->m_renderer;
  2765.     if (renderer)
  2766.         renderer->IncRef();
  2767.     return renderer;
  2768. }
  2769.  
  2770. wxGridCellEditor* wxGridTypeRegistry::GetEditor(int index)
  2771. {
  2772.     wxGridCellEditor* editor = m_typeinfo[index]->m_editor;
  2773.     if (editor)
  2774.         editor->IncRef();
  2775.     return editor;
  2776. }
  2777.  
  2778. // ----------------------------------------------------------------------------
  2779. // wxGridTableBase
  2780. // ----------------------------------------------------------------------------
  2781.  
  2782. IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject )
  2783.  
  2784.  
  2785. wxGridTableBase::wxGridTableBase()
  2786. {
  2787.     m_view = (wxGrid *) NULL;
  2788.     m_attrProvider = (wxGridCellAttrProvider *) NULL;
  2789. }
  2790.  
  2791. wxGridTableBase::~wxGridTableBase()
  2792. {
  2793.     delete m_attrProvider;
  2794. }
  2795.  
  2796. void wxGridTableBase::SetAttrProvider(wxGridCellAttrProvider *attrProvider)
  2797. {
  2798.     delete m_attrProvider;
  2799.     m_attrProvider = attrProvider;
  2800. }
  2801.  
  2802. bool wxGridTableBase::CanHaveAttributes()
  2803. {
  2804.     if ( ! GetAttrProvider() )
  2805.     {
  2806.         // use the default attr provider by default
  2807.         SetAttrProvider(new wxGridCellAttrProvider);
  2808.     }
  2809.     return TRUE;
  2810. }
  2811.  
  2812. wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind  kind)
  2813. {
  2814.     if ( m_attrProvider )
  2815.         return m_attrProvider->GetAttr(row, col, kind);
  2816.     else
  2817.         return (wxGridCellAttr *)NULL;
  2818. }
  2819.  
  2820. void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col)
  2821. {
  2822.     if ( m_attrProvider )
  2823.     {
  2824.         attr->SetKind(wxGridCellAttr::Cell);
  2825.         m_attrProvider->SetAttr(attr, row, col);
  2826.     }
  2827.     else
  2828.     {
  2829.         // as we take ownership of the pointer and don't store it, we must
  2830.         // free it now
  2831.         wxSafeDecRef(attr);
  2832.     }
  2833. }
  2834.  
  2835. void wxGridTableBase::SetRowAttr(wxGridCellAttr *attr, int row)
  2836. {
  2837.     if ( m_attrProvider )
  2838.     {
  2839.         attr->SetKind(wxGridCellAttr::Row);
  2840.         m_attrProvider->SetRowAttr(attr, row);
  2841.     }
  2842.     else
  2843.     {
  2844.         // as we take ownership of the pointer and don't store it, we must
  2845.         // free it now
  2846.         wxSafeDecRef(attr);
  2847.     }
  2848. }
  2849.  
  2850. void wxGridTableBase::SetColAttr(wxGridCellAttr *attr, int col)
  2851. {
  2852.     if ( m_attrProvider )
  2853.     {
  2854.         attr->SetKind(wxGridCellAttr::Col);
  2855.         m_attrProvider->SetColAttr(attr, col);
  2856.     }
  2857.     else
  2858.     {
  2859.         // as we take ownership of the pointer and don't store it, we must
  2860.         // free it now
  2861.         wxSafeDecRef(attr);
  2862.     }
  2863. }
  2864.  
  2865. bool wxGridTableBase::InsertRows( size_t WXUNUSED(pos),
  2866.                                   size_t WXUNUSED(numRows) )
  2867. {
  2868.     wxFAIL_MSG( wxT("Called grid table class function InsertRows\nbut your derived table class does not override this function") );
  2869.  
  2870.     return FALSE;
  2871. }
  2872.  
  2873. bool wxGridTableBase::AppendRows( size_t WXUNUSED(numRows) )
  2874. {
  2875.     wxFAIL_MSG( wxT("Called grid table class function AppendRows\nbut your derived table class does not override this function"));
  2876.  
  2877.     return FALSE;
  2878. }
  2879.  
  2880. bool wxGridTableBase::DeleteRows( size_t WXUNUSED(pos),
  2881.                                   size_t WXUNUSED(numRows) )
  2882. {
  2883.     wxFAIL_MSG( wxT("Called grid table class function DeleteRows\nbut your derived table class does not override this function"));
  2884.  
  2885.     return FALSE;
  2886. }
  2887.  
  2888. bool wxGridTableBase::InsertCols( size_t WXUNUSED(pos),
  2889.                                   size_t WXUNUSED(numCols) )
  2890. {
  2891.     wxFAIL_MSG( wxT("Called grid table class function InsertCols\nbut your derived table class does not override this function"));
  2892.  
  2893.     return FALSE;
  2894. }
  2895.  
  2896. bool wxGridTableBase::AppendCols( size_t WXUNUSED(numCols) )
  2897. {
  2898.     wxFAIL_MSG(wxT("Called grid table class function AppendCols\nbut your derived table class does not override this function"));
  2899.  
  2900.     return FALSE;
  2901. }
  2902.  
  2903. bool wxGridTableBase::DeleteCols( size_t WXUNUSED(pos),
  2904.                                   size_t WXUNUSED(numCols) )
  2905. {
  2906.     wxFAIL_MSG( wxT("Called grid table class function DeleteCols\nbut your derived table class does not override this function"));
  2907.  
  2908.     return FALSE;
  2909. }
  2910.  
  2911.  
  2912. wxString wxGridTableBase::GetRowLabelValue( int row )
  2913. {
  2914.     wxString s;
  2915.     s << row + 1; // RD: Starting the rows at zero confuses users, no matter
  2916.                   //     how much it makes sense to us geeks.
  2917.     return s;
  2918. }
  2919.  
  2920. wxString wxGridTableBase::GetColLabelValue( int col )
  2921. {
  2922.     // default col labels are:
  2923.     //   cols 0 to 25   : A-Z
  2924.     //   cols 26 to 675 : AA-ZZ
  2925.     //   etc.
  2926.  
  2927.     wxString s;
  2928.     unsigned int i, n;
  2929.     for ( n = 1; ; n++ )
  2930.     {
  2931.         s += (_T('A') + (wxChar)( col%26 ));
  2932.         col = col/26 - 1;
  2933.         if ( col < 0 ) break;
  2934.     }
  2935.  
  2936.     // reverse the string...
  2937.     wxString s2;
  2938.     for ( i = 0;  i < n;  i++ )
  2939.     {
  2940.         s2 += s[n-i-1];
  2941.     }
  2942.  
  2943.     return s2;
  2944. }
  2945.  
  2946.  
  2947. wxString wxGridTableBase::GetTypeName( int WXUNUSED(row), int WXUNUSED(col) )
  2948. {
  2949.     return wxGRID_VALUE_STRING;
  2950. }
  2951.  
  2952. bool wxGridTableBase::CanGetValueAs( int WXUNUSED(row), int WXUNUSED(col),
  2953.                                      const wxString& typeName )
  2954. {
  2955.     return typeName == wxGRID_VALUE_STRING;
  2956. }
  2957.  
  2958. bool wxGridTableBase::CanSetValueAs( int row, int col, const wxString& typeName )
  2959. {
  2960.     return CanGetValueAs(row, col, typeName);
  2961. }
  2962.  
  2963. long wxGridTableBase::GetValueAsLong( int WXUNUSED(row), int WXUNUSED(col) )
  2964. {
  2965.     return 0;
  2966. }
  2967.  
  2968. double wxGridTableBase::GetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col) )
  2969. {
  2970.     return 0.0;
  2971. }
  2972.  
  2973. bool wxGridTableBase::GetValueAsBool( int WXUNUSED(row), int WXUNUSED(col) )
  2974. {
  2975.     return FALSE;
  2976. }
  2977.  
  2978. void wxGridTableBase::SetValueAsLong( int WXUNUSED(row), int WXUNUSED(col),
  2979.                                       long WXUNUSED(value) )
  2980. {
  2981. }
  2982.  
  2983. void wxGridTableBase::SetValueAsDouble( int WXUNUSED(row), int WXUNUSED(col),
  2984.                                         double WXUNUSED(value) )
  2985. {
  2986. }
  2987.  
  2988. void wxGridTableBase::SetValueAsBool( int WXUNUSED(row), int WXUNUSED(col),
  2989.                                       bool WXUNUSED(value) )
  2990. {
  2991. }
  2992.  
  2993.  
  2994. void* wxGridTableBase::GetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
  2995.                                          const wxString& WXUNUSED(typeName) )
  2996. {
  2997.     return NULL;
  2998. }
  2999.  
  3000. void  wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col),
  3001.                                          const wxString& WXUNUSED(typeName),
  3002.                                          void* WXUNUSED(value) )
  3003. {
  3004. }
  3005.  
  3006. //////////////////////////////////////////////////////////////////////
  3007. //
  3008. // Message class for the grid table to send requests and notifications
  3009. // to the grid view
  3010. //
  3011.  
  3012. wxGridTableMessage::wxGridTableMessage()
  3013. {
  3014.     m_table = (wxGridTableBase *) NULL;
  3015.     m_id = -1;
  3016.     m_comInt1 = -1;
  3017.     m_comInt2 = -1;
  3018. }
  3019.  
  3020. wxGridTableMessage::wxGridTableMessage( wxGridTableBase *table, int id,
  3021.                                         int commandInt1, int commandInt2 )
  3022. {
  3023.     m_table = table;
  3024.     m_id = id;
  3025.     m_comInt1 = commandInt1;
  3026.     m_comInt2 = commandInt2;
  3027. }
  3028.  
  3029.  
  3030.  
  3031. //////////////////////////////////////////////////////////////////////
  3032. //
  3033. // A basic grid table for string data. An object of this class will
  3034. // created by wxGrid if you don't specify an alternative table class.
  3035. //
  3036.  
  3037. WX_DEFINE_OBJARRAY(wxGridStringArray)
  3038.  
  3039. IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
  3040.  
  3041. wxGridStringTable::wxGridStringTable()
  3042.         : wxGridTableBase()
  3043. {
  3044. }
  3045.  
  3046. wxGridStringTable::wxGridStringTable( int numRows, int numCols )
  3047.         : wxGridTableBase()
  3048. {
  3049.     m_data.Alloc( numRows );
  3050.  
  3051.     wxArrayString sa;
  3052.     sa.Alloc( numCols );
  3053.     sa.Add( wxEmptyString, numCols );
  3054.  
  3055.     m_data.Add( sa, numRows );
  3056. }
  3057.  
  3058. wxGridStringTable::~wxGridStringTable()
  3059. {
  3060. }
  3061.  
  3062. int wxGridStringTable::GetNumberRows()
  3063. {
  3064.     return m_data.GetCount();
  3065. }
  3066.  
  3067. int wxGridStringTable::GetNumberCols()
  3068. {
  3069.     if ( m_data.GetCount() > 0 )
  3070.         return m_data[0].GetCount();
  3071.     else
  3072.         return 0;
  3073. }
  3074.  
  3075. wxString wxGridStringTable::GetValue( int row, int col )
  3076. {
  3077.     wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
  3078.                   _T("invalid row or column index in wxGridStringTable") );
  3079.  
  3080.     return m_data[row][col];
  3081. }
  3082.  
  3083. void wxGridStringTable::SetValue( int row, int col, const wxString& value )
  3084. {
  3085.     wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
  3086.                   _T("invalid row or column index in wxGridStringTable") );
  3087.  
  3088.     m_data[row][col] = value;
  3089. }
  3090.  
  3091. bool wxGridStringTable::IsEmptyCell( int row, int col )
  3092. {
  3093.     wxASSERT_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
  3094.                   _T("invalid row or column index in wxGridStringTable") );
  3095.  
  3096.     return (m_data[row][col] == wxEmptyString);
  3097. }
  3098.  
  3099. void wxGridStringTable::Clear()
  3100. {
  3101.     int row, col;
  3102.     int numRows, numCols;
  3103.  
  3104.     numRows = m_data.GetCount();
  3105.     if ( numRows > 0 )
  3106.     {
  3107.         numCols = m_data[0].GetCount();
  3108.  
  3109.         for ( row = 0;  row < numRows;  row++ )
  3110.         {
  3111.             for ( col = 0;  col < numCols;  col++ )
  3112.             {
  3113.                 m_data[row][col] = wxEmptyString;
  3114.             }
  3115.         }
  3116.     }
  3117. }
  3118.  
  3119.  
  3120. bool wxGridStringTable::InsertRows( size_t pos, size_t numRows )
  3121. {
  3122.     size_t curNumRows = m_data.GetCount();
  3123.     size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
  3124.                           ( GetView() ? GetView()->GetNumberCols() : 0 ) );
  3125.  
  3126.     if ( pos >= curNumRows )
  3127.     {
  3128.         return AppendRows( numRows );
  3129.     }
  3130.  
  3131.     wxArrayString sa;
  3132.     sa.Alloc( curNumCols );
  3133.     sa.Add( wxEmptyString, curNumCols );
  3134.     m_data.Insert( sa, pos, numRows );
  3135.     if ( GetView() )
  3136.     {
  3137.         wxGridTableMessage msg( this,
  3138.                                 wxGRIDTABLE_NOTIFY_ROWS_INSERTED,
  3139.                                 pos,
  3140.                                 numRows );
  3141.  
  3142.         GetView()->ProcessTableMessage( msg );
  3143.     }
  3144.  
  3145.     return TRUE;
  3146. }
  3147.  
  3148. bool wxGridStringTable::AppendRows( size_t numRows )
  3149. {
  3150.     size_t curNumRows = m_data.GetCount();
  3151.     size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
  3152.                           ( GetView() ? GetView()->GetNumberCols() : 0 ) );
  3153.  
  3154.     wxArrayString sa;
  3155.     if ( curNumCols > 0 )
  3156.     {
  3157.         sa.Alloc( curNumCols );
  3158.         sa.Add( wxEmptyString, curNumCols );
  3159.     }
  3160.  
  3161.     m_data.Add( sa, numRows );
  3162.  
  3163.     if ( GetView() )
  3164.     {
  3165.         wxGridTableMessage msg( this,
  3166.                                 wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
  3167.                                 numRows );
  3168.  
  3169.         GetView()->ProcessTableMessage( msg );
  3170.     }
  3171.  
  3172.     return TRUE;
  3173. }
  3174.  
  3175. bool wxGridStringTable::DeleteRows( size_t pos, size_t numRows )
  3176. {
  3177.     size_t curNumRows = m_data.GetCount();
  3178.  
  3179.     if ( pos >= curNumRows )
  3180.     {
  3181.         wxFAIL_MSG( wxString::Format
  3182.                     (
  3183.                         wxT("Called wxGridStringTable::DeleteRows(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu rows"),
  3184.                         (unsigned long)pos,
  3185.                         (unsigned long)numRows,
  3186.                         (unsigned long)curNumRows
  3187.                     ) );
  3188.  
  3189.         return FALSE;
  3190.     }
  3191.  
  3192.     if ( numRows > curNumRows - pos )
  3193.     {
  3194.         numRows = curNumRows - pos;
  3195.     }
  3196.  
  3197.     if ( numRows >= curNumRows )
  3198.     {
  3199.         m_data.Clear();
  3200.     }
  3201.     else
  3202.     {
  3203.         m_data.RemoveAt( pos, numRows );
  3204.     }
  3205.     if ( GetView() )
  3206.     {
  3207.         wxGridTableMessage msg( this,
  3208.                                 wxGRIDTABLE_NOTIFY_ROWS_DELETED,
  3209.                                 pos,
  3210.                                 numRows );
  3211.  
  3212.         GetView()->ProcessTableMessage( msg );
  3213.     }
  3214.  
  3215.     return TRUE;
  3216. }
  3217.  
  3218. bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
  3219. {
  3220.     size_t row, col;
  3221.  
  3222.     size_t curNumRows = m_data.GetCount();
  3223.     size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
  3224.                           ( GetView() ? GetView()->GetNumberCols() : 0 ) );
  3225.  
  3226.     if ( pos >= curNumCols )
  3227.     {
  3228.         return AppendCols( numCols );
  3229.     }
  3230.  
  3231.     for ( row = 0;  row < curNumRows;  row++ )
  3232.     {
  3233.         for ( col = pos;  col < pos + numCols;  col++ )
  3234.         {
  3235.             m_data[row].Insert( wxEmptyString, col );
  3236.         }
  3237.     }
  3238.     if ( GetView() )
  3239.     {
  3240.         wxGridTableMessage msg( this,
  3241.                                 wxGRIDTABLE_NOTIFY_COLS_INSERTED,
  3242.                                 pos,
  3243.                                 numCols );
  3244.  
  3245.         GetView()->ProcessTableMessage( msg );
  3246.     }
  3247.  
  3248.     return TRUE;
  3249. }
  3250.  
  3251. bool wxGridStringTable::AppendCols( size_t numCols )
  3252. {
  3253.     size_t row;
  3254.  
  3255.     size_t curNumRows = m_data.GetCount();
  3256. #if 0
  3257.     if ( !curNumRows )
  3258.     {
  3259.         // TODO: something better than this ?
  3260.         //
  3261.         wxFAIL_MSG( wxT("Unable to append cols to a grid table with no rows.\nCall AppendRows() first") );
  3262.         return FALSE;
  3263.     }
  3264. #endif
  3265.  
  3266.     for ( row = 0;  row < curNumRows;  row++ )
  3267.     {
  3268.         m_data[row].Add( wxEmptyString, numCols );
  3269.     }
  3270.  
  3271.     if ( GetView() )
  3272.     {
  3273.         wxGridTableMessage msg( this,
  3274.                                 wxGRIDTABLE_NOTIFY_COLS_APPENDED,
  3275.                                 numCols );
  3276.  
  3277.         GetView()->ProcessTableMessage( msg );
  3278.     }
  3279.  
  3280.     return TRUE;
  3281. }
  3282.  
  3283. bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
  3284. {
  3285.     size_t row;
  3286.  
  3287.     size_t curNumRows = m_data.GetCount();
  3288.     size_t curNumCols = ( curNumRows > 0 ? m_data[0].GetCount() :
  3289.                           ( GetView() ? GetView()->GetNumberCols() : 0 ) );
  3290.  
  3291.     if ( pos >= curNumCols )
  3292.     {
  3293.         wxFAIL_MSG( wxString::Format
  3294.                     (
  3295.                         wxT("Called wxGridStringTable::DeleteCols(pos=%lu, N=%lu)\nPos value is invalid for present table with %lu cols"),
  3296.                         (unsigned long)pos,
  3297.                         (unsigned long)numCols,
  3298.                         (unsigned long)curNumCols
  3299.                     ) );
  3300.         return FALSE;
  3301.     }
  3302.  
  3303.     if ( numCols > curNumCols - pos )
  3304.     {
  3305.         numCols = curNumCols - pos;
  3306.     }
  3307.  
  3308.     for ( row = 0;  row < curNumRows;  row++ )
  3309.     {
  3310.         if ( numCols >= curNumCols )
  3311.         {
  3312.             m_data[row].Clear();
  3313.         }
  3314.         else
  3315.         {
  3316.             m_data[row].RemoveAt( pos, numCols );
  3317.         }
  3318.     }
  3319.     if ( GetView() )
  3320.     {
  3321.         wxGridTableMessage msg( this,
  3322.                                 wxGRIDTABLE_NOTIFY_COLS_DELETED,
  3323.                                 pos,
  3324.                                 numCols );
  3325.  
  3326.         GetView()->ProcessTableMessage( msg );
  3327.     }
  3328.  
  3329.     return TRUE;
  3330. }
  3331.  
  3332. wxString wxGridStringTable::GetRowLabelValue( int row )
  3333. {
  3334.     if ( row > (int)(m_rowLabels.GetCount()) - 1 )
  3335.     {
  3336.         // using default label
  3337.         //
  3338.         return wxGridTableBase::GetRowLabelValue( row );
  3339.     }
  3340.     else
  3341.     {
  3342.         return m_rowLabels[ row ];
  3343.     }
  3344. }
  3345.  
  3346. wxString wxGridStringTable::GetColLabelValue( int col )
  3347. {
  3348.     if ( col > (int)(m_colLabels.GetCount()) - 1 )
  3349.     {
  3350.         // using default label
  3351.         //
  3352.         return wxGridTableBase::GetColLabelValue( col );
  3353.     }
  3354.     else
  3355.     {
  3356.         return m_colLabels[ col ];
  3357.     }
  3358. }
  3359.  
  3360. void wxGridStringTable::SetRowLabelValue( int row, const wxString& value )
  3361. {
  3362.     if ( row > (int)(m_rowLabels.GetCount()) - 1 )
  3363.     {
  3364.         int n = m_rowLabels.GetCount();
  3365.         int i;
  3366.         for ( i = n;  i <= row;  i++ )
  3367.         {
  3368.             m_rowLabels.Add( wxGridTableBase::GetRowLabelValue(i) );
  3369.         }
  3370.     }
  3371.  
  3372.     m_rowLabels[row] = value;
  3373. }
  3374.  
  3375. void wxGridStringTable::SetColLabelValue( int col, const wxString& value )
  3376. {
  3377.     if ( col > (int)(m_colLabels.GetCount()) - 1 )
  3378.     {
  3379.         int n = m_colLabels.GetCount();
  3380.         int i;
  3381.         for ( i = n;  i <= col;  i++ )
  3382.         {
  3383.             m_colLabels.Add( wxGridTableBase::GetColLabelValue(i) );
  3384.         }
  3385.     }
  3386.  
  3387.     m_colLabels[col] = value;
  3388. }
  3389.  
  3390.  
  3391.  
  3392. //////////////////////////////////////////////////////////////////////
  3393. //////////////////////////////////////////////////////////////////////
  3394.  
  3395. IMPLEMENT_DYNAMIC_CLASS( wxGridRowLabelWindow, wxWindow )
  3396.  
  3397. BEGIN_EVENT_TABLE( wxGridRowLabelWindow, wxWindow )
  3398.     EVT_PAINT( wxGridRowLabelWindow::OnPaint )
  3399.     EVT_MOUSEWHEEL( wxGridRowLabelWindow::OnMouseWheel)
  3400.     EVT_MOUSE_EVENTS( wxGridRowLabelWindow::OnMouseEvent )
  3401.     EVT_KEY_DOWN( wxGridRowLabelWindow::OnKeyDown )
  3402.     EVT_KEY_UP( wxGridRowLabelWindow::OnKeyUp )
  3403. END_EVENT_TABLE()
  3404.  
  3405. wxGridRowLabelWindow::wxGridRowLabelWindow( wxGrid *parent,
  3406.                                             wxWindowID id,
  3407.                                             const wxPoint &pos, const wxSize &size )
  3408.   : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
  3409. {
  3410.     m_owner = parent;
  3411. }
  3412.  
  3413. void wxGridRowLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
  3414. {
  3415.     wxPaintDC dc(this);
  3416.  
  3417.     // NO - don't do this because it will set both the x and y origin
  3418.     // coords to match the parent scrolled window and we just want to
  3419.     // set the y coord  - MB
  3420.     //
  3421.     // m_owner->PrepareDC( dc );
  3422.  
  3423.     int x, y;
  3424.     m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
  3425.     dc.SetDeviceOrigin( 0, -y );
  3426.  
  3427.     wxArrayInt rows = m_owner->CalcRowLabelsExposed( GetUpdateRegion() );
  3428.     m_owner->DrawRowLabels( dc , rows );
  3429. }
  3430.  
  3431.  
  3432. void wxGridRowLabelWindow::OnMouseEvent( wxMouseEvent& event )
  3433. {
  3434.     m_owner->ProcessRowLabelMouseEvent( event );
  3435. }
  3436.  
  3437.  
  3438. void wxGridRowLabelWindow::OnMouseWheel( wxMouseEvent& event )
  3439. {
  3440.     m_owner->GetEventHandler()->ProcessEvent(event);
  3441. }
  3442.  
  3443.  
  3444. // This seems to be required for wxMotif otherwise the mouse
  3445. // cursor must be in the cell edit control to get key events
  3446. //
  3447. void wxGridRowLabelWindow::OnKeyDown( wxKeyEvent& event )
  3448. {
  3449.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3450. }
  3451.  
  3452. void wxGridRowLabelWindow::OnKeyUp( wxKeyEvent& event )
  3453. {
  3454.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3455. }
  3456.  
  3457.  
  3458.  
  3459. //////////////////////////////////////////////////////////////////////
  3460.  
  3461. IMPLEMENT_DYNAMIC_CLASS( wxGridColLabelWindow, wxWindow )
  3462.  
  3463. BEGIN_EVENT_TABLE( wxGridColLabelWindow, wxWindow )
  3464.     EVT_PAINT( wxGridColLabelWindow::OnPaint )
  3465.     EVT_MOUSEWHEEL( wxGridColLabelWindow::OnMouseWheel)
  3466.     EVT_MOUSE_EVENTS( wxGridColLabelWindow::OnMouseEvent )
  3467.     EVT_KEY_DOWN( wxGridColLabelWindow::OnKeyDown )
  3468.     EVT_KEY_UP( wxGridColLabelWindow::OnKeyUp )
  3469. END_EVENT_TABLE()
  3470.  
  3471. wxGridColLabelWindow::wxGridColLabelWindow( wxGrid *parent,
  3472.                                             wxWindowID id,
  3473.                                             const wxPoint &pos, const wxSize &size )
  3474.   : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
  3475. {
  3476.     m_owner = parent;
  3477. }
  3478.  
  3479. void wxGridColLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
  3480. {
  3481.     wxPaintDC dc(this);
  3482.  
  3483.     // NO - don't do this because it will set both the x and y origin
  3484.     // coords to match the parent scrolled window and we just want to
  3485.     // set the x coord  - MB
  3486.     //
  3487.     // m_owner->PrepareDC( dc );
  3488.  
  3489.     int x, y;
  3490.     m_owner->CalcUnscrolledPosition( 0, 0, &x, &y );
  3491.     dc.SetDeviceOrigin( -x, 0 );
  3492.  
  3493.     wxArrayInt cols = m_owner->CalcColLabelsExposed( GetUpdateRegion() );
  3494.     m_owner->DrawColLabels( dc , cols );
  3495. }
  3496.  
  3497.  
  3498. void wxGridColLabelWindow::OnMouseEvent( wxMouseEvent& event )
  3499. {
  3500.     m_owner->ProcessColLabelMouseEvent( event );
  3501. }
  3502.  
  3503. void wxGridColLabelWindow::OnMouseWheel( wxMouseEvent& event )
  3504. {
  3505.     m_owner->GetEventHandler()->ProcessEvent(event);
  3506. }
  3507.  
  3508.  
  3509. // This seems to be required for wxMotif otherwise the mouse
  3510. // cursor must be in the cell edit control to get key events
  3511. //
  3512. void wxGridColLabelWindow::OnKeyDown( wxKeyEvent& event )
  3513. {
  3514.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3515. }
  3516.  
  3517. void wxGridColLabelWindow::OnKeyUp( wxKeyEvent& event )
  3518. {
  3519.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3520. }
  3521.  
  3522.  
  3523.  
  3524. //////////////////////////////////////////////////////////////////////
  3525.  
  3526. IMPLEMENT_DYNAMIC_CLASS( wxGridCornerLabelWindow, wxWindow )
  3527.  
  3528. BEGIN_EVENT_TABLE( wxGridCornerLabelWindow, wxWindow )
  3529.     EVT_MOUSEWHEEL( wxGridCornerLabelWindow::OnMouseWheel)
  3530.     EVT_MOUSE_EVENTS( wxGridCornerLabelWindow::OnMouseEvent )
  3531.     EVT_PAINT( wxGridCornerLabelWindow::OnPaint)
  3532.     EVT_KEY_DOWN( wxGridCornerLabelWindow::OnKeyDown )
  3533.     EVT_KEY_UP( wxGridCornerLabelWindow::OnKeyUp )
  3534. END_EVENT_TABLE()
  3535.  
  3536. wxGridCornerLabelWindow::wxGridCornerLabelWindow( wxGrid *parent,
  3537.                                                   wxWindowID id,
  3538.                                                   const wxPoint &pos, const wxSize &size )
  3539.   : wxWindow( parent, id, pos, size, wxWANTS_CHARS )
  3540. {
  3541.     m_owner = parent;
  3542. }
  3543.  
  3544. void wxGridCornerLabelWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
  3545. {
  3546.     wxPaintDC dc(this);
  3547.  
  3548.     int client_height = 0;
  3549.     int client_width = 0;
  3550.     GetClientSize( &client_width, &client_height );
  3551.  
  3552.     dc.SetPen( *wxBLACK_PEN );
  3553.     dc.DrawLine( client_width-1, client_height-1, client_width-1, 0 );
  3554.     dc.DrawLine( client_width-1, client_height-1, 0, client_height-1 );
  3555.  
  3556.     dc.SetPen( *wxWHITE_PEN );
  3557.     dc.DrawLine( 0, 0, client_width, 0 );
  3558.     dc.DrawLine( 0, 0, 0, client_height );
  3559. }
  3560.  
  3561.  
  3562. void wxGridCornerLabelWindow::OnMouseEvent( wxMouseEvent& event )
  3563. {
  3564.     m_owner->ProcessCornerLabelMouseEvent( event );
  3565. }
  3566.  
  3567.  
  3568. void wxGridCornerLabelWindow::OnMouseWheel( wxMouseEvent& event )
  3569. {
  3570.     m_owner->GetEventHandler()->ProcessEvent(event);
  3571. }
  3572.  
  3573. // This seems to be required for wxMotif otherwise the mouse
  3574. // cursor must be in the cell edit control to get key events
  3575. //
  3576. void wxGridCornerLabelWindow::OnKeyDown( wxKeyEvent& event )
  3577. {
  3578.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3579. }
  3580.  
  3581. void wxGridCornerLabelWindow::OnKeyUp( wxKeyEvent& event )
  3582. {
  3583.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3584. }
  3585.  
  3586.  
  3587.  
  3588. //////////////////////////////////////////////////////////////////////
  3589.  
  3590. IMPLEMENT_DYNAMIC_CLASS( wxGridWindow, wxWindow )
  3591.  
  3592. BEGIN_EVENT_TABLE( wxGridWindow, wxWindow )
  3593.     EVT_PAINT( wxGridWindow::OnPaint )
  3594.     EVT_MOUSEWHEEL( wxGridWindow::OnMouseWheel)
  3595.     EVT_MOUSE_EVENTS( wxGridWindow::OnMouseEvent )
  3596.     EVT_KEY_DOWN( wxGridWindow::OnKeyDown )
  3597.     EVT_KEY_UP( wxGridWindow::OnKeyUp )
  3598.     EVT_ERASE_BACKGROUND( wxGridWindow::OnEraseBackground )
  3599. END_EVENT_TABLE()
  3600.  
  3601. wxGridWindow::wxGridWindow( wxGrid *parent,
  3602.                             wxGridRowLabelWindow *rowLblWin,
  3603.                             wxGridColLabelWindow *colLblWin,
  3604.                             wxWindowID id, const wxPoint &pos, const wxSize &size )
  3605.         : wxWindow( parent, id, pos, size, wxWANTS_CHARS, wxT("grid window") )
  3606. {
  3607.     m_owner = parent;
  3608.     m_rowLabelWin = rowLblWin;
  3609.     m_colLabelWin = colLblWin;
  3610.     SetBackgroundColour(_T("WHITE"));
  3611. }
  3612.  
  3613.  
  3614. wxGridWindow::~wxGridWindow()
  3615. {
  3616. }
  3617.  
  3618.  
  3619. void wxGridWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
  3620. {
  3621.     wxPaintDC dc( this );
  3622.     m_owner->PrepareDC( dc );
  3623.     wxRegion reg = GetUpdateRegion();
  3624.     wxGridCellCoordsArray DirtyCells = m_owner->CalcCellsExposed( reg );
  3625.     m_owner->DrawGridCellArea( dc , DirtyCells);
  3626. #if WXGRID_DRAW_LINES
  3627.     m_owner->DrawAllGridLines( dc, reg );
  3628. #endif
  3629.     m_owner->DrawGridSpace( dc );
  3630.     m_owner->DrawHighlight( dc , DirtyCells );
  3631. }
  3632.  
  3633.  
  3634. void wxGridWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
  3635. {
  3636.     wxWindow::ScrollWindow( dx, dy, rect );
  3637.     m_rowLabelWin->ScrollWindow( 0, dy, rect );
  3638.     m_colLabelWin->ScrollWindow( dx, 0, rect );
  3639. }
  3640.  
  3641.  
  3642. void wxGridWindow::OnMouseEvent( wxMouseEvent& event )
  3643. {
  3644.     m_owner->ProcessGridCellMouseEvent( event );
  3645. }
  3646.  
  3647. void wxGridWindow::OnMouseWheel( wxMouseEvent& event )
  3648. {
  3649.     m_owner->GetEventHandler()->ProcessEvent(event);
  3650. }
  3651.  
  3652. // This seems to be required for wxMotif/wxGTK otherwise the mouse
  3653. // cursor must be in the cell edit control to get key events
  3654. //
  3655. void wxGridWindow::OnKeyDown( wxKeyEvent& event )
  3656. {
  3657.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3658. }
  3659.  
  3660. void wxGridWindow::OnKeyUp( wxKeyEvent& event )
  3661. {
  3662.     if ( !m_owner->GetEventHandler()->ProcessEvent( event ) ) event.Skip();
  3663. }
  3664.  
  3665. void wxGridWindow::OnEraseBackground( wxEraseEvent& WXUNUSED(event) )
  3666. {
  3667. }
  3668.  
  3669.  
  3670. //////////////////////////////////////////////////////////////////////
  3671.  
  3672. // Internal Helper function for computing row or column from some
  3673. // (unscrolled) coordinate value, using either
  3674. // m_defaultRowHeight/m_defaultColWidth or binary search on array
  3675. // of m_rowBottoms/m_ColRights to speed up the search!
  3676.  
  3677. // Internal helper macros for simpler use of that function
  3678.  
  3679. static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
  3680.                            const wxArrayInt& BorderArray, int nMax,
  3681.                            bool maxOnOverflow);
  3682.  
  3683. #define internalXToCol(x) CoordToRowOrCol(x, m_defaultColWidth, \
  3684.                                           WXGRID_MIN_COL_WIDTH, \
  3685.                                           m_colRights, m_numCols, TRUE)
  3686. #define internalYToRow(y) CoordToRowOrCol(y, m_defaultRowHeight, \
  3687.                                           WXGRID_MIN_ROW_HEIGHT, \
  3688.                                           m_rowBottoms, m_numRows, TRUE)
  3689. /////////////////////////////////////////////////////////////////////
  3690.  
  3691. IMPLEMENT_DYNAMIC_CLASS( wxGrid, wxScrolledWindow )
  3692.  
  3693. BEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
  3694.     EVT_PAINT( wxGrid::OnPaint )
  3695.     EVT_SIZE( wxGrid::OnSize )
  3696.     EVT_KEY_DOWN( wxGrid::OnKeyDown )
  3697.     EVT_KEY_UP( wxGrid::OnKeyUp )
  3698.     EVT_ERASE_BACKGROUND( wxGrid::OnEraseBackground )
  3699. END_EVENT_TABLE()
  3700.  
  3701. wxGrid::wxGrid( wxWindow *parent,
  3702.                  wxWindowID id,
  3703.                  const wxPoint& pos,
  3704.                  const wxSize& size,
  3705.                  long style,
  3706.                  const wxString& name )
  3707.   : wxScrolledWindow( parent, id, pos, size, (style | wxWANTS_CHARS), name ),
  3708.     m_colMinWidths(GRID_HASH_SIZE),
  3709.     m_rowMinHeights(GRID_HASH_SIZE)
  3710. {
  3711.     Create();
  3712. }
  3713.  
  3714.  
  3715. wxGrid::~wxGrid()
  3716. {
  3717.     // Must do this or ~wxScrollHelper will pop the wrong event handler
  3718.     SetTargetWindow(this);
  3719.     ClearAttrCache();
  3720.     wxSafeDecRef(m_defaultCellAttr);
  3721.  
  3722. #ifdef DEBUG_ATTR_CACHE
  3723.     size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
  3724.     wxPrintf(_T("wxGrid attribute cache statistics: "
  3725.                 "total: %u, hits: %u (%u%%)\n"),
  3726.              total, gs_nAttrCacheHits,
  3727.              total ? (gs_nAttrCacheHits*100) / total : 0);
  3728. #endif
  3729.  
  3730.     if (m_ownTable)
  3731.         delete m_table;
  3732.  
  3733.     delete m_typeRegistry;
  3734.     delete m_selection;
  3735. }
  3736.  
  3737.  
  3738. //
  3739. // ----- internal init and update functions
  3740. //
  3741.  
  3742. void wxGrid::Create()
  3743. {
  3744.     m_created = FALSE;    // set to TRUE by CreateGrid
  3745.  
  3746.     m_table        = (wxGridTableBase *) NULL;
  3747.     m_ownTable     = FALSE;
  3748.  
  3749.     m_cellEditCtrlEnabled = FALSE;
  3750.  
  3751.     m_defaultCellAttr = new wxGridCellAttr();
  3752.  
  3753.     // Set default cell attributes
  3754.     m_defaultCellAttr->SetDefAttr(m_defaultCellAttr);
  3755.     m_defaultCellAttr->SetKind(wxGridCellAttr::Default);
  3756.     m_defaultCellAttr->SetFont(GetFont());
  3757.     m_defaultCellAttr->SetAlignment(wxALIGN_LEFT, wxALIGN_TOP);
  3758.     m_defaultCellAttr->SetTextColour(
  3759.         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
  3760.     m_defaultCellAttr->SetBackgroundColour(
  3761.         wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
  3762.     m_defaultCellAttr->SetRenderer(new wxGridCellStringRenderer);
  3763.     m_defaultCellAttr->SetEditor(new wxGridCellTextEditor);
  3764.  
  3765.  
  3766.     m_numRows = 0;
  3767.     m_numCols = 0;
  3768.     m_currentCellCoords = wxGridNoCellCoords;
  3769.  
  3770.     m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
  3771.     m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
  3772.  
  3773.     // create the type registry
  3774.     m_typeRegistry = new wxGridTypeRegistry;
  3775.     m_selection = NULL;
  3776.  
  3777.     // subwindow components that make up the wxGrid
  3778.     m_cornerLabelWin = new wxGridCornerLabelWindow( this,
  3779.                                                     -1,
  3780.                                                     wxDefaultPosition,
  3781.                                                     wxDefaultSize );
  3782.  
  3783.     m_rowLabelWin = new wxGridRowLabelWindow( this,
  3784.                                               -1,
  3785.                                               wxDefaultPosition,
  3786.                                               wxDefaultSize );
  3787.  
  3788.     m_colLabelWin = new wxGridColLabelWindow( this,
  3789.                                               -1,
  3790.                                               wxDefaultPosition,
  3791.                                               wxDefaultSize );
  3792.  
  3793.     m_gridWin = new wxGridWindow( this,
  3794.                                   m_rowLabelWin,
  3795.                                   m_colLabelWin,
  3796.                                   -1,
  3797.                                   wxDefaultPosition,
  3798.                                   wxDefaultSize );
  3799.  
  3800.     SetTargetWindow( m_gridWin );
  3801.  
  3802.     Init();
  3803. }
  3804.  
  3805.  
  3806. bool wxGrid::CreateGrid( int numRows, int numCols,
  3807.                          wxGrid::wxGridSelectionModes selmode )
  3808. {
  3809.     wxCHECK_MSG( !m_created,
  3810.                  FALSE,
  3811.                  wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
  3812.  
  3813.     m_numRows = numRows;
  3814.     m_numCols = numCols;
  3815.  
  3816.     m_table = new wxGridStringTable( m_numRows, m_numCols );
  3817.     m_table->SetView( this );
  3818.     m_ownTable = TRUE;
  3819.     m_selection = new wxGridSelection( this, selmode );
  3820.  
  3821.     CalcDimensions();
  3822.  
  3823.     m_created = TRUE;
  3824.  
  3825.     return m_created;
  3826. }
  3827.  
  3828. void wxGrid::SetSelectionMode(wxGrid::wxGridSelectionModes selmode)
  3829. {
  3830.     wxCHECK_RET( m_created,
  3831.                  wxT("Called wxGrid::SetSelectionMode() before calling CreateGrid()") );
  3832.  
  3833.     m_selection->SetSelectionMode( selmode );
  3834. }
  3835.  
  3836. wxGrid::wxGridSelectionModes wxGrid::GetSelectionMode() const
  3837. {
  3838.     wxCHECK_MSG( m_created, wxGrid::wxGridSelectCells,
  3839.                  wxT("Called wxGrid::GetSelectionMode() before calling CreateGrid()") );
  3840.  
  3841.     return m_selection->GetSelectionMode();
  3842. }
  3843.  
  3844. bool wxGrid::SetTable( wxGridTableBase *table, bool takeOwnership,
  3845.                        wxGrid::wxGridSelectionModes selmode )
  3846. {
  3847.     if ( m_created )
  3848.     {
  3849.         // RD: Actually, this should probably be allowed.  I think it would be
  3850.         //     nice to be able to switch multiple Tables in and out of a single
  3851.         //     View at runtime.  Is there anything in the implementation that
  3852.         //     would prevent this?
  3853.  
  3854.         // At least, you now have to cope with m_selection
  3855.         wxFAIL_MSG( wxT("wxGrid::CreateGrid or wxGrid::SetTable called more than once") );
  3856.         return FALSE;
  3857.     }
  3858.     else
  3859.     {
  3860.         m_numRows = table->GetNumberRows();
  3861.         m_numCols = table->GetNumberCols();
  3862.  
  3863.         m_table = table;
  3864.         m_table->SetView( this );
  3865.         if (takeOwnership)
  3866.             m_ownTable = TRUE;
  3867.         m_selection = new wxGridSelection( this, selmode );
  3868.  
  3869.         CalcDimensions();
  3870.  
  3871.         m_created = TRUE;
  3872.     }
  3873.  
  3874.     return m_created;
  3875. }
  3876.  
  3877.  
  3878. void wxGrid::Init()
  3879. {
  3880.     m_rowLabelWidth  = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
  3881.     m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
  3882.  
  3883.     if ( m_rowLabelWin )
  3884.     {
  3885.         m_labelBackgroundColour = m_rowLabelWin->GetBackgroundColour();
  3886.     }
  3887.     else
  3888.     {
  3889.         m_labelBackgroundColour = wxColour( _T("WHITE") );
  3890.     }
  3891.  
  3892.     m_labelTextColour = wxColour( _T("BLACK") );
  3893.  
  3894.     // init attr cache
  3895.     m_attrCache.row = -1;
  3896.     m_attrCache.col = -1;
  3897.     m_attrCache.attr = NULL;
  3898.  
  3899.     // TODO: something better than this ?
  3900.     //
  3901.     m_labelFont = this->GetFont();
  3902.     m_labelFont.SetWeight( wxBOLD );
  3903.  
  3904.     m_rowLabelHorizAlign = wxALIGN_LEFT;
  3905.     m_rowLabelVertAlign  = wxALIGN_CENTRE;
  3906.  
  3907.     m_colLabelHorizAlign = wxALIGN_CENTRE;
  3908.     m_colLabelVertAlign  = wxALIGN_TOP;
  3909.  
  3910.     m_defaultColWidth  = WXGRID_DEFAULT_COL_WIDTH;
  3911.     m_defaultRowHeight = m_gridWin->GetCharHeight();
  3912.  
  3913. #if defined(__WXMOTIF__) || defined(__WXGTK__)  // see also text ctrl sizing in ShowCellEditControl()
  3914.     m_defaultRowHeight += 8;
  3915. #else
  3916.     m_defaultRowHeight += 4;
  3917. #endif
  3918.  
  3919.     m_gridLineColour = wxColour( 128, 128, 255 );
  3920.     m_gridLinesEnabled = TRUE;
  3921.     m_cellHighlightColour = m_gridLineColour;
  3922.     m_cellHighlightPenWidth = 2;
  3923.     m_cellHighlightROPenWidth = 1;
  3924.  
  3925.     m_cursorMode  = WXGRID_CURSOR_SELECT_CELL;
  3926.     m_winCapture = (wxWindow *)NULL;
  3927.     m_canDragRowSize = TRUE;
  3928.     m_canDragColSize = TRUE;
  3929.     m_canDragGridSize = TRUE;
  3930.     m_dragLastPos  = -1;
  3931.     m_dragRowOrCol = -1;
  3932.     m_isDragging = FALSE;
  3933.     m_startDragPos = wxDefaultPosition;
  3934.  
  3935.     m_waitForSlowClick = FALSE;
  3936.  
  3937.     m_rowResizeCursor = wxCursor( wxCURSOR_SIZENS );
  3938.     m_colResizeCursor = wxCursor( wxCURSOR_SIZEWE );
  3939.  
  3940.     m_currentCellCoords = wxGridNoCellCoords;
  3941.  
  3942.     m_selectingTopLeft = wxGridNoCellCoords;
  3943.     m_selectingBottomRight = wxGridNoCellCoords;
  3944.     m_selectionBackground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
  3945.     m_selectionForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
  3946.  
  3947.     m_editable = TRUE;  // default for whole grid
  3948.  
  3949.     m_inOnKeyDown = FALSE;
  3950.     m_batchCount = 0;
  3951.  
  3952.     m_extraWidth =
  3953.     m_extraHeight = 0;
  3954. }
  3955.  
  3956. // ----------------------------------------------------------------------------
  3957. // the idea is to call these functions only when necessary because they create
  3958. // quite big arrays which eat memory mostly unnecessary - in particular, if
  3959. // default widths/heights are used for all rows/columns, we may not use these
  3960. // arrays at all
  3961. //
  3962. // with some extra code, it should be possible to only store the
  3963. // widths/heights different from default ones but this will be done later...
  3964. // ----------------------------------------------------------------------------
  3965.  
  3966. void wxGrid::InitRowHeights()
  3967. {
  3968.     m_rowHeights.Empty();
  3969.     m_rowBottoms.Empty();
  3970.  
  3971.     m_rowHeights.Alloc( m_numRows );
  3972.     m_rowBottoms.Alloc( m_numRows );
  3973.  
  3974.     int rowBottom = 0;
  3975.  
  3976.     m_rowHeights.Add( m_defaultRowHeight, m_numRows );
  3977.  
  3978.     for ( int i = 0;  i < m_numRows;  i++ )
  3979.     {
  3980.         rowBottom += m_defaultRowHeight;
  3981.         m_rowBottoms.Add( rowBottom );
  3982.     }
  3983. }
  3984.  
  3985. void wxGrid::InitColWidths()
  3986. {
  3987.     m_colWidths.Empty();
  3988.     m_colRights.Empty();
  3989.  
  3990.     m_colWidths.Alloc( m_numCols );
  3991.     m_colRights.Alloc( m_numCols );
  3992.     int colRight = 0;
  3993.  
  3994.     m_colWidths.Add( m_defaultColWidth, m_numCols );
  3995.  
  3996.     for ( int i = 0;  i < m_numCols;  i++ )
  3997.     {
  3998.         colRight += m_defaultColWidth;
  3999.         m_colRights.Add( colRight );
  4000.     }
  4001. }
  4002.  
  4003. int wxGrid::GetColWidth(int col) const
  4004. {
  4005.     return m_colWidths.IsEmpty() ? m_defaultColWidth : m_colWidths[col];
  4006. }
  4007.  
  4008. int wxGrid::GetColLeft(int col) const
  4009. {
  4010.     return m_colRights.IsEmpty() ? col * m_defaultColWidth
  4011.                                  : m_colRights[col] - m_colWidths[col];
  4012. }
  4013.  
  4014. int wxGrid::GetColRight(int col) const
  4015. {
  4016.     return m_colRights.IsEmpty() ? (col + 1) * m_defaultColWidth
  4017.                                  : m_colRights[col];
  4018. }
  4019.  
  4020. int wxGrid::GetRowHeight(int row) const
  4021. {
  4022.     return m_rowHeights.IsEmpty() ? m_defaultRowHeight : m_rowHeights[row];
  4023. }
  4024.  
  4025. int wxGrid::GetRowTop(int row) const
  4026. {
  4027.     return m_rowBottoms.IsEmpty() ? row * m_defaultRowHeight
  4028.                                   : m_rowBottoms[row] - m_rowHeights[row];
  4029. }
  4030.  
  4031. int wxGrid::GetRowBottom(int row) const
  4032. {
  4033.     return m_rowBottoms.IsEmpty() ? (row + 1) * m_defaultRowHeight
  4034.                                   : m_rowBottoms[row];
  4035. }
  4036.  
  4037. void wxGrid::CalcDimensions()
  4038. {
  4039.     int cw, ch;
  4040.     GetClientSize( &cw, &ch );
  4041.  
  4042.     if ( m_rowLabelWin->IsShown() )
  4043.         cw -= m_rowLabelWidth;
  4044.     if ( m_colLabelWin->IsShown() )
  4045.         ch -= m_colLabelHeight;
  4046.  
  4047.     // grid total size
  4048.     int w = m_numCols > 0 ? GetColRight(m_numCols - 1) + m_extraWidth + 1 : 0;
  4049.     int h = m_numRows > 0 ? GetRowBottom(m_numRows - 1) + m_extraHeight + 1 : 0;
  4050.  
  4051.     // take into account editor if shown
  4052.     if( IsCellEditControlShown() )
  4053.     {
  4054.       int w2, h2;
  4055.       int r = m_currentCellCoords.GetRow();
  4056.       int c = m_currentCellCoords.GetCol();
  4057.       int x = GetColLeft(c);
  4058.       int y = GetRowTop(r);
  4059.  
  4060.       // how big is the editor
  4061.       wxGridCellAttr* attr = GetCellAttr(r, c);
  4062.       wxGridCellEditor* editor = attr->GetEditor(this, r, c);
  4063.       editor->GetControl()->GetSize(&w2, &h2);
  4064.       w2 += x;
  4065.       h2 += y;
  4066.       if( w2 > w ) w = w2;
  4067.       if( h2 > h ) h = h2;
  4068.       editor->DecRef();
  4069.       attr->DecRef();
  4070.     }
  4071.     // preserve (more or less) the previous position
  4072.     int x, y;
  4073.     GetViewStart( &x, &y );
  4074.  
  4075.     // maybe we don't need scrollbars at all?
  4076.     //
  4077.     // also adjust the position to be valid for the new scroll rangs
  4078.     if ( w <= cw )
  4079.     {
  4080.         w = x = 0;
  4081.     }
  4082.     else
  4083.     {
  4084.         if ( x >= w )
  4085.             x = w - 1;
  4086.     }
  4087.  
  4088.     if ( h <= ch )
  4089.     {
  4090.         h = y = 0;
  4091.     }
  4092.     else
  4093.     {
  4094.         if ( y >= h )
  4095.             y = h - 1;
  4096.     }
  4097.  
  4098.     // do set scrollbar parameters
  4099.     SetScrollbars( GRID_SCROLL_LINE_X, GRID_SCROLL_LINE_Y,
  4100.                    GetScrollX(w), GetScrollY(h), x, y,
  4101.                    GetBatchCount() != 0);
  4102.  
  4103.     // if our OnSize() hadn't been called (it would if we have scrollbars), we
  4104.     // still must reposition the children
  4105.     CalcWindowSizes();
  4106. }
  4107.  
  4108.  
  4109. void wxGrid::CalcWindowSizes()
  4110. {
  4111.     int cw, ch;
  4112.     GetClientSize( &cw, &ch );
  4113.  
  4114.     if ( m_cornerLabelWin->IsShown() )
  4115.         m_cornerLabelWin->SetSize( 0, 0, m_rowLabelWidth, m_colLabelHeight );
  4116.  
  4117.     if ( m_colLabelWin->IsShown() )
  4118.         m_colLabelWin->SetSize( m_rowLabelWidth, 0, cw-m_rowLabelWidth, m_colLabelHeight);
  4119.  
  4120.     if ( m_rowLabelWin->IsShown() )
  4121.         m_rowLabelWin->SetSize( 0, m_colLabelHeight, m_rowLabelWidth, ch-m_colLabelHeight);
  4122.  
  4123.     if ( m_gridWin->IsShown() )
  4124.         m_gridWin->SetSize( m_rowLabelWidth, m_colLabelHeight, cw-m_rowLabelWidth, ch-m_colLabelHeight);
  4125. }
  4126.  
  4127.  
  4128. // this is called when the grid table sends a message to say that it
  4129. // has been redimensioned
  4130. //
  4131. bool wxGrid::Redimension( wxGridTableMessage& msg )
  4132. {
  4133.     int i;
  4134.     bool result = FALSE;
  4135.  
  4136.     // Clear the attribute cache as the attribute might refer to a different
  4137.     // cell than stored in the cache after adding/removing rows/columns.
  4138.     ClearAttrCache();
  4139.     // By the same reasoning, the editor should be dismissed if columns are
  4140.     // added or removed. And for consistency, it should IMHO always be
  4141.     // removed, not only if the cell "underneath" it actually changes.
  4142.     // For now, I intentionally do not save the editor's content as the
  4143.     // cell it might want to save that stuff to might no longer exist.
  4144.     HideCellEditControl();
  4145. #if 0
  4146.     // if we were using the default widths/heights so far, we must change them
  4147.     // now
  4148.     if ( m_colWidths.IsEmpty() )
  4149.     {
  4150.         InitColWidths();
  4151.     }
  4152.  
  4153.     if ( m_rowHeights.IsEmpty() )
  4154.     {
  4155.         InitRowHeights();
  4156.     }
  4157. #endif
  4158.  
  4159.     switch ( msg.GetId() )
  4160.     {
  4161.         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
  4162.         {
  4163.             size_t pos = msg.GetCommandInt();
  4164.             int numRows = msg.GetCommandInt2();
  4165.  
  4166.             m_numRows += numRows;
  4167.  
  4168.             if ( !m_rowHeights.IsEmpty() )
  4169.             {
  4170.                 m_rowHeights.Insert( m_defaultRowHeight, pos, numRows );
  4171.                 m_rowBottoms.Insert( 0, pos, numRows );
  4172.  
  4173.                 int bottom = 0;
  4174.                 if ( pos > 0 ) bottom = m_rowBottoms[pos-1];
  4175.  
  4176.                 for ( i = pos;  i < m_numRows;  i++ )
  4177.                 {
  4178.                     bottom += m_rowHeights[i];
  4179.                     m_rowBottoms[i] = bottom;
  4180.                 }
  4181.             }
  4182.             if ( m_currentCellCoords == wxGridNoCellCoords )
  4183.             {
  4184.                 // if we have just inserted cols into an empty grid the current
  4185.                 // cell will be undefined...
  4186.                 //
  4187.                 SetCurrentCell( 0, 0 );
  4188.             }
  4189.  
  4190.             if ( m_selection )
  4191.                 m_selection->UpdateRows( pos, numRows );
  4192.             wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
  4193.             if (attrProvider)
  4194.                 attrProvider->UpdateAttrRows( pos, numRows );
  4195.  
  4196.             if ( !GetBatchCount() )
  4197.             {
  4198.                 CalcDimensions();
  4199.                 m_rowLabelWin->Refresh();
  4200.             }
  4201.         }
  4202.         result = TRUE;
  4203.         break;
  4204.  
  4205.         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
  4206.         {
  4207.             int numRows = msg.GetCommandInt();
  4208.             int oldNumRows = m_numRows;
  4209.             m_numRows += numRows;
  4210.  
  4211.             if ( !m_rowHeights.IsEmpty() )
  4212.             {
  4213.                 m_rowHeights.Add( m_defaultRowHeight, numRows );
  4214.                 m_rowBottoms.Add( 0, numRows );
  4215.  
  4216.                 int bottom = 0;
  4217.                 if ( oldNumRows > 0 ) bottom = m_rowBottoms[oldNumRows-1];
  4218.  
  4219.                 for ( i = oldNumRows;  i < m_numRows;  i++ )
  4220.                 {
  4221.                     bottom += m_rowHeights[i];
  4222.                     m_rowBottoms[i] = bottom;
  4223.                 }
  4224.             }
  4225.             if ( m_currentCellCoords == wxGridNoCellCoords )
  4226.             {
  4227.                 // if we have just inserted cols into an empty grid the current
  4228.                 // cell will be undefined...
  4229.                 //
  4230.                 SetCurrentCell( 0, 0 );
  4231.             }
  4232.             if ( !GetBatchCount() )
  4233.             {
  4234.                 CalcDimensions();
  4235.                 m_rowLabelWin->Refresh();
  4236.             }
  4237.         }
  4238.         result = TRUE;
  4239.         break;
  4240.  
  4241.         case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
  4242.         {
  4243.             size_t pos = msg.GetCommandInt();
  4244.             int numRows = msg.GetCommandInt2();
  4245.             m_numRows -= numRows;
  4246.  
  4247.             if ( !m_rowHeights.IsEmpty() )
  4248.             {
  4249.                 m_rowHeights.RemoveAt( pos, numRows );
  4250.                 m_rowBottoms.RemoveAt( pos, numRows );
  4251.  
  4252.                 int h = 0;
  4253.                 for ( i = 0;  i < m_numRows;  i++ )
  4254.                 {
  4255.                     h += m_rowHeights[i];
  4256.                     m_rowBottoms[i] = h;
  4257.                 }
  4258.             }
  4259.             if ( !m_numRows )
  4260.             {
  4261.                 m_currentCellCoords = wxGridNoCellCoords;
  4262.             }
  4263.             else
  4264.             {
  4265.                 if ( m_currentCellCoords.GetRow() >= m_numRows )
  4266.                     m_currentCellCoords.Set( 0, 0 );
  4267.             }
  4268.  
  4269.             if ( m_selection )
  4270.                 m_selection->UpdateRows( pos, -((int)numRows) );
  4271.             wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
  4272.             if (attrProvider) {
  4273.                 attrProvider->UpdateAttrRows( pos, -((int)numRows) );
  4274. // ifdef'd out following patch from Paul Gammans
  4275. #if 0
  4276.                 // No need to touch column attributes, unless we
  4277.                 // removed _all_ rows, in this case, we remove
  4278.                 // all column attributes.
  4279.                 // I hate to do this here, but the
  4280.                 // needed data is not available inside UpdateAttrRows.
  4281.                 if ( !GetNumberRows() )
  4282.                     attrProvider->UpdateAttrCols( 0, -GetNumberCols() );
  4283. #endif
  4284.             }
  4285.             if ( !GetBatchCount() )
  4286.             {
  4287.                 CalcDimensions();
  4288.                 m_rowLabelWin->Refresh();
  4289.             }
  4290.         }
  4291.         result = TRUE;
  4292.         break;
  4293.  
  4294.         case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
  4295.         {
  4296.             size_t pos = msg.GetCommandInt();
  4297.             int numCols = msg.GetCommandInt2();
  4298.             m_numCols += numCols;
  4299.  
  4300.             if ( !m_colWidths.IsEmpty() )
  4301.             {
  4302.                 m_colWidths.Insert( m_defaultColWidth, pos, numCols );
  4303.                 m_colRights.Insert( 0, pos, numCols );
  4304.  
  4305.                 int right = 0;
  4306.                 if ( pos > 0 ) right = m_colRights[pos-1];
  4307.  
  4308.                 for ( i = pos;  i < m_numCols;  i++ )
  4309.                 {
  4310.                     right += m_colWidths[i];
  4311.                     m_colRights[i] = right;
  4312.                 }
  4313.             }
  4314.             if ( m_currentCellCoords == wxGridNoCellCoords )
  4315.             {
  4316.                 // if we have just inserted cols into an empty grid the current
  4317.                 // cell will be undefined...
  4318.                 //
  4319.                 SetCurrentCell( 0, 0 );
  4320.             }
  4321.  
  4322.             if ( m_selection )
  4323.                 m_selection->UpdateCols( pos, numCols );
  4324.             wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
  4325.             if (attrProvider)
  4326.                 attrProvider->UpdateAttrCols( pos, numCols );
  4327.             if ( !GetBatchCount() )
  4328.             {
  4329.                 CalcDimensions();
  4330.                 m_colLabelWin->Refresh();
  4331.             }
  4332.  
  4333.         }
  4334.         result = TRUE;
  4335.         break;
  4336.  
  4337.         case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
  4338.         {
  4339.             int numCols = msg.GetCommandInt();
  4340.             int oldNumCols = m_numCols;
  4341.             m_numCols += numCols;
  4342.             if ( !m_colWidths.IsEmpty() )
  4343.             {
  4344.                 m_colWidths.Add( m_defaultColWidth, numCols );
  4345.                 m_colRights.Add( 0, numCols );
  4346.  
  4347.                 int right = 0;
  4348.                 if ( oldNumCols > 0 ) right = m_colRights[oldNumCols-1];
  4349.  
  4350.                 for ( i = oldNumCols;  i < m_numCols;  i++ )
  4351.                 {
  4352.                     right += m_colWidths[i];
  4353.                     m_colRights[i] = right;
  4354.                 }
  4355.             }
  4356.             if ( m_currentCellCoords == wxGridNoCellCoords )
  4357.             {
  4358.                 // if we have just inserted cols into an empty grid the current
  4359.                 // cell will be undefined...
  4360.                 //
  4361.                 SetCurrentCell( 0, 0 );
  4362.             }
  4363.             if ( !GetBatchCount() )
  4364.             {
  4365.                 CalcDimensions();
  4366.                 m_colLabelWin->Refresh();
  4367.             }
  4368.         }
  4369.         result = TRUE;
  4370.         break;
  4371.  
  4372.         case wxGRIDTABLE_NOTIFY_COLS_DELETED:
  4373.         {
  4374.             size_t pos = msg.GetCommandInt();
  4375.             int numCols = msg.GetCommandInt2();
  4376.             m_numCols -= numCols;
  4377.  
  4378.             if ( !m_colWidths.IsEmpty() )
  4379.             {
  4380.                 m_colWidths.RemoveAt( pos, numCols );
  4381.                 m_colRights.RemoveAt( pos, numCols );
  4382.  
  4383.                 int w = 0;
  4384.                 for ( i = 0;  i < m_numCols;  i++ )
  4385.                 {
  4386.                     w += m_colWidths[i];
  4387.                     m_colRights[i] = w;
  4388.                 }
  4389.             }
  4390.             if ( !m_numCols )
  4391.             {
  4392.                 m_currentCellCoords = wxGridNoCellCoords;
  4393.             }
  4394.             else
  4395.             {
  4396.                 if ( m_currentCellCoords.GetCol() >= m_numCols )
  4397.                   m_currentCellCoords.Set( 0, 0 );
  4398.             }
  4399.  
  4400.             if ( m_selection )
  4401.                 m_selection->UpdateCols( pos, -((int)numCols) );
  4402.             wxGridCellAttrProvider * attrProvider = m_table->GetAttrProvider();
  4403.             if (attrProvider) {
  4404.                 attrProvider->UpdateAttrCols( pos, -((int)numCols) );
  4405. // ifdef'd out following patch from Paul Gammans
  4406. #if 0
  4407.                 // No need to touch row attributes, unless we
  4408.                 // removed _all_ columns, in this case, we remove
  4409.                 // all row attributes.
  4410.                 // I hate to do this here, but the
  4411.                 // needed data is not available inside UpdateAttrCols.
  4412.                 if ( !GetNumberCols() )
  4413.                     attrProvider->UpdateAttrRows( 0, -GetNumberRows() );
  4414. #endif
  4415.             }
  4416.             if ( !GetBatchCount() )
  4417.             {
  4418.                 CalcDimensions();
  4419.                 m_colLabelWin->Refresh();
  4420.             }
  4421.         }
  4422.         result = TRUE;
  4423.         break;
  4424.     }
  4425.  
  4426.     if (result && !GetBatchCount() )
  4427.         m_gridWin->Refresh();
  4428.     return result;
  4429. }
  4430.  
  4431.  
  4432. wxArrayInt wxGrid::CalcRowLabelsExposed( const wxRegion& reg )
  4433. {
  4434.     wxRegionIterator iter( reg );
  4435.     wxRect r;
  4436.  
  4437.     wxArrayInt  rowlabels;
  4438.  
  4439.     int top, bottom;
  4440.     while ( iter )
  4441.     {
  4442.         r = iter.GetRect();
  4443.  
  4444.         // TODO: remove this when we can...
  4445.         // There is a bug in wxMotif that gives garbage update
  4446.         // rectangles if you jump-scroll a long way by clicking the
  4447.         // scrollbar with middle button.  This is a work-around
  4448.         //
  4449. #if defined(__WXMOTIF__)
  4450.         int cw, ch;
  4451.         m_gridWin->GetClientSize( &cw, &ch );
  4452.         if ( r.GetTop() > ch ) r.SetTop( 0 );
  4453.         r.SetBottom( wxMin( r.GetBottom(), ch ) );
  4454. #endif
  4455.  
  4456.         // logical bounds of update region
  4457.         //
  4458.         int dummy;
  4459.         CalcUnscrolledPosition( 0, r.GetTop(), &dummy, &top );
  4460.         CalcUnscrolledPosition( 0, r.GetBottom(), &dummy, &bottom );
  4461.  
  4462.         // find the row labels within these bounds
  4463.         //
  4464.         int row;
  4465.         for ( row = internalYToRow(top);  row < m_numRows;  row++ )
  4466.         {
  4467.             if ( GetRowBottom(row) < top )
  4468.                 continue;
  4469.  
  4470.             if ( GetRowTop(row) > bottom )
  4471.                 break;
  4472.  
  4473.             rowlabels.Add( row );
  4474.         }
  4475.  
  4476.         iter++ ;
  4477.     }
  4478.  
  4479.     return rowlabels;
  4480. }
  4481.  
  4482.  
  4483. wxArrayInt wxGrid::CalcColLabelsExposed( const wxRegion& reg )
  4484. {
  4485.     wxRegionIterator iter( reg );
  4486.     wxRect r;
  4487.  
  4488.     wxArrayInt colLabels;
  4489.  
  4490.     int left, right;
  4491.     while ( iter )
  4492.     {
  4493.         r = iter.GetRect();
  4494.  
  4495.         // TODO: remove this when we can...
  4496.         // There is a bug in wxMotif that gives garbage update
  4497.         // rectangles if you jump-scroll a long way by clicking the
  4498.         // scrollbar with middle button.  This is a work-around
  4499.         //
  4500. #if defined(__WXMOTIF__)
  4501.         int cw, ch;
  4502.         m_gridWin->GetClientSize( &cw, &ch );
  4503.         if ( r.GetLeft() > cw ) r.SetLeft( 0 );
  4504.         r.SetRight( wxMin( r.GetRight(), cw ) );
  4505. #endif
  4506.  
  4507.         // logical bounds of update region
  4508.         //
  4509.         int dummy;
  4510.         CalcUnscrolledPosition( r.GetLeft(), 0, &left, &dummy );
  4511.         CalcUnscrolledPosition( r.GetRight(), 0, &right, &dummy );
  4512.  
  4513.         // find the cells within these bounds
  4514.         //
  4515.         int col;
  4516.         for ( col = internalXToCol(left);  col < m_numCols;  col++ )
  4517.         {
  4518.             if ( GetColRight(col) < left )
  4519.                 continue;
  4520.  
  4521.             if ( GetColLeft(col) > right )
  4522.                 break;
  4523.  
  4524.             colLabels.Add( col );
  4525.         }
  4526.  
  4527.         iter++ ;
  4528.     }
  4529.     return colLabels;
  4530. }
  4531.  
  4532.  
  4533. wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg )
  4534. {
  4535.     wxRegionIterator iter( reg );
  4536.     wxRect r;
  4537.  
  4538.     wxGridCellCoordsArray  cellsExposed;
  4539.  
  4540.     int left, top, right, bottom;
  4541.     while ( iter )
  4542.     {
  4543.         r = iter.GetRect();
  4544.  
  4545.         // TODO: remove this when we can...
  4546.         // There is a bug in wxMotif that gives garbage update
  4547.         // rectangles if you jump-scroll a long way by clicking the
  4548.         // scrollbar with middle button.  This is a work-around
  4549.         //
  4550. #if defined(__WXMOTIF__)
  4551.         int cw, ch;
  4552.         m_gridWin->GetClientSize( &cw, &ch );
  4553.         if ( r.GetTop() > ch ) r.SetTop( 0 );
  4554.         if ( r.GetLeft() > cw ) r.SetLeft( 0 );
  4555.         r.SetRight( wxMin( r.GetRight(), cw ) );
  4556.         r.SetBottom( wxMin( r.GetBottom(), ch ) );
  4557. #endif
  4558.  
  4559.         // logical bounds of update region
  4560.         //
  4561.         CalcUnscrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
  4562.         CalcUnscrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
  4563.  
  4564.         // find the cells within these bounds
  4565.         //
  4566.         int row, col;
  4567.         for ( row = internalYToRow(top);  row < m_numRows;  row++ )
  4568.         {
  4569.             if ( GetRowBottom(row) <= top )
  4570.                 continue;
  4571.  
  4572.             if ( GetRowTop(row) > bottom )
  4573.                 break;
  4574.  
  4575.             for ( col = internalXToCol(left);  col < m_numCols;  col++ )
  4576.             {
  4577.                 if ( GetColRight(col) <= left )
  4578.                     continue;
  4579.  
  4580.                 if ( GetColLeft(col) > right )
  4581.                     break;
  4582.  
  4583.                 cellsExposed.Add( wxGridCellCoords( row, col ) );
  4584.             }
  4585.         }
  4586.  
  4587.         iter++;
  4588.     }
  4589.  
  4590.     return cellsExposed;
  4591. }
  4592.  
  4593.  
  4594. void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
  4595. {
  4596.     int x, y, row;
  4597.     wxPoint pos( event.GetPosition() );
  4598.     CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
  4599.  
  4600.     if ( event.Dragging() )
  4601.     {
  4602.         if (!m_isDragging)
  4603.         {
  4604.             m_isDragging = TRUE;
  4605.             m_rowLabelWin->CaptureMouse();
  4606.         }
  4607.  
  4608.         if ( event.LeftIsDown() )
  4609.         {
  4610.             switch( m_cursorMode )
  4611.             {
  4612.                 case WXGRID_CURSOR_RESIZE_ROW:
  4613.                 {
  4614.                     int cw, ch, left, dummy;
  4615.                     m_gridWin->GetClientSize( &cw, &ch );
  4616.                     CalcUnscrolledPosition( 0, 0, &left, &dummy );
  4617.  
  4618.                     wxClientDC dc( m_gridWin );
  4619.                     PrepareDC( dc );
  4620.                     y = wxMax( y,
  4621.                                GetRowTop(m_dragRowOrCol) +
  4622.                                GetRowMinimalHeight(m_dragRowOrCol) );
  4623.                     dc.SetLogicalFunction(wxINVERT);
  4624.                     if ( m_dragLastPos >= 0 )
  4625.                     {
  4626.                         dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
  4627.                     }
  4628.                     dc.DrawLine( left, y, left+cw, y );
  4629.                     m_dragLastPos = y;
  4630.                 }
  4631.                 break;
  4632.  
  4633.                 case WXGRID_CURSOR_SELECT_ROW:
  4634.                     if ( (row = YToRow( y )) >= 0 )
  4635.                     {
  4636.                         if ( m_selection )
  4637.                         {
  4638.                             m_selection->SelectRow( row,
  4639.                                                     event.ControlDown(),
  4640.                                                     event.ShiftDown(),
  4641.                                                     event.AltDown(),
  4642.                                                     event.MetaDown() );
  4643.                         }
  4644.                     }
  4645.  
  4646.                 // default label to suppress warnings about "enumeration value
  4647.                 // 'xxx' not handled in switch
  4648.                 default:
  4649.                     break;
  4650.             }
  4651.         }
  4652.         return;
  4653.     }
  4654.  
  4655.     if ( m_isDragging && (event.Entering() || event.Leaving()) )
  4656.         return;
  4657.  
  4658.     if (m_isDragging)
  4659.     {
  4660.         if (m_rowLabelWin->HasCapture()) m_rowLabelWin->ReleaseMouse();
  4661.         m_isDragging = FALSE;
  4662.     }
  4663.  
  4664.     // ------------ Entering or leaving the window
  4665.     //
  4666.     if ( event.Entering() || event.Leaving() )
  4667.     {
  4668.         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
  4669.     }
  4670.  
  4671.  
  4672.     // ------------ Left button pressed
  4673.     //
  4674.     else if ( event.LeftDown() )
  4675.     {
  4676.         // don't send a label click event for a hit on the
  4677.         // edge of the row label - this is probably the user
  4678.         // wanting to resize the row
  4679.         //
  4680.         if ( YToEdgeOfRow(y) < 0 )
  4681.         {
  4682.             row = YToRow(y);
  4683.             if ( row >= 0  &&
  4684.                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, row, -1, event ) )
  4685.             {
  4686.                 if ( !event.ShiftDown() && !event.ControlDown() )
  4687.                     ClearSelection();
  4688.                 if ( m_selection )
  4689.                 {
  4690.                     if ( event.ShiftDown() )
  4691.                     {
  4692.                         m_selection->SelectBlock( m_currentCellCoords.GetRow(),
  4693.                                                   0,
  4694.                                                   row,
  4695.                                                   GetNumberCols() - 1,
  4696.                                                   event.ControlDown(),
  4697.                                                   event.ShiftDown(),
  4698.                                                   event.AltDown(),
  4699.                                                   event.MetaDown() );
  4700.                     }
  4701.                     else
  4702.                     {
  4703.                         m_selection->SelectRow( row,
  4704.                                                 event.ControlDown(),
  4705.                                                 event.ShiftDown(),
  4706.                                                 event.AltDown(),
  4707.                                                 event.MetaDown() );
  4708.                     }
  4709.                 }
  4710.  
  4711.                 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
  4712.             }
  4713.         }
  4714.         else
  4715.         {
  4716.             // starting to drag-resize a row
  4717.             //
  4718.             if ( CanDragRowSize() )
  4719.                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
  4720.         }
  4721.     }
  4722.  
  4723.  
  4724.     // ------------ Left double click
  4725.     //
  4726.     else if (event.LeftDClick() )
  4727.     {
  4728.         if ( YToEdgeOfRow(y) < 0 )
  4729.         {
  4730.             row = YToRow(y);
  4731.             SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, row, -1, event );
  4732.         }
  4733.     }
  4734.  
  4735.  
  4736.     // ------------ Left button released
  4737.     //
  4738.     else if ( event.LeftUp() )
  4739.     {
  4740.         if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
  4741.         {
  4742.             DoEndDragResizeRow();
  4743.  
  4744.             // Note: we are ending the event *after* doing
  4745.             // default processing in this case
  4746.             //
  4747.             SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
  4748.         }
  4749.  
  4750.         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
  4751.         m_dragLastPos = -1;
  4752.     }
  4753.  
  4754.  
  4755.     // ------------ Right button down
  4756.     //
  4757.     else if ( event.RightDown() )
  4758.     {
  4759.         row = YToRow(y);
  4760.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, row, -1, event ) )
  4761.         {
  4762.             // no default action at the moment
  4763.         }
  4764.     }
  4765.  
  4766.  
  4767.     // ------------ Right double click
  4768.     //
  4769.     else if ( event.RightDClick() )
  4770.     {
  4771.         row = YToRow(y);
  4772.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, row, -1, event ) )
  4773.         {
  4774.             // no default action at the moment
  4775.         }
  4776.     }
  4777.  
  4778.  
  4779.     // ------------ No buttons down and mouse moving
  4780.     //
  4781.     else if ( event.Moving() )
  4782.     {
  4783.         m_dragRowOrCol = YToEdgeOfRow( y );
  4784.         if ( m_dragRowOrCol >= 0 )
  4785.         {
  4786.             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  4787.             {
  4788.                 // don't capture the mouse yet
  4789.                 if ( CanDragRowSize() )
  4790.                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, FALSE);
  4791.             }
  4792.         }
  4793.         else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
  4794.         {
  4795.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin, FALSE);
  4796.         }
  4797.     }
  4798. }
  4799.  
  4800.  
  4801. void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
  4802. {
  4803.     int x, y, col;
  4804.     wxPoint pos( event.GetPosition() );
  4805.     CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
  4806.  
  4807.     if ( event.Dragging() )
  4808.     {
  4809.         if (!m_isDragging)
  4810.         {
  4811.             m_isDragging = TRUE;
  4812.             m_colLabelWin->CaptureMouse();
  4813.         }
  4814.  
  4815.         if ( event.LeftIsDown() )
  4816.         {
  4817.             switch( m_cursorMode )
  4818.             {
  4819.                 case WXGRID_CURSOR_RESIZE_COL:
  4820.                 {
  4821.                     int cw, ch, dummy, top;
  4822.                     m_gridWin->GetClientSize( &cw, &ch );
  4823.                     CalcUnscrolledPosition( 0, 0, &dummy, &top );
  4824.  
  4825.                     wxClientDC dc( m_gridWin );
  4826.                     PrepareDC( dc );
  4827.  
  4828.                     x = wxMax( x, GetColLeft(m_dragRowOrCol) +
  4829.                                   GetColMinimalWidth(m_dragRowOrCol));
  4830.                     dc.SetLogicalFunction(wxINVERT);
  4831.                     if ( m_dragLastPos >= 0 )
  4832.                     {
  4833.                         dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
  4834.                     }
  4835.                     dc.DrawLine( x, top, x, top+ch );
  4836.                     m_dragLastPos = x;
  4837.                 }
  4838.                 break;
  4839.  
  4840.                 case WXGRID_CURSOR_SELECT_COL:
  4841.                     if ( (col = XToCol( x )) >= 0 )
  4842.                     {
  4843.                         if ( m_selection )
  4844.                         {
  4845.                             m_selection->SelectCol( col,
  4846.                                                     event.ControlDown(),
  4847.                                                     event.ShiftDown(),
  4848.                                                     event.AltDown(),
  4849.                                                     event.MetaDown() );
  4850.                         }
  4851.                     }
  4852.  
  4853.                 // default label to suppress warnings about "enumeration value
  4854.                 // 'xxx' not handled in switch
  4855.                 default:
  4856.                     break;
  4857.             }
  4858.         }
  4859.         return;
  4860.     }
  4861.  
  4862.     if ( m_isDragging && (event.Entering() || event.Leaving()) )
  4863.         return;
  4864.  
  4865.     if (m_isDragging)
  4866.     {
  4867.         if (m_colLabelWin->HasCapture()) m_colLabelWin->ReleaseMouse();
  4868.         m_isDragging = FALSE;
  4869.     }
  4870.  
  4871.     // ------------ Entering or leaving the window
  4872.     //
  4873.     if ( event.Entering() || event.Leaving() )
  4874.     {
  4875.         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
  4876.     }
  4877.  
  4878.  
  4879.     // ------------ Left button pressed
  4880.     //
  4881.     else if ( event.LeftDown() )
  4882.     {
  4883.         // don't send a label click event for a hit on the
  4884.         // edge of the col label - this is probably the user
  4885.         // wanting to resize the col
  4886.         //
  4887.         if ( XToEdgeOfCol(x) < 0 )
  4888.         {
  4889.             col = XToCol(x);
  4890.             if ( col >= 0  &&
  4891.                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
  4892.             {
  4893.                 if ( !event.ShiftDown() && !event.ControlDown() )
  4894.                     ClearSelection();
  4895.                 if ( m_selection )
  4896.                 {
  4897.                     if ( event.ShiftDown() )
  4898.                     {
  4899.                         m_selection->SelectBlock( 0,
  4900.                                                   m_currentCellCoords.GetCol(),
  4901.                                                   GetNumberRows() - 1, col,
  4902.                                                   event.ControlDown(),
  4903.                                                   event.ShiftDown(),
  4904.                                                   event.AltDown(),
  4905.                                                   event.MetaDown() );
  4906.                     }
  4907.                     else
  4908.                     {
  4909.                         m_selection->SelectCol( col,
  4910.                                                 event.ControlDown(),
  4911.                                                 event.ShiftDown(),
  4912.                                                 event.AltDown(),
  4913.                                                 event.MetaDown() );
  4914.                     }
  4915.                 }
  4916.  
  4917.                 ChangeCursorMode(WXGRID_CURSOR_SELECT_COL, m_colLabelWin);
  4918.             }
  4919.         }
  4920.         else
  4921.         {
  4922.             // starting to drag-resize a col
  4923.             //
  4924.             if ( CanDragColSize() )
  4925.                 ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin);
  4926.         }
  4927.     }
  4928.  
  4929.  
  4930.     // ------------ Left double click
  4931.     //
  4932.     if ( event.LeftDClick() )
  4933.     {
  4934.         if ( XToEdgeOfCol(x) < 0 )
  4935.         {
  4936.             col = XToCol(x);
  4937.             SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event );
  4938.         }
  4939.     }
  4940.  
  4941.  
  4942.     // ------------ Left button released
  4943.     //
  4944.     else if ( event.LeftUp() )
  4945.     {
  4946.         if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
  4947.         {
  4948.             DoEndDragResizeCol();
  4949.  
  4950.             // Note: we are ending the event *after* doing
  4951.             // default processing in this case
  4952.             //
  4953.             SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
  4954.         }
  4955.  
  4956.         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin);
  4957.         m_dragLastPos  = -1;
  4958.     }
  4959.  
  4960.  
  4961.     // ------------ Right button down
  4962.     //
  4963.     else if ( event.RightDown() )
  4964.     {
  4965.         col = XToCol(x);
  4966.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) )
  4967.         {
  4968.             // no default action at the moment
  4969.         }
  4970.     }
  4971.  
  4972.  
  4973.     // ------------ Right double click
  4974.     //
  4975.     else if ( event.RightDClick() )
  4976.     {
  4977.         col = XToCol(x);
  4978.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) )
  4979.         {
  4980.             // no default action at the moment
  4981.         }
  4982.     }
  4983.  
  4984.  
  4985.     // ------------ No buttons down and mouse moving
  4986.     //
  4987.     else if ( event.Moving() )
  4988.     {
  4989.         m_dragRowOrCol = XToEdgeOfCol( x );
  4990.         if ( m_dragRowOrCol >= 0 )
  4991.         {
  4992.             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  4993.             {
  4994.                 // don't capture the cursor yet
  4995.                 if ( CanDragColSize() )
  4996.                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, m_colLabelWin, FALSE);
  4997.             }
  4998.         }
  4999.         else if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
  5000.         {
  5001.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_colLabelWin, FALSE);
  5002.         }
  5003.     }
  5004. }
  5005.  
  5006.  
  5007. void wxGrid::ProcessCornerLabelMouseEvent( wxMouseEvent& event )
  5008. {
  5009.     if ( event.LeftDown() )
  5010.     {
  5011.         // indicate corner label by having both row and
  5012.         // col args == -1
  5013.         //
  5014.         if ( !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, -1, event ) )
  5015.         {
  5016.             SelectAll();
  5017.         }
  5018.     }
  5019.  
  5020.     else if ( event.LeftDClick() )
  5021.     {
  5022.         SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, -1, event );
  5023.     }
  5024.  
  5025.     else if ( event.RightDown() )
  5026.     {
  5027.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, -1, event ) )
  5028.         {
  5029.             // no default action at the moment
  5030.         }
  5031.     }
  5032.  
  5033.     else if ( event.RightDClick() )
  5034.     {
  5035.         if ( !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, -1, event ) )
  5036.         {
  5037.             // no default action at the moment
  5038.         }
  5039.     }
  5040. }
  5041.  
  5042. void wxGrid::ChangeCursorMode(CursorMode mode,
  5043.                               wxWindow *win,
  5044.                               bool captureMouse)
  5045. {
  5046. #ifdef __WXDEBUG__
  5047.     static const wxChar *cursorModes[] =
  5048.     {
  5049.         _T("SELECT_CELL"),
  5050.         _T("RESIZE_ROW"),
  5051.         _T("RESIZE_COL"),
  5052.         _T("SELECT_ROW"),
  5053.         _T("SELECT_COL")
  5054.     };
  5055.  
  5056.     wxLogTrace(_T("grid"),
  5057.                _T("wxGrid cursor mode (mouse capture for %s): %s -> %s"),
  5058.                win == m_colLabelWin ? _T("colLabelWin")
  5059.                                     : win ? _T("rowLabelWin")
  5060.                                           : _T("gridWin"),
  5061.                cursorModes[m_cursorMode], cursorModes[mode]);
  5062. #endif // __WXDEBUG__
  5063.  
  5064.     if ( mode == m_cursorMode &&
  5065.          win == m_winCapture &&
  5066.          captureMouse == (m_winCapture != NULL))
  5067.         return;
  5068.  
  5069.     if ( !win )
  5070.     {
  5071.         // by default use the grid itself
  5072.         win = m_gridWin;
  5073.     }
  5074.  
  5075.     if ( m_winCapture )
  5076.     {
  5077.         if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse();
  5078.         m_winCapture = (wxWindow *)NULL;
  5079.     }
  5080.  
  5081.     m_cursorMode = mode;
  5082.  
  5083.     switch ( m_cursorMode )
  5084.     {
  5085.         case WXGRID_CURSOR_RESIZE_ROW:
  5086.             win->SetCursor( m_rowResizeCursor );
  5087.             break;
  5088.  
  5089.         case WXGRID_CURSOR_RESIZE_COL:
  5090.             win->SetCursor( m_colResizeCursor );
  5091.             break;
  5092.  
  5093.         default:
  5094.             win->SetCursor( *wxSTANDARD_CURSOR );
  5095.     }
  5096.  
  5097.     // we need to capture mouse when resizing
  5098.     bool resize = m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ||
  5099.                   m_cursorMode == WXGRID_CURSOR_RESIZE_COL;
  5100.  
  5101.     if ( captureMouse && resize )
  5102.     {
  5103.         win->CaptureMouse();
  5104.         m_winCapture = win;
  5105.     }
  5106. }
  5107.  
  5108. void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
  5109. {
  5110.     int x, y;
  5111.     wxPoint pos( event.GetPosition() );
  5112.     CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
  5113.  
  5114.     wxGridCellCoords coords;
  5115.     XYToCell( x, y, coords );
  5116.  
  5117.     int cell_rows, cell_cols;
  5118.     GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols );
  5119.     if ((cell_rows < 0) || (cell_cols < 0))
  5120.     {
  5121.         coords.SetRow(coords.GetRow() + cell_rows);
  5122.         coords.SetCol(coords.GetCol() + cell_cols);
  5123.     }
  5124.  
  5125.     if ( event.Dragging() )
  5126.     {
  5127.         //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
  5128.  
  5129.         // Don't start doing anything until the mouse has been drug at
  5130.         // least 3 pixels in any direction...
  5131.         if (! m_isDragging)
  5132.         {
  5133.             if (m_startDragPos == wxDefaultPosition)
  5134.             {
  5135.                 m_startDragPos = pos;
  5136.                 return;
  5137.             }
  5138.             if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
  5139.                 return;
  5140.         }
  5141.  
  5142.         m_isDragging = TRUE;
  5143.         if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  5144.         {
  5145.             // Hide the edit control, so it
  5146.             // won't interfer with drag-shrinking.
  5147.             if ( IsCellEditControlShown() )
  5148.             {
  5149.                 HideCellEditControl();
  5150.                 SaveEditControlValue();
  5151.             }
  5152.  
  5153.             // Have we captured the mouse yet?
  5154.             if (! m_winCapture)
  5155.             {
  5156.                 m_winCapture = m_gridWin;
  5157.                 m_winCapture->CaptureMouse();
  5158.             }
  5159.  
  5160.             if ( coords != wxGridNoCellCoords )
  5161.             {
  5162.                 if ( event.ControlDown() )
  5163.                 {
  5164.                     if ( m_selectingKeyboard == wxGridNoCellCoords)
  5165.                         m_selectingKeyboard = coords;
  5166.                     HighlightBlock ( m_selectingKeyboard, coords );
  5167.                 }
  5168.                 else
  5169.                 {
  5170.                     if ( !IsSelection() )
  5171.                     {
  5172.                         HighlightBlock( coords, coords );
  5173.                     }
  5174.                     else
  5175.                     {
  5176.                         HighlightBlock( m_currentCellCoords, coords );
  5177.                     }
  5178.                 }
  5179.  
  5180.                 if (! IsVisible(coords))
  5181.                 {
  5182.                     MakeCellVisible(coords);
  5183.                     // TODO: need to introduce a delay or something here.  The
  5184.                     // scrolling is way to fast, at least on MSW - also on GTK.
  5185.                 }
  5186.             }
  5187.         }
  5188.         else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
  5189.         {
  5190.             int cw, ch, left, dummy;
  5191.             m_gridWin->GetClientSize( &cw, &ch );
  5192.             CalcUnscrolledPosition( 0, 0, &left, &dummy );
  5193.  
  5194.             wxClientDC dc( m_gridWin );
  5195.             PrepareDC( dc );
  5196.             y = wxMax( y, GetRowTop(m_dragRowOrCol) +
  5197.                           GetRowMinimalHeight(m_dragRowOrCol) );
  5198.             dc.SetLogicalFunction(wxINVERT);
  5199.             if ( m_dragLastPos >= 0 )
  5200.             {
  5201.                 dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
  5202.             }
  5203.             dc.DrawLine( left, y, left+cw, y );
  5204.             m_dragLastPos = y;
  5205.         }
  5206.         else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
  5207.         {
  5208.             int cw, ch, dummy, top;
  5209.             m_gridWin->GetClientSize( &cw, &ch );
  5210.             CalcUnscrolledPosition( 0, 0, &dummy, &top );
  5211.  
  5212.             wxClientDC dc( m_gridWin );
  5213.             PrepareDC( dc );
  5214.             x = wxMax( x, GetColLeft(m_dragRowOrCol) +
  5215.                           GetColMinimalWidth(m_dragRowOrCol) );
  5216.             dc.SetLogicalFunction(wxINVERT);
  5217.             if ( m_dragLastPos >= 0 )
  5218.             {
  5219.                 dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
  5220.             }
  5221.             dc.DrawLine( x, top, x, top+ch );
  5222.             m_dragLastPos = x;
  5223.         }
  5224.  
  5225.         return;
  5226.     }
  5227.  
  5228.     m_isDragging = FALSE;
  5229.     m_startDragPos = wxDefaultPosition;
  5230.  
  5231.     // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
  5232.     //     immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
  5233.     //     wxGTK
  5234. #if 0
  5235.     if ( event.Entering() || event.Leaving() )
  5236.     {
  5237.         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5238.         m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
  5239.     }
  5240.     else
  5241. #endif // 0
  5242.  
  5243.     // ------------ Left button pressed
  5244.     //
  5245.     if ( event.LeftDown() && coords != wxGridNoCellCoords )
  5246.     {
  5247.         if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
  5248.                        coords.GetRow(),
  5249.                        coords.GetCol(),
  5250.                        event ) )
  5251.         {
  5252.             if ( !event.ControlDown() )
  5253.                 ClearSelection();
  5254.             if ( event.ShiftDown() )
  5255.             {
  5256.                 if ( m_selection )
  5257.                 {
  5258.                     m_selection->SelectBlock( m_currentCellCoords.GetRow(),
  5259.                                               m_currentCellCoords.GetCol(),
  5260.                                               coords.GetRow(),
  5261.                                               coords.GetCol(),
  5262.                                               event.ControlDown(),
  5263.                                               event.ShiftDown(),
  5264.                                               event.AltDown(),
  5265.                                               event.MetaDown() );
  5266.                 }
  5267.             }
  5268.             else if ( XToEdgeOfCol(x) < 0  &&
  5269.                       YToEdgeOfRow(y) < 0 )
  5270.             {
  5271.                 DisableCellEditControl();
  5272.                 MakeCellVisible( coords );
  5273.  
  5274.                 // if this is the second click on this cell then start
  5275.                 // the edit control
  5276.                 if ( m_waitForSlowClick &&
  5277.                      (coords == m_currentCellCoords) &&
  5278.                      CanEnableCellControl())
  5279.                 {
  5280.                     EnableCellEditControl();
  5281.  
  5282.                     wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
  5283.                     wxGridCellEditor *editor = attr->GetEditor(this,
  5284.                                                                coords.GetRow(),
  5285.                                                                coords.GetCol());
  5286.                     editor->StartingClick();
  5287.                     editor->DecRef();
  5288.                     attr->DecRef();
  5289.  
  5290.                     m_waitForSlowClick = FALSE;
  5291.                 }
  5292.                 else
  5293.                 {
  5294.                     if ( event.ControlDown() )
  5295.                     {
  5296.                         if ( m_selection )
  5297.                         {
  5298.                             m_selection->ToggleCellSelection( coords.GetRow(),
  5299.                                                               coords.GetCol(),
  5300.                                                               event.ControlDown(),
  5301.                                                               event.ShiftDown(),
  5302.                                                               event.AltDown(),
  5303.                                                               event.MetaDown() );
  5304.                         }
  5305.                         m_selectingTopLeft = wxGridNoCellCoords;
  5306.                         m_selectingBottomRight = wxGridNoCellCoords;
  5307.                         m_selectingKeyboard = coords;
  5308.                     }
  5309.                     else
  5310.                     {
  5311.                         SetCurrentCell( coords );
  5312.                         if ( m_selection )
  5313.                         {
  5314.                             if ( m_selection->GetSelectionMode() !=
  5315.                                     wxGrid::wxGridSelectCells )
  5316.                             {
  5317.                                 HighlightBlock( coords, coords );
  5318.                             }
  5319.                         }
  5320.                     }
  5321.                     m_waitForSlowClick = TRUE;
  5322.                 }
  5323.             }
  5324.         }
  5325.     }
  5326.  
  5327.  
  5328.     // ------------ Left double click
  5329.     //
  5330.     else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
  5331.     {
  5332.         DisableCellEditControl();
  5333.  
  5334.         if ( XToEdgeOfCol(x) < 0  &&  YToEdgeOfRow(y) < 0 )
  5335.         {
  5336.             SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
  5337.                        coords.GetRow(),
  5338.                        coords.GetCol(),
  5339.                        event );
  5340.         }
  5341.     }
  5342.  
  5343.  
  5344.     // ------------ Left button released
  5345.     //
  5346.     else if ( event.LeftUp() )
  5347.     {
  5348.         if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  5349.         {
  5350.             if ( m_selectingTopLeft != wxGridNoCellCoords &&
  5351.                  m_selectingBottomRight != wxGridNoCellCoords )
  5352.             {
  5353.                 if (m_winCapture)
  5354.                 {
  5355.                     if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse();
  5356.                     m_winCapture = NULL;
  5357.                 }
  5358.  
  5359.                 if ( m_selection )
  5360.                 {
  5361.                     m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
  5362.                                               m_selectingTopLeft.GetCol(),
  5363.                                               m_selectingBottomRight.GetRow(),
  5364.                                               m_selectingBottomRight.GetCol(),
  5365.                                               event.ControlDown(),
  5366.                                               event.ShiftDown(),
  5367.                                               event.AltDown(),
  5368.                                               event.MetaDown() );
  5369.                 }
  5370.  
  5371.                 m_selectingTopLeft = wxGridNoCellCoords;
  5372.                 m_selectingBottomRight = wxGridNoCellCoords;
  5373.             }
  5374.  
  5375.             // Show the edit control, if it has been hidden for
  5376.             // drag-shrinking.
  5377.             ShowCellEditControl();
  5378.         }
  5379.         else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
  5380.         {
  5381.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5382.             DoEndDragResizeRow();
  5383.  
  5384.             // Note: we are ending the event *after* doing
  5385.             // default processing in this case
  5386.             //
  5387.             SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
  5388.         }
  5389.         else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
  5390.         {
  5391.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5392.             DoEndDragResizeCol();
  5393.  
  5394.             // Note: we are ending the event *after* doing
  5395.             // default processing in this case
  5396.             //
  5397.             SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
  5398.         }
  5399.  
  5400.         m_dragLastPos = -1;
  5401.     }
  5402.  
  5403.  
  5404.     // ------------ Right button down
  5405.     //
  5406.     else if ( event.RightDown() && coords != wxGridNoCellCoords )
  5407.     {
  5408.         DisableCellEditControl();
  5409.         if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
  5410.                          coords.GetRow(),
  5411.                          coords.GetCol(),
  5412.                          event ) )
  5413.         {
  5414.             // no default action at the moment
  5415.         }
  5416.     }
  5417.  
  5418.  
  5419.     // ------------ Right double click
  5420.     //
  5421.     else if ( event.RightDClick() && coords != wxGridNoCellCoords )
  5422.     {
  5423.         DisableCellEditControl();
  5424.         if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
  5425.                          coords.GetRow(),
  5426.                          coords.GetCol(),
  5427.                          event ) )
  5428.         {
  5429.             // no default action at the moment
  5430.         }
  5431.     }
  5432.  
  5433.     // ------------ Moving and no button action
  5434.     //
  5435.     else if ( event.Moving() && !event.IsButton() )
  5436.     {
  5437.         if( coords.GetRow() < 0 || coords.GetCol() < 0 )
  5438.         {
  5439.             // out of grid cell area
  5440.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5441.             return;
  5442.         }
  5443.  
  5444.         int dragRow = YToEdgeOfRow( y );
  5445.         int dragCol = XToEdgeOfCol( x );
  5446.  
  5447.         // Dragging on the corner of a cell to resize in both
  5448.         // directions is not implemented yet...
  5449.         //
  5450.         if ( dragRow >= 0  &&  dragCol >= 0 )
  5451.         {
  5452.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5453.             return;
  5454.         }
  5455.  
  5456.         if ( dragRow >= 0 )
  5457.         {
  5458.             m_dragRowOrCol = dragRow;
  5459.  
  5460.             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  5461.             {
  5462.                 if ( CanDragRowSize() && CanDragGridSize() )
  5463.                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW);
  5464.             }
  5465.  
  5466.             if ( dragCol >= 0 )
  5467.             {
  5468.                 m_dragRowOrCol = dragCol;
  5469.             }
  5470.  
  5471.             return;
  5472.         }
  5473.  
  5474.         if ( dragCol >= 0 )
  5475.         {
  5476.             m_dragRowOrCol = dragCol;
  5477.  
  5478.             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
  5479.             {
  5480.                 if ( CanDragColSize() && CanDragGridSize() )
  5481.                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL);
  5482.             }
  5483.  
  5484.             return;
  5485.         }
  5486.  
  5487.         // Neither on a row or col edge
  5488.         //
  5489.         if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
  5490.         {
  5491.             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
  5492.         }
  5493.     }
  5494. }
  5495.  
  5496.  
  5497. void wxGrid::DoEndDragResizeRow()
  5498. {
  5499.     if ( m_dragLastPos >= 0 )
  5500.     {
  5501.         // erase the last line and resize the row
  5502.         //
  5503.         int cw, ch, left, dummy;
  5504.         m_gridWin->GetClientSize( &cw, &ch );
  5505.         CalcUnscrolledPosition( 0, 0, &left, &dummy );
  5506.  
  5507.         wxClientDC dc( m_gridWin );
  5508.         PrepareDC( dc );
  5509.         dc.SetLogicalFunction( wxINVERT );
  5510.         dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
  5511.         HideCellEditControl();
  5512.         SaveEditControlValue();
  5513.  
  5514.         int rowTop = GetRowTop(m_dragRowOrCol);
  5515.         SetRowSize( m_dragRowOrCol,
  5516.                     wxMax( m_dragLastPos - rowTop, WXGRID_MIN_ROW_HEIGHT ) );
  5517.  
  5518.         if ( !GetBatchCount() )
  5519.         {
  5520.             // Only needed to get the correct rect.y:
  5521.             wxRect rect ( CellToRect( m_dragRowOrCol, 0 ) );
  5522.             rect.x = 0;
  5523.             CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
  5524.             rect.width = m_rowLabelWidth;
  5525.             rect.height = ch - rect.y;
  5526.             m_rowLabelWin->Refresh( TRUE, &rect );
  5527.             rect.width = cw;
  5528.             // if there is a multicell block, paint all of it
  5529.             if (m_table)
  5530.             {
  5531.                 int i, cell_rows, cell_cols, subtract_rows = 0;
  5532.                 int leftCol = XToCol(left);
  5533.                 int rightCol = XToCol(left+cw);
  5534.                 if (leftCol >= 0)
  5535.                 {
  5536.                     if (rightCol < 0) rightCol = m_numCols;
  5537.                     for (i=leftCol; i<rightCol; i++)
  5538.                     {
  5539.                         GetCellSize(m_dragRowOrCol, i, &cell_rows, &cell_cols);
  5540.                         if (cell_rows < subtract_rows)
  5541.                             subtract_rows = cell_rows;
  5542.                     }
  5543.                     rect.y = GetRowTop(m_dragRowOrCol + subtract_rows);
  5544.                     CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
  5545.                     rect.height = ch - rect.y;
  5546.                 }
  5547.             }
  5548.             m_gridWin->Refresh( FALSE, &rect );
  5549.         }
  5550.  
  5551.         ShowCellEditControl();
  5552.     }
  5553. }
  5554.  
  5555.  
  5556. void wxGrid::DoEndDragResizeCol()
  5557. {
  5558.     if ( m_dragLastPos >= 0 )
  5559.     {
  5560.         // erase the last line and resize the col
  5561.         //
  5562.         int cw, ch, dummy, top;
  5563.         m_gridWin->GetClientSize( &cw, &ch );
  5564.         CalcUnscrolledPosition( 0, 0, &dummy, &top );
  5565.  
  5566.         wxClientDC dc( m_gridWin );
  5567.         PrepareDC( dc );
  5568.         dc.SetLogicalFunction( wxINVERT );
  5569.         dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top+ch );
  5570.         HideCellEditControl();
  5571.         SaveEditControlValue();
  5572.  
  5573.         int colLeft = GetColLeft(m_dragRowOrCol);
  5574.         SetColSize( m_dragRowOrCol,
  5575.                     wxMax( m_dragLastPos - colLeft,
  5576.                            GetColMinimalWidth(m_dragRowOrCol) ) );
  5577.  
  5578.         if ( !GetBatchCount() )
  5579.         {
  5580.             // Only needed to get the correct rect.x:
  5581.             wxRect rect ( CellToRect( 0, m_dragRowOrCol ) );
  5582.             rect.y = 0;
  5583.             CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
  5584.             rect.width = cw - rect.x;
  5585.             rect.height = m_colLabelHeight;
  5586.             m_colLabelWin->Refresh( TRUE, &rect );
  5587.             rect.height = ch;
  5588.             // if there is a multicell block, paint all of it
  5589.             if (m_table)
  5590.             {
  5591.                 int i, cell_rows, cell_cols, subtract_cols = 0;
  5592.                 int topRow = YToRow(top);
  5593.                 int bottomRow = YToRow(top+cw);
  5594.                 if (topRow >= 0)
  5595.                 {
  5596.                     if (bottomRow < 0) bottomRow = m_numRows;
  5597.                     for (i=topRow; i<bottomRow; i++)
  5598.                     {
  5599.                         GetCellSize(i, m_dragRowOrCol, &cell_rows, &cell_cols);
  5600.                         if (cell_cols < subtract_cols)
  5601.                             subtract_cols = cell_cols;
  5602.                     }
  5603.                     rect.x = GetColLeft(m_dragRowOrCol + subtract_cols);
  5604.                     CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
  5605.                     rect.width = cw - rect.x;
  5606.                 }
  5607.             }
  5608.             m_gridWin->Refresh( FALSE, &rect );
  5609.         }
  5610.  
  5611.         ShowCellEditControl();
  5612.     }
  5613. }
  5614.  
  5615.  
  5616.  
  5617. //
  5618. // ------ interaction with data model
  5619. //
  5620. bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg )
  5621. {
  5622.     switch ( msg.GetId() )
  5623.     {
  5624.         case wxGRIDTABLE_REQUEST_VIEW_GET_VALUES:
  5625.             return GetModelValues();
  5626.  
  5627.         case wxGRIDTABLE_REQUEST_VIEW_SEND_VALUES:
  5628.             return SetModelValues();
  5629.  
  5630.         case wxGRIDTABLE_NOTIFY_ROWS_INSERTED:
  5631.         case wxGRIDTABLE_NOTIFY_ROWS_APPENDED:
  5632.         case wxGRIDTABLE_NOTIFY_ROWS_DELETED:
  5633.         case wxGRIDTABLE_NOTIFY_COLS_INSERTED:
  5634.         case wxGRIDTABLE_NOTIFY_COLS_APPENDED:
  5635.         case wxGRIDTABLE_NOTIFY_COLS_DELETED:
  5636.             return Redimension( msg );
  5637.  
  5638.         default:
  5639.             return FALSE;
  5640.     }
  5641. }
  5642.  
  5643.  
  5644.  
  5645. // The behaviour of this function depends on the grid table class
  5646. // Clear() function.  For the default wxGridStringTable class the
  5647. // behavious is to replace all cell contents with wxEmptyString but
  5648. // not to change the number of rows or cols.
  5649. //
  5650. void wxGrid::ClearGrid()
  5651. {
  5652.     if ( m_table )
  5653.     {
  5654.         if (IsCellEditControlEnabled())
  5655.             DisableCellEditControl();
  5656.  
  5657.         m_table->Clear();
  5658.         if ( !GetBatchCount() ) m_gridWin->Refresh();
  5659.     }
  5660. }
  5661.  
  5662.  
  5663. bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
  5664. {
  5665.     // TODO: something with updateLabels flag
  5666.  
  5667.     if ( !m_created )
  5668.     {
  5669.         wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") );
  5670.         return FALSE;
  5671.     }
  5672.  
  5673.     if ( m_table )
  5674.     {
  5675.         if (IsCellEditControlEnabled())
  5676.             DisableCellEditControl();
  5677.  
  5678.         return m_table->InsertRows( pos, numRows );
  5679.  
  5680.         // the table will have sent the results of the insert row
  5681.         // operation to this view object as a grid table message
  5682.     }
  5683.     return FALSE;
  5684. }
  5685.  
  5686.  
  5687. bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) )
  5688. {
  5689.     // TODO: something with updateLabels flag
  5690.  
  5691.     if ( !m_created )
  5692.     {
  5693.         wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") );
  5694.         return FALSE;
  5695.     }
  5696.  
  5697.     return ( m_table && m_table->AppendRows( numRows ) );
  5698.     // the table will have sent the results of the append row
  5699.     // operation to this view object as a grid table message
  5700. }
  5701.  
  5702.  
  5703. bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) )
  5704. {
  5705.     // TODO: something with updateLabels flag
  5706.  
  5707.     if ( !m_created )
  5708.     {
  5709.         wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") );
  5710.         return FALSE;
  5711.     }
  5712.  
  5713.     if ( m_table )
  5714.     {
  5715.         if (IsCellEditControlEnabled())
  5716.             DisableCellEditControl();
  5717.  
  5718.         return (m_table->DeleteRows( pos, numRows ));
  5719.         // the table will have sent the results of the delete row
  5720.         // operation to this view object as a grid table message
  5721.     }
  5722.     return FALSE;
  5723. }
  5724.  
  5725.  
  5726. bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
  5727. {
  5728.     // TODO: something with updateLabels flag
  5729.  
  5730.     if ( !m_created )
  5731.     {
  5732.         wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") );
  5733.         return FALSE;
  5734.     }
  5735.  
  5736.     if ( m_table )
  5737.     {
  5738.         if (IsCellEditControlEnabled())
  5739.             DisableCellEditControl();
  5740.  
  5741.         return m_table->InsertCols( pos, numCols );
  5742.         // the table will have sent the results of the insert col
  5743.         // operation to this view object as a grid table message
  5744.     }
  5745.     return FALSE;
  5746. }
  5747.  
  5748.  
  5749. bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) )
  5750. {
  5751.     // TODO: something with updateLabels flag
  5752.  
  5753.     if ( !m_created )
  5754.     {
  5755.         wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") );
  5756.         return FALSE;
  5757.     }
  5758.  
  5759.     return ( m_table && m_table->AppendCols( numCols ) );
  5760.     // the table will have sent the results of the append col
  5761.     // operation to this view object as a grid table message
  5762. }
  5763.  
  5764.  
  5765. bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) )
  5766. {
  5767.     // TODO: something with updateLabels flag
  5768.  
  5769.     if ( !m_created )
  5770.     {
  5771.         wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") );
  5772.         return FALSE;
  5773.     }
  5774.  
  5775.     if ( m_table )
  5776.     {
  5777.         if (IsCellEditControlEnabled())
  5778.             DisableCellEditControl();
  5779.  
  5780.         return ( m_table->DeleteCols( pos, numCols ) );
  5781.         // the table will have sent the results of the delete col
  5782.         // operation to this view object as a grid table message
  5783.     }
  5784.     return FALSE;
  5785. }
  5786.  
  5787.  
  5788.  
  5789. //
  5790. // ----- event handlers
  5791. //
  5792.  
  5793. // Generate a grid event based on a mouse event and
  5794. // return the result of ProcessEvent()
  5795. //
  5796. int wxGrid::SendEvent( const wxEventType type,
  5797.                         int row, int col,
  5798.                         wxMouseEvent& mouseEv )
  5799. {
  5800.    bool claimed;
  5801.    bool vetoed= FALSE;
  5802.  
  5803.    if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
  5804.    {
  5805.        int rowOrCol = (row == -1 ? col : row);
  5806.  
  5807.        wxGridSizeEvent gridEvt( GetId(),
  5808.                type,
  5809.                this,
  5810.                rowOrCol,
  5811.                mouseEv.GetX() + GetRowLabelSize(),
  5812.                mouseEv.GetY() + GetColLabelSize(),
  5813.                mouseEv.ControlDown(),
  5814.                mouseEv.ShiftDown(),
  5815.                mouseEv.AltDown(),
  5816.                mouseEv.MetaDown() );
  5817.  
  5818.        claimed = GetEventHandler()->ProcessEvent(gridEvt);
  5819.        vetoed = !gridEvt.IsAllowed();
  5820.    }
  5821.    else if ( type == wxEVT_GRID_RANGE_SELECT )
  5822.    {
  5823.        // Right now, it should _never_ end up here!
  5824.        wxGridRangeSelectEvent gridEvt( GetId(),
  5825.                type,
  5826.                this,
  5827.                m_selectingTopLeft,
  5828.                m_selectingBottomRight,
  5829.                TRUE,
  5830.                mouseEv.ControlDown(),
  5831.                mouseEv.ShiftDown(),
  5832.                mouseEv.AltDown(),
  5833.                mouseEv.MetaDown() );
  5834.  
  5835.        claimed = GetEventHandler()->ProcessEvent(gridEvt);
  5836.        vetoed = !gridEvt.IsAllowed();
  5837.    }
  5838.    else
  5839.    {
  5840.        wxGridEvent gridEvt( GetId(),
  5841.                type,
  5842.                this,
  5843.                row, col,
  5844.                mouseEv.GetX() + GetRowLabelSize(),
  5845.                mouseEv.GetY() + GetColLabelSize(),
  5846.                FALSE,
  5847.                mouseEv.ControlDown(),
  5848.                mouseEv.ShiftDown(),
  5849.                mouseEv.AltDown(),
  5850.                mouseEv.MetaDown() );
  5851.        claimed = GetEventHandler()->ProcessEvent(gridEvt);
  5852.        vetoed = !gridEvt.IsAllowed();
  5853.    }
  5854.  
  5855.    // A Veto'd event may not be `claimed' so test this first
  5856.    if (vetoed) return -1;
  5857.    return claimed ? 1 : 0;
  5858. }
  5859.  
  5860.  
  5861. // Generate a grid event of specified type and return the result
  5862. // of ProcessEvent().
  5863. //
  5864. int wxGrid::SendEvent( const wxEventType type,
  5865.                         int row, int col )
  5866. {
  5867.    bool claimed;
  5868.    bool vetoed= FALSE;
  5869.  
  5870.     if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
  5871.     {
  5872.         int rowOrCol = (row == -1 ? col : row);
  5873.  
  5874.         wxGridSizeEvent gridEvt( GetId(),
  5875.                                  type,
  5876.                                  this,
  5877.                                  rowOrCol );
  5878.  
  5879.         claimed = GetEventHandler()->ProcessEvent(gridEvt);
  5880.         vetoed  = !gridEvt.IsAllowed();
  5881.     }
  5882.     else
  5883.     {
  5884.         wxGridEvent gridEvt( GetId(),
  5885.                              type,
  5886.                              this,
  5887.                              row, col );
  5888.  
  5889.         claimed = GetEventHandler()->ProcessEvent(gridEvt);
  5890.         vetoed  = !gridEvt.IsAllowed();
  5891.      }
  5892.  
  5893.     // A Veto'd event may not be `claimed' so test this first
  5894.     if (vetoed) return -1;
  5895.     return claimed ? 1 : 0;
  5896. }
  5897.  
  5898.  
  5899. void wxGrid::OnPaint( wxPaintEvent& WXUNUSED(event) )
  5900. {
  5901.     wxPaintDC dc(this);  // needed to prevent zillions of paint events on MSW
  5902. }
  5903.  
  5904. void wxGrid::Refresh(bool eraseb, const wxRect* rect)
  5905. {
  5906.     // Don't do anything if between Begin/EndBatch...
  5907.     // EndBatch() will do all this on the last nested one anyway.
  5908.     if (! GetBatchCount())
  5909.     {
  5910.         // Refresh to get correct scrolled position:
  5911.         wxScrolledWindow::Refresh(eraseb,rect);
  5912.  
  5913.         if (rect)
  5914.         {
  5915.             int rect_x, rect_y, rectWidth, rectHeight;
  5916.             int width_label, width_cell, height_label, height_cell;
  5917.             int x, y;
  5918.  
  5919.             //Copy rectangle can get scroll offsets..
  5920.             rect_x = rect->GetX();
  5921.             rect_y = rect->GetY();
  5922.             rectWidth = rect->GetWidth();
  5923.             rectHeight = rect->GetHeight();
  5924.  
  5925.             width_label = m_rowLabelWidth - rect_x;
  5926.             if (width_label > rectWidth) width_label = rectWidth;
  5927.  
  5928.             height_label = m_colLabelHeight - rect_y;
  5929.             if (height_label > rectHeight) height_label = rectHeight;
  5930.  
  5931.             if (rect_x > m_rowLabelWidth)
  5932.             {
  5933.                 x = rect_x - m_rowLabelWidth;
  5934.                 width_cell = rectWidth;
  5935.             }
  5936.             else
  5937.             {
  5938.                 x = 0;
  5939.                 width_cell = rectWidth - (m_rowLabelWidth - rect_x);
  5940.             }
  5941.  
  5942.             if (rect_y > m_colLabelHeight)
  5943.             {
  5944.                 y = rect_y - m_colLabelHeight;
  5945.                 height_cell = rectHeight;
  5946.             }
  5947.             else
  5948.             {
  5949.                 y = 0;
  5950.                 height_cell = rectHeight - (m_colLabelHeight - rect_y);
  5951.             }
  5952.  
  5953.             // Paint corner label part intersecting rect.
  5954.             if ( width_label > 0 && height_label > 0 )
  5955.             {
  5956.                 wxRect anotherrect(rect_x, rect_y, width_label, height_label);
  5957.                 m_cornerLabelWin->Refresh(eraseb, &anotherrect);
  5958.             }
  5959.  
  5960.             // Paint col labels part intersecting rect.
  5961.             if ( width_cell > 0 && height_label > 0 )
  5962.             {
  5963.                 wxRect anotherrect(x, rect_y, width_cell, height_label);
  5964.                 m_colLabelWin->Refresh(eraseb, &anotherrect);
  5965.             }
  5966.  
  5967.             // Paint row labels part intersecting rect.
  5968.             if ( width_label > 0 && height_cell > 0 )
  5969.             {
  5970.                 wxRect anotherrect(rect_x, y, width_label, height_cell);
  5971.                 m_rowLabelWin->Refresh(eraseb, &anotherrect);
  5972.             }
  5973.  
  5974.             // Paint cell area part intersecting rect.
  5975.             if ( width_cell > 0 && height_cell > 0 )
  5976.             {
  5977.                 wxRect anotherrect(x, y, width_cell, height_cell);
  5978.                 m_gridWin->Refresh(eraseb, &anotherrect);
  5979.             }
  5980.         }
  5981.         else
  5982.         {
  5983.             m_cornerLabelWin->Refresh(eraseb, NULL);
  5984.             m_colLabelWin->Refresh(eraseb, NULL);
  5985.             m_rowLabelWin->Refresh(eraseb, NULL);
  5986.             m_gridWin->Refresh(eraseb, NULL);
  5987.         }
  5988.     }
  5989. }
  5990.  
  5991. void wxGrid::OnSize( wxSizeEvent& event )
  5992. {
  5993.     // position the child windows
  5994.     CalcWindowSizes();
  5995.  
  5996.     // don't call CalcDimensions() from here, the base class handles the size
  5997.     // changes itself
  5998.     event.Skip();
  5999. }
  6000.  
  6001.  
  6002. void wxGrid::OnKeyDown( wxKeyEvent& event )
  6003. {
  6004.     if ( m_inOnKeyDown )
  6005.     {
  6006.         // shouldn't be here - we are going round in circles...
  6007.         //
  6008.         wxFAIL_MSG( wxT("wxGrid::OnKeyDown called while already active") );
  6009.     }
  6010.  
  6011.     m_inOnKeyDown = TRUE;
  6012.  
  6013.     // propagate the event up and see if it gets processed
  6014.     //
  6015.     wxWindow *parent = GetParent();
  6016.     wxKeyEvent keyEvt( event );
  6017.     keyEvt.SetEventObject( parent );
  6018.  
  6019.     if ( !parent->GetEventHandler()->ProcessEvent( keyEvt ) )
  6020.     {
  6021.  
  6022.         // try local handlers
  6023.         //
  6024.         switch ( event.KeyCode() )
  6025.         {
  6026.             case WXK_UP:
  6027.                 if ( event.ControlDown() )
  6028.                 {
  6029.                     MoveCursorUpBlock( event.ShiftDown() );
  6030.                 }
  6031.                 else
  6032.                 {
  6033.                     MoveCursorUp( event.ShiftDown() );
  6034.                 }
  6035.                 break;
  6036.  
  6037.             case WXK_DOWN:
  6038.                 if ( event.ControlDown() )
  6039.                 {
  6040.                     MoveCursorDownBlock( event.ShiftDown() );
  6041.                 }
  6042.                 else
  6043.                 {
  6044.                     MoveCursorDown( event.ShiftDown() );
  6045.                 }
  6046.                 break;
  6047.  
  6048.             case WXK_LEFT:
  6049.                 if ( event.ControlDown() )
  6050.                 {
  6051.                     MoveCursorLeftBlock( event.ShiftDown() );
  6052.                 }
  6053.                 else
  6054.                 {
  6055.                     MoveCursorLeft( event.ShiftDown() );
  6056.                 }
  6057.                 break;
  6058.  
  6059.             case WXK_RIGHT:
  6060.                 if ( event.ControlDown() )
  6061.                 {
  6062.                     MoveCursorRightBlock( event.ShiftDown() );
  6063.                 }
  6064.                 else
  6065.                 {
  6066.                     MoveCursorRight( event.ShiftDown() );
  6067.                 }
  6068.                 break;
  6069.  
  6070.             case WXK_RETURN:
  6071.             case WXK_NUMPAD_ENTER:
  6072.                 if ( event.ControlDown() )
  6073.                 {
  6074.                     event.Skip();  // to let the edit control have the return
  6075.                 }
  6076.                 else
  6077.                 {
  6078.                     if ( GetGridCursorRow() < GetNumberRows()-1 )
  6079.                     {
  6080.                         MoveCursorDown( event.ShiftDown() );
  6081.                     }
  6082.                     else
  6083.                     {
  6084.                         // at the bottom of a column
  6085.                         HideCellEditControl();
  6086.                         SaveEditControlValue();
  6087.                     }
  6088.                 }
  6089.                 break;
  6090.  
  6091.             case WXK_ESCAPE:
  6092.                 ClearSelection();
  6093.                 break;
  6094.  
  6095.             case WXK_TAB:
  6096.                 if (event.ShiftDown())
  6097.                 {
  6098.                     if ( GetGridCursorCol() > 0 )
  6099.                     {
  6100.                         MoveCursorLeft( FALSE );
  6101.                     }
  6102.                     else
  6103.                     {
  6104.                         // at left of grid
  6105.                         HideCellEditControl();
  6106.                         SaveEditControlValue();
  6107.                     }
  6108.                 }
  6109.                 else
  6110.                 {
  6111.                     if ( GetGridCursorCol() < GetNumberCols()-1 )
  6112.                     {
  6113.                         MoveCursorRight( FALSE );
  6114.                     }
  6115.                     else
  6116.                     {
  6117.                         // at right of grid
  6118.                         HideCellEditControl();
  6119.                         SaveEditControlValue();
  6120.                     }
  6121.                 }
  6122.                 break;
  6123.  
  6124.             case WXK_HOME:
  6125.                 if ( event.ControlDown() )
  6126.                 {
  6127.                     MakeCellVisible( 0, 0 );
  6128.                     SetCurrentCell( 0, 0 );
  6129.                 }
  6130.                 else
  6131.                 {
  6132.                     event.Skip();
  6133.                 }
  6134.                 break;
  6135.  
  6136.             case WXK_END:
  6137.                 if ( event.ControlDown() )
  6138.                 {
  6139.                     MakeCellVisible( m_numRows-1, m_numCols-1 );
  6140.                     SetCurrentCell( m_numRows-1, m_numCols-1 );
  6141.                 }
  6142.                 else
  6143.                 {
  6144.                     event.Skip();
  6145.                 }
  6146.                 break;
  6147.  
  6148.             case WXK_PRIOR:
  6149.                 MovePageUp();
  6150.                 break;
  6151.  
  6152.             case WXK_NEXT:
  6153.                 MovePageDown();
  6154.                 break;
  6155.  
  6156.             case WXK_SPACE:
  6157.                 if ( event.ControlDown() )
  6158.                 {
  6159.                     if ( m_selection )
  6160.                     {
  6161.                         m_selection->ToggleCellSelection( m_currentCellCoords.GetRow(),
  6162.                                                           m_currentCellCoords.GetCol(),
  6163.                                                           event.ControlDown(),
  6164.                                                           event.ShiftDown(),
  6165.                                                           event.AltDown(),
  6166.                                                           event.MetaDown() );
  6167.                     }
  6168.                     break;
  6169.                 }
  6170.                 if ( !IsEditable() )
  6171.                 {
  6172.                     MoveCursorRight( FALSE );
  6173.                     break;
  6174.                 }
  6175.                 // Otherwise fall through to default
  6176.  
  6177.             default:
  6178.                 // is it possible to edit the current cell at all?
  6179.                 if ( !IsCellEditControlEnabled() && CanEnableCellControl() )
  6180.                 {
  6181.                     // yes, now check whether the cells editor accepts the key
  6182.                     int row = m_currentCellCoords.GetRow();
  6183.                     int col = m_currentCellCoords.GetCol();
  6184.                     wxGridCellAttr* attr = GetCellAttr(row, col);
  6185.                     wxGridCellEditor *editor = attr->GetEditor(this, row, col);
  6186.  
  6187.                     // <F2> is special and will always start editing, for
  6188.                     // other keys - ask the editor itself
  6189.                     if ( (event.KeyCode() == WXK_F2 && !event.HasModifiers())
  6190.                          || editor->IsAcceptedKey(event) )
  6191.                     {
  6192.                         // ensure cell is visble
  6193.                         MakeCellVisible(row, col);
  6194.                         EnableCellEditControl();
  6195.  
  6196.                         // a problem can arise if the cell is not completely
  6197.                         // visible (even after calling MakeCellVisible the
  6198.                         // control is not created and calling StartingKey will
  6199.                         // crash the app
  6200.                         if( editor->IsCreated() && m_cellEditCtrlEnabled ) editor->StartingKey(event);
  6201.                     }
  6202.                     else
  6203.                     {
  6204.                         event.Skip();
  6205.                     }
  6206.  
  6207.                     editor->DecRef();
  6208.                     attr->DecRef();
  6209.                 }
  6210.                 else
  6211.                 {
  6212.                     // let others process char events with modifiers or all
  6213.                     // char events for readonly cells
  6214.                     event.Skip();
  6215.                 }
  6216.                 break;
  6217.         }
  6218.     }
  6219.  
  6220.     m_inOnKeyDown = FALSE;
  6221. }
  6222.  
  6223. void wxGrid::OnKeyUp( wxKeyEvent& event )
  6224. {
  6225.     // try local handlers
  6226.     //
  6227.     if ( event.KeyCode() == WXK_SHIFT )
  6228.     {
  6229.         if ( m_selectingTopLeft != wxGridNoCellCoords &&
  6230.              m_selectingBottomRight != wxGridNoCellCoords )
  6231.         {
  6232.             if ( m_selection )
  6233.             {
  6234.                 m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
  6235.                                           m_selectingTopLeft.GetCol(),
  6236.                                           m_selectingBottomRight.GetRow(),
  6237.                                           m_selectingBottomRight.GetCol(),
  6238.                                           event.ControlDown(),
  6239.                                           TRUE,
  6240.                                           event.AltDown(),
  6241.                                           event.MetaDown() );
  6242.             }
  6243.         }
  6244.  
  6245.         m_selectingTopLeft = wxGridNoCellCoords;
  6246.         m_selectingBottomRight = wxGridNoCellCoords;
  6247.         m_selectingKeyboard = wxGridNoCellCoords;
  6248.     }
  6249. }
  6250.  
  6251. void wxGrid::OnEraseBackground(wxEraseEvent&)
  6252. {
  6253. }
  6254.  
  6255. void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
  6256. {
  6257.     if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
  6258.     {
  6259.         // the event has been intercepted - do nothing
  6260.         return;
  6261.     }
  6262.  
  6263.     wxClientDC dc(m_gridWin);
  6264.     PrepareDC(dc);
  6265.  
  6266.     if ( m_currentCellCoords != wxGridNoCellCoords )
  6267.     {
  6268.         HideCellEditControl();
  6269.         DisableCellEditControl();
  6270.  
  6271.         if ( IsVisible( m_currentCellCoords, FALSE ) )
  6272.         {
  6273.             wxRect r;
  6274.             r = BlockToDeviceRect(m_currentCellCoords, m_currentCellCoords);
  6275.             if ( !m_gridLinesEnabled )
  6276.             {
  6277.                 r.x--;
  6278.                 r.y--;
  6279.                 r.width++;
  6280.                 r.height++;
  6281.             }
  6282.  
  6283.             wxGridCellCoordsArray cells = CalcCellsExposed( r );
  6284.  
  6285.             // Otherwise refresh redraws the highlight!
  6286.             m_currentCellCoords = coords;
  6287.  
  6288.             DrawGridCellArea(dc,cells);
  6289.             DrawAllGridLines( dc, r );
  6290.         }
  6291.     }
  6292.  
  6293.     m_currentCellCoords = coords;
  6294.  
  6295.     wxGridCellAttr* attr = GetCellAttr(coords);
  6296.     DrawCellHighlight(dc, attr);
  6297.     attr->DecRef();
  6298. }
  6299.  
  6300.  
  6301. void wxGrid::HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol )
  6302. {
  6303.     int temp;
  6304.     wxGridCellCoords updateTopLeft, updateBottomRight;
  6305.  
  6306.     if ( m_selection )
  6307.     {
  6308.         if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
  6309.         {
  6310.             leftCol = 0;
  6311.             rightCol = GetNumberCols() - 1;
  6312.         }
  6313.         else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
  6314.         {
  6315.             topRow = 0;
  6316.             bottomRow = GetNumberRows() - 1;
  6317.         }
  6318.     }
  6319.  
  6320.     if ( topRow > bottomRow )
  6321.     {
  6322.         temp = topRow;
  6323.         topRow = bottomRow;
  6324.         bottomRow = temp;
  6325.     }
  6326.  
  6327.     if ( leftCol > rightCol )
  6328.     {
  6329.         temp = leftCol;
  6330.         leftCol = rightCol;
  6331.         rightCol = temp;
  6332.     }
  6333.  
  6334.     updateTopLeft = wxGridCellCoords( topRow, leftCol );
  6335.     updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
  6336.  
  6337.     // First the case that we selected a completely new area
  6338.     if ( m_selectingTopLeft == wxGridNoCellCoords ||
  6339.          m_selectingBottomRight == wxGridNoCellCoords )
  6340.     {
  6341.         wxRect rect;
  6342.         rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ),
  6343.                                   wxGridCellCoords ( bottomRow, rightCol ) );
  6344.         m_gridWin->Refresh( FALSE, &rect );
  6345.     }
  6346.     // Now handle changing an existing selection area.
  6347.     else if ( m_selectingTopLeft != updateTopLeft ||
  6348.               m_selectingBottomRight != updateBottomRight )
  6349.     {
  6350.         // Compute two optimal update rectangles:
  6351.         // Either one rectangle is a real subset of the
  6352.         // other, or they are (almost) disjoint!
  6353.         wxRect  rect[4];
  6354.         bool    need_refresh[4];
  6355.         need_refresh[0] =
  6356.         need_refresh[1] =
  6357.         need_refresh[2] =
  6358.         need_refresh[3] = FALSE;
  6359.         int     i;
  6360.  
  6361.         // Store intermediate values
  6362.         wxCoord oldLeft   = m_selectingTopLeft.GetCol();
  6363.         wxCoord oldTop    = m_selectingTopLeft.GetRow();
  6364.         wxCoord oldRight  = m_selectingBottomRight.GetCol();
  6365.         wxCoord oldBottom = m_selectingBottomRight.GetRow();
  6366.  
  6367.         // Determine the outer/inner coordinates.
  6368.         if (oldLeft > leftCol)
  6369.         {
  6370.             temp = oldLeft;
  6371.             oldLeft = leftCol;
  6372.             leftCol = temp;
  6373.         }
  6374.         if (oldTop > topRow )
  6375.         {
  6376.             temp = oldTop;
  6377.             oldTop = topRow;
  6378.             topRow = temp;
  6379.         }
  6380.         if (oldRight < rightCol )
  6381.         {
  6382.             temp = oldRight;
  6383.             oldRight = rightCol;
  6384.             rightCol = temp;
  6385.         }
  6386.         if (oldBottom < bottomRow)
  6387.         {
  6388.             temp = oldBottom;
  6389.             oldBottom = bottomRow;
  6390.             bottomRow = temp;
  6391.         }
  6392.  
  6393.         // Now, either the stuff marked old is the outer
  6394.         // rectangle or we don't have a situation where one
  6395.         // is contained in the other.
  6396.  
  6397.         if ( oldLeft < leftCol )
  6398.         {
  6399.             // Refresh the newly selected or deselected
  6400.             // area to the left of the old or new selection.
  6401.             need_refresh[0] = TRUE;
  6402.             rect[0] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
  6403.                                                             oldLeft ),
  6404.                                          wxGridCellCoords ( oldBottom,
  6405.                                                             leftCol - 1 ) );
  6406.         }
  6407.  
  6408.         if ( oldTop  < topRow )
  6409.         {
  6410.             // Refresh the newly selected or deselected
  6411.             // area above the old or new selection.
  6412.             need_refresh[1] = TRUE;
  6413.             rect[1] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
  6414.                                                             leftCol ),
  6415.                                          wxGridCellCoords ( topRow - 1,
  6416.                                                             rightCol ) );
  6417.         }
  6418.  
  6419.         if ( oldRight > rightCol )
  6420.         {
  6421.             // Refresh the newly selected or deselected
  6422.             // area to the right of the old or new selection.
  6423.             need_refresh[2] = TRUE;
  6424.             rect[2] = BlockToDeviceRect( wxGridCellCoords ( oldTop,
  6425.                                                             rightCol + 1 ),
  6426.                                          wxGridCellCoords ( oldBottom,
  6427.                                                             oldRight ) );
  6428.         }
  6429.  
  6430.         if ( oldBottom > bottomRow )
  6431.         {
  6432.             // Refresh the newly selected or deselected
  6433.             // area below the old or new selection.
  6434.             need_refresh[3] = TRUE;
  6435.             rect[3] = BlockToDeviceRect( wxGridCellCoords ( bottomRow + 1,
  6436.                                                             leftCol ),
  6437.                                          wxGridCellCoords ( oldBottom,
  6438.                                                             rightCol ) );
  6439.         }
  6440.  
  6441.         // various Refresh() calls
  6442.         for (i = 0; i < 4; i++ )
  6443.             if ( need_refresh[i] && rect[i] != wxGridNoCellRect )
  6444.                 m_gridWin->Refresh( FALSE, &(rect[i]) );
  6445.     }
  6446.     // Change Selection
  6447.     m_selectingTopLeft = updateTopLeft;
  6448.     m_selectingBottomRight = updateBottomRight;
  6449. }
  6450.  
  6451. //
  6452. // ------ functions to get/send data (see also public functions)
  6453. //
  6454.  
  6455. bool wxGrid::GetModelValues()
  6456. {
  6457.     // Hide the editor, so it won't hide a changed value.
  6458.     HideCellEditControl();
  6459.  
  6460.     if ( m_table )
  6461.     {
  6462.         // all we need to do is repaint the grid
  6463.         //
  6464.         m_gridWin->Refresh();
  6465.         return TRUE;
  6466.     }
  6467.  
  6468.     return FALSE;
  6469. }
  6470.  
  6471.  
  6472. bool wxGrid::SetModelValues()
  6473. {
  6474.     int row, col;
  6475.  
  6476.     // Disable the editor, so it won't hide a changed value.
  6477.     // Do we also want to save the current value of the editor first?
  6478.     // I think so ...
  6479.     DisableCellEditControl();
  6480.  
  6481.     if ( m_table )
  6482.     {
  6483.         for ( row = 0;  row < m_numRows;  row++ )
  6484.         {
  6485.             for ( col = 0;  col < m_numCols;  col++ )
  6486.             {
  6487.                 m_table->SetValue( row, col, GetCellValue(row, col) );
  6488.             }
  6489.         }
  6490.  
  6491.         return TRUE;
  6492.     }
  6493.  
  6494.     return FALSE;
  6495. }
  6496.  
  6497.  
  6498.  
  6499. // Note - this function only draws cells that are in the list of
  6500. // exposed cells (usually set from the update region by
  6501. // CalcExposedCells)
  6502. //
  6503. void wxGrid::DrawGridCellArea( wxDC& dc, const wxGridCellCoordsArray& cells )
  6504. {
  6505.     if ( !m_numRows || !m_numCols ) return;
  6506.  
  6507.     int i, numCells = cells.GetCount();
  6508.     int row, col, cell_rows, cell_cols;
  6509.     wxGridCellCoordsArray redrawCells;
  6510.  
  6511.     for ( i = numCells-1; i >= 0;  i-- )
  6512.     {
  6513.         row = cells[i].GetRow();
  6514.         col = cells[i].GetCol();
  6515.         GetCellSize( row, col, &cell_rows, &cell_cols );
  6516.  
  6517.         // If this cell is part of a multicell block, find owner for repaint
  6518.         if ( cell_rows <= 0 || cell_cols <= 0 )
  6519.         {
  6520.             wxGridCellCoords cell(row+cell_rows, col+cell_cols);
  6521.             bool marked = FALSE;
  6522.             for ( int j = 0;  j < numCells;  j++ )
  6523.             {
  6524.                 if ( cell == cells[j] )
  6525.                 {
  6526.                     marked = TRUE;
  6527.                     break;
  6528.                 }
  6529.             }
  6530.             if (!marked)
  6531.             {
  6532.                 int count = redrawCells.GetCount();
  6533.                 for (int j = 0; j < count; j++)
  6534.                 {
  6535.                     if ( cell == redrawCells[j] )
  6536.                     {
  6537.                         marked = TRUE;
  6538.                         break;
  6539.                     }
  6540.                 }
  6541.                 if (!marked) redrawCells.Add( cell );
  6542.             }
  6543.             continue; // don't bother drawing this cell
  6544.         }
  6545.  
  6546.         // If this cell is empty, find cell to left that might want to overflow
  6547.         if (m_table && m_table->IsEmptyCell(row, col))
  6548.         {
  6549.             for ( int l = 0; l < cell_rows; l++ )
  6550.             {
  6551.                 // find a cell in this row to left alreay marked for repaint
  6552.                 int left = col;
  6553.                 for (int k = 0; k < int(redrawCells.GetCount()); k++)
  6554.                     if ((redrawCells[k].GetCol() < left) &&
  6555.                         (redrawCells[k].GetRow() == row))
  6556.                         left=redrawCells[k].GetCol();
  6557.  
  6558.                 if (left == col) left = 0; // oh well
  6559.  
  6560.                 for (int j = col-1; j >= left; j--)
  6561.                 {
  6562.                     if (!m_table->IsEmptyCell(row+l, j))
  6563.                     {
  6564.                         if (GetCellOverflow(row+l, j))
  6565.                         {
  6566.                             wxGridCellCoords cell(row+l, j);
  6567.                             bool marked = FALSE;
  6568.  
  6569.                             for (int k = 0; k < numCells; k++)
  6570.                             {
  6571.                                 if ( cell == cells[k] )
  6572.                                 {
  6573.                                     marked = TRUE;
  6574.                                     break;
  6575.                                 }
  6576.                             }
  6577.                             if (!marked)
  6578.                             {
  6579.                                 int count = redrawCells.GetCount();
  6580.                                 for (int k = 0; k < count; k++)
  6581.                                 {
  6582.                                     if ( cell == redrawCells[k] )
  6583.                                     {
  6584.                                         marked = TRUE;
  6585.                                         break;
  6586.                                     }
  6587.                                 }
  6588.                                 if (!marked) redrawCells.Add( cell );
  6589.                             }
  6590.                         }
  6591.                         break;
  6592.                     }
  6593.                 }
  6594.             }
  6595.         }
  6596.         DrawCell( dc, cells[i] );
  6597.     }
  6598.  
  6599.     numCells = redrawCells.GetCount();
  6600.  
  6601.     for ( i = numCells - 1; i >= 0;  i-- )
  6602.     {
  6603.         DrawCell( dc, redrawCells[i] );
  6604.     }
  6605. }
  6606.  
  6607.  
  6608. void wxGrid::DrawGridSpace( wxDC& dc )
  6609. {
  6610.   int cw, ch;
  6611.   m_gridWin->GetClientSize( &cw, &ch );
  6612.  
  6613.   int right, bottom;
  6614.   CalcUnscrolledPosition( cw, ch, &right, &bottom );
  6615.  
  6616.   int rightCol = m_numCols > 0 ? GetColRight(m_numCols - 1) : 0;
  6617.   int bottomRow = m_numRows > 0 ? GetRowBottom(m_numRows - 1) : 0 ;
  6618.  
  6619.   if ( right > rightCol || bottom > bottomRow )
  6620.   {
  6621.       int left, top;
  6622.       CalcUnscrolledPosition( 0, 0, &left, &top );
  6623.  
  6624.       dc.SetBrush( wxBrush(GetDefaultCellBackgroundColour(), wxSOLID) );
  6625.       dc.SetPen( *wxTRANSPARENT_PEN );
  6626.  
  6627.       if ( right > rightCol )
  6628.       {
  6629.           dc.DrawRectangle( rightCol, top, right - rightCol, ch);
  6630.       }
  6631.  
  6632.       if ( bottom > bottomRow )
  6633.       {
  6634.           dc.DrawRectangle( left, bottomRow, cw, bottom - bottomRow);
  6635.       }
  6636.   }
  6637. }
  6638.  
  6639.  
  6640. void wxGrid::DrawCell( wxDC& dc, const wxGridCellCoords& coords )
  6641. {
  6642.     int row = coords.GetRow();
  6643.     int col = coords.GetCol();
  6644.  
  6645.     if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
  6646.         return;
  6647.  
  6648.     // we draw the cell border ourselves
  6649. #if !WXGRID_DRAW_LINES
  6650.     if ( m_gridLinesEnabled )
  6651.         DrawCellBorder( dc, coords );
  6652. #endif
  6653.  
  6654.     wxGridCellAttr* attr = GetCellAttr(row, col);
  6655.  
  6656.     bool isCurrent = coords == m_currentCellCoords;
  6657.  
  6658.     wxRect rect = CellToRect( row, col );
  6659.  
  6660.     // if the editor is shown, we should use it and not the renderer
  6661.     // Note: However, only if it is really _shown_, i.e. not hidden!
  6662.     if ( isCurrent && IsCellEditControlShown() )
  6663.     {
  6664.         wxGridCellEditor *editor = attr->GetEditor(this, row, col);
  6665.         editor->PaintBackground(rect, attr);
  6666.         editor->DecRef();
  6667.     }
  6668.     else
  6669.     {
  6670.         // but all the rest is drawn by the cell renderer and hence may be
  6671.         // customized
  6672.         wxGridCellRenderer *renderer = attr->GetRenderer(this, row, col);
  6673.         renderer->Draw(*this, *attr, dc, rect, row, col, IsInSelection(coords));
  6674.         renderer->DecRef();
  6675.     }
  6676.  
  6677.     attr->DecRef();
  6678. }
  6679.  
  6680. void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr )
  6681. {
  6682.     int row = m_currentCellCoords.GetRow();
  6683.     int col = m_currentCellCoords.GetCol();
  6684.  
  6685.     if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
  6686.         return;
  6687.  
  6688.     wxRect rect = CellToRect(row, col);
  6689.  
  6690.     // hmmm... what could we do here to show that the cell is disabled?
  6691.     // for now, I just draw a thinner border than for the other ones, but
  6692.     // it doesn't look really good
  6693.  
  6694.     int penWidth = attr->IsReadOnly() ? m_cellHighlightROPenWidth : m_cellHighlightPenWidth;
  6695.  
  6696.     if (penWidth > 0)
  6697.     {
  6698.         // The center of th drawn line is where the position/width/height of
  6699.         // the rectangle is actually at, (on wxMSW atr least,) so we will
  6700.         // reduce the size of the rectangle to compensate for the thickness of
  6701.         // the line.  If this is too strange on non wxMSW platforms then
  6702.         // please #ifdef this appropriately.
  6703.         rect.x += penWidth/2;
  6704.         rect.y += penWidth/2;
  6705.         rect.width -= penWidth-1;
  6706.         rect.height -= penWidth-1;
  6707.  
  6708.  
  6709.         // Now draw the rectangle
  6710.         dc.SetPen(wxPen(m_cellHighlightColour, penWidth, wxSOLID));
  6711.         dc.SetBrush(*wxTRANSPARENT_BRUSH);
  6712.         dc.DrawRectangle(rect);
  6713.     }
  6714.  
  6715. #if 0
  6716.         // VZ: my experiments with 3d borders...
  6717.  
  6718.         // how to properly set colours for arbitrary bg?
  6719.         wxCoord x1 = rect.x,
  6720.                 y1 = rect.y,
  6721.                 x2 = rect.x + rect.width -1,
  6722.                 y2 = rect.y + rect.height -1;
  6723.  
  6724.         dc.SetPen(*wxWHITE_PEN);
  6725.         dc.DrawLine(x1, y1, x2, y1);
  6726.         dc.DrawLine(x1, y1, x1, y2);
  6727.  
  6728.         dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1);
  6729.         dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2 );
  6730.  
  6731.         dc.SetPen(*wxBLACK_PEN);
  6732.         dc.DrawLine(x1, y2, x2, y2);
  6733.         dc.DrawLine(x2, y1, x2, y2+1);
  6734. #endif // 0
  6735. }
  6736.  
  6737.  
  6738. void wxGrid::DrawCellBorder( wxDC& dc, const wxGridCellCoords& coords )
  6739. {
  6740.     int row = coords.GetRow();
  6741.     int col = coords.GetCol();
  6742.     if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
  6743.         return;
  6744.  
  6745.     dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
  6746.  
  6747.     wxRect rect = CellToRect( row, col );
  6748.  
  6749.     // right hand border
  6750.     //
  6751.     dc.DrawLine( rect.x + rect.width, rect.y,
  6752.                  rect.x + rect.width, rect.y + rect.height + 1 );
  6753.  
  6754.     // bottom border
  6755.     //
  6756.     dc.DrawLine( rect.x,              rect.y + rect.height,
  6757.                  rect.x + rect.width, rect.y + rect.height);
  6758. }
  6759.  
  6760. void wxGrid::DrawHighlight(wxDC& dc,const  wxGridCellCoordsArray& cells)
  6761. {
  6762.     // This if block was previously in wxGrid::OnPaint but that doesn't
  6763.     // seem to get called under wxGTK - MB
  6764.     //
  6765.     if ( m_currentCellCoords == wxGridNoCellCoords  &&
  6766.          m_numRows && m_numCols )
  6767.     {
  6768.         m_currentCellCoords.Set(0, 0);
  6769.     }
  6770.  
  6771.     if ( IsCellEditControlShown() )
  6772.     {
  6773.         // don't show highlight when the edit control is shown
  6774.         return;
  6775.     }
  6776.  
  6777.     // if the active cell was repainted, repaint its highlight too because it
  6778.     // might have been damaged by the grid lines
  6779.     size_t count = cells.GetCount();
  6780.     for ( size_t n = 0; n < count; n++ )
  6781.     {
  6782.         if ( cells[n] == m_currentCellCoords )
  6783.         {
  6784.             wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
  6785.             DrawCellHighlight(dc, attr);
  6786.             attr->DecRef();
  6787.  
  6788.             break;
  6789.         }
  6790.     }
  6791. }
  6792.  
  6793. // TODO: remove this ???
  6794. // This is used to redraw all grid lines e.g. when the grid line colour
  6795. // has been changed
  6796. //
  6797. void wxGrid::DrawAllGridLines( wxDC& dc, const wxRegion & WXUNUSED(reg) )
  6798. {
  6799. #if !WXGRID_DRAW_LINES
  6800.     return;
  6801. #endif
  6802.  
  6803.     if ( !m_gridLinesEnabled ||
  6804.          !m_numRows ||
  6805.          !m_numCols ) return;
  6806.  
  6807.     int top, bottom, left, right;
  6808.  
  6809. #if 0  //#ifndef __WXGTK__
  6810.     if (reg.IsEmpty())
  6811.     {
  6812.       int cw, ch;
  6813.       m_gridWin->GetClientSize(&cw, &ch);
  6814.  
  6815.       // virtual coords of visible area
  6816.       //
  6817.       CalcUnscrolledPosition( 0, 0, &left, &top );
  6818.       CalcUnscrolledPosition( cw, ch, &right, &bottom );
  6819.     }
  6820.     else
  6821.     {
  6822.       wxCoord x, y, w, h;
  6823.       reg.GetBox(x, y, w, h);
  6824.       CalcUnscrolledPosition( x, y, &left, &top );
  6825.       CalcUnscrolledPosition( x + w, y + h, &right, &bottom );
  6826.     }
  6827. #else
  6828.       int cw, ch;
  6829.       m_gridWin->GetClientSize(&cw, &ch);
  6830.       CalcUnscrolledPosition( 0, 0, &left, &top );
  6831.       CalcUnscrolledPosition( cw, ch, &right, &bottom );
  6832. #endif
  6833.  
  6834.     // avoid drawing grid lines past the last row and col
  6835.     //
  6836.     right = wxMin( right, GetColRight(m_numCols - 1) );
  6837.     bottom = wxMin( bottom, GetRowBottom(m_numRows - 1) );
  6838.  
  6839.     // no gridlines inside multicells, clip them out
  6840.     int leftCol   = XToCol(left);
  6841.     int topRow    = YToRow(top);
  6842.     int rightCol  = XToCol(right);
  6843.     int bottomRow = YToRow(bottom);
  6844.     wxRegion clippedcells(0, 0, cw, ch);
  6845.  
  6846.     if ((leftCol >= 0) && (topRow >= 0))
  6847.     {
  6848.         if (rightCol  < 0) rightCol  = m_numCols;
  6849.         if (bottomRow < 0) bottomRow = m_numRows;
  6850.  
  6851.         int i, j, cell_rows, cell_cols;
  6852.         wxRect rect;
  6853.  
  6854.         for (j=topRow; j<bottomRow; j++)
  6855.         {
  6856.             for (i=leftCol; i<rightCol; i++)
  6857.             {
  6858.                 GetCellSize( j, i, &cell_rows, &cell_cols );
  6859.                 if ((cell_rows > 1) || (cell_cols > 1))
  6860.                 {
  6861.                     rect = CellToRect(j,i);
  6862.                     CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  6863.                     clippedcells.Subtract(rect);
  6864.                 }
  6865.                 else if ((cell_rows < 0) || (cell_cols < 0))
  6866.                 {
  6867.                     rect = CellToRect(j+cell_rows, i+cell_cols);
  6868.                     CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  6869.                     clippedcells.Subtract(rect);
  6870.                 }
  6871.             }
  6872.         }
  6873.     }
  6874.     dc.SetClippingRegion( clippedcells );
  6875.  
  6876.     dc.SetPen( wxPen(GetGridLineColour(), 1, wxSOLID) );
  6877.  
  6878.     // horizontal grid lines
  6879.     //
  6880.     int i;
  6881.     for ( i = internalYToRow(top); i < m_numRows; i++ )
  6882.     {
  6883.         int bot = GetRowBottom(i) - 1;
  6884.  
  6885.         if ( bot > bottom )
  6886.         {
  6887.             break;
  6888.         }
  6889.  
  6890.         if ( bot >= top )
  6891.         {
  6892.             dc.DrawLine( left, bot, right, bot );
  6893.         }
  6894.     }
  6895.  
  6896.  
  6897.     // vertical grid lines
  6898.     //
  6899.     for ( i = internalXToCol(left); i < m_numCols; i++ )
  6900.     {
  6901.         int colRight = GetColRight(i) - 1;
  6902.         if ( colRight > right )
  6903.         {
  6904.             break;
  6905.         }
  6906.  
  6907.         if ( colRight >= left )
  6908.         {
  6909.             dc.DrawLine( colRight, top, colRight, bottom );
  6910.         }
  6911.     }
  6912.     dc.DestroyClippingRegion();
  6913. }
  6914.  
  6915.  
  6916. void wxGrid::DrawRowLabels( wxDC& dc ,const wxArrayInt& rows)
  6917. {
  6918.     if ( !m_numRows ) return;
  6919.  
  6920.     size_t i;
  6921.     size_t numLabels = rows.GetCount();
  6922.  
  6923.     for ( i = 0;  i < numLabels;  i++ )
  6924.     {
  6925.         DrawRowLabel( dc, rows[i] );
  6926.     }
  6927. }
  6928.  
  6929.  
  6930. void wxGrid::DrawRowLabel( wxDC& dc, int row )
  6931. {
  6932.     if ( GetRowHeight(row) <= 0 )
  6933.         return;
  6934.  
  6935.     int rowTop = GetRowTop(row),
  6936.         rowBottom = GetRowBottom(row) - 1;
  6937.  
  6938.     dc.SetPen( *wxBLACK_PEN );
  6939.     dc.DrawLine( m_rowLabelWidth-1, rowTop,
  6940.                  m_rowLabelWidth-1, rowBottom );
  6941.  
  6942.     dc.DrawLine( 0, rowBottom, m_rowLabelWidth-1, rowBottom );
  6943.  
  6944.     dc.SetPen( *wxWHITE_PEN );
  6945.     dc.DrawLine( 0, rowTop, 0, rowBottom );
  6946.     dc.DrawLine( 0, rowTop, m_rowLabelWidth-1, rowTop );
  6947.  
  6948.     dc.SetBackgroundMode( wxTRANSPARENT );
  6949.     dc.SetTextForeground( GetLabelTextColour() );
  6950.     dc.SetFont( GetLabelFont() );
  6951.  
  6952.     int hAlign, vAlign;
  6953.     GetRowLabelAlignment( &hAlign, &vAlign );
  6954.  
  6955.     wxRect rect;
  6956.     rect.SetX( 2 );
  6957.     rect.SetY( GetRowTop(row) + 2 );
  6958.     rect.SetWidth( m_rowLabelWidth - 4 );
  6959.     rect.SetHeight( GetRowHeight(row) - 4 );
  6960.     DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
  6961. }
  6962.  
  6963.  
  6964. void wxGrid::DrawColLabels( wxDC& dc,const wxArrayInt& cols )
  6965. {
  6966.     if ( !m_numCols ) return;
  6967.  
  6968.     size_t i;
  6969.     size_t numLabels = cols.GetCount();
  6970.  
  6971.     for ( i = 0;  i < numLabels;  i++ )
  6972.     {
  6973.         DrawColLabel( dc, cols[i] );
  6974.     }
  6975. }
  6976.  
  6977.  
  6978. void wxGrid::DrawColLabel( wxDC& dc, int col )
  6979. {
  6980.     if ( GetColWidth(col) <= 0 )
  6981.         return;
  6982.  
  6983.     int colLeft = GetColLeft(col),
  6984.         colRight = GetColRight(col) - 1;
  6985.  
  6986.     dc.SetPen( *wxBLACK_PEN );
  6987.     dc.DrawLine( colRight, 0,
  6988.                  colRight, m_colLabelHeight-1 );
  6989.  
  6990.     dc.DrawLine( colLeft, m_colLabelHeight-1,
  6991.                  colRight, m_colLabelHeight-1 );
  6992.  
  6993.     dc.SetPen( *wxWHITE_PEN );
  6994.     dc.DrawLine( colLeft, 0, colLeft, m_colLabelHeight-1 );
  6995.     dc.DrawLine( colLeft, 0, colRight, 0 );
  6996.  
  6997.     dc.SetBackgroundMode( wxTRANSPARENT );
  6998.     dc.SetTextForeground( GetLabelTextColour() );
  6999.     dc.SetFont( GetLabelFont() );
  7000.  
  7001.     dc.SetBackgroundMode( wxTRANSPARENT );
  7002.     dc.SetTextForeground( GetLabelTextColour() );
  7003.     dc.SetFont( GetLabelFont() );
  7004.  
  7005.     int hAlign, vAlign;
  7006.     GetColLabelAlignment( &hAlign, &vAlign );
  7007.  
  7008.     wxRect rect;
  7009.     rect.SetX( colLeft + 2 );
  7010.     rect.SetY( 2 );
  7011.     rect.SetWidth( GetColWidth(col) - 4 );
  7012.     rect.SetHeight( m_colLabelHeight - 4 );
  7013.     DrawTextRectangle( dc, GetColLabelValue( col ), rect, hAlign, vAlign );
  7014. }
  7015.  
  7016. void wxGrid::DrawTextRectangle( wxDC& dc,
  7017.                                 const wxString& value,
  7018.                                 const wxRect& rect,
  7019.                                 int horizAlign,
  7020.                                 int vertAlign )
  7021. {
  7022.     wxArrayString lines;
  7023.  
  7024.     StringToLines( value, lines );
  7025.  
  7026.  
  7027.     //Forward to new API.
  7028.     DrawTextRectangle(  dc,
  7029.                         lines,
  7030.                         rect,
  7031.                         horizAlign,
  7032.                         vertAlign );
  7033.  
  7034. }
  7035.  
  7036. void wxGrid::DrawTextRectangle( wxDC& dc,
  7037.                                 const wxArrayString& lines,
  7038.                                 const wxRect& rect,
  7039.                                 int horizAlign,
  7040.                                 int vertAlign )
  7041. {
  7042.     long textWidth, textHeight;
  7043.     long lineWidth, lineHeight;
  7044.  
  7045.     dc.SetClippingRegion( rect );
  7046.     if ( lines.GetCount() )
  7047.     {
  7048.         GetTextBoxSize( dc, lines, &textWidth, &textHeight );
  7049.         dc.GetTextExtent( lines[0], &lineWidth, &lineHeight );
  7050.  
  7051.         float x, y;
  7052.         switch ( horizAlign )
  7053.         {
  7054.             case wxALIGN_RIGHT:
  7055.                 x = rect.x + (rect.width - textWidth - 1);
  7056.                 break;
  7057.  
  7058.             case wxALIGN_CENTRE:
  7059.                 x = rect.x + ((rect.width - textWidth)/2);
  7060.                 break;
  7061.  
  7062.             case wxALIGN_LEFT:
  7063.             default:
  7064.                 x = rect.x + 1;
  7065.                 break;
  7066.         }
  7067.  
  7068.         switch ( vertAlign )
  7069.         {
  7070.             case wxALIGN_BOTTOM:
  7071.                 y = rect.y + (rect.height - textHeight - 1);
  7072.                 break;
  7073.  
  7074.             case wxALIGN_CENTRE:
  7075.                 y = rect.y + ((rect.height - textHeight)/2);
  7076.                 break;
  7077.  
  7078.             case wxALIGN_TOP:
  7079.             default:
  7080.                 y = rect.y + 1;
  7081.                 break;
  7082.         }
  7083.  
  7084.         for ( size_t i = 0;  i < lines.GetCount();  i++ )
  7085.         {
  7086.             dc.DrawText( lines[i], (int)x, (int)y );
  7087.             y += lineHeight;
  7088.         }
  7089.     }
  7090.  
  7091.     dc.DestroyClippingRegion();
  7092. }
  7093.  
  7094.  
  7095. // Split multi line text up into an array of strings.  Any existing
  7096. // contents of the string array are preserved.
  7097. //
  7098. void wxGrid::StringToLines( const wxString& value, wxArrayString& lines )
  7099. {
  7100.     int startPos = 0;
  7101.     int pos;
  7102.     wxString eol = wxTextFile::GetEOL( wxTextFileType_Unix );
  7103.     wxString tVal = wxTextFile::Translate( value, wxTextFileType_Unix );
  7104.  
  7105.     while ( startPos < (int)tVal.Length() )
  7106.     {
  7107.         pos = tVal.Mid(startPos).Find( eol );
  7108.         if ( pos < 0 )
  7109.         {
  7110.             break;
  7111.         }
  7112.         else if ( pos == 0 )
  7113.         {
  7114.             lines.Add( wxEmptyString );
  7115.         }
  7116.         else
  7117.         {
  7118.             lines.Add( value.Mid(startPos, pos) );
  7119.         }
  7120.         startPos += pos+1;
  7121.     }
  7122.     if ( startPos < (int)value.Length() )
  7123.     {
  7124.         lines.Add( value.Mid( startPos ) );
  7125.     }
  7126. }
  7127.  
  7128.  
  7129. void wxGrid::GetTextBoxSize( wxDC& dc,
  7130.                              const wxArrayString& lines,
  7131.                              long *width, long *height )
  7132. {
  7133.     long w = 0;
  7134.     long h = 0;
  7135.     long lineW, lineH;
  7136.  
  7137.     size_t i;
  7138.     for ( i = 0;  i < lines.GetCount();  i++ )
  7139.     {
  7140.         dc.GetTextExtent( lines[i], &lineW, &lineH );
  7141.         w = wxMax( w, lineW );
  7142.         h += lineH;
  7143.     }
  7144.  
  7145.     *width = w;
  7146.     *height = h;
  7147. }
  7148.  
  7149. //
  7150. // ------ Batch processing.
  7151. //
  7152. void wxGrid::EndBatch()
  7153. {
  7154.     if ( m_batchCount > 0 )
  7155.     {
  7156.         m_batchCount--;
  7157.         if ( !m_batchCount )
  7158.         {
  7159.             CalcDimensions();
  7160.             m_rowLabelWin->Refresh();
  7161.             m_colLabelWin->Refresh();
  7162.             m_cornerLabelWin->Refresh();
  7163.             m_gridWin->Refresh();
  7164.         }
  7165.     }
  7166. }
  7167.  
  7168. // Use this, rather than wxWindow::Refresh(), to force an immediate
  7169. // repainting of the grid. Has no effect if you are already inside a
  7170. // BeginBatch / EndBatch block.
  7171. //
  7172. void wxGrid::ForceRefresh()
  7173. {
  7174.     BeginBatch();
  7175.     EndBatch();
  7176. }
  7177.  
  7178.  
  7179. //
  7180. // ------ Edit control functions
  7181. //
  7182.  
  7183.  
  7184. void wxGrid::EnableEditing( bool edit )
  7185. {
  7186.     // TODO: improve this ?
  7187.     //
  7188.     if ( edit != m_editable )
  7189.     {
  7190.         if(!edit) EnableCellEditControl(edit);
  7191.         m_editable = edit;
  7192.     }
  7193. }
  7194.  
  7195.  
  7196. void wxGrid::EnableCellEditControl( bool enable )
  7197. {
  7198.     if (! m_editable)
  7199.         return;
  7200.  
  7201.     if ( m_currentCellCoords == wxGridNoCellCoords )
  7202.         SetCurrentCell( 0, 0 );
  7203.  
  7204.     if ( enable != m_cellEditCtrlEnabled )
  7205.     {
  7206.         if ( enable )
  7207.         {
  7208.             if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
  7209.                 return;
  7210.  
  7211.             // this should be checked by the caller!
  7212.             wxASSERT_MSG( CanEnableCellControl(),
  7213.                           _T("can't enable editing for this cell!") );
  7214.  
  7215.             // do it before ShowCellEditControl()
  7216.             m_cellEditCtrlEnabled = enable;
  7217.  
  7218.             ShowCellEditControl();
  7219.         }
  7220.         else
  7221.         {
  7222.             //FIXME:add veto support
  7223.             SendEvent( wxEVT_GRID_EDITOR_HIDDEN);
  7224.  
  7225.             HideCellEditControl();
  7226.             SaveEditControlValue();
  7227.  
  7228.             // do it after HideCellEditControl()
  7229.             m_cellEditCtrlEnabled = enable;
  7230.         }
  7231.     }
  7232. }
  7233.  
  7234. bool wxGrid::IsCurrentCellReadOnly() const
  7235. {
  7236.     // const_cast
  7237.     wxGridCellAttr* attr = ((wxGrid *)this)->GetCellAttr(m_currentCellCoords);
  7238.     bool readonly = attr->IsReadOnly();
  7239.     attr->DecRef();
  7240.  
  7241.     return readonly;
  7242. }
  7243.  
  7244. bool wxGrid::CanEnableCellControl() const
  7245. {
  7246.     return m_editable && !IsCurrentCellReadOnly();
  7247. }
  7248.  
  7249. bool wxGrid::IsCellEditControlEnabled() const
  7250. {
  7251.     // the cell edit control might be disable for all cells or just for the
  7252.     // current one if it's read only
  7253.     return m_cellEditCtrlEnabled ? !IsCurrentCellReadOnly() : FALSE;
  7254. }
  7255.  
  7256. bool wxGrid::IsCellEditControlShown() const
  7257. {
  7258.     bool isShown = FALSE;
  7259.  
  7260.     if ( m_cellEditCtrlEnabled )
  7261.     {
  7262.         int row = m_currentCellCoords.GetRow();
  7263.         int col = m_currentCellCoords.GetCol();
  7264.         wxGridCellAttr* attr = GetCellAttr(row, col);
  7265.         wxGridCellEditor* editor = attr->GetEditor((wxGrid*) this, row, col);
  7266.         attr->DecRef();
  7267.  
  7268.         if ( editor )
  7269.         {
  7270.             if ( editor->IsCreated() )
  7271.             {
  7272.                 isShown = editor->GetControl()->IsShown();
  7273.             }
  7274.  
  7275.             editor->DecRef();
  7276.         }
  7277.     }
  7278.  
  7279.     return isShown;
  7280. }
  7281.  
  7282. void wxGrid::ShowCellEditControl()
  7283. {
  7284.     if ( IsCellEditControlEnabled() )
  7285.     {
  7286.         if ( !IsVisible( m_currentCellCoords ) )
  7287.         {
  7288.             m_cellEditCtrlEnabled = FALSE;
  7289.             return;
  7290.         }
  7291.         else
  7292.         {
  7293.             wxRect rect = CellToRect( m_currentCellCoords );
  7294.             int row = m_currentCellCoords.GetRow();
  7295.             int col = m_currentCellCoords.GetCol();
  7296.  
  7297.             // if this is part of a multicell, find owner (topleft)
  7298.             int cell_rows, cell_cols;
  7299.             GetCellSize( row, col, &cell_rows, &cell_cols );
  7300.             if ( cell_rows <= 0 || cell_cols <= 0 )
  7301.             {
  7302.                 row += cell_rows;
  7303.                 col += cell_cols;
  7304.                 m_currentCellCoords.SetRow( row );
  7305.                 m_currentCellCoords.SetCol( col );
  7306.             }
  7307.  
  7308.             // convert to scrolled coords
  7309.             //
  7310.             CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  7311.  
  7312.             // done in PaintBackground()
  7313. #if 0
  7314.             // erase the highlight and the cell contents because the editor
  7315.             // might not cover the entire cell
  7316.             wxClientDC dc( m_gridWin );
  7317.             PrepareDC( dc );
  7318.             dc.SetBrush(*wxLIGHT_GREY_BRUSH); //wxBrush(attr->GetBackgroundColour(), wxSOLID));
  7319.             dc.SetPen(*wxTRANSPARENT_PEN);
  7320.             dc.DrawRectangle(rect);
  7321. #endif // 0
  7322.  
  7323.             // cell is shifted by one pixel
  7324.             // However, don't allow x or y to become negative
  7325.             // since the SetSize() method interprets that as
  7326.             // "don't change."
  7327.             if (rect.x > 0)
  7328.                 rect.x--;
  7329.             if (rect.y > 0)
  7330.                 rect.y--;
  7331.  
  7332.             wxGridCellAttr* attr = GetCellAttr(row, col);
  7333.             wxGridCellEditor* editor = attr->GetEditor(this, row, col);
  7334.             if ( !editor->IsCreated() )
  7335.             {
  7336.                 editor->Create(m_gridWin, -1,
  7337.                                new wxGridCellEditorEvtHandler(this, editor));
  7338.  
  7339.                 wxGridEditorCreatedEvent evt(GetId(),
  7340.                                              wxEVT_GRID_EDITOR_CREATED,
  7341.                                              this,
  7342.                                              row,
  7343.                                              col,
  7344.                                              editor->GetControl());
  7345.                 GetEventHandler()->ProcessEvent(evt);
  7346.             }
  7347.  
  7348.             // resize editor to overflow into righthand cells if allowed
  7349.             int maxWidth = rect.width;
  7350.             wxString value = GetCellValue(row, col);
  7351.             if ( (value != wxEmptyString) && (attr->GetOverflow()) )
  7352.             {
  7353.                 int y;
  7354.                 GetTextExtent(value, &maxWidth, &y,
  7355.                         NULL, NULL, &attr->GetFont());
  7356.                 if (maxWidth < rect.width) maxWidth = rect.width;
  7357.             }
  7358.             int client_right = m_gridWin->GetClientSize().GetWidth();
  7359.             if (rect.x+maxWidth > client_right)
  7360.                 maxWidth = client_right - rect.x;
  7361.  
  7362.             if ((maxWidth > rect.width) && (col < m_numCols) && m_table)
  7363.             {
  7364.                 GetCellSize( row, col, &cell_rows, &cell_cols );
  7365.                 // may have changed earlier
  7366.                 for (int i = col+cell_cols; i < m_numCols; i++)
  7367.                 {
  7368.                     int c_rows, c_cols;
  7369.                     GetCellSize( row, i, &c_rows, &c_cols );
  7370.                     // looks weird going over a multicell
  7371.                     if (m_table->IsEmptyCell(row,i) &&
  7372.                             (rect.width < maxWidth) && (c_rows == 1))
  7373.                         rect.width += GetColWidth(i);
  7374.                     else
  7375.                         break;
  7376.                 }
  7377.                 if (rect.GetRight() > client_right)
  7378.                     rect.SetRight(client_right-1);
  7379.             }
  7380.             editor->SetCellAttr(attr);
  7381.             editor->SetSize( rect );
  7382.             editor->Show( TRUE, attr );
  7383.  
  7384.             // recalc dimensions in case we need to
  7385.             // expand the scrolled window to account for editor
  7386.             CalcDimensions();
  7387.  
  7388.             editor->BeginEdit(row, col, this);
  7389.             editor->SetCellAttr(NULL);
  7390.  
  7391.             editor->DecRef();
  7392.             attr->DecRef();
  7393.         }
  7394.     }
  7395. }
  7396.  
  7397.  
  7398. void wxGrid::HideCellEditControl()
  7399. {
  7400.     if ( IsCellEditControlEnabled() )
  7401.     {
  7402.         int row = m_currentCellCoords.GetRow();
  7403.         int col = m_currentCellCoords.GetCol();
  7404.  
  7405.         wxGridCellAttr* attr = GetCellAttr(row, col);
  7406.         wxGridCellEditor *editor = attr->GetEditor(this, row, col);
  7407.         editor->Show( FALSE );
  7408.         editor->DecRef();
  7409.         attr->DecRef();
  7410.         m_gridWin->SetFocus();
  7411.         // refresh whole row to the right
  7412.         wxRect rect( CellToRect(row, col) );
  7413.         CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y );
  7414.         rect.width = m_gridWin->GetClientSize().GetWidth() - rect.x;
  7415.         m_gridWin->Refresh( FALSE, &rect );
  7416.     }
  7417. }
  7418.  
  7419.  
  7420. void wxGrid::SaveEditControlValue()
  7421. {
  7422.     if ( IsCellEditControlEnabled() )
  7423.     {
  7424.         int row = m_currentCellCoords.GetRow();
  7425.         int col = m_currentCellCoords.GetCol();
  7426.  
  7427.         wxString oldval = GetCellValue(row,col);
  7428.  
  7429.         wxGridCellAttr* attr = GetCellAttr(row, col);
  7430.         wxGridCellEditor* editor = attr->GetEditor(this, row, col);
  7431.         bool changed = editor->EndEdit(row, col, this);
  7432.  
  7433.         editor->DecRef();
  7434.         attr->DecRef();
  7435.  
  7436.         if (changed)
  7437.         {
  7438.             if ( SendEvent( wxEVT_GRID_CELL_CHANGE,
  7439.                        m_currentCellCoords.GetRow(),
  7440.                        m_currentCellCoords.GetCol() ) < 0 ) {
  7441.  
  7442.                 // Event has been vetoed, set the data back.
  7443.                 SetCellValue(row,col,oldval);
  7444.             }
  7445.         }
  7446.     }
  7447. }
  7448.  
  7449.  
  7450. //
  7451. // ------ Grid location functions
  7452. //  Note that all of these functions work with the logical coordinates of
  7453. //  grid cells and labels so you will need to convert from device
  7454. //  coordinates for mouse events etc.
  7455. //
  7456.  
  7457. void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords )
  7458. {
  7459.     int row = YToRow(y);
  7460.     int col = XToCol(x);
  7461.  
  7462.     if ( row == -1  ||  col == -1 )
  7463.     {
  7464.         coords = wxGridNoCellCoords;
  7465.     }
  7466.     else
  7467.     {
  7468.         coords.Set( row, col );
  7469.     }
  7470. }
  7471.  
  7472.  
  7473. // Internal Helper function for computing row or column from some
  7474. // (unscrolled) coordinate value, using either
  7475. // m_defaultRowHeight/m_defaultColWidth or binary search on array
  7476. // of m_rowBottoms/m_ColRights to speed up the search!
  7477.  
  7478. static int CoordToRowOrCol(int coord, int defaultDist, int minDist,
  7479.                            const wxArrayInt& BorderArray, int nMax,
  7480.                            bool maxOnOverflow)
  7481. {
  7482.     if (!defaultDist)
  7483.         defaultDist = 1;
  7484.     size_t i_max = coord / defaultDist,
  7485.            i_min = 0;
  7486.  
  7487.     if (BorderArray.IsEmpty())
  7488.     {
  7489.         if((int) i_max < nMax)
  7490.             return i_max;
  7491.         return maxOnOverflow ? nMax - 1 : -1;
  7492.     }
  7493.  
  7494.     if ( i_max >= BorderArray.GetCount())
  7495.         i_max = BorderArray.GetCount() - 1;
  7496.     else
  7497.     {
  7498.         if ( coord >= BorderArray[i_max])
  7499.         {
  7500.             i_min = i_max;
  7501.             i_max = coord / minDist;
  7502.         }
  7503.         if ( i_max >= BorderArray.GetCount())
  7504.             i_max = BorderArray.GetCount() - 1;
  7505.     }
  7506.     if ( coord >= BorderArray[i_max])
  7507.         return maxOnOverflow ? (int)i_max : -1;
  7508.     if ( coord < BorderArray[0] )
  7509.         return 0;
  7510.  
  7511.     while ( i_max - i_min > 0 )
  7512.     {
  7513.         wxCHECK_MSG(BorderArray[i_min] <= coord && coord < BorderArray[i_max],
  7514.                     0, _T("wxGrid: internal error in CoordToRowOrCol"));
  7515.         if (coord >=  BorderArray[ i_max - 1])
  7516.             return i_max;
  7517.         else
  7518.             i_max--;
  7519.         int median = i_min + (i_max - i_min + 1) / 2;
  7520.         if (coord < BorderArray[median])
  7521.             i_max = median;
  7522.         else
  7523.             i_min = median;
  7524.     }
  7525.     return i_max;
  7526. }
  7527.  
  7528. int wxGrid::YToRow( int y )
  7529. {
  7530.     return CoordToRowOrCol(y, m_defaultRowHeight,
  7531.                            WXGRID_MIN_ROW_HEIGHT, m_rowBottoms, m_numRows, FALSE);
  7532. }
  7533.  
  7534.  
  7535. int wxGrid::XToCol( int x )
  7536. {
  7537.     return CoordToRowOrCol(x, m_defaultColWidth,
  7538.                            WXGRID_MIN_COL_WIDTH, m_colRights, m_numCols, FALSE);
  7539. }
  7540.  
  7541.  
  7542. // return the row number that that the y coord is near the edge of, or
  7543. // -1 if not near an edge
  7544. //
  7545. int wxGrid::YToEdgeOfRow( int y )
  7546. {
  7547.     int i;
  7548.     i = internalYToRow(y);
  7549.  
  7550.     if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE )
  7551.     {
  7552.         // We know that we are in row i, test whether we are
  7553.         // close enough to lower or upper border, respectively.
  7554.         if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE )
  7555.             return i;
  7556.         else if( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE )
  7557.             return i - 1;
  7558.     }
  7559.  
  7560.     return -1;
  7561. }
  7562.  
  7563.  
  7564. // return the col number that that the x coord is near the edge of, or
  7565. // -1 if not near an edge
  7566. //
  7567. int wxGrid::XToEdgeOfCol( int x )
  7568. {
  7569.     int i;
  7570.     i = internalXToCol(x);
  7571.  
  7572.     if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE )
  7573.     {
  7574.         // We know that we are in column i,  test whether we are
  7575.         // close enough to right or left border, respectively.
  7576.         if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE )
  7577.             return i;
  7578.         else if( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE )
  7579.             return i - 1;
  7580.     }
  7581.  
  7582.     return -1;
  7583. }
  7584.  
  7585.  
  7586. wxRect wxGrid::CellToRect( int row, int col )
  7587. {
  7588.     wxRect rect( -1, -1, -1, -1 );
  7589.  
  7590.     if ( row >= 0  &&  row < m_numRows  &&
  7591.          col >= 0  &&  col < m_numCols )
  7592.     {
  7593.         int i, cell_rows, cell_cols;
  7594.         rect.width = rect.height = 0;
  7595.         GetCellSize( row, col, &cell_rows, &cell_cols );
  7596.         // if negative then find multicell owner
  7597.         if (cell_rows < 0) row += cell_rows;
  7598.         if (cell_cols < 0) col += cell_cols;
  7599.         GetCellSize( row, col, &cell_rows, &cell_cols );
  7600.  
  7601.         rect.x = GetColLeft(col);
  7602.         rect.y = GetRowTop(row);
  7603.         for (i=col; i<col+cell_cols; i++)
  7604.             rect.width  += GetColWidth(i);
  7605.         for (i=row; i<row+cell_rows; i++)
  7606.             rect.height += GetRowHeight(i);
  7607.     }
  7608.  
  7609.     // if grid lines are enabled, then the area of the cell is a bit smaller
  7610.     if (m_gridLinesEnabled) {
  7611.         rect.width -= 1;
  7612.         rect.height -= 1;
  7613.     }
  7614.     return rect;
  7615. }
  7616.  
  7617.  
  7618. bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible )
  7619. {
  7620.     // get the cell rectangle in logical coords
  7621.     //
  7622.     wxRect r( CellToRect( row, col ) );
  7623.  
  7624.     // convert to device coords
  7625.     //
  7626.     int left, top, right, bottom;
  7627.     CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
  7628.     CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
  7629.  
  7630.     // check against the client area of the grid window
  7631.     //
  7632.     int cw, ch;
  7633.     m_gridWin->GetClientSize( &cw, &ch );
  7634.  
  7635.     if ( wholeCellVisible )
  7636.     {
  7637.         // is the cell wholly visible ?
  7638.         //
  7639.         return ( left >= 0  &&  right <= cw  &&
  7640.                  top >= 0  &&  bottom <= ch );
  7641.     }
  7642.     else
  7643.     {
  7644.         // is the cell partly visible ?
  7645.         //
  7646.         return ( ((left >=0 && left < cw) || (right > 0 && right <= cw))  &&
  7647.                  ((top >=0 && top < ch) || (bottom > 0 && bottom <= ch)) );
  7648.     }
  7649. }
  7650.  
  7651.  
  7652. // make the specified cell location visible by doing a minimal amount
  7653. // of scrolling
  7654. //
  7655. void wxGrid::MakeCellVisible( int row, int col )
  7656. {
  7657.  
  7658.     int i;
  7659.     int xpos = -1, ypos = -1;
  7660.  
  7661.     if ( row >= 0  &&  row < m_numRows  &&
  7662.          col >= 0  &&  col < m_numCols )
  7663.     {
  7664.         // get the cell rectangle in logical coords
  7665.         //
  7666.         wxRect r( CellToRect( row, col ) );
  7667.  
  7668.         // convert to device coords
  7669.         //
  7670.         int left, top, right, bottom;
  7671.         CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
  7672.         CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
  7673.  
  7674.         int cw, ch;
  7675.         m_gridWin->GetClientSize( &cw, &ch );
  7676.  
  7677.         if ( top < 0 )
  7678.         {
  7679.             ypos = r.GetTop();
  7680.         }
  7681.         else if ( bottom > ch )
  7682.         {
  7683.             int h = r.GetHeight();
  7684.             ypos = r.GetTop();
  7685.             for ( i = row-1;  i >= 0;  i-- )
  7686.             {
  7687.                 int rowHeight = GetRowHeight(i);
  7688.                 if ( h + rowHeight > ch )
  7689.                     break;
  7690.  
  7691.                 h += rowHeight;
  7692.                 ypos -= rowHeight;
  7693.             }
  7694.  
  7695.             // we divide it later by GRID_SCROLL_LINE, make sure that we don't
  7696.             // have rounding errors (this is important, because if we do, we
  7697.             // might not scroll at all and some cells won't be redrawn)
  7698.             //
  7699.             // Sometimes GRID_SCROLL_LINE/2 is not enough, so just add a full
  7700.             // scroll unit...
  7701.             ypos += GRID_SCROLL_LINE_Y;
  7702.         }
  7703.  
  7704.         if ( left < 0 )
  7705.         {
  7706.             xpos = r.GetLeft();
  7707.         }
  7708.         else if ( right > cw )
  7709.         {
  7710.             int w = r.GetWidth();
  7711.             xpos = r.GetLeft();
  7712.             for ( i = col-1;  i >= 0;  i-- )
  7713.             {
  7714.                 int colWidth = GetColWidth(i);
  7715.                 if ( w + colWidth > cw )
  7716.                     break;
  7717.  
  7718.                 w += colWidth;
  7719.                 xpos -= colWidth;
  7720.             }
  7721.  
  7722.             // see comment for ypos above
  7723.             xpos += GRID_SCROLL_LINE_X;
  7724.         }
  7725.  
  7726.         if ( xpos != -1  ||  ypos != -1 )
  7727.         {
  7728.             if ( xpos != -1 )
  7729.                 xpos /= GRID_SCROLL_LINE_X;
  7730.             if ( ypos != -1 )
  7731.                 ypos /= GRID_SCROLL_LINE_Y;
  7732.             Scroll( xpos, ypos );
  7733.             AdjustScrollbars();
  7734.         }
  7735.     }
  7736. }
  7737.  
  7738.  
  7739. //
  7740. // ------ Grid cursor movement functions
  7741. //
  7742.  
  7743. bool wxGrid::MoveCursorUp( bool expandSelection )
  7744. {
  7745.     if ( m_currentCellCoords != wxGridNoCellCoords  &&
  7746.          m_currentCellCoords.GetRow() >= 0 )
  7747.     {
  7748.         if ( expandSelection)
  7749.         {
  7750.             if ( m_selectingKeyboard == wxGridNoCellCoords )
  7751.                 m_selectingKeyboard = m_currentCellCoords;
  7752.             if ( m_selectingKeyboard.GetRow() > 0 )
  7753.             {
  7754.                 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 );
  7755.                 MakeCellVisible( m_selectingKeyboard.GetRow(),
  7756.                                  m_selectingKeyboard.GetCol() );
  7757.                 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  7758.             }
  7759.         }
  7760.         else if ( m_currentCellCoords.GetRow() > 0 )
  7761.         {
  7762.             ClearSelection();
  7763.             MakeCellVisible( m_currentCellCoords.GetRow() - 1,
  7764.                              m_currentCellCoords.GetCol() );
  7765.             SetCurrentCell( m_currentCellCoords.GetRow() - 1,
  7766.                             m_currentCellCoords.GetCol() );
  7767.         }
  7768.         else
  7769.             return FALSE;
  7770.         return TRUE;
  7771.     }
  7772.  
  7773.     return FALSE;
  7774. }
  7775.  
  7776.  
  7777. bool wxGrid::MoveCursorDown( bool expandSelection )
  7778. {
  7779.     if ( m_currentCellCoords != wxGridNoCellCoords  &&
  7780.          m_currentCellCoords.GetRow() < m_numRows )
  7781.     {
  7782.         if ( expandSelection )
  7783.         {
  7784.             if ( m_selectingKeyboard == wxGridNoCellCoords )
  7785.                 m_selectingKeyboard = m_currentCellCoords;
  7786.             if ( m_selectingKeyboard.GetRow() < m_numRows-1 )
  7787.             {
  7788.                 m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 );
  7789.                 MakeCellVisible( m_selectingKeyboard.GetRow(),
  7790.                         m_selectingKeyboard.GetCol() );
  7791.                 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  7792.             }
  7793.         }
  7794.         else if ( m_currentCellCoords.GetRow() < m_numRows - 1 )
  7795.         {
  7796.             ClearSelection();
  7797.             MakeCellVisible( m_currentCellCoords.GetRow() + 1,
  7798.                              m_currentCellCoords.GetCol() );
  7799.             SetCurrentCell( m_currentCellCoords.GetRow() + 1,
  7800.                             m_currentCellCoords.GetCol() );
  7801.         }
  7802.         else
  7803.             return FALSE;
  7804.         return TRUE;
  7805.     }
  7806.  
  7807.     return FALSE;
  7808. }
  7809.  
  7810.  
  7811. bool wxGrid::MoveCursorLeft( bool expandSelection )
  7812. {
  7813.     if ( m_currentCellCoords != wxGridNoCellCoords  &&
  7814.          m_currentCellCoords.GetCol() >= 0 )
  7815.     {
  7816.         if ( expandSelection )
  7817.         {
  7818.             if ( m_selectingKeyboard == wxGridNoCellCoords )
  7819.                 m_selectingKeyboard = m_currentCellCoords;
  7820.             if ( m_selectingKeyboard.GetCol() > 0 )
  7821.             {
  7822.                 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 );
  7823.                 MakeCellVisible( m_selectingKeyboard.GetRow(),
  7824.                         m_selectingKeyboard.GetCol() );
  7825.                 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  7826.             }
  7827.         }
  7828.         else if ( m_currentCellCoords.GetCol() > 0 )
  7829.         {
  7830.             ClearSelection();
  7831.             MakeCellVisible( m_currentCellCoords.GetRow(),
  7832.                              m_currentCellCoords.GetCol() - 1 );
  7833.             SetCurrentCell( m_currentCellCoords.GetRow(),
  7834.                             m_currentCellCoords.GetCol() - 1 );
  7835.         }
  7836.         else
  7837.             return FALSE;
  7838.         return TRUE;
  7839.     }
  7840.  
  7841.     return FALSE;
  7842. }
  7843.  
  7844.  
  7845. bool wxGrid::MoveCursorRight( bool expandSelection )
  7846. {
  7847.     if ( m_currentCellCoords != wxGridNoCellCoords  &&
  7848.          m_currentCellCoords.GetCol() < m_numCols )
  7849.     {
  7850.         if ( expandSelection )
  7851.         {
  7852.             if ( m_selectingKeyboard == wxGridNoCellCoords )
  7853.                 m_selectingKeyboard = m_currentCellCoords;
  7854.             if ( m_selectingKeyboard.GetCol() < m_numCols - 1 )
  7855.             {
  7856.                 m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 );
  7857.                 MakeCellVisible( m_selectingKeyboard.GetRow(),
  7858.                         m_selectingKeyboard.GetCol() );
  7859.                 HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  7860.             }
  7861.         }
  7862.         else if ( m_currentCellCoords.GetCol() < m_numCols - 1 )
  7863.         {
  7864.             ClearSelection();
  7865.             MakeCellVisible( m_currentCellCoords.GetRow(),
  7866.                              m_currentCellCoords.GetCol() + 1 );
  7867.             SetCurrentCell( m_currentCellCoords.GetRow(),
  7868.                             m_currentCellCoords.GetCol() + 1 );
  7869.         }
  7870.         else
  7871.             return FALSE;
  7872.         return TRUE;
  7873.     }
  7874.  
  7875.     return FALSE;
  7876. }
  7877.  
  7878.  
  7879. bool wxGrid::MovePageUp()
  7880. {
  7881.     if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
  7882.  
  7883.     int row = m_currentCellCoords.GetRow();
  7884.     if ( row > 0 )
  7885.     {
  7886.         int cw, ch;
  7887.         m_gridWin->GetClientSize( &cw, &ch );
  7888.  
  7889.         int y = GetRowTop(row);
  7890.         int newRow = YToRow( y - ch + 1 );
  7891.         if ( newRow == -1 )
  7892.         {
  7893.             newRow = 0;
  7894.         }
  7895.         else if ( newRow == row )
  7896.         {
  7897.             newRow = row - 1;
  7898.         }
  7899.  
  7900.         MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
  7901.         SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
  7902.  
  7903.         return TRUE;
  7904.     }
  7905.  
  7906.     return FALSE;
  7907. }
  7908.  
  7909. bool wxGrid::MovePageDown()
  7910. {
  7911.     if ( m_currentCellCoords == wxGridNoCellCoords ) return FALSE;
  7912.  
  7913.     int row = m_currentCellCoords.GetRow();
  7914.     if ( row < m_numRows )
  7915.     {
  7916.         int cw, ch;
  7917.         m_gridWin->GetClientSize( &cw, &ch );
  7918.  
  7919.         int y = GetRowTop(row);
  7920.         int newRow = YToRow( y + ch );
  7921.         if ( newRow == -1 )
  7922.         {
  7923.             newRow = m_numRows - 1;
  7924.         }
  7925.         else if ( newRow == row )
  7926.         {
  7927.             newRow = row + 1;
  7928.         }
  7929.  
  7930.         MakeCellVisible( newRow, m_currentCellCoords.GetCol() );
  7931.         SetCurrentCell( newRow, m_currentCellCoords.GetCol() );
  7932.  
  7933.         return TRUE;
  7934.     }
  7935.  
  7936.     return FALSE;
  7937. }
  7938.  
  7939. bool wxGrid::MoveCursorUpBlock( bool expandSelection )
  7940. {
  7941.     if ( m_table &&
  7942.          m_currentCellCoords != wxGridNoCellCoords  &&
  7943.          m_currentCellCoords.GetRow() > 0 )
  7944.     {
  7945.         int row = m_currentCellCoords.GetRow();
  7946.         int col = m_currentCellCoords.GetCol();
  7947.  
  7948.         if ( m_table->IsEmptyCell(row, col) )
  7949.         {
  7950.             // starting in an empty cell: find the next block of
  7951.             // non-empty cells
  7952.             //
  7953.             while ( row > 0 )
  7954.             {
  7955.                 row-- ;
  7956.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  7957.             }
  7958.         }
  7959.         else if ( m_table->IsEmptyCell(row-1, col) )
  7960.         {
  7961.             // starting at the top of a block: find the next block
  7962.             //
  7963.             row--;
  7964.             while ( row > 0 )
  7965.             {
  7966.                 row-- ;
  7967.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  7968.             }
  7969.         }
  7970.         else
  7971.         {
  7972.             // starting within a block: find the top of the block
  7973.             //
  7974.             while ( row > 0 )
  7975.             {
  7976.                 row-- ;
  7977.                 if ( m_table->IsEmptyCell(row, col) )
  7978.                 {
  7979.                     row++ ;
  7980.                     break;
  7981.                 }
  7982.             }
  7983.         }
  7984.  
  7985.         MakeCellVisible( row, col );
  7986.         if ( expandSelection )
  7987.         {
  7988.             m_selectingKeyboard = wxGridCellCoords( row, col );
  7989.             HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  7990.         }
  7991.         else
  7992.         {
  7993.             ClearSelection();
  7994.             SetCurrentCell( row, col );
  7995.         }
  7996.         return TRUE;
  7997.     }
  7998.  
  7999.     return FALSE;
  8000. }
  8001.  
  8002. bool wxGrid::MoveCursorDownBlock( bool expandSelection )
  8003. {
  8004.     if ( m_table &&
  8005.          m_currentCellCoords != wxGridNoCellCoords  &&
  8006.          m_currentCellCoords.GetRow() < m_numRows-1 )
  8007.     {
  8008.         int row = m_currentCellCoords.GetRow();
  8009.         int col = m_currentCellCoords.GetCol();
  8010.  
  8011.         if ( m_table->IsEmptyCell(row, col) )
  8012.         {
  8013.             // starting in an empty cell: find the next block of
  8014.             // non-empty cells
  8015.             //
  8016.             while ( row < m_numRows-1 )
  8017.             {
  8018.                 row++ ;
  8019.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8020.             }
  8021.         }
  8022.         else if ( m_table->IsEmptyCell(row+1, col) )
  8023.         {
  8024.             // starting at the bottom of a block: find the next block
  8025.             //
  8026.             row++;
  8027.             while ( row < m_numRows-1 )
  8028.             {
  8029.                 row++ ;
  8030.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8031.             }
  8032.         }
  8033.         else
  8034.         {
  8035.             // starting within a block: find the bottom of the block
  8036.             //
  8037.             while ( row < m_numRows-1 )
  8038.             {
  8039.                 row++ ;
  8040.                 if ( m_table->IsEmptyCell(row, col) )
  8041.                 {
  8042.                     row-- ;
  8043.                     break;
  8044.                 }
  8045.             }
  8046.         }
  8047.  
  8048.         MakeCellVisible( row, col );
  8049.         if ( expandSelection )
  8050.         {
  8051.             m_selectingKeyboard = wxGridCellCoords( row, col );
  8052.             HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  8053.         }
  8054.         else
  8055.         {
  8056.             ClearSelection();
  8057.             SetCurrentCell( row, col );
  8058.         }
  8059.  
  8060.         return TRUE;
  8061.     }
  8062.  
  8063.     return FALSE;
  8064. }
  8065.  
  8066. bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
  8067. {
  8068.     if ( m_table &&
  8069.          m_currentCellCoords != wxGridNoCellCoords  &&
  8070.          m_currentCellCoords.GetCol() > 0 )
  8071.     {
  8072.         int row = m_currentCellCoords.GetRow();
  8073.         int col = m_currentCellCoords.GetCol();
  8074.  
  8075.         if ( m_table->IsEmptyCell(row, col) )
  8076.         {
  8077.             // starting in an empty cell: find the next block of
  8078.             // non-empty cells
  8079.             //
  8080.             while ( col > 0 )
  8081.             {
  8082.                 col-- ;
  8083.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8084.             }
  8085.         }
  8086.         else if ( m_table->IsEmptyCell(row, col-1) )
  8087.         {
  8088.             // starting at the left of a block: find the next block
  8089.             //
  8090.             col--;
  8091.             while ( col > 0 )
  8092.             {
  8093.                 col-- ;
  8094.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8095.             }
  8096.         }
  8097.         else
  8098.         {
  8099.             // starting within a block: find the left of the block
  8100.             //
  8101.             while ( col > 0 )
  8102.             {
  8103.                 col-- ;
  8104.                 if ( m_table->IsEmptyCell(row, col) )
  8105.                 {
  8106.                     col++ ;
  8107.                     break;
  8108.                 }
  8109.             }
  8110.         }
  8111.  
  8112.         MakeCellVisible( row, col );
  8113.         if ( expandSelection )
  8114.         {
  8115.             m_selectingKeyboard = wxGridCellCoords( row, col );
  8116.             HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  8117.         }
  8118.         else
  8119.         {
  8120.             ClearSelection();
  8121.             SetCurrentCell( row, col );
  8122.         }
  8123.  
  8124.         return TRUE;
  8125.     }
  8126.  
  8127.     return FALSE;
  8128. }
  8129.  
  8130. bool wxGrid::MoveCursorRightBlock( bool expandSelection )
  8131. {
  8132.     if ( m_table &&
  8133.          m_currentCellCoords != wxGridNoCellCoords  &&
  8134.          m_currentCellCoords.GetCol() < m_numCols-1 )
  8135.     {
  8136.         int row = m_currentCellCoords.GetRow();
  8137.         int col = m_currentCellCoords.GetCol();
  8138.  
  8139.         if ( m_table->IsEmptyCell(row, col) )
  8140.         {
  8141.             // starting in an empty cell: find the next block of
  8142.             // non-empty cells
  8143.             //
  8144.             while ( col < m_numCols-1 )
  8145.             {
  8146.                 col++ ;
  8147.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8148.             }
  8149.         }
  8150.         else if ( m_table->IsEmptyCell(row, col+1) )
  8151.         {
  8152.             // starting at the right of a block: find the next block
  8153.             //
  8154.             col++;
  8155.             while ( col < m_numCols-1 )
  8156.             {
  8157.                 col++ ;
  8158.                 if ( !(m_table->IsEmptyCell(row, col)) ) break;
  8159.             }
  8160.         }
  8161.         else
  8162.         {
  8163.             // starting within a block: find the right of the block
  8164.             //
  8165.             while ( col < m_numCols-1 )
  8166.             {
  8167.                 col++ ;
  8168.                 if ( m_table->IsEmptyCell(row, col) )
  8169.                 {
  8170.                     col-- ;
  8171.                     break;
  8172.                 }
  8173.             }
  8174.         }
  8175.  
  8176.         MakeCellVisible( row, col );
  8177.         if ( expandSelection )
  8178.         {
  8179.             m_selectingKeyboard = wxGridCellCoords( row, col );
  8180.             HighlightBlock( m_currentCellCoords, m_selectingKeyboard );
  8181.         }
  8182.         else
  8183.         {
  8184.             ClearSelection();
  8185.             SetCurrentCell( row, col );
  8186.         }
  8187.  
  8188.         return TRUE;
  8189.     }
  8190.  
  8191.     return FALSE;
  8192. }
  8193.  
  8194.  
  8195.  
  8196. //
  8197. // ------ Label values and formatting
  8198. //
  8199.  
  8200. void wxGrid::GetRowLabelAlignment( int *horiz, int *vert )
  8201. {
  8202.     *horiz = m_rowLabelHorizAlign;
  8203.     *vert  = m_rowLabelVertAlign;
  8204. }
  8205.  
  8206. void wxGrid::GetColLabelAlignment( int *horiz, int *vert )
  8207. {
  8208.     *horiz = m_colLabelHorizAlign;
  8209.     *vert  = m_colLabelVertAlign;
  8210. }
  8211.  
  8212. wxString wxGrid::GetRowLabelValue( int row )
  8213. {
  8214.     if ( m_table )
  8215.     {
  8216.         return m_table->GetRowLabelValue( row );
  8217.     }
  8218.     else
  8219.     {
  8220.         wxString s;
  8221.         s << row;
  8222.         return s;
  8223.     }
  8224. }
  8225.  
  8226. wxString wxGrid::GetColLabelValue( int col )
  8227. {
  8228.     if ( m_table )
  8229.     {
  8230.         return m_table->GetColLabelValue( col );
  8231.     }
  8232.     else
  8233.     {
  8234.         wxString s;
  8235.         s << col;
  8236.         return s;
  8237.     }
  8238. }
  8239.  
  8240.  
  8241. void wxGrid::SetRowLabelSize( int width )
  8242. {
  8243.     width = wxMax( width, 0 );
  8244.     if ( width != m_rowLabelWidth )
  8245.     {
  8246.         if ( width == 0 )
  8247.         {
  8248.             m_rowLabelWin->Show( FALSE );
  8249.             m_cornerLabelWin->Show( FALSE );
  8250.         }
  8251.         else if ( m_rowLabelWidth == 0 )
  8252.         {
  8253.             m_rowLabelWin->Show( TRUE );
  8254.             if ( m_colLabelHeight > 0 ) m_cornerLabelWin->Show( TRUE );
  8255.         }
  8256.  
  8257.         m_rowLabelWidth = width;
  8258.         CalcWindowSizes();
  8259.         wxScrolledWindow::Refresh( TRUE );
  8260.     }
  8261. }
  8262.  
  8263.  
  8264. void wxGrid::SetColLabelSize( int height )
  8265. {
  8266.     height = wxMax( height, 0 );
  8267.     if ( height != m_colLabelHeight )
  8268.     {
  8269.         if ( height == 0 )
  8270.         {
  8271.             m_colLabelWin->Show( FALSE );
  8272.             m_cornerLabelWin->Show( FALSE );
  8273.         }
  8274.         else if ( m_colLabelHeight == 0 )
  8275.         {
  8276.             m_colLabelWin->Show( TRUE );
  8277.             if ( m_rowLabelWidth > 0 ) m_cornerLabelWin->Show( TRUE );
  8278.         }
  8279.  
  8280.         m_colLabelHeight = height;
  8281.         CalcWindowSizes();
  8282.         wxScrolledWindow::Refresh( TRUE );
  8283.     }
  8284. }
  8285.  
  8286.  
  8287. void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
  8288. {
  8289.     if ( m_labelBackgroundColour != colour )
  8290.     {
  8291.         m_labelBackgroundColour = colour;
  8292.         m_rowLabelWin->SetBackgroundColour( colour );
  8293.         m_colLabelWin->SetBackgroundColour( colour );
  8294.         m_cornerLabelWin->SetBackgroundColour( colour );
  8295.  
  8296.         if ( !GetBatchCount() )
  8297.         {
  8298.             m_rowLabelWin->Refresh();
  8299.             m_colLabelWin->Refresh();
  8300.             m_cornerLabelWin->Refresh();
  8301.         }
  8302.     }
  8303. }
  8304.  
  8305. void wxGrid::SetLabelTextColour( const wxColour& colour )
  8306. {
  8307.     if ( m_labelTextColour != colour )
  8308.     {
  8309.         m_labelTextColour = colour;
  8310.         if ( !GetBatchCount() )
  8311.         {
  8312.             m_rowLabelWin->Refresh();
  8313.             m_colLabelWin->Refresh();
  8314.         }
  8315.     }
  8316. }
  8317.  
  8318. void wxGrid::SetLabelFont( const wxFont& font )
  8319. {
  8320.     m_labelFont = font;
  8321.     if ( !GetBatchCount() )
  8322.     {
  8323.         m_rowLabelWin->Refresh();
  8324.         m_colLabelWin->Refresh();
  8325.     }
  8326. }
  8327.  
  8328. void wxGrid::SetRowLabelAlignment( int horiz, int vert )
  8329. {
  8330.     // allow old (incorrect) defs to be used
  8331.     switch ( horiz )
  8332.     {
  8333.         case wxLEFT:   horiz = wxALIGN_LEFT; break;
  8334.         case wxRIGHT:  horiz = wxALIGN_RIGHT; break;
  8335.         case wxCENTRE: horiz = wxALIGN_CENTRE; break;
  8336.     }
  8337.  
  8338.     switch ( vert )
  8339.     {
  8340.         case wxTOP:    vert = wxALIGN_TOP;    break;
  8341.         case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
  8342.         case wxCENTRE: vert = wxALIGN_CENTRE; break;
  8343.     }
  8344.  
  8345.     if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
  8346.     {
  8347.         m_rowLabelHorizAlign = horiz;
  8348.     }
  8349.  
  8350.     if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
  8351.     {
  8352.         m_rowLabelVertAlign = vert;
  8353.     }
  8354.  
  8355.     if ( !GetBatchCount() )
  8356.     {
  8357.         m_rowLabelWin->Refresh();
  8358.     }
  8359. }
  8360.  
  8361. void wxGrid::SetColLabelAlignment( int horiz, int vert )
  8362. {
  8363.     // allow old (incorrect) defs to be used
  8364.     switch ( horiz )
  8365.     {
  8366.         case wxLEFT:   horiz = wxALIGN_LEFT; break;
  8367.         case wxRIGHT:  horiz = wxALIGN_RIGHT; break;
  8368.         case wxCENTRE: horiz = wxALIGN_CENTRE; break;
  8369.     }
  8370.  
  8371.     switch ( vert )
  8372.     {
  8373.         case wxTOP:    vert = wxALIGN_TOP;    break;
  8374.         case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
  8375.         case wxCENTRE: vert = wxALIGN_CENTRE; break;
  8376.     }
  8377.  
  8378.     if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
  8379.     {
  8380.         m_colLabelHorizAlign = horiz;
  8381.     }
  8382.  
  8383.     if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
  8384.     {
  8385.         m_colLabelVertAlign = vert;
  8386.     }
  8387.  
  8388.     if ( !GetBatchCount() )
  8389.     {
  8390.         m_colLabelWin->Refresh();
  8391.     }
  8392. }
  8393.  
  8394. void wxGrid::SetRowLabelValue( int row, const wxString& s )
  8395. {
  8396.     if ( m_table )
  8397.     {
  8398.         m_table->SetRowLabelValue( row, s );
  8399.         if ( !GetBatchCount() )
  8400.         {
  8401.             wxRect rect = CellToRect( row, 0);
  8402.             if ( rect.height > 0 )
  8403.             {
  8404.                 CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
  8405.                 rect.x = 0;
  8406.                 rect.width = m_rowLabelWidth;
  8407.                 m_rowLabelWin->Refresh( TRUE, &rect );
  8408.             }
  8409.         }
  8410.     }
  8411. }
  8412.  
  8413. void wxGrid::SetColLabelValue( int col, const wxString& s )
  8414. {
  8415.     if ( m_table )
  8416.     {
  8417.         m_table->SetColLabelValue( col, s );
  8418.         if ( !GetBatchCount() )
  8419.         {
  8420.             wxRect rect = CellToRect( 0, col );
  8421.             if ( rect.width > 0 )
  8422.             {
  8423.                 CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
  8424.                 rect.y = 0;
  8425.                 rect.height = m_colLabelHeight;
  8426.                 m_colLabelWin->Refresh( TRUE, &rect );
  8427.             }
  8428.         }
  8429.     }
  8430. }
  8431.  
  8432. void wxGrid::SetGridLineColour( const wxColour& colour )
  8433. {
  8434.     if ( m_gridLineColour != colour )
  8435.     {
  8436.         m_gridLineColour = colour;
  8437.  
  8438.         wxClientDC dc( m_gridWin );
  8439.         PrepareDC( dc );
  8440.         DrawAllGridLines( dc, wxRegion() );
  8441.     }
  8442. }
  8443.  
  8444.  
  8445. void wxGrid::SetCellHighlightColour( const wxColour& colour )
  8446. {
  8447.     if ( m_cellHighlightColour != colour )
  8448.     {
  8449.         m_cellHighlightColour = colour;
  8450.  
  8451.         wxClientDC dc( m_gridWin );
  8452.         PrepareDC( dc );
  8453.         wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
  8454.         DrawCellHighlight(dc, attr);
  8455.         attr->DecRef();
  8456.     }
  8457. }
  8458.  
  8459. void wxGrid::SetCellHighlightPenWidth(int width)
  8460. {
  8461.     if (m_cellHighlightPenWidth != width) {
  8462.         m_cellHighlightPenWidth = width;
  8463.  
  8464.         // Just redrawing the cell highlight is not enough since that won't
  8465.         // make any visible change if the the thickness is getting smaller.
  8466.         int row = m_currentCellCoords.GetRow();
  8467.         int col = m_currentCellCoords.GetCol();
  8468.         if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
  8469.             return;
  8470.         wxRect rect = CellToRect(row, col);
  8471.         m_gridWin->Refresh(TRUE, &rect);
  8472.     }
  8473. }
  8474.  
  8475. void wxGrid::SetCellHighlightROPenWidth(int width)
  8476. {
  8477.     if (m_cellHighlightROPenWidth != width) {
  8478.         m_cellHighlightROPenWidth = width;
  8479.  
  8480.         // Just redrawing the cell highlight is not enough since that won't
  8481.         // make any visible change if the the thickness is getting smaller.
  8482.         int row = m_currentCellCoords.GetRow();
  8483.         int col = m_currentCellCoords.GetCol();
  8484.         if ( GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
  8485.             return;
  8486.         wxRect rect = CellToRect(row, col);
  8487.         m_gridWin->Refresh(TRUE, &rect);
  8488.     }
  8489. }
  8490.  
  8491. void wxGrid::EnableGridLines( bool enable )
  8492. {
  8493.     if ( enable != m_gridLinesEnabled )
  8494.     {
  8495.         m_gridLinesEnabled = enable;
  8496.  
  8497.         if ( !GetBatchCount() )
  8498.         {
  8499.             if ( enable )
  8500.             {
  8501.                 wxClientDC dc( m_gridWin );
  8502.                 PrepareDC( dc );
  8503.                 DrawAllGridLines( dc, wxRegion() );
  8504.             }
  8505.             else
  8506.             {
  8507.                 m_gridWin->Refresh();
  8508.             }
  8509.         }
  8510.     }
  8511. }
  8512.  
  8513.  
  8514. int wxGrid::GetDefaultRowSize()
  8515. {
  8516.     return m_defaultRowHeight;
  8517. }
  8518.  
  8519. int wxGrid::GetRowSize( int row )
  8520. {
  8521.     wxCHECK_MSG( row >= 0 && row < m_numRows, 0, _T("invalid row index") );
  8522.  
  8523.     return GetRowHeight(row);
  8524. }
  8525.  
  8526. int wxGrid::GetDefaultColSize()
  8527. {
  8528.     return m_defaultColWidth;
  8529. }
  8530.  
  8531. int wxGrid::GetColSize( int col )
  8532. {
  8533.     wxCHECK_MSG( col >= 0 && col < m_numCols, 0, _T("invalid column index") );
  8534.  
  8535.     return GetColWidth(col);
  8536. }
  8537.  
  8538. // ============================================================================
  8539. // access to the grid attributes: each of them has a default value in the grid
  8540. // itself and may be overidden on a per-cell basis
  8541. // ============================================================================
  8542.  
  8543. // ----------------------------------------------------------------------------
  8544. // setting default attributes
  8545. // ----------------------------------------------------------------------------
  8546.  
  8547. void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
  8548. {
  8549.     m_defaultCellAttr->SetBackgroundColour(col);
  8550. #ifdef __WXGTK__
  8551.     m_gridWin->SetBackgroundColour(col);
  8552. #endif
  8553. }
  8554.  
  8555. void wxGrid::SetDefaultCellTextColour( const wxColour& col )
  8556. {
  8557.     m_defaultCellAttr->SetTextColour(col);
  8558. }
  8559.  
  8560. void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
  8561. {
  8562.     m_defaultCellAttr->SetAlignment(horiz, vert);
  8563. }
  8564.  
  8565. void wxGrid::SetDefaultCellOverflow( bool allow )
  8566. {
  8567.     m_defaultCellAttr->SetOverflow(allow);
  8568. }
  8569.  
  8570. void wxGrid::SetDefaultCellFont( const wxFont& font )
  8571. {
  8572.     m_defaultCellAttr->SetFont(font);
  8573. }
  8574.  
  8575. void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
  8576. {
  8577.     m_defaultCellAttr->SetRenderer(renderer);
  8578. }
  8579.  
  8580. void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
  8581. {
  8582.     m_defaultCellAttr->SetEditor(editor);
  8583. }
  8584.  
  8585. // ----------------------------------------------------------------------------
  8586. // access to the default attrbiutes
  8587. // ----------------------------------------------------------------------------
  8588.  
  8589. wxColour wxGrid::GetDefaultCellBackgroundColour()
  8590. {
  8591.     return m_defaultCellAttr->GetBackgroundColour();
  8592. }
  8593.  
  8594. wxColour wxGrid::GetDefaultCellTextColour()
  8595. {
  8596.     return m_defaultCellAttr->GetTextColour();
  8597. }
  8598.  
  8599. wxFont wxGrid::GetDefaultCellFont()
  8600. {
  8601.     return m_defaultCellAttr->GetFont();
  8602. }
  8603.  
  8604. void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert )
  8605. {
  8606.     m_defaultCellAttr->GetAlignment(horiz, vert);
  8607. }
  8608.  
  8609. bool wxGrid::GetDefaultCellOverflow()
  8610. {
  8611.     return m_defaultCellAttr->GetOverflow();
  8612. }
  8613.  
  8614. wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
  8615. {
  8616.     return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
  8617. }
  8618.  
  8619. wxGridCellEditor *wxGrid::GetDefaultEditor() const
  8620. {
  8621.     return m_defaultCellAttr->GetEditor(NULL,0,0);
  8622. }
  8623.  
  8624. // ----------------------------------------------------------------------------
  8625. // access to cell attributes
  8626. // ----------------------------------------------------------------------------
  8627.  
  8628. wxColour wxGrid::GetCellBackgroundColour(int row, int col)
  8629. {
  8630.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8631.     wxColour colour = attr->GetBackgroundColour();
  8632.     attr->DecRef();
  8633.     return colour;
  8634. }
  8635.  
  8636. wxColour wxGrid::GetCellTextColour( int row, int col )
  8637. {
  8638.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8639.     wxColour colour = attr->GetTextColour();
  8640.     attr->DecRef();
  8641.     return colour;
  8642. }
  8643.  
  8644. wxFont wxGrid::GetCellFont( int row, int col )
  8645. {
  8646.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8647.     wxFont font = attr->GetFont();
  8648.     attr->DecRef();
  8649.     return font;
  8650. }
  8651.  
  8652. void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
  8653. {
  8654.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8655.     attr->GetAlignment(horiz, vert);
  8656.     attr->DecRef();
  8657. }
  8658.  
  8659. bool wxGrid::GetCellOverflow( int row, int col )
  8660. {
  8661.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8662.     bool allow = attr->GetOverflow();
  8663.     attr->DecRef();
  8664.     return allow;
  8665. }
  8666.  
  8667. void wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols )
  8668. {
  8669.     wxGridCellAttr *attr = GetCellAttr(row, col);
  8670.     attr->GetSize( num_rows, num_cols );
  8671.     attr->DecRef();
  8672. }
  8673.  
  8674. wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col)
  8675. {
  8676.     wxGridCellAttr* attr = GetCellAttr(row, col);
  8677.     wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
  8678.     attr->DecRef();
  8679.  
  8680.     return renderer;
  8681. }
  8682.  
  8683. wxGridCellEditor* wxGrid::GetCellEditor(int row, int col)
  8684. {
  8685.     wxGridCellAttr* attr = GetCellAttr(row, col);
  8686.     wxGridCellEditor* editor = attr->GetEditor(this, row, col);
  8687.     attr->DecRef();
  8688.  
  8689.     return editor;
  8690. }
  8691.  
  8692. bool wxGrid::IsReadOnly(int row, int col) const
  8693. {
  8694.     wxGridCellAttr* attr = GetCellAttr(row, col);
  8695.     bool isReadOnly = attr->IsReadOnly();
  8696.     attr->DecRef();
  8697.     return isReadOnly;
  8698. }
  8699.  
  8700. // ----------------------------------------------------------------------------
  8701. // attribute support: cache, automatic provider creation, ...
  8702. // ----------------------------------------------------------------------------
  8703.  
  8704. bool wxGrid::CanHaveAttributes()
  8705. {
  8706.     if ( !m_table )
  8707.     {
  8708.         return FALSE;
  8709.     }
  8710.  
  8711.     return m_table->CanHaveAttributes();
  8712. }
  8713.  
  8714. void wxGrid::ClearAttrCache()
  8715. {
  8716.     if ( m_attrCache.row != -1 )
  8717.     {
  8718.         wxSafeDecRef(m_attrCache.attr);
  8719.         m_attrCache.attr = NULL;
  8720.         m_attrCache.row = -1;
  8721.     }
  8722. }
  8723.  
  8724. void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
  8725. {
  8726.     if ( attr != NULL )
  8727.     {
  8728.         wxGrid *self = (wxGrid *)this;  // const_cast
  8729.  
  8730.         self->ClearAttrCache();
  8731.         self->m_attrCache.row = row;
  8732.         self->m_attrCache.col = col;
  8733.         self->m_attrCache.attr = attr;
  8734.         wxSafeIncRef(attr);
  8735.     }
  8736. }
  8737.  
  8738. bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
  8739. {
  8740.     if ( row == m_attrCache.row && col == m_attrCache.col )
  8741.     {
  8742.         *attr = m_attrCache.attr;
  8743.         wxSafeIncRef(m_attrCache.attr);
  8744.  
  8745. #ifdef DEBUG_ATTR_CACHE
  8746.         gs_nAttrCacheHits++;
  8747. #endif
  8748.  
  8749.         return TRUE;
  8750.     }
  8751.     else
  8752.     {
  8753. #ifdef DEBUG_ATTR_CACHE
  8754.         gs_nAttrCacheMisses++;
  8755. #endif
  8756.         return FALSE;
  8757.     }
  8758. }
  8759.  
  8760. wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
  8761. {
  8762.     wxGridCellAttr *attr = NULL;
  8763.     // Additional test to avoid looking at the cache e.g. for
  8764.     // wxNoCellCoords, as this will confuse memory management.
  8765.     if ( row >= 0 )
  8766.     {
  8767.         if ( !LookupAttr(row, col, &attr) )
  8768.         {
  8769.             attr = m_table ? m_table->GetAttr(row, col , wxGridCellAttr::Any)
  8770.                            : (wxGridCellAttr *)NULL;
  8771.             CacheAttr(row, col, attr);
  8772.         }
  8773.     }
  8774.     if (attr)
  8775.     {
  8776.         attr->SetDefAttr(m_defaultCellAttr);
  8777.     }
  8778.     else
  8779.     {
  8780.         attr = m_defaultCellAttr;
  8781.         attr->IncRef();
  8782.     }
  8783.  
  8784.     return attr;
  8785. }
  8786.  
  8787. wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
  8788. {
  8789.     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
  8790.  
  8791.     wxCHECK_MSG( m_table, attr,
  8792.                   _T("we may only be called if CanHaveAttributes() returned TRUE and then m_table should be !NULL") );
  8793.  
  8794.     attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell);
  8795.     if ( !attr )
  8796.     {
  8797.         attr = new wxGridCellAttr(m_defaultCellAttr);
  8798.  
  8799.         // artificially inc the ref count to match DecRef() in caller
  8800.         attr->IncRef();
  8801.         m_table->SetAttr(attr, row, col);
  8802.     }
  8803.  
  8804.     return attr;
  8805. }
  8806.  
  8807. // ----------------------------------------------------------------------------
  8808. // setting column attributes (wrappers around SetColAttr)
  8809. // ----------------------------------------------------------------------------
  8810.  
  8811. void wxGrid::SetColFormatBool(int col)
  8812. {
  8813.     SetColFormatCustom(col, wxGRID_VALUE_BOOL);
  8814. }
  8815.  
  8816. void wxGrid::SetColFormatNumber(int col)
  8817. {
  8818.     SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
  8819. }
  8820.  
  8821. void wxGrid::SetColFormatFloat(int col, int width, int precision)
  8822. {
  8823.     wxString typeName = wxGRID_VALUE_FLOAT;
  8824.     if ( (width != -1) || (precision != -1) )
  8825.     {
  8826.         typeName << _T(':') << width << _T(',') << precision;
  8827.     }
  8828.  
  8829.     SetColFormatCustom(col, typeName);
  8830. }
  8831.  
  8832. void wxGrid::SetColFormatCustom(int col, const wxString& typeName)
  8833. {
  8834.     wxGridCellAttr *attr = (wxGridCellAttr *)NULL;
  8835.  
  8836.     attr = m_table->GetAttr(-1, col, wxGridCellAttr::Col );
  8837.     if(!attr)
  8838.         attr = new wxGridCellAttr;
  8839.     wxGridCellRenderer *renderer = GetDefaultRendererForType(typeName);
  8840.     attr->SetRenderer(renderer);
  8841.  
  8842.     SetColAttr(col, attr);
  8843.  
  8844. }
  8845.  
  8846. // ----------------------------------------------------------------------------
  8847. // setting cell attributes: this is forwarded to the table
  8848. // ----------------------------------------------------------------------------
  8849.  
  8850. void wxGrid::SetAttr(int row, int col, wxGridCellAttr *attr)
  8851. {
  8852.     if ( CanHaveAttributes() )
  8853.     {
  8854.         m_table->SetAttr(attr, row, col);
  8855.         ClearAttrCache();
  8856.     }
  8857.     else
  8858.     {
  8859.         wxSafeDecRef(attr);
  8860.     }
  8861. }
  8862.  
  8863. void wxGrid::SetRowAttr(int row, wxGridCellAttr *attr)
  8864. {
  8865.     if ( CanHaveAttributes() )
  8866.     {
  8867.         m_table->SetRowAttr(attr, row);
  8868.         ClearAttrCache();
  8869.     }
  8870.     else
  8871.     {
  8872.         wxSafeDecRef(attr);
  8873.     }
  8874. }
  8875.  
  8876. void wxGrid::SetColAttr(int col, wxGridCellAttr *attr)
  8877. {
  8878.     if ( CanHaveAttributes() )
  8879.     {
  8880.         m_table->SetColAttr(attr, col);
  8881.         ClearAttrCache();
  8882.     }
  8883.     else
  8884.     {
  8885.         wxSafeDecRef(attr);
  8886.     }
  8887. }
  8888.  
  8889. void wxGrid::SetCellBackgroundColour( int row, int col, const wxColour& colour )
  8890. {
  8891.     if ( CanHaveAttributes() )
  8892.     {
  8893.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8894.         attr->SetBackgroundColour(colour);
  8895.         attr->DecRef();
  8896.     }
  8897. }
  8898.  
  8899. void wxGrid::SetCellTextColour( int row, int col, const wxColour& colour )
  8900. {
  8901.     if ( CanHaveAttributes() )
  8902.     {
  8903.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8904.         attr->SetTextColour(colour);
  8905.         attr->DecRef();
  8906.     }
  8907. }
  8908.  
  8909. void wxGrid::SetCellFont( int row, int col, const wxFont& font )
  8910. {
  8911.     if ( CanHaveAttributes() )
  8912.     {
  8913.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8914.         attr->SetFont(font);
  8915.         attr->DecRef();
  8916.     }
  8917. }
  8918.  
  8919. void wxGrid::SetCellAlignment( int row, int col, int horiz, int vert )
  8920. {
  8921.     if ( CanHaveAttributes() )
  8922.     {
  8923.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8924.         attr->SetAlignment(horiz, vert);
  8925.         attr->DecRef();
  8926.     }
  8927. }
  8928.  
  8929. void wxGrid::SetCellOverflow( int row, int col, bool allow )
  8930. {
  8931.     if ( CanHaveAttributes() )
  8932.     {
  8933.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8934.         attr->SetOverflow(allow);
  8935.         attr->DecRef();
  8936.     }
  8937. }
  8938.  
  8939. void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols )
  8940. {
  8941.     if ( CanHaveAttributes() )
  8942.     {
  8943.         int cell_rows, cell_cols;
  8944.  
  8945.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  8946.         attr->GetSize(&cell_rows, &cell_cols);
  8947.         attr->SetSize(num_rows, num_cols);
  8948.         attr->DecRef();
  8949.  
  8950.         // Cannot set the size of a cell to 0 or negative values
  8951.         // While it is perfectly legal to do that, this function cannot
  8952.         // handle all the possibilies, do it by hand by getting the CellAttr.
  8953.         // You can only set the size of a cell to 1,1 or greater with this fn
  8954.         wxASSERT_MSG( !((cell_rows < 1) || (cell_cols < 1)),
  8955.                       wxT("wxGrid::SetCellSize setting cell size that is already part of another cell"));
  8956.         wxASSERT_MSG( !((num_rows < 1) || (num_cols < 1)),
  8957.                       wxT("wxGrid::SetCellSize setting cell size to < 1"));
  8958.  
  8959.         // if this was already a multicell then "turn off" the other cells first
  8960.         if ((cell_rows > 1) || (cell_rows > 1))
  8961.         {
  8962.             int i, j;
  8963.             for (j=row; j<row+cell_rows; j++)
  8964.             {
  8965.                 for (i=col; i<col+cell_cols; i++)
  8966.                 {
  8967.                     if ((i != col) || (j != row))
  8968.                     {
  8969.                         wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
  8970.                         attr_stub->SetSize( 1, 1 );
  8971.                         attr_stub->DecRef();
  8972.                     }
  8973.                 }
  8974.             }
  8975.         }
  8976.  
  8977.         // mark the cells that will be covered by this cell to
  8978.         // negative or zero values to point back at this cell
  8979.         if (((num_rows > 1) || (num_cols > 1)) && (num_rows >= 1) && (num_cols >= 1))
  8980.         {
  8981.             int i, j;
  8982.             for (j=row; j<row+num_rows; j++)
  8983.             {
  8984.                 for (i=col; i<col+num_cols; i++)
  8985.                 {
  8986.                     if ((i != col) || (j != row))
  8987.                     {
  8988.                         wxGridCellAttr *attr_stub = GetOrCreateCellAttr(j, i);
  8989.                         attr_stub->SetSize( row-j, col-i );
  8990.                         attr_stub->DecRef();
  8991.                     }
  8992.                 }
  8993.             }
  8994.         }
  8995.     }
  8996. }
  8997.  
  8998. void wxGrid::SetCellRenderer(int row, int col, wxGridCellRenderer *renderer)
  8999. {
  9000.     if ( CanHaveAttributes() )
  9001.     {
  9002.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  9003.         attr->SetRenderer(renderer);
  9004.         attr->DecRef();
  9005.     }
  9006. }
  9007.  
  9008. void wxGrid::SetCellEditor(int row, int col, wxGridCellEditor* editor)
  9009. {
  9010.     if ( CanHaveAttributes() )
  9011.     {
  9012.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  9013.         attr->SetEditor(editor);
  9014.         attr->DecRef();
  9015.     }
  9016. }
  9017.  
  9018. void wxGrid::SetReadOnly(int row, int col, bool isReadOnly)
  9019. {
  9020.     if ( CanHaveAttributes() )
  9021.     {
  9022.         wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
  9023.         attr->SetReadOnly(isReadOnly);
  9024.         attr->DecRef();
  9025.     }
  9026. }
  9027.  
  9028. // ----------------------------------------------------------------------------
  9029. // Data type registration
  9030. // ----------------------------------------------------------------------------
  9031.  
  9032. void wxGrid::RegisterDataType(const wxString& typeName,
  9033.                               wxGridCellRenderer* renderer,
  9034.                               wxGridCellEditor* editor)
  9035. {
  9036.     m_typeRegistry->RegisterDataType(typeName, renderer, editor);
  9037. }
  9038.  
  9039.  
  9040. wxGridCellEditor* wxGrid::GetDefaultEditorForCell(int row, int col) const
  9041. {
  9042.     wxString typeName = m_table->GetTypeName(row, col);
  9043.     return GetDefaultEditorForType(typeName);
  9044. }
  9045.  
  9046. wxGridCellRenderer* wxGrid::GetDefaultRendererForCell(int row, int col) const
  9047. {
  9048.     wxString typeName = m_table->GetTypeName(row, col);
  9049.     return GetDefaultRendererForType(typeName);
  9050. }
  9051.  
  9052. wxGridCellEditor*
  9053. wxGrid::GetDefaultEditorForType(const wxString& typeName) const
  9054. {
  9055.     int index = m_typeRegistry->FindOrCloneDataType(typeName);
  9056.     if ( index == wxNOT_FOUND )
  9057.     {
  9058.         wxFAIL_MSG(wxT("Unknown data type name"));
  9059.  
  9060.         return NULL;
  9061.     }
  9062.  
  9063.     return m_typeRegistry->GetEditor(index);
  9064. }
  9065.  
  9066. wxGridCellRenderer*
  9067. wxGrid::GetDefaultRendererForType(const wxString& typeName) const
  9068. {
  9069.     int index = m_typeRegistry->FindOrCloneDataType(typeName);
  9070.     if ( index == wxNOT_FOUND )
  9071.     {
  9072.         wxFAIL_MSG(wxT("Unknown data type name"));
  9073.  
  9074.         return NULL;
  9075.     }
  9076.  
  9077.     return m_typeRegistry->GetRenderer(index);
  9078. }
  9079.  
  9080.  
  9081. // ----------------------------------------------------------------------------
  9082. // row/col size
  9083. // ----------------------------------------------------------------------------
  9084.  
  9085. void wxGrid::EnableDragRowSize( bool enable )
  9086. {
  9087.     m_canDragRowSize = enable;
  9088. }
  9089.  
  9090.  
  9091. void wxGrid::EnableDragColSize( bool enable )
  9092. {
  9093.     m_canDragColSize = enable;
  9094. }
  9095.  
  9096. void wxGrid::EnableDragGridSize( bool enable )
  9097. {
  9098.     m_canDragGridSize = enable;
  9099. }
  9100.  
  9101.  
  9102. void wxGrid::SetDefaultRowSize( int height, bool resizeExistingRows )
  9103. {
  9104.     m_defaultRowHeight = wxMax( height, WXGRID_MIN_ROW_HEIGHT );
  9105.  
  9106.     if ( resizeExistingRows )
  9107.     {
  9108.         // since we are resizing all rows to the default row size,
  9109.         // we can simply clear the row heights and row bottoms
  9110.         // arrays (which also allows us to take advantage of
  9111.         // some speed optimisations)
  9112.         m_rowHeights.Empty();
  9113.         m_rowBottoms.Empty();
  9114.         if ( !GetBatchCount() )
  9115.             CalcDimensions();
  9116.     }
  9117. }
  9118.  
  9119. void wxGrid::SetRowSize( int row, int height )
  9120. {
  9121.     wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") );
  9122.  
  9123.     if ( m_rowHeights.IsEmpty() )
  9124.     {
  9125.         // need to really create the array
  9126.         InitRowHeights();
  9127.     }
  9128.  
  9129.     int h = wxMax( 0, height );
  9130.     int diff = h - m_rowHeights[row];
  9131.  
  9132.     m_rowHeights[row] = h;
  9133.     int i;
  9134.     for ( i = row;  i < m_numRows;  i++ )
  9135.     {
  9136.         m_rowBottoms[i] += diff;
  9137.     }
  9138.     if ( !GetBatchCount() )
  9139.         CalcDimensions();
  9140. }
  9141.  
  9142. void wxGrid::SetDefaultColSize( int width, bool resizeExistingCols )
  9143. {
  9144.     m_defaultColWidth = wxMax( width, WXGRID_MIN_COL_WIDTH );
  9145.  
  9146.     if ( resizeExistingCols )
  9147.     {
  9148.         // since we are resizing all columns to the default column size,
  9149.         // we can simply clear the col widths and col rights
  9150.         // arrays (which also allows us to take advantage of
  9151.         // some speed optimisations)
  9152.         m_colWidths.Empty();
  9153.         m_colRights.Empty();
  9154.         if ( !GetBatchCount() )
  9155.             CalcDimensions();
  9156.     }
  9157. }
  9158.  
  9159. void wxGrid::SetColSize( int col, int width )
  9160. {
  9161.     wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") );
  9162.  
  9163.     // should we check that it's bigger than GetColMinimalWidth(col) here?
  9164.  
  9165.     if ( m_colWidths.IsEmpty() )
  9166.     {
  9167.         // need to really create the array
  9168.         InitColWidths();
  9169.     }
  9170.  
  9171.     int w = wxMax( 0, width );
  9172.     int diff = w - m_colWidths[col];
  9173.     m_colWidths[col] = w;
  9174.  
  9175.     int i;
  9176.     for ( i = col;  i < m_numCols;  i++ )
  9177.     {
  9178.         m_colRights[i] += diff;
  9179.     }
  9180.     if ( !GetBatchCount() )
  9181.         CalcDimensions();
  9182. }
  9183.  
  9184.  
  9185. void wxGrid::SetColMinimalWidth( int col, int width )
  9186. {
  9187.     m_colMinWidths.Put(col, width);
  9188. }
  9189.  
  9190. void wxGrid::SetRowMinimalHeight( int row, int width )
  9191. {
  9192.     m_rowMinHeights.Put(row, width);
  9193. }
  9194.  
  9195. int wxGrid::GetColMinimalWidth(int col) const
  9196. {
  9197.     long value = m_colMinWidths.Get(col);
  9198.     return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_COL_WIDTH;
  9199. }
  9200.  
  9201. int wxGrid::GetRowMinimalHeight(int row) const
  9202. {
  9203.     long value = m_rowMinHeights.Get(row);
  9204.     return value != wxNOT_FOUND ? (int)value : WXGRID_MIN_ROW_HEIGHT;
  9205. }
  9206.  
  9207. // ----------------------------------------------------------------------------
  9208. // auto sizing
  9209. // ----------------------------------------------------------------------------
  9210.  
  9211. void wxGrid::AutoSizeColOrRow( int colOrRow, bool setAsMin, bool column )
  9212. {
  9213.     wxClientDC dc(m_gridWin);
  9214.  
  9215.     // init both of them to avoid compiler warnings, even if weo nly need one
  9216.     int row = -1,
  9217.         col = -1;
  9218.     if ( column )
  9219.         col = colOrRow;
  9220.     else
  9221.         row = colOrRow;
  9222.  
  9223.     wxCoord extent, extentMax = 0;
  9224.     int max = column ? m_numRows : m_numCols;
  9225.     for ( int rowOrCol = 0; rowOrCol < max; rowOrCol++ )
  9226.     {
  9227.         if ( column )
  9228.             row = rowOrCol;
  9229.         else
  9230.             col = rowOrCol;
  9231.  
  9232.         wxGridCellAttr* attr = GetCellAttr(row, col);
  9233.         wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
  9234.         if ( renderer )
  9235.         {
  9236.             wxSize size = renderer->GetBestSize(*this, *attr, dc, row, col);
  9237.             extent = column ? size.x : size.y;
  9238.             if ( extent > extentMax )
  9239.             {
  9240.                 extentMax = extent;
  9241.             }
  9242.  
  9243.             renderer->DecRef();
  9244.         }
  9245.  
  9246.         attr->DecRef();
  9247.     }
  9248.  
  9249.     // now also compare with the column label extent
  9250.     wxCoord w, h;
  9251.     dc.SetFont( GetLabelFont() );
  9252.  
  9253.     if ( column )
  9254.         dc.GetTextExtent( GetColLabelValue(col), &w, &h );
  9255.     else
  9256.         dc.GetTextExtent( GetRowLabelValue(row), &w, &h );
  9257.  
  9258.     extent = column ? w : h;
  9259.     if ( extent > extentMax )
  9260.     {
  9261.         extentMax = extent;
  9262.     }
  9263.  
  9264.     if ( !extentMax )
  9265.     {
  9266.         // empty column - give default extent (notice that if extentMax is less
  9267.         // than default extent but != 0, it's ok)
  9268.         extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
  9269.     }
  9270.     else
  9271.     {
  9272.         if ( column )
  9273.         {
  9274.             // leave some space around text
  9275.             extentMax += 10;
  9276.         }
  9277.         else
  9278.         {
  9279.             extentMax += 6;
  9280.         }
  9281.     }
  9282.  
  9283.     if ( column )
  9284.     {
  9285.         SetColSize(col, extentMax);
  9286.         if ( !GetBatchCount() )
  9287.         {
  9288.             int cw, ch, dummy;
  9289.             m_gridWin->GetClientSize( &cw, &ch );
  9290.             wxRect rect ( CellToRect( 0, col ) );
  9291.             rect.y = 0;
  9292.             CalcScrolledPosition(rect.x, 0, &rect.x, &dummy);
  9293.             rect.width = cw - rect.x;
  9294.             rect.height = m_colLabelHeight;
  9295.             m_colLabelWin->Refresh( TRUE, &rect );
  9296.         }
  9297.     }
  9298.     else
  9299.     {
  9300.         SetRowSize(row, extentMax);
  9301.         if ( !GetBatchCount() )
  9302.         {
  9303.             int cw, ch, dummy;
  9304.             m_gridWin->GetClientSize( &cw, &ch );
  9305.             wxRect rect ( CellToRect( row, 0 ) );
  9306.             rect.x = 0;
  9307.             CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
  9308.             rect.width = m_rowLabelWidth;
  9309.             rect.height = ch - rect.y;
  9310.             m_rowLabelWin->Refresh( TRUE, &rect );
  9311.         }
  9312.     }
  9313.     if ( setAsMin )
  9314.     {
  9315.         if ( column )
  9316.             SetColMinimalWidth(col, extentMax);
  9317.         else
  9318.             SetRowMinimalHeight(row, extentMax);
  9319.     }
  9320. }
  9321.  
  9322. int wxGrid::SetOrCalcColumnSizes(bool calcOnly, bool setAsMin)
  9323. {
  9324.     int width = m_rowLabelWidth;
  9325.  
  9326.     if ( !calcOnly )
  9327.         BeginBatch();
  9328.  
  9329.     for ( int col = 0; col < m_numCols; col++ )
  9330.     {
  9331.         if ( !calcOnly )
  9332.         {
  9333.             AutoSizeColumn(col, setAsMin);
  9334.         }
  9335.  
  9336.         width += GetColWidth(col);
  9337.     }
  9338.  
  9339.     if ( !calcOnly )
  9340.         EndBatch();
  9341.  
  9342.     return width;
  9343. }
  9344.  
  9345. int wxGrid::SetOrCalcRowSizes(bool calcOnly, bool setAsMin)
  9346. {
  9347.     int height = m_colLabelHeight;
  9348.  
  9349.     if ( !calcOnly )
  9350.         BeginBatch();
  9351.  
  9352.     for ( int row = 0; row < m_numRows; row++ )
  9353.     {
  9354.         if ( !calcOnly )
  9355.         {
  9356.             AutoSizeRow(row, setAsMin);
  9357.         }
  9358.  
  9359.         height += GetRowHeight(row);
  9360.     }
  9361.  
  9362.     if ( !calcOnly )
  9363.         EndBatch();
  9364.  
  9365.     return height;
  9366. }
  9367.  
  9368. void wxGrid::AutoSize()
  9369. {
  9370.     BeginBatch();
  9371.  
  9372.     wxSize size(SetOrCalcColumnSizes(FALSE), SetOrCalcRowSizes(FALSE));
  9373.  
  9374.     // round up the size to a multiple of scroll step - this ensures that we
  9375.     // won't get the scrollbars if we're sized exactly to this width
  9376.     // CalcDimension adds m_extraWidth + 1 etc. to calculate the necessary
  9377.     // scrollbar steps
  9378.     wxSize sizeFit(GetScrollX(size.x + m_extraWidth + 1) * GRID_SCROLL_LINE_X,
  9379.                    GetScrollY(size.y + m_extraHeight + 1) * GRID_SCROLL_LINE_Y);
  9380.  
  9381.     // distribute the extra space between the columns/rows to avoid having
  9382.     // extra white space
  9383.  
  9384.     // Remove the extra m_extraWidth + 1 added above
  9385.     wxCoord diff = sizeFit.x - size.x + (m_extraWidth + 1);
  9386.     if ( diff && m_numCols )
  9387.     {
  9388.         // try to resize the columns uniformly
  9389.         wxCoord diffPerCol = diff / m_numCols;
  9390.         if ( diffPerCol )
  9391.         {
  9392.             for ( int col = 0; col < m_numCols; col++ )
  9393.             {
  9394.                 SetColSize(col, GetColWidth(col) + diffPerCol);
  9395.             }
  9396.         }
  9397.  
  9398.         // add remaining amount to the last columns
  9399.         diff -= diffPerCol * m_numCols;
  9400.         if ( diff )
  9401.         {
  9402.             for ( int col = m_numCols - 1; col >= m_numCols - diff; col-- )
  9403.             {
  9404.                 SetColSize(col, GetColWidth(col) + 1);
  9405.             }
  9406.         }
  9407.     }
  9408.  
  9409.     // same for rows
  9410.     diff = sizeFit.y - size.y - (m_extraHeight + 1);
  9411.     if ( diff && m_numRows )
  9412.     {
  9413.         // try to resize the columns uniformly
  9414.         wxCoord diffPerRow = diff / m_numRows;
  9415.         if ( diffPerRow )
  9416.         {
  9417.             for ( int row = 0; row < m_numRows; row++ )
  9418.             {
  9419.                 SetRowSize(row, GetRowHeight(row) + diffPerRow);
  9420.             }
  9421.         }
  9422.  
  9423.         // add remaining amount to the last rows
  9424.         diff -= diffPerRow * m_numRows;
  9425.         if ( diff )
  9426.         {
  9427.             for ( int row = m_numRows - 1; row >= m_numRows - diff; row-- )
  9428.             {
  9429.                 SetRowSize(row, GetRowHeight(row) + 1);
  9430.             }
  9431.         }
  9432.     }
  9433.  
  9434.     EndBatch();
  9435.  
  9436.     SetClientSize(sizeFit);
  9437. }
  9438.  
  9439. wxSize wxGrid::DoGetBestSize() const
  9440. {
  9441.     // don't set sizes, only calculate them
  9442.     wxGrid *self = (wxGrid *)this;  // const_cast
  9443.  
  9444.     int width, height;
  9445.     width = self->SetOrCalcColumnSizes(TRUE);
  9446.     height = self->SetOrCalcRowSizes(TRUE);
  9447.  
  9448.     int maxwidth, maxheight;
  9449.     wxDisplaySize( & maxwidth, & maxheight );
  9450.  
  9451.     if ( width > maxwidth ) width = maxwidth;
  9452.     if ( height > maxheight ) height = maxheight;
  9453.  
  9454.     return wxSize( width, height );
  9455. }
  9456.  
  9457. void wxGrid::Fit()
  9458. {
  9459.     AutoSize();
  9460. }
  9461.  
  9462.  
  9463. wxPen& wxGrid::GetDividerPen() const
  9464. {
  9465.     return wxNullPen;
  9466. }
  9467.  
  9468. // ----------------------------------------------------------------------------
  9469. // cell value accessor functions
  9470. // ----------------------------------------------------------------------------
  9471.  
  9472. void wxGrid::SetCellValue( int row, int col, const wxString& s )
  9473. {
  9474.     if ( m_table )
  9475.     {
  9476.         m_table->SetValue( row, col, s );
  9477.         if ( !GetBatchCount() )
  9478.         {
  9479.             int dummy;
  9480.             wxRect rect( CellToRect( row, col ) );
  9481.             rect.x = 0;
  9482.             rect.width = m_gridWin->GetClientSize().GetWidth();
  9483.             CalcScrolledPosition(0, rect.y, &dummy, &rect.y);
  9484.             m_gridWin->Refresh( FALSE, &rect );
  9485.         }
  9486.  
  9487.         if ( m_currentCellCoords.GetRow() == row &&
  9488.              m_currentCellCoords.GetCol() == col &&
  9489.              IsCellEditControlShown())
  9490.              // Note: If we are using IsCellEditControlEnabled,
  9491.              // this interacts badly with calling SetCellValue from
  9492.              // an EVT_GRID_CELL_CHANGE handler.
  9493.         {
  9494.             HideCellEditControl();
  9495.             ShowCellEditControl(); // will reread data from table
  9496.         }
  9497.     }
  9498. }
  9499.  
  9500.  
  9501. //
  9502. // ------ Block, row and col selection
  9503. //
  9504.  
  9505. void wxGrid::SelectRow( int row, bool addToSelected )
  9506. {
  9507.     if ( IsSelection() && !addToSelected )
  9508.         ClearSelection();
  9509.  
  9510.     if ( m_selection )
  9511.         m_selection->SelectRow( row, FALSE, addToSelected );
  9512. }
  9513.  
  9514.  
  9515. void wxGrid::SelectCol( int col, bool addToSelected )
  9516. {
  9517.     if ( IsSelection() && !addToSelected )
  9518.         ClearSelection();
  9519.  
  9520.     if ( m_selection )
  9521.         m_selection->SelectCol( col, FALSE, addToSelected );
  9522. }
  9523.  
  9524.  
  9525. void wxGrid::SelectBlock( int topRow, int leftCol, int bottomRow, int rightCol,
  9526.                           bool addToSelected )
  9527. {
  9528.     if ( IsSelection() && !addToSelected )
  9529.         ClearSelection();
  9530.  
  9531.     if ( m_selection )
  9532.         m_selection->SelectBlock( topRow, leftCol, bottomRow, rightCol,
  9533.                                   FALSE, addToSelected );
  9534. }
  9535.  
  9536.  
  9537. void wxGrid::SelectAll()
  9538. {
  9539.     if ( m_numRows > 0 && m_numCols > 0 )
  9540.     {
  9541.         if ( m_selection )
  9542.             m_selection->SelectBlock( 0, 0, m_numRows-1, m_numCols-1 );
  9543.     }
  9544. }
  9545.  
  9546. //
  9547. // ------ Cell, row and col deselection
  9548. //
  9549.  
  9550. void wxGrid::DeselectRow( int row )
  9551. {
  9552.     if ( !m_selection )
  9553.         return;
  9554.  
  9555.     if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
  9556.     {
  9557.         if ( m_selection->IsInSelection(row, 0 ) )
  9558.             m_selection->ToggleCellSelection( row, 0);
  9559.     }
  9560.     else
  9561.     {
  9562.         int nCols = GetNumberCols();
  9563.         for ( int i = 0; i < nCols ; i++ )
  9564.         {
  9565.             if ( m_selection->IsInSelection(row, i ) )
  9566.                 m_selection->ToggleCellSelection( row, i);
  9567.         }
  9568.     }
  9569. }
  9570.  
  9571. void wxGrid::DeselectCol( int col )
  9572. {
  9573.     if ( !m_selection )
  9574.         return;
  9575.  
  9576.     if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
  9577.     {
  9578.         if ( m_selection->IsInSelection(0, col ) )
  9579.             m_selection->ToggleCellSelection( 0, col);
  9580.     }
  9581.     else
  9582.     {
  9583.         int nRows = GetNumberRows();
  9584.         for ( int i = 0; i < nRows ; i++ )
  9585.         {
  9586.             if ( m_selection->IsInSelection(i, col ) )
  9587.                 m_selection->ToggleCellSelection(i, col);
  9588.         }
  9589.     }
  9590. }
  9591.  
  9592. void wxGrid::DeselectCell( int row, int col )
  9593. {
  9594.     if ( m_selection && m_selection->IsInSelection(row, col) )
  9595.         m_selection->ToggleCellSelection(row, col);
  9596. }
  9597.  
  9598. bool wxGrid::IsSelection()
  9599. {
  9600.     return ( m_selection && (m_selection->IsSelection() ||
  9601.              ( m_selectingTopLeft != wxGridNoCellCoords &&
  9602.                m_selectingBottomRight != wxGridNoCellCoords) ) );
  9603. }
  9604.  
  9605. bool wxGrid::IsInSelection( int row, int col ) const
  9606. {
  9607.     return ( m_selection && (m_selection->IsInSelection( row, col ) ||
  9608.              ( row >= m_selectingTopLeft.GetRow() &&
  9609.                col >= m_selectingTopLeft.GetCol() &&
  9610.                row <= m_selectingBottomRight.GetRow() &&
  9611.                col <= m_selectingBottomRight.GetCol() )) );
  9612. }
  9613.  
  9614. wxGridCellCoordsArray wxGrid::GetSelectedCells() const
  9615. {
  9616.     if (!m_selection) { wxGridCellCoordsArray a; return a; }
  9617.     return m_selection->m_cellSelection;
  9618. }
  9619. wxGridCellCoordsArray wxGrid::GetSelectionBlockTopLeft() const
  9620. {
  9621.     if (!m_selection) { wxGridCellCoordsArray a; return a; }
  9622.     return m_selection->m_blockSelectionTopLeft;
  9623. }
  9624. wxGridCellCoordsArray wxGrid::GetSelectionBlockBottomRight() const
  9625. {
  9626.     if (!m_selection) { wxGridCellCoordsArray a; return a; }
  9627.     return m_selection->m_blockSelectionBottomRight;
  9628. }
  9629. wxArrayInt wxGrid::GetSelectedRows() const
  9630. {
  9631.     if (!m_selection) { wxArrayInt a; return a; }
  9632.     return m_selection->m_rowSelection;
  9633. }
  9634. wxArrayInt wxGrid::GetSelectedCols() const
  9635. {
  9636.     if (!m_selection) { wxArrayInt a; return a; }
  9637.     return m_selection->m_colSelection;
  9638. }
  9639.  
  9640.  
  9641. void wxGrid::ClearSelection()
  9642. {
  9643.     m_selectingTopLeft = wxGridNoCellCoords;
  9644.     m_selectingBottomRight = wxGridNoCellCoords;
  9645.     if ( m_selection )
  9646.         m_selection->ClearSelection();
  9647. }
  9648.  
  9649.  
  9650. // This function returns the rectangle that encloses the given block
  9651. // in device coords clipped to the client size of the grid window.
  9652. //
  9653. wxRect wxGrid::BlockToDeviceRect( const wxGridCellCoords &topLeft,
  9654.                                   const wxGridCellCoords &bottomRight )
  9655. {
  9656.     wxRect rect( wxGridNoCellRect );
  9657.     wxRect cellRect;
  9658.  
  9659.     cellRect = CellToRect( topLeft );
  9660.     if ( cellRect != wxGridNoCellRect )
  9661.     {
  9662.         rect = cellRect;
  9663.     }
  9664.     else
  9665.     {
  9666.         rect = wxRect( 0, 0, 0, 0 );
  9667.     }
  9668.  
  9669.     cellRect = CellToRect( bottomRight );
  9670.     if ( cellRect != wxGridNoCellRect )
  9671.     {
  9672.         rect += cellRect;
  9673.     }
  9674.     else
  9675.     {
  9676.         return wxGridNoCellRect;
  9677.     }
  9678.  
  9679.     int i, j;
  9680.     int left = rect.GetLeft();
  9681.     int top = rect.GetTop();
  9682.     int right = rect.GetRight();
  9683.     int bottom = rect.GetBottom();
  9684.  
  9685.     int leftCol = topLeft.GetCol();
  9686.     int topRow = topLeft.GetRow();
  9687.     int rightCol = bottomRight.GetCol();
  9688.     int bottomRow = bottomRight.GetRow();
  9689.  
  9690.     if (left > right)
  9691.     {
  9692.         i = left;
  9693.         left = right;
  9694.         right = i;
  9695.         i = leftCol;
  9696.         leftCol=rightCol;
  9697.         rightCol = i;
  9698.     }
  9699.  
  9700.     if (top > bottom)
  9701.     {
  9702.         i = top;
  9703.         top = bottom;
  9704.         bottom = i;
  9705.         i = topRow;
  9706.         topRow = bottomRow;
  9707.         bottomRow = i;
  9708.     }
  9709.  
  9710.  
  9711.     for ( j = topRow; j <= bottomRow; j++ )
  9712.     {
  9713.         for ( i = leftCol; i <= rightCol; i++ )
  9714.         {
  9715.             if ((j==topRow) || (j==bottomRow) || (i==leftCol) || (i==rightCol))
  9716.             {
  9717.                 cellRect = CellToRect( j, i );
  9718.  
  9719.                 if (cellRect.x < left)
  9720.                     left = cellRect.x;
  9721.                 if (cellRect.y < top)
  9722.                     top = cellRect.y;
  9723.                 if (cellRect.x + cellRect.width > right)
  9724.                     right = cellRect.x + cellRect.width;
  9725.                 if (cellRect.y + cellRect.height > bottom)
  9726.                     bottom = cellRect.y + cellRect.height;
  9727.             }
  9728.             else i = rightCol; // jump over inner cells.
  9729.         }
  9730.     }
  9731.  
  9732.     // convert to scrolled coords
  9733.     //
  9734.     CalcScrolledPosition( left, top, &left, &top );
  9735.     CalcScrolledPosition( right, bottom, &right, &bottom );
  9736.  
  9737.     int cw, ch;
  9738.     m_gridWin->GetClientSize( &cw, &ch );
  9739.  
  9740.     if (right < 0 || bottom < 0 || left > cw || top > ch)
  9741.         return wxRect( 0, 0, 0, 0);
  9742.  
  9743.     rect.SetLeft( wxMax(0, left) );
  9744.     rect.SetTop( wxMax(0, top) );
  9745.     rect.SetRight( wxMin(cw, right) );
  9746.     rect.SetBottom( wxMin(ch, bottom) );
  9747.  
  9748.     return rect;
  9749. }
  9750.  
  9751.  
  9752.  
  9753. //
  9754. // ------ Grid event classes
  9755. //
  9756.  
  9757. IMPLEMENT_DYNAMIC_CLASS( wxGridEvent, wxNotifyEvent )
  9758.  
  9759. wxGridEvent::wxGridEvent( int id, wxEventType type, wxObject* obj,
  9760.                           int row, int col, int x, int y, bool sel,
  9761.                           bool control, bool shift, bool alt, bool meta )
  9762.         : wxNotifyEvent( type, id )
  9763. {
  9764.     m_row = row;
  9765.     m_col = col;
  9766.     m_x = x;
  9767.     m_y = y;
  9768.     m_selecting = sel;
  9769.     m_control = control;
  9770.     m_shift = shift;
  9771.     m_alt = alt;
  9772.     m_meta = meta;
  9773.  
  9774.     SetEventObject(obj);
  9775. }
  9776.  
  9777.  
  9778. IMPLEMENT_DYNAMIC_CLASS( wxGridSizeEvent, wxNotifyEvent )
  9779.  
  9780. wxGridSizeEvent::wxGridSizeEvent( int id, wxEventType type, wxObject* obj,
  9781.                                   int rowOrCol, int x, int y,
  9782.                                   bool control, bool shift, bool alt, bool meta )
  9783.         : wxNotifyEvent( type, id )
  9784. {
  9785.     m_rowOrCol = rowOrCol;
  9786.     m_x = x;
  9787.     m_y = y;
  9788.     m_control = control;
  9789.     m_shift = shift;
  9790.     m_alt = alt;
  9791.     m_meta = meta;
  9792.  
  9793.     SetEventObject(obj);
  9794. }
  9795.  
  9796.  
  9797. IMPLEMENT_DYNAMIC_CLASS( wxGridRangeSelectEvent, wxNotifyEvent )
  9798.  
  9799. wxGridRangeSelectEvent::wxGridRangeSelectEvent(int id, wxEventType type, wxObject* obj,
  9800.                                                const wxGridCellCoords& topLeft,
  9801.                                                const wxGridCellCoords& bottomRight,
  9802.                                                bool sel, bool control,
  9803.                                                bool shift, bool alt, bool meta )
  9804.         : wxNotifyEvent( type, id )
  9805. {
  9806.     m_topLeft     = topLeft;
  9807.     m_bottomRight = bottomRight;
  9808.     m_selecting   = sel;
  9809.     m_control     = control;
  9810.     m_shift       = shift;
  9811.     m_alt         = alt;
  9812.     m_meta        = meta;
  9813.  
  9814.     SetEventObject(obj);
  9815. }
  9816.  
  9817.  
  9818. IMPLEMENT_DYNAMIC_CLASS(wxGridEditorCreatedEvent, wxCommandEvent)
  9819.  
  9820. wxGridEditorCreatedEvent::wxGridEditorCreatedEvent(int id, wxEventType type,
  9821.                                                    wxObject* obj, int row,
  9822.                                                    int col, wxControl* ctrl)
  9823.     : wxCommandEvent(type, id)
  9824. {
  9825.     SetEventObject(obj);
  9826.     m_row = row;
  9827.     m_col = col;
  9828.     m_ctrl = ctrl;
  9829. }
  9830.  
  9831.  
  9832. #endif // !wxUSE_NEW_GRID/wxUSE_NEW_GRID
  9833.  
  9834. #endif // wxUSE_GRID
  9835.