Better startup experience for simulator.

Pre-load signals list (and plot panel if there is an schText simulation
command).

Also fixes a bug where the workbook was getting dirtied on open because
the events would fire after the dirty flag had been cleared.
This commit is contained in:
Jeff Young 2023-02-14 00:03:30 +00:00
parent df022acc11
commit 9ce18dffdd
2 changed files with 75 additions and 53 deletions

View File

@ -363,12 +363,6 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
attr->SetReadOnly();
m_signalsGrid->SetColAttr( COL_SIGNAL_NAME, attr );
attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetColAttr( COL_SIGNAL_SHOW, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_cursorsGrid->SetColAttr( COL_CURSOR_NAME, attr );
@ -557,16 +551,13 @@ void SIM_PLOT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
cfg->m_Simulator.white_background = !m_darkMode;
}
if( !m_isNonUserClose ) // If we're exiting the project has already been released.
{
PROJECT_FILE& project = Prj().GetProjectFile();
PROJECT_FILE& project = Prj().GetProjectFile();
if( project.m_SchematicSettings )
project.m_SchematicSettings->m_NgspiceSimulatorSettings->SaveToFile();
if( project.m_SchematicSettings )
project.m_SchematicSettings->m_NgspiceSimulatorSettings->SaveToFile();
if( m_schematicFrame )
m_schematicFrame->SaveProjectSettings();
}
if( m_schematicFrame )
m_schematicFrame->SaveProjectSettings();
}
@ -589,6 +580,14 @@ void SIM_PLOT_FRAME::initWorkbook()
if( !LoadWorkbook( filename.GetFullPath() ) )
m_simulator->Settings()->SetWorkbookFilename( "" );
}
else if( LoadSimulator() )
{
if( !m_circuitModel->GetSchTextSimCommand().IsEmpty() )
NewPlotPanel( m_circuitModel->GetSchTextSimCommand(), m_circuitModel->GetSimOptions() );
rebuildSignalsList();
rebuildSignalsGrid( m_filter->GetValue() );
}
}
@ -649,13 +648,11 @@ void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
{
m_signalsGrid->ClearRows();
if( !GetCurrentPlot() )
return;
if( aFilter.IsEmpty() )
aFilter = wxS( "*" );
EDA_COMBINED_MATCHER matcher( aFilter, CTX_SIGNAL );
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
int row = 0;
for( const wxString& signal : m_signals )
@ -665,15 +662,48 @@ void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
if( matcher.Find( signal, matches, offset ) && offset == 0 )
{
m_signalsGrid->AppendRows( 1 );
TRACE* trace = plotPanel ? plotPanel->GetTrace( signal ) : nullptr;
m_signalsGrid->AppendRows( 1 );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_NAME, signal );
if( TRACE* trace = GetCurrentPlot()->GetTrace( signal ) )
if( !plotPanel )
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_SIGNAL_SHOW, attr );
}
else
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetRenderer( new wxGridCellBoolRenderer() );
attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_SIGNAL_SHOW, attr );
}
if( trace )
m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxS( "1" ) );
if( !plotPanel || !trace )
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, wxEmptyString );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
}
else
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr = new wxGridCellAttr;
attr->SetRenderer( new GRID_CELL_COLOR_RENDERER( this ) );
attr->SetEditor( new GRID_CELL_COLOR_SELECTOR( this, m_signalsGrid ) );
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
@ -693,21 +723,6 @@ void SIM_PLOT_FRAME::rebuildSignalsGrid( wxString aFilter )
attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
}
else
{
wxGridCellAttr* attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_SIGNAL_COLOR, attr );
m_signalsGrid->SetCellValue( row, COL_SIGNAL_COLOR, wxEmptyString );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_1, attr );
attr = new wxGridCellAttr;
attr->SetReadOnly();
m_signalsGrid->SetAttr( row, COL_CURSOR_2, attr );
}
row++;
}
@ -723,6 +738,9 @@ void SIM_PLOT_FRAME::rebuildSignalsList()
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( GetCurrentSimCommand() );
wxString unconnected = wxString( wxS( "unconnected-(" ) );
if( simType == ST_UNKNOWN )
simType = ST_TRANSIENT;
unconnected.Replace( '(', '_' ); // Convert to SPICE markup
if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
@ -804,8 +822,7 @@ bool SIM_PLOT_FRAME::LoadSimulator()
if( !m_simulator->Attach( m_circuitModel, reporter ) )
{
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" )
+ errors );
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + errors );
return false;
}
@ -1305,7 +1322,7 @@ void SIM_PLOT_FRAME::addTrace( const wxString& aName, SIM_TRACE_TYPE aType )
return;
}
SIM_TYPE simType = m_circuitModel->GetSimType();
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( plotPanel->GetSimCommand() );
if( simType == ST_UNKNOWN )
{
@ -1357,20 +1374,20 @@ void SIM_PLOT_FRAME::removeTrace( const wxString& aSignalName )
}
void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aTraceType,
SIM_PLOT_PANEL* aPlotPanel )
{
SIM_TYPE simType = m_circuitModel->GetSimType();
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aPlotPanel->GetSimCommand() );
wxString traceTitle = aName;
wxString vectorName = aName;
if( aType & SPT_AC_MAG )
if( aTraceType & SPT_AC_MAG )
traceTitle += _( " (gain)" );
else if( aType & SPT_AC_PHASE )
else if( aTraceType & SPT_AC_PHASE )
traceTitle += _( " (phase)" );
if( aType & SPT_POWER )
if( aTraceType & SPT_POWER )
vectorName = vectorName.AfterFirst( '(' ).BeforeLast( ')' ) + wxS( ":power" );
if( !SIM_PANEL_BASE::IsPlottable( simType ) )
@ -1393,15 +1410,15 @@ void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
std::vector<double> data_y;
// Now, Y axis data
switch( m_circuitModel->GetSimType() )
switch( simType )
{
case ST_AC:
wxASSERT_MSG( !( ( aType & SPT_AC_MAG ) && ( aType & SPT_AC_PHASE ) ),
wxASSERT_MSG( !( ( aTraceType & SPT_AC_MAG ) && ( aTraceType & SPT_AC_PHASE ) ),
wxT( "Cannot set both AC_PHASE and AC_MAG bits" ) );
if( aType & SPT_AC_MAG )
if( aTraceType & SPT_AC_MAG )
data_y = m_simulator->GetMagPlot( (const char*) vectorName.c_str() );
else if( aType & SPT_AC_PHASE )
else if( aTraceType & SPT_AC_PHASE )
data_y = m_simulator->GetPhasePlot( (const char*) vectorName.c_str() );
else
wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) );
@ -1422,7 +1439,7 @@ void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
// for each input step
SPICE_DC_PARAMS source1, source2;
if( m_circuitModel->GetSimType() == ST_DC
if( simType == ST_DC
&& m_circuitModel->ParseDCCommand( m_circuitModel->GetSimCommand(), &source1, &source2 )
&& !source2.m_source.IsEmpty() )
{
@ -1443,7 +1460,7 @@ void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
source2.m_source,
v.ToString() );
if( TRACE* trace = aPlotPanel->AddTrace( name, aName, aType ) )
if( TRACE* trace = aPlotPanel->AddTrace( name, aName, aTraceType ) )
{
if( data_y.size() >= size )
{
@ -1460,7 +1477,7 @@ void SIM_PLOT_FRAME::updateTrace( const wxString& aName, SIM_TRACE_TYPE aType,
offset += inner;
}
}
else if( TRACE* trace = aPlotPanel->AddTrace( traceTitle, aName, aType ) )
else if( TRACE* trace = aPlotPanel->AddTrace( traceTitle, aName, aTraceType ) )
{
if( data_y.size() >= size )
aPlotPanel->SetTraceData( trace, size, data_x.data(), data_y.data() );
@ -1818,10 +1835,15 @@ bool SIM_PLOT_FRAME::LoadWorkbook( const wxString& aPath )
// Remember the loaded workbook filename.
m_simulator->Settings()->SetWorkbookFilename( filename.GetFullPath() );
// Successfully loading a workbook does not count as modifying it.
m_workbookModified = false;
updateTitle();
// Successfully loading a workbook does not count as modifying it. Clear the modified
// flag after all the EVT_WORKBOOK_MODIFIED events have been processed.
CallAfter( [=]()
{
m_workbookModified = false;
} );
return true;
}

View File

@ -269,11 +269,11 @@ private:
* trace, then add it.
*
* @param aName is the device/net name.
* @param aType describes the type of plot.
* @param aTraceType 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.
*/
void updateTrace( const wxString& aName, SIM_TRACE_TYPE aType, SIM_PLOT_PANEL* aPlotPanel );
void updateTrace( const wxString& aName, SIM_TRACE_TYPE aTraceType, SIM_PLOT_PANEL* aPlotPanel );
/**
* Rebuild the list of signals available from the netlist.