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;
144 m_instances = aSymbol.m_instances;
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_instances )
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_instances.size() - 1; ii >= 0; --ii )
569 {
570 if( m_instances[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_instances[ii].m_Reference, m_instances[ii].m_Unit,
577 m_Uuid.AsString() );
578
579 m_instances.erase( m_instances.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_instances.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_instances.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_instances.size() );
631
632 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
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
693 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
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_instances )
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_instances )
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
934 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
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_instances )
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 wxString& aVariantName ) const
1298{
1299 if( aResolve )
1300 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText, 0, aVariantName );
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,
1469 PROPERTY_BASE* aProperty, const wxString& aVariantName )
1470{
1471 bool updateValue = true;
1472 bool updateExclFromBOM = true;
1473 bool updateExclFromBoard = true;
1474 bool updateDNP = true;
1475 bool updateOtherFields = true;
1476 bool updatePins = true;
1477
1478 if( aProperty )
1479 {
1480 updateValue = aProperty->Name() == _HKI( "Value" );
1481 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
1482 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
1483 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
1484 updateOtherFields = false;
1485 updatePins = false;
1486 }
1487
1488 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateDNP && !updateOtherFields && !updatePins )
1489 {
1490 return;
1491 }
1492
1493 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
1494 // in sync in multi-unit parts.
1495 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
1496 {
1497 wxString ref = GetRef( &aSourceSheet );
1498
1499 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1500 {
1501 SCH_SCREEN* screen = sheet.LastScreen();
1502 std::vector<SCH_SYMBOL*> otherUnits;
1503
1504 CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
1505
1506 for( SCH_SYMBOL* otherUnit : otherUnits )
1507 {
1508 aCommit.Modify( otherUnit, screen );
1509
1510 if( updateValue )
1511 otherUnit->SetValueFieldText( GetField( FIELD_T::VALUE )->GetText() );
1512
1513 if( updateOtherFields )
1514 {
1515 for( SCH_FIELD& field : m_fields )
1516 {
1517 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
1518 {
1519 // already handled
1520 continue;
1521 }
1522
1523 SCH_FIELD* otherField;
1524
1525 if( field.IsMandatory() )
1526 otherField = otherUnit->GetField( field.GetId() );
1527 else
1528 otherField = otherUnit->GetField( field.GetName() );
1529
1530 if( otherField )
1531 {
1532 otherField->SetText( field.GetText() );
1533 }
1534 else
1535 {
1536 SCH_FIELD newField( field );
1537 const_cast<KIID&>( newField.m_Uuid ) = KIID();
1538
1539 newField.Offset( -GetPosition() );
1540 newField.Offset( otherUnit->GetPosition() );
1541
1542 newField.SetParent( otherUnit );
1543 otherUnit->AddField( newField );
1544 }
1545 }
1546
1547 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
1548 {
1549 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
1550
1551 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
1552 otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
1553 }
1554 }
1555
1556 if( updateExclFromBOM )
1557 otherUnit->SetExcludedFromBOM( m_excludedFromBOM );
1558
1559 if( updateExclFromBoard )
1560 otherUnit->SetExcludedFromBoard( m_excludedFromBoard );
1561
1562 if( updateDNP )
1563 otherUnit->SetDNP( GetDNP( &aSourceSheet, aVariantName ), &sheet, aVariantName );
1564
1565 if( updatePins )
1566 {
1567 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
1568 {
1569 for( SCH_PIN* src_pin : otherUnit->GetPinsByNumber( model_pin->GetNumber() ) )
1570 src_pin->SetAlt( model_pin->GetAlt() );
1571 }
1572 }
1573 }
1574 }
1575 }
1576}
1577
1578
1579void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
1580{
1581 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1582 aFunction( pin.get() );
1583
1584 for( SCH_FIELD& field : m_fields )
1585 aFunction( &field );
1586}
1587
1588
1589SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
1590{
1591 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1592 {
1593 if( pin->GetNumber() == aNumber )
1594 return pin.get();
1595 }
1596
1597 return nullptr;
1598}
1599
1600
1601std::vector<SCH_PIN*> SCH_SYMBOL::GetPinsByNumber( const wxString& aNumber ) const
1602{
1603 std::vector<SCH_PIN*> pins;
1604
1605 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1606 {
1607 if( pin->GetNumber() == aNumber )
1608 pins.push_back( pin.get() );
1609 }
1610
1611 return pins;
1612}
1613
1614
1615const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
1616{
1617 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1618 {
1619 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
1620 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
1621
1622 if( pin_unit > 0 && pin_unit != GetUnit() )
1623 continue;
1624
1625 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
1626 continue;
1627
1628 if( pin->GetPosition() == aPos )
1629 return pin.get();
1630 }
1631
1632 return nullptr;
1633}
1634
1635
1636std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
1637{
1638 if( m_part )
1639 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
1640
1641 return std::vector<SCH_PIN*>();
1642}
1643
1644
1645std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
1646{
1647 if( m_part )
1648 return m_part->GetPins();
1649
1650 return std::vector<SCH_PIN*>();
1651}
1652
1653
1655{
1656 return m_part ? m_part->GetPinCount() : 0;
1657}
1658
1659
1661{
1662 auto it = m_pinMap.find( aLibPin );
1663
1664 if( it != m_pinMap.end() )
1665 return it->second;
1666
1667 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
1668 return nullptr;
1669}
1670
1671
1672std::vector<const SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
1673{
1674 std::vector<const SCH_PIN*> pins;
1675 int unit = m_unit;
1676
1677 if( !aSheet && Schematic() )
1678 aSheet = &Schematic()->CurrentSheet();
1679
1680 if( aSheet )
1681 unit = GetUnitSelection( aSheet );
1682
1683 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1684 {
1685 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
1686 continue;
1687
1688 pins.push_back( pin.get() );
1689 }
1690
1691 return pins;
1692}
1693
1694
1695std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet )
1696{
1697 std::vector<SCH_PIN*> pins;
1698 int unit = m_unit;
1699
1700 if( !aSheet && Schematic() )
1701 aSheet = &Schematic()->CurrentSheet();
1702
1703 if( aSheet )
1704 unit = GetUnitSelection( aSheet );
1705
1706 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1707 {
1708 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
1709 continue;
1710
1711 pins.push_back( pin.get() );
1712 }
1713
1714 return pins;
1715}
1716
1717
1718std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
1719{
1720 // Back-compat shim: return graphical pins for all units/body styles, violating const
1721 return const_cast<SCH_SYMBOL*>( this )->GetPins( nullptr );
1722}
1723
1724
1726{
1727 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
1728
1729 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
1730
1731 std::swap( m_lib_id, symbol->m_lib_id );
1732
1733 m_pins.swap( symbol->m_pins ); // std::vector's swap()
1734
1735 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
1736 pin->SetParent( symbol );
1737
1738 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1739 pin->SetParent( this );
1740
1741 LIB_SYMBOL* libSymbol = symbol->m_part.release();
1742 symbol->m_part = std::move( m_part );
1743 symbol->UpdatePins();
1744 m_part.reset( libSymbol );
1745 UpdatePins();
1746
1747 std::swap( m_pos, symbol->m_pos );
1748 std::swap( m_unit, symbol->m_unit );
1749 std::swap( m_bodyStyle, symbol->m_bodyStyle );
1750
1751 m_fields.swap( symbol->m_fields ); // std::vector's swap()
1752
1753 for( SCH_FIELD& field : symbol->m_fields )
1754 field.SetParent( symbol );
1755
1756 for( SCH_FIELD& field : m_fields )
1757 field.SetParent( this );
1758
1759 TRANSFORM tmp = m_transform;
1760
1761 m_transform = symbol->m_transform;
1762 symbol->m_transform = tmp;
1763
1764 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
1765 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
1766 std::swap( m_DNP, symbol->m_DNP );
1767 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
1768
1769 std::swap( m_instances, symbol->m_instances );
1770 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
1771}
1772
1773
1774void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
1775{
1776 for( const SCH_FIELD& field : m_fields )
1777 {
1778 if( field.IsPrivate() )
1779 continue;
1780
1781 if( field.IsMandatory() )
1782 aVars->push_back( field.GetCanonicalName().Upper() );
1783 else
1784 aVars->push_back( field.GetName() );
1785 }
1786
1787 aVars->push_back( wxT( "OP" ) );
1788 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
1789 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
1790 aVars->push_back( wxT( "UNIT" ) );
1791 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
1792 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
1793 aVars->push_back( wxT( "SYMBOL_NAME" ) );
1794 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
1795 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
1796 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
1797 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
1798 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
1799 aVars->push_back( wxT( "DNP" ) );
1800 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
1801 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
1802 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
1803 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
1804 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
1805 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
1806 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
1807}
1808
1809
1810bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
1811{
1812 return ResolveTextVar( aPath, token, wxEmptyString, aDepth );
1813}
1814
1815
1816bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token,
1817 const wxString& aVariantName, int aDepth ) const
1818{
1819 static wxRegEx operatingPoint( wxT( "^"
1820 "OP"
1821 "(:[^.]*)?" // pin
1822 "(.([0-9])?" // precisionStr
1823 "([a-zA-Z]*))?" // rangeStr
1824 "$" ) );
1825
1826 wxCHECK( aPath, false );
1827
1828 SCHEMATIC* schematic = Schematic();
1829
1830 if( !schematic )
1831 return false;
1832
1833 if( operatingPoint.Matches( *token ) )
1834 {
1835 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
1836 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
1837 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
1838
1839 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
1840 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
1841
1842 SIM_LIB_MGR simLibMgr( &schematic->Project() );
1843
1844 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
1845 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
1846
1847 if( m_part )
1848 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
1849
1850 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
1851
1852 NULL_REPORTER devnull;
1853 SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1,
1854 aVariantName, devnull ).model;
1855 SPICE_ITEM spiceItem;
1856 spiceItem.refName = GetRef( aPath );
1857
1858 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
1859 spiceRef = spiceRef.Lower();
1860
1861 if( pin.IsEmpty() )
1862 {
1863 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1864 return true;
1865 }
1866 else if( pin == wxS( ":power" ) )
1867 {
1868 if( rangeStr.IsEmpty() )
1869 range = wxS( "~W" );
1870
1871 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
1872 return true;
1873 }
1874 else
1875 {
1876 pin = pin.SubString( 1, -1 ); // Strip ':' from front
1877
1878 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
1879 {
1880 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
1881
1882 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
1883 {
1884 if( model.GetPins().size() == 2 )
1885 {
1886 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1887 }
1888 else
1889 {
1890 wxString signalName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
1891 *token = schematic->GetOperatingPoint( signalName, precision, range );
1892 }
1893
1894 return true;
1895 }
1896 }
1897 }
1898
1899 *token = wxS( "?" );
1900 return true;
1901 }
1902
1903 if( token->Contains( ':' ) )
1904 {
1905 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
1906 return true;
1907 }
1908
1909 for( const SCH_FIELD& field : m_fields )
1910 {
1911 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName() : field.GetName();
1912
1913 wxString textToken = field.GetText();
1914 textToken.Replace( " ", wxEmptyString );
1915 wxString tokenString = "${" + fieldName + "}";
1916
1917 // If the field data is just a reference to the field, don't resolve
1918 if( textToken.IsSameAs( tokenString, false ) )
1919 return true;
1920
1921 if( token->IsSameAs( fieldName, false ) )
1922 {
1923 if( field.GetId() == FIELD_T::REFERENCE )
1924 {
1925 *token = GetRef( aPath, true );
1926 }
1927 else if( !aVariantName.IsEmpty() )
1928 {
1929 // Check for variant-specific field value
1930 std::optional<SCH_SYMBOL_VARIANT> variant = GetVariant( *aPath, aVariantName );
1931
1932 if( variant && variant->m_Fields.contains( fieldName ) )
1933 *token = variant->m_Fields.at( fieldName );
1934 else
1935 *token = field.GetShownText( aPath, false, aDepth + 1 );
1936 }
1937 else
1938 {
1939 *token = field.GetShownText( aPath, false, aDepth + 1 );
1940 }
1941
1942 return true;
1943 }
1944 }
1945
1946 // Consider missing simulation fields as empty, not un-resolved
1947 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
1948 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
1949 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
1950 {
1951 *token = wxEmptyString;
1952 return true;
1953 }
1954
1955 for( const TEMPLATE_FIELDNAME& templateFieldname :
1957 {
1958 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
1959 {
1960 // If we didn't find it in the fields list then it isn't set on this symbol.
1961 // Just return an empty string.
1962 *token = wxEmptyString;
1963 return true;
1964 }
1965 }
1966
1967 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1968 {
1969 wxString footprint = GetFootprintFieldText( true, aPath, false );
1970
1971 wxArrayString parts = wxSplit( footprint, ':' );
1972
1973 if( parts.Count() > 0 )
1974 *token = parts[0];
1975 else
1976 *token = wxEmptyString;
1977
1978 return true;
1979 }
1980 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1981 {
1982 wxString footprint = GetFootprintFieldText( true, aPath, false );
1983
1984 wxArrayString parts = wxSplit( footprint, ':' );
1985
1986 if( parts.Count() > 1 )
1987 *token = parts[std::min( 1, (int) parts.size() - 1 )];
1988 else
1989 *token = wxEmptyString;
1990
1991 return true;
1992 }
1993 else if( token->IsSameAs( wxT( "UNIT" ) ) )
1994 {
1995 *token = SubReference( GetUnitSelection( aPath ) );
1996 return true;
1997 }
1998 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
1999 {
2000 *token = GetRef( aPath, false );
2001 return true;
2002 }
2003 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
2004 {
2005 *token = m_lib_id.GetUniStringLibNickname();
2006 return true;
2007 }
2008 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
2009 {
2010 *token = m_lib_id.GetUniStringLibItemName();
2011 return true;
2012 }
2013 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
2014 {
2015 *token = GetShownDescription( aDepth + 1 );
2016 return true;
2017 }
2018 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
2019 {
2020 *token = GetShownKeyWords( aDepth + 1 );
2021 return true;
2022 }
2023 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
2024 {
2025 *token = wxEmptyString;
2026
2027 if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
2028 *token = _( "Excluded from BOM" );
2029
2030 return true;
2031 }
2032 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
2033 {
2034 *token = wxEmptyString;
2035
2036 if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
2037 *token = _( "Excluded from board" );
2038
2039 return true;
2040 }
2041 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
2042 {
2043 *token = wxEmptyString;
2044
2045 if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
2046 *token = _( "Excluded from simulation" );
2047
2048 return true;
2049 }
2050 else if( token->IsSameAs( wxT( "DNP" ) ) )
2051 {
2052 *token = wxEmptyString;
2053
2054 if( aPath->GetDNP() || this->ResolveDNP() )
2055 *token = _( "DNP" );
2056
2057 return true;
2058 }
2059 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
2060 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
2061 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
2062 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
2063 || token->StartsWith( wxT( "UNIT(" ) ) )
2064 {
2065 wxString pinNumber = token->AfterFirst( '(' );
2066 pinNumber = pinNumber.BeforeLast( ')' );
2067
2068 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
2069 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
2070 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
2071
2072 // First, try to find the pin in the current unit (for backward compatibility)
2073 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
2074 std::vector<const SCH_PIN*> pinsToSearch;
2075 std::vector<const SCH_PIN*> altPinsToSearch;
2076
2077 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2078 {
2079 for( SCH_PIN* pin : GetAllLibPins() )
2080 pinsToSearch.push_back( pin );
2081 }
2082 else
2083 {
2084 for( const SCH_PIN* pin : GetPins( aPath ) )
2085 pinsToSearch.push_back( pin );
2086
2087 for( SCH_PIN* pin : GetAllLibPins() )
2088 altPinsToSearch.push_back( pin );
2089 }
2090
2091 for( const SCH_PIN* pin : pinsToSearch )
2092 {
2093 if( pin->GetNumber() == pinNumber )
2094 {
2095 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2096 {
2097 int pinUnit = pin->GetUnit();
2098 wxString result;
2099
2100 if( isReferenceFunction )
2101 {
2102 // Return the full unit reference (e.g., "J601A")
2103 if( pinUnit > 0 )
2104 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
2105 else
2106 result = GetRef( aPath, false );
2107 }
2108 else if( isShortReferenceFunction )
2109 {
2110 // Return the reference without unit (e.g., "J601")
2111 result = GetRef( aPath, false );
2112 }
2113 else if( isUnitFunction )
2114 {
2115 // Return only the unit letter (e.g., "A")
2116 if( pinUnit > 0 )
2117 result = SubReference( pinUnit, false );
2118 else
2119 result = wxEmptyString;
2120 }
2121
2122 *token = result;
2123 return true;
2124 }
2125 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2126 {
2127 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
2128 return true;
2129 }
2130 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2131 {
2132 *token = pin->GetBaseName();
2133 return true;
2134 }
2135 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2136 {
2137 // Build list of alternate names only (no base name)
2138 wxString altList;
2139
2140 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2141
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 SCH_CONNECTION* conn = pin->Connection( aPath );
2154
2155 if( !conn )
2156 {
2157 *token = wxEmptyString;
2158 }
2159 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2160 {
2161 wxString netName = conn->LocalName();
2162 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2163 *token = wxT( "NC" );
2164 else
2165 *token = netName;
2166 }
2167 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2168 {
2169 *token = conn->Name();
2170 }
2171 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2172 {
2173 *token = pin->GetEffectiveNetClass( aPath )->GetName();
2174 }
2175
2176 return true;
2177 }
2178 }
2179
2180 // If pin not found in current unit, search all units (auto-resolution)
2181 for( const SCH_PIN* pin : altPinsToSearch )
2182 {
2183 if( pin->GetNumber() == pinNumber )
2184 {
2185 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
2186 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2187 {
2188 *token = pin->GetBaseName();
2189 return true;
2190 }
2191 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2192 {
2193 // Build list of alternate names only (no base name)
2194 wxString altList;
2195
2196 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2197
2198 for( const auto& [altName, altDef] : alts )
2199 {
2200 if( !altList.IsEmpty() )
2201 altList += wxT( ", " );
2202 altList += altName;
2203 }
2204
2205 *token = altList;
2206 return true;
2207 }
2208
2209 // For net-related functions, find which sheet path has this pin's unit
2210 int pinUnit = pin->GetUnit();
2211
2212 // Search all sheets for a symbol with our reference and the correct unit
2213 // This is needed because each unit of a multi-unit symbol is a separate object
2214 SCH_SHEET_PATH targetPath;
2215 SCH_SYMBOL* targetSymbol = nullptr;
2216
2217 if( Schematic() )
2218 {
2219 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
2220 {
2221 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2222 {
2223 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2224
2225 // Check if this symbol has the same reference designator and the correct unit
2226 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
2227 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
2228 {
2229 targetPath = sheetPath; // Copy the sheet path
2230 targetSymbol = symbol;
2231 break;
2232 }
2233 }
2234
2235 if( targetSymbol )
2236 break;
2237 }
2238 }
2239
2240 if( !targetSymbol )
2241 {
2242 // Unit not placed on any sheet
2243 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
2244 return true;
2245 }
2246
2247 // Get the pin from the actual instance symbol we found
2248 // Match by pin number, not by pointer, since the library pins are different objects
2249 SCH_PIN* instancePin = nullptr;
2250
2251 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
2252 {
2253 if( candidate->GetNumber() == pinNumber )
2254 {
2255 instancePin = candidate;
2256 break;
2257 }
2258 }
2259
2260 if( !instancePin )
2261 {
2262 *token = wxEmptyString;
2263 return true;
2264 }
2265
2266 // PIN_NAME doesn't need connection data, just instance pin
2267 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2268 {
2269 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
2270 return true;
2271 }
2272
2273 // Now get the connection from the correct sheet path
2274 SCH_CONNECTION* conn = instancePin->Connection( &targetPath );
2275
2276 if( !conn )
2277 {
2278 *token = wxEmptyString;
2279 }
2280 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2281 {
2282 wxString netName = conn->LocalName();
2283 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2284 *token = wxT( "NC" );
2285 else
2286 *token = netName;
2287 }
2288 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2289 {
2290 *token = conn->Name();
2291 }
2292 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2293 {
2294 *token = instancePin->GetEffectiveNetClass( &targetPath )->GetName();
2295 }
2296
2297 return true;
2298 }
2299 }
2300
2301 // If we got here, no pin was found - report unresolved
2302 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
2303 return true;
2304 }
2305
2306 // See if parent can resolve it (this will recurse to ancestors)
2307 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
2308 return true;
2309
2310 return false;
2311}
2312
2313
2314void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
2315{
2316 if( aSheetPath )
2317 {
2318 KIID_PATH path = aSheetPath->Path();
2319
2320 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2321 {
2322 if( instance.m_Path == path )
2323 {
2324 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2325 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2326 else
2327 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2328 }
2329 }
2330 }
2331 else
2332 {
2333 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2334 {
2335 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2336 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2337 else
2338 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2339 }
2340 }
2341
2342 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2343 pin->ClearDefaultNetName( aSheetPath );
2344
2345 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
2346 // When clearing for a specific sheet path, we must preserve the field text because it serves
2347 // as a fallback for GetRef() when instances for other sheet paths are looked up.
2348 // See issue #20173: modifying field text here corrupts references in shared screens.
2349 if( !aSheetPath )
2350 {
2351 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
2352
2353 if( currentReference.IsEmpty() || aResetPrefix )
2355 else
2357 }
2358}
2359
2360
2362{
2363 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
2364 wxCHECK( aSheetPath.size() > 0, false );
2365
2366 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
2367 {
2368 // if aSheetPath is found, nothing to do:
2369 if( instance.m_Path == aSheetPath )
2370 return false;
2371 }
2372
2373 // This entry does not exist: add it, with its last-used reference
2374 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
2375 return true;
2376}
2377
2378
2379void SCH_SYMBOL::SetOrientation( int aOrientation )
2380{
2381 TRANSFORM temp = TRANSFORM();
2382 bool transform = false;
2383
2384 switch( aOrientation )
2385 {
2386 case SYM_ORIENT_0:
2387 case SYM_NORMAL: // default transform matrix
2389 break;
2390
2391 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
2392 temp.x1 = 0;
2393 temp.y1 = 1;
2394 temp.x2 = -1;
2395 temp.y2 = 0;
2396 transform = true;
2397 break;
2398
2399 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
2400 temp.x1 = 0;
2401 temp.y1 = -1;
2402 temp.x2 = 1;
2403 temp.y2 = 0;
2404 transform = true;
2405 break;
2406
2407 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
2408 temp.x1 = -1;
2409 temp.y1 = 0;
2410 temp.x2 = 0;
2411 temp.y2 = 1;
2412 transform = true;
2413 break;
2414
2415 case SYM_MIRROR_X: // Mirror X (incremental transform)
2416 temp.x1 = 1;
2417 temp.y1 = 0;
2418 temp.x2 = 0;
2419 temp.y2 = -1;
2420 transform = true;
2421 break;
2422
2423 case SYM_ORIENT_90:
2426 break;
2427
2428 case SYM_ORIENT_180:
2432 break;
2433
2434 case SYM_ORIENT_270:
2437 break;
2438
2439 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
2442 break;
2443
2444 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
2447 break;
2448
2453 break;
2454
2455 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
2458 break;
2459
2460 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
2463 break;
2464
2469 break;
2470
2471 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
2474 break;
2475
2476 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
2479 break;
2480
2485 break;
2486
2487 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
2490 break;
2491
2492 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
2495 break;
2496
2501 break;
2502
2503 default:
2504 transform = false;
2505 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
2506 break;
2507 }
2508
2509 if( transform )
2510 {
2511 /* The new matrix transform is the old matrix transform modified by the
2512 * requested transformation, which is the temp transform (rot,
2513 * mirror ..) in order to have (in term of matrix transform):
2514 * transform coord = new_m_transform * coord
2515 * where transform coord is the coord modified by new_m_transform from
2516 * the initial value coord.
2517 * new_m_transform is computed (from old_m_transform and temp) to
2518 * have:
2519 * transform coord = old_m_transform * temp
2520 */
2521 TRANSFORM newTransform;
2522
2523 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
2524 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
2525 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
2526 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
2527 m_transform = newTransform;
2528 }
2529}
2530
2531
2533{
2534 /*
2535 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
2536 * now, so let's just cache it for the moment.
2537 */
2540
2541 int rotate_values[] = { SYM_ORIENT_0,
2553
2554 // Try to find the current transform option:
2555 TRANSFORM transform = m_transform;
2556 SCH_SYMBOL temp( *this );
2557 temp.SetParentGroup( nullptr );
2558
2559 for( int type_rotate : rotate_values )
2560 {
2561 temp.SetOrientation( type_rotate );
2562
2563 if( transform == temp.GetTransform() )
2564 {
2566 return type_rotate;
2567 }
2568 }
2569
2570 // Error: orientation not found in list (should not happen)
2571 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
2572
2573 return SYM_NORMAL;
2574}
2575
2576
2577#if defined( DEBUG )
2578
2579void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
2580{
2581 // for now, make it look like XML:
2582 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
2583 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
2584 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
2585 << ">\n";
2586
2587 // skip the reference, it's been output already.
2588 for( int i = 1; i < (int) GetFields().size(); ++i )
2589 {
2590 const wxString& value = GetFields()[i].GetText();
2591
2592 if( !value.IsEmpty() )
2593 {
2594 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
2595 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
2596 }
2597 }
2598
2599 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
2600}
2601
2602#endif
2603
2604
2605BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
2606{
2607 BOX2I bBox;
2608
2609 if( m_part )
2610 bBox = m_part->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2611 else
2612 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2613
2614 bBox = m_transform.TransformCoordinate( bBox );
2615 bBox.Normalize();
2616
2617 bBox.Offset( m_pos );
2618
2619 if( aIncludeFields )
2620 {
2621 for( const SCH_FIELD& field : m_fields )
2622 {
2623 if( field.IsVisible() )
2624 bBox.Merge( field.GetBoundingBox() );
2625 }
2626 }
2627
2628 return bBox;
2629}
2630
2631
2633{
2634 try
2635 {
2636 return doGetBoundingBox( false, false );
2637 }
2638 catch( const boost::bad_pointer& e )
2639 {
2640 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
2641 return BOX2I();
2642 }
2643}
2644
2645
2647{
2648 return doGetBoundingBox( true, false );
2649}
2650
2651
2653{
2654 return doGetBoundingBox( true, true );
2655}
2656
2657
2658void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2659{
2660 wxString msg;
2661
2662 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
2663 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
2664
2665 auto addExcludes = [&]()
2666 {
2667 wxArrayString msgs;
2668
2669 if( GetExcludedFromSim() )
2670 msgs.Add( _( "Simulation" ) );
2671
2672 if( GetExcludedFromBOM() )
2673 msgs.Add( _( "BOM" ) );
2674
2675 if( GetExcludedFromBoard() )
2676 msgs.Add( _( "Board" ) );
2677
2678 if( GetDNP( currentSheet ) )
2679 msgs.Add( _( "DNP" ) );
2680
2681 msg = wxJoin( msgs, '|' );
2682 msg.Replace( '|', wxS( ", " ) );
2683
2684 if( !msg.empty() )
2685 aList.emplace_back( _( "Exclude from" ), msg );
2686 };
2687
2688 // part and alias can differ if alias is not the root
2689 if( m_part )
2690 {
2691 if( m_part.get() != LIB_SYMBOL::GetDummy() )
2692 {
2693 if( m_part->IsPower() )
2694 {
2695 // Don't use GetShownText(); we want to see the variable references here
2696 aList.emplace_back( _( "Power symbol" ),
2697 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2698 }
2699 else
2700 {
2701 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
2702
2703 // Don't use GetShownText(); we want to see the variable references here
2704 aList.emplace_back( _( "Value" ),
2705 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2706 addExcludes();
2707 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2708 }
2709
2710#if 0 // Display symbol flags, for debug only
2711 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
2712#endif
2713
2714 if( !m_part->IsRoot() )
2715 {
2716 msg = _( "Missing parent" );
2717
2718 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
2719
2720 if( parent )
2721 msg = parent->GetName();
2722
2723 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
2724 }
2725 else if( !m_lib_id.GetLibNickname().empty() )
2726 {
2727 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
2728 }
2729 else
2730 {
2731 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
2732 }
2733
2734 // Display the current associated footprint, if exists.
2735 // Don't use GetShownText(); we want to see the variable references here
2736 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
2737
2738 if( msg.IsEmpty() )
2739 msg = _( "<Unknown>" );
2740
2741 aList.emplace_back( _( "Footprint" ), msg );
2742
2743 // Display description of the symbol, and keywords found in lib
2744 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
2745 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
2746 }
2747 }
2748 else
2749 {
2750 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
2751
2752 // Don't use GetShownText(); we want to see the variable references here
2753 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2754 addExcludes();
2755 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2756
2757 wxString libNickname = GetLibId().GetLibNickname();
2758
2759 if( libNickname.empty() )
2760 msg = _( "No library defined!" );
2761 else
2762 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
2763
2764 aList.emplace_back( _( "Library" ), msg );
2765 }
2766}
2767
2768
2773
2774
2776{
2777 std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
2778
2779 if( !libSymbolRef )
2780 return nullptr;
2781
2783}
2784
2785
2787{
2788 int dx = m_pos.x;
2789
2791 MIRROR( m_pos.x, aCenter );
2792 dx -= m_pos.x; // dx,0 is the move vector for this transform
2793
2794 for( SCH_FIELD& field : m_fields )
2795 {
2796 // Move the fields to the new position because the symbol itself has moved.
2797 VECTOR2I pos = field.GetTextPos();
2798 pos.x -= dx;
2799 field.SetTextPos( pos );
2800 }
2801}
2802
2803
2805{
2806 int dy = m_pos.y;
2807
2809 MIRROR( m_pos.y, aCenter );
2810 dy -= m_pos.y; // 0,dy is the move vector for this transform
2811
2812 for( SCH_FIELD& field : m_fields )
2813 {
2814 // Move the fields to the new position because the symbol itself has moved.
2815 VECTOR2I pos = field.GetTextPos();
2816 pos.y -= dy;
2817 field.SetTextPos( pos );
2818 }
2819}
2820
2821
2822void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
2823{
2824 VECTOR2I prev = m_pos;
2825
2826 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
2827
2829
2830 for( SCH_FIELD& field : m_fields )
2831 {
2832 // Move the fields to the new position because the symbol itself has moved.
2833 VECTOR2I pos = field.GetTextPos();
2834 pos.x -= prev.x - m_pos.x;
2835 pos.y -= prev.y - m_pos.y;
2836 field.SetTextPos( pos );
2837 }
2838}
2839
2840
2841bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
2842{
2843 if( aSearchData.searchMetadata )
2844 {
2845 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
2846 return true;
2847
2848 if( EDA_ITEM::Matches( GetShownDescription(), aSearchData ) )
2849 return true;
2850
2851 if( EDA_ITEM::Matches( GetShownKeyWords(), aSearchData ) )
2852 return true;
2853 }
2854
2855 for( SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
2856 {
2857 if( drawItem.Matches( aSearchData, aAuxData ) )
2858 return true;
2859 }
2860
2861 // Symbols are searchable via the child field and pin item text.
2862 return false;
2863}
2864
2865
2866void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
2867{
2868 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2869 {
2870 SCH_PIN* lib_pin = pin->GetLibPin();
2871
2872 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
2873 continue;
2874
2875 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
2876 aItemList.push_back( item );
2877 }
2878}
2879
2880
2881bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
2882 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
2883{
2884 bool changed = false;
2885
2886 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2887 {
2888 bool previousState = pin->IsDangling();
2889 pin->SetIsDangling( true );
2890
2891 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
2892
2893 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
2894 bool do_break = false;
2895
2896 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
2897 {
2898 DANGLING_END_ITEM& each_item = *it;
2899
2900 // Some people like to stack pins on top of each other in a symbol to indicate
2901 // internal connection. While technically connected, it is not particularly useful
2902 // to display them that way, so skip any pins that are in the same symbol as this
2903 // one.
2904 if( each_item.GetParent() == this )
2905 continue;
2906
2907 switch( each_item.GetType() )
2908 {
2909 case PIN_END:
2910 case LABEL_END:
2911 case SHEET_LABEL_END:
2912 case WIRE_END:
2913 case NO_CONNECT_END:
2914 case JUNCTION_END:
2915 pin->SetIsDangling( false );
2916 do_break = true;
2917 break;
2918
2919 default: break;
2920 }
2921
2922 if( do_break )
2923 break;
2924 }
2925
2926 changed = ( changed || ( previousState != pin->IsDangling() ) );
2927 }
2928
2929 return changed;
2930}
2931
2932
2934{
2935 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
2936 return VECTOR2I( 0, 0 );
2937
2938 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
2939}
2940
2941
2942bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
2943{
2944 // Do not compare to ourself.
2945 if( aItem == this )
2946 return false;
2947
2948 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
2949
2950 // Don't compare against a different SCH_ITEM.
2951 wxCHECK( symbol, false );
2952
2953 // The move algorithm marks any pins that are being moved without something attached
2954 // (during the move) as dangling. We always need to recheck connectivity in this case
2955 // or we will not notice changes when the user places the symbol back in the same position
2956 // it started.
2957 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2958 {
2959 if( pin->IsDangling() )
2960 return true;
2961 }
2962
2963 if( GetPosition() != symbol->GetPosition() )
2964 return true;
2965
2966 if( GetLibId() != symbol->GetLibId() )
2967 return true;
2968
2969 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
2970 return true;
2971
2972 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
2973 return true;
2974
2975 // Power symbol value field changes are connectivity changes.
2976 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
2977 return true;
2978
2979 if( m_pins.size() != symbol->m_pins.size() )
2980 return true;
2981
2982 for( size_t i = 0; i < m_pins.size(); i++ )
2983 {
2984 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
2985 return true;
2986 }
2987
2988 return false;
2989}
2990
2991
2992std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
2993{
2994 std::vector<VECTOR2I> retval;
2995
2996 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2997 {
2998 // Collect only pins attached to the current unit and convert.
2999 // others are not associated to this symbol instance
3000 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3001 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3002
3003 if( pin_unit > 0 && pin_unit != GetUnit() )
3004 continue;
3005
3006 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3007 continue;
3008
3009 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
3010 }
3011
3012 return retval;
3013}
3014
3015
3017{
3018 if( m_part )
3019 {
3020 // Calculate the position relative to the symbol.
3021 VECTOR2I libPosition = aPosition - m_pos;
3022
3023 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
3024 }
3025
3026 return nullptr;
3027}
3028
3029
3030wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
3031{
3032 return wxString::Format( _( "Symbol %s [%s]" ),
3034 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
3035}
3036
3037
3038INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
3039{
3040 for( KICAD_T scanType : aScanTypes )
3041 {
3042 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
3043 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3044 {
3045 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
3046 return INSPECT_RESULT::QUIT;
3047 }
3048
3049 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
3050 {
3051 for( SCH_FIELD& field : m_fields )
3052 {
3053 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
3054 return INSPECT_RESULT::QUIT;
3055 }
3056 }
3057
3058 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
3059 {
3060 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
3061 return INSPECT_RESULT::QUIT;
3062 }
3063
3064 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3065 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3066 {
3067 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3068 return INSPECT_RESULT::QUIT;
3069 }
3070
3071 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3072 {
3073 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3074 return INSPECT_RESULT::QUIT;
3075 }
3076
3077 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3078 {
3079 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3080 return INSPECT_RESULT::QUIT;
3081 }
3082
3083 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3084 {
3085 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3086 {
3087 // Collect only pins attached to the current unit and convert.
3088 // others are not associated to this symbol instance
3089 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3090 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3091
3092 if( pin_unit > 0 && pin_unit != GetUnit() )
3093 continue;
3094
3095 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3096 continue;
3097
3098 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3099 return INSPECT_RESULT::QUIT;
3100 }
3101 }
3102 }
3103
3105}
3106
3107
3108bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3109{
3110 if( Type() != aItem.Type() )
3111 return Type() < aItem.Type();
3112
3113 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3114
3116
3117 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3118 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3119
3120 if( m_pos.x != symbol->m_pos.x )
3121 return m_pos.x < symbol->m_pos.x;
3122
3123 if( m_pos.y != symbol->m_pos.y )
3124 return m_pos.y < symbol->m_pos.y;
3125
3126 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3127}
3128
3129
3130bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3131{
3132 std::vector<SCH_FIELD*> fields, otherFields;
3133
3134 GetFields( fields, false );
3135 aSymbol.GetFields( otherFields, false );
3136
3137 if( fields.size() != otherFields.size() )
3138 return false;
3139
3140 for( int ii = 0; ii < (int) fields.size(); ii++ )
3141 {
3142 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3143 continue;
3144
3145 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3146 return false;
3147 }
3148
3149 return true;
3150}
3151
3152
3153bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3154{
3155 return !( *this == aSymbol );
3156}
3157
3158
3160{
3161 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3162 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3163
3164 if( &aSymbol != this )
3165 {
3166 SYMBOL::operator=( aSymbol );
3167
3168 m_lib_id = aSymbol.m_lib_id;
3169 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3170 m_pos = aSymbol.m_pos;
3171 m_unit = aSymbol.m_unit;
3172 m_bodyStyle = aSymbol.m_bodyStyle;
3173 m_transform = aSymbol.m_transform;
3174
3175 m_instances = aSymbol.m_instances;
3176
3177 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3178
3179 // Reparent fields after assignment to new symbol.
3180 for( SCH_FIELD& field : m_fields )
3181 field.SetParent( this );
3182
3183 UpdatePins();
3184 }
3185
3186 return *this;
3187}
3188
3189
3190bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3191{
3192 BOX2I bBox = GetBodyBoundingBox();
3193 bBox.Inflate( aAccuracy / 2 );
3194
3195 if( bBox.Contains( aPosition ) )
3196 return true;
3197
3198 return false;
3199}
3200
3201
3202bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3203{
3205 return false;
3206
3207 BOX2I rect = aRect;
3208
3209 rect.Inflate( aAccuracy / 2 );
3210
3211 if( aContained )
3212 return rect.Contains( GetBodyBoundingBox() );
3213
3214 return rect.Intersects( GetBodyBoundingBox() );
3215}
3216
3217
3218bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3219{
3221 return false;
3222
3223 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3224}
3225
3226
3227bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3228{
3229 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3230
3231 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3232 {
3233 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3234 continue;
3235
3236 // Collect only pins attached to the current unit and convert.
3237 // others are not associated to this symbol instance
3238 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3239 continue;
3240
3241 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3242 continue;
3243
3244 if( pin->GetLocalPosition() == new_pos )
3245 return true;
3246 }
3247
3248 return false;
3249}
3250
3251
3253{
3254 return m_isInNetlist;
3255}
3256
3257
3258void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3259 const VECTOR2I& aOffset, bool aDimmed )
3260{
3261 if( aBackground )
3262 return;
3263
3264 if( m_part )
3265 {
3266 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3267
3268 // Copy the source so we can re-orient and translate it.
3269 LIB_SYMBOL tempSymbol( *m_part );
3270 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3271
3272 // Copy the pin info from the symbol to the temp pins
3273 for( unsigned i = 0; i < tempPins.size(); ++i )
3274 {
3275 SCH_PIN* symbolPin = GetPin( libPins[i] );
3276 SCH_PIN* tempPin = tempPins[i];
3277
3278 if( !symbolPin )
3279 continue;
3280
3281 tempPin->SetName( symbolPin->GetShownName() );
3282 tempPin->SetType( symbolPin->GetType() );
3283 tempPin->SetShape( symbolPin->GetShape() );
3284
3285 if( symbolPin->IsDangling() )
3286 tempPin->SetFlags( IS_DANGLING );
3287 }
3288
3289 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3290 {
3291 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3292 {
3293 // Use SCH_FIELD's text resolver
3294 SCH_FIELD dummy( this, FIELD_T::USER );
3295 dummy.SetText( text->GetText() );
3296 text->SetText( dummy.GetShownText( false ) );
3297 }
3298 }
3299
3300 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3301 TRANSFORM savedTransform = renderSettings->m_Transform;
3302 renderSettings->m_Transform = GetTransform();
3303 aPlotter->StartBlock( nullptr );
3304
3305 for( bool local_background : { true, false } )
3306 {
3307 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3308
3309 for( SCH_FIELD field : m_fields )
3310 {
3311 field.ClearRenderCache();
3312 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3313
3314 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3315 && ( field.IsVisible() || field.IsForceVisible() ) )
3316 {
3317 PlotLocalPowerIconShape( aPlotter );
3318 }
3319 }
3320 }
3321
3322 wxString variant = Schematic()->GetCurrentVariant();
3323 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
3324
3325 if( GetDNP( sheet, variant ) )
3326 PlotDNP( aPlotter );
3327
3328 // Plot attributes to a hypertext menu
3329 if( aPlotOpts.m_PDFPropertyPopups )
3330 {
3331 std::vector<wxString> properties;
3332
3333 for( const SCH_FIELD& field : GetFields() )
3334 {
3335 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3336
3337 if( text_field.IsEmpty() )
3338 continue;
3339
3340 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3341 }
3342
3343 if( !m_part->GetKeyWords().IsEmpty() )
3344 {
3345 properties.emplace_back(
3346 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ), m_part->GetKeyWords() ) );
3347 }
3348
3349 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3350 }
3351
3352 aPlotter->EndBlock( nullptr );
3353 renderSettings->m_Transform = savedTransform;
3354
3355 if( !m_part->IsPower() )
3356 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3357 }
3358}
3359
3360
3361void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3362{
3363 BOX2I bbox = GetBodyBoundingBox();
3365 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3366 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3367 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3368
3369 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3370 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3371 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3372
3373 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3374 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3375
3376 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3377
3378 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3379 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3380}
3381
3382
3386static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3387{
3388 double lineWidth = aSize / 10.0;
3389
3390 std::vector<SCH_SHAPE> shapeList;
3391 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3392 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3393
3394 for( const SCH_SHAPE& shape : shapeList )
3395 {
3396 // Currently there are only 2 shapes: BEZIER and CIRCLE
3397 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3398
3399 if( shape.GetShape() == SHAPE_T::BEZIER )
3400 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3401 tolerance, lineWidth );
3402 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3403 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3404 }
3405}
3406
3407
3409{
3410 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3411
3412 // Plot the local power pin indicator icon shape
3413 BOX2I bbox = field->GetBoundingBox();
3414
3415 // Calculate the text orientation according to the parent orientation.
3416 EDA_ANGLE orient = field->GetTextAngle();
3417
3418 if( GetTransform().y1 )
3419 {
3420 // Rotate symbol 90 degrees.
3421 if( orient.IsHorizontal() )
3422 orient = ANGLE_VERTICAL;
3423 else
3424 orient = ANGLE_HORIZONTAL;
3425 }
3426
3427 bool rotated = !orient.IsHorizontal();
3428
3429 VECTOR2D pos;
3430 double size = bbox.GetHeight() / 1.5;
3431
3432 if( rotated )
3433 {
3434 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3435 size = bbox.GetWidth() / 1.5;
3436 }
3437 else
3438 {
3439 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3440 }
3441
3442 // TODO: build and plot icon shape
3443 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3444}
3445
3446
3447void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter ) const
3448{
3449 if( m_part )
3450 {
3451 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3452 TRANSFORM savedTransform = renderSettings->m_Transform;
3453 renderSettings->m_Transform = GetTransform();
3454
3455 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3456
3457 // Copy the source to stay const
3458 LIB_SYMBOL tempSymbol( *m_part );
3459 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3460 SCH_PLOT_OPTS plotOpts;
3461
3462 // Copy the pin info from the symbol to the temp pins
3463 for( unsigned i = 0; i < tempPins.size(); ++i )
3464 {
3465 SCH_PIN* symbolPin = GetPin( libPins[i] );
3466 SCH_PIN* tempPin = tempPins[i];
3467
3468 if( !symbolPin )
3469 continue;
3470
3471 tempPin->SetName( symbolPin->GetShownName() );
3472 tempPin->SetType( symbolPin->GetType() );
3473 tempPin->SetShape( symbolPin->GetShape() );
3474 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3475 }
3476
3477 renderSettings->m_Transform = savedTransform;
3478 }
3479}
3480
3481
3483{
3484 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3485 {
3486 if( pin->IsBrightened() )
3487 return true;
3488 }
3489
3490 return false;
3491}
3492
3493
3495{
3496 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3497 pin->ClearBrightened();
3498}
3499
3500
3501/*
3502 * When modified at the schematic level, we still store the values of these flags in the
3503 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
3504 * will be created and stored locally in the schematic.
3505 */
3507{
3508 return m_part && m_part->GetShowPinNames();
3509}
3510
3511
3513{
3514 if( m_part )
3515 m_part->SetShowPinNames( aShow );
3516}
3517
3518
3520{
3521 return m_part && m_part->GetShowPinNumbers();
3522}
3523
3524
3526{
3527 if( m_part )
3528 m_part->SetShowPinNumbers( aShow );
3529}
3530
3531
3533{
3534 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3535 {
3536 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3537 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3538
3539 if( pin_unit > 0 && pin_unit != GetUnit() )
3540 continue;
3541
3542 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3543 continue;
3544
3545 if( pin->IsPointClickableAnchor( aPos ) )
3546 return true;
3547 }
3548
3549 return false;
3550}
3551
3552
3554{
3555 // return true if the symbol is equivalent to a global label:
3556 // It is a Power symbol
3557 // It has only one pin type Power input
3558
3560 return false;
3561
3562 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3563
3564 if( pin_list.size() != 1 )
3565 return false;
3566
3567 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3568}
3569
3570
3572{
3573 // return true if the symbol is equivalent to a local label:
3574 // It is a Power symbol
3575 // It has only one pin type Power input
3576
3578 return false;
3579
3580 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3581
3582 if( pin_list.size() != 1 )
3583 return false;
3584
3585 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3586}
3587
3588
3590{
3591 if( !m_part )
3592 return false;
3593
3594 return m_part->IsLocalPower();
3595}
3596
3597
3599{
3600 if( !m_part )
3601 return false;
3602
3603 return m_part->IsGlobalPower();
3604}
3605
3606
3608{
3609 return IsLocalPower() || IsGlobalPower();
3610}
3611
3612
3614{
3615 wxCHECK( m_part, false );
3616
3617 return m_part->IsNormal();
3618}
3619
3620
3621std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
3622{
3623 std::unordered_set<wxString> componentClass;
3624
3625 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
3626 {
3627 for( const SCH_FIELD& field : fields )
3628 {
3629 if( field.GetCanonicalName() == wxT( "Component Class" ) )
3630 {
3631 if( field.GetShownText( aPath, false ) != wxEmptyString )
3632 componentClass.insert( field.GetShownText( aPath, false ) );
3633 }
3634 }
3635 };
3636
3637 // First get component classes set on the symbol itself
3638 getComponentClassFields( m_fields );
3639
3640 // Now get component classes set on any enclosing rule areas
3641 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
3642 {
3643 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
3644 {
3645 getComponentClassFields( label->GetFields() );
3646 }
3647 }
3648
3649 return componentClass;
3650}
3651
3652
3653std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
3654 const wxString& aVariantName ) const
3655{
3656 SCH_SYMBOL_INSTANCE instance;
3657
3658 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
3659 return std::nullopt;
3660
3661 return instance.m_Variants.find( aVariantName )->second;
3662}
3663
3664
3665void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
3666{
3667 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
3668
3669 // The instance path must already exist.
3670 if( !instance )
3671 return;
3672
3673 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
3674}
3675
3676
3677void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
3678{
3679 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3680
3681 // The instance path must already exist.
3682 if( !instance || !instance->m_Variants.contains( aVariantName ) )
3683 return;
3684
3685 instance->m_Variants.erase( aVariantName );
3686}
3687
3688
3689void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
3690 const wxString& aNewName )
3691{
3692 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3693
3694 // The instance path must already exist and contain the old variant.
3695 if( !instance || !instance->m_Variants.contains( aOldName ) )
3696 return;
3697
3698 // Get the variant data, update the name, and re-insert with new key
3699 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
3700 variant.m_Name = aNewName;
3701 instance->m_Variants.erase( aOldName );
3702 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
3703}
3704
3705
3706void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
3707 const wxString& aNewVariant )
3708{
3709 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3710
3711 // The instance path must already exist and contain the source variant.
3712 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
3713 return;
3714
3715 // Copy the variant data with a new name
3716 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
3717 variant.m_Name = aNewVariant;
3718 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
3719}
3720
3721
3722bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
3723{
3724 if( Type() != aOther.Type() )
3725 return false;
3726
3727 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3728
3729 if( GetLibId() != symbol.GetLibId() )
3730 return false;
3731
3732 if( GetPosition() != symbol.GetPosition() )
3733 return false;
3734
3735 if( GetUnit() != symbol.GetUnit() )
3736 return false;
3737
3738 if( GetBodyStyle() != symbol.GetBodyStyle() )
3739 return false;
3740
3741 if( GetTransform() != symbol.GetTransform() )
3742 return false;
3743
3744 if( GetFields() != symbol.GetFields() )
3745 return false;
3746
3747 if( m_pins.size() != symbol.m_pins.size() )
3748 return false;
3749
3750 for( unsigned i = 0; i < m_pins.size(); ++i )
3751 {
3752 if( *m_pins[i] != *symbol.m_pins[i] )
3753 return false;
3754 }
3755
3756 return true;
3757}
3758
3759
3760double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3761{
3762 if( Type() != aOther.Type() )
3763 return 0.0;
3764
3765 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3766
3767 if( GetLibId() != symbol.GetLibId() )
3768 return 0.0;
3769
3770 if( GetPosition() == symbol.GetPosition() )
3771 return 1.0;
3772
3773 return 0.0;
3774}
3775
3776
3777void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
3778 double aLineWidth, bool aHorizontal )
3779{
3780 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
3781
3782 double x_right = aSize / 1.6180339887;
3783 double x_middle = x_right / 2.0;
3784
3785 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
3786 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
3787 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
3788
3789 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
3790 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
3791 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
3792 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
3793 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
3794
3795 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3796 aShapeList.back().SetStart( bottomPt );
3797 aShapeList.back().SetBezierC1( bottomAnchorPt );
3798 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
3799 aShapeList.back().SetEnd( leftPt );
3800
3801
3802 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3803 aShapeList.back().SetStart( leftPt );
3804 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
3805 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
3806 aShapeList.back().SetEnd( rightPt );
3807
3808 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3809 aShapeList.back().SetStart( rightPt );
3810 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
3811 aShapeList.back().SetBezierC2( bottomAnchorPt );
3812 aShapeList.back().SetEnd( bottomPt );
3813
3814 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
3815 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
3816 aShapeList.back().SetRadius( aSize / 15.0 );
3817
3818 for( SCH_SHAPE& shape : aShapeList )
3819 {
3820 if( aHorizontal )
3821 shape.Rotate( VECTOR2I( 0, 0 ), true );
3822
3823 shape.Move( aPos );
3824 }
3825}
3826
3827
3829{
3830 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3831 {
3832 if( instance.m_Path == aSheetPath )
3833 return &instance;
3834 }
3835
3836 return nullptr;
3837}
3838
3839
3841{
3842 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
3843 {
3844 if( instance.m_Path == aSheetPath )
3845 return &instance;
3846 }
3847
3848 return nullptr;
3849}
3850
3851
3852static struct SCH_SYMBOL_DESC
3853{
3855 {
3857 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
3858 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
3859 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
3860 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
3861
3865
3872
3879
3880 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
3881 {
3882 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3883 return symbol->GetLibSymbolRef() != nullptr;
3884
3885 return false;
3886 };
3887
3888 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
3890 .SetAvailableFunc( hasLibPart );
3891
3892 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
3894 .SetAvailableFunc( hasLibPart );
3895
3896 const wxString groupFields = _HKI( "Fields" );
3897
3900 groupFields );
3903 groupFields );
3904 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
3905 NO_SETTER( SCH_SYMBOL, wxString ),
3907 groupFields );
3908 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
3909 NO_SETTER( SCH_SYMBOL, wxString ),
3911 groupFields );
3912 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
3914 groupFields );
3915
3916 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
3917 {
3918 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3919 return symbol->IsMultiUnit();
3920
3921 return false;
3922 };
3923
3924 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
3925 {
3926 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3927 return symbol->IsMultiBodyStyle();
3928
3929 return false;
3930 };
3931
3934 .SetAvailableFunc( multiUnit )
3936 []( INSPECTABLE* aItem )
3937 {
3938 wxPGChoices choices;
3939
3940 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3941 {
3942 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
3943 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
3944 }
3945
3946 return choices;
3947 } );
3948
3951 .SetAvailableFunc( multiBodyStyle )
3953 []( INSPECTABLE* aItem )
3954 {
3955 wxPGChoices choices;
3956
3957 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3958 {
3959 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3960 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3961 }
3962
3963 return choices;
3964 } );
3965
3966 const wxString groupAttributes = _HKI( "Attributes" );
3967
3968 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
3971 groupAttributes );
3972 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
3975 groupAttributes );
3976 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
3979 groupAttributes );
3980 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
3983 groupAttributes );
3984 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
3987 groupAttributes );
3988 }
3990
3991
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:937
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:153
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:147
const KIID m_Uuid
Definition eda_item.h:521
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:532
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:406
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:533
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:588
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:606
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:368
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
std::vector< const SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:202
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:712
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:116
FIELD_T GetId() const
Definition sch_field.h:120
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:252
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:507
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:471
SCH_LAYER_ID m_layer
Definition sch_item.h:772
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:174
void SetName(const wxString &aName)
Definition sch_pin.cpp:409
const wxString & GetName() const
Definition sch_pin.cpp:391
bool IsDangling() const override
Definition sch_pin.cpp:451
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:1338
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:256
const wxString & GetShownName() const
Definition sch_pin.cpp:567
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
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
bool GetExcludedFromSim() const
bool GetExcludedFromBoard() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
size_t size() const
Forwarded method from std::vector.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
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
std::vector< SCH_SYMBOL_INSTANCE > m_instances
Define the hierarchical path and reference of the symbol.
void UpdatePrefix()
Set the prefix based on the current reference designator.
wxString m_prefix
C, R, U, Q etc - the first character(s) which typically indicate what the symbol is.
wxString GetDescription() const override
std::unordered_map< SCH_PIN *, SCH_PIN * > m_pinMap
Library pin pointer : SCH_PIN indices.
void SetMirrorX(bool aMirror)
Definition sch_symbol.h:322
bool IsSymbolLikePowerGlobalLabel() const
VECTOR2I m_pos
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.
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:873
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:870
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:767
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:742
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:752
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:874
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool HasConnectivityChanges(const SCH_ITEM *aItem, const SCH_SHEET_PATH *aInstance=nullptr) const override
Check if aItem has connectivity changes against this object.
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
bool GetExcludedFromSimProp() const
Definition sch_symbol.h:737
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_instances), if this entry does not already exist.
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:727
static std::unordered_map< TRANSFORM, int > s_transformToOrientationCache
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
Search for a SCH_FIELD with aFieldName.
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
bool IsPointClickableAnchor(const VECTOR2I &aPos) const override
void UpdateFields(const SCH_SHEET_PATH *aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields)
Restore fields to the original library values.
wxString m_schLibSymbolName
The name used to look up a symbol in the symbol library embedded in a schematic.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
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.
bool HasDeMorganBodyStyles() const override
std::vector< SCH_FIELD > m_fields
Variable length list of fields.
std::vector< SCH_PIN * > GetAllLibPins() const
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) 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:712
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:867
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.
void SyncOtherUnits(const SCH_SHEET_PATH &aSourceSheet, SCH_COMMIT &aCommit, PROPERTY_BASE *aProperty, const wxString &aVariantName=wxEmptyString)
Keep fields other than the reference, include/exclude flags, and alternate pin assignments in sync in...
void Init(const VECTOR2I &pos=VECTOR2I(0, 0))
void SetExcludedFromPosFilesProp(bool aEnable)
Definition sch_symbol.h:772
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:714
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber) const
Find all symbol pins with the given number.
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
void SetX(int aX)
Definition sch_symbol.h:871
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:722
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:757
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:365
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:354
@ 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