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 getOrCreate = [&]( const wxString& aName, std::unique_ptr<PROPERTY_BASE> aProp )
721 {
722 auto it = m_dynamicPropertyCache.find( aName );
723
724 if( it == m_dynamicPropertyCache.end() )
725 it = m_dynamicPropertyCache.emplace( aName, std::move( aProp ) ).first;
726
727 return it->second.get();
728 };
729
730 for( const SCH_FIELD& field : GetFields() )
731 {
732 if( !field.IsMandatory() )
733 continue;
734
735 if( field.IsPrivate() )
736 continue;
737
738 const wxString& name = field.GetUntranslatedName();
739
740 if( PROPERTY_MANAGER::Instance().GetProperty( TYPE_HASH( SCH_SYMBOL ), name ) )
741 continue;
742
743 props.push_back( getOrCreate( name, std::make_unique<SCH_SYMBOL_FIELD_PROPERTY>( name ) ) );
744 }
745
746 std::vector<const SCH_FIELD*> userFields;
747
748 for( const SCH_FIELD& field : GetFields() )
749 {
750 if( field.IsMandatory() || field.IsPrivate() )
751 continue;
752
753 userFields.push_back( &field );
754 }
755
756 std::ranges::sort( userFields,
757 []( const SCH_FIELD* a, const SCH_FIELD* b )
758 {
759 return a->GetUntranslatedName().CmpNoCase( b->GetUntranslatedName() ) < 0;
760 } );
761
762 for( const SCH_FIELD* field : userFields )
763 {
764 const wxString& name = field->GetUntranslatedName();
765 props.push_back( getOrCreate( name, std::make_unique<SCH_SYMBOL_FIELD_PROPERTY>( name ) ) );
766 }
767
769 props.push_back( prop );
770
771 // Pin Map group: only meaningful when the symbol carries at least one effective associated footprint.
773 {
774 props.push_back(
775 getOrCreate( PIN_MAP_FOOTPRINT_PROP, std::make_unique<SCH_SYMBOL_PIN_MAP_FOOTPRINT_PROPERTY>() ) );
776 props.push_back( getOrCreate( PIN_MAP_MODE_PROP, std::make_unique<SCH_SYMBOL_PIN_MAP_MODE_PROPERTY>() ) );
777 props.push_back( getOrCreate( PIN_MAP_NAME_PROP, std::make_unique<SCH_SYMBOL_PIN_MAP_NAME_PROPERTY>() ) );
778
779 // One read-only row per symbol pin under a collapsible group, showing
780 // the effective pad each pin resolves to.
781 if( aPath )
782 {
783 for( const SCH_PIN* pin : GetPins( aPath ) )
784 {
785 for( const wxString& number : pin->GetStackedPinNumbers() )
786 {
787 if( number.IsEmpty() )
788 continue;
789
790 const wxString propName = PIN_MAP_ENTRY_PREFIX + number;
791
792 props.push_back( getOrCreate(
793 propName, std::make_unique<SCH_SYMBOL_PIN_MAP_ENTRY_PROPERTY>( propName, number ) ) );
794 }
795 }
796 }
797 }
798
799 return props;
800}
801
802
803void SCH_SYMBOL::Init( const VECTOR2I& pos )
804{
806 m_pos = pos;
807 m_unit = 1; // In multi unit chip - which unit to draw.
808 m_bodyStyle = BODY_STYLE::BASE; // De Morgan Handling
809
810 // The rotation/mirror transformation matrix. pos normal
812
813 auto addField =
814 [&]( FIELD_T id, SCH_LAYER_ID layer )
815 {
816 m_fields.emplace_back( this, id, GetDefaultFieldName( id, UNTRANSLATED ) );
817 m_fields.back().SetTextPos( pos );
818 m_fields.back().SetLayer( layer );
819 };
820
821 // construct only the mandatory fields
823 addField( FIELD_T::VALUE, LAYER_VALUEPART );
824 addField( FIELD_T::FOOTPRINT, LAYER_FIELDS );
825 addField( FIELD_T::DATASHEET, LAYER_FIELDS );
827
828 m_prefix = wxString( wxT( "U" ) );
829 m_doNetlist = true;
831 m_signalName.clear();
832}
833
834
836{
837 return new SCH_SYMBOL( *this );
838}
839
840
841void SCH_SYMBOL::Serialize( google::protobuf::Any& aContainer ) const
842{
843 kiapi::schematic::types::SchematicSymbolInstance symbol;
844 Serialize( symbol );
845 aContainer.PackFrom( symbol );
846}
847
848
849void SCH_SYMBOL::Serialize( kiapi::schematic::types::SchematicSymbolInstance& aSymbol ) const
850{
851 using namespace kiapi::common;
852 using namespace kiapi::schematic::types;
853
854 aSymbol.mutable_id()->set_value( m_Uuid.AsStdString() );
855 PackVector2( *aSymbol.mutable_position(), GetPosition(), schIUScale );
856 aSymbol.set_locked( IsLocked() ? types::LockedState::LS_LOCKED : types::LockedState::LS_UNLOCKED );
857 aSymbol.set_fields_autoplaced( GetFieldsAutoplaced() != AUTOPLACE_NONE );
858
859 if( !UseLibIdLookup() )
860 {
861 LIB_ID id;
863 PackLibId( aSymbol.mutable_lib_id(), id );
864 }
865
867
868 SchematicSymbolTransform* transform = aSymbol.mutable_transform();
869 transform->set_orientation(
871 transform->set_mirror_x( GetMirrorX() );
872 transform->set_mirror_y( GetMirrorY() );
873
874 if( GetBodyStyleCount() > 1 )
875 aSymbol.mutable_body_style()->set_style( GetBodyStyle() );
876
877 GetField( FIELD_T::REFERENCE )->Serialize( *aSymbol.mutable_reference_field(), schIUScale );
878 GetField( FIELD_T::VALUE )->Serialize( *aSymbol.mutable_value_field(), schIUScale );
879 GetField( FIELD_T::FOOTPRINT )->Serialize( *aSymbol.mutable_footprint_field(), schIUScale );
880 GetField( FIELD_T::DATASHEET )->Serialize( *aSymbol.mutable_datasheet_field(), schIUScale );
881 GetField( FIELD_T::DESCRIPTION )->Serialize( *aSymbol.mutable_description_field(), schIUScale );
882
883 for( const SCH_FIELD& field : GetFields() )
884 {
885 if( field.IsMandatory() )
886 continue;
887
888 field.Serialize( *aSymbol.add_user_fields(), schIUScale );
889 }
890
891 if( m_part )
892 m_part->Serialize( *aSymbol.mutable_definition(), /* aSkipPins = */ true );
893
894 aSymbol.set_show_pin_names( GetShowPinNames() );
895 aSymbol.set_show_pin_numbers( GetShowPinNumbers() );
896
897 PackDistance( *aSymbol.mutable_pin_name_offset(), GetPinNameOffset(), schIUScale );
898
899 kiapi::common::PackCustomProperties( aSymbol.mutable_custom_properties(), *this );
900}
901
902
903bool SCH_SYMBOL::Deserialize( const google::protobuf::Any& aContainer )
904{
905 kiapi::schematic::types::SchematicSymbolInstance symbol;
906
907 if( !aContainer.UnpackTo( &symbol ) )
908 return false;
909
910 return Deserialize( symbol );
911}
912
913
914bool SCH_SYMBOL::Deserialize( const kiapi::schematic::types::SchematicSymbolInstance& aSymbol )
915{
916 using namespace kiapi::common;
917 using namespace kiapi::common::types;
918 using namespace kiapi::schematic::types;
919
920 // Published rows and the item index hold this identity and its pins, so they must not outlive the change
921 if( SCH_SCREEN* screen = GetParentScreen() )
922 screen->BumpConnectivityRevision();
923
924 const_cast<::KIID&>( m_Uuid ) = ::KIID( aSymbol.id().value() );
925 SetPosition( UnpackVector2( aSymbol.position(), schIUScale ) );
926 SetLocked( aSymbol.locked() == LockedState::LS_LOCKED );
927 SetFieldsAutoplaced( aSymbol.fields_autoplaced() ? AUTOPLACE_AUTO : AUTOPLACE_NONE );
928 kiapi::common::UnpackCustomProperties( aSymbol.custom_properties(), *this );
929
930 if( aSymbol.has_lib_id() )
931 SetSchSymbolLibraryName( UnpackLibId( aSymbol.lib_id() ).Format() );
932
934 SetOrientationProp( FromProtoEnum<SYMBOL_ORIENTATION_PROP>( aSymbol.transform().orientation() ) );
935 SetMirrorX( aSymbol.transform().mirror_x() );
936 SetMirrorY( aSymbol.transform().mirror_y() );
937
938 // Generally clients should not send symbols without definitions, but if they do as an update for
939 // an existing symbol, it's better to skip deserialization than delete the existing definition,
940 // especially since definitions are cached separately
941 const bool haveDefinition = aSymbol.has_definition();
942
943 std::unordered_map<::KIID, wxString> pinAltMap;
944
945 if( haveDefinition )
946 {
947 const SchematicSymbol& def = aSymbol.definition();
948
949 LIB_ID libId = UnpackLibId( def.id() );
950 m_lib_id = libId;
951
952 for( const SchematicSymbolChild& child : def.items() )
953 {
954 if( TypeNameFromAny( child.item() ) != std::optional<KICAD_T>( SCH_PIN_T ) )
955 continue;
956
957 SchematicPin pinProto;
958
959 if( child.item().UnpackTo( &pinProto ) && pinProto.has_active_alternate() )
960 pinAltMap[::KIID( pinProto.id().value() )] = wxString::FromUTF8( pinProto.active_alternate() );
961 }
962
963 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( libId.GetLibItemName() );
964
965 if( !libSymbol->Deserialize( def ) )
966 {
967 delete libSymbol;
968 return false;
969 }
970
971 SetLibSymbol( libSymbol );
972 }
973
974 if( aSymbol.has_body_style() )
975 SetBodyStyle( aSymbol.body_style().style() );
976
977 GetField( FIELD_T::REFERENCE )->Deserialize( aSymbol.reference_field(), schIUScale );
978 GetField( FIELD_T::VALUE )->Deserialize( aSymbol.value_field(), schIUScale );
979 GetField( FIELD_T::FOOTPRINT )->Deserialize( aSymbol.footprint_field(), schIUScale );
980 GetField( FIELD_T::DATASHEET )->Deserialize( aSymbol.datasheet_field(), schIUScale );
981 GetField( FIELD_T::DESCRIPTION )->Deserialize( aSymbol.description_field(), schIUScale );
982
983 std::set<wxString> incoming;
984
985 for( const SchematicField& fieldProto : aSymbol.user_fields() )
986 {
987 wxString name = wxString::FromUTF8( fieldProto.name() );
988 SCH_FIELD* existing = GetField( name );
989
990 // Don't duplicate existing mandatory fields.
991 if( existing && existing->IsMandatory() )
992 continue;
993
994 incoming.insert( name );
995
996 if( existing )
997 existing->Deserialize( fieldProto, schIUScale );
998 else
999 AddField( SCH_FIELD( this, FIELD_T::USER, name ) )->Deserialize( fieldProto, schIUScale );
1000 }
1001
1002 std::vector<wxString> toRemove;
1003
1004 for( const SCH_FIELD& field : GetFields() )
1005 {
1006 if( !field.IsMandatory() && !incoming.count( field.GetName( false ) ) )
1007 toRemove.push_back( field.GetName( false ) );
1008 }
1009
1010 for( const wxString& name : toRemove )
1011 RemoveField( name );
1012
1013 if( aSymbol.has_show_pin_names() )
1014 SetShowPinNames( aSymbol.show_pin_names() );
1015
1016 if( aSymbol.has_show_pin_numbers() )
1017 SetShowPinNumbers( aSymbol.show_pin_numbers() );
1018
1019 if( aSymbol.has_pin_name_offset() )
1020 SetPinNameOffset( UnpackDistance( aSymbol.pin_name_offset(), schIUScale ) );
1021
1022 // The proto is storing a single pin struct that has the UUID and alternate selection
1023 // as well as the library pin definition. Deserializing the pin will have set up most
1024 // of this, but we want to make sure that the UUIDs of the instance pins round-trip
1025 // so we have to set them up in advance so that UpdatePins links them up with the
1026 // lib pins, and then we need to set the alternates for pins if applicable
1027
1028 if( haveDefinition )
1029 {
1030 m_pins.clear();
1031
1032 for( SCH_PIN* pin : GetAllLibPins() )
1033 {
1034 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
1035 m_pins.back()->SetParent( this );
1036 const_cast<::KIID&>( m_pins.back() ->m_Uuid ) = pin->m_Uuid;
1037 }
1038
1039 UpdatePins();
1040
1042 {
1043 if( pinAltMap.contains( pin->m_Uuid ) )
1044 pin->SetAlt( pinAltMap.at( pin->m_Uuid ) );
1045 }
1046 }
1047
1048 return true;
1049}
1050
1051
1053{
1054 return m_part == nullptr;
1055}
1056
1057
1059{
1060 // If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
1061 // going to end up moving the symbol's pins off-grid.
1062
1063 // The minimal grid size allowed to place a pin is 25 mils
1064 const int min_grid_size = schIUScale.MilsToIU( 25 );
1065
1066 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1067 {
1068 if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
1069 return false;
1070
1071 if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
1072 return false;
1073 }
1074
1075 return true;
1076}
1077
1078
1079void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
1080{
1081 m_lib_id = aLibId;
1082}
1083
1084
1086{
1087 if( !m_schLibSymbolName.IsEmpty() )
1088 return m_schLibSymbolName;
1089 else
1090 return m_lib_id.Format();
1091}
1092
1093
1095{
1096 wxCHECK2( !aLibSymbol || aLibSymbol->IsRoot(), aLibSymbol = nullptr );
1097
1098 m_part.reset( aLibSymbol );
1099
1100 // Library content changed, so cached flattened alternates may be stale.
1101 m_variantSymbolCache.clear();
1102
1103 // We've just reset the library symbol, so the lib_pins, which were just
1104 // pointers to the old symbol, need to be cleared.
1105 for( auto& pin : m_pins )
1106 pin->SetLibPin( nullptr );
1107
1108 UpdatePins();
1109}
1110
1111
1113{
1114 if( m_part )
1115 return m_part->GetDescription();
1116
1117 return wxEmptyString;
1118}
1119
1120
1121wxString SCH_SYMBOL::GetShownDescription( RESOLUTION_CONTEXT aContext, int aDepth ) const
1122{
1123 if( m_part )
1124 return m_part->GetShownDescription( aContext, aDepth );
1125
1126 return wxEmptyString;
1127}
1128
1129
1131{
1132 if( m_part )
1133 return m_part->GetKeyWords();
1134
1135 return wxEmptyString;
1136}
1137
1138
1139wxString SCH_SYMBOL::GetShownKeyWords( RESOLUTION_CONTEXT aContext, int aDepth ) const
1140{
1141 if( m_part )
1142 return m_part->GetShownKeyWords( aContext, aDepth );
1143
1144 return wxEmptyString;
1145}
1146
1147
1149{
1150 if( m_part )
1151 return m_part->GetDatasheetField().GetText();
1152
1153 return wxEmptyString;
1154}
1155
1156
1158{
1159 if( SCH_SCREEN* screen = GetParentScreen() )
1160 screen->BumpConnectivityRevision();
1161
1162 updatePins();
1163}
1164
1165
1167{
1168 std::map<wxString, wxString> altPinMap;
1169 std::map<wxString, SCH_PIN::ALT> altPinDefs;
1170 std::map<wxString, std::vector<SCH_PIN*>> pinUuidMap;
1171 std::set<SCH_PIN*> unassignedSchPins;
1172 std::vector<SCH_PIN*> unassignedLibPins;
1173
1174 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1175 {
1176 // Saved order keeps duplicate-number identities independent of allocation order.
1177 pinUuidMap[pin->GetNumber()].push_back( pin.get() );
1178
1179 unassignedSchPins.insert( pin.get() );
1180
1181 if( !pin->GetAlt().IsEmpty() )
1182 {
1183 altPinMap[pin->GetNumber()] = pin->GetAlt();
1184 auto altDefIt = pin->GetAlternates().find( pin->GetAlt() );
1185
1186 if( altDefIt != pin->GetAlternates().end() )
1187 altPinDefs[pin->GetNumber()] = altDefIt->second;
1188 }
1189
1190 pin->SetLibPin( nullptr );
1191 }
1192
1193 m_pinMap.clear();
1194
1195 if( !m_part )
1196 return;
1197
1198 // NB: Don't filter by unit: this data-structure is used for all instances,
1199 // some of which might have different units.
1200 for( SCH_PIN* libPin : m_part->GetGraphicalPins( ALL_UNITS, m_bodyStyle ) )
1201 {
1202 SCH_PIN* pin = nullptr;
1203
1204 auto ii = pinUuidMap.find( libPin->GetNumber() );
1205
1206 if( ii == pinUuidMap.end() || ii->second.empty() )
1207 {
1208 unassignedLibPins.push_back( libPin );
1209 continue;
1210 }
1211
1212 auto it = ii->second.begin();
1213 pin = *it;
1214 ii->second.erase( it );
1215 pin->GetAlternates() = libPin->GetAlternates();
1216 pin->SetLibPin( libPin );
1217 pin->SetPosition( libPin->GetPosition() );
1218 pin->SetUnit( libPin->GetUnit() );
1219 pin->SetBodyStyle( libPin->GetBodyStyle() );
1220
1221 unassignedSchPins.erase( pin );
1222
1223 auto iii = altPinMap.find( libPin->GetNumber() );
1224
1225 if( iii != altPinMap.end() )
1226 {
1227 wxString altName = iii->second;
1228
1229 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
1230 {
1231 auto defIt = altPinDefs.find( libPin->GetNumber() );
1232
1233 if( defIt != altPinDefs.end() )
1234 {
1235 for( const auto& [name, alt] : pin->GetAlternates() )
1236 {
1237 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
1238 {
1239 altName = name;
1240 break;
1241 }
1242 }
1243 }
1244 }
1245
1246 pin->SetAlt( altName );
1247 }
1248
1249 m_pinMap[libPin] = pin;
1250 }
1251
1252 // Add any pins that were not found in the symbol
1253 size_t nextUnassigned = 0;
1254
1255 for( SCH_PIN* libPin : unassignedLibPins )
1256 {
1257 SCH_PIN* pin = nullptr;
1258
1259 // First try to re-use an existing pin
1260 if( !unassignedSchPins.empty() )
1261 {
1262 while( nextUnassigned < m_pins.size()
1263 && !unassignedSchPins.contains( m_pins[nextUnassigned].get() ) )
1264 {
1265 ++nextUnassigned;
1266 }
1267
1268 pin = m_pins.at( nextUnassigned++ ).get();
1269 unassignedSchPins.erase( pin );
1270 }
1271 else
1272 {
1273 // This is a pin that was not found in the symbol, so create a new one.
1274 pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( this, libPin ) ) ).get();
1275 }
1276
1277 m_pinMap[libPin] = pin;
1278 pin->GetAlternates() = libPin->GetAlternates();
1279 pin->SetLibPin( libPin );
1280 pin->SetPosition( libPin->GetPosition() );
1281 pin->SetUnit( libPin->GetUnit() );
1282 pin->SetBodyStyle( libPin->GetBodyStyle() );
1283 pin->SetNumber( libPin->GetNumber() );
1284
1285 auto iii = altPinMap.find( libPin->GetNumber() );
1286
1287 if( iii != altPinMap.end() )
1288 {
1289 wxString altName = iii->second;
1290
1291 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
1292 {
1293 auto defIt = altPinDefs.find( libPin->GetNumber() );
1294
1295 if( defIt != altPinDefs.end() )
1296 {
1297 for( const auto& [name, alt] : pin->GetAlternates() )
1298 {
1299 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
1300 {
1301 altName = name;
1302 break;
1303 }
1304 }
1305 }
1306 }
1307
1308 pin->SetAlt( altName );
1309 }
1310 }
1311
1312 // If we have any pins left in the symbol that were not found in the library, remove them.
1313 for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
1314 {
1315 auto it2 = unassignedSchPins.find( it1->get() );
1316
1317 if( it2 != unassignedSchPins.end() )
1318 {
1319 it1 = m_pins.erase( it1 );
1320 unassignedSchPins.erase( it2 );
1321 }
1322 else
1323 {
1324 ++it1;
1325 }
1326 }
1327
1328 // If the symbol is selected, then its pins are selected.
1329 if( IsSelected() )
1330 {
1331 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1332 pin->SetSelected();
1333 }
1334}
1335
1336
1337void SCH_SYMBOL::SetBodyStyle( int aBodyStyle )
1338{
1339 if( aBodyStyle != m_bodyStyle )
1340 {
1341 m_bodyStyle = aBodyStyle;
1342
1343 // The body style may have a different pin layout so the update the pin map.
1344 UpdatePins();
1345 }
1346}
1347
1348
1350{
1351 if( m_part )
1352 return m_part->GetUnitCount();
1353
1354 return 0;
1355}
1356
1357
1359{
1360 if( m_part )
1361 return m_part->GetBodyStyleCount();
1362
1363 return 0;
1364}
1365
1366
1368{
1369 if( m_part )
1370 return m_part->HasDeMorganBodyStyles();
1371
1372 return false;
1373}
1374
1375
1376wxString SCH_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
1377{
1378 if( m_part )
1379 return m_part->GetUnitDisplayName( aUnit, aLabel );
1380 else if( aLabel )
1381 return wxString::Format( _( "Unit %s" ), SubReference( aUnit ) );
1382 else
1383 return SubReference( aUnit );
1384}
1385
1386
1387wxString SCH_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
1388{
1389 if( m_part )
1390 return m_part->GetBodyStyleDescription( aBodyStyle, aLabel );
1391 else
1392 return wxT( "?" );
1393}
1394
1395
1396bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance, const KIID_PATH& aSheetPath, bool aTestFromEnd ) const
1397{
1398 if( !aTestFromEnd )
1399 {
1400 auto it = m_instancePathIndex.find( aSheetPath );
1401
1402 if( it != m_instancePathIndex.end() )
1403 {
1404 aInstance = m_instances[it->second];
1405 return true;
1406 }
1407
1408 return false;
1409 }
1410
1411 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1412 {
1413 if( instance.m_Path.EndsWith( aSheetPath ) )
1414 {
1415 aInstance = instance;
1416 return true;
1417 }
1418 }
1419
1420 return false;
1421}
1422
1423
1424void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
1425{
1426 RemoveInstance( aInstancePath.Path() );
1427}
1428
1429
1430void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
1431{
1432 bool removed = false;
1433
1434 // Search for an existing path and remove it if found
1435 // (search from back to avoid invalidating iterator on remove)
1436 for( int ii = m_instances.size() - 1; ii >= 0; --ii )
1437 {
1438 if( m_instances[ii].m_Path == aInstancePath )
1439 {
1440 wxLogTrace( traceSchSheetPaths,
1441 wxS( "Removing symbol instance:\n"
1442 " sheet path %s\n"
1443 " reference %s, unit %d from symbol %s." ),
1444 aInstancePath.AsString(), m_instances[ii].m_Reference, m_instances[ii].m_Unit,
1445 m_Uuid.AsString() );
1446
1447 m_instances.erase( m_instances.begin() + ii );
1448 removed = true;
1449 }
1450 }
1451
1452 if( removed )
1453 {
1456 }
1457}
1458
1459
1461{
1462 m_instancePathIndex.clear();
1463 m_instancePathIndex.reserve( m_instances.size() );
1464
1465 for( size_t i = 0; i < m_instances.size(); ++i )
1466 m_instancePathIndex[m_instances[i].m_Path] = i;
1467}
1468
1469
1470void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, int aUnit )
1471{
1472 SCH_SYMBOL_INSTANCE instance;
1473 instance.m_Path = aPath;
1474 instance.m_Reference = aRef;
1475 instance.m_Unit = aUnit;
1476
1477 AddHierarchicalReference( instance );
1478}
1479
1480
1482{
1483 SCH_SYMBOL_INSTANCE instance = aInstance;
1484 RemoveInstance( instance.m_Path );
1485
1486 wxLogTrace( traceSchSheetPaths,
1487 wxS( "Adding symbol '%s' instance:\n"
1488 " sheet path '%s'\n"
1489 " reference '%s'\n"
1490 " unit %d\n" ),
1491 m_Uuid.AsString(), instance.m_Path.AsString(), instance.m_Reference, instance.m_Unit );
1492
1493 m_instancePathIndex[instance.m_Path] = m_instances.size();
1494 m_instances.push_back( instance );
1496
1497 // This should set the default instance to the first saved instance data for each symbol
1498 // when importing sheets.
1499 if( m_instances.size() == 1 )
1500 {
1502 m_unit = instance.m_Unit;
1503 }
1504}
1505
1506
1507const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
1508{
1509 KIID_PATH path = sheet->Path();
1510 wxString ref;
1511 wxString subRef;
1512
1513 const bool traceEnabled = wxLog::IsAllowedTraceMask( traceSchSymbolRef );
1514
1515 if( traceEnabled )
1516 {
1517 wxLogTrace( traceSchSymbolRef, "GetRef for symbol %s on path %s (sheet path has %zu sheets)",
1518 m_Uuid.AsString(), path.AsString(), sheet->size() );
1519 wxLogTrace( traceSchSymbolRef, " Symbol has %zu instance references", m_instances.size() );
1520 }
1521
1522 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1523 {
1524 const SCH_SYMBOL_INSTANCE& instance = m_instances[it->second];
1525
1526 ref = instance.m_Reference;
1527 subRef = SubReference( instance.m_Unit );
1528
1529 if( traceEnabled )
1530 wxLogTrace( traceSchSymbolRef, " MATCH FOUND: ref=%s", ref );
1531 }
1532
1533 // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
1534 // use this as a default for this path. This will happen if we load a version 1 schematic
1535 // file. It will also mean that multiple instances of the same sheet by default all have
1536 // the same symbol references, but perhaps this is best.
1537 if( ref.IsEmpty() && !GetField( FIELD_T::REFERENCE )->GetText().IsEmpty() )
1538 {
1540
1541 if( traceEnabled )
1542 wxLogTrace( traceSchSymbolRef, " Using fallback from REFERENCE field: %s", ref );
1543 }
1544
1545 if( ref.IsEmpty() )
1546 {
1548
1549 if( traceEnabled )
1550 wxLogTrace( traceSchSymbolRef, " Using unannotated reference: %s", ref );
1551 }
1552
1553 if( aIncludeUnit && GetUnitCount() > 1 )
1554 ref += subRef;
1555
1556 if( traceEnabled )
1557 wxLogTrace( traceSchSymbolRef, " Final reference: %s", ref );
1558
1559 return ref;
1560}
1561
1562
1563void SCH_SYMBOL::SetRefProp( const wxString& aRef )
1564{
1566
1567 if( validator.DoValidate( aRef, nullptr ) )
1568 SetRef( &Schematic()->CurrentSheet(), aRef );
1569}
1570
1571
1572void SCH_SYMBOL::SetValueProp( const wxString& aValue )
1573{
1574 wxString currentVariant = Schematic()->GetCurrentVariant();
1575 SetValueFieldText( aValue, &Schematic()->CurrentSheet(), currentVariant );
1576}
1577
1578
1579void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
1580{
1581 KIID_PATH path = sheet->Path();
1582 const wxString previousPrefix = m_prefix;
1583 const bool wasDoNetlist = m_doNetlist;
1584 bool changed = false;
1585
1586 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1587 changed = std::exchange( m_instances[it->second].m_Reference, ref ) != ref;
1588 else
1590
1591 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1592 pin->ClearDefaultNetName( sheet );
1593
1594 if( Schematic() && *sheet == Schematic()->CurrentSheet() )
1595 {
1596 changed |= GetField( FIELD_T::REFERENCE )->GetText() != ref;
1598 }
1599
1600 // Reinit the m_prefix member if needed
1602
1603 if( m_prefix.IsEmpty() )
1604 m_prefix = wxT( "U" );
1605
1606 // Power symbols have references starting with # and are not included in netlists
1607 m_doNetlist = !ref.StartsWith( wxT( "#" ) );
1608
1609 if( changed || m_prefix != previousPrefix || m_doNetlist != wasDoNetlist )
1611}
1612
1613
1614void SCH_SYMBOL::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath,
1615 const wxString& aVariantName )
1616{
1617 wxCHECK_MSG( !aFieldName.IsEmpty(), /* void */, wxT( "Can't set text on a field with no name!" ) );
1618
1619 SCH_FIELD* field = GetField( aFieldName );
1620
1621 wxCHECK_MSG( field, /* void */, wxT( "Can't set text on a field not yet added to the symbol!" ) );
1622
1623 switch( field->GetId() )
1624 {
1625 case FIELD_T::REFERENCE:
1626 wxCHECK( aPath, /* void */ );
1627 SetRef( aPath, aFieldText );
1628 break;
1629
1630 default:
1631 {
1632 wxString defaultText = field->GetText( aPath );
1633
1634 if( aVariantName.IsEmpty() )
1635 {
1636 if( aFieldText != defaultText )
1637 field->SetText( aFieldText );
1638 }
1639 else
1640 {
1641 SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1642
1643 wxCHECK( instance, /* void */ );
1644
1645 // Diff against the value the variant resolves to without an explicit override so
1646 // alternate symbol fields read back through the UI are not re-stored as overrides.
1647 if( LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath ) )
1648 {
1649 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1650
1651 if( altField && !altField->GetText().IsEmpty() )
1652 defaultText = altField->GetText();
1653 }
1654
1655 bool changed = false;
1656
1657 if( instance->m_Variants.contains( aVariantName ) )
1658 {
1659 auto& fields = instance->m_Variants[aVariantName].m_Fields;
1660
1661 if( aFieldText != defaultText )
1662 {
1663 auto [entry, inserted] = fields.try_emplace( aFieldName, aFieldText );
1664 changed = inserted || std::exchange( entry->second, aFieldText ) != aFieldText;
1665 }
1666 else
1667 {
1668 changed = fields.erase( aFieldName ) != 0;
1669 }
1670 }
1671 else if( aFieldText != defaultText )
1672 {
1673 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1674
1675 newVariant.InitializeAttributes( *this );
1676 newVariant.m_Fields[aFieldName] = aFieldText;
1677 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1678 changed = true;
1679 }
1680
1681 if( changed )
1683 }
1684
1685 break;
1686 }
1687 }
1688}
1689
1690
1691wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
1692 const wxString& aVariantName ) const
1693{
1694 wxCHECK( !aFieldName.IsEmpty(), wxEmptyString );
1695
1696 const SCH_FIELD* field = GetField( aFieldName );
1697
1698 wxCHECK( field, wxEmptyString );
1699
1700 switch( field->GetId() )
1701 {
1702 case FIELD_T::REFERENCE:
1703 wxCHECK( aPath, field->GetText() );
1704 return GetRef( aPath, false );
1705 break;
1706
1707 case FIELD_T::FOOTPRINT:
1708 if( !aVariantName.IsEmpty() && aPath )
1709 {
1710 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1711
1712 if( instance && instance->m_Variants.contains( aVariantName )
1713 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
1714 {
1715 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
1716 }
1717
1718 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1719
1720 if( altSymbol )
1721 {
1722 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::FOOTPRINT );
1723
1724 if( altField && !altField->GetText().IsEmpty() )
1725 return altField->GetText();
1726 }
1727 }
1728
1729 return GetFootprintFieldText( nullptr, RAW_VALUE );
1730
1731 default:
1732 if( aVariantName.IsEmpty() )
1733 {
1734 return field->GetText();
1735 }
1736 else if( aPath )
1737 {
1738 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1739
1740 if( instance && instance->m_Variants.contains( aVariantName ) )
1741 {
1742 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
1743
1744 if( variant.m_Fields.contains( aFieldName ) )
1745 return variant.m_Fields.at( aFieldName );
1746
1747 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1748
1749 if( altSymbol )
1750 {
1751 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1752
1753 if( altField && !altField->GetText().IsEmpty() )
1754 return altField->GetText();
1755 }
1756 }
1757 }
1758
1759 break;
1760 }
1761
1762 return field->GetText();
1763}
1764
1765
1766bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const
1767{
1768 KIID_PATH path = aSheet->Path();
1769
1770 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1771 {
1772 if( instance.m_Path == path )
1773 return !instance.m_Reference.IsEmpty() && instance.m_Reference.Last() != '?';
1774 }
1775
1776 return false;
1777}
1778
1779
1781{
1782 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
1783
1784 refDesignator.Replace( "~", " " );
1785
1786 wxString prefix = refDesignator;
1787
1788 while( prefix.Length() )
1789 {
1790 wxUniCharRef last = prefix.Last();
1791
1792 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
1793 prefix.RemoveLast();
1794 else
1795 break;
1796 }
1797
1798 // Avoid a prefix containing trailing/leading spaces
1799 prefix.Trim( true );
1800 prefix.Trim( false );
1801
1802 if( !prefix.IsEmpty() )
1803 SetPrefix( prefix );
1804}
1805
1806
1807wxString SCH_SYMBOL::SubReference( int aUnit, bool aAddSeparator ) const
1808{
1809 // A custom unit display name overrides the default A/B/C (or numeric) suffix.
1810 if( m_part )
1811 {
1812 const std::map<int, wxString>& names = m_part->GetUnitDisplayNames();
1813 auto it = names.find( aUnit );
1814
1815 if( it != names.end() )
1816 {
1817 wxString subRef;
1818
1819 if( SCHEMATIC* schematic = Schematic() )
1820 {
1821 int sep = schematic->Settings().m_SubpartIdSeparator;
1822
1823 if( sep != 0 && aAddSeparator )
1824 subRef << wxChar( sep );
1825 }
1826
1827 subRef << it->second;
1828 return subRef;
1829 }
1830 }
1831
1832 if( SCHEMATIC* schematic = Schematic() )
1833 return schematic->Settings().SubReference( aUnit, aAddSeparator );
1834
1835 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
1836}
1837
1838
1840{
1841 KIID_PATH path = aSheet->Path();
1842
1843 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1844 return m_instances[it->second].m_Unit;
1845
1846 // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
1847 // version 1 schematic file.
1848 return m_unit;
1849}
1850
1851
1852void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
1853{
1854 KIID_PATH path = aSheet->Path();
1855
1856 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1857 {
1858 if( std::exchange( m_instances[it->second].m_Unit, aUnitSelection ) != aUnitSelection )
1860
1861 return;
1862 }
1863
1864 // didn't find it; better add it
1866}
1867
1868
1869void SCH_SYMBOL::setVariantAttribute( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName,
1870 bool SCH_SYMBOL::*aBase, bool SCH_SYMBOL_VARIANT::*aOverride )
1871{
1872 bool* attribute = &( this->*aBase );
1873
1874 if( aInstance && !aVariantName.IsEmpty() )
1875 {
1876 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1877
1878 wxCHECK_MSG( instance, /* void */,
1879 wxString::Format( wxS( "Cannot set attribute for invalid sheet path '%s'." ),
1880 aInstance->PathHumanReadable() ) );
1881
1882 auto variant = instance->m_Variants.find( aVariantName );
1883
1884 if( variant == instance->m_Variants.end() )
1885 {
1886 if( aEnable == this->*aBase )
1887 return;
1888
1889 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1890 newVariant.InitializeAttributes( *this );
1891 newVariant.*aOverride = aEnable;
1892 AddVariant( *aInstance, newVariant );
1893 return;
1894 }
1895
1896 attribute = &( variant->second.*aOverride );
1897 }
1898
1899 if( *attribute == aEnable )
1900 return;
1901
1902 *attribute = aEnable;
1904}
1905
1906
1907void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1908{
1909 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_DNP, &SCH_SYMBOL_VARIANT::m_DNP );
1910}
1911
1912
1913bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1914{
1915 if( !aInstance || aVariantName.IsEmpty() )
1916 return m_DNP;
1917
1918 SCH_SYMBOL_INSTANCE instance;
1919
1920 if( !GetInstance( instance, aInstance->Path() ) )
1921 return m_DNP;
1922
1923 if( instance.m_Variants.contains( aVariantName ) )
1924 return instance.m_Variants[aVariantName].m_DNP;
1925
1926 return m_DNP;
1927}
1928
1929
1931 const wxString& aVariantName )
1932{
1933 if( !aInstance || aVariantName.IsEmpty() )
1934 {
1935 m_pinMapOverride = aOverride;
1936 return;
1937 }
1938
1939 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1940
1941 wxCHECK_MSG( instance, /* void */,
1942 wxString::Format( wxS( "Cannot set pin map override for invalid sheet path '%s'." ),
1943 aInstance->PathHumanReadable() ) );
1944
1945 if( instance->m_Variants.contains( aVariantName ) )
1946 {
1947 instance->m_Variants[aVariantName].m_PinMapOverride = aOverride;
1948 }
1949 else if( !aOverride.IsDefault() )
1950 {
1951 SCH_SYMBOL_VARIANT variant( aVariantName );
1952
1953 variant.InitializeAttributes( *this );
1954 variant.m_PinMapOverride = aOverride;
1955 AddVariant( *aInstance, variant );
1956 }
1957}
1958
1959
1961 const wxString& aVariantName ) const
1962{
1964
1965 if( aInstance && !aVariantName.IsEmpty() )
1966 {
1967 SCH_SYMBOL_INSTANCE instance;
1968
1969 if( GetInstance( instance, aInstance->Path() ) && instance.m_Variants.contains( aVariantName ) )
1970 result = instance.m_Variants[aVariantName].m_PinMapOverride;
1971 }
1972
1973 // Units 2..N follow unit 1's record; resolve that here so callers never see a delegate.
1974 if( result.IsDelegate() && aInstance )
1975 result = resolveDelegatedPinMapOverride( *aInstance, aVariantName );
1976
1977 return result;
1978}
1979
1980
1982 const wxString& aVariantName ) const
1983{
1984 if( !Schematic() )
1986
1987 wxString ref = GetRef( &aSheet );
1988
1989 for( const SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1990 {
1991 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1992 {
1993 SCH_SYMBOL* sibling = static_cast<SCH_SYMBOL*>( item );
1994
1995 if( sibling == this || sibling->GetUnit() != 1 )
1996 continue;
1997
1998 if( sibling->GetRef( &sheet ).CmpNoCase( ref ) != 0 )
1999 continue;
2000
2001 PIN_MAP_INSTANCE_OVERRIDE unit1 = sibling->GetPinMapOverride( &sheet, aVariantName );
2002
2003 // Guard against a unit-1 record that itself (incorrectly) delegates.
2004 if( unit1.IsDelegate() )
2006
2007 return unit1;
2008 }
2009 }
2010
2012}
2013
2014
2015void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
2016{
2017 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromBOM,
2019}
2020
2021
2022bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
2023{
2024 if( !aInstance || aVariantName.IsEmpty() )
2025 return m_excludedFromBOM;
2026
2027 SCH_SYMBOL_INSTANCE instance;
2028
2029 if( !GetInstance( instance, aInstance->Path() ) )
2030 return m_excludedFromBOM;
2031
2032 if( instance.m_Variants.contains( aVariantName ) )
2033 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
2034
2035 // If the variant has not been defined yet, return the default exclude from BOM setting.
2036 return m_excludedFromBOM;
2037}
2038
2039
2040void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
2041{
2042 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromSim,
2044}
2045
2046
2047bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
2048{
2049 if( !aInstance || aVariantName.IsEmpty() )
2050 return m_excludedFromSim;
2051
2052 SCH_SYMBOL_INSTANCE instance;
2053
2054 if( !GetInstance( instance, aInstance->Path() ) )
2055 return m_excludedFromSim;
2056
2057 if( instance.m_Variants.contains( aVariantName ) )
2058 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
2059
2060 // If variant is not defined yet, return default exclude from simulation setting.
2061 return m_excludedFromSim;
2062}
2063
2064
2065void SCH_SYMBOL::SetExcludedFromBoard( bool aEnable, const SCH_SHEET_PATH* aInstance,
2066 const wxString& aVariantName )
2067{
2068 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromBoard,
2070}
2071
2072
2074 const wxString& aVariantName ) const
2075{
2076 if( !aInstance || aVariantName.IsEmpty() )
2077 return m_excludedFromBoard;
2078
2079 SCH_SYMBOL_INSTANCE instance;
2080
2081 if( !GetInstance( instance, aInstance->Path() ) )
2082 return m_excludedFromBoard;
2083
2084 if( instance.m_Variants.contains( aVariantName ) )
2085 return instance.m_Variants[aVariantName].m_ExcludedFromBoard;
2086
2087 // If variant is not defined yet, return default exclude from board setting.
2088 return m_excludedFromBoard;
2089}
2090
2091
2092void SCH_SYMBOL::SetExcludedFromPosFiles( bool aEnable, const SCH_SHEET_PATH* aInstance,
2093 const wxString& aVariantName )
2094{
2095 setVariantAttribute( aEnable, aInstance, aVariantName, &SCH_SYMBOL::m_excludedFromPosFiles,
2097}
2098
2099
2101 const wxString& aVariantName ) const
2102{
2103 if( !aInstance || aVariantName.IsEmpty() )
2105
2106 SCH_SYMBOL_INSTANCE instance;
2107
2108 if( !GetInstance( instance, aInstance->Path() ) )
2110
2111 if( instance.m_Variants.contains( aVariantName ) )
2112 return instance.m_Variants[aVariantName].m_ExcludedFromPosFiles;
2113
2114 // If variant is not defined yet, return default exclude from position files setting.
2116}
2117
2118
2119void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
2120{
2121 bool changed = false;
2122
2123 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2124 changed |= std::exchange( instance.m_Unit, aUnitSelection ) != aUnitSelection;
2125
2126 if( changed )
2128}
2129
2130
2131const wxString SCH_SYMBOL::GetValue( const SCH_SHEET_PATH* aInstance, RESOLUTION_CONTEXT aContext,
2132 const wxString& aVariantName ) const
2133{
2134 if( aVariantName.IsEmpty() || !aInstance )
2135 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aContext );
2136
2137 std::optional variant = GetVariant( *aInstance, aVariantName );
2138
2139 if( variant )
2140 {
2141 const wxString& fieldName = GetField( FIELD_T::VALUE )->GetName();
2142
2143 auto resolve =
2144 [&]( const wxString& aText ) -> wxString
2145 {
2146 std::function<bool( wxString* )> resolver =
2147 [&]( wxString* token ) -> bool
2148 {
2149 return ResolveTextVar( aInstance, token, aVariantName, 1 );
2150 };
2151
2152 return ExpandTextVars( aText, &resolver, aContext );
2153 };
2154
2155 if( variant->m_Fields.contains( fieldName ) )
2156 return resolve( variant->m_Fields[fieldName] );
2157
2158 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aInstance );
2159
2160 if( altSymbol )
2161 {
2162 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::VALUE );
2163
2164 if( altField && !altField->GetText().IsEmpty() )
2165 return resolve( altField->GetText() );
2166 }
2167 }
2168
2169 // Fall back to default value when variant doesn't have an override
2170
2171 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aContext, aVariantName );
2172}
2173
2174
2175void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance,
2176 const wxString& aVariantName )
2177{
2178 if( !aInstance || aVariantName.IsEmpty() )
2179 {
2180 GetField( FIELD_T::VALUE )->SetText( aValue );
2181 return;
2182 }
2183
2184 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
2185
2186 wxCHECK( instance, /* void */ );
2187
2188 wxString fieldName = GetField( FIELD_T::VALUE )->GetName();
2189
2190 if( instance->m_Variants.contains( aVariantName ) )
2191 {
2192 instance->m_Variants[aVariantName].m_Fields[fieldName] = aValue;
2193 }
2194 else
2195 {
2196 SCH_SYMBOL_VARIANT newVariant( aVariantName );
2197
2198 newVariant.InitializeAttributes( *this );
2199 newVariant.m_Fields[fieldName] = aValue;
2200 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
2201 }
2202}
2203
2204
2206 const wxString& aVariantName ) const
2207{
2208 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aContext, aVariantName );
2209
2210}
2211
2212
2213void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
2214{
2215 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
2216}
2217
2218
2220{
2221 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
2222 return field;
2223
2224 m_fields.emplace_back( this, aFieldType );
2225 return &m_fields.back();
2226}
2227
2228
2229const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
2230{
2231 return FindField( m_fields, aFieldType );
2232}
2233
2234
2235SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
2236{
2237 return FindField( m_fields, aFieldName );
2238}
2239
2240
2241const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
2242{
2243 return FindField( m_fields, aFieldName );
2244}
2245
2246
2247void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
2248{
2249 for( const SCH_FIELD& field : m_fields )
2250 {
2251 if( aVisibleOnly )
2252 {
2253 if( !field.IsVisible() || field.GetText().IsEmpty() )
2254 continue;
2255 }
2256
2257 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
2258 }
2259
2260 std::sort( aVector.begin(), aVector.end(),
2261 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
2262 {
2263 return lhs->GetOrdinal() < rhs->GetOrdinal();
2264 } );
2265}
2266
2267
2269{
2270 return NextFieldOrdinal( m_fields );
2271}
2272
2273
2275{
2276 m_fields.push_back( aField );
2277
2279
2280 return &m_fields.back();
2281}
2282
2283
2284void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
2285{
2286 // aFieldName may refer to the name owned by the field being removed.
2287 wxString fieldName = aFieldName;
2288
2289 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
2290 {
2291 if( m_fields[ii].IsMandatory() )
2292 continue;
2293
2294 if( fieldName == m_fields[ii].GetName( false ) )
2295 {
2296 m_fields.erase( m_fields.begin() + ii );
2297
2298 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2299 {
2300 for( auto& variant : instance.m_Variants )
2301 variant.second.m_Fields.erase( fieldName );
2302 }
2303
2305
2306 return;
2307 }
2308 }
2309}
2310
2311
2313{
2314 for( SCH_FIELD& field : m_fields )
2315 {
2316 if( field.GetName().IsSameAs( aFieldName, false ) )
2317 return &field;
2318 }
2319
2320 return nullptr;
2321}
2322
2323
2324const SCH_FIELD* SCH_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
2325{
2326 for( const SCH_FIELD& field : m_fields )
2327 {
2328 if( field.GetName().IsSameAs( aFieldName, false ) )
2329 return &field;
2330 }
2331
2332 return nullptr;
2333}
2334
2335
2336void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
2337 bool aResetRef, bool aResetOtherFields )
2338{
2339 if( m_part )
2340 {
2341 std::vector<SCH_FIELD*> fields;
2342 m_part->GetFields( fields );
2343
2344 for( const SCH_FIELD* libField : fields )
2345 {
2346 SCH_FIELD* schField;
2347 FIELD_T fieldType = FIELD_T::USER;
2348
2349 if( libField->IsMandatory() )
2350 {
2351 fieldType = libField->GetId();
2352 schField = GetField( fieldType );
2353 }
2354 else
2355 {
2356 schField = GetField( libField->GetUntranslatedName() );
2357
2358 if( !schField )
2359 {
2360 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetUntranslatedName() ) );
2361 schField->ImportValues( *libField );
2362 schField->SetTextPos( m_pos + libField->GetTextPos() );
2363 }
2364 }
2365
2366 schField->SetPrivate( libField->IsPrivate() );
2367
2368 if( aUpdateStyle )
2369 {
2370 schField->ImportValues( *libField );
2371 schField->SetTextPos( m_pos + libField->GetTextPos() );
2372 }
2373
2374 if( fieldType == FIELD_T::REFERENCE && aPath )
2375 {
2376 if( aResetRef )
2377 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
2378 else if( aUpdateRef )
2379 SetRef( aPath, libField->GetText() );
2380 }
2381 else if( fieldType == FIELD_T::VALUE )
2382 {
2383 SetValueFieldText( UnescapeString( libField->GetText() ) );
2384 }
2385 else if( fieldType == FIELD_T::DATASHEET )
2386 {
2387 if( aResetOtherFields )
2388 schField->SetText( GetDatasheet() ); // alias-specific value
2389 else if( aUpdateOtherFields )
2390 schField->SetText( libField->GetText() );
2391 }
2392 else
2393 {
2394 if( aResetOtherFields || aUpdateOtherFields )
2395 schField->SetText( libField->GetText() );
2396 }
2397 }
2398 }
2399}
2400
2401
2402void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit,
2403 PROPERTY_BASE* aProperty, const wxString& aVariantName )
2404{
2405 bool updateValue = true;
2406 bool updateExclFromBOM = true;
2407 bool updateExclFromBoard = true;
2408 bool updateExclFromPosFiles = true;
2409 bool updateDNP = true;
2410 bool updateOtherFields = true;
2411 bool updatePins = true;
2412 bool updatePinMapOverride = true;
2413
2414 if( aProperty )
2415 {
2416 updateValue = aProperty->Name() == _HKI( "Value" );
2417 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
2418 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
2419 updateExclFromPosFiles = aProperty->Name() == _HKI( "Exclude From Position Files" );
2420 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
2421 updatePinMapOverride = aProperty->Name() == wxS( "Pin Map Mode" ) || aProperty->Name() == wxS( "Pin Map Name" );
2422 updateOtherFields = false;
2423 updatePins = false;
2424 }
2425
2426 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateExclFromPosFiles && !updateDNP
2427 && !updateOtherFields && !updatePins && !updatePinMapOverride )
2428 {
2429 return;
2430 }
2431
2432 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
2433 // in sync in multi-unit parts.
2434 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
2435 {
2436 wxString ref = GetRef( &aSourceSheet );
2437
2438 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
2439 {
2440 SCH_SCREEN* screen = sheet.LastScreen();
2441 std::vector<SCH_SYMBOL*> otherUnits;
2442
2443 CollectOtherUnits( ref, GetUnitSelection( &aSourceSheet ), m_lib_id, sheet, &otherUnits );
2444
2445 for( SCH_SYMBOL* otherUnit : otherUnits )
2446 {
2447 aCommit.Modify( otherUnit, screen );
2448
2449 if( updateValue )
2450 {
2451 otherUnit->SetFieldText( GetField( FIELD_T::VALUE )->GetName(),
2452 GetValue( &aSourceSheet, RAW_VALUE, aVariantName ),
2453 &sheet, aVariantName );
2454 }
2455
2456 if( updateOtherFields )
2457 {
2458 for( SCH_FIELD& field : m_fields )
2459 {
2460 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
2461 {
2462 // already handled
2463 continue;
2464 }
2465
2466 SCH_FIELD* otherField;
2467
2468 if( field.IsMandatory() )
2469 otherField = otherUnit->GetField( field.GetId() );
2470 else
2471 otherField = otherUnit->GetField( field.GetName() );
2472
2473 if( otherField )
2474 {
2475 otherField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet, aVariantName );
2476 }
2477 else
2478 {
2479 SCH_FIELD newField( field );
2480 const_cast<KIID&>( newField.m_Uuid ) = KIID();
2481
2482 newField.Offset( -GetPosition() );
2483 newField.Offset( otherUnit->GetPosition() );
2484
2485 newField.SetParent( otherUnit );
2486 SCH_FIELD* addedField = otherUnit->AddField( newField );
2487
2488 if( !aVariantName.IsEmpty() )
2489 {
2490 addedField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet,
2491 aVariantName );
2492 }
2493 }
2494 }
2495
2496 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
2497 {
2498 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
2499
2500 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
2501 otherUnit->RemoveField( otherField.GetName() );
2502 }
2503 }
2504
2505 if( updateExclFromBOM )
2506 {
2507 otherUnit->SetExcludedFromBOM( GetExcludedFromBOM( &aSourceSheet, aVariantName ), &sheet,
2508 aVariantName );
2509 }
2510
2511 if( updateExclFromBoard )
2512 {
2513 otherUnit->SetExcludedFromBoard( GetExcludedFromBoard( &aSourceSheet, aVariantName ), &sheet,
2514 aVariantName );
2515 }
2516
2517 if( updateExclFromPosFiles )
2518 {
2519 otherUnit->SetExcludedFromPosFiles( GetExcludedFromPosFiles( &aSourceSheet, aVariantName ), &sheet,
2520 aVariantName );
2521 }
2522
2523 if( updateDNP )
2524 otherUnit->SetDNP( GetDNP( &aSourceSheet, aVariantName ), &sheet, aVariantName );
2525
2526 if( updatePinMapOverride )
2527 otherUnit->SetPinMapOverride( GetPinMapOverride( &aSourceSheet, aVariantName ), &sheet,
2528 aVariantName );
2529
2530 if( updatePins )
2531 {
2532 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
2533 {
2534 for( SCH_PIN* src_pin : otherUnit->GetPinsByNumber( model_pin->GetNumber() ) )
2535 src_pin->SetAlt( model_pin->GetAlt() );
2536 }
2537 }
2538 }
2539 }
2540 }
2541}
2542
2543
2544void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
2545{
2546 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2547 aFunction( pin.get() );
2548
2549 for( SCH_FIELD& field : m_fields )
2550 aFunction( &field );
2551}
2552
2553
2559
2560
2561SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
2562{
2563 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2564 {
2565 if( pin->GetNumber() == aNumber )
2566 return pin.get();
2567 }
2568
2569 return nullptr;
2570}
2571
2572
2573SCH_PIN* SCH_SYMBOL::GetPinByEffectivePadNumber( const wxString& aPadNumber, const SCH_SHEET_PATH* aSheet,
2574 const wxString& aVariantName ) const
2575{
2576 if( !aSheet )
2577 return nullptr;
2578
2579 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2580 {
2581 for( const wxString& pad : ExpandStackedPinNotation( pin->GetEffectivePadNumber( *aSheet, aVariantName ) ) )
2582 {
2583 if( pad == aPadNumber )
2584 return pin.get();
2585 }
2586 }
2587
2588 return nullptr;
2589}
2590
2591
2592std::vector<SCH_PIN*> SCH_SYMBOL::GetPinsByNumber( const wxString& aNumber ) const
2593{
2594 std::vector<SCH_PIN*> pins;
2595
2596 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2597 {
2598 if( pin->GetNumber() == aNumber )
2599 pins.push_back( pin.get() );
2600 }
2601
2602 return pins;
2603}
2604
2605
2606const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
2607{
2608 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2609 {
2610 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2611 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2612
2613 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
2614 continue;
2615
2616 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
2617 continue;
2618
2619 if( pin->GetPosition() == aPos )
2620 return pin.get();
2621 }
2622
2623 return nullptr;
2624}
2625
2626
2627std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
2628{
2629 if( m_part )
2630 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
2631
2632 return std::vector<SCH_PIN*>();
2633}
2634
2635
2636std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
2637{
2638 if( m_part )
2639 return m_part->GetGraphicalPins( ALL_UNITS, ALL_BODY_STYLES );
2640
2641 return std::vector<SCH_PIN*>();
2642}
2643
2644
2646{
2647 return m_part ? m_part->GetPinCount() : 0;
2648}
2649
2650
2652{
2653 auto it = m_pinMap.find( aLibPin );
2654
2655 if( it != m_pinMap.end() )
2656 return it->second;
2657
2658 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
2659 return nullptr;
2660}
2661
2662
2663std::vector<const SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
2664{
2665 std::vector<const SCH_PIN*> pins;
2666 int unit = m_unit;
2667
2668 if( !aSheet && Schematic() )
2669 aSheet = &Schematic()->CurrentSheet();
2670
2671 if( aSheet )
2672 unit = GetUnitSelection( aSheet );
2673
2674 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2675 {
2676 if( unit != ALL_UNITS && pin->GetUnit() != ALL_UNITS && pin->GetUnit() != unit )
2677 continue;
2678
2679 pins.push_back( pin.get() );
2680 }
2681
2682 return pins;
2683}
2684
2685
2686std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet )
2687{
2688 std::vector<SCH_PIN*> pins;
2689 int unit = m_unit;
2690
2691 if( !aSheet && Schematic() )
2692 aSheet = &Schematic()->CurrentSheet();
2693
2694 if( aSheet )
2695 unit = GetUnitSelection( aSheet );
2696
2697 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2698 {
2699 if( unit != ALL_UNITS && pin->GetUnit() != ALL_UNITS && pin->GetUnit() != unit )
2700 continue;
2701
2702 pins.push_back( pin.get() );
2703 }
2704
2705 return pins;
2706}
2707
2708
2709std::vector<SCH_PIN*> SCH_SYMBOL::GetGraphicalPins( int aUnit, int aBodyStyle ) const
2710{
2711 std::vector<SCH_PIN*> pins;
2712
2713 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2714 {
2715 // Unit filtering:
2716 if( aUnit != ALL_UNITS
2717 && pin->GetUnit() != ALL_UNITS
2718 && pin->GetUnit() != aUnit )
2719 {
2720 continue;
2721 }
2722
2723 // Body style filtering:
2724 if( aBodyStyle != ALL_BODY_STYLES
2725 && pin->GetBodyStyle() != ALL_BODY_STYLES
2726 && pin->GetBodyStyle() != aBodyStyle )
2727 {
2728 continue;
2729 }
2730
2731 pins.push_back( pin.get() );
2732 }
2733
2734 return pins;
2735}
2736
2737
2739{
2740 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
2741
2742 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
2743
2744 std::swap( m_pos, symbol->m_pos );
2745 std::swap( m_lib_id, symbol->m_lib_id );
2746 std::swap( m_prefix, symbol->m_prefix );
2747
2748 {
2749 m_pins.swap( symbol->m_pins ); // std::vector's swap()
2750
2751 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
2752 pin->SetParent( symbol );
2753
2754 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2755 pin->SetParent( this );
2756 }
2757
2758 LIB_SYMBOL* libSymbol = symbol->m_part.release();
2759 symbol->m_part = std::move( m_part );
2760 symbol->UpdatePins();
2761 m_part.reset( libSymbol );
2762 UpdatePins();
2763
2764 {
2765 m_fields.swap( symbol->m_fields ); // std::vector's swap()
2766
2767 for( SCH_FIELD& field : symbol->m_fields )
2768 field.SetParent( symbol );
2769
2770 for( SCH_FIELD& field : m_fields )
2771 field.SetParent( this );
2772 }
2773
2774 TRANSFORM tmp = m_transform;
2775 m_transform = symbol->m_transform;
2776 symbol->m_transform = tmp;
2777
2778 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
2779 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
2780 std::swap( m_DNP, symbol->m_DNP );
2781 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
2782 std::swap( m_excludedFromPosFiles, symbol->m_excludedFromPosFiles );
2783 std::swap( m_pinMapOverride, symbol->m_pinMapOverride );
2784
2785 std::swap( m_instances, symbol->m_instances );
2786 std::swap( m_instancePathIndex, symbol->m_instancePathIndex );
2787 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
2788 std::swap( m_doNetlist, symbol->m_doNetlist );
2789 std::swap( m_passthroughMode, symbol->m_passthroughMode );
2790 std::swap( m_signalName, symbol->m_signalName );
2791
2792 m_variantSymbolCache.clear();
2793 symbol->m_variantSymbolCache.clear();
2794}
2795
2796
2797void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
2798{
2799 for( const SCH_FIELD& field : m_fields )
2800 {
2801 if( field.IsPrivate() )
2802 continue;
2803
2804 if( field.IsMandatory() )
2805 aVars->push_back( field.GetUntranslatedName().Upper() );
2806 else
2807 aVars->push_back( field.GetName() );
2808 }
2809
2810 aVars->push_back( wxT( "OP" ) );
2811 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
2812 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
2813 aVars->push_back( wxT( "UNIT" ) );
2814 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
2815 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
2816 aVars->push_back( wxT( "SYMBOL_NAME" ) );
2817 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
2818 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
2819 aVars->push_back( wxT( "SYMBOL_IS_POWER" ) );
2820 aVars->push_back( wxT( "SYMBOL_IS_LOCAL_POWER" ) );
2821 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
2822 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
2823 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
2824 aVars->push_back( wxT( "DNP" ) );
2825 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
2826 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
2827 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
2828 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
2829 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
2830 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
2831 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
2832}
2833
2834
2835bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
2836{
2837 wxString variant;
2838
2839 if( Schematic() )
2840 variant = Schematic()->GetCurrentVariant();
2841
2842 return ResolveTextVar( aPath, token, variant, aDepth );
2843}
2844
2845
2846bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, const wxString& aVariantName,
2847 int aDepth ) const
2848{
2849 // Per-thread regex. CONNECTION_GRAPH::resolveAllDrivers calls this from worker
2850 // threads, and wxRegEx::Matches is not safe to call concurrently on one instance.
2851 thread_local wxRegEx operatingPoint( wxT( "^"
2852 "OP"
2853 "(:[^.]*)?" // pin
2854 "(.([0-9])?" // precisionStr
2855 "([a-zA-Z]*))?" // rangeStr
2856 "$" ) );
2857
2858 if( !aPath )
2859 return false;
2860
2862
2863 if( !schematic )
2864 return false;
2865
2867 && ( operatingPoint.Matches( *token ) || token->StartsWith( wxS( "NET_NAME(" ) )
2868 || token->StartsWith( wxS( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxS( "NET_CLASS(" ) ) ) )
2869 {
2870 token->clear();
2871 return true;
2872 }
2873
2874 if( operatingPoint.Matches( *token ) )
2875 {
2876 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
2877 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
2878 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
2879
2880 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
2881 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
2882
2883 SIM_LIB_MGR simLibMgr( &schematic->Project() );
2884
2885 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
2886 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
2887
2888 if( m_part )
2889 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
2890
2891 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
2892
2893 NULL_REPORTER devnull;
2894 SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1,
2895 aVariantName, devnull ).model;
2896 SPICE_ITEM spiceItem;
2897 spiceItem.refName = GetRef( aPath );
2898
2899 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
2900 spiceRef = spiceRef.Lower();
2901
2902 if( pin.IsEmpty() )
2903 {
2904 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2905 return true;
2906 }
2907 else if( pin == wxS( ":power" ) )
2908 {
2909 if( rangeStr.IsEmpty() )
2910 range = wxS( "~W" );
2911
2912 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
2913 return true;
2914 }
2915 else
2916 {
2917 pin = pin.SubString( 1, -1 ); // Strip ':' from front
2918
2919 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
2920 {
2921 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
2922
2923 if( !symbolPin )
2924 continue;
2925
2926 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
2927 {
2928 if( model.GetPins().size() == 2 )
2929 {
2930 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2931 }
2932 else
2933 {
2934 wxString netChainName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
2935 *token = schematic->GetOperatingPoint( netChainName, precision, range );
2936 }
2937
2938 return true;
2939 }
2940 }
2941 }
2942
2943 *token = wxS( "?" );
2944 return true;
2945 }
2946
2947 if( token->Contains( ':' ) )
2948 {
2949 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
2950 return true;
2951 }
2952
2953 for( const SCH_FIELD& field : m_fields )
2954 {
2955 wxString fieldName = field.IsMandatory() ? field.GetUntranslatedName() : field.GetName();
2956
2957 wxString textToken = field.GetText();
2958 textToken.Replace( " ", wxEmptyString );
2959 wxString tokenString = "${" + fieldName + "}";
2960
2961 // If the field data is just a reference to the field, don't resolve
2962 if( textToken.IsSameAs( tokenString, false ) )
2963 return true;
2964
2965 if( token->IsSameAs( fieldName, false ) )
2966 {
2967 if( field.GetId() == FIELD_T::REFERENCE )
2968 *token = GetRef( aPath, true );
2969 else
2970 *token = field.GetShownText( aPath, INTERNAL, aVariantName, aDepth + 1 );
2971
2972 return true;
2973 }
2974 }
2975
2976 // Consider missing simulation fields as empty, not un-resolved
2977 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
2978 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
2979 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
2980 {
2981 *token = wxEmptyString;
2982 return true;
2983 }
2984
2985 for( const TEMPLATE_FIELDNAME& templateFieldname :
2986 schematic->Project().GetProjectFile().m_TemplateFieldNames.GetResolvedTemplateFieldNames() )
2987 {
2988 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
2989 {
2990 // If we didn't find it in the fields list then it isn't set on this symbol.
2991 // Just return an empty string.
2992 *token = wxEmptyString;
2993 return true;
2994 }
2995 }
2996
2997 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
2998 {
2999 wxString footprint = GetFootprintFieldText( aPath, INTERNAL, aVariantName );
3000
3001 wxArrayString parts = wxSplit( footprint, ':' );
3002
3003 if( parts.Count() > 0 )
3004 *token = parts[0];
3005 else
3006 *token = wxEmptyString;
3007
3008 return true;
3009 }
3010 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
3011 {
3012 wxString footprint = GetFootprintFieldText( aPath, INTERNAL, aVariantName );
3013
3014 wxArrayString parts = wxSplit( footprint, ':' );
3015
3016 if( parts.Count() > 1 )
3017 *token = parts[std::min( 1, (int) parts.size() - 1 )];
3018 else
3019 *token = wxEmptyString;
3020
3021 return true;
3022 }
3023 else if( token->IsSameAs( wxT( "UNIT" ) ) )
3024 {
3025 *token = SubReference( GetUnitSelection( aPath ) );
3026 return true;
3027 }
3028 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
3029 {
3030 *token = GetRef( aPath, false );
3031 return true;
3032 }
3033 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
3034 {
3035 *token = m_lib_id.GetUniStringLibNickname();
3036 return true;
3037 }
3038 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
3039 {
3040 *token = m_lib_id.GetUniStringLibItemName();
3041 return true;
3042 }
3043 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
3044 {
3045 *token = GetShownDescription( INTERNAL, aDepth + 1 );
3046 return true;
3047 }
3048 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
3049 {
3050 *token = GetShownKeyWords( INTERNAL, aDepth + 1 );
3051 return true;
3052 }
3053 else if( token->IsSameAs( wxT( "SYMBOL_IS_POWER" ) ) )
3054 {
3055 *token = this->IsPower() ? wxString( wxS( "Power Symbol" ) ) : wxString( "" );
3056 return true;
3057 }
3058 else if( token->IsSameAs( wxT( "SYMBOL_IS_LOCAL_POWER" ) ) )
3059 {
3060 *token = this->IsLocalPower() ? wxString( wxS( "Local Power Symbol" ) ) : wxString( "" );
3061 return true;
3062 }
3063 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
3064 {
3065 *token = wxEmptyString;
3066
3067 if( aPath->GetExcludedFromBOM( aVariantName ) || this->ResolveExcludedFromBOM( aPath, aVariantName ) )
3068 *token = wxS( "Excluded from BOM" );
3069
3070 return true;
3071 }
3072 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
3073 {
3074 *token = wxEmptyString;
3075
3076 if( aPath->GetExcludedFromBoard( aVariantName ) || this->ResolveExcludedFromBoard( aPath, aVariantName ) )
3077 *token = wxS( "Excluded from board" );
3078
3079 return true;
3080 }
3081 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
3082 {
3083 *token = wxEmptyString;
3084
3085 if( aPath->GetExcludedFromSim( aVariantName ) || this->ResolveExcludedFromSim( aPath, aVariantName ) )
3086 *token = wxS( "Excluded from simulation" );
3087
3088 return true;
3089 }
3090 else if( token->IsSameAs( wxT( "DNP" ) ) )
3091 {
3092 *token = wxEmptyString;
3093
3094 if( aPath->GetDNP( aVariantName ) || this->ResolveDNP( aPath, aVariantName ) )
3095 *token = wxS( "DNP" );
3096
3097 return true;
3098 }
3099 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
3100 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
3101 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
3102 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
3103 || token->StartsWith( wxT( "UNIT(" ) ) )
3104 {
3105 wxString pinNumber = token->AfterFirst( '(' );
3106 pinNumber = pinNumber.BeforeLast( ')' );
3107
3108 auto resolvePinConnection =
3109 [&]( const SCH_PIN& pin, const SCH_SHEET_PATH& path )
3110 {
3111 const bool local = token->StartsWith( wxS( "SHORT_NET_NAME" ) );
3112 const auto name = pin.GetConnectionName( &path, local );
3113
3114 if( !name )
3115 {
3116 token->clear();
3117 return;
3118 }
3119
3120 if( local )
3121 *token = name->Lower().StartsWith( wxS( "unconnected" ) ) ? wxString( "NC" ) : *name;
3122 else if( token->StartsWith( wxS( "NET_NAME" ) ) )
3123 *token = *name;
3124 else if( token->StartsWith( wxS( "NET_CLASS" ) ) )
3125 *token = pin.GetEffectiveNetClass( &path )->GetName();
3126 };
3127
3128 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
3129 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
3130 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
3131
3132 // First, try to find the pin in the current unit (for backward compatibility)
3133 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
3134 std::vector<const SCH_PIN*> pinsToSearch;
3135 std::vector<const SCH_PIN*> altPinsToSearch;
3136
3137 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
3138 {
3139 for( SCH_PIN* pin : GetAllLibPins() )
3140 pinsToSearch.push_back( pin );
3141 }
3142 else
3143 {
3144 for( const SCH_PIN* pin : GetPins( aPath ) )
3145 pinsToSearch.push_back( pin );
3146
3147 for( SCH_PIN* pin : GetAllLibPins() )
3148 altPinsToSearch.push_back( pin );
3149 }
3150
3151 for( const SCH_PIN* pin : pinsToSearch )
3152 {
3153 if( pin->GetNumber() == pinNumber )
3154 {
3155 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
3156 {
3157 int pinUnit = pin->GetUnit();
3158 wxString result;
3159
3160 if( isReferenceFunction )
3161 {
3162 // Return the full unit reference (e.g., "J601A")
3163 if( pinUnit != ALL_UNITS )
3164 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
3165 else
3166 result = GetRef( aPath, false );
3167 }
3168 else if( isShortReferenceFunction )
3169 {
3170 // Return the reference without unit (e.g., "J601")
3171 result = GetRef( aPath, false );
3172 }
3173 else if( isUnitFunction )
3174 {
3175 // Return only the unit letter (e.g., "A")
3176 if( pinUnit != ALL_UNITS )
3177 result = SubReference( pinUnit, false );
3178 else
3179 result = wxEmptyString;
3180 }
3181
3182 *token = std::move( result );
3183 return true;
3184 }
3185 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
3186 {
3187 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
3188 return true;
3189 }
3190 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
3191 {
3192 *token = pin->GetBaseName();
3193 return true;
3194 }
3195 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
3196 {
3197 // Build list of alternate names only (no base name)
3198 wxString altList;
3199
3200 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
3201
3202 for( const auto& [altName, altDef] : alts )
3203 {
3204 if( !altList.IsEmpty() )
3205 altList += wxT( ", " );
3206
3207 altList += altName;
3208 }
3209
3210 *token = std::move( altList );
3211 return true;
3212 }
3213
3214 resolvePinConnection( *pin, *aPath );
3215
3216 return true;
3217 }
3218 }
3219
3220 // If pin not found in current unit, search all units (auto-resolution)
3221 for( const SCH_PIN* pin : altPinsToSearch )
3222 {
3223 if( pin->GetNumber() == pinNumber )
3224 {
3225 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
3226 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
3227 {
3228 *token = pin->GetBaseName();
3229 return true;
3230 }
3231 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
3232 {
3233 // Build list of alternate names only (no base name)
3234 wxString altList;
3235
3236 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
3237
3238 for( const auto& [altName, altDef] : alts )
3239 {
3240 if( !altList.IsEmpty() )
3241 altList += wxT( ", " );
3242 altList += altName;
3243 }
3244
3245 *token = altList;
3246 return true;
3247 }
3248
3249 // For net-related functions, find which sheet path has this pin's unit
3250 int pinUnit = pin->GetUnit();
3251
3252 // Search all sheets for a symbol with our reference and the correct unit
3253 // This is needed because each unit of a multi-unit symbol is a separate object
3254 SCH_SHEET_PATH targetPath;
3255 SCH_SYMBOL* targetSymbol = nullptr;
3256
3257 if( Schematic() )
3258 {
3259 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
3260 {
3261 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
3262 {
3263 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
3264
3265 // Check if this symbol has the same reference designator and the correct unit
3266 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
3267 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
3268 {
3269 targetPath = sheetPath; // Copy the sheet path
3270 targetSymbol = symbol;
3271 break;
3272 }
3273 }
3274
3275 if( targetSymbol )
3276 break;
3277 }
3278 }
3279
3280 if( !targetSymbol )
3281 {
3282 // Unit not placed on any sheet
3283 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
3284 return true;
3285 }
3286
3287 // Get the pin from the actual instance symbol we found
3288 // Match by pin number, not by pointer, since the library pins are different objects
3289 SCH_PIN* instancePin = nullptr;
3290
3291 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
3292 {
3293 if( candidate->GetNumber() == pinNumber )
3294 {
3295 instancePin = candidate;
3296 break;
3297 }
3298 }
3299
3300 if( !instancePin )
3301 {
3302 *token = wxEmptyString;
3303 return true;
3304 }
3305
3306 // PIN_NAME doesn't need connection data, just instance pin
3307 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
3308 {
3309 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
3310 return true;
3311 }
3312
3313 resolvePinConnection( *instancePin, targetPath );
3314
3315 return true;
3316 }
3317 }
3318
3319 // If we got here, no pin was found - report unresolved
3320 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
3321 return true;
3322 }
3323 // The great property resolver: ${PROPERTY.My_Property}
3324 else if( token->StartsWith( wxS( "PROPERTY." ) ) )
3325 {
3326 // Get the second half, convert _ to ' '
3327 wxString propertyName = token->AfterFirst( '.' );
3328 propertyName.Replace( wxS( "_" ), wxS( " " ) );
3329
3330 // Check if the property manager knows this property
3332 PROPERTY_BASE* property = propMgr.GetProperty( TYPE_HASH( *this ), propertyName );
3333
3334 if( !property )
3335 {
3336 for( PROPERTY_BASE* candidate : GetDynamicProperties( aPath ) )
3337 {
3338 if( propertyName.CmpNoCase( candidate->Name() ) == 0 )
3339 {
3340 property = candidate;
3341 break;
3342 }
3343 }
3344 }
3345
3346 if( !property || property->IsHiddenFromPropertiesManager() )
3347 return false;
3348
3349 if( !propMgr.IsAvailableFor( TYPE_HASH( *this ), property, const_cast<SCH_SYMBOL*>( this ) ) )
3350 return false;
3351
3352 // Property-panel getters use the displayed instance, which may differ from this text's path.
3353 wxAny sourceValue;
3354 const wxString& name = property->Name();
3355
3356 if( name == wxS( "Reference" ) )
3357 sourceValue = GetRef( aPath );
3358 else if( name == wxS( "Value" ) )
3359 sourceValue = GetValue( aPath, RAW_VALUE, aVariantName );
3360 else if( name == wxS( "Unit" ) )
3361 sourceValue = GetUnitSelection( aPath );
3362 else if( name == wxS( "Exclude From Simulation" ) )
3363 sourceValue = GetExcludedFromSim( aPath, aVariantName );
3364 else if( name == wxS( "Exclude From Bill of Materials" ) )
3365 sourceValue = GetExcludedFromBOM( aPath, aVariantName );
3366 else if( name == wxS( "Exclude From Board" ) )
3367 sourceValue = GetExcludedFromBoard( aPath, aVariantName );
3368 else if( name == wxS( "Exclude From Position Files" ) )
3369 sourceValue = GetExcludedFromPosFiles( aPath, aVariantName );
3370 else if( name == wxS( "Do not Populate" ) )
3371 sourceValue = GetDNP( aPath, aVariantName );
3372 else if( auto* instanceProperty = dynamic_cast<SCH_SYMBOL_INSTANCE_PROPERTY*>( property ) )
3373 sourceValue = instanceProperty->ValueForInstance( this, aPath, aVariantName );
3374 else
3375 sourceValue = Get( property );
3376
3377 KICAD_DIFF::DIFF_VALUE value = KICAD_DIFF::WxAnyToDiffValue( sourceValue, property );
3378
3380 return false;
3381
3382 *token = value.ToDisplayString( EDA_UNITS::MILS, schIUScale );
3383 return true;
3384 }
3385
3386 // See if parent can resolve it (this will recurse to ancestors)
3387 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
3388 return true;
3389
3390 return false;
3391}
3392
3393
3394void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
3395{
3396 if( aSheetPath )
3397 {
3398 KIID_PATH path = aSheetPath->Path();
3399
3400 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3401 {
3402 if( instance.m_Path == path )
3403 {
3404 if( instance.m_Reference.IsEmpty() || aResetPrefix )
3405 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
3406 else
3407 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
3408 }
3409 }
3410 }
3411 else
3412 {
3413 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3414 {
3415 if( instance.m_Reference.IsEmpty() || aResetPrefix )
3416 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
3417 else
3418 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
3419 }
3420 }
3421
3422 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3423 pin->ClearDefaultNetName( aSheetPath );
3424
3425 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
3426 // When clearing for a specific sheet path, we must preserve the field text because it serves
3427 // as a fallback for GetRef() when instances for other sheet paths are looked up.
3428 // See issue #20173: modifying field text here corrupts references in shared screens.
3429 if( !aSheetPath )
3430 {
3431 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
3432
3433 if( currentReference.IsEmpty() || aResetPrefix )
3435 else
3437 }
3438}
3439
3440
3442{
3443 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
3444 wxCHECK( aSheetPath.size() > 0, false );
3445
3446 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
3447 {
3448 // if aSheetPath is found, nothing to do:
3449 if( instance.m_Path == aSheetPath )
3450 return false;
3451 }
3452
3453 // This entry does not exist: add it, with its last-used reference
3454 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
3455 return true;
3456}
3457
3458
3459bool SCH_SYMBOL::SetInstanceProjectName( const KIID_PATH& aSheetPath, const wxString& aProjectName )
3460{
3461 SCH_SYMBOL_INSTANCE* instance = getInstance( aSheetPath );
3462
3463 if( !instance )
3464 return false;
3465
3466 instance->m_ProjectName = aProjectName;
3467 return true;
3468}
3469
3470
3471void SCH_SYMBOL::SetOrientation( int aOrientation )
3472{
3473 TRANSFORM temp = TRANSFORM();
3474 bool transform = false;
3475
3476 switch( aOrientation )
3477 {
3478 case SYM_ORIENT_0:
3479 case SYM_NORMAL: // default transform matrix
3481 break;
3482
3483 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
3484 temp.x1 = 0;
3485 temp.y1 = 1;
3486 temp.x2 = -1;
3487 temp.y2 = 0;
3488 transform = true;
3489 break;
3490
3491 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
3492 temp.x1 = 0;
3493 temp.y1 = -1;
3494 temp.x2 = 1;
3495 temp.y2 = 0;
3496 transform = true;
3497 break;
3498
3499 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
3500 temp.x1 = -1;
3501 temp.y1 = 0;
3502 temp.x2 = 0;
3503 temp.y2 = 1;
3504 transform = true;
3505 break;
3506
3507 case SYM_MIRROR_X: // Mirror X (incremental transform)
3508 temp.x1 = 1;
3509 temp.y1 = 0;
3510 temp.x2 = 0;
3511 temp.y2 = -1;
3512 transform = true;
3513 break;
3514
3515 case SYM_ORIENT_90:
3518 break;
3519
3520 case SYM_ORIENT_180:
3524 break;
3525
3526 case SYM_ORIENT_270:
3529 break;
3530
3531 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
3534 break;
3535
3536 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
3539 break;
3540
3545 break;
3546
3547 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
3550 break;
3551
3552 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
3555 break;
3556
3561 break;
3562
3563 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
3566 break;
3567
3568 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
3571 break;
3572
3577 break;
3578
3579 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
3582 break;
3583
3584 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
3587 break;
3588
3593 break;
3594
3595 default:
3596 transform = false;
3597 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
3598 break;
3599 }
3600
3601 if( transform )
3602 {
3603 /* The new matrix transform is the old matrix transform modified by the
3604 * requested transformation, which is the temp transform (rot,
3605 * mirror ..) in order to have (in term of matrix transform):
3606 * transform coord = new_m_transform * coord
3607 * where transform coord is the coord modified by new_m_transform from
3608 * the initial value coord.
3609 * new_m_transform is computed (from old_m_transform and temp) to
3610 * have:
3611 * transform coord = old_m_transform * temp
3612 */
3613 TRANSFORM newTransform;
3614
3615 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
3616 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
3617 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
3618 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
3619 m_transform = newTransform;
3620 }
3621}
3622
3623
3625{
3626 /*
3627 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
3628 * now, so let's just cache it for the moment.
3629 */
3632
3633 int rotate_values[] = { SYM_ORIENT_0,
3645
3646 // Try to find the current transform option:
3647 TRANSFORM transform = m_transform;
3648 SCH_SYMBOL temp( *this );
3649 temp.SetParentGroup( nullptr );
3650
3651 for( int type_rotate : rotate_values )
3652 {
3653 temp.SetOrientation( type_rotate );
3654
3655 if( transform == temp.GetTransform() )
3656 {
3658 return type_rotate;
3659 }
3660 }
3661
3662 // Error: orientation not found in list (should not happen)
3663 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
3664
3665 return SYM_NORMAL;
3666}
3667
3668
3669#if defined( DEBUG )
3670
3671void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
3672{
3673 // for now, make it look like XML:
3674 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
3675 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
3676 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
3677 << ">\n";
3678
3679 // skip the reference, it's been output already.
3680 for( int i = 1; i < (int) GetFields().size(); ++i )
3681 {
3682 const wxString& value = GetFields()[i].GetText();
3683
3684 if( !value.IsEmpty() )
3685 {
3686 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
3687 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
3688 }
3689 }
3690
3691 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
3692}
3693
3694#endif
3695
3696
3697BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
3698{
3699 BOX2I bBox;
3700 const SCH_SHEET_PATH* sheetPath = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
3701 const LIB_SYMBOL* effSym = GetEffectiveLibSymbol( sheetPath );
3702
3703 if( effSym )
3704 bBox = effSym->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3705 else
3706 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3707
3708 bBox = m_transform.TransformCoordinate( bBox );
3709 bBox.Normalize();
3710
3711 bBox.Offset( m_pos );
3712
3713 if( aIncludeFields )
3714 {
3715 for( const SCH_FIELD& field : m_fields )
3716 {
3717 if( field.IsVisible() )
3718 bBox.Merge( field.GetBoundingBox() );
3719 }
3720 }
3721
3722 return bBox;
3723}
3724
3725
3727{
3728 try
3729 {
3730 return doGetBoundingBox( false, false );
3731 }
3732 catch( const boost::bad_pointer& e )
3733 {
3734 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
3735 return BOX2I();
3736 }
3737}
3738
3739
3741{
3742 return doGetBoundingBox( true, false );
3743}
3744
3745
3747{
3748 return doGetBoundingBox( true, true );
3749}
3750
3751
3752void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
3753{
3754 wxString msg;
3755
3756 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
3757 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
3758 wxString currentVariant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
3759
3760 auto addExcludes = [&]()
3761 {
3762 wxArrayString msgs;
3763
3764 if( GetExcludedFromSim() )
3765 msgs.Add( _( "Simulation" ) );
3766
3767 if( GetExcludedFromBOM() )
3768 msgs.Add( _( "BOM" ) );
3769
3770 if( GetExcludedFromBoard() )
3771 msgs.Add( _( "Board" ) );
3772
3773 if( GetDNP( currentSheet, currentVariant ) )
3774 msgs.Add( _( "DNP" ) );
3775
3776 msg = wxJoin( msgs, '|' );
3777 msg.Replace( '|', wxS( ", " ) );
3778
3779 if( !msg.empty() )
3780 aList.emplace_back( _( "Exclude from" ), msg );
3781 };
3782
3783 // part and alias can differ if alias is not the root
3784 if( m_part )
3785 {
3786 if( m_part.get() != LIB_SYMBOL::GetDummy() )
3787 {
3788 if( m_part->IsPower() )
3789 {
3790 // Don't use GetShownText(); we want to see the variable references here
3791 aList.emplace_back( _( "Power symbol" ),
3792 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3793 }
3794 else
3795 {
3796 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
3797
3798 // Don't use GetShownText(); we want to see the variable references here
3799 aList.emplace_back( _( "Value" ),
3800 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3801 addExcludes();
3802 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3803 }
3804
3805#if 0 // Display symbol flags, for debug only
3806 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
3807#endif
3808
3809 if( !m_part->IsRoot() )
3810 {
3811 msg = _( "Missing parent" );
3812
3813 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
3814
3815 if( parent )
3816 msg = parent->GetName();
3817
3818 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
3819 }
3820 else if( !m_lib_id.GetLibNickname().empty() )
3821 {
3822 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
3823 }
3824 else
3825 {
3826 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
3827 }
3828
3829 // Display the current associated footprint, if exists.
3830 // Don't use GetShownText(); we want to see the variable references here
3831 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
3832
3833 if( msg.IsEmpty() )
3834 msg = _( "<Unknown>" );
3835
3836 aList.emplace_back( _( "Footprint" ), msg );
3837
3838 // Display description of the symbol, and keywords found in lib
3839 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
3840 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
3841 }
3842 }
3843 else
3844 {
3845 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
3846
3847 // Don't use GetShownText(); we want to see the variable references here
3848 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3849 addExcludes();
3850 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3851
3852 wxString libNickname = GetLibId().GetLibNickname();
3853
3854 if( libNickname.empty() )
3855 msg = _( "No library defined!" );
3856 else
3857 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
3858
3859 aList.emplace_back( _( "Library" ), msg );
3860 }
3861}
3862
3863
3868
3869
3871{
3872 if( std::unique_ptr<LIB_SYMBOL>& libSymbol = GetLibSymbolRef() )
3873 return libSymbol->GetEmbeddedFiles();
3874
3875 return nullptr;
3876}
3877
3878
3880{
3881 int dx = m_pos.x;
3882
3884 MIRROR( m_pos.x, aCenter );
3885 dx -= m_pos.x; // dx,0 is the move vector for this transform
3886
3887 for( SCH_FIELD& field : m_fields )
3888 {
3889 // Move the fields to the new position because the symbol itself has moved.
3890 VECTOR2I pos = field.GetTextPos();
3891 pos.x -= dx;
3892 field.SetTextPos( pos );
3893 }
3894}
3895
3896
3898{
3899 int dy = m_pos.y;
3900
3902 MIRROR( m_pos.y, aCenter );
3903 dy -= m_pos.y; // 0,dy is the move vector for this transform
3904
3905 for( SCH_FIELD& field : m_fields )
3906 {
3907 // Move the fields to the new position because the symbol itself has moved.
3908 VECTOR2I pos = field.GetTextPos();
3909 pos.y -= dy;
3910 field.SetTextPos( pos );
3911 }
3912}
3913
3914
3915void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
3916{
3917 VECTOR2I prev = m_pos;
3918
3919 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
3920
3922
3923 for( SCH_FIELD& field : m_fields )
3924 {
3925 // Move the fields to the new position because the symbol itself has moved.
3926 VECTOR2I pos = field.GetTextPos();
3927 pos.x -= prev.x - m_pos.x;
3928 pos.y -= prev.y - m_pos.y;
3929 field.SetTextPos( pos );
3930 }
3931}
3932
3933
3934bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
3935{
3936 if( aSearchData.searchMetadata )
3937 {
3938 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
3939 return true;
3940
3941 if( EDA_ITEM::Matches( GetShownDescription( FOR_GUI ), aSearchData ) )
3942 return true;
3943
3944 if( EDA_ITEM::Matches( GetShownKeyWords( FOR_GUI ), aSearchData ) )
3945 return true;
3946 }
3947
3948 // Fields are searched as separate items
3949
3950 // Search non-field lib draw items (pins, graphical text) for completeness.
3951 if( const std::unique_ptr<LIB_SYMBOL>& libSymbol = GetLibSymbolRef() )
3952 {
3953 for( const SCH_ITEM& drawItem : libSymbol->GetDrawItems() )
3954 {
3955 if( drawItem.Type() == SCH_FIELD_T )
3956 continue;
3957
3958 if( drawItem.Matches( aSearchData, aAuxData ) )
3959 return true;
3960 }
3961 }
3962
3963 // Symbols are searchable via the child field and pin item text.
3964 return false;
3965}
3966
3967
3968void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
3969{
3970 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3971 {
3972 if( SCH_PIN* lib_pin = pin->GetLibPin() )
3973 {
3974 if( lib_pin->GetUnit() != ALL_UNITS && m_unit != ALL_UNITS && m_unit != lib_pin->GetUnit() )
3975 continue;
3976
3977 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
3978 aItemList.push_back( item );
3979 }
3980 }
3981}
3982
3983
3984bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
3985 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
3986{
3987 bool changed = false;
3988
3989 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3990 {
3991 bool previousState = pin->IsDangling();
3992 pin->SetIsDangling( true );
3993
3994 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
3995
3996 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
3997 bool do_break = false;
3998
3999 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
4000 {
4001 DANGLING_END_ITEM& each_item = *it;
4002
4003 // Some people like to stack pins on top of each other in a symbol to indicate
4004 // internal connection. While technically connected, it is not particularly useful
4005 // to display them that way, so skip any pins that are in the same symbol as this
4006 // one.
4007 if( each_item.GetParent() == this )
4008 continue;
4009
4010 switch( each_item.GetType() )
4011 {
4012 case PIN_END:
4013 case LABEL_END:
4014 case SHEET_LABEL_END:
4015 case WIRE_END:
4016 case NO_CONNECT_END:
4017 case JUNCTION_END:
4018 pin->SetIsDangling( false );
4019 do_break = true;
4020 break;
4021
4022 default: break;
4023 }
4024
4025 if( do_break )
4026 break;
4027 }
4028
4029 changed = ( changed || ( previousState != pin->IsDangling() ) );
4030 }
4031
4032 return changed;
4033}
4034
4035
4037{
4038 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
4039 return VECTOR2I( 0, 0 );
4040
4041 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
4042}
4043
4044
4045bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
4046{
4047 // Do not compare to ourself.
4048 if( aItem == this )
4049 return false;
4050
4051 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
4052
4053 // Don't compare against a different SCH_ITEM.
4054 wxCHECK( symbol, false );
4055
4056 // The move algorithm marks any pins that are being moved without something attached
4057 // (during the move) as dangling. We always need to recheck connectivity in this case
4058 // or we will not notice changes when the user places the symbol back in the same position
4059 // it started.
4060 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4061 {
4062 if( pin->IsDangling() )
4063 return true;
4064 }
4065
4066 if( GetPosition() != symbol->GetPosition() )
4067 return true;
4068
4069 if( GetLibId() != symbol->GetLibId() )
4070 return true;
4071
4072 if( GetPassthroughMode() != symbol->GetPassthroughMode() )
4073 return true;
4074
4075 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
4076 return true;
4077
4078 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
4079 return true;
4080
4081 // Power symbol value field changes are connectivity changes.
4082 if( IsPower() && ( GetValue( aInstance, FOR_NETNAME ) != symbol->GetValue( aInstance, FOR_NETNAME ) ) )
4083 return true;
4084
4085 if( m_pins.size() != symbol->m_pins.size() )
4086 return true;
4087
4088 for( size_t i = 0; i < m_pins.size(); i++ )
4089 {
4090 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
4091 return true;
4092 }
4093
4094 return false;
4095}
4096
4097
4098std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
4099{
4100 std::vector<VECTOR2I> retval;
4101
4102 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4103 {
4104 // Collect only pins attached to the current unit and convert.
4105 // others are not associated to this symbol instance
4106 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4107 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4108
4109 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4110 continue;
4111
4112 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4113 continue;
4114
4115 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
4116 }
4117
4118 return retval;
4119}
4120
4121
4123{
4124 const SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4125 LIB_SYMBOL* effectiveSymbol = const_cast<LIB_SYMBOL*>( GetEffectiveLibSymbol( sheet ) );
4126
4127 if( effectiveSymbol )
4128 {
4129 // Calculate the position relative to the symbol.
4130 VECTOR2I libPosition = aPosition - m_pos;
4131
4132 return effectiveSymbol->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
4133 }
4134
4135 return nullptr;
4136}
4137
4138
4139wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
4140{
4141 return wxString::Format( _( "Symbol %s [%s]" ),
4143 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
4144}
4145
4146
4147INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
4148{
4149 for( KICAD_T scanType : aScanTypes )
4150 {
4151 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
4152 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
4153 {
4154 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
4155 return INSPECT_RESULT::QUIT;
4156 }
4157
4158 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
4159 {
4160 for( SCH_FIELD& field : m_fields )
4161 {
4162 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
4163 return INSPECT_RESULT::QUIT;
4164 }
4165 }
4166
4167 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
4168 {
4169 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
4170 return INSPECT_RESULT::QUIT;
4171 }
4172
4173 if( scanType == SCH_FIELD_LOCATE_VALUE_T
4174 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
4175 {
4176 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
4177 return INSPECT_RESULT::QUIT;
4178 }
4179
4180 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
4181 {
4182 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
4183 return INSPECT_RESULT::QUIT;
4184 }
4185
4186 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
4187 {
4188 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
4189 return INSPECT_RESULT::QUIT;
4190 }
4191
4192 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
4193 {
4194 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4195 {
4196 // Collect only pins attached to the current unit and convert.
4197 // others are not associated to this symbol instance
4198 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4199 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4200
4201 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4202 continue;
4203
4204 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4205 continue;
4206
4207 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
4208 return INSPECT_RESULT::QUIT;
4209 }
4210 }
4211 }
4212
4214}
4215
4216
4217bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
4218{
4219 if( Type() != aItem.Type() )
4220 return Type() < aItem.Type();
4221
4222 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
4223
4225
4226 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
4227 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
4228
4229 if( m_pos.x != symbol->m_pos.x )
4230 return m_pos.x < symbol->m_pos.x;
4231
4232 if( m_pos.y != symbol->m_pos.y )
4233 return m_pos.y < symbol->m_pos.y;
4234
4235 if( m_prefix != symbol->m_prefix )
4236 return m_prefix < symbol->m_prefix;
4237
4238 if( m_schLibSymbolName != symbol->m_schLibSymbolName )
4239 return m_schLibSymbolName < symbol->m_schLibSymbolName;
4240
4241 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
4242}
4243
4244
4245bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
4246{
4247 // Don't compare m_lib_id: it may be instance-specific. Compare m_schLibSymbolName
4248 // instead.
4249 if( m_schLibSymbolName != aSymbol.m_schLibSymbolName )
4250 return false;
4251
4252 // m_prefix is an interesting one. It's sort of part of the annotation, which we don't
4253 // compare, but it's also sort of a higher level than the annotation itself. For now,
4254 // we skip it along with the annotation (FIELD_T::REFERENCE).
4255#if 0
4256 if( m_prefix != aSymbol.m_prefix )
4257 return false;
4258#endif
4259
4260 std::vector<SCH_FIELD*> fields, otherFields;
4261
4262 GetFields( fields, false );
4263 aSymbol.GetFields( otherFields, false );
4264
4265 if( fields.size() != otherFields.size() )
4266 return false;
4267
4268 for( int ii = 0; ii < (int) fields.size(); ii++ )
4269 {
4270 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
4271 continue;
4272
4273 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
4274 return false;
4275 }
4276
4277 if( m_doNetlist != aSymbol.m_doNetlist )
4278 return false;
4279
4280 if( m_passthroughMode != aSymbol.m_passthroughMode )
4281 return false;
4282
4283 // m_signalName has more to do with the placement on the schematic than the symbol itself
4284#if 0
4285 if( m_signalName != aSymbol.m_signalName )
4286 return false;
4287#endif
4288
4289 if( m_pins.size() != aSymbol.m_pins.size() )
4290 return false;
4291
4292 for( int ii = 0; ii < (int) m_pins.size(); ++ii )
4293 {
4294 SCH_PIN* matched = aSymbol.GetPin( m_pins[ii]->GetNumber() );
4295
4296 if( !matched )
4297 return false;
4298
4299 if( *m_pins[ii] != *matched )
4300 return false;
4301 }
4302
4303 return true;
4304}
4305
4306
4307bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
4308{
4309 return !( *this == aSymbol );
4310}
4311
4312
4314{
4315 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
4316 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
4317
4318 if( &aSymbol != this )
4319 {
4320 SYMBOL::operator=( aSymbol );
4321
4322 m_pos = aSymbol.m_pos;
4323 m_lib_id = aSymbol.m_lib_id;
4324 m_prefix = aSymbol.m_prefix;
4325
4326 // Pin relinking still needs the previous library's alternate definitions.
4327 auto oldPart = std::exchange( m_part, aSymbol.m_part ? std::make_unique<LIB_SYMBOL>( *aSymbol.m_part )
4328 : nullptr );
4329
4330 m_unit = aSymbol.m_unit;
4331 m_bodyStyle = aSymbol.m_bodyStyle;
4332 m_transform = aSymbol.m_transform;
4333
4334 m_instances = aSymbol.m_instances;
4336 m_doNetlist = aSymbol.m_doNetlist;
4338 m_signalName = aSymbol.m_signalName;
4340
4341 {
4342 m_fields = aSymbol.m_fields; // std::vector's assignment operator
4343
4344 // Reparent fields after assignment to new symbol.
4345 for( SCH_FIELD& field : m_fields )
4346 field.SetParent( this );
4347 }
4348
4349 UpdatePins();
4350 m_variantSymbolCache.clear();
4351 }
4352
4353 return *this;
4354}
4355
4356
4357bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
4358{
4359 BOX2I bBox = GetBodyBoundingBox();
4360 bBox.Inflate( aAccuracy / 2 );
4361
4362 if( bBox.Contains( aPosition ) )
4363 return true;
4364
4365 return false;
4366}
4367
4368
4369bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
4370{
4372 return false;
4373
4374 BOX2I rect = aRect;
4375
4376 rect.Inflate( aAccuracy / 2 );
4377
4378 if( aContained )
4379 return rect.Contains( GetBodyBoundingBox() );
4380
4381 return rect.Intersects( GetBodyBoundingBox() );
4382}
4383
4384
4385bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
4386{
4388 return false;
4389
4390 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
4391}
4392
4393
4394bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
4395{
4396 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
4397
4398 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4399 {
4400 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
4401 continue;
4402
4403 // Collect only pins attached to the current unit and convert.
4404 // others are not associated to this symbol instance
4405 if( pin->GetUnit() != ALL_UNITS && pin->GetUnit() != GetUnit() )
4406 continue;
4407
4408 if( pin->GetBodyStyle() != ALL_BODY_STYLES && pin->GetBodyStyle() != GetBodyStyle() )
4409 continue;
4410
4411 if( pin->GetLocalPosition() == new_pos )
4412 return true;
4413 }
4414
4415 return false;
4416}
4417
4418
4420{
4421 return m_doNetlist;
4422}
4423
4424
4425void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
4426 const VECTOR2I& aOffset, bool aDimmed )
4427{
4428 if( aBackground )
4429 return;
4430
4431 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4432 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
4433
4434 if( effectiveSym )
4435 {
4436 bool usingAlternate = ( effectiveSym != m_part.get() );
4437
4438 std::vector<SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4439
4440 // Copy the source so we can re-orient and translate it.
4441 LIB_SYMBOL tempSymbol( *effectiveSym );
4442 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
4443 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
4444
4445 // Copy the pin info from the symbol to the temp pins.
4446 for( unsigned i = 0; i < tempPins.size(); ++i )
4447 {
4448 SCH_PIN* symbolPin = symbolPins[i];
4449 SCH_PIN* tempPin = tempPins[i];
4450
4451 if( !symbolPin )
4452 continue;
4453
4454 tempPin->SetName( symbolPin->GetShownName() );
4455 tempPin->SetType( symbolPin->GetType() );
4456 tempPin->SetShape( symbolPin->GetShape() );
4457
4458 if( symbolPin->IsDangling() )
4459 tempPin->SetFlags( IS_DANGLING );
4460 }
4461
4462 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
4463 {
4464 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
4465 {
4466 // Use SCH_FIELD's text resolver
4467 SCH_FIELD dummy( this, FIELD_T::USER );
4468 dummy.SetText( text->GetText() );
4469 text->SetText( dummy.GetShownText( FOR_CANVAS ) );
4470 }
4471 }
4472
4473 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4474 TRANSFORM savedTransform = renderSettings->m_Transform;
4475 renderSettings->m_Transform = GetTransform();
4476 aPlotter->StartBlock( nullptr );
4477
4478 wxString variant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
4479 bool dnp = GetDNP( sheet, variant );
4480
4481 for( bool local_background : { true, false } )
4482 {
4483 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
4484
4485 for( SCH_FIELD field : m_fields )
4486 {
4487 field.ClearRenderCache();
4488 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
4489
4491 && field.GetId() == FIELD_T::VALUE
4492 && ( field.IsVisible() || field.IsForceVisible() )
4493 && !local_background )
4494 {
4495 PlotLocalPowerIconShape( aPlotter );
4496 }
4497 }
4498 }
4499
4500 if( dnp && renderSettings->m_ShowDNPMarkers )
4501 PlotDNP( aPlotter );
4502
4503 // Plot attributes to a hypertext menu
4504 if( aPlotOpts.m_PDFPropertyPopups )
4505 {
4506 std::vector<wxString> properties;
4507
4508 for( const SCH_FIELD& field : GetFields() )
4509 {
4510 wxString text_field = field.GetShownText( sheet, FOR_GUI, variant );
4511
4512 if( text_field.IsEmpty() )
4513 continue;
4514
4515 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
4516 }
4517
4518 if( !effectiveSym->GetKeyWords().IsEmpty() )
4519 {
4520 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
4521 _( "Keywords" ),
4522 effectiveSym->GetShownKeyWords( FOR_GUI ) ) );
4523 }
4524
4525 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
4526 }
4527
4528 aPlotter->EndBlock( nullptr );
4529 renderSettings->m_Transform = savedTransform;
4530
4531 if( !effectiveSym->IsPower() )
4532 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
4533 }
4534}
4535
4536
4537void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
4538{
4539 BOX2I bbox = GetBodyBoundingBox();
4541 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
4542 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
4543 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
4544
4545 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
4546 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
4547 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
4548
4549 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4550 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
4551
4552 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
4553
4554 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
4555 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
4556}
4557
4558
4562static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
4563{
4564 double lineWidth = aSize / 10.0;
4565
4566 std::vector<SCH_SHAPE> shapeList;
4567 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
4568 int tolerance = 100; // approx error to approximate a Bezier curve by segments
4569
4570 for( const SCH_SHAPE& shape : shapeList )
4571 {
4572 // Currently there are only 2 shapes: BEZIER and CIRCLE
4573 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
4574
4575 if( shape.GetShape() == SHAPE_T::BEZIER )
4576 {
4577 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
4578 tolerance, lineWidth );
4579 }
4580 else if( shape.GetShape() == SHAPE_T::CIRCLE )
4581 {
4582 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
4583 }
4584 }
4585}
4586
4587
4589{
4590 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
4591
4592 // Plot the local power pin indicator icon shape
4593 BOX2I bbox = field->GetBoundingBox();
4594
4595 // Calculate the text orientation according to the parent orientation.
4596 EDA_ANGLE orient = field->GetTextAngle();
4597
4598 if( GetTransform().y1 )
4599 {
4600 // Rotate symbol 90 degrees.
4601 if( orient.IsHorizontal() )
4602 orient = ANGLE_VERTICAL;
4603 else
4604 orient = ANGLE_HORIZONTAL;
4605 }
4606
4607 bool rotated = !orient.IsHorizontal();
4608
4609 VECTOR2D pos;
4610 double size = bbox.GetHeight() / 1.5;
4611
4612 if( rotated )
4613 {
4614 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
4615 size = bbox.GetWidth() / 1.5;
4616 }
4617 else
4618 {
4619 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
4620 }
4621
4622 plotLocalPowerIcon( aPlotter, pos, size, rotated );
4623}
4624
4625
4626void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter, bool aDnp ) const
4627{
4628 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
4629 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
4630
4631 if( effectiveSym )
4632 {
4633 bool usingAlternate = ( effectiveSym != m_part.get() );
4634
4635 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
4636 TRANSFORM savedTransform = renderSettings->m_Transform;
4637 renderSettings->m_Transform = GetTransform();
4638
4639 std::vector<SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4640
4641 // Copy the source to stay const
4642 LIB_SYMBOL tempSymbol( *effectiveSym );
4643 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
4644 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
4645 SCH_PLOT_OPTS plotOpts;
4646
4647 // Copy the pin info from the symbol to the temp pins.
4648 for( unsigned i = 0; i < tempPins.size(); ++i )
4649 {
4650 SCH_PIN* symbolPin = symbolPins[i];
4651 SCH_PIN* tempPin = tempPins[i];
4652
4653 if( !symbolPin )
4654 continue;
4655
4656 tempPin->SetName( symbolPin->GetShownName() );
4657 tempPin->SetType( symbolPin->GetType() );
4658 tempPin->SetShape( symbolPin->GetShape() );
4659 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, aDnp );
4660 }
4661
4662 renderSettings->m_Transform = savedTransform;
4663 }
4664}
4665
4666
4668{
4669 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4670 {
4671 if( pin->IsBrightened() )
4672 return true;
4673 }
4674
4675 return false;
4676}
4677
4678
4680{
4681 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
4682 pin->ClearBrightened();
4683}
4684
4685
4686/*
4687 * When modified at the schematic level, we still store the values of these flags in the
4688 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
4689 * will be created and stored locally in the schematic.
4690 */
4692{
4693 return m_part && m_part->GetShowPinNames();
4694}
4695
4696
4698{
4699 if( m_part )
4700 m_part->SetShowPinNames( aShow );
4701}
4702
4703
4705{
4706 return m_part && m_part->GetShowPinNumbers();
4707}
4708
4709
4711{
4712 if( m_part )
4713 m_part->SetShowPinNumbers( aShow );
4714}
4715
4716
4718{
4719 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4720 {
4721 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4722 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4723
4724 if( pin_unit != ALL_UNITS && pin_unit != GetUnit() )
4725 continue;
4726
4727 if( pin_bodyStyle != ALL_BODY_STYLES && pin_bodyStyle != GetBodyStyle() )
4728 continue;
4729
4730 if( pin->IsPointClickableAnchor( aPos ) )
4731 return true;
4732 }
4733
4734 return false;
4735}
4736
4737
4739{
4740 // return true if the symbol is equivalent to a global label:
4741 // It is a Power symbol
4742 // It has only one pin type Power input
4743
4745 return false;
4746
4747 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4748
4749 if( pin_list.size() != 1 )
4750 return false;
4751
4752 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4753}
4754
4755
4757{
4758 // return true if the symbol is equivalent to a local label:
4759 // It is a Power symbol
4760 // It has only one pin type Power input
4761
4763 return false;
4764
4765 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4766
4767 if( pin_list.size() != 1 )
4768 return false;
4769
4770 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4771}
4772
4773
4775{
4776 if( !m_part )
4777 return false;
4778
4779 return m_part->IsLocalPower();
4780}
4781
4782
4784{
4785 if( !m_part )
4786 return false;
4787
4788 return m_part->IsGlobalPower();
4789}
4790
4791
4793{
4794 return IsLocalPower() || IsGlobalPower();
4795}
4796
4797
4799{
4800 wxCHECK( m_part, false );
4801
4802 return m_part->IsNormal();
4803}
4804
4805
4806std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
4807{
4808 std::unordered_set<wxString> componentClass;
4809
4810 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
4811 {
4812 for( const SCH_FIELD& field : fields )
4813 {
4814 if( field.GetUntranslatedName() == wxT( "Component Class" ) )
4815 {
4816 if( field.GetShownText( aPath, INTERNAL ) != wxEmptyString )
4817 componentClass.insert( field.GetShownText( aPath, INTERNAL ) );
4818 }
4819 }
4820 };
4821
4822 // First get component classes set on the symbol itself
4823 getComponentClassFields( m_fields );
4824
4825 // Now get component classes set on any enclosing rule areas
4826 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
4827 {
4828 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
4829 {
4830 getComponentClassFields( label->GetFields() );
4831 }
4832 }
4833
4834 return componentClass;
4835}
4836
4837
4838std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
4839 const wxString& aVariantName ) const
4840{
4841 SCH_SYMBOL_INSTANCE instance;
4842
4843 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
4844 return std::nullopt;
4845
4846 return instance.m_Variants.find( aVariantName )->second;
4847}
4848
4849
4850void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
4851{
4852 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
4853
4854 // The instance path must already exist.
4855 if( !instance )
4856 return;
4857
4858 if( instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) ).second )
4860}
4861
4862
4863LIB_SYMBOL* SCH_SYMBOL::GetVariantLibSymbol( const wxString& aVariantName,
4864 const SCH_SHEET_PATH& aPath ) const
4865{
4866 if( aVariantName.IsEmpty() )
4867 return nullptr;
4868
4869 const SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4870
4871 if( !instance || !instance->m_Variants.contains( aVariantName ) )
4872 return nullptr;
4873
4874 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
4875
4876 if( !variant.m_SymbolOverride )
4877 return nullptr;
4878
4879 const LIB_ID& libId = *variant.m_SymbolOverride;
4880 wxString libIdStr = libId.Format();
4881
4882 // Cache by LIB_ID string so hierarchical instances sharing the same alternate symbol
4883 // reuse a single flattened copy regardless of sheet path or variant name. Failed
4884 // resolutions are cached as nullptr to keep unresolvable overrides from hitting the
4885 // library adapter on every paint.
4886 auto cacheIt = m_variantSymbolCache.find( libIdStr );
4887
4888 if( cacheIt != m_variantSymbolCache.end() )
4889 return cacheIt->second.get();
4890
4891 if( libId == m_lib_id )
4892 {
4893 m_variantSymbolCache[libIdStr] = nullptr;
4894 return nullptr;
4895 }
4896
4898
4899 if( !schematic )
4900 return nullptr;
4901
4903
4904 if( !adapter )
4905 return nullptr;
4906
4907 try
4908 {
4909 if( LIB_SYMBOL* libSymbol = adapter->LoadSymbol( libId ) )
4910 {
4911 std::unique_ptr<LIB_SYMBOL>& cached = m_variantSymbolCache[libIdStr];
4912
4913 cached = libSymbol->Flatten();
4914
4915 if( m_part && cached && !ValidateVariantSymbolCompatibility( *m_part, *cached ).empty() )
4916 {
4917 cached.reset();
4918 return nullptr;
4919 }
4920
4921 return cached.get();
4922 }
4923 }
4924 catch( const IO_ERROR& )
4925 {
4926 }
4927
4928 m_variantSymbolCache[libIdStr] = nullptr;
4929 return nullptr;
4930}
4931
4932
4934{
4935 if( aPath && Schematic() )
4936 {
4937 const wxString& variantName = Schematic()->GetCurrentVariant();
4938
4939 if( !variantName.IsEmpty() )
4940 {
4941 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( variantName, *aPath );
4942
4943 if( altSymbol )
4944 return altSymbol;
4945 }
4946 }
4947
4948 return m_part.get();
4949}
4950
4951
4952std::vector<SCH_PIN*> SCH_SYMBOL::MapLibPins( const std::vector<SCH_PIN*>& aLibPins, bool aByNumber ) const
4953{
4954 std::vector<SCH_PIN*> mapped;
4955
4956 mapped.reserve( aLibPins.size() );
4957
4958 if( aByNumber )
4959 {
4960 const LIB_SYMBOL* baseSymbol = m_part.get();
4961
4962 if( !baseSymbol )
4963 {
4964 mapped.resize( aLibPins.size(), nullptr );
4965 return mapped;
4966 }
4967
4968 std::vector<SCH_PIN*> basePins = baseSymbol->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4969 std::vector<bool> matched( basePins.size(), false );
4970
4971 for( const SCH_PIN* alternatePin : aLibPins )
4972 {
4973 SCH_PIN* instancePin = nullptr;
4974
4975 for( size_t i = 0; i < basePins.size(); ++i )
4976 {
4977 if( matched[i] || !VariantSymbolPinsMatch( *basePins[i], *alternatePin ) )
4978 continue;
4979
4980 matched[i] = true;
4981 instancePin = GetPin( const_cast<SCH_PIN*>( basePins[i] ) );
4982 break;
4983 }
4984
4985 mapped.push_back( instancePin );
4986 }
4987 }
4988 else
4989 {
4990 for( const SCH_PIN* libPin : aLibPins )
4991 mapped.push_back( GetPin( const_cast<SCH_PIN*>( libPin ) ) );
4992 }
4993
4994 return mapped;
4995}
4996
4997
4998void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
4999{
5000 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5001
5002 // The instance path must already exist.
5003 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5004 return;
5005
5006 instance->m_Variants.erase( aVariantName );
5007
5009}
5010
5011
5012void SCH_SYMBOL::ClearVariantField( const KIID_PATH& aPath, const wxString& aVariantName,
5013 const wxString& aFieldName )
5014{
5015 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5016
5017 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5018 return;
5019
5020 if( instance->m_Variants[aVariantName].m_Fields.erase( aFieldName ) )
5022}
5023
5024
5025void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
5026 const wxString& aNewName )
5027{
5028 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5029
5030 // The instance path must already exist and contain the old variant.
5031 if( aOldName == aNewName || !instance || !instance->m_Variants.contains( aOldName ) )
5032 return;
5033
5034 // Get the variant data, update the name, and re-insert with new key
5035 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
5036 variant.m_Name = aNewName;
5037 instance->m_Variants.erase( aOldName );
5038 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
5039
5041}
5042
5043
5044void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
5045 const wxString& aNewVariant )
5046{
5047 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5048
5049 // The instance path must already exist and contain the source variant.
5050 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
5051 return;
5052
5053 // Copy the variant data with a new name
5054 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
5055 variant.m_Name = aNewVariant;
5056
5057 if( instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) ).second )
5059}
5060
5061
5063 const wxString& aVariantName,
5064 const LIB_ID& aLibId )
5065{
5066 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5067
5068 if( !instance )
5069 return;
5070
5071 if( !instance->m_Variants.contains( aVariantName ) )
5072 {
5073 SCH_SYMBOL_VARIANT newVariant( aVariantName );
5074 newVariant.InitializeAttributes( *this );
5075 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
5076 }
5077
5078 const bool changed = std::exchange( instance->m_Variants[aVariantName].m_SymbolOverride, aLibId ) != aLibId;
5079 m_variantSymbolCache.clear();
5080
5081 if( changed )
5083}
5084
5085
5087 const wxString& aVariantName )
5088{
5089 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
5090
5091 if( !instance || !instance->m_Variants.contains( aVariantName ) )
5092 return false;
5093
5094 SCH_SYMBOL_VARIANT& variant = instance->m_Variants[aVariantName];
5095
5096 if( !variant.m_SymbolOverride )
5097 return false;
5098
5099 variant.m_SymbolOverride.reset();
5100 m_variantSymbolCache.clear();
5101
5103
5104 return true;
5105}
5106
5107
5108bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
5109{
5110 if( Type() != aOther.Type() )
5111 return false;
5112
5113 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
5114
5115 if( GetLibId() != symbol.GetLibId() )
5116 return false;
5117
5118 if( GetPosition() != symbol.GetPosition() )
5119 return false;
5120
5121 if( GetUnit() != symbol.GetUnit() )
5122 return false;
5123
5124 if( GetBodyStyle() != symbol.GetBodyStyle() )
5125 return false;
5126
5127 if( GetTransform() != symbol.GetTransform() )
5128 return false;
5129
5130 if( GetFields() != symbol.GetFields() )
5131 return false;
5132
5133 if( m_pins.size() != symbol.m_pins.size() )
5134 return false;
5135
5136 if( m_excludedFromSim != symbol.m_excludedFromSim )
5137 return false;
5138
5139 if( m_excludedFromBOM != symbol.m_excludedFromBOM )
5140 return false;
5141
5142 if( m_DNP != symbol.m_DNP )
5143 return false;
5144
5146 return false;
5147
5149 return false;
5150
5152 return false;
5153
5154 for( unsigned i = 0; i < m_pins.size(); ++i )
5155 {
5156 if( *m_pins[i] != *symbol.m_pins[i] )
5157 return false;
5158 }
5159
5160#if 0
5161 // This has historically been a compare of the current instance, rather than a compare
5162 // of all instances. Probably better to keep it that way for now.
5163 if( m_instanceReferences != symbol.m_instanceReferences )
5164 return false;
5165#endif
5166
5167 return true;
5168}
5169
5170
5171double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
5172{
5173 if( Type() != aOther.Type() )
5174 return 0.0;
5175
5176 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
5177
5178 if( GetLibId() != symbol.GetLibId() )
5179 return 0.0;
5180
5181 if( GetPosition() == symbol.GetPosition() )
5182 return 1.0;
5183
5184 return 0.0;
5185}
5186
5187
5188void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
5189 double aLineWidth, bool aHorizontal )
5190{
5191 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
5192
5193 double x_right = aSize / 1.6180339887;
5194 double x_middle = x_right / 2.0;
5195
5196 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
5197 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
5198 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
5199
5200 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
5201 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
5202 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
5203 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
5204 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
5205
5206 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5207 aShapeList.back().SetStart( bottomPt );
5208 aShapeList.back().SetBezierC1( bottomAnchorPt );
5209 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
5210 aShapeList.back().SetEnd( leftPt );
5211
5212
5213 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5214 aShapeList.back().SetStart( leftPt );
5215 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
5216 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
5217 aShapeList.back().SetEnd( rightPt );
5218
5219 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
5220 aShapeList.back().SetStart( rightPt );
5221 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
5222 aShapeList.back().SetBezierC2( bottomAnchorPt );
5223 aShapeList.back().SetEnd( bottomPt );
5224
5225 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
5226 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
5227 aShapeList.back().SetRadius( aSize / 15.0 );
5228
5229 for( SCH_SHAPE& shape : aShapeList )
5230 {
5231 if( aHorizontal )
5232 shape.Rotate( VECTOR2I( 0, 0 ), true );
5233
5234 shape.Move( aPos );
5235 }
5236}
5237
5238
5240{
5241 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
5242 return &m_instances[it->second];
5243
5244 return nullptr;
5245}
5246
5247
5249{
5250 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
5251 return &m_instances[it->second];
5252
5253 return nullptr;
5254}
5255
5256
5257static struct SCH_SYMBOL_DESC
5258{
5260 {
5262 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
5263 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
5264 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
5265 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
5266
5272
5273 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position X" ),
5276 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position Y" ),
5279
5282 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror X" ),
5284 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror Y" ),
5286
5287 auto hasLibPart =
5288 []( INSPECTABLE* aItem ) -> bool
5289 {
5290 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5291 return symbol->GetLibSymbolRef() != nullptr;
5292
5293 return false;
5294 };
5295
5296 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ),
5298 .SetAvailableFunc( hasLibPart );
5299
5300 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ),
5302 .SetAvailableFunc( hasLibPart );
5303
5304 const wxString groupFields = _HKI( "Fields" );
5305
5306 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Reference" ),
5308 groupFields );
5309 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Value" ),
5311 groupFields );
5312 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
5314 groupFields );
5315 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
5317 groupFields );
5318 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ),
5320 groupFields );
5321
5322 auto multiUnit =
5323 [=]( INSPECTABLE* aItem ) -> bool
5324 {
5325 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5326 return symbol->IsMultiUnit();
5327
5328 return false;
5329 };
5330
5331 auto multiBodyStyle =
5332 [=]( INSPECTABLE* aItem ) -> bool
5333 {
5334 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5335 return symbol->IsMultiBodyStyle();
5336
5337 return false;
5338 };
5339
5340 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Unit" ),
5342 .SetAvailableFunc( multiUnit )
5344 []( INSPECTABLE* aItem )
5345 {
5346 wxPGChoices choices;
5347
5348 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5349 {
5350 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
5351 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
5352 }
5353
5354 return choices;
5355 } );
5356
5357 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Body Style" ),
5359 .SetAvailableFunc( multiBodyStyle )
5361 []( INSPECTABLE* aItem )
5362 {
5363 wxPGChoices choices;
5364
5365 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
5366 {
5367 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
5368 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
5369 }
5370
5371 return choices;
5372 } );
5373
5374 const wxString groupAttributes = _HKI( "Attributes" );
5375
5376 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
5378 groupAttributes );
5379 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
5381 groupAttributes );
5382 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
5384 groupAttributes );
5385 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
5387 groupAttributes );
5388 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
5390 groupAttributes );
5391 }
5393
5394
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
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:783
A text control validator used for validating the text allowed in fields.
Definition validators.h:138
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
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:136
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:533
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:606
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:441
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:521
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:615
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:277
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:263
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:366
friend class INSPECTABLE
Definition property.h:492
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:304
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:839
SCH_SCREEN * GetParentScreen() const
Definition sch_item.cpp:308
int m_bodyStyle
Definition sch_item.h:840
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:817
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:674
virtual void SetUnit(int aUnit)
Definition sch_item.h:242
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:842
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:855
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:673
SCH_LAYER_ID m_layer
Definition sch_item.h:838
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:73
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:322
bool IsSymbolLikePowerGlobalLabel() const
VECTOR2I m_pos
PASSTHROUGH_MODE GetPassthroughMode() const
Definition sch_symbol.h:855
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:165
LIB_ID m_lib_id
Name and library the symbol was loaded from, i.e. 74xx:74LS00.
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:461
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:539
void SetRefProp(const wxString &aRef)
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.
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:896
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:305
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_variantSymbolCache
int GetY() const
Definition sch_symbol.h:901
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:113
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)
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
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:339
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:544
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:180
int GetX() const
Definition sch_symbol.h:898
bool GetExcludedFromPosFilesProp() const
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) 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:902
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:334
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 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:296
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...
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:895
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.
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:163
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:178
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:351
std::map< wxString, std::unique_ptr< PROPERTY_BASE > > m_dynamicPropertyCache
Per-object cache of dynamic property descriptors for custom fields and effective pin-map entries,...
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:856
void SetX(int aX)
Definition sch_symbol.h:899
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:239
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:182
std::unordered_set< wxString > GetComponentClassNames(const SCH_SHEET_PATH *aPath) const
Return the component classes this symbol belongs in.
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
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
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...
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_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
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
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:89
@ FOR_GUI
Definition common.h:91
@ FOR_CANVAS
Definition common.h:90
@ FOR_NETNAME
Definition common.h:92
@ RAW_VALUE
Definition common.h:96
@ INTERNAL
Definition common.h:94
#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:471
@ LAYER_DEVICE
Definition layer_ids.h:488
@ LAYER_VALUEPART
Definition layer_ids.h:483
@ LAYER_FIELDS
Definition layer_ids.h:484
@ LAYER_REFERENCEPART
Definition layer_ids.h:482
@ LAYER_DNP_MARKER
Definition layer_ids.h:500
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:895
#define ENUM_TO_WXANY(type)
Definition property.h:890
@ 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
bool IsDefault() const
Definition pin_map.h:210
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_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