1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #include <sch_edit_frame.h>
26 #include <widgets/msgpanel.h>
27 #include <bitmaps.h>
28 #include <core/mirror.h>
29 #include <lib_pin.h>
30 #include <lib_text.h>
31 #include <lib_shape.h>
32 #include <sch_symbol.h>
33 #include <sch_sheet_path.h>
34 #include <schematic.h>
35 #include <trace_helpers.h>
36 #include <trigo.h>
37 #include <refdes_utils.h>
38 #include <wx/log.h>
39 #include <string_utils.h>
40 
41 
42 /**
43  * Convert a wxString to UTF8 and replace any control characters with a ~,
44  * where a control character is one of the first ASCII values up to ' ' 32d.
45  */
toUTFTildaText(const wxString & txt)46 std::string toUTFTildaText( const wxString& txt )
47 {
48     std::string ret = TO_UTF8( txt );
49 
50     for( std::string::iterator it = ret.begin();  it!=ret.end();  ++it )
51     {
52         if( (unsigned char) *it <= ' ' )
53             *it = '~';
54     }
55     return ret;
56 }
57 
58 
59 /**
60  * Used to draw a dummy shape when a LIB_SYMBOL is not found in library
61  *
62  * This symbol is a 400 mils square with the text "??"
63  * DEF DUMMY U 0 40 Y Y 1 0 N
64  * F0 "U" 0 -350 60 H V
65  * F1 "DUMMY" 0 350 60 H V
66  * DRAW
67  * T 0 0 0 150 0 0 0 ??
68  * S -200 200 200 -200 0 1 0
69  * ENDDRAW
70  * ENDDEF
71  */
dummy()72 static LIB_SYMBOL* dummy()
73 {
74     static LIB_SYMBOL* symbol;
75 
76     if( !symbol )
77     {
78         symbol = new LIB_SYMBOL( wxEmptyString );
79 
80         LIB_SHAPE* square = new LIB_SHAPE( symbol, SHAPE_T::RECT );
81 
82         square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
83         square->SetEnd( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
84 
85         LIB_TEXT* text = new LIB_TEXT( symbol );
86 
87         text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
88         text->SetText( wxString( wxT( "??" ) ) );
89 
90         symbol->AddDrawItem( square );
91         symbol->AddDrawItem( text );
92     }
93 
94     return symbol;
95 }
96 
97 
SCH_SYMBOL(const wxPoint & aPos,SCH_ITEM * aParent)98 SCH_SYMBOL::SCH_SYMBOL( const wxPoint& aPos, SCH_ITEM* aParent ) :
99     SCH_ITEM( aParent, SCH_SYMBOL_T )
100 {
101     Init( aPos );
102 }
103 
104 
SCH_SYMBOL(const LIB_SYMBOL & aSymbol,const LIB_ID & aLibId,const SCH_SHEET_PATH * aSheet,int unit,int convert,const wxPoint & pos)105 SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId,
106                         const SCH_SHEET_PATH* aSheet, int unit, int convert, const wxPoint& pos ) :
107     SCH_ITEM( nullptr, SCH_SYMBOL_T )
108 {
109     Init( pos );
110 
111     m_unit      = unit;
112     m_convert   = convert;
113     m_lib_id    = aLibId;
114 
115     std::unique_ptr< LIB_SYMBOL > part;
116 
117     part = aSymbol.Flatten();
118     part->SetParent();
119     SetLibSymbol( part.release() );
120 
121     // Copy fields from the library symbol
122     UpdateFields( aSheet,
123                   true,   /* update style */
124                   false,  /* update ref */
125                   false,  /* update other fields */
126                   true,   /* reset ref */
127                   true    /* reset other fields */ );
128 
129     m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
130 
131     if( aSheet )
132     {
133         SetRef( aSheet, UTIL::GetRefDesUnannotated( m_prefix ) );
134 
135         // Value and footprint name are stored in the SCH_SHEET_PATH path manager,
136         // if aSheet != nullptr, not in the symbol itself.
137         // Copy them to the currently displayed field texts
138         SetValue( GetValue( aSheet, false ) );
139         SetFootprint( GetFootprint( aSheet, false ) );
140     }
141 
142     // Inherit the include in bill of materials and board netlist settings from library symbol.
143     m_inBom = aSymbol.GetIncludeInBom();
144     m_onBoard = aSymbol.GetIncludeOnBoard();
145 }
146 
147 
SCH_SYMBOL(const LIB_SYMBOL & aSymbol,const SCH_SHEET_PATH * aSheet,const PICKED_SYMBOL & aSel,const wxPoint & pos)148 SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet,
149                         const PICKED_SYMBOL& aSel, const wxPoint& pos ) :
150     SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, pos )
151 {
152     // Set any fields that were modified as part of the symbol selection
153     for( const std::pair<int, wxString>& i : aSel.Fields )
154     {
155         SCH_FIELD* field = GetFieldById( i.first );
156 
157         if( field )
158             field->SetText( i.second );
159     }
160 }
161 
162 
SCH_SYMBOL(const SCH_SYMBOL & aSymbol)163 SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
164     SCH_ITEM( aSymbol )
165 {
166     m_parent      = aSymbol.m_parent;
167     m_pos         = aSymbol.m_pos;
168     m_unit        = aSymbol.m_unit;
169     m_convert     = aSymbol.m_convert;
170     m_lib_id      = aSymbol.m_lib_id;
171     m_isInNetlist = aSymbol.m_isInNetlist;
172     m_inBom       = aSymbol.m_inBom;
173     m_onBoard     = aSymbol.m_onBoard;
174 
175     if( aSymbol.m_part )
176         SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part.get() ) );
177 
178     const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
179 
180     m_transform = aSymbol.m_transform;
181     m_prefix = aSymbol.m_prefix;
182     m_instanceReferences = aSymbol.m_instanceReferences;
183     m_fields = aSymbol.m_fields;
184 
185     // Re-parent the fields, which before this had aSymbol as parent
186     for( SCH_FIELD& field : m_fields )
187         field.SetParent( this );
188 
189     m_fieldsAutoplaced = aSymbol.m_fieldsAutoplaced;
190     m_schLibSymbolName = aSymbol.m_schLibSymbolName;
191 }
192 
193 
Init(const wxPoint & pos)194 void SCH_SYMBOL::Init( const wxPoint& pos )
195 {
196     m_pos     = pos;
197     m_unit    = 1;  // In multi unit chip - which unit to draw.
198     m_convert = LIB_ITEM::LIB_CONVERT::BASE;  // De Morgan Handling
199 
200     // The rotation/mirror transformation matrix. pos normal
201     m_transform = TRANSFORM();
202 
203     // construct only the mandatory fields, which are the first 4 only.
204     for( int i = 0; i < MANDATORY_FIELDS; ++i )
205     {
206         m_fields.emplace_back( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) );
207 
208         if( i == REFERENCE_FIELD )
209             m_fields.back().SetLayer( LAYER_REFERENCEPART );
210         else if( i == VALUE_FIELD )
211             m_fields.back().SetLayer( LAYER_VALUEPART );
212         else
213             m_fields.back().SetLayer( LAYER_FIELDS );
214     }
215 
216     m_prefix = wxString( wxT( "U" ) );
217     m_isInNetlist = true;
218     m_inBom = true;
219     m_onBoard = true;
220 }
221 
222 
Clone() const223 EDA_ITEM* SCH_SYMBOL::Clone() const
224 {
225     return new SCH_SYMBOL( *this );
226 }
227 
228 
ViewGetLayers(int aLayers[],int & aCount) const229 void SCH_SYMBOL::ViewGetLayers( int aLayers[], int& aCount ) const
230 {
231     aCount      = 4;
232     aLayers[0]  = LAYER_DANGLING;       // Pins are drawn by their parent symbol, so the parent
233                                         // symbol needs to draw to LAYER_DANGLING
234     aLayers[1]  = LAYER_DEVICE;
235     aLayers[2]  = LAYER_DEVICE_BACKGROUND;
236     aLayers[3]  = LAYER_SELECTION_SHADOWS;
237 }
238 
239 
SetLibId(const LIB_ID & aLibId)240 void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
241 {
242     if( m_lib_id != aLibId )
243     {
244         m_lib_id = aLibId;
245         SetModified();
246     }
247 }
248 
249 
GetSchSymbolLibraryName() const250 wxString SCH_SYMBOL::GetSchSymbolLibraryName() const
251 {
252     if( !m_schLibSymbolName.IsEmpty() )
253         return m_schLibSymbolName;
254     else
255         return m_lib_id.Format();
256 }
257 
258 
SetLibSymbol(LIB_SYMBOL * aLibSymbol)259 void SCH_SYMBOL::SetLibSymbol( LIB_SYMBOL* aLibSymbol )
260 {
261     wxCHECK2( ( aLibSymbol == nullptr ) || ( aLibSymbol->IsRoot() ), aLibSymbol = nullptr );
262 
263     m_part.reset( aLibSymbol );
264     UpdatePins();
265 }
266 
267 
GetDescription() const268 wxString SCH_SYMBOL::GetDescription() const
269 {
270     if( m_part )
271         return m_part->GetDescription();
272 
273     return wxEmptyString;
274 }
275 
276 
GetDatasheet() const277 wxString SCH_SYMBOL::GetDatasheet() const
278 {
279     if( m_part )
280         return m_part->GetDatasheetField().GetText();
281 
282     return wxEmptyString;
283 }
284 
285 
UpdatePins()286 void SCH_SYMBOL::UpdatePins()
287 {
288     std::map<wxString, wxString> altPinMap;
289     std::map<wxString, KIID>     pinUuidMap;
290 
291     for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
292     {
293         pinUuidMap[ pin->GetNumber() ] = pin->m_Uuid;
294 
295         if( !pin->GetAlt().IsEmpty() )
296             altPinMap[ pin->GetNumber() ] = pin->GetAlt();
297     }
298 
299     m_pins.clear();
300     m_pinMap.clear();
301 
302     if( !m_part )
303         return;
304 
305     unsigned i = 0;
306 
307     for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) )
308     {
309         wxASSERT( libPin->Type() == LIB_PIN_T );
310 
311         if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) )
312             continue;
313 
314         m_pins.push_back( std::make_unique<SCH_PIN>( libPin, this ) );
315 
316         auto ii = pinUuidMap.find( libPin->GetNumber() );
317 
318         if( ii != pinUuidMap.end() )
319             const_cast<KIID&>( m_pins.back()->m_Uuid ) = ii->second;
320 
321         auto iii = altPinMap.find( libPin->GetNumber() );
322 
323         if( iii != altPinMap.end() )
324             m_pins.back()->SetAlt( iii->second );
325 
326         m_pinMap[ libPin ] = i;
327 
328         ++i;
329     }
330 }
331 
332 
SetUnit(int aUnit)333 void SCH_SYMBOL::SetUnit( int aUnit )
334 {
335     if( m_unit != aUnit )
336     {
337         m_unit = aUnit;
338         SetModified();
339     }
340 }
341 
342 
UpdateUnit(int aUnit)343 void SCH_SYMBOL::UpdateUnit( int aUnit )
344 {
345     m_unit = aUnit;
346 }
347 
348 
SetConvert(int aConvert)349 void SCH_SYMBOL::SetConvert( int aConvert )
350 {
351     if( m_convert != aConvert )
352     {
353         m_convert = aConvert;
354 
355         // The convert may have a different pin layout so the update the pin map.
356         UpdatePins();
357         SetModified();
358     }
359 }
360 
361 
SetTransform(const TRANSFORM & aTransform)362 void SCH_SYMBOL::SetTransform( const TRANSFORM& aTransform )
363 {
364     if( m_transform != aTransform )
365     {
366         m_transform = aTransform;
367         SetModified();
368     }
369 }
370 
371 
GetUnitCount() const372 int SCH_SYMBOL::GetUnitCount() const
373 {
374     if( m_part )
375         return m_part->GetUnitCount();
376 
377     return 0;
378 }
379 
380 
Print(const RENDER_SETTINGS * aSettings,const wxPoint & aOffset)381 void SCH_SYMBOL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
382 {
383     LIB_SYMBOL_OPTIONS opts;
384     opts.transform = m_transform;
385     opts.draw_visible_fields = false;
386     opts.draw_hidden_fields = false;
387 
388     if( m_part )
389     {
390         m_part->Print( aSettings, m_pos + aOffset, m_unit, m_convert, opts );
391     }
392     else    // Use dummy() part if the actual cannot be found.
393     {
394         dummy()->Print( aSettings, m_pos + aOffset, 0, 0, opts );
395     }
396 
397     for( SCH_FIELD& field : m_fields )
398         field.Print( aSettings, aOffset );
399 }
400 
401 
AddHierarchicalReference(const KIID_PATH & aPath,const wxString & aRef,int aUnit,const wxString & aValue,const wxString & aFootprint)402 void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef,
403                                            int aUnit, const wxString& aValue,
404                                            const wxString& aFootprint )
405 {
406     // Search for an existing path and remove it if found (should not occur)
407     for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
408     {
409         if( m_instanceReferences[ii].m_Path == aPath )
410         {
411             wxLogTrace( traceSchSheetPaths, "Removing symbol instance:\n"
412                                             "  sheet path %s\n"
413                                             "  reference %s, unit %d from symbol %s.",
414                                             aPath.AsString(),
415                                             m_instanceReferences[ii].m_Reference,
416                                             m_instanceReferences[ii].m_Unit,
417                                             m_Uuid.AsString() );
418 
419             m_instanceReferences.erase( m_instanceReferences.begin() + ii );
420             ii--;
421         }
422     }
423 
424     SYMBOL_INSTANCE_REFERENCE instance;
425     instance.m_Path = aPath;
426     instance.m_Reference = aRef;
427     instance.m_Unit = aUnit;
428     instance.m_Value = aValue;
429     instance.m_Footprint = aFootprint;
430 
431     wxLogTrace( traceSchSheetPaths, "Adding symbol instance:\n"
432                                     "  sheet path %s\n"
433                                     "  reference %s, unit %d to symbol %s.",
434                                     aPath.AsString(),
435                                     aRef,
436                                     aUnit,
437                                     m_Uuid.AsString() );
438 
439     m_instanceReferences.push_back( instance );
440 }
441 
442 
GetRef(const SCH_SHEET_PATH * sheet,bool aIncludeUnit) const443 const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
444 {
445     KIID_PATH path = sheet->Path();
446     wxString  ref;
447 
448     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
449     {
450         if( instance.m_Path == path )
451         {
452             ref = instance.m_Reference;
453             break;
454         }
455     }
456 
457     // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
458     // use this as a default for this path.  This will happen if we load a version 1 schematic
459     // file.  It will also mean that multiple instances of the same sheet by default all have
460     // the same symbol references, but perhaps this is best.
461     if( ref.IsEmpty() && !GetField( REFERENCE_FIELD )->GetText().IsEmpty() )
462     {
463         const_cast<SCH_SYMBOL*>( this )->SetRef( sheet, GetField( REFERENCE_FIELD )->GetText() );
464         ref = GetField( REFERENCE_FIELD )->GetText();
465     }
466 
467     if( ref.IsEmpty() )
468         ref = UTIL::GetRefDesUnannotated( m_prefix );
469 
470     if( aIncludeUnit && GetUnitCount() > 1 )
471         ref += LIB_SYMBOL::SubReference( GetUnit() );
472 
473     return ref;
474 }
475 
476 
IsReferenceStringValid(const wxString & aReferenceString)477 bool SCH_SYMBOL::IsReferenceStringValid( const wxString& aReferenceString )
478 {
479     return !UTIL::GetRefDesPrefix( aReferenceString ).IsEmpty();
480 }
481 
482 
SetRef(const SCH_SHEET_PATH * sheet,const wxString & ref)483 void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
484 {
485     KIID_PATH path = sheet->Path();
486     bool      notInArray = true;
487 
488     // check to see if it is already there before inserting it
489     for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
490     {
491         if( instance.m_Path == path )
492         {
493             instance.m_Reference = ref;
494             notInArray = false;
495         }
496     }
497 
498     if( notInArray )
499         AddHierarchicalReference( path, ref, m_unit );
500 
501     for( std::unique_ptr<SCH_PIN>& pin : m_pins )
502         pin->ClearDefaultNetName( sheet );
503 
504     SCH_FIELD* rf = GetField( REFERENCE_FIELD );
505 
506     rf->SetText( ref );  // for drawing.
507 
508     // Reinit the m_prefix member if needed
509     m_prefix = UTIL::GetRefDesPrefix( ref );
510 
511     if( m_prefix.IsEmpty() )
512         m_prefix = wxT( "U" );
513 
514     // Power symbols have references starting with # and are not included in netlists
515     m_isInNetlist = ! ref.StartsWith( wxT( "#" ) );
516 }
517 
518 
IsAnnotated(const SCH_SHEET_PATH * aSheet)519 bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet )
520 {
521     KIID_PATH path = aSheet->Path();
522 
523     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
524     {
525         if( instance.m_Path == path )
526             return instance.m_Reference.Last() != '?';
527     }
528 
529     return false;
530 }
531 
532 
GetUnitSelection(const SCH_SHEET_PATH * aSheet) const533 int SCH_SYMBOL::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const
534 {
535     KIID_PATH path = aSheet->Path();
536 
537     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
538     {
539         if( instance.m_Path == path )
540             return instance.m_Unit;
541     }
542 
543     // If it was not found in m_Paths array, then use m_unit.  This will happen if we load a
544     // version 1 schematic file.
545     return m_unit;
546 }
547 
548 
SetUnitSelection(const SCH_SHEET_PATH * aSheet,int aUnitSelection)549 void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
550 {
551     KIID_PATH path = aSheet->Path();
552 
553     // check to see if it is already there before inserting it
554     for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
555     {
556         if( instance.m_Path == path )
557         {
558             instance.m_Unit = aUnitSelection;
559             return;
560         }
561     }
562 
563     // didn't find it; better add it
564     AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), aUnitSelection );
565 }
566 
567 
SetUnitSelection(int aUnitSelection)568 void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
569 {
570     for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
571         instance.m_Unit = aUnitSelection;
572 }
573 
574 
GetValue(const SCH_SHEET_PATH * sheet,bool aResolve) const575 const wxString SCH_SYMBOL::GetValue( const SCH_SHEET_PATH* sheet, bool aResolve ) const
576 {
577     KIID_PATH path = sheet->Path();
578 
579     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
580     {
581         if( instance.m_Path == path && !instance.m_Value.IsEmpty() )
582         {
583             // This can only be an override from an Update Schematic from PCB, and therefore
584             // will always be fully resolved.
585             return instance.m_Value;
586         }
587     }
588 
589     if( !aResolve )
590         return GetField( VALUE_FIELD )->GetText();
591 
592     return GetField( VALUE_FIELD )->GetShownText();
593 }
594 
595 
SetValue(const SCH_SHEET_PATH * sheet,const wxString & aValue)596 void SCH_SYMBOL::SetValue( const SCH_SHEET_PATH* sheet, const wxString& aValue )
597 {
598     if( sheet == nullptr )
599     {
600         // Clear instance overrides and set primary field value
601         for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
602             instance.m_Value = wxEmptyString;
603 
604         m_fields[ VALUE_FIELD ].SetText( aValue );
605         return;
606     }
607 
608     KIID_PATH path = sheet->Path();
609 
610     // check to see if it is already there before inserting it
611     for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
612     {
613         if( instance.m_Path == path )
614         {
615             instance.m_Value = aValue;
616             return;
617         }
618     }
619 
620     // didn't find it; better add it
621     AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), m_unit,
622                               aValue, wxEmptyString );
623 }
624 
625 
GetFootprint(const SCH_SHEET_PATH * sheet,bool aResolve) const626 const wxString SCH_SYMBOL::GetFootprint( const SCH_SHEET_PATH* sheet, bool aResolve ) const
627 {
628     KIID_PATH path = sheet->Path();
629 
630     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
631     {
632         if( instance.m_Path == path && !instance.m_Footprint.IsEmpty() )
633         {
634             // This can only be an override from an Update Schematic from PCB, and therefore
635             // will always be fully resolved.
636             return instance.m_Footprint;
637         }
638     }
639 
640     if( !aResolve )
641         return GetField( FOOTPRINT_FIELD )->GetText();
642 
643     return GetField( FOOTPRINT_FIELD )->GetShownText();
644 }
645 
646 
SetFootprint(const SCH_SHEET_PATH * sheet,const wxString & aFootprint)647 void SCH_SYMBOL::SetFootprint( const SCH_SHEET_PATH* sheet, const wxString& aFootprint )
648 {
649     if( sheet == nullptr )
650     {
651         // Clear instance overrides and set primary field value
652         for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
653             instance.m_Footprint = wxEmptyString;
654 
655         m_fields[ FOOTPRINT_FIELD ].SetText( aFootprint );
656         return;
657     }
658 
659     KIID_PATH path = sheet->Path();
660 
661     // check to see if it is already there before inserting it
662     for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
663     {
664         if( instance.m_Path == path )
665         {
666             instance.m_Footprint = aFootprint;
667             return;
668         }
669     }
670 
671     // didn't find it; better add it
672     AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), m_unit,
673                               wxEmptyString, aFootprint );
674 }
675 
676 
GetField(MANDATORY_FIELD_T aFieldType)677 SCH_FIELD* SCH_SYMBOL::GetField( MANDATORY_FIELD_T aFieldType )
678 {
679     return &m_fields[aFieldType];
680 }
681 
682 
GetField(MANDATORY_FIELD_T aFieldType) const683 const SCH_FIELD* SCH_SYMBOL::GetField( MANDATORY_FIELD_T aFieldType ) const
684 {
685     return &m_fields[aFieldType];
686 }
687 
688 
GetFieldById(int aFieldId)689 SCH_FIELD* SCH_SYMBOL::GetFieldById( int aFieldId )
690 {
691     for( size_t ii = 0; ii < m_fields.size(); ++ii )
692     {
693         if( m_fields[ii].GetId() == aFieldId )
694             return &m_fields[ii];
695     }
696 
697     return nullptr;
698 }
699 
700 
GetFieldText(const wxString & aFieldName,SCH_EDIT_FRAME * aFrame) const701 wxString SCH_SYMBOL::GetFieldText( const wxString& aFieldName, SCH_EDIT_FRAME* aFrame ) const
702 {
703     for( const SCH_FIELD& field : m_fields )
704     {
705         if( aFieldName == field.GetName() || aFieldName == field.GetCanonicalName() )
706             return field.GetText();
707     }
708 
709     return wxEmptyString;
710 }
711 
712 
GetFields(std::vector<SCH_FIELD * > & aVector,bool aVisibleOnly)713 void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly )
714 {
715     for( SCH_FIELD& field : m_fields )
716     {
717         if( !aVisibleOnly || ( field.IsVisible() && !field.IsVoid() ) )
718             aVector.push_back( &field );
719     }
720 }
721 
722 
AddField(const SCH_FIELD & aField)723 SCH_FIELD* SCH_SYMBOL::AddField( const SCH_FIELD& aField )
724 {
725     int newNdx = m_fields.size();
726 
727     m_fields.push_back( aField );
728     return &m_fields[newNdx];
729 }
730 
731 
RemoveField(const wxString & aFieldName)732 void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
733 {
734     for( unsigned i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
735     {
736         if( aFieldName == m_fields[i].GetName( false ) )
737         {
738             m_fields.erase( m_fields.begin() + i );
739             return;
740         }
741     }
742 }
743 
744 
FindField(const wxString & aFieldName,bool aIncludeDefaultFields)745 SCH_FIELD* SCH_SYMBOL::FindField( const wxString& aFieldName, bool aIncludeDefaultFields )
746 {
747     unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
748 
749     for( unsigned i = start; i < m_fields.size(); ++i )
750     {
751         if( aFieldName == m_fields[i].GetName( false ) )
752             return &m_fields[i];
753     }
754 
755     return nullptr;
756 }
757 
758 
UpdateFields(const SCH_SHEET_PATH * aPath,bool aUpdateStyle,bool aUpdateRef,bool aUpdateOtherFields,bool aResetRef,bool aResetOtherFields)759 void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef,
760                                bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields )
761 {
762     if( m_part )
763     {
764         wxString                symbolName;
765         std::vector<LIB_FIELD*> fields;
766 
767         m_part->GetFields( fields );
768 
769         for( const LIB_FIELD* libField : fields )
770         {
771             int id = libField->GetId();
772             SCH_FIELD* schField;
773 
774             if( id >= 0 && id < MANDATORY_FIELDS )
775             {
776                 schField = GetFieldById( id );
777             }
778             else
779             {
780                 schField = FindField( libField->GetCanonicalName() );
781 
782                 if( !schField )
783                 {
784                     wxString  fieldName = libField->GetCanonicalName();
785                     SCH_FIELD newField( wxPoint( 0, 0), GetFieldCount(), this, fieldName );
786                     schField = AddField( newField );
787                 }
788             }
789 
790             if( aUpdateStyle )
791             {
792                 schField->ImportValues( *libField );
793                 schField->SetTextPos( m_pos + libField->GetTextPos() );
794             }
795 
796             if( id == REFERENCE_FIELD && aPath )
797             {
798                 if( aResetRef )
799                     SetRef( aPath, m_part->GetReferenceField().GetText() );
800                 else if( aUpdateRef )
801                     SetRef( aPath, libField->GetText() );
802             }
803             else if( id == VALUE_FIELD )
804             {
805                 if( aResetOtherFields )
806                     SetValue( aPath, UnescapeString( m_lib_id.GetLibItemName() ) ); // alias-specific value
807                 else
808                     SetValue( aPath, UnescapeString( libField->GetText() ) );
809             }
810             else if( id == FOOTPRINT_FIELD )
811             {
812                 if( aResetOtherFields || aUpdateOtherFields )
813                     SetFootprint( aPath, libField->GetText() );
814             }
815             else if( id == DATASHEET_FIELD )
816             {
817                 if( aResetOtherFields )
818                     schField->SetText( GetDatasheet() ); // alias-specific value
819                 else if( aUpdateOtherFields )
820                     schField->SetText( libField->GetText() );
821             }
822             else
823             {
824                 if( aResetOtherFields || aUpdateOtherFields )
825                     schField->SetText( libField->GetText() );
826             }
827         }
828     }
829 }
830 
831 
RunOnChildren(const std::function<void (SCH_ITEM *)> & aFunction)832 void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction )
833 {
834     for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
835         aFunction( pin.get() );
836 
837     for( SCH_FIELD& field : m_fields )
838         aFunction( &field );
839 }
840 
841 
GetPin(const wxString & aNumber) const842 SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
843 {
844     for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
845     {
846         if( pin->GetNumber() == aNumber )
847             return pin.get();
848     }
849 
850     return nullptr;
851 }
852 
853 
GetLibPins(std::vector<LIB_PIN * > & aPinsList) const854 void SCH_SYMBOL::GetLibPins( std::vector<LIB_PIN*>& aPinsList ) const
855 {
856     if( m_part )
857         m_part->GetPins( aPinsList, m_unit, m_convert );
858 }
859 
860 
GetPin(LIB_PIN * aLibPin)861 SCH_PIN* SCH_SYMBOL::GetPin( LIB_PIN* aLibPin )
862 {
863     wxASSERT( m_pinMap.count( aLibPin ) );
864     return m_pins[ m_pinMap.at( aLibPin ) ].get();
865 }
866 
867 
GetPins(const SCH_SHEET_PATH * aSheet) const868 std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
869 {
870     std::vector<SCH_PIN*> pins;
871 
872     if( aSheet == nullptr )
873     {
874         wxCHECK_MSG( Schematic(), pins, "Can't call GetPins on a symbol with no schematic" );
875 
876         aSheet = &Schematic()->CurrentSheet();
877     }
878 
879     int unit = GetUnitSelection( aSheet );
880 
881     for( const auto& p : m_pins )
882     {
883         if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) )
884             continue;
885 
886         pins.push_back( p.get() );
887     }
888 
889     return pins;
890 }
891 
892 
SwapData(SCH_ITEM * aItem)893 void SCH_SYMBOL::SwapData( SCH_ITEM* aItem )
894 {
895     wxCHECK_RET( (aItem != nullptr) && (aItem->Type() == SCH_SYMBOL_T),
896                  wxT( "Cannot swap data with invalid symbol." ) );
897 
898     SCH_SYMBOL* symbol = (SCH_SYMBOL*) aItem;
899 
900     std::swap( m_lib_id, symbol->m_lib_id );
901 
902     LIB_SYMBOL* libSymbol = symbol->m_part.release();
903     symbol->m_part.reset( m_part.release() );
904     symbol->UpdatePins();
905     m_part.reset( libSymbol );
906     UpdatePins();
907 
908     std::swap( m_pos, symbol->m_pos );
909     std::swap( m_unit, symbol->m_unit );
910     std::swap( m_convert, symbol->m_convert );
911 
912     m_fields.swap( symbol->m_fields );    // std::vector's swap()
913 
914     for( SCH_FIELD& field : symbol->m_fields )
915         field.SetParent( symbol );
916 
917     for( SCH_FIELD& field : m_fields )
918         field.SetParent( this );
919 
920     TRANSFORM tmp = m_transform;
921 
922     m_transform = symbol->m_transform;
923     symbol->m_transform = tmp;
924 
925     std::swap( m_instanceReferences, symbol->m_instanceReferences );
926     std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
927 }
928 
929 
GetContextualTextVars(wxArrayString * aVars) const930 void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
931 {
932     for( int i = 0; i < MANDATORY_FIELDS; ++i )
933         aVars->push_back( m_fields[i].GetCanonicalName().Upper() );
934 
935     for( size_t i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
936         aVars->push_back( m_fields[i].GetName() );
937 
938     aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
939     aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
940     aVars->push_back( wxT( "UNIT" ) );
941 }
942 
943 
ResolveTextVar(wxString * token,int aDepth) const944 bool SCH_SYMBOL::ResolveTextVar( wxString* token, int aDepth ) const
945 {
946     SCHEMATIC* schematic = Schematic();
947 
948     // SCH_SYMOL object has no context outside a schematic.
949     wxCHECK( schematic, false );
950 
951     for( int i = 0; i < MANDATORY_FIELDS; ++i )
952     {
953         if( token->IsSameAs( m_fields[ i ].GetCanonicalName().Upper() ) )
954         {
955             if( i == REFERENCE_FIELD )
956                 *token = GetRef( &schematic->CurrentSheet(), true );
957             else if( i == VALUE_FIELD )
958                 *token = GetValue( &schematic->CurrentSheet(), true );
959             else if( i == FOOTPRINT_FIELD )
960                 *token = GetFootprint( &schematic->CurrentSheet(), true );
961             else
962                 *token = m_fields[ i ].GetShownText( aDepth + 1 );
963 
964             return true;
965         }
966     }
967 
968     for( size_t i = MANDATORY_FIELDS; i < m_fields.size(); ++i )
969     {
970         if( token->IsSameAs( m_fields[ i ].GetName() )
971             || token->IsSameAs( m_fields[ i ].GetName().Upper() ) )
972         {
973             *token = m_fields[ i ].GetShownText( aDepth + 1 );
974             return true;
975         }
976     }
977 
978     for( const TEMPLATE_FIELDNAME& templateFieldname :
979             schematic->Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
980     {
981         if( token->IsSameAs( templateFieldname.m_Name )
982             || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
983         {
984             // If we didn't find it in the fields list then it isn't set on this symbol.
985             // Just return an empty string.
986             *token = wxEmptyString;
987             return true;
988         }
989     }
990 
991     if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
992     {
993         wxString footprint;
994 
995         footprint = GetFootprint( &schematic->CurrentSheet(), true );
996 
997         wxArrayString parts = wxSplit( footprint, ':' );
998 
999         *token = parts[ 0 ];
1000         return true;
1001     }
1002     else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
1003     {
1004         wxString footprint;
1005 
1006         footprint = GetFootprint( &schematic->CurrentSheet(), true );
1007 
1008         wxArrayString parts = wxSplit( footprint, ':' );
1009 
1010         *token = parts[ std::min( 1, (int) parts.size() - 1 ) ];
1011         return true;
1012     }
1013     else if( token->IsSameAs( wxT( "UNIT" ) ) )
1014     {
1015         int unit;
1016 
1017         unit = GetUnitSelection( &schematic->CurrentSheet() );
1018 
1019         *token = LIB_SYMBOL::SubReference( unit );
1020         return true;
1021     }
1022 
1023     return false;
1024 }
1025 
1026 
ClearAnnotation(const SCH_SHEET_PATH * aSheetPath)1027 void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath )
1028 {
1029     // Build a reference with no annotation, i.e. a reference ending with a single '?'
1030     wxString defRef = UTIL::GetRefDesUnannotated( m_prefix );
1031 
1032     if( aSheetPath )
1033     {
1034         KIID_PATH path = aSheetPath->Path();
1035 
1036         for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
1037         {
1038             if( instance.m_Path == path )
1039                 instance.m_Reference = defRef;
1040         }
1041     }
1042     else
1043     {
1044         for( SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
1045             instance.m_Reference = defRef;
1046     }
1047 
1048     for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1049         pin->ClearDefaultNetName( aSheetPath );
1050 
1051     // These 2 changes do not work in complex hierarchy.
1052     // When a clear annotation is made, the calling function must call a
1053     // UpdateAllScreenReferences for the active sheet.
1054     // But this call cannot made here.
1055     m_fields[REFERENCE_FIELD].SetText( defRef ); //for drawing.
1056 }
1057 
1058 
AddSheetPathReferenceEntryIfMissing(const KIID_PATH & aSheetPath)1059 bool SCH_SYMBOL::AddSheetPathReferenceEntryIfMissing( const KIID_PATH& aSheetPath )
1060 {
1061     // a empty sheet path is illegal:
1062     wxCHECK( aSheetPath.size() > 0, false );
1063 
1064     wxString reference_path;
1065 
1066     for( const SYMBOL_INSTANCE_REFERENCE& instance : m_instanceReferences )
1067     {
1068         // if aSheetPath is found, nothing to do:
1069         if( instance.m_Path == aSheetPath )
1070             return false;
1071     }
1072 
1073     // This entry does not exist: add it, with its last-used reference
1074     AddHierarchicalReference( aSheetPath, m_fields[REFERENCE_FIELD].GetText(), m_unit );
1075     return true;
1076 }
1077 
1078 
ReplaceInstanceSheetPath(const KIID_PATH & aOldSheetPath,const KIID_PATH & aNewSheetPath)1079 bool SCH_SYMBOL::ReplaceInstanceSheetPath( const KIID_PATH& aOldSheetPath,
1080                                            const KIID_PATH& aNewSheetPath )
1081 {
1082     auto it = std::find_if( m_instanceReferences.begin(), m_instanceReferences.end(),
1083                 [ aOldSheetPath ]( SYMBOL_INSTANCE_REFERENCE& r )->bool
1084                 {
1085                     return aOldSheetPath == r.m_Path;
1086                 }
1087             );
1088 
1089     if( it != m_instanceReferences.end() )
1090     {
1091         wxLogTrace( traceSchSheetPaths,
1092                     "Replacing sheet path %s\n  with sheet path %s\n  for symbol %s.",
1093                     aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
1094 
1095         it->m_Path = aNewSheetPath;
1096         return true;
1097     }
1098 
1099     wxLogTrace( traceSchSheetPaths,
1100             "Could not find sheet path %s\n  to replace with sheet path %s\n  for symbol %s.",
1101             aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
1102 
1103     return false;
1104 }
1105 
1106 
SetOrientation(int aOrientation)1107 void SCH_SYMBOL::SetOrientation( int aOrientation )
1108 {
1109     TRANSFORM temp = TRANSFORM();
1110     bool transform = false;
1111 
1112     switch( aOrientation )
1113     {
1114     case SYM_ORIENT_0:
1115     case SYM_NORMAL:                    // default transform matrix
1116         m_transform.x1 = 1;
1117         m_transform.y2 = -1;
1118         m_transform.x2 = m_transform.y1 = 0;
1119         break;
1120 
1121     case SYM_ROTATE_COUNTERCLOCKWISE:  // Rotate + (incremental rotation)
1122         temp.x1   = temp.y2 = 0;
1123         temp.y1   = 1;
1124         temp.x2   = -1;
1125         transform = true;
1126         break;
1127 
1128     case SYM_ROTATE_CLOCKWISE:          // Rotate - (incremental rotation)
1129         temp.x1   = temp.y2 = 0;
1130         temp.y1   = -1;
1131         temp.x2   = 1;
1132         transform = true;
1133         break;
1134 
1135     case SYM_MIRROR_Y:                  // Mirror Y (incremental rotation)
1136         temp.x1   = -1;
1137         temp.y2   = 1;
1138         temp.y1   = temp.x2 = 0;
1139         transform = true;
1140         break;
1141 
1142     case SYM_MIRROR_X:                  // Mirror X (incremental rotation)
1143         temp.x1   = 1;
1144         temp.y2   = -1;
1145         temp.y1   = temp.x2 = 0;
1146         transform = true;
1147         break;
1148 
1149     case SYM_ORIENT_90:
1150         SetOrientation( SYM_ORIENT_0 );
1151         SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1152         break;
1153 
1154     case SYM_ORIENT_180:
1155         SetOrientation( SYM_ORIENT_0 );
1156         SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1157         SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1158         break;
1159 
1160     case SYM_ORIENT_270:
1161         SetOrientation( SYM_ORIENT_0 );
1162         SetOrientation( SYM_ROTATE_CLOCKWISE );
1163         break;
1164 
1165     case ( SYM_ORIENT_0 + SYM_MIRROR_X ):
1166         SetOrientation( SYM_ORIENT_0 );
1167         SetOrientation( SYM_MIRROR_X );
1168         break;
1169 
1170     case ( SYM_ORIENT_0 + SYM_MIRROR_Y ):
1171         SetOrientation( SYM_ORIENT_0 );
1172         SetOrientation( SYM_MIRROR_Y );
1173         break;
1174 
1175     case ( SYM_ORIENT_90 + SYM_MIRROR_X ):
1176         SetOrientation( SYM_ORIENT_90 );
1177         SetOrientation( SYM_MIRROR_X );
1178         break;
1179 
1180     case ( SYM_ORIENT_90 + SYM_MIRROR_Y ):
1181         SetOrientation( SYM_ORIENT_90 );
1182         SetOrientation( SYM_MIRROR_Y );
1183         break;
1184 
1185     case ( SYM_ORIENT_180 + SYM_MIRROR_X ):
1186         SetOrientation( SYM_ORIENT_180 );
1187         SetOrientation( SYM_MIRROR_X );
1188         break;
1189 
1190     case ( SYM_ORIENT_180 + SYM_MIRROR_Y ):
1191         SetOrientation( SYM_ORIENT_180 );
1192         SetOrientation( SYM_MIRROR_Y );
1193         break;
1194 
1195     case ( SYM_ORIENT_270 + SYM_MIRROR_X ):
1196         SetOrientation( SYM_ORIENT_270 );
1197         SetOrientation( SYM_MIRROR_X );
1198         break;
1199 
1200     case ( SYM_ORIENT_270 + SYM_MIRROR_Y ):
1201         SetOrientation( SYM_ORIENT_270 );
1202         SetOrientation( SYM_MIRROR_Y );
1203         break;
1204 
1205     default:
1206         transform = false;
1207         wxFAIL_MSG( "Invalid schematic symbol orientation type." );
1208         break;
1209     }
1210 
1211     if( transform )
1212     {
1213         /* The new matrix transform is the old matrix transform modified by the
1214          *  requested transformation, which is the temp transform (rot,
1215          *  mirror ..) in order to have (in term of matrix transform):
1216          *     transform coord = new_m_transform * coord
1217          *  where transform coord is the coord modified by new_m_transform from
1218          *  the initial value coord.
1219          *  new_m_transform is computed (from old_m_transform and temp) to
1220          *  have:
1221          *     transform coord = old_m_transform * temp
1222          */
1223         TRANSFORM newTransform;
1224 
1225         newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
1226         newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
1227         newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
1228         newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
1229         m_transform = newTransform;
1230     }
1231 }
1232 
1233 
GetOrientation()1234 int SCH_SYMBOL::GetOrientation()
1235 {
1236     int rotate_values[] =
1237     {
1238         SYM_ORIENT_0,
1239         SYM_ORIENT_90,
1240         SYM_ORIENT_180,
1241         SYM_ORIENT_270,
1242         SYM_MIRROR_X + SYM_ORIENT_0,
1243         SYM_MIRROR_X + SYM_ORIENT_90,
1244         SYM_MIRROR_X + SYM_ORIENT_270,
1245         SYM_MIRROR_Y,
1246         SYM_MIRROR_Y + SYM_ORIENT_0,
1247         SYM_MIRROR_Y + SYM_ORIENT_90,
1248         SYM_MIRROR_Y + SYM_ORIENT_180,
1249         SYM_MIRROR_Y + SYM_ORIENT_270
1250     };
1251 
1252     // Try to find the current transform option:
1253     TRANSFORM transform = m_transform;
1254 
1255     for( int type_rotate : rotate_values )
1256     {
1257         SetOrientation( type_rotate );
1258 
1259         if( transform == m_transform )
1260             return type_rotate;
1261     }
1262 
1263     // Error: orientation not found in list (should not happen)
1264     wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
1265     m_transform = transform;
1266 
1267     return SYM_NORMAL;
1268 }
1269 
1270 
1271 #if defined(DEBUG)
1272 
Show(int nestLevel,std::ostream & os) const1273 void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
1274 {
1275     // for now, make it look like XML:
1276     NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
1277                                  << " ref=\"" << TO_UTF8( GetField( REFERENCE_FIELD )->GetName() )
1278                                  << '"' << " chipName=\""
1279                                  << GetLibId().Format() << '"' << m_pos
1280                                  << " layer=\"" << m_layer
1281                                  << '"' << ">\n";
1282 
1283     // skip the reference, it's been output already.
1284     for( int i = 1; i < GetFieldCount();  ++i )
1285     {
1286         const wxString& value = GetFields()[i].GetText();
1287 
1288         if( !value.IsEmpty() )
1289         {
1290             NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
1291                                              << TO_UTF8( GetFields()[i].GetName() )
1292                                              << '"' << " value=\""
1293                                              << TO_UTF8( value ) << "\"/>\n";
1294         }
1295     }
1296 
1297     NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
1298 }
1299 
1300 #endif
1301 
1302 
doGetBoundingBox(bool aIncludePins,bool aIncludeFields) const1303 EDA_RECT SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
1304 {
1305     EDA_RECT    bBox;
1306 
1307     if( m_part )
1308         bBox = m_part->GetBodyBoundingBox( m_unit, m_convert, aIncludePins );
1309     else
1310         bBox = dummy()->GetBodyBoundingBox( m_unit, m_convert, aIncludePins );
1311 
1312     int x0 = bBox.GetX();
1313     int xm = bBox.GetRight();
1314 
1315     // We must reverse Y values, because matrix orientation
1316     // suppose Y axis normal for the library items coordinates,
1317     // m_transform reverse Y values, but bBox is already reversed!
1318     int y0 = -bBox.GetY();
1319     int ym = -bBox.GetBottom();
1320 
1321     // Compute the real Boundary box (rotated, mirrored ...)
1322     int x1 = m_transform.x1 * x0 + m_transform.y1 * y0;
1323     int y1 = m_transform.x2 * x0 + m_transform.y2 * y0;
1324     int x2 = m_transform.x1 * xm + m_transform.y1 * ym;
1325     int y2 = m_transform.x2 * xm + m_transform.y2 * ym;
1326 
1327     bBox.SetX( x1 );
1328     bBox.SetY( y1 );
1329     bBox.SetWidth( x2 - x1 );
1330     bBox.SetHeight( y2 - y1 );
1331     bBox.Normalize();
1332 
1333     bBox.Offset( m_pos );
1334 
1335     if( aIncludeFields )
1336     {
1337         for( const SCH_FIELD& field : m_fields )
1338         {
1339             if( field.IsVisible() )
1340                 bBox.Merge( field.GetBoundingBox() );
1341         }
1342     }
1343 
1344     return bBox;
1345 }
1346 
1347 
GetBodyBoundingBox() const1348 EDA_RECT SCH_SYMBOL::GetBodyBoundingBox() const
1349 {
1350     return doGetBoundingBox( false, false );
1351 }
1352 
1353 
GetBodyAndPinsBoundingBox() const1354 EDA_RECT SCH_SYMBOL::GetBodyAndPinsBoundingBox() const
1355 {
1356     return doGetBoundingBox( true, false );
1357 }
1358 
1359 
GetBoundingBox() const1360 const EDA_RECT SCH_SYMBOL::GetBoundingBox() const
1361 {
1362     return doGetBoundingBox( true, true );
1363 }
1364 
1365 
GetMsgPanelInfo(EDA_DRAW_FRAME * aFrame,std::vector<MSG_PANEL_ITEM> & aList)1366 void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1367 {
1368     wxString msg;
1369 
1370     SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
1371     SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
1372 
1373     // part and alias can differ if alias is not the root
1374     if( m_part )
1375     {
1376         if( m_part.get() != dummy() )
1377         {
1378             aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
1379 
1380             msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" );
1381             aList.emplace_back( msg, GetValue( currentSheet, true ) );
1382 
1383 #if 0       // Display symbol flags, for debug only
1384             aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
1385 #endif
1386 
1387             // Display symbol reference in library and library
1388             aList.emplace_back( _( "Name" ), UnescapeString( GetLibId().GetLibItemName() ) );
1389 
1390             if( !m_part->IsRoot() )
1391             {
1392                 msg = _( "Missing parent" );
1393 
1394                 std::shared_ptr< LIB_SYMBOL > parent = m_part->GetParent().lock();
1395 
1396                 if( parent )
1397                     msg = parent->GetName();
1398 
1399                 aList.emplace_back( _( "Alias of" ), UnescapeString( msg ) );
1400             }
1401             else if( !m_lib_id.GetLibNickname().empty() )
1402             {
1403                 aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
1404             }
1405             else
1406             {
1407                 aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
1408             }
1409 
1410             // Display the current associated footprint, if exists.
1411             msg = GetFootprint( currentSheet, true );
1412 
1413             if( msg.IsEmpty() )
1414                 msg = _( "<Unknown>" );
1415 
1416             aList.emplace_back( _( "Footprint" ), msg );
1417 
1418             // Display description of the symbol, and keywords found in lib
1419             aList.emplace_back( _( "Description" ), m_part->GetDescription()  );
1420             aList.emplace_back( _( "Keywords" ), m_part->GetKeyWords() );
1421         }
1422     }
1423     else
1424     {
1425         aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
1426 
1427         aList.emplace_back( _( "Value" ), GetValue( currentSheet, true ) );
1428         aList.emplace_back( _( "Name" ), GetLibId().GetLibItemName() );
1429 
1430         wxString libNickname = GetLibId().GetLibNickname();
1431 
1432         if( libNickname.empty() )
1433             msg = _( "No library defined!" );
1434         else
1435             msg.Printf( _( "Symbol not found in %s!" ), libNickname );
1436 
1437         aList.emplace_back( _( "Library" ), msg );
1438     }
1439 }
1440 
1441 
GetMenuImage() const1442 BITMAPS SCH_SYMBOL::GetMenuImage() const
1443 {
1444     return BITMAPS::add_component;
1445 }
1446 
1447 
MirrorHorizontally(int aCenter)1448 void SCH_SYMBOL::MirrorHorizontally( int aCenter )
1449 {
1450     int dx = m_pos.x;
1451 
1452     SetOrientation( SYM_MIRROR_Y );
1453     MIRROR( m_pos.x, aCenter );
1454     dx -= m_pos.x;     // dx,0 is the move vector for this transform
1455 
1456     for( SCH_FIELD& field : m_fields )
1457     {
1458         // Move the fields to the new position because the symbol itself has moved.
1459         wxPoint pos = field.GetTextPos();
1460         pos.x -= dx;
1461         field.SetTextPos( pos );
1462     }
1463 }
1464 
1465 
MirrorVertically(int aCenter)1466 void SCH_SYMBOL::MirrorVertically( int aCenter )
1467 {
1468     int dy = m_pos.y;
1469 
1470     SetOrientation( SYM_MIRROR_X );
1471     MIRROR( m_pos.y, aCenter );
1472     dy -= m_pos.y;     // 0,dy is the move vector for this transform
1473 
1474     for( SCH_FIELD& field : m_fields )
1475     {
1476         // Move the fields to the new position because the symbol itself has moved.
1477         wxPoint pos = field.GetTextPos();
1478         pos.y -= dy;
1479         field.SetTextPos( pos );
1480     }
1481 }
1482 
1483 
Rotate(const wxPoint & aCenter)1484 void SCH_SYMBOL::Rotate( const wxPoint& aCenter )
1485 {
1486     wxPoint prev = m_pos;
1487 
1488     RotatePoint( &m_pos, aCenter, 900 );
1489 
1490     SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
1491 
1492     for( SCH_FIELD& field : m_fields )
1493     {
1494         // Move the fields to the new position because the symbol itself has moved.
1495         wxPoint pos = field.GetTextPos();
1496         pos.x -= prev.x - m_pos.x;
1497         pos.y -= prev.y - m_pos.y;
1498         field.SetTextPos( pos );
1499     }
1500 }
1501 
1502 
Matches(const wxFindReplaceData & aSearchData,void * aAuxData) const1503 bool SCH_SYMBOL::Matches( const wxFindReplaceData& aSearchData, void* aAuxData ) const
1504 {
1505     wxLogTrace( traceFindItem, wxT( "  item " ) + GetSelectMenuText( EDA_UNITS::MILLIMETRES ) );
1506 
1507     // Symbols are searchable via the child field and pin item text.
1508     return false;
1509 }
1510 
1511 
GetEndPoints(std::vector<DANGLING_END_ITEM> & aItemList)1512 void SCH_SYMBOL::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
1513 {
1514     for( auto& pin : m_pins )
1515     {
1516         LIB_PIN* lib_pin = pin->GetLibPin();
1517 
1518         if( lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
1519             continue;
1520 
1521         DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
1522         aItemList.push_back( item );
1523     }
1524 }
1525 
1526 
UpdateDanglingState(std::vector<DANGLING_END_ITEM> & aItemList,const SCH_SHEET_PATH * aPath)1527 bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
1528                                       const SCH_SHEET_PATH* aPath )
1529 {
1530     bool changed = false;
1531 
1532     for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1533     {
1534         bool previousState = pin->IsDangling();
1535         pin->SetIsDangling( true );
1536 
1537         wxPoint pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
1538 
1539         for( DANGLING_END_ITEM& each_item : aItemList )
1540         {
1541             // Some people like to stack pins on top of each other in a symbol to indicate
1542             // internal connection. While technically connected, it is not particularly useful
1543             // to display them that way, so skip any pins that are in the same symbol as this
1544             // one.
1545             if( each_item.GetParent() == this )
1546                 continue;
1547 
1548             switch( each_item.GetType() )
1549             {
1550             case PIN_END:
1551             case LABEL_END:
1552             case SHEET_LABEL_END:
1553             case WIRE_END:
1554             case NO_CONNECT_END:
1555             case JUNCTION_END:
1556 
1557                 if( pos == each_item.GetPosition() )
1558                     pin->SetIsDangling( false );
1559 
1560                 break;
1561 
1562             default:
1563                 break;
1564             }
1565 
1566             if( !pin->IsDangling() )
1567                 break;
1568         }
1569 
1570         changed = ( changed || ( previousState != pin->IsDangling() ) );
1571     }
1572 
1573     return changed;
1574 }
1575 
1576 
GetPinPhysicalPosition(const LIB_PIN * Pin) const1577 wxPoint SCH_SYMBOL::GetPinPhysicalPosition( const LIB_PIN* Pin ) const
1578 {
1579     wxCHECK_MSG( Pin != nullptr && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ),
1580                  wxT( "Cannot get physical position of pin." ) );
1581 
1582     return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_pos;
1583 }
1584 
1585 
GetConnectionPoints() const1586 std::vector<wxPoint> SCH_SYMBOL::GetConnectionPoints() const
1587 {
1588     std::vector<wxPoint> retval;
1589 
1590     for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1591     {
1592         // Collect only pins attached to the current unit and convert.
1593         // others are not associated to this symbol instance
1594         int pin_unit = pin->GetLibPin()->GetUnit();
1595         int pin_convert = pin->GetLibPin()->GetConvert();
1596 
1597         if( pin_unit > 0 && pin_unit != GetUnit() )
1598             continue;
1599 
1600         if( pin_convert > 0 && pin_convert != GetConvert() )
1601             continue;
1602 
1603         retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
1604     }
1605 
1606     return retval;
1607 }
1608 
1609 
GetDrawItem(const wxPoint & aPosition,KICAD_T aType)1610 LIB_ITEM* SCH_SYMBOL::GetDrawItem( const wxPoint& aPosition, KICAD_T aType )
1611 {
1612     if( m_part )
1613     {
1614         // Calculate the position relative to the symbol.
1615         wxPoint libPosition = aPosition - m_pos;
1616 
1617         return m_part->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform );
1618     }
1619 
1620     return nullptr;
1621 }
1622 
1623 
GetSelectMenuText(EDA_UNITS aUnits) const1624 wxString SCH_SYMBOL::GetSelectMenuText( EDA_UNITS aUnits ) const
1625 {
1626     return wxString::Format( _( "Symbol %s [%s]" ),
1627                              GetField( REFERENCE_FIELD )->GetShownText(),
1628                              UnescapeString( GetLibId().GetLibItemName() ) );
1629 }
1630 
1631 
Visit(INSPECTOR aInspector,void * aTestData,const KICAD_T aFilterTypes[])1632 SEARCH_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData,
1633                                  const KICAD_T aFilterTypes[] )
1634 {
1635     KICAD_T     stype;
1636 
1637     for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
1638     {
1639         if( stype == SCH_LOCATE_ANY_T
1640           || ( stype == SCH_SYMBOL_T )
1641           || ( stype == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
1642         {
1643             if( SEARCH_RESULT::QUIT == aInspector( this, aTestData ) )
1644                 return SEARCH_RESULT::QUIT;
1645         }
1646 
1647         if( stype == SCH_LOCATE_ANY_T || stype == SCH_FIELD_T )
1648         {
1649             for( SCH_FIELD& field : m_fields )
1650             {
1651                 if( SEARCH_RESULT::QUIT == aInspector( &field, (void*) this ) )
1652                     return SEARCH_RESULT::QUIT;
1653             }
1654         }
1655 
1656         if( stype == SCH_FIELD_LOCATE_REFERENCE_T )
1657         {
1658             if( SEARCH_RESULT::QUIT == aInspector( GetField( REFERENCE_FIELD ), (void*) this ) )
1659                 return SEARCH_RESULT::QUIT;
1660         }
1661 
1662         if( stype == SCH_FIELD_LOCATE_VALUE_T
1663                 || ( stype == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
1664         {
1665             if( SEARCH_RESULT::QUIT == aInspector( GetField( VALUE_FIELD ), (void*) this ) )
1666                 return SEARCH_RESULT::QUIT;
1667         }
1668 
1669         if( stype == SCH_FIELD_LOCATE_FOOTPRINT_T )
1670         {
1671             if( SEARCH_RESULT::QUIT == aInspector( GetField( FOOTPRINT_FIELD ), (void*) this ) )
1672                 return SEARCH_RESULT::QUIT;
1673         }
1674 
1675         if( stype == SCH_FIELD_LOCATE_DATASHEET_T )
1676         {
1677             if( SEARCH_RESULT::QUIT == aInspector( GetField( DATASHEET_FIELD ), (void*) this ) )
1678                 return SEARCH_RESULT::QUIT;
1679         }
1680 
1681         if( stype == SCH_LOCATE_ANY_T || stype == SCH_PIN_T )
1682         {
1683             for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1684             {
1685                 // Collect only pins attached to the current unit and convert.
1686                 // others are not associated to this symbol instance
1687                 int pin_unit = pin->GetLibPin()->GetUnit();
1688                 int pin_convert = pin->GetLibPin()->GetConvert();
1689 
1690                 if( pin_unit > 0 && pin_unit != GetUnit() )
1691                     continue;
1692 
1693                 if( pin_convert > 0 && pin_convert != GetConvert() )
1694                     continue;
1695 
1696                 if( SEARCH_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
1697                     return SEARCH_RESULT::QUIT;
1698             }
1699         }
1700     }
1701 
1702     return SEARCH_RESULT::CONTINUE;
1703 }
1704 
1705 
operator <(const SCH_ITEM & aItem) const1706 bool SCH_SYMBOL::operator <( const SCH_ITEM& aItem ) const
1707 {
1708     if( Type() != aItem.Type() )
1709         return Type() < aItem.Type();
1710 
1711     auto symbol = static_cast<const SCH_SYMBOL*>( &aItem );
1712 
1713     EDA_RECT rect = GetBodyAndPinsBoundingBox();
1714 
1715     if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
1716         return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
1717 
1718     if( m_pos.x != symbol->m_pos.x )
1719         return m_pos.x < symbol->m_pos.x;
1720 
1721     if( m_pos.y != symbol->m_pos.y )
1722         return m_pos.y < symbol->m_pos.y;
1723 
1724     return m_Uuid < aItem.m_Uuid;       // Ensure deterministic sort
1725 }
1726 
1727 
operator ==(const SCH_SYMBOL & aSymbol) const1728 bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
1729 {
1730     if( GetFieldCount() !=  aSymbol.GetFieldCount() )
1731         return false;
1732 
1733     for( int i = VALUE_FIELD; i < GetFieldCount(); i++ )
1734     {
1735         if( GetFields()[i].GetText().Cmp( aSymbol.GetFields()[i].GetText() ) != 0 )
1736             return false;
1737     }
1738 
1739     return true;
1740 }
1741 
1742 
operator !=(const SCH_SYMBOL & aSymbol) const1743 bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
1744 {
1745     return !( *this == aSymbol );
1746 }
1747 
1748 
operator =(const SCH_ITEM & aItem)1749 SCH_SYMBOL& SCH_SYMBOL::operator=( const SCH_ITEM& aItem )
1750 {
1751     wxCHECK_MSG( Type() == aItem.Type(), *this,
1752                  wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
1753                  GetClass() );
1754 
1755     if( &aItem != this )
1756     {
1757         SCH_ITEM::operator=( aItem );
1758 
1759         SCH_SYMBOL* c = (SCH_SYMBOL*) &aItem;
1760 
1761         m_lib_id    = c->m_lib_id;
1762 
1763         LIB_SYMBOL* libSymbol = c->m_part ? new LIB_SYMBOL( *c->m_part.get() ) : nullptr;
1764 
1765         m_part.reset( libSymbol );
1766         m_pos       = c->m_pos;
1767         m_unit      = c->m_unit;
1768         m_convert   = c->m_convert;
1769         m_transform = c->m_transform;
1770 
1771         m_instanceReferences = c->m_instanceReferences;
1772 
1773         m_fields    = c->m_fields;    // std::vector's assignment operator
1774 
1775         // Reparent fields after assignment to new symbol.
1776         for( SCH_FIELD& field : m_fields )
1777             field.SetParent( this );
1778 
1779         UpdatePins();
1780     }
1781 
1782     return *this;
1783 }
1784 
1785 
HitTest(const wxPoint & aPosition,int aAccuracy) const1786 bool SCH_SYMBOL::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1787 {
1788     EDA_RECT bBox = GetBodyBoundingBox();
1789     bBox.Inflate( aAccuracy / 2 );
1790 
1791     if( bBox.Contains( aPosition ) )
1792         return true;
1793 
1794     return false;
1795 }
1796 
1797 
HitTest(const EDA_RECT & aRect,bool aContained,int aAccuracy) const1798 bool SCH_SYMBOL::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1799 {
1800     if( m_flags & STRUCT_DELETED || m_flags & SKIP_STRUCT )
1801         return false;
1802 
1803     EDA_RECT rect = aRect;
1804 
1805     rect.Inflate( aAccuracy / 2 );
1806 
1807     if( aContained )
1808         return rect.Contains( GetBodyBoundingBox() );
1809 
1810     return rect.Intersects( GetBodyBoundingBox() );
1811 }
1812 
1813 
doIsConnected(const wxPoint & aPosition) const1814 bool SCH_SYMBOL::doIsConnected( const wxPoint& aPosition ) const
1815 {
1816     wxPoint new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
1817 
1818     for( const auto& pin : m_pins )
1819     {
1820         if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
1821             continue;
1822 
1823         // Collect only pins attached to the current unit and convert.
1824         // others are not associated to this symbol instance
1825         int pin_unit = pin->GetLibPin()->GetUnit();
1826         int pin_convert = pin->GetLibPin()->GetConvert();
1827 
1828         if( pin_unit > 0 && pin_unit != GetUnit() )
1829             continue;
1830 
1831         if( pin_convert > 0 && pin_convert != GetConvert() )
1832             continue;
1833 
1834         if( pin->GetLocalPosition() == new_pos )
1835             return true;
1836     }
1837 
1838     return false;
1839 }
1840 
1841 
IsInNetlist() const1842 bool SCH_SYMBOL::IsInNetlist() const
1843 {
1844     return m_isInNetlist;
1845 }
1846 
1847 
Plot(PLOTTER * aPlotter) const1848 void SCH_SYMBOL::Plot( PLOTTER* aPlotter ) const
1849 {
1850     if( m_part )
1851     {
1852         TRANSFORM temp = GetTransform();
1853         aPlotter->StartBlock( nullptr );
1854 
1855         m_part->Plot( aPlotter, GetUnit(), GetConvert(), m_pos, temp );
1856 
1857         for( SCH_FIELD field : m_fields )
1858             field.Plot( aPlotter );
1859 
1860         aPlotter->EndBlock( nullptr );
1861     }
1862 }
1863 
1864 
HasBrightenedPins()1865 bool SCH_SYMBOL::HasBrightenedPins()
1866 {
1867     for( const auto& pin : m_pins )
1868     {
1869         if( pin->IsBrightened() )
1870             return true;
1871     }
1872 
1873     return false;
1874 }
1875 
1876 
ClearBrightenedPins()1877 void SCH_SYMBOL::ClearBrightenedPins()
1878 {
1879     for( auto& pin : m_pins )
1880         pin->ClearBrightened();
1881 }
1882 
1883 
IsPointClickableAnchor(const wxPoint & aPos) const1884 bool SCH_SYMBOL::IsPointClickableAnchor( const wxPoint& aPos ) const
1885 {
1886     for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1887     {
1888         int pin_unit = pin->GetLibPin()->GetUnit();
1889         int pin_convert = pin->GetLibPin()->GetConvert();
1890 
1891         if( pin_unit > 0 && pin_unit != GetUnit() )
1892             continue;
1893 
1894         if( pin_convert > 0 && pin_convert != GetConvert() )
1895             continue;
1896 
1897         if( pin->IsPointClickableAnchor( aPos ) )
1898             return true;
1899     }
1900 
1901     return false;
1902 }
1903