diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index c1adbb0b24..a06c654855 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -2218,6 +2218,14 @@ private: // SetColPos() and ResetColPos()) void RefreshAfterColPosChange(); + // 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 @@ -2238,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 5a8831f792..2f01b2f667 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -2418,7 +2418,6 @@ void wxGrid::Init() m_selection = NULL; m_defaultCellAttr = NULL; m_typeRegistry = NULL; - m_winCapture = NULL; m_rowLabelWidth = WXGRID_DEFAULT_ROW_LABEL_WIDTH; m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT; @@ -3847,18 +3846,33 @@ void wxGrid::CancelMouseCapture() // cancel operation currently in progress, whatever it is if ( m_winCapture ) { - m_isDragging = false; - m_startDragPos = wxDefaultPosition; - - m_cursorMode = WXGRID_CURSOR_SELECT_CELL; - m_winCapture->SetCursor( *wxSTANDARD_CURSOR ); - m_winCapture = NULL; + DoAfterDraggingEnd(); // remove traces of whatever we drew on screen Refresh(); } } +void wxGrid::DoAfterDraggingEnd() +{ + m_isDragging = false; + m_startDragPos = wxDefaultPosition; + + m_cursorMode = WXGRID_CURSOR_SELECT_CELL; + m_winCapture->SetCursor( *wxSTANDARD_CURSOR ); + m_winCapture = NULL; +} + +void wxGrid::EndDraggingIfNecessary() +{ + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + + DoAfterDraggingEnd(); + } +} + void wxGrid::ChangeCursorMode(CursorMode mode, wxWindow *win, bool captureMouse) @@ -3893,11 +3907,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, win = m_gridWin; } - if ( m_winCapture ) - { - m_winCapture->ReleaseMouse(); - m_winCapture = NULL; - } + EndDraggingIfNecessary(); m_cursorMode = mode; @@ -4015,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()); @@ -4056,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 @@ -4156,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(); @@ -4262,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 @@ -4283,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() ) @@ -4311,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() ) {