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.

1589 lines
46 KiB

15 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
5 years ago
5 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) 2015 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file sch_text.cpp
  27. * @brief Code for handling schematic texts (texts, labels, hlabels and global labels).
  28. */
  29. #include <sch_symbol.h>
  30. #include <sch_edit_frame.h>
  31. #include <plotter.h>
  32. #include <widgets/msgpanel.h>
  33. #include <gal/stroke_font.h>
  34. #include <bitmaps.h>
  35. #include <kicad_string.h>
  36. #include <sch_text.h>
  37. #include <schematic.h>
  38. #include <settings/color_settings.h>
  39. #include <sch_painter.h>
  40. #include <default_values.h>
  41. #include <wx/debug.h>
  42. #include <dialogs/html_messagebox.h>
  43. #include <project/project_file.h>
  44. #include <project/net_settings.h>
  45. #include <core/mirror.h>
  46. #include <dialog_helpers.h>
  47. #include <trigo.h>
  48. using KIGFX::SCH_RENDER_SETTINGS;
  49. bool IncrementLabelMember( wxString& name, int aIncrement )
  50. {
  51. int ii, nn;
  52. long number = 0;
  53. ii = name.Len() - 1;
  54. nn = 0;
  55. // No number found, but simply repeating the same label is valid
  56. if( !wxIsdigit( name.GetChar( ii ) ) )
  57. return true;
  58. while( ii >= 0 && wxIsdigit( name.GetChar( ii ) ) )
  59. {
  60. ii--;
  61. nn++;
  62. }
  63. ii++; /* digits are starting at ii position */
  64. wxString litt_number = name.Right( nn );
  65. if( litt_number.ToLong( &number ) )
  66. {
  67. number += aIncrement;
  68. // Don't let result go below zero
  69. if( number > -1 )
  70. {
  71. name.Remove( ii );
  72. name << number;
  73. return true;
  74. }
  75. }
  76. return false;
  77. }
  78. /* Coding polygons for global symbol graphic shapes.
  79. * the first parml is the number of corners
  80. * others are the corners coordinates in reduced units
  81. * the real coordinate is the reduced coordinate * text half size
  82. */
  83. static int TemplateIN_HN[] = { 6, 0, 0, -1, -1, -2, -1, -2, 1, -1, 1, 0, 0 };
  84. static int TemplateIN_HI[] = { 6, 0, 0, 1, 1, 2, 1, 2, -1, 1, -1, 0, 0 };
  85. static int TemplateIN_UP[] = { 6, 0, 0, 1, -1, 1, -2, -1, -2, -1, -1, 0, 0 };
  86. static int TemplateIN_BOTTOM[] = { 6, 0, 0, 1, 1, 1, 2, -1, 2, -1, 1, 0, 0 };
  87. static int TemplateOUT_HN[] = { 6, -2, 0, -1, 1, 0, 1, 0, -1, -1, -1, -2, 0 };
  88. static int TemplateOUT_HI[] = { 6, 2, 0, 1, -1, 0, -1, 0, 1, 1, 1, 2, 0 };
  89. static int TemplateOUT_UP[] = { 6, 0, -2, 1, -1, 1, 0, -1, 0, -1, -1, 0, -2 };
  90. static int TemplateOUT_BOTTOM[] = { 6, 0, 2, 1, 1, 1, 0, -1, 0, -1, 1, 0, 2 };
  91. static int TemplateUNSPC_HN[] = { 5, 0, -1, -2, -1, -2, 1, 0, 1, 0, -1 };
  92. static int TemplateUNSPC_HI[] = { 5, 0, -1, 2, -1, 2, 1, 0, 1, 0, -1 };
  93. static int TemplateUNSPC_UP[] = { 5, 1, 0, 1, -2, -1, -2, -1, 0, 1, 0 };
  94. static int TemplateUNSPC_BOTTOM[] = { 5, 1, 0, 1, 2, -1, 2, -1, 0, 1, 0 };
  95. static int TemplateBIDI_HN[] = { 5, 0, 0, -1, -1, -2, 0, -1, 1, 0, 0 };
  96. static int TemplateBIDI_HI[] = { 5, 0, 0, 1, -1, 2, 0, 1, 1, 0, 0 };
  97. static int TemplateBIDI_UP[] = { 5, 0, 0, -1, -1, 0, -2, 1, -1, 0, 0 };
  98. static int TemplateBIDI_BOTTOM[] = { 5, 0, 0, -1, 1, 0, 2, 1, 1, 0, 0 };
  99. static int Template3STATE_HN[] = { 5, 0, 0, -1, -1, -2, 0, -1, 1, 0, 0 };
  100. static int Template3STATE_HI[] = { 5, 0, 0, 1, -1, 2, 0, 1, 1, 0, 0 };
  101. static int Template3STATE_UP[] = { 5, 0, 0, -1, -1, 0, -2, 1, -1, 0, 0 };
  102. static int Template3STATE_BOTTOM[] = { 5, 0, 0, -1, 1, 0, 2, 1, 1, 0, 0 };
  103. static int* TemplateShape[5][4] =
  104. {
  105. { TemplateIN_HN, TemplateIN_UP, TemplateIN_HI, TemplateIN_BOTTOM },
  106. { TemplateOUT_HN, TemplateOUT_UP, TemplateOUT_HI, TemplateOUT_BOTTOM },
  107. { TemplateBIDI_HN, TemplateBIDI_UP, TemplateBIDI_HI, TemplateBIDI_BOTTOM },
  108. { Template3STATE_HN, Template3STATE_UP, Template3STATE_HI, Template3STATE_BOTTOM },
  109. { TemplateUNSPC_HN, TemplateUNSPC_UP, TemplateUNSPC_HI, TemplateUNSPC_BOTTOM }
  110. };
  111. SCH_TEXT::SCH_TEXT( const wxPoint& pos, const wxString& text, KICAD_T aType ) :
  112. SCH_ITEM( NULL, aType ),
  113. EDA_TEXT( text ),
  114. m_shape( PINSHEETLABEL_SHAPE::PS_INPUT ),
  115. m_isDangling( false ),
  116. m_connectionType( CONNECTION_TYPE::NONE ),
  117. m_spin_style( LABEL_SPIN_STYLE::LEFT )
  118. {
  119. m_layer = LAYER_NOTES;
  120. SetTextPos( pos );
  121. SetMultilineAllowed( true );
  122. }
  123. SCH_TEXT::SCH_TEXT( const SCH_TEXT& aText ) :
  124. SCH_ITEM( aText ),
  125. EDA_TEXT( aText ),
  126. m_shape( aText.m_shape ),
  127. m_isDangling( aText.m_isDangling ),
  128. m_connectionType( aText.m_connectionType ),
  129. m_spin_style( aText.m_spin_style )
  130. { }
  131. EDA_ITEM* SCH_TEXT::Clone() const
  132. {
  133. return new SCH_TEXT( *this );
  134. }
  135. bool SCH_TEXT::IncrementLabel( int aIncrement )
  136. {
  137. wxString text = GetText();
  138. bool ReturnVal = IncrementLabelMember( text, aIncrement );
  139. if( ReturnVal )
  140. SetText( text );
  141. return ReturnVal;
  142. }
  143. wxPoint SCH_TEXT::GetSchematicTextOffset( const RENDER_SETTINGS* aSettings ) const
  144. {
  145. wxPoint text_offset;
  146. // add an offset to x (or y) position to aid readability of text on a wire or line
  147. int dist = GetTextOffset( aSettings ) + GetPenWidth();
  148. switch( GetLabelSpinStyle() )
  149. {
  150. case LABEL_SPIN_STYLE::UP:
  151. case LABEL_SPIN_STYLE::BOTTOM:
  152. text_offset.x = -dist;
  153. break; // Vert Orientation
  154. default:
  155. case LABEL_SPIN_STYLE::LEFT:
  156. case LABEL_SPIN_STYLE::RIGHT:
  157. text_offset.y = -dist;
  158. break; // Horiz Orientation
  159. }
  160. return text_offset;
  161. }
  162. void SCH_TEXT::MirrorHorizontally( int aCenter )
  163. {
  164. // Text is NOT really mirrored; it is moved to a suitable horizontal position
  165. SetLabelSpinStyle( GetLabelSpinStyle().MirrorY() );
  166. SetTextX( MIRRORVAL( GetTextPos().x, aCenter ) );
  167. }
  168. void SCH_TEXT::MirrorVertically( int aCenter )
  169. {
  170. // Text is NOT really mirrored; it is moved to a suitable vertical position
  171. SetLabelSpinStyle( GetLabelSpinStyle().MirrorX() );
  172. SetTextY( MIRRORVAL( GetTextPos().y, aCenter ) );
  173. }
  174. void SCH_TEXT::Rotate( wxPoint aCenter )
  175. {
  176. wxPoint pt = GetTextPos();
  177. RotatePoint( &pt, aCenter, 900 );
  178. wxPoint offset = pt - GetTextPos();
  179. Rotate90( false );
  180. SetTextPos( GetTextPos() + offset );
  181. }
  182. void SCH_TEXT::Rotate90( bool aClockwise )
  183. {
  184. if( aClockwise )
  185. SetLabelSpinStyle( GetLabelSpinStyle().RotateCW() );
  186. else
  187. SetLabelSpinStyle( GetLabelSpinStyle().RotateCCW() );
  188. }
  189. void SCH_TEXT::MirrorSpinStyle( bool aLeftRight )
  190. {
  191. if( aLeftRight )
  192. SetLabelSpinStyle( GetLabelSpinStyle().MirrorY() );
  193. else
  194. SetLabelSpinStyle( GetLabelSpinStyle().MirrorX() );
  195. }
  196. void SCH_TEXT::SetLabelSpinStyle( LABEL_SPIN_STYLE aSpinStyle )
  197. {
  198. m_spin_style = aSpinStyle;
  199. // Assume "Right" and Left" mean which side of the anchor the text will be on
  200. // Thus we want to left justify text up agaisnt the anchor if we are on the right
  201. switch( aSpinStyle )
  202. {
  203. default:
  204. wxASSERT_MSG( 1, "Bad spin style" );
  205. break;
  206. case LABEL_SPIN_STYLE::RIGHT: // Horiz Normal Orientation
  207. //
  208. m_spin_style = LABEL_SPIN_STYLE::RIGHT; // Handle the error spin style by resetting
  209. SetTextAngle( TEXT_ANGLE_HORIZ );
  210. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  211. SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  212. break;
  213. case LABEL_SPIN_STYLE::UP: // Vert Orientation UP
  214. SetTextAngle( TEXT_ANGLE_VERT );
  215. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  216. SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  217. break;
  218. case LABEL_SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
  219. SetTextAngle( TEXT_ANGLE_HORIZ );
  220. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  221. SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  222. break;
  223. case LABEL_SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
  224. SetTextAngle( TEXT_ANGLE_VERT );
  225. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  226. SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  227. break;
  228. }
  229. }
  230. void SCH_TEXT::SwapData( SCH_ITEM* aItem )
  231. {
  232. SCH_TEXT* item = (SCH_TEXT*) aItem;
  233. std::swap( m_layer, item->m_layer );
  234. std::swap( m_shape, item->m_shape );
  235. std::swap( m_isDangling, item->m_isDangling );
  236. std::swap( m_spin_style, item->m_spin_style );
  237. SwapText( *item );
  238. SwapEffects( *item );
  239. }
  240. bool SCH_TEXT::operator<( const SCH_ITEM& aItem ) const
  241. {
  242. if( Type() != aItem.Type() )
  243. return Type() < aItem.Type();
  244. auto other = static_cast<const SCH_TEXT*>( &aItem );
  245. if( GetLayer() != other->GetLayer() )
  246. return GetLayer() < other->GetLayer();
  247. if( GetPosition().x != other->GetPosition().x )
  248. return GetPosition().x < other->GetPosition().x;
  249. if( GetPosition().y != other->GetPosition().y )
  250. return GetPosition().y < other->GetPosition().y;
  251. return GetText() < other->GetText();
  252. }
  253. int SCH_TEXT::GetTextOffset( const RENDER_SETTINGS* aSettings ) const
  254. {
  255. double ratio;
  256. if( aSettings )
  257. ratio = static_cast<const SCH_RENDER_SETTINGS*>( aSettings )->m_TextOffsetRatio;
  258. else if( Schematic() )
  259. ratio = Schematic()->Settings().m_TextOffsetRatio;
  260. else
  261. ratio = DEFAULT_TEXT_OFFSET_RATIO; // For previews (such as in Preferences), etc.
  262. return KiROUND( ratio * GetTextSize().y );
  263. return 0;
  264. }
  265. int SCH_TEXT::GetPenWidth() const
  266. {
  267. return GetEffectiveTextPenWidth();
  268. }
  269. void SCH_TEXT::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
  270. {
  271. COLOR4D color = aSettings->GetLayerColor( m_layer );
  272. wxPoint text_offset = aOffset + GetSchematicTextOffset( aSettings );
  273. EDA_TEXT::Print( aSettings, text_offset, color );
  274. }
  275. void SCH_TEXT::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  276. {
  277. // Normal text labels cannot be tested for dangling ends.
  278. if( Type() == SCH_TEXT_T )
  279. return;
  280. DANGLING_END_ITEM item( LABEL_END, this, GetTextPos() );
  281. aItemList.push_back( item );
  282. }
  283. bool SCH_TEXT::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
  284. const SCH_SHEET_PATH* aPath )
  285. {
  286. // Normal text labels cannot be tested for dangling ends.
  287. if( Type() == SCH_TEXT_T )
  288. return false;
  289. bool previousState = m_isDangling;
  290. m_isDangling = true;
  291. m_connectionType = CONNECTION_TYPE::NONE;
  292. for( unsigned ii = 0; ii < aItemList.size(); ii++ )
  293. {
  294. DANGLING_END_ITEM& item = aItemList[ii];
  295. if( item.GetItem() == this )
  296. continue;
  297. switch( item.GetType() )
  298. {
  299. case PIN_END:
  300. case LABEL_END:
  301. case SHEET_LABEL_END:
  302. case NO_CONNECT_END:
  303. if( GetTextPos() == item.GetPosition() )
  304. {
  305. m_isDangling = false;
  306. if( aPath && item.GetType() != PIN_END )
  307. m_connected_items[ *aPath ].insert( static_cast<SCH_ITEM*>( item.GetItem() ) );
  308. }
  309. break;
  310. case BUS_START_END:
  311. m_connectionType = CONNECTION_TYPE::BUS;
  312. KI_FALLTHROUGH;
  313. case WIRE_START_END:
  314. {
  315. // These schematic items have created 2 DANGLING_END_ITEM one per end. But being
  316. // a paranoid programmer, I'll check just in case.
  317. ii++;
  318. wxCHECK_MSG( ii < aItemList.size(), previousState != m_isDangling,
  319. wxT( "Dangling end type list overflow. Bad programmer!" ) );
  320. int accuracy = 1; // We have rounding issues with an accuracy of 0
  321. DANGLING_END_ITEM & nextItem = aItemList[ii];
  322. m_isDangling = !TestSegmentHit( GetTextPos(), item.GetPosition(),
  323. nextItem.GetPosition(), accuracy );
  324. if( !m_isDangling )
  325. {
  326. if( m_connectionType != CONNECTION_TYPE::BUS )
  327. m_connectionType = CONNECTION_TYPE::NET;
  328. // Add the line to the connected items, since it won't be picked
  329. // up by a search of intersecting connection points
  330. if( aPath )
  331. {
  332. auto sch_item = static_cast<SCH_ITEM*>( item.GetItem() );
  333. AddConnectionTo( *aPath, sch_item );
  334. sch_item->AddConnectionTo( *aPath, this );
  335. }
  336. }
  337. }
  338. break;
  339. default:
  340. break;
  341. }
  342. if( !m_isDangling )
  343. break;
  344. }
  345. if( m_isDangling )
  346. m_connectionType = CONNECTION_TYPE::NONE;
  347. return previousState != m_isDangling;
  348. }
  349. std::vector<wxPoint> SCH_TEXT::GetConnectionPoints() const
  350. {
  351. // Normal text labels do not have connection points. All others do.
  352. if( Type() == SCH_TEXT_T )
  353. return {};
  354. return { GetTextPos() };
  355. }
  356. const EDA_RECT SCH_TEXT::GetBoundingBox() const
  357. {
  358. EDA_RECT rect = GetTextBox();
  359. if( GetTextAngle() != 0 ) // Rotate rect
  360. {
  361. wxPoint pos = rect.GetOrigin();
  362. wxPoint end = rect.GetEnd();
  363. RotatePoint( &pos, GetTextPos(), GetTextAngle() );
  364. RotatePoint( &end, GetTextPos(), GetTextAngle() );
  365. rect.SetOrigin( pos );
  366. rect.SetEnd( end );
  367. }
  368. rect.Normalize();
  369. return rect;
  370. }
  371. wxString getElectricalTypeLabel( PINSHEETLABEL_SHAPE aType )
  372. {
  373. switch( aType )
  374. {
  375. case PINSHEETLABEL_SHAPE::PS_INPUT: return _( "Input" );
  376. case PINSHEETLABEL_SHAPE::PS_OUTPUT: return _( "Output" );
  377. case PINSHEETLABEL_SHAPE::PS_BIDI: return _( "Bidirectional" );
  378. case PINSHEETLABEL_SHAPE::PS_TRISTATE: return _( "Tri-State" );
  379. case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED: return _( "Passive" );
  380. default: return wxT( "???" );
  381. }
  382. }
  383. void SCH_TEXT::GetContextualTextVars( wxArrayString* aVars ) const
  384. {
  385. if( Type() == SCH_GLOBAL_LABEL_T || Type() == SCH_HIER_LABEL_T || Type() == SCH_SHEET_PIN_T )
  386. aVars->push_back( wxT( "CONNECTION_TYPE" ) );
  387. if( Type() == SCH_SHEET_PIN_T && m_parent )
  388. static_cast<SCH_SHEET*>( m_parent )->GetContextualTextVars( aVars );
  389. }
  390. wxString SCH_TEXT::GetShownText( int aDepth ) const
  391. {
  392. std::function<bool( wxString* )> textResolver =
  393. [&]( wxString* token ) -> bool
  394. {
  395. if( ( Type() == SCH_GLOBAL_LABEL_T
  396. || Type() == SCH_HIER_LABEL_T
  397. || Type() == SCH_SHEET_PIN_T )
  398. && token->IsSameAs( wxT( "CONNECTION_TYPE" ) ) )
  399. {
  400. *token = getElectricalTypeLabel( GetShape() );
  401. return true;
  402. }
  403. if( Type() == SCH_SHEET_PIN_T && m_parent )
  404. {
  405. SCH_SHEET* sheet = static_cast<SCH_SHEET*>( m_parent );
  406. if( sheet->ResolveTextVar( token, aDepth ) )
  407. return true;
  408. }
  409. if( Type() == SCH_TEXT_T )
  410. {
  411. if( token->Contains( ':' ) )
  412. {
  413. if( Schematic()->ResolveCrossReference( token, aDepth ) )
  414. return true;
  415. }
  416. else
  417. {
  418. SCHEMATIC* schematic = Schematic();
  419. SCH_SHEET* sheet = schematic ? schematic->CurrentSheet().Last() : nullptr;
  420. if( sheet && sheet->ResolveTextVar( token, aDepth + 1 ) )
  421. return true;
  422. }
  423. }
  424. return false;
  425. };
  426. bool processTextVars = false;
  427. wxString text = EDA_TEXT::GetShownText( &processTextVars );
  428. if( processTextVars )
  429. {
  430. wxCHECK_MSG( Schematic(), wxEmptyString, "No parent SCHEMATIC set for SCH_TEXT!" );
  431. PROJECT* project = nullptr;
  432. if( Schematic() )
  433. project = &Schematic()->Prj();
  434. if( aDepth < 10 )
  435. text = ExpandTextVars( text, &textResolver, nullptr, project );
  436. }
  437. return text;
  438. }
  439. wxString SCH_TEXT::GetSelectMenuText( EDA_UNITS aUnits ) const
  440. {
  441. return wxString::Format( _( "Graphic Text '%s'" ), ShortenedShownText() );
  442. }
  443. BITMAPS SCH_TEXT::GetMenuImage() const
  444. {
  445. return BITMAPS::text;
  446. }
  447. bool SCH_TEXT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  448. {
  449. EDA_RECT bBox = GetBoundingBox();
  450. bBox.Inflate( aAccuracy );
  451. return bBox.Contains( aPosition );
  452. }
  453. bool SCH_TEXT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  454. {
  455. EDA_RECT bBox = GetBoundingBox();
  456. bBox.Inflate( aAccuracy );
  457. if( aContained )
  458. return aRect.Contains( bBox );
  459. return aRect.Intersects( bBox );
  460. }
  461. void SCH_TEXT::Plot( PLOTTER* aPlotter ) const
  462. {
  463. static std::vector<wxPoint> s_poly;
  464. RENDER_SETTINGS* settings = aPlotter->RenderSettings();
  465. SCH_CONNECTION* connection = Connection();
  466. int layer = ( connection && connection->IsBus() ) ? LAYER_BUS : m_layer;
  467. COLOR4D color = settings->GetLayerColor( layer );
  468. int penWidth = GetEffectiveTextPenWidth( settings->GetDefaultPenWidth() );
  469. penWidth = std::max( penWidth, settings->GetMinPenWidth() );
  470. aPlotter->SetCurrentLineWidth( penWidth );
  471. if( IsMultilineAllowed() )
  472. {
  473. std::vector<wxPoint> positions;
  474. wxArrayString strings_list;
  475. wxStringSplit( GetShownText(), strings_list, '\n' );
  476. positions.reserve( strings_list.Count() );
  477. GetLinePositions( positions, (int) strings_list.Count() );
  478. for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
  479. {
  480. wxPoint textpos = positions[ii] + GetSchematicTextOffset( aPlotter->RenderSettings() );
  481. wxString& txt = strings_list.Item( ii );
  482. aPlotter->Text( textpos, color, txt, GetTextAngle(), GetTextSize(), GetHorizJustify(),
  483. GetVertJustify(), penWidth, IsItalic(), IsBold() );
  484. }
  485. }
  486. else
  487. {
  488. wxPoint textpos = GetTextPos() + GetSchematicTextOffset( aPlotter->RenderSettings() );
  489. aPlotter->Text( textpos, color, GetShownText(), GetTextAngle(), GetTextSize(),
  490. GetHorizJustify(), GetVertJustify(), penWidth, IsItalic(), IsBold() );
  491. }
  492. // Draw graphic symbol for global or hierarchical labels
  493. CreateGraphicShape( aPlotter->RenderSettings(), s_poly, GetTextPos() );
  494. if( s_poly.size() )
  495. aPlotter->PlotPoly( s_poly, FILL_TYPE::NO_FILL, penWidth );
  496. }
  497. void SCH_TEXT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList )
  498. {
  499. wxString msg;
  500. switch( Type() )
  501. {
  502. case SCH_TEXT_T: msg = _( "Graphic Text" ); break;
  503. case SCH_LABEL_T: msg = _( "Label" ); break;
  504. case SCH_GLOBAL_LABEL_T: msg = _( "Global Label" ); break;
  505. case SCH_HIER_LABEL_T: msg = _( "Hierarchical Label" ); break;
  506. case SCH_SHEET_PIN_T: msg = _( "Hierarchical Sheet Pin" ); break;
  507. default: return;
  508. }
  509. // Don't use GetShownText() here; we want to show the user the variable references
  510. aList.push_back( MSG_PANEL_ITEM( msg, UnescapeString( GetText() ) ) );
  511. switch( GetLabelSpinStyle() )
  512. {
  513. case LABEL_SPIN_STYLE::LEFT: msg = _( "Horizontal left" ); break;
  514. case LABEL_SPIN_STYLE::UP: msg = _( "Vertical up" ); break;
  515. case LABEL_SPIN_STYLE::RIGHT: msg = _( "Horizontal right" ); break;
  516. case LABEL_SPIN_STYLE::BOTTOM: msg = _( "Vertical down" ); break;
  517. default: msg = wxT( "???" ); break;
  518. }
  519. aList.push_back( MSG_PANEL_ITEM( _( "Orientation" ), msg, BROWN ) );
  520. wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
  521. int style = 0;
  522. if( IsItalic() )
  523. style = 1;
  524. if( IsBold() )
  525. style += 2;
  526. aList.push_back( MSG_PANEL_ITEM( _( "Style" ), textStyle[style] ) );
  527. // Display electrical type if it is relevant
  528. if( Type() == SCH_GLOBAL_LABEL_T || Type() == SCH_HIER_LABEL_T || Type() == SCH_SHEET_PIN_T )
  529. {
  530. msg = getElectricalTypeLabel( GetShape() );
  531. aList.push_back( MSG_PANEL_ITEM( _( "Type" ), msg ) );
  532. }
  533. // Display text size (X or Y value, with are the same value in Eeschema)
  534. msg = MessageTextFromValue( aFrame->GetUserUnits(), GetTextWidth() );
  535. aList.push_back( MSG_PANEL_ITEM( _( "Size" ), msg ) );
  536. SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
  537. if( frame )
  538. {
  539. if( SCH_CONNECTION* conn = Connection() )
  540. {
  541. conn->AppendInfoToMsgPanel( aList );
  542. NET_SETTINGS& netSettings = Schematic()->Prj().GetProjectFile().NetSettings();
  543. const wxString& netname = conn->Name( true );
  544. if( netSettings.m_NetClassAssignments.count( netname ) )
  545. {
  546. const wxString& netclassName = netSettings.m_NetClassAssignments[ netname ];
  547. aList.push_back( MSG_PANEL_ITEM( _( "Assigned Netclass" ), netclassName ) );
  548. }
  549. }
  550. }
  551. }
  552. #if defined(DEBUG)
  553. void SCH_TEXT::Show( int nestLevel, std::ostream& os ) const
  554. {
  555. // XML output:
  556. wxString s = GetClass();
  557. NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str()
  558. << " layer=\"" << m_layer << '"'
  559. << " shape=\"" << static_cast<int>( m_shape ) << '"'
  560. << " dangling=\"" << m_isDangling << '"'
  561. << '>'
  562. << TO_UTF8( GetText() )
  563. << "</" << s.Lower().mb_str() << ">\n";
  564. }
  565. #endif
  566. SCH_LABEL::SCH_LABEL( const wxPoint& pos, const wxString& text )
  567. : SCH_TEXT( pos, text, SCH_LABEL_T )
  568. {
  569. m_layer = LAYER_LOCLABEL;
  570. m_shape = PINSHEETLABEL_SHAPE::PS_INPUT;
  571. m_isDangling = true;
  572. SetMultilineAllowed( false );
  573. }
  574. EDA_ITEM* SCH_LABEL::Clone() const
  575. {
  576. return new SCH_LABEL( *this );
  577. }
  578. bool SCH_LABEL::IsType( const KICAD_T aScanTypes[] ) const
  579. {
  580. static KICAD_T wireTypes[] = { SCH_LINE_LOCATE_WIRE_T, SCH_PIN_T, EOT };
  581. static KICAD_T busTypes[] = { SCH_LINE_LOCATE_BUS_T, EOT };
  582. if( SCH_ITEM::IsType( aScanTypes ) )
  583. return true;
  584. wxCHECK_MSG( Schematic(), false, "No parent SCHEMATIC set for SCH_LABEL!" );
  585. SCH_SHEET_PATH current = Schematic()->CurrentSheet();
  586. for( const KICAD_T* p = aScanTypes; *p != EOT; ++p )
  587. {
  588. if( *p == SCH_LABEL_LOCATE_WIRE_T )
  589. {
  590. wxASSERT( m_connected_items.count( current ) );
  591. for( SCH_ITEM* connection : m_connected_items.at( current ) )
  592. {
  593. if( connection->IsType( wireTypes ) )
  594. return true;
  595. }
  596. }
  597. else if ( *p == SCH_LABEL_LOCATE_BUS_T )
  598. {
  599. wxASSERT( m_connected_items.count( current ) );
  600. for( SCH_ITEM* connection : m_connected_items.at( current ) )
  601. {
  602. if( connection->IsType( busTypes ) )
  603. return true;
  604. }
  605. }
  606. }
  607. return false;
  608. }
  609. const EDA_RECT SCH_LABEL::GetBoundingBox() const
  610. {
  611. EDA_RECT rect = GetTextBox();
  612. rect.Offset( 0, -GetTextOffset() );
  613. if( GetTextAngle() != 0.0 )
  614. {
  615. // Rotate rect
  616. wxPoint pos = rect.GetOrigin();
  617. wxPoint end = rect.GetEnd();
  618. RotatePoint( &pos, GetTextPos(), GetTextAngle() );
  619. RotatePoint( &end, GetTextPos(), GetTextAngle() );
  620. rect.SetOrigin( pos );
  621. rect.SetEnd( end );
  622. rect.Normalize();
  623. }
  624. // Labels have a position point that is outside of the TextBox
  625. rect.Merge( GetPosition() );
  626. return rect;
  627. }
  628. wxString SCH_LABEL::GetSelectMenuText( EDA_UNITS aUnits ) const
  629. {
  630. return wxString::Format( _( "Label '%s'" ), ShortenedShownText() );
  631. }
  632. BITMAPS SCH_LABEL::GetMenuImage() const
  633. {
  634. return BITMAPS::add_line_label;
  635. }
  636. SCH_GLOBALLABEL::SCH_GLOBALLABEL( const wxPoint& pos, const wxString& text ) :
  637. SCH_TEXT( pos, text, SCH_GLOBAL_LABEL_T ),
  638. m_intersheetRefsField( { 0, 0 }, 0, this )
  639. {
  640. m_layer = LAYER_GLOBLABEL;
  641. m_shape = PINSHEETLABEL_SHAPE::PS_BIDI;
  642. m_isDangling = true;
  643. SetMultilineAllowed( false );
  644. SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  645. m_intersheetRefsField.SetText( wxT( "${INTERSHEET_REFS}" ) );
  646. m_intersheetRefsField.SetLayer( LAYER_GLOBLABEL );
  647. m_intersheetRefsField.SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  648. m_fieldsAutoplaced = FIELDS_AUTOPLACED_AUTO;
  649. }
  650. SCH_GLOBALLABEL::SCH_GLOBALLABEL( const SCH_GLOBALLABEL& aGlobalLabel ) :
  651. SCH_TEXT( aGlobalLabel ),
  652. m_intersheetRefsField( { 0, 0 }, 0, this )
  653. {
  654. m_intersheetRefsField = aGlobalLabel.m_intersheetRefsField;
  655. // Re-parent the fields, which before this had aGlobalLabel as parent
  656. m_intersheetRefsField.SetParent( this );
  657. m_fieldsAutoplaced = aGlobalLabel.m_fieldsAutoplaced;
  658. }
  659. EDA_ITEM* SCH_GLOBALLABEL::Clone() const
  660. {
  661. return new SCH_GLOBALLABEL( *this );
  662. }
  663. void SCH_GLOBALLABEL::SwapData( SCH_ITEM* aItem )
  664. {
  665. SCH_TEXT::SwapData( aItem );
  666. SCH_GLOBALLABEL* globalLabel = static_cast<SCH_GLOBALLABEL*>( aItem );
  667. // Swap field data wholesale...
  668. std::swap( m_intersheetRefsField, globalLabel->m_intersheetRefsField );
  669. // ...and then reset parent pointers.
  670. globalLabel->m_intersheetRefsField.SetParent( globalLabel );
  671. m_intersheetRefsField.SetParent( this );
  672. }
  673. SEARCH_RESULT SCH_GLOBALLABEL::Visit( INSPECTOR aInspector, void* testData,
  674. const KICAD_T aFilterTypes[] )
  675. {
  676. KICAD_T stype;
  677. for( const KICAD_T* p = aFilterTypes; (stype = *p) != EOT; ++p )
  678. {
  679. // If caller wants to inspect my type
  680. if( stype == SCH_LOCATE_ANY_T || stype == Type() )
  681. {
  682. if( SEARCH_RESULT::QUIT == aInspector( this, NULL ) )
  683. return SEARCH_RESULT::QUIT;
  684. }
  685. if( stype == SCH_LOCATE_ANY_T || stype == SCH_FIELD_T )
  686. {
  687. if( SEARCH_RESULT::QUIT == aInspector( GetIntersheetRefs(), this ) )
  688. return SEARCH_RESULT::QUIT;
  689. }
  690. }
  691. return SEARCH_RESULT::CONTINUE;
  692. }
  693. void SCH_GLOBALLABEL::RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction )
  694. {
  695. aFunction( &m_intersheetRefsField );
  696. }
  697. wxPoint SCH_GLOBALLABEL::GetSchematicTextOffset( const RENDER_SETTINGS* aSettings ) const
  698. {
  699. wxPoint text_offset;
  700. int dist = GetTextOffset( aSettings );
  701. switch( m_shape )
  702. {
  703. case PINSHEETLABEL_SHAPE::PS_INPUT:
  704. case PINSHEETLABEL_SHAPE::PS_BIDI:
  705. case PINSHEETLABEL_SHAPE::PS_TRISTATE:
  706. dist += GetTextHeight() * 3 / 4; // Use three-quarters-height as proxy for triangle size
  707. break;
  708. case PINSHEETLABEL_SHAPE::PS_OUTPUT:
  709. case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED:
  710. default:
  711. break;
  712. }
  713. switch( GetLabelSpinStyle() )
  714. {
  715. default:
  716. case LABEL_SPIN_STYLE::LEFT: text_offset.x -= dist; break;
  717. case LABEL_SPIN_STYLE::UP: text_offset.y -= dist; break;
  718. case LABEL_SPIN_STYLE::RIGHT: text_offset.x += dist; break;
  719. case LABEL_SPIN_STYLE::BOTTOM: text_offset.y += dist; break;
  720. }
  721. return text_offset;
  722. }
  723. void SCH_GLOBALLABEL::SetLabelSpinStyle( LABEL_SPIN_STYLE aSpinStyle )
  724. {
  725. m_spin_style = aSpinStyle;
  726. switch( aSpinStyle )
  727. {
  728. default:
  729. wxASSERT_MSG( 1, "Bad spin style" );
  730. m_spin_style = LABEL_SPIN_STYLE::RIGHT;
  731. KI_FALLTHROUGH;
  732. case LABEL_SPIN_STYLE::RIGHT: // Horiz Normal Orientation
  733. SetTextAngle( TEXT_ANGLE_HORIZ );
  734. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  735. break;
  736. case LABEL_SPIN_STYLE::UP: // Vert Orientation UP
  737. SetTextAngle( TEXT_ANGLE_VERT );
  738. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  739. break;
  740. case LABEL_SPIN_STYLE::LEFT: // Horiz Orientation
  741. SetTextAngle( TEXT_ANGLE_HORIZ );
  742. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  743. break;
  744. case LABEL_SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
  745. SetTextAngle( TEXT_ANGLE_VERT );
  746. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  747. break;
  748. }
  749. }
  750. void SCH_GLOBALLABEL::Rotate( wxPoint aCenter )
  751. {
  752. wxPoint pt = GetTextPos();
  753. RotatePoint( &pt, aCenter, 900 );
  754. wxPoint offset = pt - GetTextPos();
  755. Rotate90( false );
  756. SetTextPos( GetTextPos() + offset );
  757. m_intersheetRefsField.SetTextPos( m_intersheetRefsField.GetTextPos() + offset );
  758. }
  759. void SCH_GLOBALLABEL::Rotate90( bool aClockwise )
  760. {
  761. SCH_TEXT::Rotate90( aClockwise );
  762. if( m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_VERT
  763. && m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
  764. {
  765. if( !aClockwise )
  766. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  767. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_HORIZ );
  768. }
  769. else if( m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_VERT
  770. && m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
  771. {
  772. if( !aClockwise )
  773. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  774. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_HORIZ );
  775. }
  776. else if( m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_HORIZ
  777. && m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
  778. {
  779. if( aClockwise )
  780. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  781. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_VERT );
  782. }
  783. else if( m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_HORIZ
  784. && m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_RIGHT )
  785. {
  786. if( aClockwise )
  787. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  788. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_VERT );
  789. }
  790. wxPoint pos = m_intersheetRefsField.GetTextPos();
  791. RotatePoint( &pos, GetPosition(), aClockwise ? -900 : 900 );
  792. m_intersheetRefsField.SetTextPos( pos );
  793. }
  794. void SCH_GLOBALLABEL::MirrorSpinStyle( bool aLeftRight )
  795. {
  796. SCH_TEXT::MirrorSpinStyle( aLeftRight );
  797. if( ( aLeftRight && m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_HORIZ )
  798. || ( !aLeftRight && m_intersheetRefsField.GetTextAngle() == TEXT_ANGLE_VERT ) )
  799. {
  800. if( m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
  801. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  802. else
  803. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  804. }
  805. wxPoint pos = m_intersheetRefsField.GetTextPos();
  806. wxPoint delta = GetPosition() - pos;
  807. if( aLeftRight )
  808. pos.x = GetPosition().x + delta.x;
  809. else
  810. pos.y = GetPosition().y + delta.y;
  811. m_intersheetRefsField.SetTextPos( pos );
  812. }
  813. void SCH_GLOBALLABEL::MirrorHorizontally( int aCenter )
  814. {
  815. wxPoint old_pos = GetPosition();
  816. SCH_TEXT::MirrorHorizontally( aCenter );
  817. if( m_intersheetRefsField.GetHorizJustify() == GR_TEXT_HJUSTIFY_LEFT )
  818. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  819. else
  820. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  821. wxPoint pos = m_intersheetRefsField.GetTextPos();
  822. wxPoint delta = old_pos - pos;
  823. pos.x = GetPosition().x + delta.x;
  824. m_intersheetRefsField.SetPosition( pos );
  825. }
  826. void SCH_GLOBALLABEL::MirrorVertically( int aCenter )
  827. {
  828. wxPoint old_pos = GetPosition();
  829. SCH_TEXT::MirrorVertically( aCenter );
  830. wxPoint pos = m_intersheetRefsField.GetTextPos();
  831. wxPoint delta = old_pos - pos;
  832. pos.y = GetPosition().y + delta.y;
  833. m_intersheetRefsField.SetPosition( pos );
  834. }
  835. void SCH_GLOBALLABEL::UpdateIntersheetRefProps()
  836. {
  837. m_intersheetRefsField.SetTextSize( GetTextSize() );
  838. m_intersheetRefsField.SetItalic( IsItalic() );
  839. m_intersheetRefsField.SetBold( IsBold() );
  840. m_intersheetRefsField.SetTextThickness( GetTextThickness() );
  841. if( m_fieldsAutoplaced == FIELDS_AUTOPLACED_AUTO )
  842. AutoplaceFields( nullptr, false );
  843. }
  844. void SCH_GLOBALLABEL::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
  845. {
  846. int margin = GetTextOffset();
  847. int labelLen = GetBoundingBoxBase().GetSizeMax();
  848. int penOffset = GetPenWidth() / 2;
  849. // Set both axes to penOffset; we're going to overwrite the text axis below
  850. wxPoint offset( -penOffset, -penOffset );
  851. switch( GetLabelSpinStyle() )
  852. {
  853. default:
  854. case LABEL_SPIN_STYLE::LEFT:
  855. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_HORIZ );
  856. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  857. offset.x = - ( labelLen + margin / 2 );
  858. break;
  859. case LABEL_SPIN_STYLE::UP:
  860. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_VERT );
  861. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  862. offset.y = - ( labelLen + margin / 2 );
  863. break;
  864. case LABEL_SPIN_STYLE::RIGHT:
  865. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_HORIZ );
  866. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  867. offset.x = labelLen + margin /2 ;
  868. break;
  869. case LABEL_SPIN_STYLE::BOTTOM:
  870. m_intersheetRefsField.SetTextAngle( TEXT_ANGLE_VERT );
  871. m_intersheetRefsField.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  872. offset.y = labelLen + margin / 2;
  873. break;
  874. }
  875. m_intersheetRefsField.SetTextPos( GetPosition() + offset );
  876. m_fieldsAutoplaced = FIELDS_AUTOPLACED_AUTO;
  877. }
  878. bool SCH_GLOBALLABEL::ResolveTextVar( wxString* token, int aDepth ) const
  879. {
  880. if( token->IsSameAs( wxT( "INTERSHEET_REFS" ) ) && Schematic() )
  881. {
  882. auto it = Schematic()->GetPageRefsMap().find( GetText() );
  883. if( it != Schematic()->GetPageRefsMap().end() )
  884. {
  885. SCHEMATIC_SETTINGS& settings = Schematic()->Settings();
  886. std::vector<wxString> pageListCopy;
  887. pageListCopy.insert( pageListCopy.end(), it->second.begin(), it->second.end() );
  888. std::sort( pageListCopy.begin(), pageListCopy.end() );
  889. if( !settings.m_IntersheetRefsListOwnPage )
  890. {
  891. wxString currentPage = Schematic()->CurrentSheet().GetPageNumber();
  892. pageListCopy.erase( std::remove( pageListCopy.begin(),
  893. pageListCopy.end(),
  894. currentPage ), pageListCopy.end() );
  895. }
  896. token->Printf( "%s", settings.m_IntersheetRefsPrefix );
  897. if( ( settings.m_IntersheetRefsFormatShort ) && ( pageListCopy.size() > 2 ) )
  898. {
  899. token->Append( wxString::Format( wxT( "%s..%s" ),
  900. pageListCopy.front(),
  901. pageListCopy.back() ) );
  902. }
  903. else
  904. {
  905. for( const wxString& pageNo : pageListCopy )
  906. token->Append( wxString::Format( wxT( "%s," ), pageNo ) );
  907. if( !token->IsEmpty() && token->Last() == ',' )
  908. token->RemoveLast();
  909. }
  910. token->Append( settings.m_IntersheetRefsSuffix );
  911. }
  912. return true;
  913. }
  914. return false;
  915. }
  916. void SCH_GLOBALLABEL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset )
  917. {
  918. static std::vector<wxPoint> s_poly;
  919. SCH_CONNECTION* connection = Connection();
  920. int layer = ( connection && connection->IsBus() ) ? LAYER_BUS : m_layer;
  921. wxDC* DC = aSettings->GetPrintDC();
  922. COLOR4D color = aSettings->GetLayerColor( layer );
  923. int penWidth = std::max( GetPenWidth(), aSettings->GetDefaultPenWidth() );
  924. wxPoint text_offset = aOffset + GetSchematicTextOffset( aSettings );
  925. EDA_TEXT::Print( aSettings, text_offset, color );
  926. CreateGraphicShape( aSettings, s_poly, GetTextPos() + aOffset );
  927. GRPoly( nullptr, DC, s_poly.size(), &s_poly[0], false, penWidth, color, color );
  928. if( Schematic()->Settings().m_IntersheetRefsShow )
  929. m_intersheetRefsField.Print( aSettings, aOffset );
  930. }
  931. void SCH_GLOBALLABEL::Plot( PLOTTER* aPlotter ) const
  932. {
  933. SCH_TEXT::Plot( aPlotter );
  934. bool show = Schematic()->Settings().m_IntersheetRefsShow;
  935. if ( show )
  936. m_intersheetRefsField.Plot( aPlotter );
  937. }
  938. void SCH_GLOBALLABEL::CreateGraphicShape( const RENDER_SETTINGS* aRenderSettings,
  939. std::vector<wxPoint>& aPoints, const wxPoint& Pos ) const
  940. {
  941. int margin = GetTextOffset( aRenderSettings );
  942. int halfSize = ( GetTextHeight() / 2 ) + margin;
  943. int linewidth = GetPenWidth();
  944. int symb_len = LenSize( GetShownText(), linewidth ) + 2 * margin;
  945. int x = symb_len + linewidth + 3;
  946. int y = halfSize + linewidth + 3;
  947. aPoints.clear();
  948. // Create outline shape : 6 points
  949. aPoints.emplace_back( wxPoint( 0, 0 ) );
  950. aPoints.emplace_back( wxPoint( 0, -y ) ); // Up
  951. aPoints.emplace_back( wxPoint( -x, -y ) ); // left
  952. aPoints.emplace_back( wxPoint( -x, 0 ) ); // Up left
  953. aPoints.emplace_back( wxPoint( -x, y ) ); // left down
  954. aPoints.emplace_back( wxPoint( 0, y ) ); // down
  955. int x_offset = 0;
  956. switch( m_shape )
  957. {
  958. case PINSHEETLABEL_SHAPE::PS_INPUT:
  959. x_offset = -halfSize;
  960. aPoints[0].x += halfSize;
  961. break;
  962. case PINSHEETLABEL_SHAPE::PS_OUTPUT:
  963. aPoints[3].x -= halfSize;
  964. break;
  965. case PINSHEETLABEL_SHAPE::PS_BIDI:
  966. case PINSHEETLABEL_SHAPE::PS_TRISTATE:
  967. x_offset = -halfSize;
  968. aPoints[0].x += halfSize;
  969. aPoints[3].x -= halfSize;
  970. break;
  971. case PINSHEETLABEL_SHAPE::PS_UNSPECIFIED:
  972. default:
  973. break;
  974. }
  975. int angle = 0;
  976. switch( GetLabelSpinStyle() )
  977. {
  978. default:
  979. case LABEL_SPIN_STYLE::LEFT: break;
  980. case LABEL_SPIN_STYLE::UP: angle = -900; break;
  981. case LABEL_SPIN_STYLE::RIGHT: angle = 1800; break;
  982. case LABEL_SPIN_STYLE::BOTTOM: angle = 900; break;
  983. }
  984. // Rotate outlines and move corners in real position
  985. for( wxPoint& aPoint : aPoints )
  986. {
  987. aPoint.x += x_offset;
  988. if( angle )
  989. RotatePoint( &aPoint, angle );
  990. aPoint += Pos;
  991. }
  992. aPoints.push_back( aPoints[0] ); // closing
  993. }
  994. const EDA_RECT SCH_GLOBALLABEL::GetBoundingBoxBase() const
  995. {
  996. // build the bounding box on the global label only, without taking in account
  997. // the intersheets references, just the bounding box of the graphic shape
  998. int x = GetTextPos().x;
  999. int y = GetTextPos().y;
  1000. int penWidth = GetEffectiveTextPenWidth();
  1001. int margin = GetTextOffset();
  1002. int height = ( ( GetTextHeight() * 15 ) / 10 ) + penWidth + margin;
  1003. int length = LenSize( GetShownText(), penWidth )
  1004. + height // add height for triangular shapes
  1005. - margin; // margin added to height not needed here
  1006. int dx, dy;
  1007. switch( GetLabelSpinStyle() ) // respect orientation
  1008. {
  1009. default:
  1010. case LABEL_SPIN_STYLE::LEFT:
  1011. dx = -length;
  1012. dy = height;
  1013. y -= height / 2;
  1014. break;
  1015. case LABEL_SPIN_STYLE::UP:
  1016. dx = height;
  1017. dy = -length;
  1018. x -= height / 2;
  1019. break;
  1020. case LABEL_SPIN_STYLE::RIGHT:
  1021. dx = length;
  1022. dy = height;
  1023. y -= height / 2;
  1024. break;
  1025. case LABEL_SPIN_STYLE::BOTTOM:
  1026. dx = height;
  1027. dy = length;
  1028. x -= height / 2;
  1029. break;
  1030. }
  1031. EDA_RECT box( wxPoint( x, y ), wxSize( dx, dy ) );
  1032. box.Normalize();
  1033. return box;
  1034. }
  1035. const EDA_RECT SCH_GLOBALLABEL::GetBoundingBox() const
  1036. {
  1037. // build the bounding box on the global label only, including the intersheets references
  1038. // full bounding box if they are shown
  1039. EDA_RECT box( GetBoundingBoxBase() );
  1040. // Note: Schematic() can be null in preference preview panel
  1041. if( Schematic() && Schematic()->Settings().m_IntersheetRefsShow )
  1042. {
  1043. box.Merge( m_intersheetRefsField.GetBoundingBox() );
  1044. box.Normalize();
  1045. }
  1046. return box;
  1047. }
  1048. wxString SCH_GLOBALLABEL::GetSelectMenuText( EDA_UNITS aUnits ) const
  1049. {
  1050. return wxString::Format( _( "Global Label '%s'" ), ShortenedShownText() );
  1051. }
  1052. BITMAPS SCH_GLOBALLABEL::GetMenuImage() const
  1053. {
  1054. return BITMAPS::add_glabel;
  1055. }
  1056. SCH_HIERLABEL::SCH_HIERLABEL( const wxPoint& pos, const wxString& text, KICAD_T aType )
  1057. : SCH_TEXT( pos, text, aType )
  1058. {
  1059. m_layer = LAYER_HIERLABEL;
  1060. m_shape = PINSHEETLABEL_SHAPE::PS_INPUT;
  1061. m_isDangling = true;
  1062. SetMultilineAllowed( false );
  1063. }
  1064. EDA_ITEM* SCH_HIERLABEL::Clone() const
  1065. {
  1066. return new SCH_HIERLABEL( *this );
  1067. }
  1068. void SCH_HIERLABEL::SetLabelSpinStyle( LABEL_SPIN_STYLE aSpinStyle )
  1069. {
  1070. m_spin_style = aSpinStyle;
  1071. // Assume "Right" and Left" mean which side of the port symbol the text will be on
  1072. // If we are left of the symbol, we want to right justify to line up with the symbol
  1073. switch( aSpinStyle )
  1074. {
  1075. default:
  1076. wxLogWarning( "SetLabelSpinStyle bad spin style" );
  1077. break;
  1078. case LABEL_SPIN_STYLE::LEFT:
  1079. //
  1080. m_spin_style = LABEL_SPIN_STYLE::LEFT; // Handle the error spin style by resetting
  1081. SetTextAngle( TEXT_ANGLE_HORIZ );
  1082. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1083. SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  1084. break;
  1085. case LABEL_SPIN_STYLE::UP:
  1086. SetTextAngle( TEXT_ANGLE_VERT );
  1087. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1088. SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  1089. break;
  1090. case LABEL_SPIN_STYLE::RIGHT:
  1091. SetTextAngle( TEXT_ANGLE_HORIZ );
  1092. SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  1093. SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  1094. break;
  1095. case LABEL_SPIN_STYLE::BOTTOM:
  1096. SetTextAngle( TEXT_ANGLE_VERT );
  1097. SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  1098. SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  1099. break;
  1100. }
  1101. }
  1102. void SCH_HIERLABEL::Print( const RENDER_SETTINGS* aSettings, const wxPoint& offset )
  1103. {
  1104. wxCHECK_RET( Schematic(), "No parent SCHEMATIC set for SCH_LABEL!" );
  1105. static std::vector <wxPoint> Poly;
  1106. wxDC* DC = aSettings->GetPrintDC();
  1107. SCH_CONNECTION* conn = Connection();
  1108. bool isBus = conn && conn->IsBus();
  1109. COLOR4D color = aSettings->GetLayerColor( isBus ? LAYER_BUS : m_layer );
  1110. int penWidth = std::max( GetPenWidth(), aSettings->GetDefaultPenWidth() );
  1111. wxPoint textOffset = offset + GetSchematicTextOffset( aSettings );
  1112. EDA_TEXT::Print( aSettings, textOffset, color );
  1113. CreateGraphicShape( aSettings, Poly, GetTextPos() + offset );
  1114. GRPoly( nullptr, DC, Poly.size(), &Poly[0], false, penWidth, color, color );
  1115. }
  1116. void SCH_HIERLABEL::CreateGraphicShape( const RENDER_SETTINGS* aSettings,
  1117. std::vector<wxPoint>& aPoints, const wxPoint& aPos ) const
  1118. {
  1119. CreateGraphicShape( aSettings, aPoints, aPos, m_shape );
  1120. }
  1121. void SCH_HIERLABEL::CreateGraphicShape( const RENDER_SETTINGS* aSettings,
  1122. std::vector<wxPoint>& aPoints, const wxPoint& aPos, PINSHEETLABEL_SHAPE aShape ) const
  1123. {
  1124. int* Template = TemplateShape[static_cast<int>( aShape )][static_cast<int>( m_spin_style )];
  1125. int halfSize = GetTextHeight() / 2;
  1126. int imax = *Template;
  1127. Template++;
  1128. aPoints.clear();
  1129. for( int ii = 0; ii < imax; ii++ )
  1130. {
  1131. wxPoint corner;
  1132. corner.x = ( halfSize * (*Template) ) + aPos.x;
  1133. Template++;
  1134. corner.y = ( halfSize * (*Template) ) + aPos.y;
  1135. Template++;
  1136. aPoints.push_back( corner );
  1137. }
  1138. }
  1139. const EDA_RECT SCH_HIERLABEL::GetBoundingBox() const
  1140. {
  1141. int penWidth = GetEffectiveTextPenWidth();
  1142. int margin = GetTextOffset();
  1143. int x = GetTextPos().x;
  1144. int y = GetTextPos().y;
  1145. int height = GetTextHeight() + penWidth + margin;
  1146. int length = LenSize( GetShownText(), penWidth )
  1147. + height; // add height for triangular shapes
  1148. int dx, dy;
  1149. switch( GetLabelSpinStyle() )
  1150. {
  1151. default:
  1152. case LABEL_SPIN_STYLE::LEFT:
  1153. dx = -length;
  1154. dy = height;
  1155. x += Mils2iu( DANGLING_SYMBOL_SIZE );
  1156. y -= height / 2;
  1157. break;
  1158. case LABEL_SPIN_STYLE::UP:
  1159. dx = height;
  1160. dy = -length;
  1161. x -= height / 2;
  1162. y += Mils2iu( DANGLING_SYMBOL_SIZE );
  1163. break;
  1164. case LABEL_SPIN_STYLE::RIGHT:
  1165. dx = length;
  1166. dy = height;
  1167. x -= Mils2iu( DANGLING_SYMBOL_SIZE );
  1168. y -= height / 2;
  1169. break;
  1170. case LABEL_SPIN_STYLE::BOTTOM:
  1171. dx = height;
  1172. dy = length;
  1173. x -= height / 2;
  1174. y -= Mils2iu( DANGLING_SYMBOL_SIZE );
  1175. break;
  1176. }
  1177. EDA_RECT box( wxPoint( x, y ), wxSize( dx, dy ) );
  1178. box.Normalize();
  1179. return box;
  1180. }
  1181. wxPoint SCH_HIERLABEL::GetSchematicTextOffset( const RENDER_SETTINGS* aSettings ) const
  1182. {
  1183. wxPoint text_offset;
  1184. int dist = GetTextOffset( aSettings );
  1185. dist += GetTextWidth();
  1186. switch( GetLabelSpinStyle() )
  1187. {
  1188. default:
  1189. case LABEL_SPIN_STYLE::LEFT: text_offset.x = -dist; break; // Orientation horiz normale
  1190. case LABEL_SPIN_STYLE::UP: text_offset.y = -dist; break; // Orientation vert UP
  1191. case LABEL_SPIN_STYLE::RIGHT: text_offset.x = dist; break; // Orientation horiz inverse
  1192. case LABEL_SPIN_STYLE::BOTTOM: text_offset.y = dist; break; // Orientation vert BOTTOM
  1193. }
  1194. return text_offset;
  1195. }
  1196. wxString SCH_HIERLABEL::GetSelectMenuText( EDA_UNITS aUnits ) const
  1197. {
  1198. return wxString::Format( _( "Hierarchical Label '%s'" ), ShortenedShownText() );
  1199. }
  1200. BITMAPS SCH_HIERLABEL::GetMenuImage() const
  1201. {
  1202. return BITMAPS::add_hierarchical_label;
  1203. }
  1204. HTML_MESSAGE_BOX* SCH_TEXT::ShowSyntaxHelp( wxWindow* aParentWindow )
  1205. {
  1206. wxString msg =
  1207. #include "sch_text_help_md.h"
  1208. ;
  1209. HTML_MESSAGE_BOX* dlg = new HTML_MESSAGE_BOX( nullptr, _( "Syntax Help" ) );
  1210. wxSize sz( 320, 320 );
  1211. dlg->SetMinSize( dlg->ConvertDialogToPixels( sz ) );
  1212. dlg->SetDialogSizeInDU( sz.x, sz.y );
  1213. wxString html_txt;
  1214. ConvertMarkdown2Html( wxGetTranslation( msg ), html_txt );
  1215. dlg->m_htmlWindow->AppendToPage( html_txt );
  1216. dlg->ShowModeless();
  1217. return dlg;
  1218. }