KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_sim_model.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) 2022 Mikolaj Wielgus
5 * Copyright (C) 2022 CERN
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * https://www.gnu.org/licenses/gpl-3.0.html
21 * or you may search the http://www.gnu.org website for the version 3 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
27#include <dialog_sim_model.h>
28#include <sim/sim_property.h>
30#include <sim/sim_model.h>
31#include <sim/sim_model_ibis.h>
35#include <grid_tricks.h>
38#include <kiplatform/ui.h>
39#include <confirm.h>
40#include <string_utils.h>
41#include <locale_io.h>
42#include <wx/filedlg.h>
43#include <fmt/format.h>
44#include <sch_edit_frame.h>
47#include <wx/log.h>
48
50
51#define FORCE_UPDATE_PINS true
52
53
54bool equivalent( SIM_MODEL::DEVICE_T a, SIM_MODEL::DEVICE_T b )
55{
56 // A helper to handle SPICE's use of 'E' and 'H' for voltage sources and 'F' and 'G' for
57 // current sources
58 return a == b
59 || SIM_MODEL::DeviceInfo( a ).description == SIM_MODEL::DeviceInfo( b ).description;
60};
61
62
63template <typename T>
64DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, EDA_BASE_FRAME* aFrame, T& aSymbol,
65 std::vector<SCH_FIELD>& aFields ) :
66 DIALOG_SIM_MODEL_BASE( aParent ),
67 m_frame( aFrame ),
68 m_symbol( aSymbol ),
69 m_fields( aFields ),
70 m_libraryModelsMgr( &Prj() ),
71 m_builtinModelsMgr( &Prj() ),
72 m_prevModel( nullptr ),
73 m_curModelType( SIM_MODEL::TYPE::NONE ),
74 m_scintillaTricksCode( nullptr ),
75 m_scintillaTricksSubckt( nullptr ),
76 m_firstCategory( nullptr ),
77 m_prevParamGridSelection( nullptr ),
78 m_lastParamGridWidth( 0 )
79{
80 m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
82
83 for( SCH_PIN* pin : aSymbol.GetPins() )
84 {
85 // De Morgan conversions are equivalences, not additional items to simulate
86 if( !pin->GetParentSymbol()->HasAlternateBodyStyle() || pin->GetBodyStyle() < 2 )
87 m_sortedPartPins.push_back( pin );
88 }
89
90 std::sort( m_sortedPartPins.begin(), m_sortedPartPins.end(),
91 []( const SCH_PIN* lhs, const SCH_PIN* rhs )
92 {
93 // We sort by StrNumCmp because SIM_MODEL_BASE sorts with it too.
94 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
95 } );
96
97 m_waveformChoice->Clear();
98 m_deviceChoice->Clear();
99 m_deviceSubtypeChoice->Clear();
100
101 m_scintillaTricksCode = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
102 m_scintillaTricksSubckt = new SCINTILLA_TRICKS( m_subckt, wxT( "()" ), false );
103
104 m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
105
106 wxPropertyGrid* grid = m_paramGrid->GetGrid();
107
108 // In wx 3.0 the color will be wrong sometimes.
109 grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
110
111 grid->Bind( wxEVT_SET_FOCUS, &DIALOG_SIM_MODEL::onParamGridSetFocus, this );
112 grid->Bind( wxEVT_UPDATE_UI, &DIALOG_SIM_MODEL::onUpdateUI, this );
113
114 grid->DedicateKey( WXK_RETURN );
115 grid->DedicateKey( WXK_NUMPAD_ENTER );
116 grid->DedicateKey( WXK_UP );
117 grid->DedicateKey( WXK_DOWN );
118
119#if wxCHECK_VERSION( 3, 3, 0 )
120 grid->AddActionTrigger( wxPGKeyboardAction::Edit, WXK_RETURN );
121 grid->AddActionTrigger( wxPGKeyboardAction::NextProperty, WXK_RETURN );
122 grid->AddActionTrigger( wxPGKeyboardAction::Edit, WXK_NUMPAD_ENTER );
123 grid->AddActionTrigger( wxPGKeyboardAction::NextProperty, WXK_NUMPAD_ENTER );
124#else
125 grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_RETURN );
126 grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_RETURN );
127 grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_NUMPAD_ENTER );
128 grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_NUMPAD_ENTER );
129#endif
130
132 m_pinAssignmentsGrid->PushEventHandler( new GRID_TRICKS( m_pinAssignmentsGrid ) );
133
135
136 // Now all widgets have the size fixed, call FinishDialogSettings
138}
139
140
141template <typename T>
143{
144 // Disable all properties. This is necessary because some of their methods are called after
145 // destruction of DIALOG_SIM_MODEL, oddly. When disabled, they never access their models.
146 for( wxPropertyGridIterator it = m_paramGrid->GetIterator(); !it.AtEnd(); ++it )
147 {
148 SIM_PROPERTY* prop = dynamic_cast<SIM_PROPERTY*>( *it );
149
150 if( !prop )
151 continue;
152
153 prop->Disable();
154 }
155
156 // Delete the GRID_TRICKS.
157 m_pinAssignmentsGrid->PopEventHandler( true );
158
159 delete m_scintillaTricksCode;
160 delete m_scintillaTricksSubckt;
161}
162
163
164template <typename T>
166{
167 wxCommandEvent dummyEvent;
168 wxString deviceType;
169 wxString modelType;
170 wxString modelParams;
171 wxString pinMap;
172 bool storeInValue = false;
173
174 WX_STRING_REPORTER reporter;
175
176 auto setFieldValue =
177 [&]( const wxString& aFieldName, const wxString& aValue )
178 {
179 for( SCH_FIELD& field : m_fields )
180 {
181 if( field.GetName() == aFieldName )
182 {
183 field.SetText( aValue );
184 return;
185 }
186 }
187
188 m_fields.emplace_back( &m_symbol, -1, aFieldName );
189 m_fields.back().SetText( aValue );
190 };
191
192 // Infer RLC and VI models if they aren't specified
193 if( SIM_MODEL::InferSimModel( m_symbol, &m_fields, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
194 &deviceType, &modelType, &modelParams, &pinMap ) )
195 {
196 setFieldValue( SIM_DEVICE_FIELD, deviceType );
197
198 if( !modelType.IsEmpty() )
199 setFieldValue( SIM_DEVICE_SUBTYPE_FIELD, modelType );
200
201 setFieldValue( SIM_PARAMS_FIELD, modelParams );
202
203 setFieldValue( SIM_PINS_FIELD, pinMap );
204
205 storeInValue = true;
206
207 // In case the storeInValue checkbox is turned off (if it's left on then we'll overwrite
208 // this field with the actual value):
209 m_fields[ VALUE_FIELD ].SetText( wxT( "${SIM.PARAMS}" ) );
210 }
211
212 std::string libraryFilename = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::LIBRARY_FIELD );
213
214 if( libraryFilename != "" )
215 {
216 // The model is sourced from a library, optionally with instance overrides.
217 m_rbLibraryModel->SetValue( true );
218
219 if( !loadLibrary( libraryFilename, reporter ) )
220 {
221 if( reporter.HasMessage() )
222 m_infoBar->ShowMessage( reporter.GetMessages() );
223
224 m_libraryPathText->ChangeValue( libraryFilename );
225 m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, reporter );
226
227 m_libraryModelsMgr.CreateModel( nullptr, m_sortedPartPins, m_fields, reporter );
228
229 m_modelListBox->Append( _( "<unknown>" ) );
230 m_modelListBox->SetSelection( 0 );
231 }
232 else
233 {
234 std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
235 int modelIdx = m_modelListBox->FindString( modelName );
236
237 if( modelIdx == wxNOT_FOUND )
238 {
239 m_infoBar->ShowMessage( wxString::Format( _( "No model named '%s' in library." ),
240 modelName ) );
241
242 // Default to first item in library
243 m_modelListBox->SetSelection( 0 );
244 }
245 else
246 {
247 m_infoBar->Hide();
248 m_modelListBox->SetSelection( modelIdx );
249 }
250
251 m_curModelType = curModel().GetType();
252 }
253
254 if( isIbisLoaded() && ( m_modelListBox->GetSelection() >= 0 ) )
255 {
256 int idx = 0;
257 wxString sel = m_modelListBox->GetStringSelection();
258
259 if( m_modelListBoxEntryToLibraryIdx.contains( sel ) )
260 idx = m_modelListBoxEntryToLibraryIdx.at( sel );
261
262 auto ibismodel =
263 dynamic_cast<SIM_MODEL_IBIS*>( &m_libraryModelsMgr.GetModels()[idx].get() );
264
265 if( ibismodel )
266 {
267 onModelNameChoice( dummyEvent ); // refresh list of pins
268
269 int i = 0;
270
271 for( const std::pair<std::string, std::string>& strs : ibismodel->GetIbisPins() )
272 {
273 if( strs.first
275 {
276 auto ibisLibrary = static_cast<const SIM_LIBRARY_IBIS*>( library() );
277
278 ibismodel->ChangePin( *ibisLibrary, strs.first );
279 m_pinCombobox->SetSelection( static_cast<int>( i ) );
280 break;
281 }
282 i++;
283 }
284
285 if( i < static_cast<int>( ibismodel->GetIbisPins().size() ) )
286 {
287 onPinCombobox( dummyEvent ); // refresh list of models
288
289 m_pinModelCombobox->SetStringSelection(
291 }
292
294 {
295 ibismodel->SwitchSingleEndedDiff( true );
296 m_differentialCheckbox->SetValue( true );
297 }
298 else
299 {
300 ibismodel->SwitchSingleEndedDiff( false );
301 m_differentialCheckbox->SetValue( false );
302 }
303 }
304 }
305 }
306 else if( !SIM_MODEL::GetFieldValue( &m_fields, SIM_DEVICE_FIELD ).empty()
308 {
309 // The model is sourced from the instance.
310 m_rbBuiltinModel->SetValue( true );
311
312 reporter.Clear();
313 m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields, reporter );
314
315 if( reporter.HasMessage() )
316 DisplayErrorMessage( this, reporter.GetMessages() );
317 }
318
319 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
320 {
321 if( m_rbBuiltinModel->GetValue() && type == m_curModelType )
322 {
323 reporter.Clear();
324 m_builtinModelsMgr.CreateModel( m_fields, m_sortedPartPins, false, reporter );
325
326 if( reporter.HasMessage() )
327 {
328 DisplayErrorMessage( this, _( "Failed to read simulation model from fields." )
329 + wxT( "\n\n" ) + reporter.GetMessages() );
330 }
331 }
332 else
333 {
334 m_builtinModelsMgr.CreateModel( type, m_sortedPartPins, reporter );
335 }
336
337 SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType;
338
339 if( !m_curModelTypeOfDeviceType.count( deviceTypeT ) )
340 m_curModelTypeOfDeviceType[deviceTypeT] = type;
341 }
342
343 if( storeInValue )
344 curModel().SetIsStoredInValue( true );
345
346 m_saveInValueCheckbox->SetValue( curModel().IsStoredInValue() );
347
348 onRadioButton( dummyEvent );
349 return DIALOG_SIM_MODEL_BASE::TransferDataToWindow();
350}
351
352
353template <typename T>
355{
356 m_pinAssignmentsGrid->CommitPendingChanges();
357 m_paramGrid->GetGrid()->CommitChangesFromEditor();
358
359 if( !DIALOG_SIM_MODEL_BASE::TransferDataFromWindow() )
360 return false;
361
362 SIM_MODEL& model = curModel();
363 std::string path;
364 std::string name;
365
366 if( m_rbLibraryModel->GetValue() )
367 {
368 path = m_libraryPathText->GetValue();
369 wxFileName fn( path );
370
371 if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
372 path = fn.GetFullPath();
373
374 if( m_modelListBox->GetSelection() >= 0 )
375 name = m_modelListBox->GetStringSelection().ToStdString();
376 else if( dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( &model ) )
378 }
379
382
383 if( isIbisLoaded() )
384 {
385 int idx = 0;
386 wxString sel = m_modelListBox->GetStringSelection();
387
388 if( m_modelListBoxEntryToLibraryIdx.contains( sel ) )
389 idx = m_modelListBoxEntryToLibraryIdx.at( sel );
390
391 auto* ibismodel =
392 static_cast<SIM_MODEL_IBIS*>( &m_libraryModelsMgr.GetModels().at( idx ).get() );
393
394 if( ibismodel )
395 {
396 std::string pins;
397 std::string modelName = std::string( m_pinModelCombobox->GetValue().c_str() );
398 std::string differential;
399
400 if( m_pinCombobox->GetSelection() >= 0 )
401 pins = ibismodel->GetIbisPins().at( m_pinCombobox->GetSelection() ).first;
402
403 if( ibismodel->CanDifferential() && m_differentialCheckbox->GetValue() )
404 differential = "1";
405
409 }
410 }
411
412 if( model.GetType() == SIM_MODEL::TYPE::RAWSPICE )
413 {
414 if( m_modelNotebook->GetSelection() == 0 )
415 updateModelCodeTab( &model );
416
417 wxString code = m_codePreview->GetText().Trim( true ).Trim( false );
418 model.SetParamValue( "model", std::string( code.ToUTF8() ) );
419 }
420
421 model.SetIsStoredInValue( m_saveInValueCheckbox->GetValue() );
422
423 for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row )
424 {
425 wxString modelPinName = m_pinAssignmentsGrid->GetCellValue( row, PIN_COLUMN::MODEL );
426 wxString symbolPinName = m_sortedPartPins.at( row )->GetShownNumber();
427
428 model.AssignSymbolPinNumberToModelPin( getModelPinIndex( modelPinName ),
429 std::string( symbolPinName.ToUTF8() ) );
430 }
431
432 removeOrphanedPinAssignments( &model );
433
434 curModel().WriteFields( m_fields );
435
436 return true;
437}
438
439
440template <typename T>
442{
443 // always enable the library browser button -- it makes for fewer clicks if the user has a
444 // whole bunch of inferred passives that they want to specify library models for
445 m_browseButton->Enable();
446
447 // if we're in an undetermined state then enable everything for faster access
448 bool undetermined = !m_rbLibraryModel->GetValue() && !m_rbBuiltinModel->GetValue();
449 bool enableLibCtrls = m_rbLibraryModel->GetValue() || undetermined;
450 bool enableBuiltinCtrls = m_rbBuiltinModel->GetValue() || undetermined;
451
452 m_pathLabel->Enable( enableLibCtrls );
453 m_libraryPathText->Enable( enableLibCtrls );
454 m_modelNameLabel->Enable( enableLibCtrls );
455 m_modelFilter->Enable( enableLibCtrls && !isIbisLoaded() );
456 m_modelListBox->Enable( enableLibCtrls );
457 m_pinLabel->Enable( enableLibCtrls );
458 m_pinCombobox->Enable( enableLibCtrls );
459 m_differentialCheckbox->Enable( enableLibCtrls );
460 m_pinModelLabel->Enable( enableLibCtrls );
461 m_pinModelCombobox->Enable( enableLibCtrls );
462 m_waveformLabel->Enable( enableLibCtrls );
463 m_waveformChoice->Enable( enableLibCtrls );
464
465 m_deviceLabel->Enable( enableBuiltinCtrls );
466 m_deviceChoice->Enable( enableBuiltinCtrls );
467 m_deviceSubtypeLabel->Enable( enableBuiltinCtrls );
468 m_deviceSubtypeChoice->Enable( enableBuiltinCtrls );
469
470 SIM_MODEL* model = &curModel();
471
472 updateIbisWidgets( model );
473 updateBuiltinModelWidgets( model );
474 updateModelParamsTab( model );
475 updateModelCodeTab( model );
476 updatePinAssignments( model, model != m_prevModel );
477
478 std::string ref = SIM_MODEL::GetFieldValue( &m_fields, SIM_REFERENCE_FIELD );
479
480 m_modelPanel->Layout();
481 m_pinAssignmentsPanel->Layout();
482 m_parametersPanel->Layout();
483 m_codePanel->Layout();
484
485 SendSizeEvent( wxSEND_EVENT_POST );
486
487 m_prevModel = &curModel();
488}
489
490
491template <typename T>
493{
494 SIM_MODEL_IBIS* modelibis = isIbisLoaded() ? dynamic_cast<SIM_MODEL_IBIS*>( aModel )
495 : nullptr;
496
497 m_pinLabel->Show( isIbisLoaded() );
498 m_pinCombobox->Show( isIbisLoaded() );
499 m_pinModelLabel->Show( isIbisLoaded() );
500 m_pinModelCombobox->Show( isIbisLoaded() );
501 m_waveformLabel->Show( isIbisLoaded() );
502 m_waveformChoice->Show( isIbisLoaded() );
503
504 if( aModel != m_prevModel )
505 {
506 m_waveformChoice->Clear();
507
508 if( isIbisLoaded() )
509 {
510 for( SIM_MODEL::TYPE type : { SIM_MODEL::TYPE::KIBIS_DEVICE,
511 SIM_MODEL::TYPE::KIBIS_DRIVER_DC,
512 SIM_MODEL::TYPE::KIBIS_DRIVER_RECT,
513 SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS } )
514 {
515 SIM_MODEL::DEVICE_T deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
516 const std::string& deviceTypeDesc = SIM_MODEL::DeviceInfo( deviceType ).description;
517
518 if( deviceType == aModel->GetDeviceType()
519 || deviceTypeDesc == aModel->GetDeviceInfo().description )
520 {
521 m_waveformChoice->Append( SIM_MODEL::TypeInfo( type ).description );
522
523 if( type == aModel->GetType() )
524 m_waveformChoice->SetSelection( m_waveformChoice->GetCount() - 1 );
525 }
526 }
527 }
528 }
529
530 m_differentialCheckbox->Show( isIbisLoaded() && modelibis && modelibis->CanDifferential() );
531 m_modelNameLabel->SetLabel( isIbisLoaded() ? _( "Component:" ) : _( "Model:" ) );
532}
533
534
535template <typename T>
537{
538 // Change the Type choice to match the current device type.
539 if( aModel != m_prevModel )
540 {
541 m_deviceChoice->Clear();
542 m_deviceSubtypeChoice->Clear();
543
544 if( !m_rbLibraryModel->GetValue() )
545 {
546 for( SIM_MODEL::DEVICE_T deviceType : SIM_MODEL::DEVICE_T_ITERATOR() )
547 {
548 if( !SIM_MODEL::DeviceInfo( deviceType ).showInMenu )
549 continue;
550
551 m_deviceChoice->Append( SIM_MODEL::DeviceInfo( deviceType ).description );
552
553 if( equivalent( deviceType, aModel->GetDeviceType() ) )
554 m_deviceChoice->SetSelection( m_deviceChoice->GetCount() - 1 );
555 }
556
557 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
558 {
559 if( type == SIM_MODEL::TYPE::KIBIS_DEVICE
560 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_DC
561 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_RECT
562 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS )
563 {
564 continue;
565 }
566
567 SIM_MODEL::DEVICE_T deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
568 const std::string& deviceTypeDesc = SIM_MODEL::DeviceInfo( deviceType ).description;
569
570 if( deviceType == aModel->GetDeviceType()
571 || deviceTypeDesc == aModel->GetDeviceInfo().description )
572 {
573 m_deviceSubtypeChoice->Append( SIM_MODEL::TypeInfo( type ).description );
574
575 if( type == aModel->GetType() )
576 m_deviceSubtypeChoice->SetSelection( m_deviceSubtypeChoice->GetCount()
577 - 1 );
578 }
579 }
580 }
581
582 m_deviceSubtypeLabel->Show( m_deviceSubtypeChoice->GetCount() > 1 );
583 m_deviceSubtypeChoice->Show( m_deviceSubtypeChoice->GetCount() > 1 );
584 }
585
586 if( dynamic_cast<SIM_MODEL_RAW_SPICE*>( aModel ) )
587 m_modelNotebook->SetSelection( 1 );
588 else
589 m_modelNotebook->SetSelection( 0 );
590
591 if( aModel->HasPrimaryValue() )
592 {
593 const SIM_MODEL::PARAM& primary = aModel->GetParam( 0 );
594
595 m_saveInValueCheckbox->SetLabel( wxString::Format( _( "Save parameter '%s (%s)' in Value "
596 "field" ),
597 primary.info.description,
598 primary.info.name ) );
599 m_saveInValueCheckbox->Enable( true );
600 }
601 else
602 {
603 m_saveInValueCheckbox->SetLabel( _( "Save primary parameter in Value field" ) );
604 m_saveInValueCheckbox->SetValue( false );
605 m_saveInValueCheckbox->Enable( false );
606 }
607}
608
609
610template <typename T>
612{
613 if( aModel != m_prevModel )
614 {
615 // This wxPropertyGridManager column and header stuff has to be here because it segfaults in
616 // the constructor.
617
618 m_paramGridMgr->SetColumnCount( PARAM_COLUMN::END_ );
619
620 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::DESCRIPTION, _( "Parameter" ) );
621 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::UNIT, _( "Unit" ) );
622 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::DEFAULT, _( "Default" ) );
623 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::TYPE, _( "Type" ) );
624
625 m_paramGridMgr->ShowHeader();
626
627
628 m_paramGrid->Clear();
629
630 m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "Geometry" ) );
631 m_paramGrid->HideProperty( "Geometry" );
632
633 m_paramGrid->Append( new wxPropertyCategory( "AC" ) );
634 m_paramGrid->HideProperty( "AC" );
635
636 m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
637 m_paramGrid->HideProperty( "DC" );
638
639 m_paramGrid->Append( new wxPropertyCategory( "S-Parameters" ) );
640 m_paramGrid->HideProperty( "S-Parameters" );
641
642 m_paramGrid->Append( new wxPropertyCategory( "Capacitance" ) );
643 m_paramGrid->HideProperty( "Capacitance" );
644
645 m_paramGrid->Append( new wxPropertyCategory( "Temperature" ) );
646 m_paramGrid->HideProperty( "Temperature" );
647
648 m_paramGrid->Append( new wxPropertyCategory( "Noise" ) );
649 m_paramGrid->HideProperty( "Noise" );
650
651 m_paramGrid->Append( new wxPropertyCategory( "Distributed Quantities" ) );
652 m_paramGrid->HideProperty( "Distributed Quantities" );
653
654 m_paramGrid->Append( new wxPropertyCategory( "Waveform" ) );
655 m_paramGrid->HideProperty( "Waveform" );
656
657 m_paramGrid->Append( new wxPropertyCategory( "Limiting Values" ) );
658 m_paramGrid->HideProperty( "Limiting Values" );
659
660 m_paramGrid->Append( new wxPropertyCategory( "Advanced" ) );
661 m_paramGrid->HideProperty( "Advanced" );
662
663 m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
664 m_paramGrid->HideProperty( "Flags" );
665
666 m_paramGrid->CollapseAll();
667
668 for( int i = 0; i < aModel->GetParamCount(); ++i )
669 addParamPropertyIfRelevant( aModel, i );
670
671 m_paramGrid->CollapseAll();
672 m_paramGrid->Expand( "AC" );
673 m_paramGrid->Expand( "Waveform" );
674 }
675
676 adjustParamGridColumns( m_paramGrid->GetGrid()->GetSize().GetX(), true );
677
678 // Set all properties to default colors.
679 // Update properties in models that have autofill.
680 for( wxPropertyGridIterator it = m_paramGrid->GetIterator(); !it.AtEnd(); ++it )
681 {
682 wxColour bgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetBgCol();
683 wxColour fgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetFgCol();
684
685 for( int col = 0; col < m_paramGridMgr->GetColumnCount(); ++col )
686 {
687 ( *it )->GetCell( col ).SetBgCol( bgCol );
688 ( *it )->GetCell( col ).SetFgCol( fgCol );
689 }
690
691 SIM_PROPERTY* prop = dynamic_cast<SIM_PROPERTY*>( *it );
692
693 if( !prop )
694 continue;
695
696 const SIM_MODEL::PARAM& param = prop->GetParam();
697
698 // Model values other than the currently edited value may have changed. Update them.
699 // This feature is called "autofill" and present only in certain models. Don't do it for
700 // models that don't have it for performance reasons.
701 if( aModel->HasAutofill() )
702 ( *it )->SetValueFromString( param.value );
703 }
704}
705
706
707template <typename T>
709{
710 if( dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( aModel ) )
711 return;
712
713 wxString text;
714 SPICE_ITEM item;
715
716 item.modelName = m_modelListBox->GetStringSelection();
717
718 if( m_rbBuiltinModel->GetValue() || item.modelName == "" )
719 item.modelName = m_fields.at( REFERENCE_FIELD ).GetText();
720
721 text << aModel->SpiceGenerator().Preview( item );
722
723 m_codePreview->SetText( text );
724 m_codePreview->SelectNone();
725}
726
727
728template <typename T>
729void DIALOG_SIM_MODEL<T>::updatePinAssignments( SIM_MODEL* aModel, bool aForceUpdatePins )
730{
731 if( m_pinAssignmentsGrid->GetNumberRows() == 0 )
732 {
733 m_pinAssignmentsGrid->AppendRows( static_cast<int>( m_sortedPartPins.size() ) );
734
735 for( int ii = 0; ii < m_pinAssignmentsGrid->GetNumberRows(); ++ii )
736 {
737 wxString symbolPinString = getSymbolPinString( ii );
738
739 m_pinAssignmentsGrid->SetReadOnly( ii, PIN_COLUMN::SYMBOL );
740 m_pinAssignmentsGrid->SetCellValue( ii, PIN_COLUMN::SYMBOL, symbolPinString );
741 }
742
743 aForceUpdatePins = true;
744 }
745
746 if( aForceUpdatePins )
747 {
748 // Reset the grid.
749 for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row )
750 m_pinAssignmentsGrid->SetCellValue( row, PIN_COLUMN::MODEL, _( "Not Connected" ) );
751
752 // Now set up the grid values in the Model column.
753 for( int modelPinIndex = 0; modelPinIndex < aModel->GetPinCount(); ++modelPinIndex )
754 {
755 wxString symbolPinNumber = aModel->GetPin( modelPinIndex ).symbolPinNumber;
756
757 if( symbolPinNumber == "" )
758 continue;
759
760 int symbolPinRow = findSymbolPinRow( symbolPinNumber );
761
762 if( symbolPinRow == -1 )
763 continue;
764
765 wxString modelPinString = getModelPinString( aModel, modelPinIndex );
766 m_pinAssignmentsGrid->SetCellValue( symbolPinRow, PIN_COLUMN::MODEL, modelPinString );
767 }
768 }
769
770 for( int ii = 0; ii < m_pinAssignmentsGrid->GetNumberRows(); ++ii )
771 {
772 // Set up the Model column cell editors with dropdown options.
773 std::vector<BITMAPS> modelPinIcons;
774 wxArrayString modelPinChoices;
775
776 for( int jj = 0; jj < aModel->GetPinCount(); ++jj )
777 {
778 if( aModel->GetPin( jj ).symbolPinNumber != "" )
779 modelPinIcons.push_back( PinShapeGetBitmap( GRAPHIC_PINSHAPE::LINE ) );
780 else
781 modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
782
783 modelPinChoices.Add( getModelPinString( aModel, jj ) );
784 }
785
786 modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
787 modelPinChoices.Add( _( "Not Connected" ) );
788
789 // Using `new` here shouldn't cause a memory leak because `SetCellEditor()` calls
790 // `DecRef()` on its last editor.
791 m_pinAssignmentsGrid->SetCellEditor( ii, PIN_COLUMN::MODEL,
792 new GRID_CELL_ICON_TEXT_POPUP( modelPinIcons,
793 modelPinChoices ) );
794 }
795
796 // TODO: Show a preview of the symbol with the pin numbers shown.
797
798 if( aModel->GetType() == SIM_MODEL::TYPE::SUBCKT )
799 {
800 SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( aModel );
801 m_subckt->SetText( subckt->GetSpiceCode() );
802 m_subckt->SetEditable( false );
803 }
804 else
805 {
806 m_subcktLabel->Show( false );
807 m_subckt->Show( false );
808 }
809}
810
811
812template <typename T>
814{
815 for( int i = 0; i < aModel->GetPinCount(); ++i )
816 {
817 if( !m_symbol.GetPin( aModel->GetPin( i ).symbolPinNumber ) )
818 aModel->AssignSymbolPinNumberToModelPin( i, "" );
819 }
820}
821
822
823template <typename T>
824bool DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aLibraryPath, REPORTER& aReporter,
825 bool aForceReload )
826{
827 if( m_prevLibrary == aLibraryPath && !aForceReload )
828 return true;
829
830 m_libraryModelsMgr.SetForceFullParse();
831 m_libraryModelsMgr.SetLibrary( aLibraryPath, aReporter );
832
834 return false;
835
836 std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
837
838 for( const auto& [baseModelName, baseModel] : library()->GetModels() )
839 {
840 if( baseModelName == modelName )
841 m_libraryModelsMgr.CreateModel( &baseModel, m_sortedPartPins, m_fields, aReporter );
842 else
843 m_libraryModelsMgr.CreateModel( &baseModel, m_sortedPartPins, aReporter );
844 }
845
846 m_rbLibraryModel->SetValue( true );
847 m_libraryPathText->ChangeValue( aLibraryPath );
848
849 m_modelListBoxEntryToLibraryIdx.clear();
850 wxArrayString modelNames;
851
852 bool modelNameExists = false;
853 for( const auto& [name, model] : library()->GetModels() )
854 {
855 modelNames.Add( name );
856 m_modelListBoxEntryToLibraryIdx[name] = m_modelListBoxEntryToLibraryIdx.size();
857 if( name == modelName )
858 modelNameExists = true;
859 }
860
861 modelNames.Sort();
862
863 m_modelListBox->Clear();
864 m_modelListBox->Append( modelNames );
865
866 if( !modelNameExists )
867 {
868 m_infoBar->ShowMessage(
869 wxString::Format( _( "No model named '%s' in '%s'." ), modelName, aLibraryPath ) );
870 return false;
871 }
872
873 if( isIbisLoaded() )
874 {
875 wxArrayString emptyArray;
876 m_pinModelCombobox->Set( emptyArray );
877 m_pinCombobox->Set( emptyArray );
878 m_pinModelCombobox->SetSelection( -1 );
879 m_pinCombobox->SetSelection( -1 );
880 }
881
882 m_modelListBox->SetStringSelection( modelName );
883
884 if( m_modelListBox->GetSelection() < 0 && m_modelListBox->GetCount() > 0 )
885 m_modelListBox->SetSelection( 0 );
886
887 m_curModelType = curModel().GetType();
888
889 m_prevLibrary = aLibraryPath;
890 return true;
891}
892
893
894template <typename T>
896{
897 if( aModel->GetParam( aParamIndex ).info.dir == SIM_MODEL::PARAM::DIR_OUT )
898 return;
899
900 switch( aModel->GetParam( aParamIndex ).info.category )
901 {
902 case CATEGORY::AC:
903 m_paramGrid->HideProperty( "AC", false );
904 m_paramGrid->AppendIn( "AC", newParamProperty( aModel, aParamIndex ) );
905 break;
906
907 case CATEGORY::DC:
908 m_paramGrid->HideProperty( "DC", false );
909 m_paramGrid->AppendIn( "DC", newParamProperty( aModel, aParamIndex ) );
910 break;
911
912 case CATEGORY::S_PARAM:
913 m_paramGrid->HideProperty( "S-Parameters", false );
914 m_paramGrid->AppendIn( "S-Parameters", newParamProperty( aModel, aParamIndex ) );
915 break;
916
917 case CATEGORY::CAPACITANCE:
918 m_paramGrid->HideProperty( "Capacitance", false );
919 m_paramGrid->AppendIn( "Capacitance", newParamProperty( aModel, aParamIndex ) );
920 break;
921
922 case CATEGORY::TEMPERATURE:
923 m_paramGrid->HideProperty( "Temperature", false );
924 m_paramGrid->AppendIn( "Temperature", newParamProperty( aModel, aParamIndex ) );
925 break;
926
927 case CATEGORY::NOISE:
928 m_paramGrid->HideProperty( "Noise", false );
929 m_paramGrid->AppendIn( "Noise", newParamProperty( aModel, aParamIndex ) );
930 break;
931
932 case CATEGORY::DISTRIBUTED_QUANTITIES:
933 m_paramGrid->HideProperty( "Distributed Quantities", false );
934 m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aModel, aParamIndex ) );
935 break;
936
937 case CATEGORY::WAVEFORM:
938 m_paramGrid->HideProperty( "Waveform", false );
939 m_paramGrid->AppendIn( "Waveform", newParamProperty( aModel, aParamIndex ) );
940 break;
941
942 case CATEGORY::GEOMETRY:
943 m_paramGrid->HideProperty( "Geometry", false );
944 m_paramGrid->AppendIn( "Geometry", newParamProperty( aModel, aParamIndex ) );
945 break;
946
947 case CATEGORY::LIMITING_VALUES:
948 m_paramGrid->HideProperty( "Limiting Values", false );
949 m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aModel, aParamIndex ) );
950 break;
951
952 case CATEGORY::ADVANCED:
953 m_paramGrid->HideProperty( "Advanced", false );
954 m_paramGrid->AppendIn( "Advanced", newParamProperty( aModel, aParamIndex ) );
955 break;
956
957 case CATEGORY::FLAGS:
958 m_paramGrid->HideProperty( "Flags", false );
959 m_paramGrid->AppendIn( "Flags", newParamProperty( aModel, aParamIndex ) );
960 break;
961
962 default:
963 m_paramGrid->Insert( m_firstCategory, newParamProperty( aModel, aParamIndex ) );
964 break;
965
966 case CATEGORY::INITIAL_CONDITIONS:
967 case CATEGORY::SUPERFLUOUS:
968 return;
969 }
970}
971
972
973template <typename T>
974wxPGProperty* DIALOG_SIM_MODEL<T>::newParamProperty( SIM_MODEL* aModel, int aParamIndex ) const
975{
976 const SIM_MODEL::PARAM& param = aModel->GetParam( aParamIndex );
977 wxString paramDescription;
978
979 if( param.info.description == "" )
980 paramDescription = wxString::Format( "%s", param.info.name );
981 else
982 paramDescription = wxString::Format( "%s (%s)", param.info.description, param.info.name );
983
984 wxPGProperty* prop = nullptr;
985
986 switch( param.info.type )
987 {
989 // TODO.
990 prop = new SIM_BOOL_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex );
991 prop->SetAttribute( wxPG_BOOL_USE_CHECKBOX, true );
992 break;
993
995 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex,
997 break;
998
1000 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex,
1002 break;
1003
1004 //case TYPE_COMPLEX:
1005 // break;
1006
1008 // Special case: K-line mutual inductance statement parameters l1 and l2 are references
1009 // to other inductors in the circuit.
1010 if( dynamic_cast<SIM_MODEL_L_MUTUAL*>( aModel ) != nullptr
1011 && ( param.info.name == "l1" || param.info.name == "l2" ) )
1012 {
1013 wxArrayString inductors;
1014
1015 if( SCH_EDIT_FRAME* schEditFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
1016 {
1017 SPICE_CIRCUIT_MODEL circuit( &schEditFrame->Schematic() );
1018 NULL_REPORTER devNul;
1019
1021 devNul );
1022
1023 for( const SPICE_ITEM& item : circuit.GetItems() )
1024 {
1025 if( item.model->GetDeviceType() == SIM_MODEL::DEVICE_T::L )
1026 inductors.push_back( item.refName );
1027 }
1028
1029 inductors.Sort(
1030 []( const wxString& a, const wxString& b ) -> int
1031 {
1032 return StrNumCmp( a, b, true );
1033 } );
1034 }
1035
1036 if( inductors.empty() )
1037 {
1038 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel,
1039 aParamIndex, SIM_VALUE::TYPE_STRING );
1040 }
1041 else
1042 {
1043 prop = new SIM_ENUM_PROPERTY( paramDescription, param.info.name, *aModel,
1044 aParamIndex, inductors );
1045 }
1046 }
1047 else if( param.info.enumValues.empty() )
1048 {
1049 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, *aModel,
1050 aParamIndex, SIM_VALUE::TYPE_STRING );
1051 }
1052 else
1053 {
1054 wxArrayString values;
1055
1056 for( const std::string& string : aModel->GetParam( aParamIndex ).info.enumValues )
1057 values.Add( string );
1058
1059 prop = new SIM_ENUM_PROPERTY( paramDescription, param.info.name, *aModel, aParamIndex,
1060 values );
1061 }
1062 break;
1063
1064 default:
1065 prop = new wxStringProperty( paramDescription, param.info.name );
1066 break;
1067 }
1068
1069 prop->SetAttribute( wxPG_ATTR_UNITS, wxString::FromUTF8( param.info.unit.c_str() ) );
1070
1071 // Legacy due to the way we extracted the parameters from Ngspice.
1072 prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue ) );
1073
1074 wxString typeStr;
1075
1076 switch( param.info.type )
1077 {
1078 case SIM_VALUE::TYPE_BOOL: typeStr = wxT( "Bool" ); break;
1079 case SIM_VALUE::TYPE_INT: typeStr = wxT( "Int" ); break;
1080 case SIM_VALUE::TYPE_FLOAT: typeStr = wxT( "Float" ); break;
1081 case SIM_VALUE::TYPE_COMPLEX: typeStr = wxT( "Complex" ); break;
1082 case SIM_VALUE::TYPE_STRING: typeStr = wxT( "String" ); break;
1083 case SIM_VALUE::TYPE_BOOL_VECTOR: typeStr = wxT( "Bool Vector" ); break;
1084 case SIM_VALUE::TYPE_INT_VECTOR: typeStr = wxT( "Int Vector" ); break;
1085 case SIM_VALUE::TYPE_FLOAT_VECTOR: typeStr = wxT( "Float Vector" ); break;
1086 case SIM_VALUE::TYPE_COMPLEX_VECTOR: typeStr = wxT( "Complex Vector" ); break;
1087 }
1088
1089 prop->SetCell( PARAM_COLUMN::TYPE, typeStr );
1090
1091 return prop;
1092}
1093
1094
1095template <typename T>
1096int DIALOG_SIM_MODEL<T>::findSymbolPinRow( const wxString& aSymbolPinNumber ) const
1097{
1098 for( int row = 0; row < static_cast<int>( m_sortedPartPins.size() ); ++row )
1099 {
1100 SCH_PIN* pin = m_sortedPartPins[row];
1101
1102 if( pin->GetNumber() == aSymbolPinNumber )
1103 return row;
1104 }
1105
1106 return -1;
1107}
1108
1109
1110template <typename T>
1112{
1113 if( m_rbLibraryModel->GetValue() )
1114 {
1115 wxString sel = m_modelListBox->GetStringSelection();
1116
1117 if( m_modelListBoxEntryToLibraryIdx.contains( sel ) )
1118 return m_libraryModelsMgr.GetModels()
1119 .at( m_modelListBoxEntryToLibraryIdx.at( sel ) )
1120 .get();
1121 }
1122 else
1123 {
1124 if( static_cast<int>( m_curModelType )
1125 < static_cast<int>( m_builtinModelsMgr.GetModels().size() ) )
1126 return m_builtinModelsMgr.GetModels().at( static_cast<int>( m_curModelType ) );
1127 }
1128
1129 return m_builtinModelsMgr.GetModels().at( static_cast<int>( SIM_MODEL::TYPE::NONE ) );
1130}
1131
1132
1133template <typename T>
1135{
1136 if( m_libraryModelsMgr.GetLibraries().size() == 1 )
1137 return &m_libraryModelsMgr.GetLibraries().begin()->second.get();
1138
1139 return nullptr;
1140}
1141
1142
1143template <typename T>
1144wxString DIALOG_SIM_MODEL<T>::getSymbolPinString( int symbolPinIndex ) const
1145{
1146 SCH_PIN* pin = m_sortedPartPins.at( symbolPinIndex );
1147 wxString pinNumber;
1148 wxString pinName;
1149
1150 if( pin )
1151 {
1152 pinNumber = pin->GetShownNumber();
1153 pinName = pin->GetShownName();
1154 }
1155
1156 if( !pinName.IsEmpty() && pinName != pinNumber )
1157 pinNumber += wxString::Format( wxT( " (\"%s\")" ), pinName );
1158
1159 return pinNumber;
1160}
1161
1162
1163template <typename T>
1164wxString DIALOG_SIM_MODEL<T>::getModelPinString( SIM_MODEL* aModel, int aModelPinIndex ) const
1165{
1166 const wxString& modelPinName = aModel->GetPin( aModelPinIndex ).modelPinName;
1167
1168 LOCALE_IO toggle;
1169
1170 wxString modelPinNumber = wxString::Format( "%d", aModelPinIndex + 1 );
1171
1172 if( !modelPinName.IsEmpty() && modelPinName != modelPinNumber )
1173 modelPinNumber += wxString::Format( wxT( " (\"%s\")" ), modelPinName );
1174
1175 return modelPinNumber;
1176}
1177
1178
1179template <typename T>
1180int DIALOG_SIM_MODEL<T>::getModelPinIndex( const wxString& aModelPinString ) const
1181{
1182 if( aModelPinString == "Not Connected" )
1184
1185 int length = aModelPinString.Find( " " );
1186
1187 if( length == wxNOT_FOUND )
1188 length = static_cast<int>( aModelPinString.Length() );
1189
1190 long result = 0;
1191 aModelPinString.Mid( 0, length ).ToCLong( &result );
1192
1193 return static_cast<int>( result - 1 );
1194}
1195
1196
1197template <typename T>
1198void DIALOG_SIM_MODEL<T>::onRadioButton( wxCommandEvent& aEvent )
1199{
1200 m_prevModel = nullptr; // Ensure the Model panel will be rebuild after updating other params.
1201 updateWidgets();
1202}
1203
1204
1205template <typename T>
1206void DIALOG_SIM_MODEL<T>::onLibraryPathText( wxCommandEvent& aEvent )
1207{
1208 m_rbLibraryModel->SetValue( true );
1209}
1210
1211
1212template <typename T>
1214{
1215 m_rbLibraryModel->SetValue( true );
1216
1217 WX_STRING_REPORTER reporter;
1218 wxString path = m_libraryPathText->GetValue();
1219
1220 if( loadLibrary( path, reporter, true ) || path.IsEmpty() )
1221 m_infoBar->Hide();
1222 else if( reporter.HasMessage() )
1223 m_infoBar->ShowMessage( reporter.GetMessages() );
1224
1225 updateWidgets();
1226}
1227
1228
1229template <typename T>
1231{
1232 CallAfter(
1233 [this]()
1234 {
1235 // Disable logging -- otherwise we'll end up in an endless loop of show-log,
1236 // kill-focus, show-log, kill-focus, etc.
1237 wxLogNull doNotLog;
1238
1239 wxCommandEvent dummy;
1240 onLibraryPathTextEnter( dummy );
1241 } );
1242
1243 aEvent.Skip(); // mandatory in wxFocusEvent events
1244}
1245
1246
1247template <typename T>
1248void DIALOG_SIM_MODEL<T>::onBrowseButtonClick( wxCommandEvent& aEvent )
1249{
1250 static wxString s_mruPath;
1251
1252 wxString path = s_mruPath.IsEmpty() ? Prj().GetProjectPath() : s_mruPath;
1253 wxFileDialog dlg( this, _( "Browse Models" ), path );
1254
1255 if( dlg.ShowModal() == wxID_CANCEL )
1256 return;
1257
1258 m_rbLibraryModel->SetValue( true );
1259
1260 path = dlg.GetPath();
1261 wxFileName fn( path );
1262
1263 s_mruPath = fn.GetPath();
1264
1265 if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( wxS( ".." ) ) )
1266 path = fn.GetFullPath();
1267
1268 WX_STRING_REPORTER reporter;
1269
1270 if( loadLibrary( path, reporter, true ) )
1271 m_infoBar->Hide();
1272 else
1273 m_infoBar->ShowMessage( reporter.GetMessages() );
1274
1275 updateWidgets();
1276}
1277
1278
1279template <typename T>
1280void DIALOG_SIM_MODEL<T>::onFilterCharHook( wxKeyEvent& aKeyStroke )
1281{
1282 int sel = m_modelListBox->GetSelection();
1283
1284 switch( aKeyStroke.GetKeyCode() )
1285 {
1286 case WXK_UP:
1287 if( sel == wxNOT_FOUND )
1288 sel = m_modelListBox->GetCount() - 1;
1289 else
1290 sel--;
1291
1292 break;
1293
1294 case WXK_DOWN:
1295 if( sel == wxNOT_FOUND )
1296 sel = 0;
1297 else
1298 sel++;
1299
1300 break;
1301
1302 case WXK_RETURN:
1303 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
1304 return;
1305
1306 default:
1307 aKeyStroke.Skip(); // Any other key: pass on to search box directly.
1308 return;
1309 }
1310
1311 if( sel >= 0 && sel < (int) m_modelListBox->GetCount() )
1312 m_modelListBox->SetSelection( sel );
1313}
1314
1315
1316template <typename T>
1317void DIALOG_SIM_MODEL<T>::onModelFilter( wxCommandEvent& aEvent )
1318{
1319 wxArrayString modelNames;
1320 wxString current = m_modelListBox->GetStringSelection();
1321 wxString filter = wxT( "*" ) + m_modelFilter->GetValue() + wxT( "*" );
1322
1323 for( const auto& [name, model] : library()->GetModels() )
1324 {
1325 wxString wx_name( name );
1326
1327 if( wx_name.Matches( filter ) )
1328 modelNames.Add( wx_name );
1329 }
1330
1331 modelNames.Sort();
1332
1333 m_modelListBox->Clear();
1334 m_modelListBox->Append( modelNames );
1335
1336 if( !m_modelListBox->SetStringSelection( current ) )
1337 m_modelListBox->SetSelection( 0 );
1338}
1339
1340
1341template <typename T>
1342void DIALOG_SIM_MODEL<T>::onModelNameChoice( wxCommandEvent& aEvent )
1343{
1344 if( isIbisLoaded() )
1345 {
1346 wxArrayString pinLabels;
1347 SIM_MODEL_IBIS* modelkibis = dynamic_cast<SIM_MODEL_IBIS*>( &curModel() );
1348
1349 wxCHECK2( modelkibis, return );
1350
1351 for( std::pair<wxString, wxString> strs : modelkibis->GetIbisPins() )
1352 pinLabels.Add( strs.first + wxT( " - " ) + strs.second );
1353
1354 m_pinCombobox->Set( pinLabels );
1355
1356 wxArrayString emptyArray;
1357 m_pinModelCombobox->Set( emptyArray );
1358 }
1359
1360 m_rbLibraryModel->SetValue( true );
1361
1362 if( SIM_MODEL_SPICE_FALLBACK* fallback =
1363 dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( &curModel() ) )
1364 {
1365 wxArrayString lines = wxSplit( fallback->GetSpiceCode(), '\n' );
1366 wxString code;
1367
1368 for( const wxString& line : lines )
1369 {
1370 if( !line.StartsWith( '*' ) )
1371 {
1372 if( !code.IsEmpty() )
1373 code += "\n";
1374
1375 code += line;
1376 }
1377 }
1378
1379 m_infoBar->ShowMessage( wxString::Format( _( "Failed to parse:\n\n"
1380 "%s\n"
1381 "Using generic SPICE model." ),
1382 code ) );
1383 }
1384 else
1385 {
1386 m_infoBar->Hide();
1387 }
1388
1389 updateWidgets();
1390}
1391
1392
1393template <typename T>
1394void DIALOG_SIM_MODEL<T>::onPinCombobox( wxCommandEvent& aEvent )
1395{
1396 wxArrayString modelLabels;
1397
1398 SIM_MODEL_IBIS& ibisModel = static_cast<SIM_MODEL_IBIS&>( curModel() );
1399
1400 std::vector<std::pair<std::string, std::string>> strs = ibisModel.GetIbisPins();
1401 std::string pinNumber = strs.at( m_pinCombobox->GetSelection() ).first;
1402
1403 const SIM_LIBRARY_IBIS* ibisLibrary = dynamic_cast<const SIM_LIBRARY_IBIS*>( library() );
1404
1405 ibisModel.ChangePin( *ibisLibrary, pinNumber );
1406
1407 ibisModel.m_enableDiff = ibisLibrary->isPinDiff( ibisModel.GetComponentName(), pinNumber );
1408
1409 for( wxString modelName : ibisModel.GetIbisModels() )
1410 modelLabels.Add( modelName );
1411
1412 m_pinModelCombobox->Set( modelLabels );
1413
1414 if( m_pinModelCombobox->GetCount() == 1 )
1415 m_pinModelCombobox->SetSelection( 0 );
1416 else
1417 m_pinModelCombobox->SetSelection( -1 );
1418
1419 updateWidgets();
1420}
1421
1422
1423template <typename T>
1425{
1426 m_pinCombobox->SetSelection( m_pinCombobox->FindString( m_pinCombobox->GetValue() ) );
1427
1428 onPinModelCombobox( aEvent );
1429}
1430
1431
1432template <typename T>
1433void DIALOG_SIM_MODEL<T>::onPinModelCombobox( wxCommandEvent& aEvent )
1434{
1435 updateWidgets();
1436}
1437
1438
1439template <typename T>
1441{
1442 m_pinModelCombobox->SetSelection(
1443 m_pinModelCombobox->FindString( m_pinModelCombobox->GetValue() ) );
1444}
1445
1446
1447template <typename T>
1449{
1450 if( SIM_MODEL_IBIS* modelibis = dynamic_cast<SIM_MODEL_IBIS*>( &curModel() ) )
1451 {
1452 bool diff = m_differentialCheckbox->GetValue() && modelibis->CanDifferential();
1453 modelibis->SwitchSingleEndedDiff( diff );
1454
1455 updateWidgets();
1456 }
1457}
1458
1459
1460template <typename T>
1461void DIALOG_SIM_MODEL<T>::onDeviceTypeChoice( wxCommandEvent& aEvent )
1462{
1463 m_rbBuiltinModel->SetValue( true );
1464
1465 for( SIM_MODEL::DEVICE_T deviceType : SIM_MODEL::DEVICE_T_ITERATOR() )
1466 {
1467 if( SIM_MODEL::DeviceInfo( deviceType ).description
1468 == m_deviceChoice->GetStringSelection() )
1469 {
1470 m_curModelType = m_curModelTypeOfDeviceType.at( deviceType );
1471 break;
1472 }
1473 }
1474
1475 updateWidgets();
1476}
1477
1478
1479template <typename T>
1480void DIALOG_SIM_MODEL<T>::onWaveformChoice( wxCommandEvent& aEvent )
1481{
1482 SIM_MODEL::DEVICE_T deviceType = curModel().GetDeviceType();
1483 wxString typeDescription = m_waveformChoice->GetStringSelection();
1484
1485 for( SIM_MODEL::TYPE type : { SIM_MODEL::TYPE::KIBIS_DEVICE,
1486 SIM_MODEL::TYPE::KIBIS_DRIVER_DC,
1487 SIM_MODEL::TYPE::KIBIS_DRIVER_RECT,
1488 SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS } )
1489 {
1490 if( equivalent( deviceType, SIM_MODEL::TypeInfo( type ).deviceType )
1491 && typeDescription == SIM_MODEL::TypeInfo( type ).description )
1492 {
1493 int idx = 0;
1494 wxString sel = m_modelListBox->GetStringSelection();
1495
1496 if( m_modelListBoxEntryToLibraryIdx.contains( sel ) )
1497 idx = m_modelListBoxEntryToLibraryIdx.at( sel );
1498
1499 auto& baseModel =
1500 static_cast<SIM_MODEL_IBIS&>( m_libraryModelsMgr.GetModels()[idx].get() );
1501
1502 m_libraryModelsMgr.SetModel( idx, std::make_unique<SIM_MODEL_IBIS>( type, baseModel ) );
1503
1504 try
1505 {
1506 m_libraryModelsMgr.GetModels()[idx].get().ReadDataFields( &m_fields,
1507 m_sortedPartPins );
1508 }
1509 catch( IO_ERROR& err )
1510 {
1511 DisplayErrorMessage( this, err.What() );
1512 }
1513
1514 m_curModelType = type;
1515 break;
1516 }
1517 }
1518
1519 m_curModelTypeOfDeviceType.at( deviceType ) = m_curModelType;
1520 updateWidgets();
1521}
1522
1523
1524template <typename T>
1525void DIALOG_SIM_MODEL<T>::onTypeChoice( wxCommandEvent& aEvent )
1526{
1527 SIM_MODEL::DEVICE_T deviceType = curModel().GetDeviceType();
1528 wxString typeDescription = m_deviceSubtypeChoice->GetStringSelection();
1529
1530 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
1531 {
1532 if( equivalent( deviceType, SIM_MODEL::TypeInfo( type ).deviceType )
1533 && typeDescription == SIM_MODEL::TypeInfo( type ).description )
1534 {
1535 m_curModelType = type;
1536 break;
1537 }
1538 }
1539
1540 m_curModelTypeOfDeviceType.at( deviceType ) = m_curModelType;
1541 updateWidgets();
1542}
1543
1544
1545template <typename T>
1546void DIALOG_SIM_MODEL<T>::onPageChanging( wxBookCtrlEvent& event )
1547{
1548 updateModelCodeTab( &curModel() );
1549}
1550
1551
1552template <typename T>
1554{
1555 int symbolPinIndex = aEvent.GetRow();
1556 wxString oldModelPinName = aEvent.GetString();
1557 wxString modelPinName = m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() );
1558
1559 int oldModelPinIndex = getModelPinIndex( oldModelPinName );
1560 int modelPinIndex = getModelPinIndex( modelPinName );
1561
1562 if( oldModelPinIndex != SIM_MODEL_PIN::NOT_CONNECTED )
1563 curModel().AssignSymbolPinNumberToModelPin( oldModelPinIndex, "" );
1564
1565 if( modelPinIndex != SIM_MODEL_PIN::NOT_CONNECTED )
1566 {
1567 SCH_PIN* symbolPin = m_sortedPartPins.at( symbolPinIndex );
1568
1569 curModel().AssignSymbolPinNumberToModelPin( modelPinIndex, symbolPin->GetShownNumber() );
1570 }
1571
1572 updatePinAssignments( &curModel(), FORCE_UPDATE_PINS );
1573
1574 aEvent.Skip();
1575}
1576
1577
1578template <typename T>
1580{
1581 wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinAssignmentsGrid );
1582
1583 int gridWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinAssignmentsGrid ).x;
1584 m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::MODEL, gridWidth / 2 );
1585 m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::SYMBOL, gridWidth / 2 );
1586
1587 aEvent.Skip();
1588}
1589
1590
1591template <typename T>
1593{
1594 // By default, when a property grid is focused, the textbox is not immediately focused until
1595 // Tab key is pressed. This is inconvenient, so we fix that here.
1596
1597 wxPropertyGrid* grid = m_paramGrid->GetGrid();
1598 wxPGProperty* selected = grid->GetSelection();
1599
1600 if( !selected )
1601 selected = grid->wxPropertyGridInterface::GetFirst();
1602
1603#if wxCHECK_VERSION( 3, 3, 0 )
1604 if( selected )
1605 grid->DoSelectProperty( selected, wxPGSelectPropertyFlags::Focus );
1606#else
1607 if( selected )
1608 grid->DoSelectProperty( selected, wxPG_SEL_FOCUS );
1609#endif
1610
1611 aEvent.Skip();
1612}
1613
1614
1615template <typename T>
1616void DIALOG_SIM_MODEL<T>::onParamGridSelectionChange( wxPropertyGridEvent& aEvent )
1617{
1618 wxPropertyGrid* grid = m_paramGrid->GetGrid();
1619
1620 // Jump over categories.
1621 if( grid->GetSelection() && grid->GetSelection()->IsCategory() )
1622 {
1623 wxPGProperty* selection = grid->GetSelection();
1624
1625 // If the new selection is immediately above the previous selection, we jump up. Otherwise
1626 // we jump down. We do this by simulating up or down arrow keys.
1627
1628 wxPropertyGridIterator it = grid->GetIterator( wxPG_ITERATE_VISIBLE, selection );
1629 it.Next();
1630
1631 wxKeyEvent* keyEvent = new wxKeyEvent( wxEVT_KEY_DOWN );
1632
1633 if( *it == m_prevParamGridSelection )
1634 {
1635 if( !selection->IsExpanded() )
1636 {
1637 grid->Expand( selection );
1638 keyEvent->m_keyCode = WXK_DOWN;
1639 wxQueueEvent( grid, keyEvent );
1640
1641 // Does not work for some reason.
1642 /*m_paramGrid->DoSelectProperty( selection->Item( selection->GetChildCount() - 1 ),
1643 wxPG_SEL_FOCUS );*/
1644 }
1645 else
1646 {
1647 keyEvent->m_keyCode = WXK_UP;
1648 wxQueueEvent( grid, keyEvent );
1649 }
1650 }
1651 else
1652 {
1653 if( !selection->IsExpanded() )
1654 grid->Expand( selection );
1655
1656 keyEvent->m_keyCode = WXK_DOWN;
1657 wxQueueEvent( grid, keyEvent );
1658 }
1659
1660 m_prevParamGridSelection = grid->GetSelection();
1661 return;
1662 }
1663
1664 wxWindow* editorControl = grid->GetEditorControl();
1665
1666 if( !editorControl )
1667 {
1668 m_prevParamGridSelection = grid->GetSelection();
1669 return;
1670 }
1671
1672 // Without this the user had to press tab before they could edit the field.
1673 editorControl->SetFocus();
1674 m_prevParamGridSelection = grid->GetSelection();
1675}
1676
1677
1678template <typename T>
1679void DIALOG_SIM_MODEL<T>::onUpdateUI( wxUpdateUIEvent& aEvent )
1680{
1681 // This is currently patched in wxPropertyGrid::ScrollWindow() in the Mac wxWidgets fork.
1682 // However, we may need this version if it turns out to be an issue on other platforms and
1683 // we can't get it upstreamed.
1684#if 0
1685 // It's a shame to do this on the UpdateUI event, but neither the wxPropertyGridManager,
1686 // wxPropertyGridPage, wxPropertyGrid, nor the wxPropertyGrid's GetCanvas() window appear
1687 // to get scroll events.
1688
1689 wxPropertyGrid* grid = m_paramGrid->GetGrid();
1690 wxTextCtrl* ctrl = grid->GetEditorTextCtrl();
1691
1692 if( ctrl )
1693 {
1694 wxRect ctrlRect = ctrl->GetScreenRect();
1695 wxRect gridRect = grid->GetScreenRect();
1696
1697 if( ctrlRect.GetTop() < gridRect.GetTop() || ctrlRect.GetBottom() > gridRect.GetBottom() )
1698 grid->ClearSelection();
1699 }
1700#endif
1701}
1702
1703
1704template <typename T>
1705void DIALOG_SIM_MODEL<T>::adjustParamGridColumns( int aWidth, bool aForce )
1706{
1707 wxPropertyGrid* grid = m_paramGridMgr->GetGrid();
1708 int margin = 15;
1709 int indent = 20;
1710
1711 if( aWidth != m_lastParamGridWidth || aForce )
1712 {
1713 m_lastParamGridWidth = aWidth;
1714
1715 grid->FitColumns();
1716
1717 std::vector<int> colWidths;
1718
1719 for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
1720 {
1721 if( ii == PARAM_COLUMN::DESCRIPTION )
1722 colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin + indent );
1723 else if( ii == PARAM_COLUMN::VALUE )
1724 colWidths.push_back( std::max( 72,
1725 grid->GetState()->GetColumnWidth( ii ) ) + margin );
1726 else
1727 colWidths.push_back( 60 + margin );
1728
1729 aWidth -= colWidths[ ii ];
1730 }
1731
1732 for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
1733 grid->SetColumnProportion( ii, colWidths[ ii ] );
1734
1735 grid->ResetColumnSizes();
1736 grid->RefreshEditor();
1737 }
1738}
1739
1740
1741template <typename T>
1743{
1744 adjustParamGridColumns( event.GetSize().GetX(), false );
1745
1746 event.Skip();
1747}
1748
1749
1750template class DIALOG_SIM_MODEL<SCH_SYMBOL>;
1751template class DIALOG_SIM_MODEL<LIB_SYMBOL>;
const char * name
Definition: DXF_plotter.cpp:59
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
@ INVALID_BITMAP
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
Class DIALOG_SIM_MODEL_BASE.
wxPropertyGridManager * m_paramGridMgr
STD_BITMAP_BUTTON * m_browseButton
wxStyledTextCtrl * m_subckt
wxPropertyGridPage * m_paramGrid
wxStyledTextCtrl * m_codePreview
void onTypeChoice(wxCommandEvent &aEvent) override
void onLibraryPathTextKillFocus(wxFocusEvent &aEvent) override
wxString getSymbolPinString(int aSymbolPinNumber) const
void updateBuiltinModelWidgets(SIM_MODEL *aModel)
void onPinAssignmentsGridCellChange(wxGridEvent &aEvent) override
void onFilterCharHook(wxKeyEvent &aKeyStroke) override
int findSymbolPinRow(const wxString &aSymbolPinNumber) const
void onModelNameChoice(wxCommandEvent &aEvent) override
void onRadioButton(wxCommandEvent &aEvent) override
SCINTILLA_TRICKS * m_scintillaTricksSubckt
bool loadLibrary(const wxString &aLibraryPath, REPORTER &aReporter, bool aForceReload=false)
int getModelPinIndex(const wxString &aModelPinString) const
void onModelFilter(wxCommandEvent &aEvent) override
void onLibraryPathText(wxCommandEvent &aEvent) override
void onDifferentialCheckbox(wxCommandEvent &event) override
void onParamGridSelectionChange(wxPropertyGridEvent &aEvent)
void removeOrphanedPinAssignments(SIM_MODEL *aModel)
void adjustParamGridColumns(int aWidth, bool aForce)
std::vector< SCH_PIN * > m_sortedPartPins
Pins of the current part.
wxPGProperty * newParamProperty(SIM_MODEL *aModel, int aParamIndex) const
void onPinModelCombobox(wxCommandEvent &event) override
const SIM_LIBRARY * library() const
SIM_MODEL & curModel() const
void onBrowseButtonClick(wxCommandEvent &aEvent) override
void onPinComboboxTextEnter(wxCommandEvent &event) override
void onPinCombobox(wxCommandEvent &event) override
SCINTILLA_TRICKS * m_scintillaTricksCode
void updatePinAssignments(SIM_MODEL *aModel, bool aForceUpdatePins)
void onUpdateUI(wxUpdateUIEvent &aEvent)
DIALOG_SIM_MODEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame, T &aSymbol, std::vector< SCH_FIELD > &aFields)
wxString getModelPinString(SIM_MODEL *aModel, int aModelPinIndex) const
void onPinAssignmentsGridSize(wxSizeEvent &aEvent) override
void updateIbisWidgets(SIM_MODEL *aModel)
void onParamGridSetFocus(wxFocusEvent &aEvent)
void updateModelParamsTab(SIM_MODEL *aModel)
bool TransferDataFromWindow() override
void updateModelCodeTab(SIM_MODEL *aModel)
void onSizeParamGrid(wxSizeEvent &event) override
void onPageChanging(wxNotebookEvent &event) override
void onWaveformChoice(wxCommandEvent &aEvent) override
void onPinModelComboboxTextEnter(wxCommandEvent &event) override
void onLibraryPathTextEnter(wxCommandEvent &aEvent) override
void onDeviceTypeChoice(wxCommandEvent &aEvent) override
bool TransferDataToWindow() override
void addParamPropertyIfRelevant(SIM_MODEL *aModel, int aParamIndex)
The base frame for deriving all KiCad main window classes.
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
virtual bool ReadSchematicAndLibraries(unsigned aNetlistOptions, REPORTER &aReporter)
Process the schematic and Spice libraries to create net mapping and a list of SPICE_ITEMs.
const std::list< SPICE_ITEM > & GetItems() const
Return the list of items representing schematic symbols in the Spice world.
A singleton reporter that reports to nowhere.
Definition: reporter.h:203
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:146
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
virtual bool HasMessageOfSeverity(int aSeverityMask) const
Returns true if the reporter has one or more messages matching the specified severity mask.
Definition: reporter.cpp:53
Schematic editor (Eeschema) main window.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
wxString GetShownNumber() const
Definition: sch_pin.cpp:518
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
static constexpr auto MODEL_FIELD
static constexpr auto PIN_FIELD
static constexpr auto DIFF_FIELD
bool isPinDiff(const std::string &aComp, const std::string &aPinNumber) const
static constexpr auto LIBRARY_FIELD
Definition: sim_library.h:35
static constexpr auto NAME_FIELD
Definition: sim_library.h:36
std::vector< std::pair< std::string, std::string > > GetIbisPins() const
bool CanDifferential() const
std::vector< std::string > GetIbisModels() const
bool ChangePin(const SIM_LIBRARY_IBIS &aLib, const std::string &aPinNumber)
update the list of available models based on the pin number.
std::string GetComponentName() const
std::string GetSpiceCode() const
static TYPE ReadTypeFromFields(const std::vector< SCH_FIELD > &aFields, REPORTER &aReporter)
Definition: sim_model.cpp:390
static INFO TypeInfo(TYPE aType)
Definition: sim_model.cpp:105
int GetPinCount() const
Definition: sim_model.h:471
static void SetFieldValue(std::vector< SCH_FIELD > &aFields, const wxString &aFieldName, const std::string &aValue, bool aIsVisible=true)
Definition: sim_model.cpp:672
void ReadDataFields(const std::vector< SCH_FIELD > *aFields, const std::vector< SCH_PIN * > &aPins)
Definition: sim_model.cpp:427
const SPICE_GENERATOR & SpiceGenerator() const
Definition: sim_model.h:435
virtual const PARAM & GetParam(unsigned aParamIndex) const
Definition: sim_model.cpp:793
static bool InferSimModel(T &aSymbol, std::vector< SCH_FIELD > *aFields, bool aResolve, SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString *aDeviceType, wxString *aModelType, wxString *aModelParams, wxString *aPinMap)
Definition: sim_model.cpp:1086
static std::string GetFieldValue(const std::vector< SCH_FIELD > *aFields, const wxString &aFieldName, bool aResolve=true)
Definition: sim_model.cpp:653
int GetParamCount() const
Definition: sim_model.h:481
void AssignSymbolPinNumberToModelPin(int aPinIndex, const wxString &aSymbolPinNumber)
Definition: sim_model.cpp:762
DEVICE_INFO GetDeviceInfo() const
Definition: sim_model.h:460
DEVICE_T GetDeviceType() const
Definition: sim_model.h:463
static DEVICE_INFO DeviceInfo(DEVICE_T aDeviceType)
Definition: sim_model.cpp:60
virtual bool HasAutofill() const
Definition: sim_model.h:498
void SetParamValue(int aParamIndex, const std::string &aValue, SIM_VALUE::NOTATION aNotation=SIM_VALUE::NOTATION::SI)
Definition: sim_model.cpp:849
const SIM_MODEL_PIN & GetPin(unsigned aIndex) const
Definition: sim_model.h:472
void SetIsStoredInValue(bool aIsStoredInValue)
Definition: sim_model.h:504
virtual bool HasPrimaryValue() const
Definition: sim_model.h:499
TYPE GetType() const
Definition: sim_model.h:464
const SIM_MODEL::PARAM & GetParam() const
Definition: sim_property.h:60
@ TYPE_BOOL
Definition: sim_value.h:67
@ TYPE_FLOAT_VECTOR
Definition: sim_value.h:75
@ TYPE_BOOL_VECTOR
Definition: sim_value.h:73
@ TYPE_INT
Definition: sim_value.h:68
@ TYPE_FLOAT
Definition: sim_value.h:69
@ TYPE_INT_VECTOR
Definition: sim_value.h:74
@ TYPE_COMPLEX_VECTOR
Definition: sim_value.h:76
@ TYPE_STRING
Definition: sim_value.h:71
@ TYPE_COMPLEX
Definition: sim_value.h:70
Special netlist exporter flavor that allows one to override simulation commands.
virtual std::string Preview(const SPICE_ITEM &aItem) const
void SetBitmap(const wxBitmapBundle &aBmp)
void ClearRows()
wxWidgets recently added an ASSERT which fires if the position is greater than or equal to the number...
Definition: wx_grid.h:193
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: wx_infobar.cpp:310
A wrapper for reporting to a wxString object.
Definition: reporter.h:171
bool HasMessage() const override
Returns true if the reporter client is non-empty.
Definition: reporter.cpp:97
const wxString & GetMessages() const
Definition: reporter.cpp:84
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:195
This file is part of the common library.
static bool empty(const wxTextEntryBase *aCtrl)
bool equivalent(SIM_MODEL::DEVICE_T a, SIM_MODEL::DEVICE_T b)
#define FORCE_UPDATE_PINS
#define _(s)
PROJECT & Prj()
Definition: kicad.cpp:597
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: wxgtk/ui.cpp:252
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:155
BITMAPS PinShapeGetBitmap(GRAPHIC_PINSHAPE aShape)
Definition: pin_type.cpp:246
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_UNDEFINED
@ NONE
No connection to this item.
SIM_MODEL::TYPE TYPE
Definition: sim_model.cpp:57
#define SIM_PINS_FIELD
Definition: sim_model.h:54
#define SIM_DEVICE_FIELD
Definition: sim_model.h:52
#define SIM_REFERENCE_FIELD
Definition: sim_model.h:49
#define SIM_PARAMS_FIELD
Definition: sim_model.h:55
#define SIM_DEVICE_SUBTYPE_FIELD
Definition: sim_model.h:53
std::vector< FAB_LAYER_COLOR > dummy
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
std::vector< std::string > enumValues
Definition: sim_model.h:388
SIM_VALUE::TYPE type
Definition: sim_model.h:379
std::string defaultValue
Definition: sim_model.h:382
std::string description
Definition: sim_model.h:383
std::string value
Definition: sim_model.h:400
const INFO & info
Definition: sim_model.h:401
static constexpr auto NOT_CONNECTED
Definition: sim_model.h:73
const std::string modelPinName
Definition: sim_model.h:70
wxString symbolPinNumber
Definition: sim_model.h:71
std::string modelName
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".