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