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