Allow panning with selectable key

Add optins to mouse dialog to allow modifier key-based mouse movement
panning

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2492
This commit is contained in:
Seth Hillbrand 2025-08-11 13:18:18 -07:00
parent 833a5ee3ab
commit a7e6fa8198
11 changed files with 291 additions and 82 deletions

View File

@ -111,6 +111,14 @@ bool PANEL_MOUSE_SETTINGS::TransferDataFromWindow()
default: break; default: break;
} }
switch( m_choicePanMoveKey->GetSelection() )
{
case 1: cfg->m_Input.motion_pan_modifier = WXK_ALT; break;
case 2: cfg->m_Input.motion_pan_modifier = WXK_CONTROL; break;
case 3: cfg->m_Input.motion_pan_modifier = WXK_SHIFT; break;
default: cfg->m_Input.motion_pan_modifier = 0; break;
}
cfg->m_Input.center_on_zoom = m_checkZoomCenter->GetValue(); cfg->m_Input.center_on_zoom = m_checkZoomCenter->GetValue();
cfg->m_Input.auto_pan = m_checkAutoPan->GetValue(); cfg->m_Input.auto_pan = m_checkAutoPan->GetValue();
cfg->m_Input.auto_pan_acceleration = m_autoPanSpeed->GetValue(); cfg->m_Input.auto_pan_acceleration = m_autoPanSpeed->GetValue();
@ -178,6 +186,14 @@ void PANEL_MOUSE_SETTINGS::applySettingsToPanel( const COMMON_SETTINGS& aSetting
default: break; default: break;
} }
switch( aSettings.m_Input.motion_pan_modifier )
{
case WXK_ALT: m_choicePanMoveKey->SetSelection( 1 ); break;
case WXK_CONTROL: m_choicePanMoveKey->SetSelection( 2 ); break;
case WXK_SHIFT: m_choicePanMoveKey->SetSelection( 3 ); break;
default: m_choicePanMoveKey->SetSelection( 0 ); break;
}
m_currentScrollMod.zoom = aSettings.m_Input.scroll_modifier_zoom; m_currentScrollMod.zoom = aSettings.m_Input.scroll_modifier_zoom;
m_currentScrollMod.panh = aSettings.m_Input.scroll_modifier_pan_h; m_currentScrollMod.panh = aSettings.m_Input.scroll_modifier_pan_h;
m_currentScrollMod.panv = aSettings.m_Input.scroll_modifier_pan_v; m_currentScrollMod.panv = aSettings.m_Input.scroll_modifier_pan_v;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -156,6 +156,19 @@ PANEL_MOUSE_SETTINGS_BASE::PANEL_MOUSE_SETTINGS_BASE( wxWindow* parent, wxWindow
fgSizer1->Add( m_choiceRightButtonDrag, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 ); fgSizer1->Add( m_choiceRightButtonDrag, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 );
m_panMoveKeyLabel = new wxStaticText( this, wxID_ANY, _("Pan on mouse movement with key:"), wxDefaultPosition, wxDefaultSize, 0 );
m_panMoveKeyLabel->Wrap( -1 );
fgSizer1->Add( m_panMoveKeyLabel, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 );
wxString m_choicePanMoveKeyChoices[] = { _("None"), _("Alt"), _("Ctrl"), _("Shift") };
int m_choicePanMoveKeyNChoices = sizeof( m_choicePanMoveKeyChoices ) / sizeof( wxString );
m_choicePanMoveKey = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choicePanMoveKeyNChoices, m_choicePanMoveKeyChoices, 0 );
m_choicePanMoveKey->SetSelection( 0 );
fgSizer1->Add( m_choicePanMoveKey, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 ); fgSizer1->Add( 0, 0, 1, wxEXPAND, 5 );

View File

@ -934,11 +934,11 @@
<property name="width">0</property> <property name="width">0</property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="false"> <object class="sizeritem" expanded="true">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property> <property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="false"> <object class="wxFlexGridSizer" expanded="true">
<property name="cols">3</property> <property name="cols">3</property>
<property name="flexible_direction">wxHORIZONTAL</property> <property name="flexible_direction">wxHORIZONTAL</property>
<property name="growablecols">2</property> <property name="growablecols">2</property>
@ -1361,6 +1361,143 @@
<property name="width">0</property> <property name="width">0</property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Pan on mouse movement with key:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_panMoveKeyLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
<property name="proportion">0</property>
<object class="wxChoice" expanded="false">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices">&quot;None&quot; &quot;Alt&quot; &quot;Ctrl&quot; &quot;Shift&quot;</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_choicePanMoveKey</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">0</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="false">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="false">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object> </object>
</object> </object>
</object> </object>

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6) // C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -61,6 +61,8 @@ class PANEL_MOUSE_SETTINGS_BASE : public RESETTABLE_PANEL
wxChoice* m_choiceMiddleButtonDrag; wxChoice* m_choiceMiddleButtonDrag;
wxStaticText* m_staticText31; wxStaticText* m_staticText31;
wxChoice* m_choiceRightButtonDrag; wxChoice* m_choiceRightButtonDrag;
wxStaticText* m_panMoveKeyLabel;
wxChoice* m_choicePanMoveKey;
wxStaticText* m_scrollLabel; wxStaticText* m_scrollLabel;
wxStaticLine* m_staticline2; wxStaticLine* m_staticline2;
wxStaticText* m_staticText21; wxStaticText* m_staticText21;

View File

@ -716,6 +716,7 @@ KIGFX::VC_SETTINGS EDA_DRAW_PANEL_GAL::GetVcSettings()
vcSettings.m_scrollModifierZoom = cfg->m_Input.scroll_modifier_zoom; vcSettings.m_scrollModifierZoom = cfg->m_Input.scroll_modifier_zoom;
vcSettings.m_scrollModifierPanH = cfg->m_Input.scroll_modifier_pan_h; vcSettings.m_scrollModifierPanH = cfg->m_Input.scroll_modifier_pan_h;
vcSettings.m_scrollModifierPanV = cfg->m_Input.scroll_modifier_pan_v; vcSettings.m_scrollModifierPanV = cfg->m_Input.scroll_modifier_pan_v;
vcSettings.m_motionPanModifier = cfg->m_Input.motion_pan_modifier;
vcSettings.m_dragLeft = cfg->m_Input.drag_left; vcSettings.m_dragLeft = cfg->m_Input.drag_left;
vcSettings.m_dragMiddle = cfg->m_Input.drag_middle; vcSettings.m_dragMiddle = cfg->m_Input.drag_middle;
vcSettings.m_dragRight = cfg->m_Input.drag_right; vcSettings.m_dragRight = cfg->m_Input.drag_right;

View File

@ -269,6 +269,9 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_v", m_params.emplace_back( new PARAM<int>( "input.scroll_modifier_pan_v",
&m_Input.scroll_modifier_pan_v, WXK_SHIFT ) ); &m_Input.scroll_modifier_pan_v, WXK_SHIFT ) );
m_params.emplace_back( new PARAM<int>( "input.motion_pan_modifier",
&m_Input.motion_pan_modifier, 0 ) );
m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_zoom", m_params.emplace_back( new PARAM<bool>( "input.reverse_scroll_zoom",
&m_Input.reverse_scroll_zoom, false ) ); &m_Input.reverse_scroll_zoom, false ) );

View File

@ -76,6 +76,7 @@ void VC_SETTINGS::Reset()
m_scrollModifierZoom = 0; m_scrollModifierZoom = 0;
m_scrollModifierPanH = WXK_CONTROL; m_scrollModifierPanH = WXK_CONTROL;
m_scrollModifierPanV = WXK_SHIFT; m_scrollModifierPanV = WXK_SHIFT;
m_motionPanModifier = 0;
m_dragLeft = MOUSE_DRAG_ACTION::NONE; m_dragLeft = MOUSE_DRAG_ACTION::NONE;
m_dragMiddle = MOUSE_DRAG_ACTION::PAN; m_dragMiddle = MOUSE_DRAG_ACTION::PAN;
m_dragRight = MOUSE_DRAG_ACTION::PAN; m_dragRight = MOUSE_DRAG_ACTION::PAN;

View File

@ -73,9 +73,16 @@ static std::unique_ptr<ZOOM_CONTROLLER> GetZoomControllerForPlatform( bool aAcce
WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, EDA_DRAW_PANEL_GAL* aParentPanel ) : WX_VIEW_CONTROLS::WX_VIEW_CONTROLS( VIEW* aView, EDA_DRAW_PANEL_GAL* aParentPanel ) :
VIEW_CONTROLS( aView ), m_state( IDLE ), m_parentPanel( aParentPanel ), VIEW_CONTROLS( aView ),
m_scrollScale( 1.0, 1.0 ), m_cursorPos( 0, 0 ), m_updateCursor( true ), m_state( IDLE ),
m_infinitePanWorks( false ), m_gestureLastZoomFactor( 1.0 ) m_parentPanel( aParentPanel ),
m_scrollScale( 1.0, 1.0 ),
m_cursorPos( 0, 0 ),
m_updateCursor( true ),
m_metaPanning( false ),
m_metaPanStart( 0, 0 ),
m_infinitePanWorks( false ),
m_gestureLastZoomFactor( 1.0 )
{ {
LoadSettings(); LoadSettings();
@ -178,6 +185,7 @@ void WX_VIEW_CONTROLS::LoadSettings()
m_settings.m_dragRight = cfg->m_Input.drag_right; m_settings.m_dragRight = cfg->m_Input.drag_right;
m_settings.m_scrollReverseZoom = cfg->m_Input.reverse_scroll_zoom; m_settings.m_scrollReverseZoom = cfg->m_Input.reverse_scroll_zoom;
m_settings.m_scrollReversePanH = cfg->m_Input.reverse_scroll_pan_h; m_settings.m_scrollReversePanH = cfg->m_Input.reverse_scroll_pan_h;
m_settings.m_motionPanModifier = cfg->m_Input.motion_pan_modifier;
m_zoomController.reset(); m_zoomController.reset();
@ -238,6 +246,37 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
} }
} }
if( m_settings.m_motionPanModifier != WXK_NONE
&& wxGetKeyState( static_cast<wxKeyCode>( m_settings.m_motionPanModifier ) ) )
{
if( !m_metaPanning )
{
m_metaPanning = true;
m_metaPanStart = mousePos;
aEvent.StopPropagation();
}
else
{
VECTOR2D d = m_metaPanStart - mousePos;
m_metaPanStart = mousePos;
VECTOR2D delta = m_view->ToWorld( d, false );
m_view->SetCenter( m_view->GetCenter() + delta );
aEvent.StopPropagation();
}
if( m_updateCursor )
m_cursorPos = GetClampedCoords( m_view->ToWorld( mousePos ) );
else
m_updateCursor = true;
aEvent.Skip();
return;
}
else
{
m_metaPanning = false;
}
if( m_state != DRAG_PANNING && m_state != DRAG_ZOOMING ) if( m_state != DRAG_PANNING && m_state != DRAG_ZOOMING )
handleCursorCapture( x, y ); handleCursorCapture( x, y );
@ -284,8 +323,7 @@ void WX_VIEW_CONTROLS::onMotion( wxMouseEvent& aEvent )
{ {
if( !justWarped ) if( !justWarped )
{ {
if( m_infinitePanWorks if( m_infinitePanWorks && KIPLATFORM::UI::WarpPointer( m_parentPanel, x + warpX, y + warpY ) )
&& KIPLATFORM::UI::WarpPointer( m_parentPanel, x + warpX, y + warpY ) )
{ {
m_dragStartPoint += VECTOR2D( warpX, warpY ); m_dragStartPoint += VECTOR2D( warpX, warpY );
justWarped = true; justWarped = true;
@ -394,8 +432,7 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& aEvent )
// as vertical scroll events and confuse the user. // as vertical scroll events and confuse the user.
if( modifiers == m_settings.m_scrollModifierZoom && axis == wxMOUSE_WHEEL_VERTICAL ) if( modifiers == m_settings.m_scrollModifierZoom && axis == wxMOUSE_WHEEL_VERTICAL )
{ {
const int rotation = const int rotation = aEvent.GetWheelRotation() * ( m_settings.m_scrollReverseZoom ? -1 : 1 );
aEvent.GetWheelRotation() * ( m_settings.m_scrollReverseZoom ? -1 : 1 );
const double zoomScale = m_zoomController->GetScaleForRotation( rotation ); const double zoomScale = m_zoomController->GetScaleForRotation( rotation );
if( IsCursorWarpingEnabled() ) if( IsCursorWarpingEnabled() )
@ -477,8 +514,8 @@ void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
{ {
case IDLE: case IDLE:
case AUTO_PANNING: case AUTO_PANNING:
if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::PAN ) || if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::PAN )
( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::PAN ) ) || ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::PAN ) )
{ {
m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() ); m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
setState( DRAG_PANNING ); setState( DRAG_PANNING );
@ -489,8 +526,8 @@ void WX_VIEW_CONTROLS::onButton( wxMouseEvent& aEvent )
m_parentPanel->CaptureMouse(); m_parentPanel->CaptureMouse();
#endif #endif
} }
else if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::ZOOM ) || else if( ( aEvent.MiddleDown() && m_settings.m_dragMiddle == MOUSE_DRAG_ACTION::ZOOM )
( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::ZOOM ) ) || ( aEvent.RightDown() && m_settings.m_dragRight == MOUSE_DRAG_ACTION::ZOOM ) )
{ {
m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() ); m_dragStartPoint = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
m_zoomStartPoint = m_dragStartPoint; m_zoomStartPoint = m_dragStartPoint;
@ -635,8 +672,7 @@ void WX_VIEW_CONTROLS::onTimer( wxTimerEvent& aEvent )
case IDLE: // Just remove unnecessary warnings case IDLE: // Just remove unnecessary warnings
case DRAG_PANNING: case DRAG_PANNING:
case DRAG_ZOOMING: case DRAG_ZOOMING: break;
break;
} }
} }
@ -689,8 +725,7 @@ void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
const auto& boundary = m_view->GetBoundary(); const auto& boundary = m_view->GetBoundary();
// Flip scroll direction in flipped view // Flip scroll direction in flipped view
const double xstart = ( m_view->IsMirroredX() ? const double xstart = ( m_view->IsMirroredX() ? boundary.GetRight() : boundary.GetLeft() );
boundary.GetRight() : boundary.GetLeft() );
const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 ); const double xdelta = ( m_view->IsMirroredX() ? -1 : 1 );
if( dir == wxHORIZONTAL ) if( dir == wxHORIZONTAL )
@ -700,9 +735,7 @@ void WX_VIEW_CONTROLS::onScroll( wxScrollWinEvent& aEvent )
m_view->SetCenter( center ); m_view->SetCenter( center );
} }
else if( type == wxEVT_SCROLLWIN_THUMBRELEASE || else if( type == wxEVT_SCROLLWIN_THUMBRELEASE || type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLLWIN_BOTTOM )
type == wxEVT_SCROLLWIN_TOP ||
type == wxEVT_SCROLLWIN_BOTTOM )
{ {
// Do nothing on thumb release, we don't care about it. // Do nothing on thumb release, we don't care about it.
// We don't have a concept of top or bottom in our viewport, so ignore those events. // We don't have a concept of top or bottom in our viewport, so ignore those events.
@ -769,8 +802,7 @@ void WX_VIEW_CONTROLS::CaptureCursor( bool aEnabled )
// Calling it without calling ReleaseMouse() is not accepted by wxWidgets (MSW specific) // Calling it without calling ReleaseMouse() is not accepted by wxWidgets (MSW specific)
m_parentPanel->m_MouseCapturedLost = false; m_parentPanel->m_MouseCapturedLost = false;
} }
else if( !aEnabled && m_parentPanel->HasCapture() else if( !aEnabled && m_parentPanel->HasCapture() && m_state != DRAG_PANNING && m_state != DRAG_ZOOMING )
&& m_state != DRAG_PANNING && m_state != DRAG_ZOOMING )
{ {
m_parentPanel->ReleaseMouse(); m_parentPanel->ReleaseMouse();
@ -793,6 +825,8 @@ void WX_VIEW_CONTROLS::CancelDrag()
m_parentPanel->ReleaseMouse(); m_parentPanel->ReleaseMouse();
#endif #endif
} }
m_metaPanning = false;
} }
@ -833,8 +867,8 @@ VECTOR2D WX_VIEW_CONTROLS::GetCursorPosition( bool aEnableSnapping ) const
} }
void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView, void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpView, bool aTriggeredByArrows,
bool aTriggeredByArrows, long aArrowCommand ) long aArrowCommand )
{ {
m_updateCursor = false; m_updateCursor = false;
@ -860,8 +894,7 @@ void WX_VIEW_CONTROLS::SetCursorPosition( const VECTOR2D& aPosition, bool aWarpV
} }
void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition, void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView = true )
bool aWarpView = true )
{ {
m_updateCursor = false; m_updateCursor = false;
@ -878,8 +911,7 @@ void WX_VIEW_CONTROLS::SetCrossHairCursorPosition( const VECTOR2D& aPosition,
} }
void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates, void WX_VIEW_CONTROLS::WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates, bool aWarpView )
bool aWarpView )
{ {
if( aWorldCoordinates ) if( aWorldCoordinates )
{ {
@ -937,8 +969,7 @@ void WX_VIEW_CONTROLS::PinCursorInsideNonAutoscrollArea( bool aWarpMouseCursor )
border += 2; border += 2;
VECTOR2D topLeft( border, border ); VECTOR2D topLeft( border, border );
VECTOR2D botRight( m_view->GetScreenPixelSize().x - border, VECTOR2D botRight( m_view->GetScreenPixelSize().x - border, m_view->GetScreenPixelSize().y - border );
m_view->GetScreenPixelSize().y - border );
topLeft = m_view->ToWorld( topLeft ); topLeft = m_view->ToWorld( topLeft );
botRight = m_view->ToWorld( botRight ); botRight = m_view->ToWorld( botRight );
@ -1028,8 +1059,7 @@ bool WX_VIEW_CONTROLS::handleAutoPanning( const wxMouseEvent& aEvent )
return false; return false;
case DRAG_PANNING: case DRAG_PANNING:
case DRAG_ZOOMING: case DRAG_ZOOMING: return false;
return false;
} }
wxCHECK_MSG( false, false, wxT( "This line should never be reached" ) ); wxCHECK_MSG( false, false, wxT( "This line should never be reached" ) );
@ -1114,10 +1144,8 @@ void WX_VIEW_CONTROLS::UpdateScrollbars()
// We add the width of the scroll bar thumb to the range because the scroll range is given by // We add the width of the scroll bar thumb to the range because the scroll range is given by
// the full bar while the position is given by the left/top position of the thumb // the full bar while the position is given by the left/top position of the thumb
VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() + VECTOR2I newRange( m_scrollScale.x * boundary.GetWidth() + m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ),
m_parentPanel->GetScrollThumb( wxSB_HORIZONTAL ), m_scrollScale.y * boundary.GetHeight() + m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
m_scrollScale.y * boundary.GetHeight() +
m_parentPanel->GetScrollThumb( wxSB_VERTICAL ) );
// Flip scroll direction in flipped view // Flip scroll direction in flipped view
if( m_view->IsMirroredX() ) if( m_view->IsMirroredX() )
@ -1128,8 +1156,7 @@ void WX_VIEW_CONTROLS::UpdateScrollbars()
if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL ) if( m_scrollPos != newScroll || newRange.x != m_parentPanel->GetScrollRange( wxSB_HORIZONTAL )
|| newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) ) || newRange.y != m_parentPanel->GetScrollRange( wxSB_VERTICAL ) )
{ {
m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y, m_parentPanel->SetScrollbars( 1, 1, newRange.x, newRange.y, newScroll.x, newScroll.y, true );
true );
m_scrollPos = newScroll; m_scrollPos = newScroll;
#if !defined( __APPLE__ ) && !defined( WIN32 ) #if !defined( __APPLE__ ) && !defined( WIN32 )

View File

@ -96,6 +96,8 @@ public:
int scroll_modifier_pan_h; int scroll_modifier_pan_h;
int scroll_modifier_pan_v; int scroll_modifier_pan_v;
int motion_pan_modifier;
MOUSE_DRAG_ACTION drag_left; MOUSE_DRAG_ACTION drag_left;
MOUSE_DRAG_ACTION drag_middle; MOUSE_DRAG_ACTION drag_middle;
MOUSE_DRAG_ACTION drag_right; MOUSE_DRAG_ACTION drag_right;

View File

@ -109,6 +109,9 @@ struct GAL_API VC_SETTINGS
/// What modifier key to enable vertical with the (vertical) scroll wheel. /// What modifier key to enable vertical with the (vertical) scroll wheel.
int m_scrollModifierPanV; int m_scrollModifierPanV;
/// What modifier key pans the view when the mouse moves with it held.
int m_motionPanModifier;
MOUSE_DRAG_ACTION m_dragLeft; MOUSE_DRAG_ACTION m_dragLeft;
MOUSE_DRAG_ACTION m_dragMiddle; MOUSE_DRAG_ACTION m_dragMiddle;
MOUSE_DRAG_ACTION m_dragRight; MOUSE_DRAG_ACTION m_dragRight;

View File

@ -89,15 +89,14 @@ public:
/// @copydoc VIEW_CONTROLS::GetRawCursorPosition() /// @copydoc VIEW_CONTROLS::GetRawCursorPosition()
VECTOR2D GetRawCursorPosition( bool aSnappingEnabled = true ) const override; VECTOR2D GetRawCursorPosition( bool aSnappingEnabled = true ) const override;
void SetCursorPosition( const VECTOR2D& aPosition, bool warpView, void SetCursorPosition( const VECTOR2D& aPosition, bool warpView, bool aTriggeredByArrows,
bool aTriggeredByArrows, long aArrowCommand ) override; long aArrowCommand ) override;
/// @copydoc VIEW_CONTROLS::SetCrossHairCursorPosition() /// @copydoc VIEW_CONTROLS::SetCrossHairCursorPosition()
void SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView ) override; void SetCrossHairCursorPosition( const VECTOR2D& aPosition, bool aWarpView ) override;
/// @copydoc VIEW_CONTROLS::CursorWarp() /// @copydoc VIEW_CONTROLS::CursorWarp()
void WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false, void WarpMouseCursor( const VECTOR2D& aPosition, bool aWorldCoordinates = false, bool aWarpView = false ) override;
bool aWarpView = false ) override;
/// @copydoc VIEW_CONTROLS::CenterOnCursor() /// @copydoc VIEW_CONTROLS::CenterOnCursor()
void CenterOnCursor() override; void CenterOnCursor() override;
@ -108,8 +107,7 @@ public:
/// End any mouse drag action still in progress. /// End any mouse drag action still in progress.
void CancelDrag(); void CancelDrag();
void ForceCursorPosition( bool aEnabled, void ForceCursorPosition( bool aEnabled, const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) ) override;
const VECTOR2D& aPosition = VECTOR2D( 0, 0 ) ) override;
/// Applies VIEW_CONTROLS settings from the program #COMMON_SETTINGS. /// Applies VIEW_CONTROLS settings from the program #COMMON_SETTINGS.
void LoadSettings() override; void LoadSettings() override;
@ -199,6 +197,12 @@ private:
/// Flag deciding whether the cursor position should be calculated using the mouse position. /// Flag deciding whether the cursor position should be calculated using the mouse position.
bool m_updateCursor; bool m_updateCursor;
/// True if we are panning via the meta key.
bool m_metaPanning;
/// Last mouse position when panning via the meta key.
VECTOR2D m_metaPanStart;
/// Flag to indicate if infinite panning works on this platform. /// Flag to indicate if infinite panning works on this platform.
bool m_infinitePanWorks; bool m_infinitePanWorks;