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