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.

648 lines
20 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <advanced_config.h>
  24. #include <base_units.h>
  25. #include <pgm_base.h>
  26. #include <sch_edit_frame.h>
  27. #include <plotters/plotter.h>
  28. #include <widgets/msgpanel.h>
  29. #include <bitmaps.h>
  30. #include <string_utils.h>
  31. #include <schematic.h>
  32. #include <settings/color_settings.h>
  33. #include <sch_painter.h>
  34. #include <wx/log.h>
  35. #include <dialogs/html_message_box.h>
  36. #include <project/project_file.h>
  37. #include <trigo.h>
  38. #include <geometry/geometry_utils.h>
  39. #include <sch_textbox.h>
  40. #include <tools/sch_navigate_tool.h>
  41. SCH_TEXTBOX::SCH_TEXTBOX( SCH_LAYER_ID aLayer, int aLineWidth, FILL_T aFillType,
  42. const wxString& aText, KICAD_T aType ) :
  43. SCH_SHAPE( SHAPE_T::RECTANGLE, aLayer, aLineWidth, aFillType, aType ),
  44. EDA_TEXT( schIUScale, aText )
  45. {
  46. m_layer = aLayer;
  47. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  48. SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  49. SetMultilineAllowed( true );
  50. m_excludedFromSim = false;
  51. int defaultMargin = GetLegacyTextMargin();
  52. m_marginLeft = defaultMargin;
  53. m_marginTop = defaultMargin;
  54. m_marginRight = defaultMargin;
  55. m_marginBottom = defaultMargin;
  56. }
  57. SCH_TEXTBOX::SCH_TEXTBOX( const SCH_TEXTBOX& aText ) :
  58. SCH_SHAPE( aText ),
  59. EDA_TEXT( aText )
  60. {
  61. m_excludedFromSim = aText.m_excludedFromSim;
  62. m_marginLeft = aText.m_marginLeft;
  63. m_marginTop = aText.m_marginTop;
  64. m_marginRight = aText.m_marginRight;
  65. m_marginBottom = aText.m_marginBottom;
  66. }
  67. int SCH_TEXTBOX::GetLegacyTextMargin() const
  68. {
  69. if( m_layer == LAYER_DEVICE )
  70. return KiROUND( GetTextSize().y * 0.8 );
  71. else
  72. return KiROUND( GetStroke().GetWidth() / 2.0 ) + KiROUND( GetTextSize().y * 0.75 );
  73. }
  74. void SCH_TEXTBOX::MirrorHorizontally( int aCenter )
  75. {
  76. SCH_SHAPE::MirrorHorizontally( aCenter );
  77. // Text is NOT really mirrored; it just has its justification flipped
  78. if( GetTextAngle() == ANGLE_HORIZONTAL )
  79. {
  80. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  81. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  82. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  83. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  84. }
  85. }
  86. void SCH_TEXTBOX::MirrorVertically( int aCenter )
  87. {
  88. SCH_SHAPE::MirrorVertically( aCenter );
  89. // Text is NOT really mirrored; it just has its justification flipped
  90. if( GetTextAngle() == ANGLE_VERTICAL )
  91. {
  92. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  93. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  94. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  95. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  96. }
  97. }
  98. void SCH_TEXTBOX::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
  99. {
  100. SCH_SHAPE::Rotate( aCenter, aRotateCCW );
  101. SetTextAngle( GetTextAngle() == ANGLE_VERTICAL ? ANGLE_HORIZONTAL : ANGLE_VERTICAL );
  102. }
  103. void SCH_TEXTBOX::Rotate90( bool aClockwise )
  104. {
  105. SetTextAngle( GetTextAngle() == ANGLE_VERTICAL ? ANGLE_HORIZONTAL : ANGLE_VERTICAL );
  106. }
  107. VECTOR2I SCH_TEXTBOX::GetDrawPos() const
  108. {
  109. BOX2I bbox = BOX2I( m_start, m_end - m_start );
  110. bbox.Normalize();
  111. VECTOR2I pos( bbox.GetLeft() + m_marginLeft, bbox.GetBottom() - m_marginBottom );
  112. if( GetTextAngle().IsVertical() )
  113. {
  114. switch( GetHorizJustify() )
  115. {
  116. case GR_TEXT_H_ALIGN_LEFT:
  117. pos.y = bbox.GetBottom() - m_marginBottom;
  118. break;
  119. case GR_TEXT_H_ALIGN_CENTER:
  120. pos.y = ( bbox.GetTop() + bbox.GetBottom() ) / 2;
  121. break;
  122. case GR_TEXT_H_ALIGN_RIGHT:
  123. pos.y = bbox.GetTop() + m_marginTop;
  124. break;
  125. case GR_TEXT_H_ALIGN_INDETERMINATE:
  126. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  127. break;
  128. }
  129. switch( GetVertJustify() )
  130. {
  131. case GR_TEXT_V_ALIGN_TOP:
  132. pos.x = bbox.GetLeft() + m_marginLeft;
  133. break;
  134. case GR_TEXT_V_ALIGN_CENTER:
  135. pos.x = ( bbox.GetLeft() + bbox.GetRight() ) / 2;
  136. break;
  137. case GR_TEXT_V_ALIGN_BOTTOM:
  138. pos.x = bbox.GetRight() - m_marginRight;
  139. break;
  140. case GR_TEXT_V_ALIGN_INDETERMINATE:
  141. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  142. break;
  143. }
  144. }
  145. else
  146. {
  147. switch( GetHorizJustify() )
  148. {
  149. case GR_TEXT_H_ALIGN_LEFT:
  150. pos.x = bbox.GetLeft() + m_marginLeft;
  151. break;
  152. case GR_TEXT_H_ALIGN_CENTER:
  153. pos.x = ( bbox.GetLeft() + bbox.GetRight() ) / 2;
  154. break;
  155. case GR_TEXT_H_ALIGN_RIGHT:
  156. pos.x = bbox.GetRight() - m_marginRight;
  157. break;
  158. case GR_TEXT_H_ALIGN_INDETERMINATE:
  159. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  160. break;
  161. }
  162. switch( GetVertJustify() )
  163. {
  164. case GR_TEXT_V_ALIGN_TOP:
  165. pos.y = bbox.GetTop() + m_marginTop;
  166. break;
  167. case GR_TEXT_V_ALIGN_CENTER:
  168. pos.y = ( bbox.GetTop() + bbox.GetBottom() ) / 2;
  169. break;
  170. case GR_TEXT_V_ALIGN_BOTTOM:
  171. pos.y = bbox.GetBottom() - m_marginBottom;
  172. break;
  173. case GR_TEXT_V_ALIGN_INDETERMINATE:
  174. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  175. break;
  176. }
  177. }
  178. return pos;
  179. }
  180. void SCH_TEXTBOX::swapData( SCH_ITEM* aItem )
  181. {
  182. SCH_SHAPE::swapData( aItem );
  183. SCH_TEXTBOX* item = static_cast<SCH_TEXTBOX*>( aItem );
  184. std::swap( m_marginLeft, item->m_marginLeft );
  185. std::swap( m_marginTop, item->m_marginTop );
  186. std::swap( m_marginRight, item->m_marginRight );
  187. std::swap( m_marginBottom, item->m_marginBottom );
  188. SwapText( *item );
  189. SwapAttributes( *item );
  190. }
  191. bool SCH_TEXTBOX::operator<( const SCH_ITEM& aItem ) const
  192. {
  193. if( Type() != aItem.Type() )
  194. return Type() < aItem.Type();
  195. auto other = static_cast<const SCH_TEXTBOX*>( &aItem );
  196. if( GetLayer() != other->GetLayer() )
  197. return GetLayer() < other->GetLayer();
  198. if( GetPosition().x != other->GetPosition().x )
  199. return GetPosition().x < other->GetPosition().x;
  200. if( GetPosition().y != other->GetPosition().y )
  201. return GetPosition().y < other->GetPosition().y;
  202. if( GetMarginLeft() != other->GetMarginLeft() )
  203. return GetMarginLeft() < other->GetMarginLeft();
  204. if( GetMarginTop() != other->GetMarginTop() )
  205. return GetMarginTop() < other->GetMarginTop();
  206. if( GetMarginRight() != other->GetMarginRight() )
  207. return GetMarginRight() < other->GetMarginRight();
  208. if( GetMarginBottom() != other->GetMarginBottom() )
  209. return GetMarginBottom() < other->GetMarginBottom();
  210. if( GetExcludedFromSim() != other->GetExcludedFromSim() )
  211. return GetExcludedFromSim() - other->GetExcludedFromSim();
  212. return GetText() < other->GetText();
  213. }
  214. KIFONT::FONT* SCH_TEXTBOX::GetDrawFont( const RENDER_SETTINGS* aSettings ) const
  215. {
  216. KIFONT::FONT* font = EDA_TEXT::GetFont();
  217. if( !font )
  218. font = KIFONT::FONT::GetFont( GetDefaultFont( aSettings ), IsBold(), IsItalic() );
  219. return font;
  220. }
  221. wxString SCH_TEXTBOX::GetShownText( const RENDER_SETTINGS* aSettings, const SCH_SHEET_PATH* aPath,
  222. bool aAllowExtraText, int aDepth ) const
  223. {
  224. SCH_SHEET* sheet = nullptr;
  225. if( aPath )
  226. sheet = aPath->Last();
  227. std::function<bool( wxString* )> textResolver =
  228. [&]( wxString* token ) -> bool
  229. {
  230. if( sheet )
  231. {
  232. if( sheet->ResolveTextVar( aPath, token, aDepth + 1 ) )
  233. return true;
  234. }
  235. return false;
  236. };
  237. wxString text = EDA_TEXT::GetShownText( aAllowExtraText, aDepth );
  238. if( HasTextVars() )
  239. {
  240. if( aDepth < ADVANCED_CFG::GetCfg().m_ResolveTextRecursionDepth )
  241. text = ExpandTextVars( text, &textResolver );
  242. }
  243. if( text.Contains( wxT( "@{" ) ) )
  244. text = EvaluateText( text );
  245. VECTOR2I size = GetEnd() - GetStart();
  246. int colWidth;
  247. if( GetTextAngle().IsVertical() )
  248. colWidth = abs( size.y ) - ( GetMarginTop() + GetMarginBottom() );
  249. else
  250. colWidth = abs( size.x ) - ( GetMarginLeft() + GetMarginRight() );
  251. GetDrawFont( aSettings )->LinebreakText( text, colWidth, GetTextSize(), GetEffectiveTextPenWidth(),
  252. IsBold(), IsItalic() );
  253. return text;
  254. }
  255. bool SCH_TEXTBOX::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
  256. {
  257. BOX2I rect = GetBoundingBox();
  258. rect.Inflate( aAccuracy );
  259. return rect.Contains( aPosition );
  260. }
  261. bool SCH_TEXTBOX::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
  262. {
  263. BOX2I rect = aRect;
  264. rect.Inflate( aAccuracy );
  265. if( aContained )
  266. return rect.Contains( GetBoundingBox() );
  267. return rect.Intersects( GetBoundingBox() );
  268. }
  269. bool SCH_TEXTBOX::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
  270. {
  271. return KIGEOM::BoxHitTest( aPoly, GetBoundingBox(), aContained );
  272. }
  273. bool SCH_TEXTBOX::IsHypertext() const
  274. {
  275. if( HasHyperlink() )
  276. return true;
  277. return IsURL( GetShownText( false ) );
  278. }
  279. void SCH_TEXTBOX::DoHypertextAction( EDA_DRAW_FRAME* aFrame ) const
  280. {
  281. wxCHECK_MSG( IsHypertext(), /* void */,
  282. wxT( "Calling a hypertext menu on a SCH_TEXTBOX with no hyperlink?" ) );
  283. SCH_NAVIGATE_TOOL* navTool = aFrame->GetToolManager()->GetTool<SCH_NAVIGATE_TOOL>();
  284. if( HasHyperlink() )
  285. navTool->HypertextCommand( m_hyperlink );
  286. else
  287. navTool->HypertextCommand( GetShownText( false ) );
  288. }
  289. wxString SCH_TEXTBOX::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
  290. {
  291. return wxString::Format( _( "Text box '%s'" ),
  292. aFull ? GetShownText( false ) : KIUI::EllipsizeMenuText( GetText() ) );
  293. }
  294. BITMAPS SCH_TEXTBOX::GetMenuImage() const
  295. {
  296. return BITMAPS::add_textbox;
  297. }
  298. void SCH_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
  299. int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
  300. {
  301. if( IsPrivate() )
  302. return;
  303. SCH_SHAPE::Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
  304. if( aBackground )
  305. return;
  306. SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
  307. SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
  308. int penWidth = GetEffectivePenWidth( renderSettings );
  309. COLOR4D color = GetStroke().GetColor();
  310. COLOR4D bg = renderSettings->GetBackgroundColor();
  311. KIFONT::FONT* font = GetDrawFont( renderSettings );
  312. color = GetTextColor();
  313. if( !aPlotter->GetColorMode() || color == COLOR4D::UNSPECIFIED )
  314. color = renderSettings->GetLayerColor( m_layer );
  315. if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
  316. bg = COLOR4D::WHITE;
  317. if( aDimmed )
  318. {
  319. color.Desaturate( );
  320. color = color.Mix( bg, 0.5f );
  321. }
  322. penWidth = GetEffectiveTextPenWidth( renderSettings->GetDefaultPenWidth() );
  323. penWidth = std::max( penWidth, renderSettings->GetMinPenWidth() );
  324. aPlotter->SetCurrentLineWidth( penWidth );
  325. TEXT_ATTRIBUTES attrs;
  326. std::vector<VECTOR2I> positions;
  327. wxArrayString strings_list;
  328. wxStringSplit( GetShownText( renderSettings, sheet, true ), strings_list, '\n' );
  329. positions.reserve( strings_list.Count() );
  330. if( renderSettings->m_Transform != TRANSFORM() || aOffset != VECTOR2I() )
  331. {
  332. SCH_TEXTBOX temp( *this );
  333. if( renderSettings->m_Transform.y1 )
  334. {
  335. temp.SetTextAngle( temp.GetTextAngle() == ANGLE_HORIZONTAL ? ANGLE_VERTICAL
  336. : ANGLE_HORIZONTAL );
  337. }
  338. temp.SetStart( renderSettings->TransformCoordinate( m_start ) + aOffset );
  339. temp.SetEnd( renderSettings->TransformCoordinate( m_end ) + aOffset );
  340. attrs = temp.GetAttributes();
  341. temp.GetLinePositions( renderSettings, positions, (int) strings_list.Count() );
  342. }
  343. else
  344. {
  345. attrs = GetAttributes();
  346. GetLinePositions( renderSettings, positions, (int) strings_list.Count() );
  347. }
  348. attrs.m_StrokeWidth = penWidth;
  349. attrs.m_Multiline = false;
  350. for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
  351. {
  352. aPlotter->PlotText( positions[ii], color, strings_list.Item( ii ), attrs, font,
  353. GetFontMetrics() );
  354. }
  355. if( HasHyperlink() )
  356. aPlotter->HyperlinkBox( GetBoundingBox(), GetHyperlink() );
  357. }
  358. void SCH_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  359. {
  360. // Don't use GetShownText() here; we want to show the user the variable references
  361. aList.emplace_back( _( "Text Box" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
  362. SCH_ITEM::GetMsgPanelInfo( aFrame, aList );
  363. if( m_excludedFromSim )
  364. aList.emplace_back( _( "Exclude from" ), _( "Simulation" ) );
  365. aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
  366. wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
  367. int style = IsBold() && IsItalic() ? 3 : IsBold() ? 2 : IsItalic() ? 1 : 0;
  368. aList.emplace_back( _( "Style" ), textStyle[style] );
  369. aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
  370. aList.emplace_back( _( "Box Width" ),
  371. aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
  372. aList.emplace_back( _( "Box Height" ),
  373. aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
  374. m_stroke.GetMsgPanelInfo( aFrame, aList );
  375. }
  376. bool SCH_TEXTBOX::operator==( const SCH_ITEM& aOther ) const
  377. {
  378. if( Type() != aOther.Type() )
  379. return false;
  380. const SCH_TEXTBOX& other = static_cast<const SCH_TEXTBOX&>( aOther );
  381. if( m_excludedFromSim != other.m_excludedFromSim )
  382. return false;
  383. if( GetMarginLeft() != other.GetMarginLeft() )
  384. return false;
  385. if( GetMarginTop() != other.GetMarginTop() )
  386. return false;
  387. if( GetMarginRight() != other.GetMarginRight() )
  388. return false;
  389. if( GetMarginBottom() != other.GetMarginBottom() )
  390. return false;
  391. return SCH_SHAPE::operator==( aOther ) && EDA_TEXT::operator==( other );
  392. }
  393. double SCH_TEXTBOX::Similarity( const SCH_ITEM& aOther ) const
  394. {
  395. if( m_Uuid == aOther.m_Uuid )
  396. return 1.0;
  397. if( aOther.Type() != Type() )
  398. return 0.0;
  399. auto other = static_cast<const SCH_TEXTBOX&>( aOther );
  400. double similarity = SimilarityBase( other );
  401. if( m_excludedFromSim != other.m_excludedFromSim )
  402. similarity *= 0.9;
  403. if( GetMarginLeft() != other.GetMarginLeft() )
  404. similarity *= 0.9;
  405. if( GetMarginTop() != other.GetMarginTop() )
  406. similarity *= 0.9;
  407. if( GetMarginRight() != other.GetMarginRight() )
  408. similarity *= 0.9;
  409. if( GetMarginBottom() != other.GetMarginBottom() )
  410. similarity *= 0.9;
  411. similarity *= SCH_SHAPE::Similarity( aOther );
  412. similarity *= EDA_TEXT::Similarity( other );
  413. return similarity;
  414. }
  415. int SCH_TEXTBOX::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
  416. {
  417. wxASSERT( aOther.Type() == SCH_TEXTBOX_T );
  418. int retv = SCH_SHAPE::compare( aOther, aCompareFlags );
  419. if( retv )
  420. return retv;
  421. const SCH_TEXTBOX* tmp = static_cast<const SCH_TEXTBOX*>( &aOther );
  422. int result = GetText().CmpNoCase( tmp->GetText() );
  423. if( result != 0 )
  424. return result;
  425. if( GetTextWidth() != tmp->GetTextWidth() )
  426. return GetTextWidth() - tmp->GetTextWidth();
  427. if( GetTextHeight() != tmp->GetTextHeight() )
  428. return GetTextHeight() - tmp->GetTextHeight();
  429. if( IsBold() != tmp->IsBold() )
  430. return IsBold() - tmp->IsBold();
  431. if( IsItalic() != tmp->IsItalic() )
  432. return IsItalic() - tmp->IsItalic();
  433. if( GetHorizJustify() != tmp->GetHorizJustify() )
  434. return (int) GetHorizJustify() - (int) tmp->GetHorizJustify();
  435. if( GetTextAngle().AsTenthsOfADegree() != tmp->GetTextAngle().AsTenthsOfADegree() )
  436. return GetTextAngle().AsTenthsOfADegree() - tmp->GetTextAngle().AsTenthsOfADegree();
  437. if( GetMarginLeft() != tmp->GetMarginLeft() )
  438. return GetMarginLeft() - tmp->GetMarginLeft();
  439. if( GetMarginTop() != tmp->GetMarginTop() )
  440. return GetMarginTop() - tmp->GetMarginTop();
  441. if( GetMarginRight() != tmp->GetMarginRight() )
  442. return GetMarginRight() - tmp->GetMarginRight();
  443. if( GetMarginBottom() != tmp->GetMarginBottom() )
  444. return GetMarginBottom() - tmp->GetMarginBottom();
  445. return 0;
  446. }
  447. static struct SCH_TEXTBOX_DESC
  448. {
  449. SCH_TEXTBOX_DESC()
  450. {
  451. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  452. REGISTER_TYPE( SCH_TEXTBOX );
  453. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, SCH_SHAPE> );
  454. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, EDA_SHAPE> );
  455. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, EDA_TEXT> );
  456. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( SCH_SHAPE ) );
  457. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ) );
  458. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ) );
  459. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
  460. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ), _HKI( "Corner Radius" ) );
  461. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
  462. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
  463. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Thickness" ) );
  464. const wxString marginProps = _( "Margins" );
  465. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Left" ),
  466. &SCH_TEXTBOX::SetMarginLeft, &SCH_TEXTBOX::GetMarginLeft,
  467. PROPERTY_DISPLAY::PT_SIZE ),
  468. marginProps );
  469. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Top" ),
  470. &SCH_TEXTBOX::SetMarginTop, &SCH_TEXTBOX::GetMarginTop,
  471. PROPERTY_DISPLAY::PT_SIZE ),
  472. marginProps );
  473. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Right" ),
  474. &SCH_TEXTBOX::SetMarginRight, &SCH_TEXTBOX::GetMarginRight,
  475. PROPERTY_DISPLAY::PT_SIZE ),
  476. marginProps );
  477. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Bottom" ),
  478. &SCH_TEXTBOX::SetMarginBottom, &SCH_TEXTBOX::GetMarginBottom,
  479. PROPERTY_DISPLAY::PT_SIZE ),
  480. marginProps );
  481. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Text Size" ),
  482. &SCH_TEXTBOX::SetSchTextSize, &SCH_TEXTBOX::GetSchTextSize,
  483. PROPERTY_DISPLAY::PT_SIZE ),
  484. _HKI( "Text Properties" ) );
  485. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
  486. }
  487. } _SCH_TEXTBOX_DESC;