Improve usability of wxGrid actions using mouse dragging
Implement auto scrolling and handle ESCAPE to cancel the actions done by dragging the mouse, such as resizing or selecting an area. Closes #22292.
This commit is contained in:
committed by
Vadim Zeitlin
parent
8245ba96ee
commit
1b158caa83
@@ -13,7 +13,6 @@
|
||||
|
||||
- Make Begin/EndBatch() the same as the generic Freeze/Thaw()
|
||||
- Review the column reordering code, it's a mess.
|
||||
- Implement row reordering after dealing with the columns.
|
||||
*/
|
||||
|
||||
// For compilers that support precompilation, includes "wx/wx.h".
|
||||
@@ -3034,8 +3033,11 @@ void wxGrid::Init()
|
||||
m_dragMoveCol = -1;
|
||||
m_dragLastPos = -1;
|
||||
m_dragRowOrCol = -1;
|
||||
m_dragRowOrColOldSize = -1;
|
||||
m_isDragging = false;
|
||||
m_cancelledDragging = false;
|
||||
m_startDragPos = wxDefaultPosition;
|
||||
m_lastMousePos = wxDefaultPosition;
|
||||
|
||||
m_sortCol = wxNOT_FOUND;
|
||||
m_sortIsAscending = true;
|
||||
@@ -3864,12 +3866,99 @@ void wxGrid::PrepareDCFor(wxDC &dc, wxGridWindow *gridWindow)
|
||||
dc.SetDeviceOrigin(dcOrigin.x, dcOrigin.y);
|
||||
}
|
||||
|
||||
void wxGrid::CheckDoDragScroll(wxGridSubwindow *eventGridWindow, wxGridSubwindow *gridWindow,
|
||||
wxPoint posEvent, int direction)
|
||||
{
|
||||
// helper for Process{Row|Col}LabelMouseEvent, ProcessGridCellMouseEvent:
|
||||
// scroll when at the edges or outside the window w. respect to direction
|
||||
// eventGridWindow: the window that received the mouse event
|
||||
// gridWindow: the same or the corresponding non-frozen window
|
||||
|
||||
if ( !m_isDragging )
|
||||
{
|
||||
// drag is just starting
|
||||
m_lastMousePos = posEvent;
|
||||
return;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
eventGridWindow->GetSize(&w, &h);
|
||||
// ViewStart is scroll position in scroll units
|
||||
wxPoint scrollPos = GetViewStart();
|
||||
wxPoint newScrollPos = wxPoint(wxDefaultCoord, wxDefaultCoord);
|
||||
|
||||
if ( direction & wxHORIZONTAL )
|
||||
{
|
||||
// check x direction
|
||||
if ( eventGridWindow->IsFrozen() && posEvent.x < w )
|
||||
{
|
||||
// in the frozen window, moving left?
|
||||
if ( scrollPos.x > 0 && posEvent.x < m_lastMousePos.x )
|
||||
newScrollPos.x = scrollPos.x - 1;
|
||||
}
|
||||
else if ( eventGridWindow->IsFrozen() && posEvent.x >= w )
|
||||
{
|
||||
// frozen window was left, add the width of the non-frozen window
|
||||
w += gridWindow->GetSize().x;
|
||||
}
|
||||
|
||||
if ( posEvent.x < 0 && scrollPos.x > 0 )
|
||||
newScrollPos.x = scrollPos.x - 1;
|
||||
else if ( posEvent.x >= w )
|
||||
newScrollPos.x = scrollPos.x + 1;
|
||||
}
|
||||
|
||||
if ( direction & wxVERTICAL )
|
||||
{
|
||||
// check y direction
|
||||
if ( eventGridWindow->IsFrozen() && posEvent.y < h )
|
||||
{
|
||||
// in the frozen window, moving upward?
|
||||
if ( scrollPos.y && posEvent.y < m_lastMousePos.y )
|
||||
newScrollPos.y = scrollPos.y - 1;
|
||||
}
|
||||
else if ( eventGridWindow->IsFrozen() && posEvent.y >= h )
|
||||
{
|
||||
// frozen window was left, add the height of the non-frozen window
|
||||
h += gridWindow->GetSize().y;
|
||||
}
|
||||
|
||||
if ( posEvent.y < 0 && scrollPos.y > 0 )
|
||||
newScrollPos.y = scrollPos.y - 1;
|
||||
else if ( posEvent.y >= h )
|
||||
newScrollPos.y = scrollPos.y + 1;
|
||||
}
|
||||
|
||||
if ( newScrollPos.x != wxDefaultCoord || newScrollPos.y != wxDefaultCoord )
|
||||
Scroll(newScrollPos);
|
||||
|
||||
m_lastMousePos = posEvent;
|
||||
}
|
||||
|
||||
bool wxGrid::CheckIfDragCancelled(wxMouseEvent *event)
|
||||
{
|
||||
// helper for Process{Row|Col}LabelMouseEvent, ProcessGridCellMouseEvent:
|
||||
// block re-triggering m_isDragging
|
||||
if ( !m_cancelledDragging )
|
||||
return false;
|
||||
|
||||
if ( event->LeftIsDown() )
|
||||
return true;
|
||||
|
||||
m_cancelledDragging = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindow* rowLabelWin )
|
||||
{
|
||||
int y;
|
||||
wxGridWindow *gridWindow = rowLabelWin->IsFrozen() ? m_frozenRowGridWin : m_gridWin;
|
||||
|
||||
event.SetPosition(event.GetPosition() + GetGridWindowOffset(gridWindow));
|
||||
// store position, before it's modified in the next step
|
||||
const wxPoint posEvent = event.GetPosition();
|
||||
|
||||
event.SetPosition(posEvent + GetGridWindowOffset(gridWindow));
|
||||
|
||||
// for drag, we could be moving from the window sending the event to the other
|
||||
if ( rowLabelWin->IsFrozen() && event.GetPosition().y > rowLabelWin->GetClientSize().y )
|
||||
@@ -3878,6 +3967,15 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
|
||||
CalcGridWindowUnscrolledPosition(0, event.GetPosition().y, NULL, &y, gridWindow);
|
||||
int row = YToRow( y );
|
||||
|
||||
if ( CheckIfDragCancelled(&event) )
|
||||
return;
|
||||
|
||||
if ( event.Dragging() && (m_winCapture == rowLabelWin) )
|
||||
{
|
||||
// scroll when at the edges or outside the window
|
||||
CheckDoDragScroll(rowLabelWin, m_rowLabelWin, posEvent, wxVERTICAL);
|
||||
}
|
||||
|
||||
if ( event.Dragging() )
|
||||
{
|
||||
if (!m_isDragging)
|
||||
@@ -3995,7 +4093,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
|
||||
row = YToEdgeOfRow(y);
|
||||
if ( row != wxNOT_FOUND && CanDragRowSize(row) )
|
||||
{
|
||||
DoStartResizeRowOrCol(row);
|
||||
DoStartResizeRowOrCol(row, GetRowSize(row));
|
||||
ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, rowLabelWin);
|
||||
}
|
||||
else // not a request to start resizing
|
||||
@@ -4157,6 +4255,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event, wxGridRowLabelWindo
|
||||
|
||||
ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, rowLabelWin);
|
||||
m_dragLastPos = -1;
|
||||
m_lastMousePos = wxDefaultPosition;
|
||||
m_isDragging = false;
|
||||
}
|
||||
|
||||
@@ -4311,13 +4410,14 @@ void wxGrid::DoColHeaderClick(int col)
|
||||
}
|
||||
}
|
||||
|
||||
void wxGrid::DoStartResizeRowOrCol(int col)
|
||||
void wxGrid::DoStartResizeRowOrCol(int col, int size)
|
||||
{
|
||||
// Hide the editor if it's currently shown to avoid any weird interactions
|
||||
// with it while dragging the row/column separator.
|
||||
AcceptCellEditControlIfShown();
|
||||
|
||||
m_dragRowOrCol = col;
|
||||
m_dragRowOrColOldSize = size;
|
||||
}
|
||||
|
||||
void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindow* colLabelWin )
|
||||
@@ -4325,7 +4425,10 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo
|
||||
int x;
|
||||
wxGridWindow *gridWindow = colLabelWin->IsFrozen() ? m_frozenColGridWin : m_gridWin;
|
||||
|
||||
event.SetPosition(event.GetPosition() + GetGridWindowOffset(gridWindow));
|
||||
// store position, before it's modified in the next step
|
||||
const wxPoint posEvent = event.GetPosition();
|
||||
|
||||
event.SetPosition(posEvent + GetGridWindowOffset(gridWindow));
|
||||
|
||||
// for drag, we could be moving from the window sending the event to the other
|
||||
if (colLabelWin->IsFrozen() && event.GetPosition().x > colLabelWin->GetClientSize().x)
|
||||
@@ -4334,6 +4437,16 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo
|
||||
CalcGridWindowUnscrolledPosition(event.GetPosition().x, 0, &x, NULL, gridWindow);
|
||||
|
||||
int col = XToCol(x);
|
||||
|
||||
if ( CheckIfDragCancelled(&event) )
|
||||
return;
|
||||
|
||||
if ( event.Dragging() && (m_winCapture == colLabelWin) )
|
||||
{
|
||||
// scroll when at the edges or outside the window
|
||||
CheckDoDragScroll(colLabelWin, GetColLabelWindow(), posEvent, wxHORIZONTAL);
|
||||
}
|
||||
|
||||
if ( event.Dragging() )
|
||||
{
|
||||
if (!m_isDragging)
|
||||
@@ -4452,7 +4565,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo
|
||||
int colEdge = XToEdgeOfCol(x);
|
||||
if ( colEdge != wxNOT_FOUND && CanDragColSize(colEdge) )
|
||||
{
|
||||
DoStartResizeRowOrCol(colEdge);
|
||||
DoStartResizeRowOrCol(colEdge, GetColSize(colEdge));
|
||||
ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, colLabelWin);
|
||||
}
|
||||
else // not a request to start resizing
|
||||
@@ -4611,6 +4724,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event, wxGridColLabelWindo
|
||||
|
||||
ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
|
||||
m_dragLastPos = -1;
|
||||
m_lastMousePos = wxDefaultPosition;
|
||||
m_isDragging = false;
|
||||
}
|
||||
|
||||
@@ -4736,6 +4850,7 @@ void wxGrid::DoAfterDraggingEnd()
|
||||
|
||||
m_isDragging = false;
|
||||
m_startDragPos = wxDefaultPosition;
|
||||
m_lastMousePos = wxDefaultPosition;
|
||||
|
||||
m_cursorMode = WXGRID_CURSOR_SELECT_CELL;
|
||||
m_winCapture->SetCursor( *wxSTANDARD_CURSOR );
|
||||
@@ -4803,9 +4918,6 @@ void wxGrid::ChangeCursorMode(CursorMode mode,
|
||||
|
||||
case WXGRID_CURSOR_MOVE_ROW:
|
||||
case WXGRID_CURSOR_MOVE_COL:
|
||||
// Currently we don't capture mouse when moving columns, which is
|
||||
// almost certainly wrong.
|
||||
captureMouse = false;
|
||||
win->SetCursor( wxCursor(wxCURSOR_HAND) );
|
||||
break;
|
||||
|
||||
@@ -4931,12 +5043,16 @@ wxGrid::DoGridCellLeftDown(wxMouseEvent& event,
|
||||
{
|
||||
int dragRowOrCol = wxNOT_FOUND;
|
||||
if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
|
||||
{
|
||||
dragRowOrCol = XToEdgeOfCol(pos.x);
|
||||
DoStartResizeRowOrCol(dragRowOrCol, GetColSize(dragRowOrCol));
|
||||
}
|
||||
else
|
||||
{
|
||||
dragRowOrCol = YToEdgeOfRow(pos.y);
|
||||
DoStartResizeRowOrCol(dragRowOrCol, GetRowSize(dragRowOrCol));
|
||||
}
|
||||
wxCHECK_RET( dragRowOrCol != -1, "Can't determine row or column in resizing mode" );
|
||||
|
||||
DoStartResizeRowOrCol(dragRowOrCol);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -5115,13 +5231,20 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event, wxGridWindow *eventG
|
||||
// the window receiving the event might not be the same as the one under
|
||||
// the mouse (e.g. in the case of a dragging event started in one window,
|
||||
// but continuing over another one)
|
||||
|
||||
if ( CheckIfDragCancelled(&event) )
|
||||
return;
|
||||
|
||||
wxGridWindow *gridWindow =
|
||||
DevicePosToGridWindow(event.GetPosition() + eventGridWindow->GetPosition());
|
||||
|
||||
if ( !gridWindow )
|
||||
gridWindow = eventGridWindow;
|
||||
|
||||
event.SetPosition(event.GetPosition() + eventGridWindow->GetPosition() -
|
||||
// store position, before it's modified in the next step
|
||||
const wxPoint posEvent = event.GetPosition();
|
||||
|
||||
event.SetPosition(posEvent + eventGridWindow->GetPosition() -
|
||||
wxPoint(m_rowLabelWidth, m_colLabelHeight));
|
||||
|
||||
wxPoint pos = CalcGridWindowUnscrolledPosition(event.GetPosition(), gridWindow);
|
||||
@@ -5152,6 +5275,13 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event, wxGridWindow *eventG
|
||||
|
||||
const bool isDraggingWithLeft = event.Dragging() && event.LeftIsDown();
|
||||
|
||||
if ( isDraggingWithLeft && (m_winCapture == eventGridWindow) )
|
||||
{
|
||||
// scroll when at the edges or outside the window
|
||||
CheckDoDragScroll(eventGridWindow, m_gridWin, posEvent,
|
||||
wxHORIZONTAL | wxVERTICAL);
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -5295,7 +5425,7 @@ void wxGrid::DoEndDragResizeCol(const wxMouseEvent& event, wxGridWindow* gridWin
|
||||
|
||||
void wxGrid::DoHeaderStartDragResizeCol(int col)
|
||||
{
|
||||
DoStartResizeRowOrCol(col);
|
||||
DoStartResizeRowOrCol(col, GetColSize(col));
|
||||
}
|
||||
|
||||
void wxGrid::DoHeaderDragResizeCol(int width)
|
||||
@@ -6185,7 +6315,44 @@ void wxGrid::OnKeyDown( wxKeyEvent& event )
|
||||
break;
|
||||
|
||||
case WXK_ESCAPE:
|
||||
ClearSelection();
|
||||
if ( m_isDragging && m_winCapture )
|
||||
{
|
||||
switch ( m_cursorMode )
|
||||
{
|
||||
case WXGRID_CURSOR_MOVE_COL:
|
||||
case WXGRID_CURSOR_MOVE_ROW:
|
||||
// end row/column moving
|
||||
m_winCapture->Refresh();
|
||||
m_dragLastPos = -1;
|
||||
break;
|
||||
|
||||
case WXGRID_CURSOR_RESIZE_ROW:
|
||||
case WXGRID_CURSOR_RESIZE_COL:
|
||||
// reset to size from before dragging
|
||||
(m_cursorMode == WXGRID_CURSOR_RESIZE_ROW
|
||||
? static_cast<const wxGridOperations&>(wxGridRowOperations())
|
||||
: static_cast<const wxGridOperations&>(wxGridColumnOperations())
|
||||
).SetLineSize(this, m_dragRowOrCol, m_dragRowOrColOldSize);
|
||||
|
||||
m_dragRowOrCol = -1;
|
||||
break;
|
||||
|
||||
case WXGRID_CURSOR_SELECT_CELL:
|
||||
case WXGRID_CURSOR_SELECT_ROW:
|
||||
case WXGRID_CURSOR_SELECT_COL:
|
||||
if ( m_selection )
|
||||
m_selection->CancelSelecting();
|
||||
break;
|
||||
}
|
||||
EndDraggingIfNecessary();
|
||||
|
||||
// ensure that a new drag operation is only started after a LeftUp
|
||||
m_cancelledDragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearSelection();
|
||||
}
|
||||
break;
|
||||
|
||||
case WXK_TAB:
|
||||
|
||||
Reference in New Issue
Block a user