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 <tomasz.wlostowski@cern.ch>
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
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/stc/stc.h>
28 
29 #include <project/project_file.h>
30 #include <sch_edit_frame.h>
31 #include <eeschema_id.h>
32 #include <kiway.h>
33 #include <confirm.h>
34 #include <bitmaps.h>
36 #include <widgets/tuner_slider.h>
39 #include <pgm_base.h>
40 #include "ngspice.h"
41 #include "sim_plot_colors.h"
42 #include "sim_plot_frame.h"
43 #include "sim_plot_panel.h"
44 #include "spice_simulator.h"
45 #include "spice_reporter.h"
46 #include <menus_helpers.h>
47 #include <tool/tool_manager.h>
48 #include <tools/ee_actions.h>
49 #include <eeschema_settings.h>
50 #include <wx/ffile.h>
51 #include <wx/filedlg.h>
52 #include <dialog_shim.h>
53 
55 {
56  int res = (int) aFirst | (int) aSecond;
57 
58  return (SIM_PLOT_TYPE) res;
59 }
60 
61 
63 {
64 public:
66  m_parent( aParent )
67  {
68  }
69 
70  REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
71  {
72  wxCommandEvent* event = new wxCommandEvent( EVT_SIM_REPORT );
73  event->SetString( aText );
74  wxQueueEvent( m_parent, event );
75  return *this;
76  }
77 
78  bool HasMessage() const override
79  {
80  return false; // Technically "indeterminate" rather than false.
81  }
82 
83  void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override
84  {
85  wxCommandEvent* event = NULL;
86 
87  switch( aNewState )
88  {
89  case SIM_IDLE:
90  event = new wxCommandEvent( EVT_SIM_FINISHED );
91  break;
92 
93  case SIM_RUNNING:
94  event = new wxCommandEvent( EVT_SIM_STARTED );
95  break;
96 
97  default:
98  wxFAIL;
99  return;
100  }
101 
102  wxQueueEvent( m_parent, event );
103  }
104 
105 private:
107 };
108 
109 
110 // Store the path of saved workbooks during the session
112 
113 
114 SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
115  SIM_PLOT_FRAME_BASE( aParent ),
116  m_lastSimPlot( nullptr ),
117  m_plotNumber( 0 )
118 {
119  SetKiway( this, aKiway );
121 
123 
124  if( m_schematicFrame == NULL )
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  if( m_savedWorkbooksPath.IsEmpty() )
153 
154  m_reporter = new SIM_THREAD_REPORTER( this );
155  m_simulator->SetReporter( m_reporter );
156 
157  // the settings dialog will be created later, on demand.
158  // if created in the ctor, for some obscure reason, there is an issue
159  // on Windows: when open it, the simulator frame is sent to the background.
160  // instead of being behind the dialog frame (as it does)
161  m_settingsDlg = nullptr;
162 
164 
165  Connect( EVT_SIM_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onSimUpdate ), NULL, this );
166  Connect( EVT_SIM_REPORT, wxCommandEventHandler( SIM_PLOT_FRAME::onSimReport ), NULL, this );
167  Connect( EVT_SIM_STARTED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimStarted ), NULL, this );
168  Connect( EVT_SIM_FINISHED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimFinished ), NULL, this );
169  Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ),
170  NULL, this );
171 
172  // Toolbar buttons
173  m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
174  KiBitmap( BITMAPS::sim_run ), _( "Run Simulation" ), wxITEM_NORMAL );
175  m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _( "Add Signals" ),
176  KiBitmap( BITMAPS::sim_add_signal ), _( "Add signals to plot" ), wxITEM_NORMAL );
177  m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _( "Probe" ),
178  KiBitmap( BITMAPS::sim_probe ), _( "Probe signals on the schematic" ), wxITEM_NORMAL );
179  m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _( "Tune" ),
180  KiBitmap( BITMAPS::sim_tune ), _( "Tune component values" ), wxITEM_NORMAL );
181  m_toolSettings = m_toolBar->AddTool( wxID_ANY, _( "Sim Parameters" ),
182  KiBitmap( BITMAPS::config ), _( "Simulation parameters and settings" ), wxITEM_NORMAL );
183 
184  Connect( m_toolSimulate->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
185  wxCommandEventHandler( SIM_PLOT_FRAME::onSimulate ), NULL, this );
186  Connect( m_toolAddSignals->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
187  wxCommandEventHandler( SIM_PLOT_FRAME::onAddSignal ), NULL, this );
188  Connect( m_toolProbe->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
189  wxCommandEventHandler( SIM_PLOT_FRAME::onProbe ), NULL, this );
190  Connect( m_toolTune->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
191  wxCommandEventHandler( SIM_PLOT_FRAME::onTune ), NULL, this );
192  Connect( m_toolSettings->GetId(), wxEVT_COMMAND_TOOL_CLICKED,
193  wxCommandEventHandler( SIM_PLOT_FRAME::onSettings ), NULL, this );
194 
195  // Bind toolbar buttons event to existing menu event handlers, so they behave the same
196  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this,
197  m_runSimulation->GetId() );
198  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
199  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
200  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
201  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onShowNetlist, this,
202  m_showNetlist->GetId() );
203  Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
204 
205  m_toolBar->Realize();
206 
207 #ifndef wxHAS_NATIVE_TABART
208  // Non-native default tab art has ulgy gradients we don't want
209  m_plotNotebook->SetArtProvider( new wxAuiSimpleTabArt() );
210 #endif
211 
212  // Ensure new items are taken in account by sizers:
213  Layout();
214 
215  // resize the subwindows size. At least on Windows, calling wxSafeYield before
216  // resizing the subwindows forces the wxSplitWindows size events automatically generated
217  // by wxWidgets to be executed before our resize code.
218  // Otherwise, the changes made by setSubWindowsSashSize are overwritten by one these
219  // events
220  wxSafeYield();
222 
223  // Ensure the window is on top
224  Raise();
225 
226  initWorkbook();
227 }
228 
229 
231 {
232  m_simulator->SetReporter( nullptr );
233  delete m_reporter;
234  delete m_signalsIconColorList;
235 
236  if( m_settingsDlg )
237  m_settingsDlg->Destroy();
238 }
239 
240 
242 {
243  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
244  wxASSERT( cfg );
245 
246  if( cfg )
247  {
249 
250  // Read subwindows sizes (should be > 0 )
256  }
257 
259 
260  NGSPICE* currentSim = dynamic_cast<NGSPICE*>( m_simulator.get() );
261 
262  if( currentSim )
263  m_simulator->Settings() = project.m_SchematicSettings->m_NgspiceSimulatorSettings;
264 }
265 
266 
268 {
269  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
270  wxASSERT( cfg );
271 
272  if( cfg )
273  {
275 
276  cfg->m_Simulator.plot_panel_width = m_splitterLeftRight->GetSashPosition();
277  cfg->m_Simulator.plot_panel_height = m_splitterPlotAndConsole->GetSashPosition();
278  cfg->m_Simulator.signal_panel_height = m_splitterSignals->GetSashPosition();
279  cfg->m_Simulator.cursors_panel_height = m_splitterTuneValues->GetSashPosition();
281  }
282 
283  if( !m_isNonUserClose ) // If we're exiting the project has already been released.
284  {
286 
287  if( project.m_SchematicSettings )
288  project.m_SchematicSettings->m_NgspiceSimulatorSettings->SaveToFile();
289 
290  if( m_schematicFrame )
292  }
293 }
294 
295 
297 {
298  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( aCfg );
299  wxASSERT( cfg );
300 
301  return cfg ? &cfg->m_Simulator.window : nullptr;
302 }
303 
304 
306 {
307  m_workbook = std::make_unique<SIM_WORKBOOK>();
308 
309  if( !m_simulator->Settings()->GetWorkbookFilename().IsEmpty() )
310  {
311  wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
312  filename.SetPath( Prj().GetProjectPath() );
313 
314  if( !loadWorkbook( filename.GetFullPath() ) )
315  {
316  // Empty the workbook filename to prevent error messages from appearing again
317  m_simulator->Settings()->SetWorkbookFilename( "" );
318  }
319  }
320 }
321 
322 
324 {
325  wxFileName filename = Prj().AbsolutePath(
326  m_simulator->Settings()->GetWorkbookFilename() );
327 
328  bool readOnly = false;
329  bool unsaved = false;
330 
331  if( filename.IsOk() && filename.FileExists() )
332  readOnly = !filename.IsFileWritable();
333  else
334  unsaved = true;
335 
336  wxString title;
337 
338  if( m_workbook->IsModified() )
339  title = wxT( "*" ) + filename.GetName();
340  else
341  title = filename.GetName();
342 
343  if( readOnly )
344  title += wxS( " " ) + _( "[Read Only]" );
345 
346  if( unsaved )
347  title += wxS( " " ) + _( "[Unsaved]" );
348 
349  title += wxT( " \u2014 " ) + _( "Spice Simulator" );
350 
351  SetTitle( title );
352 }
353 
354 
356 {
357  // We need to keep track of the plot panel positions
358  for( unsigned int i = 0; i < m_plotNotebook->GetPageCount(); i++ )
359  m_workbook->SetPlotPanelPosition(
360  dynamic_cast<SIM_PANEL_BASE*>( m_plotNotebook->GetPage( i ) ), i );
361 }
362 
363 
365 {
366  updateTitle();
367 }
368 
369 
370 // A small helper struct to handle bitmaps initialisation in menus
372 {
373  int m_MenuId;
375 };
376 
377 
379 {
380  // Give icons to menuitems of the main menubar
381  BM_MENU_INIT_ITEM bm_list[]
382  {
383  // File menu:
384  { wxID_NEW, BITMAPS::simulator },
385  { wxID_OPEN, BITMAPS::directory_open },
386  { wxID_SAVE, BITMAPS::save },
389  { wxID_CLOSE, BITMAPS::exit },
390 
391  // simulator menu:
398 
399  // View menu
400  { wxID_ZOOM_IN, BITMAPS::zoom_in },
401  { wxID_ZOOM_OUT, BITMAPS::zoom_out },
402  { wxID_ZOOM_FIT, BITMAPS::zoom_fit_in_page },
407 
408  { 0, BITMAPS::INVALID_BITMAP } // Sentinel
409  };
410 
411  // wxMenuItems are already created and attached to the m_mainMenu wxMenuBar.
412  // A problem is the fact setting bitmaps in wxMenuItems after they are attached
413  // to a wxMenu do not work in all cases.
414  // So the trick is:
415  // Remove the wxMenuItem from its wxMenu
416  // Set the bitmap
417  // Insert the modified wxMenuItem to its previous place
418  for( int ii = 0; bm_list[ii].m_MenuId; ++ii )
419  {
420  wxMenuItem* item = m_mainMenu->FindItem( bm_list[ii].m_MenuId );
421 
422  if( !item || ( bm_list[ii].m_Bitmap == BITMAPS::INVALID_BITMAP ) )
423  continue;
424 
425  wxMenu* menu = item->GetMenu();
426 
427  // Calculate the initial index of item inside the wxMenu parent.
428  wxMenuItemList& mlist = menu->GetMenuItems();
429  int mpos = mlist.IndexOf( item );
430 
431  if( mpos >= 0 ) // Should be always the case
432  {
433  // Modify the bitmap
434  menu->Remove( item );
435  AddBitmapToMenuItem( item, KiBitmap( bm_list[ii].m_Bitmap ) );
436 
437  // Insert item to its the initial index
438  menu->Insert( mpos, item );
439  }
440  }
441 }
442 
443 
445 {
448 
451 
454 
457 }
458 
459 
460 void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
461 {
462  STRING_FORMATTER formatter;
463 
464  if( !m_settingsDlg )
465  m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
466 
467  m_simConsole->Clear();
469 
470  if( aSimCommand.IsEmpty() )
471  {
472  SIM_PANEL_BASE* plotPanel = currentPlotWindow();
473 
474  if( plotPanel && m_workbook->HasPlotPanel( plotPanel ) )
475  m_exporter->SetSimCommand( plotPanel->GetSimCommand() );
476  }
477  else
478  {
479  m_exporter->SetSimCommand( aSimCommand );
480  }
481 
482  if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) )
483  {
484  DisplayErrorMessage( this, _( "There were errors during netlist export, aborted." ) );
485  return;
486  }
487 
488  if( m_exporter->GetSimType() == ST_UNKNOWN )
489  {
490  DisplayInfoMessage( this, _( "You need to select the simulation settings first." ) );
491  return;
492  }
493 
494  m_simulator->LoadNetlist( formatter.GetString() );
495  updateTuners();
496  applyTuners();
497  m_simulator->Run();
498 }
499 
500 
502 {
503  m_simulator->Stop();
504 }
505 
506 
508 {
509  return m_simulator ? m_simulator->IsRunning() : false;
510 }
511 
512 
514 {
515  SIM_PANEL_BASE* plotPanel = nullptr;
517 
518  if( SIM_PANEL_BASE::IsPlottable( simType ) )
519  {
520  SIM_PLOT_PANEL* panel;
521  panel = new SIM_PLOT_PANEL( aSimCommand, m_plotNotebook, this, wxID_ANY );
522 
524  Pgm().GetCommonSettings()->m_Input.scroll_modifier_zoom != 0 );
525 
526  plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
527  }
528  else
529  {
530  SIM_NOPLOT_PANEL* panel;
531  panel = new SIM_NOPLOT_PANEL( aSimCommand, m_plotNotebook, wxID_ANY );
532  plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
533  }
534 
535  wxString pageTitle( m_simulator->TypeToName( simType, true ) );
536  pageTitle.Prepend( wxString::Format( _( "Plot%u - " ), (unsigned int) ++m_plotNumber ) );
537 
538  m_workbook->AddPlotPanel( plotPanel );
539 
540  m_plotNotebook->AddPage( dynamic_cast<wxWindow*>( plotPanel ), pageTitle, true );
541 
542  updateFrame();
543  return plotPanel;
544 }
545 
546 
547 void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
548 {
549  addPlot( aNetName, SPT_VOLTAGE, "V" );
550 }
551 
552 
553 void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam )
554 {
555  addPlot( aDeviceName, SPT_CURRENT, aParam );
556 }
557 
558 
560 {
561  SIM_PANEL_BASE* plotPanel = currentPlotWindow();
562 
563  if( !plotPanel )
564  return;
565 
566  // For now limit the tuner tool to RLC components
567  char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aSymbol, 0 )[0];
568 
569  if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR
570  && primitiveType != SP_INDUCTOR )
571  return;
572 
573  const wxString componentName = aSymbol->GetField( REFERENCE_FIELD )->GetText();
574 
575  // Do not add multiple instances for the same component
576  auto tunerIt = std::find_if( m_tuners.begin(), m_tuners.end(), [&]( const TUNER_SLIDER* t )
577  {
578  return t->GetComponentName() == componentName;
579  }
580  );
581 
582  if( tunerIt != m_tuners.end() )
583  return; // We already have it
584 
585  try
586  {
587  TUNER_SLIDER* tuner = new TUNER_SLIDER( this, m_tunePanel, aSymbol );
588  m_tuneSizer->Add( tuner );
589  m_tuners.push_back( tuner );
590  m_tunePanel->Layout();
591  }
592  catch( const KI_PARAM_ERROR& e )
593  {
594  // Sorry, no bonus
595  DisplayErrorMessage( nullptr, e.What() );
596  }
597 }
598 
599 
600 void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
601 {
602  if( aErase )
603  m_tuners.remove( aTuner );
604 
605  aTuner->Destroy();
606  m_tunePanel->Layout();
607 }
608 
609 
611 {
612  SIM_PANEL_BASE* curPage = currentPlotWindow();
613 
614  return ( ( !curPage || curPage->GetType() == ST_UNKNOWN ) ?
615  nullptr :
616  dynamic_cast<SIM_PLOT_PANEL*>( curPage ) );
617 }
618 
619 
621 {
622  return m_exporter.get();
623 }
624 
625 
626 std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& SIM_PLOT_FRAME::GetSimulatorSettings()
627 {
628  wxASSERT( m_simulator->Settings() );
629 
630  return m_simulator->Settings();
631 }
632 
633 
634 void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam )
635 {
636  SIM_TYPE simType = m_exporter->GetSimType();
637 
638  if( simType == ST_UNKNOWN )
639  {
640  m_simConsole->AppendText( _( "Error: simulation type not defined!\n" ) );
641  m_simConsole->SetInsertionPointEnd();
642  return;
643  }
644  else if( !SIM_PANEL_BASE::IsPlottable( simType ) )
645  {
646  m_simConsole->AppendText( _( "Error: simulation type doesn't support plotting!\n" ) );
647  m_simConsole->SetInsertionPointEnd();
648  return;
649  }
650 
651  // Create a new plot if the current one displays a different type
652  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
653 
654  if( !plotPanel || plotPanel->GetType() != simType )
655  plotPanel =
656  dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( m_exporter->GetUsedSimCommand() ) );
657 
658  wxASSERT( plotPanel );
659 
660  if( !plotPanel ) // Something is wrong
661  return;
662 
663  bool updated = false;
664  SIM_PLOT_TYPE xAxisType = GetXAxisType( simType );
665 
666  if( xAxisType == SPT_LIN_FREQUENCY || xAxisType == SPT_LOG_FREQUENCY )
667  {
668  int baseType = aType & ~( SPT_AC_MAG | SPT_AC_PHASE );
669 
670  // Add two plots: magnitude & phase
671  updated |=
672  updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_MAG ), aParam, plotPanel );
673  updated |= updatePlot( aName, ( SIM_PLOT_TYPE )( baseType | SPT_AC_PHASE ), aParam,
674  plotPanel );
675  }
676  else
677  {
678  updated = updatePlot( aName, aType, aParam, plotPanel );
679  }
680 
681  if( updated )
682  {
684  }
685 }
686 
687 
688 void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
689 {
690  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
691 
692  if( !plotPanel )
693  return;
694 
695  if( aErase )
696  m_workbook->RemoveTrace( plotPanel, aPlotName );
697 
698  wxASSERT( plotPanel->TraceShown( aPlotName ) );
699  plotPanel->DeleteTrace( aPlotName );
700  plotPanel->GetPlotWin()->Fit();
701 
703  wxCommandEvent dummy;
705  updateFrame();
706 }
707 
708 
710 {
712 
713  if( m_settingsDlg )
715 }
716 
717 
718 bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam,
719  SIM_PLOT_PANEL* aPanel )
720 {
721  SIM_TYPE simType = m_exporter->GetSimType();
722  wxString spiceVector = m_exporter->ComponentToVector( aName, aType, aParam );
723 
724  if( !SIM_PANEL_BASE::IsPlottable( simType ) )
725  {
726  // There is no plot to be shown
727  m_simulator->Command( wxString::Format( "print %s", spiceVector ).ToStdString() );
728 
729  return false;
730  }
731 
732  // First, handle the x axis
733  wxString xAxisName( m_simulator->GetXAxis( simType ) );
734 
735  if( xAxisName.IsEmpty() )
736  return false;
737 
738  auto data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
739  unsigned int size = data_x.size();
740 
741  if( data_x.empty() )
742  return false;
743 
744  std::vector<double> data_y;
745 
746  // Now, Y axis data
747  switch( m_exporter->GetSimType() )
748  {
749  case ST_AC:
750  wxASSERT_MSG( !( ( aType & SPT_AC_MAG ) && ( aType & SPT_AC_PHASE ) ),
751  "Cannot set both AC_PHASE and AC_MAG bits" );
752 
753  if( aType & SPT_AC_MAG )
754  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
755  else if( aType & SPT_AC_PHASE )
756  data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
757  else
758  wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
759 
760  break;
761 
762  case ST_NOISE:
763  case ST_DC:
764  case ST_TRANSIENT:
765  data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
766  break;
767 
768  default:
769  wxASSERT_MSG( false, "Unhandled plot type" );
770  return false;
771  }
772 
773  if( data_y.size() != size )
774  return false;
775 
776  // If we did a two-source DC analysis, we need to split the resulting vector and add traces
777  // for each input step
778  SPICE_DC_PARAMS source1, source2;
779 
780  if( m_exporter->GetSimType() == ST_DC &&
781  m_exporter->ParseDCCommand( m_exporter->GetUsedSimCommand(), &source1, &source2 ) )
782  {
783  if( !source2.m_source.IsEmpty() )
784  {
785  // Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step
786  SPICE_VALUE v = source2.m_vstart;
787  wxString name;
788 
789  size_t offset = 0;
790  size_t outer = ( size_t )( ( source2.m_vend - v ) / source2.m_vincrement ).ToDouble();
791  size_t inner = data_x.size() / ( outer + 1 );
792 
793  wxASSERT( data_x.size() % ( outer + 1 ) == 0 );
794 
795  for( size_t idx = 0; idx <= outer; idx++ )
796  {
797  name = wxString::Format( "%s (%s = %s V)", aName, source2.m_source, v.ToString() );
798 
799  std::vector<double> sub_x( data_x.begin() + offset,
800  data_x.begin() + offset + inner );
801  std::vector<double> sub_y( data_y.begin() + offset,
802  data_y.begin() + offset + inner );
803 
804  if( aPanel->AddTrace( name, inner, sub_x.data(), sub_y.data(), aType, aParam ) )
805  m_workbook->AddTrace( aPanel, name );
806 
807  v = v + source2.m_vincrement;
808  offset += inner;
809  }
810 
811  updateFrame();
812  return true;
813  }
814  }
815 
816  if( aPanel->AddTrace( aName, size, data_x.data(), data_y.data(), aType, aParam ) )
817  m_workbook->AddTrace( aPanel, aName );
818 
819  updateFrame();
820  return true;
821 }
822 
823 
825 {
826  m_signals->ClearAll();
827 
828  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
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 
843  m_signalsIconColorList = new wxImageList( isize, isize, false );
844  else
845  m_signalsIconColorList->RemoveAll();
846 
847  for( const auto& trace : CurrentPlot()->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 {
931  m_workbook->Clear();
932  m_plotNotebook->DeleteAllPages();
933 
934  wxTextFile file( aPath );
935 
936  if( !file.Open() )
937  {
938  updateFrame();
939  return false;
940  }
941 
942  long plotsCount;
943 
944  if( !file.GetFirstLine().ToLong( &plotsCount ) ) // GetFirstLine instead of GetNextLine
945  {
946  file.Close();
947  updateFrame();
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  updateFrame();
958  return false;
959  }
960 
961  wxString simCommand = file.GetNextLine();
962  NewPlotPanel( simCommand );
963  StartSimulation( simCommand );
964 
965  // Perform simulation, so plots can be added with values
966  do
967  {
968  wxThread::This()->Sleep( 50 );
969  }
970  while( IsSimulationRunning() );
971 
972  if( !file.GetNextLine().ToLong( &tracesCount ) )
973  {
974  updateFrame();
975  return false;
976  }
977 
978  for( long j = 0; j < tracesCount; ++j )
979  {
980  long traceType;
981  wxString name, param;
982 
983  if( !file.GetNextLine().ToLong( &traceType ) )
984  {
985  file.Close();
986  updateFrame();
987  return false;
988  }
989 
990  name = file.GetNextLine();
991  param = file.GetNextLine();
992 
993  if( name.IsEmpty() || param.IsEmpty() )
994  {
995  file.Close();
996  updateFrame();
997  return false;
998  }
999 
1000  addPlot( name, (SIM_PLOT_TYPE) traceType, param );
1001  }
1002  }
1003 
1004  file.Close();
1005 
1006  // Successfully loading a workbook does not count as modyfying it.
1007  m_workbook->ClrModified();
1008 
1009  updateFrame();
1010  return true;
1011 }
1012 
1013 
1014 bool SIM_PLOT_FRAME::saveWorkbook( const wxString& aPath )
1015 {
1016  wxString savePath = aPath;
1017 
1018  if( !savePath.Lower().EndsWith(".wbk") )
1019  savePath += ".wbk";
1020 
1021  wxTextFile file( savePath );
1022 
1023  if( file.Exists() )
1024  {
1025  if( !file.Open() )
1026  return false;
1027 
1028  file.Clear();
1029  }
1030  else
1031  {
1032  file.Create();
1033  }
1034 
1035  std::vector<const SIM_PANEL_BASE*> plotPanels = m_workbook->GetSortedPlotPanels();
1036 
1037  file.AddLine( wxString::Format( "%llu", plotPanels.size() ) );
1038 
1039  for( const SIM_PANEL_BASE*& plotPanel : plotPanels )
1040  {
1041  file.AddLine( wxString::Format( "%d", plotPanel->GetType() ) );
1042  file.AddLine( plotPanel->GetSimCommand() );
1043 
1044  const SIM_PLOT_PANEL* panel = dynamic_cast<const SIM_PLOT_PANEL*>( plotPanel );
1045 
1046  if( !panel )
1047  file.AddLine( wxString::Format( "%llu", 0ull ) );
1048  else
1049  {
1050  file.AddLine( wxString::Format( "%llu", panel->GetTraces().size() ) );
1051 
1052  for( const auto& trace : panel->GetTraces() )
1053  {
1054  file.AddLine( wxString::Format( "%d", trace.second->GetType() ) );
1055  file.AddLine( trace.second->GetName() );
1056  file.AddLine( trace.second->GetParam() );
1057  }
1058  }
1059  }
1060 
1061  bool res = file.Write();
1062  file.Close();
1063 
1064  // Store the filename of the last saved workbook. It will be used to restore the simulation if
1065  // the frame is closed and then opened again.
1066  m_simulator->Settings()->SetWorkbookFilename( wxFileName( savePath ).GetFullName() );
1067  m_workbook->ClrModified();
1068  updateFrame();
1069 
1070  return res;
1071 }
1072 
1073 
1075 {
1076  switch( aType )
1077  {
1078  case ST_AC:
1079  return SPT_LIN_FREQUENCY;
1081 
1082  case ST_DC:
1083  return SPT_SWEEP;
1084 
1085  case ST_TRANSIENT:
1086  return SPT_TIME;
1087 
1088  default:
1089  wxASSERT_MSG( false, "Unhandled simulation type" );
1090  return (SIM_PLOT_TYPE) 0;
1091  }
1092 }
1093 
1094 
1095 void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
1096 {
1097  SIM_TYPE type = m_exporter->GetSimType();
1098 
1099  if( SIM_PANEL_BASE::IsPlottable( type ) )
1100  {
1101  NewPlotPanel( m_exporter->GetUsedSimCommand() );
1102  updateFrame();
1103  }
1104 }
1105 
1106 
1107 void SIM_PLOT_FRAME::menuOpenWorkbook( wxCommandEvent& event )
1108 {
1109  wxFileDialog openDlg( this, _( "Open simulation workbook" ), m_savedWorkbooksPath, "",
1110  WorkbookFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
1111 
1112  if( openDlg.ShowModal() == wxID_CANCEL )
1113  return;
1114 
1115  m_savedWorkbooksPath = openDlg.GetDirectory();
1116 
1117  if( !loadWorkbook( openDlg.GetPath() ) )
1118  DisplayErrorMessage( this, _( "There was an error while opening the workbook file" ) );
1119 }
1120 
1121 
1122 void SIM_PLOT_FRAME::menuSaveWorkbook( wxCommandEvent& event )
1123 {
1124  if( !m_workbook->IsModified() )
1125  return;
1126 
1127  wxString filename = m_simulator->Settings()->GetWorkbookFilename();
1128 
1129  if( filename.IsEmpty() )
1130  {
1131  menuSaveWorkbookAs( event );
1132  return;
1133  }
1134 
1135  if ( !saveWorkbook( Prj().AbsolutePath( m_simulator->Settings()->GetWorkbookFilename() ) ) )
1136  DisplayErrorMessage( this, _( "There was an error while saving the workbook file" ) );
1137 }
1138 
1139 
1140 void SIM_PLOT_FRAME::menuSaveWorkbookAs( wxCommandEvent& event )
1141 {
1142  wxString defaultFilename = m_simulator->Settings()->GetWorkbookFilename();
1143 
1144  if( defaultFilename.IsEmpty() )
1145  defaultFilename = Prj().GetProjectName() + wxT( ".wbk" );
1146 
1147  wxFileDialog saveAsDlg( this, _( "Save Simulation Workbook As" ), m_savedWorkbooksPath,
1148  defaultFilename, WorkbookFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1149 
1150  if( saveAsDlg.ShowModal() == wxID_CANCEL )
1151  return;
1152 
1153  m_savedWorkbooksPath = saveAsDlg.GetDirectory();
1154 
1155  if( !saveWorkbook( saveAsDlg.GetPath() ) )
1156  DisplayErrorMessage( this, _( "There was an error while saving the workbook file" ) );
1157 }
1158 
1159 
1160 void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
1161 {
1162  if( !CurrentPlot() )
1163  return;
1164 
1165  wxFileDialog saveDlg( this, _( "Save Plot as Image" ), "", "",
1166  PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1167 
1168  if( saveDlg.ShowModal() == wxID_CANCEL )
1169  return;
1170 
1171  CurrentPlot()->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
1172 }
1173 
1174 
1175 void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
1176 {
1177  if( !CurrentPlot() )
1178  return;
1179 
1180  const wxChar SEPARATOR = ';';
1181 
1182  wxFileDialog saveDlg( this, _( "Save Plot Data" ), "", "",
1183  CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1184 
1185  if( saveDlg.ShowModal() == wxID_CANCEL )
1186  return;
1187 
1188  wxFFile out( saveDlg.GetPath(), "wb" );
1189  bool timeWritten = false;
1190 
1191  for( const auto& t : CurrentPlot()->GetTraces() )
1192  {
1193  const TRACE* trace = t.second;
1194 
1195  if( !timeWritten )
1196  {
1197  out.Write( wxString::Format( "Time%c", SEPARATOR ) );
1198 
1199  for( double v : trace->GetDataX() )
1200  out.Write( wxString::Format( "%g%c", v, SEPARATOR ) );
1201 
1202  out.Write( "\r\n" );
1203  timeWritten = true;
1204  }
1205 
1206  out.Write( wxString::Format( "%s%c", t.first, SEPARATOR ) );
1207 
1208  for( double v : trace->GetDataY() )
1209  out.Write( wxString::Format( "%g%c", v, SEPARATOR ) );
1210 
1211  out.Write( "\r\n" );
1212  }
1213 
1214  out.Close();
1215 }
1216 
1217 
1218 void SIM_PLOT_FRAME::menuZoomIn( wxCommandEvent& event )
1219 {
1220  if( CurrentPlot() )
1221  CurrentPlot()->GetPlotWin()->ZoomIn();
1222 }
1223 
1224 
1225 void SIM_PLOT_FRAME::menuZoomOut( wxCommandEvent& event )
1226 {
1227  if( CurrentPlot() )
1228  CurrentPlot()->GetPlotWin()->ZoomOut();
1229 }
1230 
1231 
1232 void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event )
1233 {
1234  if( CurrentPlot() )
1235  CurrentPlot()->GetPlotWin()->Fit();
1236 }
1237 
1238 
1239 void SIM_PLOT_FRAME::menuShowGrid( wxCommandEvent& event )
1240 {
1242 
1243  if( plot )
1244  plot->ShowGrid( !plot->IsGridShown() );
1245 }
1246 
1247 
1248 void SIM_PLOT_FRAME::menuShowGridUpdate( wxUpdateUIEvent& event )
1249 {
1251 
1252  event.Check( plot ? plot->IsGridShown() : false );
1253 }
1254 
1255 
1256 void SIM_PLOT_FRAME::menuShowLegend( wxCommandEvent& event )
1257 {
1259 
1260  if( plot )
1261  plot->ShowLegend( !plot->IsLegendShown() );
1262 }
1263 
1264 
1265 void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event )
1266 {
1268  event.Check( plot ? plot->IsLegendShown() : false );
1269 }
1270 
1271 
1272 void SIM_PLOT_FRAME::menuShowDotted( wxCommandEvent& event )
1273 {
1275 
1276  if( plot )
1277  plot->SetDottedCurrentPhase( !plot->GetDottedCurrentPhase() );
1278 }
1279 
1280 
1281 void SIM_PLOT_FRAME::menuShowDottedUpdate( wxUpdateUIEvent& event )
1282 {
1284 
1285  event.Check( plot ? plot->GetDottedCurrentPhase() : false );
1286 }
1287 
1288 
1289 void SIM_PLOT_FRAME::menuWhiteBackground( wxCommandEvent& event )
1290 {
1292 
1293  // Rebuild the color list to plot traces
1295 
1296  // Now send changes to all SIM_PLOT_PANEL
1297  for( size_t page = 0; page < m_plotNotebook->GetPageCount(); page++ )
1298  {
1299  wxWindow* curPage = m_plotNotebook->GetPage( page );
1300 
1301  // ensure it is truly a plot panel and not the (zero plots) placeholder
1302  // which is only SIM_PLOT_PANEL_BASE
1303  SIM_PLOT_PANEL* panel = dynamic_cast<SIM_PLOT_PANEL*>( curPage );
1304 
1305  if( panel != nullptr )
1306  {
1307  panel->UpdatePlotColors();
1308  }
1309  }
1310 }
1311 
1312 
1313 void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
1314 {
1315  int idx = event.GetSelection();
1316 
1317  if( idx == wxNOT_FOUND )
1318  return;
1319 
1320  SIM_PANEL_BASE* plotPanel =
1321  dynamic_cast<SIM_PANEL_BASE*>( m_plotNotebook->GetPage( idx ) );
1322 
1323  m_workbook->RemovePlotPanel( plotPanel );
1324  wxCommandEvent dummy;
1325  onCursorUpdate( dummy );
1326 }
1327 
1328 
1329 void SIM_PLOT_FRAME::onPlotClosed( wxAuiNotebookEvent& event )
1330 {
1331  updateWorkbook();
1332  updateFrame();
1333 }
1334 
1335 
1336 void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
1337 {
1338  updateSignalList();
1339  wxCommandEvent dummy;
1340  onCursorUpdate( dummy );
1341 
1342  updateWorkbook();
1343  updateFrame();
1344 }
1345 
1346 
1347 void SIM_PLOT_FRAME::onPlotDragged( wxAuiNotebookEvent& event )
1348 {
1349  updateWorkbook();
1350  updateFrame();
1351 }
1352 
1353 
1354 void SIM_PLOT_FRAME::onSignalDblClick( wxMouseEvent& event )
1355 {
1356  // Remove signal from the plot panel when double clicked
1357  long idx = m_signals->GetFocusedItem();
1358 
1359  if( idx != wxNOT_FOUND )
1360  removePlot( m_signals->GetItemText( idx, 0 ) );
1361 }
1362 
1363 
1364 void SIM_PLOT_FRAME::onSignalRClick( wxListEvent& event )
1365 {
1366  int idx = event.GetIndex();
1367 
1368  if( idx != wxNOT_FOUND )
1369  m_signals->Select( idx );
1370 
1371  idx = m_signals->GetFirstSelected();
1372 
1373  if( idx != wxNOT_FOUND )
1374  {
1375  const wxString& netName = m_signals->GetItemText( idx, 0 );
1376  SIGNAL_CONTEXT_MENU ctxMenu( netName, this );
1377  m_signals->PopupMenu( &ctxMenu );
1378  }
1379 }
1380 
1381 
1382 void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
1383 {
1384  if( IsSimulationRunning() )
1385  StopSimulation();
1386  else
1387  StartSimulation();
1388 }
1389 
1390 
1391 void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
1392 {
1393  SIM_PANEL_BASE* plotPanelWindow = currentPlotWindow();
1394 
1395  if( !m_settingsDlg )
1396  m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
1397 
1398  // Initial processing is required to e.g. display a list of power sources
1400 
1401  if( !m_exporter->ProcessNetlist( NET_ALL_FLAGS ) )
1402  {
1403  DisplayErrorMessage( this, _( "There were errors during netlist export, aborted." ) );
1404  return;
1405  }
1406 
1407  if( m_workbook->HasPlotPanel( plotPanelWindow ) )
1408  m_settingsDlg->SetSimCommand( plotPanelWindow->GetSimCommand() );
1409 
1410  if( m_settingsDlg->ShowModal() == wxID_OK )
1411  {
1412  wxString oldCommand;
1413 
1414  if( m_workbook->HasPlotPanel( plotPanelWindow ) )
1415  oldCommand = plotPanelWindow->GetSimCommand();
1416  else
1417  oldCommand = wxString();
1418 
1419  wxString newCommand = m_settingsDlg->GetSimCommand();
1420  SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
1421 
1422  // If it is a new simulation type, open a new plot
1423  // For the DC sim, check if sweep source type has changed (char 4 will contain 'v',
1424  // 'i', 'r' or 't'.
1425  if( !plotPanelWindow
1426  || ( plotPanelWindow && plotPanelWindow->GetType() != newSimType )
1427  || ( newSimType == ST_DC
1428  && oldCommand.Lower().GetChar( 4 ) != newCommand.Lower().GetChar( 4 ) ) )
1429  {
1430  plotPanelWindow = NewPlotPanel( newCommand );
1431  }
1432  else
1433  {
1434  // Update simulation command in the current plot
1435  plotPanelWindow->SetSimCommand( newCommand );
1436  }
1437 
1438  m_simulator->Init();
1439  updateFrame();
1440  }
1441 }
1442 
1443 
1444 void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event )
1445 {
1446  if( IsSimulationRunning() )
1447  {
1448  DisplayInfoMessage( this, _( "Simulator is running. Try later" ) );
1449  return;
1450  }
1451 
1452  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1453 
1454  if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() )
1455  {
1456  DisplayInfoMessage( this, _( "You need to run plot-providing simulation first." ) );
1457  return;
1458  }
1459 
1460  DIALOG_SIGNAL_LIST dialog( this, m_exporter.get() );
1461  dialog.ShowModal();
1462 }
1463 
1464 
1465 void SIM_PLOT_FRAME::onProbe( wxCommandEvent& event )
1466 {
1467  if( m_schematicFrame == NULL )
1468  return;
1469 
1470  if( IsSimulationRunning() )
1471  {
1472  DisplayInfoMessage( this, _( "Simulator is running. Try later" ) );
1473  return;
1474  }
1475 
1477  m_schematicFrame->Raise();
1478 }
1479 
1480 
1481 void SIM_PLOT_FRAME::onTune( wxCommandEvent& event )
1482 {
1483  if( m_schematicFrame == NULL )
1484  return;
1485 
1487  m_schematicFrame->Raise();
1488 }
1489 
1490 
1491 void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event )
1492 {
1493  class NETLIST_VIEW_DIALOG : public DIALOG_SHIM
1494  {
1495  public:
1496  enum
1497  {
1498  MARGIN_LINE_NUMBERS
1499  };
1500 
1501  void onClose( wxCloseEvent& evt )
1502  {
1503  EndModal( GetReturnCode() );
1504  }
1505 
1506  NETLIST_VIEW_DIALOG( wxWindow* parent, wxString source) :
1507  DIALOG_SHIM( parent, wxID_ANY, "SPICE Netlist",
1508  wxDefaultPosition, wxDefaultSize,
1509  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
1510  {
1511  wxStyledTextCtrl* text = new wxStyledTextCtrl( this, wxID_ANY );
1512  text->SetMinSize( wxSize( 600, 400 ) );
1513 
1514  text->SetMarginWidth( MARGIN_LINE_NUMBERS, 50 );
1515  text->StyleSetForeground( wxSTC_STYLE_LINENUMBER, wxColour( 75, 75, 75 ) );
1516  text->StyleSetBackground( wxSTC_STYLE_LINENUMBER, wxColour( 220, 220, 220 ) );
1517  text->SetMarginType( MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER );
1518 
1519  wxFont font = wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_TELETYPE,
1520  wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString );
1521  text->StyleSetFont( wxSTC_STYLE_DEFAULT, font );
1522 
1523  text->SetWrapMode( wxSTC_WRAP_WORD );
1524 
1525  text->SetText( source );
1526 
1527  text->StyleClearAll();
1528  text->SetLexer( wxSTC_LEX_SPICE );
1529 
1530  wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
1531  sizer->Add( text, 1, wxEXPAND );
1532  SetSizer( sizer );
1533 
1534  Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ), NULL,
1535  this );
1536 
1537  finishDialogSettings();
1538  }
1539  };
1540 
1541  if( m_schematicFrame == NULL || m_simulator == NULL )
1542  return;
1543 
1544  NETLIST_VIEW_DIALOG dlg( this, m_simulator->GetNetlist() );
1545  dlg.ShowModal();
1546 }
1547 
1548 
1549 bool SIM_PLOT_FRAME::canCloseWindow( wxCloseEvent& aEvent )
1550 {
1551  if( m_workbook->IsModified() )
1552  {
1553  wxFileName filename = m_simulator->Settings()->GetWorkbookFilename();
1554 
1555  if( filename.GetName().IsEmpty() )
1556  filename.SetFullName( Prj().GetProjectName() + wxT( ".wbk" ) );
1557 
1558  wxString msg = _( "Save changes to \"%s\" before closing?" );
1559 
1560  return HandleUnsavedChanges( this, wxString::Format( msg, filename.GetFullName() ),
1561  [&]()->bool { return saveWorkbook( Prj().AbsolutePath ( filename.GetFullName() ) ); } );
1562  }
1563 
1564  return true;
1565 }
1566 
1567 
1569 {
1570  if( IsSimulationRunning() )
1571  m_simulator->Stop();
1572 
1573  // Cancel a running simProbe or simTune tool
1575 
1576  SaveSettings( config() );
1577  Destroy();
1578 }
1579 
1580 
1581 void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
1582 {
1583  wxSize size = m_cursors->GetClientSize();
1584  SIM_PLOT_PANEL* plotPanel = CurrentPlot();
1585  m_cursors->ClearAll();
1586 
1587  if( !plotPanel )
1588  return;
1589 
1591  m_cursors->SetImageList(m_signalsIconColorList, wxIMAGE_LIST_SMALL);
1592 
1593  // Fill the signals listctrl
1594  m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
1595  const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT,
1596  size.x / 4 );
1597 
1598  wxString labelY1 = plotPanel->GetLabelY1();
1599  wxString labelY2 = plotPanel->GetLabelY2();
1600  wxString labelY;
1601 
1602  if( !labelY2.IsEmpty() )
1603  labelY = labelY1 + " / " + labelY2;
1604  else
1605  labelY = labelY1;
1606 
1607  const long Y_COL = m_cursors->AppendColumn( labelY, wxLIST_FORMAT_LEFT, size.x / 4 );
1608 
1609  // Update cursor values
1610  int itemidx = 0;
1611 
1612  for( const auto& trace : plotPanel->GetTraces() )
1613  {
1614  if( CURSOR* cursor = trace.second->GetCursor() )
1615  {
1616  // Find the right icon color in list.
1617  // It is the icon used in m_signals list for the same trace
1618  long iconColor = m_signals->FindItem( -1, trace.first );
1619 
1620  const wxRealPoint coords = cursor->GetCoords();
1621  long idx = m_cursors->InsertItem( itemidx++, trace.first, iconColor );
1622  m_cursors->SetItem( idx, X_COL, SPICE_VALUE( coords.x ).ToSpiceString() );
1623  m_cursors->SetItem( idx, Y_COL, SPICE_VALUE( coords.y ).ToSpiceString() );
1624  }
1625  }
1626 }
1627 
1628 
1629 void SIM_PLOT_FRAME::onSimStarted( wxCommandEvent& aEvent )
1630 {
1631  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( BITMAPS::sim_stop ) );
1632  SetCursor( wxCURSOR_ARROWWAIT );
1633 }
1634 
1635 
1636 void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
1637 {
1638  m_toolBar->SetToolNormalBitmap( ID_SIM_RUN, KiBitmap( BITMAPS::sim_run ) );
1639  SetCursor( wxCURSOR_ARROW );
1640 
1641  SIM_TYPE simType = m_exporter->GetSimType();
1642 
1643  if( simType == ST_UNKNOWN )
1644  return;
1645 
1646  SIM_PANEL_BASE* plotPanelWindow = currentPlotWindow();
1647 
1648  if( !plotPanelWindow || plotPanelWindow->GetType() != simType )
1649  plotPanelWindow = NewPlotPanel( m_exporter->GetUsedSimCommand() );
1650 
1651  if( IsSimulationRunning() )
1652  return;
1653 
1654  // If there are any signals plotted, update them
1655  if( SIM_PANEL_BASE::IsPlottable( simType ) )
1656  {
1657  SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelWindow );
1658  wxCHECK_RET( plotPanel, "not a SIM_PLOT_PANEL" );
1659 
1660  struct TRACE_DESC
1661  {
1663  wxString m_name;
1664 
1667 
1669  wxString m_param;
1670  };
1671 
1672  std::vector<struct TRACE_DESC> traceInfo;
1673 
1674  // Get information about all the traces on the plot, remove and add again
1675  for( auto& trace : plotPanel->GetTraces() )
1676  {
1677  struct TRACE_DESC placeholder;
1678  placeholder.m_name = trace.second->GetName();
1679  placeholder.m_type = trace.second->GetType();
1680  placeholder.m_param = trace.second->GetParam();
1681 
1682  traceInfo.push_back( placeholder );
1683  }
1684 
1685  for( auto& trace : traceInfo )
1686  {
1687  if( !updatePlot( trace.m_name, trace.m_type, trace.m_param, plotPanel ) )
1688  {
1689  removePlot( trace.m_name, false );
1690  m_workbook->RemoveTrace( plotPanel, trace.m_name );
1691  }
1692  }
1693 
1694  updateSignalList();
1695  plotPanel->GetPlotWin()->UpdateAll();
1696  plotPanel->ResetScales();
1697  updateFrame();
1698  }
1699  else if( simType == ST_OP )
1700  {
1701  m_simConsole->AppendText( _( "\n\nSimulation results:\n\n" ) );
1702  m_simConsole->SetInsertionPointEnd();
1703 
1704  for( const auto& vec : m_simulator->AllPlots() )
1705  {
1706  std::vector<double> val_list = m_simulator->GetRealPlot( vec, 1 );
1707 
1708  if( val_list.size() == 0 ) // The list of values can be empty!
1709  continue;
1710 
1711  double val = val_list.at( 0 );
1712  wxString outLine, signal;
1713  SIM_PLOT_TYPE type = m_exporter->VectorToSignal( vec, signal );
1714 
1715  const size_t tab = 25; //characters
1716  size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
1717 
1718  outLine.Printf( wxT( "%s%s" ), ( signal + wxT( ":" ) ).Pad( padding, wxUniChar( ' ' ) ),
1719  SPICE_VALUE( val ).ToSpiceString() );
1720 
1721  outLine.Append( type == SPT_CURRENT ? "A\n" : "V\n" );
1722 
1723  m_simConsole->AppendText( outLine );
1724  m_simConsole->SetInsertionPointEnd();
1725 
1726  // @todo display calculated values on the schematic
1727  }
1728  }
1729 }
1730 
1731 
1732 void SIM_PLOT_FRAME::onSimUpdate( wxCommandEvent& aEvent )
1733 {
1734  if( IsSimulationRunning() )
1735  StopSimulation();
1736 
1737  if( CurrentPlot() != m_lastSimPlot )
1738  {
1739  // We need to rerun simulation, as the simulator currently stores
1740  // results for another plot
1741  StartSimulation();
1742  }
1743  else
1744  {
1745  // Incremental update
1746  m_simConsole->Clear();
1747  // Do not export netlist, it is already stored in the simulator
1748  applyTuners();
1749  m_simulator->Run();
1750  }
1751 }
1752 
1753 
1754 void SIM_PLOT_FRAME::onSimReport( wxCommandEvent& aEvent )
1755 {
1756  m_simConsole->AppendText( aEvent.GetString() + "\n" );
1757  m_simConsole->SetInsertionPointEnd();
1758 }
1759 
1760 
1762  SIM_PLOT_FRAME* aPlotFrame ) :
1763  m_signal( aSignal ),
1764  m_plotFrame( aPlotFrame )
1765 {
1767 
1768  AddMenuItem( this, HIDE_SIGNAL, _( "Hide Signal" ),
1769  _( "Erase the signal from plot screen" ),
1770  KiBitmap( BITMAPS::trash ) );
1771 
1772  TRACE* trace = plot->GetTrace( m_signal );
1773 
1774  if( trace->HasCursor() )
1775  AddMenuItem( this, HIDE_CURSOR, _( "Hide Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
1776  else
1777  AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
1778 
1779  Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ),
1780  NULL, this );
1781 }
1782 
1783 
1785 {
1786  SIM_PLOT_PANEL* plot = m_plotFrame->CurrentPlot();
1787 
1788  switch( aEvent.GetId() )
1789  {
1790  case HIDE_SIGNAL:
1791  m_plotFrame->removePlot( m_signal );
1792  break;
1793 
1794  case SHOW_CURSOR:
1795  plot->EnableCursor( m_signal, true );
1796  break;
1797 
1798  case HIDE_CURSOR:
1799  plot->EnableCursor( m_signal, false );
1800  break;
1801  }
1802 }
1803 
1804 
1805 wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
1806 wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
1807 
1808 wxDEFINE_EVENT( EVT_SIM_STARTED, wxCommandEvent );
1809 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
void ZoomOut(const wxPoint &centerPoint=wxDefaultPosition)
Zoom out current view and refresh display.
Definition: mathplot.cpp:2273
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:207
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
A string to store the path of saved workbooks during a session.
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:265
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 onSignalDblClick(wxMouseEvent &event) override
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:665
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
SEVERITY
Definition: ui_common.h:83
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:254
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.
void updateFrame()
Update the frame to match the changes to the workbook.
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.
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:373
#define ID_MENU_WHITE_BG
std::shared_ptr< SPICE_SIMULATOR_SETTINGS > & GetSimulatorSettings()
Schematic editor (Eeschema) main window.
wxString CsvFileWildcard()
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:82
std::unique_ptr< SIM_WORKBOOK > m_workbook
List of currently displayed tuners.
void onSimUpdate(wxCommandEvent &aEvent)
void menuOpenWorkbook(wxCommandEvent &event) override
void menuShowGrid(wxCommandEvent &event) override
void menuZoomIn(wxCommandEvent &event) override
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:64
void menuZoomOut(wxCommandEvent &event) override
SIM_THREAD_REPORTER * m_reporter
Stores the data that can be preserved across simulator sessions.
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
#define ID_SAVE_AS_CSV
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:123
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.
SIM_PLOT_TYPE GetXAxisType(SIM_TYPE aType) const
Return X axis for a given simulation type.
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:271
wxAuiNotebook * m_plotNotebook
SCH_EDIT_FRAME * m_schematicFrame
bool DeleteTrace(const wxString &aName)
void UpdateAll()
Refresh display.
Definition: mathplot.cpp:2747
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:70
SIM_STATE
void updateWorkbook()
Update the workbook to match the changes in the frame.
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
void AddBitmapToMenuItem(wxMenuItem *aMenu, const wxBitmap &aImage)
Add a bitmap to a menuitem.
Definition: bitmap.cpp:240
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:99
#define NULL
#define ID_MENU_SHOW_NETLIST
wxString GetLabelY2() const
static TOOL_ACTION simTune
Definition: ee_actions.h:211
static void FillDefaultColorList(bool aWhiteBg)
Fills m_colorList by a default set of colors.
< Helper class to handle Spice way of expressing values (e.g. 10.5 Meg) Helper class to recognize Spi...
Definition: spice_value.h:34
wxSplitterWindow * m_splitterLeftRight
void ZoomIn(const wxPoint &centerPoint=wxDefaultPosition)
Zoom into current view and refresh display.
Definition: mathplot.cpp:2216
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.
void SetSimCommand(const wxString &aSimCommand)
SIM_TYPE
< Possible simulation types
Definition: sim_types.h:31
bool AddTrace(const wxString &aName, int aPoints, const double *aX, const double *aY, SIM_PLOT_TYPE aType, const wxString &aParam)
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:258
void menuSaveWorkbookAs(wxCommandEvent &event) override
#define _(s)
wxToolBarToolBase * m_toolAddSignals
Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
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)
SIM_PANEL_BASE * currentPlotWindow() const
Return the currently opened plot panel (or NULL if there is none).
const std::string & GetString()
Definition: richio.h:438
void onSignalRClick(wxListEvent &event) override
void ResetScales()
Update trace line style.
bool IsSimulationRunning()
#define ID_MENU_SHOW_LEGEND
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
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 m_savedWorkbooksPath
static wxString GetSpiceField(SPICE_FIELD aField, SCH_SYMBOL *aSymbol, unsigned aCtl)
Retrieve either the requested field value or the default value.
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
const wxString & GetSimCommand() const
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:2011
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:59
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
bool updatePlot(const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam, SIM_PLOT_PANEL *aPanel)
Update plot in a particular SIM_PLOT_PANEL.
void updateSignalList()
Update the list of currently plotted signals.
#define ID_MENU_DOTTED
unsigned int m_plotNumber
int m_splitterSignalsSashPosition
void updateTitle()
Set the main window title bar text.
SIM_PLOT_PANEL * CurrentPlot() const
Return the currently opened plot panel (or NULL if there is none).
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:210
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:129
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 removePlot(const wxString &aPlotName, bool aErase=true)
Remove a plot with a specific title.
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:2972
const std::map< wxString, TRACE * > & GetTraces() const
wxSplitterWindow * m_splitterPlotAndConsole
void menuShowGridUpdate(wxUpdateUIEvent &event) override
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:280
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:133
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)