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