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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <api/api_enums.h>
22#include <api/api_utils.h>
23#include <sch_collectors.h>
24#include <sch_commit.h>
25#include <sch_edit_frame.h>
26#include <widgets/msgpanel.h>
27#include <bitmaps.h>
28#include <core/mirror.h>
29#include "lib_symbol.h"
30#include <sch_shape.h>
31#include <pgm_base.h>
32#include <sim/sim_model.h>
33#include <sim/spice_generator.h>
34#include <sim/sim_lib_mgr.h>
35#include <trace_helpers.h>
36#include <trigo.h>
37#include <refdes_utils.h>
38#include <wx/log.h>
40#include <sch_plotter.h>
41#include <string_utils.h>
43#include <sch_rule_area.h>
44#include <api/api_sch_utils.h>
45#include <api/schematic/schematic_types.pb.h>
46#include <project_sch.h>
49
50#include <utility>
51#include <validators.h>
52#include <properties/property.h>
54
55
56std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
57
58
63std::string toUTFTildaText( const wxString& txt )
64{
65 std::string ret = TO_UTF8( txt );
66
67 for( char& c : ret )
68 {
69 if( (unsigned char) c <= ' ' )
70 c = '~';
71 }
72
73 return ret;
74}
75
76
84
85
86SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId, const SCH_SHEET_PATH* aSheet, int aUnit,
87 int aBodyStyle, const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
88 SYMBOL( aParent, SCH_SYMBOL_T )
89{
90 Init( aPosition );
91
92 m_unit = aUnit;
93 m_bodyStyle = aBodyStyle;
94 m_lib_id = aLibId;
95
96 std::unique_ptr<LIB_SYMBOL> part;
97
98 part = aSymbol.Flatten();
99 part->SetParent();
100 SetLibSymbol( part.release() );
101
102 // Copy fields from the library symbol
103 UpdateFields( aSheet, true, /* update style */
104 false, /* update ref */
105 false, /* update other fields */
106 true, /* reset ref */
107 true /* reset other fields */ );
108
109 m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
110
111 if( aSheet )
113
114 // Inherit the include in bill of materials and board netlist settings from flattened
115 // library symbol.
116 m_excludedFromSim = m_part->GetExcludedFromSim();
117 m_excludedFromBOM = m_part->GetExcludedFromBOM();
118 m_excludedFromBoard = m_part->GetExcludedFromBoard();
119 m_excludedFromPosFiles = m_part->GetExcludedFromPosFiles();
121 m_signalName.clear();
122}
123
124
125SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet, const PICKED_SYMBOL& aSel,
126 const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
127 SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, aPosition, aParent )
128{
129 // Set any fields that were modified as part of the symbol selection
130 for( const auto& [fieldId, fieldValue] : aSel.Fields )
131 {
132 if( fieldId == FIELD_T::REFERENCE )
133 SetRef( aSheet, fieldValue );
134 else if( SCH_FIELD* field = GetField( fieldId ) )
135 field->SetText( fieldValue );
136 }
137}
138
139
141 SYMBOL( aSymbol )
142{
143 m_parent = aSymbol.m_parent;
144 m_pos = aSymbol.m_pos;
145 m_unit = aSymbol.m_unit;
146 m_bodyStyle = aSymbol.m_bodyStyle;
147 m_lib_id = aSymbol.m_lib_id;
149 m_DNP = aSymbol.m_DNP;
150
151 const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
152
153 m_transform = aSymbol.m_transform;
154 m_prefix = aSymbol.m_prefix;
155 m_instances = aSymbol.m_instances;
157 m_fields = aSymbol.m_fields;
159 m_signalName = aSymbol.m_signalName;
160
161 // Re-parent the fields, which before this had aSymbol as parent
162 for( SCH_FIELD& field : m_fields )
163 field.SetParent( this );
164
165 m_pins.clear();
166
167 // Copy (and re-parent) the pins
168 for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
169 {
170 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
171 m_pins.back()->SetParent( this );
172 }
173
174 if( aSymbol.m_part )
175 SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part ) );
176
179}
180
181
185
186
187void SCH_SYMBOL::Init( const VECTOR2I& pos )
188{
190 m_pos = pos;
191 m_unit = 1; // In multi unit chip - which unit to draw.
192 m_bodyStyle = BODY_STYLE::BASE; // De Morgan Handling
193
194 // The rotation/mirror transformation matrix. pos normal
196
197 auto addField = [&]( FIELD_T id, SCH_LAYER_ID layer )
198 {
199 m_fields.emplace_back( this, id, GetCanonicalFieldName( id ) );
200 m_fields.back().SetTextPos( pos );
201 m_fields.back().SetLayer( layer );
202 };
203
204 // construct only the mandatory fields
206 addField( FIELD_T::VALUE, LAYER_VALUEPART );
207 addField( FIELD_T::FOOTPRINT, LAYER_FIELDS );
208 addField( FIELD_T::DATASHEET, LAYER_FIELDS );
210
211 m_prefix = wxString( wxT( "U" ) );
212 m_isInNetlist = true;
214 m_signalName.clear();
215}
216
217
219{
220 return new SCH_SYMBOL( *this );
221}
222
223
224void SCH_SYMBOL::Serialize( google::protobuf::Any& aContainer ) const
225{
226 using namespace kiapi::common;
227 using namespace kiapi::schematic::types;
228
229 SchematicSymbolInstance symbol;
230
231 symbol.mutable_id()->set_value( m_Uuid.AsStdString() );
232 PackVector2( *symbol.mutable_position(), GetPosition(), schIUScale );
233 symbol.set_locked( IsLocked() ? types::LockedState::LS_LOCKED : types::LockedState::LS_UNLOCKED );
234
235 SchematicSymbolTransform* transform = symbol.mutable_transform();
236 transform->set_orientation(
238 transform->set_mirror_x( GetMirrorX() );
239 transform->set_mirror_y( GetMirrorY() );
240
241 if( GetBodyStyleCount() > 1 )
242 symbol.mutable_body_style()->set_style( GetBodyStyle() );
243
244 SchematicSymbol* def = symbol.mutable_definition();
245 PackLibId( def->mutable_id(), m_lib_id );
246
247 google::protobuf::Any any;
248
250 any.UnpackTo( symbol.mutable_reference_field() );
251
253 any.UnpackTo( symbol.mutable_value_field() );
254
256 any.UnpackTo( symbol.mutable_footprint_field() );
257
259 any.UnpackTo( symbol.mutable_datasheet_field() );
260
262 any.UnpackTo( symbol.mutable_description_field() );
263
264 for( const SCH_FIELD& field : GetFields() )
265 {
266 if( field.IsMandatory() )
267 continue;
268
269 field.Serialize( any );
270 any.UnpackTo( symbol.add_user_fields() );
271 }
272
273 if( m_part )
274 {
275 m_part->GetField( FIELD_T::REFERENCE )->Serialize( any );
276 any.UnpackTo( def->mutable_reference_field() );
277
278 m_part->GetField( FIELD_T::VALUE )->Serialize( any );
279 any.UnpackTo( def->mutable_value_field() );
280
281 m_part->GetField( FIELD_T::FOOTPRINT )->Serialize( any );
282 any.UnpackTo( def->mutable_footprint_field() );
283
284 m_part->GetField( FIELD_T::DATASHEET )->Serialize( any );
285 any.UnpackTo( def->mutable_datasheet_field() );
286
287 m_part->GetField( FIELD_T::DESCRIPTION )->Serialize( any );
288 any.UnpackTo( def->mutable_description_field() );
289
290 for( const SCH_ITEM& drawItem : m_part->GetDrawItems() )
291 {
292 if( drawItem.Type() == SCH_FIELD_T && static_cast<const SCH_FIELD&>( drawItem ).IsMandatory() )
293 continue;
294
295 // pins in the definition are not serialized; we serialize them via PackSymbol
296 // with the sheet-specific information
297 if( drawItem.Type() == SCH_PIN_T )
298 continue;
299
300 SchematicSymbolChild* item = def->add_items();
301 item->mutable_unit()->set_unit( drawItem.GetUnit() );
302 item->mutable_body_style()->set_style( drawItem.GetBodyStyle() );
303 item->set_is_private( drawItem.IsPrivate() );
304 drawItem.Serialize( *item->mutable_item() );
305 }
306
307 def->set_unit_count( m_part->GetUnitCount() );
308 def->set_body_style_count( m_part->GetBodyStyleCount() );
309 def->set_keywords( m_part->GetKeyWords().ToUTF8() );
310
311 for( const wxString& filter : m_part->GetFPFilters() )
312 def->add_footprint_filters( filter.ToUTF8() );
313 }
314
315 symbol.set_show_pin_names( GetShowPinNames() );
316 symbol.set_show_pin_numbers( GetShowPinNumbers() );
317
318 PackDistance( *symbol.mutable_pin_name_offset(), GetPinNameOffset(), schIUScale );
319
320 aContainer.PackFrom( symbol );
321}
322
323
324bool SCH_SYMBOL::Deserialize( const google::protobuf::Any& aContainer )
325{
326 using namespace kiapi::common;
327 using namespace kiapi::common::types;
328 using namespace kiapi::schematic::types;
329
330 SchematicSymbolInstance symbol;
331
332 if( !aContainer.UnpackTo( &symbol ) )
333 return false;
334
335 const_cast<::KIID&>( m_Uuid ) = ::KIID( symbol.id().value() );
336 SetPosition( UnpackVector2( symbol.position(), schIUScale ) );
337 SetLocked( symbol.locked() == LockedState::LS_LOCKED );
338
339 SetOrientationProp( FromProtoEnum<SYMBOL_ORIENTATION_PROP>( symbol.transform().orientation() ) );
340 SetMirrorX( symbol.transform().mirror_x() );
341 SetMirrorY( symbol.transform().mirror_y() );
342
343 const SchematicSymbol& def = symbol.definition();
344
345 LIB_ID libId = UnpackLibId( def.id() );
346 m_lib_id = libId;
347
348 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( libId.GetLibItemName() );
349 libSymbol->SetLibId( libId );
350
351 google::protobuf::Any any;
352
353 any.PackFrom( def.reference_field() );
354 libSymbol->GetField( FIELD_T::REFERENCE )->Deserialize( any );
355
356 any.PackFrom( def.value_field() );
357 libSymbol->GetField( FIELD_T::VALUE )->Deserialize( any );
358
359 any.PackFrom( def.footprint_field() );
360 libSymbol->GetField( FIELD_T::FOOTPRINT )->Deserialize( any );
361
362 any.PackFrom( def.datasheet_field() );
363 libSymbol->GetField( FIELD_T::DATASHEET )->Deserialize( any );
364
365 any.PackFrom( def.description_field() );
367
368 std::unordered_map<::KIID, wxString> pinAltMap;
369
370 for( const SchematicSymbolChild& child : def.items() )
371 {
372 std::optional<KICAD_T> type = TypeNameFromAny( child.item() );
373
374 if( !type )
375 continue;
376
377 std::unique_ptr<EDA_ITEM> item = CreateItemForType( *type, libSymbol );
378
379 if( !item || !item->Deserialize( child.item() ) )
380 continue;
381
382 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
383
384 if( schItem->Type() == SCH_PIN_T )
385 {
386 SchematicPin pinProto;
387
388 if( child.item().UnpackTo( &pinProto ) )
389 {
390 if( pinProto.has_active_alternate() )
391 pinAltMap[schItem->m_Uuid] = wxString::FromUTF8( pinProto.active_alternate() );
392 }
393 }
394
395 if( child.has_unit() )
396 schItem->SetUnit( child.unit().unit() );
397
398 if( child.has_body_style() )
399 schItem->SetBodyStyle( child.body_style().style() );
400
401 schItem->SetLayer( LAYER_DEVICE );
402 schItem->SetPrivate( child.is_private() );
403 libSymbol->AddDrawItem( schItem );
404 }
405
406 if( def.unit_count() > 0 )
407 libSymbol->SetUnitCount( def.unit_count(), false );
408
409 if( def.body_style_count() > 0 )
410 libSymbol->SetBodyStyleCount( def.body_style_count(), false, false );
411
412 if( !def.keywords().empty() )
413 libSymbol->SetKeyWords( wxString::FromUTF8( def.keywords() ) );
414
415 if( def.footprint_filters_size() > 0 )
416 {
417 wxArrayString filters;
418
419 for( const std::string& filter : def.footprint_filters() )
420 filters.Add( wxString::FromUTF8( filter ) );
421
422 libSymbol->SetFPFilters( filters );
423 }
424
425 SetLibSymbol( libSymbol );
426
427 if( symbol.has_body_style() )
428 SetBodyStyle( symbol.body_style().style() );
429
430 any.PackFrom( symbol.reference_field() );
432
433 any.PackFrom( symbol.value_field() );
435
436 any.PackFrom( symbol.footprint_field() );
438
439 any.PackFrom( symbol.datasheet_field() );
441
442 any.PackFrom( symbol.description_field() );
444
445 std::set<wxString> incoming;
446
447 for( const SchematicField& fieldProto : symbol.user_fields() )
448 {
449 wxString name = wxString::FromUTF8( fieldProto.name() );
450 SCH_FIELD* existing = GetField( name );
451
452 // Don't duplicate existing or mandatory fields.
453 if( existing && existing->IsMandatory() )
454 continue;
455
456 incoming.insert( name );
457 any.PackFrom( fieldProto );
458
459 if( existing )
460 existing->Deserialize( any );
461 else
463 }
464
465 std::vector<wxString> toRemove;
466
467 for( const SCH_FIELD& field : GetFields() )
468 {
469 if( !field.IsMandatory() && !incoming.count( field.GetName( false ) ) )
470 toRemove.push_back( field.GetName( false ) );
471 }
472
473 for( const wxString& name : toRemove )
474 RemoveField( name );
475
476 SetShowPinNames( symbol.show_pin_names() );
477 SetShowPinNumbers( symbol.show_pin_numbers() );
478 SetPinNameOffset( UnpackDistance( symbol.pin_name_offset(), schIUScale ) );
479
480 // The proto is storing a single pin struct that has the UUID and alternate selection
481 // as well as the library pin definition. Deserializing the pin will have set up most
482 // of this, but we want to make sure that the UUIDs of the instance pins round-trip
483 // so we have to set them up in advance so that UpdatePins links them up with the
484 // lib pins, and then we need to set the alternates for pins if applicable
485
486 m_pins.clear();
488
489 for( SCH_PIN* pin : GetAllLibPins() )
490 {
491 m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
492 m_pins.back()->SetParent( this );
493 const_cast<::KIID&>( m_pins.back() ->m_Uuid ) = pin->m_Uuid;
494
495 // We also need to reset the lib pin to use relative coordinates
496 pin->SetPosition( t.TransformCoordinate( pin->GetLocalPosition() - m_pos ) );
497 }
498
499 UpdatePins();
500
501 for( SCH_PIN* pin : GetPins() )
502 {
503 if( pinAltMap.contains( pin->m_Uuid ) )
504 pin->SetAlt( pinAltMap.at( pin->m_Uuid ) );
505 }
506
507 return true;
508}
509
510
512{
513 return m_part == nullptr;
514}
515
516
518{
519 // If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
520 // going to end up moving the symbol's pins off-grid.
521
522 // The minimal grid size allowed to place a pin is 25 mils
523 const int min_grid_size = schIUScale.MilsToIU( 25 );
524
525 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
526 {
527 if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
528 return false;
529
530 if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
531 return false;
532 }
533
534 return true;
535}
536
537
538void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
539{
540 m_lib_id = aLibId;
541}
542
543
545{
546 if( !m_schLibSymbolName.IsEmpty() )
547 return m_schLibSymbolName;
548 else
549 return m_lib_id.Format();
550}
551
552
554{
555 wxCHECK2( !aLibSymbol || aLibSymbol->IsRoot(), aLibSymbol = nullptr );
556
557 m_part.reset( aLibSymbol );
558
559 // Library content changed, so cached flattened alternates may be stale.
560 m_variantSymbolCache.clear();
561
562 // We've just reset the library symbol, so the lib_pins, which were just
563 // pointers to the old symbol, need to be cleared.
564 for( auto& pin : m_pins )
565 pin->SetLibPin( nullptr );
566
567 UpdatePins();
568}
569
570
572{
573 if( m_part )
574 return m_part->GetDescription();
575
576 return wxEmptyString;
577}
578
579
580wxString SCH_SYMBOL::GetShownDescription( int aDepth ) const
581{
582 if( m_part )
583 return m_part->GetShownDescription( aDepth );
584
585 return wxEmptyString;
586}
587
588
590{
591 if( m_part )
592 return m_part->GetKeyWords();
593
594 return wxEmptyString;
595}
596
597
598wxString SCH_SYMBOL::GetShownKeyWords( int aDepth ) const
599{
600 if( m_part )
601 return m_part->GetShownKeyWords( aDepth );
602
603 return wxEmptyString;
604}
605
606
608{
609 if( m_part )
610 return m_part->GetDatasheetField().GetText();
611
612 return wxEmptyString;
613}
614
615
617{
618 std::map<wxString, wxString> altPinMap;
619 std::map<wxString, SCH_PIN::ALT> altPinDefs;
620 std::map<wxString, std::set<SCH_PIN*>> pinUuidMap;
621 std::set<SCH_PIN*> unassignedSchPins;
622 std::set<SCH_PIN*> unassignedLibPins;
623
624 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
625 {
626 pinUuidMap[pin->GetNumber()].insert( pin.get() );
627
628 unassignedSchPins.insert( pin.get() );
629
630 if( !pin->GetAlt().IsEmpty() )
631 {
632 altPinMap[pin->GetNumber()] = pin->GetAlt();
633 auto altDefIt = pin->GetAlternates().find( pin->GetAlt() );
634
635 if( altDefIt != pin->GetAlternates().end() )
636 altPinDefs[pin->GetNumber()] = altDefIt->second;
637 }
638
639 pin->SetLibPin( nullptr );
640 }
641
642 m_pinMap.clear();
643
644 if( !m_part )
645 return;
646
647 for( SCH_PIN* libPin : m_part->GetPins() )
648 {
649 // NW: Don't filter by unit: this data-structure is used for all instances,
650 // some of which might have different units.
651 if( libPin->GetBodyStyle() && m_bodyStyle && m_bodyStyle != libPin->GetBodyStyle() )
652 continue;
653
654 SCH_PIN* pin = nullptr;
655
656 auto ii = pinUuidMap.find( libPin->GetNumber() );
657
658 if( ii == pinUuidMap.end() || ii->second.empty() )
659 {
660 unassignedLibPins.insert( libPin );
661 continue;
662 }
663
664 auto it = ii->second.begin();
665 pin = *it;
666 ii->second.erase( it );
667 pin->GetAlternates() = libPin->GetAlternates();
668 pin->SetLibPin( libPin );
669 pin->SetPosition( libPin->GetPosition() );
670 pin->SetUnit( libPin->GetUnit() );
671 pin->SetBodyStyle( libPin->GetBodyStyle() );
672
673 unassignedSchPins.erase( pin );
674
675 auto iii = altPinMap.find( libPin->GetNumber() );
676
677 if( iii != altPinMap.end() )
678 {
679 wxString altName = iii->second;
680
681 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
682 {
683 auto defIt = altPinDefs.find( libPin->GetNumber() );
684
685 if( defIt != altPinDefs.end() )
686 {
687 for( const auto& [name, alt] : pin->GetAlternates() )
688 {
689 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
690 {
691 altName = name;
692 break;
693 }
694 }
695 }
696 }
697
698 pin->SetAlt( altName );
699 }
700
701 m_pinMap[libPin] = pin;
702 }
703
704 // Add any pins that were not found in the symbol
705 for( SCH_PIN* libPin : unassignedLibPins )
706 {
707 SCH_PIN* pin = nullptr;
708
709 // First try to re-use an existing pin
710 if( !unassignedSchPins.empty() )
711 {
712 auto it = unassignedSchPins.begin();
713 pin = *it;
714 unassignedSchPins.erase( it );
715 }
716 else
717 {
718 // This is a pin that was not found in the symbol, so create a new one.
719 pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( this, libPin ) ) ).get();
720 }
721
722 m_pinMap[libPin] = pin;
723 pin->GetAlternates() = libPin->GetAlternates();
724 pin->SetLibPin( libPin );
725 pin->SetPosition( libPin->GetPosition() );
726 pin->SetUnit( libPin->GetUnit() );
727 pin->SetBodyStyle( libPin->GetBodyStyle() );
728 pin->SetNumber( libPin->GetNumber() );
729
730 auto iii = altPinMap.find( libPin->GetNumber() );
731
732 if( iii != altPinMap.end() )
733 {
734 wxString altName = iii->second;
735
736 if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
737 {
738 auto defIt = altPinDefs.find( libPin->GetNumber() );
739
740 if( defIt != altPinDefs.end() )
741 {
742 for( const auto& [name, alt] : pin->GetAlternates() )
743 {
744 if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
745 {
746 altName = name;
747 break;
748 }
749 }
750 }
751 }
752
753 pin->SetAlt( altName );
754 }
755 }
756
757 // If we have any pins left in the symbol that were not found in the library, remove them.
758 for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
759 {
760 auto it2 = unassignedSchPins.find( it1->get() );
761
762 if( it2 != unassignedSchPins.end() )
763 {
764 it1 = m_pins.erase( it1 );
765 unassignedSchPins.erase( it2 );
766 }
767 else
768 {
769 ++it1;
770 }
771 }
772
773 // If the symbol is selected, then its pins are selected.
774 if( IsSelected() )
775 {
776 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
777 pin->SetSelected();
778 }
779}
780
781
782void SCH_SYMBOL::SetBodyStyle( int aBodyStyle )
783{
784 if( aBodyStyle != m_bodyStyle )
785 {
786 m_bodyStyle = aBodyStyle;
787
788 // The body style may have a different pin layout so the update the pin map.
789 UpdatePins();
790 }
791}
792
793
795{
796 if( m_part )
797 return m_part->GetUnitCount();
798
799 return 0;
800}
801
802
804{
805 if( m_part )
806 return m_part->GetBodyStyleCount();
807
808 return 0;
809}
810
811
813{
814 if( m_part )
815 return m_part->HasDeMorganBodyStyles();
816
817 return false;
818}
819
820
821wxString SCH_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
822{
823 if( m_part )
824 return m_part->GetUnitDisplayName( aUnit, aLabel );
825 else if( aLabel )
826 return wxString::Format( _( "Unit %s" ), SubReference( aUnit ) );
827 else
828 return SubReference( aUnit );
829}
830
831
832wxString SCH_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
833{
834 if( m_part )
835 return m_part->GetBodyStyleDescription( aBodyStyle, aLabel );
836 else
837 return wxT( "?" );
838}
839
840
841bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance, const KIID_PATH& aSheetPath, bool aTestFromEnd ) const
842{
843 if( !aTestFromEnd )
844 {
845 auto it = m_instancePathIndex.find( aSheetPath );
846
847 if( it != m_instancePathIndex.end() )
848 {
849 aInstance = m_instances[it->second];
850 return true;
851 }
852
853 return false;
854 }
855
856 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
857 {
858 if( instance.m_Path.EndsWith( aSheetPath ) )
859 {
860 aInstance = instance;
861 return true;
862 }
863 }
864
865 return false;
866}
867
868
869void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
870{
871 RemoveInstance( aInstancePath.Path() );
872}
873
874
875void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
876{
877 bool removed = false;
878
879 // Search for an existing path and remove it if found
880 // (search from back to avoid invalidating iterator on remove)
881 for( int ii = m_instances.size() - 1; ii >= 0; --ii )
882 {
883 if( m_instances[ii].m_Path == aInstancePath )
884 {
885 wxLogTrace( traceSchSheetPaths,
886 wxS( "Removing symbol instance:\n"
887 " sheet path %s\n"
888 " reference %s, unit %d from symbol %s." ),
889 aInstancePath.AsString(), m_instances[ii].m_Reference, m_instances[ii].m_Unit,
890 m_Uuid.AsString() );
891
892 m_instances.erase( m_instances.begin() + ii );
893 removed = true;
894 }
895 }
896
897 if( removed )
899}
900
901
903{
904 m_instancePathIndex.clear();
905 m_instancePathIndex.reserve( m_instances.size() );
906
907 for( size_t i = 0; i < m_instances.size(); ++i )
908 m_instancePathIndex[m_instances[i].m_Path] = i;
909}
910
911
912void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, int aUnit )
913{
914 SCH_SYMBOL_INSTANCE instance;
915 instance.m_Path = aPath;
916 instance.m_Reference = aRef;
917 instance.m_Unit = aUnit;
918
919 AddHierarchicalReference( instance );
920}
921
922
924{
925 RemoveInstance( aInstance.m_Path );
926
927 SCH_SYMBOL_INSTANCE instance = aInstance;
928
929 wxLogTrace( traceSchSheetPaths,
930 wxS( "Adding symbol '%s' instance:\n"
931 " sheet path '%s'\n"
932 " reference '%s'\n"
933 " unit %d\n" ),
934 m_Uuid.AsString(), instance.m_Path.AsString(), instance.m_Reference, instance.m_Unit );
935
936 m_instancePathIndex[instance.m_Path] = m_instances.size();
937 m_instances.push_back( instance );
938
939 // This should set the default instance to the first saved instance data for each symbol
940 // when importing sheets.
941 if( m_instances.size() == 1 )
942 {
944 m_unit = instance.m_Unit;
945 }
946}
947
948
949const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
950{
951 KIID_PATH path = sheet->Path();
952 wxString ref;
953 wxString subRef;
954
955 wxLogTrace( traceSchSymbolRef, "GetRef for symbol %s on path %s (sheet path has %zu sheets)",
956 m_Uuid.AsString(), path.AsString(), sheet->size() );
957
958 wxLogTrace( traceSchSymbolRef, " Symbol has %zu instance references", m_instances.size() );
959
960 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
961 {
962 const SCH_SYMBOL_INSTANCE& instance = m_instances[it->second];
963
964 ref = instance.m_Reference;
965 subRef = SubReference( instance.m_Unit );
966 wxLogTrace( traceSchSymbolRef, " MATCH FOUND: ref=%s", ref );
967 }
968
969 // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
970 // use this as a default for this path. This will happen if we load a version 1 schematic
971 // file. It will also mean that multiple instances of the same sheet by default all have
972 // the same symbol references, but perhaps this is best.
973 if( ref.IsEmpty() && !GetField( FIELD_T::REFERENCE )->GetText().IsEmpty() )
974 {
976 wxLogTrace( traceSchSymbolRef, " Using fallback from REFERENCE field: %s", ref );
977 }
978
979 if( ref.IsEmpty() )
980 {
982 wxLogTrace( traceSchSymbolRef, " Using unannotated reference: %s", ref );
983 }
984
985 if( aIncludeUnit && GetUnitCount() > 1 )
986 ref += subRef;
987
988 wxLogTrace( traceSchSymbolRef, " Final reference: %s", ref );
989
990 return ref;
991}
992
993
994void SCH_SYMBOL::SetRefProp( const wxString& aRef )
995{
997
998 if( validator.DoValidate( aRef, nullptr ) )
999 SetRef( &Schematic()->CurrentSheet(), aRef );
1000}
1001
1002
1003void SCH_SYMBOL::SetValueProp( const wxString& aValue )
1004{
1005 wxString currentVariant = Schematic()->GetCurrentVariant();
1006 SetValueFieldText( aValue, &Schematic()->CurrentSheet(), currentVariant );
1007}
1008
1009
1010void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
1011{
1012 KIID_PATH path = sheet->Path();
1013
1014 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1015 m_instances[it->second].m_Reference = ref;
1016 else
1018
1019 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1020 pin->ClearDefaultNetName( sheet );
1021
1022 if( Schematic() && *sheet == Schematic()->CurrentSheet() )
1024
1025 // Reinit the m_prefix member if needed
1027
1028 if( m_prefix.IsEmpty() )
1029 m_prefix = wxT( "U" );
1030
1031 // Power symbols have references starting with # and are not included in netlists
1032 m_isInNetlist = !ref.StartsWith( wxT( "#" ) );
1033}
1034
1035
1036void SCH_SYMBOL::SetFieldText( const wxString& aFieldName, const wxString& aFieldText, const SCH_SHEET_PATH* aPath,
1037 const wxString& aVariantName )
1038{
1039 wxCHECK( !aFieldName.IsEmpty(), /* void */ );
1040
1041 SCH_FIELD* field = GetField( aFieldName );
1042
1043 wxCHECK( field, /* void */ );
1044
1045 switch( field->GetId() )
1046 {
1047 case FIELD_T::REFERENCE:
1048 wxCHECK( aPath, /* void */ );
1049 SetRef( aPath, aFieldText );
1050 break;
1051
1052 default:
1053 {
1054 wxString defaultText = field->GetText( aPath );
1055
1056 if( aVariantName.IsEmpty() )
1057 {
1058 if( aFieldText != defaultText )
1059 field->SetText( aFieldText );
1060 }
1061 else
1062 {
1063 SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1064
1065 wxCHECK( instance, /* void */ );
1066
1067 // Diff against the value the variant resolves to without an explicit override so
1068 // alternate symbol fields read back through the UI are not re-stored as overrides.
1069 if( LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath ) )
1070 {
1071 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1072
1073 if( altField && !altField->GetText().IsEmpty() )
1074 defaultText = altField->GetText();
1075 }
1076
1077 if( instance->m_Variants.contains( aVariantName ) )
1078 {
1079 if( aFieldText != defaultText )
1080 instance->m_Variants[aVariantName].m_Fields[aFieldName] = aFieldText;
1081 else
1082 instance->m_Variants[aVariantName].m_Fields.erase( aFieldName );
1083 }
1084 else if( aFieldText != defaultText )
1085 {
1086 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1087
1088 newVariant.InitializeAttributes( *this );
1089 newVariant.m_Fields[aFieldName] = aFieldText;
1090 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1091 }
1092 }
1093
1094 break;
1095 }
1096 }
1097}
1098
1099
1100wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, const SCH_SHEET_PATH* aPath,
1101 const wxString& aVariantName ) const
1102{
1103 wxCHECK( !aFieldName.IsEmpty(), wxEmptyString );
1104
1105 const SCH_FIELD* field = GetField( aFieldName );
1106
1107 wxCHECK( field, wxEmptyString );
1108
1109 switch( field->GetId() )
1110 {
1111 case FIELD_T::REFERENCE:
1112 wxCHECK( aPath, field->GetText() );
1113 return GetRef( aPath, false );
1114 break;
1115
1116 case FIELD_T::FOOTPRINT:
1117 if( !aVariantName.IsEmpty() && aPath )
1118 {
1119 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1120
1121 if( instance && instance->m_Variants.contains( aVariantName )
1122 && instance->m_Variants.at( aVariantName ).m_Fields.contains( aFieldName ) )
1123 {
1124 return instance->m_Variants.at( aVariantName ).m_Fields.at( aFieldName );
1125 }
1126
1127 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1128
1129 if( altSymbol )
1130 {
1131 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::FOOTPRINT );
1132
1133 if( altField && !altField->GetText().IsEmpty() )
1134 return altField->GetText();
1135 }
1136 }
1137
1138 return GetFootprintFieldText( false, nullptr, false );
1139
1140 default:
1141 if( aVariantName.IsEmpty() )
1142 {
1143 return field->GetText();
1144 }
1145 else if( aPath )
1146 {
1147 const SCH_SYMBOL_INSTANCE* instance = getInstance( *aPath );
1148
1149 if( instance && instance->m_Variants.contains( aVariantName ) )
1150 {
1151 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
1152
1153 if( variant.m_Fields.contains( aFieldName ) )
1154 return variant.m_Fields.at( aFieldName );
1155
1156 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aPath );
1157
1158 if( altSymbol )
1159 {
1160 const SCH_FIELD* altField = altSymbol->GetField( aFieldName );
1161
1162 if( altField && !altField->GetText().IsEmpty() )
1163 return altField->GetText();
1164 }
1165 }
1166 }
1167
1168 break;
1169 }
1170
1171 return field->GetText();
1172}
1173
1174
1175bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const
1176{
1177 KIID_PATH path = aSheet->Path();
1178
1179 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1180 {
1181 if( instance.m_Path == path )
1182 return !instance.m_Reference.IsEmpty() && instance.m_Reference.Last() != '?';
1183 }
1184
1185 return false;
1186}
1187
1188
1190{
1191 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
1192
1193 refDesignator.Replace( "~", " " );
1194
1195 wxString prefix = refDesignator;
1196
1197 while( prefix.Length() )
1198 {
1199 wxUniCharRef last = prefix.Last();
1200
1201 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
1202 prefix.RemoveLast();
1203 else
1204 break;
1205 }
1206
1207 // Avoid a prefix containing trailing/leading spaces
1208 prefix.Trim( true );
1209 prefix.Trim( false );
1210
1211 if( !prefix.IsEmpty() )
1212 SetPrefix( prefix );
1213}
1214
1215
1216wxString SCH_SYMBOL::SubReference( int aUnit, bool aAddSeparator ) const
1217{
1218 // A custom unit display name overrides the default A/B/C (or numeric) suffix.
1219 if( m_part )
1220 {
1221 const std::map<int, wxString>& names = m_part->GetUnitDisplayNames();
1222 auto it = names.find( aUnit );
1223
1224 if( it != names.end() && !it->second.IsEmpty() )
1225 {
1226 wxString subRef;
1227
1228 if( SCHEMATIC* schematic = Schematic() )
1229 {
1230 int sep = schematic->Settings().m_SubpartIdSeparator;
1231
1232 if( sep != 0 && aAddSeparator )
1233 subRef << wxChar( sep );
1234 }
1235
1236 subRef << it->second;
1237 return subRef;
1238 }
1239 }
1240
1241 if( SCHEMATIC* schematic = Schematic() )
1242 return schematic->Settings().SubReference( aUnit, aAddSeparator );
1243
1244 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
1245}
1246
1247
1249{
1250 KIID_PATH path = aSheet->Path();
1251
1252 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1253 return m_instances[it->second].m_Unit;
1254
1255 // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
1256 // version 1 schematic file.
1257 return m_unit;
1258}
1259
1260
1261void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
1262{
1263 KIID_PATH path = aSheet->Path();
1264
1265 if( auto it = m_instancePathIndex.find( path ); it != m_instancePathIndex.end() )
1266 {
1267 m_instances[it->second].m_Unit = aUnitSelection;
1268 return;
1269 }
1270
1271 // didn't find it; better add it
1273}
1274
1275
1276void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1277{
1278 if( !aInstance || aVariantName.IsEmpty() )
1279 {
1280 m_DNP = aEnable;
1281 return;
1282 }
1283
1284 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1285
1286 wxCHECK_MSG( instance, /* void */,
1287 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1288 aInstance->PathHumanReadable() ) );
1289
1290 if( aVariantName.IsEmpty() )
1291 {
1292 m_DNP = aEnable;
1293 }
1294 else
1295 {
1296 if( instance->m_Variants.contains( aVariantName ) )
1297 {
1298 instance->m_Variants[aVariantName].m_DNP = aEnable;
1299 }
1300 else if( aEnable != m_DNP )
1301 {
1302 SCH_SYMBOL_VARIANT variant( aVariantName );
1303
1304 variant.InitializeAttributes( *this );
1305 variant.m_DNP = aEnable;
1306 AddVariant( *aInstance, variant );
1307 }
1308 }
1309}
1310
1311
1312bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1313{
1314 if( !aInstance || aVariantName.IsEmpty() )
1315 return m_DNP;
1316
1317 SCH_SYMBOL_INSTANCE instance;
1318
1319 if( !GetInstance( instance, aInstance->Path() ) )
1320 return m_DNP;
1321
1322 if( instance.m_Variants.contains( aVariantName ) )
1323 return instance.m_Variants[aVariantName].m_DNP;
1324
1325 return m_DNP;
1326}
1327
1328
1330 const wxString& aVariantName )
1331{
1332 if( !aInstance || aVariantName.IsEmpty() )
1333 {
1334 m_pinMapOverride = aOverride;
1335 return;
1336 }
1337
1338 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1339
1340 wxCHECK_MSG( instance, /* void */,
1341 wxString::Format( wxS( "Cannot set pin map override for invalid sheet path '%s'." ),
1342 aInstance->PathHumanReadable() ) );
1343
1344 if( instance->m_Variants.contains( aVariantName ) )
1345 {
1346 instance->m_Variants[aVariantName].m_PinMapOverride = aOverride;
1347 }
1348 else if( !aOverride.IsDefault() )
1349 {
1350 SCH_SYMBOL_VARIANT variant( aVariantName );
1351
1352 variant.InitializeAttributes( *this );
1353 variant.m_PinMapOverride = aOverride;
1354 AddVariant( *aInstance, variant );
1355 }
1356}
1357
1358
1360 const wxString& aVariantName ) const
1361{
1363
1364 if( aInstance && !aVariantName.IsEmpty() )
1365 {
1366 SCH_SYMBOL_INSTANCE instance;
1367
1368 if( GetInstance( instance, aInstance->Path() ) && instance.m_Variants.contains( aVariantName ) )
1369 result = instance.m_Variants[aVariantName].m_PinMapOverride;
1370 }
1371
1372 // Units 2..N follow unit 1's record; resolve that here so callers never see a delegate.
1373 if( result.IsDelegate() && aInstance )
1374 result = resolveDelegatedPinMapOverride( *aInstance, aVariantName );
1375
1376 return result;
1377}
1378
1379
1381 const wxString& aVariantName ) const
1382{
1383 if( !Schematic() )
1385
1386 wxString ref = GetRef( &aSheet );
1387
1388 for( const SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1389 {
1390 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
1391 {
1392 SCH_SYMBOL* sibling = static_cast<SCH_SYMBOL*>( item );
1393
1394 if( sibling == this || sibling->GetUnit() != 1 )
1395 continue;
1396
1397 if( sibling->GetRef( &sheet ).CmpNoCase( ref ) != 0 )
1398 continue;
1399
1400 PIN_MAP_INSTANCE_OVERRIDE unit1 = sibling->GetPinMapOverride( &sheet, aVariantName );
1401
1402 // Guard against a unit-1 record that itself (incorrectly) delegates.
1403 if( unit1.IsDelegate() )
1405
1406 return unit1;
1407 }
1408 }
1409
1411}
1412
1413
1414void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1415{
1416 if( !aInstance || aVariantName.IsEmpty() )
1417 {
1418 m_excludedFromBOM = aEnable;
1419 return;
1420 }
1421
1422 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1423
1424 wxCHECK_MSG( instance, /* void */,
1425 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1426 aInstance->PathHumanReadable() ) );
1427
1428 if( aVariantName.IsEmpty() )
1429 {
1430 m_excludedFromBOM = aEnable;
1431 }
1432 else
1433 {
1434 if( instance->m_Variants.contains( aVariantName ) )
1435 {
1436 instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable;
1437 }
1438 else if( aEnable != m_excludedFromBOM )
1439 {
1440 SCH_SYMBOL_VARIANT variant( aVariantName );
1441
1442 variant.InitializeAttributes( *this );
1443 variant.m_ExcludedFromBOM = aEnable;
1444 AddVariant( *aInstance, variant );
1445 }
1446 }
1447}
1448
1449
1450bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1451{
1452 if( !aInstance || aVariantName.IsEmpty() )
1453 return m_excludedFromBOM;
1454
1455 SCH_SYMBOL_INSTANCE instance;
1456
1457 if( !GetInstance( instance, aInstance->Path() ) )
1458 return m_excludedFromBOM;
1459
1460 if( instance.m_Variants.contains( aVariantName ) )
1461 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
1462
1463 // If the variant has not been defined yet, return the default exclude from BOM setting.
1464 return m_excludedFromBOM;
1465}
1466
1467
1468void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1469{
1470 if( !aInstance || aVariantName.IsEmpty() )
1471 {
1472 m_excludedFromSim = aEnable;
1473 return;
1474 }
1475
1476 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1477
1478 wxCHECK_MSG( instance, /* void */,
1479 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1480 aInstance->PathHumanReadable() ) );
1481
1482 if( aVariantName.IsEmpty() )
1483 {
1484 m_excludedFromSim = aEnable;
1485 }
1486 else
1487 {
1488 if( instance->m_Variants.contains( aVariantName ) )
1489 {
1490 instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable;
1491 }
1492 else if( aEnable != m_excludedFromSim )
1493 {
1494 SCH_SYMBOL_VARIANT variant( aVariantName );
1495
1496 variant.InitializeAttributes( *this );
1497 variant.m_ExcludedFromSim = aEnable;
1498 AddVariant( *aInstance, variant );
1499 }
1500 }
1501}
1502
1503
1504bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1505{
1506 if( !aInstance || aVariantName.IsEmpty() )
1507 return m_excludedFromSim;
1508
1509 SCH_SYMBOL_INSTANCE instance;
1510
1511 if( !GetInstance( instance, aInstance->Path() ) )
1512 return m_excludedFromSim;
1513
1514 if( instance.m_Variants.contains( aVariantName ) )
1515 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
1516
1517 // If variant is not defined yet, return default exclude from simulation setting.
1518 return m_excludedFromSim;
1519}
1520
1521
1522void SCH_SYMBOL::SetExcludedFromBoard( bool aEnable, const SCH_SHEET_PATH* aInstance,
1523 const wxString& aVariantName )
1524{
1525 if( !aInstance || aVariantName.IsEmpty() )
1526 {
1527 m_excludedFromBoard = aEnable;
1528 return;
1529 }
1530
1531 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1532
1533 wxCHECK_MSG( instance, /* void */,
1534 wxString::Format( wxS( "Cannot set exclude from board for invalid sheet path '%s'." ),
1535 aInstance->PathHumanReadable() ) );
1536
1537 if( aVariantName.IsEmpty() )
1538 {
1539 m_excludedFromBoard = aEnable;
1540 }
1541 else
1542 {
1543 if( instance->m_Variants.contains( aVariantName ) )
1544 {
1545 instance->m_Variants[aVariantName].m_ExcludedFromBoard = aEnable;
1546 }
1547 else if( aEnable != m_excludedFromBoard )
1548 {
1549 SCH_SYMBOL_VARIANT variant( aVariantName );
1550
1551 variant.InitializeAttributes( *this );
1552 variant.m_ExcludedFromBoard = aEnable;
1553 AddVariant( *aInstance, variant );
1554 }
1555 }
1556}
1557
1558
1560 const wxString& aVariantName ) const
1561{
1562 if( !aInstance || aVariantName.IsEmpty() )
1563 return m_excludedFromBoard;
1564
1565 SCH_SYMBOL_INSTANCE instance;
1566
1567 if( !GetInstance( instance, aInstance->Path() ) )
1568 return m_excludedFromBoard;
1569
1570 if( instance.m_Variants.contains( aVariantName ) )
1571 return instance.m_Variants[aVariantName].m_ExcludedFromBoard;
1572
1573 // If variant is not defined yet, return default exclude from board setting.
1574 return m_excludedFromBoard;
1575}
1576
1577
1578void SCH_SYMBOL::SetExcludedFromPosFiles( bool aEnable, const SCH_SHEET_PATH* aInstance,
1579 const wxString& aVariantName )
1580{
1581 if( !aInstance || aVariantName.IsEmpty() )
1582 {
1583 m_excludedFromPosFiles = aEnable;
1584 return;
1585 }
1586
1587 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1588
1589 wxCHECK_MSG( instance, /* void */,
1590 wxString::Format( wxS( "Cannot set exclude from pos files for invalid sheet path '%s'." ),
1591 aInstance->PathHumanReadable() ) );
1592
1593 if( aVariantName.IsEmpty() )
1594 {
1595 m_excludedFromPosFiles = aEnable;
1596 }
1597 else
1598 {
1599 if( instance->m_Variants.contains( aVariantName ) )
1600 {
1601 instance->m_Variants[aVariantName].m_ExcludedFromPosFiles = aEnable;
1602 }
1603 else if( aEnable != m_excludedFromPosFiles )
1604 {
1605 SCH_SYMBOL_VARIANT variant( aVariantName );
1606
1607 variant.InitializeAttributes( *this );
1608 variant.m_ExcludedFromPosFiles = aEnable;
1609 AddVariant( *aInstance, variant );
1610 }
1611 }
1612}
1613
1614
1616 const wxString& aVariantName ) const
1617{
1618 if( !aInstance || aVariantName.IsEmpty() )
1620
1621 SCH_SYMBOL_INSTANCE instance;
1622
1623 if( !GetInstance( instance, aInstance->Path() ) )
1625
1626 if( instance.m_Variants.contains( aVariantName ) )
1627 return instance.m_Variants[aVariantName].m_ExcludedFromPosFiles;
1628
1629 // If variant is not defined yet, return default exclude from position files setting.
1631}
1632
1633
1634void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
1635{
1636 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
1637 instance.m_Unit = aUnitSelection;
1638}
1639
1640
1641const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aInstance,
1642 bool aAllowExtraText, const wxString& aVariantName ) const
1643{
1644 if( aVariantName.IsEmpty() || !aInstance )
1645 {
1646 if( aResolve )
1647 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1648
1649 return GetField( FIELD_T::VALUE )->GetText();
1650 }
1651
1652 std::optional variant = GetVariant( *aInstance, aVariantName );
1653
1654 if( variant )
1655 {
1656 const wxString& fieldName = GetField( FIELD_T::VALUE )->GetName();
1657
1658 if( variant->m_Fields.contains( fieldName ) )
1659 return variant->m_Fields[fieldName];
1660
1661 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( aVariantName, *aInstance );
1662
1663 if( altSymbol )
1664 {
1665 const SCH_FIELD* altField = altSymbol->GetField( FIELD_T::VALUE );
1666
1667 if( altField && !altField->GetText().IsEmpty() )
1668 return altField->GetText();
1669 }
1670 }
1671
1672 // Fall back to default value when variant doesn't have an override
1673 if( aResolve )
1674 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1675
1676 return GetField( FIELD_T::VALUE )->GetText();
1677}
1678
1679
1680void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance,
1681 const wxString& aVariantName )
1682{
1683 if( !aInstance || aVariantName.IsEmpty() )
1684 {
1685 GetField( FIELD_T::VALUE )->SetText( aValue );
1686 return;
1687 }
1688
1689 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1690
1691 wxCHECK( instance, /* void */ );
1692
1693 wxString fieldName = GetField( FIELD_T::VALUE )->GetName();
1694
1695 if( instance->m_Variants.contains( aVariantName ) )
1696 {
1697 instance->m_Variants[aVariantName].m_Fields[fieldName] = aValue;
1698 }
1699 else
1700 {
1701 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1702
1703 newVariant.InitializeAttributes( *this );
1704 newVariant.m_Fields[fieldName] = aValue;
1705 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1706 }
1707}
1708
1709
1710const wxString SCH_SYMBOL::GetFootprintFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
1711 bool aAllowExtraText, const wxString& aVariantName ) const
1712{
1713 if( aResolve )
1714 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText, 0, aVariantName );
1715
1716 return GetField( FIELD_T::FOOTPRINT )->GetText();
1717}
1718
1719
1720void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
1721{
1722 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
1723}
1724
1725
1727{
1728 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
1729 return field;
1730
1731 m_fields.emplace_back( this, aFieldType );
1732 return &m_fields.back();
1733}
1734
1735
1736const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
1737{
1738 return FindField( m_fields, aFieldType );
1739}
1740
1741
1742SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
1743{
1744 return FindField( m_fields, aFieldName );
1745}
1746
1747
1748const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
1749{
1750 return FindField( m_fields, aFieldName );
1751}
1752
1753
1754void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
1755{
1756 for( const SCH_FIELD& field : m_fields )
1757 {
1758 if( aVisibleOnly )
1759 {
1760 if( !field.IsVisible() || field.GetText().IsEmpty() )
1761 continue;
1762 }
1763
1764 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
1765 }
1766
1767 std::sort( aVector.begin(), aVector.end(),
1768 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1769 {
1770 return lhs->GetOrdinal() < rhs->GetOrdinal();
1771 } );
1772}
1773
1774
1776{
1777 return NextFieldOrdinal( m_fields );
1778}
1779
1780
1782{
1783 m_fields.push_back( aField );
1784 return &m_fields.back();
1785}
1786
1787
1788void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
1789{
1790 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
1791 {
1792 if( m_fields[ii].IsMandatory() )
1793 continue;
1794
1795 if( aFieldName == m_fields[ii].GetName( false ) )
1796 {
1797 m_fields.erase( m_fields.begin() + ii );
1798 return;
1799 }
1800 }
1801}
1802
1803
1805{
1806 for( SCH_FIELD& field : m_fields )
1807 {
1808 if( field.GetName().IsSameAs( aFieldName, false ) )
1809 return &field;
1810 }
1811
1812 return nullptr;
1813}
1814
1815
1816const SCH_FIELD* SCH_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
1817{
1818 for( const SCH_FIELD& field : m_fields )
1819 {
1820 if( field.GetName().IsSameAs( aFieldName, false ) )
1821 return &field;
1822 }
1823
1824 return nullptr;
1825}
1826
1827
1828void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
1829 bool aResetRef, bool aResetOtherFields )
1830{
1831 if( m_part )
1832 {
1833 std::vector<SCH_FIELD*> fields;
1834 m_part->GetFields( fields );
1835
1836 for( const SCH_FIELD* libField : fields )
1837 {
1838 SCH_FIELD* schField;
1839 FIELD_T fieldType = FIELD_T::USER;
1840
1841 if( libField->IsMandatory() )
1842 {
1843 fieldType = libField->GetId();
1844 schField = GetField( fieldType );
1845 }
1846 else
1847 {
1848 schField = GetField( libField->GetCanonicalName() );
1849
1850 if( !schField )
1851 {
1852 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetCanonicalName() ) );
1853 schField->ImportValues( *libField );
1854 schField->SetTextPos( m_pos + libField->GetTextPos() );
1855 }
1856 }
1857
1858 schField->SetPrivate( libField->IsPrivate() );
1859
1860 if( aUpdateStyle )
1861 {
1862 schField->ImportValues( *libField );
1863 schField->SetTextPos( m_pos + libField->GetTextPos() );
1864 }
1865
1866 if( fieldType == FIELD_T::REFERENCE && aPath )
1867 {
1868 if( aResetRef )
1869 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
1870 else if( aUpdateRef )
1871 SetRef( aPath, libField->GetText() );
1872 }
1873 else if( fieldType == FIELD_T::VALUE )
1874 {
1875 SetValueFieldText( UnescapeString( libField->GetText() ) );
1876 }
1877 else if( fieldType == FIELD_T::DATASHEET )
1878 {
1879 if( aResetOtherFields )
1880 schField->SetText( GetDatasheet() ); // alias-specific value
1881 else if( aUpdateOtherFields )
1882 schField->SetText( libField->GetText() );
1883 }
1884 else
1885 {
1886 if( aResetOtherFields || aUpdateOtherFields )
1887 schField->SetText( libField->GetText() );
1888 }
1889 }
1890 }
1891}
1892
1893
1894void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit,
1895 PROPERTY_BASE* aProperty, const wxString& aVariantName )
1896{
1897 bool updateValue = true;
1898 bool updateExclFromBOM = true;
1899 bool updateExclFromBoard = true;
1900 bool updateExclFromPosFiles = true;
1901 bool updateDNP = true;
1902 bool updateOtherFields = true;
1903 bool updatePins = true;
1904 bool updatePinMapOverride = true;
1905
1906 if( aProperty )
1907 {
1908 updateValue = aProperty->Name() == _HKI( "Value" );
1909 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
1910 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
1911 updateExclFromPosFiles = aProperty->Name() == _HKI( "Exclude From Position Files" );
1912 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
1913 updatePinMapOverride = aProperty->Name() == wxS( "Pin Map Mode" ) || aProperty->Name() == wxS( "Pin Map Name" );
1914 updateOtherFields = false;
1915 updatePins = false;
1916 }
1917
1918 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateExclFromPosFiles && !updateDNP
1919 && !updateOtherFields && !updatePins && !updatePinMapOverride )
1920 {
1921 return;
1922 }
1923
1924 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
1925 // in sync in multi-unit parts.
1926 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
1927 {
1928 wxString ref = GetRef( &aSourceSheet );
1929
1930 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1931 {
1932 SCH_SCREEN* screen = sheet.LastScreen();
1933 std::vector<SCH_SYMBOL*> otherUnits;
1934
1935 CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
1936
1937 for( SCH_SYMBOL* otherUnit : otherUnits )
1938 {
1939 aCommit.Modify( otherUnit, screen );
1940
1941 if( updateValue )
1942 {
1943 otherUnit->SetFieldText( GetField( FIELD_T::VALUE )->GetName(),
1944 GetValue( false, &aSourceSheet, false, aVariantName ), &sheet,
1945 aVariantName );
1946 }
1947
1948 if( updateOtherFields )
1949 {
1950 for( SCH_FIELD& field : m_fields )
1951 {
1952 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
1953 {
1954 // already handled
1955 continue;
1956 }
1957
1958 SCH_FIELD* otherField;
1959
1960 if( field.IsMandatory() )
1961 otherField = otherUnit->GetField( field.GetId() );
1962 else
1963 otherField = otherUnit->GetField( field.GetName() );
1964
1965 if( otherField )
1966 {
1967 otherField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet, aVariantName );
1968 }
1969 else
1970 {
1971 SCH_FIELD newField( field );
1972 const_cast<KIID&>( newField.m_Uuid ) = KIID();
1973
1974 newField.Offset( -GetPosition() );
1975 newField.Offset( otherUnit->GetPosition() );
1976
1977 newField.SetParent( otherUnit );
1978 SCH_FIELD* addedField = otherUnit->AddField( newField );
1979
1980 if( !aVariantName.IsEmpty() )
1981 {
1982 addedField->SetText( field.GetText( &aSourceSheet, aVariantName ), &sheet,
1983 aVariantName );
1984 }
1985 }
1986 }
1987
1988 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
1989 {
1990 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
1991
1992 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
1993 otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
1994 }
1995 }
1996
1997 if( updateExclFromBOM )
1998 {
1999 otherUnit->SetExcludedFromBOM( GetExcludedFromBOM( &aSourceSheet, aVariantName ), &sheet,
2000 aVariantName );
2001 }
2002
2003 if( updateExclFromBoard )
2004 {
2005 otherUnit->SetExcludedFromBoard( GetExcludedFromBoard( &aSourceSheet, aVariantName ), &sheet,
2006 aVariantName );
2007 }
2008
2009 if( updateExclFromPosFiles )
2010 {
2011 otherUnit->SetExcludedFromPosFiles( GetExcludedFromPosFiles( &aSourceSheet, aVariantName ), &sheet,
2012 aVariantName );
2013 }
2014
2015 if( updateDNP )
2016 otherUnit->SetDNP( GetDNP( &aSourceSheet, aVariantName ), &sheet, aVariantName );
2017
2018 if( updatePinMapOverride )
2019 otherUnit->SetPinMapOverride( GetPinMapOverride( &aSourceSheet, aVariantName ), &sheet,
2020 aVariantName );
2021
2022 if( updatePins )
2023 {
2024 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
2025 {
2026 for( SCH_PIN* src_pin : otherUnit->GetPinsByNumber( model_pin->GetNumber() ) )
2027 src_pin->SetAlt( model_pin->GetAlt() );
2028 }
2029 }
2030 }
2031 }
2032 }
2033}
2034
2035
2036void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
2037{
2038 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2039 aFunction( pin.get() );
2040
2041 for( SCH_FIELD& field : m_fields )
2042 aFunction( &field );
2043}
2044
2045
2051
2052
2053SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
2054{
2055 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2056 {
2057 if( pin->GetNumber() == aNumber )
2058 return pin.get();
2059 }
2060
2061 return nullptr;
2062}
2063
2064
2065SCH_PIN* SCH_SYMBOL::GetPinByEffectivePadNumber( const wxString& aPadNumber, const SCH_SHEET_PATH* aSheet,
2066 const wxString& aVariantName ) const
2067{
2068 if( !aSheet )
2069 return nullptr;
2070
2071 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2072 {
2073 for( const wxString& pad : ExpandStackedPinNotation( pin->GetEffectivePadNumber( *aSheet, aVariantName ) ) )
2074 {
2075 if( pad == aPadNumber )
2076 return pin.get();
2077 }
2078 }
2079
2080 return nullptr;
2081}
2082
2083
2084std::vector<SCH_PIN*> SCH_SYMBOL::GetPinsByNumber( const wxString& aNumber ) const
2085{
2086 std::vector<SCH_PIN*> pins;
2087
2088 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2089 {
2090 if( pin->GetNumber() == aNumber )
2091 pins.push_back( pin.get() );
2092 }
2093
2094 return pins;
2095}
2096
2097
2098const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
2099{
2100 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2101 {
2102 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
2103 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
2104
2105 if( pin_unit > 0 && pin_unit != GetUnit() )
2106 continue;
2107
2108 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
2109 continue;
2110
2111 if( pin->GetPosition() == aPos )
2112 return pin.get();
2113 }
2114
2115 return nullptr;
2116}
2117
2118
2119std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
2120{
2121 if( m_part )
2122 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
2123
2124 return std::vector<SCH_PIN*>();
2125}
2126
2127
2128std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
2129{
2130 if( m_part )
2131 return m_part->GetPins();
2132
2133 return std::vector<SCH_PIN*>();
2134}
2135
2136
2138{
2139 return m_part ? m_part->GetPinCount() : 0;
2140}
2141
2142
2144{
2145 auto it = m_pinMap.find( aLibPin );
2146
2147 if( it != m_pinMap.end() )
2148 return it->second;
2149
2150 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
2151 return nullptr;
2152}
2153
2154
2155std::vector<const SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
2156{
2157 std::vector<const SCH_PIN*> pins;
2158 int unit = m_unit;
2159
2160 if( !aSheet && Schematic() )
2161 aSheet = &Schematic()->CurrentSheet();
2162
2163 if( aSheet )
2164 unit = GetUnitSelection( aSheet );
2165
2166 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2167 {
2168 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
2169 continue;
2170
2171 pins.push_back( pin.get() );
2172 }
2173
2174 return pins;
2175}
2176
2177
2178std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet )
2179{
2180 std::vector<SCH_PIN*> pins;
2181 int unit = m_unit;
2182
2183 if( !aSheet && Schematic() )
2184 aSheet = &Schematic()->CurrentSheet();
2185
2186 if( aSheet )
2187 unit = GetUnitSelection( aSheet );
2188
2189 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
2190 {
2191 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
2192 continue;
2193
2194 pins.push_back( pin.get() );
2195 }
2196
2197 return pins;
2198}
2199
2200
2201std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
2202{
2203 // Back-compat shim: return graphical pins for all units/body styles, violating const
2204 return const_cast<SCH_SYMBOL*>( this )->GetPins( nullptr );
2205}
2206
2207
2209{
2210 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
2211
2212 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
2213
2214 std::swap( m_lib_id, symbol->m_lib_id );
2215
2216 m_pins.swap( symbol->m_pins ); // std::vector's swap()
2217
2218 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
2219 pin->SetParent( symbol );
2220
2221 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2222 pin->SetParent( this );
2223
2224 LIB_SYMBOL* libSymbol = symbol->m_part.release();
2225 symbol->m_part = std::move( m_part );
2226 symbol->UpdatePins();
2227 m_part.reset( libSymbol );
2228 UpdatePins();
2229
2230 std::swap( m_pos, symbol->m_pos );
2231
2232 m_fields.swap( symbol->m_fields ); // std::vector's swap()
2233
2234 for( SCH_FIELD& field : symbol->m_fields )
2235 field.SetParent( symbol );
2236
2237 for( SCH_FIELD& field : m_fields )
2238 field.SetParent( this );
2239
2240 TRANSFORM tmp = m_transform;
2241
2242 m_transform = symbol->m_transform;
2243 symbol->m_transform = tmp;
2244
2245 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
2246 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
2247 std::swap( m_DNP, symbol->m_DNP );
2248 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
2249 std::swap( m_excludedFromPosFiles, symbol->m_excludedFromPosFiles );
2250 std::swap( m_pinMapOverride, symbol->m_pinMapOverride );
2251
2252 std::swap( m_instances, symbol->m_instances );
2253 std::swap( m_instancePathIndex, symbol->m_instancePathIndex );
2254 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
2255
2256 m_variantSymbolCache.clear();
2257 symbol->m_variantSymbolCache.clear();
2258}
2259
2260
2261void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
2262{
2263 for( const SCH_FIELD& field : m_fields )
2264 {
2265 if( field.IsPrivate() )
2266 continue;
2267
2268 if( field.IsMandatory() )
2269 aVars->push_back( field.GetCanonicalName().Upper() );
2270 else
2271 aVars->push_back( field.GetName() );
2272 }
2273
2274 aVars->push_back( wxT( "OP" ) );
2275 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
2276 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
2277 aVars->push_back( wxT( "UNIT" ) );
2278 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
2279 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
2280 aVars->push_back( wxT( "SYMBOL_NAME" ) );
2281 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
2282 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
2283 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
2284 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
2285 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
2286 aVars->push_back( wxT( "DNP" ) );
2287 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
2288 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
2289 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
2290 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
2291 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
2292 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
2293 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
2294}
2295
2296
2297bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
2298{
2299 return ResolveTextVar( aPath, token, wxEmptyString, aDepth );
2300}
2301
2302
2303bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token,
2304 const wxString& aVariantName, int aDepth ) const
2305{
2306 // Per-thread regex. CONNECTION_GRAPH::resolveAllDrivers calls this from worker
2307 // threads, and wxRegEx::Matches is not safe to call concurrently on one instance.
2308 thread_local wxRegEx operatingPoint( wxT( "^"
2309 "OP"
2310 "(:[^.]*)?" // pin
2311 "(.([0-9])?" // precisionStr
2312 "([a-zA-Z]*))?" // rangeStr
2313 "$" ) );
2314
2315 if( !aPath )
2316 return false;
2317
2318 SCHEMATIC* schematic = Schematic();
2319
2320 if( !schematic )
2321 return false;
2322
2323 wxString variant = aVariantName.IsEmpty() ? schematic->GetCurrentVariant() : aVariantName;
2324
2325 if( operatingPoint.Matches( *token ) )
2326 {
2327 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
2328 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
2329 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
2330
2331 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
2332 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
2333
2334 SIM_LIB_MGR simLibMgr( &schematic->Project() );
2335
2336 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
2337 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
2338
2339 if( m_part )
2340 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
2341
2342 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
2343
2344 NULL_REPORTER devnull;
2345 SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1,
2346 aVariantName, devnull ).model;
2347 SPICE_ITEM spiceItem;
2348 spiceItem.refName = GetRef( aPath );
2349
2350 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
2351 spiceRef = spiceRef.Lower();
2352
2353 if( pin.IsEmpty() )
2354 {
2355 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2356 return true;
2357 }
2358 else if( pin == wxS( ":power" ) )
2359 {
2360 if( rangeStr.IsEmpty() )
2361 range = wxS( "~W" );
2362
2363 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
2364 return true;
2365 }
2366 else
2367 {
2368 pin = pin.SubString( 1, -1 ); // Strip ':' from front
2369
2370 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
2371 {
2372 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
2373
2374 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
2375 {
2376 if( model.GetPins().size() == 2 )
2377 {
2378 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2379 }
2380 else
2381 {
2382 wxString netChainName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
2383 *token = schematic->GetOperatingPoint( netChainName, precision, range );
2384 }
2385
2386 return true;
2387 }
2388 }
2389 }
2390
2391 *token = wxS( "?" );
2392 return true;
2393 }
2394
2395 if( token->Contains( ':' ) )
2396 {
2397 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
2398 return true;
2399 }
2400
2401 for( const SCH_FIELD& field : m_fields )
2402 {
2403 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName() : field.GetName();
2404
2405 wxString textToken = field.GetText();
2406 textToken.Replace( " ", wxEmptyString );
2407 wxString tokenString = "${" + fieldName + "}";
2408
2409 // If the field data is just a reference to the field, don't resolve
2410 if( textToken.IsSameAs( tokenString, false ) )
2411 return true;
2412
2413 if( token->IsSameAs( fieldName, false ) )
2414 {
2415 if( field.GetId() == FIELD_T::REFERENCE )
2416 {
2417 *token = GetRef( aPath, true );
2418 }
2419 else if( !aVariantName.IsEmpty() )
2420 {
2421 // Check for variant-specific field value
2422 std::optional<SCH_SYMBOL_VARIANT> symVariant = GetVariant( *aPath, aVariantName );
2423
2424 if( symVariant && symVariant->m_Fields.contains( fieldName ) )
2425 *token = symVariant->m_Fields.at( fieldName );
2426 else
2427 *token = field.GetShownText( aPath, false, aDepth + 1 );
2428 }
2429 else
2430 {
2431 *token = field.GetShownText( aPath, false, aDepth + 1 );
2432 }
2433
2434 return true;
2435 }
2436 }
2437
2438 // Consider missing simulation fields as empty, not un-resolved
2439 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
2440 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
2441 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
2442 {
2443 *token = wxEmptyString;
2444 return true;
2445 }
2446
2447 for( const TEMPLATE_FIELDNAME& templateFieldname :
2448 schematic->Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
2449 {
2450 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
2451 {
2452 // If we didn't find it in the fields list then it isn't set on this symbol.
2453 // Just return an empty string.
2454 *token = wxEmptyString;
2455 return true;
2456 }
2457 }
2458
2459 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
2460 {
2461 wxString footprint = GetFootprintFieldText( true, aPath, false );
2462
2463 wxArrayString parts = wxSplit( footprint, ':' );
2464
2465 if( parts.Count() > 0 )
2466 *token = parts[0];
2467 else
2468 *token = wxEmptyString;
2469
2470 return true;
2471 }
2472 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
2473 {
2474 wxString footprint = GetFootprintFieldText( true, aPath, false );
2475
2476 wxArrayString parts = wxSplit( footprint, ':' );
2477
2478 if( parts.Count() > 1 )
2479 *token = parts[std::min( 1, (int) parts.size() - 1 )];
2480 else
2481 *token = wxEmptyString;
2482
2483 return true;
2484 }
2485 else if( token->IsSameAs( wxT( "UNIT" ) ) )
2486 {
2487 *token = SubReference( GetUnitSelection( aPath ) );
2488 return true;
2489 }
2490 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
2491 {
2492 *token = GetRef( aPath, false );
2493 return true;
2494 }
2495 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
2496 {
2497 *token = m_lib_id.GetUniStringLibNickname();
2498 return true;
2499 }
2500 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
2501 {
2502 *token = m_lib_id.GetUniStringLibItemName();
2503 return true;
2504 }
2505 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
2506 {
2507 *token = GetShownDescription( aDepth + 1 );
2508 return true;
2509 }
2510 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
2511 {
2512 *token = GetShownKeyWords( aDepth + 1 );
2513 return true;
2514 }
2515 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
2516 {
2517 *token = wxEmptyString;
2518
2519 if( aPath->GetExcludedFromBOM( variant ) || this->ResolveExcludedFromBOM( aPath, variant ) )
2520 *token = _( "Excluded from BOM" );
2521
2522 return true;
2523 }
2524 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
2525 {
2526 *token = wxEmptyString;
2527
2528 if( aPath->GetExcludedFromBoard( variant ) || this->ResolveExcludedFromBoard( aPath, variant ) )
2529 *token = _( "Excluded from board" );
2530
2531 return true;
2532 }
2533 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
2534 {
2535 *token = wxEmptyString;
2536
2537 if( aPath->GetExcludedFromSim( variant ) || this->ResolveExcludedFromSim( aPath, variant ) )
2538 *token = _( "Excluded from simulation" );
2539
2540 return true;
2541 }
2542 else if( token->IsSameAs( wxT( "DNP" ) ) )
2543 {
2544 *token = wxEmptyString;
2545
2546 if( aPath->GetDNP( variant ) || this->ResolveDNP( aPath, variant ) )
2547 *token = _( "DNP" );
2548
2549 return true;
2550 }
2551 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
2552 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
2553 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
2554 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
2555 || token->StartsWith( wxT( "UNIT(" ) ) )
2556 {
2557 wxString pinNumber = token->AfterFirst( '(' );
2558 pinNumber = pinNumber.BeforeLast( ')' );
2559
2560 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
2561 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
2562 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
2563
2564 // First, try to find the pin in the current unit (for backward compatibility)
2565 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
2566 std::vector<const SCH_PIN*> pinsToSearch;
2567 std::vector<const SCH_PIN*> altPinsToSearch;
2568
2569 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2570 {
2571 for( SCH_PIN* pin : GetAllLibPins() )
2572 pinsToSearch.push_back( pin );
2573 }
2574 else
2575 {
2576 for( const SCH_PIN* pin : GetPins( aPath ) )
2577 pinsToSearch.push_back( pin );
2578
2579 for( SCH_PIN* pin : GetAllLibPins() )
2580 altPinsToSearch.push_back( pin );
2581 }
2582
2583 for( const SCH_PIN* pin : pinsToSearch )
2584 {
2585 if( pin->GetNumber() == pinNumber )
2586 {
2587 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2588 {
2589 int pinUnit = pin->GetUnit();
2590 wxString result;
2591
2592 if( isReferenceFunction )
2593 {
2594 // Return the full unit reference (e.g., "J601A")
2595 if( pinUnit > 0 )
2596 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
2597 else
2598 result = GetRef( aPath, false );
2599 }
2600 else if( isShortReferenceFunction )
2601 {
2602 // Return the reference without unit (e.g., "J601")
2603 result = GetRef( aPath, false );
2604 }
2605 else if( isUnitFunction )
2606 {
2607 // Return only the unit letter (e.g., "A")
2608 if( pinUnit > 0 )
2609 result = SubReference( pinUnit, false );
2610 else
2611 result = wxEmptyString;
2612 }
2613
2614 *token = std::move( result );
2615 return true;
2616 }
2617 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2618 {
2619 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
2620 return true;
2621 }
2622 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2623 {
2624 *token = pin->GetBaseName();
2625 return true;
2626 }
2627 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2628 {
2629 // Build list of alternate names only (no base name)
2630 wxString altList;
2631
2632 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2633
2634 for( const auto& [altName, altDef] : alts )
2635 {
2636 if( !altList.IsEmpty() )
2637 altList += wxT( ", " );
2638
2639 altList += altName;
2640 }
2641
2642 *token = std::move( altList );
2643 return true;
2644 }
2645
2646 SCH_CONNECTION* conn = pin->Connection( aPath );
2647
2648 if( !conn )
2649 {
2650 *token = wxEmptyString;
2651 }
2652 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2653 {
2654 wxString netName = conn->LocalName();
2655
2656 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2657 *token = wxT( "NC" );
2658 else
2659 *token = std::move( netName );
2660 }
2661 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2662 {
2663 *token = conn->Name();
2664 }
2665 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2666 {
2667 *token = pin->GetEffectiveNetClass( aPath )->GetName();
2668 }
2669
2670 return true;
2671 }
2672 }
2673
2674 // If pin not found in current unit, search all units (auto-resolution)
2675 for( const SCH_PIN* pin : altPinsToSearch )
2676 {
2677 if( pin->GetNumber() == pinNumber )
2678 {
2679 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
2680 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2681 {
2682 *token = pin->GetBaseName();
2683 return true;
2684 }
2685 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2686 {
2687 // Build list of alternate names only (no base name)
2688 wxString altList;
2689
2690 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2691
2692 for( const auto& [altName, altDef] : alts )
2693 {
2694 if( !altList.IsEmpty() )
2695 altList += wxT( ", " );
2696 altList += altName;
2697 }
2698
2699 *token = altList;
2700 return true;
2701 }
2702
2703 // For net-related functions, find which sheet path has this pin's unit
2704 int pinUnit = pin->GetUnit();
2705
2706 // Search all sheets for a symbol with our reference and the correct unit
2707 // This is needed because each unit of a multi-unit symbol is a separate object
2708 SCH_SHEET_PATH targetPath;
2709 SCH_SYMBOL* targetSymbol = nullptr;
2710
2711 if( Schematic() )
2712 {
2713 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
2714 {
2715 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2716 {
2717 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2718
2719 // Check if this symbol has the same reference designator and the correct unit
2720 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
2721 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
2722 {
2723 targetPath = sheetPath; // Copy the sheet path
2724 targetSymbol = symbol;
2725 break;
2726 }
2727 }
2728
2729 if( targetSymbol )
2730 break;
2731 }
2732 }
2733
2734 if( !targetSymbol )
2735 {
2736 // Unit not placed on any sheet
2737 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
2738 return true;
2739 }
2740
2741 // Get the pin from the actual instance symbol we found
2742 // Match by pin number, not by pointer, since the library pins are different objects
2743 SCH_PIN* instancePin = nullptr;
2744
2745 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
2746 {
2747 if( candidate->GetNumber() == pinNumber )
2748 {
2749 instancePin = candidate;
2750 break;
2751 }
2752 }
2753
2754 if( !instancePin )
2755 {
2756 *token = wxEmptyString;
2757 return true;
2758 }
2759
2760 // PIN_NAME doesn't need connection data, just instance pin
2761 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2762 {
2763 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
2764 return true;
2765 }
2766
2767 // Now get the connection from the correct sheet path
2768 SCH_CONNECTION* conn = instancePin->Connection( &targetPath );
2769
2770 if( !conn )
2771 {
2772 *token = wxEmptyString;
2773 }
2774 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2775 {
2776 wxString netName = conn->LocalName();
2777 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2778 *token = wxT( "NC" );
2779 else
2780 *token = netName;
2781 }
2782 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2783 {
2784 *token = conn->Name();
2785 }
2786 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2787 {
2788 *token = instancePin->GetEffectiveNetClass( &targetPath )->GetName();
2789 }
2790
2791 return true;
2792 }
2793 }
2794
2795 // If we got here, no pin was found - report unresolved
2796 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
2797 return true;
2798 }
2799
2800 // See if parent can resolve it (this will recurse to ancestors)
2801 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
2802 return true;
2803
2804 return false;
2805}
2806
2807
2808void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
2809{
2810 if( aSheetPath )
2811 {
2812 KIID_PATH path = aSheetPath->Path();
2813
2814 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2815 {
2816 if( instance.m_Path == path )
2817 {
2818 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2819 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2820 else
2821 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2822 }
2823 }
2824 }
2825 else
2826 {
2827 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2828 {
2829 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2830 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2831 else
2832 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2833 }
2834 }
2835
2836 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2837 pin->ClearDefaultNetName( aSheetPath );
2838
2839 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
2840 // When clearing for a specific sheet path, we must preserve the field text because it serves
2841 // as a fallback for GetRef() when instances for other sheet paths are looked up.
2842 // See issue #20173: modifying field text here corrupts references in shared screens.
2843 if( !aSheetPath )
2844 {
2845 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
2846
2847 if( currentReference.IsEmpty() || aResetPrefix )
2849 else
2851 }
2852}
2853
2854
2856{
2857 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
2858 wxCHECK( aSheetPath.size() > 0, false );
2859
2860 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
2861 {
2862 // if aSheetPath is found, nothing to do:
2863 if( instance.m_Path == aSheetPath )
2864 return false;
2865 }
2866
2867 // This entry does not exist: add it, with its last-used reference
2868 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
2869 return true;
2870}
2871
2872
2873void SCH_SYMBOL::SetOrientation( int aOrientation )
2874{
2875 TRANSFORM temp = TRANSFORM();
2876 bool transform = false;
2877
2878 switch( aOrientation )
2879 {
2880 case SYM_ORIENT_0:
2881 case SYM_NORMAL: // default transform matrix
2883 break;
2884
2885 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
2886 temp.x1 = 0;
2887 temp.y1 = 1;
2888 temp.x2 = -1;
2889 temp.y2 = 0;
2890 transform = true;
2891 break;
2892
2893 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
2894 temp.x1 = 0;
2895 temp.y1 = -1;
2896 temp.x2 = 1;
2897 temp.y2 = 0;
2898 transform = true;
2899 break;
2900
2901 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
2902 temp.x1 = -1;
2903 temp.y1 = 0;
2904 temp.x2 = 0;
2905 temp.y2 = 1;
2906 transform = true;
2907 break;
2908
2909 case SYM_MIRROR_X: // Mirror X (incremental transform)
2910 temp.x1 = 1;
2911 temp.y1 = 0;
2912 temp.x2 = 0;
2913 temp.y2 = -1;
2914 transform = true;
2915 break;
2916
2917 case SYM_ORIENT_90:
2920 break;
2921
2922 case SYM_ORIENT_180:
2926 break;
2927
2928 case SYM_ORIENT_270:
2931 break;
2932
2933 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
2936 break;
2937
2938 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
2941 break;
2942
2947 break;
2948
2949 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
2952 break;
2953
2954 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
2957 break;
2958
2963 break;
2964
2965 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
2968 break;
2969
2970 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
2973 break;
2974
2979 break;
2980
2981 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
2984 break;
2985
2986 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
2989 break;
2990
2995 break;
2996
2997 default:
2998 transform = false;
2999 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
3000 break;
3001 }
3002
3003 if( transform )
3004 {
3005 /* The new matrix transform is the old matrix transform modified by the
3006 * requested transformation, which is the temp transform (rot,
3007 * mirror ..) in order to have (in term of matrix transform):
3008 * transform coord = new_m_transform * coord
3009 * where transform coord is the coord modified by new_m_transform from
3010 * the initial value coord.
3011 * new_m_transform is computed (from old_m_transform and temp) to
3012 * have:
3013 * transform coord = old_m_transform * temp
3014 */
3015 TRANSFORM newTransform;
3016
3017 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
3018 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
3019 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
3020 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
3021 m_transform = newTransform;
3022 }
3023}
3024
3025
3027{
3028 /*
3029 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
3030 * now, so let's just cache it for the moment.
3031 */
3034
3035 int rotate_values[] = { SYM_ORIENT_0,
3047
3048 // Try to find the current transform option:
3049 TRANSFORM transform = m_transform;
3050 SCH_SYMBOL temp( *this );
3051 temp.SetParentGroup( nullptr );
3052
3053 for( int type_rotate : rotate_values )
3054 {
3055 temp.SetOrientation( type_rotate );
3056
3057 if( transform == temp.GetTransform() )
3058 {
3060 return type_rotate;
3061 }
3062 }
3063
3064 // Error: orientation not found in list (should not happen)
3065 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
3066
3067 return SYM_NORMAL;
3068}
3069
3070
3071#if defined( DEBUG )
3072
3073void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
3074{
3075 // for now, make it look like XML:
3076 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
3077 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
3078 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
3079 << ">\n";
3080
3081 // skip the reference, it's been output already.
3082 for( int i = 1; i < (int) GetFields().size(); ++i )
3083 {
3084 const wxString& value = GetFields()[i].GetText();
3085
3086 if( !value.IsEmpty() )
3087 {
3088 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
3089 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
3090 }
3091 }
3092
3093 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
3094}
3095
3096#endif
3097
3098
3099BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
3100{
3101 BOX2I bBox;
3102 const SCH_SHEET_PATH* sheetPath = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
3103 const LIB_SYMBOL* effSym = GetEffectiveLibSymbol( sheetPath );
3104
3105 if( effSym )
3106 bBox = effSym->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3107 else
3108 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
3109
3110 bBox = m_transform.TransformCoordinate( bBox );
3111 bBox.Normalize();
3112
3113 bBox.Offset( m_pos );
3114
3115 if( aIncludeFields )
3116 {
3117 for( const SCH_FIELD& field : m_fields )
3118 {
3119 if( field.IsVisible() )
3120 bBox.Merge( field.GetBoundingBox() );
3121 }
3122 }
3123
3124 return bBox;
3125}
3126
3127
3129{
3130 try
3131 {
3132 return doGetBoundingBox( false, false );
3133 }
3134 catch( const boost::bad_pointer& e )
3135 {
3136 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
3137 return BOX2I();
3138 }
3139}
3140
3141
3143{
3144 return doGetBoundingBox( true, false );
3145}
3146
3147
3149{
3150 return doGetBoundingBox( true, true );
3151}
3152
3153
3154void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
3155{
3156 wxString msg;
3157
3158 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
3159 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
3160 wxString currentVariant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
3161
3162 auto addExcludes = [&]()
3163 {
3164 wxArrayString msgs;
3165
3166 if( GetExcludedFromSim() )
3167 msgs.Add( _( "Simulation" ) );
3168
3169 if( GetExcludedFromBOM() )
3170 msgs.Add( _( "BOM" ) );
3171
3172 if( GetExcludedFromBoard() )
3173 msgs.Add( _( "Board" ) );
3174
3175 if( GetDNP( currentSheet, currentVariant ) )
3176 msgs.Add( _( "DNP" ) );
3177
3178 msg = wxJoin( msgs, '|' );
3179 msg.Replace( '|', wxS( ", " ) );
3180
3181 if( !msg.empty() )
3182 aList.emplace_back( _( "Exclude from" ), msg );
3183 };
3184
3185 // part and alias can differ if alias is not the root
3186 if( m_part )
3187 {
3188 if( m_part.get() != LIB_SYMBOL::GetDummy() )
3189 {
3190 if( m_part->IsPower() )
3191 {
3192 // Don't use GetShownText(); we want to see the variable references here
3193 aList.emplace_back( _( "Power symbol" ),
3194 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3195 }
3196 else
3197 {
3198 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
3199
3200 // Don't use GetShownText(); we want to see the variable references here
3201 aList.emplace_back( _( "Value" ),
3202 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3203 addExcludes();
3204 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3205 }
3206
3207#if 0 // Display symbol flags, for debug only
3208 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
3209#endif
3210
3211 if( !m_part->IsRoot() )
3212 {
3213 msg = _( "Missing parent" );
3214
3215 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
3216
3217 if( parent )
3218 msg = parent->GetName();
3219
3220 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
3221 }
3222 else if( !m_lib_id.GetLibNickname().empty() )
3223 {
3224 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
3225 }
3226 else
3227 {
3228 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
3229 }
3230
3231 // Display the current associated footprint, if exists.
3232 // Don't use GetShownText(); we want to see the variable references here
3233 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
3234
3235 if( msg.IsEmpty() )
3236 msg = _( "<Unknown>" );
3237
3238 aList.emplace_back( _( "Footprint" ), msg );
3239
3240 // Display description of the symbol, and keywords found in lib
3241 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
3242 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
3243 }
3244 }
3245 else
3246 {
3247 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
3248
3249 // Don't use GetShownText(); we want to see the variable references here
3250 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3251 addExcludes();
3252 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3253
3254 wxString libNickname = GetLibId().GetLibNickname();
3255
3256 if( libNickname.empty() )
3257 msg = _( "No library defined!" );
3258 else
3259 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
3260
3261 aList.emplace_back( _( "Library" ), msg );
3262 }
3263}
3264
3265
3270
3271
3273{
3274 std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
3275
3276 if( !libSymbolRef )
3277 return nullptr;
3278
3280}
3281
3282
3284{
3285 int dx = m_pos.x;
3286
3288 MIRROR( m_pos.x, aCenter );
3289 dx -= m_pos.x; // dx,0 is the move vector for this transform
3290
3291 for( SCH_FIELD& field : m_fields )
3292 {
3293 // Move the fields to the new position because the symbol itself has moved.
3294 VECTOR2I pos = field.GetTextPos();
3295 pos.x -= dx;
3296 field.SetTextPos( pos );
3297 }
3298}
3299
3300
3302{
3303 int dy = m_pos.y;
3304
3306 MIRROR( m_pos.y, aCenter );
3307 dy -= m_pos.y; // 0,dy is the move vector for this transform
3308
3309 for( SCH_FIELD& field : m_fields )
3310 {
3311 // Move the fields to the new position because the symbol itself has moved.
3312 VECTOR2I pos = field.GetTextPos();
3313 pos.y -= dy;
3314 field.SetTextPos( pos );
3315 }
3316}
3317
3318
3319void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
3320{
3321 VECTOR2I prev = m_pos;
3322
3323 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
3324
3326
3327 for( SCH_FIELD& field : m_fields )
3328 {
3329 // Move the fields to the new position because the symbol itself has moved.
3330 VECTOR2I pos = field.GetTextPos();
3331 pos.x -= prev.x - m_pos.x;
3332 pos.y -= prev.y - m_pos.y;
3333 field.SetTextPos( pos );
3334 }
3335}
3336
3337
3338bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
3339{
3340 if( aSearchData.searchMetadata )
3341 {
3342 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
3343 return true;
3344
3345 if( EDA_ITEM::Matches( GetShownDescription(), aSearchData ) )
3346 return true;
3347
3348 if( EDA_ITEM::Matches( GetShownKeyWords(), aSearchData ) )
3349 return true;
3350 }
3351
3352 // Fields are searched as separate items
3353
3354 // Search non-field lib draw items (pins, graphical text) for completeness.
3355 for( const SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
3356 {
3357 if( drawItem.Type() == SCH_FIELD_T )
3358 continue;
3359
3360 if( drawItem.Matches( aSearchData, aAuxData ) )
3361 return true;
3362 }
3363
3364 // Symbols are searchable via the child field and pin item text.
3365 return false;
3366}
3367
3368
3369void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
3370{
3371 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3372 {
3373 SCH_PIN* lib_pin = pin->GetLibPin();
3374
3375 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
3376 continue;
3377
3378 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
3379 aItemList.push_back( item );
3380 }
3381}
3382
3383
3384bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
3385 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
3386{
3387 bool changed = false;
3388
3389 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3390 {
3391 bool previousState = pin->IsDangling();
3392 pin->SetIsDangling( true );
3393
3394 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
3395
3396 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
3397 bool do_break = false;
3398
3399 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
3400 {
3401 DANGLING_END_ITEM& each_item = *it;
3402
3403 // Some people like to stack pins on top of each other in a symbol to indicate
3404 // internal connection. While technically connected, it is not particularly useful
3405 // to display them that way, so skip any pins that are in the same symbol as this
3406 // one.
3407 if( each_item.GetParent() == this )
3408 continue;
3409
3410 switch( each_item.GetType() )
3411 {
3412 case PIN_END:
3413 case LABEL_END:
3414 case SHEET_LABEL_END:
3415 case WIRE_END:
3416 case NO_CONNECT_END:
3417 case JUNCTION_END:
3418 pin->SetIsDangling( false );
3419 do_break = true;
3420 break;
3421
3422 default: break;
3423 }
3424
3425 if( do_break )
3426 break;
3427 }
3428
3429 changed = ( changed || ( previousState != pin->IsDangling() ) );
3430 }
3431
3432 return changed;
3433}
3434
3435
3437{
3438 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
3439 return VECTOR2I( 0, 0 );
3440
3441 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
3442}
3443
3444
3445bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
3446{
3447 // Do not compare to ourself.
3448 if( aItem == this )
3449 return false;
3450
3451 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
3452
3453 // Don't compare against a different SCH_ITEM.
3454 wxCHECK( symbol, false );
3455
3456 // The move algorithm marks any pins that are being moved without something attached
3457 // (during the move) as dangling. We always need to recheck connectivity in this case
3458 // or we will not notice changes when the user places the symbol back in the same position
3459 // it started.
3460 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3461 {
3462 if( pin->IsDangling() )
3463 return true;
3464 }
3465
3466 if( GetPosition() != symbol->GetPosition() )
3467 return true;
3468
3469 if( GetLibId() != symbol->GetLibId() )
3470 return true;
3471
3472 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
3473 return true;
3474
3475 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
3476 return true;
3477
3478 // Power symbol value field changes are connectivity changes.
3479 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
3480 return true;
3481
3482 if( m_pins.size() != symbol->m_pins.size() )
3483 return true;
3484
3485 for( size_t i = 0; i < m_pins.size(); i++ )
3486 {
3487 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
3488 return true;
3489 }
3490
3491 return false;
3492}
3493
3494
3495std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
3496{
3497 std::vector<VECTOR2I> retval;
3498
3499 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3500 {
3501 // Collect only pins attached to the current unit and convert.
3502 // others are not associated to this symbol instance
3503 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3504 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3505
3506 if( pin_unit > 0 && pin_unit != GetUnit() )
3507 continue;
3508
3509 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3510 continue;
3511
3512 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
3513 }
3514
3515 return retval;
3516}
3517
3518
3520{
3521 if( m_part )
3522 {
3523 // Calculate the position relative to the symbol.
3524 VECTOR2I libPosition = aPosition - m_pos;
3525
3526 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
3527 }
3528
3529 return nullptr;
3530}
3531
3532
3533wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
3534{
3535 return wxString::Format( _( "Symbol %s [%s]" ),
3537 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
3538}
3539
3540
3541INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
3542{
3543 for( KICAD_T scanType : aScanTypes )
3544 {
3545 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
3546 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3547 {
3548 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
3549 return INSPECT_RESULT::QUIT;
3550 }
3551
3552 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
3553 {
3554 for( SCH_FIELD& field : m_fields )
3555 {
3556 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
3557 return INSPECT_RESULT::QUIT;
3558 }
3559 }
3560
3561 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
3562 {
3563 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
3564 return INSPECT_RESULT::QUIT;
3565 }
3566
3567 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3568 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3569 {
3570 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3571 return INSPECT_RESULT::QUIT;
3572 }
3573
3574 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3575 {
3576 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3577 return INSPECT_RESULT::QUIT;
3578 }
3579
3580 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3581 {
3582 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3583 return INSPECT_RESULT::QUIT;
3584 }
3585
3586 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3587 {
3588 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3589 {
3590 // Collect only pins attached to the current unit and convert.
3591 // others are not associated to this symbol instance
3592 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3593 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3594
3595 if( pin_unit > 0 && pin_unit != GetUnit() )
3596 continue;
3597
3598 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3599 continue;
3600
3601 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3602 return INSPECT_RESULT::QUIT;
3603 }
3604 }
3605 }
3606
3608}
3609
3610
3611bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3612{
3613 if( Type() != aItem.Type() )
3614 return Type() < aItem.Type();
3615
3616 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3617
3619
3620 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3621 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3622
3623 if( m_pos.x != symbol->m_pos.x )
3624 return m_pos.x < symbol->m_pos.x;
3625
3626 if( m_pos.y != symbol->m_pos.y )
3627 return m_pos.y < symbol->m_pos.y;
3628
3629 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3630}
3631
3632
3633bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3634{
3635 std::vector<SCH_FIELD*> fields, otherFields;
3636
3637 GetFields( fields, false );
3638 aSymbol.GetFields( otherFields, false );
3639
3640 if( fields.size() != otherFields.size() )
3641 return false;
3642
3643 for( int ii = 0; ii < (int) fields.size(); ii++ )
3644 {
3645 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3646 continue;
3647
3648 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3649 return false;
3650 }
3651
3652 return true;
3653}
3654
3655
3656bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3657{
3658 return !( *this == aSymbol );
3659}
3660
3661
3663{
3664 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3665 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3666
3667 if( &aSymbol != this )
3668 {
3669 SYMBOL::operator=( aSymbol );
3670
3671 m_lib_id = aSymbol.m_lib_id;
3672 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3673 m_pos = aSymbol.m_pos;
3674 m_unit = aSymbol.m_unit;
3675 m_bodyStyle = aSymbol.m_bodyStyle;
3676 m_transform = aSymbol.m_transform;
3677
3678 m_instances = aSymbol.m_instances;
3680
3681 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3682
3683 // Reparent fields after assignment to new symbol.
3684 for( SCH_FIELD& field : m_fields )
3685 field.SetParent( this );
3686
3687 UpdatePins();
3688 m_variantSymbolCache.clear();
3689 }
3690
3691 return *this;
3692}
3693
3694
3695bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3696{
3697 BOX2I bBox = GetBodyBoundingBox();
3698 bBox.Inflate( aAccuracy / 2 );
3699
3700 if( bBox.Contains( aPosition ) )
3701 return true;
3702
3703 return false;
3704}
3705
3706
3707bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3708{
3710 return false;
3711
3712 BOX2I rect = aRect;
3713
3714 rect.Inflate( aAccuracy / 2 );
3715
3716 if( aContained )
3717 return rect.Contains( GetBodyBoundingBox() );
3718
3719 return rect.Intersects( GetBodyBoundingBox() );
3720}
3721
3722
3723bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3724{
3726 return false;
3727
3728 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3729}
3730
3731
3732bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3733{
3734 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3735
3736 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3737 {
3738 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3739 continue;
3740
3741 // Collect only pins attached to the current unit and convert.
3742 // others are not associated to this symbol instance
3743 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3744 continue;
3745
3746 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3747 continue;
3748
3749 if( pin->GetLocalPosition() == new_pos )
3750 return true;
3751 }
3752
3753 return false;
3754}
3755
3756
3758{
3759 return m_isInNetlist;
3760}
3761
3762
3763void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3764 const VECTOR2I& aOffset, bool aDimmed )
3765{
3766 if( aBackground )
3767 return;
3768
3769 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
3770 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
3771
3772 if( effectiveSym )
3773 {
3774 bool usingAlternate = ( effectiveSym != m_part.get() );
3775
3776 std::vector<const SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3777
3778 // Copy the source so we can re-orient and translate it.
3779 LIB_SYMBOL tempSymbol( *effectiveSym );
3780 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3781 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
3782
3783 // Copy the pin info from the symbol to the temp pins.
3784 for( unsigned i = 0; i < tempPins.size(); ++i )
3785 {
3786 SCH_PIN* symbolPin = symbolPins[i];
3787 SCH_PIN* tempPin = tempPins[i];
3788
3789 if( !symbolPin )
3790 continue;
3791
3792 tempPin->SetName( symbolPin->GetShownName() );
3793 tempPin->SetType( symbolPin->GetType() );
3794 tempPin->SetShape( symbolPin->GetShape() );
3795
3796 if( symbolPin->IsDangling() )
3797 tempPin->SetFlags( IS_DANGLING );
3798 }
3799
3800 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3801 {
3802 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3803 {
3804 // Use SCH_FIELD's text resolver
3805 SCH_FIELD dummy( this, FIELD_T::USER );
3806 dummy.SetText( text->GetText() );
3807 text->SetText( dummy.GetShownText( false ) );
3808 }
3809 }
3810
3811 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3812 TRANSFORM savedTransform = renderSettings->m_Transform;
3813 renderSettings->m_Transform = GetTransform();
3814 aPlotter->StartBlock( nullptr );
3815
3816 wxString variant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
3817 bool dnp = GetDNP( sheet, variant );
3818
3819 for( bool local_background : { true, false } )
3820 {
3821 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3822
3823 for( SCH_FIELD field : m_fields )
3824 {
3825 field.ClearRenderCache();
3826 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3827
3828 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3829 && ( field.IsVisible() || field.IsForceVisible() ) )
3830 {
3831 PlotLocalPowerIconShape( aPlotter );
3832 }
3833 }
3834 }
3835
3836 if( dnp )
3837 PlotDNP( aPlotter );
3838
3839 // Plot attributes to a hypertext menu
3840 if( aPlotOpts.m_PDFPropertyPopups )
3841 {
3842 std::vector<wxString> properties;
3843
3844 for( const SCH_FIELD& field : GetFields() )
3845 {
3846 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3847
3848 if( text_field.IsEmpty() )
3849 continue;
3850
3851 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3852 }
3853
3854 if( !effectiveSym->GetKeyWords().IsEmpty() )
3855 {
3856 properties.emplace_back(
3857 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ),
3858 effectiveSym->GetKeyWords() ) );
3859 }
3860
3861 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3862 }
3863
3864 aPlotter->EndBlock( nullptr );
3865 renderSettings->m_Transform = savedTransform;
3866
3867 if( !effectiveSym->IsPower() )
3868 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3869 }
3870}
3871
3872
3873void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3874{
3875 BOX2I bbox = GetBodyBoundingBox();
3877 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3878 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3879 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3880
3881 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3882 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3883 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3884
3885 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3886 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3887
3888 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3889
3890 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3891 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3892}
3893
3894
3898static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3899{
3900 double lineWidth = aSize / 10.0;
3901
3902 std::vector<SCH_SHAPE> shapeList;
3903 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3904 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3905
3906 for( const SCH_SHAPE& shape : shapeList )
3907 {
3908 // Currently there are only 2 shapes: BEZIER and CIRCLE
3909 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3910
3911 if( shape.GetShape() == SHAPE_T::BEZIER )
3912 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3913 tolerance, lineWidth );
3914 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3915 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3916 }
3917}
3918
3919
3921{
3922 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3923
3924 // Plot the local power pin indicator icon shape
3925 BOX2I bbox = field->GetBoundingBox();
3926
3927 // Calculate the text orientation according to the parent orientation.
3928 EDA_ANGLE orient = field->GetTextAngle();
3929
3930 if( GetTransform().y1 )
3931 {
3932 // Rotate symbol 90 degrees.
3933 if( orient.IsHorizontal() )
3934 orient = ANGLE_VERTICAL;
3935 else
3936 orient = ANGLE_HORIZONTAL;
3937 }
3938
3939 bool rotated = !orient.IsHorizontal();
3940
3941 VECTOR2D pos;
3942 double size = bbox.GetHeight() / 1.5;
3943
3944 if( rotated )
3945 {
3946 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3947 size = bbox.GetWidth() / 1.5;
3948 }
3949 else
3950 {
3951 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3952 }
3953
3954 // TODO: build and plot icon shape
3955 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3956}
3957
3958
3959void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter, bool aDnp ) const
3960{
3961 SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
3962 const LIB_SYMBOL* effectiveSym = GetEffectiveLibSymbol( sheet );
3963
3964 if( effectiveSym )
3965 {
3966 bool usingAlternate = ( effectiveSym != m_part.get() );
3967
3968 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3969 TRANSFORM savedTransform = renderSettings->m_Transform;
3970 renderSettings->m_Transform = GetTransform();
3971
3972 std::vector<const SCH_PIN*> libPins = effectiveSym->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3973
3974 // Copy the source to stay const
3975 LIB_SYMBOL tempSymbol( *effectiveSym );
3976 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3977 std::vector<SCH_PIN*> symbolPins = MapLibPins( libPins, usingAlternate );
3978 SCH_PLOT_OPTS plotOpts;
3979
3980 // Copy the pin info from the symbol to the temp pins.
3981 for( unsigned i = 0; i < tempPins.size(); ++i )
3982 {
3983 SCH_PIN* symbolPin = symbolPins[i];
3984 SCH_PIN* tempPin = tempPins[i];
3985
3986 if( !symbolPin )
3987 continue;
3988
3989 tempPin->SetName( symbolPin->GetShownName() );
3990 tempPin->SetType( symbolPin->GetType() );
3991 tempPin->SetShape( symbolPin->GetShape() );
3992 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, aDnp );
3993 }
3994
3995 renderSettings->m_Transform = savedTransform;
3996 }
3997}
3998
3999
4001{
4002 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4003 {
4004 if( pin->IsBrightened() )
4005 return true;
4006 }
4007
4008 return false;
4009}
4010
4011
4013{
4014 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
4015 pin->ClearBrightened();
4016}
4017
4018
4019/*
4020 * When modified at the schematic level, we still store the values of these flags in the
4021 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
4022 * will be created and stored locally in the schematic.
4023 */
4025{
4026 return m_part && m_part->GetShowPinNames();
4027}
4028
4029
4031{
4032 if( m_part )
4033 m_part->SetShowPinNames( aShow );
4034}
4035
4036
4038{
4039 return m_part && m_part->GetShowPinNumbers();
4040}
4041
4042
4044{
4045 if( m_part )
4046 m_part->SetShowPinNumbers( aShow );
4047}
4048
4049
4051{
4052 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
4053 {
4054 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
4055 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
4056
4057 if( pin_unit > 0 && pin_unit != GetUnit() )
4058 continue;
4059
4060 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
4061 continue;
4062
4063 if( pin->IsPointClickableAnchor( aPos ) )
4064 return true;
4065 }
4066
4067 return false;
4068}
4069
4070
4072{
4073 // return true if the symbol is equivalent to a global label:
4074 // It is a Power symbol
4075 // It has only one pin type Power input
4076
4078 return false;
4079
4080 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4081
4082 if( pin_list.size() != 1 )
4083 return false;
4084
4085 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4086}
4087
4088
4090{
4091 // return true if the symbol is equivalent to a local label:
4092 // It is a Power symbol
4093 // It has only one pin type Power input
4094
4096 return false;
4097
4098 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
4099
4100 if( pin_list.size() != 1 )
4101 return false;
4102
4103 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
4104}
4105
4106
4108{
4109 if( !m_part )
4110 return false;
4111
4112 return m_part->IsLocalPower();
4113}
4114
4115
4117{
4118 if( !m_part )
4119 return false;
4120
4121 return m_part->IsGlobalPower();
4122}
4123
4124
4126{
4127 return IsLocalPower() || IsGlobalPower();
4128}
4129
4130
4132{
4133 wxCHECK( m_part, false );
4134
4135 return m_part->IsNormal();
4136}
4137
4138
4139std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
4140{
4141 std::unordered_set<wxString> componentClass;
4142
4143 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
4144 {
4145 for( const SCH_FIELD& field : fields )
4146 {
4147 if( field.GetCanonicalName() == wxT( "Component Class" ) )
4148 {
4149 if( field.GetShownText( aPath, false ) != wxEmptyString )
4150 componentClass.insert( field.GetShownText( aPath, false ) );
4151 }
4152 }
4153 };
4154
4155 // First get component classes set on the symbol itself
4156 getComponentClassFields( m_fields );
4157
4158 // Now get component classes set on any enclosing rule areas
4159 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
4160 {
4161 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
4162 {
4163 getComponentClassFields( label->GetFields() );
4164 }
4165 }
4166
4167 return componentClass;
4168}
4169
4170
4171std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
4172 const wxString& aVariantName ) const
4173{
4174 SCH_SYMBOL_INSTANCE instance;
4175
4176 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
4177 return std::nullopt;
4178
4179 return instance.m_Variants.find( aVariantName )->second;
4180}
4181
4182
4183void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
4184{
4185 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
4186
4187 // The instance path must already exist.
4188 if( !instance )
4189 return;
4190
4191 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
4192}
4193
4194
4195LIB_SYMBOL* SCH_SYMBOL::GetVariantLibSymbol( const wxString& aVariantName,
4196 const SCH_SHEET_PATH& aPath ) const
4197{
4198 if( aVariantName.IsEmpty() )
4199 return nullptr;
4200
4201 const SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4202
4203 if( !instance || !instance->m_Variants.contains( aVariantName ) )
4204 return nullptr;
4205
4206 const SCH_SYMBOL_VARIANT& variant = instance->m_Variants.at( aVariantName );
4207
4208 if( !variant.m_SymbolOverride )
4209 return nullptr;
4210
4211 const LIB_ID& libId = *variant.m_SymbolOverride;
4212 wxString libIdStr = libId.Format();
4213
4214 // Cache by LIB_ID string so hierarchical instances sharing the same alternate symbol
4215 // reuse a single flattened copy regardless of sheet path or variant name. Failed
4216 // resolutions are cached as nullptr to keep unresolvable overrides from hitting the
4217 // library adapter on every paint.
4218 auto cacheIt = m_variantSymbolCache.find( libIdStr );
4219
4220 if( cacheIt != m_variantSymbolCache.end() )
4221 return cacheIt->second.get();
4222
4223 if( libId == m_lib_id )
4224 {
4225 m_variantSymbolCache[libIdStr] = nullptr;
4226 return nullptr;
4227 }
4228
4229 SCHEMATIC* schematic = Schematic();
4230
4231 if( !schematic )
4232 return nullptr;
4233
4234 SYMBOL_LIBRARY_ADAPTER* adapter = PROJECT_SCH::SymbolLibAdapter( &schematic->Project() );
4235
4236 if( !adapter )
4237 return nullptr;
4238
4239 try
4240 {
4241 if( LIB_SYMBOL* libSymbol = adapter->LoadSymbol( libId ) )
4242 {
4243 std::unique_ptr<LIB_SYMBOL>& cached = m_variantSymbolCache[libIdStr];
4244
4245 cached = libSymbol->Flatten();
4246
4247 if( m_part && !ValidateVariantSymbolCompatibility( *m_part, *cached ).empty() )
4248 {
4249 cached.reset();
4250 return nullptr;
4251 }
4252
4253 return cached.get();
4254 }
4255 }
4256 catch( const IO_ERROR& )
4257 {
4258 }
4259
4260 m_variantSymbolCache[libIdStr] = nullptr;
4261 return nullptr;
4262}
4263
4264
4266{
4267 if( aPath && Schematic() )
4268 {
4269 const wxString& variantName = Schematic()->GetCurrentVariant();
4270
4271 if( !variantName.IsEmpty() )
4272 {
4273 LIB_SYMBOL* altSymbol = GetVariantLibSymbol( variantName, *aPath );
4274
4275 if( altSymbol )
4276 return altSymbol;
4277 }
4278 }
4279
4280 return m_part.get();
4281}
4282
4283
4284std::vector<SCH_PIN*> SCH_SYMBOL::MapLibPins( const std::vector<const SCH_PIN*>& aLibPins,
4285 bool aByNumber ) const
4286{
4287 std::vector<SCH_PIN*> mapped;
4288
4289 mapped.reserve( aLibPins.size() );
4290
4291 if( aByNumber )
4292 {
4293 const LIB_SYMBOL* baseSymbol = m_part.get();
4294 std::vector<const SCH_PIN*> basePins = baseSymbol->GetGraphicalPins( GetUnit(), GetBodyStyle() );
4295 std::vector<bool> matched( basePins.size(), false );
4296
4297 for( const SCH_PIN* alternatePin : aLibPins )
4298 {
4299 SCH_PIN* instancePin = nullptr;
4300
4301 for( size_t i = 0; i < basePins.size(); ++i )
4302 {
4303 if( matched[i] || !VariantSymbolPinsMatch( *basePins[i], *alternatePin ) )
4304 continue;
4305
4306 matched[i] = true;
4307 instancePin = GetPin( const_cast<SCH_PIN*>( basePins[i] ) );
4308 break;
4309 }
4310
4311 mapped.push_back( instancePin );
4312 }
4313 }
4314 else
4315 {
4316 for( const SCH_PIN* libPin : aLibPins )
4317 mapped.push_back( GetPin( const_cast<SCH_PIN*>( libPin ) ) );
4318 }
4319
4320 return mapped;
4321}
4322
4323
4324void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
4325{
4326 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4327
4328 // The instance path must already exist.
4329 if( !instance || !instance->m_Variants.contains( aVariantName ) )
4330 return;
4331
4332 instance->m_Variants.erase( aVariantName );
4333}
4334
4335
4336void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
4337 const wxString& aNewName )
4338{
4339 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4340
4341 // The instance path must already exist and contain the old variant.
4342 if( !instance || !instance->m_Variants.contains( aOldName ) )
4343 return;
4344
4345 // Get the variant data, update the name, and re-insert with new key
4346 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
4347 variant.m_Name = aNewName;
4348 instance->m_Variants.erase( aOldName );
4349 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
4350}
4351
4352
4353void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
4354 const wxString& aNewVariant )
4355{
4356 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4357
4358 // The instance path must already exist and contain the source variant.
4359 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
4360 return;
4361
4362 // Copy the variant data with a new name
4363 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
4364 variant.m_Name = aNewVariant;
4365 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
4366}
4367
4368
4370 const wxString& aVariantName,
4371 const LIB_ID& aLibId )
4372{
4373 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4374
4375 if( !instance )
4376 return;
4377
4378 if( !instance->m_Variants.contains( aVariantName ) )
4379 {
4380 SCH_SYMBOL_VARIANT newVariant( aVariantName );
4381 newVariant.InitializeAttributes( *this );
4382 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
4383 }
4384
4385 instance->m_Variants[aVariantName].m_SymbolOverride = aLibId;
4386 m_variantSymbolCache.clear();
4387}
4388
4389
4391 const wxString& aVariantName )
4392{
4393 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
4394
4395 if( !instance || !instance->m_Variants.contains( aVariantName ) )
4396 return false;
4397
4398 SCH_SYMBOL_VARIANT& variant = instance->m_Variants[aVariantName];
4399
4400 if( !variant.m_SymbolOverride )
4401 return false;
4402
4403 variant.m_SymbolOverride.reset();
4404 m_variantSymbolCache.clear();
4405 return true;
4406}
4407
4408
4409bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
4410{
4411 if( Type() != aOther.Type() )
4412 return false;
4413
4414 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
4415
4416 if( GetLibId() != symbol.GetLibId() )
4417 return false;
4418
4419 if( GetPosition() != symbol.GetPosition() )
4420 return false;
4421
4422 if( GetUnit() != symbol.GetUnit() )
4423 return false;
4424
4425 if( GetBodyStyle() != symbol.GetBodyStyle() )
4426 return false;
4427
4428 if( GetTransform() != symbol.GetTransform() )
4429 return false;
4430
4431 if( GetFields() != symbol.GetFields() )
4432 return false;
4433
4434 if( m_pins.size() != symbol.m_pins.size() )
4435 return false;
4436
4437 if( m_excludedFromSim != symbol.m_excludedFromSim )
4438 return false;
4439
4440 if( m_excludedFromBOM != symbol.m_excludedFromBOM )
4441 return false;
4442
4443 if( m_DNP != symbol.m_DNP )
4444 return false;
4445
4447 return false;
4448
4450 return false;
4451
4453 return false;
4454
4455 for( unsigned i = 0; i < m_pins.size(); ++i )
4456 {
4457 if( *m_pins[i] != *symbol.m_pins[i] )
4458 return false;
4459 }
4460
4461#if 0
4462 // This has historically been a compare of the current instance, rather than a compare
4463 // of all instances. Probably better to keep it that way for now.
4464 if( m_instanceReferences != symbol.m_instanceReferences )
4465 return false;
4466#endif
4467
4468 return true;
4469}
4470
4471
4472double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
4473{
4474 if( Type() != aOther.Type() )
4475 return 0.0;
4476
4477 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
4478
4479 if( GetLibId() != symbol.GetLibId() )
4480 return 0.0;
4481
4482 if( GetPosition() == symbol.GetPosition() )
4483 return 1.0;
4484
4485 return 0.0;
4486}
4487
4488
4489void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
4490 double aLineWidth, bool aHorizontal )
4491{
4492 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
4493
4494 double x_right = aSize / 1.6180339887;
4495 double x_middle = x_right / 2.0;
4496
4497 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
4498 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
4499 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
4500
4501 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
4502 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
4503 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
4504 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
4505 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
4506
4507 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4508 aShapeList.back().SetStart( bottomPt );
4509 aShapeList.back().SetBezierC1( bottomAnchorPt );
4510 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
4511 aShapeList.back().SetEnd( leftPt );
4512
4513
4514 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4515 aShapeList.back().SetStart( leftPt );
4516 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
4517 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
4518 aShapeList.back().SetEnd( rightPt );
4519
4520 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4521 aShapeList.back().SetStart( rightPt );
4522 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
4523 aShapeList.back().SetBezierC2( bottomAnchorPt );
4524 aShapeList.back().SetEnd( bottomPt );
4525
4526 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
4527 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
4528 aShapeList.back().SetRadius( aSize / 15.0 );
4529
4530 for( SCH_SHAPE& shape : aShapeList )
4531 {
4532 if( aHorizontal )
4533 shape.Rotate( VECTOR2I( 0, 0 ), true );
4534
4535 shape.Move( aPos );
4536 }
4537}
4538
4539
4541{
4542 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
4543 return &m_instances[it->second];
4544
4545 return nullptr;
4546}
4547
4548
4550{
4551 if( auto it = m_instancePathIndex.find( aSheetPath ); it != m_instancePathIndex.end() )
4552 return &m_instances[it->second];
4553
4554 return nullptr;
4555}
4556
4557
4558static struct SCH_SYMBOL_DESC
4559{
4561 {
4563 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
4564 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
4565 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
4566 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
4567
4573
4580
4587
4588 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
4589 {
4590 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4591 return symbol->GetLibSymbolRef() != nullptr;
4592
4593 return false;
4594 };
4595
4596 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
4598 .SetAvailableFunc( hasLibPart );
4599
4600 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
4602 .SetAvailableFunc( hasLibPart );
4603
4604 const wxString groupFields = _HKI( "Fields" );
4605
4608 groupFields );
4611 groupFields );
4612 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
4613 NO_SETTER( SCH_SYMBOL, wxString ),
4615 groupFields );
4616 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
4617 NO_SETTER( SCH_SYMBOL, wxString ),
4619 groupFields );
4620 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
4622 groupFields );
4623
4624 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
4625 {
4626 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4627 return symbol->IsMultiUnit();
4628
4629 return false;
4630 };
4631
4632 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
4633 {
4634 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4635 return symbol->IsMultiBodyStyle();
4636
4637 return false;
4638 };
4639
4642 .SetAvailableFunc( multiUnit )
4644 []( INSPECTABLE* aItem )
4645 {
4646 wxPGChoices choices;
4647
4648 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4649 {
4650 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
4651 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
4652 }
4653
4654 return choices;
4655 } );
4656
4659 .SetAvailableFunc( multiBodyStyle )
4661 []( INSPECTABLE* aItem )
4662 {
4663 wxPGChoices choices;
4664
4665 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4666 {
4667 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
4668 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
4669 }
4670
4671 return choices;
4672 } );
4673
4674 const wxString groupAttributes = _HKI( "Attributes" );
4675
4676 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
4679 groupAttributes );
4680 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
4683 groupAttributes );
4684 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
4687 groupAttributes );
4688 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
4691 groupAttributes );
4692 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
4695 groupAttributes );
4696 }
4698
4699
const char * name
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:47
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
BITMAPS
A list of all bitmap identifiers.
@ add_component
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr const Vec GetEnd() const
Definition box2.h:208
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:142
constexpr coord_type GetY() const
Definition box2.h:204
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr coord_type GetX() const
Definition box2.h:203
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:757
constexpr size_type GetHeight() const
Definition box2.h:211
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:164
constexpr const Vec & GetOrigin() const
Definition box2.h:206
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:255
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:307
constexpr coord_type GetBottom() const
Definition box2.h:218
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:102
static std::vector< DANGLING_END_ITEM >::iterator get_lower_pos(std::vector< DANGLING_END_ITEM > &aItemListByPos, const VECTOR2I &aPos)
Definition sch_item.cpp:959
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition sch_item.h:93
DANGLING_END_T GetType() const
Definition sch_item.h:129
const EDA_ITEM * GetParent() const
Definition sch_item.h:128
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:158
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:152
const KIID m_Uuid
Definition eda_item.h:531
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:542
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:416
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:113
bool IsSelected() const
Definition eda_item.h:132
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:543
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:37
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
virtual void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:595
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
static ENUM_MAP< T > & Instance()
Definition property.h:721
A text control validator used for validating the text allowed in fields.
Definition validators.h:138
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:38
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxString AsString() const
Definition kiid.cpp:423
Definition kiid.h:46
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
UTF8 Format() const
Definition lib_id.cpp:132
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
wxString GetKeyWords() const override
Definition lib_symbol.h:210
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 IsPower() const override
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
Definition lib_symbol.h:230
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.
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
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:809
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
void SetKeyWords(const wxString &aKeyWords)
void SetBodyStyleCount(int aCount, bool aDuplicateDrawItems, bool aDuplicatePins)
Set or clear the alternate body style (DeMorgan) for the symbol.
void SetFPFilters(const wxArrayString &aFilters)
Definition lib_symbol.h:240
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.
void SetLibId(const LIB_ID &aLibId)
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
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:354
A singleton reporter that reports to nowhere.
Definition reporter.h:250
Base plotter engine class.
Definition plotter.h:133
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:525
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:228
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition plotter.h:587
virtual void ThickSegment(const VECTOR2I &start, const VECTOR2I &end, int width, void *aData)
Definition plotter.cpp:536
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition plotter.h:514
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:596
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
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:90
wxString GetCurrentVariant() const
Return the current variant being edited.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:189
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:128
FIELD_T GetId() const
Definition sch_field.h:132
void ImportValues(const SCH_FIELD &aSource)
Copy parameters from a SCH_FIELD source.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
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
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:241
void SetLocked(bool aLocked) override
Definition sch_item.h:251
int m_unit
Definition sch_item.h:776
int m_bodyStyle
Definition sch_item.h:777
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:724
void SetPrivate(bool aPrivate)
Definition sch_item.h:247
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:268
int GetBodyStyle() const
Definition sch_item.h:242
bool IsLocked() const override
Definition sch_item.cpp:148
friend class LIB_SYMBOL
Definition sch_item.h:797
int GetUnit() const
Definition sch_item.h:233
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition sch_item.cpp:523
virtual void ClearCaches()
Definition sch_item.cpp:676
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:339
virtual void SetUnit(int aUnit)
Definition sch_item.h:232
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:779
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:792
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:52
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:487
SCH_LAYER_ID m_layer
Definition sch_item.h:775
ALT GetAlt(const wxString &aAlt)
Definition sch_pin.h:217
void SetName(const wxString &aName)
Definition sch_pin.cpp:517
const wxString & GetName() const
Definition sch_pin.cpp:499
bool IsDangling() const override
Definition sch_pin.cpp:560
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:1572
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition sch_pin.h:102
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:350
const wxString & GetShownName() const
Definition sch_pin.cpp:676
void SetType(ELECTRICAL_PINTYPE aType)
Definition sch_pin.cpp:427
const wxString & GetNumber() const
Definition sch_pin.h:130
GRAPHIC_PINSHAPE GetShape() const
Definition sch_pin.cpp:372
ELECTRICAL_PINTYPE GetType() const
Definition sch_pin.cpp:407
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.
PIN_MAP_INSTANCE_OVERRIDE m_PinMapOverride
Per-instance pin-to-pad map override for this variant (issue #2282).
std::optional< LIB_ID > m_SymbolOverride
Alternate library symbol to substitute for the base symbol in this variant, if any.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
Schematic symbol object.
Definition sch_symbol.h:69
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:516
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:315
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:160
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:445
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:533
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
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
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 SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:915
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.
wxString m_signalName
bool ClearVariantSymbolOverride(const SCH_SHEET_PATH &aPath, const wxString &aVariantName)
Remove the alternate-symbol override for a given variant and sheet instance.
SYMBOL_ORIENTATION_PROP GetOrientationProp() const
Definition sch_symbol.h:298
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_variantSymbolCache
int GetY() const
Definition sch_symbol.h:920
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:108
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:332
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:538
void SetVariantSymbolOverride(const SCH_SHEET_PATH &aPath, const wxString &aVariantName, const LIB_ID &aLibId)
Set the alternate-symbol override for a given variant and sheet instance.
int GetX() const
Definition sch_symbol.h:917
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:794
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:769
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
void ClearCaches() override
wxString GetShownKeyWords(int aDepth=0) const override
PASSTHROUGH_MODE m_passthroughMode
bool IsInNetlist() const
std::optional< SCH_SYMBOL_VARIANT > GetVariant(const SCH_SHEET_PATH &aInstance, const wxString &aVariantName) const
PIN_MAP_INSTANCE_OVERRIDE GetPinMapOverride(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
bool GetExcludedFromBoardProp() const
Definition sch_symbol.h:779
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:921
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:764
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:327
wxString GetRefProp() const
Definition sch_symbol.h:502
void SetPinMapOverride(const PIN_MAP_INSTANCE_OVERRIDE &aOverride, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
Set the per-instance pin-to-pad map override (issue #2282).
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:754
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.
SCH_PIN * GetPinByEffectivePadNumber(const wxString &aPadNumber, const SCH_SHEET_PATH *aSheet, const wxString &aVariantName=wxEmptyString) const
Find the pin whose effective footprint pad number (issue #2282) is aPadNumber on aSheet,...
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:289
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:721
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.
std::unordered_map< KIID_PATH, size_t > m_instancePathIndex
Index from an instance's sheet path to its position in m_instances for O(1) lookups.
std::vector< SCH_PIN * > MapLibPins(const std::vector< const SCH_PIN * > &aLibPins, bool aByNumber) const
Map pins of an effective library symbol to this symbol's instance pins.
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:914
PIN_MAP_INSTANCE_OVERRIDE resolveDelegatedPinMapOverride(const SCH_SHEET_PATH &aSheet, const wxString &aVariantName) const
Return unit 1's pin-map override for a unit that delegates to it (issue #2282).
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 rebuildInstancePathIndex()
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:799
wxString GetShownDescription(int aDepth=0) const override
const LIB_SYMBOL * GetEffectiveLibSymbol(const SCH_SHEET_PATH *aPath=nullptr) const
Return the library symbol to use for rendering and bounding box calculations.
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:158
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.
LIB_SYMBOL * GetVariantLibSymbol(const wxString &aVariantName, const SCH_SHEET_PATH &aPath) const
Resolve the alternate library symbol for a given variant.
void SetValueProp(const wxString &aValue)
void SetUnitProp(int aUnit)
Definition sch_symbol.h:527
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
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:344
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetDNPProp(bool aEnable)
Definition sch_symbol.h:723
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:918
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.
PIN_MAP_INSTANCE_OVERRIDE m_pinMapOverride
Base (no-variant) pin-to-pad map override applied when no variant override exists for the sheet path ...
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:509
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:232
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:749
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:784
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:177
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:44
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:59
bool m_DNP
True if symbol is set to 'Do Not Populate'.
Definition symbol.h:274
bool m_excludedFromPosFiles
Definition symbol.h:273
SYMBOL(KICAD_T idType)
Definition symbol.h:61
bool m_excludedFromSim
Definition symbol.h:270
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:170
const TRANSFORM & GetTransform() const
Definition symbol.h:243
int GetPinNameOffset() const
Definition symbol.h:159
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:164
bool m_excludedFromBOM
Definition symbol.h:271
bool m_excludedFromBoard
Definition symbol.h:272
virtual bool GetShowPinNames() const
Definition symbol.h:165
void SetPinNameOffset(int aOffset)
Set the offset in mils of the pin name text from the pin symbol.
Definition symbol.h:158
SYMBOL & operator=(const SYMBOL &aItem)
Definition symbol.h:89
virtual bool GetShowPinNumbers() const
Definition symbol.h:171
TRANSFORM m_transform
The rotation/mirror transformation.
Definition symbol.h:263
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
TRANSFORM InverseTransform() const
Calculate the Inverse mirror/rotation transform.
Definition transform.cpp:55
VECTOR2I TransformCoordinate(const VECTOR2I &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition transform.cpp:40
wxString wx_str() const
Definition utf8.cpp:41
wxString m_Name
bool m_ExcludedFromBOM
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
bool m_ExcludedFromSim
bool m_ExcludedFromBoard
A type-safe container of any type.
Definition ki_any.h:92
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
static bool empty(const wxTextEntryBase *aCtrl)
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:48
INSPECT_RESULT
Definition eda_item.h:42
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:89
#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:59
@ NO_FILL
Definition eda_shape.h:60
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
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:455
@ LAYER_DEVICE
Definition layer_ids.h:472
@ LAYER_VALUEPART
Definition layer_ids.h:467
@ LAYER_FIELDS
Definition layer_ids.h:468
@ LAYER_REFERENCEPART
Definition layer_ids.h:466
@ LAYER_DNP_MARKER
Definition layer_ids.h:484
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
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.
KICOMMON_API int UnpackDistance(const types::Distance &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API std::optional< KICAD_T > TypeNameFromAny(const google::protobuf::Any &aMessage)
Definition api_utils.cpp:35
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackDistance(types::Distance &aOutput, int aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackLibId(types::LibraryIdentifier *aOutput, const LIB_ID &aId)
KICOMMON_API LIB_ID UnpackLibId(const types::LibraryIdentifier &aId)
#define _HKI(x)
Definition page_info.cpp:40
see class PGM_BASE
@ PT_NC
not connected (must be left open)
Definition pin_type.h:46
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
#define TYPE_HASH(x)
Definition property.h:74
#define NO_SETTER(owner, type)
Definition property.h:833
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition property.h:828
@ 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:383
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:372
@ NO_CONNECT_END
Definition sch_item.h:84
@ SHEET_LABEL_END
Definition sch_item.h:83
@ LABEL_END
Definition sch_item.h:80
@ JUNCTION_END
Definition sch_item.h:78
@ PIN_END
Definition sch_item.h:79
@ WIRE_END
Definition sch_item.h:76
@ BASE
Definition sch_item.h:56
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
std::vector< wxString > ExpandStackedPinNotation(const wxString &aPinName, bool *aValid)
Expand stacked pin notation like [1,2,3], [1-4], [A1-A4], or [AA1-AA3,AB4,CD12-CD14] into individual ...
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:85
Per-instance override of the active pin map and a sparse delta on top.
Definition pin_map.h:199
bool IsDefault() const
Definition pin_map.h:209
bool IsDelegate() const
Definition pin_map.h:218
bool m_PDFPropertyPopups
Definition sch_plotter.h:61
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:47
@ SYMBOL_ANGLE_180
Definition symbol.h:50
@ SYMBOL_ANGLE_0
Definition symbol.h:48
@ SYMBOL_ANGLE_90
Definition symbol.h:49
@ SYMBOL_ANGLE_270
Definition symbol.h:51
@ SYM_ORIENT_270
Definition symbol.h:38
@ SYM_ROTATE_CLOCKWISE
Definition symbol.h:33
@ SYM_ROTATE_COUNTERCLOCKWISE
Definition symbol.h:34
@ SYM_MIRROR_Y
Definition symbol.h:40
@ SYM_ORIENT_180
Definition symbol.h:37
@ SYM_MIRROR_X
Definition symbol.h:39
@ SYM_NORMAL
Definition symbol.h:32
@ SYM_ORIENT_90
Definition symbol.h:36
@ SYM_ORIENT_0
Definition symbol.h:35
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)
nlohmann::json_schema::json_validator validator
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:225
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:71
@ SCH_FIELD_LOCATE_REFERENCE_T
Definition typeinfo.h:177
@ SCH_FIELD_LOCATE_FOOTPRINT_T
Definition typeinfo.h:179
@ SCH_SYMBOL_T
Definition typeinfo.h:169
@ SCH_FIELD_T
Definition typeinfo.h:147
@ SCH_LOCATE_ANY_T
Definition typeinfo.h:196
@ SCH_FIELD_LOCATE_VALUE_T
Definition typeinfo.h:178
@ SCH_FIELD_LOCATE_DATASHEET_T
Definition typeinfo.h:180
@ SCH_SYMBOL_LOCATE_POWER_T
Definition typeinfo.h:193
@ SCH_PIN_T
Definition typeinfo.h:150
Custom text control validator definitions.
std::vector< VARIANT_COMPAT_RESULT > ValidateVariantSymbolCompatibility(const LIB_SYMBOL &aBase, const LIB_SYMBOL &aCandidate)
Check whether aCandidate can be used as a variant symbol override for aBase.
bool VariantSymbolPinsMatch(const SCH_PIN &aBase, const SCH_PIN &aCandidate)
Check whether two graphical pins occupy the same variant-symbol connection slot.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682