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 // Search instance fields rather than lib template fields so that modified values
2826 // (e.g. a "+5VA" symbol derived from "+5V") are matched correctly. Skip the
2827 // Reference field to avoid infinite recursion: SCH_FIELD::Matches() for REFERENCE
2828 // calls back into SCH_SYMBOL::Matches().
2829 for( const SCH_FIELD& field : m_fields )
2830 {
2831 if( field.GetId() == FIELD_T::REFERENCE )
2832 continue;
2833
2834 if( field.Matches( aSearchData, aAuxData ) )
2835 return true;
2836 }
2837
2838 // Search non-field lib draw items (pins, graphical text) for completeness.
2839 for( const SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
2840 {
2841 if( drawItem.Type() == SCH_FIELD_T )
2842 continue;
2843
2844 if( drawItem.Matches( aSearchData, aAuxData ) )
2845 return true;
2846 }
2847
2848 // Symbols are searchable via the child field and pin item text.
2849 return false;
2850}
2851
2852
2853void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
2854{
2855 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2856 {
2857 SCH_PIN* lib_pin = pin->GetLibPin();
2858
2859 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
2860 continue;
2861
2862 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
2863 aItemList.push_back( item );
2864 }
2865}
2866
2867
2868bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
2869 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
2870{
2871 bool changed = false;
2872
2873 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2874 {
2875 bool previousState = pin->IsDangling();
2876 pin->SetIsDangling( true );
2877
2878 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
2879
2880 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
2881 bool do_break = false;
2882
2883 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
2884 {
2885 DANGLING_END_ITEM& each_item = *it;
2886
2887 // Some people like to stack pins on top of each other in a symbol to indicate
2888 // internal connection. While technically connected, it is not particularly useful
2889 // to display them that way, so skip any pins that are in the same symbol as this
2890 // one.
2891 if( each_item.GetParent() == this )
2892 continue;
2893
2894 switch( each_item.GetType() )
2895 {
2896 case PIN_END:
2897 case LABEL_END:
2898 case SHEET_LABEL_END:
2899 case WIRE_END:
2900 case NO_CONNECT_END:
2901 case JUNCTION_END:
2902 pin->SetIsDangling( false );
2903 do_break = true;
2904 break;
2905
2906 default: break;
2907 }
2908
2909 if( do_break )
2910 break;
2911 }
2912
2913 changed = ( changed || ( previousState != pin->IsDangling() ) );
2914 }
2915
2916 return changed;
2917}
2918
2919
2921{
2922 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
2923 return VECTOR2I( 0, 0 );
2924
2925 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
2926}
2927
2928
2929bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
2930{
2931 // Do not compare to ourself.
2932 if( aItem == this )
2933 return false;
2934
2935 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
2936
2937 // Don't compare against a different SCH_ITEM.
2938 wxCHECK( symbol, false );
2939
2940 // The move algorithm marks any pins that are being moved without something attached
2941 // (during the move) as dangling. We always need to recheck connectivity in this case
2942 // or we will not notice changes when the user places the symbol back in the same position
2943 // it started.
2944 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2945 {
2946 if( pin->IsDangling() )
2947 return true;
2948 }
2949
2950 if( GetPosition() != symbol->GetPosition() )
2951 return true;
2952
2953 if( GetLibId() != symbol->GetLibId() )
2954 return true;
2955
2956 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
2957 return true;
2958
2959 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
2960 return true;
2961
2962 // Power symbol value field changes are connectivity changes.
2963 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
2964 return true;
2965
2966 if( m_pins.size() != symbol->m_pins.size() )
2967 return true;
2968
2969 for( size_t i = 0; i < m_pins.size(); i++ )
2970 {
2971 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
2972 return true;
2973 }
2974
2975 return false;
2976}
2977
2978
2979std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
2980{
2981 std::vector<VECTOR2I> retval;
2982
2983 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2984 {
2985 // Collect only pins attached to the current unit and convert.
2986 // others are not associated to this symbol instance
2987 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2988 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2989
2990 if( pin_unit > 0 && pin_unit != GetUnit() )
2991 continue;
2992
2993 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
2994 continue;
2995
2996 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
2997 }
2998
2999 return retval;
3000}
3001
3002
3004{
3005 if( m_part )
3006 {
3007 // Calculate the position relative to the symbol.
3008 VECTOR2I libPosition = aPosition - m_pos;
3009
3010 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
3011 }
3012
3013 return nullptr;
3014}
3015
3016
3017wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
3018{
3019 return wxString::Format( _( "Symbol %s [%s]" ),
3021 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
3022}
3023
3024
3025INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
3026{
3027 for( KICAD_T scanType : aScanTypes )
3028 {
3029 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
3030 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3031 {
3032 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
3033 return INSPECT_RESULT::QUIT;
3034 }
3035
3036 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
3037 {
3038 for( SCH_FIELD& field : m_fields )
3039 {
3040 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
3041 return INSPECT_RESULT::QUIT;
3042 }
3043 }
3044
3045 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
3046 {
3047 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
3048 return INSPECT_RESULT::QUIT;
3049 }
3050
3051 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3052 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3053 {
3054 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3055 return INSPECT_RESULT::QUIT;
3056 }
3057
3058 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3059 {
3060 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3061 return INSPECT_RESULT::QUIT;
3062 }
3063
3064 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3065 {
3066 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3067 return INSPECT_RESULT::QUIT;
3068 }
3069
3070 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3071 {
3072 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3073 {
3074 // Collect only pins attached to the current unit and convert.
3075 // others are not associated to this symbol instance
3076 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3077 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3078
3079 if( pin_unit > 0 && pin_unit != GetUnit() )
3080 continue;
3081
3082 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3083 continue;
3084
3085 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3086 return INSPECT_RESULT::QUIT;
3087 }
3088 }
3089 }
3090
3092}
3093
3094
3095bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3096{
3097 if( Type() != aItem.Type() )
3098 return Type() < aItem.Type();
3099
3100 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3101
3103
3104 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3105 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3106
3107 if( m_pos.x != symbol->m_pos.x )
3108 return m_pos.x < symbol->m_pos.x;
3109
3110 if( m_pos.y != symbol->m_pos.y )
3111 return m_pos.y < symbol->m_pos.y;
3112
3113 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3114}
3115
3116
3117bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3118{
3119 std::vector<SCH_FIELD*> fields, otherFields;
3120
3121 GetFields( fields, false );
3122 aSymbol.GetFields( otherFields, false );
3123
3124 if( fields.size() != otherFields.size() )
3125 return false;
3126
3127 for( int ii = 0; ii < (int) fields.size(); ii++ )
3128 {
3129 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3130 continue;
3131
3132 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3133 return false;
3134 }
3135
3136 return true;
3137}
3138
3139
3140bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3141{
3142 return !( *this == aSymbol );
3143}
3144
3145
3147{
3148 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3149 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3150
3151 if( &aSymbol != this )
3152 {
3153 SYMBOL::operator=( aSymbol );
3154
3155 m_lib_id = aSymbol.m_lib_id;
3156 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3157 m_pos = aSymbol.m_pos;
3158 m_unit = aSymbol.m_unit;
3159 m_bodyStyle = aSymbol.m_bodyStyle;
3160 m_transform = aSymbol.m_transform;
3161
3162 m_instances = aSymbol.m_instances;
3163
3164 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3165
3166 // Reparent fields after assignment to new symbol.
3167 for( SCH_FIELD& field : m_fields )
3168 field.SetParent( this );
3169
3170 UpdatePins();
3171 }
3172
3173 return *this;
3174}
3175
3176
3177bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3178{
3179 BOX2I bBox = GetBodyBoundingBox();
3180 bBox.Inflate( aAccuracy / 2 );
3181
3182 if( bBox.Contains( aPosition ) )
3183 return true;
3184
3185 return false;
3186}
3187
3188
3189bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3190{
3192 return false;
3193
3194 BOX2I rect = aRect;
3195
3196 rect.Inflate( aAccuracy / 2 );
3197
3198 if( aContained )
3199 return rect.Contains( GetBodyBoundingBox() );
3200
3201 return rect.Intersects( GetBodyBoundingBox() );
3202}
3203
3204
3205bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3206{
3208 return false;
3209
3210 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3211}
3212
3213
3214bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3215{
3216 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3217
3218 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3219 {
3220 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3221 continue;
3222
3223 // Collect only pins attached to the current unit and convert.
3224 // others are not associated to this symbol instance
3225 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3226 continue;
3227
3228 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3229 continue;
3230
3231 if( pin->GetLocalPosition() == new_pos )
3232 return true;
3233 }
3234
3235 return false;
3236}
3237
3238
3240{
3241 return m_isInNetlist;
3242}
3243
3244
3245void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3246 const VECTOR2I& aOffset, bool aDimmed )
3247{
3248 if( aBackground )
3249 return;
3250
3251 if( m_part )
3252 {
3253 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3254
3255 // Copy the source so we can re-orient and translate it.
3256 LIB_SYMBOL tempSymbol( *m_part );
3257 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3258
3259 // Copy the pin info from the symbol to the temp pins
3260 for( unsigned i = 0; i < tempPins.size(); ++i )
3261 {
3262 SCH_PIN* symbolPin = GetPin( libPins[i] );
3263 SCH_PIN* tempPin = tempPins[i];
3264
3265 if( !symbolPin )
3266 continue;
3267
3268 tempPin->SetName( symbolPin->GetShownName() );
3269 tempPin->SetType( symbolPin->GetType() );
3270 tempPin->SetShape( symbolPin->GetShape() );
3271
3272 if( symbolPin->IsDangling() )
3273 tempPin->SetFlags( IS_DANGLING );
3274 }
3275
3276 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3277 {
3278 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3279 {
3280 // Use SCH_FIELD's text resolver
3281 SCH_FIELD dummy( this, FIELD_T::USER );
3282 dummy.SetText( text->GetText() );
3283 text->SetText( dummy.GetShownText( false ) );
3284 }
3285 }
3286
3287 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3288 TRANSFORM savedTransform = renderSettings->m_Transform;
3289 renderSettings->m_Transform = GetTransform();
3290 aPlotter->StartBlock( nullptr );
3291
3292 wxString variant = Schematic()->GetCurrentVariant();
3293 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
3294 bool dnp = GetDNP( sheet, variant );
3295
3296 for( bool local_background : { true, false } )
3297 {
3298 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3299
3300 for( SCH_FIELD field : m_fields )
3301 {
3302 field.ClearRenderCache();
3303 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3304
3305 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3306 && ( field.IsVisible() || field.IsForceVisible() ) )
3307 {
3308 PlotLocalPowerIconShape( aPlotter );
3309 }
3310 }
3311 }
3312
3313 if( dnp )
3314 PlotDNP( aPlotter );
3315
3316 // Plot attributes to a hypertext menu
3317 if( aPlotOpts.m_PDFPropertyPopups )
3318 {
3319 std::vector<wxString> properties;
3320
3321 for( const SCH_FIELD& field : GetFields() )
3322 {
3323 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3324
3325 if( text_field.IsEmpty() )
3326 continue;
3327
3328 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3329 }
3330
3331 if( !m_part->GetKeyWords().IsEmpty() )
3332 {
3333 properties.emplace_back(
3334 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ), m_part->GetKeyWords() ) );
3335 }
3336
3337 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3338 }
3339
3340 aPlotter->EndBlock( nullptr );
3341 renderSettings->m_Transform = savedTransform;
3342
3343 if( !m_part->IsPower() )
3344 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3345 }
3346}
3347
3348
3349void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3350{
3351 BOX2I bbox = GetBodyBoundingBox();
3353 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3354 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3355 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3356
3357 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3358 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3359 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3360
3361 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3362 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3363
3364 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3365
3366 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3367 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3368}
3369
3370
3374static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3375{
3376 double lineWidth = aSize / 10.0;
3377
3378 std::vector<SCH_SHAPE> shapeList;
3379 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3380 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3381
3382 for( const SCH_SHAPE& shape : shapeList )
3383 {
3384 // Currently there are only 2 shapes: BEZIER and CIRCLE
3385 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3386
3387 if( shape.GetShape() == SHAPE_T::BEZIER )
3388 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3389 tolerance, lineWidth );
3390 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3391 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3392 }
3393}
3394
3395
3397{
3398 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3399
3400 // Plot the local power pin indicator icon shape
3401 BOX2I bbox = field->GetBoundingBox();
3402
3403 // Calculate the text orientation according to the parent orientation.
3404 EDA_ANGLE orient = field->GetTextAngle();
3405
3406 if( GetTransform().y1 )
3407 {
3408 // Rotate symbol 90 degrees.
3409 if( orient.IsHorizontal() )
3410 orient = ANGLE_VERTICAL;
3411 else
3412 orient = ANGLE_HORIZONTAL;
3413 }
3414
3415 bool rotated = !orient.IsHorizontal();
3416
3417 VECTOR2D pos;
3418 double size = bbox.GetHeight() / 1.5;
3419
3420 if( rotated )
3421 {
3422 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3423 size = bbox.GetWidth() / 1.5;
3424 }
3425 else
3426 {
3427 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3428 }
3429
3430 // TODO: build and plot icon shape
3431 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3432}
3433
3434
3435void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter, bool aDnp ) const
3436{
3437 if( m_part )
3438 {
3439 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3440 TRANSFORM savedTransform = renderSettings->m_Transform;
3441 renderSettings->m_Transform = GetTransform();
3442
3443 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3444
3445 // Copy the source to stay const
3446 LIB_SYMBOL tempSymbol( *m_part );
3447 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3448 SCH_PLOT_OPTS plotOpts;
3449
3450 // Copy the pin info from the symbol to the temp pins
3451 for( unsigned i = 0; i < tempPins.size(); ++i )
3452 {
3453 SCH_PIN* symbolPin = GetPin( libPins[i] );
3454 SCH_PIN* tempPin = tempPins[i];
3455
3456 if( !symbolPin )
3457 continue;
3458
3459 tempPin->SetName( symbolPin->GetShownName() );
3460 tempPin->SetType( symbolPin->GetType() );
3461 tempPin->SetShape( symbolPin->GetShape() );
3462 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, aDnp );
3463 }
3464
3465 renderSettings->m_Transform = savedTransform;
3466 }
3467}
3468
3469
3471{
3472 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3473 {
3474 if( pin->IsBrightened() )
3475 return true;
3476 }
3477
3478 return false;
3479}
3480
3481
3483{
3484 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3485 pin->ClearBrightened();
3486}
3487
3488
3489/*
3490 * When modified at the schematic level, we still store the values of these flags in the
3491 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
3492 * will be created and stored locally in the schematic.
3493 */
3495{
3496 return m_part && m_part->GetShowPinNames();
3497}
3498
3499
3501{
3502 if( m_part )
3503 m_part->SetShowPinNames( aShow );
3504}
3505
3506
3508{
3509 return m_part && m_part->GetShowPinNumbers();
3510}
3511
3512
3514{
3515 if( m_part )
3516 m_part->SetShowPinNumbers( aShow );
3517}
3518
3519
3521{
3522 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3523 {
3524 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3525 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3526
3527 if( pin_unit > 0 && pin_unit != GetUnit() )
3528 continue;
3529
3530 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3531 continue;
3532
3533 if( pin->IsPointClickableAnchor( aPos ) )
3534 return true;
3535 }
3536
3537 return false;
3538}
3539
3540
3542{
3543 // return true if the symbol is equivalent to a global label:
3544 // It is a Power symbol
3545 // It has only one pin type Power input
3546
3548 return false;
3549
3550 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3551
3552 if( pin_list.size() != 1 )
3553 return false;
3554
3555 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3556}
3557
3558
3560{
3561 // return true if the symbol is equivalent to a local label:
3562 // It is a Power symbol
3563 // It has only one pin type Power input
3564
3566 return false;
3567
3568 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3569
3570 if( pin_list.size() != 1 )
3571 return false;
3572
3573 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3574}
3575
3576
3578{
3579 if( !m_part )
3580 return false;
3581
3582 return m_part->IsLocalPower();
3583}
3584
3585
3587{
3588 if( !m_part )
3589 return false;
3590
3591 return m_part->IsGlobalPower();
3592}
3593
3594
3596{
3597 return IsLocalPower() || IsGlobalPower();
3598}
3599
3600
3602{
3603 wxCHECK( m_part, false );
3604
3605 return m_part->IsNormal();
3606}
3607
3608
3609std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
3610{
3611 std::unordered_set<wxString> componentClass;
3612
3613 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
3614 {
3615 for( const SCH_FIELD& field : fields )
3616 {
3617 if( field.GetCanonicalName() == wxT( "Component Class" ) )
3618 {
3619 if( field.GetShownText( aPath, false ) != wxEmptyString )
3620 componentClass.insert( field.GetShownText( aPath, false ) );
3621 }
3622 }
3623 };
3624
3625 // First get component classes set on the symbol itself
3626 getComponentClassFields( m_fields );
3627
3628 // Now get component classes set on any enclosing rule areas
3629 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
3630 {
3631 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
3632 {
3633 getComponentClassFields( label->GetFields() );
3634 }
3635 }
3636
3637 return componentClass;
3638}
3639
3640
3641std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
3642 const wxString& aVariantName ) const
3643{
3644 SCH_SYMBOL_INSTANCE instance;
3645
3646 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
3647 return std::nullopt;
3648
3649 return instance.m_Variants.find( aVariantName )->second;
3650}
3651
3652
3653void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
3654{
3655 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
3656
3657 // The instance path must already exist.
3658 if( !instance )
3659 return;
3660
3661 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
3662}
3663
3664
3665void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
3666{
3667 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3668
3669 // The instance path must already exist.
3670 if( !instance || !instance->m_Variants.contains( aVariantName ) )
3671 return;
3672
3673 instance->m_Variants.erase( aVariantName );
3674}
3675
3676
3677void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
3678 const wxString& aNewName )
3679{
3680 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3681
3682 // The instance path must already exist and contain the old variant.
3683 if( !instance || !instance->m_Variants.contains( aOldName ) )
3684 return;
3685
3686 // Get the variant data, update the name, and re-insert with new key
3687 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
3688 variant.m_Name = aNewName;
3689 instance->m_Variants.erase( aOldName );
3690 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
3691}
3692
3693
3694void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
3695 const wxString& aNewVariant )
3696{
3697 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3698
3699 // The instance path must already exist and contain the source variant.
3700 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
3701 return;
3702
3703 // Copy the variant data with a new name
3704 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
3705 variant.m_Name = aNewVariant;
3706 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
3707}
3708
3709
3710bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
3711{
3712 if( Type() != aOther.Type() )
3713 return false;
3714
3715 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3716
3717 if( GetLibId() != symbol.GetLibId() )
3718 return false;
3719
3720 if( GetPosition() != symbol.GetPosition() )
3721 return false;
3722
3723 if( GetUnit() != symbol.GetUnit() )
3724 return false;
3725
3726 if( GetBodyStyle() != symbol.GetBodyStyle() )
3727 return false;
3728
3729 if( GetTransform() != symbol.GetTransform() )
3730 return false;
3731
3732 if( GetFields() != symbol.GetFields() )
3733 return false;
3734
3735 if( m_pins.size() != symbol.m_pins.size() )
3736 return false;
3737
3738 if( m_excludedFromSim != symbol.m_excludedFromSim )
3739 return false;
3740
3741 if( m_excludedFromBOM != symbol.m_excludedFromBOM )
3742 return false;
3743
3744 if( m_DNP != symbol.m_DNP )
3745 return false;
3746
3748 return false;
3749
3751 return false;
3752
3753 for( unsigned i = 0; i < m_pins.size(); ++i )
3754 {
3755 if( *m_pins[i] != *symbol.m_pins[i] )
3756 return false;
3757 }
3758
3759#if 0
3760 // This has historically been a compare of the current instance, rather than a compare
3761 // of all instances. Probably better to keep it that way for now.
3762 if( m_instanceReferences != symbol.m_instanceReferences )
3763 return false;
3764#endif
3765
3766 return true;
3767}
3768
3769
3770double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3771{
3772 if( Type() != aOther.Type() )
3773 return 0.0;
3774
3775 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
3776
3777 if( GetLibId() != symbol.GetLibId() )
3778 return 0.0;
3779
3780 if( GetPosition() == symbol.GetPosition() )
3781 return 1.0;
3782
3783 return 0.0;
3784}
3785
3786
3787void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
3788 double aLineWidth, bool aHorizontal )
3789{
3790 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
3791
3792 double x_right = aSize / 1.6180339887;
3793 double x_middle = x_right / 2.0;
3794
3795 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
3796 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
3797 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
3798
3799 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
3800 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
3801 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
3802 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
3803 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
3804
3805 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3806 aShapeList.back().SetStart( bottomPt );
3807 aShapeList.back().SetBezierC1( bottomAnchorPt );
3808 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
3809 aShapeList.back().SetEnd( leftPt );
3810
3811
3812 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3813 aShapeList.back().SetStart( leftPt );
3814 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
3815 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
3816 aShapeList.back().SetEnd( rightPt );
3817
3818 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
3819 aShapeList.back().SetStart( rightPt );
3820 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
3821 aShapeList.back().SetBezierC2( bottomAnchorPt );
3822 aShapeList.back().SetEnd( bottomPt );
3823
3824 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
3825 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
3826 aShapeList.back().SetRadius( aSize / 15.0 );
3827
3828 for( SCH_SHAPE& shape : aShapeList )
3829 {
3830 if( aHorizontal )
3831 shape.Rotate( VECTOR2I( 0, 0 ), true );
3832
3833 shape.Move( aPos );
3834 }
3835}
3836
3837
3839{
3840 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
3841 {
3842 if( instance.m_Path == aSheetPath )
3843 return &instance;
3844 }
3845
3846 return nullptr;
3847}
3848
3849
3851{
3852 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
3853 {
3854 if( instance.m_Path == aSheetPath )
3855 return &instance;
3856 }
3857
3858 return nullptr;
3859}
3860
3861
3862static struct SCH_SYMBOL_DESC
3863{
3865 {
3867 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
3868 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
3869 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
3870 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
3871
3877
3884
3891
3892 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
3893 {
3894 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3895 return symbol->GetLibSymbolRef() != nullptr;
3896
3897 return false;
3898 };
3899
3900 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
3902 .SetAvailableFunc( hasLibPart );
3903
3904 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
3906 .SetAvailableFunc( hasLibPart );
3907
3908 const wxString groupFields = _HKI( "Fields" );
3909
3912 groupFields );
3915 groupFields );
3916 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
3917 NO_SETTER( SCH_SYMBOL, wxString ),
3919 groupFields );
3920 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
3921 NO_SETTER( SCH_SYMBOL, wxString ),
3923 groupFields );
3924 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
3926 groupFields );
3927
3928 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
3929 {
3930 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3931 return symbol->IsMultiUnit();
3932
3933 return false;
3934 };
3935
3936 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
3937 {
3938 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3939 return symbol->IsMultiBodyStyle();
3940
3941 return false;
3942 };
3943
3946 .SetAvailableFunc( multiUnit )
3948 []( INSPECTABLE* aItem )
3949 {
3950 wxPGChoices choices;
3951
3952 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3953 {
3954 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
3955 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
3956 }
3957
3958 return choices;
3959 } );
3960
3963 .SetAvailableFunc( multiBodyStyle )
3965 []( INSPECTABLE* aItem )
3966 {
3967 wxPGChoices choices;
3968
3969 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
3970 {
3971 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3972 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3973 }
3974
3975 return choices;
3976 } );
3977
3978 const wxString groupAttributes = _HKI( "Attributes" );
3979
3980 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
3983 groupAttributes );
3984 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
3987 groupAttributes );
3988 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
3991 groupAttributes );
3992 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
3995 groupAttributes );
3996 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
3999 groupAttributes );
4000 }
4002
4003
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:958
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:155
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:149
const KIID m_Uuid
Definition eda_item.h:528
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:539
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:413
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:117
bool IsSelected() const
Definition eda_item.h:129
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:540
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:91
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:158
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:560
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:578
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:48
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.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
Holds all the data relating to one schematic.
Definition schematic.h:89
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:104
wxString GetCurrentVariant() const
Return the current variant being edited.
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:188
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:123
FIELD_T GetId() const
Definition sch_field.h:127
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
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
int m_unit
Definition sch_item.h:782
int m_bodyStyle
Definition sch_item.h:783
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:730
void SetPrivate(bool aPrivate)
Definition sch_item.h:253
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:269
int GetBodyStyle() const
Definition sch_item.h:248
friend class LIB_SYMBOL
Definition sch_item.h:803
int GetUnit() const
Definition sch_item.h:239
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition sch_item.cpp:524
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:785
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:798
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:488
SCH_LAYER_ID m_layer
Definition sch_item.h:781
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:174
void SetName(const wxString &aName)
Definition sch_pin.cpp:421
const wxString & GetName() const
Definition sch_pin.cpp:403
bool IsDangling() const override
Definition sch_pin.cpp:464
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:1356
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:96
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:254
const wxString & GetShownName() const
Definition sch_pin.cpp:580
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:331
const wxString & GetNumber() const
Definition sch_pin.h:124
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:276
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:311
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:522
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:539
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:877
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:544
int GetX() const
Definition sch_symbol.h:874
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:771
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:746
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:756
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:878
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:741
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:508
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:731
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:716
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:871
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:776
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:533
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:718
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:875
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:515
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:726
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:761
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:52
INSPECT_RESULT
Definition eda_item.h:46
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:93
#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:58
@ NO_FILL
Definition eda_shape.h:59
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:60
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:451
@ LAYER_DEVICE
Definition layer_ids.h:468
@ LAYER_VALUEPART
Definition layer_ids.h:463
@ LAYER_FIELDS
Definition layer_ids.h:464
@ LAYER_REFERENCEPART
Definition layer_ids.h:462
@ LAYER_DNP_MARKER
Definition layer_ids.h:480
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:372
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:361
@ 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:75
@ SCH_FIELD_LOCATE_REFERENCE_T
Definition typeinfo.h:181
@ SCH_FIELD_LOCATE_FOOTPRINT_T
Definition typeinfo.h:183
@ SCH_SYMBOL_T
Definition typeinfo.h:173
@ SCH_FIELD_T
Definition typeinfo.h:151
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:200
@ SCH_FIELD_LOCATE_VALUE_T
Definition typeinfo.h:182
@ SCH_FIELD_LOCATE_DATASHEET_T
Definition typeinfo.h:184
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:197
@ SCH_PIN_T
Definition typeinfo.h:154
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686