KiCad PCB EDA Suite
Loading...
Searching...
No Matches
lib_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) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2022 CERN
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <font/outline_font.h>
24#include <sch_draw_panel.h>
25#include <plotters/plotter.h>
26#include <sch_screen.h>
27#include <template_fieldnames.h>
28#include <transform.h>
30#include <sch_pin.h>
31#include <sch_shape.h>
32#include <trace_helpers.h>
33#include <common.h>
34#include <api/api_enums.h>
35#include <api/api_sch_utils.h>
36#include <api/api_utils.h>
37
39
40// TODO(JE) remove m_library; shouldn't be needed with legacy remapping
42
43#include <algorithm>
44#include <functional>
45#include <memory>
46#include <unordered_map>
47#include <unordered_set>
48#include <advanced_config.h>
49#include <properties/property.h>
51
52#include <api/schematic/schematic_types.pb.h>
53
61static std::shared_ptr<LIB_SYMBOL> GetSafeRootSymbol( const LIB_SYMBOL* aSymbol, const char* aCallerName )
62{
63 std::set<const LIB_SYMBOL*> visited;
64 visited.insert( aSymbol );
65
66 std::shared_ptr<LIB_SYMBOL> current = aSymbol->SharedPtr();
67 std::shared_ptr<LIB_SYMBOL> parent = aSymbol->GetParent().lock();
68
69 while( parent )
70 {
71 if( visited.count( parent.get() ) )
72 {
73 // Build chain description for logging
74 wxString chain = aSymbol->GetName();
75
76 for( const LIB_SYMBOL* sym : visited )
77 {
78 if( sym != aSymbol )
79 chain += wxT( " -> " ) + sym->GetName();
80 }
81
82 chain += wxT( " -> " ) + parent->GetName() + wxT( " (CYCLE)" );
83
84 wxLogTrace( traceSymbolInheritance,
85 wxT( "%s: Circular inheritance detected in symbol '%s' (lib: %s). Chain: %s" ),
86 aCallerName,
87 aSymbol->GetName(),
88 aSymbol->GetLibId().GetLibNickname().wx_str(),
89 chain );
90
91 // Return current (last valid symbol before cycle)
92 return current;
93 }
94
95 visited.insert( parent.get() );
96 current = parent;
97 parent = parent->GetParent().lock();
98 }
99
100 return current;
101}
102
103
104wxString LIB_SYMBOL::getShownDescription( RESOLUTION_CONTEXT aContext, int aDepth ) const
105{
106 wxString shownText = GetDescriptionField().GetShownText( aContext, aDepth );
107
108 if( shownText.IsEmpty() && IsDerived() )
109 {
110 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
111
112 if( root.get() != this )
113 shownText = root->GetDescriptionField().GetShownText( aContext, aDepth );
114 }
115
116 return shownText;
117}
118
119
120wxString LIB_SYMBOL::GetShownDescription( RESOLUTION_CONTEXT aContext, int aDepth ) const
121{
122 if( aContext == FOR_GUI )
124
125 return getShownDescription( aContext, aDepth );
126}
127
128
133
134
135void LIB_SYMBOL::SetDescription( const wxString& aDescription )
136{
137 GetDescriptionField().SetText( aDescription );
140}
141
142
143void LIB_SYMBOL::SetKeyWords( const wxString& aKeyWords )
144{
145 m_keyWords = aKeyWords;
147}
148
149
150wxString LIB_SYMBOL::GetShownKeyWords( RESOLUTION_CONTEXT aContext, int aDepth ) const
151{
152 if( aContext == RAW_VALUE )
153 return GetKeyWords();
154
155 wxString text = GetKeyWords();
156
157 std::function<bool( wxString* )> libSymbolResolver =
158 [&]( wxString* token ) -> bool
159 {
160 return ResolveTextVar( token, aDepth + 1 );
161 };
162
163 text = ResolveTextVars( text, &libSymbolResolver, aDepth );
164
165 return text;
166}
167
168
175
176
178{
179 m_searchTermsCache.clear();
180 m_searchTermsCache.reserve( 6 );
181
182 // Order matters, see SEARCH_TERM_CACHE_INDEX
183 m_searchTermsCache.emplace_back( SEARCH_TERM( GetLibNickname(), 4 ) );
184 m_searchTermsCache.emplace_back( SEARCH_TERM( GetName(), 8, true ) );
185 m_searchTermsCache.emplace_back( SEARCH_TERM( GetLIB_ID().Format(), 16, true ) );
186
187 wxStringTokenizer keywordTokenizer( GetShownKeyWords( FOR_GUI ), " \t\r\n", wxTOKEN_STRTOK );
188
189 while( keywordTokenizer.HasMoreTokens() )
190 m_searchTermsCache.emplace_back( SEARCH_TERM( keywordTokenizer.GetNextToken(), 4 ) );
191
192 // Also include keywords as one long string, just in case
195
196 // Add relational term for unit count
197 m_searchTermsCache.emplace_back( SEARCH_TERM( wxString::Format( wxT( "units=%d" ), GetUnitCount() ), 1 ) );
198
199 wxString footprint = GetFootprint();
200
201 if( !footprint.IsEmpty() )
202 m_searchTermsCache.emplace_back( SEARCH_TERM( footprint, 1 ) );
203}
204
205
206void LIB_SYMBOL::GetChooserFields( std::map<wxString, wxString>& aColumnMap )
207{
208 aColumnMap = m_chooserFieldsCache;
209}
210
211
213{
214 m_chooserFieldsCache.clear();
215
216 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
217 {
218 SCH_FIELD* field = static_cast<SCH_FIELD*>( &item );
219
220 if( field->ShowInChooser() )
221 m_chooserFieldsCache[field->GetName()] = field->EDA_TEXT::GetShownText( FOR_GUI );
222 }
223
224 // If the user has a field named "Keywords", then prefer that. Otherwise add the KiCad
225 // keywords.
226 const wxString localizedKeywords = _( "Keywords" );
227
228 if( !m_chooserFieldsCache.contains( localizedKeywords ) )
229 m_chooserFieldsCache[localizedKeywords] = GetShownKeyWords( FOR_GUI );
230}
231
232
233bool operator<( const LIB_SYMBOL& aItem1, const LIB_SYMBOL& aItem2 )
234{
235 return aItem1.GetName() < aItem2.GetName();
236}
237
238
241{
242 void operator()( void const* ) const {}
243};
244
245
246LIB_SYMBOL::LIB_SYMBOL( const wxString& aName, LIB_SYMBOL* aParent, LEGACY_SYMBOL_LIB* aLibrary ) :
248 m_me( this, null_deleter() )
249{
250 m_lastModDate = 0;
251 m_unitCount = 1;
252 m_demorgan = false;
255 m_unitsLocked = false;
257 m_library = nullptr;
258
259 auto addField = [&]( FIELD_T id, bool visible )
260 {
261 SCH_FIELD* field = new SCH_FIELD( this, id );
262 field->SetVisible( visible );
263 m_drawings[SCH_FIELD_T].push_back( field );
264 };
265
266 // construct only the mandatory fields
267 addField( FIELD_T::REFERENCE, true );
268 addField( FIELD_T::VALUE, true );
269 addField( FIELD_T::FOOTPRINT, false );
270 addField( FIELD_T::DATASHEET, false );
271 addField( FIELD_T::DESCRIPTION, false );
272
273 SetName( aName );
274 SetParent( aParent );
275 SetLib( aLibrary );
280}
281
282
283LIB_SYMBOL::LIB_SYMBOL( const LIB_SYMBOL& aSymbol, LEGACY_SYMBOL_LIB* aLibrary, bool aCopyEmbeddedFiles ) :
284 SYMBOL( aSymbol ),
285 EMBEDDED_FILES( aSymbol, aCopyEmbeddedFiles ),
286 m_me( this, null_deleter() )
287{
288 m_library = aLibrary;
289 m_name = aSymbol.m_name;
290 m_fpFilters = wxArrayString( aSymbol.m_fpFilters );
291 m_pinMaps = aSymbol.m_pinMaps;
293 m_unitCount = aSymbol.m_unitCount;
294 m_demorgan = aSymbol.m_demorgan;
297 m_options = aSymbol.m_options;
298 m_libId = aSymbol.m_libId;
299 m_keyWords = aSymbol.m_keyWords;
300
303
305 // Raw member, not the accessor, which would bake a root's body styles into a derived copy
307
309
310 for( const SCH_ITEM& oldItem : aSymbol.m_drawings )
311 {
312 if( ( oldItem.GetFlags() & ( IS_NEW | STRUCT_DELETED ) ) != 0 )
313 continue;
314
315 try
316 {
317 SCH_ITEM* newItem = (SCH_ITEM*) oldItem.Clone();
318 newItem->ClearSelected();
319 newItem->SetParent( this );
320 m_drawings.push_back( newItem );
321 }
322 catch( ... )
323 {
324 wxFAIL_MSG( "Failed to clone SCH_ITEM." );
325 return;
326 }
327 }
328
329 SetParent( aSymbol.m_parent.lock().get() );
334}
335
336
337void LIB_SYMBOL::Serialize( kiapi::schematic::types::SchematicSymbol& aOutput, bool aSkipPins ) const
338{
339 using namespace kiapi::common;
340 using namespace kiapi::schematic::types;
341
342 SchematicSymbol& def = aOutput;
343 def.Clear();
344 PackLibId( def.mutable_id(), m_libId );
345
346 SchematicSymbolType symbolType = SchematicSymbolType::SST_NORMAL;
347
348 if( IsGlobalPower() )
349 symbolType = SchematicSymbolType::SST_GLOBAL_POWER;
350 else if( IsLocalPower() )
351 symbolType = SchematicSymbolType::SST_LOCAL_POWER;
352
353 def.set_type( symbolType );
354
355 SchematicSymbolAttributes* attributes = def.mutable_attributes();
356 attributes->set_exclude_from_simulation( GetExcludedFromSim() );
357 attributes->set_exclude_from_bill_of_materials( GetExcludedFromBOM() );
358 attributes->set_exclude_from_board( GetExcludedFromBoard() );
359 attributes->set_exclude_from_position_files( GetExcludedFromPosFiles() );
360 attributes->set_do_not_populate( GetDNP() );
361
362 GetField( FIELD_T::REFERENCE )->Serialize( *def.mutable_reference_field(), schIUScale );
363 GetField( FIELD_T::VALUE )->Serialize( *def.mutable_value_field(), schIUScale );
364 GetField( FIELD_T::FOOTPRINT )->Serialize( *def.mutable_footprint_field(), schIUScale );
365 GetField( FIELD_T::DATASHEET )->Serialize( *def.mutable_datasheet_field(), schIUScale );
366
367 for( const SCH_ITEM& drawItem : GetDrawItems() )
368 {
369 if( drawItem.Type() == SCH_FIELD_T && static_cast<const SCH_FIELD&>( drawItem ).IsMandatory() )
370 continue;
371
372 if( aSkipPins && drawItem.Type() == SCH_PIN_T )
373 continue;
374
375 SchematicSymbolChild* item = def.add_items();
376 item->mutable_unit()->set_unit( drawItem.GetUnit() );
377 item->mutable_body_style()->set_style( drawItem.GetBodyStyle() );
378 item->set_is_private( drawItem.IsPrivate() );
379 drawItem.Serialize( *item->mutable_item() );
380 }
381
382 def.set_unit_count( GetUnitCount() );
383
384 for( int bodyStyle = BODY_STYLE::BASE; bodyStyle <= GetBodyStyleCount(); ++bodyStyle )
385 def.add_body_style()->set_name( GetBodyStyleDescription( bodyStyle, false ).ToUTF8() );
386
387 def.set_keywords( GetKeyWords().ToUTF8() );
388
389 for( const wxString& filter : GetFPFilters() )
390 def.add_footprint_filters( filter.ToUTF8() );
391
392 JumperSettings* jumpers = def.mutable_jumpers();
393 jumpers->set_duplicate_names_are_jumpered( GetDuplicatePinNumbersAreJumpers() );
394
395 for( const std::set<wxString>& group : JumperPinGroups() )
396 {
397 JumperGroup* jumperGroup = jumpers->add_groups();
398
399 for( const wxString& pinNumber : group )
400 jumperGroup->add_pin_numbers( pinNumber.ToUTF8() );
401 }
402
403 def.set_units_locked( UnitsLocked() );
404 def.set_embedded_fonts( GetAreFontsEmbedded() );
405 def.set_show_pin_numbers( GetShowPinNumbers() );
406 def.set_show_pin_names( GetShowPinNames() );
407 PackDistance( *def.mutable_pin_name_offset(), GetPinNameOffset(), schIUScale );
408
409 for( const auto& [unit, displayName] : GetUnitDisplayNames() )
410 {
411 SchematicUnitDisplayName* protoName = def.add_unit_display_names();
412 protoName->set_unit( unit );
413 protoName->set_name( displayName.ToUTF8() );
414 }
415
416 SymbolPinMaps* pinMaps = def.mutable_pin_maps();
417
419 {
420 AssociatedFootprint* a = pinMaps->add_associated_footprints();
421 PackLibId( a->mutable_footprint(), assoc.m_FootprintLibId );
422 a->set_map_name( assoc.m_MapName.ToUTF8() );
423 }
424
425 for( const PIN_MAP& map : GetEffectivePinMaps().GetAll() )
426 {
427 PinMap* m = pinMaps->add_pin_maps();
428 m->set_name( map.GetName().ToUTF8() );
429
430 for( const PIN_MAP_ENTRY& entry : map.GetEntries() )
431 {
432 PinMapEntry* e = m->add_entries();
433 e->set_pin_number( entry.m_PinNumber.ToUTF8() );
434 e->set_pad_number( entry.m_PadNumber.ToUTF8() );
435 }
436 }
437}
438
439
440void LIB_SYMBOL::Serialize( google::protobuf::Any& aContainer ) const
441{
442 kiapi::schematic::types::SchematicSymbol def;
443 Serialize( def );
444 aContainer.PackFrom( def );
445}
446
447
448bool LIB_SYMBOL::Deserialize( const kiapi::schematic::types::SchematicSymbol& aInput )
449{
450 using namespace kiapi::common;
451 using namespace kiapi::common::types;
452 using namespace kiapi::schematic::types;
453
454 const SchematicSymbol& def = aInput;
455
456 LIB_ID libId = UnpackLibId( def.id() );
457 SetLibId( libId );
458
459 switch( def.type() )
460 {
461 case SchematicSymbolType::SST_GLOBAL_POWER: SetGlobalPower(); break;
462 case SchematicSymbolType::SST_LOCAL_POWER: SetLocalPower(); break;
463 default: break;
464 }
465
466 if( def.has_attributes() )
467 {
468 SetExcludedFromSim( def.attributes().exclude_from_simulation() );
469 SetExcludedFromBOM( def.attributes().exclude_from_bill_of_materials() );
470 SetExcludedFromBoard( def.attributes().exclude_from_board() );
471 SetExcludedFromPosFiles( def.attributes().exclude_from_position_files() );
472 SetDNP( def.attributes().do_not_populate() );
473 }
474
475 GetField( FIELD_T::REFERENCE )->Deserialize( def.reference_field(), schIUScale );
476 GetField( FIELD_T::VALUE )->Deserialize( def.value_field(), schIUScale );
477 GetField( FIELD_T::FOOTPRINT )->Deserialize( def.footprint_field(), schIUScale );
478 GetField( FIELD_T::DATASHEET )->Deserialize( def.datasheet_field(), schIUScale );
479 GetField( FIELD_T::DESCRIPTION )->Deserialize( def.description_field(), schIUScale );
480
481 for( const SchematicSymbolChild& child : def.items() )
482 {
483 std::optional<KICAD_T> type = TypeNameFromAny( child.item() );
484
485 if( !type )
486 continue;
487
488 std::unique_ptr<EDA_ITEM> item = CreateItemForType( *type, this );
489
490 if( !item || !item->Deserialize( child.item() ) )
491 continue;
492
493 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
494
495 if( child.has_unit() )
496 schItem->SetUnit( child.unit().unit() );
497
498 if( child.has_body_style() )
499 schItem->SetBodyStyle( child.body_style().style() );
500
501 schItem->SetLayer( LAYER_DEVICE );
502 schItem->SetPrivate( child.is_private() );
503 AddDrawItem( schItem, false );
504 }
505
506 if( def.unit_count() > 0 )
507 SetUnitCount( def.unit_count(), false );
508
509 if( def.body_style_size() > 0 )
510 {
511 std::vector<wxString> bodyStyleNames;
512
513 for( const SchematicBodyStyle& bodyStyle : def.body_style() )
514 bodyStyleNames.emplace_back( wxString::FromUTF8( bodyStyle.name() ) );
515
516 SetBodyStyleNames( bodyStyleNames );
517 SetBodyStyleCount( static_cast<int>( bodyStyleNames.size() ), false, false );
518 }
519
520 if( !def.keywords().empty() )
521 SetKeyWords( wxString::FromUTF8( def.keywords() ) );
522
523 if( def.footprint_filters_size() > 0 )
524 {
525 wxArrayString filters;
526
527 for( const std::string& filter : def.footprint_filters() )
528 filters.Add( wxString::FromUTF8( filter ) );
529
530 SetFPFilters( filters );
531 }
532
533 SetDuplicatePinNumbersAreJumpers( def.jumpers().duplicate_names_are_jumpered() );
534
535 for( const JumperGroup& group : def.jumpers().groups() )
536 {
537 std::set<wxString> pinNumbers;
538
539 for( const std::string& pinNumber : group.pin_numbers() )
540 pinNumbers.insert( wxString::FromUTF8( pinNumber ) );
541
542 if( !pinNumbers.empty() )
543 JumperPinGroups().push_back( std::move( pinNumbers ) );
544 }
545
546 LockUnits( def.units_locked() );
547 SetAreFontsEmbedded( def.embedded_fonts() );
548
549 for( const SchematicUnitDisplayName& displayName : def.unit_display_names() )
550 GetUnitDisplayNames()[displayName.unit()] = wxString::FromUTF8( displayName.name() );
551
552 SetShowPinNumbers( def.show_pin_numbers() );
553 SetShowPinNames( def.show_pin_names() );
554 SetPinNameOffset( UnpackDistance( def.pin_name_offset(), schIUScale ) );
555
556 if( def.has_pin_maps() )
557 {
558 PIN_MAP_SET pinMapSet;
559
560 for( const PinMap& map : def.pin_maps().pin_maps() )
561 {
562 PIN_MAP pinMap( wxString::FromUTF8( map.name() ) );
563
564 for( const PinMapEntry& entry : map.entries() )
565 {
566 pinMap.SetEntry( wxString::FromUTF8( entry.pin_number() ), wxString::FromUTF8( entry.pad_number() ) );
567 }
568
569 pinMapSet.AddOrReplace( std::move( pinMap ) );
570 }
571
572 std::vector<ASSOCIATED_FOOTPRINT> associatedFootprints;
573
574 for( const AssociatedFootprint& footprint : def.pin_maps().associated_footprints() )
575 {
577 assoc.m_FootprintLibId = UnpackLibId( footprint.footprint() );
578 assoc.m_MapName = wxString::FromUTF8( footprint.map_name() );
579 associatedFootprints.push_back( std::move( assoc ) );
580 }
581
582 SetPinMaps( pinMapSet );
583 SetAssociatedFootprints( std::move( associatedFootprints ) );
584 }
585
586 return true;
587}
588
589
590bool LIB_SYMBOL::Deserialize( const google::protobuf::Any& aContainer )
591{
592 kiapi::schematic::types::SchematicSymbol def;
593
594 if( !aContainer.UnpackTo( &def ) )
595 return false;
596
597 return Deserialize( def );
598}
599
600
602{
603 if( &aSymbol == this )
604 return aSymbol;
605
606 SYMBOL::operator=( aSymbol );
607
608 m_library = aSymbol.m_library;
609 m_name = aSymbol.m_name;
610 m_fpFilters = wxArrayString( aSymbol.m_fpFilters );
611 m_pinMaps = aSymbol.m_pinMaps;
613 m_unitCount = aSymbol.m_unitCount;
614 m_demorgan = aSymbol.m_demorgan;
617 m_options = aSymbol.m_options;
618 m_libId = aSymbol.m_libId;
619 m_keyWords = aSymbol.m_keyWords;
620
623
625 // Raw member, not the accessor, which would bake a root's body styles into a derived copy
627
628 m_drawings.clear();
629
630 for( const SCH_ITEM& oldItem : aSymbol.m_drawings )
631 {
632 if( ( oldItem.GetFlags() & ( IS_NEW | STRUCT_DELETED ) ) != 0 )
633 continue;
634
635 SCH_ITEM* newItem = (SCH_ITEM*) oldItem.Clone();
636 newItem->SetParent( this );
637 m_drawings.push_back( newItem );
638 }
639
640 m_drawings.sort();
641
642 SetParent( aSymbol.m_parent.lock().get() );
643
644 EMBEDDED_FILES::operator=( aSymbol );
645
650
651 return *this;
652}
653
654
661{
662 static LIB_SYMBOL* symbol;
663
664 if( !symbol )
665 {
666 symbol = new LIB_SYMBOL( wxEmptyString );
667
669
670 square->SetPosition( VECTOR2I( schIUScale.MilsToIU( -200 ), schIUScale.MilsToIU( 200 ) ) );
671 square->SetEnd( VECTOR2I( schIUScale.MilsToIU( 200 ), schIUScale.MilsToIU( -200 ) ) );
672 symbol->AddDrawItem( square );
673
674 SCH_TEXT* text = new SCH_TEXT( { 0, 0 }, wxT( "??" ), LAYER_DEVICE );
675
676 text->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 150 ), schIUScale.MilsToIU( 150 ) ) );
677 symbol->AddDrawItem( text );
678 }
679
680 return symbol;
681}
682
683
685{
686 unsigned depth = 0;
687 std::set<const LIB_SYMBOL*> visited;
688 visited.insert( this );
689
690 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
691
692 while( parent )
693 {
694 // Cycle detected - parent chain points back to an already visited symbol
695 if( visited.count( parent.get() ) )
696 {
697 wxLogTrace( traceSymbolInheritance,
698 wxT( "GetInheritanceDepth: Circular inheritance detected in symbol '%s' "
699 "(lib: %s)" ),
700 m_name, m_libId.GetLibNickname().wx_str() );
701 break;
702 }
703
704 visited.insert( parent.get() );
705 depth++;
706 parent = parent->m_parent.lock();
707 }
708
709 return depth;
710}
711
712
713std::shared_ptr<LIB_SYMBOL> LIB_SYMBOL::GetRootSymbol() const
714{
715 std::set<const LIB_SYMBOL*> visited;
716 visited.insert( this );
717
718 std::shared_ptr<LIB_SYMBOL> current = m_me;
719 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
720
721 while( parent )
722 {
723 // Cycle detected - parent chain points back to an already visited symbol
724 if( visited.count( parent.get() ) )
725 {
726 wxLogTrace( traceSymbolInheritance,
727 wxT( "GetRootSymbol: Circular inheritance detected in symbol '%s' "
728 "(lib: %s)" ),
729 m_name, m_libId.GetLibNickname().wx_str() );
730 break;
731 }
732
733 visited.insert( parent.get() );
734 current = parent;
735 parent = parent->m_parent.lock();
736 }
737
738 return current;
739}
740
741
743{
744 if( IsDerived() )
745 {
746 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
747
748 if( root.get() != this )
749 return root->m_unitsLocked;
750 }
751
752 return m_unitsLocked;
753}
754
755
756wxString LIB_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
757{
758 const LIB_SYMBOL* owner = this;
759 std::shared_ptr<LIB_SYMBOL> root;
760
761 if( IsDerived() )
762 {
763 root = GetSafeRootSymbol( this, __FUNCTION__ );
764 owner = root.get();
765 }
766
767 if( owner->m_unitDisplayNames.contains( aUnit ) )
768 return owner->m_unitDisplayNames.at( aUnit );
769 else if( aLabel )
770 return wxString::Format( _( "Unit %s" ), LIB_SYMBOL::LetterSubReference( aUnit, 'A' ) );
771 else
772 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
773}
774
775
776wxString LIB_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
777{
779 {
780 if( aBodyStyle == BODY_STYLE::DEMORGAN )
781 return aLabel ? _( "Alternate" ) : wxString( _HKI( "Alternate" ) );
782 else if( aBodyStyle == BODY_STYLE::BASE )
783 return aLabel ? _( "Standard" ) : wxString( _HKI( "Standard" ) );
784 }
785 else if( IsMultiBodyStyle() )
786 {
787 const std::vector<wxString>& names = GetBodyStyleNames();
788
789 // Draw items common to every body style carry a body style of 0
790 if( aBodyStyle >= BODY_STYLE::BASE && aBodyStyle <= (int) names.size() )
791 return names[aBodyStyle - 1];
792 }
793
794 return wxT( "?" );
795}
796
797
798void LIB_SYMBOL::SetName( const wxString& aName )
799{
800 m_name = aName;
801 m_libId.SetLibItemName( aName );
802
803 if( m_searchTermsCache.empty() )
805
808}
809
810
811void LIB_SYMBOL::SetLibId( const LIB_ID& aLibId )
812{
813 m_libId = aLibId;
814
815 if( m_searchTermsCache.empty() )
817
819}
820
821
823{
824 if( aParent )
825 {
826 // Prevent circular inheritance by checking if aParent is derived from this symbol
827 std::set<const LIB_SYMBOL*> visited;
828 visited.insert( this );
829
830 std::shared_ptr<LIB_SYMBOL> ancestor = aParent->SharedPtr();
831
832 while( ancestor )
833 {
834 if( visited.count( ancestor.get() ) )
835 {
836 wxLogTrace( traceSymbolInheritance,
837 wxT( "SetParent: Rejecting parent '%s' for symbol '%s' - would create "
838 "circular inheritance (lib: %s)" ),
839 aParent->GetName(), m_name, m_libId.GetLibNickname().wx_str() );
840
841 // Don't set the parent - it would create circular inheritance
842 return;
843 }
844
845 visited.insert( ancestor.get() );
846 ancestor = ancestor->m_parent.lock();
847 }
848
849 m_parent = aParent->SharedPtr();
850
851 // Keep the recorded parent name in sync so serialization never has to dereference the live
852 // parent pointer (which can dangle, see SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol).
853 m_parentName = aParent->GetName();
854 }
855 else
856 {
857 // Only drop the live pointer. The recorded parent name is left untouched so a derived
858 // symbol whose live parent has been lost can still be serialized by name.
859 m_parent.reset();
860 }
861}
862
863
865{
867 return wxEmptyString;
868
870}
871
872
873std::unique_ptr<LIB_SYMBOL> LIB_SYMBOL::Flatten() const
874{
875 std::unique_ptr<LIB_SYMBOL> retv;
876
877 if( IsDerived() )
878 {
879 // Build parent chain with cycle detection - collect from this symbol up to root
880 std::vector<const LIB_SYMBOL*> parentChain;
881 std::set<const LIB_SYMBOL*> visited;
882 visited.insert( this );
883
884 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
885
886 wxCHECK_MSG( parent, retv, wxString::Format( "Parent of derived symbol '%s' undefined", m_name ) );
887
888 while( parent )
889 {
890 // Cycle detected - parent chain points back to an already visited symbol
891 if( visited.count( parent.get() ) )
892 {
893 wxLogTrace( traceSymbolInheritance,
894 wxT( "Flatten: Circular inheritance detected in symbol '%s' (lib: %s)" ),
895 m_name, m_libId.GetLibNickname().wx_str() );
896 break;
897 }
898
899 visited.insert( parent.get() );
900 parentChain.push_back( parent.get() );
901 parent = parent->m_parent.lock();
902 }
903
904 // Start with the root (last in chain) and work down
905 if( !parentChain.empty() )
906 {
907 retv = std::make_unique<LIB_SYMBOL>( *parentChain.back() );
908
909 // Apply each derived symbol's overrides from root down (skip the root itself)
910 for( int i = static_cast<int>( parentChain.size() ) - 2; i >= 0; --i )
911 {
912 const LIB_SYMBOL* derived = parentChain[i];
913
914 // Overwrite parent's mandatory fields for fields which are defined in derived.
915 for( FIELD_T fieldId : MANDATORY_FIELDS )
916 {
917 if( !derived->GetField( fieldId )->GetText().IsEmpty() )
918 *retv->GetField( fieldId ) = *derived->GetField( fieldId );
919 }
920
921 // Grab all the rest of derived symbol fields.
922 for( const SCH_ITEM& item : derived->m_drawings[SCH_FIELD_T] )
923 {
924 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
925
926 if( field->IsMandatory() )
927 continue;
928
929 SCH_FIELD* newField = new SCH_FIELD( *field );
930 newField->SetParent( retv.get() );
931
932 SCH_FIELD* parentField = retv->GetField( field->GetName() );
933
934 if( !parentField )
935 {
936 retv->AddDrawItem( newField );
937 }
938 else
939 {
940 retv->RemoveDrawItem( parentField );
941 retv->AddDrawItem( newField );
942 }
943 }
944
945 if( !derived->m_keyWords.IsEmpty() )
946 retv->SetKeyWords( derived->m_keyWords );
947
948 if( !derived->m_fpFilters.IsEmpty() )
949 retv->SetFPFilters( derived->m_fpFilters );
950 }
951 }
952 else
953 {
954 // Cycle detected at immediate parent level - just copy this symbol
955 retv = std::make_unique<LIB_SYMBOL>( *this );
956 retv->m_parent.reset();
957 return retv;
958 }
959
960 // Now apply this symbol's overrides (the original "this" symbol)
961 retv->m_name = m_name;
962 retv->SetLibId( m_libId );
963
964 // Overwrite parent's mandatory fields for fields which are defined in this.
965 for( FIELD_T fieldId : MANDATORY_FIELDS )
966 {
967 if( !GetField( fieldId )->GetText().IsEmpty() )
968 *retv->GetField( fieldId ) = *GetField( fieldId );
969 }
970
971 // Grab all the rest of derived symbol fields.
972 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
973 {
974 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
975
976 // Mandatory fields were already resolved.
977 if( field->IsMandatory() )
978 continue;
979
980 SCH_FIELD* newField = new SCH_FIELD( *field );
981 newField->SetParent( retv.get() );
982
983 SCH_FIELD* parentField = retv->GetField( field->GetName() );
984
985 if( !parentField ) // Derived symbol field does not exist in parent symbol.
986 {
987 retv->AddDrawItem( newField );
988 }
989 else // Derived symbol field overrides the parent symbol field.
990 {
991 retv->RemoveDrawItem( parentField );
992 retv->AddDrawItem( newField );
993 }
994 }
995
996 // Use this symbol's keywords/filters if set, otherwise keep inherited ones
997 if( !m_keyWords.IsEmpty() )
998 retv->SetKeyWords( m_keyWords );
999
1000 if( !m_fpFilters.IsEmpty() )
1001 retv->SetFPFilters( m_fpFilters );
1002
1003 for( const auto& file : EmbeddedFileMap() )
1004 {
1005 EMBEDDED_FILES::EMBEDDED_FILE* newFile = new EMBEDDED_FILES::EMBEDDED_FILE( *file.second );
1006 retv->AddFile( newFile );
1007 }
1008
1009 // Get excluded flags from the immediate parent (first in chain)
1010 if( !parentChain.empty() )
1011 {
1012 retv->SetExcludedFromSim( parentChain.front()->GetExcludedFromSim() );
1013 retv->SetExcludedFromBOM( parentChain.front()->GetExcludedFromBOM() );
1014 retv->SetExcludedFromBoard( parentChain.front()->GetExcludedFromBoard() );
1015 retv->SetExcludedFromPosFiles( parentChain.front()->GetExcludedFromPosFiles() );
1016 }
1017
1018 // Pin maps and associated footprints inherit as a coupled bundle; copy the resolved
1019 // effective bundle so the flattened symbol is self-contained.
1020 retv->m_pinMaps = GetEffectivePinMaps();
1021 retv->m_associatedFootprints = GetEffectiveAssociatedFootprints();
1022
1023 retv->m_parent.reset();
1024 }
1025 else
1026 {
1027 retv = std::make_unique<LIB_SYMBOL>( *this );
1028 }
1029
1030 return retv;
1031}
1032
1033
1035{
1036 m_library = aLibrary;
1037
1038 if( m_searchTermsCache.empty() )
1040
1042}
1043
1044
1045const wxString LIB_SYMBOL::GetLibraryName() const
1046{
1047 if( m_library )
1048 return m_library->GetName();
1049
1050 return m_libId.GetLibNickname();
1051}
1052
1053
1055{
1056 if( IsDerived() )
1057 {
1058 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1059
1060 if( root.get() != this )
1061 return root->IsLocalPower();
1062 }
1063
1064 return m_options == ENTRY_LOCAL_POWER;
1065}
1066
1067
1069{
1070 if( IsDerived() )
1071 {
1072 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1073
1074 if( root.get() != this )
1075 {
1076 root->SetLocalPower();
1077 return;
1078 }
1079 }
1080
1082}
1083
1084
1086{
1087 if( IsDerived() )
1088 {
1089 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1090
1091 if( root.get() != this )
1092 return root->IsGlobalPower();
1093 }
1094
1095 return m_options == ENTRY_GLOBAL_POWER;
1096}
1097
1098
1100{
1101 return IsLocalPower() || IsGlobalPower();
1102}
1103
1104
1106{
1107 if( IsDerived() )
1108 {
1109 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1110
1111 if( root.get() != this )
1112 {
1113 root->SetGlobalPower();
1114 return;
1115 }
1116 }
1117
1119}
1120
1121
1123{
1124 if( IsDerived() )
1125 {
1126 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1127
1128 if( root.get() != this )
1129 return root->IsNormal();
1130 }
1131
1132 return m_options == ENTRY_NORMAL;
1133}
1134
1135
1137{
1138 if( IsDerived() )
1139 {
1140 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1141
1142 if( root.get() != this )
1143 {
1144 root->SetNormal();
1145 return;
1146 }
1147 }
1148
1150}
1151
1152
1153wxString LIB_SYMBOL::LetterSubReference( int aUnit, wxChar aInitialLetter )
1154{
1155 // use letters as notation. To allow more than 26 units, the sub ref
1156 // use one letter if letter = A .. Z or a ... z, and 2 letters otherwise
1157 // first letter is expected to be 'A' or 'a' (i.e. 26 letters are available)
1158 int u;
1159 wxString suffix;
1160
1161 do
1162 {
1163 u = ( aUnit - 1 ) % 26;
1164 suffix = wxChar( aInitialLetter + u ) + suffix;
1165 aUnit = ( aUnit - u ) / 26;
1166 } while( aUnit > 0 );
1167
1168 return suffix;
1169}
1170
1171
1172bool LIB_SYMBOL::ResolveTextVar( wxString* token, int aDepth ) const
1173{
1174 wxString footprint;
1175
1176 for( const SCH_ITEM& item : m_drawings )
1177 {
1178 if( item.Type() == SCH_FIELD_T )
1179 {
1180 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
1181
1182 if( field.GetId() == FIELD_T::FOOTPRINT )
1183 footprint = field.GetShownText( nullptr, INTERNAL, wxEmptyString, aDepth + 1 );
1184
1185 if( token->IsSameAs( field.GetUntranslatedName().Upper() ) || token->IsSameAs( field.GetName(), false ) )
1186 {
1187 *token = field.GetShownText( nullptr, INTERNAL, wxEmptyString, aDepth + 1 );
1188 return true;
1189 }
1190 }
1191 }
1192
1193 // Consider missing simulation fields as empty, not un-resolved
1194 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
1195 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
1196 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
1197 {
1198 *token = wxEmptyString;
1199 return true;
1200 }
1201
1202 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1203 {
1204 wxArrayString parts = wxSplit( footprint, ':' );
1205
1206 if( parts.Count() > 0 )
1207 *token = parts[0];
1208 else
1209 *token = wxEmptyString;
1210
1211 return true;
1212 }
1213 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1214 {
1215 wxArrayString parts = wxSplit( footprint, ':' );
1216
1217 if( parts.Count() > 1 )
1218 *token = parts[std::min( 1, (int) parts.size() - 1 )];
1219 else
1220 *token = wxEmptyString;
1221
1222 return true;
1223 }
1224 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
1225 {
1226 *token = m_libId.GetUniStringLibNickname();
1227 return true;
1228 }
1229 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
1230 {
1231 *token = m_libId.GetUniStringLibItemName();
1232 return true;
1233 }
1234 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
1235 {
1236 *token = GetShownDescription( INTERNAL, aDepth + 1 );
1237 return true;
1238 }
1239 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
1240 {
1241 *token = GetShownKeyWords( INTERNAL, aDepth + 1 );
1242 return true;
1243 }
1244 else if( token->IsSameAs( wxT( "SYMBOL_IS_POWER" ) ) )
1245 {
1246 *token = this->IsPower() ? wxString( wxS( "Power Symbol" ) ) : wxString( "" );
1247 return true;
1248 }
1249 else if( token->IsSameAs( wxT( "SYMBOL_IS_LOCAL_POWER" ) ) )
1250 {
1251 *token = this->IsLocalPower() ? wxString( wxS( "Local Power Symbol" ) ) : wxString( "" );
1252 return true;
1253 }
1254 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
1255 {
1256 *token = this->GetExcludedFromBOM() ? wxS( "Excluded from BOM" ) : wxEmptyString;
1257 return true;
1258 }
1259 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
1260 {
1261 *token = this->GetExcludedFromBoard() ? wxS( "Excluded from board" ) : wxEmptyString;
1262 return true;
1263 }
1264 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
1265 {
1266 *token = this->GetExcludedFromSim() ? wxS( "Excluded from simulation" ) : wxEmptyString;
1267 return true;
1268 }
1269 else if( token->IsSameAs( wxT( "DNP" ) ) )
1270 {
1271 *token = this->GetDNP() ? wxS( "DNP" ) : wxEmptyString;
1272 return true;
1273 }
1274
1275 return false;
1276}
1277
1278
1279void LIB_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
1280 const VECTOR2I& aOffset, bool aDimmed )
1281{
1282 wxASSERT( aPlotter != nullptr );
1283
1284 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
1285 COLOR4D color = renderSettings->GetLayerColor( LAYER_DEVICE );
1286 COLOR4D bg = renderSettings->GetBackgroundColor();
1287
1288 if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
1289 bg = COLOR4D::WHITE;
1290
1291 if( color.m_text && Schematic() )
1292 color = COLOR4D( ResolveText( *color.m_text, &Schematic()->CurrentSheet() ) );
1293
1294 if( aDimmed )
1295 {
1296 color.Desaturate();
1297 color = color.Mix( bg, 0.5f );
1298 }
1299
1300 aPlotter->SetColor( color );
1301
1302 for( SCH_ITEM& item : m_drawings )
1303 {
1304 // Do not plot private items
1305 if( item.IsPrivate() )
1306 continue;
1307
1308 // LIB_FIELDs are not plotted here, because this plot function is used to plot schematic
1309 // items which have their own SCH_FIELDs
1310 if( item.Type() == SCH_FIELD_T )
1311 continue;
1312
1313 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
1314 continue;
1315
1316 if( aBodyStyle && item.m_bodyStyle && ( item.m_bodyStyle != aBodyStyle ) )
1317 continue;
1318
1319 item.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1320 }
1321}
1322
1323
1324void LIB_SYMBOL::PlotFields( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit,
1325 int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
1326{
1327 wxASSERT( aPlotter != nullptr );
1328
1329 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
1330 COLOR4D color = renderSettings->GetLayerColor( LAYER_FIELDS );
1331 COLOR4D bg = renderSettings->GetBackgroundColor();
1332
1333 if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
1334 bg = COLOR4D::WHITE;
1335
1336 if( aDimmed )
1337 {
1338 color.Desaturate();
1339 color = color.Mix( bg, 0.5f );
1340 }
1341
1342 aPlotter->SetColor( color );
1343
1344 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
1345 {
1346 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
1347
1348 if( !renderSettings->m_ShowHiddenFields && !field.IsVisible() )
1349 continue;
1350
1351 // The reference is a special case: we should change the basic text
1352 // to add '?' and the part id
1353 wxString tmp = field.GetText();
1354
1355 field.SetText( field.GetFullText( aUnit ) );
1356 item.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1357
1358 field.SetText( tmp );
1359 }
1360}
1361
1362
1364{
1365 std::vector<SCH_SHAPE*> potential_top_items;
1366 std::vector<SCH_ITEM*> bottom_items;
1367
1368 for( SCH_ITEM& item : m_drawings )
1369 {
1370 if( item.Type() == SCH_SHAPE_T )
1371 {
1372 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
1373
1374 if( shape.GetFillMode() == FILL_T::FILLED_WITH_COLOR )
1375 potential_top_items.push_back( &shape );
1376 else
1377 bottom_items.push_back( &item );
1378 }
1379 else
1380 {
1381 bottom_items.push_back( &item );
1382 }
1383 }
1384
1385 std::sort( potential_top_items.begin(), potential_top_items.end(),
1386 []( SCH_ITEM* a, SCH_ITEM* b )
1387 {
1388 return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
1389 } );
1390
1391 for( SCH_SHAPE* item : potential_top_items )
1392 {
1393 for( SCH_ITEM* bottom_item : bottom_items )
1394 {
1395 if( item->GetBoundingBox().Contains( bottom_item->GetBoundingBox() ) )
1396 {
1397 item->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1398 break;
1399 }
1400 }
1401 }
1402}
1403
1404
1406{
1407 wxASSERT( aItem != nullptr );
1408
1409 // none of the MANDATORY_FIELDS may be removed in RAM, but they may be
1410 // omitted when saving to disk.
1411 if( aItem->Type() == SCH_FIELD_T )
1412 {
1413 if( static_cast<SCH_FIELD*>( aItem )->IsMandatory() )
1414 return;
1415 }
1416
1417 LIB_ITEMS& items = m_drawings[aItem->Type()];
1418
1419 for( LIB_ITEMS::iterator i = items.begin(); i != items.end(); i++ )
1420 {
1421 if( &*i == aItem )
1422 {
1423 items.erase( i );
1424 cachePinCount();
1426 break;
1427 }
1428 }
1429}
1430
1431
1432void LIB_SYMBOL::AddDrawItem( SCH_ITEM* aItem, bool aSort )
1433{
1434 if( aItem )
1435 {
1436 aItem->SetParent( this );
1437
1438 m_drawings.push_back( aItem );
1439
1440 if( aSort )
1441 m_drawings.sort();
1442
1443 cachePinCount();
1445 }
1446}
1447
1448
1449std::vector<const SCH_PIN*> LIB_SYMBOL::GetGraphicalPins( int aUnit, int aBodyStyle ) const
1450{
1451 if( IsDerived() )
1452 {
1453 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1454
1455 if( root.get() != this )
1456 return const_cast<const LIB_SYMBOL*>( root.get() )->GetGraphicalPins( aUnit, aBodyStyle );
1457 }
1458
1459 std::vector<const SCH_PIN*> pins;
1460
1461 /* Notes:
1462 * when aUnit == 0: no unit filtering
1463 * when aBodyStyle == 0: no body style filtering
1464 * when m_unit == 0, the item is common to all units
1465 * when m_bodyStyle == 0, the item is common to all body styles
1466 */
1467
1468 for( const SCH_ITEM& item : m_drawings[SCH_PIN_T] )
1469 {
1470 // Unit filtering:
1471 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
1472 continue;
1473
1474 // Body style filtering:
1475 if( aBodyStyle && item.m_bodyStyle && ( item.m_bodyStyle != aBodyStyle ) )
1476 continue;
1477
1478 pins.push_back( static_cast<const SCH_PIN*>( &item ) );
1479 }
1480
1481 return pins;
1482}
1483
1484
1485std::vector<SCH_PIN*> LIB_SYMBOL::GetGraphicalPins( int aUnit, int aBodyStyle )
1486{
1487 if( IsDerived() )
1488 {
1489 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1490
1491 if( root.get() != this )
1492 return root->GetGraphicalPins( aUnit, aBodyStyle );
1493 }
1494
1495 std::vector<SCH_PIN*> pins;
1496
1497 /* Notes:
1498 * when aUnit == 0: no unit filtering
1499 * when aBodyStyle == 0: no body style filtering
1500 * when m_unit == 0, the item is common to all units
1501 * when m_bodyStyle == 0, the item is common to all body styles
1502 */
1503
1504 for( SCH_ITEM& item : m_drawings[SCH_PIN_T] )
1505 {
1506 // Unit filtering:
1507 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
1508 continue;
1509
1510 // Body style filtering:
1511 if( aBodyStyle && item.m_bodyStyle && ( item.m_bodyStyle != aBodyStyle ) )
1512 continue;
1513
1514 pins.push_back( static_cast<SCH_PIN*>( &item ) );
1515 }
1516
1517 return pins;
1518}
1519
1520
1521std::vector<LIB_SYMBOL::UNIT_PIN_INFO> LIB_SYMBOL::GetUnitPinInfo() const
1522{
1523 std::vector<UNIT_PIN_INFO> units;
1524
1525 int unitCount = std::max( GetUnitCount(), 1 );
1526
1527 auto compareByPosition =
1528 []( const SCH_PIN* a, const SCH_PIN* b )
1529 {
1530 VECTOR2I positionA = a->GetPosition();
1531 VECTOR2I positionB = b->GetPosition();
1532
1533 if( positionA.x != positionB.x )
1534 return positionA.x < positionB.x;
1535
1536 return positionA.y < positionB.y;
1537 };
1538
1539 for( int unitIdx = 1; unitIdx <= unitCount; ++unitIdx )
1540 {
1541 UNIT_PIN_INFO unitInfo;
1542 unitInfo.m_unitName = GetUnitDisplayName( unitIdx, false );
1543
1544 std::vector<const SCH_PIN*> pinList = GetGraphicalPins( unitIdx, 0 );
1545
1546 std::sort( pinList.begin(), pinList.end(), compareByPosition );
1547
1548 std::unordered_set<wxString> seenNumbers;
1549
1550 for( const SCH_PIN* basePin : pinList )
1551 {
1552 bool stackedValid = false;
1553 std::vector<wxString> expandedNumbers = basePin->GetStackedPinNumbers( &stackedValid );
1554
1555 if( stackedValid && !expandedNumbers.empty() )
1556 {
1557 for( const wxString& number : expandedNumbers )
1558 {
1559 if( seenNumbers.insert( number ).second )
1560 unitInfo.m_pinNumbers.push_back( number );
1561 }
1562
1563 continue;
1564 }
1565
1566 const wxString& number = basePin->GetNumber();
1567
1568 if( !number.IsEmpty() && seenNumbers.insert( number ).second )
1569 unitInfo.m_pinNumbers.push_back( number );
1570 }
1571
1572 units.push_back( std::move( unitInfo ) );
1573 }
1574
1575 return units;
1576}
1577
1578
1579std::vector<LIB_SYMBOL::LOGICAL_PIN> LIB_SYMBOL::GetLogicalPins( int aUnit, int aBodyStyle ) const
1580{
1581 std::vector<LOGICAL_PIN> out;
1582
1583 for( const SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1584 {
1585 bool valid = false;
1586 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &valid );
1587
1588 if( valid && !expanded.empty() )
1589 {
1590 for( const wxString& num : expanded )
1591 {
1592 out.push_back( LOGICAL_PIN{ pin, num } );
1593 wxLogTrace( traceStackedPins, "GetLogicalPins: base='%s' -> '%s'", pin->GetShownNumber(), num );
1594 }
1595 }
1596 else
1597 {
1598 out.push_back( LOGICAL_PIN{ pin, pin->GetShownNumber() } );
1599 wxLogTrace( traceStackedPins, "GetLogicalPins: base='%s' (no expansion)", pin->GetShownNumber() );
1600 }
1601 }
1602
1603 return out;
1604}
1605
1606
1608{
1609 return m_pinCountCache;
1610}
1611
1612
1614{
1615 m_pinCountCache = 0;
1616
1617 for( SCH_PIN* pin : GetGraphicalPins( 0 /* all units */, 1 /* single body style */ ) )
1618 {
1619 int pinCount = pin->GetStackedPinCount();
1620 m_pinCountCache += pinCount;
1621 }
1622}
1623
1624
1625const SCH_PIN* LIB_SYMBOL::GetPin( const wxString& aNumber, int aUnit, int aBodyStyle ) const
1626{
1627 for( const SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1628 {
1629 if( aNumber == pin->GetNumber() )
1630 return pin;
1631 }
1632
1633 return nullptr;
1634}
1635
1636
1637std::vector<SCH_PIN*> LIB_SYMBOL::GetPinsByNumber( const wxString& aNumber, int aUnit, int aBodyStyle )
1638{
1639 std::vector<SCH_PIN*> pins;
1640
1641 for( SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1642 {
1643 if( aNumber == pin->GetNumber() )
1644 pins.push_back( pin );
1645 }
1646
1647 return pins;
1648}
1649
1650
1651bool LIB_SYMBOL::HasPinNumber( const wxString& aNumber ) const
1652{
1653 if( GetPin( aNumber ) )
1654 return true;
1655
1656 for( const SCH_PIN* pin : GetGraphicalPins( 0, 0 ) )
1657 {
1658 for( const wxString& logicalNumber : pin->GetStackedPinNumbers() )
1659 {
1660 if( aNumber == logicalNumber )
1661 return true;
1662 }
1663 }
1664
1665 return false;
1666}
1667
1668
1669bool LIB_SYMBOL::PinsConflictWith( const LIB_SYMBOL& aOtherPart, bool aTestNums, bool aTestNames, bool aTestType,
1670 bool aTestOrientation, bool aTestLength ) const
1671{
1672 for( const SCH_PIN* pin : GetGraphicalPins() )
1673 {
1674 wxASSERT( pin );
1675 bool foundMatch = false;
1676
1677 for( const SCH_PIN* otherPin : aOtherPart.GetGraphicalPins() )
1678 {
1679 wxASSERT( otherPin );
1680
1681 // Same unit?
1682 if( pin->GetUnit() != otherPin->GetUnit() )
1683 continue;
1684
1685 // Same body stype?
1686 if( pin->GetBodyStyle() != otherPin->GetBodyStyle() )
1687 continue;
1688
1689 // Same position?
1690 if( pin->GetPosition() != otherPin->GetPosition() )
1691 continue;
1692
1693 // Same number?
1694 if( aTestNums && ( pin->GetNumber() != otherPin->GetNumber() ) )
1695 continue;
1696
1697 // Same name?
1698 if( aTestNames && ( pin->GetName() != otherPin->GetName() ) )
1699 continue;
1700
1701 // Same electrical type?
1702 if( aTestType && ( pin->GetType() != otherPin->GetType() ) )
1703 continue;
1704
1705 // Same orientation?
1706 if( aTestOrientation && ( pin->GetOrientation() != otherPin->GetOrientation() ) )
1707 continue;
1708
1709 // Same length?
1710 if( aTestLength && ( pin->GetLength() != otherPin->GetLength() ) )
1711 continue;
1712
1713 foundMatch = true;
1714 break; // Match found so search is complete.
1715 }
1716
1717 if( !foundMatch )
1718 {
1719 // This means there was not an identical (according to the arguments)
1720 // pin at the same position in the other symbol.
1721 return true;
1722 }
1723 }
1724
1725 // The loop never gave up, so no conflicts were found.
1726 return false;
1727}
1728
1729std::vector<SCH_PIN*> LIB_SYMBOL::GetPins() const
1730{
1731 // Back-compat shim: return graphical pins for all units/body styles, violating const
1732 return const_cast<LIB_SYMBOL*>( this )->GetGraphicalPins( 0, 0 );
1733}
1734
1735
1736const BOX2I LIB_SYMBOL::GetUnitBoundingBox( int aUnit, int aBodyStyle, bool aIgnoreHiddenFields,
1737 bool aIgnoreLabelsOnInvisiblePins ) const
1738{
1739 BOX2I bBox; // Start with a fresh BOX2I so the Merge algorithm works
1740
1741 if( IsDerived() )
1742 {
1743 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1744
1745 if( root.get() != this )
1746 bBox = root->GetUnitBoundingBox( aUnit, aBodyStyle, aIgnoreHiddenFields, aIgnoreLabelsOnInvisiblePins );
1747 }
1748
1749 for( const SCH_ITEM& item : m_drawings )
1750 {
1751 if( item.m_unit > 0 && m_unitCount > 1 && aUnit > 0 && aUnit != item.m_unit )
1752 continue;
1753
1754 if( item.m_bodyStyle > 0 && aBodyStyle > 0 && aBodyStyle != item.m_bodyStyle )
1755 continue;
1756
1757 if( aIgnoreHiddenFields && item.Type() == SCH_FIELD_T )
1758 {
1759 if( !static_cast<const SCH_FIELD&>( item ).IsVisible() )
1760 continue;
1761 }
1762
1763 if( item.Type() == SCH_PIN_T && !aIgnoreLabelsOnInvisiblePins )
1764 {
1765 const SCH_PIN& pin = static_cast<const SCH_PIN&>( item );
1766 bBox.Merge( pin.GetBoundingBox( true, true, false ) );
1767 }
1768 else
1769 {
1770 bBox.Merge( item.GetBoundingBox() );
1771 }
1772 }
1773
1774 return bBox;
1775}
1776
1777
1778const BOX2I LIB_SYMBOL::GetBodyBoundingBox( int aUnit, int aBodyStyle, bool aIncludePins,
1779 bool aIncludePrivateItems ) const
1780{
1781 BOX2I bbox;
1782
1783 for( const SCH_ITEM& item : m_drawings )
1784 {
1785 if( item.m_unit > 0 && aUnit > 0 && aUnit != item.m_unit )
1786 continue;
1787
1788 if( item.m_bodyStyle > 0 && aBodyStyle > 0 && aBodyStyle != item.m_bodyStyle )
1789 continue;
1790
1791 if( item.IsPrivate() && !aIncludePrivateItems )
1792 continue;
1793
1794 if( item.Type() == SCH_FIELD_T )
1795 continue;
1796
1797 if( item.Type() == SCH_PIN_T )
1798 {
1799 const SCH_PIN& pin = static_cast<const SCH_PIN&>( item );
1800
1801 if( pin.IsVisible() )
1802 {
1803 // Note: the roots of the pins are always included for symbols that don't have
1804 // a well-defined body.
1805
1806 if( aIncludePins )
1807 bbox.Merge( pin.GetBoundingBox( false, false, false ) );
1808 else
1809 bbox.Merge( pin.GetPinRoot() );
1810 }
1811 }
1812 else
1813 {
1814 bbox.Merge( item.GetBoundingBox() );
1815 }
1816 }
1817
1818 return bbox;
1819}
1820
1821
1823{
1824 // cacheSearchTerms() reads the shown-description cache, so refresh it first.
1827 cachePinCount();
1829}
1830
1831
1838
1839
1841{
1842 AddDrawItem( aField );
1843}
1844
1845
1846void LIB_SYMBOL::SetFields( const std::vector<SCH_FIELD>& aFieldsList )
1847{
1849
1850 for( const SCH_FIELD& src : aFieldsList )
1851 {
1852 // drawings is a ptr_vector, new and copy an object on the heap.
1853 SCH_FIELD* field = new SCH_FIELD( src );
1854
1855 field->SetParent( this );
1856 m_drawings.push_back( field );
1857 }
1858
1859 m_drawings.sort();
1863}
1864
1865
1866void LIB_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aList, bool aVisibleOnly ) const
1867{
1868 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
1869 {
1870 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
1871
1872 if( aVisibleOnly )
1873 {
1874 if( !field->IsVisible() || field->GetText().IsEmpty() )
1875 continue;
1876 }
1877
1878 aList.push_back( const_cast<SCH_FIELD*>( field ) );
1879 }
1880
1881 std::sort( aList.begin(), aList.end(),
1882 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1883 {
1884 return lhs->GetOrdinal() < rhs->GetOrdinal();
1885 } );
1886}
1887
1888
1889void LIB_SYMBOL::CopyFields( std::vector<SCH_FIELD>& aList )
1890{
1891 std::vector<SCH_FIELD*> orderedFields;
1892
1893 GetFields( orderedFields );
1894
1895 for( SCH_FIELD* field : orderedFields )
1896 aList.emplace_back( *field );
1897}
1898
1899
1901{
1902 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
1903
1904 if( !parent )
1905 return;
1906
1907 std::unique_ptr<LIB_SYMBOL> flattenedParent = parent->Flatten();
1908
1909 auto selected =
1910 [&]( const wxString& aFieldName )
1911 {
1912 return aOptions.m_updateAllFields
1913 || aOptions.m_updateFields.count( aFieldName ) > 0;
1914 };
1915
1916 std::vector<SCH_FIELD> fields;
1917 std::vector<SCH_FIELD> result;
1918 CopyFields( fields );
1919
1920 for( SCH_FIELD& field : fields )
1921 {
1922 bool copy = true;
1923 SCH_FIELD* parentField = nullptr;
1924
1925 if( selected( field.GetName() ) )
1926 {
1927 if( field.IsMandatory() )
1928 parentField = flattenedParent->GetField( field.GetId() );
1929 else
1930 parentField = flattenedParent->GetField( field.GetName() );
1931
1932 if( parentField )
1933 {
1934 bool resetText = parentField->GetText().IsEmpty() ? aOptions.m_resetEmptyText
1935 : aOptions.m_resetText;
1936
1937 if( resetText )
1938 field.SetText( parentField->GetText() );
1939
1940 if( aOptions.m_resetVisibility )
1941 {
1942 field.SetVisible( parentField->IsVisible() );
1943 field.SetNameShown( parentField->IsNameShown() );
1944 }
1945
1946 if( aOptions.m_resetEffects )
1947 {
1948 // SetAttributes() also overwrites the visible bit and position, so save
1949 // and restore them here.
1950 bool visible = field.IsVisible();
1951 VECTOR2I pos = field.GetPosition();
1952
1953 field.SetAttributes( *parentField );
1954
1955 field.SetVisible( visible );
1956 field.SetPosition( pos );
1957 }
1958
1959 if( aOptions.m_resetPositions )
1960 field.SetTextPos( parentField->GetTextPos() );
1961 }
1962 else if( aOptions.m_removeExtraFields )
1963 {
1964 copy = false;
1965 }
1966 }
1967
1968 if( copy )
1969 result.emplace_back( std::move( field ) );
1970 }
1971
1972 std::vector<SCH_FIELD*> parentFields;
1973
1974 flattenedParent->GetFields( parentFields );
1975
1976 for( SCH_FIELD* parentField : parentFields )
1977 {
1978 if( !selected( parentField->GetName() ) )
1979 continue;
1980
1981 if( !GetField( parentField->GetName() ) )
1982 {
1983 result.emplace_back( this, FIELD_T::USER );
1984 SCH_FIELD* newField = &result.back();
1985
1986 newField->SetName( parentField->GetUntranslatedName() );
1987 newField->SetText( parentField->GetText() );
1988 newField->SetAttributes( *parentField ); // Includes visible bit and position
1989 }
1990 }
1991
1992 SetFields( result );
1993}
1994
1995
1997{
1998 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T id
1999
2000 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2001 ordinal = std::max( ordinal, static_cast<const SCH_FIELD*>( &item )->GetOrdinal() + 1 );
2002
2003 return ordinal;
2004}
2005
2006
2007const SCH_FIELD* LIB_SYMBOL::GetField( FIELD_T aFieldType ) const
2008{
2009 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2010 {
2011 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
2012
2013 if( field->GetId() == aFieldType )
2014 return field;
2015 }
2016
2017 return nullptr;
2018}
2019
2020
2022{
2023 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2024 {
2025 SCH_FIELD* field = static_cast<SCH_FIELD*>( &item );
2026
2027 if( field->GetId() == aFieldType )
2028 return field;
2029 }
2030
2031 return nullptr;
2032}
2033
2034
2035const SCH_FIELD* LIB_SYMBOL::GetField( const wxString& aFieldName ) const
2036{
2037 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2038 {
2039 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
2040
2041 if( field.GetName() == aFieldName )
2042 return &field;
2043 }
2044
2045 return nullptr;
2046}
2047
2048
2049SCH_FIELD* LIB_SYMBOL::GetField( const wxString& aFieldName )
2050{
2051 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2052 {
2053 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
2054
2055 if( field.GetName() == aFieldName )
2056 return &field;
2057 }
2058
2059 return nullptr;
2060}
2061
2062
2064{
2065 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2066 {
2067 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
2068
2069 if( field.GetUntranslatedName().IsSameAs( aFieldName, false ) )
2070 return &field;
2071 }
2072
2073 return nullptr;
2074}
2075
2076
2077const SCH_FIELD* LIB_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
2078{
2079 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2080 {
2081 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
2082
2083 if( field.GetUntranslatedName().IsSameAs( aFieldName, false ) )
2084 return &field;
2085 }
2086
2087 return nullptr;
2088}
2089
2090
2092{
2093 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
2094 wxASSERT( field != nullptr );
2095 return *field;
2096}
2097
2098
2100{
2101 const SCH_FIELD* field = GetField( FIELD_T::REFERENCE );
2102 wxASSERT( field != nullptr );
2103 return *field;
2104}
2105
2106
2108{
2109 const SCH_FIELD* field = GetField( FIELD_T::FOOTPRINT );
2110 wxASSERT( field != nullptr );
2111 return *field;
2112}
2113
2114
2116{
2117 const SCH_FIELD* field = GetField( FIELD_T::DATASHEET );
2118 wxASSERT( field != nullptr );
2119 return *field;
2120}
2121
2122
2124{
2125 const SCH_FIELD* field = GetField( FIELD_T::DESCRIPTION );
2126 wxASSERT( field != nullptr );
2127 return *field;
2128}
2129
2130
2132{
2133 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
2134
2135 refDesignator.Replace( wxS( "~" ), wxS( " " ) );
2136
2137 wxString prefix = refDesignator;
2138
2139 while( prefix.Length() )
2140 {
2141 wxUniCharRef last = prefix.Last();
2142
2143 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
2144 prefix.RemoveLast();
2145 else
2146 break;
2147 }
2148
2149 // Avoid a prefix containing trailing/leading spaces
2150 prefix.Trim( true );
2151 prefix.Trim( false );
2152
2153 return prefix;
2154}
2155
2156
2157void LIB_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
2158{
2159 for( SCH_ITEM& item : m_drawings )
2160 aFunction( &item );
2161}
2162
2163
2164void LIB_SYMBOL::Move( const VECTOR2I& aOffset )
2165{
2166 for( SCH_ITEM& item : m_drawings )
2167 item.Move( aOffset );
2168}
2169
2170
2171// Before V10 we didn't store the number of body styles in a symbol -- we just looked through all
2172// its drawings each time we wanted to know. This is now only used to set the count when a legacy
2173// symbol is first read. (Legacy symbols also didn't support arbitrary body styles, so the count
2174// is always 1 or 2, and when 2 it is always a De Morgan pair.)
2176{
2177 for( const SCH_ITEM& item : m_drawings )
2178 {
2179 if( item.m_bodyStyle > BODY_STYLE::BASE )
2180 return true;
2181 }
2182
2183 if( IsDerived() )
2184 {
2185 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2186
2187 if( root.get() != this )
2188 return root->HasLegacyAlternateBodyStyle();
2189 }
2190
2191 return false;
2192}
2193
2194
2196{
2197 if( IsDerived() )
2198 {
2199 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2200
2201 if( root.get() != this )
2202 return root->GetMaxPinNumber();
2203 }
2204
2205 int maxPinNumber = 0;
2206
2207 for( const SCH_ITEM& item : m_drawings[SCH_PIN_T] )
2208 {
2209 const SCH_PIN* pin = static_cast<const SCH_PIN*>( &item );
2210 long currentPinNumber = 0;
2211
2212 if( pin->GetNumber().ToLong( &currentPinNumber ) )
2213 maxPinNumber = std::max( maxPinNumber, (int) currentPinNumber );
2214 }
2215
2216 return maxPinNumber;
2217}
2218
2219
2221{
2223
2224 for( SCH_ITEM& item : m_drawings )
2225 item.ClearTempFlags();
2226}
2227
2228
2230{
2232
2233 for( SCH_ITEM& item : m_drawings )
2234 item.ClearEditFlags();
2235}
2236
2237
2238SCH_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I& aPoint )
2239{
2240 for( SCH_ITEM& item : m_drawings )
2241 {
2242 if( ( aUnit && item.m_unit && aUnit != item.m_unit )
2243 || ( aBodyStyle && item.m_bodyStyle && aBodyStyle != item.m_bodyStyle )
2244 || ( item.Type() != aType && aType != TYPE_NOT_INIT ) )
2245 {
2246 continue;
2247 }
2248
2249 if( item.HitTest( aPoint ) )
2250 return &item;
2251 }
2252
2253 return nullptr;
2254}
2255
2256
2257SCH_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I& aPoint,
2258 const TRANSFORM& aTransform )
2259{
2260 /* we use LocateDrawItem( int aUnit, int convert, KICAD_T type, const
2261 * VECTOR2I& pt ) to search items.
2262 * because this function uses DefaultTransform as orient/mirror matrix
2263 * we temporary copy aTransform in DefaultTransform
2264 */
2265 TRANSFORM transform = DefaultTransform;
2266 DefaultTransform = aTransform;
2267
2268 SCH_ITEM* item = LocateDrawItem( aUnit, aBodyStyle, aType, aPoint );
2269
2270 // Restore matrix
2271 DefaultTransform = transform;
2272
2273 return item;
2274}
2275
2276
2277INSPECT_RESULT LIB_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
2278{
2279 // The part itself is never inspected, only its children
2280 for( SCH_ITEM& item : m_drawings )
2281 {
2282 if( item.IsType( aScanTypes ) )
2283 {
2284 if( aInspector( &item, aTestData ) == INSPECT_RESULT::QUIT )
2285 return INSPECT_RESULT::QUIT;
2286 }
2287 }
2288
2290}
2291
2292
2293void LIB_SYMBOL::SetUnitCount( int aCount, bool aDuplicateDrawItems )
2294{
2295 // A LIB_SYMBOL must always have at least one unit. Passing a value less than 1 would
2296 // erase the mandatory fields (which all have m_unit == 0), leaving the symbol in a
2297 // broken state that crashes later when callers dereference GetReferenceField() etc.
2298 wxCHECK_RET( aCount >= 1, wxString::Format( wxT( "Invalid unit count %d, ignoring." ), aCount ) );
2299
2300 if( m_unitCount == aCount )
2301 return;
2302
2303 if( aCount < m_unitCount )
2304 {
2305 // Iterate each drawing-type bucket and erase items that belong to units > aCount.
2306 for( int type = LIB_ITEMS_CONTAINER::FIRST_TYPE; type <= LIB_ITEMS_CONTAINER::LAST_TYPE; ++type )
2307 {
2308 auto it = m_drawings.begin( type );
2309
2310 while( it != m_drawings.end( type ) )
2311 {
2312 if( it->m_unit > aCount )
2313 it = m_drawings.erase( it ); // returns next iterator
2314 else
2315 ++it;
2316 }
2317 }
2318 }
2319 else if( aDuplicateDrawItems )
2320 {
2321 int prevCount = m_unitCount;
2322
2323 // Temporary storage for new items, as adding new items directly to
2324 // m_drawings may cause the buffer reallocation which invalidates the
2325 // iterators
2326 std::vector<SCH_ITEM*> tmp;
2327
2328 for( SCH_ITEM& item : m_drawings )
2329 {
2330 if( item.m_unit != 1 )
2331 continue;
2332
2333 for( int j = prevCount + 1; j <= aCount; j++ )
2334 {
2335 SCH_ITEM* newItem = item.Duplicate( IGNORE_PARENT_GROUP );
2336 newItem->m_unit = j;
2337 tmp.push_back( newItem );
2338 }
2339 }
2340
2341 for( SCH_ITEM* item : tmp )
2342 m_drawings.push_back( item );
2343 }
2344
2345 m_drawings.sort();
2346 m_unitCount = aCount;
2348}
2349
2350
2352{
2353 if( IsDerived() )
2354 {
2355 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2356
2357 if( root.get() != this )
2358 return root->GetUnitCount();
2359 }
2360
2361 return m_unitCount;
2362}
2363
2364
2366{
2367 if( HasDeMorganBodyStyles() )
2368 return 2;
2369
2370 return std::max( 1, (int) GetBodyStyleNames().size() );
2371}
2372
2373
2375{
2376 if( IsDerived() )
2377 {
2378 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2379
2380 if( root.get() != this )
2381 return root->m_demorgan;
2382 }
2383
2384 return m_demorgan;
2385}
2386
2387
2388const std::vector<wxString>& LIB_SYMBOL::GetBodyStyleNames() const
2389{
2390 if( IsDerived() )
2391 {
2392 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2393
2394 if( root.get() != this )
2395 return root->m_bodyStyleNames;
2396 }
2397
2398 return m_bodyStyleNames;
2399}
2400
2401
2402void LIB_SYMBOL::SetBodyStyleCount( int aCount, bool aDuplicateDrawItems, bool aDuplicatePins )
2403{
2404 wxCHECK_RET( aCount >= 1,
2405 wxString::Format( wxT( "Invalid body style count %d, ignoring." ), aCount ) );
2406
2407 int prevCount = GetBodyStyleCount();
2408
2409 // Populate the new body styles from the standard one
2410 if( prevCount < aCount && ( aDuplicateDrawItems || aDuplicatePins ) )
2411 {
2412 std::vector<SCH_ITEM*> tmp; // Adding to m_drawings while iterating it invalidates the iterator
2413
2414 for( SCH_ITEM& item : m_drawings )
2415 {
2416 if( item.Type() != SCH_PIN_T && !aDuplicateDrawItems )
2417 continue;
2418
2419 if( item.m_bodyStyle == BODY_STYLE::BASE )
2420 {
2421 for( int j = prevCount + 1; j <= aCount; j++ )
2422 {
2423 SCH_ITEM* newItem = item.Duplicate( IGNORE_PARENT_GROUP );
2424 newItem->m_bodyStyle = j;
2425 tmp.push_back( newItem );
2426 }
2427 }
2428 }
2429
2430 for( SCH_ITEM* item : tmp )
2431 m_drawings.push_back( item );
2432
2433 m_drawings.sort();
2434 }
2435
2436 // A caller that already cleared the De Morgan flag or the body style names reports a
2437 // previous count of 1, so the deletion cannot be conditional on the count dropping
2438 PruneBodyStyleDrawItems( aCount );
2439}
2440
2441
2442void LIB_SYMBOL::PruneBodyStyleDrawItems( int aBodyStyleCount )
2443{
2445
2446 while( i != m_drawings.end() )
2447 {
2448 if( i->m_bodyStyle > aBodyStyleCount )
2449 i = m_drawings.erase( i );
2450 else
2451 ++i;
2452 }
2453}
2454
2455
2456std::vector<SCH_ITEM*> LIB_SYMBOL::GetUnitDrawItems( int aUnit, int aBodyStyle )
2457{
2458 std::vector<SCH_ITEM*> unitItems;
2459
2460 for( SCH_ITEM& item : m_drawings )
2461 {
2462 if( item.Type() == SCH_FIELD_T )
2463 continue;
2464
2465 if( ( aBodyStyle == -1 && item.GetUnit() == aUnit ) || ( aUnit == -1 && item.GetBodyStyle() == aBodyStyle )
2466 || ( aUnit == item.GetUnit() && aBodyStyle == item.GetBodyStyle() ) )
2467 {
2468 unitItems.push_back( &item );
2469 }
2470 }
2471
2472 return unitItems;
2473}
2474
2475
2476std::vector<LIB_SYMBOL_UNIT> LIB_SYMBOL::GetUnitDrawItems()
2477{
2478 std::vector<LIB_SYMBOL_UNIT> units;
2479
2480 // Enforce writing out of all defined unit/body-style combinations
2481 for( int unit = 1; unit <= GetUnitCount(); unit++ )
2482 {
2483 for( int bodyStyle = 1; bodyStyle <= GetBodyStyleCount(); bodyStyle++ )
2484 {
2485 LIB_SYMBOL_UNIT record;
2486 record.m_unit = unit;
2487 record.m_bodyStyle = bodyStyle;
2488 units.push_back( std::move( record ) );
2489 }
2490 }
2491
2492 for( SCH_ITEM& item : m_drawings )
2493 {
2494 if( item.Type() == SCH_FIELD_T )
2495 continue;
2496
2497 int unit = item.GetUnit();
2498 int bodyStyle = item.GetBodyStyle();
2499
2500 auto it = std::find_if( units.begin(), units.end(),
2501 [unit, bodyStyle]( const LIB_SYMBOL_UNIT& a )
2502 {
2503 return a.m_unit == unit && a.m_bodyStyle == bodyStyle;
2504 } );
2505
2506 if( it == units.end() )
2507 {
2508 LIB_SYMBOL_UNIT record;
2509 record.m_unit = unit;
2510 record.m_bodyStyle = bodyStyle;
2511 it = units.insert( units.end(), std::move( record ) );
2512 }
2513
2514 it->m_items.push_back( &item );
2515 }
2516
2517 std::sort( units.begin(), units.end(),
2518 []( const LIB_SYMBOL_UNIT& a, const LIB_SYMBOL_UNIT& b )
2519 {
2520 if( a.m_unit == b.m_unit )
2521 return a.m_bodyStyle < b.m_bodyStyle;
2522
2523 return a.m_unit < b.m_unit;
2524 } );
2525
2526 return units;
2527}
2528
2529
2530#define REPORT( msg ) \
2531 { \
2532 if( aReporter ) \
2533 aReporter->Report( msg ); \
2534 }
2535#define ITEM_DESC( item ) ( item )->GetItemDescription( &unitsProvider, false )
2536
2537int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags, REPORTER* aReporter ) const
2538{
2539 UNITS_PROVIDER unitsProvider( schIUScale, EDA_UNITS::MM );
2540
2541 if( m_me == aRhs.m_me )
2542 return 0;
2543
2544 int retv = 0;
2545
2546 if( aCompareFlags & COMPARE_FLAGS::IDENTITY )
2547 {
2548 if( int tmp = m_name.Cmp( aRhs.m_name ) )
2549 {
2550 retv = tmp;
2551 REPORT( _( "Name differs." ) );
2552
2553 if( !aReporter )
2554 return retv;
2555 }
2556
2557 if( int tmp = m_libId.compare( aRhs.m_libId ) )
2558 {
2559 retv = tmp;
2560 REPORT( _( "Library ID differs." ) );
2561
2562 if( !aReporter )
2563 return retv;
2564 }
2565
2566 if( m_parent.lock() < aRhs.m_parent.lock() )
2567 retv = -1;
2568 else if( m_parent.lock() > aRhs.m_parent.lock() )
2569 retv = 1;
2570
2571 if( retv )
2572 {
2573 REPORT( _( "Symbol parent differs." ) );
2574
2575 if( !aReporter )
2576 return retv;
2577 }
2578 }
2579
2580 if( m_options != aRhs.m_options )
2581 {
2582 retv = ( m_options == ENTRY_NORMAL ) ? -1 : 1;
2583 REPORT( _( "Power flag differs." ) );
2584
2585 if( !aReporter )
2586 return retv;
2587 }
2588
2589 if( int tmp = m_unitCount - aRhs.m_unitCount )
2590 {
2591 retv = tmp;
2592 REPORT( _( "Unit count differs." ) );
2593
2594 if( !aReporter )
2595 return retv;
2596 }
2597
2598 // Make sure shapes are sorted. No need with fields or pins as those are matched by id/name and number.
2599
2600 std::set<const SCH_ITEM*, SCH_ITEM::cmp_items> aShapes;
2601 std::set<const SCH_FIELD*> aFields;
2602 std::set<const SCH_PIN*> aPins;
2603
2604 for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
2605 {
2606 if( it->Type() == SCH_SHAPE_T )
2607 aShapes.insert( &( *it ) );
2608 else if( it->Type() == SCH_FIELD_T )
2609 aFields.insert( static_cast<const SCH_FIELD*>( &( *it ) ) );
2610 else if( it->Type() == SCH_PIN_T )
2611 aPins.insert( static_cast<const SCH_PIN*>( &( *it ) ) );
2612 }
2613
2614 std::set<const SCH_ITEM*, SCH_ITEM::cmp_items> bShapes;
2615 std::set<const SCH_FIELD*> bFields;
2616 std::set<const SCH_PIN*> bPins;
2617
2618 for( auto it = aRhs.m_drawings.begin(); it != aRhs.m_drawings.end(); ++it )
2619 {
2620 if( it->Type() == SCH_SHAPE_T )
2621 bShapes.insert( &( *it ) );
2622 else if( it->Type() == SCH_FIELD_T )
2623 bFields.insert( static_cast<const SCH_FIELD*>( &( *it ) ) );
2624 else if( it->Type() == SCH_PIN_T )
2625 bPins.insert( static_cast<const SCH_PIN*>( &( *it ) ) );
2626 }
2627
2628 if( int tmp = static_cast<int>( aShapes.size() - bShapes.size() ) )
2629 {
2630 retv = tmp;
2631 REPORT( _( "Graphic item count differs." ) );
2632
2633 if( !aReporter )
2634 return retv;
2635 }
2636 else
2637 {
2638 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
2639 {
2640 if( int tmp2 = ( *aIt )->compare( *( *bIt ), aCompareFlags ) )
2641 {
2642 retv = tmp2;
2643 REPORT( wxString::Format( _( "Graphic item differs: %s; %s." ),
2644 ITEM_DESC( *aIt ),
2645 ITEM_DESC( *bIt ) ) );
2646
2647 if( !aReporter )
2648 return retv;
2649 }
2650 }
2651 }
2652
2653 for( const SCH_PIN* aPin : aPins )
2654 {
2655 const SCH_PIN* bPin = aRhs.GetPin( aPin->GetNumber(), aPin->GetUnit(), aPin->GetBodyStyle() );
2656
2657 if( !bPin )
2658 {
2659 retv = 1;
2660 REPORT( wxString::Format( _( "Extra pin in schematic symbol: %s." ), ITEM_DESC( aPin ) ) );
2661
2662 if( !aReporter )
2663 return retv;
2664 }
2665 else if( int tmp = static_cast<const SCH_ITEM*>( aPin )->compare( *bPin, aCompareFlags ) )
2666 {
2667 retv = tmp;
2668 REPORT( wxString::Format( _( "Pin %s differs: %s; %s" ),
2669 aPin->GetNumber(),
2670 ITEM_DESC( aPin ),
2671 ITEM_DESC( bPin ) ) );
2672
2673 if( !aReporter )
2674 return retv;
2675 }
2676 }
2677
2678 for( const SCH_PIN* bPin : bPins )
2679 {
2680 const SCH_PIN* aPin = GetPin( bPin->GetNumber(), bPin->GetUnit(), bPin->GetBodyStyle() );
2681
2682 if( !aPin )
2683 {
2684 retv = 1;
2685 REPORT( wxString::Format( _( "Missing pin in schematic symbol: %s." ), ITEM_DESC( bPin ) ) );
2686
2687 if( !aReporter )
2688 return retv;
2689 }
2690 }
2691
2692 for( const SCH_FIELD* aField : aFields )
2693 {
2694 const SCH_FIELD* bField = nullptr;
2695
2696 if( aField->IsMandatory() )
2697 bField = aRhs.GetField( aField->GetId() );
2698 else
2699 bField = aRhs.GetField( aField->GetName() );
2700
2701 if( !bField )
2702 {
2703 if( aCompareFlags & COMPARE_FLAGS::EXTRA_FIELDS )
2704 {
2705 retv = 1;
2706 REPORT( wxString::Format( _( "Extra field in schematic symbol: %s." ), aField->GetName( false ) ) );
2707
2708 if( !aReporter )
2709 return retv;
2710 }
2711 }
2712 else
2713 {
2714 if( ( aCompareFlags & COMPARE_FLAGS::FIELD_TEXT ) && aField->GetId() != FIELD_T::REFERENCE )
2715 {
2716 if( int tmp = aField->GetText().compare( bField->GetText() ) )
2717 {
2718 retv = tmp;
2719 REPORT( wxString::Format( _( "Field '%s' differs: %s; %s." ),
2720 aField->GetName( false ),
2721 aField->GetText(),
2722 bField->GetText() ) );
2723
2724 if( !aReporter )
2725 return retv;
2726 }
2727 }
2728
2729 if( aCompareFlags & COMPARE_FLAGS::FIELD_SIZE_AND_STYLE )
2730 {
2731 if( aField->GetFont() != bField->GetFont() )
2732 {
2733 retv = std::less<KIFONT::FONT*>{}( aField->GetFont(), bField->GetFont() ) ? -1 : 1;
2734 REPORT( wxString::Format( _( "Field '%s' fonts differ." ), aField->GetName( false ) ) );
2735
2736 if( !aReporter )
2737 return retv;
2738 }
2739
2740 if( aField->GetTextSize() != bField->GetTextSize() )
2741 {
2742 if( aField->GetTextSize().x != bField->GetTextSize().x )
2743 retv = aField->GetTextSize().x - bField->GetTextSize().x;
2744 else
2745 retv = aField->GetTextSize().y - bField->GetTextSize().y;
2746
2747 REPORT( wxString::Format( _( "Field '%s' text sizes differ." ), aField->GetName( false ) ) );
2748
2749 if( !aReporter )
2750 return retv;
2751 }
2752
2753 if( int tmp = aField->GetAttributes().Compare( bField->GetAttributes() ) )
2754 {
2755 retv = tmp;
2756 REPORT( wxString::Format( _( "Field '%s' text styles differ." ), aField->GetName( false ) ) );
2757
2758 if( !aReporter )
2759 return retv;
2760 }
2761 }
2762
2763 if( aCompareFlags & COMPARE_FLAGS::FIELD_VISIBILITY )
2764 {
2765 if( aField->IsVisible() != bField->IsVisible() )
2766 {
2767 retv = aField->IsVisible() ? 1 : -1;
2768 REPORT( wxString::Format( _( "Field '%s' visibility flags differ." ), aField->GetName( false ) ) );
2769
2770 if( !aReporter )
2771 return retv;
2772 }
2773
2774 if( aField->IsNameShown() != bField->IsNameShown() )
2775 {
2776 retv = aField->IsNameShown() ? 1 : -1;
2777 REPORT( wxString::Format( _( "Field '%s' name shown flags differ." ), aField->GetName( false ) ) );
2778
2779 if( !aReporter )
2780 return retv;
2781 }
2782 }
2783
2784 if( aField->IsPrivate() != bField->IsPrivate() )
2785 {
2786 retv = aField->IsPrivate() ? 1 : -1;
2787 REPORT( wxString::Format( _( "Field '%s' privacy flags differ." ), aField->GetName( false ) ) );
2788
2789 if( !aReporter )
2790 return retv;
2791 }
2792
2793 if( aCompareFlags & COMPARE_FLAGS::FIELD_POSITIONS )
2794 {
2795 if( aField->GetPosition().x != bField->GetPosition().x )
2796 retv = aField->GetPosition().x - bField->GetPosition().x;
2797
2798 if( aField->GetPosition().y != bField->GetPosition().y )
2799 retv = aField->GetPosition().y - bField->GetPosition().y;
2800
2801 if( retv )
2802 {
2803 REPORT( wxString::Format( _( "Field '%s' positions differ." ), aField->GetName( false ) ) );
2804
2805 if( !aReporter )
2806 return retv;
2807 }
2808 }
2809 }
2810 }
2811
2812 if( aCompareFlags & COMPARE_FLAGS::MISSING_FIELDS )
2813 {
2814 for( const SCH_FIELD* bField : bFields )
2815 {
2816 const SCH_FIELD* aField = nullptr;
2817
2818 if( bField->IsMandatory() )
2819 aField = GetField( bField->GetId() );
2820 else
2821 aField = GetField( bField->GetName() );
2822
2823 if( !aField )
2824 {
2825 retv = 1;
2826 REPORT( wxString::Format( _( "Missing field in schematic symbol: %s." ), bField->GetName( false ) ) );
2827
2828 if( !aReporter )
2829 return retv;
2830 }
2831 }
2832 }
2833
2834 if( int tmp = static_cast<int>( m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount() ) )
2835 {
2836 retv = tmp;
2837 REPORT( _( "Footprint filter count differs." ) );
2838
2839 if( !aReporter )
2840 return retv;
2841 }
2842 else
2843 {
2844 for( size_t i = 0; i < m_fpFilters.GetCount(); i++ )
2845 {
2846 if( int tmp2 = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] ) )
2847 {
2848 retv = tmp2;
2849 REPORT( _( "Footprint filters differ." ) );
2850
2851 if( !aReporter )
2852 return retv;
2853 }
2854 }
2855 }
2856
2857 if( int tmp = static_cast<int>( m_pinMaps.GetAll().size() - aRhs.m_pinMaps.GetAll().size() ) )
2858 {
2859 retv = tmp;
2860 REPORT( _( "Pin map count differs." ) );
2861
2862 if( !aReporter )
2863 return retv;
2864 }
2865 else if( m_pinMaps != aRhs.m_pinMaps )
2866 {
2867 retv = 1;
2868 REPORT( _( "Pin maps differ." ) );
2869
2870 if( !aReporter )
2871 return retv;
2872 }
2873
2874 if( int tmp = static_cast<int>( m_associatedFootprints.size() - aRhs.m_associatedFootprints.size() ) )
2875 {
2876 retv = tmp;
2877 REPORT( _( "Associated footprint count differs." ) );
2878
2879 if( !aReporter )
2880 return retv;
2881 }
2883 {
2884 retv = 1;
2885 REPORT( _( "Associated footprints differ." ) );
2886
2887 if( !aReporter )
2888 return retv;
2889 }
2890
2891 if( int tmp = m_keyWords.Cmp( aRhs.m_keyWords ) )
2892 {
2893 retv = tmp;
2894 REPORT( _( "Symbol keywords differ." ) );
2895
2896 if( !aReporter )
2897 return retv;
2898 }
2899
2900 if( int tmp = m_pinNameOffset - aRhs.m_pinNameOffset )
2901 {
2902 retv = tmp;
2903 REPORT( _( "Symbol pin name offsets differ." ) );
2904
2905 if( !aReporter )
2906 return retv;
2907 }
2908
2909 if( aCompareFlags & COMPARE_FLAGS::PIN_VISIBILITIES )
2910 {
2911 if( m_showPinNames != aRhs.m_showPinNames )
2912 {
2913 retv = ( m_showPinNames ) ? 1 : -1;
2914 REPORT( _( "Show pin names settings differ." ) );
2915
2916 if( !aReporter )
2917 return retv;
2918 }
2919
2921 {
2922 retv = ( m_showPinNumbers ) ? 1 : -1;
2923 REPORT( _( "Show pin numbers settings differ." ) );
2924
2925 if( !aReporter )
2926 return retv;
2927 }
2928 }
2929
2930 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_SIM )
2931 {
2933 {
2934 retv = ( m_excludedFromSim ) ? -1 : 1;
2935 REPORT( _( "Exclude from simulation settings differ." ) );
2936
2937 if( !aReporter )
2938 return retv;
2939 }
2940 }
2941
2942 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_BOM )
2943 {
2945 {
2946 retv = ( m_excludedFromBOM ) ? -1 : 1;
2947 REPORT( _( "Exclude from bill of materials settings differ." ) );
2948
2949 if( !aReporter )
2950 return retv;
2951 }
2952 }
2953
2954 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_BOARD )
2955 {
2957 {
2958 retv = ( m_excludedFromBoard ) ? -1 : 1;
2959 REPORT( _( "Exclude from board settings differ." ) );
2960
2961 if( !aReporter )
2962 return retv;
2963 }
2964 }
2965
2966 if( aCompareFlags & COMPARE_FLAGS::DNP )
2967 {
2968 if( m_DNP != aRhs.m_DNP )
2969 {
2970 retv = ( m_DNP ) ? -1 : 1;
2971 REPORT( _( "Do not populate settings differ." ) );
2972
2973 if( !aReporter )
2974 return retv;
2975 }
2976 }
2977
2978 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_POS_FILES )
2979 {
2981 {
2982 retv = ( m_excludedFromPosFiles ) ? -1 : 1;
2983 REPORT( _( "Exclude from position files settings differ." ) );
2984
2985 if( !aReporter )
2986 return retv;
2987 }
2988 }
2989
2990 if( !aReporter )
2991 {
2992 if( m_unitsLocked != aRhs.m_unitsLocked )
2993 return ( m_unitsLocked ) ? 1 : -1;
2994
2995 // Compare unit display names...
2997 return -1;
2998 else if( m_unitDisplayNames > aRhs.m_unitDisplayNames )
2999 return 1;
3000
3001 // ... and body style names.
3003 return -1;
3004 else if( m_bodyStyleNames > aRhs.m_bodyStyleNames )
3005 return 1;
3006 }
3007
3008 return retv;
3009}
3010
3011
3012int LIB_SYMBOL::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
3013{
3014 if( Type() != aOther.Type() )
3015 return Type() - aOther.Type();
3016
3017 const LIB_SYMBOL* tmp = static_cast<const LIB_SYMBOL*>( &aOther );
3018
3019 return Compare( *tmp, aCompareFlags );
3020}
3021
3022
3023double LIB_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3024{
3025 wxCHECK( aOther.Type() == LIB_SYMBOL_T, 0.0 );
3026
3027 const LIB_SYMBOL& other = static_cast<const LIB_SYMBOL&>( aOther );
3028 double similarity = 0.0;
3029 int totalItems = 0;
3030
3031 if( m_Uuid == aOther.m_Uuid )
3032 return 1.0;
3033
3034 for( const SCH_ITEM& item : m_drawings )
3035 {
3036 totalItems += 1;
3037 double max_similarity = 0.0;
3038
3039 for( const SCH_ITEM& otherItem : other.m_drawings )
3040 {
3041 double temp_similarity = item.Similarity( otherItem );
3042 max_similarity = std::max( max_similarity, temp_similarity );
3043
3044 if( max_similarity == 1.0 )
3045 break;
3046 }
3047
3048 similarity += max_similarity;
3049 }
3050
3051 for( const SCH_PIN* pin : GetGraphicalPins( 0, 0 ) )
3052 {
3053 totalItems += 1;
3054 double max_similarity = 0.0;
3055
3056 for( const SCH_PIN* otherPin : other.GetGraphicalPins( 0, 0 ) )
3057 {
3058 double temp_similarity = pin->Similarity( *otherPin );
3059 max_similarity = std::max( max_similarity, temp_similarity );
3060
3061 if( max_similarity == 1.0 )
3062 break;
3063 }
3064
3065 similarity += max_similarity;
3066 }
3067
3068 if( totalItems == 0 )
3069 similarity = 0.0;
3070 else
3071 similarity /= totalItems;
3072
3074 similarity *= 0.9;
3075
3077 similarity *= 0.9;
3078
3080 similarity *= 0.9;
3081
3083 similarity *= 0.9;
3084
3085 if( m_flags != other.m_flags )
3086 similarity *= 0.9;
3087
3088 if( m_unitCount != other.m_unitCount )
3089 similarity *= 0.5;
3090
3091 if( GetBodyStyleCount() != other.GetBodyStyleCount() )
3092 similarity *= 0.5;
3093 else if( m_bodyStyleNames != other.m_bodyStyleNames )
3094 similarity *= 0.9;
3095
3096 if( m_pinNameOffset != other.m_pinNameOffset )
3097 similarity *= 0.9;
3098
3099 if( m_showPinNames != other.m_showPinNames )
3100 similarity *= 0.9;
3101
3102 if( m_showPinNumbers != other.m_showPinNumbers )
3103 similarity *= 0.9;
3104
3105 return similarity;
3106}
3107
3108
3110{
3111 return static_cast<EMBEDDED_FILES*>( this );
3112}
3113
3114
3116{
3117 return static_cast<const EMBEDDED_FILES*>( this );
3118}
3119
3120
3121void LIB_SYMBOL::AppendParentEmbeddedFiles( std::vector<EMBEDDED_FILES*>& aStack ) const
3122{
3123 std::set<const LIB_SYMBOL*> visited;
3124 visited.insert( this );
3125
3126 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
3127
3128 while( parent )
3129 {
3130 // Cycle detected - parent chain points back to an already visited symbol
3131 if( visited.count( parent.get() ) )
3132 {
3133 wxLogTrace( traceSymbolInheritance,
3134 wxT( "AppendParentEmbeddedFiles: Circular inheritance detected in "
3135 "symbol '%s' (lib: %s)" ),
3136 m_name, m_libId.GetLibNickname().wx_str() );
3137 break;
3138 }
3139
3140 visited.insert( parent.get() );
3141 aStack.push_back( parent->GetEmbeddedFiles() );
3142 parent = parent->GetParent().lock();
3143 }
3144}
3145
3146
3147std::set<KIFONT::OUTLINE_FONT*> LIB_SYMBOL::GetFonts() const
3148{
3149 using EMBEDDING_PERMISSION = KIFONT::OUTLINE_FONT::EMBEDDING_PERMISSION;
3150
3151 std::set<KIFONT::OUTLINE_FONT*> fonts;
3152
3153 for( const SCH_ITEM& item : m_drawings )
3154 {
3155 if( item.Type() == SCH_TEXT_T )
3156 {
3157 const SCH_TEXT& text = static_cast<const SCH_TEXT&>( item );
3158
3159 if( KIFONT::FONT* font = text.GetFont(); font && !font->IsStroke() )
3160 {
3161 KIFONT::OUTLINE_FONT* outline = static_cast<KIFONT::OUTLINE_FONT*>( font );
3163
3164 if( permission == EMBEDDING_PERMISSION::EDITABLE || permission == EMBEDDING_PERMISSION::INSTALLABLE )
3165 fonts.insert( outline );
3166 }
3167 }
3168 }
3169
3170 return fonts;
3171}
3172
3173
3175{
3176 std::set<KIFONT::OUTLINE_FONT*> fonts = GetFonts();
3177
3178 for( KIFONT::OUTLINE_FONT* font : fonts )
3179 {
3180 auto file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3181
3182 if( !file )
3183 {
3184 wxLogTrace( "EMBED", "Failed to add font file: %s", font->GetFileName() );
3185 continue;
3186 }
3187
3189 }
3190}
3191
3192
3193std::optional<const std::set<wxString>> LIB_SYMBOL::GetJumperPinGroup( const wxString& aPinNumber ) const
3194{
3195 for( const std::set<wxString>& group : m_jumperPinGroups )
3196 {
3197 if( group.contains( aPinNumber ) )
3198 return group;
3199 }
3200
3201 return std::nullopt;
3202}
3203
3204static struct LIB_SYMBOL_DESC
3205{
3207 {
3211
3212 const wxString groupFields = _HKI( "Fields" );
3213
3214 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Reference" ),
3216 groupFields );
3217 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Value" ),
3219 groupFields );
3220 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Footprint" ),
3222 groupFields );
3223 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Datasheet" ),
3225 groupFields );
3226 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Keywords" ),
3228 groupFields );
3229
3230 const wxString groupSymbolDef = _HKI( "Symbol Definition" );
3231
3232 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Define as Power Symbol" ),
3234 groupSymbolDef );
3235 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Define as Local Power Symbol" ),
3237 groupSymbolDef );
3238
3239 const wxString groupPinDisplay = _HKI( "Pin Display" );
3240
3241 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Show Pin Number" ),
3243 groupPinDisplay );
3244 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Show Pin Name" ),
3246 groupPinDisplay );
3247 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Place Pin Names Inside" ),
3249 groupPinDisplay );
3250 propMgr.AddProperty( new PROPERTY<SYMBOL, int>( _HKI( "Pin Name Position Offset" ),
3252 groupPinDisplay );
3253
3254 const wxString groupAttributes = _HKI( "Attributes" );
3255
3256 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Simulation" ),
3258 groupAttributes );
3259 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Board" ),
3261 groupAttributes );
3262 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Bill of Materials" ),
3264 groupAttributes );
3265 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Position Files" ),
3267 groupAttributes );
3268
3269 const wxString groupUnits = _HKI( "Units and Body Styles" );
3270
3271 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, int>( _HKI( "Number of Symbol Units" ),
3273 groupUnits );
3274 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Units are Interchangeable" ),
3276 groupUnits );
3277
3278 auto multiBodyStyle =
3279 [=]( INSPECTABLE* aItem ) -> bool
3280 {
3281 if( LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( aItem ) )
3282 return symbol->IsMultiBodyStyle();
3283
3284 return false;
3285 };
3286
3287 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Body Styles" ),
3289 groupUnits )
3290 .SetAvailableFunc( multiBodyStyle )
3291 .SetChoicesFunc( []( INSPECTABLE* aItem )
3292 {
3293 wxPGChoices choices;
3294
3295 if( LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( aItem ) )
3296 {
3297 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3298 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3299 }
3300
3301 return choices;
3302 } );
3303 }
std::unique_ptr< EDA_ITEM > CreateItemForType(KICAD_T aType, EDA_ITEM *aContainer)
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
double square(double x)
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:653
static const COLOR4D WHITE
Definition color4d.h:402
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:399
virtual void ClearEditFlags()
Definition eda_item.h:178
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearSelected()
Definition eda_item.h:153
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:606
virtual EDA_ITEM * Clone() const
Create a duplicate of this item with linked list members set to NULL.
Definition eda_item.cpp:278
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:153
EDA_ITEM_FLAGS GetFlags() const
Definition eda_item.h:167
virtual void ClearTempFlags()
Definition eda_item.h:191
FILL_T GetFillMode() const
Definition eda_shape.h:148
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:301
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
virtual bool IsVisible() const
Definition eda_text.h:226
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:389
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:342
const TEXT_ATTRIBUTES & GetAttributes() const
Definition eda_text.h:270
bool IsEmpty() const
EMBEDDED_FILES & operator=(EMBEDDED_FILES &&other) noexcept
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
const std::map< wxString, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
EMBEDDED_FILES()=default
void SetAreFontsEmbedded(bool aEmbedFonts)
bool GetAreFontsEmbedded() const
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:94
Class OUTLINE_FONT implements outline font drawing.
EMBEDDING_PERMISSION GetEmbeddingPermission() const
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
std::shared_ptr< wxString > m_text
Definition color4d.h:396
COLOR4D & Desaturate()
Removes color (in HSL model)
Definition color4d.cpp:530
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Definition color4d.h:292
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
Object used to load, save, search, and otherwise manipulate symbol library files.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
UTF8 Format() const
Definition lib_id.cpp:132
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Define a library symbol object.
Definition lib_symbol.h:119
LIB_ITEMS_CONTAINER m_drawings
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
SCH_FIELD & GetDescriptionField()
Return reference to the description field.
Definition lib_symbol.h:453
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:188
const BOX2I GetUnitBoundingBox(int aUnit, int aBodyStyle, bool aIgnoreHiddenFields=true, bool aIgnoreLabelsOnInvisiblePins=true) const
Get the bounding box for the symbol.
wxString GetKeyWords() const override
Definition lib_symbol.h:215
void SetGlobalPower()
std::weak_ptr< LIB_SYMBOL > & GetParent()
Definition lib_symbol.h:150
wxString GetBodyStyleProp() const override
Definition lib_symbol.h:584
LIBRENTRYOPTIONS m_options
Special symbol features such as POWER or NORMAL.
wxString GetRefProp() const
Definition lib_symbol.h:472
bool PinsConflictWith(const LIB_SYMBOL &aOtherSymbol, bool aTestNums, bool aTestNames, bool aTestType, bool aTestOrientation, bool aTestLength) const
Return true if this symbol's pins do not match another symbol's pins.
bool GetUnitsInterchangeableProp() const
Definition lib_symbol.h:574
wxString m_shownDescriptionCache
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.
void GetFields(std::vector< SCH_FIELD * > &aList, bool aVisibleOnly=false) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
bool IsPower() const override
wxString GetPrefix()
const std::vector< ASSOCIATED_FOOTPRINT > & GetEffectiveAssociatedFootprints() const
Definition lib_symbol.h:295
bool UnitsLocked() const
Check whether symbol units are interchangeable.
SCH_FIELD & GetDatasheetField()
Return reference to the datasheet field.
Definition lib_symbol.h:449
void RefreshLibraryTreeCaches()
std::weak_ptr< LIB_SYMBOL > m_parent
Use for inherited symbols.
void SetExcludedFromBoardProp(bool aExclude)
Definition lib_symbol.h:620
void cachePinCount()
std::vector< struct LIB_SYMBOL_UNIT > GetUnitDrawItems()
Return a list of SCH_ITEM objects separated by unit and convert number.
std::map< int, wxString > m_unitDisplayNames
std::vector< std::set< wxString > > m_jumperPinGroups
A list of jumper pin groups, each of which is a set of pin numbers that should be jumpered together (...
void ClearTempFlags() override
Clears the status flag all draw objects in this symbol.
void Serialize(kiapi::schematic::types::SchematicSymbol &aOutput, bool aSkipPins=false) const
void SetKeywordsProp(const wxString &aKeywords)
Definition lib_symbol.h:518
bool IsDerived() const
Definition lib_symbol.h:236
std::map< int, wxString > & GetUnitDisplayNames()
Definition lib_symbol.h:870
void SetDuplicatePinNumbersAreJumpers(bool aEnabled)
Definition lib_symbol.h:874
bool m_demorgan
True if there are two body styles: normal and De Morgan If false, the body style count is taken from ...
wxString GetFootprint() override
For items with footprint fields.
const wxString GetLibraryName() const
void SetFields(const std::vector< SCH_FIELD > &aFieldsList)
Overwrite all the existing fields in this symbol with fields supplied in aFieldsList.
void SetExcludedFromPosFilesProp(bool aExclude)
Definition lib_symbol.h:626
void SetLib(LEGACY_SYMBOL_LIB *aLibrary)
bool GetPowerSymbolProp() const
Definition lib_symbol.h:523
bool IsMultiBodyStyle() const override
Definition lib_symbol.h:894
int GetMaxPinNumber() const
std::vector< SEARCH_TERM > m_searchTermsCache
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.
SCH_FIELD & GetFootprintField()
Return reference to the footprint field.
Definition lib_symbol.h:445
void SetAssociatedFootprints(std::vector< ASSOCIATED_FOOTPRINT > aList)
Definition lib_symbol.h:267
void FixupDrawItems()
This function finds the filled draw items that are covering up smaller draw items and replaces their ...
void SetBodyStyleNames(const std::vector< wxString > &aBodyStyleNames)
Definition lib_symbol.h:905
bool IsNormal() const override
wxString m_name
void SetUnitsInterchangeableProp(bool aInterchangeable)
Definition lib_symbol.h:579
std::set< KIFONT::OUTLINE_FONT * > GetFonts() const override
LEGACY_SYMBOL_LIB * m_library
bool GetExcludedFromPosFilesProp() const
Definition lib_symbol.h:625
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
wxString m_keyWords
Search keywords.
SCH_ITEM * LocateDrawItem(int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I &aPoint)
Locate a draw object.
static wxString LetterSubReference(int aUnit, wxChar aInitialLetter)
double Similarity(const SCH_ITEM &aSymbol) const override
Return a measure of similarity between this symbol and aSymbol.
static LIB_SYMBOL * GetDummy()
Returns a dummy LIB_SYMBOL, used when one is missing in the schematic.
void PlotFields(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed)
Plot symbol fields.
wxString GetDatasheetProp() const
Definition lib_symbol.h:503
void LockUnits(bool aLockUnits)
Set interchangeable the property for symbol units.
Definition lib_symbol.h:365
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:832
std::shared_ptr< LIB_SYMBOL > GetRootSymbol() const
Get the parent symbol that does not have another parent.
void SetRefProp(const wxString &aRef)
Definition lib_symbol.h:477
void SetParent(LIB_SYMBOL *aParent=nullptr)
std::vector< UNIT_PIN_INFO > GetUnitPinInfo() const
Return pin-number lists for each unit, ordered consistently for gate swapping.
wxString GetName() const override
Definition lib_symbol.h:181
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
void cacheChooserFields()
std::shared_ptr< LIB_SYMBOL > m_me
wxString GetValueProp() const
Definition lib_symbol.h:482
bool GetExcludedFromBOMProp() const
Definition lib_symbol.h:605
void SetKeyWords(const wxString &aKeyWords)
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:437
bool IsLocalPower() const override
LIB_SYMBOL(const wxString &aName, LIB_SYMBOL *aParent=nullptr, LEGACY_SYMBOL_LIB *aLibrary=nullptr)
int GetUnitProp() const
Definition lib_symbol.h:564
wxArrayString GetFPFilters() const
Definition lib_symbol.h:247
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
void GetChooserFields(std::map< wxString, wxString > &aColumnMap) override
Retrieves a key/value map of the fields on this item that should be exposed to the library browser/ch...
bool HasLegacyAlternateBodyStyle() const
Before V10 we didn't store the number of body styles in a symbol – we just looked through all its dra...
std::shared_ptr< LIB_SYMBOL > SharedPtr() const
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared.
Definition lib_symbol.h:128
bool GetPinNamesInsideProp() const
Definition lib_symbol.h:551
const std::vector< wxString > & GetBodyStyleNames() const
void SetBodyStyleProp(const wxString &aBodyStyle) override
Definition lib_symbol.h:589
void SetPinMaps(const PIN_MAP_SET &aPinMaps)
Definition lib_symbol.h:263
timestamp_t m_lastModDate
void SetExcludedFromSimProp(bool aExclude)
Definition lib_symbol.h:600
bool GetExcludedFromBoardProp() const
Definition lib_symbol.h:615
std::optional< const std::set< wxString > > GetJumperPinGroup(const wxString &aPinNumber) const
Retrieves the jumper group containing the specified pin number, if one exists.
wxString getShownDescription(RESOLUTION_CONTEXT aContext, int aDepth) const
LIB_ID m_libId
void SetLocalPower()
std::vector< SCH_PIN * > GetPins() const override
bool HasPinNumber(const wxString &aNumber) const
Return true if aNumber names a pin of this symbol, in any unit or body style.
void SetBodyStyleCount(int aCount, bool aDuplicateDrawItems, bool aDuplicatePins)
Set the number of body styles for the symbol.
wxString GetLibNickname() const override
Sets the Description field text value.
Definition lib_symbol.h:194
void SetFootprintProp(const wxString &aFootprint)
Definition lib_symbol.h:497
std::vector< LOGICAL_PIN > GetLogicalPins(int aUnit, int aBodyStyle) const
Return all logical pins (expanded) filtered by unit/body.
bool HasDeMorganBodyStyles() const override
const LIB_SYMBOL & operator=(const LIB_SYMBOL &aSymbol)
bool m_unitsLocked
True if symbol has multiple units and changing one unit does not automatically change another unit.
wxArrayString m_fpFilters
List of suitable footprint names for the symbol (wild card names accepted).
void Move(const VECTOR2I &aOffset) override
Move the symbol aOffset.
void SetFPFilters(const wxArrayString &aFilters)
Definition lib_symbol.h:245
const PIN_MAP_SET & GetEffectivePinMaps() const
Definition lib_symbol.h:280
void CopyFields(std::vector< SCH_FIELD > &aList)
Create a copy of the SCH_FIELDs, sorted in ordinal order.
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
int compare(const SCH_ITEM &aOther, int aCompareFlags=~(COMPARE_FLAGS::UUID|COMPARE_FLAGS::UNIT)) const override
The library symbol specific sort order is as follows:
bool GetExcludedFromSimProp() const
Definition lib_symbol.h:595
int GetBodyStyleCount() const override
The body styles are a property of the drawings, which a derived symbol inherits from its root symbol ...
void SetDatasheetProp(const wxString &aDatasheet)
Definition lib_symbol.h:508
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...
EMBEDDED_FILES * GetEmbeddedFiles() override
void SetPowerSymbolProp(bool aIsPower)
Definition lib_symbol.h:528
void SetExcludedFromBOMProp(bool aExclude)
Definition lib_symbol.h:610
int m_unitCount
Number of units (parts) per package.
void SyncFieldsFromParent(const LIB_FIELD_SYNC_OPTIONS &aOptions)
Reconcile this derived symbol's fields with those of its (flattened) parent.
wxString GetShownKeyWords(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
bool IsGlobalPower() const override
wxString GetBodyStyleDescription(int aBodyStyle, bool aLabel) const override
unsigned GetInheritanceDepth() const
Get the number of parents for this symbol.
int GetUnitCount() const override
bool Deserialize(const kiapi::schematic::types::SchematicSymbol &aInput)
PIN_MAP_SET m_pinMaps
Named pin-to-pad maps owned by this symbol (issue #2282).
wxString GetKeywordsProp() const
Definition lib_symbol.h:513
std::vector< wxString > m_bodyStyleNames
void AppendParentEmbeddedFiles(std::vector< EMBEDDED_FILES * > &aStack) const
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber, int aUnit=0, int aBodyStyle=0)
Return all pin objects with the requested pin aNumber.
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
Definition lib_symbol.h:339
void SetValueProp(const wxString &aValue)
Definition lib_symbol.h:487
int GetPinCount() override
std::map< wxString, wxString > m_chooserFieldsCache
void SetLibId(const LIB_ID &aLibId)
void cacheSearchTerms()
void AddField(SCH_FIELD *aField)
Add a field.
void ClearEditFlags() override
int m_pinCountCache
bool GetLocalPowerSymbolProp() const
Definition lib_symbol.h:536
bool GetDuplicatePinNumbersAreJumpers() const
Definition lib_symbol.h:873
void deleteAllFields()
LIB_ID GetLIB_ID() const override
Definition lib_symbol.h:183
std::vector< ASSOCIATED_FOOTPRINT > m_associatedFootprints
Footprints associated with this symbol, each tied to a named pin map.
const SCH_PIN * GetPin(const wxString &aNumber, int aUnit=0, int aBodyStyle=0) const
Return pin object with the requested pin aNumber.
bool m_duplicatePinNumbersAreJumpers
Flag that this symbol should automatically treat sets of two or more pins with the same number as jum...
void SetUnitProp(int aUnits)
Definition lib_symbol.h:569
wxString GetFootprintProp() const
Definition lib_symbol.h:492
std::vector< std::set< wxString > > & JumperPinGroups()
Each jumper pin group is a set of pin numbers that should be treated as internally connected.
Definition lib_symbol.h:880
void SetPinNamesInsideProp(bool aInside)
Definition lib_symbol.h:556
int Compare(const LIB_SYMBOL &aRhs, int aCompareFlags=~COMPARE_FLAGS::UNIT, REPORTER *aReporter=nullptr) const
Comparison test that can be used for operators.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
wxString GetUnitDisplayName(int aUnit, bool aLabel) const override
Return the user-defined display name for aUnit for symbols with units.
wxString m_parentName
The name of the parent symbol or empty if root symbol.
void EmbedFonts() override
void SetLocalPowerSymbolProp(bool aIsLocalPower)
Definition lib_symbol.h:541
virtual void SetName(const wxString &aName)
void SetNormal()
void PruneBodyStyleDrawItems(int aBodyStyleCount)
Delete the draw items belonging to a body style beyond aBodyStyleCount.
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:441
wxString GetShownDescription(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
void cacheShownDescription()
int GetNextFieldOrdinal() const
Return the next ordinal for a user field for this symbol.
ITERATOR_BASE< SCH_ITEM, MULTIVECTOR< SCH_ITEM, FIRST_TYPE_VAL, LAST_TYPE_VAL >, typename ITEM_PTR_VECTOR::iterator > ITERATOR
ITERATOR end(int aType=UNDEFINED_TYPE)
ITERATOR begin(int aType=UNDEFINED_TYPE)
A symbol-owned ordered set of named pin maps.
Definition pin_map.h:124
const std::vector< PIN_MAP > & GetAll() const
Definition pin_map.h:139
void AddOrReplace(PIN_MAP aMap)
Insert aMap, replacing any existing entry with the same name.
Definition pin_map.cpp:113
A named pin map.
Definition pin_map.h:65
void SetEntry(const wxString &aPinNumber, const wxString &aPadNumber)
Set the pad number for a symbol pin.
Definition pin_map.cpp:59
Base plotter engine class.
Definition plotter.h:136
bool GetColorMode() const
Definition plotter.h:164
virtual void SetColor(const COLOR4D &color)=0
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:277
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:263
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.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
bool IsMandatory() const
wxString GetFullText(int unit=1) const
Return the text of a field.
VECTOR2I GetPosition() const override
bool IsNameShown() const
Definition sch_field.h:228
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:138
FIELD_T GetId() const
Definition sch_field.h:142
wxString GetUntranslatedName() const
Get the untranslated field name for storage, variable look-up, etc.
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
wxString GetShownText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString, int aDepth=0) const
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetName(const wxString &aName)
bool ShowInChooser() const
Definition sch_field.h:249
void SetText(const wxString &aText) override
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
virtual void SetBodyStyle(int aBodyStyle)
Definition sch_item.h:246
int m_unit
Definition sch_item.h:791
int m_bodyStyle
Definition sch_item.h:792
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition sch_item.h:739
void SetPrivate(bool aPrivate)
Definition sch_item.h:252
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:281
friend class LIB_SYMBOL
Definition sch_item.h:812
@ MISSING_FIELDS
Definition sch_item.h:709
@ EXCLUDE_FROM_BOARD
Definition sch_item.h:718
@ FIELD_VISIBILITY
Definition sch_item.h:712
@ EXCLUDE_FROM_POS_FILES
Definition sch_item.h:721
@ EXTRA_FIELDS
Definition sch_item.h:710
@ FIELD_SIZE_AND_STYLE
Definition sch_item.h:713
@ EXCLUDE_FROM_BOM
Definition sch_item.h:720
@ FIELD_TEXT
Definition sch_item.h:711
@ EXCLUDE_FROM_SIM
Definition sch_item.h:717
@ FIELD_POSITIONS
Definition sch_item.h:714
@ PIN_VISIBILITIES
Definition sch_item.h:715
bool IsPrivate() const
Definition sch_item.h:253
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:346
virtual void SetUnit(int aUnit)
Definition sch_item.h:236
SCH_ITEM(EDA_ITEM *aParent, KICAD_T aType, int aUnit=0, int aBodyStyle=0)
Definition sch_item.cpp:52
wxString ResolveText(const wxString &aText, const SCH_SHEET_PATH *aPath, int aDepth=0) const
Definition sch_item.cpp:390
VECTOR2I GetPosition() const override
Definition sch_pin.cpp:354
const KIGFX::COLOR4D & GetBackgroundColor() const override
Return current background color settings.
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 GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:227
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
Definition symbol.h:206
bool m_showPinNumbers
Definition symbol.h:268
bool m_excludedFromPosFiles
Definition symbol.h:273
SYMBOL(KICAD_T idType)
Definition symbol.h:61
bool m_excludedFromSim
Definition symbol.h:270
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
Definition symbol.h:236
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:170
bool m_showPinNames
Definition symbol.h:267
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
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
Definition symbol.h:176
virtual bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:197
virtual void SetDNP(bool aDNP, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Definition symbol.h:238
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
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:212
void SetExcludedFromPosFiles(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from position files flag.
Definition symbol.h:221
virtual bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:182
SYMBOL & operator=(const SYMBOL &aItem)
Definition symbol.h:89
virtual bool GetShowPinNumbers() const
Definition symbol.h:171
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
Definition symbol.h:191
int m_pinNameOffset
The offset in mils to draw the pin name.
Definition symbol.h:265
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
wxString wx_str() const
Definition utf8.cpp:41
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:333
RESOLUTION_CONTEXT
Definition common.h:87
@ FOR_GUI
Definition common.h:89
@ RAW_VALUE
Definition common.h:94
@ INTERNAL
Definition common.h:92
#define DEFAULT_PIN_NAME_OFFSET
The intersheets references prefix string.
#define _(s)
@ FILLED_WITH_COLOR
Definition eda_fill.h:33
@ FILLED_WITH_BG_BODYCOLOR
Definition eda_fill.h:32
RECURSE_MODE
Definition eda_item.h:50
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#define IS_NEW
New item, just created.
#define STRUCT_DELETED
flag indication structures to be erased
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
TRANSFORM DefaultTransform
Definition transform.cpp:28
const wxChar *const traceSymbolInheritance
Flag to enable tracing of circular symbol inheritance detection.
const wxChar *const traceStackedPins
Flag to enable debug output for stacked pins handling in symbol/pin code.
@ LAYER_DEVICE
Definition layer_ids.h:488
@ LAYER_FIELDS
Definition layer_ids.h:484
#define REPORT(msg)
static std::shared_ptr< LIB_SYMBOL > GetSafeRootSymbol(const LIB_SYMBOL *aSymbol, const char *aCallerName)
Helper to safely get the root symbol, detecting and logging circular inheritance.
static struct LIB_SYMBOL_DESC _LIB_SYMBOL_DESC
SEARCH_TERM_CACHE_INDEX
@ STCI_LIB_ID
@ STCI_LIB_SYMBOL_NAME
@ STCI_LIB_NICKNAME
bool operator<(const LIB_SYMBOL &aItem1, const LIB_SYMBOL &aItem2)
#define ITEM_DESC(item)
@ ENTRY_NORMAL
Definition lib_symbol.h:62
@ ENTRY_LOCAL_POWER
Definition lib_symbol.h:64
@ ENTRY_GLOBAL_POWER
Definition lib_symbol.h:63
LIB_ITEMS_CONTAINER::ITEM_PTR_VECTOR LIB_ITEMS
Definition lib_symbol.h:56
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:50
KICOMMON_API void PackDistance(types::Distance &aOutput, int 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
#define TYPE_HASH(x)
Definition property.h:74
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition ptree.cpp:194
@ BASE
Definition sch_item.h:59
@ DEMORGAN
Definition sch_item.h:60
A first-class footprint choice on a LIB_SYMBOL, tied to a named pin map.
Definition pin_map.h:159
LIB_ID m_FootprintLibId
Definition pin_map.h:160
Options controlling how a derived symbol's fields are reconciled with its parent.
Definition lib_symbol.h:85
bool m_removeExtraFields
Drop fields not present in the parent.
Definition lib_symbol.h:93
bool m_resetPositions
Copy parent field positions.
Definition lib_symbol.h:102
bool m_resetVisibility
Copy parent visibility and name-shown flags.
Definition lib_symbol.h:96
bool m_updateAllFields
Reconcile every field. When false only the names in m_updateFields are touched.
Definition lib_symbol.h:87
std::set< wxString > m_updateFields
Field names to reconcile when m_updateAllFields is false.
Definition lib_symbol.h:90
bool m_resetEffects
Copy parent text effects (font, justification, etc.) but keep local visibility/position.
Definition lib_symbol.h:99
bool m_resetEmptyText
Copy parent text even when the parent value is empty.
Definition lib_symbol.h:108
bool m_resetText
Copy parent text when the parent value is non-empty.
Definition lib_symbol.h:105
Logical pins: Return expanded logical pins based on stacked-pin notation.
Definition lib_symbol.h:701
std::vector< wxString > m_pinNumbers
Definition lib_symbol.h:715
int m_bodyStyle
The alternate body style of the unit.
Definition lib_symbol.h:74
int m_unit
The unit number.
Definition lib_symbol.h:73
One symbol-pin to footprint-pad mapping inside a PIN_MAP.
Definition pin_map.h:42
A structure for storing weighted search terms.
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared
void operator()(void const *) const
#define MANDATORY_FIELDS
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".
KIBIS_PIN * pin
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ LIB_SYMBOL_T
Definition typeinfo.h:144
@ TYPE_NOT_INIT
Definition typeinfo.h:73
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_SHAPE_T
Definition typeinfo.h:145
@ SCH_TEXT_T
Definition typeinfo.h:147
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683