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 // A custom unit display name overrides the default A/B/C (or numeric) suffix.
1135 if( m_part )
1136 {
1137 const std::map<int, wxString>& names = m_part->GetUnitDisplayNames();
1138 auto it = names.find( aUnit );
1139
1140 if( it != names.end() && !it->second.IsEmpty() )
1141 {
1142 wxString subRef;
1143
1144 if( SCHEMATIC* schematic = Schematic() )
1145 {
1146 int sep = schematic->Settings().m_SubpartIdSeparator;
1147
1148 if( sep != 0 && aAddSeparator )
1149 subRef << wxChar( sep );
1150 }
1151
1152 subRef << it->second;
1153 return subRef;
1154 }
1155 }
1156
1157 if( SCHEMATIC* schematic = Schematic() )
1158 return schematic->Settings().SubReference( aUnit, aAddSeparator );
1159
1160 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
1161}
1162
1163
1165{
1166 KIID_PATH path = aSheet->Path();
1167
1168 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
1169 {
1170 if( instance.m_Path == path )
1171 return instance.m_Unit;
1172 }
1173
1174 // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
1175 // version 1 schematic file.
1176 return m_unit;
1177}
1178
1179
1180void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
1181{
1182 KIID_PATH path = aSheet->Path();
1183
1184 // check to see if it is already there before inserting it
1185 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
1186 {
1187 if( instance.m_Path == path )
1188 {
1189 instance.m_Unit = aUnitSelection;
1190 return;
1191 }
1192 }
1193
1194 // didn't find it; better add it
1196}
1197
1198
1199void SCH_SYMBOL::SetDNP( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1200{
1201 if( !aInstance || aVariantName.IsEmpty() )
1202 {
1203 m_DNP = aEnable;
1204 return;
1205 }
1206
1207 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1208
1209 wxCHECK_MSG( instance, /* void */,
1210 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1211 aInstance->PathHumanReadable() ) );
1212
1213 if( aVariantName.IsEmpty() )
1214 {
1215 m_DNP = aEnable;
1216 }
1217 else
1218 {
1219 if( instance->m_Variants.contains( aVariantName ) && ( aEnable != instance->m_Variants[aVariantName].m_DNP ) )
1220 {
1221 instance->m_Variants[aVariantName].m_DNP = aEnable;
1222 }
1223 else
1224 {
1225 SCH_SYMBOL_VARIANT variant( aVariantName );
1226
1227 variant.InitializeAttributes( *this );
1228 variant.m_DNP = aEnable;
1229 AddVariant( *aInstance, variant );
1230 }
1231 }
1232}
1233
1234
1235bool SCH_SYMBOL::GetDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1236{
1237 if( !aInstance || aVariantName.IsEmpty() )
1238 return m_DNP;
1239
1240 SCH_SYMBOL_INSTANCE instance;
1241
1242 if( !GetInstance( instance, aInstance->Path() ) )
1243 return m_DNP;
1244
1245 if( instance.m_Variants.contains( aVariantName ) )
1246 return instance.m_Variants[aVariantName].m_DNP;
1247
1248 return m_DNP;
1249}
1250
1251
1252void SCH_SYMBOL::SetExcludedFromBOM( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1253{
1254 if( !aInstance || aVariantName.IsEmpty() )
1255 {
1256 m_excludedFromBOM = aEnable;
1257 return;
1258 }
1259
1260 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1261
1262 wxCHECK_MSG( instance, /* void */,
1263 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1264 aInstance->PathHumanReadable() ) );
1265
1266 if( aVariantName.IsEmpty() )
1267 {
1268 m_excludedFromBOM = aEnable;
1269 }
1270 else
1271 {
1272 if( instance->m_Variants.contains( aVariantName )
1273 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBOM ) )
1274 {
1275 instance->m_Variants[aVariantName].m_ExcludedFromBOM = aEnable;
1276 }
1277 else
1278 {
1279 SCH_SYMBOL_VARIANT variant( aVariantName );
1280
1281 variant.InitializeAttributes( *this );
1282 variant.m_ExcludedFromBOM = aEnable;
1283 AddVariant( *aInstance, variant );
1284 }
1285 }
1286}
1287
1288
1289bool SCH_SYMBOL::GetExcludedFromBOM( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1290{
1291 if( !aInstance || aVariantName.IsEmpty() )
1292 return m_excludedFromBOM;
1293
1294 SCH_SYMBOL_INSTANCE instance;
1295
1296 if( !GetInstance( instance, aInstance->Path() ) )
1297 return m_excludedFromBOM;
1298
1299 if( instance.m_Variants.contains( aVariantName ) )
1300 return instance.m_Variants[aVariantName].m_ExcludedFromBOM;
1301
1302 // If the variant has not been defined yet, return the default exclude from BOM setting.
1303 return m_excludedFromBOM;
1304}
1305
1306
1307void SCH_SYMBOL::SetExcludedFromSim( bool aEnable, const SCH_SHEET_PATH* aInstance, const wxString& aVariantName )
1308{
1309 if( !aInstance || aVariantName.IsEmpty() )
1310 {
1311 m_excludedFromSim = aEnable;
1312 return;
1313 }
1314
1315 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1316
1317 wxCHECK_MSG( instance, /* void */,
1318 wxString::Format( wxS( "Cannot get DNP attribute for invalid sheet path '%s'." ),
1319 aInstance->PathHumanReadable() ) );
1320
1321 if( aVariantName.IsEmpty() )
1322 {
1323 m_excludedFromSim = aEnable;
1324 }
1325 else
1326 {
1327 if( instance->m_Variants.contains( aVariantName )
1328 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromSim ) )
1329 {
1330 instance->m_Variants[aVariantName].m_ExcludedFromSim = aEnable;
1331 }
1332 else
1333 {
1334 SCH_SYMBOL_VARIANT variant( aVariantName );
1335
1336 variant.InitializeAttributes( *this );
1337 variant.m_ExcludedFromSim = aEnable;
1338 AddVariant( *aInstance, variant );
1339 }
1340 }
1341}
1342
1343
1344bool SCH_SYMBOL::GetExcludedFromSim( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
1345{
1346 if( !aInstance || aVariantName.IsEmpty() )
1347 return m_excludedFromSim;
1348
1349 SCH_SYMBOL_INSTANCE instance;
1350
1351 if( !GetInstance( instance, aInstance->Path() ) )
1352 return m_excludedFromSim;
1353
1354 if( instance.m_Variants.contains( aVariantName ) )
1355 return instance.m_Variants[aVariantName].m_ExcludedFromSim;
1356
1357 // If variant is not defined yet, return default exclude from simulation setting.
1358 return m_excludedFromSim;
1359}
1360
1361
1362void SCH_SYMBOL::SetExcludedFromBoard( bool aEnable, const SCH_SHEET_PATH* aInstance,
1363 const wxString& aVariantName )
1364{
1365 if( !aInstance || aVariantName.IsEmpty() )
1366 {
1367 m_excludedFromBoard = aEnable;
1368 return;
1369 }
1370
1371 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1372
1373 wxCHECK_MSG( instance, /* void */,
1374 wxString::Format( wxS( "Cannot set exclude from board for invalid sheet path '%s'." ),
1375 aInstance->PathHumanReadable() ) );
1376
1377 if( aVariantName.IsEmpty() )
1378 {
1379 m_excludedFromBoard = aEnable;
1380 }
1381 else
1382 {
1383 if( instance->m_Variants.contains( aVariantName )
1384 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromBoard ) )
1385 {
1386 instance->m_Variants[aVariantName].m_ExcludedFromBoard = aEnable;
1387 }
1388 else
1389 {
1390 SCH_SYMBOL_VARIANT variant( aVariantName );
1391
1392 variant.InitializeAttributes( *this );
1393 variant.m_ExcludedFromBoard = aEnable;
1394 AddVariant( *aInstance, variant );
1395 }
1396 }
1397}
1398
1399
1401 const wxString& aVariantName ) const
1402{
1403 if( !aInstance || aVariantName.IsEmpty() )
1404 return m_excludedFromBoard;
1405
1406 SCH_SYMBOL_INSTANCE instance;
1407
1408 if( !GetInstance( instance, aInstance->Path() ) )
1409 return m_excludedFromBoard;
1410
1411 if( instance.m_Variants.contains( aVariantName ) )
1412 return instance.m_Variants[aVariantName].m_ExcludedFromBoard;
1413
1414 // If variant is not defined yet, return default exclude from board setting.
1415 return m_excludedFromBoard;
1416}
1417
1418
1419void SCH_SYMBOL::SetExcludedFromPosFiles( bool aEnable, const SCH_SHEET_PATH* aInstance,
1420 const wxString& aVariantName )
1421{
1422 if( !aInstance || aVariantName.IsEmpty() )
1423 {
1424 m_excludedFromPosFiles = aEnable;
1425 return;
1426 }
1427
1428 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1429
1430 wxCHECK_MSG( instance, /* void */,
1431 wxString::Format( wxS( "Cannot set exclude from pos files for invalid sheet path '%s'." ),
1432 aInstance->PathHumanReadable() ) );
1433
1434 if( aVariantName.IsEmpty() )
1435 {
1436 m_excludedFromPosFiles = aEnable;
1437 }
1438 else
1439 {
1440 if( instance->m_Variants.contains( aVariantName )
1441 && ( aEnable != instance->m_Variants[aVariantName].m_ExcludedFromPosFiles ) )
1442 {
1443 instance->m_Variants[aVariantName].m_ExcludedFromPosFiles = aEnable;
1444 }
1445 else
1446 {
1447 SCH_SYMBOL_VARIANT variant( aVariantName );
1448
1449 variant.InitializeAttributes( *this );
1450 variant.m_ExcludedFromPosFiles = aEnable;
1451 AddVariant( *aInstance, variant );
1452 }
1453 }
1454}
1455
1456
1458 const wxString& aVariantName ) const
1459{
1460 if( !aInstance || aVariantName.IsEmpty() )
1462
1463 SCH_SYMBOL_INSTANCE instance;
1464
1465 if( !GetInstance( instance, aInstance->Path() ) )
1467
1468 if( instance.m_Variants.contains( aVariantName ) )
1469 return instance.m_Variants[aVariantName].m_ExcludedFromPosFiles;
1470
1471 // If variant is not defined yet, return default exclude from position files setting.
1473}
1474
1475
1476void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
1477{
1478 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
1479 instance.m_Unit = aUnitSelection;
1480}
1481
1482
1483const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aInstance,
1484 bool aAllowExtraText, const wxString& aVariantName ) const
1485{
1486 if( aVariantName.IsEmpty() )
1487 {
1488 if( aResolve )
1489 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1490
1491 return GetField( FIELD_T::VALUE )->GetText();
1492 }
1493
1494 std::optional variant = GetVariant( *aInstance, aVariantName );
1495
1496 if( variant && variant->m_Fields.contains( GetField( FIELD_T::VALUE )->GetName() ) )
1497 return variant->m_Fields[GetField( FIELD_T::VALUE )->GetName()];
1498
1499 // Fall back to default value when variant doesn't have an override
1500 if( aResolve )
1501 return GetField( FIELD_T::VALUE )->GetShownText( aInstance, aAllowExtraText );
1502
1503 return GetField( FIELD_T::VALUE )->GetText();
1504}
1505
1506
1507void SCH_SYMBOL::SetValueFieldText( const wxString& aValue, const SCH_SHEET_PATH* aInstance,
1508 const wxString& aVariantName )
1509{
1510 if( !aInstance || aVariantName.IsEmpty() )
1511 {
1512 GetField( FIELD_T::VALUE )->SetText( aValue );
1513 return;
1514 }
1515
1516 SCH_SYMBOL_INSTANCE* instance = getInstance( *aInstance );
1517
1518 wxCHECK( instance, /* void */ );
1519
1520 wxString fieldName = GetField( FIELD_T::VALUE )->GetName();
1521
1522 if( instance->m_Variants.contains( aVariantName ) )
1523 {
1524 instance->m_Variants[aVariantName].m_Fields[fieldName] = aValue;
1525 }
1526 else
1527 {
1528 SCH_SYMBOL_VARIANT newVariant( aVariantName );
1529
1530 newVariant.InitializeAttributes( *this );
1531 newVariant.m_Fields[fieldName] = aValue;
1532 instance->m_Variants.insert( std::make_pair( aVariantName, newVariant ) );
1533 }
1534}
1535
1536
1537const wxString SCH_SYMBOL::GetFootprintFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
1538 bool aAllowExtraText, const wxString& aVariantName ) const
1539{
1540 if( aResolve )
1541 return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText, 0, aVariantName );
1542
1543 return GetField( FIELD_T::FOOTPRINT )->GetText();
1544}
1545
1546
1547void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
1548{
1549 GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
1550}
1551
1552
1554{
1555 if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
1556 return field;
1557
1558 m_fields.emplace_back( this, aFieldType );
1559 return &m_fields.back();
1560}
1561
1562
1563const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
1564{
1565 return FindField( m_fields, aFieldType );
1566}
1567
1568
1569SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
1570{
1571 return FindField( m_fields, aFieldName );
1572}
1573
1574
1575const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
1576{
1577 return FindField( m_fields, aFieldName );
1578}
1579
1580
1581void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
1582{
1583 for( const SCH_FIELD& field : m_fields )
1584 {
1585 if( aVisibleOnly )
1586 {
1587 if( !field.IsVisible() || field.GetText().IsEmpty() )
1588 continue;
1589 }
1590
1591 aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
1592 }
1593
1594 std::sort( aVector.begin(), aVector.end(),
1595 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1596 {
1597 return lhs->GetOrdinal() < rhs->GetOrdinal();
1598 } );
1599}
1600
1601
1603{
1604 return NextFieldOrdinal( m_fields );
1605}
1606
1607
1609{
1610 m_fields.push_back( aField );
1611 return &m_fields.back();
1612}
1613
1614
1615void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
1616{
1617 for( unsigned ii = 0; ii < m_fields.size(); ++ii )
1618 {
1619 if( m_fields[ii].IsMandatory() )
1620 continue;
1621
1622 if( aFieldName == m_fields[ii].GetName( false ) )
1623 {
1624 m_fields.erase( m_fields.begin() + ii );
1625 return;
1626 }
1627 }
1628}
1629
1630
1632{
1633 for( SCH_FIELD& field : m_fields )
1634 {
1635 if( field.GetName().IsSameAs( aFieldName, false ) )
1636 return &field;
1637 }
1638
1639 return nullptr;
1640}
1641
1642
1643const SCH_FIELD* SCH_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
1644{
1645 for( const SCH_FIELD& field : m_fields )
1646 {
1647 if( field.GetName().IsSameAs( aFieldName, false ) )
1648 return &field;
1649 }
1650
1651 return nullptr;
1652}
1653
1654
1655void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef, bool aUpdateOtherFields,
1656 bool aResetRef, bool aResetOtherFields )
1657{
1658 if( m_part )
1659 {
1660 std::vector<SCH_FIELD*> fields;
1661 m_part->GetFields( fields );
1662
1663 for( const SCH_FIELD* libField : fields )
1664 {
1665 SCH_FIELD* schField;
1666 FIELD_T fieldType = FIELD_T::USER;
1667
1668 if( libField->IsMandatory() )
1669 {
1670 fieldType = libField->GetId();
1671 schField = GetField( fieldType );
1672 }
1673 else
1674 {
1675 schField = GetField( libField->GetCanonicalName() );
1676
1677 if( !schField )
1678 {
1679 schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetCanonicalName() ) );
1680 schField->ImportValues( *libField );
1681 schField->SetTextPos( m_pos + libField->GetTextPos() );
1682 }
1683 }
1684
1685 schField->SetPrivate( libField->IsPrivate() );
1686
1687 if( aUpdateStyle )
1688 {
1689 schField->ImportValues( *libField );
1690 schField->SetTextPos( m_pos + libField->GetTextPos() );
1691 }
1692
1693 if( fieldType == FIELD_T::REFERENCE && aPath )
1694 {
1695 if( aResetRef )
1696 SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
1697 else if( aUpdateRef )
1698 SetRef( aPath, libField->GetText() );
1699 }
1700 else if( fieldType == FIELD_T::VALUE )
1701 {
1702 SetValueFieldText( UnescapeString( libField->GetText() ) );
1703 }
1704 else if( fieldType == FIELD_T::DATASHEET )
1705 {
1706 if( aResetOtherFields )
1707 schField->SetText( GetDatasheet() ); // alias-specific value
1708 else if( aUpdateOtherFields )
1709 schField->SetText( libField->GetText() );
1710 }
1711 else
1712 {
1713 if( aResetOtherFields || aUpdateOtherFields )
1714 schField->SetText( libField->GetText() );
1715 }
1716 }
1717 }
1718}
1719
1720
1721void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit,
1722 PROPERTY_BASE* aProperty, const wxString& aVariantName )
1723{
1724 bool updateValue = true;
1725 bool updateExclFromBOM = true;
1726 bool updateExclFromBoard = true;
1727 bool updateExclFromPosFiles = true;
1728 bool updateDNP = true;
1729 bool updateOtherFields = true;
1730 bool updatePins = true;
1731
1732 if( aProperty )
1733 {
1734 updateValue = aProperty->Name() == _HKI( "Value" );
1735 updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
1736 updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
1737 updateExclFromPosFiles = aProperty->Name() == _HKI( "Exclude From Position Files" );
1738 updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
1739 updateOtherFields = false;
1740 updatePins = false;
1741 }
1742
1743 if( !updateValue && !updateExclFromBOM && !updateExclFromBoard && !updateExclFromPosFiles && !updateDNP && !updateOtherFields && !updatePins )
1744 {
1745 return;
1746 }
1747
1748 // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
1749 // in sync in multi-unit parts.
1750 if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
1751 {
1752 wxString ref = GetRef( &aSourceSheet );
1753
1754 for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
1755 {
1756 SCH_SCREEN* screen = sheet.LastScreen();
1757 std::vector<SCH_SYMBOL*> otherUnits;
1758
1759 CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
1760
1761 for( SCH_SYMBOL* otherUnit : otherUnits )
1762 {
1763 aCommit.Modify( otherUnit, screen );
1764
1765 if( updateValue )
1766 otherUnit->SetValueFieldText( GetField( FIELD_T::VALUE )->GetText() );
1767
1768 if( updateOtherFields )
1769 {
1770 for( SCH_FIELD& field : m_fields )
1771 {
1772 if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
1773 {
1774 // already handled
1775 continue;
1776 }
1777
1778 SCH_FIELD* otherField;
1779
1780 if( field.IsMandatory() )
1781 otherField = otherUnit->GetField( field.GetId() );
1782 else
1783 otherField = otherUnit->GetField( field.GetName() );
1784
1785 if( otherField )
1786 {
1787 otherField->SetText( field.GetText() );
1788 }
1789 else
1790 {
1791 SCH_FIELD newField( field );
1792 const_cast<KIID&>( newField.m_Uuid ) = KIID();
1793
1794 newField.Offset( -GetPosition() );
1795 newField.Offset( otherUnit->GetPosition() );
1796
1797 newField.SetParent( otherUnit );
1798 otherUnit->AddField( newField );
1799 }
1800 }
1801
1802 for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
1803 {
1804 SCH_FIELD& otherField = otherUnit->GetFields()[ii];
1805
1806 if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
1807 otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
1808 }
1809 }
1810
1811 if( updateExclFromBOM )
1812 otherUnit->SetExcludedFromBOM( m_excludedFromBOM );
1813
1814 if( updateExclFromBoard )
1815 otherUnit->SetExcludedFromBoard( m_excludedFromBoard );
1816
1817 if( updateExclFromPosFiles )
1818 otherUnit->SetExcludedFromPosFiles( m_excludedFromPosFiles );
1819
1820 if( updateDNP )
1821 otherUnit->SetDNP( GetDNP( &aSourceSheet, aVariantName ), &sheet, aVariantName );
1822
1823 if( updatePins )
1824 {
1825 for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
1826 {
1827 for( SCH_PIN* src_pin : otherUnit->GetPinsByNumber( model_pin->GetNumber() ) )
1828 src_pin->SetAlt( model_pin->GetAlt() );
1829 }
1830 }
1831 }
1832 }
1833 }
1834}
1835
1836
1837void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
1838{
1839 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1840 aFunction( pin.get() );
1841
1842 for( SCH_FIELD& field : m_fields )
1843 aFunction( &field );
1844}
1845
1846
1847SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
1848{
1849 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1850 {
1851 if( pin->GetNumber() == aNumber )
1852 return pin.get();
1853 }
1854
1855 return nullptr;
1856}
1857
1858
1859std::vector<SCH_PIN*> SCH_SYMBOL::GetPinsByNumber( const wxString& aNumber ) const
1860{
1861 std::vector<SCH_PIN*> pins;
1862
1863 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1864 {
1865 if( pin->GetNumber() == aNumber )
1866 pins.push_back( pin.get() );
1867 }
1868
1869 return pins;
1870}
1871
1872
1873const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
1874{
1875 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1876 {
1877 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
1878 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
1879
1880 if( pin_unit > 0 && pin_unit != GetUnit() )
1881 continue;
1882
1883 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
1884 continue;
1885
1886 if( pin->GetPosition() == aPos )
1887 return pin.get();
1888 }
1889
1890 return nullptr;
1891}
1892
1893
1894std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
1895{
1896 if( m_part )
1897 return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
1898
1899 return std::vector<SCH_PIN*>();
1900}
1901
1902
1903std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
1904{
1905 if( m_part )
1906 return m_part->GetPins();
1907
1908 return std::vector<SCH_PIN*>();
1909}
1910
1911
1913{
1914 return m_part ? m_part->GetPinCount() : 0;
1915}
1916
1917
1919{
1920 auto it = m_pinMap.find( aLibPin );
1921
1922 if( it != m_pinMap.end() )
1923 return it->second;
1924
1925 wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
1926 return nullptr;
1927}
1928
1929
1930std::vector<const SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
1931{
1932 std::vector<const 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 SCH_SHEET_PATH* aSheet )
1954{
1955 std::vector<SCH_PIN*> pins;
1956 int unit = m_unit;
1957
1958 if( !aSheet && Schematic() )
1959 aSheet = &Schematic()->CurrentSheet();
1960
1961 if( aSheet )
1962 unit = GetUnitSelection( aSheet );
1963
1964 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1965 {
1966 if( unit && pin->GetUnit() && pin->GetUnit() != unit )
1967 continue;
1968
1969 pins.push_back( pin.get() );
1970 }
1971
1972 return pins;
1973}
1974
1975
1976std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
1977{
1978 // Back-compat shim: return graphical pins for all units/body styles, violating const
1979 return const_cast<SCH_SYMBOL*>( this )->GetPins( nullptr );
1980}
1981
1982
1984{
1985 wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T, wxT( "Cannot swap data with invalid symbol." ) );
1986
1987 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
1988
1989 std::swap( m_lib_id, symbol->m_lib_id );
1990
1991 m_pins.swap( symbol->m_pins ); // std::vector's swap()
1992
1993 for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
1994 pin->SetParent( symbol );
1995
1996 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1997 pin->SetParent( this );
1998
1999 LIB_SYMBOL* libSymbol = symbol->m_part.release();
2000 symbol->m_part = std::move( m_part );
2001 symbol->UpdatePins();
2002 m_part.reset( libSymbol );
2003 UpdatePins();
2004
2005 std::swap( m_pos, symbol->m_pos );
2006
2007 m_fields.swap( symbol->m_fields ); // std::vector's swap()
2008
2009 for( SCH_FIELD& field : symbol->m_fields )
2010 field.SetParent( symbol );
2011
2012 for( SCH_FIELD& field : m_fields )
2013 field.SetParent( this );
2014
2015 TRANSFORM tmp = m_transform;
2016
2017 m_transform = symbol->m_transform;
2018 symbol->m_transform = tmp;
2019
2020 std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
2021 std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
2022 std::swap( m_DNP, symbol->m_DNP );
2023 std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
2024 std::swap( m_excludedFromPosFiles, symbol->m_excludedFromPosFiles );
2025
2026 std::swap( m_instances, symbol->m_instances );
2027 std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
2028}
2029
2030
2031void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
2032{
2033 for( const SCH_FIELD& field : m_fields )
2034 {
2035 if( field.IsPrivate() )
2036 continue;
2037
2038 if( field.IsMandatory() )
2039 aVars->push_back( field.GetCanonicalName().Upper() );
2040 else
2041 aVars->push_back( field.GetName() );
2042 }
2043
2044 aVars->push_back( wxT( "OP" ) );
2045 aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
2046 aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
2047 aVars->push_back( wxT( "UNIT" ) );
2048 aVars->push_back( wxT( "SHORT_REFERENCE" ) );
2049 aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
2050 aVars->push_back( wxT( "SYMBOL_NAME" ) );
2051 aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
2052 aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
2053 aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
2054 aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
2055 aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
2056 aVars->push_back( wxT( "DNP" ) );
2057 aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
2058 aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
2059 aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
2060 aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
2061 aVars->push_back( wxT( "REFERENCE(<pin_number>)" ) );
2062 aVars->push_back( wxT( "SHORT_REFERENCE(<pin_number>)" ) );
2063 aVars->push_back( wxT( "UNIT(<pin_number>)" ) );
2064}
2065
2066
2067bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
2068{
2069 return ResolveTextVar( aPath, token, wxEmptyString, aDepth );
2070}
2071
2072
2073bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token,
2074 const wxString& aVariantName, int aDepth ) const
2075{
2076 // Per-thread regex. CONNECTION_GRAPH::resolveAllDrivers calls this from worker
2077 // threads, and wxRegEx::Matches is not safe to call concurrently on one instance.
2078 thread_local wxRegEx operatingPoint( wxT( "^"
2079 "OP"
2080 "(:[^.]*)?" // pin
2081 "(.([0-9])?" // precisionStr
2082 "([a-zA-Z]*))?" // rangeStr
2083 "$" ) );
2084
2085 if( !aPath )
2086 return false;
2087
2088 SCHEMATIC* schematic = Schematic();
2089
2090 if( !schematic )
2091 return false;
2092
2093 wxString variant = aVariantName.IsEmpty() ? schematic->GetCurrentVariant() : aVariantName;
2094
2095 if( operatingPoint.Matches( *token ) )
2096 {
2097 wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
2098 wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
2099 wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
2100
2101 int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
2102 wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
2103
2104 SIM_LIB_MGR simLibMgr( &schematic->Project() );
2105
2106 std::vector<EMBEDDED_FILES*> embeddedFilesStack;
2107 embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
2108
2109 if( m_part )
2110 embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
2111
2112 simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
2113
2114 NULL_REPORTER devnull;
2115 SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ), true, aDepth + 1,
2116 aVariantName, devnull ).model;
2117 SPICE_ITEM spiceItem;
2118 spiceItem.refName = GetRef( aPath );
2119
2120 wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
2121 spiceRef = spiceRef.Lower();
2122
2123 if( pin.IsEmpty() )
2124 {
2125 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2126 return true;
2127 }
2128 else if( pin == wxS( ":power" ) )
2129 {
2130 if( rangeStr.IsEmpty() )
2131 range = wxS( "~W" );
2132
2133 *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
2134 return true;
2135 }
2136 else
2137 {
2138 pin = pin.SubString( 1, -1 ); // Strip ':' from front
2139
2140 for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
2141 {
2142 SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
2143
2144 if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
2145 {
2146 if( model.GetPins().size() == 2 )
2147 {
2148 *token = schematic->GetOperatingPoint( spiceRef, precision, range );
2149 }
2150 else
2151 {
2152 wxString netChainName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
2153 *token = schematic->GetOperatingPoint( netChainName, precision, range );
2154 }
2155
2156 return true;
2157 }
2158 }
2159 }
2160
2161 *token = wxS( "?" );
2162 return true;
2163 }
2164
2165 if( token->Contains( ':' ) )
2166 {
2167 if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
2168 return true;
2169 }
2170
2171 for( const SCH_FIELD& field : m_fields )
2172 {
2173 wxString fieldName = field.IsMandatory() ? field.GetCanonicalName() : field.GetName();
2174
2175 wxString textToken = field.GetText();
2176 textToken.Replace( " ", wxEmptyString );
2177 wxString tokenString = "${" + fieldName + "}";
2178
2179 // If the field data is just a reference to the field, don't resolve
2180 if( textToken.IsSameAs( tokenString, false ) )
2181 return true;
2182
2183 if( token->IsSameAs( fieldName, false ) )
2184 {
2185 if( field.GetId() == FIELD_T::REFERENCE )
2186 {
2187 *token = GetRef( aPath, true );
2188 }
2189 else if( !aVariantName.IsEmpty() )
2190 {
2191 // Check for variant-specific field value
2192 std::optional<SCH_SYMBOL_VARIANT> symVariant = GetVariant( *aPath, aVariantName );
2193
2194 if( symVariant && symVariant->m_Fields.contains( fieldName ) )
2195 *token = symVariant->m_Fields.at( fieldName );
2196 else
2197 *token = field.GetShownText( aPath, false, aDepth + 1 );
2198 }
2199 else
2200 {
2201 *token = field.GetShownText( aPath, false, aDepth + 1 );
2202 }
2203
2204 return true;
2205 }
2206 }
2207
2208 // Consider missing simulation fields as empty, not un-resolved
2209 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
2210 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
2211 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
2212 {
2213 *token = wxEmptyString;
2214 return true;
2215 }
2216
2217 for( const TEMPLATE_FIELDNAME& templateFieldname :
2218 schematic->Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
2219 {
2220 if( token->IsSameAs( templateFieldname.m_Name ) || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
2221 {
2222 // If we didn't find it in the fields list then it isn't set on this symbol.
2223 // Just return an empty string.
2224 *token = wxEmptyString;
2225 return true;
2226 }
2227 }
2228
2229 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
2230 {
2231 wxString footprint = GetFootprintFieldText( true, aPath, false );
2232
2233 wxArrayString parts = wxSplit( footprint, ':' );
2234
2235 if( parts.Count() > 0 )
2236 *token = parts[0];
2237 else
2238 *token = wxEmptyString;
2239
2240 return true;
2241 }
2242 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
2243 {
2244 wxString footprint = GetFootprintFieldText( true, aPath, false );
2245
2246 wxArrayString parts = wxSplit( footprint, ':' );
2247
2248 if( parts.Count() > 1 )
2249 *token = parts[std::min( 1, (int) parts.size() - 1 )];
2250 else
2251 *token = wxEmptyString;
2252
2253 return true;
2254 }
2255 else if( token->IsSameAs( wxT( "UNIT" ) ) )
2256 {
2257 *token = SubReference( GetUnitSelection( aPath ) );
2258 return true;
2259 }
2260 else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
2261 {
2262 *token = GetRef( aPath, false );
2263 return true;
2264 }
2265 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
2266 {
2267 *token = m_lib_id.GetUniStringLibNickname();
2268 return true;
2269 }
2270 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
2271 {
2272 *token = m_lib_id.GetUniStringLibItemName();
2273 return true;
2274 }
2275 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
2276 {
2277 *token = GetShownDescription( aDepth + 1 );
2278 return true;
2279 }
2280 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
2281 {
2282 *token = GetShownKeyWords( aDepth + 1 );
2283 return true;
2284 }
2285 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
2286 {
2287 *token = wxEmptyString;
2288
2289 if( aPath->GetExcludedFromBOM( variant ) || this->ResolveExcludedFromBOM( aPath, variant ) )
2290 *token = _( "Excluded from BOM" );
2291
2292 return true;
2293 }
2294 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
2295 {
2296 *token = wxEmptyString;
2297
2298 if( aPath->GetExcludedFromBoard( variant ) || this->ResolveExcludedFromBoard( aPath, variant ) )
2299 *token = _( "Excluded from board" );
2300
2301 return true;
2302 }
2303 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
2304 {
2305 *token = wxEmptyString;
2306
2307 if( aPath->GetExcludedFromSim( variant ) || this->ResolveExcludedFromSim( aPath, variant ) )
2308 *token = _( "Excluded from simulation" );
2309
2310 return true;
2311 }
2312 else if( token->IsSameAs( wxT( "DNP" ) ) )
2313 {
2314 *token = wxEmptyString;
2315
2316 if( aPath->GetDNP( variant ) || this->ResolveDNP( aPath, variant ) )
2317 *token = _( "DNP" );
2318
2319 return true;
2320 }
2321 else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) ) || token->StartsWith( wxT( "NET_NAME(" ) )
2322 || token->StartsWith( wxT( "NET_CLASS(" ) ) || token->StartsWith( wxT( "PIN_NAME(" ) )
2323 || token->StartsWith( wxT( "PIN_BASE_NAME(" ) ) || token->StartsWith( wxT( "PIN_ALT_LIST(" ) )
2324 || token->StartsWith( wxT( "REFERENCE(" ) ) || token->StartsWith( wxT( "SHORT_REFERENCE(" ) )
2325 || token->StartsWith( wxT( "UNIT(" ) ) )
2326 {
2327 wxString pinNumber = token->AfterFirst( '(' );
2328 pinNumber = pinNumber.BeforeLast( ')' );
2329
2330 bool isReferenceFunction = token->StartsWith( wxT( "REFERENCE(" ) );
2331 bool isShortReferenceFunction = token->StartsWith( wxT( "SHORT_REFERENCE(" ) );
2332 bool isUnitFunction = token->StartsWith( wxT( "UNIT(" ) );
2333
2334 // First, try to find the pin in the current unit (for backward compatibility)
2335 // For REFERENCE/SHORT_REFERENCE/UNIT functions, always search all pins to find which unit the pin belongs to
2336 std::vector<const SCH_PIN*> pinsToSearch;
2337 std::vector<const SCH_PIN*> altPinsToSearch;
2338
2339 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2340 {
2341 for( SCH_PIN* pin : GetAllLibPins() )
2342 pinsToSearch.push_back( pin );
2343 }
2344 else
2345 {
2346 for( const SCH_PIN* pin : GetPins( aPath ) )
2347 pinsToSearch.push_back( pin );
2348
2349 for( SCH_PIN* pin : GetAllLibPins() )
2350 altPinsToSearch.push_back( pin );
2351 }
2352
2353 for( const SCH_PIN* pin : pinsToSearch )
2354 {
2355 if( pin->GetNumber() == pinNumber )
2356 {
2357 if( isReferenceFunction || isShortReferenceFunction || isUnitFunction )
2358 {
2359 int pinUnit = pin->GetUnit();
2360 wxString result;
2361
2362 if( isReferenceFunction )
2363 {
2364 // Return the full unit reference (e.g., "J601A")
2365 if( pinUnit > 0 )
2366 result = GetRef( aPath, false ) + SubReference( pinUnit, false );
2367 else
2368 result = GetRef( aPath, false );
2369 }
2370 else if( isShortReferenceFunction )
2371 {
2372 // Return the reference without unit (e.g., "J601")
2373 result = GetRef( aPath, false );
2374 }
2375 else if( isUnitFunction )
2376 {
2377 // Return only the unit letter (e.g., "A")
2378 if( pinUnit > 0 )
2379 result = SubReference( pinUnit, false );
2380 else
2381 result = wxEmptyString;
2382 }
2383
2384 *token = result;
2385 return true;
2386 }
2387 else if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2388 {
2389 *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
2390 return true;
2391 }
2392 else if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2393 {
2394 *token = pin->GetBaseName();
2395 return true;
2396 }
2397 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2398 {
2399 // Build list of alternate names only (no base name)
2400 wxString altList;
2401
2402 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2403
2404 for( const auto& [altName, altDef] : alts )
2405 {
2406 if( !altList.IsEmpty() )
2407 altList += wxT( ", " );
2408 altList += altName;
2409 }
2410
2411 *token = altList;
2412 return true;
2413 }
2414
2415 SCH_CONNECTION* conn = pin->Connection( aPath );
2416
2417 if( !conn )
2418 {
2419 *token = wxEmptyString;
2420 }
2421 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2422 {
2423 wxString netName = conn->LocalName();
2424 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2425 *token = wxT( "NC" );
2426 else
2427 *token = netName;
2428 }
2429 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2430 {
2431 *token = conn->Name();
2432 }
2433 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2434 {
2435 *token = pin->GetEffectiveNetClass( aPath )->GetName();
2436 }
2437
2438 return true;
2439 }
2440 }
2441
2442 // If pin not found in current unit, search all units (auto-resolution)
2443 for( const SCH_PIN* pin : altPinsToSearch )
2444 {
2445 if( pin->GetNumber() == pinNumber )
2446 {
2447 // For PIN_BASE_NAME and PIN_ALT_LIST, we can use library data
2448 if( token->StartsWith( wxT( "PIN_BASE_NAME" ) ) )
2449 {
2450 *token = pin->GetBaseName();
2451 return true;
2452 }
2453 else if( token->StartsWith( wxT( "PIN_ALT_LIST" ) ) )
2454 {
2455 // Build list of alternate names only (no base name)
2456 wxString altList;
2457
2458 const std::map<wxString, SCH_PIN::ALT>& alts = pin->GetAlternates();
2459
2460 for( const auto& [altName, altDef] : alts )
2461 {
2462 if( !altList.IsEmpty() )
2463 altList += wxT( ", " );
2464 altList += altName;
2465 }
2466
2467 *token = altList;
2468 return true;
2469 }
2470
2471 // For net-related functions, find which sheet path has this pin's unit
2472 int pinUnit = pin->GetUnit();
2473
2474 // Search all sheets for a symbol with our reference and the correct unit
2475 // This is needed because each unit of a multi-unit symbol is a separate object
2476 SCH_SHEET_PATH targetPath;
2477 SCH_SYMBOL* targetSymbol = nullptr;
2478
2479 if( Schematic() )
2480 {
2481 for( const SCH_SHEET_PATH& sheetPath : Schematic()->Hierarchy() )
2482 {
2483 for( SCH_ITEM* item : sheetPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
2484 {
2485 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
2486
2487 // Check if this symbol has the same reference designator and the correct unit
2488 if( symbol->GetRef( &sheetPath, false ) == GetRef( aPath, false )
2489 && symbol->GetUnitSelection( &sheetPath ) == pinUnit )
2490 {
2491 targetPath = sheetPath; // Copy the sheet path
2492 targetSymbol = symbol;
2493 break;
2494 }
2495 }
2496
2497 if( targetSymbol )
2498 break;
2499 }
2500 }
2501
2502 if( !targetSymbol )
2503 {
2504 // Unit not placed on any sheet
2505 *token = wxString::Format( wxT( "<Unit %s not placed>" ), SubReference( pinUnit, false ) );
2506 return true;
2507 }
2508
2509 // Get the pin from the actual instance symbol we found
2510 // Match by pin number, not by pointer, since the library pins are different objects
2511 SCH_PIN* instancePin = nullptr;
2512
2513 for( SCH_PIN* candidate : targetSymbol->GetPins( &targetPath ) )
2514 {
2515 if( candidate->GetNumber() == pinNumber )
2516 {
2517 instancePin = candidate;
2518 break;
2519 }
2520 }
2521
2522 if( !instancePin )
2523 {
2524 *token = wxEmptyString;
2525 return true;
2526 }
2527
2528 // PIN_NAME doesn't need connection data, just instance pin
2529 if( token->StartsWith( wxT( "PIN_NAME" ) ) )
2530 {
2531 *token = instancePin->GetAlt().IsEmpty() ? instancePin->GetName() : instancePin->GetAlt();
2532 return true;
2533 }
2534
2535 // Now get the connection from the correct sheet path
2536 SCH_CONNECTION* conn = instancePin->Connection( &targetPath );
2537
2538 if( !conn )
2539 {
2540 *token = wxEmptyString;
2541 }
2542 else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
2543 {
2544 wxString netName = conn->LocalName();
2545 if( netName.Lower().StartsWith( wxT( "unconnected" ) ) )
2546 *token = wxT( "NC" );
2547 else
2548 *token = netName;
2549 }
2550 else if( token->StartsWith( wxT( "NET_NAME" ) ) )
2551 {
2552 *token = conn->Name();
2553 }
2554 else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
2555 {
2556 *token = instancePin->GetEffectiveNetClass( &targetPath )->GetName();
2557 }
2558
2559 return true;
2560 }
2561 }
2562
2563 // If we got here, no pin was found - report unresolved
2564 *token = wxString::Format( wxT( "<Unresolved: pin %s>" ), pinNumber );
2565 return true;
2566 }
2567
2568 // See if parent can resolve it (this will recurse to ancestors)
2569 if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
2570 return true;
2571
2572 return false;
2573}
2574
2575
2576void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
2577{
2578 if( aSheetPath )
2579 {
2580 KIID_PATH path = aSheetPath->Path();
2581
2582 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2583 {
2584 if( instance.m_Path == path )
2585 {
2586 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2587 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2588 else
2589 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2590 }
2591 }
2592 }
2593 else
2594 {
2595 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
2596 {
2597 if( instance.m_Reference.IsEmpty() || aResetPrefix )
2598 instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
2599 else
2600 instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
2601 }
2602 }
2603
2604 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
2605 pin->ClearDefaultNetName( aSheetPath );
2606
2607 // Only modify the REFERENCE field text when clearing ALL annotations (aSheetPath is NULL).
2608 // When clearing for a specific sheet path, we must preserve the field text because it serves
2609 // as a fallback for GetRef() when instances for other sheet paths are looked up.
2610 // See issue #20173: modifying field text here corrupts references in shared screens.
2611 if( !aSheetPath )
2612 {
2613 wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
2614
2615 if( currentReference.IsEmpty() || aResetPrefix )
2617 else
2619 }
2620}
2621
2622
2624{
2625 // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
2626 wxCHECK( aSheetPath.size() > 0, false );
2627
2628 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
2629 {
2630 // if aSheetPath is found, nothing to do:
2631 if( instance.m_Path == aSheetPath )
2632 return false;
2633 }
2634
2635 // This entry does not exist: add it, with its last-used reference
2636 AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
2637 return true;
2638}
2639
2640
2641void SCH_SYMBOL::SetOrientation( int aOrientation )
2642{
2643 TRANSFORM temp = TRANSFORM();
2644 bool transform = false;
2645
2646 switch( aOrientation )
2647 {
2648 case SYM_ORIENT_0:
2649 case SYM_NORMAL: // default transform matrix
2651 break;
2652
2653 case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
2654 temp.x1 = 0;
2655 temp.y1 = 1;
2656 temp.x2 = -1;
2657 temp.y2 = 0;
2658 transform = true;
2659 break;
2660
2661 case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
2662 temp.x1 = 0;
2663 temp.y1 = -1;
2664 temp.x2 = 1;
2665 temp.y2 = 0;
2666 transform = true;
2667 break;
2668
2669 case SYM_MIRROR_Y: // Mirror Y (incremental transform)
2670 temp.x1 = -1;
2671 temp.y1 = 0;
2672 temp.x2 = 0;
2673 temp.y2 = 1;
2674 transform = true;
2675 break;
2676
2677 case SYM_MIRROR_X: // Mirror X (incremental transform)
2678 temp.x1 = 1;
2679 temp.y1 = 0;
2680 temp.x2 = 0;
2681 temp.y2 = -1;
2682 transform = true;
2683 break;
2684
2685 case SYM_ORIENT_90:
2688 break;
2689
2690 case SYM_ORIENT_180:
2694 break;
2695
2696 case SYM_ORIENT_270:
2699 break;
2700
2701 case( SYM_ORIENT_0 + SYM_MIRROR_X ):
2704 break;
2705
2706 case( SYM_ORIENT_0 + SYM_MIRROR_Y ):
2709 break;
2710
2715 break;
2716
2717 case( SYM_ORIENT_90 + SYM_MIRROR_X ):
2720 break;
2721
2722 case( SYM_ORIENT_90 + SYM_MIRROR_Y ):
2725 break;
2726
2731 break;
2732
2733 case( SYM_ORIENT_180 + SYM_MIRROR_X ):
2736 break;
2737
2738 case( SYM_ORIENT_180 + SYM_MIRROR_Y ):
2741 break;
2742
2747 break;
2748
2749 case( SYM_ORIENT_270 + SYM_MIRROR_X ):
2752 break;
2753
2754 case( SYM_ORIENT_270 + SYM_MIRROR_Y ):
2757 break;
2758
2763 break;
2764
2765 default:
2766 transform = false;
2767 wxFAIL_MSG( "Invalid schematic symbol orientation type." );
2768 break;
2769 }
2770
2771 if( transform )
2772 {
2773 /* The new matrix transform is the old matrix transform modified by the
2774 * requested transformation, which is the temp transform (rot,
2775 * mirror ..) in order to have (in term of matrix transform):
2776 * transform coord = new_m_transform * coord
2777 * where transform coord is the coord modified by new_m_transform from
2778 * the initial value coord.
2779 * new_m_transform is computed (from old_m_transform and temp) to
2780 * have:
2781 * transform coord = old_m_transform * temp
2782 */
2783 TRANSFORM newTransform;
2784
2785 newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
2786 newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
2787 newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
2788 newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
2789 m_transform = newTransform;
2790 }
2791}
2792
2793
2795{
2796 /*
2797 * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
2798 * now, so let's just cache it for the moment.
2799 */
2802
2803 int rotate_values[] = { SYM_ORIENT_0,
2815
2816 // Try to find the current transform option:
2817 TRANSFORM transform = m_transform;
2818 SCH_SYMBOL temp( *this );
2819 temp.SetParentGroup( nullptr );
2820
2821 for( int type_rotate : rotate_values )
2822 {
2823 temp.SetOrientation( type_rotate );
2824
2825 if( transform == temp.GetTransform() )
2826 {
2828 return type_rotate;
2829 }
2830 }
2831
2832 // Error: orientation not found in list (should not happen)
2833 wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
2834
2835 return SYM_NORMAL;
2836}
2837
2838
2839#if defined( DEBUG )
2840
2841void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
2842{
2843 // for now, make it look like XML:
2844 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << " ref=\""
2845 << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() ) << '"' << " chipName=\""
2846 << GetLibId().Format().wx_str() << '"' << m_pos << " layer=\"" << m_layer << '"'
2847 << ">\n";
2848
2849 // skip the reference, it's been output already.
2850 for( int i = 1; i < (int) GetFields().size(); ++i )
2851 {
2852 const wxString& value = GetFields()[i].GetText();
2853
2854 if( !value.IsEmpty() )
2855 {
2856 NestedSpace( nestLevel + 1, os ) << "<field" << " name=\"" << TO_UTF8( GetFields()[i].GetName() ) << '"'
2857 << " value=\"" << TO_UTF8( value ) << "\"/>\n";
2858 }
2859 }
2860
2861 NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
2862}
2863
2864#endif
2865
2866
2867BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
2868{
2869 BOX2I bBox;
2870
2871 if( m_part )
2872 bBox = m_part->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2873 else
2874 bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
2875
2876 bBox = m_transform.TransformCoordinate( bBox );
2877 bBox.Normalize();
2878
2879 bBox.Offset( m_pos );
2880
2881 if( aIncludeFields )
2882 {
2883 for( const SCH_FIELD& field : m_fields )
2884 {
2885 if( field.IsVisible() )
2886 bBox.Merge( field.GetBoundingBox() );
2887 }
2888 }
2889
2890 return bBox;
2891}
2892
2893
2895{
2896 try
2897 {
2898 return doGetBoundingBox( false, false );
2899 }
2900 catch( const boost::bad_pointer& e )
2901 {
2902 wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
2903 return BOX2I();
2904 }
2905}
2906
2907
2909{
2910 return doGetBoundingBox( true, false );
2911}
2912
2913
2915{
2916 return doGetBoundingBox( true, true );
2917}
2918
2919
2920void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
2921{
2922 wxString msg;
2923
2924 SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
2925 SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
2926 wxString currentVariant = Schematic() ? Schematic()->GetCurrentVariant() : wxString();
2927
2928 auto addExcludes = [&]()
2929 {
2930 wxArrayString msgs;
2931
2932 if( GetExcludedFromSim() )
2933 msgs.Add( _( "Simulation" ) );
2934
2935 if( GetExcludedFromBOM() )
2936 msgs.Add( _( "BOM" ) );
2937
2938 if( GetExcludedFromBoard() )
2939 msgs.Add( _( "Board" ) );
2940
2941 if( GetDNP( currentSheet, currentVariant ) )
2942 msgs.Add( _( "DNP" ) );
2943
2944 msg = wxJoin( msgs, '|' );
2945 msg.Replace( '|', wxS( ", " ) );
2946
2947 if( !msg.empty() )
2948 aList.emplace_back( _( "Exclude from" ), msg );
2949 };
2950
2951 // part and alias can differ if alias is not the root
2952 if( m_part )
2953 {
2954 if( m_part.get() != LIB_SYMBOL::GetDummy() )
2955 {
2956 if( m_part->IsPower() )
2957 {
2958 // Don't use GetShownText(); we want to see the variable references here
2959 aList.emplace_back( _( "Power symbol" ),
2960 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2961 }
2962 else
2963 {
2964 aList.emplace_back( _( "Reference" ), UnescapeString( GetRef( currentSheet ) ) );
2965
2966 // Don't use GetShownText(); we want to see the variable references here
2967 aList.emplace_back( _( "Value" ),
2968 KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
2969 addExcludes();
2970 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
2971 }
2972
2973#if 0 // Display symbol flags, for debug only
2974 aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
2975#endif
2976
2977 if( !m_part->IsRoot() )
2978 {
2979 msg = _( "Missing parent" );
2980
2981 std::shared_ptr<LIB_SYMBOL> parent = m_part->GetParent().lock();
2982
2983 if( parent )
2984 msg = parent->GetName();
2985
2986 aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
2987 }
2988 else if( !m_lib_id.GetLibNickname().empty() )
2989 {
2990 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
2991 }
2992 else
2993 {
2994 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
2995 }
2996
2997 // Display the current associated footprint, if exists.
2998 // Don't use GetShownText(); we want to see the variable references here
2999 msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
3000
3001 if( msg.IsEmpty() )
3002 msg = _( "<Unknown>" );
3003
3004 aList.emplace_back( _( "Footprint" ), msg );
3005
3006 // Display description of the symbol, and keywords found in lib
3007 aList.emplace_back( _( "Description" ) + wxT( ": " ) + GetField( FIELD_T::DESCRIPTION )->GetText(),
3008 _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
3009 }
3010 }
3011 else
3012 {
3013 aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
3014
3015 // Don't use GetShownText(); we want to see the variable references here
3016 aList.emplace_back( _( "Value" ), KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
3017 addExcludes();
3018 aList.emplace_back( _( "Name" ), KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
3019
3020 wxString libNickname = GetLibId().GetLibNickname();
3021
3022 if( libNickname.empty() )
3023 msg = _( "No library defined!" );
3024 else
3025 msg.Printf( _( "Symbol not found in %s!" ), libNickname );
3026
3027 aList.emplace_back( _( "Library" ), msg );
3028 }
3029}
3030
3031
3036
3037
3039{
3040 std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
3041
3042 if( !libSymbolRef )
3043 return nullptr;
3044
3046}
3047
3048
3050{
3051 int dx = m_pos.x;
3052
3054 MIRROR( m_pos.x, aCenter );
3055 dx -= m_pos.x; // dx,0 is the move vector for this transform
3056
3057 for( SCH_FIELD& field : m_fields )
3058 {
3059 // Move the fields to the new position because the symbol itself has moved.
3060 VECTOR2I pos = field.GetTextPos();
3061 pos.x -= dx;
3062 field.SetTextPos( pos );
3063 }
3064}
3065
3066
3068{
3069 int dy = m_pos.y;
3070
3072 MIRROR( m_pos.y, aCenter );
3073 dy -= m_pos.y; // 0,dy is the move vector for this transform
3074
3075 for( SCH_FIELD& field : m_fields )
3076 {
3077 // Move the fields to the new position because the symbol itself has moved.
3078 VECTOR2I pos = field.GetTextPos();
3079 pos.y -= dy;
3080 field.SetTextPos( pos );
3081 }
3082}
3083
3084
3085void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
3086{
3087 VECTOR2I prev = m_pos;
3088
3089 RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
3090
3092
3093 for( SCH_FIELD& field : m_fields )
3094 {
3095 // Move the fields to the new position because the symbol itself has moved.
3096 VECTOR2I pos = field.GetTextPos();
3097 pos.x -= prev.x - m_pos.x;
3098 pos.y -= prev.y - m_pos.y;
3099 field.SetTextPos( pos );
3100 }
3101}
3102
3103
3104bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
3105{
3106 if( aSearchData.searchMetadata )
3107 {
3108 if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
3109 return true;
3110
3111 if( EDA_ITEM::Matches( GetShownDescription(), aSearchData ) )
3112 return true;
3113
3114 if( EDA_ITEM::Matches( GetShownKeyWords(), aSearchData ) )
3115 return true;
3116 }
3117
3118 // Search instance fields rather than lib template fields so that modified values
3119 // (e.g. a "+5VA" symbol derived from "+5V") are matched correctly. Skip the
3120 // Reference field to avoid infinite recursion: SCH_FIELD::Matches() for REFERENCE
3121 // calls back into SCH_SYMBOL::Matches().
3122 for( const SCH_FIELD& field : m_fields )
3123 {
3124 if( field.GetId() == FIELD_T::REFERENCE )
3125 continue;
3126
3127 if( field.Matches( aSearchData, aAuxData ) )
3128 return true;
3129 }
3130
3131 // Search non-field lib draw items (pins, graphical text) for completeness.
3132 for( const SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
3133 {
3134 if( drawItem.Type() == SCH_FIELD_T )
3135 continue;
3136
3137 if( drawItem.Matches( aSearchData, aAuxData ) )
3138 return true;
3139 }
3140
3141 // Symbols are searchable via the child field and pin item text.
3142 return false;
3143}
3144
3145
3146void SCH_SYMBOL::GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList )
3147{
3148 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3149 {
3150 SCH_PIN* lib_pin = pin->GetLibPin();
3151
3152 if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
3153 continue;
3154
3155 DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
3156 aItemList.push_back( item );
3157 }
3158}
3159
3160
3161bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
3162 std::vector<DANGLING_END_ITEM>& aItemListByPos, const SCH_SHEET_PATH* aPath )
3163{
3164 bool changed = false;
3165
3166 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3167 {
3168 bool previousState = pin->IsDangling();
3169 pin->SetIsDangling( true );
3170
3171 VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
3172
3173 auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
3174 bool do_break = false;
3175
3176 for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
3177 {
3178 DANGLING_END_ITEM& each_item = *it;
3179
3180 // Some people like to stack pins on top of each other in a symbol to indicate
3181 // internal connection. While technically connected, it is not particularly useful
3182 // to display them that way, so skip any pins that are in the same symbol as this
3183 // one.
3184 if( each_item.GetParent() == this )
3185 continue;
3186
3187 switch( each_item.GetType() )
3188 {
3189 case PIN_END:
3190 case LABEL_END:
3191 case SHEET_LABEL_END:
3192 case WIRE_END:
3193 case NO_CONNECT_END:
3194 case JUNCTION_END:
3195 pin->SetIsDangling( false );
3196 do_break = true;
3197 break;
3198
3199 default: break;
3200 }
3201
3202 if( do_break )
3203 break;
3204 }
3205
3206 changed = ( changed || ( previousState != pin->IsDangling() ) );
3207 }
3208
3209 return changed;
3210}
3211
3212
3214{
3215 if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
3216 return VECTOR2I( 0, 0 );
3217
3218 return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
3219}
3220
3221
3222bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem, const SCH_SHEET_PATH* aInstance ) const
3223{
3224 // Do not compare to ourself.
3225 if( aItem == this )
3226 return false;
3227
3228 const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
3229
3230 // Don't compare against a different SCH_ITEM.
3231 wxCHECK( symbol, false );
3232
3233 // The move algorithm marks any pins that are being moved without something attached
3234 // (during the move) as dangling. We always need to recheck connectivity in this case
3235 // or we will not notice changes when the user places the symbol back in the same position
3236 // it started.
3237 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3238 {
3239 if( pin->IsDangling() )
3240 return true;
3241 }
3242
3243 if( GetPosition() != symbol->GetPosition() )
3244 return true;
3245
3246 if( GetLibId() != symbol->GetLibId() )
3247 return true;
3248
3249 if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
3250 return true;
3251
3252 if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
3253 return true;
3254
3255 // Power symbol value field changes are connectivity changes.
3256 if( IsPower() && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
3257 return true;
3258
3259 if( m_pins.size() != symbol->m_pins.size() )
3260 return true;
3261
3262 for( size_t i = 0; i < m_pins.size(); i++ )
3263 {
3264 if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
3265 return true;
3266 }
3267
3268 return false;
3269}
3270
3271
3272std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
3273{
3274 std::vector<VECTOR2I> retval;
3275
3276 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3277 {
3278 // Collect only pins attached to the current unit and convert.
3279 // others are not associated to this symbol instance
3280 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3281 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3282
3283 if( pin_unit > 0 && pin_unit != GetUnit() )
3284 continue;
3285
3286 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3287 continue;
3288
3289 retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
3290 }
3291
3292 return retval;
3293}
3294
3295
3297{
3298 if( m_part )
3299 {
3300 // Calculate the position relative to the symbol.
3301 VECTOR2I libPosition = aPosition - m_pos;
3302
3303 return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
3304 }
3305
3306 return nullptr;
3307}
3308
3309
3310wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
3311{
3312 return wxString::Format( _( "Symbol %s [%s]" ),
3314 KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
3315}
3316
3317
3318INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
3319{
3320 for( KICAD_T scanType : aScanTypes )
3321 {
3322 if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
3323 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3324 {
3325 if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
3326 return INSPECT_RESULT::QUIT;
3327 }
3328
3329 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
3330 {
3331 for( SCH_FIELD& field : m_fields )
3332 {
3333 if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
3334 return INSPECT_RESULT::QUIT;
3335 }
3336 }
3337
3338 if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
3339 {
3340 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
3341 return INSPECT_RESULT::QUIT;
3342 }
3343
3344 if( scanType == SCH_FIELD_LOCATE_VALUE_T
3345 || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
3346 {
3347 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
3348 return INSPECT_RESULT::QUIT;
3349 }
3350
3351 if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
3352 {
3353 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
3354 return INSPECT_RESULT::QUIT;
3355 }
3356
3357 if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
3358 {
3359 if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
3360 return INSPECT_RESULT::QUIT;
3361 }
3362
3363 if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
3364 {
3365 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3366 {
3367 // Collect only pins attached to the current unit and convert.
3368 // others are not associated to this symbol instance
3369 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3370 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3371
3372 if( pin_unit > 0 && pin_unit != GetUnit() )
3373 continue;
3374
3375 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3376 continue;
3377
3378 if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
3379 return INSPECT_RESULT::QUIT;
3380 }
3381 }
3382 }
3383
3385}
3386
3387
3388bool SCH_SYMBOL::operator<( const SCH_ITEM& aItem ) const
3389{
3390 if( Type() != aItem.Type() )
3391 return Type() < aItem.Type();
3392
3393 const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
3394
3396
3397 if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
3398 return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
3399
3400 if( m_pos.x != symbol->m_pos.x )
3401 return m_pos.x < symbol->m_pos.x;
3402
3403 if( m_pos.y != symbol->m_pos.y )
3404 return m_pos.y < symbol->m_pos.y;
3405
3406 return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
3407}
3408
3409
3410bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
3411{
3412 std::vector<SCH_FIELD*> fields, otherFields;
3413
3414 GetFields( fields, false );
3415 aSymbol.GetFields( otherFields, false );
3416
3417 if( fields.size() != otherFields.size() )
3418 return false;
3419
3420 for( int ii = 0; ii < (int) fields.size(); ii++ )
3421 {
3422 if( fields[ii]->GetId() == FIELD_T::REFERENCE )
3423 continue;
3424
3425 if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
3426 return false;
3427 }
3428
3429 return true;
3430}
3431
3432
3433bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
3434{
3435 return !( *this == aSymbol );
3436}
3437
3438
3440{
3441 wxCHECK_MSG( Type() == aSymbol.Type(), *this,
3442 wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) + GetClass() );
3443
3444 if( &aSymbol != this )
3445 {
3446 SYMBOL::operator=( aSymbol );
3447
3448 m_lib_id = aSymbol.m_lib_id;
3449 m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
3450 m_pos = aSymbol.m_pos;
3451 m_unit = aSymbol.m_unit;
3452 m_bodyStyle = aSymbol.m_bodyStyle;
3453 m_transform = aSymbol.m_transform;
3454
3455 m_instances = aSymbol.m_instances;
3456
3457 m_fields = aSymbol.m_fields; // std::vector's assignment operator
3458
3459 // Reparent fields after assignment to new symbol.
3460 for( SCH_FIELD& field : m_fields )
3461 field.SetParent( this );
3462
3463 UpdatePins();
3464 }
3465
3466 return *this;
3467}
3468
3469
3470bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
3471{
3472 BOX2I bBox = GetBodyBoundingBox();
3473 bBox.Inflate( aAccuracy / 2 );
3474
3475 if( bBox.Contains( aPosition ) )
3476 return true;
3477
3478 return false;
3479}
3480
3481
3482bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
3483{
3485 return false;
3486
3487 BOX2I rect = aRect;
3488
3489 rect.Inflate( aAccuracy / 2 );
3490
3491 if( aContained )
3492 return rect.Contains( GetBodyBoundingBox() );
3493
3494 return rect.Intersects( GetBodyBoundingBox() );
3495}
3496
3497
3498bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
3499{
3501 return false;
3502
3503 return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
3504}
3505
3506
3507bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
3508{
3509 VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
3510
3511 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3512 {
3513 if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
3514 continue;
3515
3516 // Collect only pins attached to the current unit and convert.
3517 // others are not associated to this symbol instance
3518 if( pin->GetUnit() > 0 && pin->GetUnit() != GetUnit() )
3519 continue;
3520
3521 if( pin->GetBodyStyle() > 0 && pin->GetBodyStyle() != GetBodyStyle() )
3522 continue;
3523
3524 if( pin->GetLocalPosition() == new_pos )
3525 return true;
3526 }
3527
3528 return false;
3529}
3530
3531
3533{
3534 return m_isInNetlist;
3535}
3536
3537
3538void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
3539 const VECTOR2I& aOffset, bool aDimmed )
3540{
3541 if( aBackground )
3542 return;
3543
3544 if( m_part )
3545 {
3546 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3547
3548 // Copy the source so we can re-orient and translate it.
3549 LIB_SYMBOL tempSymbol( *m_part );
3550 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3551
3552 // Copy the pin info from the symbol to the temp pins
3553 for( unsigned i = 0; i < tempPins.size(); ++i )
3554 {
3555 SCH_PIN* symbolPin = GetPin( libPins[i] );
3556 SCH_PIN* tempPin = tempPins[i];
3557
3558 if( !symbolPin )
3559 continue;
3560
3561 tempPin->SetName( symbolPin->GetShownName() );
3562 tempPin->SetType( symbolPin->GetType() );
3563 tempPin->SetShape( symbolPin->GetShape() );
3564
3565 if( symbolPin->IsDangling() )
3566 tempPin->SetFlags( IS_DANGLING );
3567 }
3568
3569 for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
3570 {
3571 if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
3572 {
3573 // Use SCH_FIELD's text resolver
3574 SCH_FIELD dummy( this, FIELD_T::USER );
3575 dummy.SetText( text->GetText() );
3576 text->SetText( dummy.GetShownText( false ) );
3577 }
3578 }
3579
3580 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3581 TRANSFORM savedTransform = renderSettings->m_Transform;
3582 renderSettings->m_Transform = GetTransform();
3583 aPlotter->StartBlock( nullptr );
3584
3585 wxString variant = Schematic()->GetCurrentVariant();
3586 SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
3587 bool dnp = GetDNP( sheet, variant );
3588
3589 for( bool local_background : { true, false } )
3590 {
3591 tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3592
3593 for( SCH_FIELD field : m_fields )
3594 {
3595 field.ClearRenderCache();
3596 field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(), m_pos, dnp );
3597
3598 if( IsSymbolLikePowerLocalLabel() && field.GetId() == FIELD_T::VALUE
3599 && ( field.IsVisible() || field.IsForceVisible() ) )
3600 {
3601 PlotLocalPowerIconShape( aPlotter );
3602 }
3603 }
3604 }
3605
3606 if( dnp )
3607 PlotDNP( aPlotter );
3608
3609 // Plot attributes to a hypertext menu
3610 if( aPlotOpts.m_PDFPropertyPopups )
3611 {
3612 std::vector<wxString> properties;
3613
3614 for( const SCH_FIELD& field : GetFields() )
3615 {
3616 wxString text_field = field.GetShownText( sheet, false, 0, variant );
3617
3618 if( text_field.IsEmpty() )
3619 continue;
3620
3621 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), field.GetName(), text_field ) );
3622 }
3623
3624 if( !m_part->GetKeyWords().IsEmpty() )
3625 {
3626 properties.emplace_back(
3627 wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ), m_part->GetKeyWords() ) );
3628 }
3629
3630 aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
3631 }
3632
3633 aPlotter->EndBlock( nullptr );
3634 renderSettings->m_Transform = savedTransform;
3635
3636 if( !m_part->IsPower() )
3637 aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
3638 }
3639}
3640
3641
3642void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
3643{
3644 BOX2I bbox = GetBodyBoundingBox();
3646 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3647 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3648 int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3649
3650 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3651 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3652 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3653
3654 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3655 aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
3656
3657 aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
3658
3659 aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
3660 bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ), strokeWidth, nullptr );
3661}
3662
3663
3667static void plotLocalPowerIcon( PLOTTER* aPlotter, const VECTOR2D& aPos, double aSize, bool aRotate )
3668{
3669 double lineWidth = aSize / 10.0;
3670
3671 std::vector<SCH_SHAPE> shapeList;
3672 SCH_SYMBOL::BuildLocalPowerIconShape( shapeList, aPos, aSize, lineWidth, aRotate );
3673 int tolerance = 100; // approx error to approximate a Bezier curve by segments
3674
3675 for( const SCH_SHAPE& shape : shapeList )
3676 {
3677 // Currently there are only 2 shapes: BEZIER and CIRCLE
3678 FILL_T filled = shape.GetFillMode() == FILL_T::NO_FILL ? FILL_T::NO_FILL : FILL_T::FILLED_SHAPE;
3679
3680 if( shape.GetShape() == SHAPE_T::BEZIER )
3681 aPlotter->BezierCurve( shape.GetStart(), shape.GetBezierC1(), shape.GetBezierC2(), shape.GetEnd(),
3682 tolerance, lineWidth );
3683 else if( shape.GetShape() == SHAPE_T::CIRCLE )
3684 aPlotter->Circle( shape.getCenter(), shape.GetRadius() * 2, filled, lineWidth );
3685 }
3686}
3687
3688
3690{
3691 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
3692
3693 // Plot the local power pin indicator icon shape
3694 BOX2I bbox = field->GetBoundingBox();
3695
3696 // Calculate the text orientation according to the parent orientation.
3697 EDA_ANGLE orient = field->GetTextAngle();
3698
3699 if( GetTransform().y1 )
3700 {
3701 // Rotate symbol 90 degrees.
3702 if( orient.IsHorizontal() )
3703 orient = ANGLE_VERTICAL;
3704 else
3705 orient = ANGLE_HORIZONTAL;
3706 }
3707
3708 bool rotated = !orient.IsHorizontal();
3709
3710 VECTOR2D pos;
3711 double size = bbox.GetHeight() / 1.5;
3712
3713 if( rotated )
3714 {
3715 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0, bbox.GetBottom() + bbox.GetWidth() / 2.0 );
3716 size = bbox.GetWidth() / 1.5;
3717 }
3718 else
3719 {
3720 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0, bbox.GetBottom() - bbox.GetHeight() / 6.0 );
3721 }
3722
3723 // TODO: build and plot icon shape
3724 plotLocalPowerIcon( aPlotter, pos, size, rotated );
3725}
3726
3727
3728void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter, bool aDnp ) const
3729{
3730 if( m_part )
3731 {
3732 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
3733 TRANSFORM savedTransform = renderSettings->m_Transform;
3734 renderSettings->m_Transform = GetTransform();
3735
3736 std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
3737
3738 // Copy the source to stay const
3739 LIB_SYMBOL tempSymbol( *m_part );
3740 std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
3741 SCH_PLOT_OPTS plotOpts;
3742
3743 // Copy the pin info from the symbol to the temp pins
3744 for( unsigned i = 0; i < tempPins.size(); ++i )
3745 {
3746 SCH_PIN* symbolPin = GetPin( libPins[i] );
3747 SCH_PIN* tempPin = tempPins[i];
3748
3749 if( !symbolPin )
3750 continue;
3751
3752 tempPin->SetName( symbolPin->GetShownName() );
3753 tempPin->SetType( symbolPin->GetType() );
3754 tempPin->SetShape( symbolPin->GetShape() );
3755 tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, aDnp );
3756 }
3757
3758 renderSettings->m_Transform = savedTransform;
3759 }
3760}
3761
3762
3764{
3765 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3766 {
3767 if( pin->IsBrightened() )
3768 return true;
3769 }
3770
3771 return false;
3772}
3773
3774
3776{
3777 for( std::unique_ptr<SCH_PIN>& pin : m_pins )
3778 pin->ClearBrightened();
3779}
3780
3781
3782/*
3783 * When modified at the schematic level, we still store the values of these flags in the
3784 * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
3785 * will be created and stored locally in the schematic.
3786 */
3788{
3789 return m_part && m_part->GetShowPinNames();
3790}
3791
3792
3794{
3795 if( m_part )
3796 m_part->SetShowPinNames( aShow );
3797}
3798
3799
3801{
3802 return m_part && m_part->GetShowPinNumbers();
3803}
3804
3805
3807{
3808 if( m_part )
3809 m_part->SetShowPinNumbers( aShow );
3810}
3811
3812
3814{
3815 for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
3816 {
3817 int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit() : GetUnit();
3818 int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle() : GetBodyStyle();
3819
3820 if( pin_unit > 0 && pin_unit != GetUnit() )
3821 continue;
3822
3823 if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
3824 continue;
3825
3826 if( pin->IsPointClickableAnchor( aPos ) )
3827 return true;
3828 }
3829
3830 return false;
3831}
3832
3833
3835{
3836 // return true if the symbol is equivalent to a global label:
3837 // It is a Power symbol
3838 // It has only one pin type Power input
3839
3841 return false;
3842
3843 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3844
3845 if( pin_list.size() != 1 )
3846 return false;
3847
3848 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3849}
3850
3851
3853{
3854 // return true if the symbol is equivalent to a local label:
3855 // It is a Power symbol
3856 // It has only one pin type Power input
3857
3859 return false;
3860
3861 std::vector<SCH_PIN*> pin_list = GetAllLibPins();
3862
3863 if( pin_list.size() != 1 )
3864 return false;
3865
3866 return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
3867}
3868
3869
3871{
3872 if( !m_part )
3873 return false;
3874
3875 return m_part->IsLocalPower();
3876}
3877
3878
3880{
3881 if( !m_part )
3882 return false;
3883
3884 return m_part->IsGlobalPower();
3885}
3886
3887
3889{
3890 return IsLocalPower() || IsGlobalPower();
3891}
3892
3893
3895{
3896 wxCHECK( m_part, false );
3897
3898 return m_part->IsNormal();
3899}
3900
3901
3902std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
3903{
3904 std::unordered_set<wxString> componentClass;
3905
3906 auto getComponentClassFields = [&]( const std::vector<SCH_FIELD>& fields )
3907 {
3908 for( const SCH_FIELD& field : fields )
3909 {
3910 if( field.GetCanonicalName() == wxT( "Component Class" ) )
3911 {
3912 if( field.GetShownText( aPath, false ) != wxEmptyString )
3913 componentClass.insert( field.GetShownText( aPath, false ) );
3914 }
3915 }
3916 };
3917
3918 // First get component classes set on the symbol itself
3919 getComponentClassFields( m_fields );
3920
3921 // Now get component classes set on any enclosing rule areas
3922 for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
3923 {
3924 for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
3925 {
3926 getComponentClassFields( label->GetFields() );
3927 }
3928 }
3929
3930 return componentClass;
3931}
3932
3933
3934std::optional<SCH_SYMBOL_VARIANT> SCH_SYMBOL::GetVariant( const SCH_SHEET_PATH& aInstance,
3935 const wxString& aVariantName ) const
3936{
3937 SCH_SYMBOL_INSTANCE instance;
3938
3939 if( !GetInstance( instance, aInstance.Path() ) || !instance.m_Variants.contains( aVariantName ) )
3940 return std::nullopt;
3941
3942 return instance.m_Variants.find( aVariantName )->second;
3943}
3944
3945
3946void SCH_SYMBOL::AddVariant( const SCH_SHEET_PATH& aInstance, const SCH_SYMBOL_VARIANT& aVariant )
3947{
3948 SCH_SYMBOL_INSTANCE* instance = getInstance( aInstance );
3949
3950 // The instance path must already exist.
3951 if( !instance )
3952 return;
3953
3954 instance->m_Variants.insert( std::make_pair( aVariant.m_Name, aVariant ) );
3955}
3956
3957
3958void SCH_SYMBOL::DeleteVariant( const KIID_PATH& aPath, const wxString& aVariantName )
3959{
3960 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3961
3962 // The instance path must already exist.
3963 if( !instance || !instance->m_Variants.contains( aVariantName ) )
3964 return;
3965
3966 instance->m_Variants.erase( aVariantName );
3967}
3968
3969
3970void SCH_SYMBOL::RenameVariant( const KIID_PATH& aPath, const wxString& aOldName,
3971 const wxString& aNewName )
3972{
3973 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3974
3975 // The instance path must already exist and contain the old variant.
3976 if( !instance || !instance->m_Variants.contains( aOldName ) )
3977 return;
3978
3979 // Get the variant data, update the name, and re-insert with new key
3980 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aOldName];
3981 variant.m_Name = aNewName;
3982 instance->m_Variants.erase( aOldName );
3983 instance->m_Variants.insert( std::make_pair( aNewName, variant ) );
3984}
3985
3986
3987void SCH_SYMBOL::CopyVariant( const KIID_PATH& aPath, const wxString& aSourceVariant,
3988 const wxString& aNewVariant )
3989{
3990 SCH_SYMBOL_INSTANCE* instance = getInstance( aPath );
3991
3992 // The instance path must already exist and contain the source variant.
3993 if( !instance || !instance->m_Variants.contains( aSourceVariant ) )
3994 return;
3995
3996 // Copy the variant data with a new name
3997 SCH_SYMBOL_VARIANT variant = instance->m_Variants[aSourceVariant];
3998 variant.m_Name = aNewVariant;
3999 instance->m_Variants.insert( std::make_pair( aNewVariant, variant ) );
4000}
4001
4002
4003bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
4004{
4005 if( Type() != aOther.Type() )
4006 return false;
4007
4008 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
4009
4010 if( GetLibId() != symbol.GetLibId() )
4011 return false;
4012
4013 if( GetPosition() != symbol.GetPosition() )
4014 return false;
4015
4016 if( GetUnit() != symbol.GetUnit() )
4017 return false;
4018
4019 if( GetBodyStyle() != symbol.GetBodyStyle() )
4020 return false;
4021
4022 if( GetTransform() != symbol.GetTransform() )
4023 return false;
4024
4025 if( GetFields() != symbol.GetFields() )
4026 return false;
4027
4028 if( m_pins.size() != symbol.m_pins.size() )
4029 return false;
4030
4031 if( m_excludedFromSim != symbol.m_excludedFromSim )
4032 return false;
4033
4034 if( m_excludedFromBOM != symbol.m_excludedFromBOM )
4035 return false;
4036
4037 if( m_DNP != symbol.m_DNP )
4038 return false;
4039
4041 return false;
4042
4044 return false;
4045
4047 return false;
4048
4049 for( unsigned i = 0; i < m_pins.size(); ++i )
4050 {
4051 if( *m_pins[i] != *symbol.m_pins[i] )
4052 return false;
4053 }
4054
4055#if 0
4056 // This has historically been a compare of the current instance, rather than a compare
4057 // of all instances. Probably better to keep it that way for now.
4058 if( m_instanceReferences != symbol.m_instanceReferences )
4059 return false;
4060#endif
4061
4062 return true;
4063}
4064
4065
4066double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
4067{
4068 if( Type() != aOther.Type() )
4069 return 0.0;
4070
4071 const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
4072
4073 if( GetLibId() != symbol.GetLibId() )
4074 return 0.0;
4075
4076 if( GetPosition() == symbol.GetPosition() )
4077 return 1.0;
4078
4079 return 0.0;
4080}
4081
4082
4083void SCH_SYMBOL::BuildLocalPowerIconShape( std::vector<SCH_SHAPE>& aShapeList, const VECTOR2D& aPos, double aSize,
4084 double aLineWidth, bool aHorizontal )
4085{
4086 SCH_LAYER_ID layer = LAYER_DEVICE; //dummy param
4087
4088 double x_right = aSize / 1.6180339887;
4089 double x_middle = x_right / 2.0;
4090
4091 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
4092 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
4093 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
4094
4095 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
4096 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
4097 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
4098 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
4099 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
4100
4101 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4102 aShapeList.back().SetStart( bottomPt );
4103 aShapeList.back().SetBezierC1( bottomAnchorPt );
4104 aShapeList.back().SetBezierC2( leftSideAnchorPt1 );
4105 aShapeList.back().SetEnd( leftPt );
4106
4107
4108 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4109 aShapeList.back().SetStart( leftPt );
4110 aShapeList.back().SetBezierC1( leftSideAnchorPt2 );
4111 aShapeList.back().SetBezierC2( rightSideAnchorPt2 );
4112 aShapeList.back().SetEnd( rightPt );
4113
4114 aShapeList.emplace_back( SHAPE_T::BEZIER, layer, aLineWidth, FILL_T::NO_FILL );
4115 aShapeList.back().SetStart( rightPt );
4116 aShapeList.back().SetBezierC1( rightSideAnchorPt1 );
4117 aShapeList.back().SetBezierC2( bottomAnchorPt );
4118 aShapeList.back().SetEnd( bottomPt );
4119
4120 aShapeList.emplace_back( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
4121 aShapeList.back().SetCenter( ( leftPt + rightPt ) / 2.0 );
4122 aShapeList.back().SetRadius( aSize / 15.0 );
4123
4124 for( SCH_SHAPE& shape : aShapeList )
4125 {
4126 if( aHorizontal )
4127 shape.Rotate( VECTOR2I( 0, 0 ), true );
4128
4129 shape.Move( aPos );
4130 }
4131}
4132
4133
4135{
4136 for( SCH_SYMBOL_INSTANCE& instance : m_instances )
4137 {
4138 if( instance.m_Path == aSheetPath )
4139 return &instance;
4140 }
4141
4142 return nullptr;
4143}
4144
4145
4147{
4148 for( const SCH_SYMBOL_INSTANCE& instance : m_instances )
4149 {
4150 if( instance.m_Path == aSheetPath )
4151 return &instance;
4152 }
4153
4154 return nullptr;
4155}
4156
4157
4158static struct SCH_SYMBOL_DESC
4159{
4161 {
4163 .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
4164 .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
4165 .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
4166 .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
4167
4173
4180
4187
4188 auto hasLibPart = []( INSPECTABLE* aItem ) -> bool
4189 {
4190 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4191 return symbol->GetLibSymbolRef() != nullptr;
4192
4193 return false;
4194 };
4195
4196 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ), &SYMBOL::SetShowPinNumbers,
4198 .SetAvailableFunc( hasLibPart );
4199
4200 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ), &SYMBOL::SetShowPinNames,
4202 .SetAvailableFunc( hasLibPart );
4203
4204 const wxString groupFields = _HKI( "Fields" );
4205
4208 groupFields );
4211 groupFields );
4212 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
4213 NO_SETTER( SCH_SYMBOL, wxString ),
4215 groupFields );
4216 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
4217 NO_SETTER( SCH_SYMBOL, wxString ),
4219 groupFields );
4220 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ), NO_SETTER( SCH_SYMBOL, wxString ),
4222 groupFields );
4223
4224 auto multiUnit = [=]( INSPECTABLE* aItem ) -> bool
4225 {
4226 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4227 return symbol->IsMultiUnit();
4228
4229 return false;
4230 };
4231
4232 auto multiBodyStyle = [=]( INSPECTABLE* aItem ) -> bool
4233 {
4234 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4235 return symbol->IsMultiBodyStyle();
4236
4237 return false;
4238 };
4239
4242 .SetAvailableFunc( multiUnit )
4244 []( INSPECTABLE* aItem )
4245 {
4246 wxPGChoices choices;
4247
4248 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4249 {
4250 for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
4251 choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
4252 }
4253
4254 return choices;
4255 } );
4256
4259 .SetAvailableFunc( multiBodyStyle )
4261 []( INSPECTABLE* aItem )
4262 {
4263 wxPGChoices choices;
4264
4265 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
4266 {
4267 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
4268 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
4269 }
4270
4271 return choices;
4272 } );
4273
4274 const wxString groupAttributes = _HKI( "Attributes" );
4275
4276 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
4279 groupAttributes );
4280 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
4283 groupAttributes );
4284 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Board" ),
4287 groupAttributes );
4288 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Exclude From Position Files" ),
4291 groupAttributes );
4292 propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Do not Populate" ),
4295 groupAttributes );
4296 }
4298
4299
const char * name
types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:47
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h: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:963
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:162
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:156
const KIID m_Uuid
Definition eda_item.h:535
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:112
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:546
virtual bool Matches(const EDA_SEARCH_DATA &aSearchData, void *aAuxData) const
Compare the item against the search criteria in aSearchData.
Definition eda_item.h:420
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:117
bool IsSelected() const
Definition eda_item.h:136
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:93
EDA_ITEM * m_parent
Owner.
Definition eda_item.h:547
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:580
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:598
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:132
FIELD_T GetId() const
Definition sch_field.h:136
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:166
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:245
void SetLocked(bool aLocked) override
Definition sch_item.h:255
int m_unit
Definition sch_item.h:780
int m_bodyStyle
Definition sch_item.h:781
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:728
void SetPrivate(bool aPrivate)
Definition sch_item.h:251
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:272
int GetBodyStyle() const
Definition sch_item.h:246
bool IsLocked() const override
Definition sch_item.cpp:152
friend class LIB_SYMBOL
Definition sch_item.h:801
int GetUnit() const
Definition sch_item.h:237
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:343
virtual void SetUnit(int aUnit)
Definition sch_item.h:236
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:783
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:796
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:779
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:73
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:520
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:319
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:164
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:449
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:537
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:890
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:302
int GetY() const
Definition sch_symbol.h:895
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:112
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:336
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition sch_symbol.h:542
int GetX() const
Definition sch_symbol.h:892
std::vector< SCH_PIN * > GetPins() const override
bool GetExcludedFromPosFilesProp() const
Definition sch_symbol.h:769
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:744
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:754
void ClearBrightenedPins()
void SetY(int aY)
Definition sch_symbol.h:896
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:739
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:331
wxString GetRefProp() const
Definition sch_symbol.h:506
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:729
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:293
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:714
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:889
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:774
wxString GetShownDescription(int aDepth=0) const override
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:162
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:531
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:348
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetDNPProp(bool aEnable)
Definition sch_symbol.h:716
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:893
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:513
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:236
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:724
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:759
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:181
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:381
int NextFieldOrdinal(const std::vector< SCH_FIELD > &aFields)
Definition sch_field.h:370
@ 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