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