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