void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event ) { if( !CurrentPlot() ) return; wxFileDialog saveDlg( this, _( "Save plot as image" ), "", "", _( "PNG file (*.png)|*.png" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( saveDlg.ShowModal() == wxID_CANCEL ) return; CurrentPlot()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG ); }
void SIM_PLOT_FRAME::menuShowGridUpdate( wxUpdateUIEvent& event ) { SIM_PLOT_PANEL* plot = CurrentPlot(); if( plot ) event.Check( plot ? plot->IsGridShown() : false ); }
void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event ) { SIM_PLOT_PANEL* plotPanel = CurrentPlot(); // Initial processing is required to e.g. display a list of power sources updateNetlistExporter(); if( !m_exporter->ProcessNetlist( NET_ALL_FLAGS ) ) { DisplayError( this, _( "There were errors during netlist export, aborted." ) ); return; } if( !m_settingsDlg ) m_settingsDlg = new DIALOG_SIM_SETTINGS( this ); if( plotPanel ) m_settingsDlg->SetSimCommand( m_plots[plotPanel].m_simCommand ); m_settingsDlg->SetNetlistExporter( m_exporter.get() ); if( m_settingsDlg->ShowModal() == wxID_OK ) { wxString newCommand = m_settingsDlg->GetSimCommand(); SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand ); // If it is a new simulation type, open a new plot if( !plotPanel || ( plotPanel && plotPanel->GetType() != newSimType ) ) { plotPanel = NewPlotPanel( newSimType ); } m_plots[plotPanel].m_simCommand = newCommand; } }
void SIM_PLOT_FRAME::menuShowLegend( wxCommandEvent& event ) { SIM_PLOT_PANEL* plot = CurrentPlot(); if( plot ) plot->ShowLegend( !plot->IsLegendShown() ); }
void SIM_PLOT_FRAME::StartSimulation() { STRING_FORMATTER formatter; SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !m_settingsDlg ) m_settingsDlg = new DIALOG_SIM_SETTINGS( this ); m_simConsole->Clear(); updateNetlistExporter(); if( plotPanel ) m_exporter->SetSimCommand( m_plots[plotPanel].m_simCommand ); if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) ) { DisplayError( this, _( "There were errors during netlist export, aborted." ) ); return; } if( m_exporter->GetSimType() == ST_UNKNOWN ) { DisplayInfoMessage( this, _( "You need to select the simulation settings first." ) ); return; } m_simulator->LoadNetlist( formatter.GetString() ); updateTuners(); applyTuners(); m_simulator->Run(); }
void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event ) { if( !CurrentPlot() ) return; const wxChar SEPARATOR = ';'; wxFileDialog saveDlg( this, _( "Save plot data" ), "", "", "CSV file (*.csv)|*.csv", wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( saveDlg.ShowModal() == wxID_CANCEL ) return; wxFile out( saveDlg.GetPath(), wxFile::write ); bool timeWritten = false; for( const auto& t : CurrentPlot()->GetTraces() ) { const TRACE* trace = t.second; if( !timeWritten ) { out.Write( wxString::Format( "Time%c", SEPARATOR ) ); for( double v : trace->GetDataX() ) out.Write( wxString::Format( "%f%c", v, SEPARATOR ) ); out.Write( "\r\n" ); timeWritten = true; } out.Write( wxString::Format( "%s%c", t.first, SEPARATOR ) ); for( double v : trace->GetDataY() ) out.Write( wxString::Format( "%f%c", v, SEPARATOR ) ); out.Write( "\r\n" ); } out.Close(); }
void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent ) { m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( sim_run_xpm ) ); SetCursor( wxCURSOR_ARROW ); SIM_TYPE simType = m_exporter->GetSimType(); if( simType == ST_UNKNOWN ) return; SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel || plotPanel->GetType() != simType ) plotPanel = NewPlotPanel( simType ); if( IsSimulationRunning() ) return; // If there are any signals plotted, update them if( SIM_PLOT_PANEL::IsPlottable( simType ) ) { TRACE_MAP& traceMap = m_plots[plotPanel].m_traces; for( auto it = traceMap.begin(); it != traceMap.end(); /* iteration occurs in the loop */) { if( !updatePlot( it->second, plotPanel ) ) { removePlot( it->first, false ); it = traceMap.erase( it ); // remove a plot that does not exist anymore } else { ++it; } } updateSignalList(); plotPanel->UpdateAll(); plotPanel->ResetScales(); } else { /// @todo do not make it hardcoded for ngspice for( const auto& net : m_exporter->GetNetIndexMap() ) { int node = net.second; if( node > 0 ) m_simulator->Command( wxString::Format( "print v(%d)", node ).ToStdString() ); } } }
void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event ) { SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() ) { DisplayInfoMessage( this, _( "You need to run simulation first." ) ); return; } DIALOG_SIGNAL_LIST dialog( this, m_exporter.get() ); dialog.ShowModal(); }
void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent ) { SIM_TYPE type = m_exporter->GetSimType(); if( SIM_PLOT_PANEL::IsPlottable( type ) ) { SIM_PLOT_PANEL* prevPlot = CurrentPlot(); SIM_PLOT_PANEL* newPlot = NewPlotPanel( type ); // If the previous plot had the same type, copy the simulation command if( prevPlot ) m_plots[newPlot].m_simCommand = m_plots[prevPlot].m_simCommand; } }
void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event ) { if( !CurrentPlot() ) return; wxFileDialog saveDlg( this, _( "Save simulation workbook" ), "", "", _( "Workbook file (*.wbk)|*.wbk" ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( saveDlg.ShowModal() == wxID_CANCEL ) return; if( !saveWorkbook( saveDlg.GetPath() ) ) DisplayError( this, _( "There was an error while saving the workbook file" ) ); }
void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event ) { if( !CurrentPlot() ) return; wxFileDialog saveDlg( this, _( "Save Simulation Workbook" ), m_savedWorkbooksPath, "", WorkbookFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( saveDlg.ShowModal() == wxID_CANCEL ) return; m_savedWorkbooksPath = saveDlg.GetDirectory(); if( !saveWorkbook( saveDlg.GetPath() ) ) DisplayError( this, _( "There was an error while saving the workbook file" ) ); }
void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event ) { wxSize size = m_cursors->GetClientSize(); SIM_PLOT_PANEL* plotPanel = CurrentPlot(); m_cursors->ClearAll(); if( !plotPanel ) return; if( m_signalsIconColorList ) m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL); // Fill the signals listctrl m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 ); const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT, size.x / 4 ); wxString labelY1 = plotPanel->GetLabelY1(); wxString labelY2 = plotPanel->GetLabelY2(); wxString labelY; if( !labelY2.IsEmpty() ) labelY = labelY1 + " / " + labelY2; else labelY = labelY1; const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 ); // Update cursor values int itemidx = 0; for( const auto& trace : plotPanel->GetTraces() ) { if( CURSOR* cursor = trace.second->GetCursor() ) { // Find the right icon color in list. // It is the icon used in m_signals list for the same trace long iconColor = m_signals->FindItem( -1, trace.first ); const wxRealPoint coords = cursor->GetCoords(); long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor ); m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() ); m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() ); } } }
void SIM_PLOT_FRAME::onSimUpdate( wxCommandEvent& aEvent ) { if( IsSimulationRunning() ) StopSimulation(); if( CurrentPlot() != m_lastSimPlot ) { // We need to rerun simulation, as the simulator currently stores // results for another plot StartSimulation(); } else { // Incremental update m_simConsole->Clear(); // Do not export netlist, it is already stored in the simulator applyTuners(); m_simulator->Run(); } }
void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam ) { SIM_TYPE simType = m_exporter->GetSimType(); if( !SIM_PLOT_PANEL::IsPlottable( simType ) ) return; // TODO else write out in console? // Create a new plot if the current one displays a different type SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel || plotPanel->GetType() != simType ) plotPanel = NewPlotPanel( simType ); TRACE_DESC descriptor( *m_exporter, aName, aType, aParam ); bool updated = false; SIM_PLOT_TYPE xAxisType = GetXAxisType( simType ); if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY ) { int baseType = descriptor.GetType() & ~( SPT_AC_MAG | SPT_AC_PHASE ); // Add two plots: magnitude & phase TRACE_DESC mag_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_MAG ) ); TRACE_DESC phase_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_PHASE ) ); updated |= updatePlot( mag_desc, plotPanel ); updated |= updatePlot( phase_desc, plotPanel ); } else { updated = updatePlot( descriptor, plotPanel ); } if( updated ) { updateSignalList(); } }
void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase ) { SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel ) return; if( aErase ) { auto& traceMap = m_plots[plotPanel].m_traces; auto traceIt = traceMap.find( aPlotName ); wxASSERT( traceIt != traceMap.end() ); traceMap.erase( traceIt ); } wxASSERT( plotPanel->IsShown( aPlotName ) ); plotPanel->DeleteTrace( aPlotName ); plotPanel->Fit(); updateSignalList(); updateCursors(); }
void SIM_PLOT_FRAME::AddTuner( SCH_COMPONENT* aComponent ) { SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel ) return; // For now limit the tuner tool to RLC components char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aComponent, 0 )[0]; if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR && primitiveType != SP_INDUCTOR ) return; const wxString& componentName = aComponent->GetField( REFERENCE )->GetText(); // Do not add multiple instances for the same component auto tunerIt = std::find_if( m_tuners.begin(), m_tuners.end(), [&]( const TUNER_SLIDER* t ) { return t->GetComponentName() == componentName; } ); if( tunerIt != m_tuners.end() ) return; // We already have it try { TUNER_SLIDER* tuner = new TUNER_SLIDER( this, m_tunePanel, aComponent ); m_tuneSizer->Add( tuner ); m_tuners.push_back( tuner ); m_tunePanel->Layout(); } catch( const KI_PARAM_ERROR& e ) { // Sorry, no bonus DisplayError( nullptr, e.What() ); } }
void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event ) { SIM_PLOT_PANEL* plot = CurrentPlot(); event.Check( plot ? plot->IsLegendShown() : false ); }
void SIM_PLOT_FRAME::updateSignalList() { SIM_PLOT_PANEL* plotPanel = CurrentPlot(); if( !plotPanel ) return; m_signals->ClearAll(); wxSize size = m_signals->GetClientSize(); m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x ); // Build an image list, to show the color of the corresponding trace // in the plot panel // This image list is used for trace and cursor lists wxMemoryDC bmDC; const int isize = bmDC.GetCharHeight(); if( m_signalsIconColorList == NULL ) m_signalsIconColorList = new wxImageList( isize, isize, false ); else m_signalsIconColorList->RemoveAll(); for( const auto& trace : CurrentPlot()->GetTraces() ) { wxBitmap bitmap( isize, isize ); bmDC.SelectObject( bitmap ); wxColor tcolor = trace.second->GetTraceColour(); wxColour bgColor = m_signals->wxWindow::GetBackgroundColour(); bmDC.SetPen( wxPen( bgColor ) ); bmDC.SetBrush( wxBrush( bgColor ) ); bmDC.DrawRectangle( 0, 0, isize, isize ); // because bmDC.Clear() does not work in wxGTK bmDC.SetPen( wxPen( tcolor ) ); bmDC.SetBrush( wxBrush( tcolor ) ); bmDC.DrawRectangle( 0, isize / 4 + 1, isize, isize / 2 ); bmDC.SelectObject( wxNullBitmap ); // Needed to initialize bitmap bitmap.SetMask( new wxMask( bitmap, *wxBLACK ) ); m_signalsIconColorList->Add( bitmap ); } if( bmDC.IsOk() ) { bmDC.SetBrush( wxNullBrush ); bmDC.SetPen( wxNullPen ); } m_signals->SetImageList( m_signalsIconColorList, wxIMAGE_LIST_SMALL ); // Fill the signals listctrl. Keep the order of names and // the order of icon color identical, because the icons // are also used in cursor list, and the color index is // calculated from the trace name index int imgidx = 0; for( const auto& trace : m_plots[plotPanel].m_traces ) { m_signals->InsertItem( imgidx, trace.first, imgidx ); imgidx++; } }
void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event ) { if( CurrentPlot() ) CurrentPlot()->Fit(); }