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 <stambaughw@gmail.com>
6 * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26 #include <sch_draw_panel.h>
27 #include <plotters/plotter.h>
28 #include <sch_screen.h>
29 #include <richio.h>
30 #include <general.h>
31 #include <template_fieldnames.h>
32 #include <transform.h>
33 #include <symbol_library.h>
34 #include <lib_pin.h>
35 #include <settings/color_settings.h>
36 #include <lib_shape.h>
37
38 // the separator char between the subpart id and the reference
39 // 0 (no separator) or '.' or some other character
40 int LIB_SYMBOL::m_subpartIdSeparator = 0;
41
42 // the ascii char value to calculate the subpart symbol id from the part number:
43 // 'A' or '1' usually. (to print U1.A or U1.1)
44 // if this a digit, a number is used as id symbol
45 int LIB_SYMBOL::m_subpartFirstId = 'A';
46
47
GetSearchText()48 wxString LIB_SYMBOL::GetSearchText()
49 {
50 // Matches are scored by offset from front of string, so inclusion of this spacer
51 // discounts matches found after it.
52 static const wxString discount( wxT( " " ) );
53
54 wxString text = GetKeyWords() + discount + GetDescription();
55 wxString footprint = GetFootprintField().GetText();
56
57 if( !footprint.IsEmpty() )
58 {
59 text += discount + footprint;
60 }
61
62 return text;
63 }
64
65
operator <(const LIB_SYMBOL & aItem1,const LIB_SYMBOL & aItem2)66 bool operator<( const LIB_SYMBOL& aItem1, const LIB_SYMBOL& aItem2 )
67 {
68 return aItem1.GetName() < aItem2.GetName();
69 }
70
71
72 /// http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared
73 struct null_deleter
74 {
operator ()null_deleter75 void operator()(void const *) const
76 {
77 }
78 };
79
80
LIB_SYMBOL(const wxString & aName,LIB_SYMBOL * aParent,SYMBOL_LIB * aLibrary)81 LIB_SYMBOL::LIB_SYMBOL( const wxString& aName, LIB_SYMBOL* aParent, SYMBOL_LIB* aLibrary ) :
82 EDA_ITEM( LIB_SYMBOL_T ),
83 m_me( this, null_deleter() ),
84 m_includeInBom( true ),
85 m_includeOnBoard( true )
86 {
87 m_lastModDate = 0;
88 m_unitCount = 1;
89 m_pinNameOffset = Mils2iu( DEFAULT_PIN_NAME_OFFSET );
90 m_options = ENTRY_NORMAL;
91 m_unitsLocked = false;
92 m_showPinNumbers = true;
93 m_showPinNames = true;
94
95 // Add the MANDATORY_FIELDS in RAM only. These are assumed to be present
96 // when the field editors are invoked.
97 m_drawings[LIB_FIELD_T].reserve( 4 );
98 m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, VALUE_FIELD ) );
99 m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, REFERENCE_FIELD ) );
100 m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, FOOTPRINT_FIELD ) );
101 m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, DATASHEET_FIELD ) );
102
103 SetName( aName );
104
105 if( aParent )
106 SetParent( aParent );
107
108 SetLib( aLibrary );
109 }
110
111
LIB_SYMBOL(const LIB_SYMBOL & aSymbol,SYMBOL_LIB * aLibrary)112 LIB_SYMBOL::LIB_SYMBOL( const LIB_SYMBOL& aSymbol, SYMBOL_LIB* aLibrary ) :
113 EDA_ITEM( aSymbol ),
114 m_me( this, null_deleter() )
115 {
116 LIB_ITEM* newItem;
117
118 m_library = aLibrary;
119 m_name = aSymbol.m_name;
120 m_fpFilters = wxArrayString( aSymbol.m_fpFilters );
121 m_unitCount = aSymbol.m_unitCount;
122 m_unitsLocked = aSymbol.m_unitsLocked;
123 m_pinNameOffset = aSymbol.m_pinNameOffset;
124 m_showPinNumbers = aSymbol.m_showPinNumbers;
125 m_includeInBom = aSymbol.m_includeInBom;
126 m_includeOnBoard = aSymbol.m_includeOnBoard;
127 m_showPinNames = aSymbol.m_showPinNames;
128 m_lastModDate = aSymbol.m_lastModDate;
129 m_options = aSymbol.m_options;
130 m_libId = aSymbol.m_libId;
131 m_description = aSymbol.m_description;
132 m_keyWords = aSymbol.m_keyWords;
133
134 ClearSelected();
135
136 for( const LIB_ITEM& oldItem : aSymbol.m_drawings )
137 {
138 if( ( oldItem.GetFlags() & ( IS_NEW | STRUCT_DELETED ) ) != 0 )
139 continue;
140
141 try
142 {
143 newItem = (LIB_ITEM*) oldItem.Clone();
144 newItem->ClearSelected();
145 newItem->SetParent( this );
146 m_drawings.push_back( newItem );
147 }
148 catch( ... )
149 {
150 wxFAIL_MSG( "Failed to clone LIB_ITEM." );
151 }
152 }
153
154 LIB_SYMBOL_SPTR parent = aSymbol.m_parent.lock();
155
156 if( parent )
157 SetParent( parent.get() );
158 }
159
160
~LIB_SYMBOL()161 LIB_SYMBOL::~LIB_SYMBOL()
162 {
163 }
164
165
operator =(const LIB_SYMBOL & aSymbol)166 const LIB_SYMBOL& LIB_SYMBOL::operator=( const LIB_SYMBOL& aSymbol )
167 {
168 if( &aSymbol == this )
169 return aSymbol;
170
171 LIB_ITEM* newItem;
172
173 m_library = aSymbol.m_library;
174 m_name = aSymbol.m_name;
175 m_fpFilters = wxArrayString( aSymbol.m_fpFilters );
176 m_unitCount = aSymbol.m_unitCount;
177 m_unitsLocked = aSymbol.m_unitsLocked;
178 m_pinNameOffset = aSymbol.m_pinNameOffset;
179 m_showPinNumbers = aSymbol.m_showPinNumbers;
180 m_showPinNames = aSymbol.m_showPinNames;
181 m_includeInBom = aSymbol.m_includeInBom;
182 m_includeOnBoard = aSymbol.m_includeOnBoard;
183 m_lastModDate = aSymbol.m_lastModDate;
184 m_options = aSymbol.m_options;
185 m_libId = aSymbol.m_libId;
186 m_description = aSymbol.m_description;
187 m_keyWords = aSymbol.m_keyWords;
188
189 m_drawings.clear();
190
191 for( const LIB_ITEM& oldItem : aSymbol.m_drawings )
192 {
193 if( ( oldItem.GetFlags() & ( IS_NEW | STRUCT_DELETED ) ) != 0 )
194 continue;
195
196 newItem = (LIB_ITEM*) oldItem.Clone();
197 newItem->SetParent( this );
198 m_drawings.push_back( newItem );
199 }
200
201 m_drawings.sort();
202
203 LIB_SYMBOL_SPTR parent = aSymbol.m_parent.lock();
204
205 if( parent )
206 SetParent( parent.get() );
207
208 return *this;
209 }
210
211
Compare(const LIB_SYMBOL & aRhs,LIB_ITEM::COMPARE_FLAGS aCompareFlags) const212 int LIB_SYMBOL::Compare( const LIB_SYMBOL& aRhs, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const
213 {
214 if( m_me == aRhs.m_me )
215 return 0;
216
217 int retv = m_name.Cmp( aRhs.m_name );
218
219 if( retv )
220 return retv;
221
222 retv = m_libId.compare( aRhs.m_libId );
223
224 if( retv )
225 return retv;
226
227 if( m_parent.lock() < aRhs.m_parent.lock() )
228 return -1;
229
230 if( m_parent.lock() > aRhs.m_parent.lock() )
231 return 1;
232
233 if( m_options != aRhs.m_options )
234 return ( m_options == ENTRY_NORMAL ) ? -1 : 1;
235
236 if( m_unitCount != aRhs.m_unitCount )
237 return m_unitCount - aRhs.m_unitCount;
238
239 if( m_drawings.size() != aRhs.m_drawings.size() )
240 return m_drawings.size() - aRhs.m_drawings.size();
241
242 LIB_ITEMS_CONTAINER::CONST_ITERATOR lhsItemIt = m_drawings.begin();
243 LIB_ITEMS_CONTAINER::CONST_ITERATOR rhsItemIt = aRhs.m_drawings.begin();
244
245 while( lhsItemIt != m_drawings.end() )
246 {
247 const LIB_ITEM* lhsItem = static_cast<const LIB_ITEM*>( &(*lhsItemIt) );
248 const LIB_ITEM* rhsItem = static_cast<const LIB_ITEM*>( &(*rhsItemIt) );
249
250 wxCHECK( lhsItem && rhsItem, lhsItem - rhsItem );
251
252 if( lhsItem->Type() != rhsItem->Type() )
253 return lhsItem->Type() - rhsItem->Type();
254
255 // Non-mandatory fields are a special case. They can have different ordinal numbers
256 // and are compared separately below.
257 if( lhsItem->Type() == LIB_FIELD_T )
258 {
259 const LIB_FIELD* lhsField = static_cast<const LIB_FIELD*>( lhsItem );
260
261 if( lhsField->IsMandatory() )
262 retv = lhsItem->compare( *rhsItem, aCompareFlags );
263 }
264 else
265 {
266 retv = lhsItem->compare( *rhsItem, aCompareFlags );
267 }
268
269 if( retv )
270 return retv;
271
272 ++lhsItemIt;
273 ++rhsItemIt;
274 }
275
276 // Compare the optional fields.
277 for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
278 {
279 const LIB_FIELD* field = dynamic_cast<const LIB_FIELD*>( &item );
280
281 wxCHECK2( field, continue );
282
283 // Mandatory fields were already compared above.
284 if( field->IsMandatory() )
285 continue;
286
287 const LIB_FIELD* foundField = aRhs.FindField( field->GetName() );
288
289 if( foundField == nullptr )
290 return 1;
291
292 retv = item.compare( static_cast<const LIB_ITEM&>( *foundField ), aCompareFlags );
293
294 if( retv )
295 return retv;
296 }
297
298 if( m_fpFilters.GetCount() != aRhs.m_fpFilters.GetCount() )
299 return m_fpFilters.GetCount() - aRhs.m_fpFilters.GetCount();
300
301 for( size_t i = 0; i < m_fpFilters.GetCount(); i++ )
302 {
303 retv = m_fpFilters[i].Cmp( aRhs.m_fpFilters[i] );
304
305 if( retv )
306 return retv;
307 }
308
309 retv = m_description.Cmp( aRhs.m_description );
310
311 if( retv )
312 return retv;
313
314 retv = m_keyWords.Cmp( aRhs.m_keyWords );
315
316 if( retv )
317 return retv;
318
319 if( m_pinNameOffset != aRhs.m_pinNameOffset )
320 return m_pinNameOffset - aRhs.m_pinNameOffset;
321
322 if( m_unitsLocked != aRhs.m_unitsLocked )
323 return ( m_unitsLocked ) ? 1 : -1;
324
325 if( m_showPinNames != aRhs.m_showPinNames )
326 return ( m_showPinNames ) ? 1 : -1;
327
328 if( m_showPinNumbers != aRhs.m_showPinNumbers )
329 return ( m_showPinNumbers ) ? 1 : -1;
330
331 if( m_includeInBom != aRhs.m_includeInBom )
332 return ( m_includeInBom ) ? 1 : -1;
333
334 if( m_includeOnBoard != aRhs.m_includeOnBoard )
335 return ( m_includeOnBoard ) ? 1 : -1;
336
337 return 0;
338 }
339
340
GetUnitReference(int aUnit)341 wxString LIB_SYMBOL::GetUnitReference( int aUnit )
342 {
343 return LIB_SYMBOL::SubReference( aUnit, false );
344 }
345
346
SetName(const wxString & aName)347 void LIB_SYMBOL::SetName( const wxString& aName )
348 {
349 m_name = aName;
350 m_libId.SetLibItemName( aName );
351
352 GetValueField().SetText( aName );
353 }
354
355
SetParent(LIB_SYMBOL * aParent)356 void LIB_SYMBOL::SetParent( LIB_SYMBOL* aParent )
357 {
358 if( aParent )
359 m_parent = aParent->SharedPtr();
360 else
361 m_parent.reset();
362 }
363
364
Flatten() const365 std::unique_ptr< LIB_SYMBOL > LIB_SYMBOL::Flatten() const
366 {
367 std::unique_ptr< LIB_SYMBOL > retv;
368
369 if( IsAlias() )
370 {
371 LIB_SYMBOL_SPTR parent = m_parent.lock();
372
373 wxCHECK_MSG( parent, retv,
374 wxString::Format( "Parent of derived symbol '%s' undefined", m_name ) );
375
376 // Copy the parent.
377 retv.reset( new LIB_SYMBOL( *parent.get() ) );
378
379 retv->m_name = m_name;
380 retv->SetLibId( m_libId );
381
382 // Now add the inherited part mandatory field (this) information.
383 for( int i = 0; i < MANDATORY_FIELDS; i++ )
384 {
385 wxString tmp = GetFieldById( i )->GetText();
386
387 // If the field isn't defined then inherit the parent field value.
388 if( tmp.IsEmpty() )
389 retv->GetFieldById( i )->SetText( parent->GetFieldById( i )->GetText() );
390 else
391 *retv->GetFieldById( i ) = *GetFieldById( i );
392 }
393
394 // Grab all the rest of derived symbol fields.
395 for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
396 {
397 const LIB_FIELD* aliasField = dynamic_cast<const LIB_FIELD*>( &item );
398
399 wxCHECK2( aliasField, continue );
400
401 // Mandatory fields were already resolved.
402 if( aliasField->IsMandatory() )
403 continue;
404
405 LIB_FIELD* newField = new LIB_FIELD( *aliasField );
406 newField->SetParent( retv.get() );
407
408 LIB_FIELD* parentField = retv->FindField( aliasField->GetName() );
409
410 if( !parentField ) // Derived symbol field does not exist in parent symbol.
411 {
412 retv->AddDrawItem( newField );
413 }
414 else // Derived symbol field overrides the parent symbol field.
415 {
416 retv->RemoveDrawItem( parentField );
417 retv->AddDrawItem( newField );
418 }
419 }
420
421 retv->SetKeyWords( m_keyWords.IsEmpty() ? parent->GetKeyWords() : m_keyWords );
422 retv->SetDescription( m_description.IsEmpty() ? parent->GetDescription() : m_description );
423 retv->SetFPFilters( m_fpFilters.IsEmpty() ? parent->GetFPFilters() : m_fpFilters );
424 retv->UpdateFieldOrdinals();
425 }
426 else
427 {
428 retv.reset( new LIB_SYMBOL( *this ) );
429 }
430
431 return retv;
432 }
433
434
GetLibraryName() const435 const wxString LIB_SYMBOL::GetLibraryName() const
436 {
437 if( m_library )
438 return m_library->GetName();
439
440 return m_libId.GetLibNickname();
441 }
442
443
IsPower() const444 bool LIB_SYMBOL::IsPower() const
445 {
446 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
447 return parent->m_options == ENTRY_POWER;
448
449 return m_options == ENTRY_POWER;
450 }
451
452
SetPower()453 void LIB_SYMBOL::SetPower()
454 {
455 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
456 parent->m_options = ENTRY_POWER;
457
458 m_options = ENTRY_POWER;
459 }
460
461
IsNormal() const462 bool LIB_SYMBOL::IsNormal() const
463 {
464 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
465 return parent->m_options == ENTRY_NORMAL;
466
467 return m_options == ENTRY_NORMAL;
468 }
469
470
SetNormal()471 void LIB_SYMBOL::SetNormal()
472 {
473 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
474 parent->m_options = ENTRY_NORMAL;
475
476 m_options = ENTRY_NORMAL;
477 }
478
479
SubReference(int aUnit,bool aAddSeparator)480 wxString LIB_SYMBOL::SubReference( int aUnit, bool aAddSeparator )
481 {
482 wxString subRef;
483
484 if( m_subpartIdSeparator != 0 && aAddSeparator )
485 subRef << wxChar( m_subpartIdSeparator );
486
487 if( m_subpartFirstId >= '0' && m_subpartFirstId <= '9' )
488 subRef << aUnit;
489 else
490 {
491 // use letters as notation. To allow more than 26 units, the sub ref
492 // use one letter if letter = A .. Z or a ... z, and 2 letters otherwise
493 // first letter is expected to be 'A' or 'a' (i.e. 26 letters are available)
494 int u;
495 aUnit -= 1; // Unit number starts to 1. now to 0.
496
497 while( aUnit >= 26 ) // more than one letter are needed
498 {
499 u = aUnit / 26;
500 subRef << wxChar( m_subpartFirstId + u -1 );
501 aUnit %= 26;
502 }
503
504 u = m_subpartFirstId + aUnit;
505 subRef << wxChar( u );
506 }
507
508 return subRef;
509 }
510
511
Print(const RENDER_SETTINGS * aSettings,const wxPoint & aOffset,int aUnit,int aConvert,const LIB_SYMBOL_OPTIONS & aOpts)512 void LIB_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset,
513 int aUnit, int aConvert, const LIB_SYMBOL_OPTIONS& aOpts )
514 {
515 /* draw background for filled items using background option
516 * Solid lines will be drawn after the background
517 * Note also, background is not drawn when printing in black and white
518 */
519 if( !GetGRForceBlackPenState() )
520 {
521 for( LIB_ITEM& item : m_drawings )
522 {
523 if( item.Type() == LIB_SHAPE_T )
524 {
525 LIB_SHAPE& shape = static_cast<LIB_SHAPE&>( item );
526
527 // Do not draw items not attached to the current part
528 if( aUnit && shape.m_unit && ( shape.m_unit != aUnit ) )
529 continue;
530
531 if( aConvert && shape.m_convert && ( shape.m_convert != aConvert ) )
532 continue;
533
534 if( shape.GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR )
535 shape.Print( aSettings, aOffset, (void*) false, aOpts.transform );
536 }
537 }
538 }
539
540 for( LIB_ITEM& item : m_drawings )
541 {
542 // Do not draw items not attached to the current part
543 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
544 continue;
545
546 if( aConvert && item.m_convert && ( item.m_convert != aConvert ) )
547 continue;
548
549 if( item.Type() == LIB_FIELD_T )
550 {
551 LIB_FIELD& field = static_cast<LIB_FIELD&>( item );
552
553 if( field.IsVisible() && !aOpts.draw_visible_fields )
554 continue;
555
556 if( !field.IsVisible() && !aOpts.draw_hidden_fields )
557 continue;
558 }
559
560 if( item.Type() == LIB_PIN_T )
561 {
562 item.Print( aSettings, aOffset, (void*) &aOpts, aOpts.transform );
563 }
564 else if( item.Type() == LIB_FIELD_T )
565 {
566 item.Print( aSettings, aOffset, (void*) NULL, aOpts.transform );
567 }
568 else if( item.Type() == LIB_SHAPE_T )
569 {
570 LIB_SHAPE& shape = static_cast<LIB_SHAPE&>( item );
571 bool forceNoFill = shape.GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR;
572
573 shape.Print( aSettings, aOffset, (void*) forceNoFill, aOpts.transform );
574 }
575 else
576 {
577 item.Print( aSettings, aOffset, (void*) false, aOpts.transform );
578 }
579 }
580 }
581
582
Plot(PLOTTER * aPlotter,int aUnit,int aConvert,const wxPoint & aOffset,const TRANSFORM & aTransform) const583 void LIB_SYMBOL::Plot( PLOTTER* aPlotter, int aUnit, int aConvert, const wxPoint& aOffset,
584 const TRANSFORM& aTransform ) const
585 {
586 wxASSERT( aPlotter != nullptr );
587
588 aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) );
589
590 // draw background for filled items using background option
591 // Solid lines will be drawn after the background
592 for( const LIB_ITEM& item : m_drawings )
593 {
594 if( item.Type() != LIB_SHAPE_T )
595 continue;
596
597 const LIB_SHAPE& shape = static_cast<const LIB_SHAPE&>( item );
598
599 // Do not draw items not attached to the current part
600 if( aUnit && shape.m_unit && ( shape.m_unit != aUnit ) )
601 continue;
602
603 if( aConvert && shape.m_convert && ( shape.m_convert != aConvert ) )
604 continue;
605
606 if( shape.GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR && aPlotter->GetColorMode() )
607 shape.Plot( aPlotter, aOffset, true, aTransform );
608 }
609
610 // Not filled items and filled shapes are now plotted
611 // Items that have BG fills only get re-stroked to ensure the edges are in the foreground
612 for( const LIB_ITEM& item : m_drawings )
613 {
614 // Lib Fields are not plotted here, because this plot function
615 // is used to plot schematic items, which have they own fields
616 if( item.Type() == LIB_FIELD_T )
617 continue;
618
619 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
620 continue;
621
622 if( aConvert && item.m_convert && ( item.m_convert != aConvert ) )
623 continue;
624
625 bool forceNoFill = false;
626
627 if( item.Type() == LIB_SHAPE_T )
628 {
629 const LIB_SHAPE& shape = static_cast<const LIB_SHAPE&>( item );
630 forceNoFill = shape.GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR;
631 }
632
633 item.Plot( aPlotter, aOffset, !forceNoFill, aTransform );
634 }
635 }
636
637
PlotLibFields(PLOTTER * aPlotter,int aUnit,int aConvert,const wxPoint & aOffset,const TRANSFORM & aTransform)638 void LIB_SYMBOL::PlotLibFields( PLOTTER* aPlotter, int aUnit, int aConvert,
639 const wxPoint& aOffset, const TRANSFORM& aTransform )
640 {
641 wxASSERT( aPlotter != nullptr );
642
643 aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_FIELDS ) );
644 bool fill = aPlotter->GetColorMode();
645
646 for( LIB_ITEM& item : m_drawings )
647 {
648 if( item.Type() != LIB_FIELD_T )
649 continue;
650
651 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
652 continue;
653
654 if( aConvert && item.m_convert && ( item.m_convert != aConvert ) )
655 continue;
656
657 LIB_FIELD& field = (LIB_FIELD&) item;
658
659 // The reference is a special case: we should change the basic text
660 // to add '?' and the part id
661 wxString tmp = field.GetShownText();
662
663 if( field.GetId() == REFERENCE_FIELD )
664 {
665 wxString text = field.GetFullText( aUnit );
666 field.SetText( text );
667 }
668
669 item.Plot( aPlotter, aOffset, fill, aTransform );
670 field.SetText( tmp );
671 }
672 }
673
674
RemoveDrawItem(LIB_ITEM * aItem)675 void LIB_SYMBOL::RemoveDrawItem( LIB_ITEM* aItem )
676 {
677 wxASSERT( aItem != nullptr );
678
679 // none of the MANDATORY_FIELDS may be removed in RAM, but they may be
680 // omitted when saving to disk.
681 if( aItem->Type() == LIB_FIELD_T )
682 {
683 if( static_cast<LIB_FIELD*>( aItem )->IsMandatory() )
684 return;
685 }
686
687 LIB_ITEMS& items = m_drawings[ aItem->Type() ];
688
689 for( LIB_ITEMS::iterator i = items.begin(); i != items.end(); i++ )
690 {
691 if( &*i == aItem )
692 {
693 items.erase( i );
694 SetModified();
695 break;
696 }
697 }
698 }
699
700
AddDrawItem(LIB_ITEM * aItem,bool aSort)701 void LIB_SYMBOL::AddDrawItem( LIB_ITEM* aItem, bool aSort )
702 {
703 wxCHECK( aItem, /* void */ );
704
705 m_drawings.push_back( aItem );
706
707 if( aSort )
708 m_drawings.sort();
709 }
710
711
GetNextDrawItem(const LIB_ITEM * aItem,KICAD_T aType)712 LIB_ITEM* LIB_SYMBOL::GetNextDrawItem( const LIB_ITEM* aItem, KICAD_T aType )
713 {
714 if( aItem == nullptr )
715 {
716 LIB_ITEMS_CONTAINER::ITERATOR it1 = m_drawings.begin( aType );
717
718 return (it1 != m_drawings.end( aType ) ) ? &( *( m_drawings.begin( aType ) ) ) : nullptr;
719 }
720
721 // Search for the last item, assume aItem is of type aType
722 wxASSERT( ( aType == TYPE_NOT_INIT ) || ( aType == aItem->Type() ) );
723 LIB_ITEMS_CONTAINER::ITERATOR it = m_drawings.begin( aType );
724
725 while( ( it != m_drawings.end( aType ) ) && ( aItem != &( *it ) ) )
726 ++it;
727
728 // Search the next item
729 if( it != m_drawings.end( aType ) )
730 {
731 ++it;
732
733 if( it != m_drawings.end( aType ) )
734 return &( *it );
735 }
736
737 return nullptr;
738 }
739
740
GetPins(LIB_PINS & aList,int aUnit,int aConvert) const741 void LIB_SYMBOL::GetPins( LIB_PINS& aList, int aUnit, int aConvert ) const
742 {
743 /* Notes:
744 * when aUnit == 0: no unit filtering
745 * when aConvert == 0: no convert (shape selection) filtering
746 * when m_unit == 0, the body item is common to units
747 * when m_convert == 0, the body item is common to shapes
748 */
749
750 LIB_SYMBOL_SPTR parent = m_parent.lock();
751 const LIB_ITEMS_CONTAINER& drawItems = parent ? parent->m_drawings : m_drawings;
752
753 for( const LIB_ITEM& item : drawItems[LIB_PIN_T] )
754 {
755 // Unit filtering:
756 if( aUnit && item.m_unit && ( item.m_unit != aUnit ) )
757 continue;
758
759 // Shape filtering:
760 if( aConvert && item.m_convert && ( item.m_convert != aConvert ) )
761 continue;
762
763 aList.push_back( (LIB_PIN*) &item );
764 }
765 }
766
767
GetPin(const wxString & aNumber,int aUnit,int aConvert) const768 LIB_PIN* LIB_SYMBOL::GetPin( const wxString& aNumber, int aUnit, int aConvert ) const
769 {
770 LIB_PINS pinList;
771
772 GetPins( pinList, aUnit, aConvert );
773
774 for( size_t i = 0; i < pinList.size(); i++ )
775 {
776 wxASSERT( pinList[i]->Type() == LIB_PIN_T );
777
778 if( aNumber == pinList[i]->GetNumber() )
779 return pinList[i];
780 }
781
782 return nullptr;
783 }
784
785
PinsConflictWith(const LIB_SYMBOL & aOtherPart,bool aTestNums,bool aTestNames,bool aTestType,bool aTestOrientation,bool aTestLength) const786 bool LIB_SYMBOL::PinsConflictWith( const LIB_SYMBOL& aOtherPart, bool aTestNums, bool aTestNames,
787 bool aTestType, bool aTestOrientation, bool aTestLength ) const
788 {
789 LIB_PINS thisPinList;
790 GetPins( thisPinList, /* aUnit */ 0, /* aConvert */ 0 );
791
792 for( const LIB_PIN* eachThisPin : thisPinList )
793 {
794 wxASSERT( eachThisPin );
795 LIB_PINS otherPinList;
796 aOtherPart.GetPins( otherPinList, /* aUnit */ 0, /* aConvert */ 0 );
797 bool foundMatch = false;
798
799 for( const LIB_PIN* eachOtherPin : otherPinList )
800 {
801 wxASSERT( eachOtherPin );
802
803 // Same unit?
804 if( eachThisPin->GetUnit() != eachOtherPin->GetUnit() )
805 continue;
806
807 // Same body stype?
808 if( eachThisPin->GetConvert() != eachOtherPin->GetConvert() )
809 continue;
810
811 // Same position?
812 if( eachThisPin->GetPosition() != eachOtherPin->GetPosition() )
813 continue;
814
815 // Same number?
816 if( aTestNums && ( eachThisPin->GetNumber() != eachOtherPin->GetNumber() ) )
817 continue;
818
819 // Same name?
820 if( aTestNames && ( eachThisPin->GetName() != eachOtherPin->GetName() ) )
821 continue;
822
823 // Same electrical type?
824 if( aTestType && ( eachThisPin->GetType() != eachOtherPin->GetType() ) )
825 continue;
826
827 // Same orientation?
828 if( aTestOrientation
829 && ( eachThisPin->GetOrientation() != eachOtherPin->GetOrientation() ) )
830 continue;
831
832 // Same length?
833 if( aTestLength && ( eachThisPin->GetLength() != eachOtherPin->GetLength() ) )
834 continue;
835
836 foundMatch = true;
837 break; // Match found so search is complete.
838 }
839
840 if( !foundMatch )
841 {
842 // This means there was not an identical (according to the arguments)
843 // pin at the same position in the other symbol.
844 return true;
845 }
846 }
847
848 // The loop never gave up, so no conflicts were found.
849 return false;
850 }
851
852
GetUnitBoundingBox(int aUnit,int aConvert) const853 const EDA_RECT LIB_SYMBOL::GetUnitBoundingBox( int aUnit, int aConvert ) const
854 {
855 EDA_RECT bBox;
856 bool initialized = false;
857
858 for( const LIB_ITEM& item : m_drawings )
859 {
860 if( item.m_unit > 0
861 && m_unitCount > 1
862 && aUnit > 0
863 && aUnit != item.m_unit )
864 {
865 continue;
866 }
867
868 if( item.m_convert > 0 && aConvert > 0 && aConvert != item.m_convert )
869 continue;
870
871 if ( ( item.Type() == LIB_FIELD_T ) && !( ( LIB_FIELD& ) item ).IsVisible() )
872 continue;
873
874 if( initialized )
875 {
876 bBox.Merge( item.GetBoundingBox() );
877 }
878 else
879 {
880 bBox = item.GetBoundingBox();
881 initialized = true;
882 }
883 }
884
885 return bBox;
886 }
887
888
ViewGetLayers(int aLayers[],int & aCount) const889 void LIB_SYMBOL::ViewGetLayers( int aLayers[], int& aCount ) const
890 {
891 aCount = 6;
892 aLayers[0] = LAYER_DEVICE;
893 aLayers[1] = LAYER_DEVICE_BACKGROUND;
894 aLayers[2] = LAYER_REFERENCEPART;
895 aLayers[3] = LAYER_VALUEPART;
896 aLayers[4] = LAYER_FIELDS;
897 aLayers[5] = LAYER_SELECTION_SHADOWS;
898 }
899
900
GetBodyBoundingBox(int aUnit,int aConvert,bool aIncludePins) const901 const EDA_RECT LIB_SYMBOL::GetBodyBoundingBox( int aUnit, int aConvert, bool aIncludePins ) const
902 {
903 EDA_RECT bbox;
904
905 for( const LIB_ITEM& item : m_drawings )
906 {
907 if( item.m_unit > 0 && aUnit > 0 && aUnit != item.m_unit )
908 continue;
909
910 if( item.m_convert > 0 && aConvert > 0 && aConvert != item.m_convert )
911 continue;
912
913 if( item.Type() == LIB_FIELD_T )
914 continue;
915
916 if( item.Type() == LIB_PIN_T )
917 {
918 const LIB_PIN& pin = static_cast<const LIB_PIN&>( item );
919
920 // Note: the roots of the pins are always inlcuded for symbols that don't have a
921 // well-defined body.
922
923 if( aIncludePins )
924 bbox.Merge( pin.GetBoundingBox( false, true ) );
925 else
926 bbox.Merge( pin.GetPinRoot() );
927 }
928 else
929 {
930 bbox.Merge( item.GetBoundingBox() );
931 }
932 }
933
934 return bbox;
935 }
936
937
deleteAllFields()938 void LIB_SYMBOL::deleteAllFields()
939 {
940 m_drawings[ LIB_FIELD_T ].clear();
941 }
942
943
AddField(LIB_FIELD * aField)944 void LIB_SYMBOL::AddField( LIB_FIELD* aField )
945 {
946 AddDrawItem( aField );
947 }
948
949
SetFields(const std::vector<LIB_FIELD> & aFields)950 void LIB_SYMBOL::SetFields( const std::vector <LIB_FIELD>& aFields )
951 {
952 deleteAllFields();
953
954 for( unsigned i=0; i<aFields.size(); ++i )
955 {
956 // drawings is a ptr_vector, new and copy an object on the heap.
957 LIB_FIELD* field = new LIB_FIELD( aFields[i] );
958
959 field->SetParent( this );
960 m_drawings.push_back( field );
961 }
962
963 m_drawings.sort();
964 }
965
966
GetFields(std::vector<LIB_FIELD * > & aList)967 void LIB_SYMBOL::GetFields( std::vector<LIB_FIELD*>& aList )
968 {
969 // Grab the MANDATORY_FIELDS first, in expected order given by enum MANDATORY_FIELD_T
970 for( int id = 0; id < MANDATORY_FIELDS; ++id )
971 aList.push_back( GetFieldById( id ) );
972
973 // Now grab all the rest of fields.
974 for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
975 {
976 LIB_FIELD* field = static_cast<LIB_FIELD*>( &item );
977
978 if( !field->IsMandatory() )
979 aList.push_back( field );
980 }
981 }
982
983
GetFields(std::vector<LIB_FIELD> & aList)984 void LIB_SYMBOL::GetFields( std::vector<LIB_FIELD>& aList )
985 {
986 // Grab the MANDATORY_FIELDS first, in expected order given by enum MANDATORY_FIELD_T
987 for( int id = 0; id < MANDATORY_FIELDS; ++id )
988 aList.push_back( *GetFieldById( id ) );
989
990 // Now grab all the rest of fields.
991 for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
992 {
993 LIB_FIELD* field = static_cast<LIB_FIELD*>( &item );
994
995 if( !field->IsMandatory() )
996 aList.push_back( *field );
997 }
998 }
999
1000
GetFieldById(int aId) const1001 LIB_FIELD* LIB_SYMBOL::GetFieldById( int aId ) const
1002 {
1003 for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
1004 {
1005 LIB_FIELD* field = ( LIB_FIELD* ) &item;
1006
1007 if( field->GetId() == aId )
1008 return field;
1009 }
1010
1011 return nullptr;
1012 }
1013
1014
FindField(const wxString & aFieldName)1015 LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName )
1016 {
1017 for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
1018 {
1019 if( static_cast<LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
1020 return static_cast<LIB_FIELD*>( &item );
1021 }
1022
1023 return nullptr;
1024 }
1025
1026
FindField(const wxString & aFieldName) const1027 const LIB_FIELD* LIB_SYMBOL::FindField( const wxString& aFieldName ) const
1028 {
1029 for( const LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
1030 {
1031 if( static_cast<const LIB_FIELD*>( &item )->GetCanonicalName() == aFieldName )
1032 return static_cast<const LIB_FIELD*>( &item );
1033 }
1034
1035 return nullptr;
1036 }
1037
1038
GetValueField()1039 LIB_FIELD& LIB_SYMBOL::GetValueField()
1040 {
1041 LIB_FIELD* field = GetFieldById( VALUE_FIELD );
1042 wxASSERT( field != nullptr );
1043 return *field;
1044 }
1045
1046
GetReferenceField()1047 LIB_FIELD& LIB_SYMBOL::GetReferenceField()
1048 {
1049 LIB_FIELD* field = GetFieldById( REFERENCE_FIELD );
1050 wxASSERT( field != nullptr );
1051 return *field;
1052 }
1053
1054
GetFootprintField()1055 LIB_FIELD& LIB_SYMBOL::GetFootprintField()
1056 {
1057 LIB_FIELD* field = GetFieldById( FOOTPRINT_FIELD );
1058 wxASSERT( field != nullptr );
1059 return *field;
1060 }
1061
1062
GetDatasheetField()1063 LIB_FIELD& LIB_SYMBOL::GetDatasheetField()
1064 {
1065 LIB_FIELD* field = GetFieldById( DATASHEET_FIELD );
1066 wxASSERT( field != nullptr );
1067 return *field;
1068 }
1069
1070
UpdateFieldOrdinals()1071 int LIB_SYMBOL::UpdateFieldOrdinals()
1072 {
1073 int retv = 0;
1074 int lastOrdinal = MANDATORY_FIELDS;
1075
1076 for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] )
1077 {
1078 LIB_FIELD* field = dynamic_cast<LIB_FIELD*>( &item );
1079
1080 wxCHECK2( field, continue );
1081
1082 // Mandatory fields were already resolved always have the same ordinal values.
1083 if( field->IsMandatory() )
1084 continue;
1085
1086 if( field->GetId() != lastOrdinal )
1087 {
1088 field->SetId( lastOrdinal );
1089 retv += 1;
1090 }
1091
1092 lastOrdinal += 1;
1093 }
1094
1095 return retv;
1096 }
1097
1098
GetNextAvailableFieldId() const1099 int LIB_SYMBOL::GetNextAvailableFieldId() const
1100 {
1101 int retv = MANDATORY_FIELDS;
1102
1103 while( GetFieldById( retv ) )
1104 retv += 1;
1105
1106 return retv;
1107 }
1108
1109
SetOffset(const wxPoint & aOffset)1110 void LIB_SYMBOL::SetOffset( const wxPoint& aOffset )
1111 {
1112 for( LIB_ITEM& item : m_drawings )
1113 item.Offset( aOffset );
1114 }
1115
1116
RemoveDuplicateDrawItems()1117 void LIB_SYMBOL::RemoveDuplicateDrawItems()
1118 {
1119 m_drawings.unique();
1120 }
1121
1122
HasConversion() const1123 bool LIB_SYMBOL::HasConversion() const
1124 {
1125 for( const LIB_ITEM& item : m_drawings )
1126 {
1127 if( item.m_convert > LIB_ITEM::LIB_CONVERT::BASE )
1128 return true;
1129 }
1130
1131 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
1132 {
1133 for( const LIB_ITEM& item : parent->GetDrawItems() )
1134 {
1135 if( item.m_convert > LIB_ITEM::LIB_CONVERT::BASE )
1136 return true;
1137 }
1138 }
1139
1140 return false;
1141 }
1142
1143
ClearTempFlags()1144 void LIB_SYMBOL::ClearTempFlags()
1145 {
1146 for( LIB_ITEM& item : m_drawings )
1147 item.ClearTempFlags();
1148 }
1149
1150
ClearEditFlags()1151 void LIB_SYMBOL::ClearEditFlags()
1152 {
1153 for( LIB_ITEM& item : m_drawings )
1154 item.ClearEditFlags();
1155 }
1156
1157
LocateDrawItem(int aUnit,int aConvert,KICAD_T aType,const wxPoint & aPoint)1158 LIB_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aConvert,
1159 KICAD_T aType, const wxPoint& aPoint )
1160 {
1161 for( LIB_ITEM& item : m_drawings )
1162 {
1163 if( ( aUnit && item.m_unit && aUnit != item.m_unit )
1164 || ( aConvert && item.m_convert && aConvert != item.m_convert )
1165 || ( item.Type() != aType && aType != TYPE_NOT_INIT ) )
1166 {
1167 continue;
1168 }
1169
1170 if( item.HitTest( aPoint ) )
1171 return &item;
1172 }
1173
1174 return nullptr;
1175 }
1176
1177
LocateDrawItem(int aUnit,int aConvert,KICAD_T aType,const wxPoint & aPoint,const TRANSFORM & aTransform)1178 LIB_ITEM* LIB_SYMBOL::LocateDrawItem( int aUnit, int aConvert, KICAD_T aType,
1179 const wxPoint& aPoint, const TRANSFORM& aTransform )
1180 {
1181 /* we use LocateDrawItem( int aUnit, int convert, KICAD_T type, const
1182 * wxPoint& pt ) to search items.
1183 * because this function uses DefaultTransform as orient/mirror matrix
1184 * we temporary copy aTransform in DefaultTransform
1185 */
1186 LIB_ITEM* item;
1187 TRANSFORM transform = DefaultTransform;
1188 DefaultTransform = aTransform;
1189
1190 item = LocateDrawItem( aUnit, aConvert, aType, aPoint );
1191
1192 // Restore matrix
1193 DefaultTransform = transform;
1194
1195 return item;
1196 }
1197
1198
Visit(INSPECTOR aInspector,void * aTestData,const KICAD_T aFilterTypes[])1199 SEARCH_RESULT LIB_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData,
1200 const KICAD_T aFilterTypes[] )
1201 {
1202 // The part itself is never inspected, only its children
1203 for( LIB_ITEM& item : m_drawings )
1204 {
1205 if( item.IsType( aFilterTypes ) )
1206 {
1207 if( aInspector( &item, aTestData ) == SEARCH_RESULT::QUIT )
1208 return SEARCH_RESULT::QUIT;
1209 }
1210 }
1211
1212 return SEARCH_RESULT::CONTINUE;
1213 }
1214
1215
SetUnitCount(int aCount,bool aDuplicateDrawItems)1216 void LIB_SYMBOL::SetUnitCount( int aCount, bool aDuplicateDrawItems )
1217 {
1218 if( m_unitCount == aCount )
1219 return;
1220
1221 if( aCount < m_unitCount )
1222 {
1223 LIB_ITEMS_CONTAINER::ITERATOR i = m_drawings.begin();
1224
1225 while( i != m_drawings.end() )
1226 {
1227 if( i->m_unit > aCount )
1228 i = m_drawings.erase( i );
1229 else
1230 ++i;
1231 }
1232 }
1233 else if( aDuplicateDrawItems )
1234 {
1235 int prevCount = m_unitCount;
1236
1237 // Temporary storage for new items, as adding new items directly to
1238 // m_drawings may cause the buffer reallocation which invalidates the
1239 // iterators
1240 std::vector< LIB_ITEM* > tmp;
1241
1242 for( LIB_ITEM& item : m_drawings )
1243 {
1244 if( item.m_unit != 1 )
1245 continue;
1246
1247 for( int j = prevCount + 1; j <= aCount; j++ )
1248 {
1249 LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
1250 newItem->m_unit = j;
1251 tmp.push_back( newItem );
1252 }
1253 }
1254
1255 for( LIB_ITEM* item : tmp )
1256 m_drawings.push_back( item );
1257 }
1258
1259 m_drawings.sort();
1260 m_unitCount = aCount;
1261 }
1262
1263
GetUnitCount() const1264 int LIB_SYMBOL::GetUnitCount() const
1265 {
1266 if( LIB_SYMBOL_SPTR parent = m_parent.lock() )
1267 return parent->GetUnitCount();
1268
1269 return m_unitCount;
1270 }
1271
1272
SetConversion(bool aSetConvert,bool aDuplicatePins)1273 void LIB_SYMBOL::SetConversion( bool aSetConvert, bool aDuplicatePins )
1274 {
1275 if( aSetConvert == HasConversion() )
1276 return;
1277
1278 // Duplicate items to create the converted shape
1279 if( aSetConvert )
1280 {
1281 if( aDuplicatePins )
1282 {
1283 std::vector< LIB_ITEM* > tmp; // Temporarily store the duplicated pins here.
1284
1285 for( LIB_ITEM& item : m_drawings )
1286 {
1287 // Only pins are duplicated.
1288 if( item.Type() != LIB_PIN_T )
1289 continue;
1290
1291 if( item.m_convert == 1 )
1292 {
1293 LIB_ITEM* newItem = (LIB_ITEM*) item.Clone();
1294 newItem->m_convert = 2;
1295 tmp.push_back( newItem );
1296 }
1297 }
1298
1299 // Transfer the new pins to the LIB_SYMBOL.
1300 for( unsigned i = 0; i < tmp.size(); i++ )
1301 m_drawings.push_back( tmp[i] );
1302 }
1303 }
1304 else
1305 {
1306 // Delete converted shape items because the converted shape does
1307 // not exist
1308 LIB_ITEMS_CONTAINER::ITERATOR i = m_drawings.begin();
1309
1310 while( i != m_drawings.end() )
1311 {
1312 if( i->m_convert > 1 )
1313 i = m_drawings.erase( i );
1314 else
1315 ++i;
1316 }
1317 }
1318
1319 m_drawings.sort();
1320 }
1321
1322
SetSubpartIdNotation(int aSep,int aFirstId)1323 void LIB_SYMBOL::SetSubpartIdNotation( int aSep, int aFirstId )
1324 {
1325 m_subpartFirstId = 'A';
1326 m_subpartIdSeparator = 0;
1327
1328 if( aSep == '.' || aSep == '-' || aSep == '_' )
1329 m_subpartIdSeparator = aSep;
1330
1331 if( aFirstId == '1' && aSep != 0 )
1332 m_subpartFirstId = aFirstId;
1333 }
1334
1335
GetUnitDrawItems(int aUnit,int aConvert)1336 std::vector<LIB_ITEM*> LIB_SYMBOL::GetUnitDrawItems( int aUnit, int aConvert )
1337 {
1338 std::vector<LIB_ITEM*> unitItems;
1339
1340 for( LIB_ITEM& item : m_drawings )
1341 {
1342 if( item.Type() == LIB_FIELD_T )
1343 continue;
1344
1345 if( ( aConvert == -1 && item.GetUnit() == aUnit )
1346 || ( aUnit == -1 && item.GetConvert() == aConvert )
1347 || ( aUnit == item.GetUnit() && aConvert == item.GetConvert() ) )
1348 {
1349 unitItems.push_back( &item );
1350 }
1351 }
1352
1353 return unitItems;
1354 }
1355
1356
GetUnitDrawItems()1357 std::vector<struct LIB_SYMBOL_UNIT> LIB_SYMBOL::GetUnitDrawItems()
1358 {
1359 std::vector<struct LIB_SYMBOL_UNIT> units;
1360
1361 for( LIB_ITEM& item : m_drawings )
1362 {
1363 if( item.Type() == LIB_FIELD_T )
1364 continue;
1365
1366 int unit = item.GetUnit();
1367 int convert = item.GetConvert();
1368
1369 auto it = std::find_if( units.begin(), units.end(),
1370 [unit, convert]( const LIB_SYMBOL_UNIT& a )
1371 {
1372 return a.m_unit == unit && a.m_convert == convert;
1373 } );
1374
1375 if( it == units.end() )
1376 {
1377 struct LIB_SYMBOL_UNIT newUnit;
1378 newUnit.m_unit = item.GetUnit();
1379 newUnit.m_convert = item.GetConvert();
1380 newUnit.m_items.push_back( &item );
1381 units.emplace_back( newUnit );
1382 }
1383 else
1384 {
1385 it->m_items.push_back( &item );
1386 }
1387 }
1388
1389 return units;
1390 }
1391
1392
GetUniqueUnits()1393 std::vector<struct LIB_SYMBOL_UNIT> LIB_SYMBOL::GetUniqueUnits()
1394 {
1395 int unitNum;
1396 size_t i;
1397 struct LIB_SYMBOL_UNIT unit;
1398 std::vector<LIB_ITEM*> compareDrawItems;
1399 std::vector<LIB_ITEM*> currentDrawItems;
1400 std::vector<struct LIB_SYMBOL_UNIT> uniqueUnits;
1401
1402 // The first unit is guaranteed to be unique so always include it.
1403 unit.m_unit = 1;
1404 unit.m_convert = 1;
1405 unit.m_items = GetUnitDrawItems( 1, 1 );
1406
1407 // There are no unique units if there are no draw items other than fields.
1408 if( unit.m_items.size() == 0 )
1409 return uniqueUnits;
1410
1411 uniqueUnits.emplace_back( unit );
1412
1413 if( ( GetUnitCount() == 1 || UnitsLocked() ) && !HasConversion() )
1414 return uniqueUnits;
1415
1416 currentDrawItems = unit.m_items;
1417
1418 for( unitNum = 2; unitNum <= GetUnitCount(); unitNum++ )
1419 {
1420 compareDrawItems = GetUnitDrawItems( unitNum, 1 );
1421
1422 wxCHECK2_MSG( compareDrawItems.size() != 0, continue,
1423 "Multiple unit symbol defined with empty units." );
1424
1425 if( currentDrawItems.size() != compareDrawItems.size() )
1426 {
1427 unit.m_unit = unitNum;
1428 unit.m_convert = 1;
1429 unit.m_items = compareDrawItems;
1430 uniqueUnits.emplace_back( unit );
1431 }
1432 else
1433 {
1434 for( i = 0; i < currentDrawItems.size(); i++ )
1435 {
1436 if( currentDrawItems[i]->compare( *compareDrawItems[i],
1437 LIB_ITEM::COMPARE_FLAGS::UNIT ) != 0 )
1438 {
1439 unit.m_unit = unitNum;
1440 unit.m_convert = 1;
1441 unit.m_items = compareDrawItems;
1442 uniqueUnits.emplace_back( unit );
1443 }
1444 }
1445 }
1446 }
1447
1448 if( HasConversion() )
1449 {
1450 currentDrawItems = GetUnitDrawItems( 1, 2 );
1451
1452 if( ( GetUnitCount() == 1 || UnitsLocked() ) )
1453 {
1454 unit.m_unit = 1;
1455 unit.m_convert = 2;
1456 unit.m_items = currentDrawItems;
1457 uniqueUnits.emplace_back( unit );
1458
1459 return uniqueUnits;
1460 }
1461
1462 for( unitNum = 2; unitNum <= GetUnitCount(); unitNum++ )
1463 {
1464 compareDrawItems = GetUnitDrawItems( unitNum, 2 );
1465
1466 wxCHECK2_MSG( compareDrawItems.size() != 0, continue,
1467 "Multiple unit symbol defined with empty units." );
1468
1469 if( currentDrawItems.size() != compareDrawItems.size() )
1470 {
1471 unit.m_unit = unitNum;
1472 unit.m_convert = 2;
1473 unit.m_items = compareDrawItems;
1474 uniqueUnits.emplace_back( unit );
1475 }
1476 else
1477 {
1478 for( i = 0; i < currentDrawItems.size(); i++ )
1479 {
1480 if( currentDrawItems[i]->compare( *compareDrawItems[i],
1481 LIB_ITEM::COMPARE_FLAGS::UNIT ) != 0 )
1482 {
1483 unit.m_unit = unitNum;
1484 unit.m_convert = 2;
1485 unit.m_items = compareDrawItems;
1486 uniqueUnits.emplace_back( unit );
1487 }
1488 }
1489 }
1490 }
1491 }
1492
1493 return uniqueUnits;
1494 }
1495