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