diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index b01c6b4e54..a06c654855 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -2218,10 +2218,14 @@ private: // SetColPos() and ResetColPos()) void RefreshAfterColPosChange(); - // reset the variables used during dragging operations after it ended - // because we lost mouse capture + // reset the variables used during dragging operations after it ended, + // either because we called EndDraggingIfNecessary() ourselves or because + // we lost mouse capture void DoAfterDraggingEnd(); + // release the mouse capture if it's currently captured + void EndDraggingIfNecessary(); + // return the position (not index) of the column at the given logical pixel // position @@ -2242,8 +2246,12 @@ private: // 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 mouse drag event in the grid window, return false if starting + // dragging was vetoed by the user-defined wxEVT_GRID_CELL_BEGIN_DRAG + // handler + bool DoGridDragEvent(wxMouseEvent& event, + const wxGridCellCoords& coords, + bool isFirstDrag); // process different clicks on grid cells void DoGridCellLeftDown(wxMouseEvent& event, diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index c3ab7f0594..2f01b2f667 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -3863,6 +3863,16 @@ void wxGrid::DoAfterDraggingEnd() m_winCapture = NULL; } +void wxGrid::EndDraggingIfNecessary() +{ + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + + DoAfterDraggingEnd(); + } +} + void wxGrid::ChangeCursorMode(CursorMode mode, wxWindow *win, bool captureMouse) @@ -3897,11 +3907,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win = m_gridWin; } - if ( m_winCapture ) - { - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; - } + EndDraggingIfNecessary(); m_cursorMode = mode; @@ -4019,34 +4025,14 @@ void wxGrid::DoGridLineDrag(wxMouseEvent& event, const wxGridOperations& oper) oper.DrawParallelLineInRect(dc, rectWin, m_dragLastPos); } -void wxGrid::DoGridDragEvent(wxMouseEvent& event, const wxGridCellCoords& coords) +bool wxGrid::DoGridDragEvent(wxMouseEvent& event, + const wxGridCellCoords& coords, + bool isFirstDrag) { - 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; - } - - if ( abs(m_startDragPos.x - pt.x) <= DRAG_SENSITIVITY && - abs(m_startDragPos.y - pt.y) <= DRAG_SENSITIVITY ) - return; - } - - const bool isFirstDrag = !m_isDragging; - m_isDragging = true; - switch ( m_cursorMode ) { case WXGRID_CURSOR_SELECT_CELL: - // no further handling if handled by user - if ( DoGridCellDrag(event, coords, isFirstDrag) == false ) - return; - break; + return DoGridCellDrag(event, coords, isFirstDrag); case WXGRID_CURSOR_RESIZE_ROW: DoGridLineDrag(event, wxGridRowOperations()); @@ -4060,13 +4046,7 @@ void wxGrid::DoGridDragEvent(wxMouseEvent& event, const wxGridCellCoords& coords event.Skip(); } - if ( isFirstDrag ) - { - wxASSERT_MSG( !m_winCapture, "shouldn't capture the mouse twice" ); - - m_winCapture = m_gridWin; - m_winCapture->CaptureMouse(); - } + return true; } void @@ -4160,12 +4140,6 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords) { if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL ) { - if (m_winCapture) - { - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; - } - if ( coords == m_currentCellCoords && m_waitForSlowClick && CanEnableCellControl() ) { ClearSelection(); @@ -4266,14 +4240,6 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event), void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event) { - if ( event.Entering() || event.Leaving() ) - { - // we don't care about these events but we must not reset m_isDragging - // if they happen so return before anything else is done - event.Skip(); - return; - } - const wxPoint pos = CalcUnscrolledPosition(event.GetPosition()); // coordinates of the cell under mouse @@ -4287,17 +4253,64 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event) coords.SetCol(coords.GetCol() + cell_cols); } - if ( event.Dragging() ) + // Releasing the left mouse button must be processed in any case, so deal + // with it first. + if ( event.LeftUp() ) { - if ( event.LeftIsDown() ) - DoGridDragEvent(event, coords); - else - event.Skip(); + // Note that we must call this one first, before resetting the + // drag-related data, as it relies on m_cursorMode being still set and + // EndDraggingIfNecessary() resets it. + DoGridCellLeftUp(event, coords); + + EndDraggingIfNecessary(); return; } - m_isDragging = false; - m_startDragPos = wxDefaultPosition; + const bool isDraggingWithLeft = event.Dragging() && event.LeftIsDown(); + + // While dragging the mouse, only releasing the left mouse button, which + // cancels the drag operation, is processed (above) and any other events + // are just ignored while it's in progress. + if ( m_isDragging ) + { + if ( isDraggingWithLeft ) + DoGridDragEvent(event, coords, false /* not first drag */); + return; + } + + // Now check if we're starting a drag operation (if it had been already + // started, m_isDragging would be true above). + if ( isDraggingWithLeft ) + { + // To avoid accidental drags, 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; + } + + if ( abs(m_startDragPos.x - pt.x) <= DRAG_SENSITIVITY && + abs(m_startDragPos.y - pt.y) <= DRAG_SENSITIVITY ) + return; + + if ( DoGridDragEvent(event, coords, true /* first drag */) ) + { + wxASSERT_MSG( !m_winCapture, "shouldn't capture the mouse twice" ); + + m_winCapture = m_gridWin; + m_winCapture->CaptureMouse(); + + m_isDragging = true; + } + + return; + } + + // If we're not dragging, cancel any dragging operation which could have + // been in progress. + EndDraggingIfNecessary(); // deal with various button presses if ( event.IsButton() ) @@ -4315,12 +4328,6 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event) else if ( event.RightDClick() ) SendEvent(wxEVT_GRID_CELL_RIGHT_DCLICK, coords, event); } - - // this one should be called even if we're not over any cell - if ( event.LeftUp() ) - { - DoGridCellLeftUp(event, coords); - } } else if ( event.Moving() ) {