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.

472 lines
14 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2004-2022 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 <common.h>
  24. #include <sch_draw_panel.h>
  25. #include <plotters/plotter.h>
  26. #include <trigo.h>
  27. #include <base_units.h>
  28. #include <widgets/msgpanel.h>
  29. #include <bitmaps.h>
  30. #include <eda_draw_frame.h>
  31. #include <lib_item.h>
  32. #include <general.h>
  33. #include <transform.h>
  34. #include <settings/color_settings.h>
  35. #include <lib_text.h>
  36. #include <default_values.h> // For some default values
  37. #include <string_utils.h>
  38. LIB_TEXT::LIB_TEXT( LIB_SYMBOL* aParent ) :
  39. LIB_ITEM( LIB_TEXT_T, aParent ),
  40. EDA_TEXT( schIUScale, wxEmptyString )
  41. {
  42. SetTextSize( wxSize( schIUScale.MilsToIU( DEFAULT_TEXT_SIZE ), schIUScale.MilsToIU( DEFAULT_TEXT_SIZE ) ) );
  43. }
  44. void LIB_TEXT::ViewGetLayers( int aLayers[], int& aCount ) const
  45. {
  46. aCount = 2;
  47. aLayers[0] = IsPrivate() ? LAYER_PRIVATE_NOTES : LAYER_DEVICE;
  48. aLayers[1] = LAYER_SELECTION_SHADOWS;
  49. }
  50. bool LIB_TEXT::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
  51. {
  52. EDA_TEXT tmp_text( *this );
  53. tmp_text.SetTextPos( DefaultTransform.TransformCoordinate( GetTextPos() ) );
  54. /* The text orientation may need to be flipped if the
  55. * transformation matrix causes xy axes to be flipped.
  56. * this simple algo works only for schematic matrix (rot 90 or/and mirror)
  57. */
  58. bool t1 = ( DefaultTransform.x1 != 0 ) ^ ( GetTextAngle() != ANGLE_HORIZONTAL );
  59. tmp_text.SetTextAngle( t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL );
  60. return tmp_text.TextHitTest( aPosition, aAccuracy );
  61. }
  62. EDA_ITEM* LIB_TEXT::Clone() const
  63. {
  64. LIB_TEXT* newitem = new LIB_TEXT( nullptr );
  65. newitem->m_parent = m_parent;
  66. newitem->m_unit = m_unit;
  67. newitem->m_convert = m_convert;
  68. newitem->m_private = m_private;
  69. newitem->m_flags = m_flags;
  70. newitem->SetText( GetText() );
  71. newitem->SetAttributes( *this );
  72. return newitem;
  73. }
  74. int LIB_TEXT::compare( const LIB_ITEM& aOther, int aCompareFlags ) const
  75. {
  76. wxASSERT( aOther.Type() == LIB_TEXT_T );
  77. int retv = LIB_ITEM::compare( aOther, aCompareFlags );
  78. if( retv )
  79. return retv;
  80. const LIB_TEXT* tmp = ( LIB_TEXT* ) &aOther;
  81. int result = GetText().CmpNoCase( tmp->GetText() );
  82. if( result != 0 )
  83. return result;
  84. if( GetTextPos().x != tmp->GetTextPos().x )
  85. return GetTextPos().x - tmp->GetTextPos().x;
  86. if( GetTextPos().y != tmp->GetTextPos().y )
  87. return GetTextPos().y - tmp->GetTextPos().y;
  88. if( GetTextWidth() != tmp->GetTextWidth() )
  89. return GetTextWidth() - tmp->GetTextWidth();
  90. if( GetTextHeight() != tmp->GetTextHeight() )
  91. return GetTextHeight() - tmp->GetTextHeight();
  92. return 0;
  93. }
  94. void LIB_TEXT::Offset( const VECTOR2I& aOffset )
  95. {
  96. EDA_TEXT::Offset( aOffset );
  97. }
  98. void LIB_TEXT::MoveTo( const VECTOR2I& newPosition )
  99. {
  100. SetTextPos( newPosition );
  101. }
  102. void LIB_TEXT::NormalizeJustification( bool inverse )
  103. {
  104. VECTOR2I delta( 0, 0 );
  105. BOX2I bbox = GetTextBox();
  106. if( GetTextAngle().IsHorizontal() )
  107. {
  108. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  109. delta.x = bbox.GetWidth() / 2;
  110. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  111. delta.x = - bbox.GetWidth() / 2;
  112. if( GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
  113. delta.y = - bbox.GetHeight() / 2;
  114. else if( GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
  115. delta.y = bbox.GetHeight() / 2;
  116. }
  117. else
  118. {
  119. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  120. delta.y = bbox.GetWidth() / 2;
  121. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  122. delta.y = - bbox.GetWidth() / 2;
  123. if( GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
  124. delta.x = + bbox.GetHeight() / 2;
  125. else if( GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
  126. delta.x = - bbox.GetHeight() / 2;
  127. }
  128. if( inverse )
  129. SetTextPos( GetTextPos() - delta );
  130. else
  131. SetTextPos( GetTextPos() + delta );
  132. }
  133. void LIB_TEXT::MirrorHorizontal( const VECTOR2I& center )
  134. {
  135. NormalizeJustification( false );
  136. int x = GetTextPos().x;
  137. x -= center.x;
  138. x *= -1;
  139. x += center.x;
  140. if( GetTextAngle().IsHorizontal() )
  141. {
  142. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  143. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  144. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  145. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  146. }
  147. else
  148. {
  149. if( GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
  150. SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  151. else if( GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
  152. SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  153. }
  154. SetTextX( x );
  155. NormalizeJustification( true );
  156. }
  157. void LIB_TEXT::MirrorVertical( const VECTOR2I& center )
  158. {
  159. NormalizeJustification( false );
  160. int y = GetTextPos().y;
  161. y -= center.y;
  162. y *= -1;
  163. y += center.y;
  164. if( GetTextAngle().IsHorizontal() )
  165. {
  166. if( GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
  167. SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  168. else if( GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
  169. SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  170. }
  171. else
  172. {
  173. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  174. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  175. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  176. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  177. }
  178. SetTextY( y );
  179. NormalizeJustification( true );
  180. }
  181. void LIB_TEXT::Rotate( const VECTOR2I& center, bool aRotateCCW )
  182. {
  183. NormalizeJustification( false );
  184. EDA_ANGLE rot_angle = aRotateCCW ? -ANGLE_90 : ANGLE_90;
  185. VECTOR2I pt = GetTextPos();
  186. RotatePoint( pt, center, rot_angle );
  187. SetTextPos( pt );
  188. if( GetTextAngle().IsHorizontal() )
  189. {
  190. SetTextAngle( ANGLE_VERTICAL );
  191. }
  192. else
  193. {
  194. // 180° rotation is a mirror
  195. if( GetHorizJustify() == GR_TEXT_H_ALIGN_LEFT )
  196. SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
  197. else if( GetHorizJustify() == GR_TEXT_H_ALIGN_RIGHT )
  198. SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
  199. if( GetVertJustify() == GR_TEXT_V_ALIGN_TOP )
  200. SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
  201. else if( GetVertJustify() == GR_TEXT_V_ALIGN_BOTTOM )
  202. SetVertJustify( GR_TEXT_V_ALIGN_TOP );
  203. SetTextAngle( ANGLE_0 );
  204. }
  205. NormalizeJustification( true );
  206. }
  207. void LIB_TEXT::Plot( PLOTTER* plotter, bool aBackground, const VECTOR2I& offset,
  208. const TRANSFORM& aTransform, bool aDimmed ) const
  209. {
  210. wxASSERT( plotter != nullptr );
  211. if( IsPrivate() )
  212. return;
  213. if( aBackground )
  214. return;
  215. RENDER_SETTINGS* settings = plotter->RenderSettings();
  216. BOX2I bBox = GetBoundingBox();
  217. // convert coordinates from draw Y axis to symbol_editor Y axis
  218. bBox.RevertYAxis();
  219. VECTOR2I txtpos = bBox.Centre();
  220. // The text orientation may need to be flipped if the transformation matrix causes xy
  221. // axes to be flipped.
  222. int t1 = ( aTransform.x1 != 0 ) ^ ( GetTextAngle() != ANGLE_HORIZONTAL );
  223. VECTOR2I pos = aTransform.TransformCoordinate( txtpos ) + offset;
  224. COLOR4D color = GetTextColor();
  225. COLOR4D bg = settings->GetBackgroundColor();
  226. if( !plotter->GetColorMode() || color == COLOR4D::UNSPECIFIED )
  227. color = settings->GetLayerColor( LAYER_DEVICE );
  228. if( !IsVisible() )
  229. bg = settings->GetLayerColor( LAYER_HIDDEN );
  230. else if( bg == COLOR4D::UNSPECIFIED || !plotter->GetColorMode() )
  231. bg = COLOR4D::WHITE;
  232. if( aDimmed )
  233. color = color.Mix( bg, 0.5f );
  234. int penWidth = std::max( GetEffectiveTextPenWidth(), settings->GetMinPenWidth() );
  235. KIFONT::FONT* font = GetFont();
  236. if( !font )
  237. font = KIFONT::FONT::GetFont( settings->GetDefaultFont(), IsBold(), IsItalic() );
  238. plotter->Text( pos, color, GetText(), t1 ? ANGLE_HORIZONTAL : ANGLE_VERTICAL, GetTextSize(),
  239. GR_TEXT_H_ALIGN_CENTER, GR_TEXT_V_ALIGN_CENTER, penWidth, IsItalic(), IsBold(),
  240. true, font );
  241. }
  242. int LIB_TEXT::GetPenWidth() const
  243. {
  244. return GetEffectiveTextPenWidth();
  245. }
  246. KIFONT::FONT* LIB_TEXT::getDrawFont() const
  247. {
  248. KIFONT::FONT* font = EDA_TEXT::GetFont();
  249. if( !font )
  250. font = KIFONT::FONT::GetFont( GetDefaultFont(), IsBold(), IsItalic() );
  251. return font;
  252. }
  253. void LIB_TEXT::print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset, void* aData,
  254. const TRANSFORM& aTransform, bool aDimmed )
  255. {
  256. wxDC* DC = aSettings->GetPrintDC();
  257. COLOR4D color = GetTextColor();
  258. bool blackAndWhiteMode = GetGRForceBlackPenState();
  259. int penWidth = std::max( GetEffectiveTextPenWidth(), aSettings->GetDefaultPenWidth() );
  260. if( blackAndWhiteMode || color == COLOR4D::UNSPECIFIED )
  261. color = aSettings->GetLayerColor( LAYER_DEVICE );
  262. COLOR4D bg = aSettings->GetBackgroundColor();
  263. if( bg == COLOR4D::UNSPECIFIED || GetGRForceBlackPenState() )
  264. bg = COLOR4D::WHITE;
  265. if( !IsVisible() )
  266. bg = aSettings->GetLayerColor( LAYER_HIDDEN );
  267. if( aDimmed )
  268. color = color.Mix( bg, 0.5f );
  269. // Calculate the text orientation, according to the symbol orientation/mirror (needed when
  270. // draw text in schematic)
  271. EDA_ANGLE orient = GetTextAngle();
  272. if( aTransform.y1 ) // Rotate symbol 90 degrees.
  273. {
  274. if( orient == ANGLE_HORIZONTAL )
  275. orient = ANGLE_VERTICAL;
  276. else
  277. orient = ANGLE_HORIZONTAL;
  278. }
  279. KIFONT::FONT* font = GetFont();
  280. if( !font )
  281. font = KIFONT::FONT::GetFont( aSettings->GetDefaultFont(), IsBold(), IsItalic() );
  282. /*
  283. * Calculate the text justification, according to the symbol orientation/mirror.
  284. * This is a bit complicated due to cumulative calculations:
  285. * - numerous cases (mirrored or not, rotation)
  286. * - the GRText function will also recalculate H and V justifications according to the text
  287. * orientation.
  288. * - When a symbol is mirrored, the text is not mirrored and justifications are complicated
  289. * to calculate so the more easily way is to use no justifications (centered text) and
  290. * use GetBoundingBox to know the text coordinate considered as centered
  291. */
  292. BOX2I bBox = GetBoundingBox();
  293. // convert coordinates from draw Y axis to symbol_editor Y axis:
  294. bBox.RevertYAxis();
  295. VECTOR2I txtpos = bBox.Centre();
  296. // Calculate pos according to mirror/rotation.
  297. txtpos = aTransform.TransformCoordinate( txtpos ) + aOffset;
  298. GRPrintText( DC, txtpos, color, GetShownText(), orient, GetTextSize(), GR_TEXT_H_ALIGN_CENTER,
  299. GR_TEXT_V_ALIGN_CENTER, penWidth, IsItalic(), IsBold(), font );
  300. }
  301. void LIB_TEXT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
  302. {
  303. wxString msg;
  304. LIB_ITEM::GetMsgPanelInfo( aFrame, aList );
  305. // Don't use GetShownText() here; we want to show the user the variable references
  306. aList.emplace_back( _( "Text" ), UnescapeString( GetText() ) );
  307. aList.emplace_back( _( "Font" ), GetFont() ? GetFont()->GetName() : _( "Default" ) );
  308. aList.emplace_back( _( "Style" ), GetTextStyleName() );
  309. aList.emplace_back( _( "Text Size" ), aFrame->MessageTextFromValue( GetTextWidth() ) );
  310. switch ( GetHorizJustify() )
  311. {
  312. case GR_TEXT_H_ALIGN_LEFT: msg = _( "Left" ); break;
  313. case GR_TEXT_H_ALIGN_CENTER: msg = _( "Center" ); break;
  314. case GR_TEXT_H_ALIGN_RIGHT: msg = _( "Right" ); break;
  315. }
  316. aList.emplace_back( _( "H Justification" ), msg );
  317. switch ( GetVertJustify() )
  318. {
  319. case GR_TEXT_V_ALIGN_TOP: msg = _( "Top" ); break;
  320. case GR_TEXT_V_ALIGN_CENTER: msg = _( "Center" ); break;
  321. case GR_TEXT_V_ALIGN_BOTTOM: msg = _( "Bottom" ); break;
  322. }
  323. aList.emplace_back( _( "V Justification" ), msg );
  324. }
  325. const BOX2I LIB_TEXT::GetBoundingBox() const
  326. {
  327. /* Y coordinates for LIB_ITEMS are bottom to top, so we must invert the Y position when
  328. * calling GetTextBox() that works using top to bottom Y axis orientation.
  329. */
  330. BOX2I bbox = GetTextBox( -1, true );
  331. bbox.RevertYAxis();
  332. // We are using now a bottom to top Y axis.
  333. VECTOR2I orig = bbox.GetOrigin();
  334. VECTOR2I end = bbox.GetEnd();
  335. RotatePoint( orig, GetTextPos(), -GetTextAngle() );
  336. RotatePoint( end, GetTextPos(), -GetTextAngle() );
  337. bbox.SetOrigin( orig );
  338. bbox.SetEnd( end );
  339. // We are using now a top to bottom Y axis:
  340. bbox.RevertYAxis();
  341. return bbox;
  342. }
  343. wxString LIB_TEXT::GetSelectMenuText( UNITS_PROVIDER* aUnitsProvider ) const
  344. {
  345. return wxString::Format( _( "Graphic Text '%s'" ), KIUI::EllipsizeMenuText( GetShownText() ) );
  346. }
  347. BITMAPS LIB_TEXT::GetMenuImage() const
  348. {
  349. return BITMAPS::text;
  350. }
  351. void LIB_TEXT::BeginEdit( const VECTOR2I& aPosition )
  352. {
  353. SetTextPos( aPosition );
  354. }
  355. void LIB_TEXT::CalcEdit( const VECTOR2I& aPosition )
  356. {
  357. SetTextPos( aPosition );
  358. }