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.

1079 lines
26 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
// Dick Hollenbeck's KiROUND R&D // This provides better project control over rounding to int from double // than wxRound() did. This scheme provides better logging in Debug builds // and it provides for compile time calculation of constants. #include <stdio.h> #include <assert.h> #include <limits.h> //-----<KiROUND KIT>------------------------------------------------------------ /** * KiROUND * rounds a floating point number to an int using * "round halfway cases away from zero". * In Debug build an assert fires if will not fit into an int. */ #if defined( DEBUG ) // DEBUG: a macro to capture line and file, then calls this inline static inline int KiRound( double v, int line, const char* filename ) { v = v < 0 ? v - 0.5 : v + 0.5; if( v > INT_MAX + 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v ); } else if( v < INT_MIN - 0.5 ) { printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v ); } return int( v ); } #define KiROUND( v ) KiRound( v, __LINE__, __FILE__ ) #else // RELEASE: a macro so compile can pre-compute constants. #define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 ) #endif //-----</KiROUND KIT>----------------------------------------------------------- // Only a macro is compile time calculated, an inline function causes a static constructor // in a situation like this. // Therefore the Release build is best done with a MACRO not an inline function. int Computed = KiROUND( 14.3 * 8 ); int main( int argc, char** argv ) { for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 ) { int i = KiROUND( d ); printf( "t: %d %.16g\n", i, d ); } return 0; }
14 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2017 Kicad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file sch_sheet.cpp
  26. * @brief Implementation of SCH_SHEET class.
  27. */
  28. #include <fctsys.h>
  29. #include <sch_draw_panel.h>
  30. #include <draw_graphic_text.h>
  31. #include <trigo.h>
  32. #include <richio.h>
  33. #include <sch_edit_frame.h>
  34. #include <plotter.h>
  35. #include <kicad_string.h>
  36. #include <msgpanel.h>
  37. #include <sch_sheet.h>
  38. #include <sch_sheet_path.h>
  39. #include <sch_component.h>
  40. #include <netlist_object.h>
  41. #include <trace_helpers.h>
  42. SCH_SHEET::SCH_SHEET( const wxPoint& pos ) :
  43. SCH_ITEM( NULL, SCH_SHEET_T )
  44. {
  45. m_Layer = LAYER_SHEET;
  46. m_pos = pos;
  47. m_size = wxSize( MIN_SHEET_WIDTH, MIN_SHEET_HEIGHT );
  48. SetTimeStamp( GetNewTimeStamp() );
  49. m_sheetNameSize = GetDefaultTextSize();
  50. m_fileNameSize = GetDefaultTextSize();
  51. m_screen = NULL;
  52. m_name.Printf( wxT( "Sheet%8.8lX" ), (long) m_TimeStamp );
  53. m_fileName.Printf( wxT( "file%8.8lX.sch" ), (long) m_TimeStamp );
  54. }
  55. SCH_SHEET::SCH_SHEET( const SCH_SHEET& aSheet ) :
  56. SCH_ITEM( aSheet )
  57. {
  58. m_pos = aSheet.m_pos;
  59. m_size = aSheet.m_size;
  60. m_Layer = aSheet.m_Layer;
  61. SetTimeStamp( aSheet.m_TimeStamp );
  62. m_sheetNameSize = aSheet.m_sheetNameSize;
  63. m_fileNameSize = aSheet.m_fileNameSize;
  64. m_screen = aSheet.m_screen;
  65. m_name = aSheet.m_name;
  66. m_fileName = aSheet.m_fileName;
  67. m_pins = aSheet.m_pins;
  68. for( size_t i = 0; i < m_pins.size(); i++ )
  69. m_pins[i].SetParent( this );
  70. if( m_screen )
  71. m_screen->IncRefCount();
  72. }
  73. SCH_SHEET::~SCH_SHEET()
  74. {
  75. // also, look at the associated sheet & its reference count
  76. // perhaps it should be deleted also.
  77. if( m_screen )
  78. {
  79. m_screen->DecRefCount();
  80. if( m_screen->GetRefCount() == 0 )
  81. delete m_screen;
  82. }
  83. }
  84. EDA_ITEM* SCH_SHEET::Clone() const
  85. {
  86. return new SCH_SHEET( *this );
  87. }
  88. void SCH_SHEET::SetScreen( SCH_SCREEN* aScreen )
  89. {
  90. if( aScreen == m_screen )
  91. return;
  92. if( m_screen != NULL )
  93. {
  94. m_screen->DecRefCount();
  95. if( m_screen->GetRefCount() == 0 )
  96. {
  97. delete m_screen;
  98. m_screen = NULL;
  99. }
  100. }
  101. m_screen = aScreen;
  102. if( m_screen )
  103. m_screen->IncRefCount();
  104. }
  105. int SCH_SHEET::GetScreenCount() const
  106. {
  107. if( m_screen == NULL )
  108. return 0;
  109. return m_screen->GetRefCount();
  110. }
  111. SCH_SHEET* SCH_SHEET::GetRootSheet()
  112. {
  113. SCH_SHEET* sheet = dynamic_cast< SCH_SHEET* >( GetParent() );
  114. if( sheet == NULL )
  115. return this;
  116. // Recurse until a sheet is found with no parent which is the root sheet.
  117. return sheet->GetRootSheet();
  118. }
  119. void SCH_SHEET::SwapData( SCH_ITEM* aItem )
  120. {
  121. wxCHECK_RET( aItem->Type() == SCH_SHEET_T,
  122. wxString::Format( wxT( "SCH_SHEET object cannot swap data with %s object." ),
  123. GetChars( aItem->GetClass() ) ) );
  124. SCH_SHEET* sheet = ( SCH_SHEET* ) aItem;
  125. std::swap( m_pos, sheet->m_pos );
  126. std::swap( m_size, sheet->m_size );
  127. std::swap( m_name, sheet->m_name );
  128. std::swap( m_sheetNameSize, sheet->m_sheetNameSize );
  129. std::swap( m_fileNameSize, sheet->m_fileNameSize );
  130. m_pins.swap( sheet->m_pins );
  131. // Ensure sheet labels have their .m_Parent member pointing really on their
  132. // parent, after swapping.
  133. for( SCH_SHEET_PIN& sheetPin : m_pins )
  134. {
  135. sheetPin.SetParent( this );
  136. }
  137. for( SCH_SHEET_PIN& sheetPin : sheet->m_pins )
  138. {
  139. sheetPin.SetParent( sheet );
  140. }
  141. }
  142. void SCH_SHEET::AddPin( SCH_SHEET_PIN* aSheetPin )
  143. {
  144. wxASSERT( aSheetPin != NULL );
  145. wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T );
  146. m_pins.push_back( aSheetPin );
  147. renumberPins();
  148. }
  149. void SCH_SHEET::RemovePin( SCH_SHEET_PIN* aSheetPin )
  150. {
  151. wxASSERT( aSheetPin != NULL );
  152. wxASSERT( aSheetPin->Type() == SCH_SHEET_PIN_T );
  153. SCH_SHEET_PINS::iterator i;
  154. for( i = m_pins.begin(); i < m_pins.end(); ++i )
  155. {
  156. if( *i == aSheetPin )
  157. {
  158. m_pins.erase( i );
  159. renumberPins();
  160. return;
  161. }
  162. }
  163. wxLogDebug( wxT( "Fix me: attempt to remove label %s which is not in sheet %s." ),
  164. GetChars( aSheetPin->GetShownText() ), GetChars( m_name ) );
  165. }
  166. bool SCH_SHEET::HasPin( const wxString& aName )
  167. {
  168. for( const SCH_SHEET_PIN& pin : m_pins )
  169. {
  170. if( pin.GetText().CmpNoCase( aName ) == 0 )
  171. return true;
  172. }
  173. return false;
  174. }
  175. bool SCH_SHEET::IsVerticalOrientation() const
  176. {
  177. for( const SCH_SHEET_PIN& pin : m_pins )
  178. {
  179. if( pin.GetEdge() > 1 )
  180. return true;
  181. }
  182. return false;
  183. }
  184. bool SCH_SHEET::HasUndefinedPins()
  185. {
  186. for( const SCH_SHEET_PIN& pin : m_pins )
  187. {
  188. /* Search the schematic for a hierarchical label corresponding to this sheet label. */
  189. EDA_ITEM* DrawStruct = m_screen->GetDrawItems();
  190. const SCH_HIERLABEL* HLabel = NULL;
  191. for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Next() )
  192. {
  193. if( DrawStruct->Type() != SCH_HIERARCHICAL_LABEL_T )
  194. continue;
  195. HLabel = static_cast<SCH_HIERLABEL*>( DrawStruct );
  196. if( pin.GetText().CmpNoCase( HLabel->GetText() ) == 0 )
  197. break; // Found!
  198. HLabel = NULL;
  199. }
  200. if( HLabel == NULL ) // Corresponding hierarchical label not found.
  201. return true;
  202. }
  203. return false;
  204. }
  205. int SCH_SHEET::GetMinWidth() const
  206. {
  207. int width = MIN_SHEET_WIDTH;
  208. for( size_t i = 0; i < m_pins.size(); i++ )
  209. {
  210. int edge = m_pins[i].GetEdge();
  211. EDA_RECT pinRect = m_pins[i].GetBoundingBox();
  212. wxASSERT( edge != SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE );
  213. if( edge == SCH_SHEET_PIN::SHEET_TOP_SIDE || edge == SCH_SHEET_PIN::SHEET_BOTTOM_SIDE )
  214. {
  215. if( width < pinRect.GetRight() - m_pos.x )
  216. width = pinRect.GetRight() - m_pos.x;
  217. }
  218. else
  219. {
  220. if( width < pinRect.GetWidth() )
  221. width = pinRect.GetWidth();
  222. for( size_t j = 0; j < m_pins.size(); j++ )
  223. {
  224. // Check for pin directly across from the current pin.
  225. if( (i == j) || (m_pins[i].GetPosition().y != m_pins[j].GetPosition().y) )
  226. continue;
  227. if( width < pinRect.GetWidth() + m_pins[j].GetBoundingBox().GetWidth() )
  228. {
  229. width = pinRect.GetWidth() + m_pins[j].GetBoundingBox().GetWidth();
  230. break;
  231. }
  232. }
  233. }
  234. }
  235. return width;
  236. }
  237. int SCH_SHEET::GetMinHeight() const
  238. {
  239. int height = MIN_SHEET_HEIGHT;
  240. for( size_t i = 0; i < m_pins.size(); i++ )
  241. {
  242. int edge = m_pins[i].GetEdge();
  243. EDA_RECT pinRect = m_pins[i].GetBoundingBox();
  244. // Make sure pin is on top or bottom side of sheet.
  245. if( edge == SCH_SHEET_PIN::SHEET_RIGHT_SIDE || edge == SCH_SHEET_PIN::SHEET_LEFT_SIDE )
  246. {
  247. if( height < pinRect.GetBottom() - m_pos.y )
  248. height = pinRect.GetBottom() - m_pos.y;
  249. }
  250. else
  251. {
  252. if( height < pinRect.GetHeight() )
  253. height = pinRect.GetHeight();
  254. for( size_t j = 0; j < m_pins.size(); j++ )
  255. {
  256. // Check for pin directly above or below the current pin.
  257. if( (i == j) || (m_pins[i].GetPosition().x != m_pins[j].GetPosition().x) )
  258. continue;
  259. if( height < pinRect.GetHeight() + m_pins[j].GetBoundingBox().GetHeight() )
  260. {
  261. height = pinRect.GetHeight() + m_pins[j].GetBoundingBox().GetHeight();
  262. break;
  263. }
  264. }
  265. }
  266. }
  267. return height;
  268. }
  269. void SCH_SHEET::CleanupSheet()
  270. {
  271. SCH_SHEET_PINS::iterator i = m_pins.begin();
  272. while( i != m_pins.end() )
  273. {
  274. /* Search the schematic for a hierarchical label corresponding to this sheet label. */
  275. EDA_ITEM* DrawStruct = m_screen->GetDrawItems();
  276. const SCH_HIERLABEL* HLabel = NULL;
  277. for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Next() )
  278. {
  279. if( DrawStruct->Type() != SCH_HIERARCHICAL_LABEL_T )
  280. continue;
  281. HLabel = static_cast<SCH_HIERLABEL*>( DrawStruct );
  282. if( i->GetText().CmpNoCase( HLabel->GetText() ) == 0 )
  283. break; // Found!
  284. HLabel = NULL;
  285. }
  286. if( HLabel == NULL ) // Hlabel not found: delete sheet label.
  287. i = m_pins.erase( i );
  288. else
  289. ++i;
  290. }
  291. }
  292. SCH_SHEET_PIN* SCH_SHEET::GetPin( const wxPoint& aPosition )
  293. {
  294. for( SCH_SHEET_PIN& pin : m_pins )
  295. {
  296. if( pin.HitTest( aPosition, 0 ) )
  297. return &pin;
  298. }
  299. return NULL;
  300. }
  301. int SCH_SHEET::GetPenSize() const
  302. {
  303. return GetDefaultLineThickness();
  304. }
  305. wxPoint SCH_SHEET::GetSheetNamePosition()
  306. {
  307. wxPoint pos = m_pos;
  308. int margin = KiROUND( GetPenSize() / 2.0 + 4 + m_sheetNameSize * 0.3 );
  309. if( IsVerticalOrientation() )
  310. {
  311. pos.x -= margin;
  312. pos.y += m_size.y;
  313. }
  314. else
  315. {
  316. pos.y -= margin;
  317. }
  318. return pos;
  319. }
  320. wxPoint SCH_SHEET::GetFileNamePosition()
  321. {
  322. wxPoint pos = m_pos;
  323. int margin = KiROUND( GetPenSize() / 2.0 + 4 + m_fileNameSize * 0.4 );
  324. if( IsVerticalOrientation() )
  325. {
  326. pos.x += m_size.x + margin;
  327. pos.y += m_size.y;
  328. }
  329. else
  330. {
  331. pos.y += m_size.y + margin;
  332. }
  333. return pos;
  334. }
  335. void SCH_SHEET::ViewGetLayers( int aLayers[], int& aCount ) const
  336. {
  337. aCount = 2;
  338. aLayers[0] = LAYER_SHEET;
  339. aLayers[1] = LAYER_SHEET_BACKGROUND;
  340. }
  341. void SCH_SHEET::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
  342. const wxPoint& aOffset, GR_DRAWMODE aDrawMode, COLOR4D aColor )
  343. {
  344. COLOR4D txtcolor;
  345. wxString Text;
  346. COLOR4D color;
  347. int name_orientation;
  348. wxPoint pos_sheetname,pos_filename;
  349. wxPoint pos = m_pos + aOffset;
  350. int lineWidth = GetPenSize();
  351. int textWidth;
  352. wxSize textSize;
  353. EDA_RECT* clipbox = aPanel? aPanel->GetClipBox() : NULL;
  354. if( aColor != COLOR4D::UNSPECIFIED )
  355. color = aColor;
  356. else
  357. color = GetLayerColor( m_Layer );
  358. GRSetDrawMode( aDC, aDrawMode );
  359. GRRect( clipbox, aDC, pos.x, pos.y,
  360. pos.x + m_size.x, pos.y + m_size.y, lineWidth, color );
  361. pos_sheetname = GetSheetNamePosition() + aOffset;
  362. pos_filename = GetFileNamePosition() + aOffset;
  363. if( IsVerticalOrientation() )
  364. name_orientation = TEXT_ANGLE_VERT;
  365. else
  366. name_orientation = TEXT_ANGLE_HORIZ;
  367. /* Draw text : SheetName */
  368. if( aColor != COLOR4D::UNSPECIFIED )
  369. txtcolor = aColor;
  370. else
  371. txtcolor = GetLayerColor( LAYER_SHEETNAME );
  372. Text = wxT( "Sheet: " ) + m_name;
  373. textSize = wxSize( m_sheetNameSize, m_sheetNameSize );
  374. textWidth = Clamp_Text_PenSize( lineWidth, textSize, false );
  375. DrawGraphicText( clipbox, aDC, pos_sheetname,
  376. txtcolor, Text, name_orientation,
  377. textSize,
  378. GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM, textWidth,
  379. false, false );
  380. /* Draw text : FileName */
  381. if( aColor != COLOR4D::UNSPECIFIED )
  382. txtcolor = aColor;
  383. else
  384. txtcolor = GetLayerColor( LAYER_SHEETFILENAME );
  385. Text = wxT( "File: " ) + m_fileName;
  386. textSize = wxSize( m_fileNameSize, m_fileNameSize );
  387. textWidth = Clamp_Text_PenSize( lineWidth, textSize, false );
  388. DrawGraphicText( clipbox, aDC, pos_filename,
  389. txtcolor, Text, name_orientation,
  390. textSize,
  391. GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP, textWidth,
  392. false, false );
  393. /* Draw text : SheetLabel */
  394. for( SCH_SHEET_PIN& sheetPin : m_pins )
  395. {
  396. if( !sheetPin.IsMoving() )
  397. sheetPin.Draw( aPanel, aDC, aOffset, aDrawMode, aColor );
  398. }
  399. #if 0
  400. // Only for testing purposes, draw the component bounding box
  401. EDA_RECT boundingBox = GetBoundingBox();
  402. GRRect( aPanel->GetClipBox(), aDC, boundingBox, 0, BROWN );
  403. GRFilledCircle( aPanel->GetClipBox(), aDC, m_pos.x, m_pos.y, 10, 0, color, color );
  404. #endif
  405. }
  406. const EDA_RECT SCH_SHEET::GetBoundingBox() const
  407. {
  408. wxPoint end;
  409. EDA_RECT box( m_pos, m_size );
  410. int lineWidth = GetPenSize();
  411. // Determine length of texts
  412. wxString text = wxT( "Sheet: " ) + m_name;
  413. int textlen = GraphicTextWidth( text, wxSize( m_sheetNameSize, m_sheetNameSize ),
  414. false, false );
  415. text = wxT( "File: " ) + m_fileName;
  416. int textlen2 = GraphicTextWidth( text, wxSize( m_fileNameSize, m_fileNameSize ),
  417. false, false );
  418. // Calculate bounding box X size:
  419. textlen = std::max( textlen, textlen2 );
  420. end.x = std::max( m_size.x, textlen );
  421. // Calculate bounding box pos:
  422. end.y = m_size.y;
  423. end += m_pos;
  424. // Move upper and lower limits to include texts:
  425. box.SetY( box.GetY() - ( KiROUND( m_sheetNameSize * 1.3 ) + 8 ) );
  426. end.y += KiROUND( m_fileNameSize * 1.3 ) + 8;
  427. box.SetEnd( end );
  428. box.Inflate( lineWidth / 2 );
  429. return box;
  430. }
  431. int SCH_SHEET::ComponentCount()
  432. {
  433. int n = 0;
  434. if( m_screen )
  435. {
  436. EDA_ITEM* bs;
  437. for( bs = m_screen->GetDrawItems(); bs != NULL; bs = bs->Next() )
  438. {
  439. if( bs->Type() == SCH_COMPONENT_T )
  440. {
  441. SCH_COMPONENT* Cmp = (SCH_COMPONENT*) bs;
  442. if( Cmp->GetField( VALUE )->GetText().GetChar( 0 ) != '#' )
  443. n++;
  444. }
  445. if( bs->Type() == SCH_SHEET_T )
  446. {
  447. SCH_SHEET* sheet = (SCH_SHEET*) bs;
  448. n += sheet->ComponentCount();
  449. }
  450. }
  451. }
  452. return n;
  453. }
  454. bool SCH_SHEET::SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen )
  455. {
  456. if( m_screen )
  457. {
  458. EDA_ITEM* item = m_screen->GetDrawItems();
  459. while( item )
  460. {
  461. if( item->Type() == SCH_SHEET_T )
  462. {
  463. SCH_SHEET* sheet = (SCH_SHEET*) item;
  464. if( sheet->m_screen
  465. && sheet->m_screen->GetFileName().CmpNoCase( aFilename ) == 0 )
  466. {
  467. *aScreen = sheet->m_screen;
  468. return true;
  469. }
  470. if( sheet->SearchHierarchy( aFilename, aScreen ) )
  471. return true;
  472. }
  473. item = item->Next();
  474. }
  475. }
  476. return false;
  477. }
  478. bool SCH_SHEET::LocatePathOfScreen( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aList )
  479. {
  480. if( m_screen )
  481. {
  482. aList->push_back( this );
  483. if( m_screen == aScreen )
  484. return true;
  485. EDA_ITEM* strct = m_screen->GetDrawItems();
  486. while( strct )
  487. {
  488. if( strct->Type() == SCH_SHEET_T )
  489. {
  490. SCH_SHEET* ss = (SCH_SHEET*) strct;
  491. if( ss->LocatePathOfScreen( aScreen, aList ) )
  492. return true;
  493. }
  494. strct = strct->Next();
  495. }
  496. aList->pop_back();
  497. }
  498. return false;
  499. }
  500. int SCH_SHEET::CountSheets()
  501. {
  502. int count = 1; //1 = this!!
  503. if( m_screen )
  504. {
  505. EDA_ITEM* strct = m_screen->GetDrawItems();
  506. for( ; strct; strct = strct->Next() )
  507. {
  508. if( strct->Type() == SCH_SHEET_T )
  509. {
  510. SCH_SHEET* subsheet = (SCH_SHEET*) strct;
  511. count += subsheet->CountSheets();
  512. }
  513. }
  514. }
  515. return count;
  516. }
  517. wxString SCH_SHEET::GetFileName( void ) const
  518. {
  519. return m_fileName;
  520. }
  521. void SCH_SHEET::GetMsgPanelInfo( EDA_UNITS_T aUnits, MSG_PANEL_ITEMS& aList )
  522. {
  523. aList.push_back( MSG_PANEL_ITEM( _( "Sheet Name" ), m_name, CYAN ) );
  524. aList.push_back( MSG_PANEL_ITEM( _( "File Name" ), m_fileName, BROWN ) );
  525. #if 0 // Set to 1 to display the sheet time stamp (mainly for test)
  526. wxString msg;
  527. msg.Printf( wxT( "%.8X" ), m_TimeStamp );
  528. aList.push_back( MSG_PANEL_ITEM( _( "Time Stamp" ), msg, BLUE ) );
  529. #endif
  530. }
  531. void SCH_SHEET::Rotate(wxPoint aPosition)
  532. {
  533. RotatePoint( &m_pos, aPosition, 900 );
  534. RotatePoint( &m_size.x, &m_size.y, 900 );
  535. if( m_size.x < 0 )
  536. {
  537. m_pos.x += m_size.x;
  538. m_size.x = -m_size.x;
  539. }
  540. if( m_size.y < 0 )
  541. {
  542. m_pos.y += m_size.y;
  543. m_size.y = -m_size.y;
  544. }
  545. for( SCH_SHEET_PIN& sheetPin : m_pins )
  546. {
  547. sheetPin.Rotate( aPosition );
  548. }
  549. }
  550. void SCH_SHEET::MirrorX( int aXaxis_position )
  551. {
  552. MIRROR( m_pos.y, aXaxis_position );
  553. m_pos.y -= m_size.y;
  554. for( SCH_SHEET_PIN& sheetPin : m_pins )
  555. {
  556. sheetPin.MirrorX( aXaxis_position );
  557. }
  558. }
  559. void SCH_SHEET::MirrorY( int aYaxis_position )
  560. {
  561. MIRROR( m_pos.x, aYaxis_position );
  562. m_pos.x -= m_size.x;
  563. for( SCH_SHEET_PIN& label : m_pins )
  564. {
  565. label.MirrorY( aYaxis_position );
  566. }
  567. }
  568. void SCH_SHEET::SetPosition( const wxPoint& aPosition )
  569. {
  570. // Remember the sheet and all pin sheet positions must be
  571. // modified. So use Move function to do that.
  572. Move( aPosition - m_pos );
  573. }
  574. void SCH_SHEET::Resize( const wxSize& aSize )
  575. {
  576. if( aSize == m_size )
  577. return;
  578. m_size = aSize;
  579. /* Move the sheet labels according to the new sheet size. */
  580. for( SCH_SHEET_PIN& label : m_pins )
  581. {
  582. label.ConstrainOnEdge( label.GetPosition() );
  583. }
  584. }
  585. bool SCH_SHEET::Matches( wxFindReplaceData& aSearchData, void* aAuxData, wxPoint* aFindLocation )
  586. {
  587. wxLogTrace( traceFindItem, wxT( " item " ) + GetSelectMenuText( MILLIMETRES ) );
  588. // Ignore the sheet file name if searching to replace.
  589. if( !(aSearchData.GetFlags() & FR_SEARCH_REPLACE)
  590. && SCH_ITEM::Matches( m_fileName, aSearchData ) )
  591. {
  592. if( aFindLocation )
  593. *aFindLocation = GetFileNamePosition();
  594. return true;
  595. }
  596. if( SCH_ITEM::Matches( m_name, aSearchData ) )
  597. {
  598. if( aFindLocation )
  599. *aFindLocation = GetSheetNamePosition();
  600. return true;
  601. }
  602. return false;
  603. }
  604. bool SCH_SHEET::Replace( wxFindReplaceData& aSearchData, void* aAuxData )
  605. {
  606. return EDA_ITEM::Replace( aSearchData, m_name );
  607. }
  608. void SCH_SHEET::renumberPins()
  609. {
  610. int id = 2;
  611. for( SCH_SHEET_PIN& pin : m_pins )
  612. {
  613. pin.SetNumber( id );
  614. id++;
  615. }
  616. }
  617. void SCH_SHEET::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  618. {
  619. for( unsigned ii = 0; ii < GetPins().size(); ii++ )
  620. {
  621. SCH_SHEET_PIN &pinsheet = GetPins()[ii];
  622. wxCHECK2_MSG( pinsheet.Type() == SCH_SHEET_PIN_T, continue,
  623. wxT( "Invalid item in schematic sheet pin list. Bad programmer!" ) );
  624. pinsheet.GetEndPoints( aItemList );
  625. }
  626. }
  627. bool SCH_SHEET::IsDanglingStateChanged( std::vector< DANGLING_END_ITEM >& aItemList )
  628. {
  629. bool currentState = IsDangling();
  630. for( SCH_SHEET_PIN& pinsheet : GetPins() )
  631. {
  632. pinsheet.IsDanglingStateChanged( aItemList );
  633. }
  634. return currentState != IsDangling();
  635. }
  636. bool SCH_SHEET::IsDangling() const
  637. {
  638. // If any hierarchical label in the sheet is dangling, then the sheet is dangling.
  639. for( size_t i = 0; i < GetPins().size(); i++ )
  640. {
  641. if( GetPins()[i].IsDangling() )
  642. return true;
  643. }
  644. return false;
  645. }
  646. bool SCH_SHEET::IsSelectStateChanged( const wxRect& aRect )
  647. {
  648. bool previousState = IsSelected();
  649. EDA_RECT boundingBox = GetBoundingBox();
  650. if( aRect.Intersects( boundingBox ) )
  651. SetFlags( SELECTED );
  652. else
  653. ClearFlags( SELECTED );
  654. return previousState != IsSelected();
  655. }
  656. void SCH_SHEET::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
  657. {
  658. for( size_t i = 0; i < GetPins().size(); i++ )
  659. aPoints.push_back( GetPins()[i].GetPosition() );
  660. }
  661. SEARCH_RESULT SCH_SHEET::Visit( INSPECTOR aInspector, void* testData, const KICAD_T aFilterTypes[] )
  662. {
  663. KICAD_T stype;
  664. for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
  665. {
  666. // If caller wants to inspect my type
  667. if( stype == Type() )
  668. {
  669. if( SEARCH_QUIT == aInspector( this, NULL ) )
  670. return SEARCH_QUIT;
  671. }
  672. else if( stype == SCH_SHEET_PIN_T )
  673. {
  674. // Test the sheet labels.
  675. for( size_t i = 0; i < m_pins.size(); i++ )
  676. {
  677. if( SEARCH_QUIT == aInspector( &m_pins[ i ], this ) )
  678. return SEARCH_QUIT;
  679. }
  680. }
  681. }
  682. return SEARCH_CONTINUE;
  683. }
  684. wxString SCH_SHEET::GetSelectMenuText( EDA_UNITS_T aUnits ) const
  685. {
  686. return wxString::Format( _( "Hierarchical Sheet %s" ), m_name );
  687. }
  688. BITMAP_DEF SCH_SHEET::GetMenuImage() const
  689. {
  690. return add_hierarchical_subsheet_xpm;
  691. }
  692. bool SCH_SHEET::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  693. {
  694. EDA_RECT rect = GetBoundingBox();
  695. rect.Inflate( aAccuracy );
  696. return rect.Contains( aPosition );
  697. }
  698. bool SCH_SHEET::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  699. {
  700. EDA_RECT rect = aRect;
  701. rect.Inflate( aAccuracy );
  702. if( aContained )
  703. return rect.Contains( GetBoundingBox() );
  704. return rect.Intersects( GetBoundingBox() );
  705. }
  706. wxPoint SCH_SHEET::GetResizePosition() const
  707. {
  708. return wxPoint( m_pos.x + m_size.GetWidth(), m_pos.y + m_size.GetHeight() );
  709. }
  710. void SCH_SHEET::GetNetListItem( NETLIST_OBJECT_LIST& aNetListItems,
  711. SCH_SHEET_PATH* aSheetPath )
  712. {
  713. SCH_SHEET_PATH sheetPath = *aSheetPath;
  714. sheetPath.push_back( this );
  715. for( size_t i = 0; i < m_pins.size(); i++ )
  716. {
  717. NETLIST_OBJECT* item = new NETLIST_OBJECT();
  718. item->m_SheetPathInclude = sheetPath;
  719. item->m_SheetPath = *aSheetPath;
  720. item->m_Comp = &m_pins[i];
  721. item->m_Link = this;
  722. item->m_Type = NET_SHEETLABEL;
  723. item->m_Label = m_pins[i].GetText();
  724. item->m_Start = item->m_End = m_pins[i].GetPosition();
  725. aNetListItems.push_back( item );
  726. if( IsBusLabel( m_pins[i].GetText() ) )
  727. item->ConvertBusToNetListItems( aNetListItems );
  728. }
  729. }
  730. void SCH_SHEET::Plot( PLOTTER* aPlotter )
  731. {
  732. COLOR4D txtcolor = COLOR4D::UNSPECIFIED;
  733. wxSize size;
  734. wxString Text;
  735. int name_orientation;
  736. wxPoint pos_sheetname, pos_filename;
  737. wxPoint pos;
  738. aPlotter->SetColor( GetLayerColor( GetLayer() ) );
  739. int thickness = GetPenSize();
  740. aPlotter->SetCurrentLineWidth( thickness );
  741. aPlotter->MoveTo( m_pos );
  742. pos = m_pos;
  743. pos.x += m_size.x;
  744. aPlotter->LineTo( pos );
  745. pos.y += m_size.y;
  746. aPlotter->LineTo( pos );
  747. pos = m_pos;
  748. pos.y += m_size.y;
  749. aPlotter->LineTo( pos );
  750. aPlotter->FinishTo( m_pos );
  751. if( IsVerticalOrientation() )
  752. {
  753. pos_sheetname = wxPoint( m_pos.x - 8, m_pos.y + m_size.y );
  754. pos_filename = wxPoint( m_pos.x + m_size.x + 4, m_pos.y + m_size.y );
  755. name_orientation = TEXT_ANGLE_VERT;
  756. }
  757. else
  758. {
  759. pos_sheetname = wxPoint( m_pos.x, m_pos.y - 4 );
  760. pos_filename = wxPoint( m_pos.x, m_pos.y + m_size.y + 4 );
  761. name_orientation = TEXT_ANGLE_HORIZ;
  762. }
  763. /* Draw texts: SheetName */
  764. Text = m_name;
  765. size = wxSize( m_sheetNameSize, m_sheetNameSize );
  766. //pos = m_pos; pos.y -= 4;
  767. thickness = GetDefaultLineThickness();
  768. thickness = Clamp_Text_PenSize( thickness, size, false );
  769. aPlotter->SetColor( GetLayerColor( LAYER_SHEETNAME ) );
  770. bool italic = false;
  771. aPlotter->Text( pos_sheetname, txtcolor, Text, name_orientation, size,
  772. GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_BOTTOM,
  773. thickness, italic, false );
  774. /*Draw texts : FileName */
  775. Text = GetFileName();
  776. size = wxSize( m_fileNameSize, m_fileNameSize );
  777. thickness = GetDefaultLineThickness();
  778. thickness = Clamp_Text_PenSize( thickness, size, false );
  779. aPlotter->SetColor( GetLayerColor( LAYER_SHEETFILENAME ) );
  780. aPlotter->Text( pos_filename, txtcolor, Text, name_orientation, size,
  781. GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_VJUSTIFY_TOP,
  782. thickness, italic, false );
  783. aPlotter->SetColor( GetLayerColor( GetLayer() ) );
  784. /* Draw texts : SheetLabel */
  785. for( size_t i = 0; i < m_pins.size(); i++ )
  786. {
  787. m_pins[i].Plot( aPlotter );
  788. }
  789. }
  790. SCH_ITEM& SCH_SHEET::operator=( const SCH_ITEM& aItem )
  791. {
  792. wxLogDebug( wxT( "Sheet assignment operator." ) );
  793. wxCHECK_MSG( Type() == aItem.Type(), *this,
  794. wxT( "Cannot assign object type " ) + aItem.GetClass() + wxT( " to type " ) +
  795. GetClass() );
  796. if( &aItem != this )
  797. {
  798. SCH_ITEM::operator=( aItem );
  799. SCH_SHEET* sheet = (SCH_SHEET*) &aItem;
  800. m_pos = sheet->m_pos;
  801. m_size = sheet->m_size;
  802. m_name = sheet->m_name;
  803. m_sheetNameSize = sheet->m_sheetNameSize;
  804. m_fileNameSize = sheet->m_fileNameSize;
  805. m_pins = sheet->m_pins;
  806. // Ensure sheet labels have their #m_Parent member pointing really on their
  807. // parent, after assigning.
  808. for( SCH_SHEET_PIN& sheetPin : m_pins )
  809. {
  810. sheetPin.SetParent( this );
  811. }
  812. }
  813. return *this;
  814. }
  815. #if defined(DEBUG)
  816. void SCH_SHEET::Show( int nestLevel, std::ostream& os ) const
  817. {
  818. // XML output:
  819. wxString s = GetClass();
  820. NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << ">" << " sheet_name=\""
  821. << TO_UTF8( m_name ) << '"' << ">\n";
  822. // show all the pins, and check the linked list integrity
  823. for( const SCH_SHEET_PIN& label : m_pins )
  824. {
  825. label.Show( nestLevel + 1, os );
  826. }
  827. NestedSpace( nestLevel, os ) << "</" << s.Lower().mb_str() << ">\n" << std::flush;
  828. }
  829. #endif