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.

3038 lines
90 KiB

Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
2 years ago
2 years ago
6 years ago
6 years ago
2 years ago
2 years ago
2 years ago
6 months ago
18 years ago
18 years ago
18 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
Make the new schematic and symbol library file formats the default. This is a very large and potentially disruptive change so this will be an unusually long and detailed commit message. The new file formats are now the default in both the schematic and symbol library editors. Existing symbol libraries will be saved in their current format until new features are added to library symbols. Once this happens, both the legacy schematic and symbol file formats will be no longer be savable and existing libraries will have to be converted. Saving to the legacy file formats is still available for round robin testing and should not be used for normal editing. When loading the legacy schematic file, it is imperative that the schematic library symbols are rescued and/or remapped to valid library identifiers. Otherwise, there will be no way to link to the original library symbol and the user will be required manually set the library identifier. The cached symbol will be saved in the schematic file so the last library symbol in the cache will still be used but there will be no way to update it from the original library. The next save after loading a legacy schematic file will be converted to the s-expression file format. Schematics with hierarchical sheets will automatically have all sheet file name extensions changed to .kicad_sym and saved to the new format as well. Appending schematics requires that the schematic to append has already been converted to the new file format. This is required to ensure that library symbols are guaranteed to be valid for the appended schematic. The schematic symbol library symbol link resolution has been moved out of the SCH_COMPONENT object and move into the SCH_SCREEN object that owns the symbol. This was done to ensure that there is a single place where the library symbol links get resolved rather than the dozen or so different code paths that previously existed. It also removes the necessity of the SCH_COMPONENT object of requiring any knowledge of the symbol library table and/or the cache library. When opening an s-expression schematic, the legacy cache library is not loaded so any library symbols not rescued cannot be loaded. Broken library symbol links will have to be manually resolved by adding the cache library to the symbol library table and changing the links in the schematic symbol. Now that the library symbols are embedded in the schematic file, the SCH_SCREEN object maintains the list of library symbols for the schematic automatically. No external manipulation of this library cache should ever occur. ADDED: S-expression schematic and symbol library file formats.
6 years ago
18 years ago
18 years ago
2 years ago
2 years ago
1 year 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 The 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 <sch_collectors.h>
  25. #include <sch_commit.h>
  26. #include <sch_edit_frame.h>
  27. #include <widgets/msgpanel.h>
  28. #include <bitmaps.h>
  29. #include <core/mirror.h>
  30. #include <sch_shape.h>
  31. #include <pgm_base.h>
  32. #include <sim/sim_model.h>
  33. #include <sim/spice_generator.h>
  34. #include <sim/sim_lib_mgr.h>
  35. #include <trace_helpers.h>
  36. #include <trigo.h>
  37. #include <refdes_utils.h>
  38. #include <wx/log.h>
  39. #include <settings/settings_manager.h>
  40. #include <sch_plotter.h>
  41. #include <string_utils.h>
  42. #include <geometry/geometry_utils.h>
  43. #include <sch_rule_area.h>
  44. #include <utility>
  45. #include <validators.h>
  46. std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache;
  47. /**
  48. * Convert a wxString to UTF8 and replace any control characters with a ~, where a control
  49. * character is one of the first ASCII values up to ' ' 32d.
  50. */
  51. std::string toUTFTildaText( const wxString& txt )
  52. {
  53. std::string ret = TO_UTF8( txt );
  54. for( char& c : ret )
  55. {
  56. if( (unsigned char) c <= ' ' )
  57. c = '~';
  58. }
  59. return ret;
  60. }
  61. SCH_SYMBOL::SCH_SYMBOL() :
  62. SYMBOL( nullptr, SCH_SYMBOL_T )
  63. {
  64. Init( VECTOR2I( 0, 0 ) );
  65. }
  66. SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const LIB_ID& aLibId,
  67. const SCH_SHEET_PATH* aSheet, int aUnit, int aBodyStyle,
  68. const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
  69. SYMBOL( aParent, SCH_SYMBOL_T )
  70. {
  71. Init( aPosition );
  72. m_unit = aUnit;
  73. m_bodyStyle = aBodyStyle;
  74. m_lib_id = aLibId;
  75. std::unique_ptr< LIB_SYMBOL > part;
  76. part = aSymbol.Flatten();
  77. part->SetParent();
  78. SetLibSymbol( part.release() );
  79. // Copy fields from the library symbol
  80. UpdateFields( aSheet,
  81. true, /* update style */
  82. false, /* update ref */
  83. false, /* update other fields */
  84. true, /* reset ref */
  85. true /* reset other fields */ );
  86. m_prefix = UTIL::GetRefDesPrefix( m_part->GetReferenceField().GetText() );
  87. if( aSheet )
  88. SetRef( aSheet, UTIL::GetRefDesUnannotated( m_prefix ) );
  89. // Inherit the include in bill of materials and board netlist settings from flattened
  90. // library symbol.
  91. m_excludedFromSim = m_part->GetExcludedFromSim();
  92. m_excludedFromBOM = m_part->GetExcludedFromBOM();
  93. m_excludedFromBoard = m_part->GetExcludedFromBoard();
  94. }
  95. SCH_SYMBOL::SCH_SYMBOL( const LIB_SYMBOL& aSymbol, const SCH_SHEET_PATH* aSheet,
  96. const PICKED_SYMBOL& aSel, const VECTOR2I& aPosition, EDA_ITEM* aParent ) :
  97. SCH_SYMBOL( aSymbol, aSel.LibId, aSheet, aSel.Unit, aSel.Convert, aPosition, aParent )
  98. {
  99. // Set any fields that were modified as part of the symbol selection
  100. for( const auto& [fieldId, fieldValue] : aSel.Fields )
  101. {
  102. if( fieldId == FIELD_T::REFERENCE )
  103. SetRef( aSheet, fieldValue );
  104. else if( SCH_FIELD* field = GetField( fieldId ) )
  105. field->SetText( fieldValue );
  106. }
  107. }
  108. SCH_SYMBOL::SCH_SYMBOL( const SCH_SYMBOL& aSymbol ) :
  109. SYMBOL( aSymbol )
  110. {
  111. m_parent = aSymbol.m_parent;
  112. m_pos = aSymbol.m_pos;
  113. m_unit = aSymbol.m_unit;
  114. m_bodyStyle = aSymbol.m_bodyStyle;
  115. m_lib_id = aSymbol.m_lib_id;
  116. m_isInNetlist = aSymbol.m_isInNetlist;
  117. m_DNP = aSymbol.m_DNP;
  118. const_cast<KIID&>( m_Uuid ) = aSymbol.m_Uuid;
  119. m_transform = aSymbol.m_transform;
  120. m_prefix = aSymbol.m_prefix;
  121. m_instanceReferences = aSymbol.m_instanceReferences;
  122. m_fields = aSymbol.m_fields;
  123. // Re-parent the fields, which before this had aSymbol as parent
  124. for( SCH_FIELD& field : m_fields )
  125. field.SetParent( this );
  126. m_pins.clear();
  127. // Copy (and re-parent) the pins
  128. for( const std::unique_ptr<SCH_PIN>& pin : aSymbol.m_pins )
  129. {
  130. m_pins.emplace_back( std::make_unique<SCH_PIN>( *pin ) );
  131. m_pins.back()->SetParent( this );
  132. }
  133. if( aSymbol.m_part )
  134. SetLibSymbol( new LIB_SYMBOL( *aSymbol.m_part ) );
  135. m_fieldsAutoplaced = aSymbol.m_fieldsAutoplaced;
  136. m_schLibSymbolName = aSymbol.m_schLibSymbolName;
  137. }
  138. SCH_SYMBOL::~SCH_SYMBOL()
  139. {
  140. }
  141. void SCH_SYMBOL::Init( const VECTOR2I& pos )
  142. {
  143. m_layer = LAYER_DEVICE;
  144. m_pos = pos;
  145. m_unit = 1; // In multi unit chip - which unit to draw.
  146. m_bodyStyle = BODY_STYLE::BASE; // De Morgan Handling
  147. // The rotation/mirror transformation matrix. pos normal
  148. m_transform = TRANSFORM();
  149. auto addField =
  150. [&]( FIELD_T id, SCH_LAYER_ID layer )
  151. {
  152. m_fields.emplace_back( this, id, GetCanonicalFieldName( id ) );
  153. m_fields.back().SetTextPos( pos );
  154. m_fields.back().SetLayer( layer );
  155. };
  156. // construct only the mandatory fields
  157. addField( FIELD_T::REFERENCE, LAYER_REFERENCEPART );
  158. addField( FIELD_T::VALUE, LAYER_VALUEPART );
  159. addField( FIELD_T::FOOTPRINT, LAYER_FIELDS );
  160. addField( FIELD_T::DATASHEET, LAYER_FIELDS );
  161. addField( FIELD_T::DESCRIPTION, LAYER_FIELDS );
  162. m_prefix = wxString( wxT( "U" ) );
  163. m_isInNetlist = true;
  164. }
  165. EDA_ITEM* SCH_SYMBOL::Clone() const
  166. {
  167. return new SCH_SYMBOL( *this );
  168. }
  169. bool SCH_SYMBOL::IsMissingLibSymbol() const
  170. {
  171. return m_part == nullptr;
  172. }
  173. bool SCH_SYMBOL::IsMovableFromAnchorPoint() const
  174. {
  175. // If a symbol's anchor is not grid-aligned to its pins then moving from the anchor is
  176. // going to end up moving the symbol's pins off-grid.
  177. // The minimal grid size allowed to place a pin is 25 mils
  178. const int min_grid_size = schIUScale.MilsToIU( 25 );
  179. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  180. {
  181. if( ( ( pin->GetPosition().x - m_pos.x ) % min_grid_size ) != 0 )
  182. return false;
  183. if( ( ( pin->GetPosition().y - m_pos.y ) % min_grid_size ) != 0 )
  184. return false;
  185. }
  186. return true;
  187. }
  188. void SCH_SYMBOL::SetLibId( const LIB_ID& aLibId )
  189. {
  190. m_lib_id = aLibId;
  191. }
  192. wxString SCH_SYMBOL::GetSchSymbolLibraryName() const
  193. {
  194. if( !m_schLibSymbolName.IsEmpty() )
  195. return m_schLibSymbolName;
  196. else
  197. return m_lib_id.Format();
  198. }
  199. void SCH_SYMBOL::SetLibSymbol( LIB_SYMBOL* aLibSymbol )
  200. {
  201. wxCHECK2( !aLibSymbol || aLibSymbol->IsRoot(), aLibSymbol = nullptr );
  202. m_part.reset( aLibSymbol );
  203. // We've just reset the library symbol, so the lib_pins, which were just
  204. // pointers to the old symbol, need to be cleared.
  205. for( auto& pin : m_pins )
  206. pin->SetLibPin( nullptr );
  207. UpdatePins();
  208. }
  209. wxString SCH_SYMBOL::GetDescription() const
  210. {
  211. if( m_part )
  212. return m_part->GetDescription();
  213. return wxEmptyString;
  214. }
  215. wxString SCH_SYMBOL::GetKeyWords() const
  216. {
  217. if( m_part )
  218. return m_part->GetKeyWords();
  219. return wxEmptyString;
  220. }
  221. wxString SCH_SYMBOL::GetDatasheet() const
  222. {
  223. if( m_part )
  224. return m_part->GetDatasheetField().GetText();
  225. return wxEmptyString;
  226. }
  227. void SCH_SYMBOL::UpdatePins()
  228. {
  229. std::map<wxString, wxString> altPinMap;
  230. std::map<wxString, SCH_PIN::ALT> altPinDefs;
  231. std::map<wxString, std::set<SCH_PIN*>> pinUuidMap;
  232. std::set<SCH_PIN*> unassignedSchPins;
  233. std::set<SCH_PIN*> unassignedLibPins;
  234. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  235. {
  236. pinUuidMap[ pin->GetNumber() ].insert( pin.get() );
  237. unassignedSchPins.insert( pin.get() );
  238. if( !pin->GetAlt().IsEmpty() )
  239. {
  240. altPinMap[ pin->GetNumber() ] = pin->GetAlt();
  241. auto altDefIt = pin->GetAlternates().find( pin->GetAlt() );
  242. if( altDefIt != pin->GetAlternates().end() )
  243. altPinDefs[ pin->GetNumber() ] = altDefIt->second;
  244. }
  245. pin->SetLibPin( nullptr );
  246. }
  247. m_pinMap.clear();
  248. if( !m_part )
  249. return;
  250. for( SCH_PIN* libPin : m_part->GetPins() )
  251. {
  252. // NW: Don't filter by unit: this data-structure is used for all instances,
  253. // some of which might have different units.
  254. if( libPin->GetBodyStyle() && m_bodyStyle && m_bodyStyle != libPin->GetBodyStyle() )
  255. continue;
  256. SCH_PIN* pin = nullptr;
  257. auto ii = pinUuidMap.find( libPin->GetNumber() );
  258. if( ii == pinUuidMap.end() || ii->second.empty() )
  259. {
  260. unassignedLibPins.insert( libPin );
  261. continue;
  262. }
  263. auto it = ii->second.begin();
  264. pin = *it;
  265. ii->second.erase( it );
  266. pin->GetAlternates() = libPin->GetAlternates();
  267. pin->SetLibPin( libPin );
  268. pin->SetPosition( libPin->GetPosition() );
  269. unassignedSchPins.erase( pin );
  270. auto iii = altPinMap.find( libPin->GetNumber() );
  271. if( iii != altPinMap.end() )
  272. {
  273. wxString altName = iii->second;
  274. if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
  275. {
  276. auto defIt = altPinDefs.find( libPin->GetNumber() );
  277. if( defIt != altPinDefs.end() )
  278. {
  279. for( const auto& [ name, alt ] : pin->GetAlternates() )
  280. {
  281. if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
  282. {
  283. altName = name;
  284. break;
  285. }
  286. }
  287. }
  288. }
  289. pin->SetAlt( altName );
  290. }
  291. m_pinMap[ libPin ] = pin;
  292. }
  293. // Add any pins that were not found in the symbol
  294. for( SCH_PIN* libPin : unassignedLibPins )
  295. {
  296. SCH_PIN* pin = nullptr;
  297. // First try to re-use an existing pin
  298. if( !unassignedSchPins.empty() )
  299. {
  300. auto it = unassignedSchPins.begin();
  301. pin = *it;
  302. unassignedSchPins.erase( it );
  303. }
  304. else
  305. {
  306. // This is a pin that was not found in the symbol, so create a new one.
  307. pin = m_pins.emplace_back( std::make_unique<SCH_PIN>( SCH_PIN( this, libPin ) ) ).get();
  308. }
  309. m_pinMap[ libPin ] = pin;
  310. pin->GetAlternates() = libPin->GetAlternates();
  311. pin->SetLibPin( libPin );
  312. pin->SetPosition( libPin->GetPosition() );
  313. pin->SetNumber( libPin->GetNumber() );
  314. auto iii = altPinMap.find( libPin->GetNumber() );
  315. if( iii != altPinMap.end() )
  316. {
  317. wxString altName = iii->second;
  318. if( pin->GetAlternates().find( altName ) == pin->GetAlternates().end() )
  319. {
  320. auto defIt = altPinDefs.find( libPin->GetNumber() );
  321. if( defIt != altPinDefs.end() )
  322. {
  323. for( const auto& [ name, alt ] : pin->GetAlternates() )
  324. {
  325. if( alt.m_Shape == defIt->second.m_Shape && alt.m_Type == defIt->second.m_Type )
  326. {
  327. altName = name;
  328. break;
  329. }
  330. }
  331. }
  332. }
  333. pin->SetAlt( altName );
  334. }
  335. }
  336. // If we have any pins left in the symbol that were not found in the library, remove them.
  337. for( auto it1 = m_pins.begin(); it1 != m_pins.end() && !unassignedSchPins.empty(); )
  338. {
  339. auto it2 = unassignedSchPins.find( it1->get() );
  340. if( it2 != unassignedSchPins.end() )
  341. {
  342. it1 = m_pins.erase( it1 );
  343. unassignedSchPins.erase( it2 );
  344. }
  345. else
  346. {
  347. ++it1;
  348. }
  349. }
  350. // If the symbol is selected, then its pins are selected.
  351. if( IsSelected() )
  352. {
  353. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  354. pin->SetSelected();
  355. }
  356. }
  357. void SCH_SYMBOL::SetBodyStyle( int aBodyStyle )
  358. {
  359. if( aBodyStyle != m_bodyStyle )
  360. {
  361. m_bodyStyle = aBodyStyle;
  362. // The body style may have a different pin layout so the update the pin map.
  363. UpdatePins();
  364. }
  365. }
  366. int SCH_SYMBOL::GetUnitCount() const
  367. {
  368. if( m_part )
  369. return m_part->GetUnitCount();
  370. return 0;
  371. }
  372. int SCH_SYMBOL::GetBodyStyleCount() const
  373. {
  374. if( m_part )
  375. return m_part->GetBodyStyleCount();
  376. return 0;
  377. }
  378. bool SCH_SYMBOL::HasDeMorganBodyStyles() const
  379. {
  380. if( m_part )
  381. return m_part->HasDeMorganBodyStyles();
  382. return false;
  383. }
  384. wxString SCH_SYMBOL::GetUnitDisplayName( int aUnit, bool aLabel ) const
  385. {
  386. if( m_part )
  387. return m_part->GetUnitDisplayName( aUnit, aLabel );
  388. else if( aLabel )
  389. return wxString::Format( _( "Unit %s" ), SubReference( aUnit ) );
  390. else
  391. return SubReference( aUnit );
  392. }
  393. wxString SCH_SYMBOL::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
  394. {
  395. if( m_part )
  396. return m_part->GetBodyStyleDescription( aBodyStyle, aLabel );
  397. else
  398. return wxT( "?" );
  399. }
  400. bool SCH_SYMBOL::GetInstance( SCH_SYMBOL_INSTANCE& aInstance, const KIID_PATH& aSheetPath,
  401. bool aTestFromEnd ) const
  402. {
  403. for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  404. {
  405. if( !aTestFromEnd )
  406. {
  407. if( instance.m_Path == aSheetPath )
  408. {
  409. aInstance = instance;
  410. return true;
  411. }
  412. }
  413. else if( instance.m_Path.EndsWith( aSheetPath ) )
  414. {
  415. aInstance = instance;
  416. return true;
  417. }
  418. }
  419. return false;
  420. }
  421. void SCH_SYMBOL::RemoveInstance( const SCH_SHEET_PATH& aInstancePath )
  422. {
  423. RemoveInstance( aInstancePath.Path() );
  424. }
  425. void SCH_SYMBOL::RemoveInstance( const KIID_PATH& aInstancePath )
  426. {
  427. // Search for an existing path and remove it if found
  428. // (search from back to avoid invalidating iterator on remove)
  429. for( int ii = m_instanceReferences.size() - 1; ii >= 0; --ii )
  430. {
  431. if( m_instanceReferences[ii].m_Path == aInstancePath )
  432. {
  433. wxLogTrace( traceSchSheetPaths, wxS( "Removing symbol instance:\n"
  434. " sheet path %s\n"
  435. " reference %s, unit %d from symbol %s." ),
  436. aInstancePath.AsString(),
  437. m_instanceReferences[ii].m_Reference,
  438. m_instanceReferences[ii].m_Unit,
  439. m_Uuid.AsString() );
  440. m_instanceReferences.erase( m_instanceReferences.begin() + ii );
  441. }
  442. }
  443. }
  444. void SCH_SYMBOL::AddHierarchicalReference( const KIID_PATH& aPath, const wxString& aRef, int aUnit )
  445. {
  446. SCH_SYMBOL_INSTANCE instance;
  447. instance.m_Path = aPath;
  448. instance.m_Reference = aRef;
  449. instance.m_Unit = aUnit;
  450. AddHierarchicalReference( instance );
  451. }
  452. void SCH_SYMBOL::AddHierarchicalReference( const SCH_SYMBOL_INSTANCE& aInstance )
  453. {
  454. RemoveInstance( aInstance.m_Path );
  455. SCH_SYMBOL_INSTANCE instance = aInstance;
  456. wxLogTrace( traceSchSheetPaths, wxS( "Adding symbol '%s' instance:\n"
  457. " sheet path '%s'\n"
  458. " reference '%s'\n"
  459. " unit %d\n" ),
  460. m_Uuid.AsString(),
  461. instance.m_Path.AsString(),
  462. instance.m_Reference,
  463. instance.m_Unit );
  464. m_instanceReferences.push_back( instance );
  465. // This should set the default instance to the first saved instance data for each symbol
  466. // when importing sheets.
  467. if( m_instanceReferences.size() == 1 )
  468. {
  469. GetField( FIELD_T::REFERENCE )->SetText( instance.m_Reference );
  470. m_unit = instance.m_Unit;
  471. }
  472. }
  473. const wxString SCH_SYMBOL::GetRef( const SCH_SHEET_PATH* sheet, bool aIncludeUnit ) const
  474. {
  475. KIID_PATH path = sheet->Path();
  476. wxString ref;
  477. wxString subRef;
  478. for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  479. {
  480. if( instance.m_Path == path )
  481. {
  482. ref = instance.m_Reference;
  483. subRef = SubReference( instance.m_Unit );
  484. break;
  485. }
  486. }
  487. // If it was not found in m_Paths array, then see if it is in m_Field[REFERENCE] -- if so,
  488. // use this as a default for this path. This will happen if we load a version 1 schematic
  489. // file. It will also mean that multiple instances of the same sheet by default all have
  490. // the same symbol references, but perhaps this is best.
  491. if( ref.IsEmpty() && !GetField( FIELD_T::REFERENCE )->GetText().IsEmpty() )
  492. ref = GetField( FIELD_T::REFERENCE )->GetText();
  493. if( ref.IsEmpty() )
  494. ref = UTIL::GetRefDesUnannotated( m_prefix );
  495. if( aIncludeUnit && GetUnitCount() > 1 )
  496. ref += subRef;
  497. return ref;
  498. }
  499. void SCH_SYMBOL::SetRefProp( const wxString& aRef )
  500. {
  501. FIELD_VALIDATOR validator( FIELD_T::REFERENCE );
  502. if( validator.DoValidate( aRef, nullptr ) )
  503. SetRef( &Schematic()->CurrentSheet(), aRef );
  504. }
  505. void SCH_SYMBOL::SetRef( const SCH_SHEET_PATH* sheet, const wxString& ref )
  506. {
  507. KIID_PATH path = sheet->Path();
  508. bool found = false;
  509. // check to see if it is already there before inserting it
  510. for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  511. {
  512. if( instance.m_Path == path )
  513. {
  514. found = true;
  515. instance.m_Reference = ref;
  516. break;
  517. }
  518. }
  519. if( !found )
  520. AddHierarchicalReference( path, ref, m_unit );
  521. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  522. pin->ClearDefaultNetName( sheet );
  523. if( Schematic() && *sheet == Schematic()->CurrentSheet() )
  524. GetField( FIELD_T::REFERENCE )->SetText( ref );
  525. // Reinit the m_prefix member if needed
  526. m_prefix = UTIL::GetRefDesPrefix( ref );
  527. if( m_prefix.IsEmpty() )
  528. m_prefix = wxT( "U" );
  529. // Power symbols have references starting with # and are not included in netlists
  530. m_isInNetlist = ! ref.StartsWith( wxT( "#" ) );
  531. }
  532. bool SCH_SYMBOL::IsAnnotated( const SCH_SHEET_PATH* aSheet ) const
  533. {
  534. KIID_PATH path = aSheet->Path();
  535. for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  536. {
  537. if( instance.m_Path == path )
  538. return !instance.m_Reference.IsEmpty() && instance.m_Reference.Last() != '?';
  539. }
  540. return false;
  541. }
  542. void SCH_SYMBOL::UpdatePrefix()
  543. {
  544. wxString refDesignator = GetField( FIELD_T::REFERENCE )->GetText();
  545. refDesignator.Replace( "~", " " );
  546. wxString prefix = refDesignator;
  547. while( prefix.Length() )
  548. {
  549. wxUniCharRef last = prefix.Last();
  550. if( ( last >= '0' && last <= '9' ) || last == '?' || last == '*' )
  551. prefix.RemoveLast();
  552. else
  553. break;
  554. }
  555. // Avoid a prefix containing trailing/leading spaces
  556. prefix.Trim( true );
  557. prefix.Trim( false );
  558. if( !prefix.IsEmpty() )
  559. SetPrefix( prefix );
  560. }
  561. wxString SCH_SYMBOL::SubReference( int aUnit, bool aAddSeparator ) const
  562. {
  563. if( SCHEMATIC* schematic = Schematic() )
  564. return schematic->Settings().SubReference( aUnit, aAddSeparator );
  565. return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
  566. }
  567. int SCH_SYMBOL::GetUnitSelection( const SCH_SHEET_PATH* aSheet ) const
  568. {
  569. KIID_PATH path = aSheet->Path();
  570. for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  571. {
  572. if( instance.m_Path == path )
  573. return instance.m_Unit;
  574. }
  575. // If it was not found in m_Paths array, then use m_unit. This will happen if we load a
  576. // version 1 schematic file.
  577. return m_unit;
  578. }
  579. void SCH_SYMBOL::SetUnitSelection( const SCH_SHEET_PATH* aSheet, int aUnitSelection )
  580. {
  581. KIID_PATH path = aSheet->Path();
  582. // check to see if it is already there before inserting it
  583. for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  584. {
  585. if( instance.m_Path == path )
  586. {
  587. instance.m_Unit = aUnitSelection;
  588. return;
  589. }
  590. }
  591. // didn't find it; better add it
  592. AddHierarchicalReference( path, UTIL::GetRefDesUnannotated( m_prefix ), aUnitSelection );
  593. }
  594. void SCH_SYMBOL::SetUnitSelection( int aUnitSelection )
  595. {
  596. for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  597. instance.m_Unit = aUnitSelection;
  598. }
  599. const wxString SCH_SYMBOL::GetValue( bool aResolve, const SCH_SHEET_PATH* aPath,
  600. bool aAllowExtraText ) const
  601. {
  602. if( aResolve )
  603. return GetField( FIELD_T::VALUE )->GetShownText( aPath, aAllowExtraText );
  604. return GetField( FIELD_T::VALUE )->GetText();
  605. }
  606. void SCH_SYMBOL::SetValueFieldText( const wxString& aValue )
  607. {
  608. GetField( FIELD_T::VALUE )->SetText( aValue );
  609. }
  610. const wxString SCH_SYMBOL::GetFootprintFieldText( bool aResolve, const SCH_SHEET_PATH* aPath,
  611. bool aAllowExtraText ) const
  612. {
  613. if( aResolve )
  614. return GetField( FIELD_T::FOOTPRINT )->GetShownText( aPath, aAllowExtraText );
  615. return GetField( FIELD_T::FOOTPRINT )->GetText();
  616. }
  617. void SCH_SYMBOL::SetFootprintFieldText( const wxString& aFootprint )
  618. {
  619. GetField( FIELD_T::FOOTPRINT )->SetText( aFootprint );
  620. }
  621. SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType )
  622. {
  623. if( SCH_FIELD* field = FindField( m_fields, aFieldType ) )
  624. return field;
  625. m_fields.emplace_back( this, aFieldType );
  626. return &m_fields.back();
  627. }
  628. const SCH_FIELD* SCH_SYMBOL::GetField( FIELD_T aFieldType ) const
  629. {
  630. return FindField( m_fields, aFieldType );
  631. }
  632. SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName )
  633. {
  634. return FindField( m_fields, aFieldName );
  635. }
  636. const SCH_FIELD* SCH_SYMBOL::GetField( const wxString& aFieldName ) const
  637. {
  638. return FindField( m_fields, aFieldName );
  639. }
  640. void SCH_SYMBOL::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly ) const
  641. {
  642. for( const SCH_FIELD& field : m_fields )
  643. {
  644. if( aVisibleOnly )
  645. {
  646. if( !field.IsVisible() || field.GetText().IsEmpty() )
  647. continue;
  648. }
  649. aVector.push_back( const_cast<SCH_FIELD*>( &field ) );
  650. }
  651. std::sort( aVector.begin(), aVector.end(),
  652. []( SCH_FIELD* lhs, SCH_FIELD* rhs )
  653. {
  654. return lhs->GetOrdinal() < rhs->GetOrdinal();
  655. } );
  656. }
  657. int SCH_SYMBOL::GetNextFieldOrdinal() const
  658. {
  659. return NextFieldOrdinal( m_fields );
  660. }
  661. SCH_FIELD* SCH_SYMBOL::AddField( const SCH_FIELD& aField )
  662. {
  663. m_fields.push_back( aField );
  664. return &m_fields.back();
  665. }
  666. void SCH_SYMBOL::RemoveField( const wxString& aFieldName )
  667. {
  668. for( unsigned ii = 0; ii < m_fields.size(); ++ii )
  669. {
  670. if( m_fields[ii].IsMandatory() )
  671. continue;
  672. if( aFieldName == m_fields[ii].GetName( false ) )
  673. {
  674. m_fields.erase( m_fields.begin() + ii );
  675. return;
  676. }
  677. }
  678. }
  679. SCH_FIELD* SCH_SYMBOL::FindFieldCaseInsensitive( const wxString& aFieldName )
  680. {
  681. for( SCH_FIELD& field : m_fields )
  682. {
  683. if( field.GetName().IsSameAs( aFieldName, false ) )
  684. return &field;
  685. }
  686. return nullptr;
  687. }
  688. void SCH_SYMBOL::UpdateFields( const SCH_SHEET_PATH* aPath, bool aUpdateStyle, bool aUpdateRef,
  689. bool aUpdateOtherFields, bool aResetRef, bool aResetOtherFields )
  690. {
  691. if( m_part )
  692. {
  693. std::vector<SCH_FIELD*> fields;
  694. m_part->GetFields( fields );
  695. for( const SCH_FIELD* libField : fields )
  696. {
  697. SCH_FIELD* schField;
  698. FIELD_T fieldType = FIELD_T::USER;
  699. if( libField->IsMandatory() )
  700. {
  701. fieldType = libField->GetId();
  702. schField = GetField( fieldType );
  703. }
  704. else
  705. {
  706. schField = GetField( libField->GetCanonicalName() );
  707. if( !schField )
  708. {
  709. schField = AddField( SCH_FIELD( this, FIELD_T::USER, libField->GetCanonicalName() ) );
  710. schField->ImportValues( *libField );
  711. schField->SetTextPos( m_pos + libField->GetTextPos() );
  712. }
  713. }
  714. schField->SetPrivate( libField->IsPrivate() );
  715. if( aUpdateStyle )
  716. {
  717. schField->ImportValues( *libField );
  718. schField->SetTextPos( m_pos + libField->GetTextPos() );
  719. }
  720. if( fieldType == FIELD_T::REFERENCE && aPath )
  721. {
  722. if( aResetRef )
  723. SetRef( aPath, m_part->GetField( FIELD_T::REFERENCE )->GetText() );
  724. else if( aUpdateRef )
  725. SetRef( aPath, libField->GetText() );
  726. }
  727. else if( fieldType == FIELD_T::VALUE )
  728. {
  729. SetValueFieldText( UnescapeString( libField->GetText() ) );
  730. }
  731. else if( fieldType == FIELD_T::DATASHEET )
  732. {
  733. if( aResetOtherFields )
  734. schField->SetText( GetDatasheet() ); // alias-specific value
  735. else if( aUpdateOtherFields )
  736. schField->SetText( libField->GetText() );
  737. }
  738. else
  739. {
  740. if( aResetOtherFields || aUpdateOtherFields )
  741. schField->SetText( libField->GetText() );
  742. }
  743. }
  744. }
  745. }
  746. void SCH_SYMBOL::SyncOtherUnits( const SCH_SHEET_PATH& aSourceSheet, SCH_COMMIT& aCommit,
  747. PROPERTY_BASE* aProperty )
  748. {
  749. bool updateValue = true;
  750. bool updateExclFromBOM = true;
  751. bool updateExclFromBoard = true;
  752. bool updateDNP = true;
  753. bool updateOtherFields = true;
  754. bool updatePins = true;
  755. if( aProperty )
  756. {
  757. updateValue = aProperty->Name() == _HKI( "Value" );
  758. updateExclFromBoard = aProperty->Name() == _HKI( "Exclude From Board" );
  759. updateExclFromBOM = aProperty->Name() == _HKI( "Exclude From Bill of Materials" );
  760. updateDNP = aProperty->Name() == _HKI( "Do not Populate" );
  761. updateOtherFields = false;
  762. updatePins = false;
  763. }
  764. if( !updateValue
  765. && !updateExclFromBOM
  766. && !updateExclFromBoard
  767. && !updateDNP
  768. && !updateOtherFields
  769. && !updatePins )
  770. {
  771. return;
  772. }
  773. // Keep fields other than the reference, include/exclude flags, and alternate pin assignments
  774. // in sync in multi-unit parts.
  775. if( GetUnitCount() > 1 && IsAnnotated( &aSourceSheet ) )
  776. {
  777. wxString ref = GetRef( &aSourceSheet );
  778. for( SCH_SHEET_PATH& sheet : Schematic()->Hierarchy() )
  779. {
  780. SCH_SCREEN* screen = sheet.LastScreen();
  781. std::vector<SCH_SYMBOL*> otherUnits;
  782. CollectOtherUnits( ref, m_unit, m_lib_id, sheet, &otherUnits );
  783. for( SCH_SYMBOL* otherUnit : otherUnits )
  784. {
  785. aCommit.Modify( otherUnit, screen );
  786. if( updateValue )
  787. otherUnit->SetValueFieldText( GetField( FIELD_T::VALUE )->GetText() );
  788. if( updateOtherFields )
  789. {
  790. for( SCH_FIELD& field : m_fields )
  791. {
  792. if( field.GetId() == FIELD_T::REFERENCE || field.GetId() == FIELD_T::VALUE )
  793. {
  794. // already handled
  795. continue;
  796. }
  797. SCH_FIELD* otherField;
  798. if( field.IsMandatory() )
  799. otherField = otherUnit->GetField( field.GetId() );
  800. else
  801. otherField = otherUnit->GetField( field.GetName() );
  802. if( otherField )
  803. {
  804. otherField->SetText( field.GetText() );
  805. }
  806. else
  807. {
  808. SCH_FIELD newField( field );
  809. const_cast<KIID&>( newField.m_Uuid ) = KIID();
  810. newField.Offset( -GetPosition() );
  811. newField.Offset( otherUnit->GetPosition() );
  812. newField.SetParent( otherUnit );
  813. otherUnit->AddField( newField );
  814. }
  815. }
  816. for( int ii = (int) otherUnit->GetFields().size() - 1; ii >= 0; ii-- )
  817. {
  818. SCH_FIELD& otherField = otherUnit->GetFields()[ii];
  819. if( !otherField.IsMandatory() && !GetField( otherField.GetName() ) )
  820. otherUnit->GetFields().erase( otherUnit->GetFields().begin() + ii );
  821. }
  822. }
  823. if( updateExclFromBOM )
  824. otherUnit->SetExcludedFromBOM( m_excludedFromBOM );
  825. if( updateExclFromBoard )
  826. otherUnit->SetExcludedFromBoard( m_excludedFromBoard );
  827. if( updateDNP )
  828. otherUnit->SetDNP( m_DNP );
  829. if( updatePins )
  830. {
  831. for( const std::unique_ptr<SCH_PIN>& model_pin : m_pins )
  832. {
  833. SCH_PIN* src_pin = otherUnit->GetPin( model_pin->GetNumber() );
  834. if( src_pin )
  835. src_pin->SetAlt( model_pin->GetAlt() );
  836. }
  837. }
  838. }
  839. }
  840. }
  841. }
  842. void SCH_SYMBOL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction, RECURSE_MODE aMode )
  843. {
  844. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  845. aFunction( pin.get() );
  846. for( SCH_FIELD& field : m_fields )
  847. aFunction( &field );
  848. }
  849. SCH_PIN* SCH_SYMBOL::GetPin( const wxString& aNumber ) const
  850. {
  851. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  852. {
  853. if( pin->GetNumber() == aNumber )
  854. return pin.get();
  855. }
  856. return nullptr;
  857. }
  858. const SCH_PIN* SCH_SYMBOL::GetPin( const VECTOR2I& aPos ) const
  859. {
  860. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  861. {
  862. int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
  863. : GetUnit();
  864. int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
  865. : GetBodyStyle();
  866. if( pin_unit > 0 && pin_unit != GetUnit() )
  867. continue;
  868. if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
  869. continue;
  870. if( pin->GetPosition() == aPos )
  871. return pin.get();
  872. }
  873. return nullptr;
  874. }
  875. std::vector<SCH_PIN*> SCH_SYMBOL::GetLibPins() const
  876. {
  877. if( m_part )
  878. return m_part->GetGraphicalPins( m_unit, m_bodyStyle );
  879. return std::vector<SCH_PIN*>();
  880. }
  881. std::vector<SCH_PIN*> SCH_SYMBOL::GetAllLibPins() const
  882. {
  883. if( m_part )
  884. return m_part->GetPins();
  885. return std::vector<SCH_PIN*>();
  886. }
  887. size_t SCH_SYMBOL::GetFullPinCount() const
  888. {
  889. return m_part ? m_part->GetPinCount() : 0;
  890. }
  891. SCH_PIN* SCH_SYMBOL::GetPin( SCH_PIN* aLibPin ) const
  892. {
  893. auto it = m_pinMap.find( aLibPin );
  894. if( it != m_pinMap.end() )
  895. return it->second;
  896. wxFAIL_MSG_AT( "Pin not found", __FILE__, __LINE__, __FUNCTION__ );
  897. return nullptr;
  898. }
  899. std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
  900. {
  901. std::vector<SCH_PIN*> pins;
  902. int unit = m_unit;
  903. if( !aSheet && Schematic() )
  904. aSheet = &Schematic()->CurrentSheet();
  905. if( aSheet )
  906. unit = GetUnitSelection( aSheet );
  907. for( const std::unique_ptr<SCH_PIN>& p : m_pins )
  908. {
  909. if( unit && p->GetLibPin() && p->GetLibPin()->GetUnit()
  910. && ( p->GetLibPin()->GetUnit() != unit ) )
  911. {
  912. continue;
  913. }
  914. pins.push_back( p.get() );
  915. }
  916. return pins;
  917. }
  918. std::vector<SCH_PIN*> SCH_SYMBOL::GetPins() const
  919. {
  920. return GetPins( nullptr );
  921. }
  922. void SCH_SYMBOL::swapData( SCH_ITEM* aItem )
  923. {
  924. wxCHECK_RET( aItem != nullptr && aItem->Type() == SCH_SYMBOL_T,
  925. wxT( "Cannot swap data with invalid symbol." ) );
  926. SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( aItem );
  927. std::swap( m_lib_id, symbol->m_lib_id );
  928. m_pins.swap( symbol->m_pins ); // std::vector's swap()
  929. for( std::unique_ptr<SCH_PIN>& pin : symbol->m_pins )
  930. pin->SetParent( symbol );
  931. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  932. pin->SetParent( this );
  933. LIB_SYMBOL* libSymbol = symbol->m_part.release();
  934. symbol->m_part = std::move( m_part );
  935. symbol->UpdatePins();
  936. m_part.reset( libSymbol );
  937. UpdatePins();
  938. std::swap( m_pos, symbol->m_pos );
  939. std::swap( m_unit, symbol->m_unit );
  940. std::swap( m_bodyStyle, symbol->m_bodyStyle );
  941. m_fields.swap( symbol->m_fields ); // std::vector's swap()
  942. for( SCH_FIELD& field : symbol->m_fields )
  943. field.SetParent( symbol );
  944. for( SCH_FIELD& field : m_fields )
  945. field.SetParent( this );
  946. TRANSFORM tmp = m_transform;
  947. m_transform = symbol->m_transform;
  948. symbol->m_transform = tmp;
  949. std::swap( m_excludedFromSim, symbol->m_excludedFromSim );
  950. std::swap( m_excludedFromBOM, symbol->m_excludedFromBOM );
  951. std::swap( m_DNP, symbol->m_DNP );
  952. std::swap( m_excludedFromBoard, symbol->m_excludedFromBoard );
  953. std::swap( m_instanceReferences, symbol->m_instanceReferences );
  954. std::swap( m_schLibSymbolName, symbol->m_schLibSymbolName );
  955. }
  956. void SCH_SYMBOL::GetContextualTextVars( wxArrayString* aVars ) const
  957. {
  958. for( const SCH_FIELD& field : m_fields )
  959. {
  960. if( field.IsPrivate() )
  961. continue;
  962. if( field.IsMandatory() )
  963. aVars->push_back( field.GetCanonicalName().Upper() );
  964. else
  965. aVars->push_back( field.GetName() );
  966. }
  967. aVars->push_back( wxT( "OP" ) );
  968. aVars->push_back( wxT( "FOOTPRINT_LIBRARY" ) );
  969. aVars->push_back( wxT( "FOOTPRINT_NAME" ) );
  970. aVars->push_back( wxT( "UNIT" ) );
  971. aVars->push_back( wxT( "SHORT_REFERENCE" ) );
  972. aVars->push_back( wxT( "SYMBOL_LIBRARY" ) );
  973. aVars->push_back( wxT( "SYMBOL_NAME" ) );
  974. aVars->push_back( wxT( "SYMBOL_DESCRIPTION" ) );
  975. aVars->push_back( wxT( "SYMBOL_KEYWORDS" ) );
  976. aVars->push_back( wxT( "EXCLUDE_FROM_BOM" ) );
  977. aVars->push_back( wxT( "EXCLUDE_FROM_BOARD" ) );
  978. aVars->push_back( wxT( "EXCLUDE_FROM_SIM" ) );
  979. aVars->push_back( wxT( "DNP" ) );
  980. aVars->push_back( wxT( "SHORT_NET_NAME(<pin_number>)" ) );
  981. aVars->push_back( wxT( "NET_NAME(<pin_number>)" ) );
  982. aVars->push_back( wxT( "NET_CLASS(<pin_number>)" ) );
  983. aVars->push_back( wxT( "PIN_NAME(<pin_number>)" ) );
  984. }
  985. bool SCH_SYMBOL::ResolveTextVar( const SCH_SHEET_PATH* aPath, wxString* token, int aDepth ) const
  986. {
  987. static wxRegEx operatingPoint( wxT( "^"
  988. "OP"
  989. "(:[^.]*)?" // pin
  990. "(.([0-9])?" // precisionStr
  991. "([a-zA-Z]*))?" // rangeStr
  992. "$" ) );
  993. wxCHECK( aPath, false );
  994. SCHEMATIC* schematic = Schematic();
  995. if( !schematic )
  996. return false;
  997. if( operatingPoint.Matches( *token ) )
  998. {
  999. wxString pin( operatingPoint.GetMatch( *token, 1 ).Lower() );
  1000. wxString precisionStr( operatingPoint.GetMatch( *token, 3 ) );
  1001. wxString rangeStr( operatingPoint.GetMatch( *token, 4 ) );
  1002. int precision = precisionStr.IsEmpty() ? 3 : precisionStr[0] - '0';
  1003. wxString range = rangeStr.IsEmpty() ? wxString( wxS( "~A" ) ) : rangeStr;
  1004. SIM_LIB_MGR simLibMgr( &schematic->Project() );
  1005. std::vector<EMBEDDED_FILES*> embeddedFilesStack;
  1006. embeddedFilesStack.push_back( schematic->GetEmbeddedFiles() );
  1007. if( m_part )
  1008. embeddedFilesStack.push_back( m_part->GetEmbeddedFiles() );
  1009. simLibMgr.SetFilesStack( std::move( embeddedFilesStack ) );
  1010. NULL_REPORTER devnull;
  1011. SIM_MODEL& model = simLibMgr.CreateModel( aPath, const_cast<SCH_SYMBOL&>( *this ),
  1012. true, aDepth + 1, devnull ).model;
  1013. SPICE_ITEM spiceItem;
  1014. spiceItem.refName = GetRef( aPath );
  1015. wxString spiceRef = model.SpiceGenerator().ItemName( spiceItem );
  1016. spiceRef = spiceRef.Lower();
  1017. if( pin.IsEmpty() )
  1018. {
  1019. *token = schematic->GetOperatingPoint( spiceRef, precision, range );
  1020. return true;
  1021. }
  1022. else if( pin == wxS( ":power" ) )
  1023. {
  1024. if( rangeStr.IsEmpty() )
  1025. range = wxS( "~W" );
  1026. *token = schematic->GetOperatingPoint( spiceRef + wxS( ":power" ), precision, range );
  1027. return true;
  1028. }
  1029. else
  1030. {
  1031. pin = pin.SubString( 1, -1 ); // Strip ':' from front
  1032. for( const std::reference_wrapper<const SIM_MODEL_PIN>& modelPin : model.GetPins() )
  1033. {
  1034. SCH_PIN* symbolPin = GetPin( modelPin.get().symbolPinNumber );
  1035. if( pin == symbolPin->GetName().Lower() || pin == symbolPin->GetNumber().Lower() )
  1036. {
  1037. if( model.GetPins().size() == 2 )
  1038. {
  1039. *token = schematic->GetOperatingPoint( spiceRef, precision, range );
  1040. }
  1041. else
  1042. {
  1043. wxString signalName = spiceRef + wxS( ":" ) + modelPin.get().modelPinName;
  1044. *token = schematic->GetOperatingPoint( signalName, precision, range );
  1045. }
  1046. return true;
  1047. }
  1048. }
  1049. }
  1050. *token = wxS( "?" );
  1051. return true;
  1052. }
  1053. if( token->Contains( ':' ) )
  1054. {
  1055. if( schematic->ResolveCrossReference( token, aDepth + 1 ) )
  1056. return true;
  1057. }
  1058. for( const SCH_FIELD& field : m_fields )
  1059. {
  1060. wxString fieldName = field.IsMandatory() ? field.GetCanonicalName()
  1061. : field.GetName();
  1062. wxString textToken = field.GetText();
  1063. textToken.Replace( " ", wxEmptyString );
  1064. wxString tokenString = "${" + fieldName + "}";
  1065. // If the field data is just a reference to the field, don't resolve
  1066. if( textToken.IsSameAs( tokenString, false ) )
  1067. return true;
  1068. if( token->IsSameAs( fieldName, false ) )
  1069. {
  1070. if( field.GetId() == FIELD_T::REFERENCE )
  1071. *token = GetRef( aPath, true );
  1072. else
  1073. *token = field.GetShownText( aPath, false, aDepth + 1 );
  1074. return true;
  1075. }
  1076. }
  1077. // Consider missing simulation fields as empty, not un-resolved
  1078. if( token->IsSameAs( wxT( "SIM.DEVICE" ) )
  1079. || token->IsSameAs( wxT( "SIM.TYPE" ) )
  1080. || token->IsSameAs( wxT( "SIM.PINS" ) )
  1081. || token->IsSameAs( wxT( "SIM.PARAMS" ) )
  1082. || token->IsSameAs( wxT( "SIM.LIBRARY" ) )
  1083. || token->IsSameAs( wxT( "SIM.NAME" ) ) )
  1084. {
  1085. *token = wxEmptyString;
  1086. return true;
  1087. }
  1088. for( const TEMPLATE_FIELDNAME& templateFieldname :
  1089. schematic->Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
  1090. {
  1091. if( token->IsSameAs( templateFieldname.m_Name )
  1092. || token->IsSameAs( templateFieldname.m_Name.Upper() ) )
  1093. {
  1094. // If we didn't find it in the fields list then it isn't set on this symbol.
  1095. // Just return an empty string.
  1096. *token = wxEmptyString;
  1097. return true;
  1098. }
  1099. }
  1100. if( token->IsSameAs( wxT( "FOOTPRINT_LIBRARY" ) ) )
  1101. {
  1102. wxString footprint = GetFootprintFieldText( true, aPath, false );
  1103. wxArrayString parts = wxSplit( footprint, ':' );
  1104. if( parts.Count() > 0 )
  1105. *token = parts[ 0 ];
  1106. else
  1107. *token = wxEmptyString;
  1108. return true;
  1109. }
  1110. else if( token->IsSameAs( wxT( "FOOTPRINT_NAME" ) ) )
  1111. {
  1112. wxString footprint = GetFootprintFieldText( true, aPath, false );
  1113. wxArrayString parts = wxSplit( footprint, ':' );
  1114. if( parts.Count() > 1 )
  1115. *token = parts[ std::min( 1, (int) parts.size() - 1 ) ];
  1116. else
  1117. *token = wxEmptyString;
  1118. return true;
  1119. }
  1120. else if( token->IsSameAs( wxT( "UNIT" ) ) )
  1121. {
  1122. *token = SubReference( GetUnitSelection( aPath ) );
  1123. return true;
  1124. }
  1125. else if( token->IsSameAs( wxT( "SHORT_REFERENCE" ) ) )
  1126. {
  1127. *token = GetRef( aPath, false );
  1128. return true;
  1129. }
  1130. else if( token->IsSameAs( wxT( "SYMBOL_LIBRARY" ) ) )
  1131. {
  1132. *token = m_lib_id.GetUniStringLibNickname();
  1133. return true;
  1134. }
  1135. else if( token->IsSameAs( wxT( "SYMBOL_NAME" ) ) )
  1136. {
  1137. *token = m_lib_id.GetUniStringLibItemName();
  1138. return true;
  1139. }
  1140. else if( token->IsSameAs( wxT( "SYMBOL_DESCRIPTION" ) ) )
  1141. {
  1142. *token = GetDescription();
  1143. return true;
  1144. }
  1145. else if( token->IsSameAs( wxT( "SYMBOL_KEYWORDS" ) ) )
  1146. {
  1147. *token = GetKeyWords();
  1148. return true;
  1149. }
  1150. else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOM" ) ) )
  1151. {
  1152. *token = wxEmptyString;
  1153. if( aPath->GetExcludedFromBOM() || this->ResolveExcludedFromBOM() )
  1154. *token = _( "Excluded from BOM" );
  1155. return true;
  1156. }
  1157. else if( token->IsSameAs( wxT( "EXCLUDE_FROM_BOARD" ) ) )
  1158. {
  1159. *token = wxEmptyString;
  1160. if( aPath->GetExcludedFromBoard() || this->ResolveExcludedFromBoard() )
  1161. *token = _( "Excluded from board" );
  1162. return true;
  1163. }
  1164. else if( token->IsSameAs( wxT( "EXCLUDE_FROM_SIM" ) ) )
  1165. {
  1166. *token = wxEmptyString;
  1167. if( aPath->GetExcludedFromSim() || this->ResolveExcludedFromSim() )
  1168. *token = _( "Excluded from simulation" );
  1169. return true;
  1170. }
  1171. else if( token->IsSameAs( wxT( "DNP" ) ) )
  1172. {
  1173. *token = wxEmptyString;
  1174. if( aPath->GetDNP() || this->ResolveDNP() )
  1175. *token = _( "DNP" );
  1176. return true;
  1177. }
  1178. else if( token->StartsWith( wxT( "SHORT_NET_NAME(" ) )
  1179. || token->StartsWith( wxT( "NET_NAME(" ) )
  1180. || token->StartsWith( wxT( "NET_CLASS(" ) )
  1181. || token->StartsWith( wxT( "PIN_NAME(" ) ) )
  1182. {
  1183. wxString pinNumber = token->AfterFirst( '(' );
  1184. pinNumber = pinNumber.BeforeLast( ')' );
  1185. for( SCH_PIN* pin : GetPins( aPath ) )
  1186. {
  1187. if( pin->GetNumber() == pinNumber )
  1188. {
  1189. if( token->StartsWith( wxT( "PIN_NAME" ) ) )
  1190. {
  1191. *token = pin->GetAlt().IsEmpty() ? pin->GetName() : pin->GetAlt();
  1192. return true;
  1193. }
  1194. SCH_CONNECTION* conn = pin->Connection( aPath );
  1195. if( !conn )
  1196. *token = wxEmptyString;
  1197. else if( token->StartsWith( wxT( "SHORT_NET_NAME" ) ) )
  1198. *token = conn->LocalName();
  1199. else if( token->StartsWith( wxT( "NET_NAME" ) ) )
  1200. *token = conn->Name();
  1201. else if( token->StartsWith( wxT( "NET_CLASS" ) ) )
  1202. *token = pin->GetEffectiveNetClass( aPath )->GetName();
  1203. return true;
  1204. }
  1205. }
  1206. }
  1207. // See if parent can resolve it (this will recurse to ancestors)
  1208. if( aPath->Last() && aPath->Last()->ResolveTextVar( aPath, token, aDepth + 1 ) )
  1209. return true;
  1210. return false;
  1211. }
  1212. void SCH_SYMBOL::ClearAnnotation( const SCH_SHEET_PATH* aSheetPath, bool aResetPrefix )
  1213. {
  1214. if( aSheetPath )
  1215. {
  1216. KIID_PATH path = aSheetPath->Path();
  1217. for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  1218. {
  1219. if( instance.m_Path == path )
  1220. {
  1221. if( instance.m_Reference.IsEmpty() || aResetPrefix )
  1222. instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
  1223. else
  1224. instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
  1225. }
  1226. }
  1227. }
  1228. else
  1229. {
  1230. for( SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  1231. {
  1232. if( instance.m_Reference.IsEmpty() || aResetPrefix)
  1233. instance.m_Reference = UTIL::GetRefDesUnannotated( m_prefix );
  1234. else
  1235. instance.m_Reference = UTIL::GetRefDesUnannotated( instance.m_Reference );
  1236. }
  1237. }
  1238. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  1239. pin->ClearDefaultNetName( aSheetPath );
  1240. // These 2 changes do not work in complex hierarchy.
  1241. // When a clear annotation is made, the calling function must call a
  1242. // UpdateAllScreenReferences for the active sheet.
  1243. // But this call cannot made here.
  1244. wxString currentReference = GetField( FIELD_T::REFERENCE )->GetText();
  1245. if( currentReference.IsEmpty() || aResetPrefix )
  1246. GetField( FIELD_T::REFERENCE )->SetText( UTIL::GetRefDesUnannotated( m_prefix ) );
  1247. else
  1248. GetField( FIELD_T::REFERENCE )->SetText( UTIL::GetRefDesUnannotated( currentReference ) );
  1249. }
  1250. bool SCH_SYMBOL::AddSheetPathReferenceEntryIfMissing( const KIID_PATH& aSheetPath )
  1251. {
  1252. // An empty sheet path is illegal, at a minimum the root sheet UUID must be present.
  1253. wxCHECK( aSheetPath.size() > 0, false );
  1254. for( const SCH_SYMBOL_INSTANCE& instance : m_instanceReferences )
  1255. {
  1256. // if aSheetPath is found, nothing to do:
  1257. if( instance.m_Path == aSheetPath )
  1258. return false;
  1259. }
  1260. // This entry does not exist: add it, with its last-used reference
  1261. AddHierarchicalReference( aSheetPath, GetField( FIELD_T::REFERENCE )->GetText(), m_unit );
  1262. return true;
  1263. }
  1264. void SCH_SYMBOL::SetOrientation( int aOrientation )
  1265. {
  1266. TRANSFORM temp = TRANSFORM();
  1267. bool transform = false;
  1268. switch( aOrientation )
  1269. {
  1270. case SYM_ORIENT_0:
  1271. case SYM_NORMAL: // default transform matrix
  1272. m_transform = TRANSFORM();
  1273. break;
  1274. case SYM_ROTATE_COUNTERCLOCKWISE: // Rotate + (incremental rotation)
  1275. temp.x1 = 0;
  1276. temp.y1 = 1;
  1277. temp.x2 = -1;
  1278. temp.y2 = 0;
  1279. transform = true;
  1280. break;
  1281. case SYM_ROTATE_CLOCKWISE: // Rotate - (incremental rotation)
  1282. temp.x1 = 0;
  1283. temp.y1 = -1;
  1284. temp.x2 = 1;
  1285. temp.y2 = 0;
  1286. transform = true;
  1287. break;
  1288. case SYM_MIRROR_Y: // Mirror Y (incremental transform)
  1289. temp.x1 = -1;
  1290. temp.y1 = 0;
  1291. temp.x2 = 0;
  1292. temp.y2 = 1;
  1293. transform = true;
  1294. break;
  1295. case SYM_MIRROR_X: // Mirror X (incremental transform)
  1296. temp.x1 = 1;
  1297. temp.y1 = 0;
  1298. temp.x2 = 0;
  1299. temp.y2 = -1;
  1300. transform = true;
  1301. break;
  1302. case SYM_ORIENT_90:
  1303. SetOrientation( SYM_ORIENT_0 );
  1304. SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
  1305. break;
  1306. case SYM_ORIENT_180:
  1307. SetOrientation( SYM_ORIENT_0 );
  1308. SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
  1309. SetOrientation( SYM_ROTATE_COUNTERCLOCKWISE );
  1310. break;
  1311. case SYM_ORIENT_270:
  1312. SetOrientation( SYM_ORIENT_0 );
  1313. SetOrientation( SYM_ROTATE_CLOCKWISE );
  1314. break;
  1315. case ( SYM_ORIENT_0 + SYM_MIRROR_X ):
  1316. SetOrientation( SYM_ORIENT_0 );
  1317. SetOrientation( SYM_MIRROR_X );
  1318. break;
  1319. case ( SYM_ORIENT_0 + SYM_MIRROR_Y ):
  1320. SetOrientation( SYM_ORIENT_0 );
  1321. SetOrientation( SYM_MIRROR_Y );
  1322. break;
  1323. case ( SYM_ORIENT_0 + SYM_MIRROR_X + SYM_MIRROR_Y ):
  1324. SetOrientation( SYM_ORIENT_0 );
  1325. SetOrientation( SYM_MIRROR_X );
  1326. SetOrientation( SYM_MIRROR_Y );
  1327. break;
  1328. case ( SYM_ORIENT_90 + SYM_MIRROR_X ):
  1329. SetOrientation( SYM_ORIENT_90 );
  1330. SetOrientation( SYM_MIRROR_X );
  1331. break;
  1332. case ( SYM_ORIENT_90 + SYM_MIRROR_Y ):
  1333. SetOrientation( SYM_ORIENT_90 );
  1334. SetOrientation( SYM_MIRROR_Y );
  1335. break;
  1336. case ( SYM_ORIENT_90 + SYM_MIRROR_X + SYM_MIRROR_Y ):
  1337. SetOrientation( SYM_ORIENT_90 );
  1338. SetOrientation( SYM_MIRROR_X );
  1339. SetOrientation( SYM_MIRROR_Y );
  1340. break;
  1341. case ( SYM_ORIENT_180 + SYM_MIRROR_X ):
  1342. SetOrientation( SYM_ORIENT_180 );
  1343. SetOrientation( SYM_MIRROR_X );
  1344. break;
  1345. case ( SYM_ORIENT_180 + SYM_MIRROR_Y ):
  1346. SetOrientation( SYM_ORIENT_180 );
  1347. SetOrientation( SYM_MIRROR_Y );
  1348. break;
  1349. case ( SYM_ORIENT_180 + SYM_MIRROR_X + SYM_MIRROR_Y ):
  1350. SetOrientation( SYM_ORIENT_180 );
  1351. SetOrientation( SYM_MIRROR_X );
  1352. SetOrientation( SYM_MIRROR_Y );
  1353. break;
  1354. case ( SYM_ORIENT_270 + SYM_MIRROR_X ):
  1355. SetOrientation( SYM_ORIENT_270 );
  1356. SetOrientation( SYM_MIRROR_X );
  1357. break;
  1358. case ( SYM_ORIENT_270 + SYM_MIRROR_Y ):
  1359. SetOrientation( SYM_ORIENT_270 );
  1360. SetOrientation( SYM_MIRROR_Y );
  1361. break;
  1362. case ( SYM_ORIENT_270 + SYM_MIRROR_X + SYM_MIRROR_Y ):
  1363. SetOrientation( SYM_ORIENT_270 );
  1364. SetOrientation( SYM_MIRROR_X );
  1365. SetOrientation( SYM_MIRROR_Y );
  1366. break;
  1367. default:
  1368. transform = false;
  1369. wxFAIL_MSG( "Invalid schematic symbol orientation type." );
  1370. break;
  1371. }
  1372. if( transform )
  1373. {
  1374. /* The new matrix transform is the old matrix transform modified by the
  1375. * requested transformation, which is the temp transform (rot,
  1376. * mirror ..) in order to have (in term of matrix transform):
  1377. * transform coord = new_m_transform * coord
  1378. * where transform coord is the coord modified by new_m_transform from
  1379. * the initial value coord.
  1380. * new_m_transform is computed (from old_m_transform and temp) to
  1381. * have:
  1382. * transform coord = old_m_transform * temp
  1383. */
  1384. TRANSFORM newTransform;
  1385. newTransform.x1 = m_transform.x1 * temp.x1 + m_transform.x2 * temp.y1;
  1386. newTransform.y1 = m_transform.y1 * temp.x1 + m_transform.y2 * temp.y1;
  1387. newTransform.x2 = m_transform.x1 * temp.x2 + m_transform.x2 * temp.y2;
  1388. newTransform.y2 = m_transform.y1 * temp.x2 + m_transform.y2 * temp.y2;
  1389. m_transform = newTransform;
  1390. }
  1391. }
  1392. int SCH_SYMBOL::GetOrientation() const
  1393. {
  1394. /*
  1395. * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right
  1396. * now, so let's just cache it for the moment.
  1397. */
  1398. if( s_transformToOrientationCache.count( m_transform ) )
  1399. return s_transformToOrientationCache.at( m_transform );
  1400. int rotate_values[] =
  1401. {
  1402. SYM_ORIENT_0,
  1403. SYM_ORIENT_90,
  1404. SYM_ORIENT_180,
  1405. SYM_ORIENT_270,
  1406. SYM_MIRROR_X + SYM_ORIENT_0,
  1407. SYM_MIRROR_X + SYM_ORIENT_90,
  1408. SYM_MIRROR_X + SYM_ORIENT_270,
  1409. SYM_MIRROR_Y,
  1410. SYM_MIRROR_Y + SYM_ORIENT_0,
  1411. SYM_MIRROR_Y + SYM_ORIENT_90,
  1412. SYM_MIRROR_Y + SYM_ORIENT_180,
  1413. SYM_MIRROR_Y + SYM_ORIENT_270
  1414. };
  1415. // Try to find the current transform option:
  1416. TRANSFORM transform = m_transform;
  1417. SCH_SYMBOL temp( *this );
  1418. temp.SetParentGroup( nullptr );
  1419. for( int type_rotate : rotate_values )
  1420. {
  1421. temp.SetOrientation( type_rotate );
  1422. if( transform == temp.GetTransform() )
  1423. {
  1424. s_transformToOrientationCache[m_transform] = type_rotate;
  1425. return type_rotate;
  1426. }
  1427. }
  1428. // Error: orientation not found in list (should not happen)
  1429. wxFAIL_MSG( "Schematic symbol orientation matrix internal error." );
  1430. return SYM_NORMAL;
  1431. }
  1432. #if defined(DEBUG)
  1433. void SCH_SYMBOL::Show( int nestLevel, std::ostream& os ) const
  1434. {
  1435. // for now, make it look like XML:
  1436. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
  1437. << " ref=\"" << TO_UTF8( GetField( FIELD_T::REFERENCE )->GetName() )
  1438. << '"' << " chipName=\""
  1439. << GetLibId().Format().wx_str() << '"' << m_pos
  1440. << " layer=\"" << m_layer
  1441. << '"' << ">\n";
  1442. // skip the reference, it's been output already.
  1443. for( int i = 1; i < (int) GetFields().size(); ++i )
  1444. {
  1445. const wxString& value = GetFields()[i].GetText();
  1446. if( !value.IsEmpty() )
  1447. {
  1448. NestedSpace( nestLevel + 1, os ) << "<field" << " name=\""
  1449. << TO_UTF8( GetFields()[i].GetName() )
  1450. << '"' << " value=\""
  1451. << TO_UTF8( value ) << "\"/>\n";
  1452. }
  1453. }
  1454. NestedSpace( nestLevel, os ) << "</" << TO_UTF8( GetClass().Lower() ) << ">\n";
  1455. }
  1456. #endif
  1457. BOX2I SCH_SYMBOL::doGetBoundingBox( bool aIncludePins, bool aIncludeFields ) const
  1458. {
  1459. BOX2I bBox;
  1460. if( m_part )
  1461. bBox = m_part->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins, false );
  1462. else
  1463. bBox = LIB_SYMBOL::GetDummy()->GetBodyBoundingBox( m_unit, m_bodyStyle, aIncludePins,
  1464. false );
  1465. bBox = m_transform.TransformCoordinate( bBox );
  1466. bBox.Normalize();
  1467. bBox.Offset( m_pos );
  1468. if( aIncludeFields )
  1469. {
  1470. for( const SCH_FIELD& field : m_fields )
  1471. {
  1472. if( field.IsVisible() )
  1473. bBox.Merge( field.GetBoundingBox() );
  1474. }
  1475. }
  1476. return bBox;
  1477. }
  1478. BOX2I SCH_SYMBOL::GetBodyBoundingBox() const
  1479. {
  1480. try
  1481. {
  1482. return doGetBoundingBox( false, false );
  1483. }
  1484. catch( const boost::bad_pointer& e )
  1485. {
  1486. wxFAIL_MSG( wxString::Format( wxT( "Boost pointer exception occurred: %s" ), e.what() ) );
  1487. return BOX2I();
  1488. }
  1489. }
  1490. BOX2I SCH_SYMBOL::GetBodyAndPinsBoundingBox() const
  1491. {
  1492. return doGetBoundingBox( true, false );
  1493. }
  1494. const BOX2I SCH_SYMBOL::GetBoundingBox() const
  1495. {
  1496. return doGetBoundingBox( true, true );
  1497. }
  1498. void SCH_SYMBOL::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  1499. {
  1500. wxString msg;
  1501. SCH_EDIT_FRAME* schframe = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
  1502. SCH_SHEET_PATH* currentSheet = schframe ? &schframe->GetCurrentSheet() : nullptr;
  1503. auto addExcludes =
  1504. [&]()
  1505. {
  1506. wxArrayString msgs;
  1507. if( GetExcludedFromSim() )
  1508. msgs.Add( _( "Simulation" ) );
  1509. if( GetExcludedFromBOM() )
  1510. msgs.Add( _( "BOM" ) );
  1511. if( GetExcludedFromBoard() )
  1512. msgs.Add( _( "Board" ) );
  1513. if( GetDNP() )
  1514. msgs.Add( _( "DNP" ) );
  1515. msg = wxJoin( msgs, '|' );
  1516. msg.Replace( '|', wxS( ", " ) );
  1517. if( !msg.empty() )
  1518. aList.emplace_back( _( "Exclude from" ), msg );
  1519. };
  1520. // part and alias can differ if alias is not the root
  1521. if( m_part )
  1522. {
  1523. if( m_part.get() != LIB_SYMBOL::GetDummy() )
  1524. {
  1525. if( m_part->IsPower() )
  1526. {
  1527. // Don't use GetShownText(); we want to see the variable references here
  1528. aList.emplace_back( _( "Power symbol" ),
  1529. KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
  1530. }
  1531. else
  1532. {
  1533. aList.emplace_back( _( "Reference" ),
  1534. UnescapeString( GetRef( currentSheet ) ) );
  1535. // Don't use GetShownText(); we want to see the variable references here
  1536. aList.emplace_back( _( "Value" ),
  1537. KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
  1538. addExcludes();
  1539. aList.emplace_back( _( "Name" ),
  1540. KIUI::EllipsizeStatusText( aFrame,
  1541. GetLibId().GetLibItemName() ) );
  1542. }
  1543. #if 0 // Display symbol flags, for debug only
  1544. aList.emplace_back( _( "flags" ), wxString::Format( "%X", GetEditFlags() ) );
  1545. #endif
  1546. if( !m_part->IsRoot() )
  1547. {
  1548. msg = _( "Missing parent" );
  1549. std::shared_ptr< LIB_SYMBOL > parent = m_part->GetParent().lock();
  1550. if( parent )
  1551. msg = parent->GetName();
  1552. aList.emplace_back( _( "Derived from" ), UnescapeString( msg ) );
  1553. }
  1554. else if( !m_lib_id.GetLibNickname().empty() )
  1555. {
  1556. aList.emplace_back( _( "Library" ), m_lib_id.GetLibNickname() );
  1557. }
  1558. else
  1559. {
  1560. aList.emplace_back( _( "Library" ), _( "Undefined!!!" ) );
  1561. }
  1562. // Display the current associated footprint, if exists.
  1563. // Don't use GetShownText(); we want to see the variable references here
  1564. msg = KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::FOOTPRINT )->GetText() );
  1565. if( msg.IsEmpty() )
  1566. msg = _( "<Unknown>" );
  1567. aList.emplace_back( _( "Footprint" ), msg );
  1568. // Display description of the symbol, and keywords found in lib
  1569. aList.emplace_back( _( "Description" ) + wxT( ": " )
  1570. + GetField( FIELD_T::DESCRIPTION )->GetText(),
  1571. _( "Keywords" ) + wxT( ": " ) + m_part->GetKeyWords() );
  1572. }
  1573. }
  1574. else
  1575. {
  1576. aList.emplace_back( _( "Reference" ), GetRef( currentSheet ) );
  1577. // Don't use GetShownText(); we want to see the variable references here
  1578. aList.emplace_back( _( "Value" ),
  1579. KIUI::EllipsizeStatusText( aFrame, GetField( FIELD_T::VALUE )->GetText() ) );
  1580. addExcludes();
  1581. aList.emplace_back( _( "Name" ),
  1582. KIUI::EllipsizeStatusText( aFrame, GetLibId().GetLibItemName() ) );
  1583. wxString libNickname = GetLibId().GetLibNickname();
  1584. if( libNickname.empty() )
  1585. msg = _( "No library defined!" );
  1586. else
  1587. msg.Printf( _( "Symbol not found in %s!" ), libNickname );
  1588. aList.emplace_back( _( "Library" ), msg );
  1589. }
  1590. }
  1591. BITMAPS SCH_SYMBOL::GetMenuImage() const
  1592. {
  1593. return BITMAPS::add_component;
  1594. }
  1595. EMBEDDED_FILES* SCH_SYMBOL::GetEmbeddedFiles()
  1596. {
  1597. std::unique_ptr<LIB_SYMBOL>& libSymbolRef = GetLibSymbolRef();
  1598. if( !libSymbolRef )
  1599. return nullptr;
  1600. return GetLibSymbolRef()->GetEmbeddedFiles();
  1601. }
  1602. void SCH_SYMBOL::MirrorHorizontally( int aCenter )
  1603. {
  1604. int dx = m_pos.x;
  1605. SetOrientation( SYM_MIRROR_Y );
  1606. MIRROR( m_pos.x, aCenter );
  1607. dx -= m_pos.x; // dx,0 is the move vector for this transform
  1608. for( SCH_FIELD& field : m_fields )
  1609. {
  1610. // Move the fields to the new position because the symbol itself has moved.
  1611. VECTOR2I pos = field.GetTextPos();
  1612. pos.x -= dx;
  1613. field.SetTextPos( pos );
  1614. }
  1615. }
  1616. void SCH_SYMBOL::MirrorVertically( int aCenter )
  1617. {
  1618. int dy = m_pos.y;
  1619. SetOrientation( SYM_MIRROR_X );
  1620. MIRROR( m_pos.y, aCenter );
  1621. dy -= m_pos.y; // 0,dy is the move vector for this transform
  1622. for( SCH_FIELD& field : m_fields )
  1623. {
  1624. // Move the fields to the new position because the symbol itself has moved.
  1625. VECTOR2I pos = field.GetTextPos();
  1626. pos.y -= dy;
  1627. field.SetTextPos( pos );
  1628. }
  1629. }
  1630. void SCH_SYMBOL::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
  1631. {
  1632. VECTOR2I prev = m_pos;
  1633. RotatePoint( m_pos, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
  1634. SetOrientation( aRotateCCW ? SYM_ROTATE_COUNTERCLOCKWISE : SYM_ROTATE_CLOCKWISE );
  1635. for( SCH_FIELD& field : m_fields )
  1636. {
  1637. // Move the fields to the new position because the symbol itself has moved.
  1638. VECTOR2I pos = field.GetTextPos();
  1639. pos.x -= prev.x - m_pos.x;
  1640. pos.y -= prev.y - m_pos.y;
  1641. field.SetTextPos( pos );
  1642. }
  1643. }
  1644. bool SCH_SYMBOL::Matches( const EDA_SEARCH_DATA& aSearchData, void* aAuxData ) const
  1645. {
  1646. if( aSearchData.searchMetadata )
  1647. {
  1648. if( EDA_ITEM::Matches( GetSchSymbolLibraryName(), aSearchData ) )
  1649. return true;
  1650. if( EDA_ITEM::Matches( GetDescription(), aSearchData ) )
  1651. return true;
  1652. if( EDA_ITEM::Matches( GetKeyWords(), aSearchData ) )
  1653. return true;
  1654. }
  1655. for( SCH_ITEM& drawItem : GetLibSymbolRef()->GetDrawItems() )
  1656. {
  1657. if( drawItem.Matches( aSearchData, aAuxData ) )
  1658. return true;
  1659. }
  1660. // Symbols are searchable via the child field and pin item text.
  1661. return false;
  1662. }
  1663. void SCH_SYMBOL::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  1664. {
  1665. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  1666. {
  1667. SCH_PIN* lib_pin = pin->GetLibPin();
  1668. if( lib_pin && lib_pin->GetUnit() && m_unit && ( m_unit != lib_pin->GetUnit() ) )
  1669. continue;
  1670. DANGLING_END_ITEM item( PIN_END, lib_pin, GetPinPhysicalPosition( lib_pin ), this );
  1671. aItemList.push_back( item );
  1672. }
  1673. }
  1674. bool SCH_SYMBOL::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
  1675. std::vector<DANGLING_END_ITEM>& aItemListByPos,
  1676. const SCH_SHEET_PATH* aPath )
  1677. {
  1678. bool changed = false;
  1679. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  1680. {
  1681. bool previousState = pin->IsDangling();
  1682. pin->SetIsDangling( true );
  1683. VECTOR2I pos = m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos;
  1684. auto lower = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, pos );
  1685. bool do_break = false;
  1686. for( auto it = lower; it < aItemListByPos.end() && it->GetPosition() == pos; it++ )
  1687. {
  1688. DANGLING_END_ITEM& each_item = *it;
  1689. // Some people like to stack pins on top of each other in a symbol to indicate
  1690. // internal connection. While technically connected, it is not particularly useful
  1691. // to display them that way, so skip any pins that are in the same symbol as this
  1692. // one.
  1693. if( each_item.GetParent() == this )
  1694. continue;
  1695. switch( each_item.GetType() )
  1696. {
  1697. case PIN_END:
  1698. case LABEL_END:
  1699. case SHEET_LABEL_END:
  1700. case WIRE_END:
  1701. case NO_CONNECT_END:
  1702. case JUNCTION_END:
  1703. pin->SetIsDangling( false );
  1704. do_break = true;
  1705. break;
  1706. default:
  1707. break;
  1708. }
  1709. if( do_break )
  1710. break;
  1711. }
  1712. changed = ( changed || ( previousState != pin->IsDangling() ) );
  1713. }
  1714. return changed;
  1715. }
  1716. VECTOR2I SCH_SYMBOL::GetPinPhysicalPosition( const SCH_PIN* aPin ) const
  1717. {
  1718. if( ( aPin == nullptr ) || ( aPin->Type() != SCH_PIN_T ) )
  1719. return VECTOR2I( 0, 0 );
  1720. return m_transform.TransformCoordinate( aPin->GetPosition() ) + m_pos;
  1721. }
  1722. bool SCH_SYMBOL::HasConnectivityChanges( const SCH_ITEM* aItem,
  1723. const SCH_SHEET_PATH* aInstance ) const
  1724. {
  1725. // Do not compare to ourself.
  1726. if( aItem == this )
  1727. return false;
  1728. const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( aItem );
  1729. // Don't compare against a different SCH_ITEM.
  1730. wxCHECK( symbol, false );
  1731. // The move algorithm marks any pins that are being moved without something attached
  1732. // (during the move) as dangling. We always need to recheck connectivity in this case
  1733. // or we will not notice changes when the user places the symbol back in the same position
  1734. // it started.
  1735. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  1736. {
  1737. if( pin->IsDangling() )
  1738. return true;
  1739. }
  1740. if( GetPosition() != symbol->GetPosition() )
  1741. return true;
  1742. if( GetLibId() != symbol->GetLibId() )
  1743. return true;
  1744. if( GetUnitSelection( aInstance ) != symbol->GetUnitSelection( aInstance ) )
  1745. return true;
  1746. if( GetRef( aInstance ) != symbol->GetRef( aInstance ) )
  1747. return true;
  1748. // Power symbol value field changes are connectivity changes.
  1749. if( IsPower()
  1750. && ( GetValue( true, aInstance, false ) != symbol->GetValue( true, aInstance, false ) ) )
  1751. return true;
  1752. if( m_pins.size() != symbol->m_pins.size() )
  1753. return true;
  1754. for( size_t i = 0; i < m_pins.size(); i++ )
  1755. {
  1756. if( m_pins[i]->HasConnectivityChanges( symbol->m_pins[i].get() ) )
  1757. return true;
  1758. }
  1759. return false;
  1760. }
  1761. std::vector<VECTOR2I> SCH_SYMBOL::GetConnectionPoints() const
  1762. {
  1763. std::vector<VECTOR2I> retval;
  1764. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  1765. {
  1766. // Collect only pins attached to the current unit and convert.
  1767. // others are not associated to this symbol instance
  1768. int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
  1769. : GetUnit();
  1770. int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
  1771. : GetBodyStyle();
  1772. if( pin_unit > 0 && pin_unit != GetUnit() )
  1773. continue;
  1774. if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
  1775. continue;
  1776. retval.push_back( m_transform.TransformCoordinate( pin->GetLocalPosition() ) + m_pos );
  1777. }
  1778. return retval;
  1779. }
  1780. SCH_ITEM* SCH_SYMBOL::GetDrawItem( const VECTOR2I& aPosition, KICAD_T aType )
  1781. {
  1782. if( m_part )
  1783. {
  1784. // Calculate the position relative to the symbol.
  1785. VECTOR2I libPosition = aPosition - m_pos;
  1786. return m_part->LocateDrawItem( m_unit, m_bodyStyle, aType, libPosition, m_transform );
  1787. }
  1788. return nullptr;
  1789. }
  1790. wxString SCH_SYMBOL::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
  1791. {
  1792. return wxString::Format( _( "Symbol %s [%s]" ),
  1793. KIUI::EllipsizeMenuText( GetField( FIELD_T::REFERENCE )->GetText() ),
  1794. KIUI::EllipsizeMenuText( GetLibId().GetLibItemName() ) );
  1795. }
  1796. INSPECT_RESULT SCH_SYMBOL::Visit( INSPECTOR aInspector, void* aTestData,
  1797. const std::vector<KICAD_T>& aScanTypes )
  1798. {
  1799. for( KICAD_T scanType : aScanTypes )
  1800. {
  1801. if( scanType == SCH_LOCATE_ANY_T || ( scanType == SCH_SYMBOL_T )
  1802. || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
  1803. {
  1804. if( INSPECT_RESULT::QUIT == aInspector( this, aTestData ) )
  1805. return INSPECT_RESULT::QUIT;
  1806. }
  1807. if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_FIELD_T )
  1808. {
  1809. for( SCH_FIELD& field : m_fields )
  1810. {
  1811. if( INSPECT_RESULT::QUIT == aInspector( &field, (void*) this ) )
  1812. return INSPECT_RESULT::QUIT;
  1813. }
  1814. }
  1815. if( scanType == SCH_FIELD_LOCATE_REFERENCE_T )
  1816. {
  1817. if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::REFERENCE ), (void*) this ) )
  1818. return INSPECT_RESULT::QUIT;
  1819. }
  1820. if( scanType == SCH_FIELD_LOCATE_VALUE_T
  1821. || ( scanType == SCH_SYMBOL_LOCATE_POWER_T && m_part && m_part->IsPower() ) )
  1822. {
  1823. if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::VALUE ), (void*) this ) )
  1824. return INSPECT_RESULT::QUIT;
  1825. }
  1826. if( scanType == SCH_FIELD_LOCATE_FOOTPRINT_T )
  1827. {
  1828. if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::FOOTPRINT ), (void*) this ) )
  1829. return INSPECT_RESULT::QUIT;
  1830. }
  1831. if( scanType == SCH_FIELD_LOCATE_DATASHEET_T )
  1832. {
  1833. if( INSPECT_RESULT::QUIT == aInspector( GetField( FIELD_T::DATASHEET ), (void*) this ) )
  1834. return INSPECT_RESULT::QUIT;
  1835. }
  1836. if( scanType == SCH_LOCATE_ANY_T || scanType == SCH_PIN_T )
  1837. {
  1838. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  1839. {
  1840. // Collect only pins attached to the current unit and convert.
  1841. // others are not associated to this symbol instance
  1842. int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
  1843. : GetUnit();
  1844. int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
  1845. : GetBodyStyle();
  1846. if( pin_unit > 0 && pin_unit != GetUnit() )
  1847. continue;
  1848. if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
  1849. continue;
  1850. if( INSPECT_RESULT::QUIT == aInspector( pin.get(), (void*) this ) )
  1851. return INSPECT_RESULT::QUIT;
  1852. }
  1853. }
  1854. }
  1855. return INSPECT_RESULT::CONTINUE;
  1856. }
  1857. bool SCH_SYMBOL::operator <( const SCH_ITEM& aItem ) const
  1858. {
  1859. if( Type() != aItem.Type() )
  1860. return Type() < aItem.Type();
  1861. const SCH_SYMBOL* symbol = static_cast<const SCH_SYMBOL*>( &aItem );
  1862. BOX2I rect = GetBodyAndPinsBoundingBox();
  1863. if( rect.GetArea() != symbol->GetBodyAndPinsBoundingBox().GetArea() )
  1864. return rect.GetArea() < symbol->GetBodyAndPinsBoundingBox().GetArea();
  1865. if( m_pos.x != symbol->m_pos.x )
  1866. return m_pos.x < symbol->m_pos.x;
  1867. if( m_pos.y != symbol->m_pos.y )
  1868. return m_pos.y < symbol->m_pos.y;
  1869. return m_Uuid < aItem.m_Uuid; // Ensure deterministic sort
  1870. }
  1871. bool SCH_SYMBOL::operator==( const SCH_SYMBOL& aSymbol ) const
  1872. {
  1873. std::vector<SCH_FIELD*> fields, otherFields;
  1874. GetFields( fields, false );
  1875. aSymbol.GetFields( otherFields, false );
  1876. if( fields.size() != otherFields.size() )
  1877. return false;
  1878. for( int ii = 0; ii < (int) fields.size(); ii++ )
  1879. {
  1880. if( fields[ii]->GetId() == FIELD_T::REFERENCE )
  1881. continue;
  1882. if( fields[ii]->GetText().Cmp( otherFields[ii]->GetText() ) != 0 )
  1883. return false;
  1884. }
  1885. return true;
  1886. }
  1887. bool SCH_SYMBOL::operator!=( const SCH_SYMBOL& aSymbol ) const
  1888. {
  1889. return !( *this == aSymbol );
  1890. }
  1891. SCH_SYMBOL& SCH_SYMBOL::operator=( const SCH_SYMBOL& aSymbol )
  1892. {
  1893. wxCHECK_MSG( Type() == aSymbol.Type(), *this,
  1894. wxT( "Cannot assign object type " ) + aSymbol.GetClass() + wxT( " to type " ) +
  1895. GetClass() );
  1896. if( &aSymbol != this )
  1897. {
  1898. SYMBOL::operator=( aSymbol );
  1899. m_lib_id = aSymbol.m_lib_id;
  1900. m_part.reset( aSymbol.m_part ? new LIB_SYMBOL( *aSymbol.m_part ) : nullptr );
  1901. m_pos = aSymbol.m_pos;
  1902. m_unit = aSymbol.m_unit;
  1903. m_bodyStyle = aSymbol.m_bodyStyle;
  1904. m_transform = aSymbol.m_transform;
  1905. m_instanceReferences = aSymbol.m_instanceReferences;
  1906. m_fields = aSymbol.m_fields; // std::vector's assignment operator
  1907. // Reparent fields after assignment to new symbol.
  1908. for( SCH_FIELD& field : m_fields )
  1909. field.SetParent( this );
  1910. UpdatePins();
  1911. }
  1912. return *this;
  1913. }
  1914. bool SCH_SYMBOL::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
  1915. {
  1916. BOX2I bBox = GetBodyBoundingBox();
  1917. bBox.Inflate( aAccuracy / 2 );
  1918. if( bBox.Contains( aPosition ) )
  1919. return true;
  1920. return false;
  1921. }
  1922. bool SCH_SYMBOL::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
  1923. {
  1924. if( m_flags & STRUCT_DELETED || m_flags & SKIP_STRUCT )
  1925. return false;
  1926. BOX2I rect = aRect;
  1927. rect.Inflate( aAccuracy / 2 );
  1928. if( aContained )
  1929. return rect.Contains( GetBodyBoundingBox() );
  1930. return rect.Intersects( GetBodyBoundingBox() );
  1931. }
  1932. bool SCH_SYMBOL::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
  1933. {
  1934. if( m_flags & STRUCT_DELETED || m_flags & SKIP_STRUCT )
  1935. return false;
  1936. return KIGEOM::BoxHitTest( aPoly, GetBodyBoundingBox(), aContained );
  1937. }
  1938. bool SCH_SYMBOL::doIsConnected( const VECTOR2I& aPosition ) const
  1939. {
  1940. VECTOR2I new_pos = m_transform.InverseTransform().TransformCoordinate( aPosition - m_pos );
  1941. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  1942. {
  1943. if( pin->GetType() == ELECTRICAL_PINTYPE::PT_NC )
  1944. continue;
  1945. // Collect only pins attached to the current unit and convert.
  1946. // others are not associated to this symbol instance
  1947. int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
  1948. : GetUnit();
  1949. int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
  1950. : GetBodyStyle();
  1951. if( pin_unit > 0 && pin_unit != GetUnit() )
  1952. continue;
  1953. if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
  1954. continue;
  1955. if( pin->GetLocalPosition() == new_pos )
  1956. return true;
  1957. }
  1958. return false;
  1959. }
  1960. bool SCH_SYMBOL::IsInNetlist() const
  1961. {
  1962. return m_isInNetlist;
  1963. }
  1964. void SCH_SYMBOL::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
  1965. int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
  1966. {
  1967. if( aBackground )
  1968. return;
  1969. if( m_part )
  1970. {
  1971. std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
  1972. // Copy the source so we can re-orient and translate it.
  1973. LIB_SYMBOL tempSymbol( *m_part );
  1974. std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
  1975. // Copy the pin info from the symbol to the temp pins
  1976. for( unsigned i = 0; i < tempPins.size(); ++ i )
  1977. {
  1978. SCH_PIN* symbolPin = GetPin( libPins[ i ] );
  1979. SCH_PIN* tempPin = tempPins[ i ];
  1980. tempPin->SetName( symbolPin->GetShownName() );
  1981. tempPin->SetType( symbolPin->GetType() );
  1982. tempPin->SetShape( symbolPin->GetShape() );
  1983. if( symbolPin->IsDangling() )
  1984. tempPin->SetFlags( IS_DANGLING );
  1985. }
  1986. for( SCH_ITEM& item : tempSymbol.GetDrawItems() )
  1987. {
  1988. if( EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( &item ) )
  1989. {
  1990. // Use SCH_FIELD's text resolver
  1991. SCH_FIELD dummy( this, FIELD_T::USER );
  1992. dummy.SetText( text->GetText() );
  1993. text->SetText( dummy.GetShownText( false ) );
  1994. }
  1995. }
  1996. SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
  1997. TRANSFORM savedTransform = renderSettings->m_Transform;
  1998. renderSettings->m_Transform = GetTransform();
  1999. aPlotter->StartBlock( nullptr );
  2000. for( bool local_background : { true, false } )
  2001. {
  2002. tempSymbol.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(),
  2003. m_pos, GetDNP() );
  2004. for( SCH_FIELD field : m_fields )
  2005. {
  2006. field.ClearRenderCache();
  2007. field.Plot( aPlotter, local_background, aPlotOpts, GetUnit(), GetBodyStyle(),
  2008. m_pos, GetDNP() );
  2009. }
  2010. }
  2011. if( m_DNP )
  2012. PlotDNP( aPlotter );
  2013. SCH_SHEET_PATH* sheet = &Schematic()->CurrentSheet();
  2014. // Plot attributes to a hypertext menu
  2015. if( aPlotOpts.m_PDFPropertyPopups )
  2016. {
  2017. std::vector<wxString> properties;
  2018. for( const SCH_FIELD& field : GetFields() )
  2019. {
  2020. wxString text_field = field.GetShownText( sheet, false);
  2021. if( text_field.IsEmpty() )
  2022. continue;
  2023. properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
  2024. field.GetName(), text_field ) );
  2025. }
  2026. if( !m_part->GetKeyWords().IsEmpty() )
  2027. {
  2028. properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
  2029. _( "Keywords" ),
  2030. m_part->GetKeyWords() ) );
  2031. }
  2032. aPlotter->HyperlinkMenu( GetBoundingBox(), properties );
  2033. }
  2034. aPlotter->EndBlock( nullptr );
  2035. renderSettings->m_Transform = savedTransform;
  2036. if( !m_part->IsPower() )
  2037. aPlotter->Bookmark( GetBoundingBox(), GetRef( sheet ), _( "Symbols" ) );
  2038. }
  2039. }
  2040. void SCH_SYMBOL::PlotDNP( PLOTTER* aPlotter ) const
  2041. {
  2042. BOX2I bbox = GetBodyBoundingBox();
  2043. BOX2I pins = GetBodyAndPinsBoundingBox();
  2044. VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(),
  2045. pins.GetEnd().x - bbox.GetEnd().x ),
  2046. std::max( bbox.GetY() - pins.GetY(),
  2047. pins.GetEnd().y - bbox.GetEnd().y ) );
  2048. int strokeWidth = 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
  2049. margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
  2050. margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
  2051. bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
  2052. SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
  2053. aPlotter->SetColor( renderSettings->GetLayerColor( LAYER_DNP_MARKER ) );
  2054. aPlotter->ThickSegment( bbox.GetOrigin(), bbox.GetEnd(), strokeWidth, nullptr );
  2055. aPlotter->ThickSegment( bbox.GetOrigin() + VECTOR2I( bbox.GetWidth(), 0 ),
  2056. bbox.GetOrigin() + VECTOR2I( 0, bbox.GetHeight() ),
  2057. strokeWidth, nullptr );
  2058. }
  2059. void SCH_SYMBOL::PlotPins( PLOTTER* aPlotter ) const
  2060. {
  2061. if( m_part )
  2062. {
  2063. SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
  2064. TRANSFORM savedTransform = renderSettings->m_Transform;
  2065. renderSettings->m_Transform = GetTransform();
  2066. std::vector<SCH_PIN*> libPins = m_part->GetGraphicalPins( GetUnit(), GetBodyStyle() );
  2067. // Copy the source to stay const
  2068. LIB_SYMBOL tempSymbol( *m_part );
  2069. std::vector<SCH_PIN*> tempPins = tempSymbol.GetGraphicalPins( GetUnit(), GetBodyStyle() );
  2070. SCH_PLOT_OPTS plotOpts;
  2071. // Copy the pin info from the symbol to the temp pins
  2072. for( unsigned i = 0; i < tempPins.size(); ++ i )
  2073. {
  2074. SCH_PIN* symbolPin = GetPin( libPins[ i ] );
  2075. SCH_PIN* tempPin = tempPins[ i ];
  2076. tempPin->SetName( symbolPin->GetShownName() );
  2077. tempPin->SetType( symbolPin->GetType() );
  2078. tempPin->SetShape( symbolPin->GetShape() );
  2079. tempPin->Plot( aPlotter, false, plotOpts, GetUnit(), GetBodyStyle(), m_pos, GetDNP() );
  2080. }
  2081. renderSettings->m_Transform = savedTransform;
  2082. }
  2083. }
  2084. bool SCH_SYMBOL::HasBrightenedPins()
  2085. {
  2086. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  2087. {
  2088. if( pin->IsBrightened() )
  2089. return true;
  2090. }
  2091. return false;
  2092. }
  2093. void SCH_SYMBOL::ClearBrightenedPins()
  2094. {
  2095. for( std::unique_ptr<SCH_PIN>& pin : m_pins )
  2096. pin->ClearBrightened();
  2097. }
  2098. /*
  2099. * When modified at the schematic level, we still store the values of these flags in the
  2100. * associated m_part. If m_part now diverges from other usages, a new derived LIB_SYMBOL
  2101. * will be created and stored locally in the schematic.
  2102. */
  2103. bool SCH_SYMBOL::GetShowPinNames() const
  2104. {
  2105. return m_part && m_part->GetShowPinNames();
  2106. }
  2107. void SCH_SYMBOL::SetShowPinNames( bool aShow )
  2108. {
  2109. if( m_part )
  2110. m_part->SetShowPinNames( aShow );
  2111. }
  2112. bool SCH_SYMBOL::GetShowPinNumbers() const
  2113. {
  2114. return m_part && m_part->GetShowPinNumbers();
  2115. }
  2116. void SCH_SYMBOL::SetShowPinNumbers( bool aShow )
  2117. {
  2118. if( m_part )
  2119. m_part->SetShowPinNumbers( aShow );
  2120. }
  2121. bool SCH_SYMBOL::IsPointClickableAnchor( const VECTOR2I& aPos ) const
  2122. {
  2123. for( const std::unique_ptr<SCH_PIN>& pin : m_pins )
  2124. {
  2125. int pin_unit = pin->GetLibPin() ? pin->GetLibPin()->GetUnit()
  2126. : GetUnit();
  2127. int pin_bodyStyle = pin->GetLibPin() ? pin->GetLibPin()->GetBodyStyle()
  2128. : GetBodyStyle();
  2129. if( pin_unit > 0 && pin_unit != GetUnit() )
  2130. continue;
  2131. if( pin_bodyStyle > 0 && pin_bodyStyle != GetBodyStyle() )
  2132. continue;
  2133. if( pin->IsPointClickableAnchor( aPos ) )
  2134. return true;
  2135. }
  2136. return false;
  2137. }
  2138. bool SCH_SYMBOL::IsSymbolLikePowerGlobalLabel() const
  2139. {
  2140. // return true if the symbol is equivalent to a global label:
  2141. // It is a Power symbol
  2142. // It has only one pin type Power input
  2143. if( !GetLibSymbolRef() || !GetLibSymbolRef()->IsGlobalPower() )
  2144. return false;
  2145. std::vector<SCH_PIN*> pin_list = GetAllLibPins();
  2146. if( pin_list.size() != 1 )
  2147. return false;
  2148. return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
  2149. }
  2150. bool SCH_SYMBOL::IsSymbolLikePowerLocalLabel() const
  2151. {
  2152. // return true if the symbol is equivalent to a local label:
  2153. // It is a Power symbol
  2154. // It has only one pin type Power input
  2155. if( !GetLibSymbolRef() || !GetLibSymbolRef()->IsLocalPower() )
  2156. return false;
  2157. std::vector<SCH_PIN*> pin_list = GetAllLibPins();
  2158. if( pin_list.size() != 1 )
  2159. return false;
  2160. return pin_list[0]->GetType() == ELECTRICAL_PINTYPE::PT_POWER_IN;
  2161. }
  2162. bool SCH_SYMBOL::IsLocalPower() const
  2163. {
  2164. if( !m_part )
  2165. return false;
  2166. return m_part->IsLocalPower();
  2167. }
  2168. bool SCH_SYMBOL::IsGlobalPower() const
  2169. {
  2170. if( !m_part )
  2171. return false;
  2172. return m_part->IsGlobalPower();
  2173. }
  2174. bool SCH_SYMBOL::IsPower() const
  2175. {
  2176. return IsLocalPower() || IsGlobalPower();
  2177. }
  2178. bool SCH_SYMBOL::IsNormal() const
  2179. {
  2180. wxCHECK( m_part, false );
  2181. return m_part->IsNormal();
  2182. }
  2183. std::unordered_set<wxString> SCH_SYMBOL::GetComponentClassNames( const SCH_SHEET_PATH* aPath ) const
  2184. {
  2185. std::unordered_set<wxString> componentClass;
  2186. auto getComponentClassFields =
  2187. [&]( const std::vector<SCH_FIELD>& fields )
  2188. {
  2189. for( const SCH_FIELD& field : fields )
  2190. {
  2191. if( field.GetCanonicalName() == wxT( "Component Class" ) )
  2192. {
  2193. if( field.GetShownText( aPath, false ) != wxEmptyString )
  2194. componentClass.insert( field.GetShownText( aPath, false ) );
  2195. }
  2196. }
  2197. };
  2198. // First get component classes set on the symbol itself
  2199. getComponentClassFields( m_fields );
  2200. // Now get component classes set on any enclosing rule areas
  2201. for( const SCH_RULE_AREA* ruleArea : m_rule_areas_cache )
  2202. {
  2203. for( const SCH_DIRECTIVE_LABEL* label : ruleArea->GetDirectives() )
  2204. {
  2205. getComponentClassFields( label->GetFields() );
  2206. }
  2207. }
  2208. return componentClass;
  2209. }
  2210. bool SCH_SYMBOL::operator==( const SCH_ITEM& aOther ) const
  2211. {
  2212. if( Type() != aOther.Type() )
  2213. return false;
  2214. const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
  2215. if( GetLibId() != symbol.GetLibId() )
  2216. return false;
  2217. if( GetPosition() != symbol.GetPosition() )
  2218. return false;
  2219. if( GetUnit() != symbol.GetUnit() )
  2220. return false;
  2221. if( GetBodyStyle() != symbol.GetBodyStyle() )
  2222. return false;
  2223. if( GetTransform() != symbol.GetTransform() )
  2224. return false;
  2225. if( GetFields() != symbol.GetFields() )
  2226. return false;
  2227. if( m_pins.size() != symbol.m_pins.size() )
  2228. return false;
  2229. for( unsigned i = 0; i < m_pins.size(); ++i )
  2230. {
  2231. if( *m_pins[i] != *symbol.m_pins[i] )
  2232. return false;
  2233. }
  2234. return true;
  2235. }
  2236. double SCH_SYMBOL::Similarity( const SCH_ITEM& aOther ) const
  2237. {
  2238. if( Type() != aOther.Type() )
  2239. return 0.0;
  2240. const SCH_SYMBOL& symbol = static_cast<const SCH_SYMBOL&>( aOther );
  2241. if( GetLibId() != symbol.GetLibId() )
  2242. return 0.0;
  2243. if( GetPosition() == symbol.GetPosition() )
  2244. return 1.0;
  2245. return 0.0;
  2246. }
  2247. static struct SCH_SYMBOL_DESC
  2248. {
  2249. SCH_SYMBOL_DESC()
  2250. {
  2251. ENUM_MAP<SYMBOL_ORIENTATION_PROP>::Instance()
  2252. .Map( SYMBOL_ANGLE_0, wxS( "0" ) )
  2253. .Map( SYMBOL_ANGLE_90, wxS( "90" ) )
  2254. .Map( SYMBOL_ANGLE_180, wxS( "180" ) )
  2255. .Map( SYMBOL_ANGLE_270, wxS( "270" ) );
  2256. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  2257. REGISTER_TYPE( SCH_SYMBOL );
  2258. propMgr.InheritsAfter( TYPE_HASH( SCH_SYMBOL ), TYPE_HASH( SYMBOL ) );
  2259. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position X" ),
  2260. &SCH_SYMBOL::SetX, &SCH_SYMBOL::GetX, PROPERTY_DISPLAY::PT_COORD,
  2261. ORIGIN_TRANSFORMS::ABS_X_COORD ) );
  2262. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Position Y" ),
  2263. &SCH_SYMBOL::SetY, &SCH_SYMBOL::GetY, PROPERTY_DISPLAY::PT_COORD,
  2264. ORIGIN_TRANSFORMS::ABS_Y_COORD ) );
  2265. propMgr.AddProperty( new PROPERTY_ENUM<SCH_SYMBOL, SYMBOL_ORIENTATION_PROP>( _HKI( "Orientation" ),
  2266. &SCH_SYMBOL::SetOrientationProp, &SCH_SYMBOL::GetOrientationProp ) );
  2267. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror X" ),
  2268. &SCH_SYMBOL::SetMirrorX, &SCH_SYMBOL::GetMirrorX ) );
  2269. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, bool>( _HKI( "Mirror Y" ),
  2270. &SCH_SYMBOL::SetMirrorY, &SCH_SYMBOL::GetMirrorY ) );
  2271. auto hasLibPart =
  2272. []( INSPECTABLE* aItem ) -> bool
  2273. {
  2274. if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
  2275. return symbol->GetLibSymbolRef() != nullptr;
  2276. return false;
  2277. };
  2278. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin numbers" ),
  2279. &SYMBOL::SetShowPinNumbers, &SYMBOL::GetShowPinNumbers ) )
  2280. .SetAvailableFunc( hasLibPart );
  2281. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Pin names" ),
  2282. &SYMBOL::SetShowPinNames, &SYMBOL::GetShowPinNames ) )
  2283. .SetAvailableFunc( hasLibPart );
  2284. const wxString groupFields = _HKI( "Fields" );
  2285. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Reference" ),
  2286. &SCH_SYMBOL::SetRefProp, &SCH_SYMBOL::GetRefProp ),
  2287. groupFields );
  2288. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Value" ),
  2289. &SCH_SYMBOL::SetValueProp, &SCH_SYMBOL::GetValueProp ),
  2290. groupFields );
  2291. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Link" ),
  2292. NO_SETTER( SCH_SYMBOL, wxString ), &SCH_SYMBOL::GetSymbolIDAsString ),
  2293. groupFields );
  2294. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Library Description" ),
  2295. NO_SETTER( SCH_SYMBOL, wxString ), &SCH_SYMBOL::GetDescription ),
  2296. groupFields );
  2297. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Keywords" ),
  2298. NO_SETTER( SCH_SYMBOL, wxString ), &SCH_SYMBOL::GetKeyWords ),
  2299. groupFields );
  2300. auto multiUnit =
  2301. [=]( INSPECTABLE* aItem ) -> bool
  2302. {
  2303. if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
  2304. return symbol->IsMultiUnit();
  2305. return false;
  2306. };
  2307. auto multiBodyStyle =
  2308. [=]( INSPECTABLE* aItem ) -> bool
  2309. {
  2310. if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
  2311. return symbol->IsMultiBodyStyle();
  2312. return false;
  2313. };
  2314. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, int>( _HKI( "Unit" ),
  2315. &SCH_SYMBOL::SetUnitProp, &SCH_SYMBOL::GetUnitProp ) )
  2316. .SetAvailableFunc( multiUnit )
  2317. .SetChoicesFunc( []( INSPECTABLE* aItem )
  2318. {
  2319. wxPGChoices choices;
  2320. if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
  2321. {
  2322. for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
  2323. choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
  2324. }
  2325. return choices;
  2326. } );
  2327. propMgr.AddProperty( new PROPERTY<SCH_SYMBOL, wxString>( _HKI( "Body Style" ),
  2328. &SCH_SYMBOL::SetBodyStyleProp, &SCH_SYMBOL::GetBodyStyleProp ) )
  2329. .SetAvailableFunc( multiBodyStyle )
  2330. .SetChoicesFunc( []( INSPECTABLE* aItem )
  2331. {
  2332. wxPGChoices choices;
  2333. if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( aItem ) )
  2334. {
  2335. for( int ii = 1; ii <= symbol->GetBodyStyleCount(); ii++ )
  2336. choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
  2337. }
  2338. return choices;
  2339. } );
  2340. const wxString groupAttributes = _HKI( "Attributes" );
  2341. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Exclude From Board" ),
  2342. &SYMBOL::SetExcludedFromBoard, &SYMBOL::GetExcludedFromBoard ),
  2343. groupAttributes );
  2344. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Exclude From Simulation" ),
  2345. &SYMBOL::SetExcludedFromSim, &SYMBOL::GetExcludedFromSim ),
  2346. groupAttributes );
  2347. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Exclude From Bill of Materials" ),
  2348. &SYMBOL::SetExcludedFromBOM, &SYMBOL::GetExcludedFromBOM ),
  2349. groupAttributes );
  2350. propMgr.AddProperty( new PROPERTY<SYMBOL, bool>( _HKI( "Do not Populate" ),
  2351. &SYMBOL::SetDNP, &SYMBOL::GetDNP ),
  2352. groupAttributes );
  2353. }
  2354. } _SCH_SYMBOL_DESC;
  2355. ENUM_TO_WXANY( SYMBOL_ORIENTATION_PROP )