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.

635 lines
19 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 <sch_textbox.h>
  39. #include <tools/sch_navigate_tool.h>
  40. SCH_TEXTBOX::SCH_TEXTBOX( SCH_LAYER_ID aLayer, int aLineWidth, FILL_T aFillType,
  41. const wxString& aText, KICAD_T aType ) :
  42. SCH_SHAPE( SHAPE_T::RECTANGLE, aLayer, aLineWidth, aFillType, aType ),
  43. EDA_TEXT( schIUScale, aText )
  44. {
  45. m_layer = aLayer;
  46. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  47. SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  48. SetMultilineAllowed( true );
  49. m_excludedFromSim = false;
  50. int defaultMargin = GetLegacyTextMargin();
  51. m_marginLeft = defaultMargin;
  52. m_marginTop = defaultMargin;
  53. m_marginRight = defaultMargin;
  54. m_marginBottom = defaultMargin;
  55. }
  56. SCH_TEXTBOX::SCH_TEXTBOX( const SCH_TEXTBOX& aText ) :
  57. SCH_SHAPE( aText ),
  58. EDA_TEXT( aText )
  59. {
  60. m_excludedFromSim = aText.m_excludedFromSim;
  61. m_marginLeft = aText.m_marginLeft;
  62. m_marginTop = aText.m_marginTop;
  63. m_marginRight = aText.m_marginRight;
  64. m_marginBottom = aText.m_marginBottom;
  65. }
  66. int SCH_TEXTBOX::GetLegacyTextMargin() const
  67. {
  68. if( m_layer == LAYER_DEVICE )
  69. return KiROUND( GetTextSize().y * 0.8 );
  70. else
  71. return KiROUND( GetStroke().GetWidth() / 2.0 ) + KiROUND( GetTextSize().y * 0.75 );
  72. }
  73. void SCH_TEXTBOX::MirrorHorizontally( int aCenter )
  74. {
  75. SCH_SHAPE::MirrorHorizontally( aCenter );
  76. // Text is NOT really mirrored; it just has its justification flipped
  77. if( GetTextAngle() == ANGLE_HORIZONTAL )
  78. {
  79. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  80. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  81. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  82. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  83. }
  84. }
  85. void SCH_TEXTBOX::MirrorVertically( int aCenter )
  86. {
  87. SCH_SHAPE::MirrorVertically( aCenter );
  88. // Text is NOT really mirrored; it just has its justification flipped
  89. if( GetTextAngle() == ANGLE_VERTICAL )
  90. {
  91. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  92. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  93. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  94. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  95. }
  96. }
  97. void SCH_TEXTBOX::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
  98. {
  99. SCH_SHAPE::Rotate( aCenter, aRotateCCW );
  100. SetTextAngle( GetTextAngle() == ANGLE_VERTICAL ? ANGLE_HORIZONTAL : ANGLE_VERTICAL );
  101. }
  102. void SCH_TEXTBOX::Rotate90( bool aClockwise )
  103. {
  104. SetTextAngle( GetTextAngle() == ANGLE_VERTICAL ? ANGLE_HORIZONTAL : ANGLE_VERTICAL );
  105. }
  106. VECTOR2I SCH_TEXTBOX::GetDrawPos() const
  107. {
  108. BOX2I bbox = BOX2I( m_start, m_end - m_start );
  109. bbox.Normalize();
  110. VECTOR2I pos( bbox.GetLeft() + m_marginLeft, bbox.GetBottom() - m_marginBottom );
  111. if( GetTextAngle().IsVertical() )
  112. {
  113. switch( GetHorizJustify() )
  114. {
  115. case GR_TEXT_H_ALIGN_LEFT:
  116. pos.y = bbox.GetBottom() - m_marginBottom;
  117. break;
  118. case GR_TEXT_H_ALIGN_CENTER:
  119. pos.y = ( bbox.GetTop() + bbox.GetBottom() ) / 2;
  120. break;
  121. case GR_TEXT_H_ALIGN_RIGHT:
  122. pos.y = bbox.GetTop() + m_marginTop;
  123. break;
  124. case GR_TEXT_H_ALIGN_INDETERMINATE:
  125. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  126. break;
  127. }
  128. switch( GetVertJustify() )
  129. {
  130. case GR_TEXT_V_ALIGN_TOP:
  131. pos.x = bbox.GetLeft() + m_marginLeft;
  132. break;
  133. case GR_TEXT_V_ALIGN_CENTER:
  134. pos.x = ( bbox.GetLeft() + bbox.GetRight() ) / 2;
  135. break;
  136. case GR_TEXT_V_ALIGN_BOTTOM:
  137. pos.x = bbox.GetRight() - m_marginRight;
  138. break;
  139. case GR_TEXT_V_ALIGN_INDETERMINATE:
  140. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  141. break;
  142. }
  143. }
  144. else
  145. {
  146. switch( GetHorizJustify() )
  147. {
  148. case GR_TEXT_H_ALIGN_LEFT:
  149. pos.x = bbox.GetLeft() + m_marginLeft;
  150. break;
  151. case GR_TEXT_H_ALIGN_CENTER:
  152. pos.x = ( bbox.GetLeft() + bbox.GetRight() ) / 2;
  153. break;
  154. case GR_TEXT_H_ALIGN_RIGHT:
  155. pos.x = bbox.GetRight() - m_marginRight;
  156. break;
  157. case GR_TEXT_H_ALIGN_INDETERMINATE:
  158. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  159. break;
  160. }
  161. switch( GetVertJustify() )
  162. {
  163. case GR_TEXT_V_ALIGN_TOP:
  164. pos.y = bbox.GetTop() + m_marginTop;
  165. break;
  166. case GR_TEXT_V_ALIGN_CENTER:
  167. pos.y = ( bbox.GetTop() + bbox.GetBottom() ) / 2;
  168. break;
  169. case GR_TEXT_V_ALIGN_BOTTOM:
  170. pos.y = bbox.GetBottom() - m_marginBottom;
  171. break;
  172. case GR_TEXT_V_ALIGN_INDETERMINATE:
  173. wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
  174. break;
  175. }
  176. }
  177. return pos;
  178. }
  179. void SCH_TEXTBOX::swapData( SCH_ITEM* aItem )
  180. {
  181. SCH_SHAPE::swapData( aItem );
  182. SCH_TEXTBOX* item = static_cast<SCH_TEXTBOX*>( aItem );
  183. std::swap( m_layer, item->m_layer );
  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
  215. {
  216. KIFONT::FONT* font = EDA_TEXT::GetFont();
  217. if( !font )
  218. font = KIFONT::FONT::GetFont( GetDefaultFont(), IsBold(), IsItalic() );
  219. return font;
  220. }
  221. wxString SCH_TEXTBOX::GetShownText( const SCH_SHEET_PATH* aPath, bool aAllowExtraText,
  222. 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. VECTOR2I size = GetEnd() - GetStart();
  244. int colWidth;
  245. if( GetTextAngle().IsVertical() )
  246. colWidth = abs( size.y ) - ( GetMarginTop() + GetMarginBottom() );
  247. else
  248. colWidth = abs( size.x ) - ( GetMarginLeft() + GetMarginRight() );
  249. getDrawFont()->LinebreakText( text, colWidth, GetTextSize(), GetEffectiveTextPenWidth(),
  250. IsBold(), IsItalic() );
  251. return text;
  252. }
  253. bool SCH_TEXTBOX::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
  254. {
  255. BOX2I rect = GetBoundingBox();
  256. rect.Inflate( aAccuracy );
  257. return rect.Contains( aPosition );
  258. }
  259. bool SCH_TEXTBOX::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
  260. {
  261. BOX2I rect = aRect;
  262. rect.Inflate( aAccuracy );
  263. if( aContained )
  264. return rect.Contains( GetBoundingBox() );
  265. return rect.Intersects( GetBoundingBox() );
  266. }
  267. bool SCH_TEXTBOX::IsHypertext() const
  268. {
  269. if( HasHyperlink() )
  270. return true;
  271. return IsURL( GetShownText( false ) );
  272. }
  273. void SCH_TEXTBOX::DoHypertextAction( EDA_DRAW_FRAME* aFrame ) const
  274. {
  275. wxCHECK_MSG( IsHypertext(), /* void */,
  276. wxT( "Calling a hypertext menu on a SCH_TEXTBOX with no hyperlink?" ) );
  277. SCH_NAVIGATE_TOOL* navTool = aFrame->GetToolManager()->GetTool<SCH_NAVIGATE_TOOL>();
  278. if( HasHyperlink() )
  279. navTool->HypertextCommand( m_hyperlink );
  280. else
  281. navTool->HypertextCommand( GetShownText( false ) );
  282. }
  283. wxString SCH_TEXTBOX::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
  284. {
  285. return wxString::Format( _( "Text Box" ) );
  286. }
  287. BITMAPS SCH_TEXTBOX::GetMenuImage() const
  288. {
  289. return BITMAPS::add_textbox;
  290. }
  291. void SCH_TEXTBOX::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
  292. int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
  293. {
  294. if( IsPrivate() )
  295. return;
  296. SCH_SHAPE::Plot( aPlotter, aBackground, aPlotOpts, aUnit, aBodyStyle, aOffset, aDimmed );
  297. if( aBackground )
  298. return;
  299. SCH_SHEET_PATH* sheet = Schematic() ? &Schematic()->CurrentSheet() : nullptr;
  300. SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
  301. int penWidth = GetEffectivePenWidth( renderSettings );
  302. COLOR4D color = GetStroke().GetColor();
  303. COLOR4D bg = renderSettings->GetBackgroundColor();
  304. KIFONT::FONT* font = getDrawFont();
  305. color = GetTextColor();
  306. if( !aPlotter->GetColorMode() || color == COLOR4D::UNSPECIFIED )
  307. color = renderSettings->GetLayerColor( m_layer );
  308. if( bg == COLOR4D::UNSPECIFIED || !aPlotter->GetColorMode() )
  309. bg = COLOR4D::WHITE;
  310. if( aDimmed )
  311. {
  312. color.Desaturate( );
  313. color = color.Mix( bg, 0.5f );
  314. }
  315. penWidth = GetEffectiveTextPenWidth( renderSettings->GetDefaultPenWidth() );
  316. penWidth = std::max( penWidth, renderSettings->GetMinPenWidth() );
  317. aPlotter->SetCurrentLineWidth( penWidth );
  318. TEXT_ATTRIBUTES attrs;
  319. std::vector<VECTOR2I> positions;
  320. wxArrayString strings_list;
  321. wxStringSplit( GetShownText( sheet, true ), strings_list, '\n' );
  322. positions.reserve( strings_list.Count() );
  323. if( renderSettings->m_Transform != TRANSFORM() || aOffset != VECTOR2I() )
  324. {
  325. SCH_TEXTBOX temp( *this );
  326. if( renderSettings->m_Transform.y1 )
  327. {
  328. temp.SetTextAngle( temp.GetTextAngle() == ANGLE_HORIZONTAL ? ANGLE_VERTICAL
  329. : ANGLE_HORIZONTAL );
  330. }
  331. temp.SetStart( renderSettings->TransformCoordinate( m_start ) + aOffset );
  332. temp.SetEnd( renderSettings->TransformCoordinate( m_end ) + aOffset );
  333. attrs = temp.GetAttributes();
  334. temp.GetLinePositions( positions, (int) strings_list.Count() );
  335. }
  336. else
  337. {
  338. attrs = GetAttributes();
  339. GetLinePositions( positions, (int) strings_list.Count() );
  340. }
  341. attrs.m_StrokeWidth = penWidth;
  342. attrs.m_Multiline = false;
  343. for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
  344. {
  345. aPlotter->PlotText( positions[ii], color, strings_list.Item( ii ), attrs, font,
  346. GetFontMetrics() );
  347. }
  348. if( HasHyperlink() )
  349. aPlotter->HyperlinkBox( GetBoundingBox(), GetHyperlink() );
  350. }
  351. void SCH_TEXTBOX::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  352. {
  353. // Don't use GetShownText() here; we want to show the user the variable references
  354. aList.emplace_back( _( "Text Box" ), KIUI::EllipsizeStatusText( aFrame, GetText() ) );
  355. if( m_excludedFromSim )
  356. aList.emplace_back( _( "Exclude from" ), _( "Simulation" ) );
  357. aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
  358. wxString textStyle[] = { _( "Normal" ), _( "Italic" ), _( "Bold" ), _( "Bold Italic" ) };
  359. int style = IsBold() && IsItalic() ? 3 : IsBold() ? 2 : IsItalic() ? 1 : 0;
  360. aList.emplace_back( _( "Style" ), textStyle[style] );
  361. aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
  362. aList.emplace_back( _( "Box Width" ),
  363. aFrame->MessageTextFromValue( std::abs( GetEnd().x - GetStart().x ) ) );
  364. aList.emplace_back( _( "Box Height" ),
  365. aFrame->MessageTextFromValue( std::abs( GetEnd().y - GetStart().y ) ) );
  366. m_stroke.GetMsgPanelInfo( aFrame, aList );
  367. }
  368. bool SCH_TEXTBOX::operator==( const SCH_ITEM& aOther ) const
  369. {
  370. if( Type() != aOther.Type() )
  371. return false;
  372. const SCH_TEXTBOX& other = static_cast<const SCH_TEXTBOX&>( aOther );
  373. if( m_excludedFromSim != other.m_excludedFromSim )
  374. return false;
  375. if( GetMarginLeft() != other.GetMarginLeft() )
  376. return false;
  377. if( GetMarginTop() != other.GetMarginTop() )
  378. return false;
  379. if( GetMarginRight() != other.GetMarginRight() )
  380. return false;
  381. if( GetMarginBottom() != other.GetMarginBottom() )
  382. return false;
  383. return SCH_SHAPE::operator==( aOther ) && EDA_TEXT::operator==( other );
  384. }
  385. double SCH_TEXTBOX::Similarity( const SCH_ITEM& aOther ) const
  386. {
  387. if( m_Uuid == aOther.m_Uuid )
  388. return 1.0;
  389. if( aOther.Type() != Type() )
  390. return 0.0;
  391. auto other = static_cast<const SCH_TEXTBOX&>( aOther );
  392. double similarity = SimilarityBase( other );
  393. if( m_excludedFromSim != other.m_excludedFromSim )
  394. similarity *= 0.9;
  395. if( GetMarginLeft() != other.GetMarginLeft() )
  396. similarity *= 0.9;
  397. if( GetMarginTop() != other.GetMarginTop() )
  398. similarity *= 0.9;
  399. if( GetMarginRight() != other.GetMarginRight() )
  400. similarity *= 0.9;
  401. if( GetMarginBottom() != other.GetMarginBottom() )
  402. similarity *= 0.9;
  403. similarity *= SCH_SHAPE::Similarity( aOther );
  404. similarity *= EDA_TEXT::Similarity( other );
  405. return similarity;
  406. }
  407. int SCH_TEXTBOX::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
  408. {
  409. wxASSERT( aOther.Type() == SCH_TEXTBOX_T );
  410. int retv = SCH_SHAPE::compare( aOther, aCompareFlags );
  411. if( retv )
  412. return retv;
  413. const SCH_TEXTBOX* tmp = static_cast<const SCH_TEXTBOX*>( &aOther );
  414. int result = GetText().CmpNoCase( tmp->GetText() );
  415. if( result != 0 )
  416. return result;
  417. if( GetTextWidth() != tmp->GetTextWidth() )
  418. return GetTextWidth() - tmp->GetTextWidth();
  419. if( GetTextHeight() != tmp->GetTextHeight() )
  420. return GetTextHeight() - tmp->GetTextHeight();
  421. if( IsBold() != tmp->IsBold() )
  422. return IsBold() - tmp->IsBold();
  423. if( IsItalic() != tmp->IsItalic() )
  424. return IsItalic() - tmp->IsItalic();
  425. if( GetHorizJustify() != tmp->GetHorizJustify() )
  426. return GetHorizJustify() - tmp->GetHorizJustify();
  427. if( GetTextAngle().AsTenthsOfADegree() != tmp->GetTextAngle().AsTenthsOfADegree() )
  428. return GetTextAngle().AsTenthsOfADegree() - tmp->GetTextAngle().AsTenthsOfADegree();
  429. if( GetMarginLeft() != tmp->GetMarginLeft() )
  430. return GetMarginLeft() - tmp->GetMarginLeft();
  431. if( GetMarginTop() != tmp->GetMarginTop() )
  432. return GetMarginTop() - tmp->GetMarginTop();
  433. if( GetMarginRight() != tmp->GetMarginRight() )
  434. return GetMarginRight() - tmp->GetMarginRight();
  435. if( GetMarginBottom() != tmp->GetMarginBottom() )
  436. return GetMarginBottom() - tmp->GetMarginBottom();
  437. return 0;
  438. }
  439. static struct SCH_TEXTBOX_DESC
  440. {
  441. SCH_TEXTBOX_DESC()
  442. {
  443. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  444. REGISTER_TYPE( SCH_TEXTBOX );
  445. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, SCH_SHAPE> );
  446. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, EDA_SHAPE> );
  447. propMgr.AddTypeCast( new TYPE_CAST<SCH_TEXTBOX, EDA_TEXT> );
  448. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( SCH_SHAPE ) );
  449. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ) );
  450. propMgr.InheritsAfter( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ) );
  451. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_SHAPE ), _HKI( "Shape" ) );
  452. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Width" ) );
  453. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Height" ) );
  454. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Thickness" ) );
  455. const wxString marginProps = _( "Margins" );
  456. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Left" ),
  457. &SCH_TEXTBOX::SetMarginLeft, &SCH_TEXTBOX::GetMarginLeft,
  458. PROPERTY_DISPLAY::PT_SIZE ),
  459. marginProps );
  460. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Top" ),
  461. &SCH_TEXTBOX::SetMarginTop, &SCH_TEXTBOX::GetMarginTop,
  462. PROPERTY_DISPLAY::PT_SIZE ),
  463. marginProps );
  464. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Right" ),
  465. &SCH_TEXTBOX::SetMarginRight, &SCH_TEXTBOX::GetMarginRight,
  466. PROPERTY_DISPLAY::PT_SIZE ),
  467. marginProps );
  468. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Margin Bottom" ),
  469. &SCH_TEXTBOX::SetMarginBottom, &SCH_TEXTBOX::GetMarginBottom,
  470. PROPERTY_DISPLAY::PT_SIZE ),
  471. marginProps );
  472. propMgr.AddProperty( new PROPERTY<SCH_TEXTBOX, int>( _HKI( "Text Size" ),
  473. &SCH_TEXTBOX::SetSchTextSize, &SCH_TEXTBOX::GetSchTextSize,
  474. PROPERTY_DISPLAY::PT_SIZE ),
  475. _HKI( "Text Properties" ) );
  476. propMgr.Mask( TYPE_HASH( SCH_TEXTBOX ), TYPE_HASH( EDA_TEXT ), _HKI( "Orientation" ) );
  477. }
  478. } _SCH_TEXTBOX_DESC;