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 for( const auto& [unit, displayName] : GetUnitDisplayNames() )
436 {
437 SchematicUnitDisplayName* protoName = def.add_unit_display_names();
438 protoName->set_unit( unit );
439 protoName->set_name( displayName.ToUTF8() );
440 }
441
442 SymbolPinMaps* pinMaps = def.mutable_pin_maps();
443
445 {
446 AssociatedFootprint* a = pinMaps->add_associated_footprints();
447 PackLibId( a->mutable_footprint(), assoc.m_FootprintLibId );
448 a->set_map_name( assoc.m_MapName.ToUTF8() );
449 }
450
451 for( const PIN_MAP& map : GetEffectivePinMaps().GetAll() )
452 {
453 PinMap* m = pinMaps->add_pin_maps();
454 m->set_name( map.GetName().ToUTF8() );
455
456 for( const PIN_MAP_ENTRY& entry : map.GetEntries() )
457 {
458 PinMapEntry* e = m->add_entries();
459 e->set_pin_number( entry.m_PinNumber.ToUTF8() );
460 e->set_pad_number( entry.m_PadNumber.ToUTF8() );
461 }
462 }
463}
464
465
466void LIB_SYMBOL::Serialize( google::protobuf::Any& aContainer ) const
467{
468 kiapi::schematic::types::SchematicSymbol def;
469 Serialize( def );
470 aContainer.PackFrom( def );
471}
472
473
474bool LIB_SYMBOL::Deserialize( const kiapi::schematic::types::SchematicSymbol& aInput )
475{
476 using namespace kiapi::common;
477 using namespace kiapi::common::types;
478 using namespace kiapi::schematic::types;
479
480 const SchematicSymbol& def = aInput;
481
482 LIB_ID libId = UnpackLibId( def.id() );
483 SetLibId( libId );
484
485 switch( def.type() )
486 {
487 case SchematicSymbolType::SST_GLOBAL_POWER: SetGlobalPower(); break;
488 case SchematicSymbolType::SST_LOCAL_POWER: SetLocalPower(); break;
489 default: break;
490 }
491
492 if( def.has_attributes() )
493 {
494 SetExcludedFromSim( def.attributes().exclude_from_simulation() );
495 SetExcludedFromBOM( def.attributes().exclude_from_bill_of_materials() );
496 SetExcludedFromBoard( def.attributes().exclude_from_board() );
497 SetExcludedFromPosFiles( def.attributes().exclude_from_position_files() );
498 SetDNP( def.attributes().do_not_populate() );
499 }
500
501 GetField( FIELD_T::REFERENCE )->Deserialize( def.reference_field(), schIUScale );
502 GetField( FIELD_T::VALUE )->Deserialize( def.value_field(), schIUScale );
503 GetField( FIELD_T::FOOTPRINT )->Deserialize( def.footprint_field(), schIUScale );
504 GetField( FIELD_T::DATASHEET )->Deserialize( def.datasheet_field(), schIUScale );
505 GetField( FIELD_T::DESCRIPTION )->Deserialize( def.description_field(), schIUScale );
506
507 for( const SchematicSymbolChild& child : def.items() )
508 {
509 std::optional<KICAD_T> type = TypeNameFromAny( child.item() );
510
511 if( !type )
512 continue;
513
514 std::unique_ptr<EDA_ITEM> item = CreateItemForType( *type, this );
515
516 if( !item || !item->Deserialize( child.item() ) )
517 continue;
518
519 SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
520
521 if( child.has_unit() )
522 schItem->SetUnit( child.unit().unit() );
523
524 if( child.has_body_style() )
525 schItem->SetBodyStyle( child.body_style().style() );
526
527 schItem->SetLayer( LAYER_DEVICE );
528 schItem->SetPrivate( child.is_private() );
529 AddDrawItem( schItem, false );
530 }
531
532 if( def.unit_count() > 0 )
533 SetUnitCount( def.unit_count(), false );
534
535 if( def.body_style_size() > 0 )
536 {
537 std::vector<wxString> bodyStyleNames;
538
539 for( const SchematicBodyStyle& bodyStyle : def.body_style() )
540 bodyStyleNames.emplace_back( wxString::FromUTF8( bodyStyle.name() ) );
541
542 SetBodyStyleNames( bodyStyleNames );
543 SetBodyStyleCount( static_cast<int>( bodyStyleNames.size() ), false, false );
544 }
545
546 if( !def.keywords().empty() )
547 SetKeyWords( wxString::FromUTF8( def.keywords() ) );
548
549 if( def.footprint_filters_size() > 0 )
550 {
551 wxArrayString filters;
552
553 for( const std::string& filter : def.footprint_filters() )
554 filters.Add( wxString::FromUTF8( filter ) );
555
557 }
558
559 SetDuplicatePinNumbersAreJumpers( def.jumpers().duplicate_names_are_jumpered() );
560
561 JUMPER_GROUP_SET& jumperGroups = JumperPinGroups();
562 jumperGroups.Clear();
563
564 for( const JumperGroup& group : def.jumpers().groups() )
565 {
566 std::set<wxString> pinNumbers;
567
568 for( const std::string& pinNumber : group.pin_numbers() )
569 pinNumbers.insert( wxString::FromUTF8( pinNumber ) );
570
571 jumperGroups.Add( std::move( pinNumbers ) );
572 }
573
574 LockUnits( def.units_locked() );
575 SetAreFontsEmbedded( def.embedded_fonts() );
576
577 for( const SchematicUnitDisplayName& displayName : def.unit_display_names() )
578 GetUnitDisplayNames()[displayName.unit()] = wxString::FromUTF8( displayName.name() );
579
580 SetShowPinNumbers( def.show_pin_numbers() );
581 SetShowPinNames( def.show_pin_names() );
582 SetPinNameOffset( UnpackDistance( def.pin_name_offset(), schIUScale ) );
583
584 if( def.has_pin_maps() )
585 {
586 PIN_MAP_SET pinMapSet;
587
588 for( const PinMap& map : def.pin_maps().pin_maps() )
589 {
590 PIN_MAP pinMap( wxString::FromUTF8( map.name() ) );
591
592 for( const PinMapEntry& entry : map.entries() )
593 {
594 pinMap.SetEntry( wxString::FromUTF8( entry.pin_number() ), wxString::FromUTF8( entry.pad_number() ) );
595 }
596
597 pinMapSet.AddOrReplace( std::move( pinMap ) );
598 }
599
600 std::vector<ASSOCIATED_FOOTPRINT> associatedFootprints;
601
602 for( const AssociatedFootprint& footprint : def.pin_maps().associated_footprints() )
603 {
605 assoc.m_FootprintLibId = UnpackLibId( footprint.footprint() );
606 assoc.m_MapName = wxString::FromUTF8( footprint.map_name() );
607 associatedFootprints.push_back( std::move( assoc ) );
608 }
609
610 SetPinMaps( pinMapSet );
611 SetAssociatedFootprints( std::move( associatedFootprints ) );
612 }
613
614 m_cachesDirty = true;
615 return true;
616}
617
618
619bool LIB_SYMBOL::Deserialize( const google::protobuf::Any& aContainer )
620{
621 kiapi::schematic::types::SchematicSymbol def;
622
623 if( !aContainer.UnpackTo( &def ) )
624 return false;
625
626 return Deserialize( def );
627}
628
629
631{
632 if( &aSymbol == this )
633 return aSymbol;
634
635 SYMBOL::operator=( aSymbol );
636
637 m_library = aSymbol.m_library;
638 m_name = aSymbol.m_name;
639 m_fpFilters = wxArrayString( aSymbol.m_fpFilters );
640 m_pinMaps = aSymbol.m_pinMaps;
642 m_unitCount = aSymbol.m_unitCount;
643 m_demorgan = aSymbol.m_demorgan;
646 m_options = aSymbol.m_options;
647 m_libId = aSymbol.m_libId;
648 m_keyWords = aSymbol.m_keyWords;
649
652
654 // Raw member, not the accessor, which would bake a root's body styles into a derived copy
656
657 m_drawings.clear();
658
659 for( const SCH_ITEM& oldItem : aSymbol.m_drawings )
660 {
661 if( ( oldItem.GetFlags() & ( IS_NEW | STRUCT_DELETED ) ) != 0 )
662 continue;
663
664 SCH_ITEM* newItem = (SCH_ITEM*) oldItem.Clone();
665 newItem->SetParent( this );
666 m_drawings.push_back( newItem );
667 }
668
669 m_drawings.sort();
670
671 SetParent( aSymbol.m_parent.lock().get() );
672
673 EMBEDDED_FILES::operator=( aSymbol );
674
675 m_cachesDirty = true;
676
677 return *this;
678}
679
680
687{
688 static LIB_SYMBOL* symbol;
689
690 if( !symbol )
691 {
692 symbol = new LIB_SYMBOL( wxEmptyString );
693
695
696 square->SetPosition( VECTOR2I( schIUScale.MilsToIU( -200 ), schIUScale.MilsToIU( 200 ) ) );
697 square->SetEnd( VECTOR2I( schIUScale.MilsToIU( 200 ), schIUScale.MilsToIU( -200 ) ) );
698 symbol->AddDrawItem( square );
699
700 SCH_TEXT* text = new SCH_TEXT( { 0, 0 }, wxT( "??" ), LAYER_DEVICE );
701
702 text->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 150 ), schIUScale.MilsToIU( 150 ) ) );
703 symbol->AddDrawItem( text );
704 }
705
706 return symbol;
707}
708
709
711{
712 unsigned depth = 0;
713 std::set<const LIB_SYMBOL*> visited;
714 visited.insert( this );
715
716 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
717
718 while( parent )
719 {
720 // Cycle detected - parent chain points back to an already visited symbol
721 if( visited.count( parent.get() ) )
722 {
723 wxLogTrace( traceSymbolInheritance,
724 wxT( "GetInheritanceDepth: Circular inheritance detected in symbol '%s' "
725 "(lib: %s)" ),
726 m_name, m_libId.GetLibNickname().wx_str() );
727 break;
728 }
729
730 visited.insert( parent.get() );
731 depth++;
732 parent = parent->m_parent.lock();
733 }
734
735 return depth;
736}
737
738
739std::shared_ptr<LIB_SYMBOL> LIB_SYMBOL::GetRootSymbol() const
740{
741 std::set<const LIB_SYMBOL*> visited;
742 visited.insert( this );
743
744 std::shared_ptr<LIB_SYMBOL> current = m_me;
745 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
746
747 while( parent )
748 {
749 // Cycle detected - parent chain points back to an already visited symbol
750 if( visited.count( parent.get() ) )
751 {
752 wxLogTrace( traceSymbolInheritance,
753 wxT( "GetRootSymbol: Circular inheritance detected in symbol '%s' "
754 "(lib: %s)" ),
755 m_name, m_libId.GetLibNickname().wx_str() );
756 break;
757 }
758
759 visited.insert( parent.get() );
760 current = parent;
761 parent = parent->m_parent.lock();
762 }
763
764 return current;
765}
766
767
769{
770 if( IsDerived() )
771 {
772 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
773
774 if( root.get() != this )
775 return root->m_unitsLocked;
776 }
777
778 return m_unitsLocked;
779}
780
781
782wxString LIB_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
783{
784 const LIB_SYMBOL* owner = this;
785 std::shared_ptr<LIB_SYMBOL> root;
786
787 if( IsDerived() )
788 {
789 root = GetSafeRootSymbol( this, __FUNCTION__ );
790 owner = root.get();
791 }
792
793 if( owner->m_unitDisplayNames.contains( aUnit ) )
794 return owner->m_unitDisplayNames.at( aUnit );
795 else if( aLabel )
796 return wxString::Format( _( "Unit %s" ), LIB_SYMBOL::LetterSubReference( aUnit, 'A' ) );
797 else
798 return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
799}
800
801
802wxString LIB_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
803{
805 {
806 if( aBodyStyle == BODY_STYLE::DEMORGAN )
807 return aLabel ? _( "Alternate" ) : wxString( _HKI( "Alternate" ) );
808 else if( aBodyStyle == BODY_STYLE::BASE )
809 return aLabel ? _( "Standard" ) : wxString( _HKI( "Standard" ) );
810 }
811 else if( IsMultiBodyStyle() )
812 {
813 const std::vector<wxString>& names = GetBodyStyleNames();
814
815 // Draw items common to every body style carry a body style of 0
816 if( aBodyStyle >= BODY_STYLE::BASE && aBodyStyle <= (int) names.size() )
817 return names[aBodyStyle - 1];
818 }
819
820 return wxT( "?" );
821}
822
823
824void LIB_SYMBOL::SetName( const wxString& aName )
825{
826 m_name = aName;
827 m_libId.SetLibItemName( aName );
828
829 m_cachesDirty = true;
830}
831
832
833void LIB_SYMBOL::SetLibId( const LIB_ID& aLibId )
834{
835 m_libId = aLibId;
836
837 m_cachesDirty = true;
838}
839
840
842{
843 if( aParent )
844 {
845 // Prevent circular inheritance by checking if aParent is derived from this symbol
846 std::set<const LIB_SYMBOL*> visited;
847 visited.insert( this );
848
849 std::shared_ptr<LIB_SYMBOL> ancestor = aParent->SharedPtr();
850
851 while( ancestor )
852 {
853 if( visited.count( ancestor.get() ) )
854 {
855 wxLogTrace( traceSymbolInheritance, wxT( "SetParent: Rejecting parent '%s' for symbol '%s' "
856 "- would create circular inheritance (lib: %s)" ),
857 aParent->GetName(), m_name, m_libId.GetLibNickname().wx_str() );
858
859 // Don't set the parent - it would create circular inheritance
860 return;
861 }
862
863 visited.insert( ancestor.get() );
864 ancestor = ancestor->m_parent.lock();
865 }
866
867 m_parent = aParent->SharedPtr();
868
869 // Keep the recorded parent name in sync so serialization never has to dereference the live
870 // parent pointer (which can dangle, see SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol).
871 m_parentName = aParent->GetName();
872 }
873 else
874 {
875 // Only drop the live pointer. The recorded parent name is left untouched so a derived
876 // symbol whose live parent has been lost can still be serialized by name.
877 m_parent.reset();
878 }
879
880 m_cachesDirty = true;
881}
882
883
885{
887 return wxEmptyString;
888
890}
891
892
893std::unique_ptr<LIB_SYMBOL> LIB_SYMBOL::Flatten() const
894{
895 std::unique_ptr<LIB_SYMBOL> retv;
896
897 if( IsDerived() )
898 {
899 // Build parent chain with cycle detection - collect from this symbol up to root
900 std::vector<const LIB_SYMBOL*> parentChain;
901 std::set<const LIB_SYMBOL*> visited;
902 visited.insert( this );
903
904 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
905
906 wxCHECK_MSG( parent, retv, wxString::Format( "Parent of derived symbol '%s' undefined", m_name ) );
907
908 while( parent )
909 {
910 // Cycle detected - parent chain points back to an already visited symbol
911 if( visited.count( parent.get() ) )
912 {
913 wxLogTrace( traceSymbolInheritance,
914 wxT( "Flatten: Circular inheritance detected in symbol '%s' (lib: %s)" ),
915 m_name, m_libId.GetLibNickname().wx_str() );
916 break;
917 }
918
919 visited.insert( parent.get() );
920 parentChain.push_back( parent.get() );
921 parent = parent->m_parent.lock();
922 }
923
924 // Start with the root (last in chain) and work down
925 if( !parentChain.empty() )
926 {
927 retv = std::make_unique<LIB_SYMBOL>( *parentChain.back() );
928
929 // Apply each derived symbol's overrides from root down (skip the root itself)
930 for( int i = static_cast<int>( parentChain.size() ) - 2; i >= 0; --i )
931 {
932 const LIB_SYMBOL* derived = parentChain[i];
933
934 // Overwrite parent's mandatory fields for fields which are defined in derived.
935 for( FIELD_T fieldId : MANDATORY_FIELDS )
936 {
937 if( !derived->GetField( fieldId )->GetText().IsEmpty() )
938 *retv->GetField( fieldId ) = *derived->GetField( fieldId );
939 }
940
941 // Grab all the rest of derived symbol fields.
942 for( const SCH_ITEM& item : derived->m_drawings[SCH_FIELD_T] )
943 {
944 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
945
946 if( field->IsMandatory() )
947 continue;
948
949 SCH_FIELD* newField = new SCH_FIELD( *field );
950 newField->SetParent( retv.get() );
951
952 SCH_FIELD* parentField = retv->GetField( field->GetName() );
953
954 if( !parentField )
955 {
956 retv->AddDrawItem( newField );
957 }
958 else
959 {
960 retv->RemoveDrawItem( parentField );
961 retv->AddDrawItem( newField );
962 }
963 }
964
965 if( !derived->m_keyWords.IsEmpty() )
966 retv->SetKeyWords( derived->m_keyWords );
967
968 if( !derived->m_fpFilters.IsEmpty() )
969 retv->SetFPFilters( derived->m_fpFilters );
970 }
971 }
972 else
973 {
974 // Cycle detected at immediate parent level - just copy this symbol
975 retv = std::make_unique<LIB_SYMBOL>( *this );
976 retv->m_parent.reset();
977 return retv;
978 }
979
980 // Now apply this symbol's overrides (the original "this" symbol)
981 retv->m_name = m_name;
982 retv->SetLibId( m_libId );
983
984 // Overwrite parent's mandatory fields for fields which are defined in this.
985 for( FIELD_T fieldId : MANDATORY_FIELDS )
986 {
987 if( !GetField( fieldId )->GetText().IsEmpty() )
988 *retv->GetField( fieldId ) = *GetField( fieldId );
989 }
990
991 // Grab all the rest of derived symbol fields.
992 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
993 {
994 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
995
996 // Mandatory fields were already resolved.
997 if( field->IsMandatory() )
998 continue;
999
1000 SCH_FIELD* newField = new SCH_FIELD( *field );
1001 newField->SetParent( retv.get() );
1002
1003 SCH_FIELD* parentField = retv->GetField( field->GetName() );
1004
1005 if( !parentField ) // Derived symbol field does not exist in parent symbol.
1006 {
1007 retv->AddDrawItem( newField );
1008 }
1009 else // Derived symbol field overrides the parent symbol field.
1010 {
1011 retv->RemoveDrawItem( parentField );
1012 retv->AddDrawItem( newField );
1013 }
1014 }
1015
1016 // Use this symbol's keywords/filters if set, otherwise keep inherited ones
1017 if( !m_keyWords.IsEmpty() )
1018 retv->SetKeyWords( m_keyWords );
1019
1020 if( !m_fpFilters.IsEmpty() )
1021 retv->SetFPFilters( m_fpFilters );
1022
1023 // Copying the embedded files needs to go in the other direction. AddFile() silently
1024 // drops collisions, so the most relevant symbol ("this") must go first, followed by
1025 // parents up the chain to the root.
1026 {
1027 for( const auto& [name, file] : EmbeddedFileMap() )
1028 {
1030 retv->AddFile( newFile );
1031 }
1032
1033 for( const LIB_SYMBOL* ancestor : parentChain )
1034 {
1035 for( const auto& [name, file] : ancestor->EmbeddedFileMap() )
1036 {
1038 retv->AddFile( newFile );
1039 }
1040 }
1041 }
1042
1043 // Get excluded flags from the top-level parent (back of the chain). Derived symbols
1044 // aren't allowed to change the exclusion flags.
1045 if( !parentChain.empty() )
1046 {
1047 retv->SetExcludedFromSim( parentChain.back()->GetExcludedFromSim() );
1048 retv->SetExcludedFromBOM( parentChain.back()->GetExcludedFromBOM() );
1049 retv->SetExcludedFromBoard( parentChain.back()->GetExcludedFromBoard() );
1050 retv->SetExcludedFromPosFiles( parentChain.back()->GetExcludedFromPosFiles() );
1051 }
1052
1053 // Pin maps and associated footprints inherit as a coupled bundle; copy the resolved
1054 // effective bundle so the flattened symbol is self-contained.
1055 retv->m_pinMaps = GetEffectivePinMaps();
1056 retv->m_associatedFootprints = GetEffectiveAssociatedFootprints();
1057
1058 retv->m_cachesDirty = true;
1059 retv->m_parent.reset();
1060 }
1061 else
1062 {
1063 retv = std::make_unique<LIB_SYMBOL>( *this );
1064 }
1065
1066 return retv;
1067}
1068
1069
1071{
1072 m_library = aLibrary;
1073
1074 m_cachesDirty = true;
1075}
1076
1077
1078const wxString LIB_SYMBOL::GetLibraryName() const
1079{
1080 if( m_library )
1081 return m_library->GetName();
1082
1083 return m_libId.GetLibNickname();
1084}
1085
1086
1088{
1089 if( IsDerived() )
1090 {
1091 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1092
1093 if( root.get() != this )
1094 return root->IsLocalPower();
1095 }
1096
1097 return m_options == ENTRY_LOCAL_POWER;
1098}
1099
1100
1102{
1103 if( IsDerived() )
1104 {
1105 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1106
1107 if( root.get() != this )
1108 {
1109 root->SetLocalPower();
1110 return;
1111 }
1112 }
1113
1115
1116 m_cachesDirty = true;
1117}
1118
1119
1121{
1122 if( IsDerived() )
1123 {
1124 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1125
1126 if( root.get() != this )
1127 return root->IsGlobalPower();
1128 }
1129
1130 return m_options == ENTRY_GLOBAL_POWER;
1131}
1132
1133
1135{
1136 return IsLocalPower() || IsGlobalPower();
1137}
1138
1139
1141{
1142 if( IsDerived() )
1143 {
1144 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1145
1146 if( root.get() != this )
1147 {
1148 root->SetGlobalPower();
1149 return;
1150 }
1151 }
1152
1154
1155 m_cachesDirty = true;
1156}
1157
1158
1160{
1161 if( IsDerived() )
1162 {
1163 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1164
1165 if( root.get() != this )
1166 return root->IsNormal();
1167 }
1168
1169 return m_options == ENTRY_NORMAL;
1170}
1171
1172
1174{
1175 if( IsDerived() )
1176 {
1177 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1178
1179 if( root.get() != this )
1180 {
1181 root->SetNormal();
1182 return;
1183 }
1184 }
1185
1187
1188 m_cachesDirty = true;
1189}
1190
1191
1192wxString LIB_SYMBOL::LetterSubReference( int aUnit, wxChar aInitialLetter )
1193{
1194 // use letters as notation. To allow more than 26 units, the sub ref
1195 // use one letter if letter = A .. Z or a ... z, and 2 letters otherwise
1196 // first letter is expected to be 'A' or 'a' (i.e. 26 letters are available)
1197 int u;
1198 wxString suffix;
1199
1200 do
1201 {
1202 u = ( aUnit - 1 ) % 26;
1203 suffix = wxChar( aInitialLetter + u ) + suffix;
1204 aUnit = ( aUnit - u ) / 26;
1205 } while( aUnit > 0 );
1206
1207 return suffix;
1208}
1209
1210
1211bool LIB_SYMBOL::ResolveTextVar( wxString* token, int aDepth ) const
1212{
1213 wxString footprint;
1214
1215 for( const SCH_ITEM& item : m_drawings )
1216 {
1217 if( item.Type() == SCH_FIELD_T )
1218 {
1219 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
1220
1221 if( field.GetId() == FIELD_T::FOOTPRINT )
1222 footprint = field.GetShownText( nullptr, INTERNAL, wxEmptyString, aDepth + 1 );
1223
1224 if( token->IsSameAs( field.GetUntranslatedName().Upper() ) || token->IsSameAs( field.GetName(), false ) )
1225 {
1226 *token = field.GetShownText( nullptr, INTERNAL, wxEmptyString, aDepth + 1 );
1227 return true;
1228 }
1229 }
1230 }
1231
1232 // Consider missing simulation fields as empty, not un-resolved
1233 if( token->IsSameAs( wxT( "SIM.DEVICE" ) ) || token->IsSameAs( wxT( "SIM.TYPE" ) )
1234 || token->IsSameAs( wxT( "SIM.PINS" ) ) || token->IsSameAs( wxT( "SIM.PARAMS" ) )
1235 || token->IsSameAs( wxT( "SIM.LIBRARY" ) ) || token->IsSameAs( wxT( "SIM.NAME" ) ) )
1236 {
1237 *token = wxEmptyString;
1238 return true;
1239 }
1240
1241 if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
1242 {
1243 wxArrayString parts = wxSplit( footprint, ':' );
1244
1245 if( parts.Count() > 0 )
1246 *token = parts[0];
1247 else
1248 *token = wxEmptyString;
1249
1250 return true;
1251 }
1252 else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1253 {
1254 wxArrayString parts = wxSplit( footprint, ':' );
1255
1256 if( parts.Count() > 1 )
1257 *token = parts[std::min( 1, (int) parts.size() - 1 )];
1258 else
1259 *token = wxEmptyString;
1260
1261 return true;
1262 }
1263 else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
1264 {
1265 *token = m_libId.GetUniStringLibNickname();
1266 return true;
1267 }
1268 else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
1269 {
1270 *token = m_libId.GetUniStringLibItemName();
1271 return true;
1272 }
1273 else if( token->IsSameAs( wxT( "SYMBOL_PARENT" ) ) )
1274 {
1275 std::shared_ptr<LIB_SYMBOL> parent = GetParent().lock();
1276 *token = parent ? parent->GetName() : wxString();
1277 return true;
1278 }
1279 else if( token->IsSameAs( wxT( "SYMBOL_ROOT" ) ) )
1280 {
1281 std::shared_ptr<LIB_SYMBOL> root = GetRootSymbol();
1282 *token = root ? root->GetName() : GetName();
1283 return true;
1284 }
1285 else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
1286 {
1287 *token = GetShownDescription( INTERNAL, aDepth + 1 );
1288 return true;
1289 }
1290 else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
1291 {
1292 *token = GetShownKeyWords( INTERNAL, aDepth + 1 );
1293 return true;
1294 }
1295 else if( token->IsSameAs( wxT( "SYMBOL_IS_POWER" ) ) )
1296 {
1297 *token = this->IsPower() ? wxString( wxS( "Power Symbol" ) ) : wxString( "" );
1298 return true;
1299 }
1300 else if( token->IsSameAs( wxT( "SYMBOL_IS_LOCAL_POWER" ) ) )
1301 {
1302 *token = this->IsLocalPower() ? wxString( wxS( "Local Power Symbol" ) ) : wxString( "" );
1303 return true;
1304 }
1305 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
1306 {
1307 *token = this->GetExcludedFromBOM() ? wxS( "Excluded from BOM" ) : wxEmptyString;
1308 return true;
1309 }
1310 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
1311 {
1312 *token = this->GetExcludedFromBoard() ? wxS( "Excluded from board" ) : wxEmptyString;
1313 return true;
1314 }
1315 else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
1316 {
1317 *token = this->GetExcludedFromSim() ? wxS( "Excluded from simulation" ) : wxEmptyString;
1318 return true;
1319 }
1320 else if( token->IsSameAs( wxT( "DNP" ) ) )
1321 {
1322 *token = this->GetDNP() ? wxS( "DNP" ) : wxEmptyString;
1323 return true;
1324 }
1325
1326 return false;
1327}
1328
1329
1330void LIB_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit, int aBodyStyle,
1331 const VECTOR2I& aOffset, bool aDimmed )
1332{
1333 wxASSERT( aPlotter != nullptr );
1334
1335 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
1336 COLOR4D color = renderSettings->GetLayerColor( LAYER_DEVICE );
1337 COLOR4D bg = renderSettings->GetBackgroundColor();
1338
1339 if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
1340 bg = COLOR4D::WHITE;
1341
1342 if( color.m_text && Schematic() )
1343 color = COLOR4D( ResolveText( *color.m_text, &Schematic()->CurrentSheet() ) );
1344
1345 if( aDimmed )
1346 {
1347 color.Desaturate();
1348 color = color.Mix( bg, 0.5f );
1349 }
1350
1351 aPlotter->SetColor( color );
1352
1353 for( SCH_ITEM& item : m_drawings )
1354 {
1355 // Do not plot private items
1356 if( item.IsPrivate() )
1357 continue;
1358
1359 // LIB_FIELDs are not plotted here, because this plot function is used to plot schematic
1360 // items which have their own SCH_FIELDs
1361 if( item.Type() == SCH_FIELD_T )
1362 continue;
1363
1364 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
1365 continue;
1366
1367 if( aBodyStyle && item.m_bodyStyle && ( item.m_bodyStyle != aBodyStyle ) )
1368 continue;
1369
1370 item.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1371 }
1372}
1373
1374
1375void LIB_SYMBOL::PlotFields( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts, int aUnit,
1376 int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
1377{
1378 wxASSERT( aPlotter != nullptr );
1379
1380 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
1381 COLOR4D color = renderSettings->GetLayerColor( LAYER_FIELDS );
1382 COLOR4D bg = renderSettings->GetBackgroundColor();
1383
1384 if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
1385 bg = COLOR4D::WHITE;
1386
1387 if( aDimmed )
1388 {
1389 color.Desaturate();
1390 color = color.Mix( bg, 0.5f );
1391 }
1392
1393 aPlotter->SetColor( color );
1394
1395 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
1396 {
1397 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
1398
1399 if( !renderSettings->m_ShowHiddenFields && !field.IsVisible() )
1400 continue;
1401
1402 // The reference is a special case: we should change the basic text
1403 // to add '?' and the part id
1404 wxString tmp = field.GetText();
1405
1406 field.SetText( field.GetFullText( aUnit ) );
1407 item.Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
1408
1409 field.SetText( tmp );
1410 }
1411}
1412
1413
1415{
1416 std::vector<SCH_SHAPE*> potential_top_items;
1417 std::vector<SCH_ITEM*> bottom_items;
1418
1419 for( SCH_ITEM& item : m_drawings )
1420 {
1421 if( item.Type() == SCH_SHAPE_T )
1422 {
1423 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
1424
1425 if( shape.GetFillMode() == FILL_T::FILLED_WITH_COLOR )
1426 potential_top_items.push_back( &shape );
1427 else
1428 bottom_items.push_back( &item );
1429 }
1430 else
1431 {
1432 bottom_items.push_back( &item );
1433 }
1434 }
1435
1436 std::sort( potential_top_items.begin(), potential_top_items.end(),
1437 []( SCH_ITEM* a, SCH_ITEM* b )
1438 {
1439 return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
1440 } );
1441
1442 for( SCH_SHAPE* item : potential_top_items )
1443 {
1444 for( SCH_ITEM* bottom_item : bottom_items )
1445 {
1446 if( item->GetBoundingBox().Contains( bottom_item->GetBoundingBox() ) )
1447 {
1448 item->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1449 break;
1450 }
1451 }
1452 }
1453}
1454
1455
1457{
1458 wxASSERT( aItem != nullptr );
1459
1460 // none of the MANDATORY_FIELDS may be removed in RAM, but they may be
1461 // omitted when saving to disk.
1462 if( aItem->Type() == SCH_FIELD_T )
1463 {
1464 if( static_cast<SCH_FIELD*>( aItem )->IsMandatory() )
1465 return;
1466 }
1467
1468 LIB_ITEMS& items = m_drawings[aItem->Type()];
1469
1470 for( LIB_ITEMS::iterator i = items.begin(); i != items.end(); i++ )
1471 {
1472 if( &*i == aItem )
1473 {
1474 items.erase( i );
1475 m_cachesDirty = true;
1476 break;
1477 }
1478 }
1479}
1480
1481
1482void LIB_SYMBOL::AddDrawItem( SCH_ITEM* aItem, bool aSort )
1483{
1484 if( aItem )
1485 {
1486 aItem->SetParent( this );
1487
1488 m_drawings.push_back( aItem );
1489
1490 if( aSort )
1491 m_drawings.sort();
1492
1493 m_cachesDirty = true;
1494 }
1495}
1496
1497
1498std::vector<SCH_PIN*> LIB_SYMBOL::GetGraphicalPins( int aUnit, int aBodyStyle ) const
1499{
1500 if( IsDerived() )
1501 {
1502 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1503
1504 if( root.get() != this )
1505 return const_cast<const LIB_SYMBOL*>( root.get() )->GetGraphicalPins( aUnit, aBodyStyle );
1506 }
1507
1508 std::vector<SCH_PIN*> pins;
1509
1510 /* Notes:
1511 * when aUnit == 0: no unit filtering
1512 * when aBodyStyle == 0: no body style filtering
1513 * when m_unit == 0, the item is common to all units
1514 * when m_bodyStyle == 0, the item is common to all body styles
1515 */
1516
1517 for( const SCH_ITEM& item : m_drawings[SCH_PIN_T] )
1518 {
1519 // Unit filtering:
1520 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
1521 continue;
1522
1523 // Body style filtering:
1524 if( aBodyStyle && item.m_bodyStyle && ( item.m_bodyStyle != aBodyStyle ) )
1525 continue;
1526
1527 pins.push_back( static_cast<SCH_PIN*>( const_cast<SCH_ITEM*>( &item ) ) );
1528 }
1529
1530 return pins;
1531}
1532
1533
1534std::vector<LIB_SYMBOL::UNIT_PIN_INFO> LIB_SYMBOL::GetUnitPinInfo() const
1535{
1536 std::vector<UNIT_PIN_INFO> units;
1537
1538 int unitCount = std::max( GetUnitCount(), 1 );
1539
1540 auto compareByPosition =
1541 []( const SCH_PIN* a, const SCH_PIN* b )
1542 {
1543 VECTOR2I positionA = a->GetPosition();
1544 VECTOR2I positionB = b->GetPosition();
1545
1546 if( positionA.x != positionB.x )
1547 return positionA.x < positionB.x;
1548
1549 return positionA.y < positionB.y;
1550 };
1551
1552 for( int unitIdx = 1; unitIdx <= unitCount; ++unitIdx )
1553 {
1554 UNIT_PIN_INFO unitInfo;
1555 unitInfo.m_unitName = GetUnitDisplayName( unitIdx, false );
1556
1557 std::vector<SCH_PIN*> pinList = GetGraphicalPins( unitIdx, 0 );
1558
1559 std::sort( pinList.begin(), pinList.end(), compareByPosition );
1560
1561 std::unordered_set<wxString> seenNumbers;
1562
1563 for( const SCH_PIN* basePin : pinList )
1564 {
1565 bool stackedValid = false;
1566 std::vector<wxString> expandedNumbers = basePin->GetStackedPinNumbers( &stackedValid );
1567
1568 if( stackedValid && !expandedNumbers.empty() )
1569 {
1570 for( const wxString& number : expandedNumbers )
1571 {
1572 if( seenNumbers.insert( number ).second )
1573 unitInfo.m_pinNumbers.push_back( number );
1574 }
1575
1576 continue;
1577 }
1578
1579 const wxString& number = basePin->GetNumber();
1580
1581 if( !number.IsEmpty() && seenNumbers.insert( number ).second )
1582 unitInfo.m_pinNumbers.push_back( number );
1583 }
1584
1585 units.push_back( std::move( unitInfo ) );
1586 }
1587
1588 return units;
1589}
1590
1591
1592std::vector<LIB_SYMBOL::LOGICAL_PIN> LIB_SYMBOL::GetLogicalPins( int aUnit, int aBodyStyle ) const
1593{
1594 std::vector<LOGICAL_PIN> out;
1595
1596 for( const SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1597 {
1598 bool valid = false;
1599 std::vector<wxString> expanded = pin->GetStackedPinNumbers( &valid );
1600
1601 if( valid && !expanded.empty() )
1602 {
1603 for( const wxString& num : expanded )
1604 {
1605 out.push_back( LOGICAL_PIN{ pin, num } );
1606 wxLogTrace( traceStackedPins, "GetLogicalPins: base='%s' -> '%s'", pin->GetShownNumber(), num );
1607 }
1608 }
1609 else
1610 {
1611 out.push_back( LOGICAL_PIN{ pin, pin->GetShownNumber() } );
1612 wxLogTrace( traceStackedPins, "GetLogicalPins: base='%s' (no expansion)", pin->GetShownNumber() );
1613 }
1614 }
1615
1616 return out;
1617}
1618
1619
1621{
1622 if( m_cachesDirty )
1623 rebuildCaches();
1624
1625 return m_pinCountCache;
1626}
1627
1628
1629const SCH_PIN* LIB_SYMBOL::GetPin( const wxString& aNumber, int aUnit, int aBodyStyle ) const
1630{
1631 for( const SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1632 {
1633 if( aNumber == pin->GetNumber() )
1634 return pin;
1635 }
1636
1637 return nullptr;
1638}
1639
1640
1641std::vector<SCH_PIN*> LIB_SYMBOL::GetPinsByNumber( const wxString& aNumber, int aUnit, int aBodyStyle )
1642{
1643 std::vector<SCH_PIN*> pins;
1644
1645 for( SCH_PIN* pin : GetGraphicalPins( aUnit, aBodyStyle ) )
1646 {
1647 if( aNumber == pin->GetNumber() )
1648 pins.push_back( pin );
1649 }
1650
1651 return pins;
1652}
1653
1654
1655bool LIB_SYMBOL::HasPinNumber( const wxString& aNumber ) const
1656{
1657 if( GetPin( aNumber ) )
1658 return true;
1659
1660 for( const SCH_PIN* pin : GetGraphicalPins( 0, 0 ) )
1661 {
1662 for( const wxString& logicalNumber : pin->GetStackedPinNumbers() )
1663 {
1664 if( aNumber == logicalNumber )
1665 return true;
1666 }
1667 }
1668
1669 return false;
1670}
1671
1672
1673bool LIB_SYMBOL::PinsConflictWith( const LIB_SYMBOL& aOtherPart, bool aTestNums, bool aTestNames, bool aTestType,
1674 bool aTestOrientation, bool aTestLength ) const
1675{
1676 for( const SCH_PIN* pin : GetGraphicalPins() )
1677 {
1678 wxASSERT( pin );
1679 bool foundMatch = false;
1680
1681 for( const SCH_PIN* otherPin : aOtherPart.GetGraphicalPins() )
1682 {
1683 wxASSERT( otherPin );
1684
1685 // Same unit?
1686 if( pin->GetUnit() != otherPin->GetUnit() )
1687 continue;
1688
1689 // Same body stype?
1690 if( pin->GetBodyStyle() != otherPin->GetBodyStyle() )
1691 continue;
1692
1693 // Same position?
1694 if( pin->GetPosition() != otherPin->GetPosition() )
1695 continue;
1696
1697 // Same number?
1698 if( aTestNums && ( pin->GetNumber() != otherPin->GetNumber() ) )
1699 continue;
1700
1701 // Same name?
1702 if( aTestNames && ( pin->GetName() != otherPin->GetName() ) )
1703 continue;
1704
1705 // Same electrical type?
1706 if( aTestType && ( pin->GetType() != otherPin->GetType() ) )
1707 continue;
1708
1709 // Same orientation?
1710 if( aTestOrientation && ( pin->GetOrientation() != otherPin->GetOrientation() ) )
1711 continue;
1712
1713 // Same length?
1714 if( aTestLength && ( pin->GetLength() != otherPin->GetLength() ) )
1715 continue;
1716
1717 foundMatch = true;
1718 break; // Match found so search is complete.
1719 }
1720
1721 if( !foundMatch )
1722 {
1723 // This means there was not an identical (according to the arguments)
1724 // pin at the same position in the other symbol.
1725 return true;
1726 }
1727 }
1728
1729 // The loop never gave up, so no conflicts were found.
1730 return false;
1731}
1732
1733const BOX2I LIB_SYMBOL::GetUnitBoundingBox( int aUnit, int aBodyStyle, bool aIgnoreHiddenFields,
1734 bool aIgnoreLabelsOnInvisiblePins ) const
1735{
1736 BOX2I bBox; // Start with a fresh BOX2I so the Merge algorithm works
1737
1738 if( IsDerived() )
1739 {
1740 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
1741
1742 if( root.get() != this )
1743 bBox = root->GetUnitBoundingBox( aUnit, aBodyStyle, aIgnoreHiddenFields, aIgnoreLabelsOnInvisiblePins );
1744 }
1745
1746 for( const SCH_ITEM& item : m_drawings )
1747 {
1748 if( item.m_unit > 0 && m_unitCount > 1 && aUnit > 0 && aUnit != item.m_unit )
1749 continue;
1750
1751 if( item.m_bodyStyle > 0 && aBodyStyle > 0 && aBodyStyle != item.m_bodyStyle )
1752 continue;
1753
1754 if( aIgnoreHiddenFields && item.Type() == SCH_FIELD_T )
1755 {
1756 if( !static_cast<const SCH_FIELD&>( item ).IsVisible() )
1757 continue;
1758 }
1759
1760 if( item.Type() == SCH_PIN_T && !aIgnoreLabelsOnInvisiblePins )
1761 {
1762 const SCH_PIN& pin = static_cast<const SCH_PIN&>( item );
1763 bBox.Merge( pin.GetBoundingBox( true, true, false ) );
1764 }
1765 else
1766 {
1767 bBox.Merge( item.GetBoundingBox() );
1768 }
1769 }
1770
1771 return bBox;
1772}
1773
1774
1775const BOX2I LIB_SYMBOL::GetBodyBoundingBox( int aUnit, int aBodyStyle, bool aIncludePins,
1776 bool aIncludePrivateItems ) const
1777{
1778 BOX2I bbox;
1779
1780 for( const SCH_ITEM& item : m_drawings )
1781 {
1782 if( item.m_unit > 0 && aUnit > 0 && aUnit != item.m_unit )
1783 continue;
1784
1785 if( item.m_bodyStyle > 0 && aBodyStyle > 0 && aBodyStyle != item.m_bodyStyle )
1786 continue;
1787
1788 if( item.IsPrivate() && !aIncludePrivateItems )
1789 continue;
1790
1791 if( item.Type() == SCH_FIELD_T )
1792 continue;
1793
1794 if( item.Type() == SCH_PIN_T )
1795 {
1796 const SCH_PIN& pin = static_cast<const SCH_PIN&>( item );
1797
1798 if( pin.IsVisible() )
1799 {
1800 // Note: the roots of the pins are always included for symbols that don't have
1801 // a well-defined body.
1802
1803 if( aIncludePins )
1804 bbox.Merge( pin.GetBoundingBox( false, false, false ) );
1805 else
1806 bbox.Merge( pin.GetPinRoot() );
1807 }
1808 }
1809 else
1810 {
1811 bbox.Merge( item.GetBoundingBox() );
1812 }
1813 }
1814
1815 return bbox;
1816}
1817
1818
1823
1824
1826{
1827 m_drawings[SCH_FIELD_T].clear();
1828 m_cachesDirty = true;
1829}
1830
1831
1833{
1834 AddDrawItem( aField );
1835}
1836
1837
1838void LIB_SYMBOL::SetFields( const std::vector<SCH_FIELD>& aFieldsList )
1839{
1841
1842 for( const SCH_FIELD& src : aFieldsList )
1843 {
1844 // drawings is a ptr_vector, new and copy an object on the heap.
1845 SCH_FIELD* field = new SCH_FIELD( src );
1846
1847 field->SetParent( this );
1848 m_drawings.push_back( field );
1849 }
1850
1851 m_drawings.sort();
1852 m_cachesDirty = true;
1853}
1854
1855
1856void LIB_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aList, bool aVisibleOnly ) const
1857{
1858 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
1859 {
1860 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
1861
1862 if( aVisibleOnly )
1863 {
1864 if( !field->IsVisible() || field->GetText().IsEmpty() )
1865 continue;
1866 }
1867
1868 aList.push_back( const_cast<SCH_FIELD*>( field ) );
1869 }
1870
1871 std::sort( aList.begin(), aList.end(),
1872 []( SCH_FIELD* lhs, SCH_FIELD* rhs )
1873 {
1874 return lhs->GetOrdinal() < rhs->GetOrdinal();
1875 } );
1876}
1877
1878
1879void LIB_SYMBOL::CopyFields( std::vector<SCH_FIELD>& aList )
1880{
1881 std::vector<SCH_FIELD*> orderedFields;
1882
1883 GetFields( orderedFields );
1884
1885 for( SCH_FIELD* field : orderedFields )
1886 aList.emplace_back( *field );
1887}
1888
1889
1891{
1892 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
1893
1894 if( !parent )
1895 return;
1896
1897 std::unique_ptr<LIB_SYMBOL> flattenedParent = parent->Flatten();
1898
1899 auto selected =
1900 [&]( const wxString& aFieldName )
1901 {
1902 return aOptions.m_updateAllFields
1903 || aOptions.m_updateFields.count( aFieldName ) > 0;
1904 };
1905
1906 std::vector<SCH_FIELD> fieldsCopy;
1907 std::vector<SCH_FIELD> result;
1908 CopyFields( fieldsCopy );
1909
1910 for( SCH_FIELD& field : fieldsCopy )
1911 {
1912 bool copy = true;
1913 SCH_FIELD* parentField = nullptr;
1914
1915 if( selected( field.GetName() ) )
1916 {
1917 if( field.IsMandatory() )
1918 parentField = flattenedParent->GetField( field.GetId() );
1919 else
1920 parentField = flattenedParent->GetField( field.GetName() );
1921
1922 if( parentField )
1923 {
1924 bool resetText = parentField->GetText().IsEmpty() ? aOptions.m_resetEmptyText
1925 : aOptions.m_resetText;
1926
1927 if( resetText )
1928 field.SetText( parentField->GetText() );
1929
1930 if( aOptions.m_resetVisibility )
1931 {
1932 field.SetVisible( parentField->IsVisible() );
1933 field.SetNameShown( parentField->IsNameShown() );
1934 }
1935
1936 if( aOptions.m_resetEffects )
1937 {
1938 // SetAttributes() also overwrites the visible bit and position, so save
1939 // and restore them here.
1940 bool visible = field.IsVisible();
1941 VECTOR2I pos = field.GetPosition();
1942
1943 field.SetAttributes( *parentField );
1944
1945 field.SetVisible( visible );
1946 field.SetPosition( pos );
1947 }
1948
1949 if( aOptions.m_resetPositions )
1950 field.SetTextPos( parentField->GetTextPos() );
1951 }
1952 else if( aOptions.m_removeExtraFields )
1953 {
1954 copy = false;
1955 }
1956 }
1957
1958 if( copy )
1959 result.emplace_back( std::move( field ) );
1960 }
1961
1962 int nextOrdinal = GetNextFieldOrdinal();
1963 std::vector<SCH_FIELD*> parentFields;
1964
1965 flattenedParent->GetFields( parentFields );
1966
1967 for( SCH_FIELD* parentField : parentFields )
1968 {
1969 if( !selected( parentField->GetName() ) )
1970 continue;
1971
1972 if( !GetField( parentField->GetName() ) )
1973 {
1974 result.emplace_back( this, FIELD_T::USER );
1975 SCH_FIELD* newField = &result.back();
1976
1977 newField->SetName( parentField->GetUntranslatedName() );
1978 newField->SetText( parentField->GetText() );
1979 newField->SetAttributes( *parentField ); // Includes visible bit and position
1980 newField->SetOrdinal( nextOrdinal++, FIELD_T::USER );
1981 }
1982 }
1983
1984 SetFields( result );
1985}
1986
1987
1989{
1990 int ordinal = 42; // Arbitrarily larger than any mandatory FIELD_T id
1991
1992 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
1993 ordinal = std::max( ordinal, static_cast<const SCH_FIELD*>( &item )->GetOrdinal() + 1 );
1994
1995 return ordinal;
1996}
1997
1998
1999const SCH_FIELD* LIB_SYMBOL::GetField( FIELD_T aFieldType ) const
2000{
2001 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2002 {
2003 const SCH_FIELD* field = static_cast<const SCH_FIELD*>( &item );
2004
2005 if( field->GetId() == aFieldType )
2006 return field;
2007 }
2008
2009 return nullptr;
2010}
2011
2012
2014{
2015 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2016 {
2017 SCH_FIELD* field = static_cast<SCH_FIELD*>( &item );
2018
2019 if( field->GetId() == aFieldType )
2020 return field;
2021 }
2022
2023 return nullptr;
2024}
2025
2026
2027const SCH_FIELD* LIB_SYMBOL::GetField( const wxString& aFieldName ) const
2028{
2029 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2030 {
2031 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
2032
2033 if( field.GetName() == aFieldName )
2034 return &field;
2035 }
2036
2037 return nullptr;
2038}
2039
2040
2041SCH_FIELD* LIB_SYMBOL::GetField( const wxString& aFieldName )
2042{
2043 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2044 {
2045 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
2046
2047 if( field.GetName() == aFieldName )
2048 return &field;
2049 }
2050
2051 return nullptr;
2052}
2053
2054
2056{
2057 for( SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2058 {
2059 SCH_FIELD& field = static_cast<SCH_FIELD&>( item );
2060
2061 if( field.GetUntranslatedName().IsSameAs( aFieldName, false ) )
2062 return &field;
2063 }
2064
2065 return nullptr;
2066}
2067
2068
2069const SCH_FIELD* LIB_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName ) const
2070{
2071 for( const SCH_ITEM& item : m_drawings[SCH_FIELD_T] )
2072 {
2073 const SCH_FIELD& field = static_cast<const SCH_FIELD&>( item );
2074
2075 if( field.GetUntranslatedName().IsSameAs( aFieldName, false ) )
2076 return &field;
2077 }
2078
2079 return nullptr;
2080}
2081
2082
2084{
2085 const SCH_FIELD* field = GetField( FIELD_T::VALUE );
2086 wxASSERT( field != nullptr );
2087 return *field;
2088}
2089
2090
2092{
2093 const SCH_FIELD* field = GetField( FIELD_T::REFERENCE );
2094 wxASSERT( field != nullptr );
2095 return *field;
2096}
2097
2098
2100{
2101 const SCH_FIELD* field = GetField( FIELD_T::FOOTPRINT );
2102 wxASSERT( field != nullptr );
2103 return *field;
2104}
2105
2106
2108{
2109 const SCH_FIELD* field = GetField( FIELD_T::DATASHEET );
2110 wxASSERT( field != nullptr );
2111 return *field;
2112}
2113
2114
2116{
2117 const SCH_FIELD* field = GetField( FIELD_T::DESCRIPTION );
2118 wxASSERT( field != nullptr );
2119 return *field;
2120}
2121
2122
2124{
2125 wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
2126
2127 refDesignator.Replace( wxS( "~" ), wxS( " " ) );
2128
2129 wxString prefix = refDesignator;
2130
2131 while( prefix.Length() )
2132 {
2133 wxUniCharRef last = prefix.Last();
2134
2135 if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
2136 prefix.RemoveLast();
2137 else
2138 break;
2139 }
2140
2141 // Avoid a prefix containing trailing/leading spaces
2142 prefix.Trim( true );
2143 prefix.Trim( false );
2144
2145 return prefix;
2146}
2147
2148
2149void LIB_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
2150{
2151 for( SCH_ITEM& item : m_drawings )
2152 aFunction( &item );
2153
2154 // We don't know what this did, so better to be safe than sorry
2155 m_cachesDirty = true;
2156}
2157
2158
2159void LIB_SYMBOL::Move( const VECTOR2I& aOffset )
2160{
2161 for( SCH_ITEM& item : m_drawings )
2162 item.Move( aOffset );
2163}
2164
2165
2166// Before V10 we didn't store the number of body styles in a symbol -- we just looked through all
2167// its drawings each time we wanted to know. This is now only used to set the count when a legacy
2168// symbol is first read. (Legacy symbols also didn't support arbitrary body styles, so the count
2169// is always 1 or 2, and when 2 it is always a De Morgan pair.)
2171{
2172 for( const SCH_ITEM& item : m_drawings )
2173 {
2174 if( item.m_bodyStyle > BODY_STYLE::BASE )
2175 return true;
2176 }
2177
2178 if( IsDerived() )
2179 {
2180 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2181
2182 if( root.get() != this )
2183 return root->HasLegacyAlternateBodyStyle();
2184 }
2185
2186 return false;
2187}
2188
2189
2191{
2192 if( IsDerived() )
2193 {
2194 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2195
2196 if( root.get() != this )
2197 return root->GetMaxPinNumber();
2198 }
2199
2200 int maxPinNumber = 0;
2201
2202 for( const SCH_ITEM& item : m_drawings[SCH_PIN_T] )
2203 {
2204 const SCH_PIN* pin = static_cast<const SCH_PIN*>( &item );
2205 long currentPinNumber = 0;
2206
2207 if( pin->GetNumber().ToLong( &currentPinNumber ) )
2208 maxPinNumber = std::max( maxPinNumber, (int) currentPinNumber );
2209 }
2210
2211 return maxPinNumber;
2212}
2213
2214
2216{
2218
2219 for( SCH_ITEM& item : m_drawings )
2220 item.ClearTempFlags();
2221}
2222
2223
2225{
2227
2228 for( SCH_ITEM& item : m_drawings )
2229 item.ClearEditFlags();
2230}
2231
2232
2233SCH_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I& aPoint )
2234{
2235 for( SCH_ITEM& item : m_drawings )
2236 {
2237 if( ( aUnit && item.m_unit && aUnit != item.m_unit )
2238 || ( aBodyStyle && item.m_bodyStyle && aBodyStyle != item.m_bodyStyle )
2239 || ( item.Type() != aType && aType != TYPE_NOT_INIT ) )
2240 {
2241 continue;
2242 }
2243
2244 if( item.HitTest( aPoint ) )
2245 return &item;
2246 }
2247
2248 return nullptr;
2249}
2250
2251
2252SCH_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aBodyStyle, KICAD_T aType, const VECTOR2I& aPoint,
2253 const TRANSFORM& aTransform )
2254{
2255 /* we use LocateDrawItem( int aUnit, int convert, KICAD_T type, const
2256 * VECTOR2I& pt ) to search items.
2257 * because this function uses DefaultTransform as orient/mirror matrix
2258 * we temporary copy aTransform in DefaultTransform
2259 */
2260 TRANSFORM transform = DefaultTransform;
2261 DefaultTransform = aTransform;
2262
2263 SCH_ITEM* item = LocateDrawItem( aUnit, aBodyStyle, aType, aPoint );
2264
2265 // Restore matrix
2266 DefaultTransform = transform;
2267
2268 return item;
2269}
2270
2271
2272INSPECT_RESULT LIB_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData, const std::vector<KICAD_T>& aScanTypes )
2273{
2274 // The part itself is never inspected, only its children
2275 for( SCH_ITEM& item : m_drawings )
2276 {
2277 if( item.IsType( aScanTypes ) )
2278 {
2279 if( aInspector( &item, aTestData ) == INSPECT_RESULT::QUIT )
2280 return INSPECT_RESULT::QUIT;
2281 }
2282 }
2283
2285}
2286
2287
2288void LIB_SYMBOL::SetUnitCount( int aCount, bool aDuplicateDrawItems )
2289{
2290 // A LIB_SYMBOL must always have at least one unit. Passing a value less than 1 would
2291 // erase the mandatory fields (which all have m_unit == 0), leaving the symbol in a
2292 // broken state that crashes later when callers dereference GetReferenceField() etc.
2293 wxCHECK_RET( aCount >= 1, wxString::Format( wxT( "Invalid unit count %d, ignoring." ), aCount ) );
2294
2295 if( m_unitCount == aCount )
2296 return;
2297
2298 if( aCount < m_unitCount )
2299 {
2300 // Iterate each drawing-type bucket and erase items that belong to units > aCount.
2301 for( int type = LIB_ITEMS_CONTAINER::FIRST_TYPE; type <= LIB_ITEMS_CONTAINER::LAST_TYPE; ++type )
2302 {
2303 auto it = m_drawings.begin( type );
2304
2305 while( it != m_drawings.end( type ) )
2306 {
2307 if( it->m_unit > aCount )
2308 it = m_drawings.erase( it ); // returns next iterator
2309 else
2310 ++it;
2311 }
2312 }
2313 }
2314 else if( aDuplicateDrawItems )
2315 {
2316 int prevCount = m_unitCount;
2317
2318 // Temporary storage for new items, as adding new items directly to
2319 // m_drawings may cause the buffer reallocation which invalidates the
2320 // iterators
2321 std::vector<SCH_ITEM*> tmp;
2322
2323 for( SCH_ITEM& item : m_drawings )
2324 {
2325 if( item.m_unit != 1 )
2326 continue;
2327
2328 for( int j = prevCount + 1; j <= aCount; j++ )
2329 {
2330 SCH_ITEM* newItem = item.Duplicate( IGNORE_PARENT_GROUP );
2331 newItem->m_unit = j;
2332 tmp.push_back( newItem );
2333 }
2334 }
2335
2336 for( SCH_ITEM* item : tmp )
2337 m_drawings.push_back( item );
2338 }
2339
2340 m_drawings.sort();
2341 m_unitCount = aCount;
2342 m_cachesDirty = true;
2343}
2344
2345
2347{
2348 if( IsDerived() )
2349 {
2350 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2351
2352 if( root.get() != this )
2353 return root->GetUnitCount();
2354 }
2355
2356 return m_unitCount;
2357}
2358
2359
2361{
2362 if( HasDeMorganBodyStyles() )
2363 return 2;
2364
2365 return std::max( 1, (int) GetBodyStyleNames().size() );
2366}
2367
2368
2370{
2371 if( IsDerived() )
2372 {
2373 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2374
2375 if( root.get() != this )
2376 return root->m_demorgan;
2377 }
2378
2379 return m_demorgan;
2380}
2381
2382
2383const std::vector<wxString>& LIB_SYMBOL::GetBodyStyleNames() const
2384{
2385 if( IsDerived() )
2386 {
2387 std::shared_ptr<LIB_SYMBOL> root = GetSafeRootSymbol( this, __FUNCTION__ );
2388
2389 if( root.get() != this )
2390 return root->m_bodyStyleNames;
2391 }
2392
2393 return m_bodyStyleNames;
2394}
2395
2396
2397void LIB_SYMBOL::SetBodyStyleCount( int aCount, bool aDuplicateDrawItems, bool aDuplicatePins )
2398{
2399 wxCHECK_RET( aCount >= 1,
2400 wxString::Format( wxT( "Invalid body style count %d, ignoring." ), aCount ) );
2401
2402 int prevCount = GetBodyStyleCount();
2403
2404 // Populate the new body styles from the standard one
2405 if( prevCount < aCount && ( aDuplicateDrawItems || aDuplicatePins ) )
2406 {
2407 std::vector<SCH_ITEM*> tmp; // Adding to m_drawings while iterating it invalidates the iterator
2408
2409 for( SCH_ITEM& item : m_drawings )
2410 {
2411 if( item.Type() == SCH_PIN_T )
2412 {
2413 if( !aDuplicatePins )
2414 continue;
2415 }
2416 else
2417 {
2418 if( !aDuplicateDrawItems )
2419 continue;
2420 }
2421
2422 if( item.m_bodyStyle == BODY_STYLE::BASE )
2423 {
2424 for( int j = prevCount + 1; j <= aCount; j++ )
2425 {
2426 SCH_ITEM* newItem = item.Duplicate( IGNORE_PARENT_GROUP );
2427 newItem->m_bodyStyle = j;
2428 tmp.push_back( newItem );
2429 }
2430 }
2431 }
2432
2433 for( SCH_ITEM* item : tmp )
2434 m_drawings.push_back( item );
2435
2436 m_drawings.sort();
2437 }
2438
2439 // A caller that already cleared the De Morgan flag or the body style names reports a
2440 // previous count of 1, so the deletion cannot be conditional on the count dropping
2441 PruneBodyStyleDrawItems( aCount );
2442
2443 m_cachesDirty = true;
2444}
2445
2446
2447void LIB_SYMBOL::PruneBodyStyleDrawItems( int aBodyStyleCount )
2448{
2450
2451 while( i != m_drawings.end() )
2452 {
2453 if( i->m_bodyStyle > aBodyStyleCount )
2454 i = m_drawings.erase( i );
2455 else
2456 ++i;
2457 }
2458}
2459
2460
2461std::vector<SCH_ITEM*> LIB_SYMBOL::GetUnitDrawItems( int aUnit, int aBodyStyle )
2462{
2463 std::vector<SCH_ITEM*> unitItems;
2464
2465 for( SCH_ITEM& item : m_drawings )
2466 {
2467 if( item.Type() == SCH_FIELD_T )
2468 continue;
2469
2470 if( aUnit != ALL_UNITS
2471 && item.GetUnit() != ALL_UNITS
2472 && aUnit != item.GetUnit() )
2473 {
2474 continue;
2475 }
2476
2477 if( aBodyStyle != ALL_BODY_STYLES
2478 && item.GetBodyStyle() != ALL_BODY_STYLES
2479 && aBodyStyle != item.GetBodyStyle() )
2480 {
2481 continue;
2482 }
2483
2484 unitItems.push_back( &item );
2485 }
2486
2487 return unitItems;
2488}
2489
2490
2491std::vector<LIB_SYMBOL_UNIT> LIB_SYMBOL::GetUnitDrawItems()
2492{
2493 std::vector<LIB_SYMBOL_UNIT> units;
2494
2495 // Enforce writing out of all defined unit/body-style combinations
2496 for( int unit = 1; unit <= GetUnitCount(); unit++ )
2497 {
2498 for( int bodyStyle = 1; bodyStyle <= GetBodyStyleCount(); bodyStyle++ )
2499 {
2500 LIB_SYMBOL_UNIT record;
2501 record.m_unit = unit;
2502 record.m_bodyStyle = bodyStyle;
2503 units.push_back( std::move( record ) );
2504 }
2505 }
2506
2507 for( SCH_ITEM& item : m_drawings )
2508 {
2509 if( item.Type() == SCH_FIELD_T )
2510 continue;
2511
2512 int unit = item.GetUnit();
2513 int bodyStyle = item.GetBodyStyle();
2514
2515 auto it = std::find_if( units.begin(), units.end(),
2516 [unit, bodyStyle]( const LIB_SYMBOL_UNIT& a )
2517 {
2518 return a.m_unit == unit && a.m_bodyStyle == bodyStyle;
2519 } );
2520
2521 if( it == units.end() )
2522 {
2523 LIB_SYMBOL_UNIT record;
2524 record.m_unit = unit;
2525 record.m_bodyStyle = bodyStyle;
2526 it = units.insert( units.end(), std::move( record ) );
2527 }
2528
2529 it->m_items.push_back( &item );
2530 }
2531
2532 std::sort( units.begin(), units.end(),
2533 []( const LIB_SYMBOL_UNIT& a, const LIB_SYMBOL_UNIT& b )
2534 {
2535 if( a.m_unit == b.m_unit )
2536 return a.m_bodyStyle < b.m_bodyStyle;
2537
2538 return a.m_unit < b.m_unit;
2539 } );
2540
2541 return units;
2542}
2543
2544
2545#define REPORT( msg ) \
2546 { \
2547 if( aReporter ) \
2548 aReporter->Report( msg ); \
2549 }
2550
2551#define ITEM_DESC( item ) ( item )->GetItemDescription( &unitsProvider, false )
2552
2553
2561
2562
2563bool LIB_SYMBOL_ATTRIBUTES::Matches( const LIB_SYMBOL_ATTRIBUTES& aOther, int aCompareFlags ) const
2564{
2565 using FLAGS = SCH_ITEM::COMPARE_FLAGS;
2566
2567 if( options != aOther.options || unitCount != aOther.unitCount || footprintFilters != aOther.footprintFilters
2569 || keywords != aOther.keywords || pinNameOffset != aOther.pinNameOffset
2571 || bodyStyleNames != aOther.bodyStyleNames )
2572 {
2573 return false;
2574 }
2575
2576 if( ( aCompareFlags & FLAGS::PIN_VISIBILITIES )
2577 && ( showPinNames != aOther.showPinNames || showPinNumbers != aOther.showPinNumbers ) )
2578 {
2579 return false;
2580 }
2581
2582 return ( !( aCompareFlags & FLAGS::EXCLUDE_FROM_SIM ) || excludedFromSim == aOther.excludedFromSim )
2583 && ( !( aCompareFlags & FLAGS::EXCLUDE_FROM_BOM ) || excludedFromBOM == aOther.excludedFromBOM )
2584 && ( !( aCompareFlags & FLAGS::EXCLUDE_FROM_BOARD ) || excludedFromBoard == aOther.excludedFromBoard )
2585 && ( !( aCompareFlags & FLAGS::EXCLUDE_FROM_POS_FILES )
2587 && ( !( aCompareFlags & FLAGS::DNP ) || dnp == aOther.dnp );
2588}
2589
2590
2591int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, int aCompareFlags, REPORTER* aReporter ) const
2592{
2593 UNITS_PROVIDER unitsProvider( schIUScale, EDA_UNITS::MM );
2594
2595 if( m_me == aRhs.m_me )
2596 return 0;
2597
2598 int retv = 0;
2599
2600 if( aCompareFlags & COMPARE_FLAGS::IDENTITY )
2601 {
2602 if( int tmp = m_name.Cmp( aRhs.m_name ) )
2603 {
2604 retv = tmp;
2605 REPORT( _( "Name differs." ) );
2606
2607 if( !aReporter )
2608 return retv;
2609 }
2610
2611 if( int tmp = m_libId.compare( aRhs.m_libId ) )
2612 {
2613 retv = tmp;
2614 REPORT( _( "Library ID differs." ) );
2615
2616 if( !aReporter )
2617 return retv;
2618 }
2619
2620 if( m_parent.lock() < aRhs.m_parent.lock() )
2621 retv = -1;
2622 else if( m_parent.lock() > aRhs.m_parent.lock() )
2623 retv = 1;
2624
2625 if( retv )
2626 {
2627 REPORT( _( "Symbol parent differs." ) );
2628
2629 if( !aReporter )
2630 return retv;
2631 }
2632 }
2633
2634 if( m_options != aRhs.m_options )
2635 {
2636 retv = ( m_options == ENTRY_NORMAL ) ? -1 : 1;
2637 REPORT( _( "Power flag differs." ) );
2638
2639 if( !aReporter )
2640 return retv;
2641 }
2642
2643 if( int tmp = m_unitCount - aRhs.m_unitCount )
2644 {
2645 retv = tmp;
2646 REPORT( _( "Unit count differs." ) );
2647
2648 if( !aReporter )
2649 return retv;
2650 }
2651
2652 // Make sure shapes are sorted. No need with fields or pins as those are matched by id/name and number.
2653
2654 std::set<const SCH_ITEM*, SCH_ITEM::cmp_items> aShapes;
2655 std::set<const SCH_FIELD*> aFields;
2656 std::set<const SCH_PIN*> aPins;
2657
2658 for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
2659 {
2660 if( it->Type() == SCH_SHAPE_T )
2661 aShapes.insert( &( *it ) );
2662 else if( it->Type() == SCH_FIELD_T )
2663 aFields.insert( static_cast<const SCH_FIELD*>( &( *it ) ) );
2664 else if( it->Type() == SCH_PIN_T )
2665 aPins.insert( static_cast<const SCH_PIN*>( &( *it ) ) );
2666 }
2667
2668 std::set<const SCH_ITEM*, SCH_ITEM::cmp_items> bShapes;
2669 std::set<const SCH_FIELD*> bFields;
2670 std::set<const SCH_PIN*> bPins;
2671
2672 for( auto it = aRhs.m_drawings.begin(); it != aRhs.m_drawings.end(); ++it )
2673 {
2674 if( it->Type() == SCH_SHAPE_T )
2675 bShapes.insert( &( *it ) );
2676 else if( it->Type() == SCH_FIELD_T )
2677 bFields.insert( static_cast<const SCH_FIELD*>( &( *it ) ) );
2678 else if( it->Type() == SCH_PIN_T )
2679 bPins.insert( static_cast<const SCH_PIN*>( &( *it ) ) );
2680 }
2681
2682 if( int tmp = static_cast<int>( aShapes.size() - bShapes.size() ) )
2683 {
2684 retv = tmp;
2685 REPORT( _( "Graphic item count differs." ) );
2686
2687 if( !aReporter )
2688 return retv;
2689 }
2690 else
2691 {
2692 for( auto aIt = aShapes.begin(), bIt = bShapes.begin(); aIt != aShapes.end(); aIt++, bIt++ )
2693 {
2694 if( int tmp2 = ( *aIt )->compare( *( *bIt ), aCompareFlags ) )
2695 {
2696 retv = tmp2;
2697 REPORT( wxString::Format( _( "Graphic item differs: %s; %s." ),
2698 ITEM_DESC( *aIt ),
2699 ITEM_DESC( *bIt ) ) );
2700
2701 if( !aReporter )
2702 return retv;
2703 }
2704 }
2705 }
2706
2707 for( const SCH_PIN* aPin : aPins )
2708 {
2709 const SCH_PIN* bPin = aRhs.GetPin( aPin->GetNumber(), aPin->GetUnit(), aPin->GetBodyStyle() );
2710
2711 if( !bPin )
2712 {
2713 retv = 1;
2714 REPORT( wxString::Format( _( "Extra pin in schematic symbol: %s." ), ITEM_DESC( aPin ) ) );
2715
2716 if( !aReporter )
2717 return retv;
2718 }
2719 else if( int tmp = static_cast<const SCH_ITEM*>( aPin )->compare( *bPin, aCompareFlags ) )
2720 {
2721 retv = tmp;
2722 REPORT( wxString::Format( _( "Pin %s differs: %s; %s" ),
2723 aPin->GetNumber(),
2724 ITEM_DESC( aPin ),
2725 ITEM_DESC( bPin ) ) );
2726
2727 if( !aReporter )
2728 return retv;
2729 }
2730 }
2731
2732 for( const SCH_PIN* bPin : bPins )
2733 {
2734 const SCH_PIN* aPin = GetPin( bPin->GetNumber(), bPin->GetUnit(), bPin->GetBodyStyle() );
2735
2736 if( !aPin )
2737 {
2738 retv = 1;
2739 REPORT( wxString::Format( _( "Missing pin in schematic symbol: %s." ), ITEM_DESC( bPin ) ) );
2740
2741 if( !aReporter )
2742 return retv;
2743 }
2744 }
2745
2746 for( const SCH_FIELD* aField : aFields )
2747 {
2748 const SCH_FIELD* bField = nullptr;
2749
2750 if( aField->IsMandatory() )
2751 bField = aRhs.GetField( aField->GetId() );
2752 else
2753 bField = aRhs.GetField( aField->GetName() );
2754
2755 if( !bField )
2756 {
2757 if( aCompareFlags & COMPARE_FLAGS::EXTRA_FIELDS )
2758 {
2759 retv = 1;
2760 REPORT( wxString::Format( _( "Extra field in schematic symbol: %s." ), aField->GetName( false ) ) );
2761
2762 if( !aReporter )
2763 return retv;
2764 }
2765 }
2766 else
2767 {
2768 if( ( aCompareFlags & COMPARE_FLAGS::FIELD_TEXT ) && aField->GetId() != FIELD_T::REFERENCE )
2769 {
2770 if( int tmp = aField->GetText().compare( bField->GetText() ) )
2771 {
2772 retv = tmp;
2773 REPORT( wxString::Format( _( "Field '%s' differs: %s; %s." ),
2774 aField->GetName( false ),
2775 aField->GetText(),
2776 bField->GetText() ) );
2777
2778 if( !aReporter )
2779 return retv;
2780 }
2781 }
2782
2783 if( aCompareFlags & COMPARE_FLAGS::FIELD_SIZE_AND_STYLE )
2784 {
2785 if( aField->GetFont() != bField->GetFont() )
2786 {
2787 retv = std::less<KIFONT::FONT*>{}( aField->GetFont(), bField->GetFont() ) ? -1 : 1;
2788 REPORT( wxString::Format( _( "Field '%s' fonts differ." ), aField->GetName( false ) ) );
2789
2790 if( !aReporter )
2791 return retv;
2792 }
2793
2794 if( aField->GetTextSize() != bField->GetTextSize() )
2795 {
2796 if( aField->GetTextSize().x != bField->GetTextSize().x )
2797 retv = aField->GetTextSize().x - bField->GetTextSize().x;
2798 else
2799 retv = aField->GetTextSize().y - bField->GetTextSize().y;
2800
2801 REPORT( wxString::Format( _( "Field '%s' text sizes differ." ), aField->GetName( false ) ) );
2802
2803 if( !aReporter )
2804 return retv;
2805 }
2806
2807 if( int tmp = aField->GetAttributes().Compare( bField->GetAttributes() ) )
2808 {
2809 retv = tmp;
2810 REPORT( wxString::Format( _( "Field '%s' text styles differ." ), aField->GetName( false ) ) );
2811
2812 if( !aReporter )
2813 return retv;
2814 }
2815 }
2816
2817 if( aCompareFlags & COMPARE_FLAGS::FIELD_VISIBILITY )
2818 {
2819 if( aField->IsVisible() != bField->IsVisible() )
2820 {
2821 retv = aField->IsVisible() ? 1 : -1;
2822 REPORT( wxString::Format( _( "Field '%s' visibility flags differ." ), aField->GetName( false ) ) );
2823
2824 if( !aReporter )
2825 return retv;
2826 }
2827
2828 if( aField->IsNameShown() != bField->IsNameShown() )
2829 {
2830 retv = aField->IsNameShown() ? 1 : -1;
2831 REPORT( wxString::Format( _( "Field '%s' name shown flags differ." ), aField->GetName( false ) ) );
2832
2833 if( !aReporter )
2834 return retv;
2835 }
2836 }
2837
2838 if( aField->IsPrivate() != bField->IsPrivate() )
2839 {
2840 retv = aField->IsPrivate() ? 1 : -1;
2841 REPORT( wxString::Format( _( "Field '%s' privacy flags differ." ), aField->GetName( false ) ) );
2842
2843 if( !aReporter )
2844 return retv;
2845 }
2846
2847 if( aCompareFlags & COMPARE_FLAGS::FIELD_POSITIONS )
2848 {
2849 if( aField->GetPosition() != bField->GetPosition() )
2850 {
2851 if( aField->GetPosition().x != bField->GetPosition().x )
2852 retv = aField->GetPosition().x - bField->GetPosition().x;
2853 else if( aField->GetPosition().y != bField->GetPosition().y )
2854 retv = aField->GetPosition().y - bField->GetPosition().y;
2855
2856 REPORT( wxString::Format( _( "Field '%s' positions differ." ), aField->GetName( false ) ) );
2857
2858 if( !aReporter )
2859 return retv;
2860 }
2861 }
2862 }
2863 }
2864
2865 if( aCompareFlags & COMPARE_FLAGS::MISSING_FIELDS )
2866 {
2867 for( const SCH_FIELD* bField : bFields )
2868 {
2869 const SCH_FIELD* aField = nullptr;
2870
2871 if( bField->IsMandatory() )
2872 aField = GetField( bField->GetId() );
2873 else
2874 aField = GetField( bField->GetName() );
2875
2876 if( !aField )
2877 {
2878 retv = 1;
2879 REPORT( wxString::Format( _( "Missing field in schematic symbol: %s." ), bField->GetName( false ) ) );
2880
2881 if( !aReporter )
2882 return retv;
2883 }
2884 }
2885 }
2886
2887 if( int tmp = static_cast<int>( m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount() ) )
2888 {
2889 retv = tmp;
2890 REPORT( _( "Footprint filter count differs." ) );
2891
2892 if( !aReporter )
2893 return retv;
2894 }
2895 else
2896 {
2897 for( size_t i = 0; i < m_fpFilters.GetCount(); i++ )
2898 {
2899 if( int tmp2 = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] ) )
2900 {
2901 retv = tmp2;
2902 REPORT( _( "Footprint filters differ." ) );
2903
2904 if( !aReporter )
2905 return retv;
2906 }
2907 }
2908 }
2909
2910 if( int tmp = static_cast<int>( m_pinMaps.GetAll().size() - aRhs.m_pinMaps.GetAll().size() ) )
2911 {
2912 retv = tmp;
2913 REPORT( _( "Pin map count differs." ) );
2914
2915 if( !aReporter )
2916 return retv;
2917 }
2918 else if( m_pinMaps != aRhs.m_pinMaps )
2919 {
2920 retv = 1;
2921 REPORT( _( "Pin maps differ." ) );
2922
2923 if( !aReporter )
2924 return retv;
2925 }
2926
2927 if( int tmp = static_cast<int>( m_associatedFootprints.size() - aRhs.m_associatedFootprints.size() ) )
2928 {
2929 retv = tmp;
2930 REPORT( _( "Associated footprint count differs." ) );
2931
2932 if( !aReporter )
2933 return retv;
2934 }
2936 {
2937 retv = 1;
2938 REPORT( _( "Associated footprints differ." ) );
2939
2940 if( !aReporter )
2941 return retv;
2942 }
2943
2944 if( int tmp = m_keyWords.Cmp( aRhs.m_keyWords ) )
2945 {
2946 retv = tmp;
2947 REPORT( _( "Symbol keywords differ." ) );
2948
2949 if( !aReporter )
2950 return retv;
2951 }
2952
2953 if( int tmp = m_pinNameOffset - aRhs.m_pinNameOffset )
2954 {
2955 retv = tmp;
2956 REPORT( _( "Symbol pin name offsets differ." ) );
2957
2958 if( !aReporter )
2959 return retv;
2960 }
2961
2962 if( aCompareFlags & COMPARE_FLAGS::PIN_VISIBILITIES )
2963 {
2964 if( m_showPinNames != aRhs.m_showPinNames )
2965 {
2966 retv = ( m_showPinNames ) ? 1 : -1;
2967 REPORT( _( "Show pin names settings differ." ) );
2968
2969 if( !aReporter )
2970 return retv;
2971 }
2972
2974 {
2975 retv = ( m_showPinNumbers ) ? 1 : -1;
2976 REPORT( _( "Show pin numbers settings differ." ) );
2977
2978 if( !aReporter )
2979 return retv;
2980 }
2981 }
2982
2983 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_SIM )
2984 {
2986 {
2987 retv = ( m_excludedFromSim ) ? -1 : 1;
2988 REPORT( _( "Exclude from simulation settings differ." ) );
2989
2990 if( !aReporter )
2991 return retv;
2992 }
2993 }
2994
2995 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_BOM )
2996 {
2998 {
2999 retv = ( m_excludedFromBOM ) ? -1 : 1;
3000 REPORT( _( "Exclude from bill of materials settings differ." ) );
3001
3002 if( !aReporter )
3003 return retv;
3004 }
3005 }
3006
3007 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_BOARD )
3008 {
3010 {
3011 retv = ( m_excludedFromBoard ) ? -1 : 1;
3012 REPORT( _( "Exclude from board settings differ." ) );
3013
3014 if( !aReporter )
3015 return retv;
3016 }
3017 }
3018
3019 if( aCompareFlags & COMPARE_FLAGS::DNP )
3020 {
3021 if( m_DNP != aRhs.m_DNP )
3022 {
3023 retv = ( m_DNP ) ? -1 : 1;
3024 REPORT( _( "Do not populate settings differ." ) );
3025
3026 if( !aReporter )
3027 return retv;
3028 }
3029 }
3030
3031 if( aCompareFlags & COMPARE_FLAGS::EXCLUDE_FROM_POS_FILES )
3032 {
3034 {
3035 retv = ( m_excludedFromPosFiles ) ? -1 : 1;
3036 REPORT( _( "Exclude from position files settings differ." ) );
3037
3038 if( !aReporter )
3039 return retv;
3040 }
3041 }
3042
3043 if( !aReporter )
3044 {
3045 if( m_unitsLocked != aRhs.m_unitsLocked )
3046 return ( m_unitsLocked ) ? 1 : -1;
3047
3048 // Compare unit display names...
3050 return -1;
3051 else if( m_unitDisplayNames > aRhs.m_unitDisplayNames )
3052 return 1;
3053
3054 // ... and body style names.
3056 return -1;
3057 else if( m_bodyStyleNames > aRhs.m_bodyStyleNames )
3058 return 1;
3059 }
3060
3061 return retv;
3062}
3063
3064
3065int LIB_SYMBOL::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
3066{
3067 if( Type() != aOther.Type() )
3068 return Type() - aOther.Type();
3069
3070 const LIB_SYMBOL* tmp = static_cast<const LIB_SYMBOL*>( &aOther );
3071
3072 return Compare( *tmp, aCompareFlags );
3073}
3074
3075
3076double LIB_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
3077{
3078 wxCHECK( aOther.Type() == LIB_SYMBOL_T, 0.0 );
3079
3080 const LIB_SYMBOL& other = static_cast<const LIB_SYMBOL&>( aOther );
3081 double similarity = 0.0;
3082 int totalItems = 0;
3083
3084 if( m_Uuid == aOther.m_Uuid )
3085 return 1.0;
3086
3087 for( const SCH_ITEM& item : m_drawings )
3088 {
3089 totalItems += 1;
3090 double max_similarity = 0.0;
3091
3092 for( const SCH_ITEM& otherItem : other.m_drawings )
3093 {
3094 double temp_similarity = item.Similarity( otherItem );
3095 max_similarity = std::max( max_similarity, temp_similarity );
3096
3097 if( max_similarity == 1.0 )
3098 break;
3099 }
3100
3101 similarity += max_similarity;
3102 }
3103
3104 for( const SCH_PIN* pin : GetGraphicalPins( 0, 0 ) )
3105 {
3106 totalItems += 1;
3107 double max_similarity = 0.0;
3108
3109 for( const SCH_PIN* otherPin : other.GetGraphicalPins( 0, 0 ) )
3110 {
3111 double temp_similarity = pin->Similarity( *otherPin );
3112 max_similarity = std::max( max_similarity, temp_similarity );
3113
3114 if( max_similarity == 1.0 )
3115 break;
3116 }
3117
3118 similarity += max_similarity;
3119 }
3120
3121 if( totalItems == 0 )
3122 similarity = 0.0;
3123 else
3124 similarity /= totalItems;
3125
3127 similarity *= 0.9;
3128
3130 similarity *= 0.9;
3131
3133 similarity *= 0.9;
3134
3136 similarity *= 0.9;
3137
3138 if( m_flags != other.m_flags )
3139 similarity *= 0.9;
3140
3141 if( m_unitCount != other.m_unitCount )
3142 similarity *= 0.5;
3143
3144 if( GetBodyStyleCount() != other.GetBodyStyleCount() )
3145 similarity *= 0.5;
3146 else if( m_bodyStyleNames != other.m_bodyStyleNames )
3147 similarity *= 0.9;
3148
3149 if( m_pinNameOffset != other.m_pinNameOffset )
3150 similarity *= 0.9;
3151
3152 if( m_showPinNames != other.m_showPinNames )
3153 similarity *= 0.9;
3154
3155 if( m_showPinNumbers != other.m_showPinNumbers )
3156 similarity *= 0.9;
3157
3158 return similarity;
3159}
3160
3161
3163{
3164 return static_cast<EMBEDDED_FILES*>( this );
3165}
3166
3167
3169{
3170 return static_cast<const EMBEDDED_FILES*>( this );
3171}
3172
3173
3174void LIB_SYMBOL::AppendParentEmbeddedFiles( std::vector<EMBEDDED_FILES*>& aStack ) const
3175{
3176 std::set<const LIB_SYMBOL*> visited;
3177 visited.insert( this );
3178
3179 std::shared_ptr<LIB_SYMBOL> parent = m_parent.lock();
3180
3181 while( parent )
3182 {
3183 // Cycle detected - parent chain points back to an already visited symbol
3184 if( visited.count( parent.get() ) )
3185 {
3186 wxLogTrace( traceSymbolInheritance,
3187 wxT( "AppendParentEmbeddedFiles: Circular inheritance detected in "
3188 "symbol '%s' (lib: %s)" ),
3189 m_name, m_libId.GetLibNickname().wx_str() );
3190 break;
3191 }
3192
3193 visited.insert( parent.get() );
3194 aStack.push_back( parent->GetEmbeddedFiles() );
3195 parent = parent->GetParent().lock();
3196 }
3197}
3198
3199
3200std::set<KIFONT::OUTLINE_FONT*> LIB_SYMBOL::GetFonts() const
3201{
3203
3204 std::set<KIFONT::OUTLINE_FONT*> fonts;
3205
3206 auto processFont =
3207 [&]( KIFONT::FONT* font )
3208 {
3209 if( font && !font->IsStroke() )
3210 {
3211 KIFONT::OUTLINE_FONT* outline = static_cast<KIFONT::OUTLINE_FONT*>( font );
3212 PERMISSION permission = outline->GetEmbeddingPermission();
3213
3214 if( permission == PERMISSION::EDITABLE || permission == PERMISSION::INSTALLABLE )
3215 fonts.insert( outline );
3216 }
3217 };
3218
3219 for( const SCH_ITEM& item : m_drawings )
3220 {
3221 // Use dynamic_cast to catch SCH_TEXTBOX, SCH_TABLECELL, etc.
3222 if( const SCH_TEXT* text = dynamic_cast<const SCH_TEXT*>( &item ) )
3223 processFont( text->GetFont() );
3224 else if( const SCH_FIELD* field = dynamic_cast<const SCH_FIELD*>( &item ) )
3225 processFont( field->GetFont() );
3226 }
3227
3228 return fonts;
3229}
3230
3231
3233{
3234 std::set<KIFONT::OUTLINE_FONT*> fonts = GetFonts();
3235
3236 for( KIFONT::OUTLINE_FONT* font : fonts )
3237 {
3238 auto file = GetEmbeddedFiles()->AddFile( font->GetFileName(), false );
3239
3240 if( !file )
3241 {
3242 wxLogTrace( "EMBED", "Failed to add font file: %s", font->GetFileName() );
3243 continue;
3244 }
3245
3247 }
3248}
3249
3250static struct LIB_SYMBOL_DESC
3251{
3253 {
3257
3258 const wxString groupFields = _HKI( "Fields" );
3259
3260 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Reference" ),
3262 groupFields );
3263 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Value" ),
3265 groupFields );
3266 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Footprint" ),
3268 groupFields );
3269 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Datasheet" ),
3271 groupFields );
3272 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Keywords" ),
3274 groupFields );
3275
3276 const wxString groupSymbolDef = _HKI( "Symbol Definition" );
3277
3278 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Define as Power Symbol" ),
3280 groupSymbolDef );
3281 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Define as Local Power Symbol" ),
3283 groupSymbolDef );
3284
3285 const wxString groupPinDisplay = _HKI( "Pin Display" );
3286
3287 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Show Pin Number" ),
3289 groupPinDisplay );
3290 propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Show Pin Name" ),
3292 groupPinDisplay );
3293 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Place Pin Names Inside" ),
3295 groupPinDisplay );
3296 propMgr.AddProperty( new PROPERTY<SYMBOL, int>( _HKI( "Pin Name Position Offset" ),
3298 groupPinDisplay );
3299
3300 const wxString groupAttributes = _HKI( "Attributes" );
3301
3302 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Simulation" ),
3304 groupAttributes );
3305 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Board" ),
3307 groupAttributes );
3308 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Bill of Materials" ),
3310 groupAttributes );
3311 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Exclude from Position Files" ),
3313 groupAttributes );
3314
3315 const wxString groupUnits = _HKI( "Units and Body Styles" );
3316
3317 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, int>( _HKI( "Number of Symbol Units" ),
3319 groupUnits );
3320 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, bool>( _HKI( "Units are Interchangeable" ),
3322 groupUnits );
3323
3324 auto multiBodyStyle =
3325 [=]( INSPECTABLE* aItem ) -> bool
3326 {
3327 if( LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( aItem ) )
3328 return symbol->IsMultiBodyStyle();
3329
3330 return false;
3331 };
3332
3333 propMgr.AddProperty( new PROPERTY<LIB_SYMBOL, wxString>( _HKI( "Body Styles" ),
3335 groupUnits )
3336 .SetAvailableFunc( multiBodyStyle )
3337 .SetChoicesFunc( []( INSPECTABLE* aItem )
3338 {
3339 wxPGChoices choices;
3340
3341 if( LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( aItem ) )
3342 {
3343 for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
3344 choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
3345 }
3346
3347 return choices;
3348 } );
3349 }
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
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:148
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:301
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
virtual bool IsVisible() const
Definition eda_text.h:226
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp: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
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
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:136
bool GetColorMode() const
Definition plotter.h:164
virtual void SetColor(const COLOR4D &color)=0
PROPERTY_BASE & SetChoicesFunc(std::function< wxPGChoices(INSPECTABLE *)> aFunc)
Definition property.h:277
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:263
Provide class metadata.
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:839
int m_bodyStyle
Definition sch_item.h:840
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:817
COMPARE_FLAGS
The list of flags used by various compare functions.
Definition sch_item.h:744
@ MISSING_FIELDS
Definition sch_item.h:748
@ EXCLUDE_FROM_BOARD
Definition sch_item.h:757
@ FIELD_VISIBILITY
Definition sch_item.h:751
@ EXCLUDE_FROM_POS_FILES
Definition sch_item.h:760
@ EXTRA_FIELDS
Definition sch_item.h:749
@ FIELD_SIZE_AND_STYLE
Definition sch_item.h:752
@ EXCLUDE_FROM_BOM
Definition sch_item.h:759
@ FIELD_TEXT
Definition sch_item.h:750
@ EXCLUDE_FROM_SIM
Definition sch_item.h:756
@ FIELD_POSITIONS
Definition sch_item.h:753
@ PIN_VISIBILITIES
Definition sch_item.h:754
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:89
@ FOR_GUI
Definition common.h:91
@ RAW_VALUE
Definition common.h:96
@ INTERNAL
Definition common.h:94
#define DEFAULT_PIN_NAME_OFFSET
The offset of the pin name string from the end of the pin in mils.
#define _(s)
@ FILLED_WITH_COLOR
Definition eda_fill.h:33
@ FILLED_WITH_BG_BODYCOLOR
Definition eda_fill.h:32
RECURSE_MODE
Definition eda_item.h:50
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
#define IGNORE_PARENT_GROUP
Definition eda_item.h:55
#define IS_NEW
New item, just created.
#define STRUCT_DELETED
flag indication structures to be erased
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
TRANSFORM DefaultTransform
Definition transform.cpp:28
const wxChar *const traceSymbolInheritance
Flag to enable tracing of circular symbol inheritance detection.
const wxChar *const traceStackedPins
Flag to enable debug output for stacked pins handling in symbol/pin code.
@ LAYER_DEVICE
Definition layer_ids.h:488
@ LAYER_FIELDS
Definition layer_ids.h:484
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