Merge branch 'grid-mouse'

Improve mouse event handling in wxGrid during drag operations.

See https://github.com/wxWidgets/wxWidgets/pull/891

Closes #18186.
This commit is contained in:
Vadim Zeitlin
2018-08-21 13:03:09 +02:00
2 changed files with 95 additions and 72 deletions

View File

@@ -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,

View File

@@ -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() )
{