Allow opening of workbook when simulation frame is opened.

This involved splitting creation of traces from setting of trace
data.

Also renamed SIM_WORKBOOK to SIM_NOTEBOOK.  This class is a subclass
of wxAiuNotebook and represents the collection of simulation plot tabs.
It is NOT the same thing as a simulation workbook, which contains other
stuff such as measurements, plotted signals, colours, etc.

This also removes a bunch of "friend" declarations.
This commit is contained in:
Jeff Young 2023-02-12 14:55:00 +00:00
parent 78746b77c6
commit 83dd06e5d1
11 changed files with 328 additions and 409 deletions

View File

@ -354,13 +354,13 @@ if( KICAD_SPICE )
tools/simulator_control.cpp
sim/ngspice_circuit_model.cpp
sim/ngspice.cpp
sim/sim_notebook.cpp
sim/sim_panel_base.cpp
sim/sim_plot_colors.cpp
sim/sim_plot_frame.cpp
sim/sim_plot_frame_base.cpp
sim/sim_plot_panel.cpp
sim/sim_property.cpp
sim/sim_workbook.cpp
sim/spice_simulator.cpp
sim/spice_value.cpp
sim/toolbars_sim_plot_frame.cpp

View File

@ -22,28 +22,25 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <sim/sim_workbook.h>
#include <sim/sim_notebook.h>
SIM_WORKBOOK::SIM_WORKBOOK() : wxAuiNotebook()
{
m_modified = false;
}
SIM_NOTEBOOK::SIM_NOTEBOOK() :
wxAuiNotebook()
{ }
SIM_WORKBOOK::SIM_WORKBOOK( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos, const wxSize&
SIM_NOTEBOOK::SIM_NOTEBOOK( wxWindow* aParent, wxWindowID aId, const wxPoint& aPos, const wxSize&
aSize, long aStyle ) :
wxAuiNotebook( aParent, aId, aPos, aSize, aStyle )
{
m_modified = false;
}
{ }
bool SIM_WORKBOOK::AddPage( wxWindow* page, const wxString& caption, bool select, const wxBitmap& bitmap )
bool SIM_NOTEBOOK::AddPage( wxWindow* page, const wxString& caption, bool select, const wxBitmap& bitmap )
{
if( wxAuiNotebook::AddPage( page, caption, select, bitmap ) )
if( wxAuiNotebook::AddPage( page, caption, select, bitmap ) )
{
setModified();
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_MODIFIED ) );
return true;
}
@ -51,11 +48,11 @@ bool SIM_WORKBOOK::AddPage( wxWindow* page, const wxString& caption, bool select
}
bool SIM_WORKBOOK::AddPage( wxWindow* page, const wxString& text, bool select, int imageId )
bool SIM_NOTEBOOK::AddPage( wxWindow* page, const wxString& text, bool select, int imageId )
{
if( wxAuiNotebook::AddPage( page, text, select, imageId ) )
{
setModified();
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_MODIFIED ) );
return true;
}
@ -63,11 +60,11 @@ bool SIM_WORKBOOK::AddPage( wxWindow* page, const wxString& text, bool select, i
}
bool SIM_WORKBOOK::DeleteAllPages()
bool SIM_NOTEBOOK::DeleteAllPages()
{
if( wxAuiNotebook::DeleteAllPages() )
{
setModified();
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_MODIFIED ) );
return true;
}
@ -75,11 +72,11 @@ bool SIM_WORKBOOK::DeleteAllPages()
}
bool SIM_WORKBOOK::DeletePage( size_t page )
bool SIM_NOTEBOOK::DeletePage( size_t page )
{
if( wxAuiNotebook::DeletePage( page ) )
{
setModified();
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_MODIFIED ) );
return true;
}
@ -87,45 +84,4 @@ bool SIM_WORKBOOK::DeletePage( size_t page )
}
bool SIM_WORKBOOK::AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle,
const wxString& aName, int aPoints, const double* aX, const double* aY,
SIM_TRACE_TYPE aType )
{
if( aPoints && aPlotPanel->addTrace( aTitle, aName, aPoints, aX, aY, aType ) )
{
setModified();
return true;
}
return false;
}
bool SIM_WORKBOOK::DeleteTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aName )
{
if( aPlotPanel->deleteTrace( aName ) )
{
setModified();
return true;
}
return false;
}
void SIM_WORKBOOK::ClrModified()
{
m_modified = false;
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_CLR_MODIFIED ) );
}
void SIM_WORKBOOK::setModified()
{
m_modified = true;
wxPostEvent( GetParent(), wxCommandEvent( EVT_WORKBOOK_MODIFIED ) );
}
wxDEFINE_EVENT( EVT_WORKBOOK_MODIFIED, wxCommandEvent );
wxDEFINE_EVENT( EVT_WORKBOOK_CLR_MODIFIED, wxCommandEvent );

View File

@ -22,69 +22,32 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __SIM_WORKBOOK__
#define __SIM_WORKBOOK__
#ifndef SIM_NOTEBOOK_H
#define SIM_NOTEBOOK_H
#include <dialog_sim_command.h>
#include <sim/sim_panel_base.h>
#include <sim/sim_plot_panel.h>
class SIM_WORKBOOK : public wxAuiNotebook
class SIM_NOTEBOOK : public wxAuiNotebook
{
public:
SIM_WORKBOOK();
SIM_WORKBOOK( wxWindow* aParent, wxWindowID aId=wxID_ANY, const wxPoint&
aPos=wxDefaultPosition, const wxSize& aSize=wxDefaultSize, long
aStyle=wxAUI_NB_DEFAULT_STYLE );
SIM_NOTEBOOK();
SIM_NOTEBOOK( wxWindow* aParent, wxWindowID aId = wxID_ANY,
const wxPoint& aPos = wxDefaultPosition, const wxSize& aSize = wxDefaultSize,
long aStyle = wxAUI_NB_DEFAULT_STYLE );
// Methods from wxAuiNotebook
bool AddPage( wxWindow* aPage, const wxString& aCaption, bool aSelect=false, const wxBitmap& aBitmap=wxNullBitmap );
bool AddPage( wxWindow* aPage, const wxString& aCaption, bool aSelect=false,
const wxBitmap& aBitmap = wxNullBitmap );
bool AddPage( wxWindow* aPage, const wxString& aText, bool aSelect, int aImageId ) override;
bool DeleteAllPages() override;
bool DeletePage( size_t aPage ) override;
// Custom methods
bool AddTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aTitle, const wxString& aName,
int aPoints, const double* aX, const double* aY, SIM_TRACE_TYPE aType );
bool DeleteTrace( SIM_PLOT_PANEL* aPlotPanel, const wxString& aName );
void SetSimCommand( SIM_PANEL_BASE* aPlotPanel, const wxString& aSimCommand )
{
aPlotPanel->setSimCommand( aSimCommand );
setModified();
}
const wxString& GetSimCommand( const SIM_PANEL_BASE* aPlotPanel )
{
return aPlotPanel->getSimCommand();
}
void SetSimOptions( SIM_PANEL_BASE* aPlotPanel, int aOptions )
{
aPlotPanel->setSimOptions( aOptions );
setModified();
}
int GetSimOptions( const SIM_PANEL_BASE* aPlotPanel )
{
return aPlotPanel->getSimOptions();
}
void ClrModified();
bool IsModified() const { return m_modified; }
private:
void setModified();
///< Dirty bit, indicates something in the workbook has changed
bool m_modified;
};
wxDECLARE_EVENT( EVT_WORKBOOK_MODIFIED, wxCommandEvent );
wxDECLARE_EVENT( EVT_WORKBOOK_CLR_MODIFIED, wxCommandEvent );
#endif // __SIM_WORKBOOK__
#endif // SIM_NOTEBOOK_H

View File

@ -35,8 +35,6 @@
class SIM_PANEL_BASE : public wxWindow
{
friend class SIM_WORKBOOK;
public:
SIM_PANEL_BASE();
SIM_PANEL_BASE( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id,
@ -50,14 +48,8 @@ public:
SIM_TYPE GetType() const;
protected:
// We use `protected` here because members should be accessible from outside only through a
// workbook object, to prevent anyone from modifying the state without its knowledge. Otherwise
// we risk some things not getting saved.
const wxString& getSimCommand() const { return m_simCommand; }
void setSimCommand( const wxString& aSimCommand )
const wxString& GetSimCommand() const { return m_simCommand; }
void SetSimCommand( const wxString& aSimCommand )
{
wxCHECK_RET( GetType() == NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand ),
"Cannot change the type of simulation of the existing plot panel" );
@ -65,8 +57,8 @@ protected:
m_simCommand = aSimCommand;
}
const int getSimOptions() const { return m_simOptions; }
void setSimOptions( int aOptions ) { m_simOptions = aOptions; }
const int GetSimOptions() const { return m_simOptions; }
void SetSimOptions( int aOptions ) { m_simOptions = aOptions; }
private:
wxString m_simCommand;

View File

@ -330,7 +330,8 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_darkMode( true ),
m_plotNumber( 0 ),
m_simFinished( false ),
m_outputCounter( 1 )
m_outputCounter( 1 ),
m_workbookModified( false )
{
SetKiway( this, aKiway );
@ -415,12 +416,11 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
Bind( EVT_SIM_FINISHED, &SIM_PLOT_FRAME::onSimFinished, this );
Bind( EVT_SIM_CURSOR_UPDATE, &SIM_PLOT_FRAME::onCursorUpdate, this );
Bind( EVT_WORKBOOK_MODIFIED, &SIM_PLOT_FRAME::onWorkbookModified, this );
Bind( EVT_WORKBOOK_CLR_MODIFIED, &SIM_PLOT_FRAME::onWorkbookClrModified, this );
Bind( EVT_WORKBOOK_MODIFIED, &SIM_PLOT_FRAME::onNotebookModified, this );
#ifndef wxHAS_NATIVE_TABART
// Default non-native tab art has ugly gradients we don't want
m_workbook->SetArtProvider( new wxAuiSimpleTabArt() );
m_plotNotebook->SetArtProvider( new wxAuiSimpleTabArt() );
#endif
// Ensure new items are taken in account by sizers:
@ -482,16 +482,16 @@ void SIM_PLOT_FRAME::ShowChangedLanguage()
updateTitle();
for( int ii = 0; ii < (int) m_workbook->GetPageCount(); ++ii )
for( int ii = 0; ii < (int) m_plotNotebook->GetPageCount(); ++ii )
{
SIM_PANEL_BASE* plot = dynamic_cast<SIM_PLOT_PANEL*>( m_workbook->GetPage( ii ) );
SIM_PANEL_BASE* plot = dynamic_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetPage( ii ) );
plot->OnLanguageChanged();
wxString pageTitle( m_simulator->TypeToName( plot->GetType(), true ) );
pageTitle.Prepend( wxString::Format( _( "Plot%u - " ), ii+1 /* 1-based */ ) );
m_workbook->SetPageText( ii, pageTitle );
m_plotNotebook->SetPageText( ii, pageTitle );
}
m_filter->SetHint( _( "Filter" ) );
@ -582,19 +582,14 @@ WINDOW_SETTINGS* SIM_PLOT_FRAME::GetWindowSettings( APP_SETTINGS_BASE* aCfg )
void SIM_PLOT_FRAME::initWorkbook()
{
// Removed for the time being. We cannot run the simulation on simulator launch, as it may
// take a lot of time, confusing the user.
// TODO: Change workbook loading routines so that they don't run the simulation until the user
// initiates it.
/*if( !m_simulator->Settings()->GetWorkbookFilename().IsEmpty() )
if( !m_simulator->Settings()->GetWorkbookFilename().IsEmpty() )
{
wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
filename.SetPath( Prj().GetProjectPath() );
if( !loadWorkbook( filename.GetFullPath() ) )
if( !LoadWorkbook( filename.GetFullPath() ) )
m_simulator->Settings()->SetWorkbookFilename( "" );
}*/
}
}
@ -614,7 +609,7 @@ void SIM_PLOT_FRAME::updateTitle()
readOnly = !filename.IsFileWritable();
}
if( m_workbook->IsModified() )
if( m_workbookModified )
title = wxT( "*" ) + filename.GetName();
else
title = filename.GetName();
@ -721,6 +716,92 @@ void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
}
void SIM_PLOT_FRAME::rebuildSignalsList()
{
m_signals.clear();
int options = GetCurrentOptions();
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( GetCurrentSimCommand() );
wxString unconnected = wxString( wxS( "unconnected-(" ) );
unconnected.Replace( '(', '_' ); // Convert to SPICE markup
if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
{
for( const std::string& net : m_circuitModel->GetNets() )
{
// netnames are escaped (can contain "{slash}" for '/') Unscape them:
wxString netname = UnescapeString( net );
if( netname == "GND" || netname == "0" || netname.StartsWith( unconnected ) )
continue;
if( simType == ST_AC )
{
m_signals.push_back( wxString::Format( _( "V(%s) (gain)" ), netname ) );
m_signals.push_back( wxString::Format( _( "V(%s) (phase)" ), netname ) );
}
else
{
m_signals.push_back( wxString::Format( "V(%s)", netname ) );
}
}
}
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
// Add all possible currents for the device.
for( const std::string& name : item.model->SpiceGenerator().CurrentNames( item ) )
m_signals.push_back( name );
}
}
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
if( item.model->GetPinCount() >= 2 )
{
wxString name = item.model->SpiceGenerator().ItemName( item );
m_signals.push_back( wxString::Format( wxS( "P(%s)" ), name ) );
}
}
}
// Add .PROBE directives
for( const wxString& directive : m_circuitModel->GetDirectives() )
{
wxString directiveParams;
if( directive.Upper().StartsWith( wxS( ".PROBE" ), &directiveParams ) )
m_signals.push_back( directiveParams.Trim( false ) );
}
}
bool SIM_PLOT_FRAME::LoadSimulator()
{
wxString errors;
WX_STRING_REPORTER reporter( &errors );
if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) ) )
return false;
if( !m_simulator->Attach( m_circuitModel, reporter ) )
{
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" )
+ errors );
return false;
}
return true;
}
void SIM_PLOT_FRAME::StartSimulation()
{
if( m_circuitModel->CommandToSimType( GetCurrentSimCommand() ) == ST_UNKNOWN )
@ -739,11 +820,11 @@ void SIM_PLOT_FRAME::StartSimulation()
if( !plotWindow )
{
plotWindow = NewPlotPanel( schTextSimCommand, m_circuitModel->GetSimOptions() );
m_workbook->SetSimCommand( plotWindow, schTextSimCommand );
m_workbookModified = true;
}
else
{
m_circuitModel->SetSimCommandOverride( m_workbook->GetSimCommand( plotWindow ) );
m_circuitModel->SetSimCommandOverride( plotWindow->GetSimCommand() );
if( plotWindow->GetType() == schTextSimType
&& schTextSimCommand != m_circuitModel->GetLastSchTextSimCommand() )
@ -752,95 +833,27 @@ void SIM_PLOT_FRAME::StartSimulation()
"Do you wish to update the Simulation Command?" ) ) )
{
m_circuitModel->SetSimCommandOverride( wxEmptyString );
m_workbook->SetSimCommand( plotWindow, schTextSimCommand );
plotWindow->SetSimCommand( schTextSimCommand );
m_workbookModified = true;
}
}
}
m_circuitModel->SetSimOptions( GetCurrentOptions() );
wxString errors;
WX_STRING_REPORTER reporter( &errors );
if( !m_schematicFrame->ReadyToNetlist( _( "Simulator requires a fully annotated schematic." ) )
|| !m_simulator->Attach( m_circuitModel, reporter ) )
{
DisplayErrorMessage( this, _( "Errors during netlist generation; simulation aborted.\n\n" )
+ errors );
if( !LoadSimulator() )
return;
}
rebuildSignalsList();
rebuildSignalsGrid( m_filter->GetValue() );
std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
if( simulatorLock.owns_lock() )
{
wxBusyCursor toggle;
wxString unconnected = wxString( wxS( "unconnected-(" ) );
unconnected.Replace( '(', '_' ); // Convert to SPICE markup
m_simConsole->Clear();
m_signals.clear();
int options = m_circuitModel->GetSimOptions();
SIM_TYPE simType = m_circuitModel->GetSimType();
if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
{
for( const std::string& net : m_circuitModel->GetNets() )
{
// netnames are escaped (can contain "{slash}" for '/') Unscape them:
wxString netname = UnescapeString( net );
if( netname == "GND" || netname == "0" || netname.StartsWith( unconnected ) )
continue;
if( simType == ST_AC )
{
m_signals.push_back( wxString::Format( _( "V(%s) (gain)" ), netname ) );
m_signals.push_back( wxString::Format( _( "V(%s) (phase)" ), netname ) );
}
else
{
m_signals.push_back( wxString::Format( "V(%s)", netname ) );
}
}
}
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
// Add all possible currents for the device.
for( const std::string& name : item.model->SpiceGenerator().CurrentNames( item ) )
m_signals.push_back( name );
}
}
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) )
{
for( const SPICE_ITEM& item : m_circuitModel->GetItems() )
{
if( item.model->GetPinCount() >= 2 )
{
wxString name = item.model->SpiceGenerator().ItemName( item );
m_signals.push_back( wxString::Format( wxS( "P(%s)" ), name ) );
}
}
}
// Add .PROBE directives
for( const wxString& directive : m_circuitModel->GetDirectives() )
{
wxString directiveParams;
if( directive.Upper().StartsWith( wxS( ".PROBE" ), &directiveParams ) )
m_signals.push_back( directiveParams.Trim( false ) );
}
rebuildSignalsGrid( m_filter->GetValue() );
applyTuners();
@ -862,7 +875,7 @@ SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( const wxString& aSimCommand, int a
if( SIM_PANEL_BASE::IsPlottable( simType ) )
{
SIM_PLOT_PANEL* panel = new SIM_PLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
SIM_PLOT_PANEL* panel = new SIM_PLOT_PANEL( aSimCommand, aOptions, m_plotNotebook, wxID_ANY );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
COMMON_SETTINGS::INPUT cfg = Pgm().GetCommonSettings()->m_Input;
@ -870,14 +883,14 @@ SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( const wxString& aSimCommand, int a
}
else
{
SIM_NOPLOT_PANEL* panel = new SIM_NOPLOT_PANEL( aSimCommand, aOptions, m_workbook, wxID_ANY );
SIM_NOPLOT_PANEL* panel = new SIM_NOPLOT_PANEL( aSimCommand, aOptions, m_plotNotebook, wxID_ANY );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
}
wxString pageTitle( m_simulator->TypeToName( simType, true ) );
pageTitle.Prepend( wxString::Format( _( "Plot%u - " ), (unsigned int) ++m_plotNumber ) );
m_workbook->AddPage( dynamic_cast<wxWindow*>( plotPanel ), pageTitle, true );
m_plotNotebook->AddPage( dynamic_cast<wxWindow*>( plotPanel ), pageTitle, true );
return plotPanel;
}
@ -955,13 +968,10 @@ void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent )
}
if( traceType != SPT_UNKNOWN )
{
addTrace( baseSignal, (SIM_TRACE_TYPE) traceType );
}
if( !GetCurrentPlot()->GetTrace( signalName ) )
{
aEvent.Veto();
return;
m_workbookModified = true;
}
}
}
else
@ -983,6 +993,7 @@ void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent )
trace->SetTraceColour( color.ToColour() );
plot->UpdateTraceStyle( trace );
plot->UpdatePlotColors();
m_workbookModified = true;
}
}
else if( col == COL_CURSOR_1 || col == COL_CURSOR_2 )
@ -993,6 +1004,7 @@ void SIM_PLOT_FRAME::onSignalsGridCellChanged( wxGridEvent& aEvent )
bool enable = ii == row && text == wxS( "1" );
plot->EnableCursor( signalName, col == COL_CURSOR_1 ? 1 : 2, enable );
m_workbookModified = true;
}
// Update cursor checkboxes (which are really radio buttons)
@ -1054,6 +1066,8 @@ void SIM_PLOT_FRAME::DeleteMeasurement( int aRow )
m_measurementFormats[ aRow ] = m_measurementFormats[ aRow + 1 ];
m_measurementFormats.pop_back();
m_workbookModified = true;
}
@ -1090,6 +1104,8 @@ void SIM_PLOT_FRAME::updateMeasurement( int aRow )
" +"
"([a-zA-Z])\\([a-zA-Z0-9_]+\\)" ) );
m_workbookModified = true;
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
if( !plotPanel )
@ -1140,12 +1156,14 @@ void SIM_PLOT_FRAME::updateMeasurement( int aRow )
void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
{
addTrace( aNetName, SPT_VOLTAGE );
m_workbookModified = true;
}
void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName )
{
addTrace( aDeviceName, SPT_CURRENT );
m_workbookModified = true;
}
@ -1177,6 +1195,7 @@ void SIM_PLOT_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSy
m_sizerTuners->Add( tuner );
m_tuners.push_back( tuner );
m_panelTuners->Layout();
m_workbookModified = true;
}
catch( const KI_PARAM_ERROR& e )
{
@ -1225,6 +1244,7 @@ void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
aTuner->Destroy();
m_panelTuners->Layout();
m_workbookModified = true;
}
@ -1244,6 +1264,7 @@ void SIM_PLOT_FRAME::AddMeasurement( const wxString& aCmd, const wxString& aSign
m_measurementsGrid->SetCellValue( row, COL_MEASUREMENT, aCmd + wxS( " " ) + aSignal );
updateMeasurement( row );
m_workbookModified = true;
}
@ -1264,60 +1285,45 @@ const NGSPICE_CIRCUIT_MODEL* SIM_PLOT_FRAME::GetExporter() const
void SIM_PLOT_FRAME::addTrace( const wxString& aName, SIM_TRACE_TYPE aType )
{
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
if( !plotPanel )
{
m_simConsole->AppendText( _( "Error: no current simulation.\n" ) );
m_simConsole->SetInsertionPointEnd();
return;
}
SIM_TYPE simType = m_circuitModel->GetSimType();
if( simType == ST_UNKNOWN )
{
m_simConsole->AppendText( _( "Error: simulation type not defined!\n" ) );
m_simConsole->AppendText( _( "Error: simulation type not defined.\n" ) );
m_simConsole->SetInsertionPointEnd();
return;
}
else if( !SIM_PANEL_BASE::IsPlottable( simType ) )
{
m_simConsole->AppendText( _( "Error: simulation type doesn't support plotting!\n" ) );
m_simConsole->AppendText( _( "Error: simulation type doesn't support plotting.\n" ) );
m_simConsole->SetInsertionPointEnd();
return;
}
// Create a new plot if the current one displays a different type
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
if( !plotPanel || plotPanel->GetType() != simType )
{
plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( m_circuitModel->GetSimCommand(),
m_circuitModel->GetSimOptions() ) );
}
wxASSERT( plotPanel );
if( !plotPanel ) // Something is wrong
return;
bool updated = false;
SIM_TRACE_TYPE xAxisType = getXAxisType( simType );
if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
if( ( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
&& ( aType & ( SPT_AC_MAG | SPT_AC_PHASE ) ) == 0 )
{
int baseType = aType & ~( SPT_AC_MAG | SPT_AC_PHASE );
// If magnitude or phase wasn't specified, then add both
if( baseType == aType )
{
updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( baseType | SPT_AC_MAG ), plotPanel );
updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( baseType | SPT_AC_PHASE ), plotPanel );
}
else
{
updated |= updateTrace( aName, (SIM_TRACE_TYPE) ( aType ), plotPanel );
}
updateTrace( aName, (SIM_TRACE_TYPE) ( aType | SPT_AC_MAG ), plotPanel );
updateTrace( aName, (SIM_TRACE_TYPE) ( aType | SPT_AC_PHASE ), plotPanel );
}
else
{
updated = updateTrace( aName, aType, plotPanel );
updateTrace( aName, aType, plotPanel );
}
if( updated )
updateSignalsGrid();
updateSignalsGrid();
}
@ -1329,7 +1335,10 @@ void SIM_PLOT_FRAME::removeTrace( const wxString& aSignalName )
return;
wxASSERT( plotPanel->TraceShown( aSignalName ) );
m_workbook->DeleteTrace( plotPanel, aSignalName );
if( plotPanel->DeleteTrace( aSignalName ) )
m_workbookModified = true;
plotPanel->GetPlotWin()->Fit();
updateSignalsGrid();
@ -1338,7 +1347,7 @@ void SIM_PLOT_FRAME::removeTrace( const wxString& aSignalName )
}
bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
SIM_PLOT_PANEL* aPlotPanel )
{
SIM_TYPE simType = m_circuitModel->GetSimType();
@ -1359,14 +1368,14 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
// There is no plot to be shown
m_simulator->Command( wxString::Format( wxT( "print %s" ), aName ).ToStdString() );
return false;
return;
}
// First, handle the x axis
wxString xAxisName( m_simulator->GetXAxis( simType ) );
if( xAxisName.IsEmpty() )
return false;
return;
std::vector<double> data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
unsigned int size = data_x.size();
@ -1399,56 +1408,53 @@ bool SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
wxFAIL_MSG( wxT( "Unhandled plot type" ) );
}
if( data_y.size() == 0 )
return false; // Signal no longer exists
else
wxCHECK_MSG( data_y.size() >= size, false, wxT( "Not enough y data values to plot" ) );
// If we did a two-source DC analysis, we need to split the resulting vector and add traces
// for each input step
SPICE_DC_PARAMS source1, source2;
if( m_circuitModel->GetSimType() == ST_DC
&& m_circuitModel->ParseDCCommand( m_circuitModel->GetSimCommand(), &source1, &source2 ) )
&& m_circuitModel->ParseDCCommand( m_circuitModel->GetSimCommand(), &source1, &source2 )
&& !source2.m_source.IsEmpty() )
{
if( !source2.m_source.IsEmpty() )
// Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step
SPICE_VALUE v = source2.m_vstart;
wxString name;
size_t offset = 0;
size_t outer = ( size_t )( ( source2.m_vend - v ) / source2.m_vincrement ).ToDouble();
size_t inner = data_x.size() / ( outer + 1 );
wxASSERT( data_x.size() % ( outer + 1 ) == 0 );
for( size_t idx = 0; idx <= outer; idx++ )
{
// Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step
SPICE_VALUE v = source2.m_vstart;
wxString name;
name = wxString::Format( wxT( "%s (%s = %s V)" ),
traceTitle,
source2.m_source,
v.ToString() );
size_t offset = 0;
size_t outer = ( size_t )( ( source2.m_vend - v ) / source2.m_vincrement ).ToDouble();
size_t inner = data_x.size() / ( outer + 1 );
wxASSERT( data_x.size() % ( outer + 1 ) == 0 );
for( size_t idx = 0; idx <= outer; idx++ )
if( TRACE* trace = aPlotPanel->AddTrace( name, aName, aType ) )
{
name = wxString::Format( wxT( "%s (%s = %s V)" ),
traceTitle,
source2.m_source,
v.ToString() );
if( data_y.size() >= size )
{
std::vector<double> sub_x( data_x.begin() + offset,
data_x.begin() + offset + inner );
std::vector<double> sub_y( data_y.begin() + offset,
data_y.begin() + offset + inner );
std::vector<double> sub_x( data_x.begin() + offset,
data_x.begin() + offset + inner );
std::vector<double> sub_y( data_y.begin() + offset,
data_y.begin() + offset + inner );
m_workbook->AddTrace( aPlotPanel, name, aName, inner, sub_x.data(), sub_y.data(),
aType );
v = v + source2.m_vincrement;
offset += inner;
aPlotPanel->SetTraceData( trace, inner, sub_x.data(), sub_y.data() );
}
}
return true;
v = v + source2.m_vincrement;
offset += inner;
}
}
m_workbook->AddTrace( aPlotPanel, traceTitle, aName, size, data_x.data(), data_y.data(), aType );
return true;
else if( TRACE* trace = aPlotPanel->AddTrace( traceTitle, aName, aType ) )
{
if( data_y.size() >= size )
aPlotPanel->SetTraceData( trace, size, data_x.data(), data_y.data() );
}
}
@ -1557,7 +1563,7 @@ void SIM_PLOT_FRAME::applyTuners()
bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
{
m_workbook->DeleteAllPages();
m_plotNotebook->DeleteAllPages();
wxTextFile file( aPath );
@ -1643,14 +1649,6 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
}
NewPlotPanel( simCommand, simOptions );
StartSimulation();
// Perform simulation, so plots can be added with values
do
{
wxThread::This()->Sleep( 50 );
}
while( m_simulator->IsRunning() );
if( !file.GetNextLine().ToLong( &tracesCount ) )
{
@ -1774,7 +1772,12 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
}
}
LoadSimulator();
rebuildSignalsList();
rebuildSignalsGrid( m_filter->GetValue() );
updateSignalsGrid();
wxCommandEvent dummy;
onCursorUpdate( dummy );
@ -1787,7 +1790,9 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
m_simulator->Settings()->SetWorkbookFilename( filename.GetFullPath() );
// Successfully loading a workbook does not count as modifying it.
m_workbook->ClrModified();
m_workbookModified = false;
updateTitle();
return true;
}
@ -1813,11 +1818,11 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath )
file.AddLine( wxT( "version 4" ) );
file.AddLine( wxString::Format( wxT( "%llu" ), m_workbook->GetPageCount() ) );
file.AddLine( wxString::Format( wxT( "%llu" ), m_plotNotebook->GetPageCount() ) );
for( size_t i = 0; i < m_workbook->GetPageCount(); i++ )
for( size_t i = 0; i < m_plotNotebook->GetPageCount(); i++ )
{
const SIM_PANEL_BASE* basePanel = dynamic_cast<const SIM_PANEL_BASE*>( m_workbook->GetPage( i ) );
const SIM_PANEL_BASE* basePanel = dynamic_cast<const SIM_PANEL_BASE*>( m_plotNotebook->GetPage( i ) );
if( !basePanel )
{
@ -1827,8 +1832,8 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath )
file.AddLine( wxString::Format( wxT( "%d" ), basePanel->GetType() ) );
wxString command = m_workbook->GetSimCommand( basePanel );
int options = m_workbook->GetSimOptions( basePanel );
wxString command = basePanel->GetSimCommand();
int options = basePanel->GetSimOptions();
if( options & NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS )
command += wxT( "\n.kicad adjustpaths" );
@ -1902,7 +1907,9 @@ bool SIM_PLOT_FRAME::SaveWorkbook( const wxString& aPath )
m_simulator->Settings()->SetWorkbookFilename( filename.GetFullPath() );
}
m_workbook->ClrModified();
m_workbookModified = false;
updateTitle();
return res;
}
@ -1930,9 +1937,9 @@ void SIM_PLOT_FRAME::ToggleDarkModePlots()
SIM_PLOT_COLORS::FillDefaultColorList( m_darkMode );
// Now send changes to all SIM_PLOT_PANEL
for( size_t page = 0; page < m_workbook->GetPageCount(); page++ )
for( size_t page = 0; page < m_plotNotebook->GetPageCount(); page++ )
{
wxWindow* curPage = m_workbook->GetPage( page );
wxWindow* curPage = m_plotNotebook->GetPage( page );
// ensure it is truly a plot panel and not the (zero plots) placeholder
// which is only SIM_PLOT_PANEL_BASE
@ -1972,14 +1979,9 @@ void SIM_PLOT_FRAME::onPlotDragged( wxAuiNotebookEvent& event )
}
void SIM_PLOT_FRAME::onWorkbookModified( wxCommandEvent& event )
{
updateTitle();
}
void SIM_PLOT_FRAME::onWorkbookClrModified( wxCommandEvent& event )
void SIM_PLOT_FRAME::onNotebookModified( wxCommandEvent& event )
{
m_workbookModified = true;
updateTitle();
}
@ -1999,10 +2001,10 @@ bool SIM_PLOT_FRAME::EditSimCommand()
return false;
}
if( m_workbook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
if( m_plotNotebook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
{
dlg.SetSimCommand( m_workbook->GetSimCommand( plotPanelWindow ) );
dlg.SetSimOptions( m_workbook->GetSimOptions( plotPanelWindow ) );
dlg.SetSimCommand( plotPanelWindow->GetSimCommand() );
dlg.SetSimOptions( plotPanelWindow->GetSimOptions() );
}
else
{
@ -2013,8 +2015,8 @@ bool SIM_PLOT_FRAME::EditSimCommand()
{
wxString oldCommand;
if( m_workbook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
oldCommand = m_workbook->GetSimCommand( plotPanelWindow );
if( m_plotNotebook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
oldCommand = plotPanelWindow->GetSimCommand();
else
oldCommand = wxString();
@ -2038,14 +2040,15 @@ bool SIM_PLOT_FRAME::EditSimCommand()
}
else
{
if( m_workbook->GetPageIndex( plotPanelWindow ) == 0 )
if( m_plotNotebook->GetPageIndex( plotPanelWindow ) == 0 )
m_circuitModel->SetSimCommandOverride( newCommand );
// Update simulation command in the current plot
m_workbook->SetSimCommand( plotPanelWindow, newCommand );
m_workbook->SetSimOptions( plotPanelWindow, newOptions );
plotPanelWindow->SetSimCommand( newCommand );
plotPanelWindow->SetSimOptions( newOptions );
}
m_workbookModified = true;
m_simulator->Init();
return true;
}
@ -2056,7 +2059,7 @@ bool SIM_PLOT_FRAME::EditSimCommand()
bool SIM_PLOT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
{
if( m_workbook->IsModified() )
if( m_workbookModified )
{
wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
@ -2372,10 +2375,7 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
}
for( const struct TRACE_DESC& trace : traceInfo )
{
if( !updateTrace( trace.m_name, trace.m_type, plotPanel ) )
removeTrace( trace.m_name );
}
updateTrace( trace.m_name, trace.m_type, plotPanel );
rebuildSignalsGrid( m_filter->GetValue() );
plotPanel->GetPlotWin()->UpdateAll();

View File

@ -50,7 +50,7 @@ class NGSPICE_CIRCUIT_MODEL;
#include <sim/sim_plot_panel.h>
#include <sim/sim_panel_base.h>
#include <sim/sim_workbook.h>
#include <sim/sim_notebook.h>
class SIM_THREAD_REPORTER;
class TUNER_SLIDER;
@ -62,6 +62,12 @@ public:
SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent );
~SIM_PLOT_FRAME();
/**
* Check and load the current netlist into the simulator.
* @return true if document is fully annotated and netlist was loaded successfully.
*/
bool LoadSimulator();
void StartSimulation();
/**
@ -208,18 +214,18 @@ public:
wxString GetCurrentSimCommand() const
{
if( getCurrentPlotWindow() == nullptr )
return m_circuitModel->GetSchTextSimCommand();
if( getCurrentPlotWindow() )
return getCurrentPlotWindow()->GetSimCommand();
else
return m_workbook->GetSimCommand( getCurrentPlotWindow() );
return m_circuitModel->GetSchTextSimCommand();
}
int GetCurrentOptions() const
{
if( getCurrentPlotWindow() == nullptr )
return m_circuitModel->GetSimOptions();
if( getCurrentPlotWindow() )
return getCurrentPlotWindow()->GetSimOptions();
else
return m_workbook->GetSimOptions( getCurrentPlotWindow() );
return m_circuitModel->GetSimOptions();
}
// Simulator doesn't host a tool framework
@ -266,9 +272,15 @@ private:
* @param aType describes the type of plot.
* @param aParam is the parameter for the device/net (e.g. I, Id, V).
* @param aPlotPanel is the panel that should receive the update.
* @return True if a plot was successfully added/updated.
*/
bool updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, SIM_PLOT_PANEL* aPlotPanel );
void updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, SIM_PLOT_PANEL* aPlotPanel );
/**
* Rebuild the list of signals available from the netlist.
*
* Note: this is not the filtered list. See rebuildSignalsGrid() for that.
*/
void rebuildSignalsList();
/**
* Rebuild the filtered list of signals in the signals grid.
@ -295,7 +307,7 @@ private:
*/
SIM_PANEL_BASE* getCurrentPlotWindow() const
{
return dynamic_cast<SIM_PANEL_BASE*>( m_workbook->GetCurrentPage() );
return dynamic_cast<SIM_PANEL_BASE*>( m_plotNotebook->GetCurrentPage() );
}
/**
@ -319,8 +331,7 @@ private:
void onCursorsGridCellChanged( wxGridEvent& aEvent ) override;
void onMeasurementsGridCellChanged( wxGridEvent& aEvent ) override;
void onWorkbookModified( wxCommandEvent& event );
void onWorkbookClrModified( wxCommandEvent& event );
void onNotebookModified( wxCommandEvent& event );
bool canCloseWindow( wxCloseEvent& aEvent ) override;
void doCloseWindow() override;
@ -364,6 +375,7 @@ private:
unsigned int m_plotNumber;
bool m_simFinished;
unsigned int m_outputCounter;
bool m_workbookModified;
};
// Commands

View File

@ -43,11 +43,11 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
m_sizerPlot = new wxBoxSizer( wxHORIZONTAL );
m_workbook = new SIM_WORKBOOK( m_plotPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_MIDDLE_CLICK_CLOSE|wxAUI_NB_TAB_MOVE|wxAUI_NB_TOP );
m_workbook->SetMinSize( wxSize( 200,-1 ) );
m_plotNotebook = new SIM_NOTEBOOK( m_plotPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_MIDDLE_CLICK_CLOSE|wxAUI_NB_TAB_MOVE|wxAUI_NB_TOP );
m_plotNotebook->SetMinSize( wxSize( 200,-1 ) );
m_sizerPlot->Add( m_workbook, 1, wxEXPAND, 5 );
m_sizerPlot->Add( m_plotNotebook, 1, wxEXPAND, 5 );
m_plotPanel->SetSizer( m_sizerPlot );
@ -284,10 +284,10 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
this->Centre( wxBOTH );
// Connect Events
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotDragged ), NULL, this );
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_workbook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotDragged ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_filter->Connect( wxEVT_MOTION, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::OnFilterMouseMoved ), NULL, this );
m_filter->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::OnFilterText ), NULL, this );
m_signalsGrid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onSignalsGridCellChanged ), NULL, this );
@ -298,10 +298,10 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
SIM_PLOT_FRAME_BASE::~SIM_PLOT_FRAME_BASE()
{
// Disconnect Events
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotDragged ), NULL, this );
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_workbook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotDragged ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotChanged ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClose ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIM_PLOT_FRAME_BASE::onPlotClosed ), NULL, this );
m_filter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( SIM_PLOT_FRAME_BASE::OnFilterMouseMoved ), NULL, this );
m_filter->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( SIM_PLOT_FRAME_BASE::OnFilterText ), NULL, this );
m_signalsGrid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( SIM_PLOT_FRAME_BASE::onSignalsGridCellChanged ), NULL, this );

View File

@ -307,7 +307,7 @@
<property name="window_name"></property>
<property name="window_style"></property>
<object class="splitteritem" expanded="1">
<object class="wxPanel" expanded="0">
<object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
@ -358,7 +358,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">m_sizerPlot</property>
<property name="orient">wxHORIZONTAL</property>
@ -402,7 +402,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size">200,-1</property>
<property name="moveable">1</property>
<property name="name">m_workbook</property>
<property name="name">m_plotNotebook</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -413,7 +413,7 @@
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_MIDDLE_CLICK_CLOSE|wxAUI_NB_TAB_MOVE|wxAUI_NB_TOP</property>
<property name="subclass">SIM_WORKBOOK; sim_workbook.h; Not forward_declare</property>
<property name="subclass">SIM_NOTEBOOK; sim_notebook.h; </property>
<property name="tab_ctrl_height">-1</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>

View File

@ -13,7 +13,7 @@
class ACTION_TOOLBAR;
class WX_GRID;
#include "sim_workbook.h"
#include "sim_notebook.h"
#include "kiway_player.h"
#include <wx/gdicmn.h>
#include <wx/aui/aui.h>
@ -50,7 +50,7 @@ class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
wxSplitterWindow* m_splitterPlotAndConsole;
wxPanel* m_plotPanel;
wxBoxSizer* m_sizerPlot;
SIM_WORKBOOK* m_workbook;
SIM_NOTEBOOK* m_plotNotebook;
wxPanel* m_panelConsole;
wxBoxSizer* m_sizerConsole;
wxTextCtrl* m_simConsole;

View File

@ -551,7 +551,7 @@ void SIM_PLOT_PANEL::updateAxes( SIM_TRACE_TYPE aNewTraceType )
void SIM_PLOT_PANEL::prepareDCAxes()
{
wxString sim_cmd = getSimCommand().Lower();
wxString sim_cmd = GetSimCommand().Lower();
wxString rem;
if( sim_cmd.StartsWith( ".dc", &rem ) )
@ -676,67 +676,67 @@ void SIM_PLOT_PANEL::UpdateTraceStyle( TRACE* trace )
}
bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, int aPoints,
const double* aX, const double* aY, SIM_TRACE_TYPE aType )
TRACE* SIM_PLOT_PANEL::AddTrace( const wxString& aTitle, const wxString& aName,
SIM_TRACE_TYPE aType )
{
TRACE* trace = nullptr;
auto it = m_traces.find( aTitle );
if( it != m_traces.end() )
return it->second;
updateAxes( aType );
// Find previous entry, if there is one
auto prev = m_traces.find( aTitle );
bool addedNewEntry = ( prev == m_traces.end() );
if( addedNewEntry )
if( GetType() == ST_TRANSIENT )
{
if( GetType() == ST_TRANSIENT )
bool hasVoltageTraces = false;
for( const auto& [ name, candidate ] : m_traces )
{
bool hasVoltageTraces = false;
for( const auto& [ name, candidate ] : m_traces )
if( candidate->GetType() & SPT_VOLTAGE )
{
if( candidate->GetType() & SPT_VOLTAGE )
{
hasVoltageTraces = true;
break;
}
}
if( !hasVoltageTraces )
{
if( m_axis_y2 )
m_axis_y2->SetMasterScale( nullptr );
if( m_axis_y3 )
m_axis_y3->SetMasterScale( nullptr );
hasVoltageTraces = true;
break;
}
}
// New entry
trace = new TRACE( aName, aType );
trace->SetTraceColour( m_colors.GenerateColor( m_traces ) );
UpdateTraceStyle( trace );
m_traces[ aTitle ] = trace;
if( !hasVoltageTraces )
{
if( m_axis_y2 )
m_axis_y2->SetMasterScale( nullptr );
m_plotWin->AddLayer( (mpLayer*) trace );
}
else
{
trace = prev->second;
if( m_axis_y3 )
m_axis_y3->SetMasterScale( nullptr );
}
}
trace = new TRACE( aName, aType );
trace->SetTraceColour( m_colors.GenerateColor( m_traces ) );
UpdateTraceStyle( trace );
m_traces[ aTitle ] = trace;
m_plotWin->AddLayer( (mpLayer*) trace );
return trace;
}
void SIM_PLOT_PANEL::SetTraceData( TRACE* trace, unsigned int aPoints, const double* aX,
const double* aY )
{
std::vector<double> tmp( aY, aY + aPoints );
if( GetType() == ST_AC )
{
if( aType & SPT_AC_PHASE )
if( trace->GetType() & SPT_AC_PHASE )
{
for( int i = 0; i < aPoints; i++ )
for( unsigned int i = 0; i < aPoints; i++ )
tmp[i] = tmp[i] * 180.0 / M_PI; // convert to degrees
}
else
{
for( int i = 0; i < aPoints; i++ )
for( unsigned int i = 0; i < aPoints; i++ )
{
// log( 0 ) is not valid.
if( tmp[i] != 0 )
@ -747,20 +747,18 @@ bool SIM_PLOT_PANEL::addTrace( const wxString& aTitle, const wxString& aName, in
trace->SetData( std::vector<double>( aX, aX + aPoints ), tmp );
if( ( aType & SPT_AC_PHASE ) || ( aType & SPT_CURRENT ) )
if( ( trace->GetType() & SPT_AC_PHASE ) || ( trace->GetType() & SPT_CURRENT ) )
trace->SetScale( m_axis_x, m_axis_y2 );
else if( aType & SPT_POWER )
else if( trace->GetType() & SPT_POWER )
trace->SetScale( m_axis_x, m_axis_y3 );
else
trace->SetScale( m_axis_x, m_axis_y1 );
m_plotWin->UpdateAll();
return addedNewEntry;
}
bool SIM_PLOT_PANEL::deleteTrace( const wxString& aName )
bool SIM_PLOT_PANEL::DeleteTrace( const wxString& aName )
{
auto it = m_traces.find( aName );

View File

@ -185,8 +185,6 @@ protected:
class SIM_PLOT_PANEL : public SIM_PANEL_BASE
{
friend class SIM_WORKBOOK;
public:
SIM_PLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
@ -303,11 +301,11 @@ public:
return m_plotWin;
}
protected:
bool addTrace( const wxString& aTitle, const wxString& aName, int aPoints, const double* aX,
const double* aY, SIM_TRACE_TYPE aType );
TRACE* AddTrace( const wxString& aTitle, const wxString& aName, SIM_TRACE_TYPE aType );
bool deleteTrace( const wxString& aName );
void SetTraceData( TRACE* aTrace, unsigned int aPoints, const double* aX, const double* aY );
bool DeleteTrace( const wxString& aName );
private:
///< @brief Construct the plot axes for DC simulation plot.