KiCad PCB EDA Suite
sch_component.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2020 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 <fctsys.h>
26 #include <gr_basic.h>
27 #include <kicad_string.h>
28 #include <sch_edit_frame.h>
29 #include <plotter.h>
30 #include <msgpanel.h>
31 #include <bitmaps.h>
32 
33 #include <general.h>
34 #include <lib_rectangle.h>
35 #include <lib_pin.h>
36 #include <lib_text.h>
37 #include <sch_component.h>
38 #include <sch_sheet.h>
39 #include <sch_sheet_path.h>
40 #include <schematic.h>
41 #include <netlist_object.h>
42 #include <lib_item.h>
43 
45 
46 #include <wx/tokenzr.h>
47 #include <iostream>
48 #include <cctype>
49 
50 #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
51 
52 #include <trace_helpers.h>
53 
54 
59 std::string toUTFTildaText( const wxString& txt )
60 {
61  std::string ret = TO_UTF8( txt );
62 
63  for( std::string::iterator it = ret.begin(); it!=ret.end(); ++it )
64  {
65  if( (unsigned char) *it <= ' ' )
66  *it = '~';
67  }
68  return ret;
69 }
70 
71 
85 static LIB_PART* dummy()
86 {
87  static LIB_PART* part;
88 
89  if( !part )
90  {
91  part = new LIB_PART( wxEmptyString );
92 
93  LIB_RECTANGLE* square = new LIB_RECTANGLE( part );
94 
95  square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
96  square->SetEndPosition( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
97 
98  LIB_TEXT* text = new LIB_TEXT( part );
99 
100  text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
101  text->SetText( wxString( wxT( "??" ) ) );
102 
103  part->AddDrawItem( square );
104  part->AddDrawItem( text );
105  }
106 
107  return part;
108 }
109 
110 
112  SCH_ITEM( aParent, SCH_COMPONENT_T )
113 {
114  Init( aPos );
115 }
116 
117 
119  int unit, int convert, const wxPoint& pos ) :
121 {
122  Init( pos );
123 
124  m_unit = unit;
125  m_convert = convert;
126  m_lib_id = aLibId;
127 
128  std::unique_ptr< LIB_PART > part;
129 
130  part = aPart.Flatten();
131  part->SetParent();
132  SetLibSymbol( part.release() );
133 
134  // Copy fields from the library component
135  UpdateFields( true, true );
136 
137  // Update the reference -- just the prefix for now.
138  if( sheet )
139  SetRef( sheet, m_part->GetReferenceField().GetText() + wxT( "?" ) );
140  else
141  m_prefix = m_part->GetReferenceField().GetText() + wxT( "?" );
142 }
143 
144 
146  const wxPoint& pos ) :
147  SCH_COMPONENT( aPart, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, pos )
148 {
149  // Set any fields that were modified as part of the component selection
150  for( auto const& i : aSel.Fields )
151  {
152  auto field = this->GetField( i.first );
153 
154  if( field )
155  field->SetText( i.second );
156  }
157 }
158 
159 
161  SCH_ITEM( aComponent )
162 {
163  m_Parent = aComponent.m_Parent;
164  m_Pos = aComponent.m_Pos;
165  m_unit = aComponent.m_unit;
166  m_convert = aComponent.m_convert;
167  m_lib_id = aComponent.m_lib_id;
168  m_isInNetlist = aComponent.m_isInNetlist;
169  m_inBom = aComponent.m_inBom;
170  m_onBoard = aComponent.m_onBoard;
171 
172  if( aComponent.m_part )
173  SetLibSymbol( new LIB_PART( *aComponent.m_part.get() ) );
174 
175  const_cast<KIID&>( m_Uuid ) = aComponent.m_Uuid;
176 
177  m_transform = aComponent.m_transform;
178  m_prefix = aComponent.m_prefix;
180  m_Fields = aComponent.m_Fields;
181 
182  // Re-parent the fields, which before this had aComponent as parent
183  for( SCH_FIELD& field : m_Fields )
184  field.SetParent( this );
185 
187 }
188 
189 
190 void SCH_COMPONENT::Init( const wxPoint& pos )
191 {
192  m_Pos = pos;
193  m_unit = 1; // In multi unit chip - which unit to draw.
194  m_convert = LIB_ITEM::LIB_CONVERT::BASE; // De Morgan Handling
195 
196  // The rotation/mirror transformation matrix. pos normal
198 
199  // construct only the mandatory fields, which are the first 4 only.
200  for( int i = 0; i < MANDATORY_FIELDS; ++i )
201  {
202  m_Fields.emplace_back( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) );
203 
204  if( i == REFERENCE )
205  m_Fields.back().SetLayer( LAYER_REFERENCEPART );
206  else if( i == VALUE )
207  m_Fields.back().SetLayer( LAYER_VALUEPART );
208  else
209  m_Fields.back().SetLayer( LAYER_FIELDS );
210  }
211 
212  m_prefix = wxString( wxT( "U" ) );
213  m_isInNetlist = true;
214  m_inBom = true;
215  m_onBoard = true;
216 }
217 
218 
220 {
221  return new SCH_COMPONENT( *this );
222 }
223 
224 
225 void SCH_COMPONENT::ViewGetLayers( int aLayers[], int& aCount ) const
226 {
227  aCount = 3;
228  aLayers[0] = LAYER_DEVICE;
229  aLayers[1] = LAYER_DEVICE_BACKGROUND;
230  aLayers[2] = LAYER_SELECTION_SHADOWS;
231 }
232 
233 
234 void SCH_COMPONENT::SetLibId( const LIB_ID& aLibId )
235 {
236  if( m_lib_id != aLibId )
237  {
238  m_lib_id = aLibId;
239  SetModified();
240  }
241 }
242 
243 
245 {
246  if( !m_schLibSymbolName.IsEmpty() )
247  return m_schLibSymbolName;
248  else
249  return m_lib_id.Format().wx_str();
250 }
251 
252 
254 {
255  wxCHECK2( ( aLibSymbol == nullptr ) || ( aLibSymbol->IsRoot() ), aLibSymbol = nullptr );
256 
257  m_part.reset( aLibSymbol );
258  UpdatePins();
259 }
260 
261 
263 {
264  if( m_part )
265  return m_part->GetDescription();
266 
267  return wxEmptyString;
268 }
269 
270 
272 {
273  if( m_part )
274  return m_part->GetDatasheetField().GetText();
275 
276  return wxEmptyString;
277 }
278 
279 
281 {
282  m_pins.clear();
283  m_pinMap.clear();
284 
285  if( !m_part )
286  return;
287 
288  unsigned i = 0;
289 
290  for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) )
291  {
292  wxASSERT( libPin->Type() == LIB_PIN_T );
293 
294  if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) )
295  continue;
296 
297  m_pins.push_back( std::unique_ptr<SCH_PIN>( new SCH_PIN( libPin, this ) ) );
298  m_pinMap[ libPin ] = i;
299 
300  ++i;
301  }
302 }
303 
304 
306 {
307  if( m_pinMap.count( aPin ) )
308  return m_pins[ m_pinMap[aPin] ]->Connection( aSheet );
309 
310  return nullptr;
311 }
312 
313 
314 void SCH_COMPONENT::SetUnit( int aUnit )
315 {
316  if( m_unit != aUnit )
317  {
318  m_unit = aUnit;
319  SetModified();
320  }
321 }
322 
323 
324 void SCH_COMPONENT::UpdateUnit( int aUnit )
325 {
326  m_unit = aUnit;
327 }
328 
329 
330 void SCH_COMPONENT::SetConvert( int aConvert )
331 {
332  if( m_convert != aConvert )
333  {
334  m_convert = aConvert;
335 
336  // The convert may have a different pin layout so the update the pin map.
337  UpdatePins();
338  SetModified();
339  }
340 }
341 
342 
343 void SCH_COMPONENT::SetTransform( const TRANSFORM& aTransform )
344 {
345  if( m_transform != aTransform )
346  {
347  m_transform = aTransform;
348  SetModified();
349  }
350 }
351 
352 
354 {
355  if( m_part )
356  return m_part->GetUnitCount();
357 
358  return 0;
359 }
360 
361 
362 void SCH_COMPONENT::Print( RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
363 {
364  PART_DRAW_OPTIONS opts;
365  opts.transform = m_transform;
366  opts.draw_visible_fields = false;
367  opts.draw_hidden_fields = false;
368 
369  if( m_part )
370  {
371  m_part->Print( aSettings, m_Pos + aOffset, m_unit, m_convert, opts );
372  }
373  else // Use dummy() part if the actual cannot be found.
374  {
375  dummy()->Print( aSettings, m_Pos + aOffset, 0, 0, opts );
376  }
377 
378  for( SCH_FIELD& field : m_Fields )
379  field.Print( aSettings, aOffset );
380 }
381 
382 
383 void SCH_COMPONENT::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef,
384  int aUnit )
385 {
386  // Search for an existing path and remove it if found (should not occur)
387  for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
388  {
389  if( m_instanceReferences[ii].m_Path == aPath )
390  {
391  wxLogTrace( traceSchSheetPaths,
392  "Removing symbol instance:\n sheet path %s\n reference %s, unit %d\n from symbol %s.",
393  aPath.AsString(), m_instanceReferences[ii].m_Reference,
394  m_instanceReferences[ii].m_Unit, m_Uuid.AsString() );
395 
396  m_instanceReferences.erase( m_instanceReferences.begin() + ii );
397  ii--;
398  }
399  }
400 
402  instance.m_Path = aPath;
403  instance.m_Reference = aRef;
404  instance.m_Unit = aUnit;
405 
406  wxLogTrace( traceSchSheetPaths,
407  "Adding symbol instance:\n sheet path %s\n reference %s, unit %d\n to symbol %s.",
408  aPath.AsString(), aRef, aUnit, m_Uuid.AsString() );
409 
410  m_instanceReferences.push_back( instance );
411 }
412 
413 
414 const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit )
415 {
416  KIID_PATH path = sheet->Path();
417  wxString ref;
418 
419  for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
420  {
421  if( instance.m_Path == path )
422  {
423  wxLogTrace( traceSchSheetPaths,
424  "Setting symbol instance:\n sheet path %s\n reference %s, unit %d\n found in symbol %s.",
425  path.AsString(), instance.m_Reference, instance.m_Unit, m_Uuid.AsString() );
426 
427  ref = instance.m_Reference;
428  break;
429  }
430  }
431 
432  // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
433  // use this as a default for this path. This will happen if we load a version 1 schematic
434  // file. It will also mean that multiple instances of the same sheet by default all have
435  // the same component references, but perhaps this is best.
436  if( ref.IsEmpty() && !GetField( REFERENCE )->GetText().IsEmpty() )
437  {
438  SetRef( sheet, GetField( REFERENCE )->GetText() );
439  ref = GetField( REFERENCE )->GetText();
440  }
441 
442  if( ref.IsEmpty() )
443  ref = m_prefix;
444 
445  if( aIncludeUnit && GetUnitCount() > 1 )
446  ref += LIB_PART::SubReference( GetUnit() );
447 
448  return ref;
449 }
450 
451 
452 bool SCH_COMPONENT::IsReferenceStringValid( const wxString& aReferenceString )
453 {
454  wxString text = aReferenceString;
455  bool ok = true;
456 
457  // Try to unannotate this reference
458  while( !text.IsEmpty() && ( text.Last() == '?' || wxIsdigit( text.Last() ) ) )
459  text.RemoveLast();
460 
461  if( text.IsEmpty() )
462  ok = false;
463 
464  return ok;
465 }
466 
467 
468 void SCH_COMPONENT::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
469 {
470  KIID_PATH path = sheet->Path();
471  bool notInArray = true;
472 
473  // check to see if it is already there before inserting it
475  {
476  if( instance.m_Path == path )
477  {
478  instance.m_Reference = ref;
479  notInArray = false;
480  }
481  }
482 
483  if( notInArray )
484  AddHierarchicalReference( path, ref, m_unit );
485 
486  SCH_FIELD* rf = GetField( REFERENCE );
487 
488  // @todo Should we really be checking for what is a "reasonable" position?
489  if( rf->GetText().IsEmpty()
490  || ( abs( rf->GetTextPos().x - m_Pos.x ) +
491  abs( rf->GetTextPos().y - m_Pos.y ) > Mils2iu( 10000 ) ) )
492  {
493  // move it to a reasonable position
494  rf->SetTextPos( m_Pos + wxPoint( Mils2iu( 50 ), Mils2iu( 50 ) ) );
495  }
496 
497  rf->SetText( ref ); // for drawing.
498 
499  // Reinit the m_prefix member if needed
500  wxString prefix = ref;
501 
502  if( IsReferenceStringValid( prefix ) )
503  {
504  while( prefix.Last() == '?' || wxIsdigit( prefix.Last() ) )
505  prefix.RemoveLast();
506  }
507  else
508  {
509  prefix = wxT( "U" ); // Set to default ref prefix
510  }
511 
512  if( m_prefix != prefix )
513  m_prefix = prefix;
514 
515  // Power components have references starting with # and are not included in netlists
516  m_isInNetlist = ! ref.StartsWith( wxT( "#" ) );
517 }
518 
519 
521 {
522  KIID_PATH path = aSheet->Path();
523 
524  for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
525  {
526  if( instance.m_Path == path )
527  return instance.m_Reference.Last() != '?';
528  }
529 
530  return false;
531 }
532 
533 
535 {
536  KIID_PATH path = aSheet->Path();
537 
538  for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
539  {
540  if( instance.m_Path == path )
541  return instance.m_Unit;
542  }
543 
544  // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
545  // version 1 schematic file.
546  return m_unit;
547 }
548 
549 
550 void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
551 {
552  KIID_PATH path = aSheet->Path();
553  bool notInArray = true;
554 
555  // check to see if it is already there before inserting it
557  {
558  if( instance.m_Path == path )
559  {
560  instance.m_Unit = aUnitSelection;
561  notInArray = false;
562  }
563  }
564 
565  if( notInArray )
566  AddHierarchicalReference( path, m_prefix, aUnitSelection );
567 }
568 
569 
571 {
572  if( (unsigned) aFieldNdx < m_Fields.size() )
573  return &m_Fields[aFieldNdx];
574 
575  return nullptr;
576 }
577 
578 
579 const SCH_FIELD* SCH_COMPONENT::GetField( int aFieldNdx ) const
580 {
581  if( (unsigned) aFieldNdx < m_Fields.size() )
582  return &m_Fields[aFieldNdx];
583 
584  return nullptr;
585 }
586 
587 
588 wxString SCH_COMPONENT::GetFieldText( const wxString& aFieldName, SCH_EDIT_FRAME* aFrame ) const
589 {
590  for( const SCH_FIELD& field : m_Fields )
591  {
592  if( aFieldName == field.GetName() )
593  return field.GetText();
594  }
595 
596  return wxEmptyString;
597 }
598 
599 
600 void SCH_COMPONENT::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly )
601 {
602  for( SCH_FIELD& field : m_Fields )
603  {
604  if( !aVisibleOnly || ( field.IsVisible() && !field.IsVoid() ) )
605  aVector.push_back( &field );
606  }
607 }
608 
609 
611 {
612  int newNdx = m_Fields.size();
613 
614  m_Fields.push_back( aField );
615  return &m_Fields[newNdx];
616 }
617 
618 
619 void SCH_COMPONENT::RemoveField( const wxString& aFieldName )
620 {
621  for( unsigned i = MANDATORY_FIELDS; i < m_Fields.size(); ++i )
622  {
623  if( aFieldName == m_Fields[i].GetName( false ) )
624  {
625  m_Fields.erase( m_Fields.begin() + i );
626  return;
627  }
628  }
629 }
630 
631 
632 SCH_FIELD* SCH_COMPONENT::FindField( const wxString& aFieldName, bool aIncludeDefaultFields )
633 {
634  unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
635 
636  for( unsigned i = start; i < m_Fields.size(); ++i )
637  {
638  if( aFieldName == m_Fields[i].GetName( false ) )
639  return &m_Fields[i];
640  }
641 
642  return NULL;
643 }
644 
645 
646 void SCH_COMPONENT::UpdateFields( bool aResetStyle, bool aResetRef )
647 {
648  if( m_part )
649  {
650  wxString symbolName;
651  LIB_FIELDS fields;
652  m_part->GetFields( fields );
653 
654  for( const LIB_FIELD& libField : fields )
655  {
656  int idx = libField.GetId();
657  SCH_FIELD* schField;
658 
659  if( idx == REFERENCE && !aResetRef )
660  continue;
661 
662  if( idx >= 0 && idx < MANDATORY_FIELDS )
663  {
664  schField = GetField( idx );
665  }
666  else
667  {
668  schField = FindField( libField.GetCanonicalName() );
669 
670  if( !schField )
671  {
672  wxString fieldName = libField.GetCanonicalName();
673  SCH_FIELD newField( wxPoint( 0, 0), GetFieldCount(), this, fieldName );
674  schField = AddField( newField );
675  }
676  }
677 
678  if( aResetStyle )
679  {
680  schField->ImportValues( libField );
681  schField->SetTextPos( m_Pos + libField.GetTextPos() );
682  }
683 
684  if( idx == VALUE )
685  {
686  schField->SetText( m_lib_id.GetLibItemName() ); // fetch alias-specific value
687  symbolName = m_lib_id.GetLibItemName();
688  }
689  else if( idx == DATASHEET )
690  {
691  schField->SetText( GetDatasheet() ); // fetch alias-specific value
692  }
693  else
694  {
695  schField->SetText( libField.GetText() );
696  }
697  }
698  }
699 }
700 
701 
702 LIB_PIN* SCH_COMPONENT::GetPin( const wxString& number )
703 {
704  if( m_part )
705  {
706  return m_part->GetPin( number, m_unit, m_convert );
707  }
708 
709  return NULL;
710 }
711 
712 
713 void SCH_COMPONENT::GetPins( std::vector<LIB_PIN*>& aPinsList )
714 {
715  if( m_part )
716  m_part->GetPins( aPinsList, m_unit, m_convert );
717 }
718 
719 
721 {
722  SCH_PIN_PTRS ptrs;
723 
724  if( aSheet == nullptr )
725  {
726  wxCHECK_MSG( Schematic(), ptrs, "Can't call GetSchPins on a component with no schematic" );
727 
728  aSheet = &Schematic()->CurrentSheet();
729  }
730 
731  int unit = GetUnitSelection( aSheet );
732 
733  for( const auto& p : m_pins )
734  {
735  if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) )
736  continue;
737 
738  ptrs.push_back( p.get() );
739  }
740 
741  return ptrs;
742 }
743 
744 
746 {
747  wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T),
748  wxT( "Cannot swap data with invalid component." ) );
749 
750  SCH_COMPONENT* component = (SCH_COMPONENT*) aItem;
751 
752  std::swap( m_lib_id, component->m_lib_id );
753 
754  LIB_PART* part = component->m_part.release();
755  component->m_part.reset( m_part.release() );
756  component->UpdatePins();
757  m_part.reset( part );
758  UpdatePins();
759 
760  std::swap( m_Pos, component->m_Pos );
761  std::swap( m_unit, component->m_unit );
762  std::swap( m_convert, component->m_convert );
763 
764  m_Fields.swap( component->m_Fields ); // std::vector's swap()
765 
766  for( SCH_FIELD& field : component->m_Fields )
767  field.SetParent( component );
768 
769  for( SCH_FIELD& field : m_Fields )
770  field.SetParent( this );
771 
772  TRANSFORM tmp = m_transform;
773 
774  m_transform = component->m_transform;
775  component->m_transform = tmp;
776 
777  std::swap( m_instanceReferences, component->m_instanceReferences );
778 }
779 
780 
781 void SCH_COMPONENT::GetContextualTextVars( wxArrayString* aVars ) const
782 {
783  for( int i = 0; i < MANDATORY_FIELDS; ++i )
784  aVars->push_back( m_Fields[i].GetCanonicalName().Upper() );
785 
786  for( size_t i = MANDATORY_FIELDS; i < m_Fields.size(); ++i )
787  aVars->push_back( m_Fields[i].GetName() );
788 
789  aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
790  aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
791  aVars->push_back( wxT( "UNIT" ) );
792 }
793 
794 
795 bool SCH_COMPONENT::ResolveTextVar( wxString* token, int aDepth ) const
796 {
797  for( int i = 0; i < MANDATORY_FIELDS; ++i )
798  {
799  if( token->IsSameAs( m_Fields[ i ].GetCanonicalName().Upper() ) )
800  {
801  *token = m_Fields[ i ].GetShownText( aDepth + 1 );
802  return true;
803  }
804  }
805 
806  for( size_t i = MANDATORY_FIELDS; i < m_Fields.size(); ++i )
807  {
808  if( token->IsSameAs( m_Fields[ i ].GetName() )
809  || token->IsSameAs( m_Fields[ i ].GetName().Upper() ) )
810  {
811  *token = m_Fields[ i ].GetShownText( aDepth + 1 );
812  return true;
813  }
814  }
815 
816  if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
817  {
818  const SCH_FIELD& field = m_Fields[ FOOTPRINT ];
819  wxArrayString parts = wxSplit( field.GetText(), ':' );
820 
821  *token = parts[ 0 ];
822  return true;
823  }
824  else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
825  {
826  const SCH_FIELD& field = m_Fields[ FOOTPRINT ];
827  wxArrayString parts = wxSplit( field.GetText(), ':' );
828 
829  *token = parts[ std::min( 1, (int) parts.size() - 1 ) ];
830  return true;
831  }
832  else if( token->IsSameAs( wxT( "UNIT" ) ) )
833  {
834  *token = LIB_PART::SubReference( GetUnit() );
835  return true;
836  }
837 
838  return false;
839 }
840 
841 
843 {
844  // Build a reference with no annotation,
845  // i.e. a reference ended by only one '?'
846  wxString defRef = m_prefix;
847 
848  if( !IsReferenceStringValid( defRef ) )
849  { // This is a malformed reference: reinit this reference
850  m_prefix = defRef = wxT("U"); // Set to default ref prefix
851  }
852 
853  while( defRef.Last() == '?' )
854  defRef.RemoveLast();
855 
856  defRef.Append( wxT( "?" ) );
857 
858  if( aSheetPath )
859  {
860  KIID_PATH path = aSheetPath->Path();
861 
863  {
864  if( instance.m_Path == path )
865  instance.m_Reference = defRef;
866  }
867  }
868  else
869  {
871  instance.m_Reference = defRef;
872  }
873 
874  // These 2 changes do not work in complex hierarchy.
875  // When a clear annotation is made, the calling function must call a
876  // UpdateAllScreenReferences for the active sheet.
877  // But this call cannot made here.
878  m_Fields[REFERENCE].SetText( defRef ); //for drawing.
879 
880  SetModified();
881 }
882 
883 
885 {
886  // a empty sheet path is illegal:
887  wxCHECK( aSheetPath.size() > 0, false );
888 
889  wxString reference_path;
890 
891  for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
892  {
893  // if aSheetPath is found, nothing to do:
894  if( instance.m_Path == aSheetPath )
895  return false;
896  }
897 
898  // This entry does not exist: add it, with its last-used reference
900  return true;
901 }
902 
903 
905  const KIID_PATH& aNewSheetPath )
906 {
907  auto it = std::find_if( m_instanceReferences.begin(), m_instanceReferences.end(),
908  [ aOldSheetPath ]( COMPONENT_INSTANCE_REFERENCE& r )->bool
909  {
910  return aOldSheetPath == r.m_Path;
911  }
912  );
913 
914  if( it != m_instanceReferences.end() )
915  {
916  wxLogTrace( traceSchSheetPaths,
917  "Replacing sheet path %s\n with sheet path %s\n for symbol %s.",
918  aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
919 
920  it->m_Path = aNewSheetPath;
921  return true;
922  }
923 
924  wxLogTrace( traceSchSheetPaths,
925  "Could not find sheet path %s\n to replace with sheet path %s\n for symbol %s.",
926  aOldSheetPath.AsString(), aNewSheetPath.AsString(), m_Uuid.AsString() );
927 
928  return false;
929 }
930 
931 
932 void SCH_COMPONENT::SetOrientation( int aOrientation )
933 {
934  TRANSFORM temp = TRANSFORM();
935  bool transform = false;
936 
937  switch( aOrientation )
938  {
939  case CMP_ORIENT_0:
940  case CMP_NORMAL: // default transform matrix
941  m_transform.x1 = 1;
942  m_transform.y2 = -1;
944  break;
945 
946  case CMP_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
947  temp.x1 = temp.y2 = 0;
948  temp.y1 = 1;
949  temp.x2 = -1;
950  transform = true;
951  break;
952 
953  case CMP_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
954  temp.x1 = temp.y2 = 0;
955  temp.y1 = -1;
956  temp.x2 = 1;
957  transform = true;
958  break;
959 
960  case CMP_MIRROR_Y: // Mirror Y (incremental rotation)
961  temp.x1 = -1;
962  temp.y2 = 1;
963  temp.y1 = temp.x2 = 0;
964  transform = true;
965  break;
966 
967  case CMP_MIRROR_X: // Mirror X (incremental rotation)
968  temp.x1 = 1;
969  temp.y2 = -1;
970  temp.y1 = temp.x2 = 0;
971  transform = true;
972  break;
973 
974  case CMP_ORIENT_90:
977  break;
978 
979  case CMP_ORIENT_180:
983  break;
984 
985  case CMP_ORIENT_270:
988  break;
989 
990  case ( CMP_ORIENT_0 + CMP_MIRROR_X ):
993  break;
994 
995  case ( CMP_ORIENT_0 + CMP_MIRROR_Y ):
998  break;
999 
1000  case ( CMP_ORIENT_90 + CMP_MIRROR_X ):
1003  break;
1004 
1005  case ( CMP_ORIENT_90 + CMP_MIRROR_Y ):
1008  break;
1009 
1010  case ( CMP_ORIENT_180 + CMP_MIRROR_X ):
1013  break;
1014 
1015  case ( CMP_ORIENT_180 + CMP_MIRROR_Y ):
1018  break;
1019 
1020  case ( CMP_ORIENT_270 + CMP_MIRROR_X ):
1023  break;
1024 
1025  case ( CMP_ORIENT_270 + CMP_MIRROR_Y ):
1028  break;
1029 
1030  default:
1031  transform = false;
1032  wxFAIL_MSG( "Invalid schematic symbol orientation type." );
1033  break;
1034  }
1035 
1036  if( transform )
1037  {
1038  /* The new matrix transform is the old matrix transform modified by the
1039  * requested transformation, which is the temp transform (rot,
1040  * mirror ..) in order to have (in term of matrix transform):
1041  * transform coord = new_m_transform * coord
1042  * where transform coord is the coord modified by new_m_transform from
1043  * the initial value coord.
1044  * new_m_transform is computed (from old_m_transform and temp) to
1045  * have:
1046  * transform coord = old_m_transform * temp
1047  */
1048  TRANSFORM newTransform;
1049 
1050  newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
1051  newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
1052  newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
1053  newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
1054  m_transform = newTransform;
1055  }
1056 }
1057 
1058 
1060 {
1061  int rotate_values[] =
1062  {
1063  CMP_ORIENT_0,
1064  CMP_ORIENT_90,
1070  CMP_MIRROR_Y,
1075  };
1076 
1077  // Try to find the current transform option:
1078  TRANSFORM transform = m_transform;
1079 
1080  for( int type_rotate : rotate_values )
1081  {
1082  SetOrientation( type_rotate );
1083 
1084  if( transform == m_transform )
1085  return type_rotate;
1086  }
1087 
1088  // Error: orientation not found in list (should not happen)
1089  wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
1090  m_transform = transform;
1091 
1092  return CMP_NORMAL;
1093 }
1094 
1095 
1096 #if defined(DEBUG)
1097 
1098 void SCH_COMPONENT::Show( int nestLevel, std::ostream& os ) const
1099 {
1100  // for now, make it look like XML:
1101  NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
1102  << " ref=\"" << TO_UTF8( GetField( 0 )->GetName() )
1103  << '"' << " chipName=\""
1104  << GetLibId().Format() << '"' << m_Pos
1105  << " layer=\"" << m_Layer
1106  << '"' << ">\n";
1107 
1108  // skip the reference, it's been output already.
1109  for( int i = 1; i < GetFieldCount(); ++i )
1110  {
1111  wxString value = GetField( i )->GetText();
1112 
1113  if( !value.IsEmpty() )
1114  {
1115  NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
1116  << TO_UTF8( GetField( i )->GetName() )
1117  << '"' << " value=\""
1118  << TO_UTF8( value ) << "\"/>\n";
1119  }
1120  }
1121 
1122  NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
1123 }
1124 
1125 #endif
1126 
1127 
1129 {
1130  EDA_RECT bBox;
1131 
1132  if( m_part )
1133  bBox = m_part->GetBodyBoundingBox( m_unit, m_convert );
1134  else
1135  bBox = dummy()->GetBodyBoundingBox( m_unit, m_convert );
1136 
1137  int x0 = bBox.GetX();
1138  int xm = bBox.GetRight();
1139 
1140  // We must reverse Y values, because matrix orientation
1141  // suppose Y axis normal for the library items coordinates,
1142  // m_transform reverse Y values, but bBox is already reversed!
1143  int y0 = -bBox.GetY();
1144  int ym = -bBox.GetBottom();
1145 
1146  // Compute the real Boundary box (rotated, mirrored ...)
1147  int x1 = m_transform.x1 * x0 + m_transform.y1 * y0;
1148  int y1 = m_transform.x2 * x0 + m_transform.y2 * y0;
1149  int x2 = m_transform.x1 * xm + m_transform.y1 * ym;
1150  int y2 = m_transform.x2 * xm + m_transform.y2 * ym;
1151 
1152  bBox.SetX( x1 );
1153  bBox.SetY( y1 );
1154  bBox.SetWidth( x2 - x1 );
1155  bBox.SetHeight( y2 - y1 );
1156  bBox.Normalize();
1157 
1158  bBox.Offset( m_Pos );
1159  return bBox;
1160 }
1161 
1162 
1164 {
1165  EDA_RECT bbox = GetBodyBoundingBox();
1166 
1167  for( const SCH_FIELD& field : m_Fields )
1168  bbox.Merge( field.GetBoundingBox() );
1169 
1170  return bbox;
1171 }
1172 
1173 
1175 {
1176  wxString msg;
1177 
1178  SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
1179 
1180  // part and alias can differ if alias is not the root
1181  if( m_part )
1182  {
1183  if( m_part.get() != dummy() )
1184  {
1185  if( schframe )
1186  {
1187  aList.push_back( MSG_PANEL_ITEM(
1188  _( "Reference" ), GetRef( &schframe->GetCurrentSheet() ), DARKCYAN ) );
1189  }
1190 
1191  msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" );
1192 
1193  aList.push_back( MSG_PANEL_ITEM( msg, GetField( VALUE )->GetShownText(), DARKCYAN ) );
1194 
1195 #if 0 // Display component flags, for debug only
1196  aList.push_back( MSG_PANEL_ITEM( _( "flags" ),
1197  wxString::Format("%X", GetEditFlags()), BROWN ) );
1198 #endif
1199 
1200  // Display component reference in library and library
1201  aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) );
1202 
1203  if( !m_part->IsRoot() )
1204  {
1205  msg = _( "Missing parent" );
1206 
1207  std::shared_ptr< LIB_PART > parent = m_part->GetParent().lock();
1208 
1209  if( parent )
1210  msg = parent->GetName();
1211 
1212  aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), msg, BROWN ) );
1213  }
1214  else if( !m_lib_id.GetLibNickname().empty() )
1215  {
1216  aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(),
1217  BROWN ) );
1218  }
1219  else
1220  {
1221  aList.push_back( MSG_PANEL_ITEM( _( "Library" ), _( "Undefined!!!" ), RED ) );
1222  }
1223 
1224  // Display the current associated footprint, if exists.
1225  if( !GetField( FOOTPRINT )->IsVoid() )
1226  msg = GetField( FOOTPRINT )->GetShownText();
1227  else
1228  msg = _( "<Unknown>" );
1229 
1230  aList.push_back( MSG_PANEL_ITEM( _( "Footprint" ), msg, DARKRED ) );
1231 
1232  // Display description of the component, and keywords found in lib
1233  aList.push_back( MSG_PANEL_ITEM( _( "Description" ), m_part->GetDescription(),
1234  DARKCYAN ) );
1235  aList.push_back( MSG_PANEL_ITEM( _( "Key words" ), m_part->GetKeyWords(), DARKCYAN ) );
1236  }
1237  }
1238  else
1239  {
1240  if( schframe )
1241  {
1242  aList.push_back( MSG_PANEL_ITEM(
1243  _( "Reference" ), GetRef( &schframe->GetCurrentSheet() ), DARKCYAN ) );
1244  }
1245 
1246  aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetField( VALUE )->GetShownText(),
1247  DARKCYAN ) );
1248  aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) );
1249 
1250  wxString libNickname = GetLibId().GetLibNickname();
1251 
1252  if( libNickname.empty() )
1253  {
1254  aList.push_back( MSG_PANEL_ITEM( _( "Library" ), _( "No library defined!" ), RED ) );
1255  }
1256  else
1257  {
1258  msg.Printf( _( "Symbol not found in %s!" ), libNickname );
1259  aList.push_back( MSG_PANEL_ITEM( _( "Library" ), msg , RED ) );
1260  }
1261  }
1262 }
1263 
1264 
1266 {
1267  return add_component_xpm;
1268 }
1269 
1270 
1271 void SCH_COMPONENT::MirrorY( int aYaxis_position )
1272 {
1273  int dx = m_Pos.x;
1274 
1276  MIRROR( m_Pos.x, aYaxis_position );
1277  dx -= m_Pos.x; // dx,0 is the move vector for this transform
1278 
1279  for( SCH_FIELD& field : m_Fields )
1280  {
1281  // Move the fields to the new position because the component itself has moved.
1282  wxPoint pos = field.GetTextPos();
1283  pos.x -= dx;
1284  field.SetTextPos( pos );
1285  }
1286 }
1287 
1288 
1289 void SCH_COMPONENT::MirrorX( int aXaxis_position )
1290 {
1291  int dy = m_Pos.y;
1292 
1294  MIRROR( m_Pos.y, aXaxis_position );
1295  dy -= m_Pos.y; // dy,0 is the move vector for this transform
1296 
1297  for( SCH_FIELD& field : m_Fields )
1298  {
1299  // Move the fields to the new position because the component itself has moved.
1300  wxPoint pos = field.GetTextPos();
1301  pos.y -= dy;
1302  field.SetTextPos( pos );
1303  }
1304 }
1305 
1306 
1308 {
1309  wxPoint prev = m_Pos;
1310 
1311  RotatePoint( &m_Pos, aPosition, 900 );
1312 
1314 
1315  for( SCH_FIELD& field : m_Fields )
1316  {
1317  // Move the fields to the new position because the component itself has moved.
1318  wxPoint pos = field.GetTextPos();
1319  pos.x -= prev.x - m_Pos.x;
1320  pos.y -= prev.y - m_Pos.y;
1321  field.SetTextPos( pos );
1322  }
1323 }
1324 
1325 
1326 bool SCH_COMPONENT::Matches( wxFindReplaceData& aSearchData, void* aAuxData )
1327 {
1328  wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText( EDA_UNITS::MILLIMETRES ) );
1329 
1330  // Components are searchable via the child field and pin item text.
1331  return false;
1332 }
1333 
1334 
1335 void SCH_COMPONENT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
1336 {
1337  for( auto& pin : m_pins )
1338  {
1339  LIB_PIN* lib_pin = pin->GetLibPin();
1340 
1341  if( lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
1342  continue;
1343 
1344  DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
1345  aItemList.push_back( item );
1346  }
1347 }
1348 
1349 
1350 bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
1351  const SCH_SHEET_PATH* aPath )
1352 {
1353  bool changed = false;
1354 
1355  for( std::unique_ptr<SCH_PIN>& pin : m_pins )
1356  {
1357  bool previousState = pin->IsDangling();
1358  pin->SetIsDangling( true );
1359 
1360  wxPoint pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_Pos;
1361 
1362  for( DANGLING_END_ITEM& each_item : aItemList )
1363  {
1364  // Some people like to stack pins on top of each other in a symbol to indicate
1365  // internal connection. While technically connected, it is not particularly useful
1366  // to display them that way, so skip any pins that are in the same symbol as this
1367  // one.
1368  if( each_item.GetParent() == this )
1369  continue;
1370 
1371  switch( each_item.GetType() )
1372  {
1373  case PIN_END:
1374  case LABEL_END:
1375  case SHEET_LABEL_END:
1376  case WIRE_START_END:
1377  case WIRE_END_END:
1378  case NO_CONNECT_END:
1379  case JUNCTION_END:
1380 
1381  if( pos == each_item.GetPosition() )
1382  pin->SetIsDangling( false );
1383 
1384  break;
1385 
1386  default:
1387  break;
1388  }
1389 
1390  if( !pin->IsDangling() )
1391  break;
1392  }
1393 
1394  changed = ( changed || ( previousState != pin->IsDangling() ) );
1395  }
1396 
1397  return changed;
1398 }
1399 
1400 
1402 {
1403  wxCHECK_MSG( Pin != NULL && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ),
1404  wxT( "Cannot get physical position of pin." ) );
1405 
1406  return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_Pos;
1407 }
1408 
1409 
1410 void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
1411 {
1412  for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1413  {
1414  // Collect only pins attached to the current unit and convert.
1415  // others are not associated to this component instance
1416  int pin_unit = pin->GetLibPin()->GetUnit();
1417  int pin_convert = pin->GetLibPin()->GetConvert();
1418 
1419  if( pin_unit > 0 && pin_unit != GetUnit() )
1420  continue;
1421 
1422  if( pin_convert > 0 && pin_convert != GetConvert() )
1423  continue;
1424 
1425  aPoints.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_Pos );
1426  }
1427 }
1428 
1429 
1431 {
1432  if( m_part )
1433  {
1434  // Calculate the position relative to the component.
1435  wxPoint libPosition = aPosition - m_Pos;
1436 
1437  return m_part->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform );
1438  }
1439 
1440  return NULL;
1441 }
1442 
1443 
1445 {
1446  return wxString::Format( _( "Symbol %s, %s" ),
1447  GetLibId().GetLibItemName().wx_str(),
1448  GetField( REFERENCE )->GetShownText() );
1449 }
1450 
1451 
1452 SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR aInspector, void* aTestData,
1453  const KICAD_T aFilterTypes[] )
1454 {
1455  KICAD_T stype;
1456 
1457  for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
1458  {
1459  if( stype == SCH_LOCATE_ANY_T
1460  || ( stype == SCH_COMPONENT_T )
1461  || ( stype == SCH_COMPONENT_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
1462  {
1463  if( SEARCH_RESULT::QUIT == aInspector( this, aTestData ) )
1464  return SEARCH_RESULT::QUIT;
1465  }
1466 
1467  if( stype == SCH_LOCATE_ANY_T || stype == SCH_FIELD_T )
1468  {
1469  for( SCH_FIELD& field : m_Fields )
1470  {
1471  if( SEARCH_RESULT::QUIT == aInspector( &field, (void*) this ) )
1472  return SEARCH_RESULT::QUIT;
1473  }
1474  }
1475 
1476  if( stype == SCH_FIELD_LOCATE_REFERENCE_T )
1477  {
1478  if( SEARCH_RESULT::QUIT == aInspector( GetField( REFERENCE ), (void*) this ) )
1479  return SEARCH_RESULT::QUIT;
1480  }
1481 
1482  if( stype == SCH_FIELD_LOCATE_VALUE_T
1483  || ( stype == SCH_COMPONENT_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
1484  {
1485  if( SEARCH_RESULT::QUIT == aInspector( GetField( VALUE ), (void*) this ) )
1486  return SEARCH_RESULT::QUIT;
1487  }
1488 
1489  if( stype == SCH_FIELD_LOCATE_FOOTPRINT_T )
1490  {
1491  if( SEARCH_RESULT::QUIT == aInspector( GetField( FOOTPRINT ), (void*) this ) )
1492  return SEARCH_RESULT::QUIT;
1493  }
1494 
1495  if( stype == SCH_FIELD_LOCATE_DATASHEET_T )
1496  {
1497  if( SEARCH_RESULT::QUIT == aInspector( GetField( DATASHEET ), (void*) this ) )
1498  return SEARCH_RESULT::QUIT;
1499  }
1500 
1501  if( stype == SCH_LOCATE_ANY_T || stype == SCH_PIN_T )
1502  {
1503  for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
1504  {
1505  // Collect only pins attached to the current unit and convert.
1506  // others are not associated to this component instance
1507  int pin_unit = pin->GetLibPin()->GetUnit();
1508  int pin_convert = pin->GetLibPin()->GetConvert();
1509 
1510  if( pin_unit > 0 && pin_unit != GetUnit() )
1511  continue;
1512 
1513  if( pin_convert > 0 && pin_convert != GetConvert() )
1514  continue;
1515 
1516  if( SEARCH_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
1517  return SEARCH_RESULT::QUIT;
1518  }
1519  }
1520  }
1521 
1522  return SEARCH_RESULT::CONTINUE;
1523 }
1524 
1525 
1527  SCH_SHEET_PATH* aSheetPath )
1528 {
1529  if( !m_part || !m_onBoard )
1530  return;
1531 
1532  for( LIB_PIN* pin = m_part->GetNextPin(); pin; pin = m_part->GetNextPin( pin ) )
1533  {
1534  wxASSERT( pin->Type() == LIB_PIN_T );
1535 
1536  if( pin->GetUnit() && ( pin->GetUnit() != GetUnitSelection( aSheetPath ) ) )
1537  continue;
1538 
1539  if( pin->GetConvert() && ( pin->GetConvert() != GetConvert() ) )
1540  continue;
1541 
1542  wxPoint pos = GetTransform().TransformCoordinate( pin->GetPosition() ) + m_Pos;
1543 
1544  NETLIST_OBJECT* item = new NETLIST_OBJECT();
1545  item->m_SheetPathInclude = *aSheetPath;
1546  item->m_Comp = m_pins[ m_pinMap.at( pin ) ].get();
1547  item->m_SheetPath = *aSheetPath;
1548  item->m_Type = NETLIST_ITEM::PIN;
1549  item->m_Link = (SCH_ITEM*) this;
1550  item->m_ElectricalPinType = pin->GetType();
1551  item->m_PinNum = pin->GetNumber();
1552  item->m_Label = pin->GetName();
1553  item->m_Start = item->m_End = pos;
1554 
1555  aNetListItems.push_back( item );
1556 
1557  if( pin->IsPowerConnection() )
1558  {
1559  // There is an associated PIN_LABEL.
1560  item = new NETLIST_OBJECT();
1561  item->m_SheetPathInclude = *aSheetPath;
1562  item->m_Comp = m_pins[ m_pinMap.at( pin ) ].get();
1563  item->m_SheetPath = *aSheetPath;
1565  item->m_Label = pin->GetName();
1566  item->m_Start = pos;
1567  item->m_End = item->m_Start;
1568 
1569  aNetListItems.push_back( item );
1570  }
1571  }
1572 }
1573 
1574 
1575 bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
1576 {
1577  if( Type() != aItem.Type() )
1578  return Type() < aItem.Type();
1579 
1580  auto component = static_cast<const SCH_COMPONENT*>( &aItem );
1581 
1582  EDA_RECT rect = GetBodyBoundingBox();
1583 
1584  if( rect.GetArea() != component->GetBodyBoundingBox().GetArea() )
1585  return rect.GetArea() < component->GetBodyBoundingBox().GetArea();
1586 
1587  if( m_Pos.x != component->m_Pos.x )
1588  return m_Pos.x < component->m_Pos.x;
1589 
1590  if( m_Pos.y != component->m_Pos.y )
1591  return m_Pos.y < component->m_Pos.y;
1592 
1593  return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
1594 }
1595 
1596 
1597 bool SCH_COMPONENT::operator==( const SCH_COMPONENT& aComponent ) const
1598 {
1599  if( GetFieldCount() != aComponent.GetFieldCount() )
1600  return false;
1601 
1602  for( int i = VALUE; i < GetFieldCount(); i++ )
1603  {
1604  if( GetField( i )->GetText().Cmp( aComponent.GetField( i )->GetText() ) != 0 )
1605  return false;
1606  }
1607 
1608  return true;
1609 }
1610 
1611 
1612 bool SCH_COMPONENT::operator!=( const SCH_COMPONENT& aComponent ) const
1613 {
1614  return !( *this == aComponent );
1615 }
1616 
1617 
1619 {
1620  wxCHECK_MSG( Type() == aItem.Type(), *this,
1621  wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
1622  GetClass() );
1623 
1624  if( &aItem != this )
1625  {
1626  SCH_ITEM::operator=( aItem );
1627 
1628  SCH_COMPONENT* c = (SCH_COMPONENT*) &aItem;
1629 
1630  m_lib_id = c->m_lib_id;
1631 
1632  LIB_PART* libSymbol = c->m_part ? new LIB_PART( *c->m_part.get() ) : nullptr;
1633 
1634  m_part.reset( libSymbol );
1635  m_Pos = c->m_Pos;
1636  m_unit = c->m_unit;
1637  m_convert = c->m_convert;
1638  m_transform = c->m_transform;
1639 
1641 
1642  m_Fields = c->m_Fields; // std::vector's assignment operator
1643 
1644  // Reparent fields after assignment to new component.
1645  for( SCH_FIELD& field : m_Fields )
1646  field.SetParent( this );
1647 
1648  UpdatePins();
1649  }
1650 
1651  return *this;
1652 }
1653 
1654 
1655 bool SCH_COMPONENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1656 {
1657  EDA_RECT bBox = GetBodyBoundingBox();
1658  bBox.Inflate( aAccuracy );
1659 
1660  if( bBox.Contains( aPosition ) )
1661  return true;
1662 
1663  return false;
1664 }
1665 
1666 
1667 bool SCH_COMPONENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1668 {
1670  return false;
1671 
1672  EDA_RECT rect = aRect;
1673 
1674  rect.Inflate( aAccuracy );
1675 
1676  if( aContained )
1677  return rect.Contains( GetBodyBoundingBox() );
1678 
1679  return rect.Intersects( GetBodyBoundingBox() );
1680 }
1681 
1682 
1683 bool SCH_COMPONENT::doIsConnected( const wxPoint& aPosition ) const
1684 {
1685  wxPoint new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_Pos );
1686 
1687  for( const auto& pin : m_pins )
1688  {
1689  // Collect only pins attached to the current unit and convert.
1690  // others are not associated to this component instance
1691  int pin_unit = pin->GetLibPin()->GetUnit();
1692  int pin_convert = pin->GetLibPin()->GetConvert();
1693 
1694  if( pin_unit > 0 && pin_unit != GetUnit() )
1695  continue;
1696 
1697  if( pin_convert > 0 && pin_convert != GetConvert() )
1698  continue;
1699 
1700  if( pin->GetLocalPosition() == new_pos )
1701  return true;
1702  }
1703 
1704  return false;
1705 }
1706 
1707 
1709 {
1710  return m_isInNetlist;
1711 }
1712 
1713 
1714 void SCH_COMPONENT::Plot( PLOTTER* aPlotter )
1715 {
1716  if( m_part )
1717  {
1718  TRANSFORM temp = GetTransform();
1719  aPlotter->StartBlock( nullptr );
1720 
1721  m_part->Plot( aPlotter, GetUnit(), GetConvert(), m_Pos, temp );
1722 
1723  for( SCH_FIELD field : m_Fields )
1724  field.Plot( aPlotter );
1725 
1726  aPlotter->EndBlock( nullptr );
1727  }
1728 }
1729 
1730 
1732 {
1733  for( const auto& pin : m_pins )
1734  {
1735  if( pin->IsBrightened() )
1736  return true;
1737  }
1738 
1739  return false;
1740 }
1741 
1742 
1744 {
1745  for( auto& pin : m_pins )
1746  pin->ClearBrightened();
1747 }
1748 
1749 
1751 {
1752  if( m_pinMap.count( aPin ) )
1753  m_pins[ m_pinMap.at( aPin ) ]->SetBrightened();
1754 }
1755 
1756 
bool operator!=(const SCH_COMPONENT &aComponent) const
void UpdateFields(bool aResetStyle, bool aResetRef=false)
Restores fields to the original library values.
EDA_UNITS
Definition: common.h:198
bool ReplaceInstanceSheetPath(const KIID_PATH &aOldSheetPath, const KIID_PATH &aNewSheetPath)
Replace aOldSheetPath with aNewSheetPath in the instance list.
void Offset(int dx, int dy)
Definition: eda_rect.h:157
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
SCH_LAYER_ID m_Layer
Definition: sch_item.h:192
const wxChar *const traceSchSheetPaths
Flag to enable debug output of schematic symbol sheet path manipulation code.
std::vector< SCH_PIN * > SCH_PIN_PTRS
Definition: sch_component.h:71
void SetModified()
Definition: base_struct.cpp:87
void Rotate(wxPoint aPosition) override
Rotate the item around aPosition 90 degrees in the clockwise direction.
SCH_FIELD * FindField(const wxString &aFieldName, bool aIncludeDefaultFields=true)
Search for a SCH_FIELD with aFieldName.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
EDA_ITEM * m_Parent
Linked list: Link (parent struct)
Definition: base_struct.h:174
void SetLibSymbol(LIB_PART *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
void SetLibId(const LIB_ID &aName)
void Plot(PLOTTER *aPlotter) override
Plot the schematic item to aPlotter.
name of datasheet
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect.
void SetTransform(const TRANSFORM &aTransform)
virtual void EndBlock(void *aData)
calling this function allows one to define the end of a group of drawing items for instance in SVG or...
Definition: plotter.h:486
PNG memory record (file in memory).
Definition: bitmap_def.h:29
void UpdateUnit(int aUnit)
Change the unit number to aUnit without setting any internal flags.
int GetOrientation()
Get the display symbol orientation.
int y2
Definition: transform.h:51
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
bool Matches(wxFindReplaceData &aSearchData, void *aAuxData) override
Function Matches compares the item against the search criteria in aSearchData.
SCH_PINS m_pins
a SCH_PIN for every LIB_PIN (across all units)
SCH_SHEET_PATH m_SheetPathInclude
bool operator==(const SCH_COMPONENT &aComponent) const
Define a symbol library graphical text item.
Definition: lib_text.h:40
int GetX() const
Definition: eda_rect.h:111
SCH_FIELDS m_Fields
Variable length list of fields.
void ImportValues(const LIB_FIELD &aSource)
Function ImportValues copy parameters from a LIB_FIELD source.
Definition: sch_field.cpp:215
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: base_struct.h:128
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
wxPoint m_Pos
Name and library where symbol was loaded from, i.e. "74xx:74LS00".
Definition: sch_component.h:94
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
Field object used in symbol libraries.
Definition: lib_field.h:59
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Add all the connection points for this item to aPoints.
wxString GetSchSymbolLibraryName() const
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
TRANSFORM InverseTransform() const
Calculate the Inverse mirror/rotation transform.
Definition: transform.cpp:59
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:246
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:116
bool m_onBoard
True to include in netlist when updating board.
int GetUnitCount() const
Return the number of units per package of the symbol.
double square(double x)
int x2
Definition: transform.h:50
void MirrorX(int aXaxis_position) override
Mirror item relative to the X axis about aXaxis_position.
bool IsInNetlist() const
Definition: color4d.h:61
virtual void StartBlock(void *aData)
calling this function allows one to define the beginning of a group of drawing items,...
Definition: plotter.h:477
void ClearBrightenedPins()
std::vector< COMPONENT_INSTANCE_REFERENCE > m_instanceReferences
wxString AsString() const
Definition: common.cpp:165
const BITMAP_OPAQUE add_component_xpm[1]
LIB_PIN * GetPin(const wxString &number)
Find a symbol pin by number.
int x1
Definition: transform.h:48
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
wxString GetDescription() const
Return information about the aliased parts.
Schematic editor (Eeschema) main window.
SCH_SHEET_PATH m_SheetPath
LIB_ITEM * GetDrawItem(const wxPoint &aPosition, KICAD_T aType=TYPE_NOT_INIT)
Return the component library item at aPosition that is part of this component.
ELECTRICAL_PINTYPE m_ElectricalPinType
void SwapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
The base class for create windows for drawing purpose.
EDA_ITEM * m_Comp
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
bool Contains(const wxPoint &aPoint) const
Function Contains.
FIELDS_AUTOPLACED m_fieldsAutoplaced
Definition: sch_item.h:194
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_field.cpp:102
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
wxPoint TransformCoordinate(const wxPoint &aPoint) const
Calculate a new coordinate according to the mirror/rotation transform.
Definition: transform.cpp:42
The base class for drawable items used by schematic library components.
Definition: lib_item.h:61
int GetBottom() const
Definition: eda_rect.h:124
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
NETLIST_OBJECT_LIST is a container holding and owning NETLIST_OBJECTs, which are connected items in a...
void SetConvert(int aConvert)
void AddDrawItem(LIB_ITEM *aItem)
Add a new draw aItem to the draw object list.
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:105
int y1
Definition: transform.h:49
void MIRROR(T &aPoint, const T &aMirrorRef)
Definition: macros.h:175
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
Definition: sch_field.cpp:436
int GetUnit() const
Definition: lib_item.h:295
int GetUnit() const
void BrightenPin(LIB_PIN *aPin)
for transforming drawing coordinates for a wxDC device context.
Definition: transform.h:45
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:116
wxString m_schLibSymbolName
The name used to look up a symbol in the symbol library embedded in a schematic.
#define NULL
bool m_isInNetlist
True if the component should appear in the netlist.
void SetHeight(int val)
Definition: eda_rect.h:186
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:237
TRANSFORM & GetTransform() const
Subclass of DIALOG_SCH_FIND_BASE, which is generated by wxFormBuilder.
A simple container for schematic symbol instance infromation.
EDA_RECT GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the fields.
std::vector< SCH_FIELD > & GetFields()
Returns a vector of fields from the component.
bool operator<(const SCH_ITEM &aItem) const override
wxString GetText(GRAPHIC_PINSHAPE aShape)
Definition: pin_shape.cpp:58
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
SCH_COMPONENT(const wxPoint &pos=wxPoint(0, 0), SCH_ITEM *aParent=NULL)
int GetRight() const
Definition: eda_rect.h:121
std::string toUTFTildaText(const wxString &txt)
Convert a wxString to UTF8 and replace any control characters with a ~, where a control character is ...
Define a library symbol object.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
#define STRUCT_DELETED
flag indication structures to be erased
Definition: base_struct.h:126
void GetNetListItem(NETLIST_OBJECT_LIST &aNetListItems, SCH_SHEET_PATH *aSheetPath) override
Create a new NETLIST_OBJECT for the schematic object and adds it to aNetListItems.
SCH_CONNECTION * GetConnectionForPin(LIB_PIN *aPin, const SCH_SHEET_PATH &aSheet)
Retrieves the connection for a given pin of the component.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
wxString GetDatasheet() const
Return the documentation text for the given part alias.
void SetX(int val)
Definition: eda_rect.h:168
wxLogTrace helper definitions.
bool IsAnnotated(const SCH_SHEET_PATH *aSheet)
Checks if the component has a valid annotation (reference) for the given sheet path.
void SetUnit(int aUnit)
Change the unit number to aUnit.
SCH_SHEET_PATH.
std::unique_ptr< LIB_PART > m_part
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false)
Return the reference for the given sheet path.
double GetArea() const
Function GetArea returns the area of the rectangle.
std::unique_ptr< LIB_PART > Flatten() const
Return a flattened symbol inheritance to the caller.
void ClearAnnotation(SCH_SHEET_PATH *aSheetPath)
Clear exiting component annotation.
void SetWidth(int val)
Definition: eda_rect.h:180
void GetContextualTextVars(wxArrayString *aVars) const
Return the list of system text vars & fields for this symbol.
Definition: color4d.h:59
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Operator assignment is used to assign the members of aItem to another object.
int GetFieldCount() const
Return the number of fields in this symbol.
UTF8 Format() const
Definition: lib_id.cpp:237
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:150
void SetY(int val)
Definition: eda_rect.h:174
const KIID m_Uuid
Definition: base_struct.h:162
wxPoint GetPosition() const override
Definition: lib_pin.h:430
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
void Normalize()
Function Normalize ensures that the height ant width are positive.
int m_unit
The unit for multiple part per package components.
Definition: sch_component.h:99
Field Value of part, i.e. "3.3K".
void Init(const wxPoint &pos=wxPoint(0, 0))
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
Base plotter engine class.
Definition: plotter.h:114
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
void Print(RENDER_SETTINGS *aSettings, const wxPoint &aOffset) override
Print a component.
wxString GetFieldText(const wxString &aFieldName, SCH_EDIT_FRAME *aFrame) const
Search for a field named aFieldName and returns text associated with this field.
void GetPins(std::vector< LIB_PIN * > &aPinsList)
Populate a vector with all the pins from the library object.
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
const wxChar *const traceFindItem
Flag to enable find debug tracing.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
#define _(s)
Definition: 3d_actions.cpp:33
SCH_PIN_MAP m_pinMap
the component's pins mapped by LIB_PIN*
void MirrorY(int aYaxis_position) override
Mirror item relative to the Y axis about aYaxis_position.
bool HasBrightenedPins()
std::vector< LIB_FIELD > LIB_FIELDS
Definition: lib_field.h:218
STATUS_FLAGS m_Flags
Definition: base_struct.h:176
wxString AsString() const
Definition: common.h:137
wxString wx_str() const
Definition: utf8.cpp:51
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
static wxString SubReference(int aUnit, bool aAddSeparator=true)
Schematic symbol object.
Definition: sch_component.h:88
int GetY() const
Definition: eda_rect.h:112
void RemoveField(const wxString &aFieldName)
Removes a user field from the symbol.
bool IsRoot() const override
For symbols derived from other symbols, IsRoot() indicates no derivation.
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
bool m_inBom
True to include in bill of materials export.
#define TO_UTF8(wxstring)
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemList, const SCH_SHEET_PATH *aPath=nullptr) override
Test if the component's dangling state has changed for all pins.
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:102
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
Function Visit may be re-implemented for each derived class in order to handle all the types given by...
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
virtual wxString GetClass() const override
Function GetClass returns the class name.
Definition: sch_item.h:214
const wxPoint & GetTextPos() const
Definition: eda_text.h:247
SCH_SHEET_PATH & GetCurrentSheet() const
T Convert(const wxString &aValue)
Function Convert converts a wxString to a generic type T.
Definition: eagle_parser.h:175
std::vector< std::pair< int, wxString > > Fields
Definition: sch_screen.h:86
int GetConvert() const
void Print(RENDER_SETTINGS *aSettings, const wxPoint &aOffset, int aMulti, int aConvert, const PART_DRAW_OPTIONS &aOpts)
Print part.
int m_convert
The alternate body style for components that have more than one body style defined.
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition: sch_item.h:85
void AddHierarchicalReference(const KIID_PATH &aPath, const wxString &aRef, int aUnit)
Add a full hierarchical reference to this symbol.
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
SEARCH_RESULT
Definition: base_struct.h:51
static bool IsReferenceStringValid(const wxString &aReferenceString)
Tests for an acceptable reference string.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
void ViewGetLayers(int aLayers[], int &aCount) const override
Function ViewGetLayers() Returns the all the layers within the VIEW the object is painted on.
wxString GetClass() const override
Function GetClass returns the class name.
Definition of the NETLIST_OBJECT class.
Message panel definition file.
wxString m_prefix
C, R, U, Q etc - the first character which typically indicates what the component is.
const LIB_ID & GetLibId() const
NETLIST_ITEM m_Type
SCH_COMPONENT & operator=(const SCH_ITEM &aItem)
const EDA_RECT GetBodyBoundingBox(int aUnit, int aConvert) const
Get the symbol bounding box excluding fields.
SCH_ITEM * m_Link
wxPoint GetPinPhysicalPosition(const LIB_PIN *Pin) const
TRANSFORM m_transform
The rotation/mirror transformation matrix.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:187
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126
bool AddSheetPathReferenceEntryIfMissing(const KIID_PATH &aSheetPath)
Add an instance to the alternate references list (m_instanceReferences), if this entry does not alrea...
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
SCH_PIN_PTRS GetSchPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieves a list of the SCH_PINs for the given sheet path.
bool doIsConnected(const wxPoint &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
bool empty() const
Definition: utf8.h:108
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:122
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...