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