diff --git a/common/tool/actions.cpp b/common/tool/actions.cpp index a3d6be7925..5c7087a300 100644 --- a/common/tool/actions.cpp +++ b/common/tool/actions.cpp @@ -469,6 +469,20 @@ TOOL_ACTION ACTIONS::zoomTool( TOOL_ACTION_ARGS() .Icon( BITMAPS::zoom_area ) .Flags( AF_ACTIVATE ) ); +TOOL_ACTION ACTIONS::zoomUndo( TOOL_ACTION_ARGS() + .Name( "common.Control.undoZoom" ) + .Scope( AS_GLOBAL ) + .MenuText( _( "Undo Last Zoom" ) ) + .Tooltip( _( "Return zoom to level prior to last zoom action" ) ) + .Icon( BITMAPS::undo ) ); + +TOOL_ACTION ACTIONS::zoomRedo( TOOL_ACTION_ARGS() + .Name( "common.Control.redoZoom" ) + .Scope( AS_GLOBAL ) + .MenuText( _( "Redo Last Zoom" ) ) + .Tooltip( _( "Return zoom to level prior to last zoom undo" ) ) + .Icon( BITMAPS::redo ) ); + TOOL_ACTION ACTIONS::zoomPreset( TOOL_ACTION_ARGS() .Name( "common.Control.zoomPreset" ) .Scope( AS_GLOBAL ) diff --git a/common/widgets/mathplot.cpp b/common/widgets/mathplot.cpp index a7c14865a8..039803ba82 100644 --- a/common/widgets/mathplot.cpp +++ b/common/widgets/mathplot.cpp @@ -7,6 +7,7 @@ // Created: 21/07/2003 // Last edit: 2023 // Copyright: (c) David Schalig, Davide Rondini +// Copyright (c) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -1317,16 +1318,18 @@ EVT_SIZE( mpWindow::OnSize ) EVT_MIDDLE_DOWN( mpWindow::OnMouseMiddleDown ) // JLB EVT_RIGHT_UP( mpWindow::OnShowPopupMenu ) -EVT_MOUSEWHEEL( mpWindow::OnMouseWheel ) // JLB -EVT_MAGNIFY( mpWindow::OnMagnify ) -EVT_MOTION( mpWindow::OnMouseMove ) // JLB -EVT_LEFT_DOWN( mpWindow::OnMouseLeftDown ) -EVT_LEFT_UP( mpWindow::OnMouseLeftRelease ) +EVT_MOUSEWHEEL( mpWindow::onMouseWheel ) // JLB +EVT_MAGNIFY( mpWindow::onMagnify ) +EVT_MOTION( mpWindow::onMouseMove ) // JLB +EVT_LEFT_DOWN( mpWindow::onMouseLeftDown ) +EVT_LEFT_UP( mpWindow::onMouseLeftRelease ) EVT_MENU( mpID_CENTER, mpWindow::OnCenter ) EVT_MENU( mpID_FIT, mpWindow::OnFit ) -EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn ) -EVT_MENU( mpID_ZOOM_OUT, mpWindow::OnZoomOut ) +EVT_MENU( mpID_ZOOM_IN, mpWindow::onZoomIn ) +EVT_MENU( mpID_ZOOM_OUT, mpWindow::onZoomOut ) +EVT_MENU( mpID_ZOOM_UNDO, mpWindow::onZoomUndo ) +EVT_MENU( mpID_ZOOM_REDO, mpWindow::onZoomRedo ) END_EVENT_TABLE() mpWindow::mpWindow() : @@ -1394,10 +1397,13 @@ mpWindow::mpWindow( wxWindow* parent, wxWindowID id ) : // Set margins to 0 m_marginTop = 0; m_marginRight = 0; m_marginBottom = 0; m_marginLeft = 0; - m_popmenu.Append( mpID_CENTER, _( "Center on Cursor" ), _( "Center plot view to this position" ) ); - m_popmenu.Append( mpID_FIT, _( "Fit on Screen" ), _( "Set plot view to show all items" ) ); + m_popmenu.Append( mpID_ZOOM_UNDO, _( "Undo Last Zoom" ), _( "Return zoom to level prior to last zoom action" ) ); + m_popmenu.Append( mpID_ZOOM_REDO, _( "Redo Last Zoom" ), _( "Return zoom to level prior to last zoom undo" ) ); + m_popmenu.AppendSeparator(); m_popmenu.Append( mpID_ZOOM_IN, _( "Zoom In" ), _( "Zoom in plot view." ) ); m_popmenu.Append( mpID_ZOOM_OUT, _( "Zoom Out" ), _( "Zoom out plot view." ) ); + m_popmenu.Append( mpID_CENTER, _( "Center on Cursor" ), _( "Center plot view to this position" ) ); + m_popmenu.Append( mpID_FIT, _( "Fit on Screen" ), _( "Set plot view to show all items" ) ); m_layers.clear(); SetBackgroundColour( *wxWHITE ); @@ -1443,7 +1449,7 @@ void mpWindow::OnMouseMiddleDown( wxMouseEvent& event ) } -void mpWindow::OnMagnify( wxMouseEvent& event ) +void mpWindow::onMagnify( wxMouseEvent& event ) { if( !m_enableMouseNavigation ) { @@ -1463,7 +1469,7 @@ void mpWindow::OnMagnify( wxMouseEvent& event ) // Process mouse wheel events // JLB -void mpWindow::OnMouseWheel( wxMouseEvent& event ) +void mpWindow::onMouseWheel( wxMouseEvent& event ) { if( !m_enableMouseNavigation ) { @@ -1526,7 +1532,7 @@ void mpWindow::OnMouseWheel( wxMouseEvent& event ) // If the user "drags" with the right button pressed, do "pan" // JLB -void mpWindow::OnMouseMove( wxMouseEvent& event ) +void mpWindow::onMouseMove( wxMouseEvent& event ) { if( !m_enableMouseNavigation ) { @@ -1614,7 +1620,7 @@ void mpWindow::OnMouseMove( wxMouseEvent& event ) } -void mpWindow::OnMouseLeftDown( wxMouseEvent& event ) +void mpWindow::onMouseLeftDown( wxMouseEvent& event ) { m_mouseLClick.x = event.GetX(); m_mouseLClick.y = event.GetY(); @@ -1626,7 +1632,7 @@ void mpWindow::OnMouseLeftDown( wxMouseEvent& event ) } -void mpWindow::OnMouseLeftRelease( wxMouseEvent& event ) +void mpWindow::onMouseLeftRelease( wxMouseEvent& event ) { wxPoint release( event.GetX(), event.GetY() ); wxPoint press( m_mouseLClick.x, m_mouseLClick.y ); @@ -1782,6 +1788,8 @@ void mpWindow::ZoomIn( const wxPoint& centerPoint ) void mpWindow::ZoomIn( const wxPoint& centerPoint, double zoomFactor ) { + pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + wxPoint c( centerPoint ); if( c == wxDefaultPosition ) @@ -1843,6 +1851,8 @@ void mpWindow::ZoomOut( const wxPoint& centerPoint ) void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor ) { + pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + wxPoint c( centerPoint ); if( c == wxDefaultPosition ) @@ -1887,6 +1897,8 @@ void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor ) void mpWindow::ZoomRect( wxPoint p0, wxPoint p1 ) { + pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + // Compute the 2 corners in graph coordinates: double p0x = p2x( p0.x ); double p0y = p2y( p0.y ); @@ -1910,16 +1922,61 @@ void mpWindow::ZoomRect( wxPoint p0, wxPoint p1 ) } +void mpWindow::pushZoomUndo( const std::array& aZoom ) +{ + m_undoZoomStack.push( aZoom ); + + while( !m_redoZoomStack.empty() ) + m_redoZoomStack.pop(); +} + + +void mpWindow::ZoomUndo() +{ + if( m_undoZoomStack.size() ) + { + m_redoZoomStack.push( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + + std::array zoom = m_undoZoomStack.top(); + m_undoZoomStack.pop(); + + Fit( zoom[0], zoom[1], zoom[2], zoom[3] ); + AdjustLimitedView(); + } +} + + +void mpWindow::ZoomRedo() +{ + if( m_redoZoomStack.size() ) + { + m_undoZoomStack.push( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + + std::array zoom = m_redoZoomStack.top(); + m_redoZoomStack.pop(); + + Fit( zoom[0], zoom[1], zoom[2], zoom[3] ); + AdjustLimitedView(); + } +} + + void mpWindow::OnShowPopupMenu( wxMouseEvent& event ) { m_clickedX = event.GetX(); m_clickedY = event.GetY(); + + m_popmenu.Enable( mpID_ZOOM_UNDO, !m_undoZoomStack.empty() ); + m_popmenu.Enable( mpID_ZOOM_REDO, !m_redoZoomStack.empty() ); + PopupMenu( &m_popmenu, event.GetX(), event.GetY() ); } void mpWindow::OnFit( wxCommandEvent& WXUNUSED( event ) ) { + pushZoomUndo( { m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax } ); + Fit(); } @@ -1933,18 +1990,30 @@ void mpWindow::OnCenter( wxCommandEvent& WXUNUSED( event ) ) } -void mpWindow::OnZoomIn( wxCommandEvent& WXUNUSED( event ) ) +void mpWindow::onZoomIn( wxCommandEvent& WXUNUSED( event ) ) { ZoomIn( wxPoint( m_mouseMClick.x, m_mouseMClick.y ) ); } -void mpWindow::OnZoomOut( wxCommandEvent& WXUNUSED( event ) ) +void mpWindow::onZoomOut( wxCommandEvent& WXUNUSED( event ) ) { ZoomOut(); } +void mpWindow::onZoomUndo( wxCommandEvent& WXUNUSED( event ) ) +{ + ZoomUndo(); +} + + +void mpWindow::onZoomRedo( wxCommandEvent& WXUNUSED( event ) ) +{ + ZoomRedo(); +} + + void mpWindow::OnSize( wxSizeEvent& WXUNUSED( event ) ) { // Try to fit again with the new window size: diff --git a/eeschema/sim/simulator_frame.cpp b/eeschema/sim/simulator_frame.cpp index 7495324e72..f0c7a6b76d 100644 --- a/eeschema/sim/simulator_frame.cpp +++ b/eeschema/sim/simulator_frame.cpp @@ -663,6 +663,20 @@ void SIMULATOR_FRAME::setupUIConditions() return dynamic_cast( GetCurrentSimTab() ) != nullptr; }; + auto haveZoomUndo = + [this]( const SELECTION& aSel ) + { + SIM_PLOT_TAB* plotTab = dynamic_cast( GetCurrentSimTab() ); + return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0; + }; + + auto haveZoomRedo = + [this]( const SELECTION& aSel ) + { + SIM_PLOT_TAB* plotTab = dynamic_cast( GetCurrentSimTab() ); + return plotTab && plotTab->GetPlotWin()->RedoZoomStackSize() > 0; + }; + #define ENABLE( x ) ACTION_CONDITIONS().Enable( x ) #define CHECK( x ) ACTION_CONDITIONS().Check( x ) @@ -673,6 +687,8 @@ void SIMULATOR_FRAME::setupUIConditions() mgr->SetConditions( EE_ACTIONS::exportPlotAsPNG, ENABLE( havePlot ) ); mgr->SetConditions( EE_ACTIONS::exportPlotAsCSV, ENABLE( havePlot ) ); + mgr->SetConditions( ACTIONS::zoomUndo, ENABLE( haveZoomUndo ) ); + mgr->SetConditions( ACTIONS::zoomRedo, ENABLE( haveZoomRedo ) ); mgr->SetConditions( EE_ACTIONS::toggleGrid, CHECK( showGridCondition ) ); mgr->SetConditions( EE_ACTIONS::toggleLegend, CHECK( showLegendCondition ) ); mgr->SetConditions( EE_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) ); diff --git a/eeschema/sim/toolbars_simulator_frame.cpp b/eeschema/sim/toolbars_simulator_frame.cpp index 3b6063f5a4..08c1b53216 100644 --- a/eeschema/sim/toolbars_simulator_frame.cpp +++ b/eeschema/sim/toolbars_simulator_frame.cpp @@ -112,6 +112,10 @@ void SIMULATOR_FRAME::doReCreateMenuBar() // ACTION_MENU* viewMenu = new ACTION_MENU( false, tool ); + viewMenu->Add( ACTIONS::zoomUndo ); + viewMenu->Add( ACTIONS::zoomRedo ); + + viewMenu->AppendSeparator(); viewMenu->Add( ACTIONS::zoomInCenter ); viewMenu->Add( ACTIONS::zoomOutCenter ); viewMenu->Add( ACTIONS::zoomFitScreen ); diff --git a/eeschema/tools/simulator_control.cpp b/eeschema/tools/simulator_control.cpp index f2a7e924d9..30cfd61cbb 100644 --- a/eeschema/tools/simulator_control.cpp +++ b/eeschema/tools/simulator_control.cpp @@ -246,18 +246,43 @@ int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent ) { if( SIM_PLOT_TAB* plotTab = dynamic_cast( getCurrentSimTab() ) ) { - if( aEvent.IsAction( &ACTIONS::zoomInCenter ) ) + if( aEvent.IsAction( &ACTIONS::zoomInCenter ) ) + { plotTab->GetPlotWin()->ZoomIn(); + } else if( aEvent.IsAction( &ACTIONS::zoomOutCenter ) ) + { plotTab->GetPlotWin()->ZoomOut(); + } else if( aEvent.IsAction( &ACTIONS::zoomFitScreen ) ) - plotTab->GetPlotWin()->Fit(); + { + wxCommandEvent dummy; + plotTab->GetPlotWin()->OnFit( dummy ); + } } return 0; } +int SIMULATOR_CONTROL::UndoZoom( const TOOL_EVENT& aEvent ) +{ + if( SIM_PLOT_TAB* plotTab = dynamic_cast( getCurrentSimTab() ) ) + plotTab->GetPlotWin()->ZoomUndo(); + + return 0; +} + + +int SIMULATOR_CONTROL::RedoZoom( const TOOL_EVENT& aEvent ) +{ + if( SIM_PLOT_TAB* plotTab = dynamic_cast( getCurrentSimTab() ) ) + plotTab->GetPlotWin()->ZoomRedo(); + + return 0; +} + + int SIMULATOR_CONTROL::ToggleGrid( const TOOL_EVENT& aEvent ) { if( SIM_PLOT_TAB* plotTab = dynamic_cast( getCurrentSimTab() ) ) @@ -492,6 +517,8 @@ void SIMULATOR_CONTROL::setTransitions() Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomInCenter.MakeEvent() ); Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomOutCenter.MakeEvent() ); Go( &SIMULATOR_CONTROL::Zoom, ACTIONS::zoomFitScreen.MakeEvent() ); + Go( &SIMULATOR_CONTROL::UndoZoom, ACTIONS::zoomUndo.MakeEvent() ); + Go( &SIMULATOR_CONTROL::RedoZoom, ACTIONS::zoomRedo.MakeEvent() ); Go( &SIMULATOR_CONTROL::ToggleGrid, ACTIONS::toggleGrid.MakeEvent() ); Go( &SIMULATOR_CONTROL::ToggleLegend, EE_ACTIONS::toggleLegend.MakeEvent() ); Go( &SIMULATOR_CONTROL::ToggleDottedSecondary, EE_ACTIONS::toggleDottedSecondary.MakeEvent() ); diff --git a/eeschema/tools/simulator_control.h b/eeschema/tools/simulator_control.h index 95de36d73e..596b68bcfa 100644 --- a/eeschema/tools/simulator_control.h +++ b/eeschema/tools/simulator_control.h @@ -61,6 +61,8 @@ public: int Close( const TOOL_EVENT& aEvent ); int Zoom( const TOOL_EVENT& aEvent ); + int UndoZoom( const TOOL_EVENT& aEvent ); + int RedoZoom( const TOOL_EVENT& aEvent ); int ToggleGrid( const TOOL_EVENT& aEvent ); int ToggleLegend( const TOOL_EVENT& aEvent ); int ToggleDottedSecondary( const TOOL_EVENT& aEvent ); diff --git a/include/tool/actions.h b/include/tool/actions.h index f3d5f6d6e7..32af551a6c 100644 --- a/include/tool/actions.h +++ b/include/tool/actions.h @@ -101,6 +101,8 @@ public: static TOOL_ACTION zoomFitObjects; // Zooms to bbox of items on screen (except page border) static TOOL_ACTION zoomPreset; static TOOL_ACTION zoomTool; + static TOOL_ACTION zoomUndo; + static TOOL_ACTION zoomRedo; static TOOL_ACTION centerContents; static TOOL_ACTION toggleCursor; static TOOL_ACTION toggleCursorStyle; diff --git a/include/widgets/mathplot.h b/include/widgets/mathplot.h index 34b580f8fb..2b31bfea6d 100644 --- a/include/widgets/mathplot.h +++ b/include/widgets/mathplot.h @@ -7,6 +7,7 @@ // Created: 21/07/2003 // Last edit: 05/08/2016 // Copyright: (c) David Schalig, Davide Rondini +// Copyright (c) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors. // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -50,10 +51,6 @@ * Jose Luis Blanco, Val Greene.
*/ - /** - * @file mathplot.h - */ - // this definition uses windows dll to export function. // WXDLLIMPEXP_MATHPLOT definition definition changed to WXDLLIMPEXP_MATHPLOT @@ -66,7 +63,6 @@ #define WXDLLIMPEXP_DATA_MATHPLOT( type ) type #endif -#include #include #include @@ -79,9 +75,10 @@ #include #include - +#include #include - +#include +#include #include // For memory leak debug @@ -116,6 +113,8 @@ class WXDLLIMPEXP_MATHPLOT mpPrintout; enum { mpID_FIT = 2000, // !< Fit view to match bounding box of all layers + mpID_ZOOM_UNDO, + mpID_ZOOM_REDO, mpID_ZOOM_IN, // !< Zoom into view at clickposition / window center mpID_ZOOM_OUT, // !< Zoom out mpID_CENTER, // !< Center view on click position @@ -1229,25 +1228,35 @@ public: void LockY( bool aLock ) { m_yLocked = aLock; } bool GetYLocked() const { return m_yLocked; } + void ZoomUndo(); + void ZoomRedo(); + int UndoZoomStackSize() const { return m_undoZoomStack.size(); } + int RedoZoomStackSize() const { return m_redoZoomStack.size(); } + void AdjustLimitedView(); -protected: - void OnPaint( wxPaintEvent& event ); // !< Paint handler, will plot all attached layers - void OnSize( wxSizeEvent& event ); // !< Size handler, will update scroll bar sizes + void OnFit( wxCommandEvent& event ); + void OnCenter( wxCommandEvent& event ); - void OnShowPopupMenu( wxMouseEvent& event ); // !< Mouse handler, will show context menu - void OnMouseMiddleDown( wxMouseEvent& event ); // !< Mouse handler, for detecting when the user +protected: + void pushZoomUndo( const std::array& aZoom ); + + void OnPaint( wxPaintEvent& event ); // !< Paint handler, will plot all attached layers + void OnSize( wxSizeEvent& event ); // !< Size handler, will update scroll bar sizes + + void OnShowPopupMenu( wxMouseEvent& event ); // !< Mouse handler, will show context menu + void OnMouseMiddleDown( wxMouseEvent& event ); // !< Mouse handler, for detecting when the user // !< drags with the middle button or just "clicks" for the menu - void OnCenter( wxCommandEvent& event ); // !< Context menu handler - void OnFit( wxCommandEvent& event ); // !< Context menu handler - void OnZoomIn( wxCommandEvent& event ); // !< Context menu handler - void OnZoomOut( wxCommandEvent& event ); // !< Context menu handler - void OnMouseWheel( wxMouseEvent& event ); // !< Mouse handler for the wheel - void OnMagnify( wxMouseEvent& event ); // !< Pinch zoom handler - void OnMouseMove( wxMouseEvent& event ); // !< Mouse handler for mouse motion (for pan) - void OnMouseLeftDown( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) - void OnMouseLeftRelease( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) + void onZoomIn( wxCommandEvent& event ); // !< Context menu handler + void onZoomOut( wxCommandEvent& event ); // !< Context menu handler + void onZoomUndo( wxCommandEvent& event ); // !< Context menu handler + void onZoomRedo( wxCommandEvent& event ); // !< Context menu handler + void onMouseWheel( wxMouseEvent& event ); // !< Mouse handler for the wheel + void onMagnify( wxMouseEvent& event ); // !< Pinch zoom handler + void onMouseMove( wxMouseEvent& event ); // !< Mouse handler for mouse motion (for pan) + void onMouseLeftDown( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) + void onMouseLeftRelease( wxMouseEvent& event ); // !< Mouse left click (for rect zoom) bool CheckXLimits( double& desiredMax, double& desiredMin ) const { @@ -1319,6 +1328,9 @@ protected: mpInfoLayer* m_movingInfoLayer; // !< For moving info layers over the window area bool m_zooming; wxRect m_zoomRect; + std::stack> m_undoZoomStack; + std::stack> m_redoZoomStack; + DECLARE_DYNAMIC_CLASS( mpWindow ) DECLARE_EVENT_TABLE() };