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