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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <sch_collectors.h>
26#include <sch_commit.h>
27#include <sch_edit_frame.h>
28#include <widgets/msgpanel.h>
29#include <bitmaps.h>
30#include <core/mirror.h>
31#include <sch_shape.h>
32#include <pgm_base.h>
33#include <sim/sim_model.h>
34#include <sim/spice_generator.h>
35#include <sim/sim_lib_mgr.h>
36#include <trace_helpers.h>
37#include <trigo.h>
38#include <refdes_utils.h>
39#include <wx/log.h>
41#include <sch_plotter.h>
42#include <string_utils.h>
44#include <sch_rule_area.h>
45
46#include <utility>
47#include <validators.h>
48
49
50std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
51
52
57std::string toUTFTildaText( const wxString& txt )
58{
59 std::string ret = TO_UTF8( txt );
60
61 for( char& c : ret )
62 {
63 if( (unsigned char) c <= ' ' )
64 c = '~';
65 }
66
67 return ret;
68}
69
70
72 SYMBOL( nullptr, SCH_SYMBOL_T )
73{
74 Init( VECTOR2I( 0, 0 ) );
75}
76
77
78SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId, const SCH_SHEET_PATH* aSheet, int aUnit,
79 int aBodyStyle, const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
80 SYMBOL( aParent, SCH_SYMBOL_T )
81{
82 Init( aPosition );
83
84 m_unit = aUnit;
85 m_bodyStyle = aBodyStyle;
86 m_lib_id = aLibId;
87
88 std::unique_ptr<LIB_SYMBOL> part;
89
90 part = aSymbol.Flatten();
91 part->SetParent();
92 SetLibSymbol( part.release() );
93
94 // Copy fields from the library symbol
95 UpdateFields( aSheet, true, /* update style */
96 false, /* update ref */
97 false, /* update other fields */
98 true, /* reset ref */
99 true /* reset other fields */ );
100
101 m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
102
103 if( aSheet )
105
106 // Inherit the include in bill of materials and board netlist settings from flattened
107 // library symbol.
108 m_excludedFromSim = m_part->GetExcludedFromSim();
109 m_excludedFromBOM = m_part->GetExcludedFromBOM();
110 m_excludedFromBoard = m_part->GetExcludedFromBoard();
111}
112
113
114SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet, const PICKED_SYMBOL& aSel,
115 const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
116 SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, aPosition, aParent )
117{
118 // Set any fields that were modified as part of the symbol selection
119 for( const auto& [fieldId, fieldValue] : aSel.Fields )
120 {
121 if( fieldId == FIELD_T::REFERENCE )
122 SetRef( aSheet, fieldValue );
123 else if( SCH_FIELD* field = GetField( fieldId ) )
124 field->SetText( fieldValue );
125 }
126}
127
128
130 SYMBOL( aSymbol )
131{
132 m_parent = aSymbol.m_parent;
133 m_pos = aSymbol.m_pos;
134 m_unit = aSymbol.m_unit;
135 m_bodyStyle = aSymbol.m_bodyStyle;
136 m_lib_id = aSymbol.m_lib_id;
138 m_DNP = aSymbol.m_DNP;
139
140 const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
141
142 m_transform = aSymbol.m_transform;
143 m_prefix = aSymbol.m_prefix;
145 m_fields = aSymbol.m_fields;
146
147 // Re-parent the fields, which before this had aSymbol as parent
148 for( SCH_FIELD& field : m_fields )
149 field.SetParent( this );
150
151 m_pins.clear();
152
153 // Copy (and re-parent) the pins
154 for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
155 {
156 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
157 m_pins.back()->SetParent( this );
158 }
159
160 if( aSymbol.m_part )
161 SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part ) );
162
165}
166
167
171
172
173void SCH_SYMBOL::Init( const VECTOR2I& pos )
174{
176 m_pos = pos;
177 m_unit = 1; // In multi unit chip - which unit to draw.
178 m_bodyStyle = BODY_STYLE::BASE; // De Morgan Handling
179
180 // The rotation/mirror transformation matrix. pos normal
182
183 auto addField = [&]( FIELD_T id, SCH_LAYER_ID layer )
184 {
185 m_fields.emplace_back( this, id, GetCanonicalFieldName( id ) );
186 m_fields.back().SetTextPos( pos );
187 m_fields.back().SetLayer( layer );
188 };
189
190 // construct only the mandatory fields
192 addField( FIELD_T::VALUE, LAYER_VALUEPART );
193 addField( FIELD_T::FOOTPRINT, LAYER_FIELDS );
194 addField( FIELD_T::DATASHEET, LAYER_FIELDS );
196
197 m_prefix = wxString( wxT( "U" ) );
198 m_isInNetlist = true;
199}
200
201
203{
204 return new SCH_SYMBOL( *this );
205}
206
207
209{
210 return m_part == nullptr;
211}
212
213
215{
216 // If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
217 // going to end up moving the symbol's pins off-grid.
218
219 // The minimal grid size allowed to place a pin is 25 mils
220 const int min_grid_size = schIUScale.MilsToIU( 25 );
221
222 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
223 {
224 if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
225 return false;
226
227 if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
228 return false;
229 }
230
231 return true;
232}
233
234
235void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
236{
237 m_lib_id = aLibId;
238}
239
240
242{
243 if( !m_schLibSymbolName.IsEmpty() )
244 return m_schLibSymbolName;
245 else
246 return m_lib_id.Format();
247}
248
249
251{
252 wxCHECK2( !aLibSymbol || aLibSymbol->IsRoot(), aLibSymbol = nullptr );
253
254 m_part.reset( aLibSymbol );
255
256 // We've just reset the library symbol, so the lib_pins, which were just
257 // pointers to the old symbol, need to be cleared.
258 for( auto& pin : m_pins )
259 pin->SetLibPin( nullptr );
260
261 UpdatePins();
262}
263
264
266{
267 if( m_part )
268 return m_part->GetDescription();
269
270 return wxEmptyString;
271}
272
273
274wxString SCH_SYMBOL::GetShownDescription( int aDepth ) const
275{
276 if( m_part )
277 return m_part->GetShownDescription( aDepth );
278
279 return wxEmptyString;
280}
281
282
284{
285 if( m_part )
286 return m_part->GetKeyWords();
287
288 return wxEmptyString;
289}
290
291
292wxString SCH_SYMBOL::GetShownKeyWords( int aDepth ) const
293{
294 if( m_part )
295 return m_part->GetShownKeyWords( aDepth );
296
297 return wxEmptyString;
298}
299
300
302{
303 if( m_part )
304 return m_part->GetDatasheetField().GetText();
305
306 return wxEmptyString;
307}
308
309
311{
312 std::map<wxString, wxString> altPinMap;
313 std::map<wxString, SCH_PIN::ALT> altPinDefs;
314 std::map<wxString, std::set<SCH_PIN*>> pinUuidMap;
315 std::set<SCH_PIN*> unassignedSchPins;
316 std::set<SCH_PIN*> unassignedLibPins;
317
318 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
319 {
320 pinUuidMap[pin->GetNumber()].insert( pin.get() );
321
322 unassignedSchPins.insert( pin.get() );
323
324 if( !pin->GetAlt().IsEmpty() )
325 {
326 altPinMap[pin->GetNumber()] = pin->GetAlt();
327 auto altDefIt = pin->GetAlternates().find( pin->GetAlt() );
328
329 if( altDefIt != pin->GetAlternates().end() )
330 altPinDefs[pin->GetNumber()] = altDefIt->second;
331 }
332
333 pin->SetLibPin( nullptr );
334 }
335
336 m_pinMap.clear();
337
338 if( !m_part )
339 return;
340
341 for( SCH_PIN* libPin : m_part->GetPins() )
342 {
343 // NW: Don't filter by unit: this data-structure is used for all instances,
344 // some of which might have different units.
345 if( libPin->GetBodyStyle() && m_bodyStyle && m_bodyStyle != libPin->GetBodyStyle() )
346 continue;
347
348 SCH_PIN* pin = nullptr;
349
350 auto ii = pinUuidMap.find( libPin->GetNumber() );
351
352 if( ii == pinUuidMap.end() || ii->second.empty() )
353 {
354 unassignedLibPins.insert( libPin );
355 continue;
356 }
357
358 auto it = ii->second.begin();
359 pin = *it;
360 ii->second.erase( it );
361 pin->GetAlternates() = libPin->GetAlternates();
362 pin->SetLibPin( libPin );
363 pin->SetPosition( libPin->GetPosition() );
364 pin->SetUnit( libPin->GetUnit() );
365 pin->SetBodyStyle( libPin->GetBodyStyle() );
366
367 unassignedSchPins.erase( pin );
368
369 auto iii = altPinMap.find( libPin->GetNumber() );
370
371 if( iii != altPinMap.end() )
372 {
373 wxString altName = iii->second;
374
375 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
376 {
377 auto defIt = altPinDefs.find( libPin->GetNumber() );
378
379 if( defIt != altPinDefs.end() )
380 {
381 for( const auto& [name, alt] : pin->GetAlternates() )
382 {
383 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
384 {
385 altName = name;
386 break;
387 }
388 }
389 }
390 }
391
392 pin->SetAlt( altName );
393 }
394
395 m_pinMap[libPin] = pin;
396 }
397
398 // Add any pins that were not found in the symbol
399 for( SCH_PIN* libPin : unassignedLibPins )
400 {
401 SCH_PIN* pin = nullptr;
402
403 // First try to re-use an existing pin
404 if( !unassignedSchPins.empty() )
405 {
406 auto it = unassignedSchPins.begin();
407 pin = *it;
408 unassignedSchPins.erase( it );
409 }
410 else
411 {
412 // This is a pin that was not found in the symbol, so create a new one.
413 pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( this, libPin ) ) ).get();
414 }
415
416 m_pinMap[libPin] = pin;
417 pin->GetAlternates() = libPin->GetAlternates();
418 pin->SetLibPin( libPin );
419 pin->SetPosition( libPin->GetPosition() );
420 pin->SetUnit( libPin->GetUnit() );
421 pin->SetBodyStyle( libPin->GetBodyStyle() );
422 pin->SetNumber( libPin->GetNumber() );
423
424 auto iii = altPinMap.find( libPin->GetNumber() );
425
426 if( iii != altPinMap.end() )
427 {
428 wxString altName = iii->second;
429
430 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
431 {
432 auto defIt = altPinDefs.find( libPin->GetNumber() );
433
434 if( defIt != altPinDefs.end() )
435 {
436 for( const auto& [name, alt] : pin->GetAlternates() )
437 {
438 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
439 {
440 altName = name;
441 break;
442 }
443 }
444 }
445 }
446
447 pin->SetAlt( altName );
448 }
449 }
450
451 // If we have any pins left in the symbol that were not found in the library, remove them.
452 for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
453 {
454 auto it2 = unassignedSchPins.find( it1->get() );
455
456 if( it2 != unassignedSchPins.end() )
457 {
458 it1 = m_pins.erase( it1 );
459 unassignedSchPins.erase( it2 );
460 }
461 else
462 {
463 ++it1;
464 }
465 }
466
467 // If the symbol is selected, then its pins are selected.
468 if( IsSelected() )
469 {
470 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
471 pin->SetSelected();
472 }
473}
474
475
476void SCH_SYMBOL::SetBodyStyle( int aBodyStyle )
477{
478 if( aBodyStyle != m_bodyStyle )
479 {
480 m_bodyStyle = aBodyStyle;
481
482 // The body style may have a different pin layout so the update the pin map.
483 UpdatePins();
484 }
485}
486
487
489{
490 if( m_part )
491 return m_part->GetUnitCount();
492
493 return 0;
494}
495
496
498{
499 if( m_part )
500 return m_part->GetBodyStyleCount();
501
502 return 0;
503}
504
505
507{
508 if( m_part )
509 return m_part->HasDeMorganBodyStyles();
510
511 return false;
512}
513
514
515wxString SCH_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
516{
517 if( m_part )
518 return m_part->GetUnitDisplayName( aUnit, aLabel );
519 else if( aLabel )
520 return wxString::Format( _( "Unit %s" ), SubReference( aUnit ) );
521 else
522 return SubReference( aUnit );
523}
524
525
526wxString SCH_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
527{
528 if( m_part )
529 return m_part->GetBodyStyleDescription( aBodyStyle, aLabel );
530 else
531 return wxT( "?" );
532}
533
534
535bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance, const KIID_PATH& aSheetPath, bool aTestFromEnd ) const
536{
537 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
538 {
539 if( !aTestFromEnd )
540 {
541 if( instance.m_Path == aSheetPath )
542 {
543 aInstance = instance;
544 return true;
545 }
546 }
547 else if( instance.m_Path.EndsWith( aSheetPath ) )
548 {
549 aInstance = instance;
550 return true;
551 }
552 }
553
554 return false;
555}
556
557
558void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
559{
560 RemoveInstance( aInstancePath.Path() );
561}
562
563
564void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
565{
566 // Search for an existing path and remove it if found
567 // (search from back to avoid invalidating iterator on remove)
568 for( int ii = m_instanceReferences.size() - 1; ii >= 0; --ii )
569 {
570 if( m_instanceReferences[ii].m_Path == aInstancePath )
571 {
572 wxLogTrace( traceSchSheetPaths,
573 wxS( "Removing symbol instance:\n"
574 " sheet path %s\n"
575 " reference %s, unit %d from symbol %s." ),
576 aInstancePath.AsString(), m_instanceReferences[ii].m_Reference, m_instanceReferences[ii].m_Unit,
577 m_Uuid.AsString() );
578
579 m_instanceReferences.erase( m_instanceReferences.begin() + ii );
580 }
581 }
582}
583
584
585void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, int aUnit )
586{
587 SCH_SYMBOL_INSTANCE instance;
588 instance.m_Path = aPath;
589 instance.m_Reference = aRef;
590 instance.m_Unit = aUnit;
591
592 AddHierarchicalReference( instance );
593}
594
595
597{
598 RemoveInstance( aInstance.m_Path );
599
600 SCH_SYMBOL_INSTANCE instance = aInstance;
601
602 wxLogTrace( traceSchSheetPaths,
603 wxS( "Adding symbol '%s' instance:\n"
604 " sheet path '%s'\n"
605 " reference '%s'\n"
606 " unit %d\n" ),
607 m_Uuid.AsString(), instance.m_Path.AsString(), instance.m_Reference, instance.m_Unit );
608
609 m_instanceReferences.push_back( instance );
610
611 // This should set the default instance to the first saved instance data for each symbol
612 // when importing sheets.
613 if( m_instanceReferences.size() == 1 )
614 {
616 m_unit = instance.m_Unit;
617 }
618}
619
620
621const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
622{
623 KIID_PATH path = sheet->Path();
624 wxString ref;
625 wxString subRef;
626
627 wxLogTrace( traceSchSymbolRef, "GetRef for symbol %s on path %s (sheet path has %zu sheets)", m_Uuid.AsString(),
628 path.AsString(), sheet->size() );
629
630 wxLogTrace( traceSchSymbolRef, " Symbol has %zu instance references", m_instanceReferences.size() );
631
632 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
633 {
634 wxLogTrace( traceSchSymbolRef, " Instance: path=%s, ref=%s", instance.m_Path.AsString(),
635 instance.m_Reference );
636
637 if( instance.m_Path == path )
638 {
639 ref = instance.m_Reference;
640 subRef = SubReference( instance.m_Unit );
641 wxLogTrace( traceSchSymbolRef, " MATCH FOUND: ref=%s", ref );
642 break;
643 }
644 }
645
646 // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
647 // use this as a default for this path. This will happen if we load a version 1 schematic
648 // file. It will also mean that multiple instances of the same sheet by default all have
649 // the same symbol references, but perhaps this is best.
650 if( ref.IsEmpty() && !GetField( FIELD_T::REFERENCE )->GetText().IsEmpty() )
651 {
653 wxLogTrace( traceSchSymbolRef, " Using fallback from REFERENCE field: %s", ref );
654 }
655
656 if( ref.IsEmpty() )
657 {
659 wxLogTrace( traceSchSymbolRef, " Using unannotated reference: %s", ref );
660 }
661
662 if( aIncludeUnit && GetUnitCount() > 1 )
663 ref += subRef;
664
665 wxLogTrace( traceSchSymbolRef, " Final reference: %s", ref );
666
667 return ref;
668}
669
670
671void SCH_SYMBOL::SetRefProp( const wxString& aRef )
672{
674
675 if( validator.DoValidate( aRef, nullptr ) )
676 SetRef( &Schematic()->CurrentSheet(), aRef );
677}
678
679
680void SCH_SYMBOL::SetValueProp( const wxString& aValue )
681{
682 wxString currentVariant = Schematic()->GetCurrentVariant();
683 SetValueFieldText( aValue, &Schematic()->CurrentSheet(), currentVariant );
684}
685
686
687void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
688{
689 KIID_PATH path = sheet->Path();
690 bool found = false;
691
692 // check to see if it is already there before inserting it
694 {
695 if( instance.m_Path == path )
696 {
697 found = true;
698 instance.m_Reference = ref;
699 break;
700 }
701 }
702
703 if( !found )
705
706 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
707 pin->ClearDefaultNetName( sheet );
708
709 if( Schematic() && *sheet == Schematic()->CurrentSheet() )
711
712 // Reinit the m_prefix member if needed
714
715 if( m_prefix.IsEmpty() )
716 m_prefix = wxT( "U" );
717
718 // Power symbols have references starting with # and are not included in netlists
719 m_isInNetlist = !ref.StartsWith( wxT( "#" ) );
720}
721
722
723void SCH_SYMBOL::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath,
724 const wxString& aVariantName )
725{
726 wxCHECK( !aFieldName.IsEmpty(), /* void */ );
727
728 SCH_FIELD* field = GetField( aFieldName );
729
730 wxCHECK( field, /* void */ );
731
732 switch( field->GetId() )
733 {
735 wxCHECK( aPath, /* void */ );
736 SetRef( aPath, aFieldText );
737 break;
738
740 {
741 wxString defaultText = GetFootprintFieldText( false, nullptr, false );
742
743 if( aFieldText != defaultText )
744 {
745 if( aVariantName.IsEmpty() )
746 {
747 SetFootprintFieldText( aFieldText );
748 }
749 else
750 {
751 wxCHECK( aPath, /* void */ );
752
753 SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
754
755 wxCHECK( instance, /* void */ );
756
757 if( instance->m_Variants.contains( aVariantName ) )
758 {
759 instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText;
760 }
761 else
762 {
763 SCH_SYMBOL_VARIANT newVariant( aVariantName );
764
765 newVariant.InitializeAttributes( *this );
766 newVariant.m_Fields[aFieldName] = aFieldText;
767 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
768 }
769 }
770 }
771
772 break;
773 }
774
775 default:
776 {
777 wxString defaultText = field->GetText( aPath );
778
779 if( aFieldText != defaultText )
780 {
781 if( aVariantName.IsEmpty() )
782 {
783 field->SetText( aFieldText );
784 }
785 else
786 {
787 SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
788
789 wxCHECK( instance, /* void */ );
790
791 if( instance->m_Variants.contains( aVariantName ) )
792 {
793 instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText;
794 }
795 else
796 {
797 SCH_SYMBOL_VARIANT newVariant( aVariantName );
798
799 newVariant.InitializeAttributes( *this );
800 newVariant.m_Fields[aFieldName] = aFieldText;
801 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
802 }
803 }
804 }
805
806 break;
807 }
808 }
809}
810
811
812wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
813 const wxString& aVariantName ) const
814{
815 wxCHECK( !aFieldName.IsEmpty(), wxEmptyString );
816
817 const SCH_FIELD* field = GetField( aFieldName );
818
819 wxCHECK( field, wxEmptyString );
820
821 switch( field->GetId() )
822 {
824 wxCHECK( aPath, field->GetText() );
825 return GetRef( aPath, false );
826 break;
827
829 if( !aVariantName.IsEmpty() && aPath )
830 {
831 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
832
833 if( instance && instance->m_Variants.contains( aVariantName )
834 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
835 {
836 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
837 }
838 }
839
840 return GetFootprintFieldText( false, nullptr, false );
841
842 default:
843 if( aVariantName.IsEmpty() )
844 {
845 return field->GetText();
846 }
847 else
848 {
849 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
850
851 if( instance->m_Variants.contains( aVariantName )
852 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
853 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
854 }
855
856 break;
857 }
858
859 return field->GetText();
860}
861
862
863bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const
864{
865 KIID_PATH path = aSheet->Path();
866
867 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
868 {
869 if( instance.m_Path == path )
870 return !instance.m_Reference.IsEmpty() && instance.m_Reference.Last() != '?';
871 }
872
873 return false;
874}
875
876
878{
879 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
880
881 refDesignator.Replace( "~", " " );
882
883 wxString prefix = refDesignator;
884
885 while( prefix.Length() )
886 {
887 wxUniCharRef last = prefix.Last();
888
889 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
890 prefix.RemoveLast();
891 else
892 break;
893 }
894
895 // Avoid a prefix containing trailing/leading spaces
896 prefix.Trim( true );
897 prefix.Trim( false );
898
899 if( !prefix.IsEmpty() )
900 SetPrefix( prefix );
901}
902
903
904wxString SCH_SYMBOL::SubReference( int aUnit, bool aAddSeparator ) const
905{
906 if( SCHEMATIC* schematic = Schematic() )
907 return schematic->Settings().SubReference( aUnit, aAddSeparator );
908
909 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
910}
911
912
914{
915 KIID_PATH path = aSheet->Path();
916
917 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
918 {
919 if( instance.m_Path == path )
920 return instance.m_Unit;
921 }
922
923 // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
924 // version 1 schematic file.
925 return m_unit;
926}
927
928
929void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
930{
931 KIID_PATH path = aSheet->Path();
932
933 // check to see if it is already there before inserting it
935 {
936 if( instance.m_Path == path )
937 {
938 instance.m_Unit = aUnitSelection;
939 return;
940 }
941 }
942
943 // didn't find it; better add it
945}
946
947
948void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
949{
950 if( !aInstance || aVariantName.IsEmpty() )
951 {
952 m_DNP = aEnable;
953 return;
954 }
955
956 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
957
958 wxCHECK_MSG( instance, /* void */,
959 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
960 aInstance->PathHumanReadable() ) );
961
962 if( aVariantName.IsEmpty() )
963 {
964 m_DNP = aEnable;
965 }
966 else
967 {
968 if( instance->m_Variants.contains( aVariantName ) && ( aEnable != instance->m_Variants[aVariantName].m_DNP ) )
969 {
970 instance->m_Variants[aVariantName].m_DNP = aEnable;
971 }
972 else
973 {
974 SCH_SYMBOL_VARIANT variant( aVariantName );
975
976 variant.InitializeAttributes( *this );
977 variant.m_DNP = aEnable;
978 AddVariant( *aInstance, variant );
979 }
980 }
981}
982
983
984bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
985{
986 if( !aInstance || aVariantName.IsEmpty() )
987 return m_DNP;
988
989 SCH_SYMBOL_INSTANCE instance;
990
991 if( !GetInstance( instance, aInstance->Path() ) )
992 return m_DNP;
993
994 if( aVariantName.IsEmpty() )
995 return m_DNP;
996 else if( instance.m_Variants.contains( aVariantName ) )
997 return instance.m_Variants[aVariantName].m_DNP;
998
999 return m_DNP;
1000}
1001
1002
1003void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1004{
1005 if( !aInstance || aVariantName.IsEmpty() )
1006 {
1007 m_excludedFromBOM = aEnable;
1008 return;
1009 }
1010
1011 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1012
1013 wxCHECK_MSG( instance, /* void */,
1014 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1015 aInstance->PathHumanReadable() ) );
1016
1017 if( aVariantName.IsEmpty() )
1018 {
1019 m_excludedFromBOM = aEnable;
1020 }
1021 else
1022 {
1023 if( instance->m_Variants.contains( aVariantName )
1024 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBOM ) )
1025 {
1026 instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable;
1027 }
1028 else
1029 {
1030 SCH_SYMBOL_VARIANT variant( aVariantName );
1031
1032 variant.InitializeAttributes( *this );
1033 variant.m_ExcludedFromBOM = aEnable;
1034 AddVariant( *aInstance, variant );
1035 }
1036 }
1037}
1038
1039
1040bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1041{
1042 if( !aInstance || aVariantName.IsEmpty() )
1043 return m_excludedFromBOM;
1044
1045 SCH_SYMBOL_INSTANCE instance;
1046
1047 if( !GetInstance( instance, aInstance->Path() ) )
1048 return m_excludedFromBOM;
1049
1050 if( aVariantName.IsEmpty() )
1051 return m_excludedFromBOM;
1052 else if( instance.m_Variants.contains( aVariantName ) )
1053 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
1054
1055 // If the variant has not been defined yet, return the default exclude from BOM setting.
1056 return m_excludedFromBOM;
1057}
1058
1059
1060void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1061{
1062 if( !aInstance || aVariantName.IsEmpty() )
1063 {
1064 m_excludedFromSim = aEnable;
1065 return;
1066 }
1067
1068 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1069
1070 wxCHECK_MSG( instance, /* void */,
1071 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1072 aInstance->PathHumanReadable() ) );
1073
1074 if( aVariantName.IsEmpty() )
1075 {
1076 m_excludedFromSim = aEnable;
1077 }
1078 else
1079 {
1080 if( instance->m_Variants.contains( aVariantName )
1081 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromSim ) )
1082 {
1083 instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable;
1084 }
1085 else
1086 {
1087 SCH_SYMBOL_VARIANT variant( aVariantName );
1088
1089 variant.InitializeAttributes( *this );
1090 variant.m_ExcludedFromSim = aEnable;
1091 AddVariant( *aInstance, variant );
1092 }
1093 }
1094}
1095
1096
1097bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1098{
1099 if( !aInstance || aVariantName.IsEmpty() )
1100 return m_excludedFromSim;
1101
1102 SCH_SYMBOL_INSTANCE instance;
1103
1104 if( !GetInstance( instance, aInstance->Path() ) )
1105 return m_excludedFromSim;
1106
1107 if( aVariantName.IsEmpty() )
1108 return m_excludedFromSim;
1109 else if ( instance.m_Variants.contains( aVariantName ) )
1110 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
1111
1112 // If variant is not defined yet, return default exclude from simulation setting.
1113 return m_excludedFromSim;
1114}
1115
1116
1117void SCH_SYMBOL::SetExcludedFromBoard( bool aEnable, const SCH_SHEET_PATH* aInstance,
1118 const wxString& aVariantName )
1119{
1120 if( !aInstance || aVariantName.IsEmpty() )
1121 {
1122 m_excludedFromBoard = aEnable;
1123 return;
1124 }
1125
1126 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1127
1128 wxCHECK_MSG( instance, /* void */,
1129 wxString::Format( wxS( "Cannot set exclude from board for invalid sheet path '%s'." ),
1130 aInstance->PathHumanReadable() ) );
1131
1132 if( aVariantName.IsEmpty() )
1133 {
1134 m_excludedFromBoard = aEnable;
1135 }
1136 else
1137 {
1138 if( instance->m_Variants.contains( aVariantName )
1139 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBoard ) )
1140 {
1141 instance->m_Variants[aVariantName].m_ExcludedFromBoard = aEnable;
1142 }
1143 else
1144 {
1145 SCH_SYMBOL_VARIANT variant( aVariantName );
1146
1147 variant.InitializeAttributes( *this );
1148 variant.m_ExcludedFromBoard = aEnable;
1149 AddVariant( *aInstance, variant );
1150 }
1151 }
1152}
1153
1154
1156 const wxString& aVariantName ) const
1157{
1158 if( !aInstance || aVariantName.IsEmpty() )
1159 return m_excludedFromBoard;
1160
1161 SCH_SYMBOL_INSTANCE instance;
1162
1163 if( !GetInstance( instance, aInstance->Path() ) )
1164 return m_excludedFromBoard;
1165
1166 if( aVariantName.IsEmpty() )
1167 return m_excludedFromBoard;
1168 else if( instance.m_Variants.contains( aVariantName ) )
1169 return instance.m_Variants[aVariantName].m_ExcludedFromBoard;
1170
1171 // If variant is not defined yet, return default exclude from board setting.
1172 return m_excludedFromBoard;
1173}
1174
1175
1176void SCH_SYMBOL::SetExcludedFromPosFiles( bool aEnable, const SCH_SHEET_PATH* aInstance,
1177 const wxString& aVariantName )
1178{
1179 if( !aInstance || aVariantName.IsEmpty() )
1180 {
1181 m_excludedFromPosFiles = aEnable;
1182 return;
1183 }
1184
1185 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1186
1187 wxCHECK_MSG( instance, /* void */,
1188 wxString::Format( wxS( "Cannot set exclude from pos files for invalid sheet path '%s'." ),
1189 aInstance->PathHumanReadable() ) );
1190
1191 if( aVariantName.IsEmpty() )
1192 {
1193 m_excludedFromPosFiles = aEnable;
1194 }
1195 else
1196 {
1197 if( instance->m_Variants.contains( aVariantName )
1198 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromPosFiles ) )
1199 {
1200 instance->m_Variants[aVariantName].m_ExcludedFromPosFiles = aEnable;
1201 }
1202 else
1203 {
1204 SCH_SYMBOL_VARIANT variant( aVariantName );
1205
1206 variant.InitializeAttributes( *this );
1207 variant.m_ExcludedFromPosFiles = aEnable;
1208 AddVariant( *aInstance, variant );
1209 }
1210 }
1211}
1212
1213
1215 const wxString& aVariantName ) const
1216{
1217 if( !aInstance || aVariantName.IsEmpty() )
1219
1220 SCH_SYMBOL_INSTANCE instance;
1221
1222 if( !GetInstance( instance, aInstance->Path() ) )
1224
1225 if( aVariantName.IsEmpty() )
1227 else if( instance.m_Variants.contains( aVariantName ) )
1228 return instance.m_Variants[aVariantName].m_ExcludedFromPosFiles;
1229
1230 // If variant is not defined yet, return default exclude from position files setting.
1232}
1233
1234
1235void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
1236{
1237 for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
1238 instance.m_Unit = aUnitSelection;
1239}
1240
1241
1242const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aInstance,
1243 bool aAllowExtraText, const wxString& aVariantName ) const
1244{
1245 if( aVariantName.IsEmpty() )
1246 {
1247 if( aResolve )
1248 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1249
1250 return GetField( FIELD_T::VALUE )->GetText();
1251 }
1252
1253 std::optional variant = GetVariant( *aInstance, aVariantName );
1254
1255 if( variant && variant->m_Fields.contains( GetField( FIELD_T::VALUE )->GetName() ) )
1256 return variant->m_Fields[GetField( FIELD_T::VALUE )->GetName()];
1257
1258 // Fall back to default value when variant doesn't have an override
1259 if( aResolve )
1260 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1261
1262 return GetField( FIELD_T::VALUE )->GetText();
1263}
1264
1265
1266void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance,
1267 const wxString& aVariantName )
1268{
1269 if( !aInstance || aVariantName.IsEmpty() )
1270 {
1271 GetField( FIELD_T::VALUE )->SetText( aValue );
1272 return;
1273 }
1274
1275 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1276
1277 wxCHECK( instance, /* void */ );
1278
1279 wxString fieldName = GetField( FIELD_T::VALUE )->GetName();
1280
1281 if( instance->m_Variants.contains( aVariantName ) )
1282 {
1283 instance->m_Variants[aVariantName].m_Fields[fieldName] = aValue;
1284 }
1285 else
1286 {
1287 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1288
1289 newVariant.InitializeAttributes( *this );
1290 newVariant.m_Fields[fieldName] = aValue;
1291 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1292 }
1293}
1294
1295
1296const wxString SCH_SYMBOL::GetFootprintFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
1297 bool aAllowExtraText ) const
1298{
1299 if( aResolve )
1300 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText );
1301
1302 return GetField( FIELD_T::FOOTPRINT )->GetText();
1303}
1304
1305
1306void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
1307{
1308 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
1309}
1310
1311
1313{
1314 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
1315 return field;
1316
1317 m_fields.emplace_back( this, aFieldType );
1318 return &m_fields.back();
1319}
1320
1321
1322const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
1323{
1324 return FindField( m_fields, aFieldType );
1325}
1326
1327
1328SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
1329{
1330 return FindField( m_fields, aFieldName );
1331}
1332
1333
1334const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
1335{
1336 return FindField( m_fields, aFieldName );
1337}
1338
1339
1340void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
1341{
1342 for( const SCH_FIELD& field : m_fields )
1343 {
1344 if( aVisibleOnly )
1345 {
1346 if( !field.IsVisible() || field.GetText().IsEmpty() )
1347 continue;
1348 }
1349
1350 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
1351 }
1352
1353 std::sort( aVector.begin(), aVector.end(),
1354 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1355 {
1356 return lhs->GetOrdinal() < rhs->GetOrdinal();
1357 } );
1358}
1359
1360
1362{
1363 return NextFieldOrdinal( m_fields );
1364}
1365
1366
1368{
1369 m_fields.push_back( aField );
1370 return &m_fields.back();
1371}
1372
1373
1374void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
1375{
1376 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
1377 {
1378 if( m_fields[ii].IsMandatory() )
1379 continue;
1380
1381 if( aFieldName == m_fields[ii].GetName( false ) )
1382 {
1383 m_fields.erase( m_fields.begin() + ii );
1384 return;
1385 }
1386 }
1387}
1388
1389
1391{
1392 for( SCH_FIELD& field : m_fields )
1393 {
1394 if( field.GetName().IsSameAs( aFieldName, false ) )
1395 return &field;
1396 }
1397
1398 return nullptr;
1399}
1400
1401
1402void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
1403 bool aResetRef, bool aResetOtherFields )
1404{
1405 if( m_part )
1406 {
1407 std::vector<SCH_FIELD*> fields;
1408 m_part->GetFields( fields );
1409
1410 for( const SCH_FIELD* libField : fields )
1411 {
1412 SCH_FIELD* schField;
1413 FIELD_T fieldType = FIELD_T::USER;
1414
1415 if( libField->IsMandatory() )
1416 {
1417 fieldType = libField->GetId();
1418 schField = GetField( fieldType );
1419 }
1420 else
1421 {
1422 schField = GetField( libField->GetCanonicalName() );
1423
1424 if( !schField )
1425 {
1426 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetCanonicalName() ) );
1427 schField->ImportValues( *libField );
1428 schField->SetTextPos( m_pos + libField->GetTextPos() );
1429 }
1430 }
1431
1432 schField->SetPrivate( libField->IsPrivate() );
1433
1434 if( aUpdateStyle )
1435 {
1436 schField->ImportValues( *libField );
1437 schField->SetTextPos( m_pos + libField->GetTextPos() );
1438 }
1439
1440 if( fieldType == FIELD_T::REFERENCE && aPath )
1441 {
1442 if( aResetRef )
1443 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
1444 else if( aUpdateRef )
1445 SetRef( aPath, libField->GetText() );
1446 }
1447 else if( fieldType == FIELD_T::VALUE )
1448 {
1449 SetValueFieldText( UnescapeString( libField->GetText() ) );
1450 }
1451 else if( fieldType == FIELD_T::DATASHEET )
1452 {
1453 if( aResetOtherFields )
1454 schField->SetText( GetDatasheet() ); // alias-specific value
1455 else if( aUpdateOtherFields )
1456 schField->SetText( libField->GetText() );
1457 }
1458 else
1459 {
1460 if( aResetOtherFields || aUpdateOtherFields )
1461 schField->SetText( libField->GetText() );
1462 }
1463 }
1464 }
1465}
1466
1467
1468void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit, PROPERTY_BASE* aProperty )
1469{
1470 bool updateValue = true;
1471 bool updateExclFromBOM = true;
1472 bool updateExclFromBoard = true;
1473 bool updateDNP = true;
1474 bool updateOtherFields = true;
1475 bool updatePins = true;
1476
1477 if( aProperty )
1478 {
1479 updateValue = aProperty->Name() == _HKI( "Value" );
1480 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
1481 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
1482 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
1483 updateOtherFields = false;
1484 updatePins = false;
1485 }
1486
1487 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateDNP && !updateOtherFields && !updatePins )
1488 {
1489 return;
1490 }
1491
1492 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
1493 // in sync in multi-unit parts.
1494 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
1495 {
1496 wxString ref = GetRef( &aSourceSheet );
1497
1498 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1499 {
1500 SCH_SCREEN* screen = sheet.LastScreen();
1501 std::vector<SCH_SYMBOL*> otherUnits;
1502
1503 CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
1504
1505 for( SCH_SYMBOL* otherUnit : otherUnits )
1506 {
1507 aCommit.Modify( otherUnit, screen );
1508
1509 if( updateValue )
1510 otherUnit->SetValueFieldText( GetField( FIELD_T::VALUE )->GetText() );
1511
1512 if( updateOtherFields )
1513 {
1514 for( SCH_FIELD& field : m_fields )
1515 {
1516 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
1517 {
1518 // already handled
1519 continue;
1520 }
1521
1522 SCH_FIELD* otherField;
1523
1524 if( field.IsMandatory() )
1525 otherField = otherUnit->GetField( field.GetId() );
1526 else
1527 otherField = otherUnit->GetField( field.GetName() );
1528
1529 if( otherField )
1530 {
1531 otherField->SetText( field.GetText() );
1532 }
1533 else
1534 {
1535 SCH_FIELD newField( field );
1536 const_cast<KIID&>( newField.m_Uuid ) = KIID();
1537
1538 newField.Offset( -GetPosition() );
1539 newField.Offset( otherUnit->GetPosition() );
1540
1541 newField.SetParent( otherUnit );
1542 otherUnit->AddField( newField );
1543 }
1544 }
1545
1546 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
1547 {
1548 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
1549
1550 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
1551 otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
1552 }
1553 }
1554
1555 if( updateExclFromBOM )
1556 otherUnit->SetExcludedFromBOM( m_excludedFromBOM );
1557
1558 if( updateExclFromBoard )
1559 otherUnit->SetExcludedFromBoard( m_excludedFromBoard );
1560
1561 if( updateDNP )
1562 otherUnit->SetDNP( GetDNP( &aSourceSheet ), &sheet );
1563
1564 if( updatePins )
1565 {
1566 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
1567 {
1568 SCH_PIN* src_pin = otherUnit->GetPin( model_pin->GetNumber() );
1569
1570 if( src_pin )
1571 src_pin->SetAlt( model_pin->GetAlt() );
1572 }
1573 }
1574 }
1575 }
1576 }
1577}
1578
1579
1580void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
1581{
1582 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1583 aFunction( pin.get() );
1584
1585 for( SCH_FIELD& field : m_fields )
1586 aFunction( &field );
1587}
1588
1589
1590SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
1591{
1592 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1593 {
1594 if( pin->GetNumber() == aNumber )
1595 return pin.get();
1596 }
1597
1598 return nullptr;
1599}
1600
1601
1602const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
1603{
1604 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1605 {
1606 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
1607 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
1608
1609 if( pin_unit > 0 && pin_unit != GetUnit() )
1610 continue;
1611
1612 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
1613 continue;
1614
1615 if( pin->GetPosition() == aPos )
1616 return pin.get();
1617 }
1618
1619 return nullptr;
1620}
1621
1622
1623std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
1624{
1625 if( m_part )
1626 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
1627
1628 return std::vector<SCH_PIN*>();
1629}
1630
1631
1632std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
1633{
1634 if( m_part )
1635 return m_part->GetPins();
1636
1637 return std::vector<SCH_PIN*>();
1638}
1639
1640
1642{
1643 return m_part ? m_part->GetPinCount() : 0;
1644}
1645
1646
1648{
1649 auto it = m_pinMap.find( aLibPin );
1650
1651 if( it != m_pinMap.end() )
1652 return it->second;
1653
1654 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
1655 return nullptr;
1656}
1657
1658
1659std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
1660{
1661 std::vector<SCH_PIN*> pins;
1662 int unit = m_unit;
1663
1664 if( !aSheet && Schematic() )
1665 aSheet = &Schematic()->CurrentSheet();
1666
1667 if( aSheet )
1668 unit = GetUnitSelection( aSheet );
1669
1670 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1671 {
1672 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
1673 continue;
1674
1675 pins.push_back( pin.get() );
1676 }
1677
1678 return pins;
1679}
1680
1681
1682std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
1683{
1684 return GetPins( nullptr );
1685}
1686
1687
1689{
1690 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
1691
1692 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
1693
1694 std::swap( m_lib_id, symbol->m_lib_id );
1695
1696 m_pins.swap( symbol->m_pins ); // std::vector's swap()
1697
1698 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
1699 pin->SetParent( symbol );
1700
1701 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1702 pin->SetParent( this );
1703
1704 LIB_SYMBOL* libSymbol = symbol->m_part.release();
1705 symbol->m_part = std::move( m_part );
1706 symbol->UpdatePins();
1707 m_part.reset( libSymbol );
1708 UpdatePins();
1709
1710 std::swap( m_pos, symbol->m_pos );
1711 std::swap( m_unit, symbol->m_unit );
1712 std::swap( m_bodyStyle, symbol->m_bodyStyle );
1713
1714 m_fields.swap( symbol->m_fields ); // std::vector's swap()
1715
1716 for( SCH_FIELD& field : symbol->m_fields )
1717 field.SetParent( symbol );
1718
1719 for( SCH_FIELD& field : m_fields )
1720 field.SetParent( this );
1721
1722 TRANSFORM tmp = m_transform;
1723
1724 m_transform = symbol->m_transform;
1725 symbol->m_transform = tmp;
1726
1727 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
1728 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
1729 std::swap( m_DNP, symbol->m_DNP );
1730 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
1731
1732 std::swap( m_instanceReferences, symbol->m_instanceReferences );
1733 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
1734}
1735
1736
1737void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
1738{
1739 for( const SCH_FIELD& field : m_fields )
1740 {
1741 if( field.IsPrivate() )
1742 continue;
1743
1744 if( field.IsMandatory() )
1745 aVars->push_back( field.GetCanonicalName().Upper() );
1746 else
1747 aVars->push_back( field.GetName() );
1748 }
1749
1750 aVars->push_back( wxT( "OP" ) );
1751 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
1752 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
1753 aVars->push_back( wxT( "UNIT" ) );
1754 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
1755 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
1756 aVars->push_back( wxT( "SYMBOL_NAME" ) );
1757 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
1758 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
1759 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
1760 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
1761 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
1762 aVars->push_back( wxT( "DNP" ) );
1763 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
1764 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
1765 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
1766 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
1767 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
1768 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
1769 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
1770}
1771
1772
1773bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
1774{
1775 return ResolveTextVar( aPath, token, wxEmptyString, aDepth );
1776}
1777
1778
1779bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token,
1780 const wxString& aVariantName, int aDepth ) const
1781{
1782 static wxRegEx operatingPoint( wxT( "^"
1783 "OP"
1784 "(:[^.]*)?" // pin
1785 "(.([0-9])?" // precisionStr
1786 "([a-zA-Z]*))?" // rangeStr
1787 "$" ) );
1788
1789 wxCHECK( aPath, false );
1790
1791 SCHEMATIC* schematic = Schematic();
1792
1793 if( !schematic )
1794 return false;
1795
1796 if( operatingPoint.Matches( *token ) )
1797 {
1798 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
1799 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
1800 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
1801
1802 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
1803 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
1804
1805 SIM_LIB_MGR simLibMgr( &schematic->Project() );
1806
1807 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
1808 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
1809
1810 if( m_part )
1811 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
1812
1813 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
1814
1815 NULL_REPORTER devnull;
1816 SIM_MODEL& model =
1817 simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1, devnull ).model;
1818 SPICE_ITEM spiceItem;
1819 spiceItem.refName = GetRef( aPath );
1820
1821 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
1822 spiceRef = spiceRef.Lower();
1823
1824 if( pin.IsEmpty() )
1825 {
1826 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1827 return true;
1828 }
1829 else if( pin == wxS( ":power" ) )
1830 {
1831 if( rangeStr.IsEmpty() )
1832 range = wxS( "~W" );
1833
1834 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
1835 return true;
1836 }
1837 else
1838 {
1839 pin = pin.SubString( 1, -1 ); // Strip ':' from front
1840
1841 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
1842 {
1843 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
1844
1845 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
1846 {
1847 if( model.GetPins().size() == 2 )
1848 {
1849 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1850 }
1851 else
1852 {
1853 wxString signalName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
1854 *token = schematic->GetOperatingPoint( signalName, precision, range );
1855 }
1856
1857 return true;
1858 }
1859 }
1860 }
1861
1862 *token = wxS( "?" );
1863 return true;
1864 }
1865
1866 if( token->Contains( ':' ) )
1867 {
1868 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
1869 return true;
1870 }
1871
1872 for( const SCH_FIELD& field : m_fields )
1873 {
1874 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName() : field.GetName();
1875
1876 wxString textToken = field.GetText();
1877 textToken.Replace( " ", wxEmptyString );
1878 wxString tokenString = "${" + fieldName + "}";
1879
1880 // If the field data is just a reference to the field, don't resolve
1881 if( textToken.IsSameAs( tokenString, false ) )
1882 return true;
1883
1884 if( token->IsSameAs( fieldName, false ) )
1885 {
1886 if( field.GetId() == FIELD_T::REFERENCE )
1887 {
1888 *token = GetRef( aPath, true );
1889 }
1890 else if( !aVariantName.IsEmpty() )
1891 {
1892 // Check for variant-specific field value
1893 std::optional<SCH_SYMBOL_VARIANT> variant = GetVariant( *aPath, aVariantName );
1894
1895 if( variant && variant->m_Fields.contains( fieldName ) )
1896 *token = variant->m_Fields.at( fieldName );
1897 else
1898 *token = field.GetShownText( aPath, false, aDepth + 1 );
1899 }
1900 else
1901 {
1902 *token = field.GetShownText( aPath, false, aDepth + 1 );
1903 }
1904
1905 return true;
1906 }
1907 }
1908
1909 // Consider missing simulation fields as empty, not un-resolved
1910 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
1911 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
1912 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
1913 {
1914 *token = wxEmptyString;
1915 return true;
1916 }
1917
1918 for( const TEMPLATE_FIELDNAME& templateFieldname :
1920 {
1921 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
1922 {
1923 // If we didn't find it in the fields list then it isn't set on this symbol.
1924 // Just return an empty string.
1925 *token = wxEmptyString;
1926 return true;
1927 }
1928 }
1929
1930 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1931 {
1932 wxString footprint = GetFootprintFieldText( true, aPath, false );
1933
1934 wxArrayString parts = wxSplit( footprint, ':' );
1935
1936 if( parts.Count() > 0 )
1937 *token = parts[0];
1938 else
1939 *token = wxEmptyString;
1940
1941 return true;
1942 }
1943 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1944 {
1945 wxString footprint = GetFootprintFieldText( true, aPath, false );
1946
1947 wxArrayString parts = wxSplit( footprint, ':' );
1948
1949 if( parts.Count() > 1 )
1950 *token = parts[std::min( 1, (int) parts.size() - 1 )];
1951 else
1952 *token = wxEmptyString;
1953
1954 return true;
1955 }
1956 else if( token->IsSameAs( wxT( "UNIT" ) ) )
1957 {
1958 *token = SubReference( GetUnitSelection( aPath ) );
1959 return true;
1960 }
1961 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
1962 {
1963 *token = GetRef( aPath, false );
1964 return true;
1965 }
1966 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
1967 {
1968 *token = m_lib_id.GetUniStringLibNickname();
1969 return true;
1970 }
1971 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
1972 {
1973 *token = m_lib_id.GetUniStringLibItemName();
1974 return true;
1975 }
1976 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
1977 {
1978 *token = GetShownDescription( aDepth + 1 );
1979 return true;
1980 }
1981 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
1982 {
1983 *token = GetShownKeyWords( aDepth + 1 );
1984 return true;
1985 }
1986 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
1987 {
1988 *token = wxEmptyString;
1989
1990 if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
1991 *token = _( "Excluded from BOM" );
1992
1993 return true;
1994 }
1995 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
1996 {
1997 *token = wxEmptyString;
1998
1999 if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
2000 *token = _( "Excluded from board" );
2001
2002 return true;
2003 }
2004 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
2005 {
2006 *token = wxEmptyString;
2007
2008 if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
2009 *token = _( "Excluded from simulation" );
2010
2011 return true;
2012 }
2013 else if( token->IsSameAs( wxT( "DNP" ) ) )
2014 {
2015 *token = wxEmptyString;
2016
2017 if( aPath->GetDNP() || this->ResolveDNP() )
2018 *token = _( "DNP" );
2019
2020 return true;
2021 }
2022 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
2023 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
2024 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
2025 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
2026 || token->StartsWith( wxT( "UNIT(" ) ) )
2027 {
2028 wxString pinNumber = token->AfterFirst( '(' );
2029 pinNumber = pinNumber.BeforeLast( ')' );
2030
2031 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
2032 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
2033 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
2034
2035 // First, try to find the pin in the current unit (for backward compatibility)
2036 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
2037 std::vector<SCH_PIN*> pinsToSearch = ( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2038 ? GetAllLibPins() : GetPins( aPath );
2039
2040 for( SCH_PIN* pin : pinsToSearch )
2041 {
2042 if( pin->GetNumber() == pinNumber )
2043 {
2044 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2045 {
2046 int pinUnit = pin->GetUnit();
2047 wxString result;
2048
2049 if( isReferenceFunction )
2050 {
2051 // Return the full unit reference (e.g., "J601A")
2052 if( pinUnit > 0 )
2053 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
2054 else
2055 result = GetRef( aPath, false );
2056 }
2057 else if( isShortReferenceFunction )
2058 {
2059 // Return the reference without unit (e.g., "J601")
2060 result = GetRef( aPath, false );
2061 }
2062 else if( isUnitFunction )
2063 {
2064 // Return only the unit letter (e.g., "A")
2065 if( pinUnit > 0 )
2066 result = SubReference( pinUnit, false );
2067 else
2068 result = wxEmptyString;
2069 }
2070
2071 *token = result;
2072 return true;
2073 }
2074 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2075 {
2076 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
2077 return true;
2078 }
2079 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2080 {
2081 *token = pin->GetBaseName();
2082 return true;
2083 }
2084 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2085 {
2086 // Build list of alternate names only (no base name)
2087 wxString altList;
2088
2089 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2090 for( const auto& [altName, altDef] : alts )
2091 {
2092 if( !altList.IsEmpty() )
2093 altList += wxT( ", " );
2094 altList += altName;
2095 }
2096
2097 *token = altList;
2098 return true;
2099 }
2100
2101 SCH_CONNECTION* conn = pin->Connection( aPath );
2102
2103 if( !conn )
2104 *token = wxEmptyString;
2105 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2106 {
2107 wxString netName = conn->LocalName();
2108 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2109 *token = wxT( "NC" );
2110 else
2111 *token = netName;
2112 }
2113 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2114 *token = conn->Name();
2115 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2116 *token = pin->GetEffectiveNetClass( aPath )->GetName();
2117
2118 return true;
2119 }
2120 }
2121
2122 // If pin not found in current unit, search all units (auto-resolution)
2123 // Skip this for REFERENCE/SHORT_REFERENCE/UNIT functions as they already searched all units
2124 if( !isReferenceFunction && !isShortReferenceFunction && !isUnitFunction )
2125 {
2126 for( SCH_PIN* pin : GetAllLibPins() )
2127 {
2128 if( pin->GetNumber() == pinNumber )
2129 {
2130 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
2131 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2132 {
2133 *token = pin->GetBaseName();
2134 return true;
2135 }
2136 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2137 {
2138 // Build list of alternate names only (no base name)
2139 wxString altList;
2140
2141 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2142 for( const auto& [altName, altDef] : alts )
2143 {
2144 if( !altList.IsEmpty() )
2145 altList += wxT( ", " );
2146 altList += altName;
2147 }
2148
2149 *token = altList;
2150 return true;
2151 }
2152
2153 // For net-related functions, find which sheet path has this pin's unit
2154 int pinUnit = pin->GetUnit();
2155
2156 // Search all sheets for a symbol with our reference and the correct unit
2157 // This is needed because each unit of a multi-unit symbol is a separate object
2158 SCH_SHEET_PATH targetPath;
2159 SCH_SYMBOL* targetSymbol = nullptr;
2160
2161 if( Schematic() )
2162 {
2163 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
2164 {
2165 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2166 {
2167 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2168
2169 // Check if this symbol has the same reference designator and the correct unit
2170 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
2171 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
2172 {
2173 targetPath = sheetPath; // Copy the sheet path
2174 targetSymbol = symbol;
2175 break;
2176 }
2177 }
2178
2179 if( targetSymbol )
2180 break;
2181 }
2182 }
2183
2184 if( !targetSymbol )
2185 {
2186 // Unit not placed on any sheet
2187 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
2188 return true;
2189 }
2190
2191 // Get the pin from the actual instance symbol we found
2192 // Match by pin number, not by pointer, since the library pins are different objects
2193 SCH_PIN* instancePin = nullptr;
2194 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
2195 {
2196 if( candidate->GetNumber() == pinNumber )
2197 {
2198 instancePin = candidate;
2199 break;
2200 }
2201 }
2202
2203 if( !instancePin )
2204 {
2205 *token = wxEmptyString;
2206 return true;
2207 }
2208
2209 // PIN_NAME doesn't need connection data, just instance pin
2210 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2211 {
2212 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
2213 return true;
2214 }
2215
2216 // Now get the connection from the correct sheet path
2217 SCH_CONNECTION* conn = instancePin->Connection( &targetPath );
2218
2219 if( !conn )
2220 *token = wxEmptyString;
2221 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2222 {
2223 wxString netName = conn->LocalName();
2224 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2225 *token = wxT( "NC" );
2226 else
2227 *token = netName;
2228 }
2229 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2230 *token = conn->Name();
2231 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2232 *token = instancePin->GetEffectiveNetClass( &targetPath )->GetName();
2233
2234 return true;
2235 }
2236 }
2237 }
2238
2239 // If we got here, no pin was found - report unresolved
2240 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
2241 return true;
2242 }
2243
2244 // See if parent can resolve it (this will recurse to ancestors)
2245 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
2246 return true;
2247
2248 return false;
2249}
2250
2251
2252void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
2253{
2254 if( aSheetPath )
2255 {
2256 KIID_PATH path = aSheetPath->Path();
2257
2258 for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
2259 {
2260 if( instance.m_Path == path )
2261 {
2262 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2263 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2264 else
2265 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2266 }
2267 }
2268 }
2269 else
2270 {
2271 for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
2272 {
2273 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2274 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2275 else
2276 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2277 }
2278 }
2279
2280 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2281 pin->ClearDefaultNetName( aSheetPath );
2282
2283 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
2284 // When clearing for a specific sheet path, we must preserve the field text because it serves
2285 // as a fallback for GetRef() when instances for other sheet paths are looked up.
2286 // See issue #20173: modifying field text here corrupts references in shared screens.
2287 if( !aSheetPath )
2288 {
2289 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
2290
2291 if( currentReference.IsEmpty() || aResetPrefix )
2293 else
2295 }
2296}
2297
2298
2300{
2301 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
2302 wxCHECK( aSheetPath.size() > 0, false );
2303
2304 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
2305 {
2306 // if aSheetPath is found, nothing to do:
2307 if( instance.m_Path == aSheetPath )
2308 return false;
2309 }
2310
2311 // This entry does not exist: add it, with its last-used reference
2312 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
2313 return true;
2314}
2315
2316
2317void SCH_SYMBOL::SetOrientation( int aOrientation )
2318{
2319 TRANSFORM temp = TRANSFORM();
2320 bool transform = false;
2321
2322 switch( aOrientation )
2323 {
2324 case SYM_ORIENT_0:
2325 case SYM_NORMAL: // default transform matrix
2327 break;
2328
2329 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
2330 temp.x1 = 0;
2331 temp.y1 = 1;
2332 temp.x2 = -1;
2333 temp.y2 = 0;
2334 transform = true;
2335 break;
2336
2337 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
2338 temp.x1 = 0;
2339 temp.y1 = -1;
2340 temp.x2 = 1;
2341 temp.y2 = 0;
2342 transform = true;
2343 break;
2344
2345 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
2346 temp.x1 = -1;
2347 temp.y1 = 0;
2348 temp.x2 = 0;
2349 temp.y2 = 1;
2350 transform = true;
2351 break;
2352
2353 case SYM_MIRROR_X: // Mirror X (incremental transform)
2354 temp.x1 = 1;
2355 temp.y1 = 0;
2356 temp.x2 = 0;
2357 temp.y2 = -1;
2358 transform = true;
2359 break;
2360
2361 case SYM_ORIENT_90:
2364 break;
2365
2366 case SYM_ORIENT_180:
2370 break;
2371
2372 case SYM_ORIENT_270:
2375 break;
2376
2377 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
2380 break;
2381
2382 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
2385 break;
2386
2391 break;
2392
2393 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
2396 break;
2397
2398 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
2401 break;
2402
2407 break;
2408
2409 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
2412 break;
2413
2414 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
2417 break;
2418
2423 break;
2424
2425 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
2428 break;
2429
2430 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
2433 break;
2434
2439 break;
2440
2441 default:
2442 transform = false;
2443 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
2444 break;
2445 }
2446
2447 if( transform )
2448 {
2449 /* The new matrix transform is the old matrix transform modified by the
2450 * requested transformation, which is the temp transform (rot,
2451 * mirror ..) in order to have (in term of matrix transform):
2452 * transform coord = new_m_transform * coord
2453 * where transform coord is the coord modified by new_m_transform from
2454 * the initial value coord.
2455 * new_m_transform is computed (from old_m_transform and temp) to
2456 * have:
2457 * transform coord = old_m_transform * temp
2458 */
2459 TRANSFORM newTransform;
2460
2461 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
2462 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
2463 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
2464 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
2465 m_transform = newTransform;
2466 }
2467}
2468
2469
2471{
2472 /*
2473 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
2474 * now, so let's just cache it for the moment.
2475 */
2478
2479 int rotate_values[] = { SYM_ORIENT_0,
2491
2492 // Try to find the current transform option:
2493 TRANSFORM transform = m_transform;
2494 SCH_SYMBOL temp( *this );
2495 temp.SetParentGroup( nullptr );
2496
2497 for( int type_rotate : rotate_values )
2498 {
2499 temp.SetOrientation( type_rotate );
2500
2501 if( transform == temp.GetTransform() )
2502 {
2504 return type_rotate;
2505 }
2506 }
2507
2508 // Error: orientation not found in list (should not happen)
2509 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
2510
2511 return SYM_NORMAL;
2512}
2513
2514
2515#if defined( DEBUG )
2516
2517void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
2518{
2519 // for now, make it look like XML:
2520 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
2521 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
2522 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
2523 << ">\n";
2524
2525 // skip the reference, it's been output already.
2526 for( int i = 1; i < (int) GetFields().size(); ++i )
2527 {
2528 const wxString& value = GetFields()[i].GetText();
2529
2530 if( !value.IsEmpty() )
2531 {
2532 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
2533 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
2534 }
2535 }
2536
2537 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
2538}
2539
2540#endif
2541
2542
2543BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
2544{
2545 BOX2I bBox;
2546
2547 if( m_part )
2548 bBox = m_part->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2549 else
2550 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2551
2552 bBox = m_transform.TransformCoordinate( bBox );
2553 bBox.Normalize();
2554
2555 bBox.Offset( m_pos );
2556
2557 if( aIncludeFields )
2558 {
2559 for( const SCH_FIELD& field : m_fields )
2560 {
2561 if( field.IsVisible() )
2562 bBox.Merge( field.GetBoundingBox() );
2563 }
2564 }
2565
2566 return bBox;
2567}
2568
2569
2571{
2572 try
2573 {
2574 return doGetBoundingBox( false, false );
2575 }
2576 catch( const boost::bad_pointer& e )
2577 {
2578 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
2579 return BOX2I();
2580 }
2581}
2582
2583
2585{
2586 return doGetBoundingBox( true, false );
2587}
2588
2589
2591{
2592 return doGetBoundingBox( true, true );
2593}
2594
2595
2596void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2597{
2598 wxString msg;
2599
2600 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
2601 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
2602
2603 auto addExcludes = [&]()
2604 {
2605 wxArrayString msgs;
2606
2607 if( GetExcludedFromSim() )
2608 msgs.Add( _( "Simulation" ) );
2609
2610 if( GetExcludedFromBOM() )
2611 msgs.Add( _( "BOM" ) );
2612
2613 if( GetExcludedFromBoard() )
2614 msgs.Add( _( "Board" ) );
2615
2616 if( GetDNP( currentSheet ) )
2617 msgs.Add( _( "DNP" ) );
2618
2619 msg = wxJoin( msgs, '|' );
2620 msg.Replace( '|', wxS( ", " ) );
2621
2622 if( !msg.empty() )
2623 aList.emplace_back( _( "Exclude from" ), msg );
2624 };
2625
2626 // part and alias can differ if alias is not the root
2627 if( m_part )
2628 {
2629 if( m_part.get() != LIB_SYMBOL::GetDummy() )
2630 {
2631 if( m_part->IsPower() )
2632 {
2633 // Don't use GetShownText(); we want to see the variable references here
2634 aList.emplace_back( _( "Power symbol" ),
2635 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2636 }
2637 else
2638 {
2639 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
2640
2641 // Don't use GetShownText(); we want to see the variable references here
2642 aList.emplace_back( _( "Value" ),
2643 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2644 addExcludes();
2645 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2646 }
2647
2648#if 0 // Display symbol flags, for debug only
2649 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
2650#endif
2651
2652 if( !m_part->IsRoot() )
2653 {
2654 msg = _( "Missing parent" );
2655
2656 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
2657
2658 if( parent )
2659 msg = parent->GetName();
2660
2661 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
2662 }
2663 else if( !m_lib_id.GetLibNickname().empty() )
2664 {
2665 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
2666 }
2667 else
2668 {
2669 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
2670 }
2671
2672 // Display the current associated footprint, if exists.
2673 // Don't use GetShownText(); we want to see the variable references here
2674 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
2675
2676 if( msg.IsEmpty() )
2677 msg = _( "<Unknown>" );
2678
2679 aList.emplace_back( _( "Footprint" ), msg );
2680
2681 // Display description of the symbol, and keywords found in lib
2682 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
2683 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
2684 }
2685 }
2686 else
2687 {
2688 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
2689
2690 // Don't use GetShownText(); we want to see the variable references here
2691 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2692 addExcludes();
2693 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2694
2695 wxString libNickname = GetLibId().GetLibNickname();
2696
2697 if( libNickname.empty() )
2698 msg = _( "No library defined!" );
2699 else
2700 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
2701
2702 aList.emplace_back( _( "Library" ), msg );
2703 }
2704}
2705
2706
2711
2712
2714{
2715 std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
2716
2717 if( !libSymbolRef )
2718 return nullptr;
2719
2721}
2722
2723
2725{
2726 int dx = m_pos.x;
2727
2729 MIRROR( m_pos.x, aCenter );
2730 dx -= m_pos.x; // dx,0 is the move vector for this transform
2731
2732 for( SCH_FIELD& field : m_fields )
2733 {
2734 // Move the fields to the new position because the symbol itself has moved.
2735 VECTOR2I pos = field.GetTextPos();
2736 pos.x -= dx;
2737 field.SetTextPos( pos );
2738 }
2739}
2740
2741
2743{
2744 int dy = m_pos.y;
2745
2747 MIRROR( m_pos.y, aCenter );
2748 dy -= m_pos.y; // 0,dy is the move vector for this transform
2749
2750 for( SCH_FIELD& field : m_fields )
2751 {
2752 // Move the fields to the new position because the symbol itself has moved.
2753 VECTOR2I pos = field.GetTextPos();
2754 pos.y -= dy;
2755 field.SetTextPos( pos );
2756 }
2757}
2758
2759
2760void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
2761{
2762 VECTOR2I prev = m_pos;
2763
2764 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
2765
2767
2768 for( SCH_FIELD& field : m_fields )
2769 {
2770 // Move the fields to the new position because the symbol itself has moved.
2771 VECTOR2I pos = field.GetTextPos();
2772 pos.x -= prev.x - m_pos.x;
2773 pos.y -= prev.y - m_pos.y;
2774 field.SetTextPos( pos );
2775 }
2776}
2777
2778
2779bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
2780{
2781 if( aSearchData.searchMetadata )
2782 {
2783 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
2784 return true;
2785
2786 if( EDA_ITEM::Matches( GetShownDescription(), aSearchData ) )
2787 return true;
2788
2789 if( EDA_ITEM::Matches( GetShownKeyWords(), aSearchData ) )
2790 return true;
2791 }
2792
2793 for( SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
2794 {
2795 if( drawItem.Matches( aSearchData, aAuxData ) )
2796 return true;
2797 }
2798
2799 // Symbols are searchable via the child field and pin item text.
2800 return false;
2801}
2802
2803
2804void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
2805{
2806 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2807 {
2808 SCH_PIN* lib_pin = pin->GetLibPin();
2809
2810 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
2811 continue;
2812
2813 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
2814 aItemList.push_back( item );
2815 }
2816}
2817
2818
2819bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
2820 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
2821{
2822 bool changed = false;
2823
2824 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2825 {
2826 bool previousState = pin->IsDangling();
2827 pin->SetIsDangling( true );
2828
2829 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
2830
2831 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
2832 bool do_break = false;
2833
2834 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
2835 {
2836 DANGLING_END_ITEM& each_item = *it;
2837
2838 // Some people like to stack pins on top of each other in a symbol to indicate
2839 // internal connection. While technically connected, it is not particularly useful
2840 // to display them that way, so skip any pins that are in the same symbol as this
2841 // one.
2842 if( each_item.GetParent() == this )
2843 continue;
2844
2845 switch( each_item.GetType() )
2846 {
2847 case PIN_END:
2848 case LABEL_END:
2849 case SHEET_LABEL_END:
2850 case WIRE_END:
2851 case NO_CONNECT_END:
2852 case JUNCTION_END:
2853 pin->SetIsDangling( false );
2854 do_break = true;
2855 break;
2856
2857 default: break;
2858 }
2859
2860 if( do_break )
2861 break;
2862 }
2863
2864 changed = ( changed || ( previousState != pin->IsDangling() ) );
2865 }
2866
2867 return changed;
2868}
2869
2870
2872{
2873 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
2874 return VECTOR2I( 0, 0 );
2875
2876 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
2877}
2878
2879
2880bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
2881{
2882 // Do not compare to ourself.
2883 if( aItem == this )
2884 return false;
2885
2886 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
2887
2888 // Don't compare against a different SCH_ITEM.
2889 wxCHECK( symbol, false );
2890
2891 // The move algorithm marks any pins that are being moved without something attached
2892 // (during the move) as dangling. We always need to recheck connectivity in this case
2893 // or we will not notice changes when the user places the symbol back in the same position
2894 // it started.
2895 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2896 {
2897 if( pin->IsDangling() )
2898 return true;
2899 }
2900
2901 if( GetPosition() != symbol->GetPosition() )
2902 return true;
2903
2904 if( GetLibId() != symbol->GetLibId() )
2905 return true;
2906
2907 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
2908 return true;
2909
2910 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
2911 return true;
2912
2913 // Power symbol value field changes are connectivity changes.
2914 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
2915 return true;
2916
2917 if( m_pins.size() != symbol->m_pins.size() )
2918 return true;
2919
2920 for( size_t i = 0; i < m_pins.size(); i++ )
2921 {
2922 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
2923 return true;
2924 }
2925
2926 return false;
2927}
2928
2929
2930std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
2931{
2932 std::vector<VECTOR2I> retval;
2933
2934 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2935 {
2936 // Collect only pins attached to the current unit and convert.
2937 // others are not associated to this symbol instance
2938 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2939 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2940
2941 if( pin_unit > 0 && pin_unit != GetUnit() )
2942 continue;
2943
2944 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
2945 continue;
2946
2947 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
2948 }
2949
2950 return retval;
2951}
2952
2953
2955{
2956 if( m_part )
2957 {
2958 // Calculate the position relative to the symbol.
2959 VECTOR2I libPosition = aPosition - m_pos;
2960
2961 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
2962 }
2963
2964 return nullptr;
2965}
2966
2967
2968wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2969{
2970 return wxString::Format( _( "Symbol %s [%s]" ),
2972 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
2973}
2974
2975
2976INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
2977{
2978 for( KICAD_T scanType : aScanTypes )
2979 {
2980 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
2981 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
2982 {
2983 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
2984 return INSPECT_RESULT::QUIT;
2985 }
2986
2987 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
2988 {
2989 for( SCH_FIELD& field : m_fields )
2990 {
2991 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
2992 return INSPECT_RESULT::QUIT;
2993 }
2994 }
2995
2996 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
2997 {
2998 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
2999 return INSPECT_RESULT::QUIT;
3000 }
3001
3002 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3003 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3004 {
3005 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3006 return INSPECT_RESULT::QUIT;
3007 }
3008
3009 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3010 {
3011 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3012 return INSPECT_RESULT::QUIT;
3013 }
3014
3015 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3016 {
3017 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3018 return INSPECT_RESULT::QUIT;
3019 }
3020
3021 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3022 {
3023 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3024 {
3025 // Collect only pins attached to the current unit and convert.
3026 // others are not associated to this symbol instance
3027 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3028 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3029
3030 if( pin_unit > 0 && pin_unit != GetUnit() )
3031 continue;
3032
3033 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3034 continue;
3035
3036 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3037 return INSPECT_RESULT::QUIT;
3038 }
3039 }
3040 }
3041
3043}
3044
3045
3046bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3047{
3048 if( Type() != aItem.Type() )
3049 return Type() < aItem.Type();
3050
3051 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3052
3054
3055 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3056 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3057
3058 if( m_pos.x != symbol->m_pos.x )
3059 return m_pos.x < symbol->m_pos.x;
3060
3061 if( m_pos.y != symbol->m_pos.y )
3062 return m_pos.y < symbol->m_pos.y;
3063
3064 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3065}
3066
3067
3068bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3069{
3070 std::vector<SCH_FIELD*> fields, otherFields;
3071
3072 GetFields( fields, false );
3073 aSymbol.GetFields( otherFields, false );
3074
3075 if( fields.size() != otherFields.size() )
3076 return false;
3077
3078 for( int ii = 0; ii < (int) fields.size(); ii++ )
3079 {
3080 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3081 continue;
3082
3083 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3084 return false;
3085 }
3086
3087 return true;
3088}
3089
3090
3091bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3092{
3093 return !( *this == aSymbol );
3094}
3095
3096
3098{
3099 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3100 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3101
3102 if( &aSymbol != this )
3103 {
3104 SYMBOL::operator=( aSymbol );
3105
3106 m_lib_id = aSymbol.m_lib_id;
3107 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3108 m_pos = aSymbol.m_pos;
3109 m_unit = aSymbol.m_unit;
3110 m_bodyStyle = aSymbol.m_bodyStyle;
3111 m_transform = aSymbol.m_transform;
3112
3114
3115 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3116
3117 // Reparent fields after assignment to new symbol.
3118 for( SCH_FIELD& field : m_fields )
3119 field.SetParent( this );
3120
3121 UpdatePins();
3122 }
3123
3124 return *this;
3125}
3126
3127
3128bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3129{
3130 BOX2I bBox = GetBodyBoundingBox();
3131 bBox.Inflate( aAccuracy / 2 );
3132
3133 if( bBox.Contains( aPosition ) )
3134 return true;
3135
3136 return false;
3137}
3138
3139
3140bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3141{
3143 return false;
3144
3145 BOX2I rect = aRect;
3146
3147 rect.Inflate( aAccuracy / 2 );
3148
3149 if( aContained )
3150 return rect.Contains( GetBodyBoundingBox() );
3151
3152 return rect.Intersects( GetBodyBoundingBox() );
3153}
3154
3155
3156bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3157{
3159 return false;
3160
3161 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3162}
3163
3164
3165bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3166{
3167 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3168
3169 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3170 {
3171 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3172 continue;
3173
3174 // Collect only pins attached to the current unit and convert.
3175 // others are not associated to this symbol instance
3176 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3177 continue;
3178
3179 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3180 continue;
3181
3182 if( pin->GetLocalPosition() == new_pos )
3183 return true;
3184 }
3185
3186 return false;
3187}
3188
3189
3191{
3192 return m_isInNetlist;
3193}
3194
3195
3196void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3197 const VECTOR2I& aOffset, bool aDimmed )
3198{
3199 if( aBackground )
3200 return;
3201
3202 if( m_part )
3203 {
3204 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3205
3206 // Copy the source so we can re-orient and translate it.
3207 LIB_SYMBOL tempSymbol( *m_part );
3208 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3209
3210 // Copy the pin info from the symbol to the temp pins
3211 for( unsigned i = 0; i < tempPins.size(); ++i )
3212 {
3213 SCH_PIN* symbolPin = GetPin( libPins[i] );
3214 SCH_PIN* tempPin = tempPins[i];
3215
3216 if( !symbolPin )
3217 continue;
3218
3219 tempPin->SetName( symbolPin->GetShownName() );
3220 tempPin->SetType( symbolPin->GetType() );
3221 tempPin->SetShape( symbolPin->GetShape() );
3222
3223 if( symbolPin->IsDangling() )
3224 tempPin->SetFlags( IS_DANGLING );
3225 }
3226
3227 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3228 {
3229 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3230 {
3231 // Use SCH_FIELD's text resolver
3232 SCH_FIELD dummy( this, FIELD_T::USER );
3233 dummy.SetText( text->GetText() );
3234 text->SetText( dummy.GetShownText( false ) );
3235 }
3236 }
3237
3238 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3239 TRANSFORM savedTransform = renderSettings->m_Transform;
3240 renderSettings->m_Transform = GetTransform();
3241 aPlotter->StartBlock( nullptr );
3242
3243 for( bool local_background : { true, false } )
3244 {
3245 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3246
3247 for( SCH_FIELD field : m_fields )
3248 {
3249 field.ClearRenderCache();
3250 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3251
3252 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3253 && ( field.IsVisible() || field.IsForceVisible() ) )
3254 {
3255 PlotLocalPowerIconShape( aPlotter );
3256 }
3257 }
3258 }
3259
3260 wxString variant = Schematic()->GetCurrentVariant();
3261 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
3262
3263 if( GetDNP( sheet, variant ) )
3264 PlotDNP( aPlotter );
3265
3266 // Plot attributes to a hypertext menu
3267 if( aPlotOpts.m_PDFPropertyPopups )
3268 {
3269 std::vector<wxString> properties;
3270
3271 for( const SCH_FIELD& field : GetFields() )
3272 {
3273 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3274
3275 if( text_field.IsEmpty() )
3276 continue;
3277
3278 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3279 }
3280
3281 if( !m_part->GetKeyWords().IsEmpty() )
3282 {
3283 properties.emplace_back(
3284 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ), m_part->GetKeyWords() ) );
3285 }
3286
3287 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3288 }
3289
3290 aPlotter->EndBlock( nullptr );
3291 renderSettings->m_Transform = savedTransform;
3292
3293 if( !m_part->IsPower() )
3294 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3295 }
3296}
3297
3298
3299void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3300{
3301 BOX2I bbox = GetBodyBoundingBox();
3303 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3304 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3305 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3306
3307 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3308 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3309 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3310
3311 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3312 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3313
3314 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3315
3316 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3317 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3318}
3319
3320
3324static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3325{
3326 double lineWidth = aSize / 10.0;
3327
3328 std::vector<SCH_SHAPE> shapeList;
3329 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3330 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3331
3332 for( const SCH_SHAPE& shape : shapeList )
3333 {
3334 // Currently there are only 2 shapes: BEZIER and CIRCLE
3335 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3336
3337 if( shape.GetShape() == SHAPE_T::BEZIER )
3338 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3339 tolerance, lineWidth );
3340 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3341 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3342 }
3343}
3344
3346{
3347 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3348
3349 // Plot the local power pin indicator icon shape
3350 BOX2I bbox = field->GetBoundingBox();
3351
3352 // Calculate the text orientation according to the parent orientation.
3353 EDA_ANGLE orient = field->GetTextAngle();
3354
3355 if( GetTransform().y1 )
3356 {
3357 // Rotate symbol 90 degrees.
3358 if( orient.IsHorizontal() )
3359 orient = ANGLE_VERTICAL;
3360 else
3361 orient = ANGLE_HORIZONTAL;
3362 }
3363
3364 bool rotated = !orient.IsHorizontal();
3365
3366 VECTOR2D pos;
3367 double size = bbox.GetHeight() / 1.5;
3368
3369 if( rotated )
3370 {
3371 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3372 size = bbox.GetWidth() / 1.5;
3373 }
3374 else
3375 {
3376 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3377 }
3378
3379 // TODO: build and plot icon shape
3380 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3381}
3382
3383
3384void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter ) const
3385{
3386 if( m_part )
3387 {
3388 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3389 TRANSFORM savedTransform = renderSettings->m_Transform;
3390 renderSettings->m_Transform = GetTransform();
3391
3392 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3393
3394 // Copy the source to stay const
3395 LIB_SYMBOL tempSymbol( *m_part );
3396 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3397 SCH_PLOT_OPTS plotOpts;
3398
3399 // Copy the pin info from the symbol to the temp pins
3400 for( unsigned i = 0; i < tempPins.size(); ++i )
3401 {
3402 SCH_PIN* symbolPin = GetPin( libPins[i] );
3403 SCH_PIN* tempPin = tempPins[i];
3404
3405 if( !symbolPin )
3406 continue;
3407
3408 tempPin->SetName( symbolPin->GetShownName() );
3409 tempPin->SetType( symbolPin->GetType() );
3410 tempPin->SetShape( symbolPin->GetShape() );
3411 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3412 }
3413
3414 renderSettings->m_Transform = savedTransform;
3415 }
3416}
3417
3418
3420{
3421 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3422 {
3423 if( pin->IsBrightened() )
3424 return true;
3425 }
3426
3427 return false;
3428}
3429
3430
3432{
3433 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3434 pin->ClearBrightened();
3435}
3436
3437
3438/*
3439 * When modified at the schematic level, we still store the values of these flags in the
3440 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
3441 * will be created and stored locally in the schematic.
3442 */
3444{
3445 return m_part && m_part->GetShowPinNames();
3446}
3447
3448
3450{
3451 if( m_part )
3452 m_part->SetShowPinNames( aShow );
3453}
3454
3455
3457{
3458 return m_part && m_part->GetShowPinNumbers();
3459}
3460
3461
3463{
3464 if( m_part )
3465 m_part->SetShowPinNumbers( aShow );
3466}
3467
3468
3470{
3471 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3472 {
3473 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3474 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3475
3476 if( pin_unit > 0 && pin_unit != GetUnit() )
3477 continue;
3478
3479 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3480 continue;
3481
3482 if( pin->IsPointClickableAnchor( aPos ) )
3483 return true;
3484 }
3485
3486 return false;
3487}
3488
3489
3491{
3492 // return true if the symbol is equivalent to a global label:
3493 // It is a Power symbol
3494 // It has only one pin type Power input
3495
3497 return false;
3498
3499 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3500
3501 if( pin_list.size() != 1 )
3502 return false;
3503
3504 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3505}
3506
3507
3509{
3510 // return true if the symbol is equivalent to a local label:
3511 // It is a Power symbol
3512 // It has only one pin type Power input
3513
3515 return false;
3516
3517 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3518
3519 if( pin_list.size() != 1 )
3520 return false;
3521
3522 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3523}
3524
3525
3527{
3528 if( !m_part )
3529 return false;
3530
3531 return m_part->IsLocalPower();
3532}
3533
3534
3536{
3537 if( !m_part )
3538 return false;
3539
3540 return m_part->IsGlobalPower();
3541}
3542
3543
3545{
3546 return IsLocalPower() || IsGlobalPower();
3547}
3548
3549
3551{
3552 wxCHECK( m_part, false );
3553
3554 return m_part->IsNormal();
3555}
3556
3557
3558std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
3559{
3560 std::unordered_set<wxString> componentClass;
3561
3562 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
3563 {
3564 for( const SCH_FIELD& field : fields )
3565 {
3566 if( field.GetCanonicalName() == wxT( "Component Class" ) )
3567 {
3568 if( field.GetShownText( aPath, false ) != wxEmptyString )
3569 componentClass.insert( field.GetShownText( aPath, false ) );
3570 }
3571 }
3572 };
3573
3574 // First get component classes set on the symbol itself
3575 getComponentClassFields( m_fields );
3576
3577 // Now get component classes set on any enclosing rule areas
3578 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
3579 {
3580 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
3581 {
3582 getComponentClassFields( label->GetFields() );
3583 }
3584 }
3585
3586 return componentClass;
3587}
3588
3589
3590std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
3591 const wxString& aVariantName ) const
3592{
3593 SCH_SYMBOL_INSTANCE instance;
3594
3595 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
3596 return std::nullopt;
3597
3598 return instance.m_Variants.find( aVariantName )->second;
3599}
3600
3601
3602void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
3603{
3604 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
3605
3606 // The instance path must already exist.
3607 if( !instance )
3608 return;
3609
3610 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
3611}
3612
3613
3614void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
3615{
3616 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3617
3618 // The instance path must already exist.
3619 if( !instance || !instance->m_Variants.contains( aVariantName ) )
3620 return;
3621
3622 instance->m_Variants.erase( aVariantName );
3623}
3624
3625
3626void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
3627 const wxString& aNewName )
3628{
3629 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3630
3631 // The instance path must already exist and contain the old variant.
3632 if( !instance || !instance->m_Variants.contains( aOldName ) )
3633 return;
3634
3635 // Get the variant data, update the name, and re-insert with new key
3636 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
3637 variant.m_Name = aNewName;
3638 instance->m_Variants.erase( aOldName );
3639 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
3640}
3641
3642
3643void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
3644 const wxString& aNewVariant )
3645{
3646 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3647
3648 // The instance path must already exist and contain the source variant.
3649 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
3650 return;
3651
3652 // Copy the variant data with a new name
3653 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
3654 variant.m_Name = aNewVariant;
3655 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
3656}
3657
3658
3659bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
3660{
3661 if( Type() != aOther.Type() )
3662 return false;
3663
3664 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3665
3666 if( GetLibId() != symbol.GetLibId() )
3667 return false;
3668
3669 if( GetPosition() != symbol.GetPosition() )
3670 return false;
3671
3672 if( GetUnit() != symbol.GetUnit() )
3673 return false;
3674
3675 if( GetBodyStyle() != symbol.GetBodyStyle() )
3676 return false;
3677
3678 if( GetTransform() != symbol.GetTransform() )
3679 return false;
3680
3681 if( GetFields() != symbol.GetFields() )
3682 return false;
3683
3684 if( m_pins.size() != symbol.m_pins.size() )
3685 return false;
3686
3687 for( unsigned i = 0; i < m_pins.size(); ++i )
3688 {
3689 if( *m_pins[i] != *symbol.m_pins[i] )
3690 return false;
3691 }
3692
3693 return true;
3694}
3695
3696
3697double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3698{
3699 if( Type() != aOther.Type() )
3700 return 0.0;
3701
3702 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3703
3704 if( GetLibId() != symbol.GetLibId() )
3705 return 0.0;
3706
3707 if( GetPosition() == symbol.GetPosition() )
3708 return 1.0;
3709
3710 return 0.0;
3711}
3712
3713
3714void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
3715 double aLineWidth, bool aHorizontal )
3716{
3717 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
3718
3719 double x_right = aSize / 1.6180339887;
3720 double x_middle = x_right / 2.0;
3721
3722 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
3723 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
3724 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
3725
3726 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
3727 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
3728 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
3729 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
3730 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
3731
3732 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3733 aShapeList.back().SetStart( bottomPt );
3734 aShapeList.back().SetBezierC1( bottomAnchorPt );
3735 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
3736 aShapeList.back().SetEnd( leftPt );
3737
3738
3739 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3740 aShapeList.back().SetStart( leftPt );
3741 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
3742 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
3743 aShapeList.back().SetEnd( rightPt );
3744
3745 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3746 aShapeList.back().SetStart( rightPt );
3747 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
3748 aShapeList.back().SetBezierC2( bottomAnchorPt );
3749 aShapeList.back().SetEnd( bottomPt );
3750
3751 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
3752 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
3753 aShapeList.back().SetRadius( aSize / 15.0 );
3754
3755 for( SCH_SHAPE& shape : aShapeList )
3756 {
3757 if( aHorizontal )
3758 shape.Rotate( VECTOR2I( 0, 0 ), true );
3759
3760 shape.Move( aPos );
3761 }
3762}
3763
3764
3766{
3767 for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
3768 {
3769 if( instance.m_Path == aSheetPath )
3770 return &instance;
3771 }
3772
3773 return nullptr;
3774}
3775
3776
3778{
3779 for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
3780 {
3781 if( instance.m_Path == aSheetPath )
3782 return &instance;
3783 }
3784
3785 return nullptr;
3786}
3787
3788
3789static struct SCH_SYMBOL_DESC
3790{
3792 {
3794 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
3795 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
3796 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
3797 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
3798
3802
3809
3816
3817 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
3818 {
3819 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3820 return symbol->GetLibSymbolRef() != nullptr;
3821
3822 return false;
3823 };
3824
3825 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
3827 .SetAvailableFunc( hasLibPart );
3828
3829 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
3831 .SetAvailableFunc( hasLibPart );
3832
3833 const wxString groupFields = _HKI( "Fields" );
3834
3837 groupFields );
3840 groupFields );
3841 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
3842 NO_SETTER( SCH_SYMBOL, wxString ),
3844 groupFields );
3845 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
3846 NO_SETTER( SCH_SYMBOL, wxString ),
3848 groupFields );
3849 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
3851 groupFields );
3852
3853 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
3854 {
3855 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3856 return symbol->IsMultiUnit();
3857
3858 return false;
3859 };
3860
3861 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
3862 {
3863 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3864 return symbol->IsMultiBodyStyle();
3865
3866 return false;
3867 };
3868
3871 .SetAvailableFunc( multiUnit )
3873 []( INSPECTABLE* aItem )
3874 {
3875 wxPGChoices choices;
3876
3877 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3878 {
3879 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
3880 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
3881 }
3882
3883 return choices;
3884 } );
3885
3888 .SetAvailableFunc( multiBodyStyle )
3890 []( INSPECTABLE* aItem )
3891 {
3892 wxPGChoices choices;
3893
3894 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3895 {
3896 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3897 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3898 }
3899
3900 return choices;
3901 } );
3902
3903 const wxString groupAttributes = _HKI( "Attributes" );
3904
3905 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
3908 groupAttributes );
3909 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
3912 groupAttributes );
3913 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
3916 groupAttributes );
3917 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
3920 groupAttributes );
3921 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
3924 groupAttributes );
3925 }
3927
3928
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BITMAPS
A list of all bitmap identifiers.
@ add_component
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr coord_type GetY() const
Definition box2.h:208
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr coord_type GetX() const
Definition box2.h:207
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:761
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:259
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
static std::vector< DANGLING_END_ITEM >::iterator get_lower_pos(std::vector< DANGLING_END_ITEM > &aItemListByPos, const VECTOR2I &aPos)
Definition sch_item.cpp:932
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:154
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:148
const KIID m_Uuid
Definition eda_item.h:522
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:533
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:407
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:115
bool IsSelected() const
Definition eda_item.h:127
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:534
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:80
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:585
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:603
static ENUM_MAP< T > & Instance()
Definition property.h:721
A text control validator used for validating the text allowed in fields.
Definition validators.h:142
bool DoValidate(const wxString &aValue, wxWindow *aParent)
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxString AsString() const
Definition kiid.cpp:356
Definition kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
UTF8 Format() const
Definition lib_id.cpp:119
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:203
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.
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:699
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
const BOX2I GetBodyBoundingBox(int aUnit, int aBodyStyle, bool aIncludePins, bool aIncludePrivateItems) const
Get the symbol bounding box excluding fields.
EMBEDDED_FILES * GetEmbeddedFiles() override
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:328
A singleton reporter that reports to nowhere.
Definition reporter.h:216
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:232
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition plotter.h:590
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
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:599
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:276
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
const wxString & Name() const
Definition property.h:220
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.
Holds all the data relating to one schematic.
Definition schematic.h:88
wxString GetOperatingPoint(const wxString &aNetName, int aPrecision, const wxString &aRange)
SCHEMATIC_SETTINGS & Settings() const
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:103
wxString GetCurrentVariant() const
Return the current variant being edited.
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:187
bool ResolveCrossReference(wxString *token, int aDepth) const
Resolves text vars that refer to other items.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString LocalName() const
wxString Name(bool aIgnoreSheet=false) const
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:118
FIELD_T GetId() const
Definition sch_field.h:122
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetText(const wxString &aText) override
int m_unit
Definition sch_item.h:773
int m_bodyStyle
Definition sch_item.h:774
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:721
void SetPrivate(bool aPrivate)
Definition sch_item.h:252
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:247
int GetBodyStyle() const
Definition sch_item.h:247
friend class LIB_SYMBOL
Definition sch_item.h:792
int GetUnit() const
Definition sch_item.h:238
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition sch_item.cpp:502
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:776
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:789
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:54
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition sch_item.cpp:466
SCH_LAYER_ID m_layer
Definition sch_item.h:772
void SetAlt(const wxString &aAlt)
Set the name of the alternate pin.
Definition sch_pin.cpp:433
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:174
void SetName(const wxString &aName)
Definition sch_pin.cpp:419
const wxString & GetName() const
Definition sch_pin.cpp:401
bool IsDangling() const override
Definition sch_pin.cpp:461
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:1350
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:256
wxString GetShownName() const
Definition sch_pin.cpp:577
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:333
const wxString & GetNumber() const
Definition sch_pin.h:124
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:278
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:313
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
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.
Variant information for a schematic symbol.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:76
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:518
size_t GetFullPinCount() const
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.
Definition sch_symbol.h:990
wxString GetDescription() const override
std::unordered_map< SCH_PIN *, SCH_PIN * > m_pinMap
Library pin pointer : SCH_PIN indices.
void SetMirrorX(bool aMirror)
Definition sch_symbol.h:322
bool IsSymbolLikePowerGlobalLabel() const
VECTOR2I m_pos
Definition sch_symbol.h:988
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SYMBOLs don't currently support embedded files, but their LIB_SYMBOL counterparts do.
wxString GetSymbolIDAsString() const
Definition sch_symbol.h:167
LIB_ID m_lib_id
Name and library the symbol was loaded from, i.e. 74xx:74LS00.
Definition sch_symbol.h:989
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:452
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:535
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
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 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.
SYMBOL_ORIENTATION_PROP GetOrientationProp() const
Definition sch_symbol.h:305
int GetY() const
Definition sch_symbol.h:860
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:115
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
bool IsAnnotated(const SCH_SHEET_PATH *aSheet) const
Check if the symbol has a valid annotation (reference) for the given sheet path.
void SetMirrorY(bool aMirror)
Definition sch_symbol.h:339
void PlotPins(PLOTTER *aPlotter) const
Plot just the symbol pins.
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:540
int GetX() const
Definition sch_symbol.h:857
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:754
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:729
void SetBodyStyle(int aBodyStyle) override
void SetShowPinNames(bool aShow) override
Set or clear the pin name visibility flag.
wxString GetKeyWords() const override
wxString GetSchSymbolLibraryName() const
wxString GetShownKeyWords(int aDepth=0) const override
bool IsInNetlist() const
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
bool GetExcludedFromBoardProp() const
Definition sch_symbol.h:739
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:861
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.
bool GetExcludedFromSimProp() const
Definition sch_symbol.h:724
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:334
wxString GetRefProp() const
Definition sch_symbol.h:504
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instanceReferences), if this entry does not alrea...
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:714
static std::unordered_map< TRANSFORM, int > s_transformToOrientationCache
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
std::vector< SCH_SYMBOL_INSTANCE > m_instanceReferences
Define the hierarchical path and reference of the symbol.
void SyncOtherUnits(const SCH_SHEET_PATH &aSourceSheet, SCH_COMMIT &aCommit, PROPERTY_BASE *aProperty)
Keep fields other than the reference, include/exclude flags, and alternate pin assignments in sync in...
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.
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const override
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void SetOrientationProp(SYMBOL_ORIENTATION_PROP aAngle)
Orientation/mirroring access for property manager.
Definition sch_symbol.h:296
bool GetShowPinNames() const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
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:699
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.
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:854
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 swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
void Init(const VECTOR2I &pos=VECTOR2I(0, 0))
void SetExcludedFromPosFilesProp(bool aEnable)
Definition sch_symbol.h:759
wxString GetShownDescription(int aDepth=0) const override
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
bool operator<(const SCH_ITEM &aItem) const override
static void BuildLocalPowerIconShape(std::vector< SCH_SHAPE > &aShapeList, const VECTOR2D &aPos, double aSize, double aLineWidth, bool aHorizontal)
Build the local power pin indicator icon shape, at coordinate aPos.
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
void SetValueProp(const wxString &aValue)
void SetUnitProp(int aUnit)
Definition sch_symbol.h:529
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:351
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetDNPProp(bool aEnable)
Definition sch_symbol.h:701
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
void SetX(int aX)
Definition sch_symbol.h:858
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
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:511
bool IsLocalPower() const override
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
int GetUnitCount() const override
Return the number of units per package of the symbol.
void SetPrefix(const wxString &aPrefix)
Definition sch_symbol.h:239
int GetOrientation() const override
Get the display symbol orientation.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
bool IsSymbolLikePowerLocalLabel() const
bool GetExcludedFromBOMProp() const
Definition sch_symbol.h:709
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:744
void SetExcludedFromBOM(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
void PlotLocalPowerIconShape(PLOTTER *aPlotter) const
Plot the local power pin indicator icon shape.
bool IsNormal() const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
std::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 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, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
void SetFilesStack(std::vector< EMBEDDED_FILES * > aFilesStack)
Definition sim_lib_mgr.h:48
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
bool m_DNP
True if symbol is set to 'Do Not Populate'.
Definition symbol.h:278
bool m_excludedFromPosFiles
Definition symbol.h:277
SYMBOL(KICAD_T idType)
Definition symbol.h:65
bool m_excludedFromSim
Definition symbol.h:274
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:174
const TRANSFORM & GetTransform() const
Definition symbol.h:247
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:168
bool m_excludedFromBOM
Definition symbol.h:275
bool m_excludedFromBoard
Definition symbol.h:276
virtual bool GetShowPinNames() const
Definition symbol.h:169
SYMBOL & operator=(const SYMBOL &aItem)
Definition symbol.h:93
virtual bool GetShowPinNumbers() const
Definition symbol.h:175
TRANSFORM m_transform
The rotation/mirror transformation.
Definition symbol.h:267
const std::vector< TEMPLATE_FIELDNAME > & GetTemplateFieldNames()
Return a template field name list for read only access.
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:46
wxString wx_str() const
Definition utf8.cpp:45
wxString m_Name
bool m_ExcludedFromBOM
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
T Convert(const wxString &aValue)
Convert a wxString to a generic type T.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
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
FILL_T
Definition eda_shape.h:56
@ NO_FILL
Definition eda_shape.h:57
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
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:449
@ LAYER_DEVICE
Definition layer_ids.h:466
@ LAYER_VALUEPART
Definition layer_ids.h:461
@ LAYER_FIELDS
Definition layer_ids.h:462
@ LAYER_REFERENCEPART
Definition layer_ids.h:460
@ LAYER_DNP_MARKER
Definition layer_ids.h:478
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
Message panel definition file.
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.
#define _HKI(x)
Definition page_info.cpp:44
see class PGM_BASE
@ PT_NC
not connected (must be left open)
Definition pin_type.h:50
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:46
#define TYPE_HASH(x)
Definition property.h:74
#define NO_SETTER(owner, type)
Definition property.h:828
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ 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:369
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:358
@ 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
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
static void plotLocalPowerIcon(PLOTTER *aPlotter, const VECTOR2D &aPos, double aSize, bool aRotate)
plot a local power pin indicator icon.
static struct SCH_SYMBOL_DESC _SCH_SYMBOL_DESC
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::vector< std::pair< FIELD_T, wxString > > Fields
Definition sch_screen.h:88
bool m_PDFPropertyPopups
Definition sch_plotter.h:64
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:51
@ SYMBOL_ANGLE_180
Definition symbol.h:54
@ SYMBOL_ANGLE_0
Definition symbol.h:52
@ SYMBOL_ANGLE_90
Definition symbol.h:53
@ SYMBOL_ANGLE_270
Definition symbol.h:55
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_ROTATE_CLOCKWISE
Definition symbol.h:37
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition symbol.h:38
@ SYM_MIRROR_Y
Definition symbol.h:44
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_NORMAL
Definition symbol.h:36
@ SYM_ORIENT_90
Definition symbol.h:40
@ SYM_ORIENT_0
Definition symbol.h:39
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".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
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:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ SCH_FIELD_LOCATE_REFERENCE_T
Definition typeinfo.h:184
@ SCH_FIELD_LOCATE_FOOTPRINT_T
Definition typeinfo.h:186
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_FIELD_T
Definition typeinfo.h:154
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:203
@ SCH_FIELD_LOCATE_VALUE_T
Definition typeinfo.h:185
@ SCH_FIELD_LOCATE_DATASHEET_T
Definition typeinfo.h:187
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:200
@ SCH_PIN_T
Definition typeinfo.h:157
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694