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