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