KiCad PCB EDA Suite
sim_plot_frame.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 CERN
5  * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <[email protected]>
7  * @author Maciej Suminski <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 3
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * https://www.gnu.org/licenses/gpl-3.0.html
22  * or you may search the http://www.gnu.org website for the version 3 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <wx/debug.h>
28 #include <wx/stc/stc.h>
29 
30 #include <project/project_file.h>
31 #include <sch_edit_frame.h>
32 #include <eeschema_id.h>
33 #include <kiway.h>
34 #include <confirm.h>
35 #include <bitmaps.h>
37 #include <widgets/tuner_slider.h>
39 #include "string_utils.h"
41 #include <pgm_base.h>
42 #include "ngspice.h"
43 #include "sim_plot_colors.h"
44 #include "sim_plot_frame.h"
45 #include "sim_plot_panel.h"
46 #include "spice_simulator.h"
47 #include "spice_reporter.h"
48 #include <menus_helpers.h>
49 #include <tool/tool_manager.h>
50 #include <tools/ee_actions.h>
51 #include <eeschema_settings.h>
52 #include <wx/ffile.h>
53 #include <wx/filedlg.h>
54 #include <dialog_shim.h>
55 
56 
58 {
59  int res = (int) aFirst | (int) aSecond;
60 
61  return (SIM_PLOT_TYPE) res;
62 }
63 
64 
66 {
67 public:
69  m_parent( aParent )
70  {
71  }
72 
73  REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
74  {
75  wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
76  event->SetString( aText );
77  wxQueueEvent( m_parent, event );
78  return *this;
79  }
80 
81  bool HasMessage() const override
82  {
83  return false; // Technically "indeterminate" rather than false.
84  }
85 
86  void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override
87  {
88  wxCommandEvent* event = nullptr;
89 
90  switch( aNewState )
91  {
92  case SIM_IDLE:
93  event = new wxCommandEvent( EVT_SIM_FINISHED );
94  break;
95 
96  case SIM_RUNNING:
97  event = new wxCommandEvent( EVT_SIM_STARTED );
98  break;
99 
100  default:
101  wxFAIL;
102  return;
103  }
104 
105  wxQueueEvent( m_parent, event );
106  }
107 
108 private:
110 };
111 
112 
113 SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
114  SIM_PLOT_FRAME_BASE( aParent ),
115  m_lastSimPlot( nullptr ),
116  m_plotNumber( 0 ),
117  m_simFinished( false )
118 {
119  SetKiway( this, aKiway );
120  m_signalsIconColorList = nullptr;
121 
123 
124  if( m_schematicFrame == nullptr )
125  throw std::runtime_error( "There is no schematic window" );
126 
127  // Give an icon
128  wxIcon icon;
129  icon.CopyFromBitmap( KiBitmap( BITMAPS::simulator ) );
130  SetIcon( icon );
131 
133 
134  if( !m_simulator )
135  {
136  throw std::runtime_error( "Could not create simulator instance" );
137  return;
138  }
139 
140  // Get the previous size and position of windows:
141  LoadSettings( config() );
142 
143  // Prepare the color list to plot traces
145 
146  // Give icons to menuitems
148 
149  m_simulator->Init();
150 
151  m_reporter = new SIM_THREAD_REPORTER( this );
152  m_simulator->SetReporter( m_reporter );
153 
154  // the settings dialog will be created later, on demand.
155  // if created in the ctor, for some obscure reason, there is an issue
156  // on Windows: when open it, the simulator frame is sent to the background.
157  // instead of being behind the dialog frame (as it does)
158  m_settingsDlg = nullptr;
159 
161 
162  Bind( EVT_SIM_UPDATE, &SIM_PLOT_FRAME::onSimUpdate, this );
163  Bind( EVT_SIM_REPORT, &SIM_PLOT_FRAME::onSimReport, this );
164  Bind( EVT_SIM_STARTED, &SIM_PLOT_FRAME::onSimStarted, this );
165  Bind( EVT_SIM_FINISHED, &SIM_PLOT_FRAME::onSimFinished, this );
166  Bind( EVT_SIM_CURSOR_UPDATE, &SIM_PLOT_FRAME::onCursorUpdate, this );
167 
168  // Toolbar buttons
169  m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
170  KiBitmap( BITMAPS::sim_run ), _( "Run Simulation" ), wxITEM_NORMAL );
171  m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _( "Add Signals" ),
172  KiBitmap( BITMAPS::sim_add_signal ), _( "Add signals to plot" ), wxITEM_NORMAL );
173  m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _( "Probe" ),
174  KiBitmap( BITMAPS::sim_probe ), _( "Probe signals on the schematic" ), wxITEM_NORMAL );
175  m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _( "Tune" ),
176  KiBitmap( BITMAPS::sim_tune ), _( "Tune component values" ), wxITEM_NORMAL );
177  m_toolSettings = m_toolBar->AddTool( wxID_ANY, _( "Sim Parameters" ),
178  KiBitmap( BITMAPS::config ), _( "Simulation parameters and settings" ), wxITEM_NORMAL );
179 
180  // Start all toolbar buttons except settings as disabled
181  m_toolSimulate->Enable( false );
182  m_toolAddSignals->Enable( false );
183  m_toolProbe->Enable( false );
184  m_toolTune->Enable( false );
185  m_toolSettings->Enable( true );
186 
187  Bind( wxEVT_UPDATE_UI, &SIM_PLOT_FRAME::menuSimulateUpdate, this, m_toolSimulate->GetId() );
188  Bind( wxEVT_UPDATE_UI, &SIM_PLOT_FRAME::menuAddSignalsUpdate, this,
189  m_toolAddSignals->GetId() );
190  Bind( wxEVT_UPDATE_UI, &SIM_PLOT_FRAME::menuProbeUpdate, this, m_toolProbe->GetId() );
191  Bind( wxEVT_UPDATE_UI, &SIM_PLOT_FRAME::menuTuneUpdate, this, m_toolTune->GetId() );
192 
193  Bind( wxEVT_COMMAND_TOOL_CLICKED, &SIM_PLOT_FRAME::onSimulate, this, m_toolSimulate->GetId() );
194  Bind( wxEVT_COMMAND_TOOL_CLICKED, &SIM_PLOT_FRAME::onAddSignal, this,
195  m_toolAddSignals->GetId() );
196  Bind( wxEVT_COMMAND_TOOL_CLICKED, &SIM_PLOT_FRAME::onProbe, this, m_toolProbe->GetId() );
197  Bind( wxEVT_COMMAND_TOOL_CLICKED, &SIM_PLOT_FRAME::onTune, this, m_toolTune->GetId() );
198  Bind( wxEVT_COMMAND_TOOL_CLICKED, &SIM_PLOT_FRAME::onSettings, this, m_toolSettings->GetId() );
199 
200  Bind( EVT_WORKBOOK_MODIFIED, &SIM_PLOT_FRAME::onWorkbookModified, this );
201  Bind( EVT_WORKBOOK_CLR_MODIFIED, &SIM_PLOT_FRAME::onWorkbookClrModified, this );
202 
203  // Bind toolbar buttons event to existing menu event handlers, so they behave the same
204  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this,
205  m_runSimulation->GetId() );
206  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
207  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
208  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
209  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onShowNetlist, this,
210  m_showNetlist->GetId() );
211  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this,
212  m_boardAdapter->GetId() );
213 
214  m_toolBar->Realize();
215 
216 #ifndef wxHAS_NATIVE_TABART
217  // Non-native default tab art has ugly gradients we don't want
218  m_workbook->SetArtProvider( new wxAuiSimpleTabArt() );
219 #endif
220 
221  // Ensure new items are taken in account by sizers:
222  Layout();
223 
224  // resize the subwindows size. At least on Windows, calling wxSafeYield before
225  // resizing the subwindows forces the wxSplitWindows size events automatically generated
226  // by wxWidgets to be executed before our resize code.
227  // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
228  // events
229  wxSafeYield();
231 
232  // Ensure the window is on top
233  Raise();
234 
235  initWorkbook();
236  updateTitle();
237 }
238 
239 
241 {
242  m_simulator->SetReporter( nullptr );
243  delete m_reporter;
244  delete m_signalsIconColorList;
245 
246  if( m_settingsDlg )
247  m_settingsDlg->Destroy();
248 }
249 
250 
252 {
253  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
254  wxASSERT( cfg );
255 
256  if( cfg )
257  {
259 
260  // Read subwindows sizes (should be > 0 )
266  }
267 
269 
270  NGSPICE* currentSim = dynamic_cast<NGSPICE*>( m_simulator.get() );
271 
272  if( currentSim )
273  m_simulator->Settings() = project.m_SchematicSettings->m_NgspiceSimulatorSettings;
274 }
275 
276 
278 {
279  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
280  wxASSERT( cfg );
281 
282  if( cfg )
283  {
285 
286  cfg->m_Simulator.plot_panel_width = m_splitterLeftRight->GetSashPosition();
287  cfg->m_Simulator.plot_panel_height = m_splitterPlotAndConsole->GetSashPosition();
288  cfg->m_Simulator.signal_panel_height = m_splitterSignals->GetSashPosition();
289  cfg->m_Simulator.cursors_panel_height = m_splitterTuneValues->GetSashPosition();
291  }
292 
293  if( !m_isNonUserClose ) // If we're exiting the project has already been released.
294  {
296 
297  if( project.m_SchematicSettings )
298  project.m_SchematicSettings->m_NgspiceSimulatorSettings->SaveToFile();
299 
300  if( m_schematicFrame )
302  }
303 }
304 
305 
307 {
308  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
309  wxASSERT( cfg );
310 
311  return cfg ? &cfg->m_Simulator.window : nullptr;
312 }
313 
314 
316 {
317  // Removed for the time being. We cannot run the simulation on simulator launch, as it may
318  // take a lot of time, confusing the user.
319  // TODO: Change workbook loading routines so that they don't run the simulation until the user
320  // initiates it.
321 
322  /*if( !m_simulator->Settings()->GetWorkbookFilename().IsEmpty() )
323  {
324  wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
325  filename.SetPath( Prj().GetProjectPath() );
326 
327  if( !loadWorkbook( filename.GetFullPath() ) )
328  m_simulator->Settings()->SetWorkbookFilename( "" );
329  }*/
330 }
331 
332 
334 {
335  wxFileName filename = Prj().AbsolutePath( m_simulator->Settings()->GetWorkbookFilename() );
336 
337  bool readOnly = false;
338  bool unsaved = false;
339 
340  if( filename.IsOk() && filename.FileExists() )
341  readOnly = !filename.IsFileWritable();
342  else
343  unsaved = true;
344 
345  wxString title;
346 
347  if( m_workbook->IsModified() )
348  title = wxT( "*" ) + filename.GetName();
349  else
350  title = filename.GetName();
351 
352  if( readOnly )
353  title += wxS( " " ) + _( "[Read Only]" );
354 
355  if( unsaved )
356  title += wxS( " " ) + _( "[Unsaved]" );
357 
358  title += wxT( " \u2014 " ) + _( "Spice Simulator" );
359 
360  SetTitle( title );
361 }
362 
363 
364 // A small helper struct to handle bitmaps initialization in menus
366 {
367  int m_MenuId;
369 };
370 
371 
373 {
374  // Give icons to menuitems of the main menubar
375  BM_MENU_INIT_ITEM bm_list[]
376  {
377  // File menu:
378  { wxID_NEW, BITMAPS::simulator },
379  { wxID_OPEN, BITMAPS::directory_open },
380  { wxID_SAVE, BITMAPS::save },
383  { wxID_CLOSE, BITMAPS::exit },
384 
385  // simulator menu:
392 
393  // View menu
394  { wxID_ZOOM_IN, BITMAPS::zoom_in },
395  { wxID_ZOOM_OUT, BITMAPS::zoom_out },
396  { wxID_ZOOM_FIT, BITMAPS::zoom_fit_in_page },
401 
402  { 0, BITMAPS::INVALID_BITMAP } // Sentinel
403  };
404 
405  // wxMenuItems are already created and attached to the m_mainMenu wxMenuBar.
406  // A problem is the fact setting bitmaps in wxMenuItems after they are attached
407  // to a wxMenu do not work in all cases.
408  // So the trick is:
409  // Remove the wxMenuItem from its wxMenu
410  // Set the bitmap
411  // Insert the modified wxMenuItem to its previous place
412  for( int ii = 0; bm_list[ii].m_MenuId; ++ii )
413  {
414  wxMenuItem* item = m_mainMenu->FindItem( bm_list[ii].m_MenuId );
415 
416  if( !item || ( bm_list[ii].m_Bitmap == BITMAPS::INVALID_BITMAP ) )
417  continue;
418 
419  wxMenu* menu = item->GetMenu();
420 
421  // Calculate the initial index of item inside the wxMenu parent.
422  wxMenuItemList& mlist = menu->GetMenuItems();
423  int mpos = mlist.IndexOf( item );
424 
425  if( mpos >= 0 ) // Should be always the case
426  {
427  // Modify the bitmap
428  menu->Remove( item );
429  AddBitmapToMenuItem( item, KiBitmap( bm_list[ii].m_Bitmap ) );
430 
431  // Insert item to its the initial index
432  menu->Insert( mpos, item );
433  }
434  }
435 }
436 
437 
439 {
442 
445 
448 
451 }
452 
453 
454 void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
455 {
456  wxCHECK_RET( m_exporter->CommandToSimType( getCurrentSimCommand() ) != ST_UNKNOWN,
457  "Unknown simulation type" );
458 
459  STRING_FORMATTER formatter;
460 
461  if( !m_settingsDlg )
462  m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
463 
464  m_simConsole->Clear();
466 
467  if( aSimCommand.IsEmpty() )
468  m_exporter->SetSimCommand( getCurrentSimCommand() );
469  else
470  m_exporter->SetSimCommand( aSimCommand );
471 
472 
473  if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) )
474  {
475  DisplayErrorMessage( this, _( "There were errors during netlist export, aborted." ) );
476  return;
477  }
478 
479  m_simulator->LoadNetlist( formatter.GetString() );
480  updateTuners();
481  applyTuners();
482  m_simulator->Run();
483 }
484 
485 
487 {
488  m_simulator->Stop();
489 }
490 
491 
493 {
494  SIM_PANEL_BASE* plotPanel = nullptr;
496 
497  if( SIM_PANEL_BASE::IsPlottable( simType ) )
498  {
499  SIM_PLOT_PANEL* panel;
500  panel = new SIM_PLOT_PANEL( aSimCommand, m_workbook, this, wxID_ANY );
501 
503  Pgm().GetCommonSettings()->m_Input.scroll_modifier_zoom != 0 );
504 
505  plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
506  }
507  else
508  {
509  SIM_NOPLOT_PANEL* panel;
510  panel = new SIM_NOPLOT_PANEL( aSimCommand, m_workbook, wxID_ANY );
511  plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
512  }
513 
514  wxString pageTitle( m_simulator->TypeToName( simType, true ) );
515  pageTitle.Prepend( wxString::Format( _( "Plot%u - " ), (unsigned int) ++m_plotNumber ) );
516 
517  m_workbook->AddPage( dynamic_cast<wxWindow*>( plotPanel ), pageTitle, true );
518 
519  return plotPanel;
520 }
521 
522 
523 void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
524 {
525  addPlot( aNetName, SPT_VOLTAGE, "V" );
526 }
527 
528 
529 void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam )
530 {
531  addPlot( aDeviceName, SPT_CURRENT, aParam );
532 }
533 
534 
536 {
537  SIM_PANEL_BASE* plotPanel = getCurrentPlotWindow();
538 
539  if( !plotPanel )
540  return;
541 
542  // For now limit the tuner tool to RLC components
543  char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aSymbol, 0 )[0];
544 
545  if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR
546  && primitiveType != SP_INDUCTOR )
547  return;
548 
549  const wxString componentName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
550 
551  // Do not add multiple instances for the same component
552  auto tunerIt = std::find_if( m_tuners.begin(), m_tuners.end(), [&]( const TUNER_SLIDER* t )
553  {
554  return t->GetComponentName() == componentName;
555  }
556  );
557 
558  if( tunerIt != m_tuners.end() )
559  return; // We already have it
560 
561  try
562  {
563  TUNER_SLIDER* tuner = new TUNER_SLIDER( this, m_tunePanel, aSymbol );
564  m_tuneSizer->Add( tuner );
565  m_tuners.push_back( tuner );
566  m_tunePanel->Layout();
567  }
568  catch( const KI_PARAM_ERROR& e )
569  {
570  // Sorry, no bonus
571  DisplayErrorMessage( nullptr, e.What() );
572  }
573 }
574 
575 void SIM_PLOT_FRAME::UpdateTunerValue( SCH_SYMBOL* aSymbol, int aId, const wxString& aValue )
576 {
577  for( auto& item : m_schematicFrame->GetScreen()->Items().OfType( SCH_SYMBOL_T ) )
578  {
579  if( item == aSymbol )
580  {
581  SCH_FIELD* field = aSymbol->GetFieldById( aId );
582 
583  if( !field )
584  break;
585 
586  field->SetText( aValue );
587 
588  m_schematicFrame->UpdateItem( aSymbol, false, true );
590  break;
591  }
592  }
593 
594 }
595 
596 
597 void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
598 {
599  if( aErase )
600  m_tuners.remove( aTuner );
601 
602  aTuner->Destroy();
603  m_tunePanel->Layout();
604 }
605 
606 
608 {
610 
611  return ( ( !curPage || curPage->GetType() == ST_UNKNOWN ) ?
612  nullptr :
613  dynamic_cast<SIM_PLOT_PANEL*>( curPage ) );
614 }
615 
616 
618 {
619  return m_exporter.get();
620 }
621 
622 
623 std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& SIM_PLOT_FRAME::GetSimulatorSettings()
624 {
625  wxASSERT( m_simulator->Settings() );
626 
627  return m_simulator->Settings();
628 }
629 
630 
631 void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam )
632 {
633  SIM_TYPE simType = m_exporter->GetSimType();
634 
635  if( simType == ST_UNKNOWN )
636  {
637  m_simConsole->AppendText( _( "Error: simulation type not defined!\n" ) );
638  m_simConsole->SetInsertionPointEnd();
639  return;
640  }
641  else if( !SIM_PANEL_BASE::IsPlottable( simType ) )
642  {
643  m_simConsole->AppendText( _( "Error: simulation type doesn't support plotting!\n" ) );
644  m_simConsole->SetInsertionPointEnd();
645  return;
646  }
647 
648  // Create a new plot if the current one displays a different type
649  SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
650 
651  if( !plotPanel || plotPanel->GetType() != simType )
652  {
653  plotPanel =
654  dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( m_exporter->GetUsedSimCommand() ) );
655  }
656 
657  wxASSERT( plotPanel );
658 
659  if( !plotPanel ) // Something is wrong
660  return;
661 
662  bool updated = false;
663  SIM_PLOT_TYPE xAxisType = getXAxisType( simType );
664 
665  if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
666  {
667  int baseType = aType & ~( SPT_AC_MAG | SPT_AC_PHASE );
668 
669  // Add two plots: magnitude & phase
670  updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_MAG ), aParam,
671  plotPanel );
672  updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_PHASE ), aParam,
673  plotPanel );
674  }
675  else
676  {
677  updated = updatePlot( aName, aType, aParam, plotPanel );
678  }
679 
680  if( updated )
681  {
683  }
684 }
685 
686 
687 void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName )
688 {
689  SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
690 
691  if( !plotPanel )
692  return;
693 
694  wxASSERT( plotPanel->TraceShown( aPlotName ) );
695  m_workbook->DeleteTrace( plotPanel, aPlotName );
696  plotPanel->GetPlotWin()->Fit();
697 
699  wxCommandEvent dummy;
701 }
702 
703 
705 {
707 
708  if( m_settingsDlg )
710 }
711 
712 
713 bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam,
714  SIM_PLOT_PANEL* aPlotPanel )
715 {
716  SIM_TYPE simType = m_exporter->GetSimType();
717  wxString spiceVector = m_exporter->ComponentToVector( aName, aType, aParam );
718 
719  wxString plotTitle = wxString::Format( "%s(%s)", aParam, aName );
720  if( aType & SPT_AC_MAG )
721  plotTitle += " (mag)";
722  else if( aType & SPT_AC_PHASE )
723  plotTitle += " (phase)";
724 
725  if( !SIM_PANEL_BASE::IsPlottable( simType ) )
726  {
727  // There is no plot to be shown
728  m_simulator->Command( wxString::Format( "print %s", spiceVector ).ToStdString() );
729 
730  return false;
731  }
732 
733  // First, handle the x axis
734  wxString xAxisName( m_simulator->GetXAxis( simType ) );
735 
736  if( xAxisName.IsEmpty() )
737  return false;
738 
739  auto data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
740  unsigned int size = data_x.size();
741 
742  if( data_x.empty() )
743  return false;
744 
745  std::vector<double> data_y;
746 
747  // Now, Y axis data
748  switch( m_exporter->GetSimType() )
749  {
750  case ST_AC:
751  wxASSERT_MSG( !( ( aType & SPT_AC_MAG ) && ( aType & SPT_AC_PHASE ) ),
752  "Cannot set both AC_PHASE and AC_MAG bits" );
753 
754  if( aType & SPT_AC_MAG )
755  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
756  else if( aType & SPT_AC_PHASE )
757  data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
758  else
759  wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
760 
761  break;
762 
763  case ST_NOISE:
764  case ST_DC:
765  case ST_TRANSIENT:
766  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
767  break;
768 
769  default:
770  wxASSERT_MSG( false, "Unhandled plot type" );
771  return false;
772  }
773 
774  if( data_y.size() != size )
775  return false;
776 
777  // If we did a two-source DC analysis, we need to split the resulting vector and add traces
778  // for each input step
779  SPICE_DC_PARAMS source1, source2;
780 
781  if( m_exporter->GetSimType() == ST_DC &&
782  m_exporter->ParseDCCommand( m_exporter->GetUsedSimCommand(), &source1, &source2 ) )
783  {
784  if( !source2.m_source.IsEmpty() )
785  {
786  // Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step
787  SPICE_VALUE v = source2.m_vstart;
788  wxString name;
789 
790  size_t offset = 0;
791  size_t outer = ( size_t )( ( source2.m_vend - v ) / source2.m_vincrement ).ToDouble();
792  size_t inner = data_x.size() / ( outer + 1 );
793 
794  wxASSERT( data_x.size() % ( outer + 1 ) == 0 );
795 
796  for( size_t idx = 0; idx <= outer; idx++ )
797  {
798  name = wxString::Format( "%s (%s = %s V)", plotTitle, source2.m_source,
799  v.ToString() );
800 
801  std::vector<double> sub_x( data_x.begin() + offset,
802  data_x.begin() + offset + inner );
803  std::vector<double> sub_y( data_y.begin() + offset,
804  data_y.begin() + offset + inner );
805 
806  m_workbook->AddTrace( aPlotPanel, name, aName, inner, sub_x.data(), sub_y.data(),
807  aType, aParam );
808 
809  v = v + source2.m_vincrement;
810  offset += inner;
811  }
812 
813  return true;
814  }
815  }
816 
817  m_workbook->AddTrace( aPlotPanel, plotTitle, aName, size, data_x.data(), data_y.data(), aType,
818  aParam );
819 
820  return true;
821 }
822 
823 
825 {
826  m_signals->ClearAll();
827 
828  SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
829 
830  if( !plotPanel )
831  return;
832 
833  wxSize size = m_signals->GetClientSize();
834  m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x );
835 
836  // Build an image list, to show the color of the corresponding trace
837  // in the plot panel
838  // This image list is used for trace and cursor lists
839  wxMemoryDC bmDC;
840  const int isize = bmDC.GetCharHeight();
841 
842  if( m_signalsIconColorList == nullptr )
843  m_signalsIconColorList = new wxImageList( isize, isize, false );
844  else
845  m_signalsIconColorList->RemoveAll();
846 
847  for( const auto& trace : GetCurrentPlot()->GetTraces() )
848  {
849  wxBitmap bitmap( isize, isize );
850  bmDC.SelectObject( bitmap );
851  wxColour tcolor = trace.second->GetPen().GetColour();
852 
853  wxColour bgColor = m_signals->wxWindow::GetBackgroundColour();
854  bmDC.SetPen( wxPen( bgColor ) );
855  bmDC.SetBrush( wxBrush( bgColor ) );
856  bmDC.DrawRectangle( 0, 0, isize, isize ); // because bmDC.Clear() does not work in wxGTK
857 
858  bmDC.SetPen( wxPen( tcolor ) );
859  bmDC.SetBrush( wxBrush( tcolor ) );
860  bmDC.DrawRectangle( 0, isize / 4 + 1, isize, isize / 2 );
861 
862  bmDC.SelectObject( wxNullBitmap ); // Needed to initialize bitmap
863 
864  bitmap.SetMask( new wxMask( bitmap, *wxBLACK ) );
865  m_signalsIconColorList->Add( bitmap );
866  }
867 
868  if( bmDC.IsOk() )
869  {
870  bmDC.SetBrush( wxNullBrush );
871  bmDC.SetPen( wxNullPen );
872  }
873 
874  m_signals->SetImageList( m_signalsIconColorList, wxIMAGE_LIST_SMALL );
875 
876  // Fill the signals listctrl. Keep the order of names and
877  // the order of icon color identical, because the icons
878  // are also used in cursor list, and the color index is
879  // calculated from the trace name index
880  int imgidx = 0;
881 
882  for( const auto& trace : plotPanel->GetTraces() )
883  {
884  m_signals->InsertItem( imgidx, trace.first, imgidx );
885  imgidx++;
886  }
887 }
888 
889 
891 {
892  const auto& spiceItems = m_exporter->GetSpiceItems();
893 
894  for( auto it = m_tuners.begin(); it != m_tuners.end(); /* iteration inside the loop */ )
895  {
896  const wxString& ref = (*it)->GetComponentName();
897 
898  if( std::find_if( spiceItems.begin(), spiceItems.end(), [&]( const SPICE_ITEM& item )
899  {
900  return item.m_refName == ref;
901  }) == spiceItems.end() )
902  {
903  // The component does not exist anymore, remove the associated tuner
904  TUNER_SLIDER* tuner = *it;
905  it = m_tuners.erase( it );
906  RemoveTuner( tuner, false );
907  }
908  else
909  {
910  ++it;
911  }
912  }
913 }
914 
915 
917 {
918  for( auto& tuner : m_tuners )
919  {
921  std::string command( "alter @" + tuner->GetSpiceName()
922  + "=" + tuner->GetValue().ToSpiceString() );
923 
924  m_simulator->Command( command );
925  }
926 }
927 
928 
929 bool SIM_PLOT_FRAME::loadWorkbook( const wxString& aPath )
930 {
932 
933  wxTextFile file( aPath );
934 
935 #define DISPLAY_LOAD_ERROR( fmt ) DisplayErrorMessage( this, wxString::Format( _( fmt ), \
936  file.GetCurrentLine()+1 ) )
937 
938  if( !file.Open() )
939  return false;
940 
941  long plotsCount;
942 
943  if( !file.GetFirstLine().ToLong( &plotsCount ) ) // GetFirstLine instead of GetNextLine
944  {
945  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is not an integer." );
946  file.Close();
947 
948  return false;
949  }
950 
951  for( long i = 0; i < plotsCount; ++i )
952  {
953  long plotType, tracesCount;
954 
955  if( !file.GetNextLine().ToLong( &plotType ) )
956  {
957  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is not an integer." );
958  file.Close();
959 
960  return false;
961  }
962 
963  wxString simCommand = UnescapeString( file.GetNextLine() );
964  NewPlotPanel( simCommand );
965  StartSimulation( simCommand );
966 
967  // Perform simulation, so plots can be added with values
968  do
969  {
970  wxThread::This()->Sleep( 50 );
971  }
972  while( m_simulator->IsRunning() );
973 
974  if( !file.GetNextLine().ToLong( &tracesCount ) )
975  {
976  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is not an integer." );
977  file.Close();
978 
979  return false;
980  }
981 
982  for( long j = 0; j < tracesCount; ++j )
983  {
984  long traceType;
985  wxString name, param;
986 
987  if( !file.GetNextLine().ToLong( &traceType ) )
988  {
989  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is not an integer." );
990  file.Close();
991 
992  return false;
993  }
994 
995  name = file.GetNextLine();
996 
997  if( name.IsEmpty() )
998  {
999  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is empty." );
1000  file.Close();
1001 
1002  return false;
1003  }
1004 
1005  param = file.GetNextLine();
1006 
1007  if( param.IsEmpty() )
1008  {
1009  DISPLAY_LOAD_ERROR( "Error loading workbook: Line %d is empty." );
1010  file.Close();
1011 
1012  return false;
1013  }
1014 
1015  addPlot( name, (SIM_PLOT_TYPE) traceType, param );
1016  }
1017  }
1018 
1019  file.Close();
1020 
1021  wxFileName filename( aPath );
1022  filename.MakeRelativeTo( Prj().GetProjectPath() );
1023 
1024  // Remember the loaded workbook filename.
1025  m_simulator->Settings()->SetWorkbookFilename( filename.GetFullPath() );
1026 
1027  // Successfully loading a workbook does not count as modifying it.
1029  return true;
1030 }
1031 
1032 
1033 bool SIM_PLOT_FRAME::saveWorkbook( const wxString& aPath )
1034 {
1035  wxFileName filename = aPath;
1036  filename.SetExt( WorkbookFileExtension );
1037 
1038  wxTextFile file( filename.GetFullPath() );
1039 
1040  if( file.Exists() )
1041  {
1042  if( !file.Open() )
1043  return false;
1044 
1045  file.Clear();
1046  }
1047  else
1048  {
1049  file.Create();
1050  }
1051 
1052  file.AddLine( wxString::Format( "%llu", m_workbook->GetPageCount() ) );
1053 
1054  for( size_t i = 0; i < m_workbook->GetPageCount(); i++ )
1055  {
1056  const SIM_PANEL_BASE* basePanel = dynamic_cast<const SIM_PANEL_BASE*>( m_workbook->GetPage( i ) );
1057 
1058  if( !basePanel )
1059  {
1060  file.AddLine( wxString::Format( "%llu", 0ull ) );
1061  continue;
1062  }
1063 
1064  file.AddLine( wxString::Format( "%d", basePanel->GetType() ) );
1065  file.AddLine( EscapeString( m_workbook->GetSimCommand( basePanel ), CTX_LINE ) );
1066 
1067  const SIM_PLOT_PANEL* plotPanel = dynamic_cast<const SIM_PLOT_PANEL*>( basePanel );
1068 
1069  if( !plotPanel )
1070  {
1071  file.AddLine( wxString::Format( "%llu", 0ull ) );
1072  continue;
1073  }
1074 
1075  file.AddLine( wxString::Format( "%llu", plotPanel->GetTraces().size() ) );
1076 
1077  for( const auto& trace : plotPanel->GetTraces() )
1078  {
1079  file.AddLine( wxString::Format( "%d", trace.second->GetType() ) );
1080  file.AddLine( trace.second->GetName() );
1081  file.AddLine( trace.second->GetParam() );
1082  }
1083  }
1084 
1085  bool res = file.Write();
1086  file.Close();
1087 
1088  // Store the filename of the last saved workbook.
1089  if( res )
1090  {
1091  filename.MakeRelativeTo( Prj().GetProjectPath() );
1092  m_simulator->Settings()->SetWorkbookFilename( filename.GetFullPath() );
1093  }
1094 
1096  return res;
1097 }
1098 
1099 
1101 {
1102  wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
1103 
1104  if( filename.GetName().IsEmpty() )
1105  {
1106  if( Prj().GetProjectName().IsEmpty() )
1107  {
1108  filename.SetName( _( "noname" ) );
1109  filename.SetExt( WorkbookFileExtension );
1110  }
1111  else
1112  {
1113  filename.SetName( Prj().GetProjectName() );
1114  filename.SetExt( WorkbookFileExtension );
1115  }
1116  }
1117 
1118  return filename.GetFullName();
1119 }
1120 
1121 
1123 {
1124  wxFileName path = m_simulator->Settings()->GetWorkbookFilename();
1125 
1126  path.Normalize( wxPATH_NORM_ALL, Prj().GetProjectPath() );
1127  return path.GetPath();
1128 }
1129 
1130 
1132 {
1133  switch( aType )
1134  {
1136  case ST_AC: return SPT_LIN_FREQUENCY;
1137  case ST_DC: return SPT_SWEEP;
1138  case ST_TRANSIENT: return SPT_TIME;
1139  default:
1140  wxASSERT_MSG( false, "Unhandled simulation type" );
1141  return (SIM_PLOT_TYPE) 0;
1142  }
1143 }
1144 
1145 
1146 void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
1147 {
1148  SIM_TYPE type = m_exporter->GetSimType();
1149 
1150  if( SIM_PANEL_BASE::IsPlottable( type ) )
1151  NewPlotPanel( m_exporter->GetUsedSimCommand() );
1152 }
1153 
1154 
1155 void SIM_PLOT_FRAME::menuOpenWorkbook( wxCommandEvent& event )
1156 {
1157  wxFileDialog openDlg( this, _( "Open simulation workbook" ), getDefaultPath(), "",
1158  WorkbookFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
1159 
1160  if( openDlg.ShowModal() == wxID_CANCEL )
1161  return;
1162 
1163  loadWorkbook( openDlg.GetPath() );
1164 }
1165 
1166 
1167 void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event )
1168 {
1169  if( !m_workbook->IsModified() )
1170  return;
1171 
1172  wxString filename = m_simulator->Settings()->GetWorkbookFilename();
1173 
1174  if( filename.IsEmpty() )
1175  {
1176  menuSaveWorkbookAs( event );
1177  return;
1178  }
1179 
1180  saveWorkbook( Prj().AbsolutePath( m_simulator->Settings()->GetWorkbookFilename() ) );
1181 }
1182 
1183 
1184 void SIM_PLOT_FRAME::menuSaveWorkbookAs( wxCommandEvent& event )
1185 {
1186  wxFileDialog saveAsDlg( this, _( "Save Simulation Workbook As" ), getDefaultPath(),
1188  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1189 
1190  if( saveAsDlg.ShowModal() == wxID_CANCEL )
1191  return;
1192 
1193  saveWorkbook( Prj().AbsolutePath( saveAsDlg.GetPath() ) );
1194 }
1195 
1196 
1197 void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
1198 {
1199  if( !GetCurrentPlot() )
1200  return;
1201 
1202  wxFileDialog saveDlg( this, _( "Save Plot as Image" ), "", "", PngFileWildcard(),
1203  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1204 
1205  if( saveDlg.ShowModal() == wxID_CANCEL )
1206  return;
1207 
1208  GetCurrentPlot()->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
1209 }
1210 
1211 
1212 void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
1213 {
1214  if( !GetCurrentPlot() )
1215  return;
1216 
1217  const wxChar SEPARATOR = ';';
1218 
1219  wxFileDialog saveDlg( this, _( "Save Plot Data" ), "", "", CsvFileWildcard(),
1220  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1221 
1222  if( saveDlg.ShowModal() == wxID_CANCEL )
1223  return;
1224 
1225  wxFFile out( saveDlg.GetPath(), "wb" );
1226  bool timeWritten = false;
1227 
1228  for( const auto& t : GetCurrentPlot()->GetTraces() )
1229  {
1230  const TRACE* trace = t.second;
1231 
1232  if( !timeWritten )
1233  {
1234  out.Write( wxString::Format( "Time%c", SEPARATOR ) );
1235 
1236  for( double v : trace->GetDataX() )
1237  out.Write( wxString::Format( "%g%c", v, SEPARATOR ) );
1238 
1239  out.Write( "\r\n" );
1240  timeWritten = true;
1241  }
1242 
1243  out.Write( wxString::Format( "%s%c", t.first, SEPARATOR ) );
1244 
1245  for( double v : trace->GetDataY() )
1246  out.Write( wxString::Format( "%g%c", v, SEPARATOR ) );
1247 
1248  out.Write( "\r\n" );
1249  }
1250 
1251  out.Close();
1252 }
1253 
1254 
1255 void SIM_PLOT_FRAME::menuZoomIn( wxCommandEvent& event )
1256 {
1257  if( GetCurrentPlot() )
1259 }
1260 
1261 
1262 void SIM_PLOT_FRAME::menuZoomOut( wxCommandEvent& event )
1263 {
1264  if( GetCurrentPlot() )
1266 }
1267 
1268 
1269 void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event )
1270 {
1271  if( GetCurrentPlot() )
1272  GetCurrentPlot()->GetPlotWin()->Fit();
1273 }
1274 
1275 
1276 void SIM_PLOT_FRAME::menuShowGrid( wxCommandEvent& event )
1277 {
1279 
1280  if( plot )
1281  plot->ShowGrid( !plot->IsGridShown() );
1282 }
1283 
1284 
1285 void SIM_PLOT_FRAME::menuShowGridUpdate( wxUpdateUIEvent& event )
1286 {
1288 
1289  event.Check( plot ? plot->IsGridShown() : false );
1290 }
1291 
1292 
1293 void SIM_PLOT_FRAME::menuShowLegend( wxCommandEvent& event )
1294 {
1296 
1297  if( plot )
1298  plot->ShowLegend( !plot->IsLegendShown() );
1299 }
1300 
1301 
1302 void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event )
1303 {
1305  event.Check( plot ? plot->IsLegendShown() : false );
1306 }
1307 
1308 
1309 void SIM_PLOT_FRAME::menuShowDotted( wxCommandEvent& event )
1310 {
1312 
1313  if( plot )
1314  plot->SetDottedCurrentPhase( !plot->GetDottedCurrentPhase() );
1315 }
1316 
1317 
1318 void SIM_PLOT_FRAME::menuShowDottedUpdate( wxUpdateUIEvent& event )
1319 {
1321 
1322  event.Check( plot ? plot->GetDottedCurrentPhase() : false );
1323 }
1324 
1325 
1326 void SIM_PLOT_FRAME::menuWhiteBackground( wxCommandEvent& event )
1327 {
1329 
1330  // Rebuild the color list to plot traces
1332 
1333  // Now send changes to all SIM_PLOT_PANEL
1334  for( size_t page = 0; page < m_workbook->GetPageCount(); page++ )
1335  {
1336  wxWindow* curPage = m_workbook->GetPage( page );
1337 
1338  // ensure it is truly a plot panel and not the (zero plots) placeholder
1339  // which is only SIM_PLOT_PANEL_BASE
1340  SIM_PLOT_PANEL* panel = dynamic_cast<SIM_PLOT_PANEL*>( curPage );
1341 
1342  if( panel )
1343  panel->UpdatePlotColors();
1344  }
1345 }
1346 
1347 
1348 void SIM_PLOT_FRAME::menuSimulateUpdate( wxUpdateUIEvent& event )
1349 {
1350  event.Enable( m_exporter->CommandToSimType( getCurrentSimCommand() ) != ST_UNKNOWN );
1351 }
1352 
1353 
1354 void SIM_PLOT_FRAME::menuAddSignalsUpdate( wxUpdateUIEvent& event )
1355 {
1356  event.Enable( m_simFinished );
1357 }
1358 
1359 
1360 void SIM_PLOT_FRAME::menuProbeUpdate( wxUpdateUIEvent& event )
1361 {
1362  event.Enable( m_simFinished );
1363 }
1364 
1365 
1366 void SIM_PLOT_FRAME::menuTuneUpdate( wxUpdateUIEvent& event )
1367 {
1368  event.Enable( m_simFinished );
1369 }
1370 
1371 
1372 void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
1373 {
1374 }
1375 
1376 
1377 void SIM_PLOT_FRAME::onPlotClosed( wxAuiNotebookEvent& event )
1378 {
1379  if( m_workbook->GetPageCount() == 0 )
1380  {
1381  m_signals->ClearAll();
1382  m_cursors->ClearAll();
1383  }
1384  else
1385  {
1386  updateSignalList();
1387  wxCommandEvent dummy;
1388  onCursorUpdate( dummy );
1389  }
1390 }
1391 
1392 
1393 void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
1394 {
1395  updateSignalList();
1396  wxCommandEvent dummy;
1397  onCursorUpdate( dummy );
1398 }
1399 
1400 
1401 void SIM_PLOT_FRAME::onPlotDragged( wxAuiNotebookEvent& event )
1402 {
1403 }
1404 
1405 
1406 void SIM_PLOT_FRAME::onSignalDblClick( wxMouseEvent& event )
1407 {
1408  // Remove signal from the plot panel when double clicked
1409  long idx = m_signals->GetFocusedItem();
1410 
1411  if( idx != wxNOT_FOUND )
1412  removePlot( m_signals->GetItemText( idx, 0 ) );
1413 }
1414 
1415 
1416 void SIM_PLOT_FRAME::onSignalRClick( wxListEvent& event )
1417 {
1418  int idx = event.GetIndex();
1419 
1420  if( idx != wxNOT_FOUND )
1421  m_signals->Select( idx );
1422 
1423  idx = m_signals->GetFirstSelected();
1424 
1425  if( idx != wxNOT_FOUND )
1426  {
1427  const wxString& netName = m_signals->GetItemText( idx, 0 );
1428  SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
1429  m_signals->PopupMenu( &ctxMenu );
1430  }
1431 }
1432 
1433 
1434 void SIM_PLOT_FRAME::onWorkbookModified( wxCommandEvent& event )
1435 {
1436  updateTitle();
1437 }
1438 
1439 
1440 void SIM_PLOT_FRAME::onWorkbookClrModified( wxCommandEvent& event )
1441 {
1442  updateTitle();
1443 }
1444 
1445 
1446 void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
1447 {
1448  if( m_simulator->IsRunning() )
1449  StopSimulation();
1450  else
1451  StartSimulation();
1452 }
1453 
1454 
1455 void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
1456 {
1457  SIM_PANEL_BASE* plotPanelWindow = getCurrentPlotWindow();
1458 
1459  if( !m_settingsDlg )
1460  m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
1461 
1462  // Initial processing is required to e.g. display a list of power sources
1464 
1465  if( !m_exporter->ProcessNetlist( NET_ALL_FLAGS ) )
1466  {
1467  DisplayErrorMessage( this, _( "There were errors during netlist export, aborted." ) );
1468  return;
1469  }
1470 
1471  if( m_workbook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
1472  m_settingsDlg->SetSimCommand( m_workbook->GetSimCommand( plotPanelWindow ) );
1473 
1474  if( m_settingsDlg->ShowModal() == wxID_OK )
1475  {
1476  wxString oldCommand;
1477 
1478  if( m_workbook->GetPageIndex( plotPanelWindow ) != wxNOT_FOUND )
1479  oldCommand = m_workbook->GetSimCommand( plotPanelWindow );
1480  else
1481  oldCommand = wxString();
1482 
1483  wxString newCommand = m_settingsDlg->GetSimCommand();
1484  SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
1485 
1486  // If it is a new simulation type, open a new plot
1487  // For the DC sim, check if sweep source type has changed (char 4 will contain 'v',
1488  // 'i', 'r' or 't'.
1489  if( !plotPanelWindow
1490  || ( plotPanelWindow && plotPanelWindow->GetType() != newSimType )
1491  || ( newSimType == ST_DC
1492  && oldCommand.Lower().GetChar( 4 ) != newCommand.Lower().GetChar( 4 ) ) )
1493  {
1494  plotPanelWindow = NewPlotPanel( newCommand );
1495  }
1496  else
1497  {
1498  // Update simulation command in the current plot
1499  m_workbook->SetSimCommand( plotPanelWindow, newCommand );
1500  }
1501 
1502  m_simulator->Init();
1503  }
1504 }
1505 
1506 
1507 void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event )
1508 {
1509  wxCHECK_RET( m_simFinished, "No simulation results available" );
1510 
1511  SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
1512 
1513  if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() )
1514  {
1515  DisplayInfoMessage( this, _( "You need to run plot-providing simulation first." ) );
1516  return;
1517  }
1518 
1519  DIALOG_SIGNAL_LIST dialog( this, m_exporter.get() );
1520  dialog.ShowModal();
1521 }
1522 
1523 
1524 void SIM_PLOT_FRAME::onProbe( wxCommandEvent& event )
1525 {
1526  wxCHECK_RET( m_simFinished, "No simulation results available" );
1527 
1528  if( m_schematicFrame == nullptr )
1529  return;
1530 
1532  m_schematicFrame->Raise();
1533 }
1534 
1535 
1536 void SIM_PLOT_FRAME::onTune( wxCommandEvent& event )
1537 {
1538  wxCHECK_RET( m_simFinished, "No simulation results available" );
1539 
1540  if( m_schematicFrame == nullptr )
1541  return;
1542 
1544  m_schematicFrame->Raise();
1545 }
1546 
1547 
1548 void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event )
1549 {
1550  class NETLIST_VIEW_DIALOG : public DIALOG_SHIM
1551  {
1552  public:
1553  enum
1554  {
1555  MARGIN_LINE_NUMBERS
1556  };
1557 
1558  void onClose( wxCloseEvent& evt )
1559  {
1560  wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
1561  }
1562 
1563  NETLIST_VIEW_DIALOG( wxWindow* parent, wxString source) :
1564  DIALOG_SHIM( parent, wxID_ANY, "SPICE Netlist",
1565  wxDefaultPosition, wxDefaultSize,
1566  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
1567  {
1568  wxStyledTextCtrl* text = new wxStyledTextCtrl( this, wxID_ANY );
1569  text->SetMinSize( wxSize( 600, 400 ) );
1570 
1571  text->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
1572  text->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
1573  text->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
1574  text->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
1575 
1576  wxFont fixedFont = KIUI::GetMonospacedUIFont();
1577 
1578  for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
1579  text->StyleSetFont( i, fixedFont );
1580 
1581  text->StyleClearAll(); // Addresses a bug in wx3.0 where styles are not correctly set
1582 
1583  text->SetWrapMode( wxSTC_WRAP_WORD );
1584 
1585  text->SetText( source );
1586 
1587  text->SetLexer( wxSTC_LEX_SPICE );
1588 
1589  wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1590  sizer->Add( text, 1, wxEXPAND );
1591  SetSizer( sizer );
1592 
1593  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ),
1594  nullptr, this );
1595 
1596  finishDialogSettings();
1597  }
1598  };
1599 
1600  if( m_schematicFrame == nullptr || m_simulator == nullptr )
1601  return;
1602 
1603  NETLIST_VIEW_DIALOG dlg( this, m_simulator->GetNetlist() );
1604  dlg.ShowModal();
1605 }
1606 
1607 
1608 bool SIM_PLOT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
1609 {
1610  if( m_workbook->IsModified() )
1611  {
1612  wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
1613 
1614  if( filename.GetName().IsEmpty() )
1615  {
1616  if( Prj().GetProjectName().IsEmpty() )
1617  filename.SetFullName( wxT( "noname.wbk" ) );
1618  else
1619  filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
1620  }
1621 
1622  wxString fullFilename = filename.GetFullName();
1623  wxString msg = _( "Save changes to '%s' before closing?" );
1624 
1625  return HandleUnsavedChanges( this, wxString::Format( msg, fullFilename ),
1626  [&]() -> bool
1627  {
1628  return saveWorkbook( Prj().AbsolutePath( fullFilename ) );
1629  } );
1630  }
1631 
1632  return true;
1633 }
1634 
1635 
1637 {
1638  if( m_simulator->IsRunning() )
1639  m_simulator->Stop();
1640 
1641  // Cancel a running simProbe or simTune tool
1643 
1644  SaveSettings( config() );
1645  Destroy();
1646 }
1647 
1648 
1649 void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
1650 {
1651  wxSize size = m_cursors->GetClientSize();
1652  SIM_PLOT_PANEL* plotPanel = GetCurrentPlot();
1653  m_cursors->ClearAll();
1654 
1655  if( !plotPanel )
1656  return;
1657 
1659  m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL);
1660 
1661  // Fill the signals listctrl
1662  m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
1663  const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT,
1664  size.x / 4 );
1665 
1666  wxString labelY1 = plotPanel->GetLabelY1();
1667  wxString labelY2 = plotPanel->GetLabelY2();
1668  wxString labelY;
1669 
1670  if( !labelY2.IsEmpty() )
1671  labelY = labelY1 + " / " + labelY2;
1672  else
1673  labelY = labelY1;
1674 
1675  const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 );
1676 
1677  // Update cursor values
1678  int itemidx = 0;
1679 
1680  for( const auto& trace : plotPanel->GetTraces() )
1681  {
1682  if( CURSOR* cursor = trace.second->GetCursor() )
1683  {
1684  // Find the right icon color in list.
1685  // It is the icon used in m_signals list for the same trace
1686  long iconColor = m_signals->FindItem( -1, trace.first );
1687 
1688  const wxRealPoint coords = cursor->GetCoords();
1689  long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor );
1690  m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() );
1691  m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() );
1692  }
1693  }
1694 }
1695 
1696 
1697 void SIM_PLOT_FRAME::onSimStarted( wxCommandEvent& aEvent )
1698 {
1699  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( BITMAPS::sim_stop ) );
1700  SetCursor( wxCURSOR_ARROWWAIT );
1701 }
1702 
1703 
1704 void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
1705 {
1706  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( BITMAPS::sim_run ) );
1707  SetCursor( wxCURSOR_ARROW );
1708 
1709  SIM_TYPE simType = m_exporter->GetSimType();
1710 
1711  if( simType == ST_UNKNOWN )
1712  return;
1713 
1714  SIM_PANEL_BASE* plotPanelWindow = getCurrentPlotWindow();
1715 
1716  if( !plotPanelWindow || plotPanelWindow->GetType() != simType )
1717  plotPanelWindow = NewPlotPanel( m_exporter->GetUsedSimCommand() );
1718 
1719  if( m_simulator->IsRunning() )
1720  return;
1721 
1722  // If there are any signals plotted, update them
1723  if( SIM_PANEL_BASE::IsPlottable( simType ) )
1724  {
1725  SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelWindow );
1726  wxCHECK_RET( plotPanel, "not a SIM_PLOT_PANEL" );
1727 
1728  struct TRACE_DESC
1729  {
1730  wxString m_name;
1732  wxString m_param;
1733  };
1734 
1735  std::vector<struct TRACE_DESC> traceInfo;
1736 
1737  // Get information about all the traces on the plot, remove and add again
1738  for( auto& trace : plotPanel->GetTraces() )
1739  {
1740  struct TRACE_DESC placeholder;
1741  placeholder.m_name = trace.second->GetName();
1742  placeholder.m_type = trace.second->GetType();
1743  placeholder.m_param = trace.second->GetParam();
1744 
1745  traceInfo.push_back( placeholder );
1746  }
1747 
1748  for( auto& trace : traceInfo )
1749  {
1750  if( !updatePlot( trace.m_name, trace.m_type, trace.m_param, plotPanel ) )
1751  removePlot( trace.m_name );
1752  }
1753 
1754  updateSignalList();
1755  plotPanel->GetPlotWin()->UpdateAll();
1756  plotPanel->ResetScales();
1757  }
1758  else if( simType == ST_OP )
1759  {
1760  m_simConsole->AppendText( _( "\n\nSimulation results:\n\n" ) );
1761  m_simConsole->SetInsertionPointEnd();
1762 
1763  for( const auto& vec : m_simulator->AllPlots() )
1764  {
1765  std::vector<double> val_list = m_simulator->GetRealPlot( vec, 1 );
1766 
1767  if( val_list.size() == 0 ) // The list of values can be empty!
1768  continue;
1769 
1770  double val = val_list.at( 0 );
1771  wxString outLine, signal;
1772  SIM_PLOT_TYPE type = m_exporter->VectorToSignal( vec, signal );
1773 
1774  const size_t tab = 25; //characters
1775  size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
1776 
1777  outLine.Printf( wxT( "%s%s" ),
1778  ( signal + wxT( ":" ) ).Pad( padding, wxUniChar( ' ' ) ),
1779  SPICE_VALUE( val ).ToSpiceString() );
1780 
1781  outLine.Append( type == SPT_CURRENT ? "A\n" : "V\n" );
1782 
1783  m_simConsole->AppendText( outLine );
1784  m_simConsole->SetInsertionPointEnd();
1785 
1786  // @todo display calculated values on the schematic
1787  }
1788  }
1789 
1790  m_simFinished = true;
1791 }
1792 
1793 
1794 void SIM_PLOT_FRAME::onSimUpdate( wxCommandEvent& aEvent )
1795 {
1796  if( m_simulator->IsRunning() )
1797  StopSimulation();
1798 
1799  if( GetCurrentPlot() != m_lastSimPlot )
1800  {
1801  // We need to rerun simulation, as the simulator currently stores
1802  // results for another plot
1803  StartSimulation();
1804  }
1805  else
1806  {
1807  // Incremental update
1808  m_simConsole->Clear();
1809 
1810  // Do not export netlist, it is already stored in the simulator
1811  applyTuners();
1812  m_simulator->Run();
1813  }
1814 }
1815 
1816 
1817 void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
1818 {
1819  m_simConsole->AppendText( aEvent.GetString() + "\n" );
1820  m_simConsole->SetInsertionPointEnd();
1821 }
1822 
1823 
1825  SIM_PLOT_FRAME* aPlotFrame ) :
1826  m_signal( aSignal ),
1827  m_plotFrame( aPlotFrame )
1828 {
1830 
1831  AddMenuItem( this, HIDE_SIGNAL, _( "Hide Signal" ), _( "Erase the signal from plot screen" ),
1832  KiBitmap( BITMAPS::trash ) );
1833 
1834  TRACE* trace = plot->GetTrace( m_signal );
1835 
1836  if( trace->HasCursor() )
1837  AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
1838  else
1839  AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
1840 
1841  Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ),
1842  nullptr, this );
1843 }
1844 
1845 
1847 {
1848  SIM_PLOT_PANEL* plot = m_plotFrame->GetCurrentPlot();
1849 
1850  switch( aEvent.GetId() )
1851  {
1852  case HIDE_SIGNAL:
1853  m_plotFrame->removePlot( m_signal );
1854  break;
1855 
1856  case SHOW_CURSOR:
1857  plot->EnableCursor( m_signal, true );
1858  break;
1859 
1860  case HIDE_CURSOR:
1861  plot->EnableCursor( m_signal, false );
1862  break;
1863  }
1864 }
1865 
1866 
1867 wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
1868 wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
1869 
1870 wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
1871 wxDEFINE_EVENT( EVT_SIM_FINISHED, wxCommandEvent );
Field Reference of part, i.e. "IC21".
void onAddSignal(wxCommandEvent &event)
#define ID_MENU_PROBE_SIGNALS
#define ID_SAVE_AS_IMAGE
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:230
void ZoomOut(const wxPoint &centerPoint=wxDefaultPosition)
Zoom out current view and refresh display.
Definition: mathplot.cpp:2127
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:49
bool saveWorkbook(const wxString &aPath)
Save plot settings to a file.
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:239
wxString ToSpiceString() const
Return string value in Spice format (e.g.
void SetKiway(wxWindow *aDest, KIWAY *aKiway)
It is only used for debugging, since "this" is not a wxWindow*.
wxToolBarToolBase * m_toolProbe
void setIconsForMenuItems()
Give icons to menuitems of the main menubar.
void onSimStarted(wxCommandEvent &aEvent)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:53
void RemoveTuner(TUNER_SLIDER *aTuner, bool aErase=true)
Remove an existing tuner.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
bool GetPlotBgOpt() const
wxImageList * m_signalsIconColorList
SIM_PLOT_TYPE operator|(SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond)
void onPlotChanged(wxAuiNotebookEvent &event) override
void onPlotDragged(wxAuiNotebookEvent &event) override
SIM_PLOT_FRAME * m_parent
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:292
void EnableMouseWheelPan(bool enabled)
Enable/disable trackpad friendly panning (2-axis scroll wheel)
Definition: mathplot.h:1220
virtual APP_SETTINGS_BASE * config() const
Returns the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void menuWhiteBackground(wxCommandEvent &event) override
void SetSimCommand(SIM_PANEL_BASE *aPlotPanel, const wxString &aSimCommand)
Definition: sim_workbook.h:56
void onSignalDblClick(wxMouseEvent &event) override
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:677
void SaveProjectSettings() override
Save changes to the project settings to the project (.pro) file.
bool SetSimCommand(const wxString &aCommand)
virtual void SaveSettings(APP_SETTINGS_BASE *aCfg)
Save common frame parameters to a configuration data file.
mpWindow * GetPlotWin() const
This file is part of the common library.
wxSplitterWindow * m_splitterSignals
bool HasCursor() const
void onPlotClosed(wxAuiNotebookEvent &event) override
wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmap &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
Definition: bitmap.cpp:257
SIM_PANEL_BASE * NewPlotPanel(wxString aSimCommand)
Create a new plot panel for a given simulation type and adds it to the main notebook.
int m_splitterPlotAndConsoleSashPosition
void menuZoomFit(wxCommandEvent &event) override
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:145
Structure to represent a schematic symbol in the Spice simulation.
void initWorkbook()
Load the currently active workbook stored in the project settings.
wxFont GetMonospacedUIFont()
Definition: ui_common.cpp:85
bool AddPage(wxWindow *aPage, const wxString &aCaption, bool aSelect=false, const wxBitmap &aBitmap=wxNullBitmap)
const std::vector< double > & GetDataX() const
bool canCloseWindow(wxCloseEvent &aEvent) override
std::list< TUNER_SLIDER * > m_tuners
static TOOL_ACTION cancelInteractive
Definition: actions.h:62
void doCloseWindow() override
Class SIM_PLOT_FRAME_BASE.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
WINDOW_SETTINGS * GetWindowSettings(APP_SETTINGS_BASE *aCfg) override
Return a pointer to the window settings for this frame.
void menuNewPlot(wxCommandEvent &aEvent) override
void applyTuners()
Apply component values specified using tuner sliders to the current netlist.
SIM_PLOT_PANEL * GetCurrentPlot() const
Return the currently opened plot panel (or NULL if there is none).
wxString getDefaultPath()
Return the default path to be used in file browser dialog.
void AddVoltagePlot(const wxString &aNetName)
Add a voltage plot for a given net name.
void AddCurrentPlot(const wxString &aDeviceName, const wxString &aParam)
Add a current plot for a particular device.
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:383
#define ID_MENU_WHITE_BG
std::shared_ptr< SPICE_SIMULATOR_SETTINGS > & GetSimulatorSettings()
Schematic editor (Eeschema) main window.
wxString CsvFileWildcard()
wxString getDefaultFilename()
Return the default filename (with extension) to be used in file browser dialog.
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:82
bool DeleteAllPages() override
void onWorkbookModified(wxCommandEvent &event)
void onSimUpdate(wxCommandEvent &aEvent)
bool updatePlot(const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam, SIM_PLOT_PANEL *aPlotPanel)
Update plot in a particular SIM_PLOT_PANEL.
void menuOpenWorkbook(wxCommandEvent &event) override
void menuShowGrid(wxCommandEvent &event) override
void menuZoomIn(wxCommandEvent &event) override
void UpdateTunerValue(SCH_SYMBOL *aSymbol, int aId, const wxString &aValue)
Safely update a field of the associated symbol without dereferencing the symbol.
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:70
void menuZoomOut(wxCommandEvent &event) override
SIM_THREAD_REPORTER * m_reporter
List of currently displayed tuners.
void OnSimStateChange(SPICE_SIMULATOR *aObject, SIM_STATE aNewState) override
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
std::shared_ptr< SPICE_SIMULATOR > m_simulator
void menuProbeUpdate(wxUpdateUIEvent &event) override
#define ID_SAVE_AS_CSV
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:64
wxString GetLabelY1() const
wxSplitterWindow * m_splitterTuneValues
static bool IsPlottable(SIM_TYPE aSimType)
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
void AddTuner(SCH_SYMBOL *aSymbol)
Add a tuner for a symbol.
void menuSaveCsv(wxCommandEvent &event) override
void onPlotClose(wxAuiNotebookEvent &event) override
void StartSimulation(const wxString &aSimCommand=wxEmptyString)
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:269
bool IsModified() const
Definition: sim_workbook.h:68
SCH_EDIT_FRAME * m_schematicFrame
void UpdateAll()
Refresh display.
Definition: mathplot.cpp:2403
bool AddTrace(SIM_PLOT_PANEL *aPlotPanel, const wxString &aTitle, const wxString &aName, int aPoints, const double *aX, const double *aY, SIM_PLOT_TYPE aType, const wxString &aParam)
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
SIM_STATE
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
const wxString & GetSimCommand() const
void setSubWindowsSashSize()
Stores the common settings that are saved and loaded for each window / frame.
Definition: app_settings.h:81
wxString ToString() const
Return string value as when converting double to string (e.g.
SIM_PLOT_PANEL * m_lastSimPlot
imagelists used to add a small colored icon to signal names and cursors name, the same color as the c...
wxString GetLabelX() const
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:124
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:243
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:99
#define ID_MENU_SHOW_NETLIST
wxString GetLabelY2() const
static TOOL_ACTION simTune
Definition: ee_actions.h:216
static void FillDefaultColorList(bool aWhiteBg)
Fills m_colorList by a default set of colors.
void removePlot(const wxString &aPlotName)
Remove a plot with a specific title.
< Helper class to handle Spice way of expressing values (e.g. 10.5 Meg) Helper class to recognize Spi...
Definition: spice_value.h:34
wxString getCurrentSimCommand() const
wxSplitterWindow * m_splitterLeftRight
void ZoomIn(const wxPoint &centerPoint=wxDefaultPosition)
Zoom into current view and refresh display.
Definition: mathplot.cpp:2070
wxMenuItem * m_runSimulation
#define ID_MENU_TUNE_SIGNALS
void onSimReport(wxCommandEvent &aEvent)
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
SIM_TYPE
< Possible simulation types
Definition: sim_types.h:31
void menuTuneUpdate(wxUpdateUIEvent &event) override
void onSimFinished(wxCommandEvent &aEvent)
Interface to receive simulation updates from SPICE_SIMULATOR class.
SCHEMATIC & Schematic() const
Definition of file extensions used in Kicad.
void onShowNetlist(wxCommandEvent &event)
SIM_THREAD_REPORTER(SIM_PLOT_FRAME *aParent)
void menuShowLegendUpdate(wxUpdateUIEvent &event) override
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:260
void menuSaveWorkbookAs(wxCommandEvent &event) override
#define _(s)
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false)
Mark an item for refresh.
wxToolBarToolBase * m_toolAddSignals
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
SIM_PANEL_BASE * getCurrentPlotWindow() const
Return the currently opened plot panel (or NULL if there is none).
int m_splitterTuneValuesSashPosition
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
static std::shared_ptr< SPICE_SIMULATOR > CreateInstance(const std::string &aName)
void onSignalRClick(wxListEvent &event) override
void ResetScales()
Update trace line style.
void onWorkbookClrModified(wxCommandEvent &event)
#define ID_MENU_SHOW_LEGEND
void menuAddSignalsUpdate(wxUpdateUIEvent &event) override
SEVERITY
void menuShowLegend(wxCommandEvent &event) override
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
void onTune(wxCommandEvent &event)
wxToolBarToolBase * m_toolSimulate
wxString UnescapeString(const wxString &aSource)
void menuSaveImage(wxCommandEvent &event) override
#define ID_MENU_SET_SIMUL
wxString PngFileWildcard()
Implementing SIM_PLOT_FRAME_BASE.
bool loadWorkbook(const wxString &aPath)
Load plot settings from a file.
void SetNetlistExporter(NETLIST_EXPORTER_PSPICE_SIM *aExporter)
static wxString GetSpiceField(SPICE_FIELD aField, SCH_SYMBOL *aSymbol, unsigned aCtl)
Retrieve either the requested field value or the default value.
const wxString & GetSimCommand(const SIM_PANEL_BASE *aPlotPanel)
Definition: sim_workbook.h:62
void onCursorUpdate(wxCommandEvent &aEvent)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
bool DeleteTrace(SIM_PLOT_PANEL *aPlotPanel, const wxString &aName)
#define DISPLAY_LOAD_ERROR(fmt)
SIM_TYPE GetType() const
DIALOG_SIM_SETTINGS * m_settingsDlg
void Fit() override
Set view to fit global bounding box of all plot layers and refresh display.
Definition: mathplot.cpp:1910
const wxString What() const
Definition: ki_exception.h:57
void UpdatePlotColors()
Update plot colors
#define ID_MENU_ADD_SIGNAL
std::unique_ptr< NETLIST_EXPORTER_PSPICE_SIM > m_exporter
void updateNetlistExporter()
Reload the current schematic for the netlist exporter.
see class PGM_BASE
Schematic symbol object.
Definition: sch_symbol.h:78
void onSimulate(wxCommandEvent &event)
const char * name
Definition: DXF_plotter.cpp:56
void ClrModified()
SIGNAL_CONTEXT_MENU(const wxString &aSignal, SIM_PLOT_FRAME *aPlotFrame)
void onProbe(wxCommandEvent &event)
#define ID_MENU_SHOW_GRID
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
void menuSimulateUpdate(wxUpdateUIEvent &event) override
void updateSignalList()
Update the list of currently plotted signals.
#define ID_MENU_DOTTED
SIM_WORKBOOK * m_workbook
SIM_PLOT_TYPE getXAxisType(SIM_TYPE aType) const
Return X axis for a given simulation type.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
unsigned int m_plotNumber
int m_splitterSignalsSashPosition
void updateTitle()
Set the main window title bar text.
void menuShowDotted(wxCommandEvent &event) override
wxDEFINE_EVENT(EVT_SIM_UPDATE, wxCommandEvent)
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
const std::vector< double > & GetDataY() const
int m_splitterLeftRightSashPosition
void menuShowDottedUpdate(wxUpdateUIEvent &event) override
static TOOL_ACTION simProbe
Definition: ee_actions.h:215
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:128
const NETLIST_EXPORTER_PSPICE_SIM * GetExporter() const
Return the netlist exporter object used for simulations.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
Custom widget to handle quick component values modification and simulation on the fly.
Definition: tuner_slider.h:42
wxString WorkbookFileWildcard()
bool SaveScreenshot(const wxString &filename, wxBitmapType type=wxBITMAP_TYPE_BMP, wxSize imageSize=wxDefaultSize, bool fit=false)
Draw the window on a wxBitmap, then save it to a file.
Definition: mathplot.cpp:2630
const std::map< wxString, TRACE * > & GetTraces() const
wxSplitterWindow * m_splitterPlotAndConsole
void menuShowGridUpdate(wxUpdateUIEvent &event) override
const std::string WorkbookFileExtension
bool HasMessage() const override
Returns true if the reporter client is non-empty.
void menuSaveWorkbook(wxCommandEvent &event) override
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:307
SCH_FIELD * GetFieldById(int aFieldId)
Return a field in this symbol.
Definition: sch_symbol.cpp:689
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:414
SIM_PLOT_TYPE
Definition: sim_types.h:46
#define ID_MENU_RUN_SIM
Class is responsible for providing colors for traces on simulation plot.
Panel that was used as the most recent one for simulations.
void addPlot(const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam)
Add a new plot to the current panel.
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:154
void onSettings(wxCommandEvent &event)
void LoadSettings(APP_SETTINGS_BASE *aCfg) override
Load common frame parameters from a configuration file.
wxToolBarToolBase * m_toolTune
void onMenuEvent(wxMenuEvent &aEvent)
bool TraceShown(const wxString &aName) const
Cursor attached to a trace to follow its values:
virtual void LoadSettings(APP_SETTINGS_BASE *aCfg)
Load common frame parameters from a configuration file.
Special netlist exporter flavor that allows one to override simulation commands.
void updateTuners()
Filter out tuners for components that do not exist anymore.
Hold a translatable error message and may be used when throwing exceptions containing a translated er...
Definition: ki_exception.h:44
wxToolBarToolBase * m_toolSettings
HOLDER_TYPE m_type
Definition: kiway_holder.h:76
SIM_PLOT_FRAME(KIWAY *aKiway, wxWindow *aParent)