Zoom undo/redo for simulator.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14580
This commit is contained in:
Jeff Young 2023-09-26 13:18:28 +01:00
parent 51f6d38d08
commit aab0696bb6
8 changed files with 185 additions and 39 deletions

View File

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

View File

@ -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<double, 4>& 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<double, 4> 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<double, 4> 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:

View File

@ -663,6 +663,20 @@ void SIMULATOR_FRAME::setupUIConditions()
return dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() ) != nullptr;
};
auto haveZoomUndo =
[this]( const SELECTION& aSel )
{
SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( GetCurrentSimTab() );
return plotTab && plotTab->GetPlotWin()->UndoZoomStackSize() > 0;
};
auto haveZoomRedo =
[this]( const SELECTION& aSel )
{
SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( 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 ) );

View File

@ -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 );

View File

@ -246,18 +246,43 @@ int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent )
{
if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( 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<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
plotTab->GetPlotWin()->ZoomUndo();
return 0;
}
int SIMULATOR_CONTROL::RedoZoom( const TOOL_EVENT& aEvent )
{
if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( getCurrentSimTab() ) )
plotTab->GetPlotWin()->ZoomRedo();
return 0;
}
int SIMULATOR_CONTROL::ToggleGrid( const TOOL_EVENT& aEvent )
{
if( SIM_PLOT_TAB* plotTab = dynamic_cast<SIM_PLOT_TAB*>( 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() );

View File

@ -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 );

View File

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

View File

@ -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.<br>
*/
/**
* @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 <vector>
#include <wx/defs.h>
#include <wx/menu.h>
@ -79,9 +75,10 @@
#include <wx/print.h>
#include <wx/image.h>
#include <vector>
#include <deque>
#include <stack>
#include <array>
#include <algorithm>
// 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<double, 4>& 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<std::array<double, 4>> m_undoZoomStack;
std::stack<std::array<double, 4>> m_redoZoomStack;
DECLARE_DYNAMIC_CLASS( mpWindow )
DECLARE_EVENT_TABLE()
};