]> git.saurik.com Git - wxWidgets.git/commitdiff
- Main change is the addition of wxGridSelectRowsOrColumns selection mode
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 19 Sep 2008 23:33:04 +0000 (23:33 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 19 Sep 2008 23:33:04 +0000 (23:33 +0000)
  (which is still probably buggy, wxGridSelection needs to be reviewed)
- Add XYToCell() overloads returning wxGridCellCoords (instead of modifying the
  argument passed by reference -- where did this come from?) and document them.
- Added GoToCell() which does make the new current cell visible unlike
  SetGridCursor() (which was documented as doing it, but wasn't)
- Changed SetCurrentCell() to only not change the cell if wxEVT_GRID_SELECT_CELL
  it generates is vetoed, not just processed as this seems to make more sense
- Split jumbo (~400 lines) ProcessGridCellMouseEvent() function into chunks
- Add many more comments to make reading this code seem less like puzzle
  solving for the next unfortunate soul to do it

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55746 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/generic/grid.h
include/wx/generic/gridsel.h
interface/wx/grid.h
samples/grid/griddemo.cpp
samples/grid/griddemo.h
src/generic/grid.cpp
src/generic/gridsel.cpp

index 52b6591de3f2da9b268d18e90a908af22fa6dbc1..c5803d13ee08b6220640fdcf259da97e8eb509ad 100644 (file)
@@ -392,6 +392,7 @@ All (GUI):
 - wxWindow::IsBeingDeleted() now returns true not only if the window itself is
   marked for destruction but also if any of its parent windows are.
 - Improved drawing of the hint during column move in wxGrid.
+- Add wxGridSelectRowsOrColumns selection mode to wxGrid.
 - Get/HasModifiers() of wxKeyEvent are now also available in wxMouseEvent.
 
 wxGTK:
index 69ca1db214ffcf498e0ed1f491864c582951798a..b9d4935c456689cd59df12b80c878aebae85f3cf 100644 (file)
@@ -320,7 +320,7 @@ public:
 
     // Show or hide the edit control, use the specified attributes to set
     // colours/fonts for it
-    virtual void Show(bool show, wxGridCellAttr *attr = (wxGridCellAttr *)NULL);
+    virtual void Show(bool show, wxGridCellAttr *attr = NULL);
 
     // Draws the part of the cell not occupied by the control: the base class
     // version just fills it with background colour from the attribute
@@ -1145,6 +1145,10 @@ public:
                    bool takeOwnership = false,
                    wxGridSelectionModes selmode = wxGridSelectCells );
 
+    bool ProcessTableMessage(wxGridTableMessage&);
+
+    wxGridTableBase *GetTable() const { return m_table; }
+
 
     void SetSelectionMode(wxGridSelectionModes selmode);
     wxGridSelectionModes GetSelectionMode() const;
@@ -1163,20 +1167,6 @@ public:
     wxGridCellCoordsArray CalcCellsExposed( const wxRegion& reg ) const;
 
 
-    // ------ event handlers
-    //
-    void ProcessRowLabelMouseEvent( wxMouseEvent& event );
-    void ProcessColLabelMouseEvent( wxMouseEvent& event );
-    void ProcessCornerLabelMouseEvent( wxMouseEvent& event );
-    void ProcessGridCellMouseEvent( wxMouseEvent& event );
-    bool ProcessTableMessage( wxGridTableMessage& );
-
-    void DoEndDragResizeRow();
-    void DoEndDragResizeCol();
-    void DoEndDragMoveCol();
-
-    wxGridTableBase * GetTable() const { return m_table; }
-
     void ClearGrid();
     bool InsertRows(int pos = 0, int numRows = 1, bool updateLabels = true)
     {
@@ -1261,8 +1251,7 @@ public:
 
     int      GetBatchCount() { return m_batchCount; }
 
-    virtual void Refresh(bool eraseb = true,
-                         const wxRect* rect = (const wxRect *)  NULL);
+    virtual void Refresh(bool eraseb = true, const wxRect* rect = NULL);
 
     // Use this, rather than wxWindow::Refresh(), to force an
     // immediate repainting of the grid. Has no effect if you are
@@ -1297,7 +1286,12 @@ public:
     //  grid cells and labels so you will need to convert from device
     //  coordinates for mouse events etc.
     //
-    void XYToCell( int x, int y, wxGridCellCoords& ) const;
+    wxGridCellCoords XYToCell(int x, int y) const;
+    void XYToCell(int x, int y, wxGridCellCoords& coords) const
+        { coords = XYToCell(x, y); }
+    wxGridCellCoords XYToCell(const wxPoint& pos) const
+        { return XYToCell(pos.x, pos.y); }
+
     int  YToRow( int y, bool clipToMinMax = false ) const;
     int  XToCol( int x, bool clipToMinMax = false ) const;
 
@@ -1324,8 +1318,20 @@ public:
 
     // ------ grid cursor movement functions
     //
-    void SetGridCursor( int row, int col )
-        { SetCurrentCell( wxGridCellCoords(row, col) ); }
+    void SetGridCursor(int row, int col) { SetCurrentCell(row, col); }
+    void SetGridCursor(const wxGridCellCoords& c) { SetCurrentCell(c); }
+
+    void GoToCell(int row, int col)
+    {
+        if ( SetCurrentCell(row, col) )
+            MakeCellVisible(row, col);
+    }
+
+    void GoToCell(const wxGridCellCoords& coords)
+    {
+        if ( SetCurrentCell(coords) )
+            MakeCellVisible(coords);
+    }
 
     bool MoveCursorUp( bool expandSelection );
     bool MoveCursorDown( bool expandSelection );
@@ -1867,10 +1873,22 @@ protected:
 
     wxGridCellCoords m_currentCellCoords;
 
-    wxGridCellCoords m_selectingTopLeft;
-    wxGridCellCoords m_selectingBottomRight;
-    wxGridCellCoords m_selectingKeyboard;
+    // the corners of the block being currently selected or wxGridNoCellCoords
+    wxGridCellCoords m_selectedBlockTopLeft;
+    wxGridCellCoords m_selectedBlockBottomRight;
+
+    // when selecting blocks of cells (either from the keyboard using Shift
+    // with cursor keys, or by dragging the mouse), the selection is anchored
+    // at m_currentCellCoords which defines one of the corners of the rectangle
+    // being selected -- and this variable defines the other corner, i.e. it's
+    // either m_selectedBlockTopLeft or m_selectedBlockBottomRight depending on
+    // which of them is not m_currentCellCoords
+    //
+    // if no block selection is in process, it is set to wxGridNoCellCoords
+    wxGridCellCoords m_selectedBlockCorner;
+
     wxGridSelection  *m_selection;
+
     wxColour    m_selectionBackground;
     wxColour    m_selectionForeground;
 
@@ -2007,12 +2025,22 @@ protected:
     // for this to work, you should always use it and not set m_cursorMode
     // directly!
     void ChangeCursorMode(CursorMode mode,
-                          wxWindow *win = (wxWindow *)NULL,
+                          wxWindow *win = NULL,
                           bool captureMouse = true);
 
     wxWindow *m_winCapture;     // the window which captured the mouse
+
+    // this variable is used not for finding the correct current cursor but
+    // mainly for finding out what is going to happen if the mouse starts being
+    // dragged right now
+    //
+    // by default it is WXGRID_CURSOR_SELECT_CELL meaning that nothing else is
+    // going on, and it is set to one of RESIZE/SELECT/MOVE values while the
+    // corresponding operation will be started if the user starts dragging the
+    // mouse from the current position
     CursorMode m_cursorMode;
 
+
     //Column positions
     wxArrayInt m_colAt;
     int m_moveToCol;
@@ -2029,7 +2057,16 @@ protected:
     int     m_dragLastPos;
     int     m_dragRowOrCol;
 
+    // true if a drag operation is in progress; when this is true,
+    // m_startDragPos is valid, i.e. not wxDefaultPosition
     bool    m_isDragging;
+
+    // the position (in physical coordinates) where the user started dragging
+    // the mouse or wxDefaultPosition if mouse isn't being dragged
+    //
+    // notice that this can be != wxDefaultPosition while m_isDragging is still
+    // false because we wait until the mouse is moved some distance away before
+    // setting m_isDragging to true
     wxPoint m_startDragPos;
 
     bool    m_waitForSlowClick;
@@ -2053,14 +2090,20 @@ protected:
     bool Redimension( wxGridTableMessage& );
 
 
-    int SendEvent( const wxEventType, int row, int col, wxMouseEvent& );
-    int SendEvent( const wxEventType, int row, int col );
-    int SendEvent( const wxEventType type)
-    {
-        return SendEvent(type,
-                         m_currentCellCoords.GetRow(),
-                         m_currentCellCoords.GetCol());
-    }
+    // generate the appropriate grid event and return -1 if it was vetoed, 1 if
+    // it was processed (but not vetoed) and 0 if it wasn't processed
+    int SendEvent(const wxEventType evtType,
+                  int row, int col,
+                  wxMouseEvent& e);
+    int SendEvent(const wxEventType evtType,
+                  const wxGridCellCoords& coords,
+                  wxMouseEvent& e)
+        { return SendEvent(evtType, coords.GetRow(), coords.GetCol(), e); }
+    int SendEvent(const wxEventType evtType, int row, int col);
+    int SendEvent(const wxEventType evtType, const wxGridCellCoords& coords)
+        { return SendEvent(evtType, coords.GetRow(), coords.GetCol()); }
+    int SendEvent(const wxEventType evtType)
+        { return SendEvent(evtType, m_currentCellCoords); }
 
     void OnPaint( wxPaintEvent& );
     void OnSize( wxSizeEvent& );
@@ -2070,16 +2113,20 @@ protected:
     void OnEraseBackground( wxEraseEvent& );
 
 
-    void SetCurrentCell( const wxGridCellCoords& coords );
-    void SetCurrentCell( int row, int col )
-        { SetCurrentCell( wxGridCellCoords(row, col) ); }
+    bool SetCurrentCell( const wxGridCellCoords& coords );
+    bool SetCurrentCell( int row, int col )
+        { return SetCurrentCell( wxGridCellCoords(row, col) ); }
+
 
-    void HighlightBlock( int topRow, int leftCol, int bottomRow, int rightCol );
+    // this function is called to extend the block being currently selected
+    // from mouse and keyboard event handlers
+    void UpdateBlockBeingSelected(int topRow, int leftCol,
+                                  int bottomRow, int rightCol);
 
-    void HighlightBlock( const wxGridCellCoords& topLeft,
-                         const wxGridCellCoords& bottomRight )
-        { HighlightBlock( topLeft.GetRow(), topLeft.GetCol(),
-                       bottomRight.GetRow(), bottomRight.GetCol() ); }
+    void UpdateBlockBeingSelected(const wxGridCellCoords& topLeft,
+                        const wxGridCellCoords& bottomRight)
+        { UpdateBlockBeingSelected(topLeft.GetRow(), topLeft.GetCol(),
+                         bottomRight.GetRow(), bottomRight.GetCol()); }
 
     // ------ functions to get/send data (see also public functions)
     //
@@ -2090,10 +2137,56 @@ protected:
     friend class wxGridRowOperations;
     friend class wxGridColumnOperations;
 
+    // they call our private Process{{Corner,Col,Row}Label,GridCell}MouseEvent()
+    friend class wxGridCornerLabelWindow;
+    friend class wxGridColLabelWindow;
+    friend class wxGridRowLabelWindow;
+    friend class wxGridWindow;
+
 private:
     // implement wxScrolledWindow method to return m_gridWin size
     virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size);
 
+    // event handlers and their helpers
+    // --------------------------------
+
+    // process mouse drag event in WXGRID_CURSOR_SELECT_CELL mode
+    void DoGridCellDrag(wxMouseEvent& event,
+                        const wxGridCellCoords& coords,
+                        bool isFirstDrag);
+
+    // process row/column resizing drag event
+    void DoGridLineDrag(wxMouseEvent& event, const wxGridOperations& oper);
+
+    // process mouse drag event in the grid window
+    void DoGridDragEvent(wxMouseEvent& event, const wxGridCellCoords& coords);
+
+    // process different clicks on grid cells
+    void DoGridCellLeftDown(wxMouseEvent& event,
+                            const wxGridCellCoords& coords,
+                            const wxPoint& pos);
+    void DoGridCellLeftDClick(wxMouseEvent& event,
+                             const wxGridCellCoords& coords,
+                             const wxPoint& pos);
+    void DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords);
+
+    // process movement (but not dragging) event in the grid cell area
+    void DoGridMouseMoveEvent(wxMouseEvent& event,
+                              const wxGridCellCoords& coords,
+                              const wxPoint& pos);
+
+    // process mouse events in the grid window
+    void ProcessGridCellMouseEvent(wxMouseEvent& event);
+
+    // process mouse events in the row/column labels/corner windows
+    void ProcessRowLabelMouseEvent(wxMouseEvent& event);
+    void ProcessColLabelMouseEvent(wxMouseEvent& event);
+    void ProcessCornerLabelMouseEvent(wxMouseEvent& event);
+
+    void DoEndDragResizeRow();
+    void DoEndDragResizeCol();
+    void DoEndDragMoveCol();
+
 
     // common implementations of methods defined for both rows and columns
     void DeselectLine(int line, const wxGridOperations& oper);
index ab83260f917b9bbfcacae1f4162d1b1468ccf0bb..f7cefd4e1d4ac1c441552606d6339a95ccb929c5 100644 (file)
@@ -44,10 +44,23 @@ public:
                       bool ControlDown = false,  bool ShiftDown = false,
                       bool AltDown = false, bool MetaDown = false,
                       bool sendEvent = true );
+    void SelectBlock( const wxGridCellCoords& topLeft,
+                      const wxGridCellCoords& bottomRight,
+                      bool ControlDown = false,  bool ShiftDown = false,
+                      bool AltDown = false, bool MetaDown = false,
+                      bool sendEvent = true )
+    {
+        SelectBlock(topLeft.GetRow(), topLeft.GetCol(),
+                    bottomRight.GetRow(), bottomRight.GetCol(),
+                    ControlDown, ShiftDown, AltDown, MetaDown,
+                    sendEvent);
+    }
+
     void SelectCell( int row, int col,
                      bool ControlDown = false,  bool ShiftDown = false,
                      bool AltDown = false, bool MetaDown = false,
                      bool sendEvent = true );
+
     void ToggleCellSelection( int row, int col,
                               bool ControlDown = false,
                               bool ShiftDown = false,
index fdd1ee05b61ceef5af79d04f02dc975073fe90ca..82b700b5e145fd0bc94e88acf2a6f91016119743 100644 (file)
@@ -2130,6 +2130,19 @@ public:
     */
     wxGridTableBase *GetTable() const;
 
+    //@{
+    /**
+        Make the given cell current and ensure it is visible.
+
+        This method is equivalent to calling MakeCellVisible() and
+        SetGridCursor() and so, as with the latter, a wxEVT_GRID_SELECT_CELL
+        event is generated by it and the selected cell doesn't change if the
+        event is vetoed.
+     */
+    void GoToCell(int row, int col);
+    void GoToCell(const wxGridCellCoords& coords);
+    //@}
+
     /**
         Returns @true if drawing of grid lines is turned on, @false otherwise.
     */
@@ -2693,12 +2706,22 @@ public:
     */
     void SetDefaultRowSize(int height, bool resizeExistingRows = false);
 
+    //@{
     /**
         Set the grid cursor to the specified cell.
 
-        This function calls MakeCellVisible().
+        The grid cursor indicates the current cell and can be moved by the user
+        using the arrow keys or the mouse.
+
+        Calling this function generates a wxEVT_GRID_SELECT_CELL event and if
+        the event handler vetoes this event, the cursor is not moved.
+
+        This function doesn't make the target call visible, use GoToCell() to
+        do this.
     */
     void SetGridCursor(int row, int col);
+    void SetGridCursor(const wxGridCellCoords& coords);
+    //@}
 
     /**
         Sets the colour used to draw grid lines.
@@ -2883,6 +2906,27 @@ public:
     */
     int XToEdgeOfCol(int x) const;
 
+    //@{
+    /**
+        Translates logical pixel coordinates to the grid cell coordinates.
+
+        Notice that this function expects logical coordinates on input so if
+        you use this function in a mouse event handler you need to translate
+        the mouse position, which is expressed in device coordinates, to
+        logical ones.
+
+        @see XToCol(), YToRow()
+     */
+
+    // XYToCell(int, int, wxGridCellCoords&) overload is intentionally
+    // undocumented, using it is ugly and non-const reference parameters are
+    // not used in wxWidgets API
+
+    wxGridCellCoords XYToCell(int x, int y) const;
+    wxGridCellCoords XYToCell(const wxPoint& pos) const;
+
+    //@}
+
     /**
         Returns the row whose bottom edge is close to the given logical y
         position.
index 57167ea706e511fa39989005ee7f714dfdf2b317..533f984b47d0eb5197193294146a72111dc11ccb 100644 (file)
@@ -92,6 +92,7 @@ BEGIN_EVENT_TABLE( GridFrame, wxFrame )
     EVT_MENU( ID_SELCELLS,  GridFrame::SelectCells )
     EVT_MENU( ID_SELROWS,  GridFrame::SelectRows )
     EVT_MENU( ID_SELCOLS,  GridFrame::SelectCols )
+    EVT_MENU( ID_SELROWSORCOLS,  GridFrame::SelectRowsOrCols )
 
     EVT_MENU( ID_SET_CELL_FG_COLOUR, GridFrame::SetCellFgColour )
     EVT_MENU( ID_SET_CELL_BG_COLOUR, GridFrame::SetCellBgColour )
@@ -223,9 +224,10 @@ GridFrame::GridFrame()
                       selectionMenu,
                       _T("Change selection mode") );
 
-    selectionMenu->Append( ID_SELCELLS, _T("Select &Cells") );
-    selectionMenu->Append( ID_SELROWS, _T("Select &Rows") );
-    selectionMenu->Append( ID_SELCOLS, _T("Select C&ols") );
+    selectionMenu->Append( ID_SELCELLS, _T("Select &cells") );
+    selectionMenu->Append( ID_SELROWS, _T("Select &rows") );
+    selectionMenu->Append( ID_SELCOLS, _T("Select col&umns") );
+    selectionMenu->Append( ID_SELROWSORCOLS, _T("Select rows &or columns") );
 
     wxMenu *autosizeMenu = new wxMenu;
     autosizeMenu->Append( ID_SIZE_ROW, _T("Selected &row data") );
@@ -807,6 +809,11 @@ void GridFrame::SelectCols( wxCommandEvent& WXUNUSED(ev) )
     grid->SetSelectionMode( wxGrid::wxGridSelectColumns );
 }
 
+void GridFrame::SelectRowsOrCols( wxCommandEvent& WXUNUSED(ev) )
+{
+    grid->SetSelectionMode( wxGrid::wxGridSelectRowsOrColumns );
+}
+
 void GridFrame::SetCellFgColour( wxCommandEvent& WXUNUSED(ev) )
 {
     wxColour col = wxGetColourFromUser(this);
index c8eb3ac5e8ff96810c450323b08451ec045d8e16..3ec731d708b78fd369282220d7d18851bcf7400b 100644 (file)
@@ -64,6 +64,7 @@ class GridFrame : public wxFrame
     void SelectCells( wxCommandEvent& );
     void SelectRows( wxCommandEvent& );
     void SelectCols( wxCommandEvent& );
+    void SelectRowsOrCols( wxCommandEvent& );
 
     void DeselectCell(wxCommandEvent& event);
     void DeselectCol(wxCommandEvent& event);
@@ -144,6 +145,7 @@ public:
         ID_SELCELLS,
         ID_SELROWS,
         ID_SELCOLS,
+        ID_SELROWSORCOLS,
         ID_SET_CELL_FG_COLOUR,
         ID_SET_CELL_BG_COLOUR,
         ID_VTABLE,
index 41fe1d6fc9ee6eebe486269ffca27033d7d05aa3..3830a869ee62ce3ebee8ac02c2064dd9ec5a40f4 100644 (file)
@@ -471,11 +471,20 @@ public:
 
 
     // Draws a line parallel to the row or column, i.e. horizontal or vertical:
-    // pos is the vertical or horizontal position of the line and start and end
+    // pos is the horizontal or vertical position of the line and start and end
     // are the coordinates of the line extremities in the other direction
     virtual void
         DrawParallelLine(wxDC& dc, int start, int end, int pos) const = 0;
 
+    // Draw a horizontal or vertical line across the given rectangle
+    // (this is implemented in terms of above and uses Select() to extract
+    // start and end from the given rectangle)
+    void DrawParallelLineInRect(wxDC& dc, const wxRect& rect, int pos) const
+    {
+        const int posStart = Select(rect.GetPosition());
+        DrawParallelLine(dc, posStart, posStart + Select(rect.GetSize()), pos);
+    }
+
 
     // Return the row or column at the given pixel coordinate.
     virtual int
@@ -785,13 +794,22 @@ private:
 wxGridCellCoords wxGridNoCellCoords( -1, -1 );
 wxRect wxGridNoCellRect( -1, -1, -1, -1 );
 
+namespace
+{
+
 // scroll line size
-static const size_t GRID_SCROLL_LINE_X = 15;
-static const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
+const size_t GRID_SCROLL_LINE_X = 15;
+const size_t GRID_SCROLL_LINE_Y = GRID_SCROLL_LINE_X;
 
 // the size of hash tables used a bit everywhere (the max number of elements
 // in these hash tables is the number of rows/columns)
-static const int GRID_HASH_SIZE = 100;
+const int GRID_HASH_SIZE = 100;
+
+// the minimal distance in pixels the mouse needs to move to start a drag
+// operation
+const int DRAG_SENSITIVITY = 3;
+
+} // anonymous namespace
 
 // ----------------------------------------------------------------------------
 // private helpers
@@ -4708,22 +4726,22 @@ wxGrid::SetTable(wxGridTableBase *table,
             // If the newly set table is smaller than the
             // original one current cell and selection regions
             // might be invalid,
-            m_selectingKeyboard = wxGridNoCellCoords;
+            m_selectedBlockCorner = wxGridNoCellCoords;
             m_currentCellCoords =
               wxGridCellCoords(wxMin(m_numRows, m_currentCellCoords.GetRow()),
                                wxMin(m_numCols, m_currentCellCoords.GetCol()));
-            if (m_selectingTopLeft.GetRow() >= m_numRows ||
-                m_selectingTopLeft.GetCol() >= m_numCols)
+            if (m_selectedBlockTopLeft.GetRow() >= m_numRows ||
+                m_selectedBlockTopLeft.GetCol() >= m_numCols)
             {
-                m_selectingTopLeft = wxGridNoCellCoords;
-                m_selectingBottomRight = wxGridNoCellCoords;
+                m_selectedBlockTopLeft = wxGridNoCellCoords;
+                m_selectedBlockBottomRight = wxGridNoCellCoords;
             }
             else
-                m_selectingBottomRight =
+                m_selectedBlockBottomRight =
                   wxGridCellCoords(wxMin(m_numRows,
-                                         m_selectingBottomRight.GetRow()),
+                                         m_selectedBlockBottomRight.GetRow()),
                                    wxMin(m_numCols,
-                                         m_selectingBottomRight.GetCol()));
+                                         m_selectedBlockBottomRight.GetCol()));
         }
         CalcDimensions();
 
@@ -6132,6 +6150,8 @@ void wxGrid::CancelMouseCapture()
     if ( m_winCapture )
     {
         m_isDragging = false;
+        m_startDragPos = wxDefaultPosition;
+
         m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
         m_winCapture->SetCursor( *wxSTANDARD_CURSOR );
         m_winCapture = NULL;
@@ -6214,387 +6234,390 @@ void wxGrid::ChangeCursorMode(CursorMode mode,
     }
 }
 
-void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event )
-{
-    int x, y;
-    wxPoint pos( event.GetPosition() );
-    CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
+// ----------------------------------------------------------------------------
+// grid mouse event processing
+// ----------------------------------------------------------------------------
 
-    wxGridCellCoords coords;
-    XYToCell( x, y, coords );
+void
+wxGrid::DoGridCellDrag(wxMouseEvent& event,
+                       const wxGridCellCoords& coords,
+                       bool isFirstDrag)
+{
+    if ( coords == wxGridNoCellCoords )
+        return; // we're outside any valid cell
 
-    int cell_rows, cell_cols;
-    bool isFirstDrag = !m_isDragging;
-    GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols );
-    if ((cell_rows < 0) || (cell_cols < 0))
+    // Hide the edit control, so it won't interfere with drag-shrinking.
+    if ( IsCellEditControlShown() )
     {
-        coords.SetRow(coords.GetRow() + cell_rows);
-        coords.SetCol(coords.GetCol() + cell_cols);
+        HideCellEditControl();
+        SaveEditControlValue();
     }
 
-    if ( event.Dragging() )
+    switch ( event.GetModifiers() )
     {
-        //wxLogDebug("pos(%d, %d) coords(%d, %d)", pos.x, pos.y, coords.GetRow(), coords.GetCol());
-
-        // Don't start doing anything until the mouse has been dragged at
-        // least 3 pixels in any direction...
-        if (! m_isDragging)
-        {
-            if (m_startDragPos == wxDefaultPosition)
-            {
-                m_startDragPos = pos;
-                return;
-            }
-            if (abs(m_startDragPos.x - pos.x) < 4 && abs(m_startDragPos.y - pos.y) < 4)
-                return;
-        }
-
-        m_isDragging = true;
-        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
-        {
-            // Hide the edit control, so it
-            // won't interfere with drag-shrinking.
-            if ( IsCellEditControlShown() )
-            {
-                HideCellEditControl();
-                SaveEditControlValue();
-            }
+        case wxMOD_CMD:
+            if ( m_selectedBlockCorner == wxGridNoCellCoords)
+                m_selectedBlockCorner = coords;
+            UpdateBlockBeingSelected(m_selectedBlockCorner, coords);
+            break;
 
-            if ( coords != wxGridNoCellCoords )
+        case wxMOD_NONE:
+            if ( CanDragCell() )
             {
-                if ( event.CmdDown() )
-                {
-                    if ( m_selectingKeyboard == wxGridNoCellCoords)
-                        m_selectingKeyboard = coords;
-                    HighlightBlock( m_selectingKeyboard, coords );
-                }
-                else if ( CanDragCell() )
+                if ( isFirstDrag )
                 {
-                    if ( isFirstDrag )
-                    {
-                        if ( m_selectingKeyboard == wxGridNoCellCoords)
-                            m_selectingKeyboard = coords;
-
-                        SendEvent( wxEVT_GRID_CELL_BEGIN_DRAG,
-                                   coords.GetRow(),
-                                   coords.GetCol(),
-                                   event );
-                        return;
-                    }
-                }
-                else
-                {
-                    if ( !IsSelection() )
-                    {
-                        HighlightBlock( coords, coords );
-                    }
-                    else
-                    {
-                        HighlightBlock( m_currentCellCoords, coords );
-                    }
-                }
+                    if ( m_selectedBlockCorner == wxGridNoCellCoords)
+                        m_selectedBlockCorner = coords;
 
-                if (! IsVisible(coords))
-                {
-                    MakeCellVisible(coords);
-                    // TODO: need to introduce a delay or something here.  The
-                    // scrolling is way too fast, at least under MSW and GTK.
+                    SendEvent(wxEVT_GRID_CELL_BEGIN_DRAG, coords, event);
+                    return;
                 }
             }
-            // Have we captured the mouse yet?
-            if (! m_winCapture)
-            {
-                m_winCapture = m_gridWin;
-                m_winCapture->CaptureMouse();
-            }
 
+            UpdateBlockBeingSelected(m_currentCellCoords, coords);
+            break;
 
-        }
-        else if ( event.LeftIsDown() &&
-                  m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
-        {
-            int cw, ch, left, dummy;
-            m_gridWin->GetClientSize( &cw, &ch );
-            CalcUnscrolledPosition( 0, 0, &left, &dummy );
+        default:
+            // we don't handle the other key modifiers
+            event.Skip();
+    }
+}
 
-            wxClientDC dc( m_gridWin );
-            PrepareDC( dc );
-            y = wxMax( y, GetRowTop(m_dragRowOrCol) +
-                          GetRowMinimalHeight(m_dragRowOrCol) );
-            dc.SetLogicalFunction(wxINVERT);
-            if ( m_dragLastPos >= 0 )
-            {
-                dc.DrawLine( left, m_dragLastPos, left+cw, m_dragLastPos );
-            }
-            dc.DrawLine( left, y, left+cw, y );
-            m_dragLastPos = y;
-        }
-        else if ( event.LeftIsDown() &&
-                  m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
-        {
-            int cw, ch, dummy, top;
-            m_gridWin->GetClientSize( &cw, &ch );
-            CalcUnscrolledPosition( 0, 0, &dummy, &top );
+void wxGrid::DoGridLineDrag(wxMouseEvent& event, const wxGridOperations& oper)
+{
+    wxClientDC dc(m_gridWin);
+    PrepareDC(dc);
+    dc.SetLogicalFunction(wxINVERT);
 
-            wxClientDC dc( m_gridWin );
-            PrepareDC( dc );
-            x = wxMax( x, GetColLeft(m_dragRowOrCol) +
-                          GetColMinimalWidth(m_dragRowOrCol) );
-            dc.SetLogicalFunction(wxINVERT);
-            if ( m_dragLastPos >= 0 )
-            {
-                dc.DrawLine( m_dragLastPos, top, m_dragLastPos, top + ch );
-            }
-            dc.DrawLine( x, top, x, top + ch );
-            m_dragLastPos = x;
+    const wxRect rectWin(CalcUnscrolledPosition(wxPoint(0, 0)),
+                         m_gridWin->GetClientSize());
+
+    // erase the previously drawn line, if any
+    if ( m_dragLastPos >= 0 )
+        oper.DrawParallelLineInRect(dc, rectWin, m_dragLastPos);
+
+    // we need the vertical position for rows and horizontal for columns here
+    m_dragLastPos = oper.Dual().Select(CalcUnscrolledPosition(event.GetPosition()));
+
+    // don't allow resizing beneath the minimal size
+    const int posMin = oper.GetLineStartPos(this, m_dragRowOrCol) +
+                        oper.GetMinimalLineSize(this, m_dragRowOrCol);
+    if ( m_dragLastPos < posMin )
+        m_dragLastPos = posMin;
+
+    // and draw it at the new position
+    oper.DrawParallelLineInRect(dc, rectWin, m_dragLastPos);
+}
+
+void wxGrid::DoGridDragEvent(wxMouseEvent& event, const wxGridCellCoords& coords)
+{
+    if ( !m_isDragging )
+    {
+        // Don't start doing anything until the mouse has been dragged far
+        // enough
+        const wxPoint& pt = event.GetPosition();
+        if ( m_startDragPos == wxDefaultPosition )
+        {
+            m_startDragPos = pt;
+            return;
         }
 
-        return;
+        if ( abs(m_startDragPos.x - pt.x) <= DRAG_SENSITIVITY &&
+                abs(m_startDragPos.y - pt.y) <= DRAG_SENSITIVITY )
+            return;
     }
 
-    m_isDragging = false;
-    m_startDragPos = wxDefaultPosition;
+    const bool isFirstDrag = !m_isDragging;
+    m_isDragging = true;
 
-    // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
-    //     immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
-    //     wxGTK
-#if 0
-    if ( event.Entering() || event.Leaving() )
+    switch ( m_cursorMode )
     {
-        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-        m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
+        case WXGRID_CURSOR_SELECT_CELL:
+            DoGridCellDrag(event, coords, isFirstDrag);
+            break;
+
+        case WXGRID_CURSOR_RESIZE_ROW:
+            DoGridLineDrag(event, wxGridRowOperations());
+            break;
+
+        case WXGRID_CURSOR_RESIZE_COL:
+            DoGridLineDrag(event, wxGridColumnOperations());
+            break;
+
+        default:
+            event.Skip();
     }
-    else
-#endif // 0
 
-    // ------------ Left button pressed
-    //
-    if ( event.LeftDown() && coords != wxGridNoCellCoords )
+    if ( isFirstDrag )
     {
-        if ( !SendEvent( wxEVT_GRID_CELL_LEFT_CLICK,
-                       coords.GetRow(),
-                       coords.GetCol(),
-                       event ) )
-        {
-            if ( !event.CmdDown() )
-                ClearSelection();
-            if ( event.ShiftDown() )
-            {
-                if ( m_selection )
-                {
-                    m_selection->SelectBlock( m_currentCellCoords.GetRow(),
-                                              m_currentCellCoords.GetCol(),
-                                              coords.GetRow(),
-                                              coords.GetCol(),
-                                              event.ControlDown(),
-                                              event.ShiftDown(),
-                                              event.AltDown(),
-                                              event.MetaDown() );
-                }
-            }
-            else if ( XToEdgeOfCol(x) < 0 &&
-                      YToEdgeOfRow(y) < 0 )
-            {
-                DisableCellEditControl();
-                MakeCellVisible( coords );
+        m_winCapture = m_gridWin;
+        m_winCapture->CaptureMouse();
+    }
+}
 
-                if ( event.CmdDown() )
-                {
-                    if ( m_selection )
-                    {
-                        m_selection->ToggleCellSelection( coords.GetRow(),
-                                                          coords.GetCol(),
-                                                          event.ControlDown(),
-                                                          event.ShiftDown(),
-                                                          event.AltDown(),
-                                                          event.MetaDown() );
-                    }
-                    m_selectingTopLeft = wxGridNoCellCoords;
-                    m_selectingBottomRight = wxGridNoCellCoords;
-                    m_selectingKeyboard = coords;
-                }
-                else
-                {
-                    m_waitForSlowClick = m_currentCellCoords == coords &&
-                                                coords != wxGridNoCellCoords;
-                    SetCurrentCell( coords );
-                }
-            }
-        }
+void
+wxGrid::DoGridCellLeftDown(wxMouseEvent& event,
+                           const wxGridCellCoords& coords,
+                           const wxPoint& pos)
+{
+    if ( SendEvent(wxEVT_GRID_CELL_LEFT_CLICK, coords, event) )
+    {
+        // event handled by user code, no need to do anything here
+        return;
     }
 
-    // ------------ Left double click
-    //
-    else if ( event.LeftDClick() && coords != wxGridNoCellCoords )
+    if ( !event.CmdDown() )
+        ClearSelection();
+
+    if ( event.ShiftDown() )
+    {
+        if ( m_selection )
+        {
+            m_selection->SelectBlock( m_currentCellCoords,
+                                      coords,
+                                      event.ControlDown(),
+                                      event.ShiftDown(),
+                                      event.AltDown(),
+                                      event.MetaDown() );
+            m_selectedBlockCorner = coords;
+        }
+    }
+    else if ( XToEdgeOfCol(pos.x) < 0 && YToEdgeOfRow(pos.y) < 0 )
     {
         DisableCellEditControl();
+        MakeCellVisible( coords );
 
-        if ( XToEdgeOfCol(x) < 0 && YToEdgeOfRow(y) < 0 )
+        if ( event.CmdDown() )
         {
-            if ( !SendEvent( wxEVT_GRID_CELL_LEFT_DCLICK,
-                             coords.GetRow(),
-                             coords.GetCol(),
-                             event ) )
+            if ( m_selection )
             {
-                // we want double click to select a cell and start editing
-                // (i.e. to behave in same way as sequence of two slow clicks):
-                m_waitForSlowClick = true;
+                m_selection->ToggleCellSelection( coords,
+                                                  event.ControlDown(),
+                                                  event.ShiftDown(),
+                                                  event.AltDown(),
+                                                  event.MetaDown() );
             }
+            m_selectedBlockTopLeft = wxGridNoCellCoords;
+            m_selectedBlockBottomRight = wxGridNoCellCoords;
+            m_selectedBlockCorner = coords;
+        }
+        else
+        {
+            m_waitForSlowClick = m_currentCellCoords == coords &&
+                                        coords != wxGridNoCellCoords;
+            SetCurrentCell( coords );
         }
     }
+}
 
-    // ------------ Left button released
-    //
-    else if ( event.LeftUp() )
+void
+wxGrid::DoGridCellLeftDClick(wxMouseEvent& event,
+                             const wxGridCellCoords& coords,
+                             const wxPoint& pos)
+{
+    if ( XToEdgeOfCol(pos.x) < 0 && YToEdgeOfRow(pos.y) < 0 )
     {
-        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+        if ( !SendEvent(wxEVT_GRID_CELL_LEFT_DCLICK, coords, event) )
         {
-            if (m_winCapture)
-            {
-                if (m_winCapture->HasCapture())
-                    m_winCapture->ReleaseMouse();
-                m_winCapture = NULL;
-            }
-
-            if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() )
-            {
-                ClearSelection();
-                EnableCellEditControl();
+            // we want double click to select a cell and start editing
+            // (i.e. to behave in same way as sequence of two slow clicks):
+            m_waitForSlowClick = true;
+        }
+    }
+}
 
-                wxGridCellAttr *attr = GetCellAttr(coords);
-                wxGridCellEditor *editor = attr->GetEditor(this, coords.GetRow(), coords.GetCol());
-                editor->StartingClick();
-                editor->DecRef();
-                attr->DecRef();
+void
+wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords)
+{
+    if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+    {
+        if (m_winCapture)
+        {
+            if (m_winCapture->HasCapture())
+                m_winCapture->ReleaseMouse();
+            m_winCapture = NULL;
+        }
 
-                m_waitForSlowClick = false;
-            }
-            else if ( m_selectingTopLeft != wxGridNoCellCoords &&
-                 m_selectingBottomRight != wxGridNoCellCoords )
-            {
-                if ( m_selection )
-                {
-                    m_selection->SelectBlock( m_selectingTopLeft.GetRow(),
-                                              m_selectingTopLeft.GetCol(),
-                                              m_selectingBottomRight.GetRow(),
-                                              m_selectingBottomRight.GetCol(),
-                                              event.ControlDown(),
-                                              event.ShiftDown(),
-                                              event.AltDown(),
-                                              event.MetaDown() );
-                }
+        if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() )
+        {
+            ClearSelection();
+            EnableCellEditControl();
 
-                m_selectingTopLeft = wxGridNoCellCoords;
-                m_selectingBottomRight = wxGridNoCellCoords;
+            wxGridCellAttr *attr = GetCellAttr(coords);
+            wxGridCellEditor *editor = attr->GetEditor(this, coords.GetRow(), coords.GetCol());
+            editor->StartingClick();
+            editor->DecRef();
+            attr->DecRef();
 
-                // Show the edit control, if it has been hidden for
-                // drag-shrinking.
-                ShowCellEditControl();
-            }
+            m_waitForSlowClick = false;
         }
-        else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
+        else if ( m_selectedBlockTopLeft != wxGridNoCellCoords &&
+             m_selectedBlockBottomRight != wxGridNoCellCoords )
         {
-            ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-            DoEndDragResizeRow();
+            if ( m_selection )
+            {
+                m_selection->SelectBlock( m_selectedBlockTopLeft,
+                                          m_selectedBlockBottomRight,
+                                          event.ControlDown(),
+                                          event.ShiftDown(),
+                                          event.AltDown(),
+                                          event.MetaDown() );
+            }
 
-            // Note: we are ending the event *after* doing
-            // default processing in this case
-            //
-            SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
-        }
-        else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
-        {
-            ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-            DoEndDragResizeCol();
+            m_selectedBlockTopLeft = wxGridNoCellCoords;
+            m_selectedBlockBottomRight = wxGridNoCellCoords;
 
-            // Note: we are ending the event *after* doing
-            // default processing in this case
-            //
-            SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
+            // Show the edit control, if it has been hidden for
+            // drag-shrinking.
+            ShowCellEditControl();
         }
+    }
+    else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
+    {
+        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+        DoEndDragResizeRow();
 
-        m_dragLastPos = -1;
+        // Note: we are ending the event *after* doing
+        // default processing in this case
+        //
+        SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
     }
+    else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
+    {
+        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+        DoEndDragResizeCol();
 
-    // ------------ Right button down
-    //
-    else if ( event.RightDown() && coords != wxGridNoCellCoords )
+        // Note: we are ending the event *after* doing
+        // default processing in this case
+        //
+        SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event );
+    }
+
+    m_dragLastPos = -1;
+}
+
+void
+wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event),
+                             const wxGridCellCoords& coords,
+                             const wxPoint& pos)
+{
+    if ( coords.GetRow() < 0 || coords.GetCol() < 0 )
     {
-        DisableCellEditControl();
-        if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_CLICK,
-                         coords.GetRow(),
-                         coords.GetCol(),
-                         event ) )
-        {
-            // no default action at the moment
-        }
+        // out of grid cell area
+        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+        return;
     }
 
-    // ------------ Right double click
+    int dragRow = YToEdgeOfRow( pos.y );
+    int dragCol = XToEdgeOfCol( pos.x );
+
+    // Dragging on the corner of a cell to resize in both
+    // directions is not implemented yet...
     //
-    else if ( event.RightDClick() && coords != wxGridNoCellCoords )
+    if ( dragRow >= 0 && dragCol >= 0 )
     {
-        DisableCellEditControl();
-        if ( !SendEvent( wxEVT_GRID_CELL_RIGHT_DCLICK,
-                         coords.GetRow(),
-                         coords.GetCol(),
-                         event ) )
+        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+        return;
+    }
+
+    if ( dragRow >= 0 )
+    {
+        m_dragRowOrCol = dragRow;
+
+        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
         {
-            // no default action at the moment
+            if ( CanDragRowSize() && CanDragGridSize() )
+                ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false);
         }
     }
+    else if ( dragCol >= 0 )
+    {
+        m_dragRowOrCol = dragCol;
 
-    // ------------ Moving and no button action
-    //
-    else if ( event.Moving() && !event.IsButton() )
+        if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
+        {
+            if ( CanDragColSize() && CanDragGridSize() )
+                ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false);
+        }
+    }
+    else // Neither on a row or col edge
     {
-        if ( coords.GetRow() < 0 || coords.GetCol() < 0 )
+        if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
         {
-            // out of grid cell area
             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-            return;
         }
+    }
+}
 
-        int dragRow = YToEdgeOfRow( y );
-        int dragCol = XToEdgeOfCol( x );
+void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event)
+{
+    const wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
 
-        // Dragging on the corner of a cell to resize in both
-        // directions is not implemented yet...
-        //
-        if ( dragRow >= 0 && dragCol >= 0 )
-        {
-            ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-            return;
-        }
+    // coordinates of the cell under mouse
+    wxGridCellCoords coords = XYToCell(pos);
 
-        if ( dragRow >= 0 )
-        {
-            m_dragRowOrCol = dragRow;
+    int cell_rows, cell_cols;
+    GetCellSize( coords.GetRow(), coords.GetCol(), &cell_rows, &cell_cols );
+    if ( (cell_rows < 0) || (cell_cols < 0) )
+    {
+        coords.SetRow(coords.GetRow() + cell_rows);
+        coords.SetCol(coords.GetCol() + cell_cols);
+    }
 
-            if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
-            {
-                if ( CanDragRowSize() && CanDragGridSize() )
-                    ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false);
-            }
-        }
-        else if ( dragCol >= 0 )
+    if ( event.Dragging() )
+    {
+        if ( event.LeftIsDown() )
+            DoGridDragEvent(event, coords);
+        else
+            event.Skip();
+        return;
+    }
+
+    m_isDragging = false;
+    m_startDragPos = wxDefaultPosition;
+
+    // VZ: if we do this, the mode is reset to WXGRID_CURSOR_SELECT_CELL
+    //     immediately after it becomes WXGRID_CURSOR_RESIZE_ROW/COL under
+    //     wxGTK
+#if 0
+    if ( event.Entering() || event.Leaving() )
+    {
+        ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
+        m_gridWin->SetCursor( *wxSTANDARD_CURSOR );
+    }
+#endif // 0
+
+    // deal with various button presses
+    if ( event.IsButton() )
+    {
+        if ( coords != wxGridNoCellCoords )
         {
-            m_dragRowOrCol = dragCol;
+            DisableCellEditControl();
 
-            if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
-            {
-                if ( CanDragColSize() && CanDragGridSize() )
-                    ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false);
-            }
+            if ( event.LeftDown() )
+                DoGridCellLeftDown(event, coords, pos);
+            else if ( event.LeftDClick() )
+                DoGridCellLeftDClick(event, coords, pos);
+            else if ( event.RightDown() )
+                SendEvent(wxEVT_GRID_CELL_RIGHT_CLICK, coords, event);
+            else if ( event.RightDClick() )
+                SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK, coords, event);
         }
-        else // Neither on a row or col edge
+
+        // this one should be called even if we're not over any cell
+        if ( event.LeftUp() )
         {
-            if ( m_cursorMode != WXGRID_CURSOR_SELECT_CELL )
-            {
-                ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-            }
+            DoGridCellLeftUp(event, coords);
         }
     }
+    else if ( event.Moving() )
+    {
+        DoGridMouseMoveEvent(event, coords, pos);
+    }
+    else // unknown mouse event?
+    {
+        event.Skip();
+    }
 }
 
 void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
@@ -6883,12 +6906,14 @@ wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t),
 // ----- event handlers
 //
 
-// Generate a grid event based on a mouse event and
-// return the result of ProcessEvent()
-//
-int wxGrid::SendEvent( const wxEventType type,
-                        int row, int col,
-                        wxMouseEvent& mouseEv )
+// Generate a grid event based on a mouse event and return:
+//  -1 if the event was vetoed
+//  +1 if the event was processed (but not vetoed)
+//   0 if the event wasn't handled
+int
+wxGrid::SendEvent(const wxEventType type,
+                  int row, int col,
+                  wxMouseEvent& mouseEv)
 {
    bool claimed, vetoed;
 
@@ -6916,8 +6941,8 @@ int wxGrid::SendEvent( const wxEventType type,
        wxGridRangeSelectEvent gridEvt( GetId(),
                type,
                this,
-               m_selectingTopLeft,
-               m_selectingBottomRight,
+               m_selectedBlockTopLeft,
+               m_selectedBlockBottomRight,
                true,
                mouseEv.ControlDown(),
                mouseEv.ShiftDown(),
@@ -6977,11 +7002,9 @@ int wxGrid::SendEvent( const wxEventType type,
    return claimed ? 1 : 0;
 }
 
-// Generate a grid event of specified type and return the result
-// of ProcessEvent().
+// Generate a grid event of specified type, return value same as above
 //
-int wxGrid::SendEvent( const wxEventType type,
-                        int row, int col )
+int wxGrid::SendEvent(const wxEventType type, int row, int col)
 {
    bool claimed, vetoed;
 
@@ -7224,8 +7247,7 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
             case WXK_HOME:
                 if ( event.ControlDown() )
                 {
-                    MakeCellVisible( 0, 0 );
-                    SetCurrentCell( 0, 0 );
+                    GoToCell(0, 0);
                 }
                 else
                 {
@@ -7236,8 +7258,7 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
             case WXK_END:
                 if ( event.ControlDown() )
                 {
-                    MakeCellVisible( m_numRows - 1, m_numCols - 1 );
-                    SetCurrentCell( m_numRows - 1, m_numCols - 1 );
+                    GoToCell(m_numRows - 1, m_numCols - 1);
                 }
                 else
                 {
@@ -7299,16 +7320,14 @@ void wxGrid::OnKeyUp( wxKeyEvent& event )
     //
     if ( event.GetKeyCode() == WXK_SHIFT )
     {
-        if ( m_selectingTopLeft != wxGridNoCellCoords &&
-             m_selectingBottomRight != wxGridNoCellCoords )
+        if ( m_selectedBlockTopLeft != wxGridNoCellCoords &&
+             m_selectedBlockBottomRight != wxGridNoCellCoords )
         {
             if ( m_selection )
             {
                 m_selection->SelectBlock(
-                    m_selectingTopLeft.GetRow(),
-                    m_selectingTopLeft.GetCol(),
-                    m_selectingBottomRight.GetRow(),
-                    m_selectingBottomRight.GetCol(),
+                    m_selectedBlockTopLeft,
+                    m_selectedBlockBottomRight,
                     event.ControlDown(),
                     true,
                     event.AltDown(),
@@ -7316,9 +7335,9 @@ void wxGrid::OnKeyUp( wxKeyEvent& event )
             }
         }
 
-        m_selectingTopLeft = wxGridNoCellCoords;
-        m_selectingBottomRight = wxGridNoCellCoords;
-        m_selectingKeyboard = wxGridNoCellCoords;
+        m_selectedBlockTopLeft = wxGridNoCellCoords;
+        m_selectedBlockBottomRight = wxGridNoCellCoords;
+        m_selectedBlockCorner = wxGridNoCellCoords;
     }
 }
 
@@ -7367,12 +7386,12 @@ void wxGrid::OnEraseBackground(wxEraseEvent&)
 {
 }
 
-void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
+bool wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
 {
-    if ( SendEvent( wxEVT_GRID_SELECT_CELL, coords.GetRow(), coords.GetCol() ) )
+    if ( SendEvent(wxEVT_GRID_SELECT_CELL, coords) == -1 )
     {
-        // the event has been intercepted - do nothing
-        return;
+        // the event has been vetoed - do nothing
+        return false;
     }
 
 #if !defined(__WXMAC__)
@@ -7417,35 +7436,62 @@ void wxGrid::SetCurrentCell( const wxGridCellCoords& coords )
     DrawCellHighlight( dc, attr );
 #endif
     attr->DecRef();
+
+    return true;
 }
 
-void wxGrid::HighlightBlock(int topRow, int leftCol, int bottomRow, int rightCol)
+void
+wxGrid::UpdateBlockBeingSelected(int topRow, int leftCol,
+                                 int bottomRow, int rightCol)
 {
-    wxGridCellCoords updateTopLeft, updateBottomRight;
-
     if ( m_selection )
     {
-        if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectRows )
-        {
-            leftCol = 0;
-            rightCol = GetNumberCols() - 1;
-        }
-        else if ( m_selection->GetSelectionMode() == wxGrid::wxGridSelectColumns )
+        switch ( m_selection->GetSelectionMode() )
         {
-            topRow = 0;
-            bottomRow = GetNumberRows() - 1;
+            default:
+                wxFAIL_MSG( "unknown selection mode" );
+                // fall through
+
+            case wxGridSelectCells:
+                // arbitrary blocks selection allowed so just use the cell
+                // coordinates as is
+                break;
+
+            case wxGridSelectRows:
+                // only full rows selection allowd, ensure that we do select
+                // full rows
+                leftCol = 0;
+                rightCol = GetNumberCols() - 1;
+                break;
+
+            case wxGridSelectColumns:
+                // same as above but for columns
+                topRow = 0;
+                bottomRow = GetNumberRows() - 1;
+                break;
+
+            case wxGridSelectRowsOrColumns:
+                // in this mode we can select only full rows or full columns so
+                // it doesn't make sense to select blocks at all (and we can't
+                // extend the block because there is no preferred direction, we
+                // could only extend it to cover the entire grid but this is
+                // not useful)
+                return;
         }
     }
 
+    m_selectedBlockCorner = wxGridCellCoords(bottomRow, rightCol);
+    MakeCellVisible(m_selectedBlockCorner);
+
     EnsureFirstLessThanSecond(topRow, bottomRow);
     EnsureFirstLessThanSecond(leftCol, rightCol);
 
-    updateTopLeft = wxGridCellCoords( topRow, leftCol );
-    updateBottomRight = wxGridCellCoords( bottomRow, rightCol );
+    wxGridCellCoords updateTopLeft = wxGridCellCoords(topRow, leftCol),
+                     updateBottomRight = wxGridCellCoords(bottomRow, rightCol);
 
     // First the case that we selected a completely new area
-    if ( m_selectingTopLeft == wxGridNoCellCoords ||
-         m_selectingBottomRight == wxGridNoCellCoords )
+    if ( m_selectedBlockTopLeft == wxGridNoCellCoords ||
+         m_selectedBlockBottomRight == wxGridNoCellCoords )
     {
         wxRect rect;
         rect = BlockToDeviceRect( wxGridCellCoords ( topRow, leftCol ),
@@ -7454,8 +7500,8 @@ void wxGrid::HighlightBlock(int topRow, int leftCol, int bottomRow, int rightCol
     }
 
     // Now handle changing an existing selection area.
-    else if ( m_selectingTopLeft != updateTopLeft ||
-              m_selectingBottomRight != updateBottomRight )
+    else if ( m_selectedBlockTopLeft != updateTopLeft ||
+              m_selectedBlockBottomRight != updateBottomRight )
     {
         // Compute two optimal update rectangles:
         // Either one rectangle is a real subset of the
@@ -7469,10 +7515,10 @@ void wxGrid::HighlightBlock(int topRow, int leftCol, int bottomRow, int rightCol
         int     i;
 
         // Store intermediate values
-        wxCoord oldLeft = m_selectingTopLeft.GetCol();
-        wxCoord oldTop = m_selectingTopLeft.GetRow();
-        wxCoord oldRight = m_selectingBottomRight.GetCol();
-        wxCoord oldBottom = m_selectingBottomRight.GetRow();
+        wxCoord oldLeft = m_selectedBlockTopLeft.GetCol();
+        wxCoord oldTop = m_selectedBlockTopLeft.GetRow();
+        wxCoord oldRight = m_selectedBlockBottomRight.GetCol();
+        wxCoord oldBottom = m_selectedBlockBottomRight.GetRow();
 
         // Determine the outer/inner coordinates.
         EnsureFirstLessThanSecond(oldLeft, leftCol);
@@ -7531,8 +7577,8 @@ void wxGrid::HighlightBlock(int topRow, int leftCol, int bottomRow, int rightCol
     }
 
     // change selection
-    m_selectingTopLeft = updateTopLeft;
-    m_selectingBottomRight = updateBottomRight;
+    m_selectedBlockTopLeft = updateTopLeft;
+    m_selectedBlockBottomRight = updateBottomRight;
 }
 
 //
@@ -8371,7 +8417,7 @@ void wxGrid::EnableCellEditControl( bool enable )
     {
         if ( enable )
         {
-            if (SendEvent( wxEVT_GRID_EDITOR_SHOWN) <0)
+            if ( SendEvent(wxEVT_GRID_EDITOR_SHOWN) == -1 )
                 return;
 
             // this should be checked by the caller!
@@ -8385,7 +8431,7 @@ void wxGrid::EnableCellEditControl( bool enable )
         else
         {
             //FIXME:add veto support
-            SendEvent( wxEVT_GRID_EDITOR_HIDDEN );
+            SendEvent(wxEVT_GRID_EDITOR_HIDDEN);
 
             HideCellEditControl();
             SaveEditControlValue();
@@ -8624,9 +8670,7 @@ void wxGrid::SaveEditControlValue()
 
         if (changed)
         {
-            if ( SendEvent( wxEVT_GRID_CELL_CHANGE,
-                       m_currentCellCoords.GetRow(),
-                       m_currentCellCoords.GetCol() ) < 0 )
+            if ( SendEvent(wxEVT_GRID_CELL_CHANGE) == -1 )
             {
                 // Event has been vetoed, set the data back.
                 SetCellValue(row, col, oldval);
@@ -8642,19 +8686,13 @@ void wxGrid::SaveEditControlValue()
 //  coordinates for mouse events etc.
 //
 
-void wxGrid::XYToCell( int x, int y, wxGridCellCoords& coords ) const
+wxGridCellCoords wxGrid::XYToCell(int x, int y) const
 {
     int row = YToRow(y);
     int col = XToCol(x);
 
-    if ( row == -1 || col == -1 )
-    {
-        coords = wxGridNoCellCoords;
-    }
-    else
-    {
-        coords.Set( row, col );
-    }
+    return row == -1 || col == -1 ? wxGridNoCellCoords
+                                  : wxGridCellCoords(row, col);
 }
 
 // compute row or column from some (unscrolled) coordinate value, using either
@@ -8957,28 +8995,28 @@ wxGrid::DoMoveCursor(bool expandSelection,
 
     if ( expandSelection )
     {
-        if ( m_selectingKeyboard == wxGridNoCellCoords )
-            m_selectingKeyboard = m_currentCellCoords;
+        wxGridCellCoords coords = m_selectedBlockCorner;
+        if ( coords == wxGridNoCellCoords )
+            coords = m_currentCellCoords;
 
-        if ( diroper.IsAtBoundary(m_selectingKeyboard) )
+        if ( diroper.IsAtBoundary(coords) )
             return false;
 
-        diroper.Advance(m_selectingKeyboard);
+        diroper.Advance(coords);
 
-        MakeCellVisible(m_selectingKeyboard);
-        HighlightBlock(m_currentCellCoords, m_selectingKeyboard);
+        UpdateBlockBeingSelected(m_currentCellCoords, coords);
     }
-    else
+    else // don't expand selection
     {
+        ClearSelection();
+
         if ( diroper.IsAtBoundary(m_currentCellCoords) )
             return false;
 
-        ClearSelection();
-
         wxGridCellCoords coords = m_currentCellCoords;
         diroper.Advance(coords);
-        MakeCellVisible(coords);
-        SetCurrentCell(coords);
+
+        GoToCell(coords);
     }
 
     return true;
@@ -9025,8 +9063,7 @@ bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations& diroper)
         newRow = coords.GetRow();
     }
 
-    MakeCellVisible(newRow, m_currentCellCoords.GetCol());
-    SetCurrentCell(newRow, m_currentCellCoords.GetCol());
+    GoToCell(newRow, m_currentCellCoords.GetCol());
 
     return true;
 }
@@ -9097,16 +9134,14 @@ wxGrid::DoMoveCursorByBlock(bool expandSelection,
         }
     }
 
-    MakeCellVisible(coords);
     if ( expandSelection )
     {
-        m_selectingKeyboard = coords;
-        HighlightBlock(m_currentCellCoords, m_selectingKeyboard);
+        UpdateBlockBeingSelected(m_currentCellCoords, coords);
     }
     else
     {
         ClearSelection();
-        SetCurrentCell(coords);
+        GoToCell(coords);
     }
 
     return true;
@@ -10718,17 +10753,17 @@ void wxGrid::DeselectCell( int row, int col )
 bool wxGrid::IsSelection() const
 {
     return ( m_selection && (m_selection->IsSelection() ||
-             ( m_selectingTopLeft != wxGridNoCellCoords &&
-               m_selectingBottomRight != wxGridNoCellCoords) ) );
+             ( m_selectedBlockTopLeft != wxGridNoCellCoords &&
+               m_selectedBlockBottomRight != wxGridNoCellCoords) ) );
 }
 
 bool wxGrid::IsInSelection( int row, int col ) const
 {
     return ( m_selection && (m_selection->IsInSelection( row, col ) ||
-             ( row >= m_selectingTopLeft.GetRow() &&
-               col >= m_selectingTopLeft.GetCol() &&
-               row <= m_selectingBottomRight.GetRow() &&
-               col <= m_selectingBottomRight.GetCol() )) );
+             ( row >= m_selectedBlockTopLeft.GetRow() &&
+               col >= m_selectedBlockTopLeft.GetCol() &&
+               row <= m_selectedBlockBottomRight.GetRow() &&
+               col <= m_selectedBlockBottomRight.GetCol() )) );
 }
 
 wxGridCellCoordsArray wxGrid::GetSelectedCells() const
@@ -10788,13 +10823,18 @@ wxArrayInt wxGrid::GetSelectedCols() const
 
 void wxGrid::ClearSelection()
 {
-    wxRect r1 = BlockToDeviceRect( m_selectingTopLeft, m_selectingBottomRight);
-    wxRect r2 = BlockToDeviceRect( m_currentCellCoords, m_selectingKeyboard );
-    m_selectingTopLeft =
-    m_selectingBottomRight =
-    m_selectingKeyboard = wxGridNoCellCoords;
+    wxRect r1 = BlockToDeviceRect(m_selectedBlockTopLeft,
+                                  m_selectedBlockBottomRight);
+    wxRect r2 = BlockToDeviceRect(m_currentCellCoords,
+                                  m_selectedBlockCorner);
+
+    m_selectedBlockTopLeft =
+    m_selectedBlockBottomRight =
+    m_selectedBlockCorner = wxGridNoCellCoords;
+
     Refresh( false, &r1 );
     Refresh( false, &r2 );
+
     if ( m_selection )
         m_selection->ClearSelection();
 }
index f89835df90c64541a66c2de7813600d64dbadf3c..d5ba76cbbb5da898ccc53e574ba6a7f936840c7c 100644 (file)
@@ -385,15 +385,30 @@ void wxGridSelection::SelectBlock( int topRow, int leftCol,
                                    bool sendEvent )
 {
     // Fix the coordinates of the block if needed.
-    if ( m_selectionMode == wxGrid::wxGridSelectRows )
-    {
-        leftCol = 0;
-        rightCol = m_grid->GetNumberCols() - 1;
-    }
-    else if ( m_selectionMode == wxGrid::wxGridSelectColumns )
+    switch ( m_selectionMode )
     {
-        topRow = 0;
-        bottomRow = m_grid->GetNumberRows() - 1;
+        default:
+            wxFAIL_MSG( "unknown selection mode" );
+            // fall through
+
+        case wxGrid::wxGridSelectCells:
+            // nothing to do -- in this mode arbitrary blocks can be selected
+            break;
+
+        case wxGrid::wxGridSelectRows:
+            leftCol = 0;
+            rightCol = m_grid->GetNumberCols() - 1;
+            break;
+
+        case wxGrid::wxGridSelectColumns:
+            topRow = 0;
+            bottomRow = m_grid->GetNumberRows() - 1;
+            break;
+
+        case wxGrid::wxGridSelectRowsOrColumns:
+            // block selection doesn't make sense for this mode, we could only
+            // select the entire grid but this wouldn't be useful
+            return;
     }
 
     if ( topRow > bottomRow )