KiCad PCB EDA Suite
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-2023 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>
31#include <sim/sim_model.h>
32#include <sim/sim_model_kibis.h>
36#include <grid_tricks.h>
39#include <kiplatform/ui.h>
40#include <confirm.h>
41#include <string_utils.h>
42#include <locale_io.h>
43#include <wx/filedlg.h>
44#include <wx/textfile.h>
45#include <fmt/format.h>
46
48
49
50template <typename T_symbol, typename T_field>
51DIALOG_SIM_MODEL<T_symbol, T_field>::DIALOG_SIM_MODEL( wxWindow* aParent, T_symbol& aSymbol,
52 std::vector<T_field>& aFields )
53 : DIALOG_SIM_MODEL_BASE( aParent ),
54 m_symbol( aSymbol ),
55 m_fields( aFields ),
56 m_libraryModelsMgr( &Prj() ),
57 m_builtinModelsMgr( &Prj() ),
58 m_prevModel( nullptr ),
59 m_curModelType( SIM_MODEL::TYPE::NONE ),
60 m_scintillaTricks( nullptr ),
61 m_firstCategory( nullptr ),
62 m_prevParamGridSelection( nullptr ),
63 m_lastParamGridWidth( 0 ),
64 m_inKillFocus( false )
65{
67
68 m_sortedPartPins = m_symbol.GetAllLibPins();
69
70 std::sort( m_sortedPartPins.begin(), m_sortedPartPins.end(),
71 []( const LIB_PIN* lhs, const LIB_PIN* rhs )
72 {
73 // We sort by StrNumCmp because SIM_MODEL_BASE sorts with it too.
74 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
75 } );
76
77
78 m_typeChoice->Clear();
79
80 m_scintillaTricks = new SCINTILLA_TRICKS( m_codePreview, wxT( "{}" ), false );
81
82 m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange, this );
83
84 m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY
85 | wxPG_VFB_BEEP
86 | wxPG_VFB_MARK_CELL );
87
88 wxPropertyGrid* grid = m_paramGrid->GetGrid();
89
90 //grid->SetCellBackgroundColour( grid->GetPropertyDefaultCell().GetBgCol() );
91 //grid->SetCellTextColour( grid->GetPropertyDefaultCell().GetFgCol();
92
93 // In wx 3.0 the color will be wrong sometimes.
94 grid->SetCellDisabledTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
95
96 grid->Bind( wxEVT_SET_FOCUS, &DIALOG_SIM_MODEL::onParamGridSetFocus, this );
97
98 grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_RETURN );
99 grid->DedicateKey( WXK_RETURN );
100 grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_RETURN );
101
102 grid->DedicateKey( WXK_UP );
103 grid->DedicateKey( WXK_DOWN );
104
105 m_pinAssignmentsGrid->PushEventHandler( new GRID_TRICKS( m_pinAssignmentsGrid ) );
106
108
109 // Now all widgets have the size fixed, call FinishDialogSettings
111}
112
113
114template <typename T_symbol, typename T_field>
116{
117 // Disable all properties. This is necessary because some of their methods are called after
118 // destruction of DIALOG_SIM_MODEL, oddly. When disabled, they never access their models.
119 for( wxPropertyGridIterator it = m_paramGrid->GetIterator(); !it.AtEnd(); ++it )
120 {
121 SIM_PROPERTY* prop = dynamic_cast<SIM_PROPERTY*>( *it );
122
123 if( !prop )
124 continue;
125
126 prop->Disable();
127 }
128
129 // Delete the GRID_TRICKS.
130 m_pinAssignmentsGrid->PopEventHandler( true );
131
132 delete m_scintillaTricks;
133}
134
135
136template <typename T_symbol, typename T_field>
138{
139 wxCommandEvent dummyEvent;
140 wxString deviceType;
141 wxString modelType;
142 wxString modelParams;
143 wxString pinMap;
144 bool storeInValue = false;
145
146 // Infer RLC and VI models if they aren't specified
147 if( SIM_MODEL::InferSimModel( m_symbol, &m_fields, false, SIM_VALUE_GRAMMAR::NOTATION::SI,
148 &deviceType, &modelType, &modelParams, &pinMap ) )
149 {
150 m_fields.emplace_back( &m_symbol, -1, SIM_DEVICE_TYPE_FIELD );
151 m_fields.back().SetText( deviceType );
152
153 if( !modelType.IsEmpty() )
154 {
155 m_fields.emplace_back( &m_symbol, -1, SIM_TYPE_FIELD );
156 m_fields.back().SetText( modelType );
157 }
158
159 m_fields.emplace_back( &m_symbol, -1, SIM_PARAMS_FIELD );
160 m_fields.back().SetText( modelParams );
161
162 m_fields.emplace_back( &m_symbol, -1, SIM_PINS_FIELD );
163 m_fields.back().SetText( pinMap );
164
165 storeInValue = true;
166
167 // In case the storeInValue checkbox is turned off (if it's left on then we'll overwrite
168 // this field with the actual value):
169 m_fields[ VALUE_FIELD ].SetText( wxT( "${SIM.PARAMS}" ) );
170 }
171
172 std::string libraryFilename = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::LIBRARY_FIELD );
173
174 if( libraryFilename != "" )
175 {
176 // The model is sourced from a library, optionally with instance overrides.
177 m_useLibraryModelRadioButton->SetValue( true );
178
179 if( !loadLibrary( libraryFilename ) )
180 {
181 m_libraryPathText->ChangeValue( libraryFilename );
182 m_modelNameChoice->SetSelection( -1 );
183 m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
184 }
185 else
186 {
187 std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
188 int modelIdx = m_modelNameChoice->FindString( modelName );
189
190 if( modelIdx == wxNOT_FOUND )
191 {
192 DisplayErrorMessage( this, wxString::Format( _( "No model named '%s' in library." ),
193 modelName ) );
194
195 // Default to first item in library
196 m_modelNameChoice->SetSelection( 0 );
197 }
198 else
199 {
200 m_modelNameChoice->SetSelection( modelIdx );
201 }
202
203 m_curModelType = curModel().GetType();
204 }
205
206 if( isIbisLoaded() && ( m_modelNameChoice->GetSelection() >= 0 ) )
207 {
208 int idx = m_modelNameChoice->GetSelection();
209 auto kibismodel = dynamic_cast<SIM_MODEL_KIBIS*>( &m_libraryModelsMgr.GetModels().at( idx ).get() );
210
211 if( kibismodel )
212 {
213 onModelNameChoice( dummyEvent ); // refresh list of pins
214
215 int i = 0;
216
217 for( const std::pair<std::string, std::string>& strs : kibismodel->GetIbisPins() )
218 {
219 if( strs.first == SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY_KIBIS::PIN_FIELD ) )
220 {
221 auto kibisLibrary = static_cast<const SIM_LIBRARY_KIBIS*>( library() );
222
223 kibismodel->ChangePin( *kibisLibrary, strs.first );
224 m_ibisPinCombobox->SetSelection( static_cast<int>( i ) );
225 break;
226 }
227 i++;
228 }
229
230 if( i < static_cast<int>( kibismodel->GetIbisPins().size() ) )
231 {
232 onIbisPinCombobox( dummyEvent ); // refresh list of models
233
234 m_ibisModelCombobox->SetStringSelection(
236 }
237
239 {
240 kibismodel->SwitchSingleEndedDiff( true );
241 m_differentialCheckbox->SetValue( true );
242 }
243 else
244 {
245 kibismodel->SwitchSingleEndedDiff( false );
246 m_differentialCheckbox->SetValue( false );
247 }
248 }
249 }
250 }
251 else
252 {
253 // The model is sourced from the instance.
254 m_useInstanceModelRadioButton->SetValue( true );
255 m_curModelType = SIM_MODEL::ReadTypeFromFields( m_fields );
256 }
257
258 std::vector<LIB_PIN*> sourcePins = m_symbol.GetAllLibPins();
259
260 std::sort( sourcePins.begin(), sourcePins.end(),
261 []( const LIB_PIN* lhs, const LIB_PIN* rhs )
262 {
263 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
264 } );
265
266 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
267 {
268 wxString msg;
269 WX_STRING_REPORTER reporter( &msg );
270
271 m_builtinModelsMgr.SetReporter( &reporter );
272
273 if( m_useInstanceModelRadioButton->GetValue() && type == m_curModelType )
274 m_builtinModelsMgr.CreateModel( m_fields, sourcePins, false );
275 else
276 m_builtinModelsMgr.CreateModel( type, sourcePins );
277
278 if( reporter.HasMessage() )
279 {
280 DisplayErrorMessage( this, _( "Failed to read simulation model from fields." )
281 + wxT( "\n\n" ) + msg );
282 }
283
284 SIM_MODEL::DEVICE_T deviceTypeT = SIM_MODEL::TypeInfo( type ).deviceType;
285
286 if( !m_curModelTypeOfDeviceType.count( deviceTypeT ) )
287 m_curModelTypeOfDeviceType[deviceTypeT] = type;
288 }
289
290 if( storeInValue )
291 curModel().SetIsStoredInValue( true );
292
293 m_saveInValueCheckbox->SetValue( curModel().IsStoredInValue() );
294
295 onRadioButton( dummyEvent );
296 return DIALOG_SIM_MODEL_BASE::TransferDataToWindow();
297}
298
299
300template <typename T_symbol, typename T_field>
302{
303 m_pinAssignmentsGrid->CommitPendingChanges();
304
305 // This should have been done in wxPGTextCtrlEditor::OnTextCtrlEvent(), but something must
306 // be clearing it before we get here, resulting in CommitChangesFromEditor() doing nothing
307 m_paramGrid->GetGrid()->EditorsValueWasModified();
308 m_paramGrid->GetGrid()->CommitChangesFromEditor();
309
310 if( !DIALOG_SIM_MODEL_BASE::TransferDataFromWindow() )
311 return false;
312
313 if( !m_modelNameChoice->IsEmpty() )
314 {
315 std::string modelName = m_modelNameChoice->GetStringSelection().ToStdString();
316
318 }
319
320 std::string path;
321
322 if( m_useLibraryModelRadioButton->GetValue() || isIbisLoaded() )
323 {
324 path = m_libraryPathText->GetValue();
325 wxFileName fn( path );
326
327 if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( ".." ) )
328 path = fn.GetFullPath();
329 }
330
332
333 if( isIbisLoaded() )
334 {
335 SIM_MODEL_KIBIS* ibismodel = static_cast<SIM_MODEL_KIBIS*>(
336 &m_libraryModelsMgr.GetModels().at( m_modelNameChoice->GetSelection() ).get() );
337
338 if( ibismodel )
339 {
342 ibismodel->GetIbisPins().at( m_ibisPinCombobox->GetSelection() ).first );
343
346 std::string( m_ibisModelCombobox->GetValue().c_str() ) );
347
350 ibismodel->CanDifferential() && m_differentialCheckbox->GetValue() ? "1" : "" );
351 }
352 }
353
354 if( curModel().GetType() == SIM_MODEL::TYPE::RAWSPICE )
355 {
356 wxString code = m_codePreview->GetText().Trim( true ).Trim( false );
357 curModel().SetParamValue( "model", std::string( code.ToUTF8() ) );
358 }
359
360 curModel().SetIsStoredInValue( m_saveInValueCheckbox->GetValue() );
361
362 curModel().WriteFields( m_fields );
363
364 return true;
365}
366
367
368template <typename T_symbol, typename T_field>
370{
371 updateIbisWidgets();
372 updateInstanceWidgets();
373 updateModelParamsTab();
374 updateModelCodeTab();
375 updatePinAssignments();
376
377 std::string ref = SIM_MODEL::GetFieldValue( &m_fields, SIM_REFERENCE_FIELD );
378
379 m_modelPanel->Layout();
380 m_pinAssignmentsPanel->Layout();
381 m_parametersPanel->Layout();
382 m_codePanel->Layout();
383
384 SendSizeEvent( wxSEND_EVENT_POST );
385
386 m_prevModel = &curModel();
387}
388
389
390template <typename T_symbol, typename T_field>
392{
393 SIM_MODEL_KIBIS* modelkibis = isIbisLoaded() ? dynamic_cast<SIM_MODEL_KIBIS*>( &curModel() )
394 : nullptr;
395
396 m_ibisModelCombobox->Show( isIbisLoaded() );
397 m_ibisPinCombobox->Show( isIbisLoaded() );
398 m_ibisModelLabel->Show( isIbisLoaded() );
399 m_ibisPinLabel->Show( isIbisLoaded() );
400
401 m_differentialCheckbox->Show( isIbisLoaded() && modelkibis && modelkibis->CanDifferential() );
402 m_modelNameLabel->SetLabel( isIbisLoaded() ? _( "Component:" ) : _( "Model:" ) );
403}
404
405
406template <typename T_symbol, typename T_field>
408{
409 // Change the Type choice to match the current device type.
410 if( &curModel() != m_prevModel )
411 {
412 m_deviceTypeChoice->Clear();
413
414 if( m_useLibraryModelRadioButton->GetValue() )
415 {
416 m_deviceTypeChoice->Append( curModel().GetDeviceInfo().description );
417 m_deviceTypeChoice->SetSelection( 0 );
418 }
419 else
420 {
421 for( SIM_MODEL::DEVICE_T deviceType : SIM_MODEL::DEVICE_T_ITERATOR() )
422 {
423 if( !SIM_MODEL::DeviceInfo( deviceType ).isBuiltin )
424 continue;
425
426 m_deviceTypeChoice->Append( SIM_MODEL::DeviceInfo( deviceType ).description );
427
428 if( deviceType == curModel().GetDeviceType() )
429 m_deviceTypeChoice->SetSelection( m_deviceTypeChoice->GetCount() - 1 );
430 }
431 }
432
433 m_typeChoice->Clear();
434
435 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
436 {
437 if( SIM_MODEL::TypeInfo( type ).deviceType == curModel().GetDeviceType() )
438 {
439 m_typeChoice->Append( SIM_MODEL::TypeInfo( type ).description );
440
441 if( type == curModel().GetType() )
442 m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
443 }
444 }
445 }
446
447 m_typeChoice->Enable( !m_useLibraryModelRadioButton->GetValue() || isIbisLoaded() );
448
449 if( dynamic_cast<SIM_MODEL_RAW_SPICE*>( &curModel() )
450 || dynamic_cast<SIM_MODEL_SPICE_FALLBACK*>( &curModel() ) )
451 {
452 m_modelNotebook->SetSelection( 1 );
453 }
454 else
455 {
456 m_modelNotebook->SetSelection( 0 );
457 }
458
459 if( curModel().HasPrimaryValue() )
460 {
461 const SIM_MODEL::PARAM& primary = curModel().GetParam( 0 );
462
463 m_saveInValueCheckbox->SetLabel( wxString::Format( _( "Save parameter '%s (%s)' in Value "
464 "field" ),
465 primary.info.description,
466 primary.info.name ) );
467 m_saveInValueCheckbox->Enable( true );
468 }
469 else
470 {
471 m_saveInValueCheckbox->SetLabel( _( "Save primary parameter in Value field" ) );
472 m_saveInValueCheckbox->SetValue( false );
473 m_saveInValueCheckbox->Enable( false );
474 }
475}
476
477
478template <typename T_symbol, typename T_field>
480{
481 if( &curModel() != m_prevModel )
482 {
483 // This wxPropertyGridManager column and header stuff has to be here because it segfaults in
484 // the constructor.
485
486 m_paramGridMgr->SetColumnCount( PARAM_COLUMN::END_ );
487
488 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::DESCRIPTION, _( "Parameter" ) );
489 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::UNIT, _( "Unit" ) );
490 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::DEFAULT, _( "Default" ) );
491 m_paramGridMgr->SetColumnTitle( PARAM_COLUMN::TYPE, _( "Type" ) );
492
493 m_paramGridMgr->ShowHeader();
494
495
496 m_paramGrid->Clear();
497
498 m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "Geometry" ) );
499 m_paramGrid->HideProperty( "Geometry" );
500
501 m_paramGrid->Append( new wxPropertyCategory( "AC" ) );
502 m_paramGrid->HideProperty( "AC" );
503
504 m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
505 m_paramGrid->HideProperty( "DC" );
506
507 m_paramGrid->Append( new wxPropertyCategory( "Capacitance" ) );
508 m_paramGrid->HideProperty( "Capacitance" );
509
510 m_paramGrid->Append( new wxPropertyCategory( "Temperature" ) );
511 m_paramGrid->HideProperty( "Temperature" );
512
513 m_paramGrid->Append( new wxPropertyCategory( "Noise" ) );
514 m_paramGrid->HideProperty( "Noise" );
515
516 m_paramGrid->Append( new wxPropertyCategory( "Distributed Quantities" ) );
517 m_paramGrid->HideProperty( "Distributed Quantities" );
518
519 m_paramGrid->Append( new wxPropertyCategory( "Waveform" ) );
520 m_paramGrid->HideProperty( "Waveform" );
521
522 m_paramGrid->Append( new wxPropertyCategory( "Limiting Values" ) );
523 m_paramGrid->HideProperty( "Limiting Values" );
524
525 m_paramGrid->Append( new wxPropertyCategory( "Advanced" ) );
526 m_paramGrid->HideProperty( "Advanced" );
527
528 m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
529 m_paramGrid->HideProperty( "Flags" );
530
531 m_paramGrid->CollapseAll();
532
533 for( int i = 0; i < curModel().GetParamCount(); ++i )
534 addParamPropertyIfRelevant( i );
535
536 m_paramGrid->CollapseAll();
537 m_paramGrid->Expand( "AC" );
538 m_paramGrid->Expand( "Waveform" );
539 }
540
541 adjustParamGridColumns( m_paramGrid->GetGrid()->GetSize().GetX(), true );
542
543 // Set all properties to default colors.
544 // Update properties in models that have autofill.
545 for( wxPropertyGridIterator it = m_paramGrid->GetIterator(); !it.AtEnd(); ++it )
546 {
547 wxColour bgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetBgCol();
548 wxColour fgCol = m_paramGrid->GetGrid()->GetPropertyDefaultCell().GetFgCol();
549
550 for( int col = 0; col < m_paramGridMgr->GetColumnCount(); ++col )
551 {
552 ( *it )->GetCell( col ).SetBgCol( bgCol );
553 ( *it )->GetCell( col ).SetFgCol( fgCol );
554 }
555
556 SIM_PROPERTY* prop = dynamic_cast<SIM_PROPERTY*>( *it );
557
558 if( !prop )
559 continue;
560
561 const SIM_MODEL::PARAM& param = prop->GetParam();
562
563 // Model values other than the currently edited value may have changed. Update them.
564 // This feature is called "autofill" and present only in certain models. Don't do it for
565 // models that don't have it for performance reasons.
566 if( curModel().HasAutofill() )
567 ( *it )->SetValueFromString( param.value->ToString() );
568 }
569}
570
571
572template <typename T_symbol, typename T_field>
574{
575 wxString text;
576 SPICE_ITEM item;
577
578 item.modelName = m_modelNameChoice->GetStringSelection();
579
580 if( m_useInstanceModelRadioButton->GetValue() || item.modelName == "" )
581 item.modelName = m_fields.at( REFERENCE_FIELD ).GetText();
582
583 text << curModel().SpiceGenerator().Preview( item );
584
585 m_codePreview->SetText( text );
586 m_codePreview->SelectNone();
587}
588
589
590template <typename T_symbol, typename T_field>
592{
593 removeOrphanedPinAssignments();
594
595 // Reset the grid.
596
597 m_pinAssignmentsGrid->ClearRows();
598 m_pinAssignmentsGrid->AppendRows( static_cast<int>( m_sortedPartPins.size() ) );
599
600 for( int row = 0; row < m_pinAssignmentsGrid->GetNumberRows(); ++row )
601 m_pinAssignmentsGrid->SetCellValue( row, PIN_COLUMN::MODEL, _( "Not Connected" ) );
602
603 // Now set up the grid values in the Model column.
604 for( int modelPinIndex = 0; modelPinIndex < curModel().GetPinCount(); ++modelPinIndex )
605 {
606 wxString symbolPinNumber = curModel().GetPin( modelPinIndex ).symbolPinNumber;
607
608 if( symbolPinNumber == "" )
609 continue;
610
611 int symbolPinRow = findSymbolPinRow( symbolPinNumber );
612
613 if( symbolPinRow == -1 )
614 continue;
615
616 wxString modelPinString = getModelPinString( modelPinIndex );
617 m_pinAssignmentsGrid->SetCellValue( symbolPinRow, PIN_COLUMN::MODEL, modelPinString );
618 }
619
620 // Set up the Symbol column grid values and Model column cell editors with dropdown options.
621 for( int ii = 0; ii < m_pinAssignmentsGrid->GetNumberRows(); ++ii )
622 {
623 wxString symbolPinString = getSymbolPinString( ii );
624
625 m_pinAssignmentsGrid->SetReadOnly( ii, PIN_COLUMN::SYMBOL );
626 m_pinAssignmentsGrid->SetCellValue( ii, PIN_COLUMN::SYMBOL, symbolPinString );
627
628 wxString curModelPinString = m_pinAssignmentsGrid->GetCellValue( ii, PIN_COLUMN::MODEL );
629
630 std::vector<BITMAPS> modelPinIcons;
631 wxArrayString modelPinChoices;
632
633 for( int jj = 0; jj < curModel().GetPinCount(); ++jj )
634 {
635 if( curModel().GetPin( jj ).symbolPinNumber != "" )
636 modelPinIcons.push_back( PinShapeGetBitmap( GRAPHIC_PINSHAPE::LINE ) );
637 else
638 modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
639
640 modelPinChoices.Add( getModelPinString( jj ) );
641 }
642
643 modelPinIcons.push_back( BITMAPS::INVALID_BITMAP );
644 modelPinChoices.Add( _( "Not Connected" ) );
645
646 // Using `new` here shouldn't cause a memory leak because `SetCellEditor()` calls
647 // `DecRef()` on its last editor.
648 m_pinAssignmentsGrid->SetCellEditor( ii, PIN_COLUMN::MODEL,
649 new GRID_CELL_ICON_TEXT_POPUP( modelPinIcons,
650 modelPinChoices ) );
651 }
652
653 // TODO: Show a preview of the symbol with the pin numbers shown.
654
655 SIM_MODEL* model = &curModel();
656
657 if( model->GetType() == SIM_MODEL::TYPE::SUBCKT )
658 {
659 SIM_MODEL_SUBCKT* subckt = static_cast<SIM_MODEL_SUBCKT*>( model );
660 m_subckt->SetText( subckt->GetSpiceCode() );
661 }
662 else
663 {
664 m_subcktLabel->Show( false );
665 m_subckt->Show( false );
666 }
667}
668
669
670template <typename T_symbol, typename T_field>
672{
673 for( int i = 0; i < curModel().GetPinCount(); ++i )
674 {
675 if( !m_symbol.GetPin( curModel().GetPin( i ).symbolPinNumber ) )
676 curModel().SetPinSymbolPinNumber( i, "" );
677 }
678}
679
680
681template <typename T_symbol, typename T_field>
682bool DIALOG_SIM_MODEL<T_symbol, T_field>::loadLibrary( const wxString& aLibraryPath,
683 bool aForceReload )
684{
685 wxString msg;
686 WX_STRING_REPORTER reporter( &msg );
687
688 m_libraryModelsMgr.SetReporter( &reporter );
689 m_libraryModelsMgr.SetLibrary( aLibraryPath );
690
691 if( reporter.HasMessage() )
692 {
693 DisplayErrorMessage( this, msg );
694 return false;
695 }
696
697 std::vector<LIB_PIN*> sourcePins = m_symbol.GetAllLibPins();
698
699 std::sort( sourcePins.begin(), sourcePins.end(),
700 []( const LIB_PIN* lhs, const LIB_PIN* rhs )
701 {
702 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
703 } );
704
705 std::string modelName = SIM_MODEL::GetFieldValue( &m_fields, SIM_LIBRARY::NAME_FIELD );
706
707 for( auto& [baseModelName, baseModel] : library()->GetModels() )
708 {
709 if( baseModelName == modelName )
710 m_libraryModelsMgr.CreateModel( &baseModel, sourcePins, m_fields );
711 else
712 m_libraryModelsMgr.CreateModel( &baseModel, sourcePins );
713 }
714
715 if( reporter.HasMessage() )
716 DisplayErrorMessage( this, msg );
717
718 m_useLibraryModelRadioButton->SetValue( true );
719 m_libraryPathText->ChangeValue( aLibraryPath );
720
721 wxArrayString modelNames;
722
723 for( auto& [name, model] : library()->GetModels() )
724 modelNames.Add( name );
725
726 m_modelNameChoice->Clear();
727 m_modelNameChoice->Append( modelNames );
728
729 if( isIbisLoaded() )
730 {
731 wxArrayString emptyArray;
732 m_ibisModelCombobox->Set( emptyArray );
733 m_ibisPinCombobox->Set( emptyArray );
734 m_ibisModelCombobox->SetSelection( -1 );
735 m_ibisPinCombobox->SetSelection( -1 );
736 }
737
738 return true;
739}
740
741
742template <typename T_symbol, typename T_field>
744{
745 if( curModel().GetParam( aParamIndex ).info.dir == SIM_MODEL::PARAM::DIR_OUT )
746 return;
747
748 switch( curModel().GetParam( aParamIndex ).info.category )
749 {
750 case CATEGORY::AC:
751 m_paramGrid->HideProperty( "AC", false );
752 m_paramGrid->AppendIn( "AC", newParamProperty( aParamIndex ) );
753 break;
754
755 case CATEGORY::DC:
756 m_paramGrid->HideProperty( "DC", false );
757 m_paramGrid->AppendIn( "DC", newParamProperty( aParamIndex ) );
758 break;
759
761 m_paramGrid->HideProperty( "Capacitance", false );
762 m_paramGrid->AppendIn( "Capacitance", newParamProperty( aParamIndex ) );
763 break;
764
766 m_paramGrid->HideProperty( "Temperature", false );
767 m_paramGrid->AppendIn( "Temperature", newParamProperty( aParamIndex ) );
768 break;
769
770 case CATEGORY::NOISE:
771 m_paramGrid->HideProperty( "Noise", false );
772 m_paramGrid->AppendIn( "Noise", newParamProperty( aParamIndex ) );
773 break;
774
776 m_paramGrid->HideProperty( "Distributed Quantities", false );
777 m_paramGrid->AppendIn( "Distributed Quantities", newParamProperty( aParamIndex ) );
778 break;
779
781 m_paramGrid->HideProperty( "Waveform", false );
782 m_paramGrid->AppendIn( "Waveform", newParamProperty( aParamIndex ) );
783 break;
784
786 m_paramGrid->HideProperty( "Geometry", false );
787 m_paramGrid->AppendIn( "Geometry", newParamProperty( aParamIndex ) );
788 break;
789
791 m_paramGrid->HideProperty( "Limiting Values", false );
792 m_paramGrid->AppendIn( "Limiting Values", newParamProperty( aParamIndex ) );
793 break;
794
796 m_paramGrid->HideProperty( "Advanced", false );
797 m_paramGrid->AppendIn( "Advanced", newParamProperty( aParamIndex ) );
798 break;
799
800 case CATEGORY::FLAGS:
801 m_paramGrid->HideProperty( "Flags", false );
802 m_paramGrid->AppendIn( "Flags", newParamProperty( aParamIndex ) );
803 break;
804
805 default:
806 m_paramGrid->Insert( m_firstCategory, newParamProperty( aParamIndex ) );
807 break;
808
811 return;
812 }
813}
814
815
816template <typename T_symbol, typename T_field>
817wxPGProperty* DIALOG_SIM_MODEL<T_symbol, T_field>::newParamProperty( int aParamIndex ) const
818{
819 const SIM_MODEL::PARAM& param = curModel().GetParam( aParamIndex );
820 wxString paramDescription;
821
822 if( param.info.description == "" )
823 paramDescription = wxString::Format( "%s", param.info.name );
824 else
825 paramDescription = wxString::Format( "%s (%s)", param.info.description, param.info.name );
826
827 wxPGProperty* prop = nullptr;
828
829 switch( param.info.type )
830 {
832 // TODO.
833 prop = new SIM_BOOL_PROPERTY( paramDescription, param.info.name, curModel(), aParamIndex );
834 prop->SetAttribute( wxPG_BOOL_USE_CHECKBOX, true );
835 break;
836
838 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
839 aParamIndex, SIM_VALUE::TYPE_INT );
840 break;
841
843 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
844 aParamIndex, SIM_VALUE::TYPE_FLOAT );
845 break;
846
847 //case TYPE_COMPLEX:
848 // break;
849
851 if( param.info.enumValues.empty() )
852 {
853 prop = new SIM_STRING_PROPERTY( paramDescription, param.info.name, curModel(),
854 aParamIndex, SIM_VALUE::TYPE_STRING );
855 }
856 else
857 {
858 prop = new SIM_ENUM_PROPERTY( paramDescription, param.info.name, curModel(),
859 aParamIndex );
860 }
861 break;
862
863 default:
864 prop = new wxStringProperty( paramDescription, param.info.name );
865 break;
866 }
867
868 prop->SetAttribute( wxPG_ATTR_UNITS, wxString::FromUTF8( param.info.unit.c_str() ) );
869
870 // Legacy due to the way we extracted the parameters from Ngspice.
871 #if wxCHECK_VERSION( 3, 1, 0 )
872 if( param.isOtherVariant )
873 prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValueOfOtherVariant ) );
874 else
875 prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue ) );
876 #else
877 if( param.isOtherVariant )
878 prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValueOfOtherVariant.c_str() ) );
879 else
880 prop->SetCell( 3, wxString::FromUTF8( param.info.defaultValue.c_str() ) );
881 #endif
882
883 wxString typeStr;
884
885 switch( param.info.type )
886 {
887 case SIM_VALUE::TYPE_BOOL: typeStr = wxT( "Bool" ); break;
888 case SIM_VALUE::TYPE_INT: typeStr = wxT( "Int" ); break;
889 case SIM_VALUE::TYPE_FLOAT: typeStr = wxT( "Float" ); break;
890 case SIM_VALUE::TYPE_COMPLEX: typeStr = wxT( "Complex" ); break;
891 case SIM_VALUE::TYPE_STRING: typeStr = wxT( "String" ); break;
892 case SIM_VALUE::TYPE_BOOL_VECTOR: typeStr = wxT( "Bool Vector" ); break;
893 case SIM_VALUE::TYPE_INT_VECTOR: typeStr = wxT( "Int Vector" ); break;
894 case SIM_VALUE::TYPE_FLOAT_VECTOR: typeStr = wxT( "Float Vector" ); break;
895 case SIM_VALUE::TYPE_COMPLEX_VECTOR: typeStr = wxT( "Complex Vector" ); break;
896 }
897
898 prop->SetCell( PARAM_COLUMN::TYPE, typeStr );
899
900 return prop;
901}
902
903
904template <typename T_symbol, typename T_field>
905int DIALOG_SIM_MODEL<T_symbol, T_field>::findSymbolPinRow( const wxString& aSymbolPinNumber ) const
906{
907 for( int row = 0; row < static_cast<int>( m_sortedPartPins.size() ); ++row )
908 {
909 LIB_PIN* pin = m_sortedPartPins[row];
910
911 if( pin->GetNumber() == aSymbolPinNumber )
912 return row;
913 }
914
915 return -1;
916}
917
918
919template <typename T_symbol, typename T_field>
921{
922 if( m_useLibraryModelRadioButton->GetValue()
923 && m_modelNameChoice->GetSelection() != wxNOT_FOUND )
924 {
925 return m_libraryModelsMgr.GetModels().at( m_modelNameChoice->GetSelection() ).get();
926 }
927 else
928 {
929 return m_builtinModelsMgr.GetModels().at( static_cast<int>( m_curModelType ) );
930 }
931}
932
933
934template <typename T_symbol, typename T_field>
936{
937 if( m_libraryModelsMgr.GetLibraries().size() == 1 )
938 return &m_libraryModelsMgr.GetLibraries().begin()->second.get();
939
940 return nullptr;
941}
942
943
944template <typename T_symbol, typename T_field>
946{
947 LIB_PIN* pin = m_sortedPartPins.at( symbolPinIndex );
948 wxString pinNumber;
949 wxString pinName;
950
951 if( pin )
952 {
953 pinNumber = pin->GetShownNumber();
954 pinName = pin->GetShownName();
955 }
956
957 if( !pinName.IsEmpty() && pinName != pinNumber )
958 pinNumber += wxString::Format( wxT( " (%s)" ), pinName );
959
960 return pinNumber;
961}
962
963
964template <typename T_symbol, typename T_field>
966{
967 const wxString& pinName = curModel().GetPin( aModelPinIndex ).name;
968
969 LOCALE_IO toggle;
970
971 wxString pinNumber = wxString::Format( "%d", aModelPinIndex + 1 );
972
973 if( !pinName.IsEmpty() && pinName != pinNumber )
974 pinNumber += wxString::Format( wxT( " (%s)" ), pinName );
975
976 return pinNumber;
977}
978
979
980template <typename T_symbol, typename T_field>
981int DIALOG_SIM_MODEL<T_symbol, T_field>::getModelPinIndex( const wxString& aModelPinString ) const
982{
983 if( aModelPinString == "Not Connected" )
985
986 int length = aModelPinString.Find( " " );
987
988 if( length == wxNOT_FOUND )
989 length = static_cast<int>( aModelPinString.Length() );
990
991 long result = 0;
992 aModelPinString.Mid( 0, length ).ToCLong( &result );
993
994 return static_cast<int>( result - 1 );
995}
996
997
998template <typename T_symbol, typename T_field>
1000{
1001 bool fromLibrary = m_useLibraryModelRadioButton->GetValue();
1002
1003 m_pathLabel->Enable( fromLibrary );
1004 m_libraryPathText->Enable( fromLibrary );
1005 m_browseButton->Enable( fromLibrary );
1006 m_modelNameLabel->Enable( fromLibrary );
1007 m_modelNameChoice->Enable( fromLibrary );
1008 m_ibisPinLabel->Enable( fromLibrary );
1009 m_ibisPinCombobox->Enable( fromLibrary );
1010 m_differentialCheckbox->Enable( fromLibrary );
1011 m_ibisModelLabel->Enable( fromLibrary );
1012 m_ibisModelCombobox->Enable( fromLibrary );
1013
1014 m_staticTextDevType->Enable( !fromLibrary );
1015 m_deviceTypeChoice->Enable( !fromLibrary );
1016 m_staticTextSpiceType->Enable( !fromLibrary );
1017
1018 updateWidgets();
1019}
1020
1021
1022template <typename T_symbol, typename T_field>
1024{
1025 if( m_useLibraryModelRadioButton->GetValue() )
1026 {
1027 wxString path = m_libraryPathText->GetValue();
1028
1029 if( !path.IsEmpty() )
1030 {
1031 try
1032 {
1033 loadLibrary( path );
1034 updateWidgets();
1035 }
1036 catch( const IO_ERROR& )
1037 {
1038 // TODO: Add an infobar to report the error?
1039 }
1040 }
1041 }
1042}
1043
1044
1045template <typename T_symbol, typename T_field>
1047{
1048 if( !m_inKillFocus )
1049 {
1050 m_inKillFocus = true;
1051
1052 wxCommandEvent dummy;
1053 onLibraryPathTextEnter( dummy );
1054
1055 m_inKillFocus = false;
1056 }
1057}
1058
1059
1060template <typename T_symbol, typename T_field>
1062{
1063 static wxString s_mruPath;
1064
1065 wxString path = s_mruPath.IsEmpty() ? Prj().GetProjectPath() : s_mruPath;
1066 wxFileDialog dlg( this, _( "Browse Models" ), path );
1067
1068 if( dlg.ShowModal() == wxID_CANCEL )
1069 return;
1070
1071 path = dlg.GetPath();
1072 wxFileName fn( path );
1073
1074 s_mruPath = fn.GetPath();
1075
1076 if( fn.MakeRelativeTo( Prj().GetProjectPath() ) && !fn.GetFullPath().StartsWith( wxS( ".." ) ) )
1077 path = fn.GetFullPath();
1078
1079 loadLibrary( path, true );
1080 updateWidgets();
1081}
1082
1083
1084template <typename T_symbol, typename T_field>
1086{
1087 if( isIbisLoaded() )
1088 {
1089 wxArrayString pinLabels;
1090 SIM_MODEL_KIBIS* modelkibis = dynamic_cast<SIM_MODEL_KIBIS*>( &curModel() );
1091
1092 wxCHECK2( modelkibis, return );
1093
1094 for( std::pair<wxString, wxString> strs : modelkibis->GetIbisPins() )
1095 pinLabels.Add( strs.first + wxT( " - " ) + strs.second );
1096
1097 m_ibisPinCombobox->Set( pinLabels );
1098
1099 wxArrayString emptyArray;
1100 m_ibisModelCombobox->Set( emptyArray );
1101 }
1102
1103 updateWidgets();
1104}
1105
1106
1107template <typename T_symbol, typename T_field>
1109{
1110 if( isIbisLoaded() )
1111 {
1112 wxArrayString modelLabels;
1113
1114 SIM_MODEL_KIBIS& ibisModel = static_cast<SIM_MODEL_KIBIS&>( curModel() );
1115
1116 std::vector<std::pair<std::string, std::string>> strs = ibisModel.GetIbisPins();
1117 std::string pinNumber = strs.at( m_ibisPinCombobox->GetSelection() ).first;
1118
1119 const SIM_LIBRARY_KIBIS* ibisLibrary = dynamic_cast<const SIM_LIBRARY_KIBIS*>( library() );
1120
1121 ibisModel.ChangePin( *ibisLibrary, pinNumber );
1122
1123 ibisModel.m_enableDiff = ibisLibrary->isPinDiff( ibisModel.GetComponentName(), pinNumber );
1124
1125 for( wxString modelName : ibisModel.GetIbisModels() )
1126 modelLabels.Add( modelName );
1127
1128 m_ibisModelCombobox->Set( modelLabels );
1129 }
1130
1131 updateWidgets();
1132}
1133
1134
1135template <typename T_symbol, typename T_field>
1137{
1138 m_ibisPinCombobox->SetSelection(
1139 m_ibisPinCombobox->FindString( m_ibisPinCombobox->GetValue() ) );
1140
1141 onIbisPinCombobox( aEvent );
1142}
1143
1144
1145template <typename T_symbol, typename T_field>
1147{
1148 updateWidgets();
1149}
1150
1151
1152template <typename T_symbol, typename T_field>
1154{
1155 m_ibisModelCombobox->SetSelection(
1156 m_ibisModelCombobox->FindString( m_ibisModelCombobox->GetValue() ) );
1157
1158 onIbisPinCombobox( aEvent );
1159}
1160
1161template <typename T_symbol, typename T_field>
1163{
1164 if( isIbisLoaded() )
1165 {
1166 SIM_MODEL_KIBIS* modelkibis = dynamic_cast<SIM_MODEL_KIBIS*>( &curModel() );
1167 bool diff = m_differentialCheckbox->GetValue() && modelkibis->CanDifferential();
1168 modelkibis->SwitchSingleEndedDiff( diff );
1169 }
1170
1171 updateWidgets();
1172}
1173
1174
1175template <typename T_symbol, typename T_field>
1177{
1178 for( SIM_MODEL::DEVICE_T deviceType : SIM_MODEL::DEVICE_T_ITERATOR() )
1179 {
1180 if( SIM_MODEL::DeviceInfo( deviceType ).description == m_deviceTypeChoice->GetStringSelection() )
1181 {
1182 m_curModelType = m_curModelTypeOfDeviceType.at( deviceType );
1183 break;
1184 }
1185 }
1186
1187 updateWidgets();
1188}
1189
1190
1191template <typename T_symbol, typename T_field>
1193{
1194 SIM_MODEL::DEVICE_T deviceType = curModel().GetDeviceType();
1195 wxString typeDescription = m_typeChoice->GetString( m_typeChoice->GetSelection() );
1196 std::vector<LIB_PIN*> sourcePins = m_symbol.GetAllLibPins();
1197
1198 std::sort( sourcePins.begin(), sourcePins.end(),
1199 []( const LIB_PIN* lhs, const LIB_PIN* rhs )
1200 {
1201 return StrNumCmp( lhs->GetNumber(), rhs->GetNumber(), true ) < 0;
1202 } );
1203
1204 for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
1205 {
1206 if( deviceType == SIM_MODEL::TypeInfo( type ).deviceType
1207 && typeDescription == SIM_MODEL::TypeInfo( type ).description )
1208 {
1209 if( isIbisLoaded()
1210 && ( type == SIM_MODEL::TYPE::KIBIS_DEVICE
1211 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_DC
1212 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_RECT
1213 || type == SIM_MODEL::TYPE::KIBIS_DRIVER_PRBS ) )
1214 {
1215 int idx = m_modelNameChoice->GetSelection();
1216
1217 auto& kibisModel = static_cast<SIM_MODEL_KIBIS&>( m_libraryModelsMgr.GetModels().at( idx ).get() );
1218
1219 m_libraryModelsMgr.SetModel( idx, std::make_unique<SIM_MODEL_KIBIS>( type, kibisModel,
1220 m_fields, sourcePins ) );
1221 }
1222
1223 m_curModelType = type;
1224 break;
1225 }
1226 }
1227
1228 m_curModelTypeOfDeviceType.at( deviceType ) = m_curModelType;
1229 updateWidgets();
1230}
1231
1232
1233template <typename T_symbol, typename T_field>
1235{
1236 // This should have been done in wxPGTextCtrlEditor::OnTextCtrlEvent(), but something must
1237 // be clearing it before we get here, resulting in CommitChangesFromEditor() doing nothing
1238 m_paramGrid->GetGrid()->EditorsValueWasModified();
1239 m_paramGrid->GetGrid()->CommitChangesFromEditor();
1240
1241 updateModelCodeTab();
1242}
1243
1244
1245template <typename T_symbol, typename T_field>
1247{
1248 int symbolPinIndex = aEvent.GetRow();
1249 wxString oldModelPinName = aEvent.GetString();
1250 wxString modelPinName = m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() );
1251
1252 int oldModelPinIndex = getModelPinIndex( oldModelPinName );
1253 int modelPinIndex = getModelPinIndex( modelPinName );
1254
1255 if( oldModelPinIndex != SIM_MODEL::PIN::NOT_CONNECTED )
1256 curModel().SetPinSymbolPinNumber( oldModelPinIndex, "" );
1257
1258 if( modelPinIndex != SIM_MODEL::PIN::NOT_CONNECTED )
1259 {
1260 curModel().SetPinSymbolPinNumber( modelPinIndex,
1261 std::string( m_sortedPartPins.at( symbolPinIndex )->GetShownNumber().ToUTF8() ) );
1262 }
1263
1264 updatePinAssignments();
1265
1266 aEvent.Skip();
1267}
1268
1269
1270template <typename T_symbol, typename T_field>
1272{
1273 wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinAssignmentsGrid );
1274
1275 int gridWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinAssignmentsGrid ).x;
1276 m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::MODEL, gridWidth / 2 );
1277 m_pinAssignmentsGrid->SetColSize( PIN_COLUMN::SYMBOL, gridWidth / 2 );
1278
1279 aEvent.Skip();
1280}
1281
1282
1283template <typename T_symbol, typename T_field>
1285{
1286 // By default, when a property grid is focused, the textbox is not immediately focused until
1287 // Tab key is pressed. This is inconvenient, so we fix that here.
1288
1289 wxPropertyGrid* grid = m_paramGrid->GetGrid();
1290
1291 grid->CommitChangesFromEditor();
1292
1293 wxPGProperty* selected = grid->GetSelection();
1294
1295 if( !selected )
1296 selected = grid->wxPropertyGridInterface::GetFirst();
1297
1298 if( selected )
1299 grid->DoSelectProperty( selected, wxPG_SEL_FOCUS );
1300
1301 aEvent.Skip();
1302}
1303
1304
1305template <typename T_symbol, typename T_field>
1307{
1308 wxPropertyGrid* grid = m_paramGrid->GetGrid();
1309
1310 grid->CommitChangesFromEditor();
1311
1312 // Jump over categories.
1313 if( grid->GetSelection() && grid->GetSelection()->IsCategory() )
1314 {
1315 wxPGProperty* selection = grid->GetSelection();
1316
1317 // If the new selection is immediately above the previous selection, we jump up. Otherwise
1318 // we jump down. We do this by simulating up or down arrow keys.
1319
1320 wxPropertyGridIterator it = grid->GetIterator( wxPG_ITERATE_VISIBLE, selection );
1321 it.Next();
1322
1323 wxKeyEvent* keyEvent = new wxKeyEvent( wxEVT_KEY_DOWN );
1324
1325 if( *it == m_prevParamGridSelection )
1326 {
1327 if( !selection->IsExpanded() )
1328 {
1329 grid->Expand( selection );
1330 keyEvent->m_keyCode = WXK_DOWN;
1331 wxQueueEvent( grid, keyEvent );
1332
1333 // Does not work for some reason.
1334 /*m_paramGrid->DoSelectProperty( selection->Item( selection->GetChildCount() - 1 ),
1335 wxPG_SEL_FOCUS );*/
1336 }
1337 else
1338 {
1339 keyEvent->m_keyCode = WXK_UP;
1340 wxQueueEvent( grid, keyEvent );
1341 }
1342 }
1343 else
1344 {
1345 if( !selection->IsExpanded() )
1346 grid->Expand( selection );
1347
1348 keyEvent->m_keyCode = WXK_DOWN;
1349 wxQueueEvent( grid, keyEvent );
1350 }
1351
1352 m_prevParamGridSelection = grid->GetSelection();
1353 return;
1354 }
1355
1356 wxWindow* editorControl = grid->GetEditorControl();
1357 if( !editorControl )
1358 {
1359 m_prevParamGridSelection = grid->GetSelection();
1360 return;
1361 }
1362
1363 // Without this the user had to press tab before they could edit the field.
1364 editorControl->SetFocus();
1365 m_prevParamGridSelection = grid->GetSelection();
1366}
1367
1368
1369template <typename T_symbol, typename T_field>
1371{
1372 wxPropertyGrid* grid = m_paramGridMgr->GetGrid();
1373 int margin = 15;
1374 int indent = 20;
1375
1376 if( aWidth != m_lastParamGridWidth || aForce )
1377 {
1378 m_lastParamGridWidth = aWidth;
1379
1380 grid->FitColumns();
1381
1382 std::vector<int> colWidths;
1383
1384 for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
1385 {
1386 if( ii == 0 )
1387 colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin + indent );
1388 else if( ii == 1 )
1389 colWidths.push_back( grid->GetState()->GetColumnWidth( ii ) + margin );
1390 else
1391 colWidths.push_back( 50 );
1392
1393 aWidth -= colWidths[ ii ];
1394 }
1395
1396 // Account for scroll bars
1397 aWidth -= ( grid->GetSize().x - grid->GetClientSize().x );
1398
1399 if( aWidth > 0 )
1400 colWidths[ PARAM_COLUMN::VALUE ] += aWidth;
1401
1402 for( size_t ii = 0; ii < grid->GetColumnCount(); ii++ )
1403 grid->SetColumnProportion( ii, colWidths[ ii ] );
1404
1405 grid->ResetColumnSizes();
1406 grid->RefreshEditor();
1407 }
1408}
1409
1410
1411template <typename T_symbol, typename T_field>
1413{
1414 adjustParamGridColumns( event.GetSize().GetX(), false );
1415
1416 event.Skip();
1417}
1418
1419
1420
const char * name
Definition: DXF_plotter.cpp:56
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
@ small_folder
@ 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
wxPropertyGridPage * m_paramGrid
wxStyledTextCtrl * m_codePreview
void onTypeChoice(wxCommandEvent &aEvent) override
void onRadioButton(wxCommandEvent &aEvent) override
std::vector< LIB_PIN * > m_sortedPartPins
SCINTILLA_TRICKS * m_scintillaTricks
DIALOG_SIM_MODEL(wxWindow *aParent, T_symbol &aSymbol, std::vector< T_field > &aFields)
bool loadLibrary(const wxString &aLibraryPath, bool aForceReload=false)
void addParamPropertyIfRelevant(int aParamIndex)
void removeOrphanedPinAssignments()
void onPinAssignmentsGridCellChange(wxGridEvent &aEvent) override
void onPageChanging(wxNotebookEvent &event) override
void onParamGridSelectionChange(wxPropertyGridEvent &aEvent)
int findSymbolPinRow(const wxString &aSymbolPinNumber) const
void adjustParamGridColumns(int aWidth, bool aForce)
void onDeviceTypeChoice(wxCommandEvent &aEvent) override
const SIM_LIBRARY * library() const
SIM_MODEL & curModel() const
int getModelPinIndex(const wxString &aModelPinString) const
void onSizeParamGrid(wxSizeEvent &event) override
wxString getModelPinString(int aModelPinIndex) const
bool TransferDataToWindow() override
void onLibraryPathTextEnter(wxCommandEvent &aEvent) override
void onBrowseButtonClick(wxCommandEvent &aEvent) override
wxString getSymbolPinString(int aSymbolPinNumber) const
void onIbisModelCombobox(wxCommandEvent &event) override
bool TransferDataFromWindow() override
void onDifferentialCheckbox(wxCommandEvent &event) override
void onIbisModelComboboxTextEnter(wxCommandEvent &event) override
void onLibraryPathTextKillFocus(wxFocusEvent &aEvent) override
void onIbisPinComboboxTextEnter(wxCommandEvent &event) override
void onModelNameChoice(wxCommandEvent &aEvent) override
void onParamGridSetFocus(wxFocusEvent &aEvent)
void onIbisPinCombobox(wxCommandEvent &event) override
void onPinAssignmentsGridSize(wxSizeEvent &aEvent) override
wxPGProperty * newParamProperty(int aParamIndex) const
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:76
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:41
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:126
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
bool isPinDiff(const std::string &aComp, const std::string &aPinNumber) const
static constexpr auto DIFF_FIELD
static constexpr auto MODEL_FIELD
static constexpr auto PIN_FIELD
static constexpr auto LIBRARY_FIELD
Definition: sim_library.h:35
static constexpr auto NAME_FIELD
Definition: sim_library.h:36
bool ChangePin(const SIM_LIBRARY_KIBIS &aLib, std::string aPinNumber)
update the list of available models based on the pin number.
std::vector< std::string > GetIbisModels() const
std::string GetComponentName() const
bool CanDifferential() const
void SwitchSingleEndedDiff(bool aDiff) override
std::vector< std::pair< std::string, std::string > > GetIbisPins() const
std::string GetSpiceCode() const
static bool InferSimModel(T_symbol &aSymbol, std::vector< T_field > *aFields, bool aResolve, SIM_VALUE_GRAMMAR::NOTATION aNotation, wxString *aDeviceType, wxString *aModelType, wxString *aModelParams, wxString *aPinMap)
Definition: sim_model.cpp:1076
static INFO TypeInfo(TYPE aType)
Definition: sim_model.cpp:94
static void SetFieldValue(std::vector< T > &aFields, const wxString &aFieldName, const std::string &aValue)
Definition: sim_model.cpp:640
static TYPE ReadTypeFromFields(const std::vector< T > &aFields)
Definition: sim_model.cpp:368
static std::string GetFieldValue(const std::vector< T > *aFields, const wxString &aFieldName, bool aResolve=true)
Definition: sim_model.cpp:612
static DEVICE_INFO DeviceInfo(DEVICE_T aDeviceType)
Definition: sim_model.cpp:57
TYPE GetType() const
Definition: sim_model.h:462
const SIM_MODEL::PARAM & GetParam() const
Definition: sim_property.h:53
@ 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
void SetBitmap(const wxBitmap &aBmp)
A wrapper for reporting to a wxString object.
Definition: reporter.h:164
bool HasMessage() const override
Returns true if the reporter client is non-empty.
Definition: reporter.cpp:69
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:325
This file is part of the common library.
#define _(s)
@ NONE
Definition: kibis.h:53
PROJECT & Prj()
Definition: kicad.cpp:573
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: gtk/ui.cpp:126
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:156
BITMAPS PinShapeGetBitmap(GRAPHIC_PINSHAPE aShape)
Definition: pin_type.cpp:288
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
SIM_MODEL::TYPE TYPE
Definition: sim_model.cpp:54
#define SIM_PINS_FIELD
Definition: sim_model.h:53
#define SIM_DEVICE_TYPE_FIELD
Definition: sim_model.h:51
#define SIM_TYPE_FIELD
Definition: sim_model.h:52
#define SIM_REFERENCE_FIELD
Definition: sim_model.h:48
#define SIM_PARAMS_FIELD
Definition: sim_model.h:54
std::vector< FAB_LAYER_COLOR > dummy
std::vector< std::string > enumValues
Definition: sim_model.h:343
SIM_VALUE::TYPE type
Definition: sim_model.h:332
std::string defaultValue
Definition: sim_model.h:336
std::string defaultValueOfOtherVariant
Definition: sim_model.h:337
std::string description
Definition: sim_model.h:338
std::unique_ptr< SIM_VALUE > value
Definition: sim_model.h:380
const INFO & info
Definition: sim_model.h:381
static constexpr auto NOT_CONNECTED
Definition: sim_model.h:293
std::string modelName
@ VALUE_FIELD
Field Value of part, i.e. "3.3K".
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".