KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_symbol_properties.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <memory>
27
28#include <bitmaps.h>
29#include <wx/tooltip.h>
30#include <grid_tricks.h>
31#include <confirm.h>
32#include <kiface_base.h>
33#include <pin_numbers.h>
34#include <string_utils.h>
35#include <kiplatform/ui.h>
40#include <sch_collectors.h>
41#include <fields_grid_table.h>
42#include <sch_edit_frame.h>
43#include <sch_reference_list.h>
44#include <schematic.h>
45#include <sch_commit.h>
46#include <tool/tool_manager.h>
47#include <tool/actions.h>
48
49#include <dialog_sim_model.h>
50
51
52wxDEFINE_EVENT( SYMBOL_DELAY_FOCUS, wxCommandEvent );
53wxDEFINE_EVENT( SYMBOL_DELAY_SELECTION, wxCommandEvent );
54
65
66
67class SCH_PIN_TABLE_DATA_MODEL : public WX_GRID_TABLE_BASE, public std::vector<SCH_PIN>
68{
69public:
71 m_readOnlyAttr( nullptr ),
72 m_typeAttr( nullptr ),
73 m_shapeAttr( nullptr )
74 {
75 }
76
78 {
79 for( wxGridCellAttr* attr : m_nameAttrs )
80 attr->DecRef();
81
82 m_readOnlyAttr->DecRef();
83 m_typeAttr->DecRef();
84 m_shapeAttr->DecRef();
85 }
86
88 {
89 for( wxGridCellAttr* attr : m_nameAttrs )
90 attr->DecRef();
91
92 m_nameAttrs.clear();
93
94 if( m_readOnlyAttr )
95 m_readOnlyAttr->DecRef();
96
97 m_readOnlyAttr = new wxGridCellAttr;
98 m_readOnlyAttr->SetReadOnly( true );
99
100 for( const SCH_PIN& pin : *this )
101 {
102 SCH_PIN* lib_pin = pin.GetLibPin();
103 wxGridCellAttr* attr = nullptr;
104
105 if( !lib_pin || lib_pin->GetAlternates().empty() )
106 {
107 attr = new wxGridCellAttr;
108 attr->SetReadOnly( true );
109 attr->SetBackgroundColour( KIPLATFORM::UI::GetDialogBGColour() );
110 }
111 else
112 {
113 wxArrayString choices;
114 choices.push_back( lib_pin->GetName() );
115
116 for( const std::pair<const wxString, SCH_PIN::ALT>& alt : lib_pin->GetAlternates() )
117 choices.push_back( alt.first );
118
119 attr = new wxGridCellAttr();
120 attr->SetEditor( new GRID_CELL_COMBOBOX( choices ) );
121 }
122
123 m_nameAttrs.push_back( attr );
124 }
125
126 if( m_typeAttr )
127 m_typeAttr->DecRef();
128
129 m_typeAttr = new wxGridCellAttr;
131 m_typeAttr->SetReadOnly( true );
132
133 if( m_shapeAttr )
134 m_shapeAttr->DecRef();
135
136 m_shapeAttr = new wxGridCellAttr;
138 m_shapeAttr->SetReadOnly( true );
139 }
140
141 int GetNumberRows() override { return (int) size(); }
142 int GetNumberCols() override { return COL_COUNT; }
143
144 wxString GetColLabelValue( int aCol ) override
145 {
146 switch( aCol )
147 {
148 case COL_NUMBER: return _( "Number" );
149 case COL_BASE_NAME: return _( "Base Name" );
150 case COL_ALT_NAME: return _( "Alternate Assignment" );
151 case COL_TYPE: return _( "Electrical Type" );
152 case COL_SHAPE: return _( "Graphic Style" );
153 default: wxFAIL; return wxEmptyString;
154 }
155 }
156
157 bool IsEmptyCell( int row, int col ) override
158 {
159 return false; // don't allow adjacent cell overflow, even if we are actually empty
160 }
161
162 bool CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) override
163 {
164 // Don't accept random values; must use the popup to change to a known alternate
165 return false;
166 }
167
168 wxString GetValue( int aRow, int aCol ) override
169 {
170 return GetValue( at( aRow ), aCol );
171 }
172
173 static wxString GetValue( const SCH_PIN& aPin, int aCol )
174 {
175 if( aCol == COL_ALT_NAME )
176 {
177 if( !aPin.GetLibPin() || aPin.GetLibPin()->GetAlternates().empty() )
178 return wxEmptyString;
179 else if( aPin.GetAlt().IsEmpty() )
180 return aPin.GetName();
181 else
182 return aPin.GetAlt();
183 }
184
185 switch( aCol )
186 {
187 case COL_NUMBER: return aPin.GetNumber();
188 case COL_BASE_NAME: return aPin.GetBaseName();
189 case COL_TYPE: return PinTypeNames()[static_cast<int>( aPin.GetType() )];
190 case COL_SHAPE: return PinShapeNames()[static_cast<int>( aPin.GetShape() )];
191 default: wxFAIL; return wxEmptyString;
192 }
193 }
194
195 wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) override
196 {
197 switch( aCol )
198 {
199 case COL_NUMBER:
200 case COL_BASE_NAME:
201 m_readOnlyAttr->IncRef();
202 return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind );
203
204 case COL_ALT_NAME:
205 m_nameAttrs[ aRow ]->IncRef();
206 return enhanceAttr( m_nameAttrs[ aRow ], aRow, aCol, aKind );
207
208 case COL_TYPE:
209 m_typeAttr->IncRef();
210 return enhanceAttr( m_typeAttr, aRow, aCol, aKind );
211
212 case COL_SHAPE:
213 m_shapeAttr->IncRef();
214 return enhanceAttr( m_shapeAttr, aRow, aCol, aKind );
215
216 default:
217 wxFAIL;
218 return nullptr;
219 }
220 }
221
222 void SetValue( int aRow, int aCol, const wxString &aValue ) override
223 {
224 SCH_PIN& pin = at( aRow );
225
226 switch( aCol )
227 {
228 case COL_ALT_NAME:
229 if( pin.GetLibPin() && aValue == pin.GetLibPin()->GetName() )
230 pin.SetAlt( wxEmptyString );
231 else
232 pin.SetAlt( aValue );
233 break;
234
235 case COL_NUMBER:
236 case COL_BASE_NAME:
237 case COL_TYPE:
238 case COL_SHAPE:
239 // Read-only.
240 break;
241
242 default:
243 wxFAIL;
244 break;
245 }
246 }
247
248 static bool compare( const SCH_PIN& lhs, const SCH_PIN& rhs, int sortCol, bool ascending )
249 {
250 wxString lhStr = GetValue( lhs, sortCol );
251 wxString rhStr = GetValue( rhs, sortCol );
252
253 if( lhStr == rhStr )
254 {
255 // Secondary sort key is always COL_NUMBER
256 sortCol = COL_NUMBER;
257 lhStr = GetValue( lhs, sortCol );
258 rhStr = GetValue( rhs, sortCol );
259 }
260
261 bool res;
262
263 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
264 // to get the opposite sort. i.e. ~(a<b) != (a>b)
265 auto cmp = [ ascending ]( const auto a, const auto b )
266 {
267 if( ascending )
268 return a < b;
269 else
270 return b < a;
271 };
272
273 switch( sortCol )
274 {
275 case COL_NUMBER:
276 case COL_BASE_NAME:
277 case COL_ALT_NAME:
278 res = cmp( PIN_NUMBERS::Compare( lhStr, rhStr ), 0 );
279 break;
280 case COL_TYPE:
281 case COL_SHAPE:
282 res = cmp( lhStr.CmpNoCase( rhStr ), 0 );
283 break;
284 default:
285 res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
286 break;
287 }
288
289 return res;
290 }
291
292 void SortRows( int aSortCol, bool ascending )
293 {
294 std::sort( begin(), end(),
295 [ aSortCol, ascending ]( const SCH_PIN& lhs, const SCH_PIN& rhs ) -> bool
296 {
297 return compare( lhs, rhs, aSortCol, ascending );
298 } );
299 }
300
301protected:
302 std::vector<wxGridCellAttr*> m_nameAttrs;
303 wxGridCellAttr* m_readOnlyAttr;
304 wxGridCellAttr* m_typeAttr;
305 wxGridCellAttr* m_shapeAttr;
306};
307
308
311 m_symbol( nullptr ),
312 m_part( nullptr ),
314 m_editorShown( false ),
315 m_fields( nullptr ),
316 m_dataModel( nullptr )
317{
318 m_symbol = aSymbol;
319 m_part = m_symbol->GetLibSymbolRef().get();
320
321 // GetLibSymbolRef() now points to the cached part in the schematic, which should always be
322 // there for usual cases, but can be null when opening old schematics not storing the part
323 // so we need to handle m_part == nullptr
324 // wxASSERT( m_part );
325
326 m_fields = new FIELDS_GRID_TABLE( this, aParent, m_fieldsGrid, m_symbol );
327
328 m_fieldsGrid->SetTable( m_fields );
329 m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this,
330 { &aParent->Schematic(), m_part },
331 [&]( wxCommandEvent& aEvent )
332 {
333 OnAddField( aEvent );
334 } ) );
335 m_fieldsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
336
337 // Show/hide columns according to user's preference
338 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
339 {
340 m_fieldsGrid->ShowHideColumns( cfg->m_Appearance.edit_symbol_visible_columns );
341 m_shownColumns = m_fieldsGrid->GetShownColumns();
342 }
343
344 if( m_part && m_part->IsMultiBodyStyle() )
345 {
346 // Multiple body styles are a superclass of alternate pin assignments, so don't allow
347 // free-form alternate assignments as well. (We won't know how to map the alternates
348 // back and forth when the body style is changed.)
349 m_pinTablePage->Disable();
350 m_pinTablePage->SetToolTip( _( "Alternate pin assignments are not available for symbols with multiple "
351 "body styles." ) );
352 }
353 else
354 {
356
357 // Make a copy of the pins for editing
358 for( const std::unique_ptr<SCH_PIN>& pin : m_symbol->GetRawPins() )
359 m_dataModel->push_back( *pin );
360
361 m_dataModel->SortRows( COL_NUMBER, true );
362 m_dataModel->BuildAttrs();
363
364 m_pinGrid->SetTable( m_dataModel );
365 }
366
367 if( m_part && m_part->IsPower() )
368 m_spiceFieldsButton->Hide();
369
370 m_pinGrid->PushEventHandler( new GRID_TRICKS( m_pinGrid ) );
371 m_pinGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
372
373 wxFont infoFont = KIUI::GetSmallInfoFont( this );
374 m_libraryIDLabel->SetFont( infoFont );
375 m_tcLibraryID->SetFont( infoFont );
376 m_tcLibraryID->SetBackgroundColour( KIPLATFORM::UI::GetDialogBGColour() );
377
378 wxToolTip::Enable( true );
380
381 // Configure button logos
386
387 // wxFormBuilder doesn't include this event...
388 m_fieldsGrid->Bind( wxEVT_GRID_CELL_CHANGING, &DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging, this );
389 m_pinGrid->Bind( wxEVT_GRID_COL_SORT, &DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort, this );
390 Bind( SYMBOL_DELAY_FOCUS, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedFocus, this );
391 Bind( SYMBOL_DELAY_SELECTION, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedSelection, this );
392
393 wxCommandEvent* evt = new wxCommandEvent( SYMBOL_DELAY_SELECTION );
394 evt->SetClientData( new VECTOR2I( 0, FDC_VALUE ) );
395 QueueEvent( evt );
396 evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
397 evt->SetClientData( new VECTOR2I( 0, FDC_VALUE ) );
398 QueueEvent( evt );
399
401}
402
403
405{
406 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
407 {
408 cfg->m_Appearance.edit_symbol_visible_columns = m_fieldsGrid->GetShownColumnsAsString();
409 cfg->m_Appearance.edit_symbol_width = GetSize().x;
410 cfg->m_Appearance.edit_symbol_height = GetSize().y;
411 }
412
413 // Prevents crash bug in wxGrid's d'tor
414 m_fieldsGrid->DestroyTable( m_fields );
415
416 if( m_dataModel )
417 m_pinGrid->DestroyTable( m_dataModel );
418
419 m_fieldsGrid->Unbind( wxEVT_GRID_CELL_CHANGING, &DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging, this );
420 m_pinGrid->Unbind( wxEVT_GRID_COL_SORT, &DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort, this );
421 Unbind( SYMBOL_DELAY_FOCUS, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedFocus, this );
422 Unbind( SYMBOL_DELAY_SELECTION, &DIALOG_SYMBOL_PROPERTIES::HandleDelayedSelection, this );
423
424 // Delete the GRID_TRICKS.
425 m_fieldsGrid->PopEventHandler( true );
426 m_pinGrid->PopEventHandler( true );
427}
428
429
431{
432 return dynamic_cast<SCH_EDIT_FRAME*>( wxDialog::GetParent() );
433}
434
435
437{
438 if( !wxDialog::TransferDataToWindow() )
439 return false;
440
441 std::set<wxString> defined;
442
443 // Push a copy of each field into m_updateFields
444 for( SCH_FIELD& srcField : m_symbol->GetFields() )
445 {
446 SCH_FIELD field( srcField );
447
448 // change offset to be symbol-relative
449 field.Offset( -m_symbol->GetPosition() );
450
451 field.SetText( m_symbol->Schematic()->ConvertKIIDsToRefs( field.GetText() ) );
452
453 defined.insert( field.GetName() );
454 m_fields->push_back( field );
455 }
456
457 // Add in any template fieldnames not yet defined:
458 for( const TEMPLATE_FIELDNAME& templateFieldname :
459 GetParent()->Schematic().Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
460 {
461 if( defined.count( templateFieldname.m_Name ) <= 0 )
462 {
463 SCH_FIELD field( m_symbol, FIELD_T::USER, templateFieldname.m_Name );
464 field.SetVisible( templateFieldname.m_Visible );
465 m_fields->push_back( field );
466 }
467 }
468
469 // notify the grid
470 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->GetNumberRows() );
471 m_fieldsGrid->ProcessTableMessage( msg );
472
473 // If a multi-unit symbol, set up the unit selector and interchangeable checkbox.
474 if( m_symbol->IsMultiUnit() )
475 {
476 // Ensure symbol unit is the currently selected unit (mandatory in complex hierarchies)
477 // from the current sheet path, because it can be modified by previous calculations
478 m_symbol->SetUnit( m_symbol->GetUnitSelection( &GetParent()->GetCurrentSheet() ) );
479
480 for( int ii = 1; ii <= m_symbol->GetUnitCount(); ii++ )
481 m_unitChoice->Append( m_symbol->GetUnitDisplayName( ii, false ) );
482
483 if( m_symbol->GetUnit() <= ( int )m_unitChoice->GetCount() )
484 m_unitChoice->SetSelection( m_symbol->GetUnit() - 1 );
485 }
486 else
487 {
488 m_unitLabel->Enable( false );
489 m_unitChoice->Enable( false );
490 }
491
492 if( m_part && m_part->IsMultiBodyStyle() )
493 {
494 if( m_part->HasDeMorganBodyStyles() )
495 {
496 m_bodyStyleChoice->Append( _( "Standard" ) );
497 m_bodyStyleChoice->Append( _( "Alternate" ) );
498 }
499 else
500 {
501 wxASSERT( (int)m_part->GetBodyStyleNames().size() == m_part->GetBodyStyleCount() );
502
503 for( int ii = 0; ii < m_part->GetBodyStyleCount(); ii++ )
504 {
505 try
506 {
507 m_bodyStyleChoice->Append( m_part->GetBodyStyleNames().at( ii ) );
508 }
509 catch( ... )
510 {
511 m_bodyStyleChoice->Append( wxT( "???" ) );
512 }
513 }
514 }
515
516 if( m_symbol->GetBodyStyle() <= (int) m_bodyStyleChoice->GetCount() )
517 m_bodyStyleChoice->SetSelection( m_symbol->GetBodyStyle() - 1 );
518 }
519 else
520 {
521 m_bodyStyle->Enable( false );
522 m_bodyStyleChoice->Enable( false );
523 }
524
525 // Set the symbol orientation and mirroring.
526 int orientation = m_symbol->GetOrientation() & ~( SYM_MIRROR_X | SYM_MIRROR_Y );
527
528 switch( orientation )
529 {
530 default:
531 case SYM_ORIENT_0: m_orientationCtrl->SetSelection( 0 ); break;
532 case SYM_ORIENT_90: m_orientationCtrl->SetSelection( 1 ); break;
533 case SYM_ORIENT_270: m_orientationCtrl->SetSelection( 2 ); break;
534 case SYM_ORIENT_180: m_orientationCtrl->SetSelection( 3 ); break;
535 }
536
537 int mirror = m_symbol->GetOrientation() & ( SYM_MIRROR_X | SYM_MIRROR_Y );
538
539 switch( mirror )
540 {
541 default: m_mirrorCtrl->SetSelection( 0 ) ; break;
542 case SYM_MIRROR_X: m_mirrorCtrl->SetSelection( 1 ); break;
543 case SYM_MIRROR_Y: m_mirrorCtrl->SetSelection( 2 ); break;
544 }
545
546 m_cbExcludeFromSim->SetValue( m_symbol->GetExcludedFromSim() );
547 m_cbExcludeFromBom->SetValue( m_symbol->GetExcludedFromBOM() );
548 m_cbExcludeFromBoard->SetValue( m_symbol->GetExcludedFromBoard() );
549 m_cbDNP->SetValue( m_symbol->GetDNP( &GetParent()->GetCurrentSheet() ) );
550
551 if( m_part )
552 {
553 m_ShowPinNumButt->SetValue( m_part->GetShowPinNumbers() );
554 m_ShowPinNameButt->SetValue( m_part->GetShowPinNames() );
555 }
556
557 // Set the symbol's library name.
558 m_tcLibraryID->SetValue( UnescapeString( m_symbol->GetLibId().Format() ) );
559
560 Layout();
561 m_fieldsGrid->Layout();
562
563#ifdef __WXGTK__
564 wxSafeYield();
565#endif
566
567 return true;
568}
569
570
572{
573 if( !m_fieldsGrid->CommitPendingChanges() )
574 return;
575
576 m_fieldsGrid->ClearSelection();
577
578 std::vector<SCH_FIELD> fields;
579
580 for( const SCH_FIELD& field : *m_fields )
581 fields.emplace_back( field );
582
583 DIALOG_SIM_MODEL dialog( this, m_parentFrame, *m_symbol, fields );
584
585 if( dialog.ShowModal() != wxID_OK )
586 return;
587
588 // Add in any new fields
589 for( const SCH_FIELD& editedField : fields )
590 {
591 bool found = false;
592
593 for( SCH_FIELD& existingField : *m_fields )
594 {
595 if( existingField.GetName() == editedField.GetName() )
596 {
597 found = true;
598 existingField.SetText( editedField.GetText() );
599 break;
600 }
601 }
602
603 if( !found )
604 {
605 m_fields->emplace_back( editedField );
606 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
607 m_fieldsGrid->ProcessTableMessage( msg );
608 }
609 }
610
611 // Remove any deleted fields
612 for( int ii = (int) m_fields->size() - 1; ii >= 0; --ii )
613 {
614 SCH_FIELD& existingField = m_fields->at( ii );
615 bool found = false;
616
617 for( SCH_FIELD& editedField : fields )
618 {
619 if( editedField.GetName() == existingField.GetName() )
620 {
621 found = true;
622 break;
623 }
624 }
625
626 if( !found )
627 {
628 m_fieldsGrid->ClearSelection();
629 m_fields->erase( m_fields->begin() + ii );
630
631 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, ii, 1 );
632 m_fieldsGrid->ProcessTableMessage( msg );
633 }
634 }
635
636 OnModify();
637 m_fieldsGrid->ForceRefresh();
638}
639
640
642{
643 // Running the Footprint Browser gums up the works and causes the automatic cancel
644 // stuff to no longer work. So we do it here ourselves.
645 EndQuasiModal( wxID_CANCEL );
646}
647
648
650{
651 LIB_ID id;
652
653 if( !m_fieldsGrid->CommitPendingChanges() || !m_fieldsGrid->Validate() )
654 return false;
655
656 // Check for missing field names.
657 for( size_t i = 0; i < m_fields->size(); ++i )
658 {
659 SCH_FIELD& field = m_fields->at( i );
660
661 if( field.IsMandatory() )
662 continue;
663
664 wxString fieldName = field.GetName( false );
665
666 if( fieldName.IsEmpty() )
667 {
668 DisplayErrorMessage( this, _( "Fields must have a name." ) );
669
670 wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
671 evt->SetClientData( new VECTOR2I( i, FDC_VALUE ) );
672 QueueEvent( evt );
673
674 return false;
675 }
676 }
677
678 return true;
679}
680
681
683{
684 if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
685 return false;
686
687 if( !m_fieldsGrid->CommitPendingChanges() )
688 return false;
689
690 if( !m_pinGrid->CommitPendingChanges() )
691 return false;
692
693 SCH_COMMIT commit( GetParent() );
694 SCH_SCREEN* currentScreen = GetParent()->GetScreen();
695 bool replaceOnCurrentScreen;
696 wxCHECK( currentScreen, false );
697
698 // This needs to be done before the LIB_ID is changed to prevent stale library symbols in
699 // the schematic file.
700 replaceOnCurrentScreen = currentScreen->Remove( m_symbol );
701
702 // save old cmp in undo list if not already in edit, or moving ...
703 if( m_symbol->GetEditFlags() == 0 )
704 commit.Modify( m_symbol, currentScreen );
705
706 // Save current flags which could be modified by next change settings
707 EDA_ITEM_FLAGS flags = m_symbol->GetFlags();
708
709 //Set the part selection in multiple part per package
710 int unit_selection = m_unitChoice->IsEnabled() ? m_unitChoice->GetSelection() + 1 : 1;
711 m_symbol->SetUnitSelection( &GetParent()->GetCurrentSheet(), unit_selection );
712 m_symbol->SetUnit( unit_selection );
713
714 int bodyStyle_selection = m_bodyStyleChoice->IsEnabled() ? m_bodyStyleChoice->GetSelection() + 1 : 1;
715 m_symbol->SetBodyStyle( bodyStyle_selection );
716
717 switch( m_orientationCtrl->GetSelection() )
718 {
719 case 0: m_symbol->SetOrientation( SYM_ORIENT_0 ); break;
720 case 1: m_symbol->SetOrientation( SYM_ORIENT_90 ); break;
721 case 2: m_symbol->SetOrientation( SYM_ORIENT_270 ); break;
722 case 3: m_symbol->SetOrientation( SYM_ORIENT_180 ); break;
723 }
724
725 switch( m_mirrorCtrl->GetSelection() )
726 {
727 case 0: break;
728 case 1: m_symbol->SetOrientation( SYM_MIRROR_X ); break;
729 case 2: m_symbol->SetOrientation( SYM_MIRROR_Y ); break;
730 }
731
732 m_symbol->SetShowPinNames( m_ShowPinNameButt->GetValue() );
733 m_symbol->SetShowPinNumbers( m_ShowPinNumButt->GetValue() );
734
735 // Restore m_Flag modified by SetUnit() and other change settings from the dialog
736 m_symbol->ClearFlags();
737 m_symbol->SetFlags( flags );
738
739 // change all field positions from relative to absolute
740 for( SCH_FIELD& field : *m_fields )
741 {
742 field.Offset( m_symbol->GetPosition() );
743 field.SetText( m_symbol->Schematic()->ConvertRefsToKIIDs( field.GetText() ) );
744 }
745
746 SCH_FIELDS& fields = m_symbol->GetFields();
747 fields.clear();
748
749 for( SCH_FIELD& field : *m_fields )
750 {
751 const wxString& fieldName = field.GetCanonicalName();
752
753 if( fieldName.IsEmpty() && field.GetText().IsEmpty() )
754 continue;
755 else if( fieldName.IsEmpty() )
756 field.SetName( _( "untitled" ) );
757
758 fields.push_back( field );
759 }
760
761 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T ids.
762
763 for( SCH_FIELD& field : fields )
764 {
765 if( !field.IsMandatory() )
766 field.SetOrdinal( ordinal++ );
767 }
768
769 // Reference has a specific initialization, depending on the current active sheet
770 // because for a given symbol, in a complex hierarchy, there are more than one
771 // reference.
772 m_symbol->SetRef( &GetParent()->GetCurrentSheet(), m_fields->GetField( FIELD_T::REFERENCE )->GetText() );
773
774 // Similar for Value and Footprint, except that the GUI behavior is that they are kept
775 // in sync between multiple instances.
776 m_symbol->SetValueFieldText( m_fields->GetField( FIELD_T::VALUE )->GetText() );
777 m_symbol->SetFootprintFieldText( m_fields->GetField( FIELD_T::FOOTPRINT )->GetText() );
778
779 m_symbol->SetExcludedFromSim( m_cbExcludeFromSim->IsChecked() );
780 m_symbol->SetExcludedFromBOM( m_cbExcludeFromBom->IsChecked() );
781 m_symbol->SetExcludedFromBoard( m_cbExcludeFromBoard->IsChecked() );
782 m_symbol->SetDNP( m_cbDNP->IsChecked(), &GetParent()->GetCurrentSheet() );
783
784 // Update any assignments
785 if( m_dataModel )
786 {
787 for( const SCH_PIN& model_pin : *m_dataModel )
788 {
789 // map from the edited copy back to the "real" pin in the symbol.
790 SCH_PIN* src_pin = m_symbol->GetPin( model_pin.GetNumber() );
791
792 if( src_pin )
793 src_pin->SetAlt( model_pin.GetAlt() );
794 }
795 }
796
797 // Keep fields other than the reference, include/exclude flags, and alternate pin assignements
798 // in sync in multi-unit parts.
799 m_symbol->SyncOtherUnits( GetParent()->GetCurrentSheet(), commit, nullptr );
800
801 if( replaceOnCurrentScreen )
802 currentScreen->Append( m_symbol );
803
804 if( !commit.Empty() )
805 commit.Push( _( "Edit Symbol Properties" ) );
806
807 return true;
808}
809
810
812{
813 wxGridCellEditor* editor = m_fieldsGrid->GetCellEditor( event.GetRow(), event.GetCol() );
814 wxControl* control = editor->GetControl();
815
816 if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
817 {
818 event.Veto();
819 wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
820 evt->SetClientData( new VECTOR2I( event.GetRow(), event.GetCol() ) );
821 QueueEvent( evt );
822 }
823 else if( event.GetCol() == FDC_NAME )
824 {
825 wxString newName = event.GetString();
826
827 for( int i = 0; i < m_fieldsGrid->GetNumberRows(); ++i )
828 {
829 if( i == event.GetRow() )
830 continue;
831
832 if( newName.CmpNoCase( m_fieldsGrid->GetCellValue( i, FDC_NAME ) ) == 0 )
833 {
834 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
835 newName ) );
836 event.Veto();
837 wxCommandEvent *evt = new wxCommandEvent( SYMBOL_DELAY_FOCUS );
838 evt->SetClientData( new VECTOR2I( event.GetRow(), event.GetCol() ) );
839 QueueEvent( evt );
840 }
841 }
842 }
843
844 editor->DecRef();
845}
846
847
849{
850 if( m_fields->at( aEvent.GetRow() ).GetId() == FIELD_T::REFERENCE
851 && aEvent.GetCol() == FDC_VALUE )
852 {
853 wxCommandEvent* evt = new wxCommandEvent( SYMBOL_DELAY_SELECTION );
854 evt->SetClientData( new VECTOR2I( aEvent.GetRow(), aEvent.GetCol() ) );
855 QueueEvent( evt );
856 }
857
858 m_editorShown = true;
859}
860
861
863{
864 m_editorShown = false;
865}
866
867
868void DIALOG_SYMBOL_PROPERTIES::OnAddField( wxCommandEvent& event )
869{
870 m_fieldsGrid->OnAddRow(
871 [&]() -> std::pair<int, int>
872 {
874
875 newField.SetTextAngle( m_fields->GetField( FIELD_T::REFERENCE )->GetTextAngle() );
876 newField.SetVisible( false );
877
878 m_fields->push_back( newField );
879
880 // notify the grid
881 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
882 m_fieldsGrid->ProcessTableMessage( msg );
883 OnModify();
884
885 return { m_fields->size() - 1, FDC_NAME };
886 } );
887}
888
889
890void DIALOG_SYMBOL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
891{
892 m_fieldsGrid->OnDeleteRows(
893 [&]( int row )
894 {
895 if( row < m_fields->GetMandatoryRowCount() )
896 {
897 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
898 m_fields->GetMandatoryRowCount() ) );
899 return false;
900 }
901
902 return true;
903 },
904 [&]( int row )
905 {
906 m_fields->erase( m_fields->begin() + row );
907
908 // notify the grid
909 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
910 m_fieldsGrid->ProcessTableMessage( msg );
911 } );
912
913 OnModify();
914}
915
916
917void DIALOG_SYMBOL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
918{
919 m_fieldsGrid->OnMoveRowUp(
920 [&]( int row )
921 {
922 return row > m_fields->GetMandatoryRowCount();
923 },
924 [&]( int row )
925 {
926 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row - 1 ) );
927 m_fieldsGrid->ForceRefresh();
928 OnModify();
929 } );
930}
931
932
933void DIALOG_SYMBOL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
934{
935 m_fieldsGrid->OnMoveRowDown(
936 [&]( int row )
937 {
938 return row >= m_fields->GetMandatoryRowCount();
939 },
940 [&]( int row )
941 {
942 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row + 1 ) );
943 m_fieldsGrid->ForceRefresh();
944 OnModify();
945 } );
946}
947
948
954
955
961
962
968
969
975
976
978{
979 int row = aEvent.GetRow();
980
981 if( m_pinGrid->GetCellValue( row, COL_ALT_NAME ) == m_dataModel->GetValue( row, COL_BASE_NAME ) )
982 m_dataModel->SetValue( row, COL_ALT_NAME, wxEmptyString );
983
984 // These are just to get the cells refreshed
985 m_dataModel->SetValue( row, COL_TYPE, m_dataModel->GetValue( row, COL_TYPE ) );
986 m_dataModel->SetValue( row, COL_SHAPE, m_dataModel->GetValue( row, COL_SHAPE ) );
987
988 OnModify();
989}
990
991
993{
994 int sortCol = aEvent.GetCol();
995 bool ascending;
996
997 // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
998 // event, and if we ask it will give us pre-event info.
999 if( m_pinGrid->IsSortingBy( sortCol ) )
1000 // same column; invert ascending
1001 ascending = !m_pinGrid->IsSortOrderAscending();
1002 else
1003 // different column; start with ascending
1004 ascending = true;
1005
1006 m_dataModel->SortRows( sortCol, ascending );
1007 m_dataModel->BuildAttrs();
1008}
1009
1010
1012{
1013 wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinGrid );
1014
1015 // Account for scroll bars
1016 int pinTblWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinGrid ).x;
1017
1018 // Stretch the Base Name and Alternate Assignment columns to fit.
1019 for( int i = 0; i < COL_COUNT; ++i )
1020 {
1021 if( i != COL_BASE_NAME && i != COL_ALT_NAME )
1022 pinTblWidth -= m_pinGrid->GetColSize( i );
1023 }
1024
1025 if( pinTblWidth > 2 )
1026 {
1027 m_pinGrid->SetColSize( COL_BASE_NAME, pinTblWidth / 2 );
1028 m_pinGrid->SetColSize( COL_ALT_NAME, pinTblWidth / 2 );
1029 }
1030}
1031
1032
1033void DIALOG_SYMBOL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
1034{
1035 std::bitset<64> shownColumns = m_fieldsGrid->GetShownColumns();
1036
1037 if( shownColumns != m_shownColumns )
1038 {
1039 m_shownColumns = shownColumns;
1040
1041 if( !m_fieldsGrid->IsCellEditControlShown() )
1042 m_fieldsGrid->SetGridWidthsDirty();
1043 }
1044}
1045
1046
1048{
1049 VECTOR2I *loc = static_cast<VECTOR2I*>( event.GetClientData() );
1050
1051 wxCHECK_RET( loc, wxT( "Missing focus cell location" ) );
1052
1053 // Handle a delayed focus
1054
1055 m_fieldsGrid->SetFocus();
1056 m_fieldsGrid->MakeCellVisible( loc->x, loc->y );
1057 m_fieldsGrid->SetGridCursor( loc->x, loc->y );
1058
1059 m_fieldsGrid->EnableCellEditControl( true );
1060 m_fieldsGrid->ShowCellEditControl();
1061
1062 delete loc;
1063}
1064
1065
1067{
1068 VECTOR2I *loc = static_cast<VECTOR2I*>( event.GetClientData() );
1069
1070 wxCHECK_RET( loc, wxT( "Missing focus cell location" ) );
1071
1072 // Handle a delayed selection
1073 wxGridCellEditor* cellEditor = m_fieldsGrid->GetCellEditor( loc->x, loc->y );
1074
1075 if( wxTextEntry* txt = dynamic_cast<wxTextEntry*>( cellEditor->GetControl() ) )
1077
1078 cellEditor->DecRef(); // we're done; must release
1079}
1080
1081
1083{
1084 wxSize new_size = event.GetSize();
1085
1086 if( ( !m_editorShown || m_lastRequestedPinsSize != new_size ) && m_pinsSize != new_size )
1087 {
1088 m_pinsSize = new_size;
1089
1091 }
1092
1093 // We store this value to check whether the dialog is changing size. This might indicate
1094 // that the user is scaling the dialog with a grid-cell-editor shown. Some editors do not
1095 // close (at least on GTK) when the user drags a dialog corner
1096 m_lastRequestedPinsSize = new_size;
1097
1098 // Always propagate for a grid repaint (needed if the height changes, as well as width)
1099 event.Skip();
1100}
1101
1102
1103void DIALOG_SYMBOL_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
1104{
1106
1107 // Now all widgets have the size fixed, call FinishDialogSettings
1109
1110 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1111
1112 if( cfg && cfg->m_Appearance.edit_symbol_width > 0 && cfg->m_Appearance.edit_symbol_height > 0 )
1114}
1115
1116
1117void DIALOG_SYMBOL_PROPERTIES::OnCheckBox( wxCommandEvent& event )
1118{
1119 OnModify();
1120}
1121
1122
1123void DIALOG_SYMBOL_PROPERTIES::OnUnitChoice( wxCommandEvent& event )
1124{
1125 if( m_dataModel )
1126 {
1127 EDA_ITEM_FLAGS flags = m_symbol->GetFlags();
1128
1129 int unit_selection = m_unitChoice->GetSelection() + 1;
1130
1131 // We need to select a new unit to build the new unit pin list
1132 // but we should not change the symbol, so the initial unit will be selected
1133 // after rebuilding the pin list
1134 int old_unit = m_symbol->GetUnit();
1135 m_symbol->SetUnit( unit_selection );
1136
1137 // Rebuild a copy of the pins of the new unit for editing
1138 m_dataModel->clear();
1139
1140 for( const std::unique_ptr<SCH_PIN>& pin : m_symbol->GetRawPins() )
1141 m_dataModel->push_back( *pin );
1142
1143 m_dataModel->SortRows( COL_NUMBER, true );
1144 m_dataModel->BuildAttrs();
1145
1146 m_symbol->SetUnit( old_unit );
1147
1148 // Restore m_Flag modified by SetUnit()
1149 m_symbol->ClearFlags();
1150 m_symbol->SetFlags( flags );
1151 }
1152
1153 OnModify();
1154}
1155
1156
1158{
1159 event.Enable( m_symbol && m_symbol->GetLibSymbolRef() );
1160}
1161
1162
1164{
1165 event.Enable( m_symbol && m_symbol->GetLibSymbolRef() );
1166}
1167
1168
1169void DIALOG_SYMBOL_PROPERTIES::OnPageChanging( wxBookCtrlEvent& aEvent )
1170{
1171 if( !m_fieldsGrid->CommitPendingChanges() )
1172 aEvent.Veto();
1173
1174 if( !m_pinGrid->CommitPendingChanges() )
1175 aEvent.Veto();
1176}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
bool Empty() const
Definition commit.h:137
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void EndQuasiModal(int retCode)
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
EDA_BASE_FRAME * m_parentFrame
int ShowModal() override
DIALOG_SYMBOL_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Symbol Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU)
void OnSizePinsGrid(wxSizeEvent &event) override
void OnPinTableCellEdited(wxGridEvent &event) override
void OnGridEditorShown(wxGridEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void OnEditSymbol(wxCommandEvent &) override
void OnCancelButtonClick(wxCommandEvent &event) override
virtual void onUpdateEditLibrarySymbol(wxUpdateUIEvent &event) override
SCH_PIN_TABLE_DATA_MODEL * m_dataModel
void OnMoveDown(wxCommandEvent &event) override
void OnPinTableColSort(wxGridEvent &aEvent)
void OnMoveUp(wxCommandEvent &event) override
void OnDeleteField(wxCommandEvent &event) override
void OnInitDlg(wxInitDialogEvent &event) override
void OnAddField(wxCommandEvent &event) override
void OnGridEditorHidden(wxGridEvent &event) override
void OnUnitChoice(wxCommandEvent &event) override
void OnEditSpiceModel(wxCommandEvent &event) override
void OnPageChanging(wxNotebookEvent &event) override
DIALOG_SYMBOL_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_SYMBOL *aSymbol)
void HandleDelayedFocus(wxCommandEvent &event)
void HandleDelayedSelection(wxCommandEvent &event)
void OnCheckBox(wxCommandEvent &event) override
void OnGridCellChanging(wxGridEvent &event)
void OnEditLibrarySymbol(wxCommandEvent &) override
void OnUpdateSymbol(wxCommandEvent &) override
void OnExchangeSymbol(wxCommandEvent &) override
virtual void onUpdateEditSymbol(wxUpdateUIEvent &event) override
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:607
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:397
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:310
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:61
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:95
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
static int Compare(const wxString &lhs, const wxString &rhs)
virtual void Push(const wxString &aMessage=wxT("A commit"), int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
SCHEMATIC & Schematic() const
bool IsMandatory() const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetText(const wxString &aText) override
bool IsEmptyCell(int row, int col) override
wxString GetValue(int aRow, int aCol) override
std::vector< wxGridCellAttr * > m_nameAttrs
static bool compare(const SCH_PIN &lhs, const SCH_PIN &rhs, int sortCol, bool ascending)
void SortRows(int aSortCol, bool ascending)
bool CanSetValueAs(int aRow, int aCol, const wxString &aTypeName) override
static wxString GetValue(const SCH_PIN &aPin, int aCol)
wxString GetColLabelValue(int aCol) override
void SetValue(int aRow, int aCol, const wxString &aValue) override
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
void SetAlt(const wxString &aAlt)
Set the name of the alternate pin.
Definition sch_pin.cpp:433
const std::map< wxString, ALT > & GetAlternates() const
Definition sch_pin.h:160
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:174
SCH_PIN * GetLibPin() const
Definition sch_pin.h:89
const wxString & GetName() const
Definition sch_pin.cpp:401
const wxString & GetBaseName() const
Get the name without any alternates.
Definition sch_pin.cpp:410
const wxString & GetNumber() const
Definition sch_pin.h:124
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:278
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:313
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
Schematic symbol object.
Definition sch_symbol.h:76
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition wx_grid.cpp:46
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
wxDEFINE_EVENT(SYMBOL_DELAY_FOCUS, wxCommandEvent)
@ SYMBOL_PROPS_EDIT_SCHEMATIC_SYMBOL
@ SYMBOL_PROPS_WANT_EXCHANGE_SYMBOL
@ SYMBOL_PROPS_WANT_UPDATE_SYMBOL
@ SYMBOL_PROPS_EDIT_LIBRARY_SYMBOL
#define _(s)
std::uint32_t EDA_ITEM_FLAGS
@ FDC_NAME
@ FDC_VALUE
wxColour GetDialogBGColour()
Definition wxgtk/ui.cpp:61
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition wxgtk/ui.cpp:264
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
KICOMMON_API void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
const std::vector< BITMAPS > & PinTypeIcons()
Definition pin_type.cpp:162
const wxArrayString & PinTypeNames()
Definition pin_type.cpp:153
const wxArrayString & PinShapeNames()
Definition pin_type.cpp:171
const std::vector< BITMAPS > & PinShapeIcons()
Definition pin_type.cpp:180
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition sch_symbol.h:64
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
wxString UnescapeString(const wxString &aSource)
Hold a name of a symbol's field, field value, and default visibility.
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_MIRROR_Y
Definition symbol.h:44
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_ORIENT_90
Definition symbol.h:40
@ SYM_ORIENT_0
Definition symbol.h:39
wxString GetUserFieldName(int aFieldNdx, bool aTranslateForHI)
#define DO_TRANSLATE
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
VECTOR3I res
VECTOR2I end
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695