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