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
1298{
1299 if( aResolve )
1300 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText );
1301
1302 return GetField( FIELD_T::FOOTPRINT )->GetText();
1303}
1304
1305
1306void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
1307{
1308 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
1309}
1310
1311
1313{
1314 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
1315 return field;
1316
1317 m_fields.emplace_back( this, aFieldType );
1318 return &m_fields.back();
1319}
1320
1321
1322const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
1323{
1324 return FindField( m_fields, aFieldType );
1325}
1326
1327
1328SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
1329{
1330 return FindField( m_fields, aFieldName );
1331}
1332
1333
1334const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
1335{
1336 return FindField( m_fields, aFieldName );
1337}
1338
1339
1340void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
1341{
1342 for( const SCH_FIELD& field : m_fields )
1343 {
1344 if( aVisibleOnly )
1345 {
1346 if( !field.IsVisible() || field.GetText().IsEmpty() )
1347 continue;
1348 }
1349
1350 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
1351 }
1352
1353 std::sort( aVector.begin(), aVector.end(),
1354 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1355 {
1356 return lhs->GetOrdinal() < rhs->GetOrdinal();
1357 } );
1358}
1359
1360
1362{
1363 return NextFieldOrdinal( m_fields );
1364}
1365
1366
1368{
1369 m_fields.push_back( aField );
1370 return &m_fields.back();
1371}
1372
1373
1374void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
1375{
1376 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
1377 {
1378 if( m_fields[ii].IsMandatory() )
1379 continue;
1380
1381 if( aFieldName == m_fields[ii].GetName( false ) )
1382 {
1383 m_fields.erase( m_fields.begin() + ii );
1384 return;
1385 }
1386 }
1387}
1388
1389
1391{
1392 for( SCH_FIELD& field : m_fields )
1393 {
1394 if( field.GetName().IsSameAs( aFieldName, false ) )
1395 return &field;
1396 }
1397
1398 return nullptr;
1399}
1400
1401
1402void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
1403 bool aResetRef, bool aResetOtherFields )
1404{
1405 if( m_part )
1406 {
1407 std::vector<SCH_FIELD*> fields;
1408 m_part->GetFields( fields );
1409
1410 for( const SCH_FIELD* libField : fields )
1411 {
1412 SCH_FIELD* schField;
1413 FIELD_T fieldType = FIELD_T::USER;
1414
1415 if( libField->IsMandatory() )
1416 {
1417 fieldType = libField->GetId();
1418 schField = GetField( fieldType );
1419 }
1420 else
1421 {
1422 schField = GetField( libField->GetCanonicalName() );
1423
1424 if( !schField )
1425 {
1426 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetCanonicalName() ) );
1427 schField->ImportValues( *libField );
1428 schField->SetTextPos( m_pos + libField->GetTextPos() );
1429 }
1430 }
1431
1432 schField->SetPrivate( libField->IsPrivate() );
1433
1434 if( aUpdateStyle )
1435 {
1436 schField->ImportValues( *libField );
1437 schField->SetTextPos( m_pos + libField->GetTextPos() );
1438 }
1439
1440 if( fieldType == FIELD_T::REFERENCE && aPath )
1441 {
1442 if( aResetRef )
1443 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
1444 else if( aUpdateRef )
1445 SetRef( aPath, libField->GetText() );
1446 }
1447 else if( fieldType == FIELD_T::VALUE )
1448 {
1449 SetValueFieldText( UnescapeString( libField->GetText() ) );
1450 }
1451 else if( fieldType == FIELD_T::DATASHEET )
1452 {
1453 if( aResetOtherFields )
1454 schField->SetText( GetDatasheet() ); // alias-specific value
1455 else if( aUpdateOtherFields )
1456 schField->SetText( libField->GetText() );
1457 }
1458 else
1459 {
1460 if( aResetOtherFields || aUpdateOtherFields )
1461 schField->SetText( libField->GetText() );
1462 }
1463 }
1464 }
1465}
1466
1467
1468void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit, PROPERTY_BASE* aProperty )
1469{
1470 bool updateValue = true;
1471 bool updateExclFromBOM = true;
1472 bool updateExclFromBoard = true;
1473 bool updateDNP = true;
1474 bool updateOtherFields = true;
1475 bool updatePins = true;
1476
1477 if( aProperty )
1478 {
1479 updateValue = aProperty->Name() == _HKI( "Value" );
1480 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
1481 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
1482 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
1483 updateOtherFields = false;
1484 updatePins = false;
1485 }
1486
1487 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateDNP && !updateOtherFields && !updatePins )
1488 {
1489 return;
1490 }
1491
1492 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
1493 // in sync in multi-unit parts.
1494 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
1495 {
1496 wxString ref = GetRef( &aSourceSheet );
1497
1498 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1499 {
1500 SCH_SCREEN* screen = sheet.LastScreen();
1501 std::vector<SCH_SYMBOL*> otherUnits;
1502
1503 CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
1504
1505 for( SCH_SYMBOL* otherUnit : otherUnits )
1506 {
1507 aCommit.Modify( otherUnit, screen );
1508
1509 if( updateValue )
1510 otherUnit->SetValueFieldText( GetField( FIELD_T::VALUE )->GetText() );
1511
1512 if( updateOtherFields )
1513 {
1514 for( SCH_FIELD& field : m_fields )
1515 {
1516 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
1517 {
1518 // already handled
1519 continue;
1520 }
1521
1522 SCH_FIELD* otherField;
1523
1524 if( field.IsMandatory() )
1525 otherField = otherUnit->GetField( field.GetId() );
1526 else
1527 otherField = otherUnit->GetField( field.GetName() );
1528
1529 if( otherField )
1530 {
1531 otherField->SetText( field.GetText() );
1532 }
1533 else
1534 {
1535 SCH_FIELD newField( field );
1536 const_cast<KIID&>( newField.m_Uuid ) = KIID();
1537
1538 newField.Offset( -GetPosition() );
1539 newField.Offset( otherUnit->GetPosition() );
1540
1541 newField.SetParent( otherUnit );
1542 otherUnit->AddField( newField );
1543 }
1544 }
1545
1546 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
1547 {
1548 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
1549
1550 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
1551 otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
1552 }
1553 }
1554
1555 if( updateExclFromBOM )
1556 otherUnit->SetExcludedFromBOM( m_excludedFromBOM );
1557
1558 if( updateExclFromBoard )
1559 otherUnit->SetExcludedFromBoard( m_excludedFromBoard );
1560
1561 if( updateDNP )
1562 otherUnit->SetDNP( GetDNP( &aSourceSheet ), &sheet );
1563
1564 if( updatePins )
1565 {
1566 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
1567 {
1568 SCH_PIN* src_pin = otherUnit->GetPin( model_pin->GetNumber() );
1569
1570 if( src_pin )
1571 src_pin->SetAlt( model_pin->GetAlt() );
1572 }
1573 }
1574 }
1575 }
1576 }
1577}
1578
1579
1580void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
1581{
1582 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1583 aFunction( pin.get() );
1584
1585 for( SCH_FIELD& field : m_fields )
1586 aFunction( &field );
1587}
1588
1589
1590SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
1591{
1592 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1593 {
1594 if( pin->GetNumber() == aNumber )
1595 return pin.get();
1596 }
1597
1598 return nullptr;
1599}
1600
1601
1602const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
1603{
1604 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1605 {
1606 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
1607 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
1608
1609 if( pin_unit > 0 && pin_unit != GetUnit() )
1610 continue;
1611
1612 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
1613 continue;
1614
1615 if( pin->GetPosition() == aPos )
1616 return pin.get();
1617 }
1618
1619 return nullptr;
1620}
1621
1622
1623std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
1624{
1625 if( m_part )
1626 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
1627
1628 return std::vector<SCH_PIN*>();
1629}
1630
1631
1632std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
1633{
1634 if( m_part )
1635 return m_part->GetPins();
1636
1637 return std::vector<SCH_PIN*>();
1638}
1639
1640
1642{
1643 return m_part ? m_part->GetPinCount() : 0;
1644}
1645
1646
1648{
1649 auto it = m_pinMap.find( aLibPin );
1650
1651 if( it != m_pinMap.end() )
1652 return it->second;
1653
1654 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
1655 return nullptr;
1656}
1657
1658
1659std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
1660{
1661 std::vector<SCH_PIN*> pins;
1662 int unit = m_unit;
1663
1664 if( !aSheet && Schematic() )
1665 aSheet = &Schematic()->CurrentSheet();
1666
1667 if( aSheet )
1668 unit = GetUnitSelection( aSheet );
1669
1670 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1671 {
1672 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
1673 continue;
1674
1675 pins.push_back( pin.get() );
1676 }
1677
1678 return pins;
1679}
1680
1681
1682std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
1683{
1684 return GetPins( nullptr );
1685}
1686
1687
1689{
1690 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
1691
1692 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
1693
1694 std::swap( m_lib_id, symbol->m_lib_id );
1695
1696 m_pins.swap( symbol->m_pins ); // std::vector's swap()
1697
1698 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
1699 pin->SetParent( symbol );
1700
1701 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1702 pin->SetParent( this );
1703
1704 LIB_SYMBOL* libSymbol = symbol->m_part.release();
1705 symbol->m_part = std::move( m_part );
1706 symbol->UpdatePins();
1707 m_part.reset( libSymbol );
1708 UpdatePins();
1709
1710 std::swap( m_pos, symbol->m_pos );
1711 std::swap( m_unit, symbol->m_unit );
1712 std::swap( m_bodyStyle, symbol->m_bodyStyle );
1713
1714 m_fields.swap( symbol->m_fields ); // std::vector's swap()
1715
1716 for( SCH_FIELD& field : symbol->m_fields )
1717 field.SetParent( symbol );
1718
1719 for( SCH_FIELD& field : m_fields )
1720 field.SetParent( this );
1721
1722 TRANSFORM tmp = m_transform;
1723
1724 m_transform = symbol->m_transform;
1725 symbol->m_transform = tmp;
1726
1727 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
1728 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
1729 std::swap( m_DNP, symbol->m_DNP );
1730 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
1731
1732 std::swap( m_instances, symbol->m_instances );
1733 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
1734}
1735
1736
1737void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
1738{
1739 for( const SCH_FIELD& field : m_fields )
1740 {
1741 if( field.IsPrivate() )
1742 continue;
1743
1744 if( field.IsMandatory() )
1745 aVars->push_back( field.GetCanonicalName().Upper() );
1746 else
1747 aVars->push_back( field.GetName() );
1748 }
1749
1750 aVars->push_back( wxT( "OP" ) );
1751 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
1752 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
1753 aVars->push_back( wxT( "UNIT" ) );
1754 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
1755 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
1756 aVars->push_back( wxT( "SYMBOL_NAME" ) );
1757 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
1758 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
1759 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
1760 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
1761 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
1762 aVars->push_back( wxT( "DNP" ) );
1763 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
1764 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
1765 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
1766 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
1767 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
1768 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
1769 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
1770}
1771
1772
1773bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
1774{
1775 return ResolveTextVar( aPath, token, wxEmptyString, aDepth );
1776}
1777
1778
1779bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token,
1780 const wxString& aVariantName, int aDepth ) const
1781{
1782 static wxRegEx operatingPoint( wxT( "^"
1783 "OP"
1784 "(:[^.]*)?" // pin
1785 "(.([0-9])?" // precisionStr
1786 "([a-zA-Z]*))?" // rangeStr
1787 "$" ) );
1788
1789 wxCHECK( aPath, false );
1790
1791 SCHEMATIC* schematic = Schematic();
1792
1793 if( !schematic )
1794 return false;
1795
1796 if( operatingPoint.Matches( *token ) )
1797 {
1798 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
1799 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
1800 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
1801
1802 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
1803 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
1804
1805 SIM_LIB_MGR simLibMgr( &schematic->Project() );
1806
1807 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
1808 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
1809
1810 if( m_part )
1811 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
1812
1813 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
1814
1815 NULL_REPORTER devnull;
1816 SIM_MODEL& model =
1817 simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1, devnull ).model;
1818 SPICE_ITEM spiceItem;
1819 spiceItem.refName = GetRef( aPath );
1820
1821 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
1822 spiceRef = spiceRef.Lower();
1823
1824 if( pin.IsEmpty() )
1825 {
1826 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1827 return true;
1828 }
1829 else if( pin == wxS( ":power" ) )
1830 {
1831 if( rangeStr.IsEmpty() )
1832 range = wxS( "~W" );
1833
1834 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
1835 return true;
1836 }
1837 else
1838 {
1839 pin = pin.SubString( 1, -1 ); // Strip ':' from front
1840
1841 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
1842 {
1843 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
1844
1845 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
1846 {
1847 if( model.GetPins().size() == 2 )
1848 {
1849 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
1850 }
1851 else
1852 {
1853 wxString signalName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
1854 *token = schematic->GetOperatingPoint( signalName, precision, range );
1855 }
1856
1857 return true;
1858 }
1859 }
1860 }
1861
1862 *token = wxS( "?" );
1863 return true;
1864 }
1865
1866 if( token->Contains( ':' ) )
1867 {
1868 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
1869 return true;
1870 }
1871
1872 for( const SCH_FIELD& field : m_fields )
1873 {
1874 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName() : field.GetName();
1875
1876 wxString textToken = field.GetText();
1877 textToken.Replace( " ", wxEmptyString );
1878 wxString tokenString = "${" + fieldName + "}";
1879
1880 // If the field data is just a reference to the field, don't resolve
1881 if( textToken.IsSameAs( tokenString, false ) )
1882 return true;
1883
1884 if( token->IsSameAs( fieldName, false ) )
1885 {
1886 if( field.GetId() == FIELD_T::REFERENCE )
1887 {
1888 *token = GetRef( aPath, true );
1889 }
1890 else if( !aVariantName.IsEmpty() )
1891 {
1892 // Check for variant-specific field value
1893 std::optional<SCH_SYMBOL_VARIANT> variant = GetVariant( *aPath, aVariantName );
1894
1895 if( variant && variant->m_Fields.contains( fieldName ) )
1896 *token = variant->m_Fields.at( fieldName );
1897 else
1898 *token = field.GetShownText( aPath, false, aDepth + 1 );
1899 }
1900 else
1901 {
1902 *token = field.GetShownText( aPath, false, aDepth + 1 );
1903 }
1904
1905 return true;
1906 }
1907 }
1908
1909 // Consider missing simulation fields as empty, not un-resolved
1910 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
1911 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
1912 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
1913 {
1914 *token = wxEmptyString;
1915 return true;
1916 }
1917
1918 for( const TEMPLATE_FIELDNAME& templateFieldname :
1920 {
1921 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
1922 {
1923 // If we didn't find it in the fields list then it isn't set on this symbol.
1924 // Just return an empty string.
1925 *token = wxEmptyString;
1926 return true;
1927 }
1928 }
1929
1930 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1931 {
1932 wxString footprint = GetFootprintFieldText( true, aPath, false );
1933
1934 wxArrayString parts = wxSplit( footprint, ':' );
1935
1936 if( parts.Count() > 0 )
1937 *token = parts[0];
1938 else
1939 *token = wxEmptyString;
1940
1941 return true;
1942 }
1943 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1944 {
1945 wxString footprint = GetFootprintFieldText( true, aPath, false );
1946
1947 wxArrayString parts = wxSplit( footprint, ':' );
1948
1949 if( parts.Count() > 1 )
1950 *token = parts[std::min( 1, (int) parts.size() - 1 )];
1951 else
1952 *token = wxEmptyString;
1953
1954 return true;
1955 }
1956 else if( token->IsSameAs( wxT( "UNIT" ) ) )
1957 {
1958 *token = SubReference( GetUnitSelection( aPath ) );
1959 return true;
1960 }
1961 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
1962 {
1963 *token = GetRef( aPath, false );
1964 return true;
1965 }
1966 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
1967 {
1968 *token = m_lib_id.GetUniStringLibNickname();
1969 return true;
1970 }
1971 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
1972 {
1973 *token = m_lib_id.GetUniStringLibItemName();
1974 return true;
1975 }
1976 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
1977 {
1978 *token = GetShownDescription( aDepth + 1 );
1979 return true;
1980 }
1981 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
1982 {
1983 *token = GetShownKeyWords( aDepth + 1 );
1984 return true;
1985 }
1986 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
1987 {
1988 *token = wxEmptyString;
1989
1990 if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
1991 *token = _( "Excluded from BOM" );
1992
1993 return true;
1994 }
1995 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
1996 {
1997 *token = wxEmptyString;
1998
1999 if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
2000 *token = _( "Excluded from board" );
2001
2002 return true;
2003 }
2004 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
2005 {
2006 *token = wxEmptyString;
2007
2008 if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
2009 *token = _( "Excluded from simulation" );
2010
2011 return true;
2012 }
2013 else if( token->IsSameAs( wxT( "DNP" ) ) )
2014 {
2015 *token = wxEmptyString;
2016
2017 if( aPath->GetDNP() || this->ResolveDNP() )
2018 *token = _( "DNP" );
2019
2020 return true;
2021 }
2022 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
2023 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
2024 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
2025 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
2026 || token->StartsWith( wxT( "UNIT(" ) ) )
2027 {
2028 wxString pinNumber = token->AfterFirst( '(' );
2029 pinNumber = pinNumber.BeforeLast( ')' );
2030
2031 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
2032 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
2033 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
2034
2035 // First, try to find the pin in the current unit (for backward compatibility)
2036 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
2037 std::vector<SCH_PIN*> pinsToSearch = ( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2038 ? GetAllLibPins() : GetPins( aPath );
2039
2040 for( SCH_PIN* pin : pinsToSearch )
2041 {
2042 if( pin->GetNumber() == pinNumber )
2043 {
2044 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2045 {
2046 int pinUnit = pin->GetUnit();
2047 wxString result;
2048
2049 if( isReferenceFunction )
2050 {
2051 // Return the full unit reference (e.g., "J601A")
2052 if( pinUnit > 0 )
2053 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
2054 else
2055 result = GetRef( aPath, false );
2056 }
2057 else if( isShortReferenceFunction )
2058 {
2059 // Return the reference without unit (e.g., "J601")
2060 result = GetRef( aPath, false );
2061 }
2062 else if( isUnitFunction )
2063 {
2064 // Return only the unit letter (e.g., "A")
2065 if( pinUnit > 0 )
2066 result = SubReference( pinUnit, false );
2067 else
2068 result = wxEmptyString;
2069 }
2070
2071 *token = result;
2072 return true;
2073 }
2074 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2075 {
2076 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
2077 return true;
2078 }
2079 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2080 {
2081 *token = pin->GetBaseName();
2082 return true;
2083 }
2084 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2085 {
2086 // Build list of alternate names only (no base name)
2087 wxString altList;
2088
2089 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2090
2091 for( const auto& [altName, altDef] : alts )
2092 {
2093 if( !altList.IsEmpty() )
2094 altList += wxT( ", " );
2095 altList += altName;
2096 }
2097
2098 *token = altList;
2099 return true;
2100 }
2101
2102 SCH_CONNECTION* conn = pin->Connection( aPath );
2103
2104 if( !conn )
2105 {
2106 *token = wxEmptyString;
2107 }
2108 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2109 {
2110 wxString netName = conn->LocalName();
2111 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2112 *token = wxT( "NC" );
2113 else
2114 *token = netName;
2115 }
2116 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2117 {
2118 *token = conn->Name();
2119 }
2120 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2121 {
2122 *token = pin->GetEffectiveNetClass( aPath )->GetName();
2123 }
2124
2125 return true;
2126 }
2127 }
2128
2129 // If pin not found in current unit, search all units (auto-resolution)
2130 // Skip this for REFERENCE/SHORT_REFERENCE/UNIT functions as they already searched all units
2131 if( !isReferenceFunction && !isShortReferenceFunction && !isUnitFunction )
2132 {
2133 for( SCH_PIN* pin : GetAllLibPins() )
2134 {
2135 if( pin->GetNumber() == pinNumber )
2136 {
2137 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
2138 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2139 {
2140 *token = pin->GetBaseName();
2141 return true;
2142 }
2143 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2144 {
2145 // Build list of alternate names only (no base name)
2146 wxString altList;
2147
2148 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2149
2150 for( const auto& [altName, altDef] : alts )
2151 {
2152 if( !altList.IsEmpty() )
2153 altList += wxT( ", " );
2154 altList += altName;
2155 }
2156
2157 *token = altList;
2158 return true;
2159 }
2160
2161 // For net-related functions, find which sheet path has this pin's unit
2162 int pinUnit = pin->GetUnit();
2163
2164 // Search all sheets for a symbol with our reference and the correct unit
2165 // This is needed because each unit of a multi-unit symbol is a separate object
2166 SCH_SHEET_PATH targetPath;
2167 SCH_SYMBOL* targetSymbol = nullptr;
2168
2169 if( Schematic() )
2170 {
2171 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
2172 {
2173 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2174 {
2175 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2176
2177 // Check if this symbol has the same reference designator and the correct unit
2178 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
2179 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
2180 {
2181 targetPath = sheetPath; // Copy the sheet path
2182 targetSymbol = symbol;
2183 break;
2184 }
2185 }
2186
2187 if( targetSymbol )
2188 break;
2189 }
2190 }
2191
2192 if( !targetSymbol )
2193 {
2194 // Unit not placed on any sheet
2195 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
2196 return true;
2197 }
2198
2199 // Get the pin from the actual instance symbol we found
2200 // Match by pin number, not by pointer, since the library pins are different objects
2201 SCH_PIN* instancePin = nullptr;
2202
2203 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
2204 {
2205 if( candidate->GetNumber() == pinNumber )
2206 {
2207 instancePin = candidate;
2208 break;
2209 }
2210 }
2211
2212 if( !instancePin )
2213 {
2214 *token = wxEmptyString;
2215 return true;
2216 }
2217
2218 // PIN_NAME doesn't need connection data, just instance pin
2219 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2220 {
2221 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
2222 return true;
2223 }
2224
2225 // Now get the connection from the correct sheet path
2226 SCH_CONNECTION* conn = instancePin->Connection( &targetPath );
2227
2228 if( !conn )
2229 {
2230 *token = wxEmptyString;
2231 }
2232 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2233 {
2234 wxString netName = conn->LocalName();
2235 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2236 *token = wxT( "NC" );
2237 else
2238 *token = netName;
2239 }
2240 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2241 {
2242 *token = conn->Name();
2243 }
2244 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2245 {
2246 *token = instancePin->GetEffectiveNetClass( &targetPath )->GetName();
2247 }
2248
2249 return true;
2250 }
2251 }
2252 }
2253
2254 // If we got here, no pin was found - report unresolved
2255 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
2256 return true;
2257 }
2258
2259 // See if parent can resolve it (this will recurse to ancestors)
2260 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
2261 return true;
2262
2263 return false;
2264}
2265
2266
2267void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
2268{
2269 if( aSheetPath )
2270 {
2271 KIID_PATH path = aSheetPath->Path();
2272
2273 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2274 {
2275 if( instance.m_Path == path )
2276 {
2277 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2278 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2279 else
2280 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2281 }
2282 }
2283 }
2284 else
2285 {
2286 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2287 {
2288 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2289 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2290 else
2291 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2292 }
2293 }
2294
2295 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2296 pin->ClearDefaultNetName( aSheetPath );
2297
2298 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
2299 // When clearing for a specific sheet path, we must preserve the field text because it serves
2300 // as a fallback for GetRef() when instances for other sheet paths are looked up.
2301 // See issue #20173: modifying field text here corrupts references in shared screens.
2302 if( !aSheetPath )
2303 {
2304 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
2305
2306 if( currentReference.IsEmpty() || aResetPrefix )
2308 else
2310 }
2311}
2312
2313
2315{
2316 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
2317 wxCHECK( aSheetPath.size() > 0, false );
2318
2319 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
2320 {
2321 // if aSheetPath is found, nothing to do:
2322 if( instance.m_Path == aSheetPath )
2323 return false;
2324 }
2325
2326 // This entry does not exist: add it, with its last-used reference
2327 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
2328 return true;
2329}
2330
2331
2332void SCH_SYMBOL::SetOrientation( int aOrientation )
2333{
2334 TRANSFORM temp = TRANSFORM();
2335 bool transform = false;
2336
2337 switch( aOrientation )
2338 {
2339 case SYM_ORIENT_0:
2340 case SYM_NORMAL: // default transform matrix
2342 break;
2343
2344 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
2345 temp.x1 = 0;
2346 temp.y1 = 1;
2347 temp.x2 = -1;
2348 temp.y2 = 0;
2349 transform = true;
2350 break;
2351
2352 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
2353 temp.x1 = 0;
2354 temp.y1 = -1;
2355 temp.x2 = 1;
2356 temp.y2 = 0;
2357 transform = true;
2358 break;
2359
2360 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
2361 temp.x1 = -1;
2362 temp.y1 = 0;
2363 temp.x2 = 0;
2364 temp.y2 = 1;
2365 transform = true;
2366 break;
2367
2368 case SYM_MIRROR_X: // Mirror X (incremental transform)
2369 temp.x1 = 1;
2370 temp.y1 = 0;
2371 temp.x2 = 0;
2372 temp.y2 = -1;
2373 transform = true;
2374 break;
2375
2376 case SYM_ORIENT_90:
2379 break;
2380
2381 case SYM_ORIENT_180:
2385 break;
2386
2387 case SYM_ORIENT_270:
2390 break;
2391
2392 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
2395 break;
2396
2397 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
2400 break;
2401
2406 break;
2407
2408 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
2411 break;
2412
2413 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
2416 break;
2417
2422 break;
2423
2424 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
2427 break;
2428
2429 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
2432 break;
2433
2438 break;
2439
2440 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
2443 break;
2444
2445 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
2448 break;
2449
2454 break;
2455
2456 default:
2457 transform = false;
2458 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
2459 break;
2460 }
2461
2462 if( transform )
2463 {
2464 /* The new matrix transform is the old matrix transform modified by the
2465 * requested transformation, which is the temp transform (rot,
2466 * mirror ..) in order to have (in term of matrix transform):
2467 * transform coord = new_m_transform * coord
2468 * where transform coord is the coord modified by new_m_transform from
2469 * the initial value coord.
2470 * new_m_transform is computed (from old_m_transform and temp) to
2471 * have:
2472 * transform coord = old_m_transform * temp
2473 */
2474 TRANSFORM newTransform;
2475
2476 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
2477 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
2478 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
2479 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
2480 m_transform = newTransform;
2481 }
2482}
2483
2484
2486{
2487 /*
2488 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
2489 * now, so let's just cache it for the moment.
2490 */
2493
2494 int rotate_values[] = { SYM_ORIENT_0,
2506
2507 // Try to find the current transform option:
2508 TRANSFORM transform = m_transform;
2509 SCH_SYMBOL temp( *this );
2510 temp.SetParentGroup( nullptr );
2511
2512 for( int type_rotate : rotate_values )
2513 {
2514 temp.SetOrientation( type_rotate );
2515
2516 if( transform == temp.GetTransform() )
2517 {
2519 return type_rotate;
2520 }
2521 }
2522
2523 // Error: orientation not found in list (should not happen)
2524 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
2525
2526 return SYM_NORMAL;
2527}
2528
2529
2530#if defined( DEBUG )
2531
2532void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
2533{
2534 // for now, make it look like XML:
2535 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
2536 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
2537 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
2538 << ">\n";
2539
2540 // skip the reference, it's been output already.
2541 for( int i = 1; i < (int) GetFields().size(); ++i )
2542 {
2543 const wxString& value = GetFields()[i].GetText();
2544
2545 if( !value.IsEmpty() )
2546 {
2547 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
2548 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
2549 }
2550 }
2551
2552 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
2553}
2554
2555#endif
2556
2557
2558BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
2559{
2560 BOX2I bBox;
2561
2562 if( m_part )
2563 bBox = m_part->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2564 else
2565 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2566
2567 bBox = m_transform.TransformCoordinate( bBox );
2568 bBox.Normalize();
2569
2570 bBox.Offset( m_pos );
2571
2572 if( aIncludeFields )
2573 {
2574 for( const SCH_FIELD& field : m_fields )
2575 {
2576 if( field.IsVisible() )
2577 bBox.Merge( field.GetBoundingBox() );
2578 }
2579 }
2580
2581 return bBox;
2582}
2583
2584
2586{
2587 try
2588 {
2589 return doGetBoundingBox( false, false );
2590 }
2591 catch( const boost::bad_pointer& e )
2592 {
2593 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
2594 return BOX2I();
2595 }
2596}
2597
2598
2600{
2601 return doGetBoundingBox( true, false );
2602}
2603
2604
2606{
2607 return doGetBoundingBox( true, true );
2608}
2609
2610
2611void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2612{
2613 wxString msg;
2614
2615 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
2616 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
2617
2618 auto addExcludes = [&]()
2619 {
2620 wxArrayString msgs;
2621
2622 if( GetExcludedFromSim() )
2623 msgs.Add( _( "Simulation" ) );
2624
2625 if( GetExcludedFromBOM() )
2626 msgs.Add( _( "BOM" ) );
2627
2628 if( GetExcludedFromBoard() )
2629 msgs.Add( _( "Board" ) );
2630
2631 if( GetDNP( currentSheet ) )
2632 msgs.Add( _( "DNP" ) );
2633
2634 msg = wxJoin( msgs, '|' );
2635 msg.Replace( '|', wxS( ", " ) );
2636
2637 if( !msg.empty() )
2638 aList.emplace_back( _( "Exclude from" ), msg );
2639 };
2640
2641 // part and alias can differ if alias is not the root
2642 if( m_part )
2643 {
2644 if( m_part.get() != LIB_SYMBOL::GetDummy() )
2645 {
2646 if( m_part->IsPower() )
2647 {
2648 // Don't use GetShownText(); we want to see the variable references here
2649 aList.emplace_back( _( "Power symbol" ),
2650 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2651 }
2652 else
2653 {
2654 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
2655
2656 // Don't use GetShownText(); we want to see the variable references here
2657 aList.emplace_back( _( "Value" ),
2658 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2659 addExcludes();
2660 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2661 }
2662
2663#if 0 // Display symbol flags, for debug only
2664 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
2665#endif
2666
2667 if( !m_part->IsRoot() )
2668 {
2669 msg = _( "Missing parent" );
2670
2671 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
2672
2673 if( parent )
2674 msg = parent->GetName();
2675
2676 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
2677 }
2678 else if( !m_lib_id.GetLibNickname().empty() )
2679 {
2680 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
2681 }
2682 else
2683 {
2684 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
2685 }
2686
2687 // Display the current associated footprint, if exists.
2688 // Don't use GetShownText(); we want to see the variable references here
2689 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
2690
2691 if( msg.IsEmpty() )
2692 msg = _( "<Unknown>" );
2693
2694 aList.emplace_back( _( "Footprint" ), msg );
2695
2696 // Display description of the symbol, and keywords found in lib
2697 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
2698 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
2699 }
2700 }
2701 else
2702 {
2703 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
2704
2705 // Don't use GetShownText(); we want to see the variable references here
2706 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2707 addExcludes();
2708 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2709
2710 wxString libNickname = GetLibId().GetLibNickname();
2711
2712 if( libNickname.empty() )
2713 msg = _( "No library defined!" );
2714 else
2715 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
2716
2717 aList.emplace_back( _( "Library" ), msg );
2718 }
2719}
2720
2721
2726
2727
2729{
2730 std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
2731
2732 if( !libSymbolRef )
2733 return nullptr;
2734
2736}
2737
2738
2740{
2741 int dx = m_pos.x;
2742
2744 MIRROR( m_pos.x, aCenter );
2745 dx -= m_pos.x; // dx,0 is the move vector for this transform
2746
2747 for( SCH_FIELD& field : m_fields )
2748 {
2749 // Move the fields to the new position because the symbol itself has moved.
2750 VECTOR2I pos = field.GetTextPos();
2751 pos.x -= dx;
2752 field.SetTextPos( pos );
2753 }
2754}
2755
2756
2758{
2759 int dy = m_pos.y;
2760
2762 MIRROR( m_pos.y, aCenter );
2763 dy -= m_pos.y; // 0,dy is the move vector for this transform
2764
2765 for( SCH_FIELD& field : m_fields )
2766 {
2767 // Move the fields to the new position because the symbol itself has moved.
2768 VECTOR2I pos = field.GetTextPos();
2769 pos.y -= dy;
2770 field.SetTextPos( pos );
2771 }
2772}
2773
2774
2775void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
2776{
2777 VECTOR2I prev = m_pos;
2778
2779 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
2780
2782
2783 for( SCH_FIELD& field : m_fields )
2784 {
2785 // Move the fields to the new position because the symbol itself has moved.
2786 VECTOR2I pos = field.GetTextPos();
2787 pos.x -= prev.x - m_pos.x;
2788 pos.y -= prev.y - m_pos.y;
2789 field.SetTextPos( pos );
2790 }
2791}
2792
2793
2794bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
2795{
2796 if( aSearchData.searchMetadata )
2797 {
2798 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
2799 return true;
2800
2801 if( EDA_ITEM::Matches( GetShownDescription(), aSearchData ) )
2802 return true;
2803
2804 if( EDA_ITEM::Matches( GetShownKeyWords(), aSearchData ) )
2805 return true;
2806 }
2807
2808 for( SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
2809 {
2810 if( drawItem.Matches( aSearchData, aAuxData ) )
2811 return true;
2812 }
2813
2814 // Symbols are searchable via the child field and pin item text.
2815 return false;
2816}
2817
2818
2819void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
2820{
2821 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2822 {
2823 SCH_PIN* lib_pin = pin->GetLibPin();
2824
2825 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
2826 continue;
2827
2828 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
2829 aItemList.push_back( item );
2830 }
2831}
2832
2833
2834bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
2835 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
2836{
2837 bool changed = false;
2838
2839 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2840 {
2841 bool previousState = pin->IsDangling();
2842 pin->SetIsDangling( true );
2843
2844 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
2845
2846 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
2847 bool do_break = false;
2848
2849 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
2850 {
2851 DANGLING_END_ITEM& each_item = *it;
2852
2853 // Some people like to stack pins on top of each other in a symbol to indicate
2854 // internal connection. While technically connected, it is not particularly useful
2855 // to display them that way, so skip any pins that are in the same symbol as this
2856 // one.
2857 if( each_item.GetParent() == this )
2858 continue;
2859
2860 switch( each_item.GetType() )
2861 {
2862 case PIN_END:
2863 case LABEL_END:
2864 case SHEET_LABEL_END:
2865 case WIRE_END:
2866 case NO_CONNECT_END:
2867 case JUNCTION_END:
2868 pin->SetIsDangling( false );
2869 do_break = true;
2870 break;
2871
2872 default: break;
2873 }
2874
2875 if( do_break )
2876 break;
2877 }
2878
2879 changed = ( changed || ( previousState != pin->IsDangling() ) );
2880 }
2881
2882 return changed;
2883}
2884
2885
2887{
2888 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
2889 return VECTOR2I( 0, 0 );
2890
2891 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
2892}
2893
2894
2895bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
2896{
2897 // Do not compare to ourself.
2898 if( aItem == this )
2899 return false;
2900
2901 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
2902
2903 // Don't compare against a different SCH_ITEM.
2904 wxCHECK( symbol, false );
2905
2906 // The move algorithm marks any pins that are being moved without something attached
2907 // (during the move) as dangling. We always need to recheck connectivity in this case
2908 // or we will not notice changes when the user places the symbol back in the same position
2909 // it started.
2910 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2911 {
2912 if( pin->IsDangling() )
2913 return true;
2914 }
2915
2916 if( GetPosition() != symbol->GetPosition() )
2917 return true;
2918
2919 if( GetLibId() != symbol->GetLibId() )
2920 return true;
2921
2922 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
2923 return true;
2924
2925 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
2926 return true;
2927
2928 // Power symbol value field changes are connectivity changes.
2929 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
2930 return true;
2931
2932 if( m_pins.size() != symbol->m_pins.size() )
2933 return true;
2934
2935 for( size_t i = 0; i < m_pins.size(); i++ )
2936 {
2937 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
2938 return true;
2939 }
2940
2941 return false;
2942}
2943
2944
2945std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
2946{
2947 std::vector<VECTOR2I> retval;
2948
2949 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2950 {
2951 // Collect only pins attached to the current unit and convert.
2952 // others are not associated to this symbol instance
2953 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2954 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2955
2956 if( pin_unit > 0 && pin_unit != GetUnit() )
2957 continue;
2958
2959 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
2960 continue;
2961
2962 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
2963 }
2964
2965 return retval;
2966}
2967
2968
2970{
2971 if( m_part )
2972 {
2973 // Calculate the position relative to the symbol.
2974 VECTOR2I libPosition = aPosition - m_pos;
2975
2976 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
2977 }
2978
2979 return nullptr;
2980}
2981
2982
2983wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
2984{
2985 return wxString::Format( _( "Symbol %s [%s]" ),
2987 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
2988}
2989
2990
2991INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
2992{
2993 for( KICAD_T scanType : aScanTypes )
2994 {
2995 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
2996 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
2997 {
2998 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
2999 return INSPECT_RESULT::QUIT;
3000 }
3001
3002 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
3003 {
3004 for( SCH_FIELD& field : m_fields )
3005 {
3006 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
3007 return INSPECT_RESULT::QUIT;
3008 }
3009 }
3010
3011 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
3012 {
3013 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
3014 return INSPECT_RESULT::QUIT;
3015 }
3016
3017 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3018 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3019 {
3020 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3021 return INSPECT_RESULT::QUIT;
3022 }
3023
3024 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3025 {
3026 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3027 return INSPECT_RESULT::QUIT;
3028 }
3029
3030 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3031 {
3032 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3033 return INSPECT_RESULT::QUIT;
3034 }
3035
3036 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3037 {
3038 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3039 {
3040 // Collect only pins attached to the current unit and convert.
3041 // others are not associated to this symbol instance
3042 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3043 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3044
3045 if( pin_unit > 0 && pin_unit != GetUnit() )
3046 continue;
3047
3048 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3049 continue;
3050
3051 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3052 return INSPECT_RESULT::QUIT;
3053 }
3054 }
3055 }
3056
3058}
3059
3060
3061bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3062{
3063 if( Type() != aItem.Type() )
3064 return Type() < aItem.Type();
3065
3066 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3067
3069
3070 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3071 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3072
3073 if( m_pos.x != symbol->m_pos.x )
3074 return m_pos.x < symbol->m_pos.x;
3075
3076 if( m_pos.y != symbol->m_pos.y )
3077 return m_pos.y < symbol->m_pos.y;
3078
3079 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3080}
3081
3082
3083bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3084{
3085 std::vector<SCH_FIELD*> fields, otherFields;
3086
3087 GetFields( fields, false );
3088 aSymbol.GetFields( otherFields, false );
3089
3090 if( fields.size() != otherFields.size() )
3091 return false;
3092
3093 for( int ii = 0; ii < (int) fields.size(); ii++ )
3094 {
3095 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3096 continue;
3097
3098 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3099 return false;
3100 }
3101
3102 return true;
3103}
3104
3105
3106bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3107{
3108 return !( *this == aSymbol );
3109}
3110
3111
3113{
3114 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3115 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3116
3117 if( &aSymbol != this )
3118 {
3119 SYMBOL::operator=( aSymbol );
3120
3121 m_lib_id = aSymbol.m_lib_id;
3122 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3123 m_pos = aSymbol.m_pos;
3124 m_unit = aSymbol.m_unit;
3125 m_bodyStyle = aSymbol.m_bodyStyle;
3126 m_transform = aSymbol.m_transform;
3127
3128 m_instances = aSymbol.m_instances;
3129
3130 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3131
3132 // Reparent fields after assignment to new symbol.
3133 for( SCH_FIELD& field : m_fields )
3134 field.SetParent( this );
3135
3136 UpdatePins();
3137 }
3138
3139 return *this;
3140}
3141
3142
3143bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3144{
3145 BOX2I bBox = GetBodyBoundingBox();
3146 bBox.Inflate( aAccuracy / 2 );
3147
3148 if( bBox.Contains( aPosition ) )
3149 return true;
3150
3151 return false;
3152}
3153
3154
3155bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3156{
3158 return false;
3159
3160 BOX2I rect = aRect;
3161
3162 rect.Inflate( aAccuracy / 2 );
3163
3164 if( aContained )
3165 return rect.Contains( GetBodyBoundingBox() );
3166
3167 return rect.Intersects( GetBodyBoundingBox() );
3168}
3169
3170
3171bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3172{
3174 return false;
3175
3176 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3177}
3178
3179
3180bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3181{
3182 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3183
3184 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3185 {
3186 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3187 continue;
3188
3189 // Collect only pins attached to the current unit and convert.
3190 // others are not associated to this symbol instance
3191 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3192 continue;
3193
3194 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3195 continue;
3196
3197 if( pin->GetLocalPosition() == new_pos )
3198 return true;
3199 }
3200
3201 return false;
3202}
3203
3204
3206{
3207 return m_isInNetlist;
3208}
3209
3210
3211void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3212 const VECTOR2I& aOffset, bool aDimmed )
3213{
3214 if( aBackground )
3215 return;
3216
3217 if( m_part )
3218 {
3219 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3220
3221 // Copy the source so we can re-orient and translate it.
3222 LIB_SYMBOL tempSymbol( *m_part );
3223 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3224
3225 // Copy the pin info from the symbol to the temp pins
3226 for( unsigned i = 0; i < tempPins.size(); ++i )
3227 {
3228 SCH_PIN* symbolPin = GetPin( libPins[i] );
3229 SCH_PIN* tempPin = tempPins[i];
3230
3231 if( !symbolPin )
3232 continue;
3233
3234 tempPin->SetName( symbolPin->GetShownName() );
3235 tempPin->SetType( symbolPin->GetType() );
3236 tempPin->SetShape( symbolPin->GetShape() );
3237
3238 if( symbolPin->IsDangling() )
3239 tempPin->SetFlags( IS_DANGLING );
3240 }
3241
3242 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3243 {
3244 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3245 {
3246 // Use SCH_FIELD's text resolver
3247 SCH_FIELD dummy( this, FIELD_T::USER );
3248 dummy.SetText( text->GetText() );
3249 text->SetText( dummy.GetShownText( false ) );
3250 }
3251 }
3252
3253 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3254 TRANSFORM savedTransform = renderSettings->m_Transform;
3255 renderSettings->m_Transform = GetTransform();
3256 aPlotter->StartBlock( nullptr );
3257
3258 for( bool local_background : { true, false } )
3259 {
3260 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3261
3262 for( SCH_FIELD field : m_fields )
3263 {
3264 field.ClearRenderCache();
3265 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3266
3267 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3268 && ( field.IsVisible() || field.IsForceVisible() ) )
3269 {
3270 PlotLocalPowerIconShape( aPlotter );
3271 }
3272 }
3273 }
3274
3275 wxString variant = Schematic()->GetCurrentVariant();
3276 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
3277
3278 if( GetDNP( sheet, variant ) )
3279 PlotDNP( aPlotter );
3280
3281 // Plot attributes to a hypertext menu
3282 if( aPlotOpts.m_PDFPropertyPopups )
3283 {
3284 std::vector<wxString> properties;
3285
3286 for( const SCH_FIELD& field : GetFields() )
3287 {
3288 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3289
3290 if( text_field.IsEmpty() )
3291 continue;
3292
3293 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3294 }
3295
3296 if( !m_part->GetKeyWords().IsEmpty() )
3297 {
3298 properties.emplace_back(
3299 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ), m_part->GetKeyWords() ) );
3300 }
3301
3302 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3303 }
3304
3305 aPlotter->EndBlock( nullptr );
3306 renderSettings->m_Transform = savedTransform;
3307
3308 if( !m_part->IsPower() )
3309 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3310 }
3311}
3312
3313
3314void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3315{
3316 BOX2I bbox = GetBodyBoundingBox();
3318 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3319 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3320 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3321
3322 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3323 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3324 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3325
3326 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3327 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3328
3329 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3330
3331 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3332 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3333}
3334
3335
3339static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3340{
3341 double lineWidth = aSize / 10.0;
3342
3343 std::vector<SCH_SHAPE> shapeList;
3344 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3345 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3346
3347 for( const SCH_SHAPE& shape : shapeList )
3348 {
3349 // Currently there are only 2 shapes: BEZIER and CIRCLE
3350 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3351
3352 if( shape.GetShape() == SHAPE_T::BEZIER )
3353 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3354 tolerance, lineWidth );
3355 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3356 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3357 }
3358}
3359
3360
3362{
3363 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3364
3365 // Plot the local power pin indicator icon shape
3366 BOX2I bbox = field->GetBoundingBox();
3367
3368 // Calculate the text orientation according to the parent orientation.
3369 EDA_ANGLE orient = field->GetTextAngle();
3370
3371 if( GetTransform().y1 )
3372 {
3373 // Rotate symbol 90 degrees.
3374 if( orient.IsHorizontal() )
3375 orient = ANGLE_VERTICAL;
3376 else
3377 orient = ANGLE_HORIZONTAL;
3378 }
3379
3380 bool rotated = !orient.IsHorizontal();
3381
3382 VECTOR2D pos;
3383 double size = bbox.GetHeight() / 1.5;
3384
3385 if( rotated )
3386 {
3387 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3388 size = bbox.GetWidth() / 1.5;
3389 }
3390 else
3391 {
3392 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3393 }
3394
3395 // TODO: build and plot icon shape
3396 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3397}
3398
3399
3400void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter ) const
3401{
3402 if( m_part )
3403 {
3404 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3405 TRANSFORM savedTransform = renderSettings->m_Transform;
3406 renderSettings->m_Transform = GetTransform();
3407
3408 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3409
3410 // Copy the source to stay const
3411 LIB_SYMBOL tempSymbol( *m_part );
3412 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3413 SCH_PLOT_OPTS plotOpts;
3414
3415 // Copy the pin info from the symbol to the temp pins
3416 for( unsigned i = 0; i < tempPins.size(); ++i )
3417 {
3418 SCH_PIN* symbolPin = GetPin( libPins[i] );
3419 SCH_PIN* tempPin = tempPins[i];
3420
3421 if( !symbolPin )
3422 continue;
3423
3424 tempPin->SetName( symbolPin->GetShownName() );
3425 tempPin->SetType( symbolPin->GetType() );
3426 tempPin->SetShape( symbolPin->GetShape() );
3427 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
3428 }
3429
3430 renderSettings->m_Transform = savedTransform;
3431 }
3432}
3433
3434
3436{
3437 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3438 {
3439 if( pin->IsBrightened() )
3440 return true;
3441 }
3442
3443 return false;
3444}
3445
3446
3448{
3449 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3450 pin->ClearBrightened();
3451}
3452
3453
3454/*
3455 * When modified at the schematic level, we still store the values of these flags in the
3456 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
3457 * will be created and stored locally in the schematic.
3458 */
3460{
3461 return m_part && m_part->GetShowPinNames();
3462}
3463
3464
3466{
3467 if( m_part )
3468 m_part->SetShowPinNames( aShow );
3469}
3470
3471
3473{
3474 return m_part && m_part->GetShowPinNumbers();
3475}
3476
3477
3479{
3480 if( m_part )
3481 m_part->SetShowPinNumbers( aShow );
3482}
3483
3484
3486{
3487 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3488 {
3489 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3490 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3491
3492 if( pin_unit > 0 && pin_unit != GetUnit() )
3493 continue;
3494
3495 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3496 continue;
3497
3498 if( pin->IsPointClickableAnchor( aPos ) )
3499 return true;
3500 }
3501
3502 return false;
3503}
3504
3505
3507{
3508 // return true if the symbol is equivalent to a global label:
3509 // It is a Power symbol
3510 // It has only one pin type Power input
3511
3513 return false;
3514
3515 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3516
3517 if( pin_list.size() != 1 )
3518 return false;
3519
3520 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3521}
3522
3523
3525{
3526 // return true if the symbol is equivalent to a local label:
3527 // It is a Power symbol
3528 // It has only one pin type Power input
3529
3531 return false;
3532
3533 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3534
3535 if( pin_list.size() != 1 )
3536 return false;
3537
3538 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3539}
3540
3541
3543{
3544 if( !m_part )
3545 return false;
3546
3547 return m_part->IsLocalPower();
3548}
3549
3550
3552{
3553 if( !m_part )
3554 return false;
3555
3556 return m_part->IsGlobalPower();
3557}
3558
3559
3561{
3562 return IsLocalPower() || IsGlobalPower();
3563}
3564
3565
3567{
3568 wxCHECK( m_part, false );
3569
3570 return m_part->IsNormal();
3571}
3572
3573
3574std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
3575{
3576 std::unordered_set<wxString> componentClass;
3577
3578 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
3579 {
3580 for( const SCH_FIELD& field : fields )
3581 {
3582 if( field.GetCanonicalName() == wxT( "Component Class" ) )
3583 {
3584 if( field.GetShownText( aPath, false ) != wxEmptyString )
3585 componentClass.insert( field.GetShownText( aPath, false ) );
3586 }
3587 }
3588 };
3589
3590 // First get component classes set on the symbol itself
3591 getComponentClassFields( m_fields );
3592
3593 // Now get component classes set on any enclosing rule areas
3594 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
3595 {
3596 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
3597 {
3598 getComponentClassFields( label->GetFields() );
3599 }
3600 }
3601
3602 return componentClass;
3603}
3604
3605
3606std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
3607 const wxString& aVariantName ) const
3608{
3609 SCH_SYMBOL_INSTANCE instance;
3610
3611 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
3612 return std::nullopt;
3613
3614 return instance.m_Variants.find( aVariantName )->second;
3615}
3616
3617
3618void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
3619{
3620 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
3621
3622 // The instance path must already exist.
3623 if( !instance )
3624 return;
3625
3626 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
3627}
3628
3629
3630void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
3631{
3632 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3633
3634 // The instance path must already exist.
3635 if( !instance || !instance->m_Variants.contains( aVariantName ) )
3636 return;
3637
3638 instance->m_Variants.erase( aVariantName );
3639}
3640
3641
3642void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
3643 const wxString& aNewName )
3644{
3645 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3646
3647 // The instance path must already exist and contain the old variant.
3648 if( !instance || !instance->m_Variants.contains( aOldName ) )
3649 return;
3650
3651 // Get the variant data, update the name, and re-insert with new key
3652 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
3653 variant.m_Name = aNewName;
3654 instance->m_Variants.erase( aOldName );
3655 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
3656}
3657
3658
3659void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
3660 const wxString& aNewVariant )
3661{
3662 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3663
3664 // The instance path must already exist and contain the source variant.
3665 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
3666 return;
3667
3668 // Copy the variant data with a new name
3669 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
3670 variant.m_Name = aNewVariant;
3671 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
3672}
3673
3674
3675bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
3676{
3677 if( Type() != aOther.Type() )
3678 return false;
3679
3680 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3681
3682 if( GetLibId() != symbol.GetLibId() )
3683 return false;
3684
3685 if( GetPosition() != symbol.GetPosition() )
3686 return false;
3687
3688 if( GetUnit() != symbol.GetUnit() )
3689 return false;
3690
3691 if( GetBodyStyle() != symbol.GetBodyStyle() )
3692 return false;
3693
3694 if( GetTransform() != symbol.GetTransform() )
3695 return false;
3696
3697 if( GetFields() != symbol.GetFields() )
3698 return false;
3699
3700 if( m_pins.size() != symbol.m_pins.size() )
3701 return false;
3702
3703 for( unsigned i = 0; i < m_pins.size(); ++i )
3704 {
3705 if( *m_pins[i] != *symbol.m_pins[i] )
3706 return false;
3707 }
3708
3709 return true;
3710}
3711
3712
3713double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3714{
3715 if( Type() != aOther.Type() )
3716 return 0.0;
3717
3718 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3719
3720 if( GetLibId() != symbol.GetLibId() )
3721 return 0.0;
3722
3723 if( GetPosition() == symbol.GetPosition() )
3724 return 1.0;
3725
3726 return 0.0;
3727}
3728
3729
3730void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
3731 double aLineWidth, bool aHorizontal )
3732{
3733 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
3734
3735 double x_right = aSize / 1.6180339887;
3736 double x_middle = x_right / 2.0;
3737
3738 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
3739 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
3740 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
3741
3742 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
3743 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
3744 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
3745 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
3746 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
3747
3748 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3749 aShapeList.back().SetStart( bottomPt );
3750 aShapeList.back().SetBezierC1( bottomAnchorPt );
3751 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
3752 aShapeList.back().SetEnd( leftPt );
3753
3754
3755 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3756 aShapeList.back().SetStart( leftPt );
3757 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
3758 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
3759 aShapeList.back().SetEnd( rightPt );
3760
3761 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3762 aShapeList.back().SetStart( rightPt );
3763 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
3764 aShapeList.back().SetBezierC2( bottomAnchorPt );
3765 aShapeList.back().SetEnd( bottomPt );
3766
3767 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
3768 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
3769 aShapeList.back().SetRadius( aSize / 15.0 );
3770
3771 for( SCH_SHAPE& shape : aShapeList )
3772 {
3773 if( aHorizontal )
3774 shape.Rotate( VECTOR2I( 0, 0 ), true );
3775
3776 shape.Move( aPos );
3777 }
3778}
3779
3780
3782{
3783 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3784 {
3785 if( instance.m_Path == aSheetPath )
3786 return &instance;
3787 }
3788
3789 return nullptr;
3790}
3791
3792
3794{
3795 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
3796 {
3797 if( instance.m_Path == aSheetPath )
3798 return &instance;
3799 }
3800
3801 return nullptr;
3802}
3803
3804
3805static struct SCH_SYMBOL_DESC
3806{
3808 {
3810 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
3811 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
3812 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
3813 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
3814
3818
3825
3832
3833 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
3834 {
3835 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3836 return symbol->GetLibSymbolRef() != nullptr;
3837
3838 return false;
3839 };
3840
3841 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
3843 .SetAvailableFunc( hasLibPart );
3844
3845 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
3847 .SetAvailableFunc( hasLibPart );
3848
3849 const wxString groupFields = _HKI( "Fields" );
3850
3853 groupFields );
3856 groupFields );
3857 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
3858 NO_SETTER( SCH_SYMBOL, wxString ),
3860 groupFields );
3861 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
3862 NO_SETTER( SCH_SYMBOL, wxString ),
3864 groupFields );
3865 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
3867 groupFields );
3868
3869 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
3870 {
3871 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3872 return symbol->IsMultiUnit();
3873
3874 return false;
3875 };
3876
3877 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
3878 {
3879 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3880 return symbol->IsMultiBodyStyle();
3881
3882 return false;
3883 };
3884
3887 .SetAvailableFunc( multiUnit )
3889 []( INSPECTABLE* aItem )
3890 {
3891 wxPGChoices choices;
3892
3893 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3894 {
3895 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
3896 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
3897 }
3898
3899 return choices;
3900 } );
3901
3904 .SetAvailableFunc( multiBodyStyle )
3906 []( INSPECTABLE* aItem )
3907 {
3908 wxPGChoices choices;
3909
3910 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3911 {
3912 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3913 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3914 }
3915
3916 return choices;
3917 } );
3918
3919 const wxString groupAttributes = _HKI( "Attributes" );
3920
3921 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
3924 groupAttributes );
3925 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
3928 groupAttributes );
3929 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
3932 groupAttributes );
3933 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
3936 groupAttributes );
3937 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
3940 groupAttributes );
3941 }
3943
3944
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
BITMAPS
A list of all bitmap identifiers.
@ add_component
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:558
constexpr const Vec GetEnd() const
Definition box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr coord_type GetY() const
Definition box2.h:208
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr coord_type GetX() const
Definition box2.h:207
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:761
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr const Vec & GetOrigin() const
Definition box2.h:210
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:259
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
constexpr coord_type GetBottom() const
Definition box2.h:222
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
static std::vector< DANGLING_END_ITEM >::iterator get_lower_pos(std::vector< DANGLING_END_ITEM > &aItemListByPos, const VECTOR2I &aPos)
Definition sch_item.cpp:932
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition sch_item.h:96
DANGLING_END_T GetType() const
Definition sch_item.h:132
const EDA_ITEM * GetParent() const
Definition sch_item.h:131
bool IsHorizontal() const
Definition eda_angle.h:142
The base class for create windows for drawing purpose.
EDA_ITEM_FLAGS GetEditFlags() const
Definition eda_item.h:154
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:148
const KIID m_Uuid
Definition eda_item.h:522
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:533
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:407
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:115
bool IsSelected() const
Definition eda_item.h:127
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.h:113
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:534
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:39
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:80
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:585
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:603
static ENUM_MAP< T > & Instance()
Definition property.h:721
A text control validator used for validating the text allowed in fields.
Definition validators.h:142
bool DoValidate(const wxString &aValue, wxWindow *aParent)
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:37
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxString AsString() const
Definition kiid.cpp:357
Definition kiid.h:49
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
UTF8 Format() const
Definition lib_id.cpp:119
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:203
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
static wxString LetterSubReference(int aUnit, wxChar aInitialLetter)
static LIB_SYMBOL * GetDummy()
Returns a dummy LIB_SYMBOL, used when one is missing in the schematic.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:699
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
const BOX2I GetBodyBoundingBox(int aUnit, int aBodyStyle, bool aIncludePins, bool aIncludePrivateItems) const
Get the symbol bounding box excluding fields.
EMBEDDED_FILES * GetEmbeddedFiles() override
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
Definition netclass.cpp:328
A singleton reporter that reports to nowhere.
Definition reporter.h:216
Base plotter engine class.
Definition plotter.h:136
virtual void Circle(const VECTOR2I &pos, int diametre, FILL_T fill, int width)=0
virtual void Bookmark(const BOX2I &aBox, const wxString &aName, const wxString &aGroupName=wxEmptyString)
Create a bookmark to a symbol.
Definition plotter.h:528
virtual void BezierCurve(const VECTOR2I &aStart, const VECTOR2I &aControl1, const VECTOR2I &aControl2, const VECTOR2I &aEnd, int aTolerance, int aLineThickness)
Generic fallback: Cubic Bezier curve rendered as a polyline.
Definition plotter.cpp:232
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition plotter.h:590
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:540
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:517
virtual void SetColor(const COLOR4D &color)=0
virtual void EndBlock(void *aData)
calling this function allows one to define the end of a group of drawing items for instance in SVG or...
Definition plotter.h:599
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:276
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:262
const wxString & Name() const
Definition property.h:220
Provide class metadata.Helper macro to map type hashes to names.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
Holds all the data relating to one schematic.
Definition schematic.h:88
wxString GetOperatingPoint(const wxString &aNetName, int aPrecision, const wxString &aRange)
SCHEMATIC_SETTINGS & Settings() const
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:103
wxString GetCurrentVariant() const
Return the current variant being edited.
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:187
bool ResolveCrossReference(wxString *token, int aDepth) const
Resolves text vars that refer to other items.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
wxString LocalName() const
wxString Name(bool aIgnoreSheet=false) const
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH & GetCurrentSheet() const
bool IsMandatory() const
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:118
FIELD_T GetId() const
Definition sch_field.h:122
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0, const wxString &aVariantName=wxEmptyString) const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetText(const wxString &aText) override
int m_unit
Definition sch_item.h:773
int m_bodyStyle
Definition sch_item.h:774
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:721
void SetPrivate(bool aPrivate)
Definition sch_item.h:252
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:247
int GetBodyStyle() const
Definition sch_item.h:247
friend class LIB_SYMBOL
Definition sch_item.h:792
int GetUnit() const
Definition sch_item.h:238
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition sch_item.cpp:502
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:776
std::unordered_set< SCH_RULE_AREA * > m_rule_areas_cache
Store pointers to rule areas which this item is contained within.
Definition sch_item.h:789
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:54
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition sch_item.cpp:466
SCH_LAYER_ID m_layer
Definition sch_item.h:772
void SetAlt(const wxString &aAlt)
Set the name of the alternate pin.
Definition sch_pin.cpp:423
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:1340
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:256
wxString GetShownName() const
Definition sch_pin.cpp: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
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
bool GetExcludedFromSim() const
bool GetExcludedFromBoard() const
bool GetDNP() const
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
size_t size() const
Forwarded method from std::vector.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the sheet.
Variant information for a schematic symbol.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:76
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the display name for a given unit aUnit.
SCH_SYMBOL & operator=(const SCH_SYMBOL &aItem)
int GetUnitProp() const
Definition sch_symbol.h:518
size_t GetFullPinCount() const
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.
Definition sch_symbol.h:990
wxString GetDescription() const override
std::unordered_map< SCH_PIN *, SCH_PIN * > m_pinMap
Library pin pointer : SCH_PIN indices.
void SetMirrorX(bool aMirror)
Definition sch_symbol.h:322
bool IsSymbolLikePowerGlobalLabel() const
VECTOR2I m_pos
Definition sch_symbol.h:988
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SYMBOLs don't currently support embedded files, but their LIB_SYMBOL counterparts do.
wxString GetSymbolIDAsString() const
Definition sch_symbol.h:167
LIB_ID m_lib_id
Name and library the symbol was loaded from, i.e. 74xx:74LS00.
Definition sch_symbol.h:989
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
bool GetShowPinNumbers() const override
wxString GetDatasheet() const
Return the documentation text for the given part alias.
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
void SetLibId(const LIB_ID &aName)
bool HasBrightenedPins()
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the symbol's fields.
Definition sch_symbol.h:452
BOX2I GetBodyAndPinsBoundingBox() const override
Return a bounding box for the symbol body and pins but not the fields.
wxString GetBodyStyleProp() const override
Definition sch_symbol.h:535
void SetRefProp(const wxString &aRef)
INSPECT_RESULT Visit(INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
virtual void SetDNP(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
SCH_ITEM * GetDrawItem(const VECTOR2I &aPosition, KICAD_T aType=TYPE_NOT_INIT)
Return the symbol library item at aPosition that is part of this symbol.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
void PlotDNP(PLOTTER *aPlotter) const
Plot the red 'X' over the symbol.
bool operator!=(const SCH_SYMBOL &aSymbol) const
void SetShowPinNumbers(bool aShow) override
Set or clear the pin number visibility flag.
SYMBOL_ORIENTATION_PROP GetOrientationProp() const
Definition sch_symbol.h:305
int GetY() const
Definition sch_symbol.h:860
SCH_SYMBOL_INSTANCE * getInstance(const KIID_PATH &aPath)
wxString SubReference(int aUnit, bool aAddSeparator=true) const
wxString GetClass() const override
Return the class name.
Definition sch_symbol.h:115
void RemoveInstance(const SCH_SHEET_PATH &aInstancePath)
void SetFieldText(const wxString &aFieldName, const wxString &aFieldText, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString)
bool IsAnnotated(const SCH_SHEET_PATH *aSheet) const
Check if the symbol has a valid annotation (reference) for the given sheet path.
void SetMirrorY(bool aMirror)
Definition sch_symbol.h:339
void PlotPins(PLOTTER *aPlotter) const
Plot just the symbol pins.
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:540
int GetX() const
Definition sch_symbol.h:857
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:754
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
wxString GetFieldText(const wxString &aFieldName, const SCH_SHEET_PATH *aPath=nullptr, const wxString &aVariantName=wxEmptyString) const
void SetExcludedFromSim(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
void SetExcludedFromSimProp(bool aEnable)
Definition sch_symbol.h:729
void SetBodyStyle(int aBodyStyle) override
void SetShowPinNames(bool aShow) override
Set or clear the pin name visibility flag.
wxString GetKeyWords() const override
wxString GetSchSymbolLibraryName() const
wxString GetShownKeyWords(int aDepth=0) const override
bool IsInNetlist() const
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
bool GetExcludedFromBoardProp() const
Definition sch_symbol.h:739
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:861
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
bool HasConnectivityChanges(const SCH_ITEM *aItem, const SCH_SHEET_PATH *aInstance=nullptr) const override
Check if aItem has connectivity changes against this object.
bool GetExcludedFromSimProp() const
Definition sch_symbol.h:724
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool IsGlobalPower() const override
bool GetMirrorX() const
Definition sch_symbol.h:334
wxString GetRefProp() const
Definition sch_symbol.h:504
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_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:714
static std::unordered_map< TRANSFORM, int > s_transformToOrientationCache
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
void SyncOtherUnits(const SCH_SHEET_PATH &aSourceSheet, SCH_COMMIT &aCommit, PROPERTY_BASE *aProperty)
Keep fields other than the reference, include/exclude flags, and alternate pin assignments in sync in...
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
Search for a SCH_FIELD with aFieldName.
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
bool IsPointClickableAnchor(const VECTOR2I &aPos) const override
void UpdateFields(const SCH_SHEET_PATH *aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields)
Restore fields to the original library values.
wxString m_schLibSymbolName
The name used to look up a symbol in the symbol library embedded in a schematic.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
const wxString GetValue(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText, const wxString &aVariantName=wxEmptyString) const override
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
void RenameVariant(const KIID_PATH &aPath, const wxString &aOldName, const wxString &aNewName)
void SetOrientationProp(SYMBOL_ORIENTATION_PROP aAngle)
Orientation/mirroring access for property manager.
Definition sch_symbol.h:296
bool GetShowPinNames() const override
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
const wxString GetFootprintFieldText(bool aResolve, const SCH_SHEET_PATH *aPath, bool aAllowExtraText) const
bool HasDeMorganBodyStyles() const override
std::vector< SCH_FIELD > m_fields
Variable length list of fields.
std::vector< SCH_PIN * > GetAllLibPins() const
int GetBodyStyleCount() const override
Return the number of body styles of the symbol.
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
bool GetDNPProp() const
Definition sch_symbol.h:699
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
void SetFootprintFieldText(const wxString &aFootprint)
bool doIsConnected(const VECTOR2I &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
bool IsMissingLibSymbol() const
Check to see if the library symbol is set to the dummy library symbol.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:854
std::unique_ptr< LIB_SYMBOL > m_part
A flattened copy of the LIB_SYMBOL from the PROJECT object's libraries.
int GetNextFieldOrdinal() const
Return the next ordinal for a user field for this symbol.
void SetExcludedFromPosFiles(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
void Init(const VECTOR2I &pos=VECTOR2I(0, 0))
void SetExcludedFromPosFilesProp(bool aEnable)
Definition sch_symbol.h:759
wxString GetShownDescription(int aDepth=0) const override
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
bool operator<(const SCH_ITEM &aItem) const override
static void BuildLocalPowerIconShape(std::vector< SCH_SHAPE > &aShapeList, const VECTOR2D &aPos, double aSize, double aLineWidth, bool aHorizontal)
Build the local power pin indicator icon shape, at coordinate aPos.
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
void SetValueProp(const wxString &aValue)
void SetUnitProp(int aUnit)
Definition sch_symbol.h:529
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
std::vector< SCH_PIN * > GetLibPins() const
Populate a vector with all the pins from the library object that match the current unit and bodyStyle...
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, const SCH_SHEET_PATH *aPath=nullptr) override
Test if the symbol's dangling state has changed for all pins.
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetInstance(SCH_SYMBOL_INSTANCE &aInstance, const KIID_PATH &aSheetPath, bool aTestFromEnd=false) const
void AddVariant(const SCH_SHEET_PATH &aInstance, const SCH_SYMBOL_VARIANT &aVariant)
BOX2I doGetBoundingBox(bool aIncludePins, bool aIncludeFields) const
bool GetMirrorY() const
Definition sch_symbol.h:351
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetDNPProp(bool aEnable)
Definition sch_symbol.h:701
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
void SetX(int aX)
Definition sch_symbol.h:858
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
bool m_isInNetlist
True if the symbol should appear in netlist.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
wxString GetValueProp() const
Definition sch_symbol.h:511
bool IsLocalPower() const override
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
int GetUnitCount() const override
Return the number of units per package of the symbol.
void SetPrefix(const wxString &aPrefix)
Definition sch_symbol.h:239
int GetOrientation() const override
Get the display symbol orientation.
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
bool IsSymbolLikePowerLocalLabel() const
bool GetExcludedFromBOMProp() const
Definition sch_symbol.h:709
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
void SetExcludedFromBoardProp(bool aEnable)
Definition sch_symbol.h:744
void SetExcludedFromBOM(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
void PlotLocalPowerIconShape(PLOTTER *aPlotter) const
Plot the local power pin indicator icon shape.
bool IsNormal() const override
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
std::unordered_set< wxString > GetComponentClassNames(const SCH_SHEET_PATH *aPath) const
Return the component classes this symbol belongs in.
std::vector< std::unique_ptr< SCH_PIN > > m_pins
A SCH_PIN for every #LIB_PIN.
void DeleteVariant(const KIID_PATH &aPath, const wxString &aVariantName)
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
VECTOR2I GetPinPhysicalPosition(const SCH_PIN *Pin) const
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
bool IsMovableFromAnchorPoint() const override
Return true for items which are moved with the anchor point at mouse cursor and false for items moved...
bool IsPower() const override
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void CopyVariant(const KIID_PATH &aPath, const wxString &aSourceVariant, const wxString &aNewVariant)
bool operator==(const SCH_SYMBOL &aSymbol) const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
SIM_MODEL & CreateModel(SIM_MODEL::TYPE aType, const std::vector< SCH_PIN * > &aPins, REPORTER &aReporter)
void SetFilesStack(std::vector< EMBEDDED_FILES * > aFilesStack)
Definition sim_lib_mgr.h:48
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
bool m_DNP
True if symbol is set to 'Do Not Populate'.
Definition symbol.h:278
bool m_excludedFromPosFiles
Definition symbol.h:277
SYMBOL(KICAD_T idType)
Definition symbol.h:65
bool m_excludedFromSim
Definition symbol.h:274
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:174
const TRANSFORM & GetTransform() const
Definition symbol.h:247
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:168
bool m_excludedFromBOM
Definition symbol.h:275
bool m_excludedFromBoard
Definition symbol.h:276
virtual bool GetShowPinNames() const
Definition symbol.h:169
SYMBOL & operator=(const SYMBOL &aItem)
Definition symbol.h:93
virtual bool GetShowPinNumbers() const
Definition symbol.h:175
TRANSFORM m_transform
The rotation/mirror transformation.
Definition symbol.h:267
const std::vector< TEMPLATE_FIELDNAME > & GetTemplateFieldNames()
Return a template field name list for read only access.
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:46
wxString wx_str() const
Definition utf8.cpp:45
wxString m_Name
bool m_ExcludedFromBOM
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
T Convert(const wxString &aValue)
Convert a wxString to a generic type T.
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
RECURSE_MODE
Definition eda_item.h:50
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define STRUCT_DELETED
flag indication structures to be erased
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define IS_DANGLING
indicates a pin is dangling
FILL_T
Definition eda_shape.h:56
@ NO_FILL
Definition eda_shape.h:57
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
a few functions useful in geometry calculations.
const wxChar *const traceSchSymbolRef
Flag to enable debug output of schematic symbol reference resolution.
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:449
@ LAYER_DEVICE
Definition layer_ids.h:466
@ LAYER_VALUEPART
Definition layer_ids.h:461
@ LAYER_FIELDS
Definition layer_ids.h:462
@ LAYER_REFERENCEPART
Definition layer_ids.h:460
@ LAYER_DNP_MARKER
Definition layer_ids.h:478
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:45
Message panel definition file.
bool BoxHitTest(const VECTOR2I &aHitPoint, const BOX2I &aHittee, int aAccuracy)
Perform a point-to-box hit test.
KICOMMON_API wxString EllipsizeMenuText(const wxString &aString)
Ellipsize text (at the end) to be no more than 36 characters.
KICOMMON_API wxString EllipsizeStatusText(wxWindow *aWindow, const wxString &aString)
Ellipsize text (at the end) to be no more than 1/3 of the window width.
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
wxString GetRefDesUnannotated(const wxString &aSource)
Return an unannotated refdes from either a prefix or an existing refdes.
#define _HKI(x)
Definition page_info.cpp:44
see class PGM_BASE
@ PT_NC
not connected (must be left open)
Definition pin_type.h:50
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:46
#define TYPE_HASH(x)
Definition property.h:74
#define NO_SETTER(owner, type)
Definition property.h:828
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:823
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
#define REGISTER_TYPE(x)
Collection of utility functions for component reference designators (refdes)
void CollectOtherUnits(const wxString &aRef, int aUnit, const LIB_ID &aLibId, SCH_SHEET_PATH &aSheet, std::vector< SCH_SYMBOL * > *otherUnits)
const SCH_FIELD * FindField(const std::vector< SCH_FIELD > &aFields, FIELD_T aFieldId)
Definition sch_field.h:369
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:358
@ NO_CONNECT_END
Definition sch_item.h:87
@ SHEET_LABEL_END
Definition sch_item.h:86
@ LABEL_END
Definition sch_item.h:83
@ JUNCTION_END
Definition sch_item.h:81
@ PIN_END
Definition sch_item.h:82
@ WIRE_END
Definition sch_item.h:79
@ BASE
Definition sch_item.h:59
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
static void plotLocalPowerIcon(PLOTTER *aPlotter, const VECTOR2D &aPos, double aSize, bool aRotate)
plot a local power pin indicator icon.
static struct SCH_SYMBOL_DESC _SCH_SYMBOL_DESC
std::vector< FAB_LAYER_COLOR > dummy
wxString UnescapeString(const wxString &aSource)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::vector< std::pair< FIELD_T, wxString > > Fields
Definition sch_screen.h:88
bool m_PDFPropertyPopups
Definition sch_plotter.h:64
A simple container for schematic symbol instance information.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
std::string refName
Hold a name of a symbol's field, field value, and default visibility.
SYMBOL_ORIENTATION_PROP
Definition symbol.h:51
@ SYMBOL_ANGLE_180
Definition symbol.h:54
@ SYMBOL_ANGLE_0
Definition symbol.h:52
@ SYMBOL_ANGLE_90
Definition symbol.h:53
@ SYMBOL_ANGLE_270
Definition symbol.h:55
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_ROTATE_CLOCKWISE
Definition symbol.h:37
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition symbol.h:38
@ SYM_MIRROR_Y
Definition symbol.h:44
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_NORMAL
Definition symbol.h:36
@ SYM_ORIENT_90
Definition symbol.h:40
@ SYM_ORIENT_0
Definition symbol.h:39
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
std::string path
KIBIS_MODEL * model
KIBIS_PIN * pin
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:229
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:78
@ SCH_FIELD_LOCATE_REFERENCE_T
Definition typeinfo.h:184
@ SCH_FIELD_LOCATE_FOOTPRINT_T
Definition typeinfo.h:186
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_FIELD_T
Definition typeinfo.h:154
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:203
@ SCH_FIELD_LOCATE_VALUE_T
Definition typeinfo.h:185
@ SCH_FIELD_LOCATE_DATASHEET_T
Definition typeinfo.h:187
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:200
@ SCH_PIN_T
Definition typeinfo.h:157
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694