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.

807 lines
23 KiB

2 years ago
2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  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 <pgm_base.h>
  25. #include <settings/settings_manager.h>
  26. #include <eeschema_settings.h>
  27. #include <eda_item.h>
  28. #include <sch_connection.h>
  29. #include <sch_group.h>
  30. #include <sch_rule_area.h>
  31. #include <sch_draw_panel.h>
  32. #include <sch_edit_frame.h>
  33. #include <connection_graph.h>
  34. #include <netclass.h>
  35. #include <project/project_file.h>
  36. #include <project/net_settings.h>
  37. #include <font/kicad_font_name.h>
  38. // Rendering fonts is expensive (particularly when using outline fonts). At small effective
  39. // sizes (ie: zoomed out) the visual differences between outline and/or stroke fonts and the
  40. // bitmap font becomes immaterial, and there's often more to draw when zoomed out so the
  41. // performance gain becomes more significant.
  42. #define BITMAP_FONT_SIZE_THRESHOLD 3
  43. /* Constructor and destructor for SCH_ITEM */
  44. /* They are not inline because this creates problems with gcc at linking time in debug mode */
  45. SCH_ITEM::SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType, int aUnit, int aBodyStyle ) :
  46. EDA_ITEM( aParent, aType, true, false ),
  47. m_unit( aUnit ),
  48. m_bodyStyle( aBodyStyle ),
  49. m_private( false )
  50. {
  51. m_layer = LAYER_WIRE; // It's only a default, in fact
  52. m_fieldsAutoplaced = AUTOPLACE_NONE;
  53. m_connectivity_dirty = false; // Item is unconnected until it is placed, so it's clean
  54. }
  55. SCH_ITEM::SCH_ITEM( const SCH_ITEM& aItem ) :
  56. EDA_ITEM( aItem )
  57. {
  58. m_layer = aItem.m_layer;
  59. m_unit = aItem.m_unit;
  60. m_bodyStyle = aItem.m_bodyStyle;
  61. m_private = aItem.m_private;
  62. m_fieldsAutoplaced = aItem.m_fieldsAutoplaced;
  63. m_connectivity_dirty = aItem.m_connectivity_dirty;
  64. }
  65. SCH_ITEM& SCH_ITEM::operator=( const SCH_ITEM& aItem )
  66. {
  67. m_layer = aItem.m_layer;
  68. m_unit = aItem.m_unit;
  69. m_bodyStyle = aItem.m_bodyStyle;
  70. m_private = aItem.m_private;
  71. m_fieldsAutoplaced = aItem.m_fieldsAutoplaced;
  72. m_connectivity_dirty = aItem.m_connectivity_dirty;
  73. return *this;
  74. }
  75. SCH_ITEM::~SCH_ITEM()
  76. {
  77. for( const auto& it : m_connection_map )
  78. delete it.second;
  79. // Do not try to modify SCHEMATIC::ConnectionGraph()
  80. // if the schematic does not exist
  81. if( !SCHEMATIC::m_IsSchematicExists )
  82. return;
  83. SCHEMATIC* sch = Schematic();
  84. if( sch != nullptr )
  85. sch->ConnectionGraph()->RemoveItem( this );
  86. }
  87. bool SCH_ITEM::IsGroupableType() const
  88. {
  89. switch( Type() )
  90. {
  91. case SCH_SYMBOL_T:
  92. case SCH_PIN_T:
  93. case SCH_SHAPE_T:
  94. case SCH_BITMAP_T:
  95. case SCH_FIELD_T:
  96. case SCH_TEXT_T:
  97. case SCH_TEXTBOX_T:
  98. case SCH_TABLE_T:
  99. case SCH_GROUP_T:
  100. case SCH_LINE_T:
  101. case SCH_JUNCTION_T:
  102. case SCH_NO_CONNECT_T:
  103. case SCH_BUS_WIRE_ENTRY_T:
  104. case SCH_BUS_BUS_ENTRY_T:
  105. case SCH_LABEL_T:
  106. case SCH_GLOBAL_LABEL_T:
  107. case SCH_HIER_LABEL_T:
  108. case SCH_RULE_AREA_T:
  109. case SCH_DIRECTIVE_LABEL_T:
  110. case SCH_SHEET_PIN_T:
  111. case SCH_SHEET_T:
  112. return true;
  113. default:
  114. return false;
  115. }
  116. }
  117. SCH_ITEM* SCH_ITEM::Duplicate( bool addToParentGroup, SCH_COMMIT* aCommit, bool doClone ) const
  118. {
  119. SCH_ITEM* newItem = (SCH_ITEM*) Clone();
  120. if( !doClone )
  121. const_cast<KIID&>( newItem->m_Uuid ) = KIID();
  122. newItem->ClearFlags( SELECTED | BRIGHTENED );
  123. newItem->RunOnChildren(
  124. []( SCH_ITEM* aChild )
  125. {
  126. aChild->ClearFlags( SELECTED | BRIGHTENED );
  127. },
  128. RECURSE_MODE::NO_RECURSE );
  129. if( addToParentGroup )
  130. {
  131. wxCHECK_MSG( aCommit, newItem, "Must supply a commit to update parent group" );
  132. if( EDA_GROUP* group = newItem->GetParentGroup() )
  133. {
  134. aCommit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
  135. group->AddItem( newItem );
  136. }
  137. }
  138. return newItem;
  139. }
  140. wxString SCH_ITEM::GetUnitDisplayName( int aUnit, bool aLabel ) const
  141. {
  142. if( aUnit == 0 )
  143. return aLabel ? _( "All units" ) : wxString( _HKI( "All units" ) );
  144. else if( const SYMBOL* symbol = GetParentSymbol() )
  145. return symbol->GetUnitDisplayName( aUnit, aLabel );
  146. return wxEmptyString;
  147. }
  148. wxString SCH_ITEM::GetBodyStyleDescription( int aBodyStyle, bool aLabel ) const
  149. {
  150. if( aBodyStyle == 0 )
  151. return aLabel ? _( "All body styles" ) : wxString( _HKI( "All body styles" ) );
  152. else if( const SYMBOL* symbol = GetParentSymbol() )
  153. return symbol->GetBodyStyleDescription( aBodyStyle, aLabel );
  154. return wxEmptyString;
  155. }
  156. void SCH_ITEM::SetBodyStyleProp( const wxString& aBodyStyle )
  157. {
  158. if( aBodyStyle == _HKI( "All body styles" ) )
  159. {
  160. m_bodyStyle = 0;
  161. return;
  162. }
  163. if( SYMBOL* symbol = GetParentSymbol() )
  164. {
  165. for( int bodyStyle : { BODY_STYLE::BASE, BODY_STYLE::DEMORGAN } )
  166. {
  167. if( symbol->GetBodyStyleDescription( bodyStyle, false ) == aBodyStyle )
  168. {
  169. m_bodyStyle = bodyStyle;
  170. return;
  171. }
  172. }
  173. }
  174. }
  175. wxString SCH_ITEM::GetBodyStyleProp() const
  176. {
  177. return GetBodyStyleDescription( m_bodyStyle, false );
  178. }
  179. SCHEMATIC* SCH_ITEM::Schematic() const
  180. {
  181. return static_cast<SCHEMATIC*>( findParent( SCHEMATIC_T ) );
  182. }
  183. const SYMBOL* SCH_ITEM::GetParentSymbol() const
  184. {
  185. if( SYMBOL* sch_symbol = static_cast<SCH_SYMBOL*>( findParent( SCH_SYMBOL_T ) ) )
  186. return sch_symbol;
  187. if( SYMBOL* lib_symbol = static_cast<LIB_SYMBOL*>( findParent( LIB_SYMBOL_T ) ) )
  188. return lib_symbol;
  189. return nullptr;
  190. }
  191. SYMBOL* SCH_ITEM::GetParentSymbol()
  192. {
  193. if( SYMBOL* sch_symbol = static_cast<SCH_SYMBOL*>( findParent( SCH_SYMBOL_T ) ) )
  194. return sch_symbol;
  195. if( SYMBOL* lib_symbol = static_cast<LIB_SYMBOL*>( findParent( LIB_SYMBOL_T ) ) )
  196. return lib_symbol;
  197. return nullptr;
  198. }
  199. bool SCH_ITEM::ResolveExcludedFromSim( const SCH_SHEET_PATH* aInstance,
  200. const wxString& aVariantName ) const
  201. {
  202. if( GetExcludedFromSim( aInstance, aVariantName ) )
  203. return true;
  204. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  205. {
  206. if( area->GetExcludedFromSim( aInstance, aVariantName ) )
  207. return true;
  208. }
  209. return false;
  210. }
  211. bool SCH_ITEM::ResolveExcludedFromBOM( const SCH_SHEET_PATH* aInstance,
  212. const wxString& aVariantName ) const
  213. {
  214. if( GetExcludedFromBOM( aInstance, aVariantName ) )
  215. return true;
  216. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  217. {
  218. if( area->GetExcludedFromBOM( aInstance, aVariantName ) )
  219. return true;
  220. }
  221. return false;
  222. }
  223. bool SCH_ITEM::ResolveExcludedFromBoard() const
  224. {
  225. if( GetExcludedFromBoard() )
  226. return true;
  227. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  228. {
  229. if( area->GetExcludedFromBoard() )
  230. return true;
  231. }
  232. return false;
  233. }
  234. bool SCH_ITEM::ResolveDNP( const SCH_SHEET_PATH* aInstance, const wxString& aVariantName ) const
  235. {
  236. if( GetDNP( aInstance, aVariantName ) )
  237. return true;
  238. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  239. {
  240. if( area->GetDNP( aInstance, aVariantName ) )
  241. return true;
  242. }
  243. return false;
  244. }
  245. std::vector<int> SCH_ITEM::ViewGetLayers() const
  246. {
  247. // Basic fallback
  248. return { LAYER_DEVICE, LAYER_DEVICE_BACKGROUND, LAYER_SELECTION_SHADOWS };
  249. }
  250. bool SCH_ITEM::IsConnected( const VECTOR2I& aPosition ) const
  251. {
  252. if(( m_flags & STRUCT_DELETED ) || ( m_flags & SKIP_STRUCT ) )
  253. return false;
  254. return doIsConnected( aPosition );
  255. }
  256. SCH_CONNECTION* SCH_ITEM::Connection( const SCH_SHEET_PATH* aSheet ) const
  257. {
  258. if( !IsConnectable() )
  259. return nullptr;
  260. if( !aSheet )
  261. aSheet = &Schematic()->CurrentSheet();
  262. auto it = m_connection_map.find( *aSheet );
  263. if( it == m_connection_map.end() )
  264. return nullptr;
  265. else
  266. return it->second;
  267. }
  268. void SCH_ITEM::SetConnectionGraph( CONNECTION_GRAPH* aGraph )
  269. {
  270. for( auto& [path, conn] : m_connection_map )
  271. {
  272. conn->SetGraph( aGraph );
  273. for( auto& member : conn->AllMembers() )
  274. member->SetGraph( aGraph );
  275. }
  276. }
  277. std::shared_ptr<NETCLASS> SCH_ITEM::GetEffectiveNetClass( const SCH_SHEET_PATH* aSheet ) const
  278. {
  279. static std::shared_ptr<NETCLASS> nullNetclass = std::make_shared<NETCLASS>( wxEmptyString );
  280. SCHEMATIC* schematic = Schematic();
  281. if( schematic )
  282. {
  283. std::shared_ptr<NET_SETTINGS>& netSettings = schematic->Project().GetProjectFile().m_NetSettings;
  284. SCH_CONNECTION* connection = Connection( aSheet );
  285. if( connection )
  286. return netSettings->GetEffectiveNetClass( connection->Name() );
  287. else
  288. return netSettings->GetDefaultNetclass();
  289. }
  290. return nullNetclass;
  291. }
  292. void SCH_ITEM::ClearConnectedItems( const SCH_SHEET_PATH& aSheet )
  293. {
  294. auto it = m_connected_items.find( aSheet );
  295. if( it != m_connected_items.end() )
  296. it->second.clear();
  297. }
  298. const SCH_ITEM_VEC& SCH_ITEM::ConnectedItems( const SCH_SHEET_PATH& aSheet )
  299. {
  300. return m_connected_items[ aSheet ];
  301. }
  302. void SCH_ITEM::AddConnectionTo( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aItem )
  303. {
  304. SCH_ITEM_VEC& vec = m_connected_items[ aSheet ];
  305. // The vector elements are small, so reserve 1k at a time to prevent re-allocations
  306. if( vec.size() == vec.capacity() )
  307. vec.reserve( vec.size() + 4096 );
  308. // Add item to the correct place in the sorted vector if it is not already there
  309. auto it = std::lower_bound( vec.begin(), vec.end(), aItem );
  310. if( it == vec.end() || *it != aItem )
  311. vec.insert( it, aItem );
  312. }
  313. SCH_CONNECTION* SCH_ITEM::InitializeConnection( const SCH_SHEET_PATH& aSheet,
  314. CONNECTION_GRAPH* aGraph )
  315. {
  316. SCH_CONNECTION* connection = Connection( &aSheet );
  317. // N.B. Do not clear the dirty connectivity flag here because we may need
  318. // to create a connection for a different sheet, and we don't want to
  319. // skip the connection creation because the flag is cleared.
  320. if( connection )
  321. {
  322. connection->Reset();
  323. }
  324. else
  325. {
  326. connection = new SCH_CONNECTION( this );
  327. m_connection_map.insert( std::make_pair( aSheet, connection ) );
  328. }
  329. connection->SetGraph( aGraph );
  330. connection->SetSheet( aSheet );
  331. return connection;
  332. }
  333. SCH_CONNECTION* SCH_ITEM::GetOrInitConnection( const SCH_SHEET_PATH& aSheet,
  334. CONNECTION_GRAPH* aGraph )
  335. {
  336. if( !IsConnectable() )
  337. return nullptr;
  338. SCH_CONNECTION* connection = Connection( &aSheet );
  339. if( connection )
  340. return connection;
  341. else
  342. return InitializeConnection( aSheet, aGraph );
  343. }
  344. const wxString& SCH_ITEM::GetCachedDriverName() const
  345. {
  346. static wxString s_empty;
  347. return s_empty;
  348. }
  349. void SCH_ITEM::swapData( SCH_ITEM* aItem )
  350. {
  351. UNIMPLEMENTED_FOR( GetClass() );
  352. }
  353. void SCH_ITEM::SwapItemData( SCH_ITEM* aImage )
  354. {
  355. if( aImage == nullptr )
  356. return;
  357. EDA_ITEM* parent = GetParent();
  358. SwapFlags( aImage );
  359. std::swap( m_layer, aImage->m_layer );
  360. std::swap( m_unit, aImage->m_unit );
  361. std::swap( m_bodyStyle, aImage->m_bodyStyle );
  362. std::swap( m_private, aImage->m_private );
  363. std::swap( m_fieldsAutoplaced, aImage->m_fieldsAutoplaced );
  364. std::swap( m_group, aImage->m_group );
  365. swapData( aImage );
  366. SetParent( parent );
  367. }
  368. void SCH_ITEM::SwapFlags( SCH_ITEM* aItem )
  369. {
  370. EDA_ITEM_FLAGS editFlags = GetEditFlags();
  371. EDA_ITEM_FLAGS tempFlags = GetTempFlags();
  372. EDA_ITEM_FLAGS aItem_editFlags = aItem->GetEditFlags();
  373. EDA_ITEM_FLAGS aItem_tempFlags = aItem->GetTempFlags();
  374. std::swap( m_flags, aItem->m_flags );
  375. ClearEditFlags();
  376. SetFlags( editFlags );
  377. ClearTempFlags();
  378. SetFlags( tempFlags );
  379. aItem->ClearEditFlags();
  380. aItem->SetFlags( aItem_editFlags );
  381. aItem->ClearTempFlags();
  382. aItem->SetFlags( aItem_tempFlags );
  383. }
  384. void SCH_ITEM::ClearCaches()
  385. {
  386. auto clearTextCaches =
  387. []( SCH_ITEM* aItem )
  388. {
  389. EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
  390. if( text )
  391. {
  392. text->ClearBoundingBoxCache();
  393. text->ClearRenderCache();
  394. }
  395. };
  396. clearTextCaches( this );
  397. RunOnChildren( clearTextCaches, RECURSE_MODE::NO_RECURSE );
  398. }
  399. bool SCH_ITEM::operator==( const SCH_ITEM& aOther ) const
  400. {
  401. if( Type() != aOther.Type() )
  402. return false;
  403. return compare( aOther, SCH_ITEM::COMPARE_FLAGS::EQUALITY ) == 0;
  404. }
  405. bool SCH_ITEM::operator<( const SCH_ITEM& aOther ) const
  406. {
  407. if( Type() != aOther.Type() )
  408. return Type() < aOther.Type();
  409. return ( compare( aOther ) < 0 );
  410. }
  411. bool SCH_ITEM::cmp_items::operator()( const SCH_ITEM* aFirst, const SCH_ITEM* aSecond ) const
  412. {
  413. return aFirst->compare( *aSecond, COMPARE_FLAGS::EQUALITY ) < 0;
  414. }
  415. int SCH_ITEM::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
  416. {
  417. if( Type() != aOther.Type() )
  418. return Type() - aOther.Type();
  419. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::UNIT ) && m_unit != aOther.m_unit )
  420. return m_unit - aOther.m_unit;
  421. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::UNIT ) && m_bodyStyle != aOther.m_bodyStyle )
  422. return m_bodyStyle - aOther.m_bodyStyle;
  423. if( IsPrivate() != aOther.IsPrivate() )
  424. return IsPrivate() ? 1 : -1;
  425. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::SKIP_TST_POS ) )
  426. {
  427. if( GetPosition().x != aOther.GetPosition().x )
  428. return GetPosition().x - aOther.GetPosition().x;
  429. if( GetPosition().y != aOther.GetPosition().y )
  430. return GetPosition().y - aOther.GetPosition().y;
  431. }
  432. if( ( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::EQUALITY )
  433. || ( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::ERC ) )
  434. {
  435. return 0;
  436. }
  437. if( m_Uuid < aOther.m_Uuid )
  438. return -1;
  439. if( m_Uuid > aOther.m_Uuid )
  440. return 1;
  441. return 0;
  442. }
  443. const wxString& SCH_ITEM::GetDefaultFont( const RENDER_SETTINGS* aSettings ) const
  444. {
  445. static wxString defaultName = KICAD_FONT_NAME;
  446. if( aSettings )
  447. return aSettings->GetDefaultFont();
  448. else if( EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) )
  449. return cfg->m_Appearance.default_font;
  450. else
  451. return defaultName;
  452. }
  453. const KIFONT::METRICS& SCH_ITEM::GetFontMetrics() const
  454. {
  455. if( SCHEMATIC* schematic = Schematic() )
  456. return schematic->Settings().m_FontMetrics;
  457. return KIFONT::METRICS::Default();
  458. }
  459. int SCH_ITEM::GetEffectivePenWidth( const SCH_RENDER_SETTINGS* aSettings ) const
  460. {
  461. // For historical reasons, a stored value of 0 means "default width" and negative
  462. // numbers meant "don't stroke".
  463. if( GetPenWidth() < 0 )
  464. {
  465. return 0;
  466. }
  467. else if( GetPenWidth() == 0 )
  468. {
  469. if( GetParent() && GetParent()->Type() == LIB_SYMBOL_T )
  470. return std::max( aSettings->m_SymbolLineWidth, aSettings->GetMinPenWidth() );
  471. else
  472. return std::max( aSettings->GetDefaultPenWidth(), aSettings->GetMinPenWidth() );
  473. }
  474. else
  475. {
  476. return std::max( GetPenWidth(), aSettings->GetMinPenWidth() );
  477. }
  478. }
  479. bool SCH_ITEM::RenderAsBitmap( double aWorldScale ) const
  480. {
  481. if( IsHypertext() )
  482. return false;
  483. if( const EDA_TEXT* text = dynamic_cast<const EDA_TEXT*>( this ) )
  484. return text->GetTextHeight() * aWorldScale < BITMAP_FONT_SIZE_THRESHOLD;
  485. return false;
  486. }
  487. void SCH_ITEM::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  488. {
  489. wxString msg;
  490. if( SYMBOL* symbol = GetParentSymbol() )
  491. {
  492. if( symbol->IsMultiUnit() )
  493. aList.emplace_back( _( "Unit" ), GetUnitDisplayName( GetUnit(), false ) );
  494. if( symbol->IsMultiBodyStyle() )
  495. aList.emplace_back( _( "Body Style" ), GetBodyStyleDescription( GetBodyStyle(), true ) );
  496. if( dynamic_cast<LIB_SYMBOL*>( symbol ) && IsPrivate() )
  497. aList.emplace_back( _( "Private" ), wxEmptyString );
  498. }
  499. }
  500. const std::vector<wxString>* SCH_ITEM::GetEmbeddedFonts()
  501. {
  502. if( SCHEMATIC* schematic = Schematic() )
  503. return schematic->GetEmbeddedFiles()->GetFontFiles();
  504. if( SYMBOL* symbol = GetParentSymbol() )
  505. {
  506. if( EMBEDDED_FILES* symbolEmbeddedFiles = symbol->GetEmbeddedFiles() )
  507. return symbolEmbeddedFiles->UpdateFontFiles();
  508. }
  509. return nullptr;
  510. }
  511. static struct SCH_ITEM_DESC
  512. {
  513. SCH_ITEM_DESC()
  514. {
  515. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  516. REGISTER_TYPE( SCH_ITEM );
  517. propMgr.InheritsAfter( TYPE_HASH( SCH_ITEM ), TYPE_HASH( EDA_ITEM ) );
  518. #ifdef NOTYET
  519. // Not yet functional in UI
  520. propMgr.AddProperty( new PROPERTY<SCH_ITEM, bool>( _HKI( "Locked" ),
  521. &SCH_ITEM::SetLocked, &SCH_ITEM::IsLocked ) );
  522. #endif
  523. auto multiUnit =
  524. [=]( INSPECTABLE* aItem ) -> bool
  525. {
  526. if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
  527. {
  528. if( const SYMBOL* symbol = schItem->GetParentSymbol() )
  529. return symbol->IsMultiUnit();
  530. }
  531. return false;
  532. };
  533. auto multiBodyStyle =
  534. [=]( INSPECTABLE* aItem ) -> bool
  535. {
  536. if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
  537. {
  538. if( const SYMBOL* symbol = schItem->GetParentSymbol() )
  539. return symbol->IsMultiBodyStyle();
  540. }
  541. return false;
  542. };
  543. propMgr.AddProperty( new PROPERTY<SCH_ITEM, int>( _HKI( "Unit" ),
  544. &SCH_ITEM::SetUnit, &SCH_ITEM::GetUnit ) )
  545. .SetAvailableFunc( multiUnit )
  546. .SetIsHiddenFromDesignEditors()
  547. .SetChoicesFunc( []( INSPECTABLE* aItem )
  548. {
  549. wxPGChoices choices;
  550. choices.Add( _HKI( "All units" ), 0 );
  551. if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
  552. {
  553. if( SYMBOL* symbol = item->GetParentSymbol() )
  554. {
  555. for( int ii = 1; ii <= symbol->GetUnitCount(); ii++ )
  556. choices.Add( symbol->GetUnitDisplayName( ii, false ), ii );
  557. }
  558. }
  559. return choices;
  560. } );
  561. propMgr.AddProperty( new PROPERTY<SCH_ITEM, wxString>( _HKI( "Body Style" ),
  562. &SCH_ITEM::SetBodyStyleProp, &SCH_ITEM::GetBodyStyleProp ) )
  563. .SetAvailableFunc( multiBodyStyle )
  564. .SetIsHiddenFromDesignEditors()
  565. .SetChoicesFunc( []( INSPECTABLE* aItem )
  566. {
  567. wxPGChoices choices;
  568. choices.Add( _HKI( "All body styles" ) );
  569. if( SCH_ITEM* item = dynamic_cast<SCH_ITEM*>( aItem ) )
  570. {
  571. if( SYMBOL* symbol = item->GetParentSymbol() )
  572. {
  573. for( int ii : { BODY_STYLE::BASE, BODY_STYLE::DEMORGAN } )
  574. choices.Add( symbol->GetBodyStyleDescription( ii, false ) );
  575. }
  576. }
  577. return choices;
  578. } );
  579. propMgr.AddProperty( new PROPERTY<SCH_ITEM, bool>( _HKI( "Private" ),
  580. &SCH_ITEM::SetPrivate, &SCH_ITEM::IsPrivate ) )
  581. .SetIsHiddenFromDesignEditors();
  582. }
  583. } _SCH_ITEM_DESC;
  584. IMPLEMENT_ENUM_TO_WXANY( SCH_LAYER_ID )
  585. static bool lessYX( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
  586. {
  587. const auto aPos = a.GetPosition();
  588. const auto bPos = b.GetPosition();
  589. return aPos.y < bPos.y ? true : ( aPos.y > bPos.y ? false : aPos.x < bPos.x );
  590. };
  591. static bool lessType( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
  592. {
  593. return a.GetType() < b.GetType();
  594. };
  595. std::vector<DANGLING_END_ITEM>::iterator
  596. DANGLING_END_ITEM_HELPER::get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos,
  597. const VECTOR2I& aPos )
  598. {
  599. DANGLING_END_ITEM needle = DANGLING_END_ITEM( PIN_END, nullptr, aPos );
  600. auto start = aItemListByPos.begin();
  601. auto end = aItemListByPos.end();
  602. return std::lower_bound( start, end, needle, lessYX );
  603. }
  604. std::vector<DANGLING_END_ITEM>::iterator
  605. DANGLING_END_ITEM_HELPER::get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType,
  606. const DANGLING_END_T& aType )
  607. {
  608. DANGLING_END_ITEM needle = DANGLING_END_ITEM( aType, nullptr, VECTOR2I{} );
  609. auto start = aItemListByType.begin();
  610. auto end = aItemListByType.end();
  611. return std::lower_bound( start, end, needle, lessType );
  612. }
  613. void DANGLING_END_ITEM_HELPER::sort_dangling_end_items(
  614. std::vector<DANGLING_END_ITEM>& aItemListByType,
  615. std::vector<DANGLING_END_ITEM>& aItemListByPos )
  616. {
  617. // WIRE_END pairs must be kept together. Hence stable sort.
  618. std::stable_sort( aItemListByType.begin(), aItemListByType.end(), lessType );
  619. // Sort by y first, pins are more likely to share x than y.
  620. std::sort( aItemListByPos.begin(), aItemListByPos.end(), lessYX );
  621. }