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.

1877 lines
50 KiB

* KIWAY Milestone A): Make major modules into DLL/DSOs. ! The initial testing of this commit should be done using a Debug build so that all the wxASSERT()s are enabled. Also, be sure and keep enabled the USE_KIWAY_DLLs option. The tree won't likely build without it. Turning it off is senseless anyways. If you want stable code, go back to a prior version, the one tagged with "stable". * Relocate all functionality out of the wxApp derivative into more finely targeted purposes: a) DLL/DSO specific b) PROJECT specific c) EXE or process specific d) configuration file specific data e) configuration file manipulations functions. All of this functionality was blended into an extremely large wxApp derivative and that was incompatible with the desire to support multiple concurrently loaded DLL/DSO's ("KIFACE")s and multiple concurrently open projects. An amazing amount of organization come from simply sorting each bit of functionality into the proper box. * Switch to wxConfigBase from wxConfig everywhere except instantiation. * Add classes KIWAY, KIFACE, KIFACE_I, SEARCH_STACK, PGM_BASE, PGM_KICAD, PGM_SINGLE_TOP, * Remove "Return" prefix on many function names. * Remove obvious comments from CMakeLists.txt files, and from else() and endif()s. * Fix building boost for use in a DSO on linux. * Remove some of the assumptions in the CMakeLists.txt files that windows had to be the host platform when building windows binaries. * Reduce the number of wxStrings being constructed at program load time via static construction. * Pass wxConfigBase* to all SaveSettings() and LoadSettings() functions so that these functions are useful even when the wxConfigBase comes from another source, as is the case in the KICAD_MANAGER_FRAME. * Move the setting of the KIPRJMOD environment variable into class PROJECT, so that it can be moved into a project variable soon, and out of FP_LIB_TABLE. * Add the KIWAY_PLAYER which is associated with a particular PROJECT, and all its child wxFrames and wxDialogs now have a Kiway() member function which returns a KIWAY& that that window tree branch is in support of. This is like wxWindows DNA in that child windows get this member with proper value at time of construction. * Anticipate some of the needs for milestones B) and C) and make code adjustments now in an effort to reduce work in those milestones. * No testing has been done for python scripting, since milestone C) has that being largely reworked and re-thought-out.
12 years ago
18 years ago
7 years ago
7 years ago
18 years ago
18 years ago
18 years ago
18 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
18 years ago
18 years ago
18 years ago
18 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) 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. #include <fctsys.h>
  25. #include <pgm_base.h>
  26. #include <sch_draw_panel.h>
  27. #include <gr_basic.h>
  28. #include <kicad_string.h>
  29. #include <richio.h>
  30. #include <sch_edit_frame.h>
  31. #include <plotter.h>
  32. #include <msgpanel.h>
  33. #include <bitmaps.h>
  34. #include <general.h>
  35. #include <class_library.h>
  36. #include <lib_rectangle.h>
  37. #include <lib_pin.h>
  38. #include <lib_text.h>
  39. #include <sch_component.h>
  40. #include <sch_sheet.h>
  41. #include <sch_sheet_path.h>
  42. #include <sch_legacy_plugin.h>
  43. #include <netlist_object.h>
  44. #include <lib_item.h>
  45. #include <symbol_lib_table.h>
  46. #include <dialogs/dialog_schematic_find.h>
  47. #include <wx/tokenzr.h>
  48. #include <iostream>
  49. #include <cctype>
  50. #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
  51. #include <trace_helpers.h>
  52. /**
  53. * Convert a wxString to UTF8 and replace any control characters with a ~,
  54. * where a control character is one of the first ASCII values up to ' ' 32d.
  55. */
  56. std::string toUTFTildaText( const wxString& txt )
  57. {
  58. std::string ret = TO_UTF8( txt );
  59. for( std::string::iterator it = ret.begin(); it!=ret.end(); ++it )
  60. {
  61. if( (unsigned char) *it <= ' ' )
  62. *it = '~';
  63. }
  64. return ret;
  65. }
  66. /**
  67. * Used to draw a dummy shape when a LIB_PART is not found in library
  68. *
  69. * This component is a 400 mils square with the text ??
  70. * DEF DUMMY U 0 40 Y Y 1 0 N
  71. * F0 "U" 0 -350 60 H V
  72. * F1 "DUMMY" 0 350 60 H V
  73. * DRAW
  74. * T 0 0 0 150 0 0 0 ??
  75. * S -200 200 200 -200 0 1 0
  76. * ENDDRAW
  77. * ENDDEF
  78. */
  79. static LIB_PART* dummy()
  80. {
  81. static LIB_PART* part;
  82. if( !part )
  83. {
  84. part = new LIB_PART( wxEmptyString );
  85. LIB_RECTANGLE* square = new LIB_RECTANGLE( part );
  86. square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
  87. square->SetEndPosition( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
  88. LIB_TEXT* text = new LIB_TEXT( part );
  89. text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
  90. text->SetText( wxString( wxT( "??" ) ) );
  91. part->AddDrawItem( square );
  92. part->AddDrawItem( text );
  93. }
  94. return part;
  95. }
  96. SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos, SCH_ITEM* aParent ) :
  97. SCH_ITEM( aParent, SCH_COMPONENT_T )
  98. {
  99. Init( aPos );
  100. }
  101. SCH_COMPONENT::SCH_COMPONENT( LIB_PART& aPart, LIB_ID aLibId, SCH_SHEET_PATH* sheet,
  102. int unit, int convert, const wxPoint& pos ) :
  103. SCH_ITEM( NULL, SCH_COMPONENT_T )
  104. {
  105. Init( pos );
  106. m_unit = unit;
  107. m_convert = convert;
  108. m_lib_id = aLibId;
  109. std::unique_ptr< LIB_PART > part;
  110. part = aPart.Flatten();
  111. part->SetParent();
  112. m_part.reset( part.release() );
  113. // Copy fields from the library component
  114. UpdateFields( true, true );
  115. // Update the pin locations
  116. UpdatePins();
  117. // Update the reference -- just the prefix for now.
  118. if( sheet )
  119. SetRef( sheet, aPart.GetReferenceField().GetText() + wxT( "?" ) );
  120. else
  121. m_prefix = aPart.GetReferenceField().GetText() + wxT( "?" );
  122. }
  123. SCH_COMPONENT::SCH_COMPONENT(
  124. LIB_PART& aPart, SCH_SHEET_PATH* aSheet, COMPONENT_SELECTION& aSel, const wxPoint& pos )
  125. : SCH_COMPONENT( aPart, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, pos )
  126. {
  127. // Set any fields that were modified as part of the component selection
  128. for( auto const& i : aSel.Fields )
  129. {
  130. auto field = this->GetField( i.first );
  131. if( field )
  132. field->SetText( i.second );
  133. }
  134. }
  135. SCH_COMPONENT::SCH_COMPONENT( const SCH_COMPONENT& aComponent ) :
  136. SCH_ITEM( aComponent )
  137. {
  138. m_Parent = aComponent.m_Parent;
  139. m_Pos = aComponent.m_Pos;
  140. m_unit = aComponent.m_unit;
  141. m_convert = aComponent.m_convert;
  142. m_lib_id = aComponent.m_lib_id;
  143. m_isInNetlist = aComponent.m_isInNetlist;
  144. if( aComponent.m_part )
  145. m_part.reset( new LIB_PART( *aComponent.m_part.get() ) );
  146. const_cast<KIID&>( m_Uuid ) = aComponent.m_Uuid;
  147. m_transform = aComponent.m_transform;
  148. m_prefix = aComponent.m_prefix;
  149. m_instanceReferences = aComponent.m_instanceReferences;
  150. m_Fields = aComponent.m_Fields;
  151. // Re-parent the fields, which before this had aComponent as parent
  152. for( SCH_FIELD& field : m_Fields )
  153. field.SetParent( this );
  154. UpdatePins();
  155. m_fieldsAutoplaced = aComponent.m_fieldsAutoplaced;
  156. }
  157. void SCH_COMPONENT::Init( const wxPoint& pos )
  158. {
  159. m_Pos = pos;
  160. m_unit = 1; // In multi unit chip - which unit to draw.
  161. m_convert = LIB_ITEM::LIB_CONVERT::BASE; // De Morgan Handling
  162. // The rotation/mirror transformation matrix. pos normal
  163. m_transform = TRANSFORM();
  164. // construct only the mandatory fields, which are the first 4 only.
  165. for( int i = 0; i < MANDATORY_FIELDS; ++i )
  166. {
  167. m_Fields.emplace_back( pos, i, this, TEMPLATE_FIELDNAME::GetDefaultFieldName( i ) );
  168. if( i == REFERENCE )
  169. m_Fields.back().SetLayer( LAYER_REFERENCEPART );
  170. else if( i == VALUE )
  171. m_Fields.back().SetLayer( LAYER_VALUEPART );
  172. else
  173. m_Fields.back().SetLayer( LAYER_FIELDS );
  174. }
  175. m_prefix = wxString( wxT( "U" ) );
  176. m_isInNetlist = true;
  177. }
  178. EDA_ITEM* SCH_COMPONENT::Clone() const
  179. {
  180. return new SCH_COMPONENT( *this );
  181. }
  182. void SCH_COMPONENT::ViewGetLayers( int aLayers[], int& aCount ) const
  183. {
  184. aCount = 3;
  185. aLayers[0] = LAYER_DEVICE;
  186. aLayers[1] = LAYER_DEVICE_BACKGROUND;
  187. aLayers[2] = LAYER_SELECTION_SHADOWS;
  188. }
  189. void SCH_COMPONENT::SetLibId( const LIB_ID& aLibId, PART_LIBS* aLibs )
  190. {
  191. if( m_lib_id != aLibId )
  192. {
  193. m_lib_id = aLibId;
  194. SetModified();
  195. if( aLibs )
  196. {
  197. Resolve( aLibs );
  198. }
  199. else
  200. {
  201. m_part.reset();
  202. m_pins.clear();
  203. m_pinMap.clear();
  204. }
  205. }
  206. }
  207. void SCH_COMPONENT::SetLibId( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aSymLibTable,
  208. PART_LIB* aCacheLib )
  209. {
  210. if( m_lib_id == aLibId )
  211. return;
  212. m_lib_id = aLibId;
  213. SetModified();
  214. std::unique_ptr< LIB_PART > symbol;
  215. if( aSymLibTable && aSymLibTable->HasLibrary( m_lib_id.GetLibNickname() ) )
  216. {
  217. LIB_PART* tmp = aSymLibTable->LoadSymbol( m_lib_id );
  218. if( tmp )
  219. {
  220. symbol = tmp->Flatten();
  221. symbol->SetParent();
  222. }
  223. }
  224. if( !symbol && aCacheLib )
  225. {
  226. LIB_PART* tmp = aCacheLib->FindPart( m_lib_id.Format().wx_str() );
  227. if( tmp )
  228. {
  229. symbol = tmp->Flatten();
  230. symbol->SetParent();
  231. }
  232. }
  233. m_part.reset( symbol.release() );
  234. UpdatePins();
  235. }
  236. wxString SCH_COMPONENT::GetDescription() const
  237. {
  238. if( m_part )
  239. {
  240. return m_part->GetDescription();
  241. }
  242. return wxEmptyString;
  243. }
  244. wxString SCH_COMPONENT::GetDatasheet() const
  245. {
  246. if( m_part )
  247. {
  248. return m_part->GetDocFileName();
  249. }
  250. return wxEmptyString;
  251. }
  252. bool SCH_COMPONENT::Resolve( PART_LIBS* aLibs )
  253. {
  254. // I've never been happy that the actual individual PART_LIB is left up to
  255. // flimsy search path ordering. None-the-less find a part based on that design:
  256. if( LIB_PART* part = aLibs->FindLibPart( m_lib_id ) )
  257. {
  258. std::unique_ptr< LIB_PART > flattenedPart = part->Flatten();
  259. flattenedPart->SetParent();
  260. m_part.reset( flattenedPart.release() );
  261. UpdatePins();
  262. return true;
  263. }
  264. return false;
  265. }
  266. bool SCH_COMPONENT::Resolve( SYMBOL_LIB_TABLE& aLibTable, PART_LIB* aCacheLib )
  267. {
  268. std::unique_ptr< LIB_PART > part;
  269. try
  270. {
  271. // We want a full symbol not just the top level child symbol.
  272. PROPERTIES props;
  273. props[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
  274. // LIB_TABLE_BASE::LoadSymbol() throws an IO_ERROR if the the library nickname
  275. // is not found in the table so check if the library still exists in the table
  276. // before attempting to load the symbol.
  277. if( m_lib_id.IsValid() && aLibTable.HasLibrary( m_lib_id.GetLibNickname() ) )
  278. {
  279. LIB_PART* tmp = aLibTable.LoadSymbol( m_lib_id );
  280. if( tmp )
  281. {
  282. part = tmp->Flatten();
  283. part->SetParent();
  284. }
  285. }
  286. // Fall back to cache library. This is temporary until the new schematic file
  287. // format is implemented.
  288. if( !part && aCacheLib )
  289. {
  290. wxString libId = m_lib_id.Format().wx_str();
  291. libId.Replace( ":", "_" );
  292. wxLogTrace( traceSymbolResolver,
  293. "Library symbol %s not found falling back to cache library.",
  294. m_lib_id.Format().wx_str() );
  295. LIB_PART* tmp = aCacheLib->FindPart( libId );
  296. if( tmp )
  297. {
  298. part = tmp->Flatten();
  299. part->SetParent();
  300. }
  301. }
  302. if( part )
  303. {
  304. m_part.reset( part.release() );
  305. UpdatePins();
  306. return true;
  307. }
  308. }
  309. catch( const IO_ERROR& ioe )
  310. {
  311. wxLogTrace( traceSymbolResolver, "I/O error %s resolving library symbol %s", ioe.What(),
  312. m_lib_id.Format().wx_str() );
  313. }
  314. wxLogTrace( traceSymbolResolver, "Cannot resolve library symbol %s",
  315. m_lib_id.Format().wx_str() );
  316. m_part.reset();
  317. UpdatePins(); // This will clear the pin map and library symbol pin pointers.
  318. return false;
  319. }
  320. // Helper sort function, used in SCH_COMPONENT::ResolveAll, to sort sch component by lib_id
  321. static bool sort_by_libid( const SCH_COMPONENT* ref, SCH_COMPONENT* cmp )
  322. {
  323. if( ref->GetLibId() == cmp->GetLibId() )
  324. {
  325. if( ref->GetUnit() == cmp->GetUnit() )
  326. return ref->GetConvert() < cmp->GetConvert();
  327. return ref->GetUnit() < cmp->GetUnit();
  328. }
  329. return ref->GetLibId() < cmp->GetLibId();
  330. }
  331. void SCH_COMPONENT::ResolveAll(
  332. std::vector<SCH_COMPONENT*>& aComponents, SYMBOL_LIB_TABLE& aLibTable, PART_LIB* aCacheLib )
  333. {
  334. // sort it by lib part. Cmp will be grouped by same lib part.
  335. std::sort( aComponents.begin(), aComponents.end(), sort_by_libid );
  336. LIB_ID curr_libid;
  337. for( unsigned ii = 0; ii < aComponents.size(); ++ii )
  338. {
  339. SCH_COMPONENT* cmp = aComponents[ii];
  340. curr_libid = cmp->m_lib_id;
  341. cmp->Resolve( aLibTable, aCacheLib );
  342. cmp->UpdatePins();
  343. // Propagate the m_part pointer to other members using the same lib_id
  344. for( unsigned jj = ii + 1; jj < aComponents.size(); ++jj )
  345. {
  346. SCH_COMPONENT* next_cmp = aComponents[jj];
  347. if( curr_libid != next_cmp->m_lib_id )
  348. break;
  349. if( cmp->m_part )
  350. next_cmp->m_part.reset( new LIB_PART( *cmp->m_part.get() ) );
  351. next_cmp->UpdatePins();
  352. ii = jj;
  353. }
  354. }
  355. }
  356. void SCH_COMPONENT::UpdatePins()
  357. {
  358. m_pins.clear();
  359. m_pinMap.clear();
  360. if( m_part )
  361. {
  362. SCH_PIN_MAP map;
  363. unsigned i = 0;
  364. for( LIB_PIN* libPin = m_part->GetNextPin(); libPin; libPin = m_part->GetNextPin( libPin ) )
  365. {
  366. wxASSERT( libPin->Type() == LIB_PIN_T );
  367. if( libPin->GetConvert() && m_convert && ( m_convert != libPin->GetConvert() ) )
  368. continue;
  369. m_pins.push_back( std::unique_ptr<SCH_PIN>( new SCH_PIN( libPin, this ) ) );
  370. m_pinMap[ libPin ] = i;
  371. ++i;
  372. }
  373. }
  374. }
  375. SCH_CONNECTION* SCH_COMPONENT::GetConnectionForPin( LIB_PIN* aPin, const SCH_SHEET_PATH& aSheet )
  376. {
  377. if( m_pinMap.count( aPin ) )
  378. return m_pins[ m_pinMap[aPin] ]->Connection( aSheet );
  379. return nullptr;
  380. }
  381. void SCH_COMPONENT::SetUnit( int aUnit )
  382. {
  383. if( m_unit != aUnit )
  384. {
  385. m_unit = aUnit;
  386. SetModified();
  387. }
  388. }
  389. void SCH_COMPONENT::UpdateUnit( int aUnit )
  390. {
  391. m_unit = aUnit;
  392. }
  393. void SCH_COMPONENT::SetConvert( int aConvert )
  394. {
  395. if( m_convert != aConvert )
  396. {
  397. m_convert = aConvert;
  398. SetModified();
  399. }
  400. }
  401. void SCH_COMPONENT::SetTransform( const TRANSFORM& aTransform )
  402. {
  403. if( m_transform != aTransform )
  404. {
  405. m_transform = aTransform;
  406. SetModified();
  407. }
  408. }
  409. int SCH_COMPONENT::GetUnitCount() const
  410. {
  411. if( m_part )
  412. return m_part->GetUnitCount();
  413. return 0;
  414. }
  415. void SCH_COMPONENT::Print( wxDC* aDC, const wxPoint& aOffset )
  416. {
  417. auto opts = PART_DRAW_OPTIONS::Default();
  418. opts.transform = m_transform;
  419. opts.draw_visible_fields = false;
  420. opts.draw_hidden_fields = false;
  421. if( m_part )
  422. {
  423. m_part->Print( aDC, m_Pos + aOffset, m_unit, m_convert, opts );
  424. }
  425. else // Use dummy() part if the actual cannot be found.
  426. {
  427. dummy()->Print( aDC, m_Pos + aOffset, 0, 0, opts );
  428. }
  429. for( SCH_FIELD& field : m_Fields )
  430. field.Print( aDC, aOffset );
  431. }
  432. void SCH_COMPONENT::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef,
  433. int aUnit )
  434. {
  435. // Search for an existing path and remove it if found (should not occur)
  436. for( unsigned ii = 0; ii < m_instanceReferences.size(); ii++ )
  437. {
  438. if( m_instanceReferences[ii].m_Path == aPath )
  439. {
  440. m_instanceReferences.erase( m_instanceReferences.begin() + ii );
  441. ii--;
  442. }
  443. }
  444. COMPONENT_INSTANCE_REFERENCE instance;
  445. instance.m_Path = aPath;
  446. instance.m_Reference = aRef;
  447. instance.m_Unit = aUnit;
  448. m_instanceReferences.push_back( instance );
  449. }
  450. const wxString SCH_COMPONENT::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit )
  451. {
  452. KIID_PATH path = sheet->Path();
  453. wxString ref;
  454. for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  455. {
  456. if( instance.m_Path == path )
  457. {
  458. ref = instance.m_Reference;
  459. break;
  460. }
  461. }
  462. // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
  463. // use this as a default for this path. This will happen if we load a version 1 schematic
  464. // file. It will also mean that multiple instances of the same sheet by default all have
  465. // the same component references, but perhaps this is best.
  466. if( ref.IsEmpty() && !GetField( REFERENCE )->GetText().IsEmpty() )
  467. {
  468. SetRef( sheet, GetField( REFERENCE )->GetText() );
  469. ref = GetField( REFERENCE )->GetText();
  470. }
  471. if( ref.IsEmpty() )
  472. ref = m_prefix;
  473. if( aIncludeUnit )
  474. ref += LIB_PART::SubReference( GetUnit() );
  475. return ref;
  476. }
  477. bool SCH_COMPONENT::IsReferenceStringValid( const wxString& aReferenceString )
  478. {
  479. wxString text = aReferenceString;
  480. bool ok = true;
  481. // Try to unannotate this reference
  482. while( !text.IsEmpty() && ( text.Last() == '?' || wxIsdigit( text.Last() ) ) )
  483. text.RemoveLast();
  484. if( text.IsEmpty() )
  485. ok = false;
  486. return ok;
  487. }
  488. void SCH_COMPONENT::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
  489. {
  490. KIID_PATH path = sheet->Path();
  491. bool notInArray = true;
  492. // check to see if it is already there before inserting it
  493. for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  494. {
  495. if( instance.m_Path == path )
  496. {
  497. instance.m_Reference = ref;
  498. notInArray = false;
  499. }
  500. }
  501. if( notInArray )
  502. AddHierarchicalReference( path, ref, m_unit );
  503. SCH_FIELD* rf = GetField( REFERENCE );
  504. // @todo Should we really be checking for what is a "reasonable" position?
  505. if( rf->GetText().IsEmpty()
  506. || ( abs( rf->GetTextPos().x - m_Pos.x ) +
  507. abs( rf->GetTextPos().y - m_Pos.y ) > Mils2iu( 10000 ) ) )
  508. {
  509. // move it to a reasonable position
  510. rf->SetTextPos( m_Pos + wxPoint( Mils2iu( 50 ), Mils2iu( 50 ) ) );
  511. }
  512. rf->SetText( ref ); // for drawing.
  513. // Reinit the m_prefix member if needed
  514. wxString prefix = ref;
  515. if( IsReferenceStringValid( prefix ) )
  516. {
  517. while( prefix.Last() == '?' || wxIsdigit( prefix.Last() ) )
  518. prefix.RemoveLast();
  519. }
  520. else
  521. {
  522. prefix = wxT( "U" ); // Set to default ref prefix
  523. }
  524. if( m_prefix != prefix )
  525. m_prefix = prefix;
  526. // Power components have references starting with # and are not included in netlists
  527. m_isInNetlist = ! ref.StartsWith( wxT( "#" ) );
  528. }
  529. bool SCH_COMPONENT::IsAnnotated( const SCH_SHEET_PATH* aSheet )
  530. {
  531. KIID_PATH path = aSheet->Path();
  532. for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  533. {
  534. if( instance.m_Path == path )
  535. return instance.m_Reference.Last() != '?';
  536. }
  537. return false;
  538. }
  539. int SCH_COMPONENT::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const
  540. {
  541. KIID_PATH path = aSheet->Path();
  542. for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  543. {
  544. if( instance.m_Path == path )
  545. return instance.m_Unit;
  546. }
  547. // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
  548. // version 1 schematic file.
  549. return m_unit;
  550. }
  551. void SCH_COMPONENT::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
  552. {
  553. KIID_PATH path = aSheet->Path();
  554. bool notInArray = true;
  555. // check to see if it is already there before inserting it
  556. for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  557. {
  558. if( instance.m_Path == path )
  559. {
  560. instance.m_Unit = aUnitSelection;
  561. notInArray = false;
  562. }
  563. }
  564. if( notInArray )
  565. AddHierarchicalReference( path, m_prefix, aUnitSelection );
  566. }
  567. SCH_FIELD* SCH_COMPONENT::GetField( int aFieldNdx ) const
  568. {
  569. const SCH_FIELD* field;
  570. if( (unsigned) aFieldNdx < m_Fields.size() )
  571. field = &m_Fields[aFieldNdx];
  572. else
  573. field = NULL;
  574. wxASSERT( field );
  575. return const_cast<SCH_FIELD*>( field );
  576. }
  577. wxString SCH_COMPONENT::GetFieldText( const wxString& aFieldName, SCH_EDIT_FRAME* aFrame ) const
  578. {
  579. for( const SCH_FIELD& field : m_Fields )
  580. {
  581. if( aFieldName == field.GetName() )
  582. return field.GetText();
  583. }
  584. return wxEmptyString;
  585. }
  586. void SCH_COMPONENT::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly )
  587. {
  588. for( SCH_FIELD& field : m_Fields )
  589. {
  590. if( !aVisibleOnly || ( field.IsVisible() && !field.IsVoid() ) )
  591. aVector.push_back( &field );
  592. }
  593. }
  594. SCH_FIELD* SCH_COMPONENT::AddField( const SCH_FIELD& aField )
  595. {
  596. int newNdx = m_Fields.size();
  597. m_Fields.push_back( aField );
  598. return &m_Fields[newNdx];
  599. }
  600. void SCH_COMPONENT::RemoveField( const wxString& aFieldName )
  601. {
  602. for( unsigned i = MANDATORY_FIELDS; i < m_Fields.size(); ++i )
  603. {
  604. if( aFieldName == m_Fields[i].GetName( false ) )
  605. {
  606. m_Fields.erase( m_Fields.begin() + i );
  607. return;
  608. }
  609. }
  610. }
  611. SCH_FIELD* SCH_COMPONENT::FindField( const wxString& aFieldName, bool aIncludeDefaultFields )
  612. {
  613. unsigned start = aIncludeDefaultFields ? 0 : MANDATORY_FIELDS;
  614. for( unsigned i = start; i < m_Fields.size(); ++i )
  615. {
  616. if( aFieldName == m_Fields[i].GetName( false ) )
  617. return &m_Fields[i];
  618. }
  619. return NULL;
  620. }
  621. void SCH_COMPONENT::UpdateFields( bool aResetStyle, bool aResetRef )
  622. {
  623. if( m_part )
  624. {
  625. wxString symbolName;
  626. LIB_FIELDS fields;
  627. m_part->GetFields( fields );
  628. for( const LIB_FIELD& libField : fields )
  629. {
  630. int idx = libField.GetId();
  631. SCH_FIELD* schField;
  632. if( idx == REFERENCE && !aResetRef )
  633. continue;
  634. if( idx >= 0 && idx < MANDATORY_FIELDS )
  635. schField = GetField( idx );
  636. else
  637. {
  638. schField = FindField( libField.GetCanonicalName() );
  639. if( !schField )
  640. {
  641. wxString fieldName = libField.GetCanonicalName();
  642. SCH_FIELD newField( wxPoint( 0, 0), GetFieldCount(), this, fieldName );
  643. schField = AddField( newField );
  644. }
  645. }
  646. if( aResetStyle )
  647. {
  648. schField->ImportValues( libField );
  649. schField->SetTextPos( m_Pos + libField.GetTextPos() );
  650. }
  651. if( idx == VALUE )
  652. {
  653. schField->SetText( m_lib_id.GetLibItemName() ); // fetch alias-specific value
  654. symbolName = m_lib_id.GetLibItemName();
  655. }
  656. else if( idx == DATASHEET )
  657. {
  658. schField->SetText( GetDatasheet() ); // fetch alias-specific value
  659. // Some older libraries may be broken and the alias datasheet information
  660. // in the document file for the root part may have been dropped. This only
  661. // happens for the root part.
  662. if( schField->GetText().IsEmpty() && symbolName == m_part->GetName() )
  663. schField->SetText( m_part->GetField( DATASHEET )->GetText() );
  664. }
  665. else
  666. {
  667. schField->SetText( libField.GetText() );
  668. }
  669. }
  670. }
  671. }
  672. LIB_PIN* SCH_COMPONENT::GetPin( const wxString& number )
  673. {
  674. if( m_part )
  675. {
  676. return m_part->GetPin( number, m_unit, m_convert );
  677. }
  678. return NULL;
  679. }
  680. void SCH_COMPONENT::GetPins( std::vector<LIB_PIN*>& aPinsList )
  681. {
  682. if( m_part )
  683. m_part->GetPins( aPinsList, m_unit, m_convert );
  684. }
  685. SCH_PIN_PTRS SCH_COMPONENT::GetSchPins( const SCH_SHEET_PATH* aSheet ) const
  686. {
  687. if( aSheet == nullptr )
  688. aSheet = g_CurrentSheet;
  689. // TODO(JE) if this works, consider caching in m_sheet_pins
  690. int unit = GetUnitSelection( aSheet );
  691. SCH_PIN_PTRS ptrs;
  692. for( const auto& p : m_pins )
  693. {
  694. if( unit && p->GetLibPin()->GetUnit() && ( p->GetLibPin()->GetUnit() != unit ) )
  695. continue;
  696. ptrs.push_back( p.get() );
  697. }
  698. return ptrs;
  699. }
  700. void SCH_COMPONENT::SwapData( SCH_ITEM* aItem )
  701. {
  702. wxCHECK_RET( (aItem != NULL) && (aItem->Type() == SCH_COMPONENT_T),
  703. wxT( "Cannot swap data with invalid component." ) );
  704. SCH_COMPONENT* component = (SCH_COMPONENT*) aItem;
  705. std::swap( m_lib_id, component->m_lib_id );
  706. LIB_PART* part = component->m_part.release();
  707. component->m_part.reset( m_part.release() );
  708. component->UpdatePins();
  709. m_part.reset( part );
  710. UpdatePins();
  711. std::swap( m_Pos, component->m_Pos );
  712. std::swap( m_unit, component->m_unit );
  713. std::swap( m_convert, component->m_convert );
  714. m_Fields.swap( component->m_Fields ); // std::vector's swap()
  715. for( SCH_FIELD& field : component->m_Fields )
  716. field.SetParent( component );
  717. for( SCH_FIELD& field : m_Fields )
  718. field.SetParent( this );
  719. TRANSFORM tmp = m_transform;
  720. m_transform = component->m_transform;
  721. component->m_transform = tmp;
  722. std::swap( m_instanceReferences, component->m_instanceReferences );
  723. }
  724. void SCH_COMPONENT::ClearAnnotation( SCH_SHEET_PATH* aSheetPath )
  725. {
  726. // Build a reference with no annotation,
  727. // i.e. a reference ended by only one '?'
  728. wxString defRef = m_prefix;
  729. if( !IsReferenceStringValid( defRef ) )
  730. { // This is a malformed reference: reinit this reference
  731. m_prefix = defRef = wxT("U"); // Set to default ref prefix
  732. }
  733. while( defRef.Last() == '?' )
  734. defRef.RemoveLast();
  735. defRef.Append( wxT( "?" ) );
  736. if( aSheetPath )
  737. {
  738. KIID_PATH path = aSheetPath->Path();
  739. for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  740. {
  741. if( instance.m_Path == path )
  742. instance.m_Reference = defRef;
  743. }
  744. }
  745. else
  746. {
  747. for( COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  748. instance.m_Reference = defRef;
  749. }
  750. // These 2 changes do not work in complex hierarchy.
  751. // When a clear annotation is made, the calling function must call a
  752. // UpdateAllScreenReferences for the active sheet.
  753. // But this call cannot made here.
  754. m_Fields[REFERENCE].SetText( defRef ); //for drawing.
  755. SetModified();
  756. }
  757. bool SCH_COMPONENT::AddSheetPathReferenceEntryIfMissing( const KIID_PATH& aSheetPath )
  758. {
  759. // a empty sheet path is illegal:
  760. wxCHECK( aSheetPath.size() > 0, false );
  761. wxString reference_path;
  762. for( const COMPONENT_INSTANCE_REFERENCE& instance : m_instanceReferences )
  763. {
  764. // if aSheetPath is found, nothing to do:
  765. if( instance.m_Path == aSheetPath )
  766. return false;
  767. }
  768. // This entry does not exist: add it, with its last-used reference
  769. AddHierarchicalReference( aSheetPath, m_Fields[REFERENCE].GetText(), m_unit );
  770. return true;
  771. }
  772. void SCH_COMPONENT::SetOrientation( int aOrientation )
  773. {
  774. TRANSFORM temp = TRANSFORM();
  775. bool transform = false;
  776. switch( aOrientation )
  777. {
  778. case CMP_ORIENT_0:
  779. case CMP_NORMAL: // default transform matrix
  780. m_transform.x1 = 1;
  781. m_transform.y2 = -1;
  782. m_transform.x2 = m_transform.y1 = 0;
  783. break;
  784. case CMP_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
  785. temp.x1 = temp.y2 = 0;
  786. temp.y1 = 1;
  787. temp.x2 = -1;
  788. transform = true;
  789. break;
  790. case CMP_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
  791. temp.x1 = temp.y2 = 0;
  792. temp.y1 = -1;
  793. temp.x2 = 1;
  794. transform = true;
  795. break;
  796. case CMP_MIRROR_Y: // Mirror Y (incremental rotation)
  797. temp.x1 = -1;
  798. temp.y2 = 1;
  799. temp.y1 = temp.x2 = 0;
  800. transform = true;
  801. break;
  802. case CMP_MIRROR_X: // Mirror X (incremental rotation)
  803. temp.x1 = 1;
  804. temp.y2 = -1;
  805. temp.y1 = temp.x2 = 0;
  806. transform = true;
  807. break;
  808. case CMP_ORIENT_90:
  809. SetOrientation( CMP_ORIENT_0 );
  810. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  811. break;
  812. case CMP_ORIENT_180:
  813. SetOrientation( CMP_ORIENT_0 );
  814. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  815. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  816. break;
  817. case CMP_ORIENT_270:
  818. SetOrientation( CMP_ORIENT_0 );
  819. SetOrientation( CMP_ROTATE_CLOCKWISE );
  820. break;
  821. case ( CMP_ORIENT_0 + CMP_MIRROR_X ):
  822. SetOrientation( CMP_ORIENT_0 );
  823. SetOrientation( CMP_MIRROR_X );
  824. break;
  825. case ( CMP_ORIENT_0 + CMP_MIRROR_Y ):
  826. SetOrientation( CMP_ORIENT_0 );
  827. SetOrientation( CMP_MIRROR_Y );
  828. break;
  829. case ( CMP_ORIENT_90 + CMP_MIRROR_X ):
  830. SetOrientation( CMP_ORIENT_90 );
  831. SetOrientation( CMP_MIRROR_X );
  832. break;
  833. case ( CMP_ORIENT_90 + CMP_MIRROR_Y ):
  834. SetOrientation( CMP_ORIENT_90 );
  835. SetOrientation( CMP_MIRROR_Y );
  836. break;
  837. case ( CMP_ORIENT_180 + CMP_MIRROR_X ):
  838. SetOrientation( CMP_ORIENT_180 );
  839. SetOrientation( CMP_MIRROR_X );
  840. break;
  841. case ( CMP_ORIENT_180 + CMP_MIRROR_Y ):
  842. SetOrientation( CMP_ORIENT_180 );
  843. SetOrientation( CMP_MIRROR_Y );
  844. break;
  845. case ( CMP_ORIENT_270 + CMP_MIRROR_X ):
  846. SetOrientation( CMP_ORIENT_270 );
  847. SetOrientation( CMP_MIRROR_X );
  848. break;
  849. case ( CMP_ORIENT_270 + CMP_MIRROR_Y ):
  850. SetOrientation( CMP_ORIENT_270 );
  851. SetOrientation( CMP_MIRROR_Y );
  852. break;
  853. default:
  854. transform = false;
  855. wxMessageBox( wxT( "SetRotateMiroir() error: ill value" ) );
  856. break;
  857. }
  858. if( transform )
  859. {
  860. /* The new matrix transform is the old matrix transform modified by the
  861. * requested transformation, which is the temp transform (rot,
  862. * mirror ..) in order to have (in term of matrix transform):
  863. * transform coord = new_m_transform * coord
  864. * where transform coord is the coord modified by new_m_transform from
  865. * the initial value coord.
  866. * new_m_transform is computed (from old_m_transform and temp) to
  867. * have:
  868. * transform coord = old_m_transform * temp
  869. */
  870. TRANSFORM newTransform;
  871. newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
  872. newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
  873. newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
  874. newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
  875. m_transform = newTransform;
  876. }
  877. }
  878. int SCH_COMPONENT::GetOrientation()
  879. {
  880. int rotate_values[] =
  881. {
  882. CMP_ORIENT_0,
  883. CMP_ORIENT_90,
  884. CMP_ORIENT_180,
  885. CMP_ORIENT_270,
  886. CMP_MIRROR_X + CMP_ORIENT_0,
  887. CMP_MIRROR_X + CMP_ORIENT_90,
  888. CMP_MIRROR_X + CMP_ORIENT_270,
  889. CMP_MIRROR_Y,
  890. CMP_MIRROR_Y + CMP_ORIENT_0,
  891. CMP_MIRROR_Y + CMP_ORIENT_90,
  892. CMP_MIRROR_Y + CMP_ORIENT_180,
  893. CMP_MIRROR_Y + CMP_ORIENT_270
  894. };
  895. // Try to find the current transform option:
  896. TRANSFORM transform = m_transform;
  897. for( int type_rotate : rotate_values )
  898. {
  899. SetOrientation( type_rotate );
  900. if( transform == m_transform )
  901. return type_rotate;
  902. }
  903. // Error: orientation not found in list (should not happen)
  904. wxMessageBox( wxT( "Component orientation matrix internal error" ) );
  905. m_transform = transform;
  906. return CMP_NORMAL;
  907. }
  908. #if defined(DEBUG)
  909. void SCH_COMPONENT::Show( int nestLevel, std::ostream& os ) const
  910. {
  911. // for now, make it look like XML:
  912. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
  913. << " ref=\"" << TO_UTF8( GetField( 0 )->GetName() )
  914. << '"' << " chipName=\""
  915. << GetLibId().Format() << '"' << m_Pos
  916. << " layer=\"" << m_Layer
  917. << '"' << ">\n";
  918. // skip the reference, it's been output already.
  919. for( int i = 1; i < GetFieldCount(); ++i )
  920. {
  921. wxString value = GetField( i )->GetText();
  922. if( !value.IsEmpty() )
  923. {
  924. NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
  925. << TO_UTF8( GetField( i )->GetName() )
  926. << '"' << " value=\""
  927. << TO_UTF8( value ) << "\"/>\n";
  928. }
  929. }
  930. NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
  931. }
  932. #endif
  933. EDA_RECT SCH_COMPONENT::GetBodyBoundingBox() const
  934. {
  935. EDA_RECT bBox;
  936. if( m_part )
  937. {
  938. bBox = m_part->GetBodyBoundingBox( m_unit, m_convert );
  939. }
  940. else
  941. {
  942. bBox = dummy()->GetBodyBoundingBox( m_unit, m_convert );
  943. }
  944. int x0 = bBox.GetX();
  945. int xm = bBox.GetRight();
  946. // We must reverse Y values, because matrix orientation
  947. // suppose Y axis normal for the library items coordinates,
  948. // m_transform reverse Y values, but bBox is already reversed!
  949. int y0 = -bBox.GetY();
  950. int ym = -bBox.GetBottom();
  951. // Compute the real Boundary box (rotated, mirrored ...)
  952. int x1 = m_transform.x1 * x0 + m_transform.y1 * y0;
  953. int y1 = m_transform.x2 * x0 + m_transform.y2 * y0;
  954. int x2 = m_transform.x1 * xm + m_transform.y1 * ym;
  955. int y2 = m_transform.x2 * xm + m_transform.y2 * ym;
  956. bBox.SetX( x1 );
  957. bBox.SetY( y1 );
  958. bBox.SetWidth( x2 - x1 );
  959. bBox.SetHeight( y2 - y1 );
  960. bBox.Normalize();
  961. bBox.Offset( m_Pos );
  962. return bBox;
  963. }
  964. const EDA_RECT SCH_COMPONENT::GetBoundingBox() const
  965. {
  966. EDA_RECT bbox = GetBodyBoundingBox();
  967. for( size_t i = 0; i < m_Fields.size(); i++ )
  968. bbox.Merge( m_Fields[i].GetBoundingBox() );
  969. return bbox;
  970. }
  971. void SCH_COMPONENT::GetMsgPanelInfo( EDA_UNITS aUnits, MSG_PANEL_ITEMS& aList )
  972. {
  973. wxString msg;
  974. // part and alias can differ if alias is not the root
  975. if( m_part )
  976. {
  977. if( m_part.get() != dummy() )
  978. {
  979. if( g_CurrentSheet )
  980. aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( g_CurrentSheet ),
  981. DARKCYAN ) );
  982. msg = m_part->IsPower() ? _( "Power symbol" ) : _( "Value" );
  983. aList.push_back( MSG_PANEL_ITEM( msg, GetField( VALUE )->GetShownText(), DARKCYAN ) );
  984. // Display component reference in library and library
  985. aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) );
  986. if( !m_part->IsRoot() )
  987. {
  988. msg = _( "Missing parent" );
  989. std::shared_ptr< LIB_PART > parent = m_part->GetParent().lock();
  990. if( parent )
  991. msg = parent->GetName();
  992. aList.push_back( MSG_PANEL_ITEM( _( "Alias of" ), msg, BROWN ) );
  993. }
  994. if( m_part->GetLib() && m_part->GetLib()->IsCache() )
  995. aList.push_back( MSG_PANEL_ITEM( _( "Library" ),
  996. m_part->GetLib()->GetLogicalName(), RED ) );
  997. else if( !m_lib_id.GetLibNickname().empty() )
  998. aList.push_back( MSG_PANEL_ITEM( _( "Library" ), m_lib_id.GetLibNickname(),
  999. BROWN ) );
  1000. else
  1001. aList.push_back( MSG_PANEL_ITEM( _( "Library" ), _( "Undefined!!!" ), RED ) );
  1002. // Display the current associated footprint, if exists.
  1003. if( !GetField( FOOTPRINT )->IsVoid() )
  1004. msg = GetField( FOOTPRINT )->GetShownText();
  1005. else
  1006. msg = _( "<Unknown>" );
  1007. aList.push_back( MSG_PANEL_ITEM( _( "Footprint" ), msg, DARKRED ) );
  1008. // Display description of the component, and keywords found in lib
  1009. aList.push_back( MSG_PANEL_ITEM( _( "Description" ), m_part->GetDescription(),
  1010. DARKCYAN ) );
  1011. aList.push_back( MSG_PANEL_ITEM( _( "Key words" ), m_part->GetKeyWords(), DARKCYAN ) );
  1012. }
  1013. }
  1014. else
  1015. {
  1016. if( g_CurrentSheet )
  1017. aList.push_back( MSG_PANEL_ITEM( _( "Reference" ), GetRef( g_CurrentSheet ),
  1018. DARKCYAN ) );
  1019. aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetField( VALUE )->GetShownText(),
  1020. DARKCYAN ) );
  1021. aList.push_back( MSG_PANEL_ITEM( _( "Name" ), GetLibId().GetLibItemName(), BROWN ) );
  1022. wxString libNickname = GetLibId().GetLibNickname();
  1023. if( libNickname.empty() )
  1024. {
  1025. aList.push_back( MSG_PANEL_ITEM( _( "Library" ), _( "No library defined!" ), RED ) );
  1026. }
  1027. else
  1028. {
  1029. msg.Printf( _( "Symbol not found in %s!" ), libNickname );
  1030. aList.push_back( MSG_PANEL_ITEM( _( "Library" ), msg , RED ) );
  1031. }
  1032. }
  1033. }
  1034. BITMAP_DEF SCH_COMPONENT::GetMenuImage() const
  1035. {
  1036. return add_component_xpm;
  1037. }
  1038. void SCH_COMPONENT::MirrorY( int aYaxis_position )
  1039. {
  1040. int dx = m_Pos.x;
  1041. SetOrientation( CMP_MIRROR_Y );
  1042. MIRROR( m_Pos.x, aYaxis_position );
  1043. dx -= m_Pos.x; // dx,0 is the move vector for this transform
  1044. for( SCH_FIELD& field : m_Fields )
  1045. {
  1046. // Move the fields to the new position because the component itself has moved.
  1047. wxPoint pos = field.GetTextPos();
  1048. pos.x -= dx;
  1049. field.SetTextPos( pos );
  1050. }
  1051. }
  1052. void SCH_COMPONENT::MirrorX( int aXaxis_position )
  1053. {
  1054. int dy = m_Pos.y;
  1055. SetOrientation( CMP_MIRROR_X );
  1056. MIRROR( m_Pos.y, aXaxis_position );
  1057. dy -= m_Pos.y; // dy,0 is the move vector for this transform
  1058. for( SCH_FIELD& field : m_Fields )
  1059. {
  1060. // Move the fields to the new position because the component itself has moved.
  1061. wxPoint pos = field.GetTextPos();
  1062. pos.y -= dy;
  1063. field.SetTextPos( pos );
  1064. }
  1065. }
  1066. void SCH_COMPONENT::Rotate( wxPoint aPosition )
  1067. {
  1068. wxPoint prev = m_Pos;
  1069. RotatePoint( &m_Pos, aPosition, 900 );
  1070. SetOrientation( CMP_ROTATE_COUNTERCLOCKWISE );
  1071. for( SCH_FIELD& field : m_Fields )
  1072. {
  1073. // Move the fields to the new position because the component itself has moved.
  1074. wxPoint pos = field.GetTextPos();
  1075. pos.x -= prev.x - m_Pos.x;
  1076. pos.y -= prev.y - m_Pos.y;
  1077. field.SetTextPos( pos );
  1078. }
  1079. }
  1080. bool SCH_COMPONENT::Matches( wxFindReplaceData& aSearchData, void* aAuxData )
  1081. {
  1082. wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText( EDA_UNITS::MILLIMETRES ) );
  1083. // Components are searchable via the child field and pin item text.
  1084. return false;
  1085. }
  1086. void SCH_COMPONENT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  1087. {
  1088. if( m_part )
  1089. {
  1090. for( LIB_PIN* pin = m_part->GetNextPin(); pin; pin = m_part->GetNextPin( pin ) )
  1091. {
  1092. wxASSERT( pin->Type() == LIB_PIN_T );
  1093. if( pin->GetUnit() && m_unit && ( m_unit != pin->GetUnit() ) )
  1094. continue;
  1095. if( pin->GetConvert() && m_convert && ( m_convert != pin->GetConvert() ) )
  1096. continue;
  1097. DANGLING_END_ITEM item( PIN_END, pin, GetPinPhysicalPosition( pin ), this );
  1098. aItemList.push_back( item );
  1099. }
  1100. }
  1101. }
  1102. bool SCH_COMPONENT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
  1103. const SCH_SHEET_PATH* aPath )
  1104. {
  1105. bool changed = false;
  1106. for( auto& pin : m_pins )
  1107. {
  1108. bool previousState = pin->IsDangling();
  1109. pin->SetIsDangling( true );
  1110. wxPoint pos = m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos;
  1111. for( DANGLING_END_ITEM& each_item : aItemList )
  1112. {
  1113. // Some people like to stack pins on top of each other in a symbol to indicate
  1114. // internal connection. While technically connected, it is not particularly useful
  1115. // to display them that way, so skip any pins that are in the same symbol as this
  1116. // one.
  1117. if( each_item.GetParent() == this )
  1118. continue;
  1119. switch( each_item.GetType() )
  1120. {
  1121. case PIN_END:
  1122. case LABEL_END:
  1123. case SHEET_LABEL_END:
  1124. case WIRE_START_END:
  1125. case WIRE_END_END:
  1126. case NO_CONNECT_END:
  1127. case JUNCTION_END:
  1128. if( pos == each_item.GetPosition() )
  1129. pin->SetIsDangling( false );
  1130. break;
  1131. default:
  1132. break;
  1133. }
  1134. if( !pin->IsDangling() )
  1135. break;
  1136. }
  1137. changed = ( changed || ( previousState != pin->IsDangling() ) );
  1138. }
  1139. return changed;
  1140. }
  1141. wxPoint SCH_COMPONENT::GetPinPhysicalPosition( const LIB_PIN* Pin ) const
  1142. {
  1143. wxCHECK_MSG( Pin != NULL && Pin->Type() == LIB_PIN_T, wxPoint( 0, 0 ),
  1144. wxT( "Cannot get physical position of pin." ) );
  1145. return m_transform.TransformCoordinate( Pin->GetPosition() ) + m_Pos;
  1146. }
  1147. void SCH_COMPONENT::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
  1148. {
  1149. for( const auto& pin : m_pins )
  1150. {
  1151. // Collect only pins attached to the current unit and convert.
  1152. // others are not associated to this component instance
  1153. int pin_unit = pin.get()->GetLibPin()->GetUnit();
  1154. int pin_convert = pin.get()->GetLibPin()->GetConvert();
  1155. if( pin_unit > 0 && pin_unit != GetUnit() )
  1156. continue;
  1157. if( pin_convert > 0 && pin_convert != GetConvert() )
  1158. continue;
  1159. aPoints.push_back( m_transform.TransformCoordinate( pin->GetPosition() ) + m_Pos );
  1160. }
  1161. }
  1162. LIB_ITEM* SCH_COMPONENT::GetDrawItem( const wxPoint& aPosition, KICAD_T aType )
  1163. {
  1164. UpdatePins();
  1165. if( m_part )
  1166. {
  1167. // Calculate the position relative to the component.
  1168. wxPoint libPosition = aPosition - m_Pos;
  1169. return m_part->LocateDrawItem( m_unit, m_convert, aType, libPosition, m_transform );
  1170. }
  1171. return NULL;
  1172. }
  1173. wxString SCH_COMPONENT::GetSelectMenuText( EDA_UNITS aUnits ) const
  1174. {
  1175. return wxString::Format( _( "Symbol %s, %s" ),
  1176. GetLibId().GetLibItemName().wx_str(),
  1177. GetField( REFERENCE )->GetShownText() );
  1178. }
  1179. SEARCH_RESULT SCH_COMPONENT::Visit( INSPECTOR aInspector, void* aTestData,
  1180. const KICAD_T aFilterTypes[] )
  1181. {
  1182. KICAD_T stype;
  1183. for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
  1184. {
  1185. // If caller wants to inspect component type or and component children types.
  1186. if( stype == SCH_LOCATE_ANY_T || stype == Type() )
  1187. {
  1188. if( SEARCH_RESULT::QUIT == aInspector( this, aTestData ) )
  1189. return SEARCH_RESULT::QUIT;
  1190. }
  1191. if( stype == SCH_LOCATE_ANY_T || stype == SCH_FIELD_T )
  1192. {
  1193. // Test the bounding boxes of fields if they are visible and not empty.
  1194. for( SCH_FIELD& field : m_Fields )
  1195. {
  1196. if( SEARCH_RESULT::QUIT == aInspector( &field, (void*) this ) )
  1197. return SEARCH_RESULT::QUIT;
  1198. }
  1199. }
  1200. if( stype == SCH_FIELD_LOCATE_REFERENCE_T )
  1201. {
  1202. if( SEARCH_RESULT::QUIT == aInspector( GetField( REFERENCE ), (void*) this ) )
  1203. return SEARCH_RESULT::QUIT;
  1204. }
  1205. if( stype == SCH_FIELD_LOCATE_VALUE_T )
  1206. {
  1207. if( SEARCH_RESULT::QUIT == aInspector( GetField( VALUE ), (void*) this ) )
  1208. return SEARCH_RESULT::QUIT;
  1209. }
  1210. if( stype == SCH_FIELD_LOCATE_FOOTPRINT_T )
  1211. {
  1212. if( SEARCH_RESULT::QUIT == aInspector( GetField( FOOTPRINT ), (void*) this ) )
  1213. return SEARCH_RESULT::QUIT;
  1214. }
  1215. if( stype == SCH_FIELD_LOCATE_DATASHEET_T )
  1216. {
  1217. if( SEARCH_RESULT::QUIT == aInspector( GetField( DATASHEET ), (void*) this ) )
  1218. return SEARCH_RESULT::QUIT;
  1219. }
  1220. if( stype == SCH_LOCATE_ANY_T || stype == SCH_PIN_T )
  1221. {
  1222. for( auto& pin : m_pins )
  1223. {
  1224. // Collect only pins attached to the current unit and convert.
  1225. // others are not associated to this component instance
  1226. int pin_unit = pin.get()->GetLibPin()->GetUnit();
  1227. int pin_convert = pin.get()->GetLibPin()->GetConvert();
  1228. if( pin_unit > 0 && pin_unit != GetUnit() )
  1229. continue;
  1230. if( pin_convert > 0 && pin_convert != GetConvert() )
  1231. continue;
  1232. if( SEARCH_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
  1233. return SEARCH_RESULT::QUIT;
  1234. }
  1235. }
  1236. }
  1237. return SEARCH_RESULT::CONTINUE;
  1238. }
  1239. void SCH_COMPONENT::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems,
  1240. SCH_SHEET_PATH* aSheetPath )
  1241. {
  1242. if( m_part )
  1243. {
  1244. for( LIB_PIN* pin = m_part->GetNextPin(); pin; pin = m_part->GetNextPin( pin ) )
  1245. {
  1246. wxASSERT( pin->Type() == LIB_PIN_T );
  1247. if( pin->GetUnit() && ( pin->GetUnit() != GetUnitSelection( aSheetPath ) ) )
  1248. continue;
  1249. if( pin->GetConvert() && ( pin->GetConvert() != GetConvert() ) )
  1250. continue;
  1251. wxPoint pos = GetTransform().TransformCoordinate( pin->GetPosition() ) + m_Pos;
  1252. NETLIST_OBJECT* item = new NETLIST_OBJECT();
  1253. item->m_SheetPathInclude = *aSheetPath;
  1254. item->m_Comp = m_pins[ m_pinMap.at( pin ) ].get();
  1255. item->m_SheetPath = *aSheetPath;
  1256. item->m_Type = NETLIST_ITEM::PIN;
  1257. item->m_Link = (SCH_ITEM*) this;
  1258. item->m_ElectricalPinType = pin->GetType();
  1259. item->m_PinNum = pin->GetNumber();
  1260. item->m_Label = pin->GetName();
  1261. item->m_Start = item->m_End = pos;
  1262. aNetListItems.push_back( item );
  1263. if( pin->IsPowerConnection() )
  1264. {
  1265. // There is an associated PIN_LABEL.
  1266. item = new NETLIST_OBJECT();
  1267. item->m_SheetPathInclude = *aSheetPath;
  1268. item->m_Comp = NULL;
  1269. item->m_SheetPath = *aSheetPath;
  1270. item->m_Type = NETLIST_ITEM::PINLABEL;
  1271. item->m_Label = pin->GetName();
  1272. item->m_Start = pos;
  1273. item->m_End = item->m_Start;
  1274. aNetListItems.push_back( item );
  1275. }
  1276. }
  1277. }
  1278. }
  1279. bool SCH_COMPONENT::operator <( const SCH_ITEM& aItem ) const
  1280. {
  1281. if( Type() != aItem.Type() )
  1282. return Type() < aItem.Type();
  1283. auto component = static_cast<const SCH_COMPONENT*>( &aItem );
  1284. EDA_RECT rect = GetBodyBoundingBox();
  1285. if( rect.GetArea() != component->GetBodyBoundingBox().GetArea() )
  1286. return rect.GetArea() < component->GetBodyBoundingBox().GetArea();
  1287. if( m_Pos.x != component->m_Pos.x )
  1288. return m_Pos.x < component->m_Pos.x;
  1289. if( m_Pos.y != component->m_Pos.y )
  1290. return m_Pos.y < component->m_Pos.y;
  1291. return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
  1292. }
  1293. bool SCH_COMPONENT::operator==( const SCH_COMPONENT& aComponent ) const
  1294. {
  1295. if( GetFieldCount() != aComponent.GetFieldCount() )
  1296. return false;
  1297. for( int i = VALUE; i < GetFieldCount(); i++ )
  1298. {
  1299. if( GetField( i )->GetText().Cmp( aComponent.GetField( i )->GetText() ) != 0 )
  1300. return false;
  1301. }
  1302. return true;
  1303. }
  1304. bool SCH_COMPONENT::operator!=( const SCH_COMPONENT& aComponent ) const
  1305. {
  1306. return !( *this == aComponent );
  1307. }
  1308. SCH_COMPONENT& SCH_COMPONENT::operator=( const SCH_ITEM& aItem )
  1309. {
  1310. wxCHECK_MSG( Type() == aItem.Type(), *this,
  1311. wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
  1312. GetClass() );
  1313. if( &aItem != this )
  1314. {
  1315. SCH_ITEM::operator=( aItem );
  1316. SCH_COMPONENT* c = (SCH_COMPONENT*) &aItem;
  1317. m_lib_id = c->m_lib_id;
  1318. LIB_PART* libSymbol = c->m_part ? new LIB_PART( *c->m_part.get() ) : nullptr;
  1319. m_part.reset( libSymbol );
  1320. m_Pos = c->m_Pos;
  1321. m_unit = c->m_unit;
  1322. m_convert = c->m_convert;
  1323. m_transform = c->m_transform;
  1324. m_instanceReferences = c->m_instanceReferences;
  1325. m_Fields = c->m_Fields; // std::vector's assignment operator
  1326. // Reparent fields after assignment to new component.
  1327. for( SCH_FIELD& field : m_Fields )
  1328. field.SetParent( this );
  1329. UpdatePins();
  1330. }
  1331. return *this;
  1332. }
  1333. bool SCH_COMPONENT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  1334. {
  1335. EDA_RECT bBox = GetBodyBoundingBox();
  1336. bBox.Inflate( aAccuracy );
  1337. if( bBox.Contains( aPosition ) )
  1338. return true;
  1339. return false;
  1340. }
  1341. bool SCH_COMPONENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  1342. {
  1343. if( m_Flags & STRUCT_DELETED || m_Flags & SKIP_STRUCT )
  1344. return false;
  1345. EDA_RECT rect = aRect;
  1346. rect.Inflate( aAccuracy );
  1347. if( aContained )
  1348. return rect.Contains( GetBodyBoundingBox() );
  1349. return rect.Intersects( GetBodyBoundingBox() );
  1350. }
  1351. bool SCH_COMPONENT::doIsConnected( const wxPoint& aPosition ) const
  1352. {
  1353. wxPoint new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_Pos );
  1354. for( const auto& pin : m_pins )
  1355. {
  1356. // Collect only pins attached to the current unit and convert.
  1357. // others are not associated to this component instance
  1358. int pin_unit = pin.get()->GetLibPin()->GetUnit();
  1359. int pin_convert = pin.get()->GetLibPin()->GetConvert();
  1360. if( pin_unit > 0 && pin_unit != GetUnit() )
  1361. continue;
  1362. if( pin_convert > 0 && pin_convert != GetConvert() )
  1363. continue;
  1364. if( pin->GetPosition() == new_pos )
  1365. return true;
  1366. }
  1367. return false;
  1368. }
  1369. bool SCH_COMPONENT::IsInNetlist() const
  1370. {
  1371. return m_isInNetlist;
  1372. }
  1373. void SCH_COMPONENT::Plot( PLOTTER* aPlotter )
  1374. {
  1375. TRANSFORM temp;
  1376. if( m_part )
  1377. {
  1378. temp = GetTransform();
  1379. aPlotter->StartBlock( nullptr );
  1380. m_part->Plot( aPlotter, GetUnit(), GetConvert(), m_Pos, temp );
  1381. for( SCH_FIELD field : m_Fields )
  1382. field.Plot( aPlotter );
  1383. aPlotter->EndBlock( nullptr );
  1384. }
  1385. }
  1386. bool SCH_COMPONENT::HasBrightenedPins()
  1387. {
  1388. for( const auto& pin : m_pins )
  1389. {
  1390. if( pin->IsBrightened() )
  1391. return true;
  1392. }
  1393. return false;
  1394. }
  1395. void SCH_COMPONENT::ClearBrightenedPins()
  1396. {
  1397. for( auto& pin : m_pins )
  1398. pin->ClearBrightened();
  1399. }
  1400. void SCH_COMPONENT::BrightenPin( LIB_PIN* aPin )
  1401. {
  1402. if( m_pinMap.count( aPin ) )
  1403. m_pins[ m_pinMap.at( aPin ) ]->SetBrightened();
  1404. }
  1405. void SCH_COMPONENT::ClearHighlightedPins()
  1406. {
  1407. for( auto& pin : m_pins )
  1408. pin->ClearHighlighted();
  1409. }
  1410. bool SCH_COMPONENT::HasHighlightedPins()
  1411. {
  1412. for( const auto& pin : m_pins )
  1413. {
  1414. if( pin->IsHighlighted() )
  1415. return true;
  1416. }
  1417. return false;
  1418. }
  1419. void SCH_COMPONENT::HighlightPin( LIB_PIN* aPin )
  1420. {
  1421. if( m_pinMap.count( aPin ) )
  1422. m_pins[ m_pinMap.at( aPin ) ]->SetHighlighted();
  1423. }
  1424. bool SCH_COMPONENT::ClearAllHighlightFlags()
  1425. {
  1426. bool retVal = false;
  1427. if( IsHighlighted() )
  1428. {
  1429. ClearFlags( HIGHLIGHTED );
  1430. retVal = true;
  1431. }
  1432. // Clear the HIGHLIGHTED flag of pins
  1433. if( HasHighlightedPins() )
  1434. {
  1435. ClearHighlightedPins();
  1436. retVal = true;
  1437. }
  1438. // Clear the HIGHLIGHTED flag of other items, currently only fields
  1439. for( SCH_FIELD& each_field : m_Fields )
  1440. {
  1441. if( each_field.IsHighlighted() )
  1442. {
  1443. each_field.ClearFlags( HIGHLIGHTED );
  1444. retVal = true;
  1445. }
  1446. }
  1447. return retVal;
  1448. }