You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1903 lines
54 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
18 years ago
18 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 1992-2011 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. * @file sch_component.cpp
  26. * @brief Implementation of the class SCH_COMPONENT.
  27. */
  28. #include <fctsys.h>
  29. #include <appl_wxstruct.h>
  30. #include <class_drawpanel.h>
  31. #include <gr_basic.h>
  32. #include <trigo.h>
  33. #include <kicad_string.h>
  34. #include <richio.h>
  35. #include <wxEeschemaStruct.h>
  36. #include <plot_common.h>
  37. #include <general.h>
  38. #include <class_library.h>
  39. #include <lib_rectangle.h>
  40. #include <lib_pin.h>
  41. #include <lib_text.h>
  42. #include <sch_component.h>
  43. #include <sch_sheet.h>
  44. #include <sch_sheet_path.h>
  45. #include <class_netlist_object.h>
  46. #include <dialogs/dialog_schematic_find.h>
  47. #include <wx/tokenzr.h>
  48. #define NULL_STRING "_NONAME_"
  49. static LIB_COMPONENT* DummyCmp;
  50. /**
  51. * Function toUTFTildaText
  52. * convert a wxString to UTF8 and replace any control characters with a ~,
  53. * where a control character is one of the first ASCII values up to ' ' 32d.
  54. */
  55. std::string toUTFTildaText( const wxString& txt )
  56. {
  57. std::string ret = TO_UTF8( txt );
  58. for( std::string::iterator it = ret.begin(); it!=ret.end(); ++it )
  59. {
  60. if( (unsigned char) *it <= ' ' )
  61. *it = '~';
  62. /*
  63. #if defined(KICAD_GOST)
  64. if( *it == ' ' )
  65. #else
  66. if( (unsigned char) *it <= ' ' )
  67. #endif
  68. *it = '~';
  69. */
  70. }
  71. return ret;
  72. }
  73. /* Descr component <DUMMY> used when a component is not found in library,
  74. * to draw a dummy shape
  75. * This component is a 400 mils square with the text ??
  76. * DEF DUMMY U 0 40 Y Y 1 0 N
  77. * F0 "U" 0 -350 60 H V
  78. * F1 "DUMMY" 0 350 60 H V
  79. * DRAW
  80. * T 0 0 0 150 0 0 0 ??
  81. * S -200 200 200 -200 0 1 0
  82. * ENDDRAW
  83. * ENDDEF
  84. */
  85. void CreateDummyCmp()
  86. {
  87. DummyCmp = new LIB_COMPONENT( wxEmptyString );
  88. LIB_RECTANGLE* Square = new LIB_RECTANGLE( DummyCmp );
  89. Square->Move( wxPoint( -200, 200 ) );
  90. Square->SetEndPosition( wxPoint( 200, -200 ) );
  91. LIB_TEXT* Text = new LIB_TEXT( DummyCmp );
  92. Text->m_Size.x = Text->m_Size.y = 150;
  93. Text->m_Text = wxT( "??" );
  94. DummyCmp->AddDrawItem( Square );
  95. DummyCmp->AddDrawItem( Text );
  96. }
  97. SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos, SCH_ITEM* aParent ) :
  98. SCH_ITEM( aParent, SCH_COMPONENT_T )
  99. {
  100. Init( aPos );
  101. }
  102. SCH_COMPONENT::SCH_COMPONENT( LIB_COMPONENT& libComponent, SCH_SHEET_PATH* sheet, int unit,
  103. int convert, const wxPoint& pos, bool setNewItemFlag ) :
  104. SCH_ITEM( NULL, SCH_COMPONENT_T )
  105. {
  106. Init( pos );
  107. m_unit = unit;
  108. m_convert = convert;
  109. m_ChipName = libComponent.GetName();
  110. SetTimeStamp( GetNewTimeStamp() );
  111. if( setNewItemFlag )
  112. m_Flags = IS_NEW | IS_MOVED;
  113. // Import user defined fields from the library component:
  114. LIB_FIELDS libFields;
  115. libComponent.GetFields( libFields );
  116. for( LIB_FIELDS::iterator it = libFields.begin(); it!=libFields.end(); ++it )
  117. {
  118. // Can no longer insert an empty name, since names are now keys. The
  119. // field index is not used beyond the first MANDATORY_FIELDS
  120. if( it->GetName().IsEmpty() )
  121. continue;
  122. // See if field by same name already exists.
  123. SCH_FIELD* schField = FindField( it->GetName() );
  124. if( !schField )
  125. {
  126. SCH_FIELD fld( wxPoint( 0, 0 ), GetFieldCount(), this, it->GetName() );
  127. schField = AddField( fld );
  128. }
  129. schField->m_Pos = m_Pos + it->m_Pos;
  130. schField->ImportValues( *it );
  131. schField->m_Text = it->m_Text;
  132. }
  133. wxString msg = libComponent.GetReferenceField().m_Text;
  134. if( msg.IsEmpty() )
  135. msg = wxT( "U" );
  136. m_prefix = msg;
  137. // update the reference -- just the prefix for now.
  138. msg += wxT( "?" );
  139. SetRef( sheet, msg );
  140. /* Use the schematic component name instead of the library value field
  141. * name.
  142. */
  143. GetField( VALUE )->m_Text = m_ChipName;
  144. }
  145. SCH_COMPONENT::SCH_COMPONENT( const SCH_COMPONENT& aComponent ) :
  146. SCH_ITEM( aComponent )
  147. {
  148. m_Parent = aComponent.m_Parent;
  149. m_Pos = aComponent.m_Pos;
  150. m_unit = aComponent.m_unit;
  151. m_convert = aComponent.m_convert;
  152. m_ChipName = aComponent.m_ChipName;
  153. SetTimeStamp( aComponent.m_TimeStamp );
  154. m_transform = aComponent.m_transform;
  155. m_prefix = aComponent.m_prefix;
  156. m_PathsAndReferences = aComponent.m_PathsAndReferences;
  157. m_Fields = aComponent.m_Fields;
  158. // Re-parent the fields, which before this had aComponent as parent
  159. for( int i = 0; i<GetFieldCount(); ++i )
  160. {
  161. GetField( i )->SetParent( this );
  162. }
  163. }
  164. void SCH_COMPONENT::Init( const wxPoint& pos )
  165. {
  166. m_Pos = pos;
  167. m_unit = 0; // In multi unit chip - which unit to draw.
  168. m_convert = 0; // De Morgan Handling
  169. // The rotation/mirror transformation matrix. pos normal
  170. m_transform = TRANSFORM();
  171. // construct only the mandatory fields, which are the first 4 only.
  172. for( int i = 0; i < MANDATORY_FIELDS; ++i )
  173. {
  174. SCH_FIELD field( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) );
  175. if( i==REFERENCE )
  176. field.SetLayer( LAYER_REFERENCEPART );
  177. else if( i==VALUE )
  178. field.SetLayer( LAYER_VALUEPART );
  179. // else keep LAYER_FIELDS from SCH_FIELD constructor
  180. // SCH_FIELD's implicitly created copy constructor is called in here
  181. AddField( field );
  182. }
  183. m_prefix = wxString( _( "U" ) );
  184. }
  185. EDA_ITEM* SCH_COMPONENT::Clone() const
  186. {
  187. return new SCH_COMPONENT( *this );
  188. }
  189. void SCH_COMPONENT::SetLibName( const wxString& aName )
  190. {
  191. if( m_ChipName != aName )
  192. {
  193. m_ChipName = aName;
  194. SetModified();
  195. }
  196. }
  197. void SCH_COMPONENT::SetUnit( int aUnit )
  198. {
  199. if( m_unit != aUnit )
  200. {
  201. m_unit = aUnit;
  202. SetModified();
  203. }
  204. }
  205. void SCH_COMPONENT::SetConvert( int aConvert )
  206. {
  207. if( m_convert != aConvert )
  208. {
  209. m_convert = aConvert;
  210. SetModified();
  211. }
  212. }
  213. void SCH_COMPONENT::SetTransform( const TRANSFORM& aTransform )
  214. {
  215. if( m_transform != aTransform )
  216. {
  217. m_transform = aTransform;
  218. SetModified();
  219. }
  220. }
  221. int SCH_COMPONENT::GetPartCount() const
  222. {
  223. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  224. if( Entry == NULL )
  225. return 0;
  226. return Entry->GetPartCount();
  227. }
  228. void SCH_COMPONENT::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset,
  229. GR_DRAWMODE DrawMode, EDA_COLOR_T Color, bool DrawPinText )
  230. {
  231. bool dummy = false;
  232. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  233. if( Entry == NULL )
  234. {
  235. /* Create a dummy component if the actual component can not be found. */
  236. dummy = true;
  237. if( DummyCmp == NULL )
  238. CreateDummyCmp();
  239. Entry = DummyCmp;
  240. }
  241. Entry->Draw( panel, DC, m_Pos + offset, dummy ? 0 : m_unit, dummy ? 0 : m_convert,
  242. DrawMode, Color, m_transform, DrawPinText, false );
  243. SCH_FIELD* field = GetField( REFERENCE );
  244. if( field->IsVisible() && !field->IsMoving() )
  245. {
  246. field->Draw( panel, DC, offset, DrawMode );
  247. }
  248. for( int ii = VALUE; ii < GetFieldCount(); ii++ )
  249. {
  250. field = GetField( ii );
  251. if( field->IsMoving() )
  252. continue;
  253. field->Draw( panel, DC, offset, DrawMode );
  254. }
  255. #if 0
  256. /* Draw the component boundary box */
  257. {
  258. EDA_RECT BoundaryBox;
  259. BoundaryBox = GetBoundingBox();
  260. GRRect( panel->GetClipBox(), DC, BoundaryBox, 0, BROWN );
  261. #if 1
  262. if( GetField( REFERENCE )->IsVisible() )
  263. {
  264. BoundaryBox = GetField( REFERENCE )->GetBoundingBox();
  265. GRRect( panel->GetClipBox(), DC, BoundaryBox, 0, BROWN );
  266. }
  267. if( GetField( VALUE )->IsVisible() )
  268. {
  269. BoundaryBox = GetField( VALUE )->GetBoundingBox();
  270. GRRect( panel->GetClipBox(), DC, BoundaryBox, 0, BROWN );
  271. }
  272. #endif
  273. }
  274. #endif
  275. }
  276. void SCH_COMPONENT::AddHierarchicalReference( const wxString& aPath,
  277. const wxString& aRef,
  278. int aMulti )
  279. {
  280. wxString h_path, h_ref;
  281. wxStringTokenizer tokenizer;
  282. wxString separators( wxT( " " ) );
  283. // Search for an existing path and remove it if found (should not occur)
  284. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  285. {
  286. tokenizer.SetString( m_PathsAndReferences[ii], separators );
  287. h_path = tokenizer.GetNextToken();
  288. if( h_path.Cmp( aPath ) == 0 )
  289. {
  290. m_PathsAndReferences.RemoveAt( ii );
  291. ii--;
  292. }
  293. }
  294. h_ref = aPath + wxT( " " ) + aRef;
  295. h_ref << wxT( " " ) << aMulti;
  296. m_PathsAndReferences.Add( h_ref );
  297. }
  298. wxString SCH_COMPONENT::GetPath( const SCH_SHEET_PATH* sheet ) const
  299. {
  300. wxCHECK_MSG( sheet != NULL, wxEmptyString,
  301. wxT( "Cannot get component path with invalid sheet object." ) );
  302. wxString str;
  303. str.Printf( wxT( "%8.8lX" ), m_TimeStamp );
  304. return sheet->Path() + str;
  305. }
  306. const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet )
  307. {
  308. wxString path = GetPath( sheet );
  309. wxString h_path, h_ref;
  310. wxStringTokenizer tokenizer;
  311. wxString separators( wxT( " " ) );
  312. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  313. {
  314. tokenizer.SetString( m_PathsAndReferences[ii], separators );
  315. h_path = tokenizer.GetNextToken();
  316. if( h_path.Cmp( path ) == 0 )
  317. {
  318. h_ref = tokenizer.GetNextToken();
  319. /* printf( "GetRef hpath: %s\n",
  320. * TO_UTF8( m_PathsAndReferences[ii] ) ); */
  321. return h_ref;
  322. }
  323. }
  324. // if it was not found in m_Paths array, then see if it is in
  325. // m_Field[REFERENCE] -- if so, use this as a default for this path.
  326. // this will happen if we load a version 1 schematic file.
  327. // it will also mean that multiple instances of the same sheet by default
  328. // all have the same component references, but perhaps this is best.
  329. if( !GetField( REFERENCE )->m_Text.IsEmpty() )
  330. {
  331. SetRef( sheet, GetField( REFERENCE )->m_Text );
  332. return GetField( REFERENCE )->m_Text;
  333. }
  334. return m_prefix;
  335. }
  336. /* Function IsReferenceStringValid (static function)
  337. * Tests for an acceptable reference string
  338. * An acceptable reference string must support unannotation
  339. * i.e starts by letter
  340. * returns true if OK
  341. */
  342. bool SCH_COMPONENT::IsReferenceStringValid( const wxString& aReferenceString )
  343. {
  344. wxString text = aReferenceString;
  345. bool ok = true;
  346. // Try to unannotate this reference
  347. while( !text.IsEmpty() && ( text.Last() == '?' || isdigit( text.Last() ) ) )
  348. text.RemoveLast();
  349. if( text.IsEmpty() )
  350. ok = false;
  351. // Add here other constraints
  352. // Currently:no other constraint
  353. return ok;
  354. }
  355. void SCH_COMPONENT::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
  356. {
  357. wxString path = GetPath( sheet );
  358. bool notInArray = true;
  359. wxString h_path, h_ref;
  360. wxStringTokenizer tokenizer;
  361. wxString separators( wxT( " " ) );
  362. // check to see if it is already there before inserting it
  363. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  364. {
  365. tokenizer.SetString( m_PathsAndReferences[ii], separators );
  366. h_path = tokenizer.GetNextToken();
  367. if( h_path.Cmp( path ) == 0 )
  368. {
  369. // just update the reference text, not the timestamp.
  370. h_ref = h_path + wxT( " " ) + ref;
  371. h_ref += wxT( " " );
  372. tokenizer.GetNextToken(); // Skip old reference
  373. h_ref += tokenizer.GetNextToken(); // Add part selection
  374. // Ann the part selection
  375. m_PathsAndReferences[ii] = h_ref;
  376. notInArray = false;
  377. }
  378. }
  379. if( notInArray )
  380. AddHierarchicalReference( path, ref, m_unit );
  381. SCH_FIELD* rf = GetField( REFERENCE );
  382. if( rf->m_Text.IsEmpty()
  383. || ( abs( rf->m_Pos.x - m_Pos.x ) +
  384. abs( rf->m_Pos.y - m_Pos.y ) > 10000 ) )
  385. {
  386. // move it to a reasonable position
  387. rf->m_Pos = m_Pos;
  388. rf->m_Pos.x += 50; // a slight offset
  389. rf->m_Pos.y += 50;
  390. }
  391. rf->m_Text = ref; // for drawing.
  392. // Reinit the m_prefix member if needed
  393. wxString prefix = ref;
  394. if( IsReferenceStringValid( prefix ) )
  395. {
  396. while( prefix.Last() == '?' || isdigit( prefix.Last() ) )
  397. prefix.RemoveLast();
  398. }
  399. else
  400. {
  401. prefix = wxT( "U" ); // Set to default ref prefix
  402. }
  403. if( m_prefix != prefix )
  404. m_prefix = prefix;
  405. }
  406. void SCH_COMPONENT::SetTimeStamp( long aNewTimeStamp )
  407. {
  408. wxString string_timestamp, string_oldtimestamp;
  409. string_timestamp.Printf( wxT( "%08lX" ), aNewTimeStamp );
  410. string_oldtimestamp.Printf( wxT( "%08lX" ), m_TimeStamp );
  411. EDA_ITEM::SetTimeStamp( aNewTimeStamp );
  412. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  413. {
  414. m_PathsAndReferences[ii].Replace( string_oldtimestamp.GetData(),
  415. string_timestamp.GetData() );
  416. }
  417. }
  418. int SCH_COMPONENT::GetUnitSelection( SCH_SHEET_PATH* aSheet )
  419. {
  420. wxString path = GetPath( aSheet );
  421. wxString h_path, h_multi;
  422. wxStringTokenizer tokenizer;
  423. wxString separators( wxT( " " ) );
  424. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  425. {
  426. tokenizer.SetString( m_PathsAndReferences[ii], separators );
  427. h_path = tokenizer.GetNextToken();
  428. if( h_path.Cmp( path ) == 0 )
  429. {
  430. tokenizer.GetNextToken(); // Skip reference
  431. h_multi = tokenizer.GetNextToken();
  432. long imulti = 1;
  433. h_multi.ToLong( &imulti );
  434. return imulti;
  435. }
  436. }
  437. // if it was not found in m_Paths array, then use m_unit.
  438. // this will happen if we load a version 1 schematic file.
  439. return m_unit;
  440. }
  441. void SCH_COMPONENT::SetUnitSelection( SCH_SHEET_PATH* aSheet, int aUnitSelection )
  442. {
  443. wxString path = GetPath( aSheet );
  444. bool notInArray = true;
  445. wxString h_path, h_ref;
  446. wxStringTokenizer tokenizer;
  447. wxString separators( wxT( " " ) );
  448. //check to see if it is already there before inserting it
  449. for( unsigned ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  450. {
  451. tokenizer.SetString( m_PathsAndReferences[ii], separators );
  452. h_path = tokenizer.GetNextToken();
  453. if( h_path.Cmp( path ) == 0 )
  454. {
  455. //just update the unit selection.
  456. h_ref = h_path + wxT( " " );
  457. h_ref += tokenizer.GetNextToken(); // Add reference
  458. h_ref += wxT( " " );
  459. h_ref << aUnitSelection; // Add part selection
  460. // Ann the part selection
  461. m_PathsAndReferences[ii] = h_ref;
  462. notInArray = false;
  463. }
  464. }
  465. if( notInArray )
  466. AddHierarchicalReference( path, m_prefix, aUnitSelection );
  467. }
  468. SCH_FIELD* SCH_COMPONENT::GetField( int aFieldNdx ) const
  469. {
  470. const SCH_FIELD* field;
  471. if( (unsigned) aFieldNdx < m_Fields.size() )
  472. field = &m_Fields[aFieldNdx];
  473. else
  474. field = NULL;
  475. wxASSERT( field );
  476. // use cast to remove const-ness
  477. return (SCH_FIELD*) field;
  478. }
  479. SCH_FIELD* SCH_COMPONENT::AddField( const SCH_FIELD& aField )
  480. {
  481. int newNdx = m_Fields.size();
  482. m_Fields.push_back( aField );
  483. return &m_Fields[newNdx];
  484. }
  485. SCH_FIELD* SCH_COMPONENT::FindField( const wxString& aFieldName )
  486. {
  487. for( unsigned i = 0; i<m_Fields.size(); ++i )
  488. {
  489. if( aFieldName == m_Fields[i].GetName( false ) )
  490. return &m_Fields[i];
  491. }
  492. return NULL;
  493. }
  494. LIB_PIN* SCH_COMPONENT::GetPin( const wxString& number )
  495. {
  496. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  497. if( Entry == NULL )
  498. return NULL;
  499. return Entry->GetPin( number, m_unit, m_convert );
  500. }
  501. void SCH_COMPONENT::SwapData( SCH_ITEM* aItem )
  502. {
  503. wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T),
  504. wxT( "Cannot swap data with invalid component." ) );
  505. SCH_COMPONENT* component = (SCH_COMPONENT*) aItem;
  506. EXCHG( m_ChipName, component->m_ChipName );
  507. EXCHG( m_Pos, component->m_Pos );
  508. EXCHG( m_unit, component->m_unit );
  509. EXCHG( m_convert, component->m_convert );
  510. TRANSFORM tmp = m_transform;
  511. m_transform = component->m_transform;
  512. component->m_transform = tmp;
  513. m_Fields.swap( component->m_Fields ); // std::vector's swap()
  514. // Reparent items after copying data
  515. // (after swap(), m_Parent member does not point to the right parent):
  516. for( int ii = 0; ii < component->GetFieldCount(); ++ii )
  517. {
  518. component->GetField( ii )->SetParent( component );
  519. }
  520. for( int ii = 0; ii < GetFieldCount(); ++ii )
  521. {
  522. GetField( ii )->SetParent( this );
  523. }
  524. EXCHG( m_PathsAndReferences, component->m_PathsAndReferences );
  525. }
  526. void SCH_COMPONENT::ClearAnnotation( SCH_SHEET_PATH* aSheetPath )
  527. {
  528. bool keepMulti = false;
  529. LIB_COMPONENT* Entry;
  530. static const wxString separators( wxT( " " ) );
  531. wxArrayString reference_fields;
  532. Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  533. if( Entry && Entry->UnitsLocked() )
  534. keepMulti = true;
  535. // Build a reference with no annotation,
  536. // i.e. a reference ended by only one '?'
  537. wxString defRef = m_prefix;
  538. if( IsReferenceStringValid( defRef ) )
  539. {
  540. while( defRef.Last() == '?' )
  541. defRef.RemoveLast();
  542. }
  543. else
  544. { // This is a malformed reference: reinit this reference
  545. m_prefix = defRef = wxT("U"); // Set to default ref prefix
  546. }
  547. defRef.Append( wxT( "?" ) );
  548. wxString multi = wxT( "1" );
  549. // For components with units locked,
  550. // we cannot remove all annotations: part selection must be kept
  551. // For all components: if aSheetPath is not NULL,
  552. // remove annotation only for the given path
  553. if( keepMulti || aSheetPath )
  554. {
  555. wxString NewHref;
  556. wxString path;
  557. if( aSheetPath )
  558. path = GetPath( aSheetPath );
  559. for( unsigned int ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  560. {
  561. // Break hierarchical reference in path, ref and multi selection:
  562. reference_fields = wxStringTokenize( m_PathsAndReferences[ii], separators );
  563. if( aSheetPath == NULL || reference_fields[0].Cmp( path ) == 0 )
  564. {
  565. if( keepMulti ) // Get and keep part selection
  566. multi = reference_fields[2];
  567. NewHref = reference_fields[0];
  568. NewHref << wxT( " " ) << defRef << wxT( " " ) << multi;
  569. m_PathsAndReferences[ii] = NewHref;
  570. }
  571. }
  572. }
  573. else
  574. {
  575. // Clear reference strings, but does not free memory because a new annotation
  576. // will reuse it
  577. m_PathsAndReferences.Empty();
  578. m_unit = 1;
  579. }
  580. // These 2 changes do not work in complex hierarchy.
  581. // When a clear annotation is made, the calling function must call a
  582. // UpdateAllScreenReferences for the active sheet.
  583. // But this call cannot made here.
  584. m_Fields[REFERENCE].m_Text = defRef; //for drawing.
  585. SetModified();
  586. }
  587. void SCH_COMPONENT::SetOrientation( int aOrientation )
  588. {
  589. TRANSFORM temp = TRANSFORM();
  590. bool transform = false;
  591. switch( aOrientation )
  592. {
  593. case CMP_ORIENT_0:
  594. case CMP_NORMAL: // default transform matrix
  595. m_transform.x1 = 1;
  596. m_transform.y2 = -1;
  597. m_transform.x2 = m_transform.y1 = 0;
  598. break;
  599. case CMP_ROTATE_CLOCKWISE: // Rotate + (incremental rotation)
  600. temp.x1 = temp.y2 = 0;
  601. temp.y1 = 1;
  602. temp.x2 = -1;
  603. transform = true;
  604. break;
  605. case CMP_ROTATE_COUNTERCLOCKWISE: // Rotate - (incremental rotation)
  606. temp.x1 = temp.y2 = 0;
  607. temp.y1 = -1;
  608. temp.x2 = 1;
  609. transform = true;
  610. break;
  611. case CMP_MIRROR_Y: // Mirror Y (incremental rotation)
  612. temp.x1 = -1;
  613. temp.y2 = 1;
  614. temp.y1 = temp.x2 = 0;
  615. transform = true;
  616. break;
  617. case CMP_MIRROR_X: // Mirror X (incremental rotation)
  618. temp.x1 = 1;
  619. temp.y2 = -1;
  620. temp.y1 = temp.x2 = 0;
  621. transform = true;
  622. break;
  623. case CMP_ORIENT_90:
  624. SetOrientation( CMP_ORIENT_0 );
  625. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  626. break;
  627. case CMP_ORIENT_180:
  628. SetOrientation( CMP_ORIENT_0 );
  629. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  630. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  631. break;
  632. case CMP_ORIENT_270:
  633. SetOrientation( CMP_ORIENT_0 );
  634. SetOrientation( CMP_ROTATE_CLOCKWISE );
  635. break;
  636. case ( CMP_ORIENT_0 + CMP_MIRROR_X ):
  637. SetOrientation( CMP_ORIENT_0 );
  638. SetOrientation( CMP_MIRROR_X );
  639. break;
  640. case ( CMP_ORIENT_0 + CMP_MIRROR_Y ):
  641. SetOrientation( CMP_ORIENT_0 );
  642. SetOrientation( CMP_MIRROR_Y );
  643. break;
  644. case ( CMP_ORIENT_90 + CMP_MIRROR_X ):
  645. SetOrientation( CMP_ORIENT_90 );
  646. SetOrientation( CMP_MIRROR_X );
  647. break;
  648. case ( CMP_ORIENT_90 + CMP_MIRROR_Y ):
  649. SetOrientation( CMP_ORIENT_90 );
  650. SetOrientation( CMP_MIRROR_Y );
  651. break;
  652. case ( CMP_ORIENT_180 + CMP_MIRROR_X ):
  653. SetOrientation( CMP_ORIENT_180 );
  654. SetOrientation( CMP_MIRROR_X );
  655. break;
  656. case ( CMP_ORIENT_180 + CMP_MIRROR_Y ):
  657. SetOrientation( CMP_ORIENT_180 );
  658. SetOrientation( CMP_MIRROR_Y );
  659. break;
  660. case ( CMP_ORIENT_270 + CMP_MIRROR_X ):
  661. SetOrientation( CMP_ORIENT_270 );
  662. SetOrientation( CMP_MIRROR_X );
  663. break;
  664. case ( CMP_ORIENT_270 + CMP_MIRROR_Y ):
  665. SetOrientation( CMP_ORIENT_270 );
  666. SetOrientation( CMP_MIRROR_Y );
  667. break;
  668. default:
  669. transform = false;
  670. wxMessageBox( wxT( "SetRotateMiroir() error: ill value" ) );
  671. break;
  672. }
  673. if( transform )
  674. {
  675. /* The new matrix transform is the old matrix transform modified by the
  676. * requested transformation, which is the temp transform (rot,
  677. * mirror ..) in order to have (in term of matrix transform):
  678. * transform coord = new_m_transform * coord
  679. * where transform coord is the coord modified by new_m_transform from
  680. * the initial value coord.
  681. * new_m_transform is computed (from old_m_transform and temp) to
  682. * have:
  683. * transform coord = old_m_transform * temp
  684. */
  685. TRANSFORM newTransform;
  686. newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
  687. newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
  688. newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
  689. newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
  690. m_transform = newTransform;
  691. }
  692. }
  693. int SCH_COMPONENT::GetOrientation()
  694. {
  695. int type_rotate = CMP_ORIENT_0;
  696. TRANSFORM transform;
  697. int ii;
  698. #define ROTATE_VALUES_COUNT 12
  699. // list of all possibilities, but only the first 8 are actually used
  700. int rotate_value[ROTATE_VALUES_COUNT] =
  701. {
  702. CMP_ORIENT_0, CMP_ORIENT_90, CMP_ORIENT_180,
  703. CMP_ORIENT_270,
  704. CMP_MIRROR_X + CMP_ORIENT_0, CMP_MIRROR_X + CMP_ORIENT_90,
  705. CMP_MIRROR_X + CMP_ORIENT_180, CMP_MIRROR_X + CMP_ORIENT_270,
  706. CMP_MIRROR_Y + CMP_ORIENT_0, CMP_MIRROR_Y + CMP_ORIENT_90,
  707. CMP_MIRROR_Y + CMP_ORIENT_180, CMP_MIRROR_Y + CMP_ORIENT_270
  708. };
  709. // Try to find the current transform option:
  710. transform = m_transform;
  711. for( ii = 0; ii < ROTATE_VALUES_COUNT; ii++ )
  712. {
  713. type_rotate = rotate_value[ii];
  714. SetOrientation( type_rotate );
  715. if( transform == m_transform )
  716. return type_rotate;
  717. }
  718. // Error: orientation not found in list (should not happen)
  719. wxMessageBox( wxT( "Component orientation matrix internal error" ) );
  720. m_transform = transform;
  721. return CMP_NORMAL;
  722. }
  723. wxPoint SCH_COMPONENT::GetScreenCoord( const wxPoint& aPoint )
  724. {
  725. return m_transform.TransformCoordinate( aPoint );
  726. }
  727. #if defined(DEBUG)
  728. void SCH_COMPONENT::Show( int nestLevel, std::ostream& os ) const
  729. {
  730. // for now, make it look like XML:
  731. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
  732. << " ref=\"" << TO_UTF8( GetField( 0 )->GetName() )
  733. << '"' << " chipName=\""
  734. << TO_UTF8( m_ChipName ) << '"' << m_Pos
  735. << " layer=\"" << m_Layer
  736. << '"' << ">\n";
  737. // skip the reference, it's been output already.
  738. for( int i = 1; i < GetFieldCount(); ++i )
  739. {
  740. wxString value = GetField( i )->m_Text;
  741. if( !value.IsEmpty() )
  742. {
  743. NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
  744. << TO_UTF8( GetField( i )->GetName() )
  745. << '"' << " value=\""
  746. << TO_UTF8( value ) << "\"/>\n";
  747. }
  748. }
  749. NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
  750. }
  751. #endif
  752. bool SCH_COMPONENT::Save( FILE* f ) const
  753. {
  754. std::string name1;
  755. std::string name2;
  756. wxArrayString reference_fields;
  757. static wxString delimiters( wxT( " " ) );
  758. //this is redundant with the AR entries below, but it makes the
  759. //files backwards-compatible.
  760. if( m_PathsAndReferences.GetCount() > 0 )
  761. {
  762. reference_fields = wxStringTokenize( m_PathsAndReferences[0], delimiters );
  763. name1 = toUTFTildaText( reference_fields[1] );
  764. }
  765. else
  766. {
  767. if( GetField( REFERENCE )->m_Text.IsEmpty() )
  768. name1 = toUTFTildaText( m_prefix );
  769. else
  770. name1 = toUTFTildaText( GetField( REFERENCE )->m_Text );
  771. }
  772. if( !m_ChipName.IsEmpty() )
  773. {
  774. name2 = toUTFTildaText( m_ChipName );
  775. }
  776. else
  777. {
  778. name2 = NULL_STRING;
  779. }
  780. if( fprintf( f, "$Comp\n" ) == EOF )
  781. return false;
  782. if( fprintf( f, "L %s %s\n", name2.c_str(), name1.c_str() ) == EOF )
  783. return false;
  784. /* Generate unit number, convert and time stamp*/
  785. if( fprintf( f, "U %d %d %8.8lX\n", m_unit, m_convert, m_TimeStamp ) == EOF )
  786. return false;
  787. /* Save the position */
  788. if( fprintf( f, "P %d %d\n", m_Pos.x, m_Pos.y ) == EOF )
  789. return false;
  790. /* If this is a complex hierarchy; save hierarchical references.
  791. * but for simple hierarchies it is not necessary.
  792. * the reference inf is already saved
  793. * this is useful for old Eeschema version compatibility
  794. */
  795. if( m_PathsAndReferences.GetCount() > 1 )
  796. {
  797. for( unsigned int ii = 0; ii < m_PathsAndReferences.GetCount(); ii++ )
  798. {
  799. /*format:
  800. * AR Path="/140/2" Ref="C99" Part="1"
  801. * where 140 is the uid of the containing sheet
  802. * and 2 is the timestamp of this component.
  803. * (timestamps are actually 8 hex chars)
  804. * Ref is the conventional component reference for this 'path'
  805. * Part is the conventional component part selection for this 'path'
  806. */
  807. reference_fields = wxStringTokenize( m_PathsAndReferences[ii], delimiters );
  808. if( fprintf( f, "AR Path=\"%s\" Ref=\"%s\" Part=\"%s\" \n",
  809. TO_UTF8( reference_fields[0] ),
  810. TO_UTF8( reference_fields[1] ),
  811. TO_UTF8( reference_fields[2] ) ) == EOF )
  812. return false;
  813. }
  814. }
  815. // update the ugly field index, which I would like to see go away someday soon.
  816. for( unsigned i = 0; i<m_Fields.size(); ++i )
  817. {
  818. SCH_FIELD* fld = GetField( i );
  819. fld->SetId( i ); // we don't need field Ids, please be gone.
  820. }
  821. // Fixed fields:
  822. // Save fixed fields which are non blank.
  823. for( unsigned i = 0; i<MANDATORY_FIELDS; ++i )
  824. {
  825. SCH_FIELD* fld = GetField( i );
  826. if( !fld->m_Text.IsEmpty() )
  827. {
  828. if( !fld->Save( f ) )
  829. return false;
  830. }
  831. }
  832. // User defined fields:
  833. // The *policy* about which user defined fields are part of a symbol is now
  834. // only in the dialog editors. No policy should be enforced here, simply
  835. // save all the user defined fields, they are present because a dialog editor
  836. // thought they should be. If you disagree, go fix the dialog editors.
  837. for( unsigned i = MANDATORY_FIELDS; i<m_Fields.size(); ++i )
  838. {
  839. SCH_FIELD* fld = GetField( i );
  840. if( !fld->Save( f ) )
  841. return false;
  842. }
  843. /* Unit number, position, box ( old standard ) */
  844. if( fprintf( f, "\t%-4d %-4d %-4d\n", m_unit, m_Pos.x, m_Pos.y ) == EOF )
  845. return false;
  846. if( fprintf( f, "\t%-4d %-4d %-4d %-4d\n",
  847. m_transform.x1, m_transform.y1, m_transform.x2, m_transform.y2 ) == EOF )
  848. return false;
  849. if( fprintf( f, "$EndComp\n" ) == EOF )
  850. return false;
  851. return true;
  852. }
  853. bool SCH_COMPONENT::Load( LINE_READER& aLine, wxString& aErrorMsg )
  854. {
  855. int ii;
  856. char name1[256], name2[256],
  857. char1[256], char2[256], char3[256];
  858. int newfmt = 0;
  859. char* ptcar;
  860. wxString fieldName;
  861. char* line = aLine.Line();
  862. m_convert = 1;
  863. if( line[0] == '$' )
  864. {
  865. newfmt = 1;
  866. if( !aLine.ReadLine() )
  867. return true;
  868. line = aLine.Line();
  869. }
  870. if( sscanf( &line[1], "%s %s", name1, name2 ) != 2 )
  871. {
  872. aErrorMsg.Printf( wxT( "Eeschema component description error at line %d, aborted" ),
  873. aLine.LineNumber() );
  874. aErrorMsg << wxT( "\n" ) << FROM_UTF8( line );
  875. return false;
  876. }
  877. if( strcmp( name1, NULL_STRING ) != 0 )
  878. {
  879. for( ii = 0; ii < (int) strlen( name1 ); ii++ )
  880. {
  881. if( name1[ii] == '~' )
  882. name1[ii] = ' ';
  883. }
  884. m_ChipName = FROM_UTF8( name1 );
  885. if( !newfmt )
  886. GetField( VALUE )->m_Text = FROM_UTF8( name1 );
  887. }
  888. else
  889. {
  890. m_ChipName.Empty();
  891. GetField( VALUE )->m_Text.Empty();
  892. GetField( VALUE )->m_Orient = TEXT_ORIENT_HORIZ;
  893. GetField( VALUE )->m_Attributs = TEXT_NO_VISIBLE;
  894. }
  895. if( strcmp( name2, NULL_STRING ) != 0 )
  896. {
  897. bool isDigit = false;
  898. for( ii = 0; ii < (int) strlen( name2 ); ii++ )
  899. {
  900. if( name2[ii] == '~' )
  901. name2[ii] = ' ';
  902. // get RefBase from this, too. store in name1.
  903. if( name2[ii] >= '0' && name2[ii] <= '9' )
  904. {
  905. isDigit = true;
  906. name1[ii] = 0; //null-terminate.
  907. }
  908. if( !isDigit )
  909. {
  910. name1[ii] = name2[ii];
  911. }
  912. }
  913. name1[ii] = 0; //just in case
  914. int jj;
  915. for( jj = 0; jj<ii && name1[jj] == ' '; jj++ )
  916. ;
  917. if( jj == ii )
  918. {
  919. // blank string.
  920. m_prefix = wxT( "U" );
  921. }
  922. else
  923. {
  924. m_prefix = FROM_UTF8( &name1[jj] );
  925. //printf("prefix: %s\n", TO_UTF8(component->m_prefix));
  926. }
  927. if( !newfmt )
  928. GetField( REFERENCE )->m_Text = FROM_UTF8( name2 );
  929. }
  930. else
  931. {
  932. GetField( REFERENCE )->m_Attributs = TEXT_NO_VISIBLE;
  933. }
  934. /* Parse component description
  935. * These lines begin with:
  936. * "P" = Position
  937. * U = Num Unit and Conversion
  938. * "Fn" = Fields (0 .. n = = number of field)
  939. * "Ar" = Alternate reference in the case of multiple sheets referring to
  940. * one schematic file.
  941. */
  942. for( ; ; )
  943. {
  944. if( !aLine.ReadLine() )
  945. return false;
  946. line = aLine.Line();
  947. if( line[0] == 'U' )
  948. {
  949. sscanf( line + 1, "%d %d %lX", &m_unit, &m_convert, &m_TimeStamp );
  950. }
  951. else if( line[0] == 'P' )
  952. {
  953. sscanf( line + 1, "%d %d", &m_Pos.x, &m_Pos.y );
  954. // Set fields position to a default position (that is the
  955. // component position. For existing fields, the real position
  956. // will be set later
  957. for( int i = 0; i<GetFieldCount(); ++i )
  958. {
  959. if( GetField( i )->m_Text.IsEmpty() )
  960. GetField( i )->m_Pos = m_Pos;
  961. }
  962. }
  963. else if( line[0] == 'A' && line[1] == 'R' )
  964. {
  965. /* format:
  966. * AR Path="/9086AF6E/67452AA0" Ref="C99" Part="1"
  967. * where 9086AF6E is the unique timestamp of the containing sheet
  968. * and 67452AA0 is the timestamp of this component.
  969. * C99 is the reference given this path.
  970. */
  971. int ii;
  972. ptcar = line + 2;
  973. //copy the path.
  974. ii = ReadDelimitedText( name1, ptcar, 255 );
  975. ptcar += ii + 1;
  976. wxString path = FROM_UTF8( name1 );
  977. // copy the reference
  978. ii = ReadDelimitedText( name1, ptcar, 255 );
  979. ptcar += ii + 1;
  980. wxString ref = FROM_UTF8( name1 );
  981. // copy the multi, if exists
  982. ii = ReadDelimitedText( name1, ptcar, 255 );
  983. if( name1[0] == 0 ) // Nothing read, put a default value
  984. sprintf( name1, "%d", m_unit );
  985. int multi = atoi( name1 );
  986. if( multi < 0 || multi > 25 )
  987. multi = 1;
  988. AddHierarchicalReference( path, ref, multi );
  989. GetField( REFERENCE )->m_Text = ref;
  990. }
  991. else if( line[0] == 'F' )
  992. {
  993. int fieldNdx;
  994. wxString fieldText;
  995. EDA_TEXT_HJUSTIFY_T hjustify = GR_TEXT_HJUSTIFY_CENTER;
  996. EDA_TEXT_VJUSTIFY_T vjustify = GR_TEXT_VJUSTIFY_CENTER;
  997. ptcar = (char*) aLine;
  998. while( *ptcar && (*ptcar != '"') )
  999. ptcar++;
  1000. if( *ptcar != '"' )
  1001. {
  1002. aErrorMsg.Printf( wxT( "Eeschema file library field F at line %d, aborted" ),
  1003. aLine.LineNumber() );
  1004. return false;
  1005. }
  1006. ptcar += ReadDelimitedText( &fieldText, ptcar );
  1007. if( *ptcar == 0 )
  1008. {
  1009. aErrorMsg.Printf( wxT( "Component field F at line %d, aborted" ),
  1010. aLine.LineNumber() );
  1011. return false;
  1012. }
  1013. fieldNdx = atoi( line + 2 );
  1014. ReadDelimitedText( &fieldName, ptcar );
  1015. if( fieldName.IsEmpty() )
  1016. fieldName = TEMPLATE_FIELDNAME::GetDefaultFieldName( fieldNdx );
  1017. if( fieldNdx >= GetFieldCount() )
  1018. {
  1019. // The first MANDATOR_FIELDS _must_ be constructed within
  1020. // the SCH_COMPONENT constructor. This assert is simply here
  1021. // to guard against a change in that constructor.
  1022. wxASSERT( GetFieldCount() >= MANDATORY_FIELDS );
  1023. // Ignore the _supplied_ fieldNdx. It is not important anymore
  1024. // if within the user defined fields region (i.e. >= MANDATORY_FIELDS).
  1025. // We freely renumber the index to fit the next available field slot.
  1026. fieldNdx = GetFieldCount(); // new has this index after insertion
  1027. SCH_FIELD field( wxPoint( 0, 0 ),
  1028. -1, // field id is not relavant for user defined fields
  1029. this, fieldName );
  1030. AddField( field );
  1031. }
  1032. else
  1033. {
  1034. GetField( fieldNdx )->SetName( fieldName );
  1035. }
  1036. GetField( fieldNdx )->m_Text = fieldText;
  1037. memset( char3, 0, sizeof(char3) );
  1038. if( ( ii = sscanf( ptcar, "%s %d %d %d %X %s %s", char1,
  1039. &GetField( fieldNdx )->m_Pos.x,
  1040. &GetField( fieldNdx )->m_Pos.y,
  1041. &GetField( fieldNdx )->m_Size.x,
  1042. &GetField( fieldNdx )->m_Attributs,
  1043. char2, char3 ) ) < 4 )
  1044. {
  1045. aErrorMsg.Printf( wxT( "Component Field error line %d, aborted" ),
  1046. aLine.LineNumber() );
  1047. continue;
  1048. }
  1049. if( (GetField( fieldNdx )->m_Size.x == 0 ) || (ii == 4) )
  1050. GetField( fieldNdx )->m_Size.x = DEFAULT_SIZE_TEXT;
  1051. GetField( fieldNdx )->m_Orient = TEXT_ORIENT_HORIZ;
  1052. GetField( fieldNdx )->m_Size.y = GetField( fieldNdx )->m_Size.x;
  1053. if( char1[0] == 'V' )
  1054. GetField( fieldNdx )->m_Orient = TEXT_ORIENT_VERT;
  1055. if( ii >= 7 )
  1056. {
  1057. if( *char2 == 'L' )
  1058. hjustify = GR_TEXT_HJUSTIFY_LEFT;
  1059. else if( *char2 == 'R' )
  1060. hjustify = GR_TEXT_HJUSTIFY_RIGHT;
  1061. if( char3[0] == 'B' )
  1062. vjustify = GR_TEXT_VJUSTIFY_BOTTOM;
  1063. else if( char3[0] == 'T' )
  1064. vjustify = GR_TEXT_VJUSTIFY_TOP;
  1065. if( char3[1] == 'I' )
  1066. GetField( fieldNdx )->m_Italic = true;
  1067. else
  1068. GetField( fieldNdx )->m_Italic = false;
  1069. if( char3[2] == 'B' )
  1070. GetField( fieldNdx )->m_Bold = true;
  1071. else
  1072. GetField( fieldNdx )->m_Bold = false;
  1073. GetField( fieldNdx )->m_HJustify = hjustify;
  1074. GetField( fieldNdx )->m_VJustify = vjustify;
  1075. }
  1076. if( fieldNdx == REFERENCE )
  1077. if( GetField( fieldNdx )->m_Text[0] == '#' )
  1078. GetField( fieldNdx )->m_Attributs |= TEXT_NO_VISIBLE;
  1079. }
  1080. else
  1081. {
  1082. break;
  1083. }
  1084. }
  1085. if( sscanf( line, "%d %d %d", &m_unit, &m_Pos.x, &m_Pos.y ) != 3 )
  1086. {
  1087. aErrorMsg.Printf( wxT( "Component unit & pos error at line %d, aborted" ),
  1088. aLine.LineNumber() );
  1089. return false;
  1090. }
  1091. if( !aLine.ReadLine() ||
  1092. sscanf( ((char*)aLine), "%d %d %d %d",
  1093. &m_transform.x1,
  1094. &m_transform.y1,
  1095. &m_transform.x2,
  1096. &m_transform.y2 ) != 4 )
  1097. {
  1098. aErrorMsg.Printf( wxT( "Component orient error at line %d, aborted" ),
  1099. aLine.LineNumber() );
  1100. return false;
  1101. }
  1102. if( newfmt )
  1103. {
  1104. if( !aLine.ReadLine() )
  1105. return false;
  1106. line = aLine.Line();
  1107. if( strnicmp( "$End", line, 4 ) != 0 )
  1108. {
  1109. aErrorMsg.Printf( wxT( "Component End expected at line %d, aborted" ),
  1110. aLine.LineNumber() );
  1111. return false;
  1112. }
  1113. }
  1114. return true;
  1115. }
  1116. EDA_RECT SCH_COMPONENT::GetBodyBoundingBox() const
  1117. {
  1118. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1119. EDA_RECT bBox;
  1120. int x0, xm, y0, ym;
  1121. if( Entry == NULL )
  1122. {
  1123. if( DummyCmp == NULL )
  1124. CreateDummyCmp();
  1125. Entry = DummyCmp;
  1126. }
  1127. /* Get the basic Boundary box */
  1128. bBox = Entry->GetBodyBoundingBox( m_unit, m_convert );
  1129. x0 = bBox.GetX();
  1130. xm = bBox.GetRight();
  1131. // We must reverse Y values, because matrix orientation
  1132. // suppose Y axis normal for the library items coordinates,
  1133. // m_transform reverse Y values, but bBox is already reversed!
  1134. y0 = -bBox.GetY();
  1135. ym = -bBox.GetBottom();
  1136. /* Compute the real Boundary box (rotated, mirrored ...)*/
  1137. int x1 = m_transform.x1 * x0 + m_transform.y1 * y0;
  1138. int y1 = m_transform.x2 * x0 + m_transform.y2 * y0;
  1139. int x2 = m_transform.x1 * xm + m_transform.y1 * ym;
  1140. int y2 = m_transform.x2 * xm + m_transform.y2 * ym;
  1141. // H and W must be > 0:
  1142. if( x2 < x1 )
  1143. EXCHG( x2, x1 );
  1144. if( y2 < y1 )
  1145. EXCHG( y2, y1 );
  1146. bBox.SetX( x1 );
  1147. bBox.SetY( y1 );
  1148. bBox.SetWidth( x2 - x1 );
  1149. bBox.SetHeight( y2 - y1 );
  1150. bBox.Offset( m_Pos );
  1151. return bBox;
  1152. }
  1153. EDA_RECT SCH_COMPONENT::GetBoundingBox() const
  1154. {
  1155. EDA_RECT bbox = GetBodyBoundingBox();
  1156. for( size_t i = 0; i < m_Fields.size(); i++ )
  1157. {
  1158. bbox.Merge( m_Fields[i].GetBoundingBox() );
  1159. }
  1160. return bbox;
  1161. }
  1162. void SCH_COMPONENT::DisplayInfo( EDA_DRAW_FRAME* frame )
  1163. {
  1164. // search for the component in lib
  1165. // Entry and root_component can differ if Entry is an alias
  1166. LIB_ALIAS* alias = CMP_LIBRARY::FindLibraryEntry( m_ChipName );
  1167. LIB_COMPONENT* root_component = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1168. if( (alias == NULL) || (root_component == NULL) )
  1169. return;
  1170. wxString msg;
  1171. frame->ClearMsgPanel();
  1172. frame->AppendMsgPanel( _( "Reference" ),
  1173. GetRef( &( ( (SCH_EDIT_FRAME*) frame )->GetCurrentSheet() ) ),
  1174. DARKCYAN );
  1175. if( root_component->IsPower() )
  1176. msg = _( "Power symbol" );
  1177. else
  1178. msg = _( "Name" );
  1179. frame->AppendMsgPanel( msg, GetField( VALUE )->m_Text, DARKCYAN );
  1180. // Display component reference in library and library
  1181. frame->AppendMsgPanel( _( "Component" ), m_ChipName, BROWN );
  1182. if( alias->GetName() != root_component->GetName() )
  1183. frame->AppendMsgPanel( _( "Alias of" ), root_component->GetName(), BROWN );
  1184. frame->AppendMsgPanel( _( "Library" ), alias->GetLibraryName(), BROWN );
  1185. // Display description of the component, and keywords found in lib
  1186. frame->AppendMsgPanel( _( "Description" ), alias->GetDescription(), DARKCYAN );
  1187. frame->AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKCYAN );
  1188. }
  1189. void SCH_COMPONENT::MirrorY( int aYaxis_position )
  1190. {
  1191. int dx = m_Pos.x;
  1192. SetOrientation( CMP_MIRROR_Y );
  1193. m_Pos.x -= aYaxis_position;
  1194. NEGATE( m_Pos.x );
  1195. m_Pos.x += aYaxis_position;
  1196. dx -= m_Pos.x; // dx,0 is the move vector for this transform
  1197. for( int ii = 0; ii < GetFieldCount(); ii++ )
  1198. {
  1199. /* move the fields to the new position because the component itself
  1200. * has moved */
  1201. GetField( ii )->m_Pos.x -= dx;
  1202. }
  1203. }
  1204. void SCH_COMPONENT::MirrorX( int aXaxis_position )
  1205. {
  1206. int dy = m_Pos.y;
  1207. SetOrientation( CMP_MIRROR_X );
  1208. m_Pos.y -= aXaxis_position;
  1209. NEGATE( m_Pos.y );
  1210. m_Pos.y += aXaxis_position;
  1211. dy -= m_Pos.y; // dy,0 is the move vector for this transform
  1212. for( int ii = 0; ii < GetFieldCount(); ii++ )
  1213. {
  1214. /* move the fields to the new position because the component itself
  1215. * has moved */
  1216. GetField( ii )->m_Pos.y -= dy;
  1217. }
  1218. }
  1219. void SCH_COMPONENT::Rotate( wxPoint aPosition )
  1220. {
  1221. wxPoint prev = m_Pos;
  1222. RotatePoint( &m_Pos, aPosition, 900 );
  1223. //SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  1224. SetOrientation( CMP_ROTATE_CLOCKWISE );
  1225. for( int ii = 0; ii < GetFieldCount(); ii++ )
  1226. {
  1227. /* move the fields to the new position because the component itself
  1228. * has moved */
  1229. GetField( ii )->m_Pos.x -= prev.x - m_Pos.x;
  1230. GetField( ii )->m_Pos.y -= prev.y - m_Pos.y;
  1231. }
  1232. }
  1233. bool SCH_COMPONENT::Matches( wxFindReplaceData& aSearchData, void* aAuxData,
  1234. wxPoint* aFindLocation )
  1235. {
  1236. wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText() );
  1237. // Components are searchable via the child field and pin item text.
  1238. return false;
  1239. }
  1240. void SCH_COMPONENT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  1241. {
  1242. LIB_COMPONENT* Entry = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1243. if( Entry == NULL )
  1244. return;
  1245. for( LIB_PIN* Pin = Entry->GetNextPin(); Pin != NULL; Pin = Entry->GetNextPin( Pin ) )
  1246. {
  1247. wxASSERT( Pin->Type() == LIB_PIN_T );
  1248. if( Pin->GetUnit() && m_unit && ( m_unit != Pin->GetUnit() ) )
  1249. continue;
  1250. if( Pin->GetConvert() && m_convert && ( m_convert != Pin->GetConvert() ) )
  1251. continue;
  1252. DANGLING_END_ITEM item( PIN_END, Pin, GetPinPhysicalPosition( Pin ) );
  1253. aItemList.push_back( item );
  1254. }
  1255. }
  1256. wxPoint SCH_COMPONENT::GetPinPhysicalPosition( LIB_PIN* Pin )
  1257. {
  1258. wxCHECK_MSG( Pin != NULL && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ),
  1259. wxT( "Cannot get physical position of pin." ) );
  1260. return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_Pos;
  1261. }
  1262. bool SCH_COMPONENT::IsSelectStateChanged( const wxRect& aRect )
  1263. {
  1264. bool previousState = IsSelected();
  1265. EDA_RECT boundingBox = GetBoundingBox();
  1266. if( aRect.Intersects( boundingBox ) )
  1267. m_Flags |= SELECTED;
  1268. else
  1269. m_Flags &= ~SELECTED;
  1270. return previousState != IsSelected();
  1271. }
  1272. void SCH_COMPONENT::GetConnectionPoints( vector< wxPoint >& aPoints ) const
  1273. {
  1274. LIB_PIN* pin;
  1275. LIB_COMPONENT* component = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1276. wxCHECK_RET( component != NULL,
  1277. wxT( "Cannot add connection points to list. Cannot find component <" ) +
  1278. m_ChipName + wxT( "> in any of the loaded libraries." ) );
  1279. for( pin = component->GetNextPin(); pin != NULL; pin = component->GetNextPin( pin ) )
  1280. {
  1281. wxCHECK_RET( pin->Type() == LIB_PIN_T,
  1282. wxT( "GetNextPin() did not return a pin object. Bad programmer!" ) );
  1283. // Skip items not used for this part.
  1284. if( m_unit && pin->GetUnit() && ( pin->GetUnit() != m_unit ) )
  1285. continue;
  1286. if( m_convert && pin->GetConvert() && ( pin->GetConvert() != m_convert ) )
  1287. continue;
  1288. // Calculate the pin position relative to the component position and orientation.
  1289. aPoints.push_back( m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos );
  1290. }
  1291. }
  1292. LIB_ITEM* SCH_COMPONENT::GetDrawItem( const wxPoint& aPosition, KICAD_T aType )
  1293. {
  1294. LIB_COMPONENT* component = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1295. if( component == NULL )
  1296. return NULL;
  1297. // Calculate the position relative to the component.
  1298. wxPoint libPosition = aPosition - m_Pos;
  1299. return component->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform );
  1300. }
  1301. wxString SCH_COMPONENT::GetSelectMenuText() const
  1302. {
  1303. wxString tmp;
  1304. tmp.Printf( _( "Component %s, %s" ),
  1305. GetChars( m_ChipName ),
  1306. GetChars( GetField( REFERENCE )->GetText() ) );
  1307. return tmp;
  1308. }
  1309. SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR* aInspector, const void* aTestData,
  1310. const KICAD_T aFilterTypes[] )
  1311. {
  1312. KICAD_T stype;
  1313. for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
  1314. {
  1315. // If caller wants to inspect component type or and component children types.
  1316. if( stype == Type() )
  1317. {
  1318. if( SEARCH_QUIT == aInspector->Inspect( this, aTestData ) )
  1319. return SEARCH_QUIT;
  1320. }
  1321. else if( stype == SCH_FIELD_T )
  1322. {
  1323. // Test the bounding boxes of fields if they are visible and not empty.
  1324. for( int ii = 0; ii < GetFieldCount(); ii++ )
  1325. {
  1326. if( SEARCH_QUIT == aInspector->Inspect( GetField( ii ), (void*) this ) )
  1327. return SEARCH_QUIT;
  1328. }
  1329. }
  1330. else if( stype == LIB_PIN_T )
  1331. {
  1332. LIB_COMPONENT* component = CMP_LIBRARY::FindLibraryComponent( m_ChipName );
  1333. if( component != NULL )
  1334. {
  1335. LIB_PINS pins;
  1336. component->GetPins( pins, m_unit, m_convert );
  1337. for( size_t i = 0; i < pins.size(); i++ )
  1338. {
  1339. if( SEARCH_QUIT == aInspector->Inspect( pins[ i ], (void*) this ) )
  1340. return SEARCH_QUIT;
  1341. }
  1342. }
  1343. }
  1344. }
  1345. return SEARCH_CONTINUE;
  1346. }
  1347. void SCH_COMPONENT::GetNetListItem( vector<NETLIST_OBJECT*>& aNetListItems,
  1348. SCH_SHEET_PATH* aSheetPath )
  1349. {
  1350. LIB_COMPONENT* component = CMP_LIBRARY::FindLibraryComponent( GetLibName() );
  1351. if( component == NULL )
  1352. return;
  1353. for( LIB_PIN* pin = component->GetNextPin(); pin; pin = component->GetNextPin( pin ) )
  1354. {
  1355. wxASSERT( pin->Type() == LIB_PIN_T );
  1356. if( pin->GetUnit() && ( pin->GetUnit() != GetUnitSelection( aSheetPath ) ) )
  1357. continue;
  1358. if( pin->GetConvert() && ( pin->GetConvert() != GetConvert() ) )
  1359. continue;
  1360. wxPoint pos = GetTransform().TransformCoordinate( pin->GetPosition() ) + m_Pos;
  1361. NETLIST_OBJECT* item = new NETLIST_OBJECT();
  1362. item->m_SheetListInclude = *aSheetPath;
  1363. item->m_Comp = (SCH_ITEM*) pin;
  1364. item->m_SheetList = *aSheetPath;
  1365. item->m_Type = NET_PIN;
  1366. item->m_Link = (SCH_ITEM*) this;
  1367. item->m_ElectricalType = pin->GetType();
  1368. item->m_PinNum = pin->GetNumber();
  1369. item->m_Label = pin->GetName();
  1370. item->m_Start = item->m_End = pos;
  1371. aNetListItems.push_back( item );
  1372. if( ( (int) pin->GetType() == (int) PIN_POWER_IN ) && !pin->IsVisible() )
  1373. {
  1374. /* There is an associated PIN_LABEL. */
  1375. item = new NETLIST_OBJECT();
  1376. item->m_SheetListInclude = *aSheetPath;
  1377. item->m_Comp = NULL;
  1378. item->m_SheetList = *aSheetPath;
  1379. item->m_Type = NET_PINLABEL;
  1380. item->m_Label = pin->GetName();
  1381. item->m_Start = pos;
  1382. item->m_End = item->m_Start;
  1383. aNetListItems.push_back( item );
  1384. }
  1385. }
  1386. }
  1387. bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
  1388. {
  1389. if( Type() != aItem.Type() )
  1390. return Type() < aItem.Type();
  1391. SCH_COMPONENT* component = (SCH_COMPONENT*) &aItem;
  1392. EDA_RECT rect = GetBodyBoundingBox();
  1393. if( rect.GetArea() != component->GetBodyBoundingBox().GetArea() )
  1394. return rect.GetArea() < component->GetBodyBoundingBox().GetArea();
  1395. if( m_Pos.x != component->m_Pos.x )
  1396. return m_Pos.x < component->m_Pos.x;
  1397. if( m_Pos.y != component->m_Pos.y )
  1398. return m_Pos.y < component->m_Pos.y;
  1399. return false;
  1400. }
  1401. bool SCH_COMPONENT::operator==( const SCH_COMPONENT& aComponent ) const
  1402. {
  1403. if( GetFieldCount() != aComponent.GetFieldCount() )
  1404. return false;
  1405. for( int i = VALUE; i < GetFieldCount(); i++ )
  1406. {
  1407. if( GetField( i )->GetText().Cmp( aComponent.GetField( i )->GetText() ) != 0 )
  1408. return false;
  1409. }
  1410. return true;
  1411. }
  1412. bool SCH_COMPONENT::operator!=( const SCH_COMPONENT& aComponent ) const
  1413. {
  1414. return !( *this == aComponent );
  1415. }
  1416. SCH_ITEM& SCH_COMPONENT::operator=( const SCH_ITEM& aItem )
  1417. {
  1418. wxCHECK_MSG( Type() == aItem.Type(), *this,
  1419. wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
  1420. GetClass() );
  1421. if( &aItem != this )
  1422. {
  1423. SCH_ITEM::operator=( aItem );
  1424. SCH_COMPONENT* component = (SCH_COMPONENT*) &aItem;
  1425. m_ChipName = component->m_ChipName;
  1426. m_Pos = component->m_Pos;
  1427. m_unit = component->m_unit;
  1428. m_convert = component->m_convert;
  1429. m_transform = component->m_transform;
  1430. m_PathsAndReferences = component->m_PathsAndReferences;
  1431. m_Fields = component->m_Fields; // std::vector's assignment operator.
  1432. // Reparent fields after assignment to new component.
  1433. for( int ii = 0; ii < GetFieldCount(); ++ii )
  1434. {
  1435. GetField( ii )->SetParent( this );
  1436. }
  1437. }
  1438. return *this;
  1439. }
  1440. bool SCH_COMPONENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  1441. {
  1442. EDA_RECT bBox = GetBodyBoundingBox();
  1443. bBox.Inflate( aAccuracy );
  1444. if( bBox.Contains( aPosition ) )
  1445. return true;
  1446. return false;
  1447. }
  1448. bool SCH_COMPONENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  1449. {
  1450. if( m_Flags & STRUCT_DELETED || m_Flags & SKIP_STRUCT )
  1451. return false;
  1452. EDA_RECT rect = aRect;
  1453. rect.Inflate( aAccuracy );
  1454. if( aContained )
  1455. return rect.Contains( GetBodyBoundingBox() );
  1456. return rect.Intersects( GetBodyBoundingBox() );
  1457. }
  1458. bool SCH_COMPONENT::doIsConnected( const wxPoint& aPosition ) const
  1459. {
  1460. vector< wxPoint > pts;
  1461. GetConnectionPoints( pts );
  1462. for( size_t i = 0; i < pts.size(); i++ )
  1463. {
  1464. if( pts[i] == aPosition )
  1465. return true;
  1466. }
  1467. return false;
  1468. }
  1469. void SCH_COMPONENT::Plot( PLOTTER* aPlotter )
  1470. {
  1471. LIB_COMPONENT* Entry;
  1472. TRANSFORM temp = TRANSFORM();
  1473. Entry = CMP_LIBRARY::FindLibraryComponent( GetLibName() );
  1474. if( Entry == NULL )
  1475. return;
  1476. temp = GetTransform();
  1477. Entry->Plot( aPlotter, GetUnit(), GetConvert(), m_Pos, temp );
  1478. for( size_t i = 0; i < m_Fields.size(); i++ )
  1479. {
  1480. m_Fields[i].Plot( aPlotter );
  1481. }
  1482. }