KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_symbol.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <netclass.h>
22#include <api/api_enums.h>
24#include <api/api_utils.h>
25#include <schematic.h>
26#include <sch_collectors.h>
27#include <sch_commit.h>
28#include <sch_edit_frame.h>
29#include <widgets/msgpanel.h>
30#include <bitmaps.h>
31#include <common.h>
32#include <core/mirror.h>
33#include "lib_symbol.h"
34#include <pin_map.h>
35#include <sch_shape.h>
36#include <pgm_base.h>
37#include <sim/sim_model.h>
38#include <sim/spice_generator.h>
39#include <sim/sim_lib_mgr.h>
40#include <trace_helpers.h>
41#include <trigo.h>
42#include <refdes_utils.h>
43#include <wx/log.h>
45#include <sch_plotter.h>
46#include <string_utils.h>
48#include <sch_rule_area.h>
49#include <api/api_sch_utils.h>
50#include <api/schematic/schematic_types.pb.h>
51#include <project_sch.h>
56
57#include <utility>
58#include <validators.h>
59#include <properties/property.h>
61
62
63wxString SCH_SYMBOL::GetRefProp() const
64{
65 return GetRef( &Schematic()->CurrentSheet() );
66}
67
68
70{
71 return GetValue( &Schematic()->CurrentSheet(), RAW_VALUE, Schematic()->GetCurrentVariant() );
72}
73
74
76{
77 return GetUnitSelection( &Schematic()->CurrentSheet() );
78}
79
80
81void SCH_SYMBOL::SetUnitProp( int aUnit )
82{
83 SetUnitSelection( &Schematic()->CurrentSheet(), aUnit );
84 SetUnit( aUnit );
85}
86
87
89{
90 return GetDNP( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
91}
92
93
94void SCH_SYMBOL::SetDNPProp( bool aEnable )
95{
96 SetDNP( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
97}
98
99
101{
102 return GetExcludedFromBOM( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
103}
104
105
107{
108 SetExcludedFromBOM( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
109}
110
111
113{
114 return GetExcludedFromSim( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
115}
116
117
119{
120 SetExcludedFromSim( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
121}
122
123
125{
126 return GetExcludedFromBoard( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
127}
128
129
131{
132 SetExcludedFromBoard( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
133}
134
135
137{
138 return GetExcludedFromPosFiles( &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
139}
140
141
143{
144 SetExcludedFromPosFiles( aEnable, &Schematic()->CurrentSheet(), Schematic()->GetCurrentVariant() );
145}
146
147
148// Stable property names and group captions for the per-object field and pin-map properties
149static const wxString PIN_MAP_GROUP = _HKI( "Pin Map" );
150static const wxString PIN_MAP_FOOTPRINT_PROP = wxS( "Pin Map Footprint" );
151static const wxString PIN_MAP_MODE_PROP = wxS( "Pin Map Mode" );
152static const wxString PIN_MAP_NAME_PROP = wxS( "Pin Map Name" );
153static const wxString PIN_MAP_TABLE_GROUP = _HKI( "Effective Pin Map" );
154static const wxString PIN_MAP_ENTRY_PREFIX = wxS( "Pin " );
155
156
163 const SCH_SHEET_PATH* aPath = nullptr,
164 const wxString& aVariant = wxEmptyString )
165{
166 const std::unique_ptr<LIB_SYMBOL>& libSymbol = aSymbol->GetLibSymbolRef();
167
168 if( !libSymbol )
169 return nullptr;
170
171 const std::vector<ASSOCIATED_FOOTPRINT>& assoc = libSymbol->GetEffectiveAssociatedFootprints();
172
173 if( assoc.empty() )
174 return nullptr;
175
176 LIB_ID fpId;
177
178 if( const SCH_FIELD* fpField = aSymbol->GetField( FIELD_T::FOOTPRINT ) )
179 fpId.Parse( fpField->GetText( aPath, aVariant ) );
180
181 for( const ASSOCIATED_FOOTPRINT& candidate : assoc )
182 {
183 if( candidate.m_FootprintLibId == fpId )
184 return &candidate;
185 }
186
187 return &assoc.front();
188}
189
190
192{
193public:
195
196 wxAny getter( const void* aObject ) const final
197 {
198 const auto* symbol = reinterpret_cast<const SCH_SYMBOL*>( aObject );
199 SCHEMATIC* schematic = symbol->Schematic();
200 return ValueForInstance( symbol, schematic ? &schematic->CurrentSheet() : nullptr,
201 schematic ? schematic->GetCurrentVariant() : wxString() );
202 }
203
204 virtual wxAny ValueForInstance( const SCH_SYMBOL* aSymbol, const SCH_SHEET_PATH* aPath,
205 const wxString& aVariant ) const = 0;
206};
207
208
210{
211public:
212 SCH_SYMBOL_FIELD_PROPERTY( const wxString& aName ) :
214 m_name( aName )
215 {
216 SetGroup( _HKI( "Fields" ) );
217 }
218
219 size_t OwnerHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
220 size_t BaseHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
221 size_t TypeHash() const override { return TYPE_HASH( wxString ); }
222
223 void setter( void* obj, wxAny& v ) override
224 {
225 wxString value;
226
227 if( !v.GetAs( &value ) )
228 return;
229
230 SCH_SYMBOL* symbol = reinterpret_cast<SCH_SYMBOL*>( obj );
231 SCH_FIELD* field = symbol->GetField( m_name );
232
233 wxString variantName;
234 const SCH_SHEET_PATH* sheetPath = nullptr;
235
236 if( symbol->Schematic() )
237 {
238 variantName = symbol->Schematic()->GetCurrentVariant();
239 sheetPath = &symbol->Schematic()->CurrentSheet();
240 }
241
242 if( !sheetPath )
243 {
244 if( !field )
245 {
246 SCH_FIELD newField( symbol, FIELD_T::USER, m_name );
247 newField.SetText( value );
248 symbol->AddField( newField );
249 }
250 else
251 {
252 field->SetText( value );
253 }
254
255 return;
256 }
257
258 if( !field )
259 {
260 symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, m_name ) );
261 field = symbol->GetField( m_name );
262 }
263
264 field->SetText( value, sheetPath, variantName );
265 }
266
267 wxAny ValueForInstance( const SCH_SYMBOL* symbol, const SCH_SHEET_PATH* sheetPath,
268 const wxString& variantName ) const override
269 {
270 const SCH_FIELD* field = symbol->GetField( m_name );
271
272 if( !field )
273 return wxAny();
274
275 wxString text;
276
277 if( !variantName.IsEmpty() && sheetPath )
278 text = field->GetText( sheetPath, variantName );
279 else
280 text = field->GetText();
281
282 return wxAny( text );
283 }
284
285private:
286 wxString m_name;
287};
288
289
294{
295public:
301
302 size_t OwnerHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
303 size_t BaseHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
304 size_t TypeHash() const override { return TYPE_HASH( wxString ); }
305
306 bool Writeable( INSPECTABLE* aObject ) const override { return false; }
307
308 void setter( void* obj, wxAny& v ) override {}
309
310 wxAny ValueForInstance( const SCH_SYMBOL* symbol, const SCH_SHEET_PATH* sheetPath,
311 const wxString& variantName ) const override
312 {
313 if( const ASSOCIATED_FOOTPRINT* active = activeAssociatedFootprint( symbol, sheetPath, variantName ) )
314 return wxAny( active->m_FootprintLibId.Format().wx_str() );
315
316 return wxAny( wxEmptyString );
317 }
318};
319
320
326{
327public:
338
339 size_t OwnerHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
340 size_t BaseHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
341 size_t TypeHash() const override { return TYPE_HASH( int ); }
342
343 static wxPGChoices BuildChoices()
344 {
345 wxPGChoices choices;
346 choices.Add( _( "Library default" ), static_cast<int>( PIN_MAP_OVERRIDE_MODE::USE_LIBRARY_DEFAULT ) );
347 choices.Add( _( "Named map" ), static_cast<int>( PIN_MAP_OVERRIDE_MODE::USE_NAMED_MAP ) );
348 choices.Add( _( "Identity" ), static_cast<int>( PIN_MAP_OVERRIDE_MODE::FORCE_IDENTITY ) );
349
350 return choices;
351 }
352
353 void setter( void* obj, wxAny& v ) override
354 {
355 int value = 0;
356
357 if( !v.GetAs( &value ) )
358 return;
359
360 SCH_SYMBOL* symbol = reinterpret_cast<SCH_SYMBOL*>( obj );
361
362 const SCH_SHEET_PATH* sheetPath = nullptr;
363 wxString variantName;
364
365 if( symbol->Schematic() )
366 {
367 sheetPath = &symbol->Schematic()->CurrentSheet();
368 variantName = symbol->Schematic()->GetCurrentVariant();
369 }
370
371 PIN_MAP_INSTANCE_OVERRIDE override = symbol->GetPinMapOverride( sheetPath, variantName );
372 override.m_Mode = static_cast<PIN_MAP_OVERRIDE_MODE>( value );
373
374 // The active-map name is meaningful only in named-map mode; seed it from
375 // the symbol's active associated footprint when switching to named-map
376 // mode and no name has been chosen yet.
377 if( override.m_Mode == PIN_MAP_OVERRIDE_MODE::USE_NAMED_MAP && override.m_ActiveMapName.IsEmpty() )
378 {
379 if( const ASSOCIATED_FOOTPRINT* active = activeAssociatedFootprint( symbol ) )
380 override.m_ActiveMapName = active->m_MapName;
381 }
382
383 symbol->SetPinMapOverride( override, sheetPath, variantName );
384 }
385
386 wxAny ValueForInstance( const SCH_SYMBOL* symbol, const SCH_SHEET_PATH* sheetPath,
387 const wxString& variantName ) const override
388 {
389 PIN_MAP_INSTANCE_OVERRIDE override = symbol->GetPinMapOverride( sheetPath, variantName );
390
391 switch( override.m_Mode )
392 {
395 case PIN_MAP_OVERRIDE_MODE::FORCE_IDENTITY: return wxAny( static_cast<int>( override.m_Mode ) );
396
397 default: return wxAny( static_cast<int>( PIN_MAP_OVERRIDE_MODE::USE_LIBRARY_DEFAULT ) );
398 }
399 }
400};
401
402
404{
405public:
408 {
411 []( INSPECTABLE* aObject )
412 {
413 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aObject );
414
415 return symbol && SCH_SYMBOL_PIN_MAP_NAME_PROPERTY::MapNames( symbol ).size() > 1;
416 } );
418 []( INSPECTABLE* aObject ) -> wxPGChoices
419 {
420 if( const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aObject ) )
422
423 return wxPGChoices();
424 } );
425 }
426
427 size_t OwnerHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
428 size_t BaseHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
429 size_t TypeHash() const override { return TYPE_HASH( int ); }
430
431 static std::vector<wxString> MapNames( const SCH_SYMBOL* aSymbol )
432 {
433 std::vector<wxString> names;
434
435 if( const std::unique_ptr<LIB_SYMBOL>& libSymbol = aSymbol->GetLibSymbolRef() )
436 {
437 for( const PIN_MAP& map : libSymbol->GetEffectivePinMaps().GetAll() )
438 names.push_back( map.GetName() );
439 }
440
441 return names;
442 }
443
444 static wxPGChoices BuildChoices( const SCH_SYMBOL* aSymbol )
445 {
446 wxPGChoices choices;
447 const std::vector<wxString> names = MapNames( aSymbol );
448
449 for( size_t ii = 0; ii < names.size(); ++ii )
450 choices.Add( names[ii], (int) ii );
451
452 return choices;
453 }
454
455 void setter( void* obj, wxAny& v ) override
456 {
457 int value = 0;
458
459 if( !v.GetAs( &value ) )
460 return;
461
462 SCH_SYMBOL* symbol = reinterpret_cast<SCH_SYMBOL*>( obj );
463 const std::vector<wxString> names = MapNames( symbol );
464
465 if( value < 0 || value >= (int) names.size() )
466 return;
467
468 const SCH_SHEET_PATH* sheetPath = nullptr;
469 wxString variantName;
470
471 if( symbol->Schematic() )
472 {
473 sheetPath = &symbol->Schematic()->CurrentSheet();
474 variantName = symbol->Schematic()->GetCurrentVariant();
475 }
476
477 PIN_MAP_INSTANCE_OVERRIDE override = symbol->GetPinMapOverride( sheetPath, variantName );
479 override.m_ActiveMapName = names[value];
480 symbol->SetPinMapOverride( override, sheetPath, variantName );
481 }
482
483 wxAny ValueForInstance( const SCH_SYMBOL* symbol, const SCH_SHEET_PATH* sheetPath,
484 const wxString& variantName ) const override
485 {
486 PIN_MAP_INSTANCE_OVERRIDE override = symbol->GetPinMapOverride( sheetPath, variantName );
487
488 wxString active;
489
490 if( override.m_Mode == PIN_MAP_OVERRIDE_MODE::USE_NAMED_MAP )
491 active = override.m_ActiveMapName;
492
493 const std::vector<wxString> names = MapNames( symbol );
494
495 if( std::find( names.begin(), names.end(), active ) == names.end() )
496 {
497 if( const ASSOCIATED_FOOTPRINT* fp = activeAssociatedFootprint( symbol, sheetPath, variantName ) )
498 active = fp->m_MapName;
499 }
500
501 for( size_t ii = 0; ii < names.size(); ++ii )
502 {
503 if( names[ii] == active )
504 return wxAny( (int) ii );
505 }
506
507 return wxAny( 0 );
508 }
509};
510
511
516{
517public:
518 SCH_SYMBOL_PIN_MAP_ENTRY_PROPERTY( const wxString& aName, const wxString& aPinNumber ) :
520 m_pinNumber( aPinNumber )
521 {
523 }
524
525 size_t OwnerHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
526 size_t BaseHash() const override { return TYPE_HASH( SCH_SYMBOL ); }
527 size_t TypeHash() const override { return TYPE_HASH( wxString ); }
528
529 bool Writeable( INSPECTABLE* aObject ) const override { return false; }
530
531 void setter( void* obj, wxAny& v ) override {}
532
533 wxAny ValueForInstance( const SCH_SYMBOL* symbol, const SCH_SHEET_PATH* sheetPath,
534 const wxString& variantName ) const override
535 {
536 if( !sheetPath )
537 return wxAny( m_pinNumber );
538
539 for( const SCH_PIN* pin : symbol->GetPins( sheetPath ) )
540 {
541 std::vector<wxString> logical = pin->GetStackedPinNumbers();
542
543 if( std::find( logical.begin(), logical.end(), m_pinNumber ) == logical.end() )
544 continue;
545
546 wxString pad = pin->GetEffectivePadNumber( *sheetPath, variantName );
547
548 if( pad == m_pinNumber )
549 return wxAny( wxString::Format( _( "%s (identity)" ), pad ) );
550
551 return wxAny( pad );
552 }
553
554 return wxAny( m_pinNumber );
555 }
556
557private:
558 wxString m_pinNumber;
559};
560
561
562std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
563
564
569std::string toUTFTildaText( const wxString& txt )
570{
571 std::string ret = TO_UTF8( txt );
572
573 for( char& c : ret )
574 {
575 if( (unsigned char) c <= ' ' )
576 c = '~';
577 }
578
579 return ret;
580}
581
582
584 SYMBOL( nullptr, SCH_SYMBOL_T )
585{
586 Init( VECTOR2I( 0, 0 ) );
588 m_signalName.clear();
589}
590
591
592SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId, const SCH_SHEET_PATH* aSheet, int aUnit,
593 int aBodyStyle, const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
594 SYMBOL( aParent, SCH_SYMBOL_T )
595{
596 Init( aPosition );
597
598 m_unit = aUnit;
599 m_bodyStyle = aBodyStyle;
600 m_lib_id = aLibId;
601
602 std::unique_ptr<LIB_SYMBOL> part;
603
604 part = aSymbol.Flatten();
605 part->SetParent();
606 SetLibSymbol( part.release() );
607
608 // Copy fields from the library symbol
609 UpdateFields( aSheet, true, /* update style */
610 false, /* update ref */
611 false, /* update other fields */
612 true, /* reset ref */
613 true /* reset other fields */ );
614
615 m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
616
617 if( aSheet )
619
620 // Inherit the include in bill of materials and board netlist settings from flattened
621 // library symbol.
622 m_excludedFromSim = m_part->GetExcludedFromSim();
623 m_excludedFromBOM = m_part->GetExcludedFromBOM();
624 m_excludedFromBoard = m_part->GetExcludedFromBoard();
625 m_excludedFromPosFiles = m_part->GetExcludedFromPosFiles();
627 m_signalName.clear();
628}
629
630
631SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet, const PICKED_SYMBOL& aSel,
632 const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
633 SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.BodyStyle, aPosition, aParent )
634{
635 // Set any fields that were modified as part of the symbol selection
636 for( const auto& [fieldId, fieldValue] : aSel.Fields )
637 {
638 if( fieldId == FIELD_T::REFERENCE )
639 SetRef( aSheet, fieldValue );
640 else if( SCH_FIELD* field = GetField( fieldId ) )
641 field->SetText( fieldValue );
642 }
643}
644
645
647 SYMBOL( aSymbol )
648{
649 m_parent = aSymbol.m_parent;
650 m_pos = aSymbol.m_pos;
651 m_unit = aSymbol.m_unit;
652 m_bodyStyle = aSymbol.m_bodyStyle;
653 m_lib_id = aSymbol.m_lib_id;
654 m_doNetlist = aSymbol.m_doNetlist;
655 m_DNP = aSymbol.m_DNP;
656
657 const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
658
659 m_transform = aSymbol.m_transform;
660 m_prefix = aSymbol.m_prefix;
661 m_instances = aSymbol.m_instances;
664 m_signalName = aSymbol.m_signalName;
665
666 {
667 m_fields = aSymbol.m_fields; // std::vector's operator=()
668
669 // Re-parent the fields, which before this had aSymbol as parent
670 for( SCH_FIELD& field : m_fields )
671 field.SetParent( this );
672 }
673
674 {
675 m_pins.clear();
676
677 // Copy (and re-parent) the pins
678 for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
679 {
680 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
681 m_pins.back()->SetParent( this );
682 }
683 }
684
685 if( aSymbol.m_part )
686 {
687 m_part = std::make_unique<LIB_SYMBOL>( *aSymbol.m_part );
688 updatePins();
689 }
690
694}
695
696
700
701
703{
704 const std::unique_ptr<LIB_SYMBOL>& libSymbol = GetLibSymbolRef();
705
706 return libSymbol && !libSymbol->GetEffectiveAssociatedFootprints().empty();
707}
708
709
710std::vector<PROPERTY_BASE*> SCH_SYMBOL::GetDynamicProperties() const
711{
712 return GetDynamicProperties( Schematic() ? &Schematic()->CurrentSheet() : nullptr );
713}
714
715
716std::vector<PROPERTY_BASE*> SCH_SYMBOL::GetDynamicProperties( const SCH_SHEET_PATH* aPath ) const
717{
718 std::vector<PROPERTY_BASE*> props;
719
720 auto getOrCreateFieldProperty =
721 [&]( const wxString& aName )
722 {
723 auto it = m_fieldPropsStorageCache.find( aName );
724
725 if( it == m_fieldPropsStorageCache.end() )
726 {
727 auto prop = std::make_unique<SCH_SYMBOL_FIELD_PROPERTY>( aName );
728 it = m_fieldPropsStorageCache.emplace( aName, std::move( prop ) ).first;
729 }
730
731 return it->second.get();
732 };
733
734 auto getOrCreatePinMapProperty =
735 [&]( const wxString& aName, const std::function<std::unique_ptr<PROPERTY_BASE>()>& aCreator )
736 {
737 auto it = m_pinMapPropsStorageCache.find( aName );
738
739 if( it == m_pinMapPropsStorageCache.end() )
740 it = m_pinMapPropsStorageCache.emplace( aName, aCreator() ).first;
741
742 return it->second.get();
743 };
744
745 for( const SCH_FIELD& field : GetFields() )
746 {
747 if( !field.IsMandatory() )
748 continue;
749
750 if( field.IsPrivate() )
751 continue;
752
753 const wxString& name = field.GetUntranslatedName();
754
755 if( PROPERTY_MANAGER::Instance().GetProperty( TYPE_HASH( SCH_SYMBOL ), name ) )
756 continue;
757
758 props.push_back( getOrCreateFieldProperty( name ) );
759 }
760
761 std::vector<const SCH_FIELD*> userFields;
762
763 for( const SCH_FIELD& field : GetFields() )
764 {
765 if( field.IsMandatory() || field.IsPrivate() )
766 continue;
767
768 userFields.push_back( &field );
769 }
770
771 std::ranges::sort( userFields,
772 []( const SCH_FIELD* a, const SCH_FIELD* b )
773 {
774 return a->GetUntranslatedName().CmpNoCase( b->GetUntranslatedName() ) < 0;
775 } );
776
777 for( const SCH_FIELD* field : userFields )
778 {
779 const wxString& name = field->GetUntranslatedName();
780 props.push_back( getOrCreateFieldProperty( name ) );
781 }
782
784 props.push_back( prop );
785
786 // Pin Map group: only meaningful when the symbol carries at least one effective associated footprint.
788 {
789 props.push_back( getOrCreatePinMapProperty( PIN_MAP_FOOTPRINT_PROP,
790 []()
791 {
792 return std::make_unique<SCH_SYMBOL_PIN_MAP_FOOTPRINT_PROPERTY>();
793 } ) );
794 props.push_back( getOrCreatePinMapProperty( PIN_MAP_MODE_PROP,
795 []()
796 {
797 return std::make_unique<SCH_SYMBOL_PIN_MAP_MODE_PROPERTY>();
798 } ) );
799 props.push_back( getOrCreatePinMapProperty( PIN_MAP_NAME_PROP,
800 []()
801 {
802 return std::make_unique<SCH_SYMBOL_PIN_MAP_NAME_PROPERTY>();
803 } ) );
804
805 // One read-only row per symbol pin under a collapsible group, showing
806 // the effective pad each pin resolves to.
807 if( aPath )
808 {
809 for( const SCH_PIN* pin : GetPins( aPath ) )
810 {
811 for( const wxString& number : pin->GetStackedPinNumbers() )
812 {
813 if( number.IsEmpty() )
814 continue;
815
816 const wxString propName = PIN_MAP_ENTRY_PREFIX + number;
817
818 props.push_back( getOrCreatePinMapProperty( propName,
819 [&]()
820 {
821 return std::make_unique<SCH_SYMBOL_PIN_MAP_ENTRY_PROPERTY>( propName, number );
822 } ) );
823 }
824 }
825 }
826 }
827
828 return props;
829}
830
831
832void SCH_SYMBOL::Init( const VECTOR2I& pos )
833{
835 m_pos = pos;
836 m_unit = 1; // In multi unit chip - which unit to draw.
837 m_bodyStyle = BODY_STYLE::BASE; // De Morgan Handling
838
839 // The rotation/mirror transformation matrix. pos normal
841
842 auto addField =
843 [&]( FIELD_T id, SCH_LAYER_ID layer )
844 {
845 m_fields.emplace_back( this, id, GetDefaultFieldName( id, UNTRANSLATED ) );
846 m_fields.back().SetTextPos( pos );
847 m_fields.back().SetLayer( layer );
848 };
849
850 // construct only the mandatory fields
852 addField( FIELD_T::VALUE, LAYER_VALUEPART );
853 addField( FIELD_T::FOOTPRINT, LAYER_FIELDS );
854 addField( FIELD_T::DATASHEET, LAYER_FIELDS );
856
857 m_prefix = wxString( wxT( "U" ) );
858 m_doNetlist = true;
860 m_signalName.clear();
861}
862
863
865{
866 return new SCH_SYMBOL( *this );
867}
868
869
870void SCH_SYMBOL::Serialize( google::protobuf::Any& aContainer ) const
871{
872 kiapi::schematic::types::SchematicSymbolInstance symbol;
873 Serialize( symbol );
874 aContainer.PackFrom( symbol );
875}
876
877
878void SCH_SYMBOL::Serialize( kiapi::schematic::types::SchematicSymbolInstance& aSymbol ) const
879{
880 using namespace kiapi::common;
881 using namespace kiapi::schematic::types;
882
883 aSymbol.mutable_id()->set_value( m_Uuid.AsStdString() );
884 PackVector2( *aSymbol.mutable_position(), GetPosition(), schIUScale );
885 aSymbol.set_locked( IsLocked() ? types::LockedState::LS_LOCKED : types::LockedState::LS_UNLOCKED );
886 aSymbol.set_fields_autoplaced( GetFieldsAutoplaced() != AUTOPLACE_NONE );
887
888 if( !UseLibIdLookup() )
889 {
890 LIB_ID id;
892 PackLibId( aSymbol.mutable_lib_id(), id );
893 }
894
896
897 SchematicSymbolTransform* transform = aSymbol.mutable_transform();
898 transform->set_orientation(
900 transform->set_mirror_x( GetMirrorX() );
901 transform->set_mirror_y( GetMirrorY() );
902
903 if( GetBodyStyleCount() > 1 )
904 aSymbol.mutable_body_style()->set_style( GetBodyStyle() );
905
906 GetField( FIELD_T::REFERENCE )->Serialize( *aSymbol.mutable_reference_field(), schIUScale );
907 GetField( FIELD_T::VALUE )->Serialize( *aSymbol.mutable_value_field(), schIUScale );
908 GetField( FIELD_T::FOOTPRINT )->Serialize( *aSymbol.mutable_footprint_field(), schIUScale );
909 GetField( FIELD_T::DATASHEET )->Serialize( *aSymbol.mutable_datasheet_field(), schIUScale );
910 GetField( FIELD_T::DESCRIPTION )->Serialize( *aSymbol.mutable_description_field(), schIUScale );
911
912 for( const SCH_FIELD& field : GetFields() )
913 {
914 if( field.IsMandatory() )
915 continue;
916
917 field.Serialize( *aSymbol.add_user_fields(), schIUScale );
918 }
919
920 if( m_part )
921 m_part->Serialize( *aSymbol.mutable_definition(), /* aSkipPins = */ true );
922
923 aSymbol.set_show_pin_names( GetShowPinNames() );
924 aSymbol.set_show_pin_numbers( GetShowPinNumbers() );
925
926 PackDistance( *aSymbol.mutable_pin_name_offset(), GetPinNameOffset(), schIUScale );
927
928 kiapi::common::PackCustomProperties( aSymbol.mutable_custom_properties(), *this );
929}
930
931
932bool SCH_SYMBOL::Deserialize( const google::protobuf::Any& aContainer )
933{
934 kiapi::schematic::types::SchematicSymbolInstance symbol;
935
936 if( !aContainer.UnpackTo( &symbol ) )
937 return false;
938
939 return Deserialize( symbol );
940}
941
942
943bool SCH_SYMBOL::Deserialize( const kiapi::schematic::types::SchematicSymbolInstance& aSymbol )
944{
945 using namespace kiapi::common;
946 using namespace kiapi::common::types;
947 using namespace kiapi::schematic::types;
948
949 // Published rows and the item index hold this identity and its pins, so they must not outlive the change
950 if( SCH_SCREEN* screen = GetParentScreen() )
951 screen->BumpConnectivityRevision();
952
953 const_cast<::KIID&>( m_Uuid ) = ::KIID( aSymbol.id().value() );
954 SetPosition( UnpackVector2( aSymbol.position(), schIUScale ) );
955 SetLocked( aSymbol.locked() == LockedState::LS_LOCKED );
956 SetFieldsAutoplaced( aSymbol.fields_autoplaced() ? AUTOPLACE_AUTO : AUTOPLACE_NONE );
957 kiapi::common::UnpackCustomProperties( aSymbol.custom_properties(), *this );
958
959 if( aSymbol.has_lib_id() )
960 SetSchSymbolLibraryName( UnpackLibId( aSymbol.lib_id() ).Format() );
961
963 SetOrientationProp( FromProtoEnum<SYMBOL_ORIENTATION_PROP>( aSymbol.transform().orientation() ) );
964 SetMirrorX( aSymbol.transform().mirror_x() );
965 SetMirrorY( aSymbol.transform().mirror_y() );
966
967 // Generally clients should not send symbols without definitions, but if they do as an update for
968 // an existing symbol, it's better to skip deserialization than delete the existing definition,
969 // especially since definitions are cached separately
970 const bool haveDefinition = aSymbol.has_definition();
971
972 std::unordered_map<::KIID, wxString> pinAltMap;
973
974 if( haveDefinition )
975 {
976 const SchematicSymbol& def = aSymbol.definition();
977
978 LIB_ID libId = UnpackLibId( def.id() );
979 m_lib_id = libId;
980
981 for( const SchematicSymbolChild& child : def.items() )
982 {
983 if( TypeNameFromAny( child.item() ) != std::optional<KICAD_T>( SCH_PIN_T ) )
984 continue;
985
986 SchematicPin pinProto;
987
988 if( child.item().UnpackTo( &pinProto ) && pinProto.has_active_alternate() )
989 pinAltMap[::KIID( pinProto.id().value() )] = wxString::FromUTF8( pinProto.active_alternate() );
990 }
991
992 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( libId.GetLibItemName() );
993
994 if( !libSymbol->Deserialize( def ) )
995 {
996 delete libSymbol;
997 return false;
998 }
999
1000 SetLibSymbol( libSymbol );
1001 }
1002
1003 if( aSymbol.has_body_style() )
1004 SetBodyStyle( aSymbol.body_style().style() );
1005
1006 GetField( FIELD_T::REFERENCE )->Deserialize( aSymbol.reference_field(), schIUScale );
1007 GetField( FIELD_T::VALUE )->Deserialize( aSymbol.value_field(), schIUScale );
1008 GetField( FIELD_T::FOOTPRINT )->Deserialize( aSymbol.footprint_field(), schIUScale );
1009 GetField( FIELD_T::DATASHEET )->Deserialize( aSymbol.datasheet_field(), schIUScale );
1010 GetField( FIELD_T::DESCRIPTION )->Deserialize( aSymbol.description_field(), schIUScale );
1011
1012 std::set<wxString> incoming;
1013
1014 for( const SchematicField& fieldProto : aSymbol.user_fields() )
1015 {
1016 wxString name = wxString::FromUTF8( fieldProto.name() );
1017 SCH_FIELD* existing = GetField( name );
1018
1019 // Don't duplicate existing mandatory fields.
1020 if( existing && existing->IsMandatory() )
1021 continue;
1022
1023 incoming.insert( name );
1024
1025 if( existing )
1026 existing->Deserialize( fieldProto, schIUScale );
1027 else
1028 AddField( SCH_FIELD( this, FIELD_T::USER, name ) )->Deserialize( fieldProto, schIUScale );
1029 }
1030
1031 std::vector<wxString> toRemove;
1032
1033 for( const SCH_FIELD& field : GetFields() )
1034 {
1035 if( !field.IsMandatory() && !incoming.count( field.GetName( false ) ) )
1036 toRemove.push_back( field.GetName( false ) );
1037 }
1038
1039 for( const wxString& name : toRemove )
1040 RemoveField( name );
1041
1042 if( aSymbol.has_show_pin_names() )
1043 SetShowPinNames( aSymbol.show_pin_names() );
1044
1045 if( aSymbol.has_show_pin_numbers() )
1046 SetShowPinNumbers( aSymbol.show_pin_numbers() );
1047
1048 if( aSymbol.has_pin_name_offset() )
1049 SetPinNameOffset( UnpackDistance( aSymbol.pin_name_offset(), schIUScale ) );
1050
1051 // The proto is storing a single pin struct that has the UUID and alternate selection
1052 // as well as the library pin definition. Deserializing the pin will have set up most
1053 // of this, but we want to make sure that the UUIDs of the instance pins round-trip
1054 // so we have to set them up in advance so that UpdatePins links them up with the
1055 // lib pins, and then we need to set the alternates for pins if applicable
1056
1057 if( haveDefinition )
1058 {
1059 m_pins.clear();
1060
1061 for( SCH_PIN* pin : GetAllLibPins() )
1062 {
1063 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
1064 m_pins.back()->SetParent( this );
1065 const_cast<::KIID&>( m_pins.back()->m_Uuid ) = pin->m_Uuid;
1066 }
1067
1068 UpdatePins();
1069
1071 {
1072 if( pinAltMap.contains( pin->m_Uuid ) )
1073 pin->SetAlt( pinAltMap.at( pin->m_Uuid ) );
1074 }
1075 }
1076
1077 return true;
1078}
1079
1080
1082{
1083 return m_part == nullptr;
1084}
1085
1086
1088{
1089 // If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
1090 // going to end up moving the symbol's pins off-grid.
1091
1092 // The minimal grid size allowed to place a pin is 25 mils
1093 const int min_grid_size = schIUScale.MilsToIU( 25 );
1094
1095 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1096 {
1097 if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
1098 return false;
1099
1100 if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
1101 return false;
1102 }
1103
1104 return true;
1105}
1106
1107
1108void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
1109{
1110 m_lib_id = aLibId;
1111}
1112
1113
1115{
1116 if( !m_schLibSymbolName.IsEmpty() )
1117 return m_schLibSymbolName;
1118 else
1119 return m_lib_id.Format();
1120}
1121
1122
1124{
1125 wxCHECK2( !aLibSymbol || aLibSymbol->IsRoot(), aLibSymbol = nullptr );
1126
1127 m_part.reset( aLibSymbol );
1128
1129 // Library content changed, so cached flattened alternates may be stale.
1130 m_variantSymbolCache.clear();
1131
1132 // We've just reset the library symbol, so the lib_pins, which were just
1133 // pointers to the old symbol, need to be cleared.
1134 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1135 pin->SetLibPin( nullptr );
1136
1137 UpdatePins();
1138}
1139
1140
1142{
1143 if( m_part )
1144 return m_part->GetDescription();
1145
1146 return wxEmptyString;
1147}
1148
1149
1150wxString SCH_SYMBOL::GetShownDescription( RESOLUTION_CONTEXT aContext, int aDepth ) const
1151{
1152 if( m_part )
1153 return m_part->GetShownDescription( aContext, aDepth );
1154
1155 return wxEmptyString;
1156}
1157
1158
1160{
1161 if( m_part )
1162 return m_part->GetKeyWords();
1163
1164 return wxEmptyString;
1165}
1166
1167
1168wxString SCH_SYMBOL::GetShownKeyWords( RESOLUTION_CONTEXT aContext, int aDepth ) const
1169{
1170 if( m_part )
1171 return m_part->GetShownKeyWords( aContext, aDepth );
1172
1173 return wxEmptyString;
1174}
1175
1176
1178{
1179 if( m_part )
1180 return m_part->GetDatasheetField().GetText();
1181
1182 return wxEmptyString;
1183}
1184
1185
1187{
1188 if( SCH_SCREEN* screen = GetParentScreen() )
1189 screen->BumpConnectivityRevision();
1190
1191 updatePins();
1192}
1193
1194
1196{
1197 std::map<wxString, wxString> altPinMap;
1198 std::map<wxString, SCH_PIN::ALT> altPinDefs;
1199 std::map<wxString, std::vector<SCH_PIN*>> pinUuidMap;
1200 std::set<SCH_PIN*> unassignedSchPins;
1201 std::vector<SCH_PIN*> unassignedLibPins;
1202
1203 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1204 {
1205 // Saved order keeps duplicate-number identities independent of allocation order.
1206 pinUuidMap[pin->GetNumber()].push_back( pin.get() );
1207
1208 unassignedSchPins.insert( pin.get() );
1209
1210 if( !pin->GetAlt().IsEmpty() )
1211 {
1212 altPinMap[pin->GetNumber()] = pin->GetAlt();
1213 auto altDefIt = pin->GetAlternates().find( pin->GetAlt() );
1214
1215 if( altDefIt != pin->GetAlternates().end() )
1216 altPinDefs[pin->GetNumber()] = altDefIt->second;
1217 }
1218
1219 pin->SetLibPin( nullptr );
1220 }
1221
1222 m_pinMap.clear();
1223
1224 if( !m_part )
1225 return;
1226
1227 // NB: Don't filter by unit: this data-structure is used for all instances,
1228 // some of which might have different units.
1229 for( SCH_PIN* libPin : m_part->GetGraphicalPins( ALL_UNITS, m_bodyStyle ) )
1230 {
1231 SCH_PIN* pin = nullptr;
1232
1233 auto ii = pinUuidMap.find( libPin->GetNumber() );
1234
1235 if( ii == pinUuidMap.end() || ii->second.empty() )
1236 {
1237 unassignedLibPins.push_back( libPin );
1238 continue;
1239 }
1240
1241 auto it = ii->second.begin();
1242 pin = *it;
1243 ii->second.erase( it );
1244 pin->GetAlternates() = libPin->GetAlternates();
1245 pin->SetLibPin( libPin );
1246 pin->SetPosition( libPin->GetPosition() );
1247 pin->SetUnit( libPin->GetUnit() );
1248 pin->SetBodyStyle( libPin->GetBodyStyle() );
1249
1250 unassignedSchPins.erase( pin );
1251
1252 auto iii = altPinMap.find( libPin->GetNumber() );
1253
1254 if( iii != altPinMap.end() )
1255 {
1256 wxString altName = iii->second;
1257
1258 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
1259 {
1260 auto defIt = altPinDefs.find( libPin->GetNumber() );
1261
1262 if( defIt != altPinDefs.end() )
1263 {
1264 for( const auto& [name, alt] : pin->GetAlternates() )
1265 {
1266 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
1267 {
1268 altName = name;
1269 break;
1270 }
1271 }
1272 }
1273 }
1274
1275 pin->SetAlt( altName );
1276 }
1277
1278 m_pinMap[libPin] = pin;
1279 }
1280
1281 // Add any pins that were not found in the symbol
1282 size_t nextUnassigned = 0;
1283
1284 for( SCH_PIN* libPin : unassignedLibPins )
1285 {
1286 SCH_PIN* pin = nullptr;
1287
1288 // First try to re-use an existing pin
1289 if( !unassignedSchPins.empty() )
1290 {
1291 while( nextUnassigned < m_pins.size()
1292 && !unassignedSchPins.contains( m_pins[nextUnassigned].get() ) )
1293 {
1294 ++nextUnassigned;
1295 }
1296
1297 pin = m_pins.at( nextUnassigned++ ).get();
1298 unassignedSchPins.erase( pin );
1299 }
1300 else
1301 {
1302 // This is a pin that was not found in the symbol, so create a new one.
1303 pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( this, libPin ) ) ).get();
1304 }
1305
1306 m_pinMap[libPin] = pin;
1307 pin->GetAlternates() = libPin->GetAlternates();
1308 pin->SetLibPin( libPin );
1309 pin->SetPosition( libPin->GetPosition() );
1310 pin->SetUnit( libPin->GetUnit() );
1311 pin->SetBodyStyle( libPin->GetBodyStyle() );
1312 pin->SetNumber( libPin->GetNumber() );
1313
1314 auto iii = altPinMap.find( libPin->GetNumber() );
1315
1316 if( iii != altPinMap.end() )
1317 {
1318 wxString altName = iii->second;
1319
1320 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
1321 {
1322 auto defIt = altPinDefs.find( libPin->GetNumber() );
1323
1324 if( defIt != altPinDefs.end() )
1325 {
1326 for( const auto& [name, alt] : pin->GetAlternates() )
1327 {
1328 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
1329 {
1330 altName = name;
1331 break;
1332 }
1333 }
1334 }
1335 }
1336
1337 pin->SetAlt( altName );
1338 }
1339 }
1340
1341 // If we have any pins left in the symbol that were not found in the library, remove them.
1342 for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
1343 {
1344 auto it2 = unassignedSchPins.find( it1->get() );
1345
1346 if( it2 != unassignedSchPins.end() )
1347 {
1348 it1 = m_pins.erase( it1 );
1349 unassignedSchPins.erase( it2 );
1350 }
1351 else
1352 {
1353 ++it1;
1354 }
1355 }
1356
1357 // If the symbol is selected, then its pins are selected.
1358 if( IsSelected() )
1359 {
1360 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1361 pin->SetSelected();
1362 }
1363}
1364
1365
1366void SCH_SYMBOL::SetBodyStyle( int aBodyStyle )
1367{
1368 if( aBodyStyle != m_bodyStyle )
1369 {
1370 m_bodyStyle = aBodyStyle;
1371
1372 // The body style may have a different pin layout so the update the pin map.
1373 UpdatePins();
1374 }
1375}
1376
1377
1379{
1380 if( m_part )
1381 return m_part->GetUnitCount();
1382
1383 return 0;
1384}
1385
1386
1388{
1389 if( m_part )
1390 return m_part->GetBodyStyleCount();
1391
1392 return 0;
1393}
1394
1395
1397{
1398 if( m_part )
1399 return m_part->HasDeMorganBodyStyles();
1400
1401 return false;
1402}
1403
1404
1405wxString SCH_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
1406{
1407 if( m_part )
1408 return m_part->GetUnitDisplayName( aUnit, aLabel );
1409 else if( aLabel )
1410 return wxString::Format( _( "Unit %s" ), SubReference( aUnit ) );
1411 else
1412 return SubReference( aUnit );
1413}
1414
1415
1416wxString SCH_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
1417{
1418 if( m_part )
1419 return m_part->GetBodyStyleDescription( aBodyStyle, aLabel );
1420 else
1421 return wxT( "?" );
1422}
1423
1424
1425bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance, const KIID_PATH& aSheetPath, bool aTestFromEnd ) const
1426{
1427 if( !aTestFromEnd )
1428 {
1429 auto it = m_instancePathIndex.find( aSheetPath );
1430
1431 if( it != m_instancePathIndex.end() )
1432 {
1433 aInstance = m_instances[it->second];
1434 return true;
1435 }
1436
1437 return false;
1438 }
1439
1440 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1441 {
1442 if( instance.m_Path.EndsWith( aSheetPath ) )
1443 {
1444 aInstance = instance;
1445 return true;
1446 }
1447 }
1448
1449 return false;
1450}
1451
1452
1453void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
1454{
1455 RemoveInstance( aInstancePath.Path() );
1456}
1457
1458
1459void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
1460{
1461 // Search for an existing path and remove it if found
1462 auto indexIt = m_instancePathIndex.find( aInstancePath );
1463
1464 if( indexIt != m_instancePathIndex.end() )
1465 {
1466 size_t ii = indexIt->second;
1467 wxASSERT( ii < m_instances.size() );
1468 wxASSERT( m_instances[ii].m_Path == aInstancePath );
1469
1470 if( wxLog::IsAllowedTraceMask( traceSchSheetPaths ) )
1471 {
1472 wxLogTrace( traceSchSheetPaths,
1473 wxS( "Removing symbol instance:\n"
1474 " sheet path %s\n"
1475 " reference %s, unit %d from symbol %s." ),
1476 aInstancePath.AsString(), m_instances[ii].m_Reference, m_instances[ii].m_Unit,
1477 m_Uuid.AsString() );
1478 }
1479
1480 m_instances.erase( m_instances.begin() + ii );
1483 }
1484}
1485
1486
1488{
1489 m_instancePathIndex.clear();
1490 m_instancePathIndex.reserve( m_instances.size() );
1491
1492 for( size_t i = 0; i < m_instances.size(); ++i )
1493 {
1494 wxASSERT( m_instancePathIndex.find( m_instances[i].m_Path ) == m_instancePathIndex.end() );
1495 m_instancePathIndex[m_instances[i].m_Path] = i;
1496 }
1497}
1498
1499
1500void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, int aUnit )
1501{
1502 SCH_SYMBOL_INSTANCE instance;
1503 instance.m_Path = aPath;
1504 instance.m_Reference = aRef;
1505 instance.m_Unit = aUnit;
1506
1507 AddHierarchicalReference( instance );
1508}
1509
1510
1512{
1513 SCH_SYMBOL_INSTANCE instance = aInstance;
1514 RemoveInstance( instance.m_Path );
1515
1516 wxLogTrace( traceSchSheetPaths,
1517 wxS( "Adding symbol '%s' instance:\n"
1518 " sheet path '%s'\n"
1519 " reference '%s'\n"
1520 " unit %d\n" ),
1521 m_Uuid.AsString(), instance.m_Path.AsString(), instance.m_Reference, instance.m_Unit );
1522
1523 m_instancePathIndex[instance.m_Path] = m_instances.size();
1524 m_instances.push_back( instance );
1526
1527 // This should set the default instance to the first saved instance data for each symbol
1528 // when importing sheets.
1529 if( m_instances.size() == 1 )
1530 {
1532 m_unit = instance.m_Unit;
1533 }
1534}
1535
1536
1537const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
1538{
1539 KIID_PATH path = sheet->Path();
1540 wxString ref;
1541 wxString subRef;
1542
1543 const bool traceEnabled = wxLog::IsAllowedTraceMask( traceSchSymbolRef );
1544
1545 if( traceEnabled )
1546 {
1547 wxLogTrace( traceSchSymbolRef, "GetRef for symbol %s on path %s (sheet path has %zu sheets)",
1548 m_Uuid.AsString(), path.AsString(), sheet->size() );
1549 wxLogTrace( traceSchSymbolRef, " Symbol has %zu instance references", m_instances.size() );
1550 }
1551
1552 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1553 {
1554 const SCH_SYMBOL_INSTANCE& instance = m_instances[it->second];
1555
1556 ref = instance.m_Reference;
1557 subRef = SubReference( instance.m_Unit );
1558
1559 if( traceEnabled )
1560 wxLogTrace( traceSchSymbolRef, " MATCH FOUND: ref=%s", ref );
1561 }
1562
1563 // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
1564 // use this as a default for this path. This will happen if we load a version 1 schematic
1565 // file. It will also mean that multiple instances of the same sheet by default all have
1566 // the same symbol references, but perhaps this is best.
1567 if( ref.IsEmpty() && !GetField( FIELD_T::REFERENCE )->GetText().IsEmpty() )
1568 {
1570
1571 if( traceEnabled )
1572 wxLogTrace( traceSchSymbolRef, " Using fallback from REFERENCE field: %s", ref );
1573 }
1574
1575 if( ref.IsEmpty() )
1576 {
1578
1579 if( traceEnabled )
1580 wxLogTrace( traceSchSymbolRef, " Using unannotated reference: %s", ref );
1581 }
1582
1583 if( aIncludeUnit && GetUnitCount() > 1 )
1584 ref += subRef;
1585
1586 if( traceEnabled )
1587 wxLogTrace( traceSchSymbolRef, " Final reference: %s", ref );
1588
1589 return ref;
1590}
1591
1592
1593void SCH_SYMBOL::SetRefProp( const wxString& aRef )
1594{
1596
1597 if( validator.DoValidate( aRef, nullptr ) )
1598 SetRef( &Schematic()->CurrentSheet(), aRef );
1599}
1600
1601
1602void SCH_SYMBOL::SetValueProp( const wxString& aValue )
1603{
1604 wxString currentVariant = Schematic()->GetCurrentVariant();
1605 SetValueFieldText( aValue, &Schematic()->CurrentSheet(), currentVariant );
1606}
1607
1608
1609void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
1610{
1611 KIID_PATH path = sheet->Path();
1612 const wxString previousPrefix = m_prefix;
1613 const bool wasDoNetlist = m_doNetlist;
1614 bool changed = false;
1615
1616 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1617 changed = std::exchange( m_instances[it->second].m_Reference, ref ) != ref;
1618 else
1620
1621 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1622 pin->ClearDefaultNetName( sheet );
1623
1624 if( Schematic() && *sheet == Schematic()->CurrentSheet() )
1625 {
1626 changed |= GetField( FIELD_T::REFERENCE )->GetText() != ref;
1628 }
1629
1630 // Reinit the m_prefix member if needed
1632
1633 if( m_prefix.IsEmpty() )
1634 m_prefix = wxT( "U" );
1635
1636 // Power symbols have references starting with # and are not included in netlists
1637 m_doNetlist = !ref.StartsWith( wxT( "#" ) );
1638
1639 if( changed || m_prefix != previousPrefix || m_doNetlist != wasDoNetlist )
1641}
1642
1643
1644void SCH_SYMBOL::SetFieldText( SCH_FIELD* aField, const wxString& aFieldName, const wxString& aFieldText,
1645 const SCH_SHEET_PATH* aPath, const wxString& aVariantName )
1646{
1647 switch( aField->GetId() )
1648 {
1649 case FIELD_T::REFERENCE:
1650 wxCHECK( aPath, /* void */ );
1651 SetRef( aPath, aFieldText );
1652 break;
1653
1654 default:
1655 {
1656 wxString defaultText = aField->GetText( aPath );
1657
1658 if( aVariantName.IsEmpty() )
1659 {
1660 if( aFieldText != defaultText )
1661 aField->SetText( aFieldText );
1662 }
1663 else
1664 {
1665 SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1666
1667 wxCHECK( instance, /* void */ );
1668
1669 // Diff against the value the variant resolves to without an explicit override so
1670 // alternate symbol fields read back through the UI are not re-stored as overrides.
1671 if( LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath ) )
1672 {
1673 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1674
1675 if( altField && !altField->GetText().IsEmpty() )
1676 defaultText = altField->GetText();
1677 }
1678
1679 bool changed = false;
1680
1681 if( instance->m_Variants.contains( aVariantName ) )
1682 {
1683 std::map<wxString, wxString>& fields = instance->m_Variants[aVariantName].m_Fields;
1684
1685 if( aFieldText != defaultText )
1686 {
1687 auto [entry, inserted] = fields.try_emplace( aFieldName, aFieldText );
1688 changed = inserted || std::exchange( entry->second, aFieldText ) != aFieldText;
1689 }
1690 else
1691 {
1692 changed = fields.erase( aFieldName ) != 0;
1693 }
1694 }
1695 else if( aFieldText != defaultText )
1696 {
1697 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1698
1699 newVariant.InitializeAttributes( *this );
1700 newVariant.m_Fields[aFieldName] = aFieldText;
1701 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1702 changed = true;
1703 }
1704
1705 if( changed )
1707 }
1708
1709 break;
1710 }
1711 }
1712}
1713
1714
1715void SCH_SYMBOL::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath,
1716 const wxString& aVariantName )
1717{
1718 wxCHECK_MSG( !aFieldName.IsEmpty(), /* void */, wxT( "Can't set text on a field with no name!" ) );
1719
1720 SCH_FIELD* field = GetField( aFieldName );
1721
1722 wxCHECK_MSG( field, /* void */, wxT( "Can't set text on a field not yet added to the symbol!" ) );
1723
1724 SetFieldText( field, aFieldName, aFieldText, aPath, aVariantName );
1725}
1726
1727
1728wxString SCH_SYMBOL::GetFieldText( const SCH_FIELD* aField, const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
1729 const wxString& aVariantName ) const
1730{
1731 switch( aField->GetId() )
1732 {
1733 case FIELD_T::REFERENCE:
1734 wxCHECK( aPath, aField->GetText() );
1735 return GetRef( aPath, false );
1736 break;
1737
1738 case FIELD_T::FOOTPRINT:
1739 if( !aVariantName.IsEmpty() && aPath )
1740 {
1741 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1742
1743 if( instance && instance->m_Variants.contains( aVariantName )
1744 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
1745 {
1746 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
1747 }
1748
1749 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1750
1751 if( altSymbol )
1752 {
1753 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::FOOTPRINT );
1754
1755 if( altField && !altField->GetText().IsEmpty() )
1756 return altField->GetText();
1757 }
1758 }
1759
1760 return GetFootprintFieldText( nullptr, RAW_VALUE );
1761
1762 default:
1763 if( aVariantName.IsEmpty() )
1764 {
1765 return aField->GetText();
1766 }
1767 else if( aPath )
1768 {
1769 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1770
1771 if( instance && instance->m_Variants.contains( aVariantName ) )
1772 {
1773 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
1774
1775 if( variant.m_Fields.contains( aFieldName ) )
1776 return variant.m_Fields.at( aFieldName );
1777
1778 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1779
1780 if( altSymbol )
1781 {
1782 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1783
1784 if( altField && !altField->GetText().IsEmpty() )
1785 return altField->GetText();
1786 }
1787 }
1788 }
1789
1790 break;
1791 }
1792
1793 return aField->GetText();
1794}
1795
1796
1797wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
1798 const wxString& aVariantName ) const
1799{
1800 wxCHECK_MSG( !aFieldName.IsEmpty(), wxEmptyString, wxT( "Can't get text from a field with no name!" ) );
1801
1802 const SCH_FIELD* field = GetField( aFieldName );
1803
1804 wxCHECK_MSG( field, wxEmptyString, wxT( "Can't get text from a field not yet added to the symbol!" ) );
1805
1806 return GetFieldText( field, aFieldName, aPath, aVariantName );
1807}
1808
1809
1810bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const
1811{
1812 KIID_PATH path = aSheet->Path();
1813
1814 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1815 {
1816 if( instance.m_Path == path )
1817 return !instance.m_Reference.IsEmpty() && instance.m_Reference.Last() != '?';
1818 }
1819
1820 return false;
1821}
1822
1823
1825{
1826 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
1827
1828 refDesignator.Replace( "~", " " );
1829
1830 wxString prefix = refDesignator;
1831
1832 while( prefix.Length() )
1833 {
1834 wxUniCharRef last = prefix.Last();
1835
1836 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
1837 prefix.RemoveLast();
1838 else
1839 break;
1840 }
1841
1842 // Avoid a prefix containing trailing/leading spaces
1843 prefix.Trim( true );
1844 prefix.Trim( false );
1845
1846 if( !prefix.IsEmpty() )
1847 SetPrefix( prefix );
1848}
1849
1850
1851wxString SCH_SYMBOL::SubReference( int aUnit, bool aAddSeparator ) const
1852{
1853 // A custom unit display name overrides the default A/B/C (or numeric) suffix.
1854 if( m_part )
1855 {
1856 const std::map<int, wxString>& names = m_part->GetUnitDisplayNames();
1857 auto it = names.find( aUnit );
1858
1859 if( it != names.end() )
1860 {
1861 wxString subRef;
1862
1863 if( SCHEMATIC* schematic = Schematic() )
1864 {
1865 int sep = schematic->Settings().m_SubpartIdSeparator;
1866
1867 if( sep != 0 && aAddSeparator )
1868 subRef << wxChar( sep );
1869 }
1870
1871 subRef << it->second;
1872 return subRef;
1873 }
1874 }
1875
1876 if( SCHEMATIC* schematic = Schematic() )
1877 return schematic->Settings().SubReference( aUnit, aAddSeparator );
1878
1879 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
1880}
1881
1882
1884{
1885 KIID_PATH path = aSheet->Path();
1886
1887 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1888 return m_instances[it->second].m_Unit;
1889
1890 // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
1891 // version 1 schematic file.
1892 return m_unit;
1893}
1894
1895
1896void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
1897{
1898 KIID_PATH path = aSheet->Path();
1899
1900 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1901 {
1902 if( std::exchange( m_instances[it->second].m_Unit, aUnitSelection ) != aUnitSelection )
1904
1905 return;
1906 }
1907
1908 // didn't find it; better add it
1910}
1911
1912
1913void SCH_SYMBOL::setVariantAttribute( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName,
1914 bool SCH_SYMBOL::*aBase, bool SCH_SYMBOL_VARIANT::*aOverride )
1915{
1916 bool* attribute = &( this->*aBase );
1917
1918 if( aInstance && !aVariantName.IsEmpty() )
1919 {
1920 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1921
1922 wxCHECK_MSG( instance, /* void */,
1923 wxString::Format( wxS( "Cannot set attribute for invalid sheet path '%s'." ),
1924 aInstance->PathHumanReadable() ) );
1925
1926 auto it = instance->m_Variants.find( aVariantName );
1927
1928 if( it == instance->m_Variants.end() )
1929 {
1930 if( aEnable == this->*aBase )
1931 return;
1932
1933 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1934 newVariant.InitializeAttributes( *this );
1935 newVariant.*aOverride = aEnable;
1936 AddVariant( *aInstance, newVariant );
1937 return;
1938 }
1939
1940 attribute = &( it->second.*aOverride );
1941 }
1942
1943 if( *attribute == aEnable )
1944 return;
1945
1946 *attribute = aEnable;
1948}
1949
1950
1951void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1952{
1953 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_DNP, &SCH_SYMBOL_VARIANT::m_DNP );
1954}
1955
1956
1957bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1958{
1959 if( !aInstance || aVariantName.IsEmpty() )
1960 return m_DNP;
1961
1962 SCH_SYMBOL_INSTANCE instance;
1963
1964 if( !GetInstance( instance, aInstance->Path() ) )
1965 return m_DNP;
1966
1967 if( instance.m_Variants.contains( aVariantName ) )
1968 return instance.m_Variants[aVariantName].m_DNP;
1969
1970 return m_DNP;
1971}
1972
1973
1975 const wxString& aVariantName )
1976{
1977 if( !aInstance || aVariantName.IsEmpty() )
1978 {
1979 m_pinMapOverride = aOverride;
1980 return;
1981 }
1982
1983 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1984
1985 wxCHECK_MSG( instance, /* void */,
1986 wxString::Format( wxS( "Cannot set pin map override for invalid sheet path '%s'." ),
1987 aInstance->PathHumanReadable() ) );
1988
1989 if( instance->m_Variants.contains( aVariantName ) )
1990 {
1991 instance->m_Variants[aVariantName].m_PinMapOverride = aOverride;
1992 }
1993 else if( aOverride != m_pinMapOverride )
1994 {
1995 SCH_SYMBOL_VARIANT variant( aVariantName );
1996
1997 variant.InitializeAttributes( *this );
1998 variant.m_PinMapOverride = aOverride;
1999 AddVariant( *aInstance, variant );
2000 }
2001}
2002
2003
2005{
2007
2008 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2009 {
2010 for( auto& [name, variant] : instance.m_Variants )
2011 variant.m_PinMapOverride = PIN_MAP_INSTANCE_OVERRIDE();
2012 }
2013}
2014
2015
2017 const wxString& aVariantName ) const
2018{
2020
2021 if( aInstance && !aVariantName.IsEmpty() )
2022 {
2023 SCH_SYMBOL_INSTANCE instance;
2024
2025 if( GetInstance( instance, aInstance->Path() ) && instance.m_Variants.contains( aVariantName ) )
2026 result = instance.m_Variants[aVariantName].m_PinMapOverride;
2027 }
2028
2029 // Units 2..N follow unit 1's record; resolve that here so callers never see a delegate.
2030 if( result.IsDelegate() && aInstance )
2031 result = resolveDelegatedPinMapOverride( *aInstance, aVariantName );
2032
2033 return result;
2034}
2035
2036
2038 const wxString& aVariantName ) const
2039{
2040 if( !Schematic() )
2042
2043 wxString ref = GetRef( &aSheet );
2044
2045 for( const SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
2046 {
2047 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2048 {
2049 SCH_SYMBOL* sibling = static_cast<SCH_SYMBOL*>( item );
2050
2051 if( sibling == this || sibling->GetUnit() != 1 )
2052 continue;
2053
2054 if( sibling->GetRef( &sheet ).CmpNoCase( ref ) != 0 )
2055 continue;
2056
2057 PIN_MAP_INSTANCE_OVERRIDE unit1 = sibling->GetPinMapOverride( &sheet, aVariantName );
2058
2059 // Guard against a unit-1 record that itself (incorrectly) delegates.
2060 if( unit1.IsDelegate() )
2062
2063 return unit1;
2064 }
2065 }
2066
2068}
2069
2070
2071void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
2072{
2073 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromBOM,
2075}
2076
2077
2078bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
2079{
2080 if( !aInstance || aVariantName.IsEmpty() )
2081 return m_excludedFromBOM;
2082
2083 SCH_SYMBOL_INSTANCE instance;
2084
2085 if( !GetInstance( instance, aInstance->Path() ) )
2086 return m_excludedFromBOM;
2087
2088 if( instance.m_Variants.contains( aVariantName ) )
2089 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
2090
2091 // If the variant has not been defined yet, return the default exclude from BOM setting.
2092 return m_excludedFromBOM;
2093}
2094
2095
2096void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
2097{
2098 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromSim,
2100}
2101
2102
2103bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
2104{
2105 if( !aInstance || aVariantName.IsEmpty() )
2106 return m_excludedFromSim;
2107
2108 SCH_SYMBOL_INSTANCE instance;
2109
2110 if( !GetInstance( instance, aInstance->Path() ) )
2111 return m_excludedFromSim;
2112
2113 if( instance.m_Variants.contains( aVariantName ) )
2114 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
2115
2116 // If variant is not defined yet, return default exclude from simulation setting.
2117 return m_excludedFromSim;
2118}
2119
2120
2121void SCH_SYMBOL::SetExcludedFromBoard( bool aEnable, const SCH_SHEET_PATH* aInstance,
2122 const wxString& aVariantName )
2123{
2124 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromBoard,
2126}
2127
2128
2130 const wxString& aVariantName ) const
2131{
2132 if( !aInstance || aVariantName.IsEmpty() )
2133 return m_excludedFromBoard;
2134
2135 SCH_SYMBOL_INSTANCE instance;
2136
2137 if( !GetInstance( instance, aInstance->Path() ) )
2138 return m_excludedFromBoard;
2139
2140 if( instance.m_Variants.contains( aVariantName ) )
2141 return instance.m_Variants[aVariantName].m_ExcludedFromBoard;
2142
2143 // If variant is not defined yet, return default exclude from board setting.
2144 return m_excludedFromBoard;
2145}
2146
2147
2148void SCH_SYMBOL::SetExcludedFromPosFiles( bool aEnable, const SCH_SHEET_PATH* aInstance,
2149 const wxString& aVariantName )
2150{
2151 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromPosFiles,
2153}
2154
2155
2157 const wxString& aVariantName ) const
2158{
2159 if( !aInstance || aVariantName.IsEmpty() )
2161
2162 SCH_SYMBOL_INSTANCE instance;
2163
2164 if( !GetInstance( instance, aInstance->Path() ) )
2166
2167 if( instance.m_Variants.contains( aVariantName ) )
2168 return instance.m_Variants[aVariantName].m_ExcludedFromPosFiles;
2169
2170 // If variant is not defined yet, return default exclude from position files setting.
2172}
2173
2174
2175void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
2176{
2177 bool changed = false;
2178
2179 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2180 changed |= std::exchange( instance.m_Unit, aUnitSelection ) != aUnitSelection;
2181
2182 if( changed )
2184}
2185
2186
2187const wxString SCH_SYMBOL::GetValue( const SCH_SHEET_PATH* aInstance, RESOLUTION_CONTEXT aContext,
2188 const wxString& aVariantName ) const
2189{
2190 if( aVariantName.IsEmpty() || !aInstance )
2191 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aContext );
2192
2193 std::optional variant = GetVariant( *aInstance, aVariantName );
2194
2195 if( variant )
2196 {
2197 const wxString& fieldName = GetField( FIELD_T::VALUE )->GetName();
2198
2199 auto resolve =
2200 [&]( const wxString& aText ) -> wxString
2201 {
2202 std::function<bool( wxString* )> resolver =
2203 [&]( wxString* token ) -> bool
2204 {
2205 return ResolveTextVar( aInstance, token, aVariantName, 1 );
2206 };
2207
2208 return ExpandTextVars( aText, &resolver, aContext );
2209 };
2210
2211 if( variant->m_Fields.contains( fieldName ) )
2212 return resolve( variant->m_Fields[fieldName] );
2213
2214 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aInstance );
2215
2216 if( altSymbol )
2217 {
2218 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::VALUE );
2219
2220 if( altField && !altField->GetText().IsEmpty() )
2221 return resolve( altField->GetText() );
2222 }
2223 }
2224
2225 // Fall back to default value when variant doesn't have an override
2226
2227 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aContext, aVariantName );
2228}
2229
2230
2231void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance,
2232 const wxString& aVariantName )
2233{
2234 if( !aInstance || aVariantName.IsEmpty() )
2235 {
2236 GetField( FIELD_T::VALUE )->SetText( aValue );
2237 return;
2238 }
2239
2240 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
2241
2242 wxCHECK( instance, /* void */ );
2243
2244 wxString fieldName = GetField( FIELD_T::VALUE )->GetName();
2245
2246 if( instance->m_Variants.contains( aVariantName ) )
2247 {
2248 instance->m_Variants[aVariantName].m_Fields[fieldName] = aValue;
2249 }
2250 else
2251 {
2252 SCH_SYMBOL_VARIANT newVariant( aVariantName );
2253
2254 newVariant.InitializeAttributes( *this );
2255 newVariant.m_Fields[fieldName] = aValue;
2256 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
2257 }
2258}
2259
2260
2262 const wxString& aVariantName ) const
2263{
2264 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aContext, aVariantName );
2265
2266}
2267
2268
2269void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
2270{
2271 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
2272}
2273
2274
2276{
2277 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
2278 return field;
2279
2280 m_fields.emplace_back( this, aFieldType );
2281 return &m_fields.back();
2282}
2283
2284
2285const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
2286{
2287 return FindField( m_fields, aFieldType );
2288}
2289
2290
2291SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
2292{
2293 return FindField( m_fields, aFieldName );
2294}
2295
2296
2297const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
2298{
2299 return FindField( m_fields, aFieldName );
2300}
2301
2302
2303void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
2304{
2305 for( const SCH_FIELD& field : m_fields )
2306 {
2307 if( aVisibleOnly )
2308 {
2309 if( !field.IsVisible() || field.GetText().IsEmpty() )
2310 continue;
2311 }
2312
2313 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
2314 }
2315
2316 std::sort( aVector.begin(), aVector.end(),
2317 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
2318 {
2319 return lhs->GetOrdinal() < rhs->GetOrdinal();
2320 } );
2321}
2322
2323
2325{
2326 return NextFieldOrdinal( m_fields );
2327}
2328
2329
2331{
2332 m_fields.push_back( aField );
2333
2335
2336 return &m_fields.back();
2337}
2338
2339
2340void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
2341{
2342 // aFieldName may refer to the name owned by the field being removed.
2343 wxString fieldName = aFieldName;
2344
2345 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
2346 {
2347 if( m_fields[ii].IsMandatory() )
2348 continue;
2349
2350 if( fieldName == m_fields[ii].GetName( false ) )
2351 {
2352 m_fields.erase( m_fields.begin() + ii );
2353
2354 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2355 {
2356 for( auto& [name, variant] : instance.m_Variants )
2357 variant.m_Fields.erase( fieldName );
2358 }
2359
2361
2362 return;
2363 }
2364 }
2365}
2366
2367
2369{
2370 for( SCH_FIELD& field : m_fields )
2371 {
2372 if( field.GetName().IsSameAs( aFieldName, false ) )
2373 return &field;
2374 }
2375
2376 return nullptr;
2377}
2378
2379
2380const SCH_FIELD* SCH_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
2381{
2382 for( const SCH_FIELD& field : m_fields )
2383 {
2384 if( field.GetName().IsSameAs( aFieldName, false ) )
2385 return &field;
2386 }
2387
2388 return nullptr;
2389}
2390
2391
2392void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
2393 bool aResetRef, bool aResetOtherFields )
2394{
2395 if( m_part )
2396 {
2397 std::vector<SCH_FIELD*> fields;
2398 m_part->GetFields( fields );
2399
2400 for( const SCH_FIELD* libField : fields )
2401 {
2402 SCH_FIELD* schField;
2403 FIELD_T fieldType = FIELD_T::USER;
2404
2405 if( libField->IsMandatory() )
2406 {
2407 fieldType = libField->GetId();
2408 schField = GetField( fieldType );
2409 }
2410 else
2411 {
2412 schField = GetField( libField->GetUntranslatedName() );
2413
2414 if( !schField )
2415 {
2416 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetUntranslatedName() ) );
2417 schField->ImportValues( *libField );
2418 schField->SetTextPos( m_pos + libField->GetTextPos() );
2419 }
2420 }
2421
2422 schField->SetPrivate( libField->IsPrivate() );
2423
2424 if( aUpdateStyle )
2425 {
2426 schField->ImportValues( *libField );
2427 schField->SetTextPos( m_pos + libField->GetTextPos() );
2428 }
2429
2430 if( fieldType == FIELD_T::REFERENCE && aPath )
2431 {
2432 if( aResetRef )
2433 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
2434 else if( aUpdateRef )
2435 SetRef( aPath, libField->GetText() );
2436 }
2437 else if( fieldType == FIELD_T::VALUE )
2438 {
2439 SetValueFieldText( UnescapeString( libField->GetText() ) );
2440 }
2441 else if( fieldType == FIELD_T::DATASHEET )
2442 {
2443 if( aResetOtherFields )
2444 schField->SetText( GetDatasheet() ); // alias-specific value
2445 else if( aUpdateOtherFields )
2446 schField->SetText( libField->GetText() );
2447 }
2448 else
2449 {
2450 if( aResetOtherFields || aUpdateOtherFields )
2451 schField->SetText( libField->GetText() );
2452 }
2453 }
2454 }
2455}
2456
2457
2458void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit,
2459 PROPERTY_BASE* aProperty, const wxString& aVariantName )
2460{
2461 bool updateValue = true;
2462 bool updateExclFromBOM = true;
2463 bool updateExclFromBoard = true;
2464 bool updateExclFromPosFiles = true;
2465 bool updateDNP = true;
2466 bool updateOtherFields = true;
2467 bool updatePins = true;
2468 bool updatePinMapOverride = true;
2469
2470 if( aProperty )
2471 {
2472 updateValue = aProperty->Name() == _HKI( "Value" );
2473 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
2474 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
2475 updateExclFromPosFiles = aProperty->Name() == _HKI( "Exclude From Position Files" );
2476 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
2477 updatePinMapOverride = aProperty->Name() == wxS( "Pin Map Mode" ) || aProperty->Name() == wxS( "Pin Map Name" );
2478 updateOtherFields = false;
2479 updatePins = false;
2480 }
2481
2482 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateExclFromPosFiles && !updateDNP
2483 && !updateOtherFields && !updatePins && !updatePinMapOverride )
2484 {
2485 return;
2486 }
2487
2488 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
2489 // in sync in multi-unit parts.
2490 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
2491 {
2492 wxString ref = GetRef( &aSourceSheet );
2493
2494 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
2495 {
2496 SCH_SCREEN* screen = sheet.LastScreen();
2497 std::vector<SCH_SYMBOL*> otherUnits;
2498
2499 CollectOtherUnits( ref, GetUnitSelection( &aSourceSheet ), m_lib_id, sheet, &otherUnits );
2500
2501 for( SCH_SYMBOL* otherUnit : otherUnits )
2502 {
2503 aCommit.Modify( otherUnit, screen );
2504
2505 if( updateValue )
2506 {
2507 otherUnit->SetFieldText( GetField( FIELD_T::VALUE )->GetName(),
2508 GetValue( &aSourceSheet, RAW_VALUE, aVariantName ),
2509 &sheet, aVariantName );
2510 }
2511
2512 if( updateOtherFields )
2513 {
2514 for( SCH_FIELD& field : m_fields )
2515 {
2516 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
2517 {
2518 // already handled
2519 continue;
2520 }
2521
2522 SCH_FIELD* otherField;
2523
2524 if( field.IsMandatory() )
2525 otherField = otherUnit->GetField( field.GetId() );
2526 else
2527 otherField = otherUnit->GetField( field.GetName() );
2528
2529 if( otherField )
2530 {
2531 otherField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet, aVariantName );
2532 }
2533 else
2534 {
2535 SCH_FIELD newField( field );
2536 const_cast<KIID&>( newField.m_Uuid ) = KIID();
2537
2538 newField.Offset( -GetPosition() );
2539 newField.Offset( otherUnit->GetPosition() );
2540
2541 newField.SetParent( otherUnit );
2542 SCH_FIELD* addedField = otherUnit->AddField( newField );
2543
2544 if( !aVariantName.IsEmpty() )
2545 {
2546 addedField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet,
2547 aVariantName );
2548 }
2549 }
2550 }
2551
2552 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
2553 {
2554 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
2555
2556 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
2557 otherUnit->RemoveField( otherField.GetName() );
2558 }
2559 }
2560
2561 if( updateExclFromBOM )
2562 {
2563 otherUnit->SetExcludedFromBOM( GetExcludedFromBOM( &aSourceSheet, aVariantName ), &sheet,
2564 aVariantName );
2565 }
2566
2567 if( updateExclFromBoard )
2568 {
2569 otherUnit->SetExcludedFromBoard( GetExcludedFromBoard( &aSourceSheet, aVariantName ), &sheet,
2570 aVariantName );
2571 }
2572
2573 if( updateExclFromPosFiles )
2574 {
2575 otherUnit->SetExcludedFromPosFiles( GetExcludedFromPosFiles( &aSourceSheet, aVariantName ), &sheet,
2576 aVariantName );
2577 }
2578
2579 if( updateDNP )
2580 otherUnit->SetDNP( GetDNP( &aSourceSheet, aVariantName ), &sheet, aVariantName );
2581
2582 if( updatePinMapOverride )
2583 otherUnit->SetPinMapOverride( GetPinMapOverride( &aSourceSheet, aVariantName ), &sheet,
2584 aVariantName );
2585
2586 if( updatePins )
2587 {
2588 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
2589 {
2590 for( SCH_PIN* src_pin : otherUnit->GetPinsByNumber( model_pin->GetNumber() ) )
2591 src_pin->SetAlt( model_pin->GetAlt() );
2592 }
2593 }
2594 }
2595 }
2596 }
2597}
2598
2599
2600void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
2601{
2602 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2603 aFunction( pin.get() );
2604
2605 for( SCH_FIELD& field : m_fields )
2606 aFunction( &field );
2607}
2608
2609
2615
2616
2617SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
2618{
2619 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2620 {
2621 if( pin->GetNumber() == aNumber )
2622 return pin.get();
2623 }
2624
2625 return nullptr;
2626}
2627
2628
2629SCH_PIN* SCH_SYMBOL::GetPinByEffectivePadNumber( const wxString& aPadNumber, const SCH_SHEET_PATH* aSheet,
2630 const wxString& aVariantName ) const
2631{
2632 if( !aSheet )
2633 return nullptr;
2634
2635 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2636 {
2637 for( const wxString& pad : ExpandStackedPinNotation( pin->GetEffectivePadNumber( *aSheet, aVariantName ) ) )
2638 {
2639 if( pad == aPadNumber )
2640 return pin.get();
2641 }
2642 }
2643
2644 return nullptr;
2645}
2646
2647
2648std::vector<SCH_PIN*> SCH_SYMBOL::GetPinsByNumber( const wxString& aNumber ) const
2649{
2650 std::vector<SCH_PIN*> pins;
2651
2652 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2653 {
2654 if( pin->GetNumber() == aNumber )
2655 pins.push_back( pin.get() );
2656 }
2657
2658 return pins;
2659}
2660
2661
2662const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
2663{
2664 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2665 {
2666 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2667 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2668
2669 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
2670 continue;
2671
2672 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
2673 continue;
2674
2675 if( pin->GetPosition() == aPos )
2676 return pin.get();
2677 }
2678
2679 return nullptr;
2680}
2681
2682
2683std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
2684{
2685 if( m_part )
2686 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
2687
2688 return std::vector<SCH_PIN*>();
2689}
2690
2691
2692std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
2693{
2694 if( m_part )
2695 return m_part->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES );
2696
2697 return std::vector<SCH_PIN*>();
2698}
2699
2700
2702{
2703 return m_part ? m_part->GetPinCount() : 0;
2704}
2705
2706
2708{
2709 auto it = m_pinMap.find( aLibPin );
2710
2711 if( it != m_pinMap.end() )
2712 return it->second;
2713
2714 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
2715 return nullptr;
2716}
2717
2718
2719std::vector<const SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
2720{
2721 std::vector<const SCH_PIN*> pins;
2722 int unit = m_unit;
2723
2724 if( !aSheet && Schematic() )
2725 aSheet = &Schematic()->CurrentSheet();
2726
2727 if( aSheet )
2728 unit = GetUnitSelection( aSheet );
2729
2730 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2731 {
2732 if( unit != ALL_UNITS && pin->GetUnit() != ALL_UNITS && pin->GetUnit() != unit )
2733 continue;
2734
2735 pins.push_back( pin.get() );
2736 }
2737
2738 return pins;
2739}
2740
2741
2742std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet )
2743{
2744 std::vector<SCH_PIN*> pins;
2745 int unit = m_unit;
2746
2747 if( !aSheet && Schematic() )
2748 aSheet = &Schematic()->CurrentSheet();
2749
2750 if( aSheet )
2751 unit = GetUnitSelection( aSheet );
2752
2753 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2754 {
2755 if( unit != ALL_UNITS && pin->GetUnit() != ALL_UNITS && pin->GetUnit() != unit )
2756 continue;
2757
2758 pins.push_back( pin.get() );
2759 }
2760
2761 return pins;
2762}
2763
2764
2765std::vector<SCH_PIN*> SCH_SYMBOL::GetGraphicalPins( int aUnit, int aBodyStyle ) const
2766{
2767 std::vector<SCH_PIN*> pins;
2768
2769 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2770 {
2771 // Unit filtering:
2772 if( aUnit != ALL_UNITS
2773 && pin->GetUnit() != ALL_UNITS
2774 && pin->GetUnit() != aUnit )
2775 {
2776 continue;
2777 }
2778
2779 // Body style filtering:
2780 if( aBodyStyle != ALL_BODY_STYLES
2781 && pin->GetBodyStyle() != ALL_BODY_STYLES
2782 && pin->GetBodyStyle() != aBodyStyle )
2783 {
2784 continue;
2785 }
2786
2787 pins.push_back( pin.get() );
2788 }
2789
2790 return pins;
2791}
2792
2793
2795{
2796 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
2797
2798 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
2799
2800 std::swap( m_pos, symbol->m_pos );
2801 std::swap( m_lib_id, symbol->m_lib_id );
2802 std::swap( m_prefix, symbol->m_prefix );
2803
2804 {
2805 m_pins.swap( symbol->m_pins ); // std::vector's swap()
2806
2807 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
2808 pin->SetParent( symbol );
2809
2810 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2811 pin->SetParent( this );
2812 }
2813
2814 LIB_SYMBOL* libSymbol = symbol->m_part.release();
2815 symbol->m_part = std::move( m_part );
2816 symbol->UpdatePins();
2817 m_part.reset( libSymbol );
2818 UpdatePins();
2819
2820 {
2821 m_fields.swap( symbol->m_fields ); // std::vector's swap()
2822
2823 for( SCH_FIELD& field : symbol->m_fields )
2824 field.SetParent( symbol );
2825
2826 for( SCH_FIELD& field : m_fields )
2827 field.SetParent( this );
2828 }
2829
2830 std::swap( m_pinNameOffset, symbol->m_pinNameOffset );
2831 std::swap( m_showPinNames, symbol->m_showPinNames );
2832 std::swap( m_showPinNumbers, symbol->m_showPinNumbers );
2833
2834 TRANSFORM tmp = m_transform;
2835 m_transform = symbol->m_transform;
2836 symbol->m_transform = tmp;
2837
2838 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
2839 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
2840 std::swap( m_DNP, symbol->m_DNP );
2841 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
2842 std::swap( m_excludedFromPosFiles, symbol->m_excludedFromPosFiles );
2843 std::swap( m_pinMapOverride, symbol->m_pinMapOverride );
2844
2845 std::swap( m_instances, symbol->m_instances );
2846 std::swap( m_instancePathIndex, symbol->m_instancePathIndex );
2847 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
2848 std::swap( m_doNetlist, symbol->m_doNetlist );
2849 std::swap( m_passthroughMode, symbol->m_passthroughMode );
2850 std::swap( m_signalName, symbol->m_signalName );
2851
2852 m_variantSymbolCache.clear();
2853 symbol->m_variantSymbolCache.clear();
2854}
2855
2856
2857void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
2858{
2859 for( const SCH_FIELD& field : m_fields )
2860 {
2861 if( field.IsPrivate() )
2862 continue;
2863
2864 if( field.IsMandatory() )
2865 aVars->push_back( field.GetUntranslatedName().Upper() );
2866 else
2867 aVars->push_back( field.GetName() );
2868 }
2869
2870 aVars->push_back( wxT( "OP" ) );
2871 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
2872 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
2873 aVars->push_back( wxT( "UNIT" ) );
2874 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
2875 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
2876 aVars->push_back( wxT( "SYMBOL_NAME" ) );
2877 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
2878 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
2879 aVars->push_back( wxT( "SYMBOL_IS_POWER" ) );
2880 aVars->push_back( wxT( "SYMBOL_IS_LOCAL_POWER" ) );
2881 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
2882 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
2883 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
2884 aVars->push_back( wxT( "DNP" ) );
2885 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
2886 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
2887 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
2888 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
2889 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
2890 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
2891 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
2892}
2893
2894
2895bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
2896{
2897 wxString variant;
2898
2899 if( Schematic() )
2900 variant = Schematic()->GetCurrentVariant();
2901
2902 return ResolveTextVar( aPath, token, variant, aDepth );
2903}
2904
2905
2906bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, const wxString& aVariantName,
2907 int aDepth ) const
2908{
2909 // Per-thread regex. CONNECTION_GRAPH::resolveAllDrivers calls this from worker
2910 // threads, and wxRegEx::Matches is not safe to call concurrently on one instance.
2911 thread_local wxRegEx operatingPoint( wxT( "^"
2912 "OP"
2913 "(:[^.]*)?" // pin
2914 "(.([0-9])?" // precisionStr
2915 "([a-zA-Z]*))?" // rangeStr
2916 "$" ) );
2917
2918 if( !aPath )
2919 return false;
2920
2922
2923 if( !schematic )
2924 return false;
2925
2927 && ( operatingPoint.Matches( *token ) || token->StartsWith( wxS( "NET_NAME(" ) )
2928 || token->StartsWith( wxS( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxS( "NET_CLASS(" ) ) ) )
2929 {
2930 token->clear();
2931 return true;
2932 }
2933
2934 if( operatingPoint.Matches( *token ) )
2935 {
2936 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
2937 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
2938 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
2939
2940 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
2941 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
2942
2943 SIM_LIB_MGR simLibMgr( &schematic->Project() );
2944
2945 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
2946 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
2947
2948 if( m_part )
2949 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
2950
2951 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
2952
2953 NULL_REPORTER devnull;
2954 SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1,
2955 aVariantName, devnull ).model;
2956 SPICE_ITEM spiceItem;
2957 spiceItem.refName = GetRef( aPath );
2958
2959 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
2960 spiceRef = spiceRef.Lower();
2961
2962 if( pin.IsEmpty() )
2963 {
2964 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2965 return true;
2966 }
2967 else if( pin == wxS( ":power" ) )
2968 {
2969 if( rangeStr.IsEmpty() )
2970 range = wxS( "~W" );
2971
2972 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
2973 return true;
2974 }
2975 else
2976 {
2977 pin = pin.SubString( 1, -1 ); // Strip ':' from front
2978
2979 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
2980 {
2981 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
2982
2983 if( !symbolPin )
2984 continue;
2985
2986 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
2987 {
2988 if( model.GetPins().size() == 2 )
2989 {
2990 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2991 }
2992 else
2993 {
2994 wxString netChainName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
2995 *token = schematic->GetOperatingPoint( netChainName, precision, range );
2996 }
2997
2998 return true;
2999 }
3000 }
3001 }
3002
3003 *token = wxS( "?" );
3004 return true;
3005 }
3006
3007 if( token->Contains( ':' ) )
3008 {
3009 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
3010 return true;
3011 }
3012
3013 for( const SCH_FIELD& field : m_fields )
3014 {
3015 wxString fieldName = field.IsMandatory() ? field.GetUntranslatedName() : field.GetName();
3016
3017 wxString textToken = field.GetText();
3018 textToken.Replace( " ", wxEmptyString );
3019 wxString tokenString = "${" + fieldName + "}";
3020
3021 // If the field data is just a reference to the field, don't resolve
3022 if( textToken.IsSameAs( tokenString, false ) )
3023 return true;
3024
3025 if( token->IsSameAs( fieldName, false ) )
3026 {
3027 if( field.GetId() == FIELD_T::REFERENCE )
3028 *token = GetRef( aPath, true );
3029 else
3030 *token = field.GetShownText( aPath, INTERNAL, aVariantName, aDepth + 1 );
3031
3032 return true;
3033 }
3034 }
3035
3036 // Consider missing simulation fields as empty, not un-resolved
3037 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
3038 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
3039 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
3040 {
3041 *token = wxEmptyString;
3042 return true;
3043 }
3044
3045 for( const TEMPLATE_FIELDNAME& templateFieldname :
3046 schematic->Project().GetProjectFile().m_TemplateFieldNames.GetResolvedTemplateFieldNames() )
3047 {
3048 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
3049 {
3050 // If we didn't find it in the fields list then it isn't set on this symbol.
3051 // Just return an empty string.
3052 *token = wxEmptyString;
3053 return true;
3054 }
3055 }
3056
3057 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
3058 {
3059 wxString footprint = GetFootprintFieldText( aPath, INTERNAL, aVariantName );
3060
3061 wxArrayString parts = wxSplit( footprint, ':' );
3062
3063 if( parts.Count() > 0 )
3064 *token = parts[0];
3065 else
3066 *token = wxEmptyString;
3067
3068 return true;
3069 }
3070 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
3071 {
3072 wxString footprint = GetFootprintFieldText( aPath, INTERNAL, aVariantName );
3073
3074 wxArrayString parts = wxSplit( footprint, ':' );
3075
3076 if( parts.Count() > 1 )
3077 *token = parts[std::min( 1, (int) parts.size() - 1 )];
3078 else
3079 *token = wxEmptyString;
3080
3081 return true;
3082 }
3083 else if( token->IsSameAs( wxT( "UNIT" ) ) )
3084 {
3085 *token = SubReference( GetUnitSelection( aPath ) );
3086 return true;
3087 }
3088 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
3089 {
3090 *token = GetRef( aPath, false );
3091 return true;
3092 }
3093 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
3094 {
3095 *token = m_lib_id.GetUniStringLibNickname();
3096 return true;
3097 }
3098 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
3099 {
3100 *token = m_lib_id.GetUniStringLibItemName();
3101 return true;
3102 }
3103 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
3104 {
3105 *token = GetShownDescription( INTERNAL, aDepth + 1 );
3106 return true;
3107 }
3108 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
3109 {
3110 *token = GetShownKeyWords( INTERNAL, aDepth + 1 );
3111 return true;
3112 }
3113 else if( token->IsSameAs( wxT( "SYMBOL_IS_POWER" ) ) )
3114 {
3115 *token = this->IsPower() ? wxString( wxS( "Power Symbol" ) ) : wxString( "" );
3116 return true;
3117 }
3118 else if( token->IsSameAs( wxT( "SYMBOL_IS_LOCAL_POWER" ) ) )
3119 {
3120 *token = this->IsLocalPower() ? wxString( wxS( "Local Power Symbol" ) ) : wxString( "" );
3121 return true;
3122 }
3123 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
3124 {
3125 *token = wxEmptyString;
3126
3127 if( aPath->GetExcludedFromBOM( aVariantName ) || this->ResolveExcludedFromBOM( aPath, aVariantName ) )
3128 *token = wxS( "Excluded from BOM" );
3129
3130 return true;
3131 }
3132 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
3133 {
3134 *token = wxEmptyString;
3135
3136 if( aPath->GetExcludedFromBoard( aVariantName ) || this->ResolveExcludedFromBoard( aPath, aVariantName ) )
3137 *token = wxS( "Excluded from board" );
3138
3139 return true;
3140 }
3141 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
3142 {
3143 *token = wxEmptyString;
3144
3145 if( aPath->GetExcludedFromSim( aVariantName ) || this->ResolveExcludedFromSim( aPath, aVariantName ) )
3146 *token = wxS( "Excluded from simulation" );
3147
3148 return true;
3149 }
3150 else if( token->IsSameAs( wxT( "DNP" ) ) )
3151 {
3152 *token = wxEmptyString;
3153
3154 if( aPath->GetDNP( aVariantName ) || this->ResolveDNP( aPath, aVariantName ) )
3155 *token = wxS( "DNP" );
3156
3157 return true;
3158 }
3159 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
3160 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
3161 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
3162 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
3163 || token->StartsWith( wxT( "UNIT(" ) ) )
3164 {
3165 wxString pinNumber = token->AfterFirst( '(' );
3166 pinNumber = pinNumber.BeforeLast( ')' );
3167
3168 auto resolvePinConnection =
3169 [&]( const SCH_PIN& pin, const SCH_SHEET_PATH& path )
3170 {
3171 const bool local = token->StartsWith( wxS( "SHORT_NET_NAME" ) );
3172 const std::optional<wxString> name = pin.GetConnectionName( &path, local );
3173
3174 if( !name )
3175 {
3176 token->clear();
3177 return;
3178 }
3179
3180 if( local )
3181 *token = name->Lower().StartsWith( wxS( "unconnected" ) ) ? wxString( "NC" ) : *name;
3182 else if( token->StartsWith( wxS( "NET_NAME" ) ) )
3183 *token = *name;
3184 else if( token->StartsWith( wxS( "NET_CLASS" ) ) )
3185 *token = pin.GetEffectiveNetClass( &path )->GetName();
3186 };
3187
3188 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
3189 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
3190 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
3191
3192 // First, try to find the pin in the current unit (for backward compatibility)
3193 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
3194 std::vector<const SCH_PIN*> pinsToSearch;
3195 std::vector<const SCH_PIN*> altPinsToSearch;
3196
3197 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
3198 {
3199 for( SCH_PIN* pin : GetAllLibPins() )
3200 pinsToSearch.push_back( pin );
3201 }
3202 else
3203 {
3204 for( const SCH_PIN* pin : GetPins( aPath ) )
3205 pinsToSearch.push_back( pin );
3206
3207 for( SCH_PIN* pin : GetAllLibPins() )
3208 altPinsToSearch.push_back( pin );
3209 }
3210
3211 for( const SCH_PIN* pin : pinsToSearch )
3212 {
3213 if( pin->GetNumber() == pinNumber )
3214 {
3215 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
3216 {
3217 int pinUnit = pin->GetUnit();
3218 wxString result;
3219
3220 if( isReferenceFunction )
3221 {
3222 // Return the full unit reference (e.g., "J601A")
3223 if( pinUnit != ALL_UNITS )
3224 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
3225 else
3226 result = GetRef( aPath, false );
3227 }
3228 else if( isShortReferenceFunction )
3229 {
3230 // Return the reference without unit (e.g., "J601")
3231 result = GetRef( aPath, false );
3232 }
3233 else if( isUnitFunction )
3234 {
3235 // Return only the unit letter (e.g., "A")
3236 if( pinUnit != ALL_UNITS )
3237 result = SubReference( pinUnit, false );
3238 else
3239 result = wxEmptyString;
3240 }
3241
3242 *token = std::move( result );
3243 return true;
3244 }
3245 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
3246 {
3247 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
3248 return true;
3249 }
3250 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
3251 {
3252 *token = pin->GetBaseName();
3253 return true;
3254 }
3255 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
3256 {
3257 // Build list of alternate names only (no base name)
3258 wxString altList;
3259
3260 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
3261
3262 for( const auto& [altName, altDef] : alts )
3263 {
3264 if( !altList.IsEmpty() )
3265 altList += wxT( ", " );
3266
3267 altList += altName;
3268 }
3269
3270 *token = std::move( altList );
3271 return true;
3272 }
3273
3274 resolvePinConnection( *pin, *aPath );
3275
3276 return true;
3277 }
3278 }
3279
3280 // If pin not found in current unit, search all units (auto-resolution)
3281 for( const SCH_PIN* pin : altPinsToSearch )
3282 {
3283 if( pin->GetNumber() == pinNumber )
3284 {
3285 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
3286 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
3287 {
3288 *token = pin->GetBaseName();
3289 return true;
3290 }
3291 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
3292 {
3293 // Build list of alternate names only (no base name)
3294 wxString altList;
3295
3296 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
3297
3298 for( const auto& [altName, altDef] : alts )
3299 {
3300 if( !altList.IsEmpty() )
3301 altList += wxT( ", " );
3302 altList += altName;
3303 }
3304
3305 *token = altList;
3306 return true;
3307 }
3308
3309 // For net-related functions, find which sheet path has this pin's unit
3310 int pinUnit = pin->GetUnit();
3311
3312 // Search all sheets for a symbol with our reference and the correct unit
3313 // This is needed because each unit of a multi-unit symbol is a separate object
3314 SCH_SHEET_PATH targetPath;
3315 SCH_SYMBOL* targetSymbol = nullptr;
3316
3317 if( Schematic() )
3318 {
3319 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
3320 {
3321 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
3322 {
3323 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
3324
3325 // Check if this symbol has the same reference designator and the correct unit
3326 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
3327 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
3328 {
3329 targetPath = sheetPath; // Copy the sheet path
3330 targetSymbol = symbol;
3331 break;
3332 }
3333 }
3334
3335 if( targetSymbol )
3336 break;
3337 }
3338 }
3339
3340 if( !targetSymbol )
3341 {
3342 // Unit not placed on any sheet
3343 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
3344 return true;
3345 }
3346
3347 // Get the pin from the actual instance symbol we found
3348 // Match by pin number, not by pointer, since the library pins are different objects
3349 SCH_PIN* instancePin = nullptr;
3350
3351 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
3352 {
3353 if( candidate->GetNumber() == pinNumber )
3354 {
3355 instancePin = candidate;
3356 break;
3357 }
3358 }
3359
3360 if( !instancePin )
3361 {
3362 *token = wxEmptyString;
3363 return true;
3364 }
3365
3366 // PIN_NAME doesn't need connection data, just instance pin
3367 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
3368 {
3369 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
3370 return true;
3371 }
3372
3373 resolvePinConnection( *instancePin, targetPath );
3374
3375 return true;
3376 }
3377 }
3378
3379 // If we got here, no pin was found - report unresolved
3380 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
3381 return true;
3382 }
3383 // The great property resolver: ${PROPERTY.My_Property}
3384 else if( token->StartsWith( wxS( "PROPERTY." ) ) )
3385 {
3386 // Get the second half, convert _ to ' '
3387 wxString propertyName = token->AfterFirst( '.' );
3388 propertyName.Replace( wxS( "_" ), wxS( " " ) );
3389
3390 // Check if the property manager knows this property
3392 PROPERTY_BASE* property = propMgr.GetProperty( TYPE_HASH( *this ), propertyName );
3393
3394 if( !property )
3395 {
3396 for( PROPERTY_BASE* candidate : GetDynamicProperties( aPath ) )
3397 {
3398 if( propertyName.CmpNoCase( candidate->Name() ) == 0 )
3399 {
3400 property = candidate;
3401 break;
3402 }
3403 }
3404 }
3405
3406 if( !property || property->IsHiddenFromPropertiesManager() )
3407 return false;
3408
3409 if( !propMgr.IsAvailableFor( TYPE_HASH( *this ), property, const_cast<SCH_SYMBOL*>( this ) ) )
3410 return false;
3411
3412 // Property-panel getters use the displayed instance, which may differ from this text's path.
3413 wxAny sourceValue;
3414 const wxString& name = property->Name();
3415
3416 if( name == wxS( "Reference" ) )
3417 sourceValue = GetRef( aPath );
3418 else if( name == wxS( "Value" ) )
3419 sourceValue = GetValue( aPath, RAW_VALUE, aVariantName );
3420 else if( name == wxS( "Unit" ) )
3421 sourceValue = GetUnitSelection( aPath );
3422 else if( name == wxS( "Exclude From Simulation" ) )
3423 sourceValue = GetExcludedFromSim( aPath, aVariantName );
3424 else if( name == wxS( "Exclude From Bill of Materials" ) )
3425 sourceValue = GetExcludedFromBOM( aPath, aVariantName );
3426 else if( name == wxS( "Exclude From Board" ) )
3427 sourceValue = GetExcludedFromBoard( aPath, aVariantName );
3428 else if( name == wxS( "Exclude From Position Files" ) )
3429 sourceValue = GetExcludedFromPosFiles( aPath, aVariantName );
3430 else if( name == wxS( "Do not Populate" ) )
3431 sourceValue = GetDNP( aPath, aVariantName );
3432 else if( auto* instanceProperty = dynamic_cast<SCH_SYMBOL_INSTANCE_PROPERTY*>( property ) )
3433 sourceValue = instanceProperty->ValueForInstance( this, aPath, aVariantName );
3434 else
3435 sourceValue = Get( property );
3436
3437 KICAD_DIFF::DIFF_VALUE value = KICAD_DIFF::WxAnyToDiffValue( sourceValue, property );
3438
3440 return false;
3441
3442 *token = value.ToDisplayString( EDA_UNITS::MILS, schIUScale );
3443 return true;
3444 }
3445
3446 // See if parent can resolve it (this will recurse to ancestors)
3447 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
3448 return true;
3449
3450 return false;
3451}
3452
3453
3454void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
3455{
3456 if( aSheetPath )
3457 {
3458 KIID_PATH path = aSheetPath->Path();
3459
3460 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3461 {
3462 if( instance.m_Path == path )
3463 {
3464 if( instance.m_Reference.IsEmpty() || aResetPrefix )
3465 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
3466 else
3467 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
3468 }
3469 }
3470 }
3471 else
3472 {
3473 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3474 {
3475 if( instance.m_Reference.IsEmpty() || aResetPrefix )
3476 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
3477 else
3478 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
3479 }
3480 }
3481
3482 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3483 pin->ClearDefaultNetName( aSheetPath );
3484
3485 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
3486 // When clearing for a specific sheet path, we must preserve the field text because it serves
3487 // as a fallback for GetRef() when instances for other sheet paths are looked up.
3488 // See issue #20173: modifying field text here corrupts references in shared screens.
3489 if( !aSheetPath )
3490 {
3491 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
3492
3493 if( currentReference.IsEmpty() || aResetPrefix )
3495 else
3497 }
3498}
3499
3500
3502{
3503 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
3504 wxCHECK( aSheetPath.size() > 0, false );
3505
3506 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
3507 {
3508 // if aSheetPath is found, nothing to do:
3509 if( instance.m_Path == aSheetPath )
3510 return false;
3511 }
3512
3513 // This entry does not exist: add it, with its last-used reference
3514 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
3515 return true;
3516}
3517
3518
3519bool SCH_SYMBOL::SetInstanceProjectName( const KIID_PATH& aSheetPath, const wxString& aProjectName )
3520{
3521 SCH_SYMBOL_INSTANCE* instance = getInstance( aSheetPath );
3522
3523 if( !instance )
3524 return false;
3525
3526 instance->m_ProjectName = aProjectName;
3527 return true;
3528}
3529
3530
3531void SCH_SYMBOL::SetOrientation( int aOrientation )
3532{
3533 TRANSFORM temp = TRANSFORM();
3534 bool transform = false;
3535
3536 switch( aOrientation )
3537 {
3538 case SYM_ORIENT_0:
3539 case SYM_NORMAL: // default transform matrix
3541 break;
3542
3543 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
3544 temp.x1 = 0;
3545 temp.y1 = 1;
3546 temp.x2 = -1;
3547 temp.y2 = 0;
3548 transform = true;
3549 break;
3550
3551 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
3552 temp.x1 = 0;
3553 temp.y1 = -1;
3554 temp.x2 = 1;
3555 temp.y2 = 0;
3556 transform = true;
3557 break;
3558
3559 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
3560 temp.x1 = -1;
3561 temp.y1 = 0;
3562 temp.x2 = 0;
3563 temp.y2 = 1;
3564 transform = true;
3565 break;
3566
3567 case SYM_MIRROR_X: // Mirror X (incremental transform)
3568 temp.x1 = 1;
3569 temp.y1 = 0;
3570 temp.x2 = 0;
3571 temp.y2 = -1;
3572 transform = true;
3573 break;
3574
3575 case SYM_ORIENT_90:
3578 break;
3579
3580 case SYM_ORIENT_180:
3584 break;
3585
3586 case SYM_ORIENT_270:
3589 break;
3590
3591 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
3594 break;
3595
3596 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
3599 break;
3600
3605 break;
3606
3607 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
3610 break;
3611
3612 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
3615 break;
3616
3621 break;
3622
3623 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
3626 break;
3627
3628 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
3631 break;
3632
3637 break;
3638
3639 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
3642 break;
3643
3644 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
3647 break;
3648
3653 break;
3654
3655 default:
3656 transform = false;
3657 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
3658 break;
3659 }
3660
3661 if( transform )
3662 {
3663 /* The new matrix transform is the old matrix transform modified by the
3664 * requested transformation, which is the temp transform (rot,
3665 * mirror ..) in order to have (in term of matrix transform):
3666 * transform coord = new_m_transform * coord
3667 * where transform coord is the coord modified by new_m_transform from
3668 * the initial value coord.
3669 * new_m_transform is computed (from old_m_transform and temp) to
3670 * have:
3671 * transform coord = old_m_transform * temp
3672 */
3673 TRANSFORM newTransform;
3674
3675 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
3676 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
3677 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
3678 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
3679 m_transform = newTransform;
3680 }
3681}
3682
3683
3685{
3686 /*
3687 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
3688 * now, so let's just cache it for the moment.
3689 */
3692
3693 int rotate_values[] = { SYM_ORIENT_0,
3705
3706 // Try to find the current transform option:
3707 TRANSFORM transform = m_transform;
3708 SCH_SYMBOL temp( *this );
3709 temp.SetParentGroup( nullptr );
3710
3711 for( int type_rotate : rotate_values )
3712 {
3713 temp.SetOrientation( type_rotate );
3714
3715 if( transform == temp.GetTransform() )
3716 {
3718 return type_rotate;
3719 }
3720 }
3721
3722 // Error: orientation not found in list (should not happen)
3723 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
3724
3725 return SYM_NORMAL;
3726}
3727
3728
3729#if defined( DEBUG )
3730
3731void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
3732{
3733 // for now, make it look like XML:
3734 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
3735 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
3736 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
3737 << ">\n";
3738
3739 // skip the reference, it's been output already.
3740 for( int i = 1; i < (int) GetFields().size(); ++i )
3741 {
3742 const wxString& value = GetFields()[i].GetText();
3743
3744 if( !value.IsEmpty() )
3745 {
3746 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
3747 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
3748 }
3749 }
3750
3751 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
3752}
3753
3754#endif
3755
3756
3757BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
3758{
3759 BOX2I bBox;
3760 const SCH_SHEET_PATH* sheetPath = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
3761 const LIB_SYMBOL* effSym = GetEffectiveLibSymbol( sheetPath );
3762
3763 if( effSym )
3764 bBox = effSym->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3765 else
3766 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3767
3768 bBox = m_transform.TransformCoordinate( bBox );
3769 bBox.Normalize();
3770
3771 bBox.Offset( m_pos );
3772
3773 if( aIncludeFields )
3774 {
3775 for( const SCH_FIELD& field : m_fields )
3776 {
3777 if( field.IsVisible() )
3778 bBox.Merge( field.GetBoundingBox() );
3779 }
3780 }
3781
3782 return bBox;
3783}
3784
3785
3787{
3788 try
3789 {
3790 return doGetBoundingBox( false, false );
3791 }
3792 catch( const boost::bad_pointer& e )
3793 {
3794 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
3795 return BOX2I();
3796 }
3797}
3798
3799
3801{
3802 return doGetBoundingBox( true, false );
3803}
3804
3805
3807{
3808 return doGetBoundingBox( true, true );
3809}
3810
3811
3812void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
3813{
3814 wxString msg;
3815
3816 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
3817 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
3818 wxString currentVariant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
3819
3820 auto addExcludes =
3821 [&]()
3822 {
3823 wxArrayString msgs;
3824
3825 if( GetExcludedFromSim() )
3826 msgs.Add( _( "Simulation" ) );
3827
3828 if( GetExcludedFromBOM() )
3829 msgs.Add( _( "BOM" ) );
3830
3831 if( GetExcludedFromBoard() )
3832 msgs.Add( _( "Board" ) );
3833
3834 if( GetDNP( currentSheet, currentVariant ) )
3835 msgs.Add( _( "DNP" ) );
3836
3837 msg = wxJoin( msgs, '|' );
3838 msg.Replace( '|', wxS( ", " ) );
3839
3840 if( !msg.empty() )
3841 aList.emplace_back( _( "Exclude from" ), msg );
3842 };
3843
3844 // part and alias can differ if alias is not the root
3845 if( m_part )
3846 {
3847 if( m_part.get() != LIB_SYMBOL::GetDummy() )
3848 {
3849 if( m_part->IsPower() )
3850 {
3851 // Don't use GetShownText(); we want to see the variable references here
3852 aList.emplace_back( _( "Power symbol" ),
3853 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3854 }
3855 else
3856 {
3857 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
3858
3859 // Don't use GetShownText(); we want to see the variable references here
3860 aList.emplace_back( _( "Value" ),
3861 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3862 addExcludes();
3863 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3864 }
3865
3866#if 0 // Display symbol flags, for debug only
3867 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
3868#endif
3869
3870 if( !m_part->IsRoot() )
3871 {
3872 msg = _( "Missing parent" );
3873
3874 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
3875
3876 if( parent )
3877 msg = parent->GetName();
3878
3879 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
3880 }
3881 else if( !m_lib_id.GetLibNickname().empty() )
3882 {
3883 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
3884 }
3885 else
3886 {
3887 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
3888 }
3889
3890 // Display the current associated footprint, if exists.
3891 // Don't use GetShownText(); we want to see the variable references here
3892 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
3893
3894 if( msg.IsEmpty() )
3895 msg = _( "<Unknown>" );
3896
3897 aList.emplace_back( _( "Footprint" ), msg );
3898
3899 // Display description of the symbol, and keywords found in lib
3900 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
3901 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
3902 }
3903 }
3904 else
3905 {
3906 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
3907
3908 // Don't use GetShownText(); we want to see the variable references here
3909 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3910 addExcludes();
3911 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3912
3913 wxString libNickname = GetLibId().GetLibNickname();
3914
3915 if( libNickname.empty() )
3916 msg = _( "No library defined!" );
3917 else
3918 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
3919
3920 aList.emplace_back( _( "Library" ), msg );
3921 }
3922}
3923
3924
3929
3930
3932{
3933 if( std::unique_ptr<LIB_SYMBOL>& libSymbol = GetLibSymbolRef() )
3934 return libSymbol->GetEmbeddedFiles();
3935
3936 return nullptr;
3937}
3938
3939
3941{
3942 int dx = m_pos.x;
3943
3945 MIRROR( m_pos.x, aCenter );
3946 dx -= m_pos.x; // dx,0 is the move vector for this transform
3947
3948 for( SCH_FIELD& field : m_fields )
3949 {
3950 // Move the fields to the new position because the symbol itself has moved.
3951 VECTOR2I pos = field.GetTextPos();
3952 pos.x -= dx;
3953 field.SetTextPos( pos );
3954 }
3955}
3956
3957
3959{
3960 int dy = m_pos.y;
3961
3963 MIRROR( m_pos.y, aCenter );
3964 dy -= m_pos.y; // 0,dy is the move vector for this transform
3965
3966 for( SCH_FIELD& field : m_fields )
3967 {
3968 // Move the fields to the new position because the symbol itself has moved.
3969 VECTOR2I pos = field.GetTextPos();
3970 pos.y -= dy;
3971 field.SetTextPos( pos );
3972 }
3973}
3974
3975
3976void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
3977{
3978 VECTOR2I prev = m_pos;
3979
3980 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
3981
3983
3984 for( SCH_FIELD& field : m_fields )
3985 {
3986 // Move the fields to the new position because the symbol itself has moved.
3987 VECTOR2I pos = field.GetTextPos();
3988 pos.x -= prev.x - m_pos.x;
3989 pos.y -= prev.y - m_pos.y;
3990 field.SetTextPos( pos );
3991 }
3992}
3993
3994
3995bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
3996{
3997 if( aSearchData.searchMetadata )
3998 {
3999 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
4000 return true;
4001
4002 if( EDA_ITEM::Matches( GetShownDescription( FOR_GUI ), aSearchData ) )
4003 return true;
4004
4005 if( EDA_ITEM::Matches( GetShownKeyWords( FOR_GUI ), aSearchData ) )
4006 return true;
4007 }
4008
4009 // Fields are searched as separate items
4010
4011 // Search non-field lib draw items (pins, graphical text) for completeness.
4012 if( const std::unique_ptr<LIB_SYMBOL>& libSymbol = GetLibSymbolRef() )
4013 {
4014 for( const SCH_ITEM& drawItem : libSymbol->GetDrawItems() )
4015 {
4016 if( drawItem.Type() == SCH_FIELD_T )
4017 continue;
4018
4019 if( drawItem.Matches( aSearchData, aAuxData ) )
4020 return true;
4021 }
4022 }
4023
4024 // Symbols are searchable via the child field and pin item text.
4025 return false;
4026}
4027
4028
4029void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
4030{
4031 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
4032 {
4033 if( SCH_PIN* lib_pin = pin->GetLibPin() )
4034 {
4035 if( lib_pin->GetUnit() != ALL_UNITS && m_unit != ALL_UNITS && m_unit != lib_pin->GetUnit() )
4036 continue;
4037
4038 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
4039 aItemList.push_back( item );
4040 }
4041 }
4042}
4043
4044
4045bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
4046 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
4047{
4048 bool changed = false;
4049
4050 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
4051 {
4052 bool previousState = pin->IsDangling();
4053 pin->SetIsDangling( true );
4054
4055 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
4056
4057 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
4058 bool do_break = false;
4059
4060 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
4061 {
4062 DANGLING_END_ITEM& each_item = *it;
4063
4064 // Some people like to stack pins on top of each other in a symbol to indicate
4065 // internal connection. While technically connected, it is not particularly useful
4066 // to display them that way, so skip any pins that are in the same symbol as this
4067 // one.
4068 if( each_item.GetParent() == this )
4069 continue;
4070
4071 switch( each_item.GetType() )
4072 {
4073 case PIN_END:
4074 case LABEL_END:
4075 case SHEET_LABEL_END:
4076 case WIRE_END:
4077 case NO_CONNECT_END:
4078 case JUNCTION_END:
4079 pin->SetIsDangling( false );
4080 do_break = true;
4081 break;
4082
4083 default: break;
4084 }
4085
4086 if( do_break )
4087 break;
4088 }
4089
4090 changed = ( changed || ( previousState != pin->IsDangling() ) );
4091 }
4092
4093 return changed;
4094}
4095
4096
4098{
4099 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
4100 return VECTOR2I( 0, 0 );
4101
4102 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
4103}
4104
4105
4106bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
4107{
4108 // Do not compare to ourself.
4109 if( aItem == this )
4110 return false;
4111
4112 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
4113
4114 // Don't compare against a different SCH_ITEM.
4115 wxCHECK( symbol, false );
4116
4117 // The move algorithm marks any pins that are being moved without something attached
4118 // (during the move) as dangling. We always need to recheck connectivity in this case
4119 // or we will not notice changes when the user places the symbol back in the same position
4120 // it started.
4121 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4122 {
4123 if( pin->IsDangling() )
4124 return true;
4125 }
4126
4127 if( GetPosition() != symbol->GetPosition() )
4128 return true;
4129
4130 if( GetLibId() != symbol->GetLibId() )
4131 return true;
4132
4133 if( GetPassthroughMode() != symbol->GetPassthroughMode() )
4134 return true;
4135
4136 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
4137 return true;
4138
4139 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
4140 return true;
4141
4142 // Power symbol value field changes are connectivity changes.
4143 if( IsPower() && ( GetValue( aInstance, FOR_NETNAME ) != symbol->GetValue( aInstance, FOR_NETNAME ) ) )
4144 return true;
4145
4146 if( IsLocalPower() != symbol->IsLocalPower() )
4147 return true;
4148
4149 if( m_pins.size() != symbol->m_pins.size() )
4150 return true;
4151
4152 for( size_t i = 0; i < m_pins.size(); i++ )
4153 {
4154 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
4155 return true;
4156 }
4157
4158 return false;
4159}
4160
4161
4162std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
4163{
4164 std::vector<VECTOR2I> retval;
4165
4166 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4167 {
4168 // Collect only pins attached to the current unit and convert.
4169 // others are not associated to this symbol instance
4170 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4171 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4172
4173 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4174 continue;
4175
4176 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4177 continue;
4178
4179 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
4180 }
4181
4182 return retval;
4183}
4184
4185
4187{
4188 const SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4189 LIB_SYMBOL* effectiveSymbol = const_cast<LIB_SYMBOL*>( GetEffectiveLibSymbol( sheet ) );
4190
4191 if( effectiveSymbol )
4192 {
4193 // Calculate the position relative to the symbol.
4194 VECTOR2I libPosition = aPosition - m_pos;
4195
4196 return effectiveSymbol->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
4197 }
4198
4199 return nullptr;
4200}
4201
4202
4203wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
4204{
4205 return wxString::Format( _( "Symbol %s [%s]" ),
4207 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
4208}
4209
4210
4211INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
4212{
4213 for( KICAD_T scanType : aScanTypes )
4214 {
4215 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
4216 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
4217 {
4218 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
4219 return INSPECT_RESULT::QUIT;
4220 }
4221
4222 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
4223 {
4224 for( SCH_FIELD& field : m_fields )
4225 {
4226 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
4227 return INSPECT_RESULT::QUIT;
4228 }
4229 }
4230
4231 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
4232 {
4233 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
4234 return INSPECT_RESULT::QUIT;
4235 }
4236
4237 if( scanType == SCH_FIELD_LOCATE_VALUE_T
4238 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
4239 {
4240 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
4241 return INSPECT_RESULT::QUIT;
4242 }
4243
4244 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
4245 {
4246 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
4247 return INSPECT_RESULT::QUIT;
4248 }
4249
4250 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
4251 {
4252 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
4253 return INSPECT_RESULT::QUIT;
4254 }
4255
4256 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
4257 {
4258 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4259 {
4260 // Collect only pins attached to the current unit and convert.
4261 // others are not associated to this symbol instance
4262 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4263 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4264
4265 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4266 continue;
4267
4268 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4269 continue;
4270
4271 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
4272 return INSPECT_RESULT::QUIT;
4273 }
4274 }
4275 }
4276
4278}
4279
4280
4281bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
4282{
4283 if( Type() != aItem.Type() )
4284 return Type() < aItem.Type();
4285
4286 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
4287
4289
4290 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
4291 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
4292
4293 if( m_pos.x != symbol->m_pos.x )
4294 return m_pos.x < symbol->m_pos.x;
4295
4296 if( m_pos.y != symbol->m_pos.y )
4297 return m_pos.y < symbol->m_pos.y;
4298
4299 if( m_prefix != symbol->m_prefix )
4300 return m_prefix < symbol->m_prefix;
4301
4302 if( m_schLibSymbolName != symbol->m_schLibSymbolName )
4303 return m_schLibSymbolName < symbol->m_schLibSymbolName;
4304
4305 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
4306}
4307
4308
4309bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
4310{
4311 // Don't compare m_lib_id: it may be instance-specific. Compare m_schLibSymbolName
4312 // instead.
4313 if( m_schLibSymbolName != aSymbol.m_schLibSymbolName )
4314 return false;
4315
4316 // m_prefix is an interesting one. It's sort of part of the annotation, which we don't
4317 // compare, but it's also sort of a higher level than the annotation itself. For now,
4318 // we skip it along with the annotation (FIELD_T::REFERENCE).
4319#if 0
4320 if( m_prefix != aSymbol.m_prefix )
4321 return false;
4322#endif
4323
4324 std::vector<SCH_FIELD*> fields, otherFields;
4325
4326 GetFields( fields, false );
4327 aSymbol.GetFields( otherFields, false );
4328
4329 if( fields.size() != otherFields.size() )
4330 return false;
4331
4332 for( int ii = 0; ii < (int) fields.size(); ii++ )
4333 {
4334 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
4335 continue;
4336
4337 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
4338 return false;
4339 }
4340
4341 if( m_doNetlist != aSymbol.m_doNetlist )
4342 return false;
4343
4344 if( m_passthroughMode != aSymbol.m_passthroughMode )
4345 return false;
4346
4347 // m_signalName has more to do with the placement on the schematic than the symbol itself
4348#if 0
4349 if( m_signalName != aSymbol.m_signalName )
4350 return false;
4351#endif
4352
4353 // Running the pin compare on matched pins found with GetPin( number) will match all same-numbered
4354 // pins in the first symbol with the first pin of that number in the second symbol. Sort the pins
4355 // instead, which results in a more "complete" matching of source and other pins.
4356 std::set<SCH_PIN*, SCH_SYMBOL::cmp_pins> sortedPins;
4357 std::set<SCH_PIN*, SCH_SYMBOL::cmp_pins> sortedOtherPins;
4358
4359 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4360 sortedPins.insert( pin.get() );
4361
4362 for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
4363 sortedOtherPins.insert( pin.get() );
4364
4365 if( sortedPins.size() != sortedOtherPins.size() )
4366 return false;
4367
4368 for( auto aIt = sortedPins.begin(), bIt = sortedOtherPins.begin(); aIt != sortedPins.end(); ++aIt, ++bIt )
4369 {
4370 if( !( *aIt )->operator==( *( *bIt ) ) )
4371 return false;
4372 }
4373
4374 return true;
4375}
4376
4377
4378bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
4379{
4380 return !( *this == aSymbol );
4381}
4382
4383
4385{
4386 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
4387 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
4388
4389 if( &aSymbol != this )
4390 {
4391 SYMBOL::operator=( aSymbol );
4392
4393 m_pos = aSymbol.m_pos;
4394 m_lib_id = aSymbol.m_lib_id;
4395 m_prefix = aSymbol.m_prefix;
4396
4397 // Pin relinking still needs the previous library's alternate definitions.
4398 auto oldPart = std::exchange( m_part, aSymbol.m_part ? std::make_unique<LIB_SYMBOL>( *aSymbol.m_part )
4399 : nullptr );
4400
4401 m_unit = aSymbol.m_unit;
4402 m_bodyStyle = aSymbol.m_bodyStyle;
4403 m_transform = aSymbol.m_transform;
4404
4405 m_instances = aSymbol.m_instances;
4407 m_doNetlist = aSymbol.m_doNetlist;
4409 m_signalName = aSymbol.m_signalName;
4411
4412 {
4413 m_fields = aSymbol.m_fields; // std::vector's assignment operator
4414
4415 // Reparent fields after assignment to new symbol.
4416 for( SCH_FIELD& field : m_fields )
4417 field.SetParent( this );
4418 }
4419
4420 UpdatePins();
4421 m_variantSymbolCache.clear();
4422 }
4423
4424 return *this;
4425}
4426
4427
4428bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
4429{
4430 BOX2I bBox = GetBodyBoundingBox();
4431 bBox.Inflate( aAccuracy / 2 );
4432
4433 if( bBox.Contains( aPosition ) )
4434 return true;
4435
4436 return false;
4437}
4438
4439
4440bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
4441{
4443 return false;
4444
4445 BOX2I rect = aRect;
4446
4447 rect.Inflate( aAccuracy / 2 );
4448
4449 if( aContained )
4450 return rect.Contains( GetBodyBoundingBox() );
4451
4452 return rect.Intersects( GetBodyBoundingBox() );
4453}
4454
4455
4456bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
4457{
4459 return false;
4460
4461 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
4462}
4463
4464
4465bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
4466{
4467 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
4468
4469 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4470 {
4471 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
4472 continue;
4473
4474 // Collect only pins attached to the current unit and convert.
4475 // others are not associated to this symbol instance
4476 if( pin->GetUnit() != ALL_UNITS && pin->GetUnit() != GetUnit() )
4477 continue;
4478
4479 if( pin->GetBodyStyle() != ALL_BODY_STYLES && pin->GetBodyStyle() != GetBodyStyle() )
4480 continue;
4481
4482 if( pin->GetLocalPosition() == new_pos )
4483 return true;
4484 }
4485
4486 return false;
4487}
4488
4489
4491{
4492 return m_doNetlist;
4493}
4494
4495
4496void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
4497 const VECTOR2I& aOffset, bool aDimmed )
4498{
4499 if( aBackground )
4500 return;
4501
4502 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4503 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
4504
4505 if( effectiveSym )
4506 {
4507 bool usingAlternate = ( effectiveSym != m_part.get() );
4508
4509 std::vector<SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4510
4511 // Copy the source so we can re-orient and translate it.
4512 LIB_SYMBOL tempSymbol( *effectiveSym );
4513 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
4514 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
4515
4516 // Copy the pin info from the symbol to the temp pins.
4517 for( unsigned i = 0; i < tempPins.size(); ++i )
4518 {
4519 SCH_PIN* symbolPin = symbolPins[i];
4520 SCH_PIN* tempPin = tempPins[i];
4521
4522 if( !symbolPin )
4523 continue;
4524
4525 tempPin->SetName( symbolPin->GetShownName() );
4526 tempPin->SetType( symbolPin->GetType() );
4527 tempPin->SetShape( symbolPin->GetShape() );
4528
4529 if( symbolPin->IsDangling() )
4530 tempPin->SetFlags( IS_DANGLING );
4531 }
4532
4533 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
4534 {
4535 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
4536 {
4537 // Use SCH_FIELD's text resolver
4538 SCH_FIELD dummy( this, FIELD_T::USER );
4539 dummy.SetText( text->GetText() );
4540 text->SetText( dummy.GetShownText( FOR_CANVAS ) );
4541 }
4542 }
4543
4544 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4545 TRANSFORM savedTransform = renderSettings->m_Transform;
4546 renderSettings->m_Transform = GetTransform();
4547 aPlotter->StartBlock( nullptr );
4548
4549 wxString variant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
4550 bool dnp = GetDNP( sheet, variant );
4551
4552 for( bool local_background : { true, false } )
4553 {
4554 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
4555
4556 for( SCH_FIELD field : m_fields )
4557 {
4558 field.ClearRenderCache();
4559 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
4560
4562 && field.GetId() == FIELD_T::VALUE
4563 && ( field.IsVisible() || field.IsForceVisible() )
4564 && !local_background )
4565 {
4566 PlotLocalPowerIconShape( aPlotter );
4567 }
4568 }
4569 }
4570
4571 if( dnp && renderSettings->m_ShowDNPMarkers )
4572 PlotDNP( aPlotter );
4573
4574 // Plot attributes to a hypertext menu
4575 if( aPlotOpts.m_PDFPropertyPopups )
4576 {
4577 std::vector<wxString> properties;
4578
4579 for( const SCH_FIELD& field : GetFields() )
4580 {
4581 wxString text_field = field.GetShownText( sheet, FOR_GUI, variant );
4582
4583 if( text_field.IsEmpty() )
4584 continue;
4585
4586 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
4587 }
4588
4589 if( !effectiveSym->GetKeyWords().IsEmpty() )
4590 {
4591 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
4592 _( "Keywords" ),
4593 effectiveSym->GetShownKeyWords( FOR_GUI ) ) );
4594 }
4595
4596 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
4597 }
4598
4599 aPlotter->EndBlock( nullptr );
4600 renderSettings->m_Transform = savedTransform;
4601
4602 if( !effectiveSym->IsPower() )
4603 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
4604 }
4605}
4606
4607
4608void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
4609{
4610 BOX2I bbox = GetBodyBoundingBox();
4612 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
4613 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
4614 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
4615
4616 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
4617 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
4618 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
4619
4620 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4621 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
4622
4623 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
4624
4625 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
4626 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
4627}
4628
4629
4633static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
4634{
4635 double lineWidth = aSize / 10.0;
4636
4637 std::vector<SCH_SHAPE> shapeList;
4638 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
4639 int tolerance = 100; // approx error to approximate a Bezier curve by segments
4640
4641 for( const SCH_SHAPE& shape : shapeList )
4642 {
4643 // Currently there are only 2 shapes: BEZIER and CIRCLE
4644 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
4645
4646 if( shape.GetShape() == SHAPE_T::BEZIER )
4647 {
4648 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
4649 tolerance, lineWidth );
4650 }
4651 else if( shape.GetShape() == SHAPE_T::CIRCLE )
4652 {
4653 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
4654 }
4655 }
4656}
4657
4658
4660{
4661 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
4662
4663 // Plot the local power pin indicator icon shape
4664 BOX2I bbox = field->GetBoundingBox();
4665
4666 // Calculate the text orientation according to the parent orientation.
4667 EDA_ANGLE orient = field->GetTextAngle();
4668
4669 if( GetTransform().y1 )
4670 {
4671 // Rotate symbol 90 degrees.
4672 if( orient.IsHorizontal() )
4673 orient = ANGLE_VERTICAL;
4674 else
4675 orient = ANGLE_HORIZONTAL;
4676 }
4677
4678 bool rotated = !orient.IsHorizontal();
4679
4680 VECTOR2D pos;
4681 double size = bbox.GetHeight() / 1.5;
4682
4683 if( rotated )
4684 {
4685 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
4686 size = bbox.GetWidth() / 1.5;
4687 }
4688 else
4689 {
4690 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
4691 }
4692
4693 plotLocalPowerIcon( aPlotter, pos, size, rotated );
4694}
4695
4696
4697void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter, bool aDnp ) const
4698{
4699 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4700 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
4701
4702 if( effectiveSym )
4703 {
4704 bool usingAlternate = ( effectiveSym != m_part.get() );
4705
4706 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4707 TRANSFORM savedTransform = renderSettings->m_Transform;
4708 renderSettings->m_Transform = GetTransform();
4709
4710 std::vector<SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4711
4712 // Copy the source to stay const
4713 LIB_SYMBOL tempSymbol( *effectiveSym );
4714 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
4715 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
4716 SCH_PLOT_OPTS plotOpts;
4717
4718 // Copy the pin info from the symbol to the temp pins.
4719 for( unsigned i = 0; i < tempPins.size(); ++i )
4720 {
4721 SCH_PIN* symbolPin = symbolPins[i];
4722 SCH_PIN* tempPin = tempPins[i];
4723
4724 if( !symbolPin )
4725 continue;
4726
4727 tempPin->SetName( symbolPin->GetShownName() );
4728 tempPin->SetType( symbolPin->GetType() );
4729 tempPin->SetShape( symbolPin->GetShape() );
4730 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, aDnp );
4731 }
4732
4733 renderSettings->m_Transform = savedTransform;
4734 }
4735}
4736
4737
4739{
4740 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4741 {
4742 if( pin->IsBrightened() )
4743 return true;
4744 }
4745
4746 return false;
4747}
4748
4749
4751{
4752 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
4753 pin->ClearBrightened();
4754}
4755
4756
4757/*
4758 * When modified at the schematic level, we still store the values of these flags in the
4759 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
4760 * will be created and stored locally in the schematic.
4761 */
4763{
4764 return m_part && m_part->GetShowPinNames();
4765}
4766
4767
4769{
4770 if( m_part )
4771 m_part->SetShowPinNames( aShow );
4772}
4773
4774
4776{
4777 return m_part && m_part->GetShowPinNumbers();
4778}
4779
4780
4782{
4783 if( m_part )
4784 m_part->SetShowPinNumbers( aShow );
4785}
4786
4787
4789{
4790 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4791 {
4792 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4793 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4794
4795 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4796 continue;
4797
4798 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4799 continue;
4800
4801 if( pin->IsPointClickableAnchor( aPos ) )
4802 return true;
4803 }
4804
4805 return false;
4806}
4807
4808
4810{
4811 // return true if the symbol is equivalent to a global label:
4812 // It is a Power symbol
4813 // It has only one pin type Power input
4814
4816 return false;
4817
4818 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4819
4820 if( pin_list.size() != 1 )
4821 return false;
4822
4823 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4824}
4825
4826
4828{
4829 // return true if the symbol is equivalent to a local label:
4830 // It is a Power symbol
4831 // It has only one pin type Power input
4832
4834 return false;
4835
4836 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4837
4838 if( pin_list.size() != 1 )
4839 return false;
4840
4841 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4842}
4843
4844
4846{
4847 if( !m_part )
4848 return false;
4849
4850 return m_part->IsLocalPower();
4851}
4852
4853
4855{
4856 if( !m_part )
4857 return false;
4858
4859 return m_part->IsGlobalPower();
4860}
4861
4862
4864{
4865 if( !m_part || !m_part->IsPower() )
4866 return;
4867
4868 if( aLocal )
4869 m_part->SetLocalPower();
4870 else
4871 m_part->SetGlobalPower();
4872}
4873
4874
4876{
4877 return IsLocalPower() || IsGlobalPower();
4878}
4879
4880
4882{
4883 wxCHECK( m_part, false );
4884
4885 return m_part->IsNormal();
4886}
4887
4888
4889std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath,
4890 const wxString& aVariantName ) const
4891{
4892 std::unordered_set<wxString> componentClass;
4893
4894 auto getComponentClassFields =
4895 [&]( const std::vector<SCH_FIELD>& fields )
4896 {
4897 for( const SCH_FIELD& field : fields )
4898 {
4899 if( field.GetUntranslatedName() == wxT( "Component Class" ) )
4900 {
4901 if( field.GetShownText( aPath, INTERNAL ) != wxEmptyString )
4902 componentClass.insert( field.GetShownText( aPath, INTERNAL, aVariantName ) );
4903 }
4904 }
4905 };
4906
4907 // First get component classes set on the symbol itself
4908 getComponentClassFields( m_fields );
4909
4910 // Now get component classes set on any enclosing rule areas
4911 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
4912 {
4913 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
4914 {
4915 getComponentClassFields( label->GetFields() );
4916 }
4917 }
4918
4919 return componentClass;
4920}
4921
4922
4923std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
4924 const wxString& aVariantName ) const
4925{
4926 SCH_SYMBOL_INSTANCE instance;
4927
4928 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
4929 return std::nullopt;
4930
4931 return instance.m_Variants.find( aVariantName )->second;
4932}
4933
4934
4935void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
4936{
4937 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
4938
4939 // The instance path must already exist.
4940 if( !instance )
4941 return;
4942
4943 if( instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) ).second )
4945}
4946
4947
4948LIB_SYMBOL* SCH_SYMBOL::GetVariantLibSymbol( const wxString& aVariantName,
4949 const SCH_SHEET_PATH& aPath ) const
4950{
4951 if( aVariantName.IsEmpty() )
4952 return nullptr;
4953
4954 const SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4955
4956 if( !instance || !instance->m_Variants.contains( aVariantName ) )
4957 return nullptr;
4958
4959 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
4960
4961 if( !variant.m_SymbolOverride )
4962 return nullptr;
4963
4964 const LIB_ID& libId = *variant.m_SymbolOverride;
4965 wxString libIdStr = libId.Format();
4966
4967 // Cache by LIB_ID string so hierarchical instances sharing the same alternate symbol
4968 // reuse a single flattened copy regardless of sheet path or variant name. Failed
4969 // resolutions are cached as nullptr to keep unresolvable overrides from hitting the
4970 // library adapter on every paint.
4971 auto cacheIt = m_variantSymbolCache.find( libIdStr );
4972
4973 if( cacheIt != m_variantSymbolCache.end() )
4974 return cacheIt->second.get();
4975
4976 if( libId == m_lib_id )
4977 {
4978 m_variantSymbolCache[libIdStr] = nullptr;
4979 return nullptr;
4980 }
4981
4982 std::unique_ptr<LIB_SYMBOL> resolved;
4983
4984 // The schematic's copy wins so library edits only apply through an explicit update
4985 if( GetParent() && GetParent()->Type() == SCH_SCREEN_T )
4986 {
4987 const auto& libSymbols = static_cast<const SCH_SCREEN*>( GetParent() )->GetLibSymbols();
4988
4989 if( auto it = libSymbols.find( libIdStr ); it != libSymbols.end() && it->second )
4990 resolved = it->second->Flatten();
4991 }
4992
4993 if( !resolved )
4994 {
4995 if( !Schematic() )
4996 return nullptr;
4997
4998 resolved = LoadAlternateFromLibrary( libId );
4999 }
5000
5001 if( !resolved )
5002 {
5003 m_variantSymbolCache[libIdStr] = nullptr;
5004 return nullptr;
5005 }
5006
5007 std::unique_ptr<LIB_SYMBOL>& cached = m_variantSymbolCache[libIdStr];
5008
5009 cached = std::move( resolved );
5010
5011 if( m_part && !ValidateVariantSymbolCompatibility( *m_part, *cached ).empty() )
5012 {
5013 cached.reset();
5014 return nullptr;
5015 }
5016
5017 return cached.get();
5018}
5019
5020
5021std::vector<LIB_ID> SCH_SYMBOL::GetVariantSymbolOverrides() const
5022{
5023 std::vector<LIB_ID> overrides;
5024
5025 for( const SCH_SYMBOL_INSTANCE& instance : GetInstances() )
5026 {
5027 for( const auto& [name, variant] : instance.m_Variants )
5028 {
5029 if( variant.m_SymbolOverride
5030 && std::find( overrides.begin(), overrides.end(), *variant.m_SymbolOverride ) == overrides.end() )
5031 {
5032 overrides.push_back( *variant.m_SymbolOverride );
5033 }
5034 }
5035 }
5036
5037 return overrides;
5038}
5039
5040
5041std::unique_ptr<LIB_SYMBOL> SCH_SYMBOL::LoadAlternateFromLibrary( const LIB_ID& aLibId ) const
5042{
5044
5045 if( !schematic )
5046 return nullptr;
5047
5049
5050 if( !adapter )
5051 return nullptr;
5052
5053 try
5054 {
5055 const wxString nickname = aLibId.GetLibNickname().wx_str();
5056
5057 if( adapter->GetRow( nickname ) && !adapter->HasLibrary( nickname ) )
5058 adapter->LoadOne( nickname );
5059
5060 if( LIB_SYMBOL* libSymbol = adapter->LoadSymbol( aLibId ) )
5061 return libSymbol->Flatten();
5062 }
5063 catch( const IO_ERROR& )
5064 {
5065 }
5066
5067 return nullptr;
5068}
5069
5070
5072{
5073 if( aPath && Schematic() )
5074 {
5075 const wxString& variantName = Schematic()->GetCurrentVariant();
5076
5077 if( !variantName.IsEmpty() )
5078 {
5079 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( variantName, *aPath );
5080
5081 if( altSymbol )
5082 return altSymbol;
5083 }
5084 }
5085
5086 return m_part.get();
5087}
5088
5089
5090std::vector<SCH_PIN*> SCH_SYMBOL::MapLibPins( const std::vector<SCH_PIN*>& aLibPins, bool aByNumber ) const
5091{
5092 std::vector<SCH_PIN*> mapped;
5093
5094 mapped.reserve( aLibPins.size() );
5095
5096 if( aByNumber )
5097 {
5098 const LIB_SYMBOL* baseSymbol = m_part.get();
5099
5100 if( !baseSymbol )
5101 {
5102 mapped.resize( aLibPins.size(), nullptr );
5103 return mapped;
5104 }
5105
5106 std::vector<SCH_PIN*> basePins = baseSymbol->GetGraphicalPins( GetUnit(), GetBodyStyle() );
5107 std::vector<bool> matched( basePins.size(), false );
5108
5109 for( const SCH_PIN* alternatePin : aLibPins )
5110 {
5111 SCH_PIN* instancePin = nullptr;
5112
5113 for( size_t i = 0; i < basePins.size(); ++i )
5114 {
5115 if( matched[i] || !VariantSymbolPinsMatch( *basePins[i], *alternatePin ) )
5116 continue;
5117
5118 matched[i] = true;
5119 instancePin = GetPin( const_cast<SCH_PIN*>( basePins[i] ) );
5120 break;
5121 }
5122
5123 mapped.push_back( instancePin );
5124 }
5125 }
5126 else
5127 {
5128 for( const SCH_PIN* libPin : aLibPins )
5129 mapped.push_back( GetPin( const_cast<SCH_PIN*>( libPin ) ) );
5130 }
5131
5132 return mapped;
5133}
5134
5135
5136void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
5137{
5138 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5139
5140 // The instance path must already exist.
5141 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5142 return;
5143
5144 instance->m_Variants.erase( aVariantName );
5145
5147}
5148
5149
5150void SCH_SYMBOL::ClearVariantField( const KIID_PATH& aPath, const wxString& aVariantName,
5151 const wxString& aFieldName )
5152{
5153 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5154
5155 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5156 return;
5157
5158 if( instance->m_Variants[aVariantName].m_Fields.erase( aFieldName ) )
5160}
5161
5162
5163void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
5164 const wxString& aNewName )
5165{
5166 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5167
5168 // The instance path must already exist and contain the old variant.
5169 if( aOldName == aNewName || !instance || !instance->m_Variants.contains( aOldName ) )
5170 return;
5171
5172 // Get the variant data, update the name, and re-insert with new key
5173 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
5174 variant.m_Name = aNewName;
5175 instance->m_Variants.erase( aOldName );
5176 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
5177
5179}
5180
5181
5182void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
5183 const wxString& aNewVariant )
5184{
5185 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5186
5187 // The instance path must already exist and contain the source variant.
5188 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
5189 return;
5190
5191 // Copy the variant data with a new name
5192 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
5193 variant.m_Name = aNewVariant;
5194
5195 if( instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) ).second )
5197}
5198
5199
5201 const wxString& aVariantName,
5202 const LIB_ID& aLibId )
5203{
5204 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5205
5206 if( !instance )
5207 return;
5208
5209 if( !instance->m_Variants.contains( aVariantName ) )
5210 {
5211 SCH_SYMBOL_VARIANT newVariant( aVariantName );
5212 newVariant.InitializeAttributes( *this );
5213 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
5214 }
5215
5216 const bool changed = std::exchange( instance->m_Variants[aVariantName].m_SymbolOverride, aLibId ) != aLibId;
5217 m_variantSymbolCache.clear();
5218
5219 if( changed )
5221}
5222
5223
5225 const wxString& aVariantName )
5226{
5227 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5228
5229 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5230 return false;
5231
5232 SCH_SYMBOL_VARIANT& variant = instance->m_Variants[aVariantName];
5233
5234 if( !variant.m_SymbolOverride )
5235 return false;
5236
5237 variant.m_SymbolOverride.reset();
5238 m_variantSymbolCache.clear();
5239
5241
5242 return true;
5243}
5244
5245
5246bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
5247{
5248 if( Type() != aOther.Type() )
5249 return false;
5250
5251 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
5252
5253 if( GetLibId() != symbol.GetLibId() )
5254 return false;
5255
5256 if( GetPosition() != symbol.GetPosition() )
5257 return false;
5258
5259 if( GetUnit() != symbol.GetUnit() )
5260 return false;
5261
5262 if( GetBodyStyle() != symbol.GetBodyStyle() )
5263 return false;
5264
5265 if( GetTransform() != symbol.GetTransform() )
5266 return false;
5267
5268 if( GetFields() != symbol.GetFields() )
5269 return false;
5270
5271 if( m_pins.size() != symbol.m_pins.size() )
5272 return false;
5273
5274 if( m_excludedFromSim != symbol.m_excludedFromSim )
5275 return false;
5276
5277 if( m_excludedFromBOM != symbol.m_excludedFromBOM )
5278 return false;
5279
5280 if( m_DNP != symbol.m_DNP )
5281 return false;
5282
5284 return false;
5285
5287 return false;
5288
5290 return false;
5291
5292 for( unsigned i = 0; i < m_pins.size(); ++i )
5293 {
5294 if( *m_pins[i] != *symbol.m_pins[i] )
5295 return false;
5296 }
5297
5298#if 0
5299 // This has historically been a compare of the current instance, rather than a compare
5300 // of all instances. Probably better to keep it that way for now.
5301 if( m_instanceReferences != symbol.m_instanceReferences )
5302 return false;
5303#endif
5304
5305 return true;
5306}
5307
5308
5309double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
5310{
5311 if( Type() != aOther.Type() )
5312 return 0.0;
5313
5314 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
5315
5316 if( GetLibId() != symbol.GetLibId() )
5317 return 0.0;
5318
5319 if( GetPosition() == symbol.GetPosition() )
5320 return 1.0;
5321
5322 return 0.0;
5323}
5324
5325
5326void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
5327 double aLineWidth, bool aHorizontal )
5328{
5329 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
5330
5331 double x_right = aSize / 1.6180339887;
5332 double x_middle = x_right / 2.0;
5333
5334 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
5335 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
5336 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
5337
5338 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
5339 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
5340 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
5341 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
5342 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
5343
5344 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5345 aShapeList.back().SetStart( bottomPt );
5346 aShapeList.back().SetBezierC1( bottomAnchorPt );
5347 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
5348 aShapeList.back().SetEnd( leftPt );
5349
5350
5351 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5352 aShapeList.back().SetStart( leftPt );
5353 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
5354 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
5355 aShapeList.back().SetEnd( rightPt );
5356
5357 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5358 aShapeList.back().SetStart( rightPt );
5359 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
5360 aShapeList.back().SetBezierC2( bottomAnchorPt );
5361 aShapeList.back().SetEnd( bottomPt );
5362
5363 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
5364 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
5365 aShapeList.back().SetRadius( aSize / 15.0 );
5366
5367 for( SCH_SHAPE& shape : aShapeList )
5368 {
5369 if( aHorizontal )
5370 shape.Rotate( VECTOR2I( 0, 0 ), true );
5371
5372 shape.Move( aPos );
5373 }
5374}
5375
5376
5378{
5379 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
5380 return &m_instances[it->second];
5381
5382 return nullptr;
5383}
5384
5385
5387{
5388 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
5389 return &m_instances[it->second];
5390
5391 return nullptr;
5392}
5393
5394
5395static struct SCH_SYMBOL_DESC
5396{
5398 {
5400 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
5401 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
5402 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
5403 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
5404
5410
5411 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position X" ),
5414 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position Y" ),
5417
5420 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror X" ),
5422 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror Y" ),
5424
5425 auto hasLibPart =
5426 []( INSPECTABLE* aItem ) -> bool
5427 {
5428 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5429 return symbol->GetLibSymbolRef() != nullptr;
5430
5431 return false;
5432 };
5433
5434 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ),
5436 .SetAvailableFunc( hasLibPart );
5437
5438 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ),
5440 .SetAvailableFunc( hasLibPart );
5441
5442 const wxString groupFields = _HKI( "Fields" );
5443
5444 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Reference" ),
5446 groupFields );
5447 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Value" ),
5449 groupFields );
5450 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
5452 groupFields );
5453 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
5455 groupFields );
5456 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ),
5458 groupFields );
5459
5460 auto multiUnit =
5461 [=]( INSPECTABLE* aItem ) -> bool
5462 {
5463 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5464 return symbol->IsMultiUnit();
5465
5466 return false;
5467 };
5468
5469 auto multiBodyStyle =
5470 [=]( INSPECTABLE* aItem ) -> bool
5471 {
5472 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5473 return symbol->IsMultiBodyStyle();
5474
5475 return false;
5476 };
5477
5478 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Unit" ),
5480 .SetAvailableFunc( multiUnit )
5482 []( INSPECTABLE* aItem )
5483 {
5484 wxPGChoices choices;
5485
5486 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5487 {
5488 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
5489 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
5490 }
5491
5492 return choices;
5493 } );
5494
5495 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Body Style" ),
5497 .SetAvailableFunc( multiBodyStyle )
5499 []( INSPECTABLE* aItem )
5500 {
5501 wxPGChoices choices;
5502
5503 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5504 {
5505 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
5506 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
5507 }
5508
5509 return choices;
5510 } );
5511
5515 []( INSPECTABLE* aItem ) -> bool
5516 {
5517 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5518 return symbol->IsPower();
5519
5520 return false;
5521 } );
5522
5523 const wxString groupAttributes = _HKI( "Attributes" );
5524
5525 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
5527 groupAttributes );
5528 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
5530 groupAttributes );
5531 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
5533 groupAttributes );
5534 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
5536 groupAttributes );
5537 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
5539 groupAttributes );
5540 }
5542
5543
const char * name
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
BITMAPS
A list of all bitmap identifiers.
@ add_component
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr const Vec GetEnd() const
Definition box2.h:209
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr coord_type GetY() const
Definition box2.h:205
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr coord_type GetX() const
Definition box2.h:204
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:697
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr const Vec & GetOrigin() const
Definition box2.h:207
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:256
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
constexpr coord_type GetBottom() const
Definition box2.h:219
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:102
static std::vector< DANGLING_END_ITEM >::iterator get_lower_pos(std::vector< DANGLING_END_ITEM > &aItemListByPos, const VECTOR2I &aPos)
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition sch_item.h:101
DANGLING_END_T GetType() const
Definition sch_item.h:137
const EDA_ITEM * GetParent() const
Definition sch_item.h:136
bool IsHorizontal() const
Definition eda_angle.h:141
The base class for create windows for drawing purpose.
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:170
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
std::vector< PROPERTY_BASE * > GetCustomPropertiesAsInspectables() const
Definition eda_item.cpp:200
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:608
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:484
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:115
bool IsSelected() const
Definition eda_item.h:134
EDA_ITEM * GetParent() const
Definition eda_item.h:112
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:609
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:556
virtual void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:575
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:178
static ENUM_MAP< T > & Instance()
Definition property.h:792
A text control validator used for validating the text allowed in fields.
Definition validators.h:137
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
wxAny Get(PROPERTY_BASE *aProperty) const
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
A typed sum value used to carry the before/after of any single property.
wxString ToDisplayString() const
Human-readable representation with no unit context.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxString AsString() const
Definition kiid.cpp:423
Definition kiid.h:46
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
UTF8 Format() const
Definition lib_id.cpp:132
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
wxString GetKeyWords() const override
Definition lib_symbol.h:220
bool IsPower() const override
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:240
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
SCH_ITEM * LocateDrawItem(int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I &aPoint)
Locate a draw object.
static wxString LetterSubReference(int aUnit, wxChar aInitialLetter)
static LIB_SYMBOL * GetDummy()
Return a dummy LIB_SYMBOL, used when one is missing in the schematic.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:843
const BOX2I GetBodyBoundingBox(int aUnit, int aBodyStyle, bool aIncludePins, bool aIncludePrivateItems) const
Get the symbol bounding box excluding fields.
wxString GetShownKeyWords(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
bool Deserialize(const kiapi::schematic::types::SchematicSymbol &aInput)
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
A singleton reporter that reports to nowhere.
Definition reporter.h:267
A named pin map.
Definition pin_map.h:65
Base plotter engine class.
Definition plotter.h:138
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width)=0
virtual void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString)
Create a bookmark to a symbol.
Definition plotter.h:548
virtual void BezierCurve(const VECTOR2I &aStart, const VECTOR2I &aControl1, const VECTOR2I &aControl2, const VECTOR2I &aEnd, int aTolerance, int aLineThickness)
Generic fallback: Cubic Bezier curve rendered as a polyline.
Definition plotter.cpp:230
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition plotter.h:621
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:442
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:536
virtual void SetColor(const COLOR4D &color)=0
virtual void EndBlock(void *aData)
calling this function allows one to define the end of a group of drawing items for instance in SVG or...
Definition plotter.h:630
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:289
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:275
PROPERTY_BASE(const wxString &aName, PROPERTY_DISPLAY aDisplay=PT_DEFAULT, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType=ORIGIN_TRANSFORMS::NOT_A_COORD)
Used to generate unique IDs. Must come up front so it's initialized before ctor.
Definition property.h:201
PROPERTY_BASE & SetGroup(const wxString &aGroup)
Definition property.h:378
friend class INSPECTABLE
Definition property.h:501
const wxString & Name() const
Definition property.h:221
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
bool IsAvailableFor(TYPE_ID aItemClass, PROPERTY_BASE *aProp, INSPECTABLE *aItem)
Checks overriden availability and original availability of a property, returns false if the property ...
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Holds all the data relating to one schematic.
Definition schematic.h:149
wxString GetCurrentVariant() const
Return the current variant being edited.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:312
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
bool IsMandatory() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:139
FIELD_T GetId() const
Definition sch_field.h:143
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
wxString GetUntranslatedName() const
Get the untranslated field name for storage, variable look-up, etc.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
wxString GetShownText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString, int aDepth=0) const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetText(const wxString &aText) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
void SetLocked(bool aLocked) override
Definition sch_item.h:262
int m_unit
Definition sch_item.h:844
SCH_SCREEN * GetParentScreen() const
Definition sch_item.cpp:308
int m_bodyStyle
Definition sch_item.h:845
void invalidateConnectivity(KICAD_T aChangedType=TYPE_NOT_INIT)
Bump the parent screen's connectivity revision when this item, or the item owning it as a child,...
Definition sch_item.cpp:323
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.cpp:46
void SetPrivate(bool aPrivate)
Definition sch_item.h:258
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:302
int GetBodyStyle() const
Definition sch_item.h:253
bool IsLocked() const override
Definition sch_item.cpp:179
friend class LIB_SYMBOL
Definition sch_item.h:822
int GetUnit() const
Definition sch_item.h:243
virtual void ClearCaches()
Definition sch_item.cpp:891
void SetConnectivityDirty(bool aDirty=true)
Set the dirty flag.
Definition sch_item.cpp:314
void SetFieldsAutoplaced(AUTOPLACE_ALGO aAlgo)
Definition sch_item.h:679
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:847
std::unordered_set< SCH_RULE_AREA * > m_rule_areas_cache
Store pointers to rule areas which this item is contained within.
Definition sch_item.h:860
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:65
AUTOPLACE_ALGO GetFieldsAutoplaced() const
Return whether the fields have been automatically placed.
Definition sch_item.h:678
SCH_LAYER_ID m_layer
Definition sch_item.h:843
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:233
void SetName(const wxString &aName)
Definition sch_pin.cpp:545
const wxString & GetName() const
Definition sch_pin.cpp:527
bool IsDangling() const override
Definition sch_pin.cpp:588
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
Definition sch_pin.cpp:1604
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:116
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:378
const wxString & GetShownName() const
Definition sch_pin.cpp:697
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:455
const wxString & GetNumber() const
Definition sch_pin.h:144
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:400
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:435
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
bool GetExcludedFromSim() const
bool GetExcludedFromBoard() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
size_t size() const
Forwarded method from std::vector.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
size_t BaseHash() const override
Return type-id of the Base class.
size_t OwnerHash() const override
Return type-id of the Owner class.
size_t TypeHash() const override
Return type-id of the property type.
SCH_SYMBOL_FIELD_PROPERTY(const wxString &aName)
void setter(void *obj, wxAny &v) override
wxAny ValueForInstance(const SCH_SYMBOL *symbol, const SCH_SHEET_PATH *sheetPath, const wxString &variantName) const override
wxAny getter(const void *aObject) const final
PROPERTY_BASE(const wxString &aName, PROPERTY_DISPLAY aDisplay=PT_DEFAULT, ORIGIN_TRANSFORMS::COORD_TYPES_T aCoordType=ORIGIN_TRANSFORMS::NOT_A_COORD)
Used to generate unique IDs. Must come up front so it's initialized before ctor.
Definition property.h:201
virtual wxAny ValueForInstance(const SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH *aPath, const wxString &aVariant) const =0
size_t TypeHash() const override
Return type-id of the property type.
size_t BaseHash() const override
Return type-id of the Base class.
SCH_SYMBOL_PIN_MAP_ENTRY_PROPERTY(const wxString &aName, const wxString &aPinNumber)
bool Writeable(INSPECTABLE *aObject) const override
wxAny ValueForInstance(const SCH_SYMBOL *symbol, const SCH_SHEET_PATH *sheetPath, const wxString &variantName) const override
wxString m_pinNumber
size_t OwnerHash() const override
Return type-id of the Owner class.
void setter(void *obj, wxAny &v) override
wxAny ValueForInstance(const SCH_SYMBOL *symbol, const SCH_SHEET_PATH *sheetPath, const wxString &variantName) const override
size_t OwnerHash() const override
Return type-id of the Owner class.
void setter(void *obj, wxAny &v) override
size_t TypeHash() const override
Return type-id of the property type.
size_t BaseHash() const override
Return type-id of the Base class.
bool Writeable(INSPECTABLE *aObject) const override
wxAny ValueForInstance(const SCH_SYMBOL *symbol, const SCH_SHEET_PATH *sheetPath, const wxString &variantName) const override
void setter(void *obj, wxAny &v) override
size_t TypeHash() const override
Return type-id of the property type.
size_t OwnerHash() const override
Return type-id of the Owner class.
static wxPGChoices BuildChoices()
size_t BaseHash() const override
Return type-id of the Base class.
size_t TypeHash() const override
Return type-id of the property type.
static wxPGChoices BuildChoices(const SCH_SYMBOL *aSymbol)
static std::vector< wxString > MapNames(const SCH_SYMBOL *aSymbol)
size_t OwnerHash() const override
Return type-id of the Owner class.
void setter(void *obj, wxAny &v) override
wxAny ValueForInstance(const SCH_SYMBOL *symbol, const SCH_SHEET_PATH *sheetPath, const wxString &variantName) const override
size_t BaseHash() const override
Return type-id of the Base class.
Variant information for a schematic symbol.
PIN_MAP_INSTANCE_OVERRIDE m_PinMapOverride
Per-instance pin-to-pad map override for this variant (issue #2282).
std::optional< LIB_ID > m_SymbolOverride
Alternate library symbol to substitute for the base symbol in this variant, if any.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:75
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the display name for a given unit aUnit.
SCH_SYMBOL & operator=(const SCH_SYMBOL &aItem)
int GetUnitProp() const
size_t GetFullPinCount() const
std::vector< SCH_SYMBOL_INSTANCE > m_instances
Define the hierarchical path and reference of the symbol.
void UpdatePrefix()
Set the prefix based on the current reference designator.
wxString m_prefix
C, R, U, Q etc - the first character(s) which typically indicate what the symbol is.
wxString GetDescription() const override
std::unordered_map< SCH_PIN *, SCH_PIN * > m_pinMap
Library pin pointer : SCH_PIN indices.
void SetMirrorX(bool aMirror)
Definition sch_symbol.h:324
bool IsSymbolLikePowerGlobalLabel() const
VECTOR2I m_pos
PASSTHROUGH_MODE GetPassthroughMode() const
Definition sch_symbol.h:868
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SYMBOLs don't currently support embedded files, but their LIB_SYMBOL counterparts do.
wxString GetSymbolIDAsString() const
Definition sch_symbol.h:167
std::map< wxString, std::unique_ptr< PROPERTY_BASE > > m_pinMapPropsStorageCache
Same for effective pin-map entries.
LIB_ID m_lib_id
Name and library the symbol was loaded from, i.e. 74xx:74LS00.
void ClearPinMapOverrides()
Clear the base pin-to-pad map override and every variant's override.
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
bool GetShowPinNumbers() const override
wxString GetDatasheet() const
Return the documentation text for the given part alias.
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void SetLibId(const LIB_ID &aName)
bool HasBrightenedPins()
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the symbol's fields.
Definition sch_symbol.h:463
BOX2I GetBodyAndPinsBoundingBox() const override
Return a bounding box for the symbol body and pins but not the fields.
wxString GetBodyStyleProp() const override
Definition sch_symbol.h:547
void SetRefProp(const wxString &aRef)
void SetFieldText(SCH_FIELD *aField, const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath, const wxString &aVariantName)
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
virtual void SetDNP(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
SCH_ITEM * GetDrawItem(const VECTOR2I &aPosition, KICAD_T aType=TYPE_NOT_INIT)
Return the symbol library item at aPosition that is part of this symbol.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:909
void PlotDNP(PLOTTER *aPlotter) const
Plot the red 'X' over the symbol.
bool operator!=(const SCH_SYMBOL &aSymbol) const
void SetShowPinNumbers(bool aShow) override
Set or clear the pin number visibility flag.
wxString m_signalName
bool ClearVariantSymbolOverride(const SCH_SHEET_PATH &aPath, const wxString &aVariantName)
Remove the alternate-symbol override for a given variant and sheet instance.
SYMBOL_ORIENTATION_PROP GetOrientationProp() const
Definition sch_symbol.h:307
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_variantSymbolCache
int GetY() const
Definition sch_symbol.h:914
SCH_SYMBOL_INSTANCE * getInstance(const KIID_PATH &aPath)
wxString SubReference(int aUnit, bool aAddSeparator=true) const
bool m_doNetlist
True if the symbol should appear in netlist.
wxString GetClass() const override
Return the class name.
Definition sch_symbol.h:115
void setVariantAttribute(bool aEnable, const SCH_SHEET_PATH *aInstance, const wxString &aVariantName, bool SCH_SYMBOL::*aBase, bool SCH_SYMBOL_VARIANT::*aOverride)
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
bool IsAnnotated(const SCH_SHEET_PATH *aSheet) const
Check if the symbol has a valid annotation (reference) for the given sheet path.
void SetMirrorY(bool aMirror)
Definition sch_symbol.h:341
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:552
void SetVariantSymbolOverride(const SCH_SHEET_PATH &aPath, const wxString &aVariantName, const LIB_ID &aLibId)
Set the alternate-symbol override for a given variant and sheet instance.
bool UseLibIdLookup() const
Definition sch_symbol.h:182
int GetX() const
Definition sch_symbol.h:911
bool GetExcludedFromPosFilesProp() const
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
std::vector< LIB_ID > GetVariantSymbolOverrides() const
void SetExcludedFromSim(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
void SetExcludedFromSimProp(bool aEnable)
void SetBodyStyle(int aBodyStyle) override
void SetShowPinNames(bool aShow) override
Set or clear the pin name visibility flag.
wxString GetKeyWords() const override
bool SetInstanceProjectName(const KIID_PATH &aSheetPath, const wxString &aProjectName)
Set the owning project of the instance stored for aSheetPath.
wxString GetSchSymbolLibraryName() const
void ClearCaches() override
const wxString GetFootprintFieldText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const
PASSTHROUGH_MODE m_passthroughMode
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
PIN_MAP_INSTANCE_OVERRIDE GetPinMapOverride(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
bool GetExcludedFromBoardProp() const
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:915
std::vector< SCH_PIN * > MapLibPins(const std::vector< SCH_PIN * > &aLibPins, bool aByNumber) const
Map pins of an effective library symbol to this symbol's instance pins.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool HasConnectivityChanges(const SCH_ITEM *aItem, const SCH_SHEET_PATH *aInstance=nullptr) const override
Check if aItem has connectivity changes against this object.
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool GetExcludedFromSimProp() const
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool DoNetList() const
bool IsGlobalPower() const override
bool GetMirrorX() const
Definition sch_symbol.h:336
wxString GetRefProp() const
void SetPinMapOverride(const PIN_MAP_INSTANCE_OVERRIDE &aOverride, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
Set the per-instance pin-to-pad map override (issue #2282).
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instances), if this entry does not already exist.
wxString GetShownKeyWords(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const override
Compare the item against the search criteria in aSearchData.
void SetLocalPowerProp(bool aLocal)
void SetExcludedFromBOMProp(bool aEnable)
void ClearVariantField(const KIID_PATH &aPath, const wxString &aVariantName, const wxString &aFieldName)
static std::unordered_map< TRANSFORM, int > s_transformToOrientationCache
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
Search for a SCH_FIELD with aFieldName.
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
bool IsPointClickableAnchor(const VECTOR2I &aPos) const override
void UpdateFields(const SCH_SHEET_PATH *aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields)
Restore fields to the original library values.
wxString m_schLibSymbolName
The name used to look up a symbol in the symbol library embedded in a schematic.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
SCH_PIN * GetPinByEffectivePadNumber(const wxString &aPadNumber, const SCH_SHEET_PATH *aSheet, const wxString &aVariantName=wxEmptyString) const
Find the pin whose effective footprint pad number (issue #2282) is aPadNumber on aSheet,...
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void SetOrientationProp(SYMBOL_ORIENTATION_PROP aAngle)
Orientation/mirroring access for property manager.
Definition sch_symbol.h:298
bool GetShowPinNames() const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
bool HasDeMorganBodyStyles() const override
std::vector< SCH_FIELD > m_fields
Variable length list of fields.
std::vector< SCH_PIN * > GetAllLibPins() const
int GetBodyStyleCount() const override
Return the number of body styles of the symbol.
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
std::unique_ptr< LIB_SYMBOL > LoadAlternateFromLibrary(const LIB_ID &aLibId) const
Load a flattened copy of an alternate symbol from the project's symbol libraries.
bool GetDNPProp() const
void PlotPins(PLOTTER *aPlotter, bool aDnp) const
Plot just the symbol pins.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void SetFootprintFieldText(const wxString &aFootprint)
bool doIsConnected(const VECTOR2I &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
wxString GetShownDescription(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
std::unordered_map< KIID_PATH, size_t > m_instancePathIndex
Index from an instance's sheet path to its position in m_instances for O(1) lookups.
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:908
PIN_MAP_INSTANCE_OVERRIDE resolveDelegatedPinMapOverride(const SCH_SHEET_PATH &aSheet, const wxString &aVariantName) const
Return unit 1's pin-map override for a unit that delegates to it (issue #2282).
std::unique_ptr< LIB_SYMBOL > m_part
A flattened copy of the LIB_SYMBOL from the PROJECT object's libraries.
int GetNextFieldOrdinal() const
Return the next ordinal for a user field for this symbol.
void SetExcludedFromPosFiles(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void rebuildInstancePathIndex()
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
std::unordered_set< wxString > GetComponentClassNames(const SCH_SHEET_PATH *aPath, const wxString &aVariantName) const
Return the component classes this symbol belongs in.
void SyncOtherUnits(const SCH_SHEET_PATH &aSourceSheet, SCH_COMMIT &aCommit, PROPERTY_BASE *aProperty, const wxString &aVariantName=wxEmptyString)
Keep fields other than the reference, include/exclude flags, and alternate pin assignments in sync in...
void Init(const VECTOR2I &pos=VECTOR2I(0, 0))
void SetExcludedFromPosFilesProp(bool aEnable)
void updatePins()
const LIB_SYMBOL * GetEffectiveLibSymbol(const SCH_SHEET_PATH *aPath=nullptr) const
Return the library symbol to use for rendering and bounding box calculations.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
bool operator<(const SCH_ITEM &aItem) const override
static void BuildLocalPowerIconShape(std::vector< SCH_SHAPE > &aShapeList, const VECTOR2D &aPos, double aSize, double aLineWidth, bool aHorizontal)
Build the local power pin indicator icon shape, at coordinate aPos.
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
LIB_SYMBOL * GetVariantLibSymbol(const wxString &aVariantName, const SCH_SHEET_PATH &aPath) const
Resolve the alternate library symbol for a given variant.
void SetValueProp(const wxString &aValue)
void SetUnitProp(int aUnit)
void SetSchSymbolLibraryName(const wxString &aName)
The name of the symbol in the schematic library symbol list.
Definition sch_symbol.h:180
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
std::vector< SCH_PIN * > GetLibPins() const
Populate a vector with all the pins from the library object that match the current unit and bodyStyle...
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, const SCH_SHEET_PATH *aPath=nullptr) override
Test if the symbol's dangling state has changed for all pins.
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit, int aBodyStyle) const override
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
void AddVariant(const SCH_SHEET_PATH &aInstance, const SCH_SYMBOL_VARIANT &aVariant)
BOX2I doGetBoundingBox(bool aIncludePins, bool aIncludeFields) const
bool GetMirrorY() const
Definition sch_symbol.h:353
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetDNPProp(bool aEnable)
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber) const
Find all symbol pins with the given number.
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
std::vector< PROPERTY_BASE * > GetDynamicProperties() const override
Return dynamically-computed properties specific to this object instance (e.g.
void SetPassthroughMode(PASSTHROUGH_MODE aMode)
Definition sch_symbol.h:869
void SetX(int aX)
Definition sch_symbol.h:912
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
const wxString GetValue(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString) const override
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
PIN_MAP_INSTANCE_OVERRIDE m_pinMapOverride
Base (no-variant) pin-to-pad map override applied when no variant override exists for the sheet path ...
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
wxString GetValueProp() const
bool IsLocalPower() const override
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
int GetUnitCount() const override
Return the number of units per package of the symbol.
void SetPrefix(const wxString &aPrefix)
Definition sch_symbol.h:241
int GetOrientation() const override
Get the display symbol orientation.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
bool IsSymbolLikePowerLocalLabel() const
bool GetExcludedFromBOMProp() const
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
void SetExcludedFromBoardProp(bool aEnable)
void SetExcludedFromBOM(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
void PlotLocalPowerIconShape(PLOTTER *aPlotter) const
Plot the local power pin indicator icon shape.
bool IsNormal() const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
std::vector< std::unique_ptr< SCH_PIN > > m_pins
A copy of SCH_PIN objects from the library symbol.
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
wxString GetFieldText(const SCH_FIELD *aField, const wxString &aFieldName, const SCH_SHEET_PATH *aPath, const wxString &aVariantName) const
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
bool IsMovableFromAnchorPoint() const override
Return true for items which are moved with the anchor point at mouse cursor and false for items moved...
bool IsPower() const override
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
bool HasEffectiveAssociatedFootprint() const
std::map< wxString, std::unique_ptr< SCH_SYMBOL_FIELD_PROPERTY > > m_fieldPropsStorageCache
Per-object cache of dynamic property descriptors for custom fields, keyed by descriptor name and popu...
bool operator==(const SCH_SYMBOL &aSymbol) const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, std::span< const wxString > aPins, REPORTER &aReporter)
void SetFilesStack(std::vector< EMBEDDED_FILES * > aFilesStack)
Definition sim_lib_mgr.h:45
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:60
bool m_DNP
True if symbol is set to 'Do Not Populate'.
Definition symbol.h:278
bool m_showPinNumbers
Definition symbol.h:272
bool m_excludedFromPosFiles
Definition symbol.h:277
SYMBOL(KICAD_T idType)
Definition symbol.h:62
bool m_excludedFromSim
Definition symbol.h:274
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:174
bool m_showPinNames
Definition symbol.h:271
const TRANSFORM & GetTransform() const
Definition symbol.h:247
int GetPinNameOffset() const
Definition symbol.h:163
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:168
bool m_excludedFromBOM
Definition symbol.h:275
bool m_excludedFromBoard
Definition symbol.h:276
virtual bool GetShowPinNames() const
Definition symbol.h:169
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
Definition symbol.h:162
SYMBOL & operator=(const SYMBOL &aItem)
Definition symbol.h:90
virtual bool GetShowPinNumbers() const
Definition symbol.h:175
TRANSFORM m_transform
The rotation/mirror transformation.
Definition symbol.h:267
int m_pinNameOffset
The offset in mils to draw the pin name.
Definition symbol.h:269
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
wxString wx_str() const
Definition utf8.cpp:41
wxString m_Name
bool m_ExcludedFromBOM
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, RESOLUTION_CONTEXT aContext)
Definition common.cpp:60
RESOLUTION_CONTEXT
Definition common.h:91
@ FOR_GUI
Definition common.h:93
@ FOR_CANVAS
Definition common.h:92
@ FOR_NETNAME
Definition common.h:94
@ RAW_VALUE
Definition common.h:98
@ INTERNAL
Definition common.h:96
#define DEFAULT_LINE_WIDTH_MILS
The default line width in mils. (can be changed in preference menu)
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:450
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:445
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:444
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:453
FILL_T
Definition eda_fill.h:29
@ NO_FILL
Definition eda_fill.h:30
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
RECURSE_MODE
Definition eda_item.h:50
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define STRUCT_DELETED
flag indication structures to be erased
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define IS_DANGLING
indicates a pin is dangling
a few functions useful in geometry calculations.
const wxChar *const traceSchSymbolRef
Flag to enable debug output of schematic symbol reference resolution.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:477
@ LAYER_DEVICE
Definition layer_ids.h:494
@ LAYER_VALUEPART
Definition layer_ids.h:489
@ LAYER_FIELDS
Definition layer_ids.h:490
@ LAYER_REFERENCEPART
Definition layer_ids.h:488
@ LAYER_DNP_MARKER
Definition layer_ids.h:506
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
Message panel definition file.
DIFF_VALUE WxAnyToDiffValue(const wxAny &aValue, PROPERTY_BASE *aProperty)
Convert a wxAny value read from a PROPERTY_BASE getter into a DIFF_VALUE that the engine can store,...
bool BoxHitTest(const VECTOR2I &aHitPoint, const BOX2I &aHittee, int aAccuracy)
Perform a point-to-box hit test.
KICOMMON_API wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
wxString GetRefDesUnannotated(const wxString &aSource)
Return an unannotated refdes from either a prefix or an existing refdes.
KICOMMON_API int UnpackDistance(const types::Distance &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition api_utils.cpp:50
KICOMMON_API void PackCustomProperties(google::protobuf::RepeatedPtrField< types::CustomProperty > *aOutput, const EDA_ITEM &aItem)
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackDistance(types::Distance &aOutput, int aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackLibId(types::LibraryIdentifier *aOutput, const LIB_ID &aId)
KICOMMON_API LIB_ID UnpackLibId(const types::LibraryIdentifier &aId)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
#define _HKI(x)
Definition page_info.cpp:40
see class PGM_BASE
PIN_MAP_OVERRIDE_MODE
Override mode stored on a SCH_SYMBOL_INSTANCE.
Definition pin_map.h:178
@ PT_NC
not connected (must be left open)
Definition pin_type.h:46
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define NO_SETTER(owner, type)
Macro to define read-only fields (no setter method available)
Definition property.h:904
#define ENUM_TO_WXANY(type)
Definition property.h:899
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names.
Collection of utility functions for component reference designators (refdes)
void CollectOtherUnits(const wxString &aRef, int aUnit, const LIB_ID &aLibId, SCH_SHEET_PATH &aSheet, std::vector< SCH_SYMBOL * > *otherUnits)
const SCH_FIELD * FindField(const std::vector< SCH_FIELD > &aFields, FIELD_T aFieldId)
Definition sch_field.h:394
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:383
@ AUTOPLACE_NONE
Definition sch_item.h:74
@ AUTOPLACE_AUTO
Definition sch_item.h:75
@ NO_CONNECT_END
Definition sch_item.h:92
@ SHEET_LABEL_END
Definition sch_item.h:91
@ LABEL_END
Definition sch_item.h:88
@ JUNCTION_END
Definition sch_item.h:86
@ PIN_END
Definition sch_item.h:87
@ WIRE_END
Definition sch_item.h:84
@ BASE
Definition sch_item.h:64
static const wxString PIN_MAP_GROUP
static const wxString PIN_MAP_MODE_PROP
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
static const wxString PIN_MAP_FOOTPRINT_PROP
static const ASSOCIATED_FOOTPRINT * activeAssociatedFootprint(const SCH_SYMBOL *aSymbol, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariant=wxEmptyString)
static const wxString PIN_MAP_ENTRY_PREFIX
static const wxString PIN_MAP_NAME_PROP
static void plotLocalPowerIcon(PLOTTER *aPlotter, const VECTOR2D &aPos, double aSize, bool aRotate)
plot a local power pin indicator icon.
static const wxString PIN_MAP_TABLE_GROUP
static struct SCH_SYMBOL_DESC _SCH_SYMBOL_DESC
std::vector< FAB_LAYER_COLOR > dummy
std::vector< wxString > ExpandStackedPinNotation(const wxString &aPinName, bool *aValid)
Expand stacked pin notation like [1,2,3], [1-4], [A1-A4], or [AA1-AA3,AB4,CD12-CD14] into individual ...
wxString UnescapeString(const wxString &aSource)
A first-class footprint choice on a LIB_SYMBOL, tied to a named pin map.
Definition pin_map.h:159
std::vector< std::pair< FIELD_T, wxString > > Fields
Definition sch_screen.h:91
Per-instance override of the active pin map and a sparse delta on top.
Definition pin_map.h:200
PIN_MAP_OVERRIDE_MODE m_Mode
Definition pin_map.h:201
bool IsDelegate() const
Definition pin_map.h:219
bool m_PDFPropertyPopups
Definition sch_plotter.h:66
A simple container for schematic symbol instance information.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
std::string refName
Hold a name of a symbol's field, field value, and default visibility.
#define ALL_UNITS
Definition symbol.h:150
SYMBOL_ORIENTATION_PROP
Definition symbol.h:48
@ SYMBOL_ANGLE_180
Definition symbol.h:51
@ SYMBOL_ANGLE_0
Definition symbol.h:49
@ SYMBOL_ANGLE_90
Definition symbol.h:50
@ SYMBOL_ANGLE_270
Definition symbol.h:52
#define ALL_BODY_STYLES
Definition symbol.h:151
@ SYM_ORIENT_270
Definition symbol.h:39
@ SYM_ROTATE_CLOCKWISE
Definition symbol.h:34
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition symbol.h:35
@ SYM_MIRROR_Y
Definition symbol.h:41
@ SYM_ORIENT_180
Definition symbol.h:38
@ SYM_MIRROR_X
Definition symbol.h:40
@ SYM_NORMAL
Definition symbol.h:33
@ SYM_ORIENT_90
Definition symbol.h:37
@ SYM_ORIENT_0
Definition symbol.h:36
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
JSON_SCHEMA_VALIDATOR validator(schema)
std::string path
KIBIS_MODEL * model
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:227
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ SCH_FIELD_LOCATE_REFERENCE_T
Definition typeinfo.h:176
@ SCH_FIELD_LOCATE_FOOTPRINT_T
Definition typeinfo.h:178
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:195
@ SCH_FIELD_LOCATE_VALUE_T
Definition typeinfo.h:177
@ SCH_SCREEN_T
Definition typeinfo.h:198
@ SCH_FIELD_LOCATE_DATASHEET_T
Definition typeinfo.h:179
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:192
@ SCH_PIN_T
Definition typeinfo.h:149
Custom text control validator definitions.
std::vector< VARIANT_COMPAT_RESULT > ValidateVariantSymbolCompatibility(const LIB_SYMBOL &aBase, const LIB_SYMBOL &aCandidate)
Check whether aCandidate can be used as a variant symbol override for aBase.
bool VariantSymbolPinsMatch(const SCH_PIN &aBase, const SCH_PIN &aCandidate)
Check whether two graphical pins occupy the same variant-symbol connection slot.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707