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