Right click context menu for signals (including adding cursors)

This commit is contained in:
Maciej Suminski 2016-08-11 14:41:25 +02:00
parent d5ce31dc8e
commit f3fabeb9fb
8 changed files with 222 additions and 43 deletions

View File

@ -235,6 +235,24 @@ void SIM_PLOT_FRAME::onSignalDblClick( wxCommandEvent& event )
}
void SIM_PLOT_FRAME::onSignalRClick( wxMouseEvent& event )
{
int idx = m_signals->HitTest( event.GetPosition() );
if( idx != wxNOT_FOUND )
m_signals->SetSelection( idx );
idx = m_signals->GetSelection();
if( idx != wxNOT_FOUND )
{
const wxString& netName = m_signals->GetString( idx );
SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
m_signals->PopupMenu( &ctxMenu );
}
}
void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
{
if( isSimulationRunning() )
@ -291,6 +309,8 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
for( const auto& trace : plotPanel->GetTraces() )
updatePlot( trace.second->GetSpiceName(), trace.second->GetName(), plotPanel );
plotPanel->UpdateAll();
}
}
@ -301,3 +321,56 @@ void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
m_simConsole->Newline();
m_simConsole->MoveEnd(); /// @todo does not work..
}
SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::SIGNAL_CONTEXT_MENU( const wxString& aSignal,
SIM_PLOT_FRAME* aPlotFrame )
: m_signal( aSignal ), m_plotFrame( aPlotFrame )
{
SIM_PLOT_PANEL* plot = m_plotFrame->CurrentPlot();
if( plot->IsShown( m_signal ) )
{
Append( HIDE_SIGNAL, wxT( "Hide signal" ) );
TRACE* trace = plot->GetTrace( m_signal );
if( trace->HasCursor() )
Append( HIDE_CURSOR, wxT( "Hide cursor" ) );
else
Append( SHOW_CURSOR, wxT( "Show cursor" ) );
}
else
{
Append( SHOW_SIGNAL, wxT( "Show signal" ) );
}
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ), NULL, this );
}
void SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
{
SIM_PLOT_PANEL* plot = m_plotFrame->CurrentPlot();
switch( aEvent.GetId() )
{
case SHOW_SIGNAL:
m_plotFrame->AddVoltagePlot( m_signal );
break;
break;
case HIDE_SIGNAL:
plot->DeleteTrace( m_signal );
break;
case SHOW_CURSOR:
plot->EnableCursor( m_signal, true );
break;
case HIDE_CURSOR:
plot->EnableCursor( m_signal, false );
break;
}
}

View File

@ -99,6 +99,7 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
// Event handlers
void onSignalDblClick( wxCommandEvent& event ) override;
void onSignalRClick( wxMouseEvent& event ) override;
void onSimulate( wxCommandEvent& event ) override;
void onPlaceProbe( wxCommandEvent& event ) override;
@ -111,6 +112,27 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
SCH_EDIT_FRAME* m_schematicFrame;
NETLIST_EXPORTER_PSPICE* m_exporter;
SPICE_SIMULATOR* m_simulator;
// Right click context menu for signals in the listbox
class SIGNAL_CONTEXT_MENU : public wxMenu
{
public:
SIGNAL_CONTEXT_MENU( const wxString& aSignal, SIM_PLOT_FRAME* aPlotFrame );
private:
void onMenuEvent( wxMenuEvent& aEvent );
const wxString& m_signal;
SIM_PLOT_FRAME* m_plotFrame;
enum SIGNAL_CONTEXT_MENU_EVENTS
{
SHOW_SIGNAL,
HIDE_SIGNAL,
SHOW_CURSOR,
HIDE_CURSOR
};
};
};
wxDEFINE_EVENT( wxEVT_SIM_REPORT, wxCommandEvent );

View File

@ -157,6 +157,7 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
this->Connect( m_menuShowGrid->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::menuShowGrid ) );
this->Connect( m_menuShowGrid->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler( SIM_PLOT_FRAME_BASE::menuShowGridState ) );
m_signals->Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onSignalDblClick ), NULL, this );
m_signals->Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::onSignalRClick ), NULL, this );
m_simulateBtn->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onSimulate ), NULL, this );
m_probeBtn->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onPlaceProbe ), NULL, this );
m_tuneBtn->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onTune ), NULL, this );
@ -175,6 +176,7 @@ SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE()
this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::menuShowGrid ) );
this->Disconnect( wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler( SIM_PLOT_FRAME_BASE::menuShowGridState ) );
m_signals->Disconnect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onSignalDblClick ), NULL, this );
m_signals->Disconnect( wxEVT_RIGHT_UP, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::onSignalRClick ), NULL, this );
m_simulateBtn->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onSimulate ), NULL, this );
m_probeBtn->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onPlaceProbe ), NULL, this );
m_tuneBtn->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::onTune ), NULL, this );

View File

@ -206,7 +206,7 @@
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="wxMenu" expanded="0">
<object class="wxMenu" expanded="1">
<property name="label">View</property>
<property name="name">m_viewMenu</property>
<property name="permission">protected</property>
@ -790,7 +790,7 @@
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnRightUp">onSignalRClick</event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>

View File

@ -69,6 +69,7 @@ class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
virtual void menuShowGrid( wxCommandEvent& event ) { event.Skip(); }
virtual void menuShowGridState( wxUpdateUIEvent& event ) { event.Skip(); }
virtual void onSignalDblClick( wxCommandEvent& event ) { event.Skip(); }
virtual void onSignalRClick( wxMouseEvent& event ) { event.Skip(); }
virtual void onSimulate( wxCommandEvent& event ) { event.Skip(); }
virtual void onPlaceProbe( wxCommandEvent& event ) { event.Skip(); }
virtual void onTune( wxCommandEvent& event ) { event.Skip(); }

View File

@ -43,7 +43,7 @@ void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow )
if( dataX.size() <= 1 )
return;
if( m_moved )
if( m_updateRequired )
{
m_coords.x = aWindow.p2x( m_dim.x );
@ -72,7 +72,7 @@ void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow )
const double rightY = dataY[maxIdx];
m_coords.y = leftY + ( rightY - leftY ) / ( rightX - leftX ) * ( m_coords.x - leftX );
m_moved = false;
m_updateRequired = false;
}
else
{
@ -156,12 +156,17 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aSpiceName, const wxString& aName
bool SIM_PLOT_PANEL::DeleteTrace( const wxString& aName )
{
auto trace = m_traces.find( aName );
auto it = m_traces.find( aName );
if( trace != m_traces.end() )
if( it != m_traces.end() )
{
m_traces.erase( trace );
DelLayer( trace->second, true, true );
m_traces.erase( it );
TRACE* trace = it->second;
if( CURSOR* cursor = trace->GetCursor() )
DelLayer( cursor, true );
DelLayer( trace, true, true );
return true;
}
@ -174,7 +179,7 @@ void SIM_PLOT_PANEL::DeleteAllTraces()
{
for( auto& t : m_traces )
{
DelLayer( t.second, true );
DeleteTrace( t.first );
}
m_traces.clear();
@ -196,6 +201,36 @@ bool SIM_PLOT_PANEL::IsGridShown() const
}
bool SIM_PLOT_PANEL::HasCursorEnabled( const wxString& aName ) const
{
TRACE* t = GetTrace( aName );
return t ? t->HasCursor() : false;
}
void SIM_PLOT_PANEL::EnableCursor( const wxString& aName, bool aEnable )
{
TRACE* t = GetTrace( aName );
if( t == nullptr || t->HasCursor() == aEnable )
return;
if( aEnable )
{
CURSOR* c = new CURSOR( t );
t->SetCursor( c );
AddLayer( c );
}
else
{
CURSOR* c = t->GetCursor();
t->SetCursor( NULL );
DelLayer( c, true );
}
}
wxColour SIM_PLOT_PANEL::generateColor()
{
/// @todo have a look at:

View File

@ -29,46 +29,24 @@
#include <widgets/mathplot.h>
#include <map>
class TRACE : public mpFXYVector
{
public:
TRACE( const wxString& aName, const wxString& aSpiceName )
: mpFXYVector( aName ), m_spiceName( aSpiceName )
{
SetContinuity( true );
ShowName( false );
}
const wxString& GetSpiceName() const
{
return m_spiceName;
}
const std::vector<double>& GetDataX() const
{
return m_xs;
}
const std::vector<double>& GetDataY() const
{
return m_ys;
}
private:
wxString m_spiceName;
};
class TRACE;
class CURSOR : public mpInfoLayer
{
public:
CURSOR( const TRACE* aTrace )
: mpInfoLayer( wxRect( 0, 0, DRAG_MARGIN, DRAG_MARGIN ), wxTRANSPARENT_BRUSH ),
m_trace( aTrace ), m_moved( false ), m_coords( 0.0, 0.0 ), m_window( nullptr )
m_trace( aTrace ), m_updateRequired( false ), m_coords( 0.0, 0.0 ), m_window( nullptr )
{
}
void Plot( wxDC& aDC, mpWindow& aWindow ) override;
void Update()
{
m_updateRequired = true;
}
bool Inside( wxPoint& aPoint )
{
if( !m_window )
@ -80,7 +58,7 @@ public:
void Move( wxPoint aDelta ) override
{
m_moved = true;
Update();
mpInfoLayer::Move( aDelta );
}
@ -100,13 +78,68 @@ public:
private:
const TRACE* m_trace;
bool m_moved;
bool m_updateRequired;
wxRealPoint m_coords;
mpWindow* m_window;
const int DRAG_MARGIN = 10;
};
class TRACE : public mpFXYVector
{
public:
TRACE( const wxString& aName, const wxString& aSpiceName )
: mpFXYVector( aName ), m_spiceName( aSpiceName ), m_cursor( nullptr )
{
SetContinuity( true );
ShowName( false );
}
void SetData( const std::vector<double>& aXs, const std::vector<double>& aYs )
{
mpFXYVector::SetData( aXs, aYs );
if( m_cursor )
m_cursor->Update();
}
const wxString& GetSpiceName() const
{
return m_spiceName;
}
const std::vector<double>& GetDataX() const
{
return m_xs;
}
const std::vector<double>& GetDataY() const
{
return m_ys;
}
bool HasCursor() const
{
return m_cursor != nullptr;
}
void SetCursor( CURSOR* aCursor )
{
m_cursor = aCursor;
}
CURSOR* GetCursor() const
{
return m_cursor;
}
private:
wxString m_spiceName;
CURSOR* m_cursor;
};
class SIM_PLOT_PANEL : public mpWindow
{
public:
@ -120,22 +153,33 @@ public:
bool DeleteTrace( const wxString& aName );
void DeleteAllTraces();
bool IsShown( const wxString& aName ) const
{
return ( m_traces.count( aName ) != 0 );
}
void DeleteAllTraces();
const std::map<wxString, TRACE*>& GetTraces() const
{
return m_traces;
}
TRACE* GetTrace( const wxString& aName ) const
{
auto trace = m_traces.find( aName );
return trace == m_traces.end() ? NULL : trace->second;
}
void ShowGrid( bool aEnable = true );
bool IsGridShown() const;
bool HasCursorEnabled( const wxString& aName ) const;
void EnableCursor( const wxString& aName, bool aEnable );
private:
wxColour generateColor();

View File

@ -1267,11 +1267,13 @@ class WXDLLIMPEXP_MATHPLOT mpFXYVector : public mpFXY
*/
mpFXYVector(wxString name = wxEmptyString, int flags = mpALIGN_NE);
virtual ~mpFXYVector() {}
/** Changes the internal data: the set of points to draw.
Both vectors MUST be of the same length. This method DOES NOT refresh the mpWindow; do it manually.
* @sa Clear
*/
void SetData( const std::vector<double> &xs,const std::vector<double> &ys);
virtual void SetData( const std::vector<double> &xs,const std::vector<double> &ys);
/** Clears all the data, leaving the layer empty.
* @sa SetData