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.

777 lines
21 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
  5. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /*
  25. * the class DS_DATA_ITEM (and derived) defines
  26. * a basic shape of a drawing sheet (frame references and title block)
  27. * Basic shapes are line, rect and texts
  28. * the DS_DATA_ITEM coordinates units is the mm, and are relative to
  29. * one of 4 page corners.
  30. *
  31. * These items cannot be drawn or plot "as this". they should be converted
  32. * to a "draw list" (DS_DRAW_ITEM_BASE and derived items)
  33. * The list of these items is stored in a DS_DATA_MODEL instance.
  34. *
  35. * When building the draw list:
  36. * the DS_DATA_MODEL is used to create a DS_DRAW_ITEM_LIST
  37. * coordinates are converted to draw/plot coordinates.
  38. * texts are expanded if they contain format symbols.
  39. * Items with m_RepeatCount > 1 are created m_RepeatCount times
  40. *
  41. * the DS_DATA_MODEL is created only once.
  42. * the DS_DRAW_ITEM_LIST is created each time the drawing sheet is plotted/drawn
  43. *
  44. * the DS_DATA_MODEL instance is created from a S expression which
  45. * describes the drawing sheet (can be the default drawing sheet or a custom file).
  46. */
  47. #include <gr_text.h>
  48. #include <eda_rect.h>
  49. #include <math/util.h> // for KiROUND
  50. #include <view/view.h>
  51. #include <title_block.h>
  52. #include <drawing_sheet/ds_data_model.h>
  53. #include <drawing_sheet/ds_data_item.h>
  54. #include <drawing_sheet/ds_draw_item.h>
  55. #include <drawing_sheet/ds_painter.h>
  56. #include <trigo.h>
  57. using KIGFX::COLOR4D;
  58. DS_DATA_ITEM::DS_DATA_ITEM( DS_ITEM_TYPE aType )
  59. {
  60. m_pageOption = ALL_PAGES;
  61. m_type = aType;
  62. m_RepeatCount = 1;
  63. m_IncrementLabel = 1;
  64. m_LineWidth = 0;
  65. }
  66. DS_DATA_ITEM::~DS_DATA_ITEM()
  67. {
  68. for( DS_DRAW_ITEM_BASE* item : m_drawItems )
  69. delete item;
  70. }
  71. void DS_DATA_ITEM::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
  72. {
  73. int pensize = GetPenSizeUi();
  74. if( pensize == 0 )
  75. pensize = aCollector ? aCollector->GetDefaultPenSize() : 0;
  76. std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
  77. DS_DRAW_ITEM_BASE* item = nullptr;
  78. for( size_t i = 0; i < m_drawItems.size(); ++i )
  79. {
  80. item = m_drawItems[ i ];
  81. itemFlags[ i ] = item->GetFlags();
  82. if( aCollector )
  83. aCollector->Remove( item );
  84. if( aView )
  85. aView->Remove( item );
  86. delete item;
  87. }
  88. m_drawItems.clear();
  89. for( int j = 0; j < m_RepeatCount; j++ )
  90. {
  91. if( j && ! IsInsidePage( j ) )
  92. continue;
  93. if( m_type == DS_SEGMENT )
  94. item = new DS_DRAW_ITEM_LINE( this, j, GetStartPosUi( j ), GetEndPosUi( j ), pensize );
  95. else if( m_type == DS_RECT )
  96. item = new DS_DRAW_ITEM_RECT( this, j, GetStartPosUi( j ), GetEndPosUi( j ), pensize );
  97. else
  98. {
  99. wxFAIL_MSG( "Unknown drawing sheet item type" );
  100. continue;
  101. }
  102. item->SetFlags( itemFlags[ j ] );
  103. m_drawItems.push_back( item );
  104. if( aCollector )
  105. aCollector->Append( item );
  106. if( aView )
  107. aView->Add( item );
  108. }
  109. }
  110. int DS_DATA_ITEM::GetPenSizeUi()
  111. {
  112. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  113. if( m_LineWidth != 0 )
  114. return KiROUND( m_LineWidth * model.m_WSunits2Iu );
  115. else
  116. return KiROUND( model.m_DefaultLineWidth * model.m_WSunits2Iu );
  117. }
  118. void DS_DATA_ITEM::MoveToUi( const VECTOR2I& aPosition )
  119. {
  120. VECTOR2D pos_mm;
  121. pos_mm.x = aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  122. pos_mm.y = aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  123. MoveTo( pos_mm );
  124. }
  125. void DS_DATA_ITEM::MoveTo( const VECTOR2D& aPosition )
  126. {
  127. VECTOR2D vector = aPosition - GetStartPos();
  128. VECTOR2D endpos = vector + GetEndPos();
  129. MoveStartPointTo( aPosition );
  130. MoveEndPointTo( endpos );
  131. for( DS_DRAW_ITEM_BASE* drawItem : m_drawItems )
  132. {
  133. drawItem->SetPosition( GetStartPosUi( drawItem->GetIndexInPeer() ) );
  134. drawItem->SetEnd( GetEndPosUi( drawItem->GetIndexInPeer() ) );
  135. }
  136. }
  137. void DS_DATA_ITEM::MoveStartPointTo( const VECTOR2D& aPosition )
  138. {
  139. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  140. VECTOR2D position;
  141. // Calculate the position of the starting point
  142. // relative to the reference corner
  143. // aPosition is the position relative to the right top paper corner
  144. switch( m_Pos.m_Anchor )
  145. {
  146. case RB_CORNER:
  147. position = model.m_RB_Corner - aPosition;
  148. break;
  149. case RT_CORNER:
  150. position.x = model.m_RB_Corner.x - aPosition.x;
  151. position.y = aPosition.y - model.m_LT_Corner.y;
  152. break;
  153. case LB_CORNER:
  154. position.x = aPosition.x - model.m_LT_Corner.x;
  155. position.y = model.m_RB_Corner.y - aPosition.y;
  156. break;
  157. case LT_CORNER:
  158. position = aPosition - model.m_LT_Corner;
  159. break;
  160. }
  161. m_Pos.m_Pos = position;
  162. }
  163. void DS_DATA_ITEM::MoveStartPointToUi( const VECTOR2I& aPosition )
  164. {
  165. VECTOR2D pos_mm( aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu,
  166. aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
  167. MoveStartPointTo( pos_mm );
  168. }
  169. void DS_DATA_ITEM::MoveEndPointTo( const VECTOR2D& aPosition )
  170. {
  171. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  172. VECTOR2D position;
  173. // Calculate the position of the starting point
  174. // relative to the reference corner
  175. // aPosition is the position relative to the right top paper corner
  176. switch( m_End.m_Anchor )
  177. {
  178. case RB_CORNER:
  179. position = model.m_RB_Corner - aPosition;
  180. break;
  181. case RT_CORNER:
  182. position.x = model.m_RB_Corner.x - aPosition.x;
  183. position.y = aPosition.y - model.m_LT_Corner.y;
  184. break;
  185. case LB_CORNER:
  186. position.x = aPosition.x - model.m_LT_Corner.x;
  187. position.y = model.m_RB_Corner.y - aPosition.y;
  188. break;
  189. case LT_CORNER:
  190. position = aPosition - model.m_LT_Corner;
  191. break;
  192. }
  193. // Modify m_End only for items having 2 coordinates
  194. switch( GetType() )
  195. {
  196. case DS_SEGMENT:
  197. case DS_RECT:
  198. m_End.m_Pos = position;
  199. break;
  200. default:
  201. break;
  202. }
  203. }
  204. void DS_DATA_ITEM::MoveEndPointToUi( const VECTOR2I& aPosition )
  205. {
  206. VECTOR2D pos_mm;
  207. pos_mm.x = aPosition.x / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  208. pos_mm.y = aPosition.y / DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  209. MoveEndPointTo( pos_mm );
  210. }
  211. const VECTOR2D DS_DATA_ITEM::GetStartPos( int ii ) const
  212. {
  213. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  214. VECTOR2D pos( m_Pos.m_Pos.x + ( m_IncrementVector.x * ii ),
  215. m_Pos.m_Pos.y + ( m_IncrementVector.y * ii ) );
  216. switch( m_Pos.m_Anchor )
  217. {
  218. case RB_CORNER: // right bottom corner
  219. pos = model.m_RB_Corner - pos;
  220. break;
  221. case RT_CORNER: // right top corner
  222. pos.x = model.m_RB_Corner.x - pos.x;
  223. pos.y = model.m_LT_Corner.y + pos.y;
  224. break;
  225. case LB_CORNER: // left bottom corner
  226. pos.x = model.m_LT_Corner.x + pos.x;
  227. pos.y = model.m_RB_Corner.y - pos.y;
  228. break;
  229. case LT_CORNER: // left top corner
  230. pos = model.m_LT_Corner + pos;
  231. break;
  232. }
  233. return pos;
  234. }
  235. const VECTOR2I DS_DATA_ITEM::GetStartPosUi( int ii ) const
  236. {
  237. VECTOR2D pos = GetStartPos( ii ) * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  238. return VECTOR2I( KiROUND( pos.x ), KiROUND( pos.y ) );
  239. }
  240. const VECTOR2D DS_DATA_ITEM::GetEndPos( int ii ) const
  241. {
  242. VECTOR2D pos( m_End.m_Pos.x + ( m_IncrementVector.x * ii ),
  243. m_End.m_Pos.y + ( m_IncrementVector.y * ii ) );
  244. switch( m_End.m_Anchor )
  245. {
  246. case RB_CORNER: // right bottom corner
  247. pos = DS_DATA_MODEL::GetTheInstance().m_RB_Corner - pos;
  248. break;
  249. case RT_CORNER: // right top corner
  250. pos.x = DS_DATA_MODEL::GetTheInstance().m_RB_Corner.x - pos.x;
  251. pos.y = DS_DATA_MODEL::GetTheInstance().m_LT_Corner.y + pos.y;
  252. break;
  253. case LB_CORNER: // left bottom corner
  254. pos.x = DS_DATA_MODEL::GetTheInstance().m_LT_Corner.x + pos.x;
  255. pos.y = DS_DATA_MODEL::GetTheInstance().m_RB_Corner.y - pos.y;
  256. break;
  257. case LT_CORNER: // left top corner
  258. pos = DS_DATA_MODEL::GetTheInstance().m_LT_Corner + pos;
  259. break;
  260. }
  261. return pos;
  262. }
  263. const VECTOR2I DS_DATA_ITEM::GetEndPosUi( int ii ) const
  264. {
  265. VECTOR2D pos = GetEndPos( ii );
  266. pos = pos * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  267. return VECTOR2I( KiROUND( pos.x ), KiROUND( pos.y ) );
  268. }
  269. bool DS_DATA_ITEM::IsInsidePage( int ii ) const
  270. {
  271. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  272. VECTOR2D pos = GetStartPos( ii );
  273. for( int kk = 0; kk < 1; kk++ )
  274. {
  275. if( model.m_RB_Corner.x < pos.x || model.m_LT_Corner.x > pos.x )
  276. return false;
  277. if( model.m_RB_Corner.y < pos.y || model.m_LT_Corner.y > pos.y )
  278. return false;
  279. pos = GetEndPos( ii );
  280. }
  281. return true;
  282. }
  283. const wxString DS_DATA_ITEM::GetClassName() const
  284. {
  285. wxString name;
  286. switch( GetType() )
  287. {
  288. case DS_TEXT: name = _( "Text" ); break;
  289. case DS_SEGMENT: name = _( "Line" ); break;
  290. case DS_RECT: name = _( "Rectangle" ); break;
  291. case DS_POLYPOLYGON: name = _( "Imported Shape" ); break;
  292. case DS_BITMAP: name = _( "Image" ); break;
  293. }
  294. return name;
  295. }
  296. DS_DATA_ITEM_POLYGONS::DS_DATA_ITEM_POLYGONS() :
  297. DS_DATA_ITEM( DS_POLYPOLYGON )
  298. {
  299. }
  300. void DS_DATA_ITEM_POLYGONS::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
  301. {
  302. std::map<int, EDA_ITEM_FLAGS> itemFlags;
  303. DS_DRAW_ITEM_BASE* item = nullptr;
  304. for( size_t i = 0; i < m_drawItems.size(); ++i )
  305. {
  306. item = m_drawItems[ i ];
  307. itemFlags[ i ] = item->GetFlags();
  308. if( aCollector )
  309. aCollector->Remove( item );
  310. if( aView )
  311. aView->Remove( item );
  312. delete item;
  313. }
  314. m_drawItems.clear();
  315. for( int j = 0; j < m_RepeatCount; j++ )
  316. {
  317. if( j && !IsInsidePage( j ) )
  318. continue;
  319. int pensize = GetPenSizeUi();
  320. auto poly_shape = new DS_DRAW_ITEM_POLYPOLYGONS( this, j, GetStartPosUi( j ), pensize );
  321. poly_shape->SetFlags( itemFlags[ j ] );
  322. m_drawItems.push_back( poly_shape );
  323. // Transfer all outlines (basic polygons)
  324. SHAPE_POLY_SET& polygons = poly_shape->GetPolygons();
  325. for( int kk = 0; kk < GetPolyCount(); kk++ )
  326. {
  327. // Create new outline
  328. unsigned ist = GetPolyIndexStart( kk );
  329. unsigned iend = GetPolyIndexEnd( kk );
  330. polygons.NewOutline();
  331. while( ist <= iend )
  332. polygons.Append( GetCornerPositionUi( ist++, j ) );
  333. }
  334. if( aCollector )
  335. aCollector->Append( poly_shape );
  336. if( aView )
  337. aView->Add( poly_shape );
  338. }
  339. }
  340. int DS_DATA_ITEM_POLYGONS::GetPenSizeUi()
  341. {
  342. return KiROUND( m_LineWidth * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
  343. }
  344. const VECTOR2D DS_DATA_ITEM_POLYGONS::GetCornerPosition( unsigned aIdx, int aRepeat ) const
  345. {
  346. VECTOR2D pos = m_Corners[aIdx];
  347. // Rotation:
  348. RotatePoint( &pos.x, &pos.y, m_Orient );
  349. pos += GetStartPos( aRepeat );
  350. return pos;
  351. }
  352. void DS_DATA_ITEM_POLYGONS::SetBoundingBox()
  353. {
  354. if( m_Corners.size() == 0 )
  355. {
  356. m_minCoord.x = m_maxCoord.x = 0.0;
  357. m_minCoord.y = m_maxCoord.y = 0.0;
  358. return;
  359. }
  360. VECTOR2I pos;
  361. pos = m_Corners[0];
  362. RotatePoint( &pos.x, &pos.y, m_Orient );
  363. m_minCoord = m_maxCoord = pos;
  364. for( unsigned ii = 1; ii < m_Corners.size(); ii++ )
  365. {
  366. pos = m_Corners[ii];
  367. RotatePoint( &pos.x, &pos.y, m_Orient );
  368. if( m_minCoord.x > pos.x )
  369. m_minCoord.x = pos.x;
  370. if( m_minCoord.y > pos.y )
  371. m_minCoord.y = pos.y;
  372. if( m_maxCoord.x < pos.x )
  373. m_maxCoord.x = pos.x;
  374. if( m_maxCoord.y < pos.y )
  375. m_maxCoord.y = pos.y;
  376. }
  377. }
  378. bool DS_DATA_ITEM_POLYGONS::IsInsidePage( int ii ) const
  379. {
  380. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  381. VECTOR2D pos = GetStartPos( ii );
  382. pos += m_minCoord; // left top pos of bounding box
  383. if( model.m_LT_Corner.x > pos.x || model.m_LT_Corner.y > pos.y )
  384. return false;
  385. pos = GetStartPos( ii );
  386. pos += m_maxCoord; // right bottom pos of bounding box
  387. if( model.m_RB_Corner.x < pos.x || model.m_RB_Corner.y < pos.y )
  388. return false;
  389. return true;
  390. }
  391. const VECTOR2I DS_DATA_ITEM_POLYGONS::GetCornerPositionUi( unsigned aIdx, int aRepeat ) const
  392. {
  393. VECTOR2D pos = GetCornerPosition( aIdx, aRepeat );
  394. pos = pos * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu;
  395. return VECTOR2I( int( pos.x ), int( pos.y ) );
  396. }
  397. DS_DATA_ITEM_TEXT::DS_DATA_ITEM_TEXT( const wxString& aTextBase ) :
  398. DS_DATA_ITEM( DS_TEXT )
  399. {
  400. m_TextBase = aTextBase;
  401. m_IncrementLabel = 1;
  402. m_Hjustify = GR_TEXT_H_ALIGN_LEFT;
  403. m_Vjustify = GR_TEXT_V_ALIGN_CENTER;
  404. m_Italic = false;
  405. m_Bold = false;
  406. m_Font = nullptr;
  407. m_TextColor = COLOR4D::UNSPECIFIED;
  408. m_Orient = 0.0;
  409. m_LineWidth = 0.0; // 0 means use default value
  410. }
  411. void DS_DATA_ITEM_TEXT::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
  412. {
  413. int pensize = GetPenSizeUi();
  414. bool multilines = false;
  415. if( DS_DATA_MODEL::GetTheInstance().m_EditMode )
  416. {
  417. m_FullText = m_TextBase;
  418. }
  419. else
  420. {
  421. m_FullText = aCollector ? aCollector->BuildFullText( m_TextBase ) : wxString();
  422. multilines = ReplaceAntiSlashSequence();
  423. }
  424. if( pensize == 0 )
  425. pensize = aCollector ? aCollector->GetDefaultPenSize() : 1;
  426. SetConstrainedTextSize();
  427. wxSize textsize;
  428. textsize.x = KiROUND( m_ConstrainedTextSize.x * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
  429. textsize.y = KiROUND( m_ConstrainedTextSize.y * DS_DATA_MODEL::GetTheInstance().m_WSunits2Iu );
  430. if( m_Bold )
  431. pensize = GetPenSizeForBold( std::min( textsize.x, textsize.y ) );
  432. std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
  433. DS_DRAW_ITEM_TEXT* text = nullptr;
  434. for( size_t i = 0; i < m_drawItems.size(); ++i )
  435. {
  436. text = (DS_DRAW_ITEM_TEXT*) m_drawItems[ i ];
  437. itemFlags[ i ] = text->GetFlags();
  438. if( aCollector )
  439. aCollector->Remove( text );
  440. if( aView )
  441. aView->Remove( text );
  442. delete text;
  443. }
  444. m_drawItems.clear();
  445. for( int j = 0; j < m_RepeatCount; ++j )
  446. {
  447. if( j > 0 && !IsInsidePage( j ) )
  448. continue;
  449. text = new DS_DRAW_ITEM_TEXT( this, j, m_FullText, GetStartPosUi( j ), textsize, pensize,
  450. m_Font, m_Italic, m_Bold, m_TextColor );
  451. text->SetFlags( itemFlags[ j ] );
  452. m_drawItems.push_back( text );
  453. if( aCollector )
  454. aCollector->Append( text );
  455. if( aView )
  456. aView->Add( text );
  457. text->SetHorizJustify( m_Hjustify ) ;
  458. text->SetVertJustify( m_Vjustify );
  459. text->SetTextAngle( EDA_ANGLE( m_Orient, DEGREES_T ) );
  460. text->SetMultilineAllowed( multilines );
  461. // Increment label for the next text (has no meaning for multiline texts)
  462. if( m_RepeatCount > 1 && !multilines )
  463. IncrementLabel(( j + 1 ) * m_IncrementLabel );
  464. }
  465. }
  466. int DS_DATA_ITEM_TEXT::GetPenSizeUi()
  467. {
  468. DS_DATA_MODEL& model = DS_DATA_MODEL::GetTheInstance();
  469. if( m_LineWidth != 0 )
  470. return KiROUND( m_LineWidth * model.m_WSunits2Iu );
  471. else
  472. return KiROUND( model.m_DefaultTextThickness * model.m_WSunits2Iu );
  473. }
  474. void DS_DATA_ITEM_TEXT::IncrementLabel( int aIncr )
  475. {
  476. int last = m_TextBase.Len() -1;
  477. wxChar lbchar = m_TextBase[last];
  478. m_FullText = m_TextBase;
  479. m_FullText.RemoveLast();
  480. if( lbchar >= '0' && lbchar <= '9' )
  481. // A number is expected:
  482. m_FullText << (int)( aIncr + lbchar - '0' );
  483. else
  484. m_FullText << (wxChar) ( aIncr + lbchar );
  485. }
  486. // Replace the '\''n' sequence by EOL
  487. // and the sequence '\''\' by only one '\' in m_FullText
  488. // if m_FullText is a multiline text (i.e.contains '\n') return true
  489. bool DS_DATA_ITEM_TEXT::ReplaceAntiSlashSequence()
  490. {
  491. bool multiline = false;
  492. for( unsigned ii = 0; ii < m_FullText.Len(); ii++ )
  493. {
  494. if( m_FullText[ii] == '\n' )
  495. multiline = true;
  496. else if( m_FullText[ii] == '\\' )
  497. {
  498. if( ++ii >= m_FullText.Len() )
  499. break;
  500. if( m_FullText[ii] == '\\' )
  501. {
  502. // a double \\ sequence is replaced by a single \ char
  503. m_FullText.Remove(ii, 1);
  504. ii--;
  505. }
  506. else if( m_FullText[ii] == 'n' )
  507. {
  508. // Replace the "\n" sequence by a EOL char
  509. multiline = true;
  510. m_FullText[ii] = '\n';
  511. m_FullText.Remove(ii-1, 1);
  512. ii--;
  513. }
  514. }
  515. }
  516. return multiline;
  517. }
  518. void DS_DATA_ITEM_TEXT::SetConstrainedTextSize()
  519. {
  520. m_ConstrainedTextSize = m_TextSize;
  521. if( m_ConstrainedTextSize.x == 0 )
  522. m_ConstrainedTextSize.x = DS_DATA_MODEL::GetTheInstance().m_DefaultTextSize.x;
  523. if( m_ConstrainedTextSize.y == 0 )
  524. m_ConstrainedTextSize.y = DS_DATA_MODEL::GetTheInstance().m_DefaultTextSize.y;
  525. if( m_BoundingBoxSize.x || m_BoundingBoxSize.y )
  526. {
  527. // to know the X and Y size of the line, we should use
  528. // EDA_TEXT::GetTextBox()
  529. // but this function uses integers
  530. // So, to avoid truncations with our unit in mm, use microns.
  531. wxSize size_micron;
  532. #define FSCALE 1000.0
  533. int linewidth = 0;
  534. size_micron.x = KiROUND( m_ConstrainedTextSize.x * FSCALE );
  535. size_micron.y = KiROUND( m_ConstrainedTextSize.y * FSCALE );
  536. DS_DRAW_ITEM_TEXT dummy( this, 0, m_FullText, VECTOR2I( 0, 0 ), size_micron, linewidth,
  537. m_Font, m_Italic, m_Bold, m_TextColor );
  538. dummy.SetMultilineAllowed( true );
  539. dummy.SetHorizJustify( m_Hjustify ) ;
  540. dummy.SetVertJustify( m_Vjustify );
  541. dummy.SetTextAngle( EDA_ANGLE( m_Orient, DEGREES_T ) );
  542. EDA_RECT rect = dummy.GetTextBox();
  543. VECTOR2D size;
  544. size.x = rect.GetWidth() / FSCALE;
  545. size.y = rect.GetHeight() / FSCALE;
  546. if( m_BoundingBoxSize.x && size.x > m_BoundingBoxSize.x )
  547. m_ConstrainedTextSize.x *= m_BoundingBoxSize.x / size.x;
  548. if( m_BoundingBoxSize.y && size.y > m_BoundingBoxSize.y )
  549. m_ConstrainedTextSize.y *= m_BoundingBoxSize.y / size.y;
  550. }
  551. }
  552. void DS_DATA_ITEM_BITMAP::SyncDrawItems( DS_DRAW_ITEM_LIST* aCollector, KIGFX::VIEW* aView )
  553. {
  554. std::map<size_t, EDA_ITEM_FLAGS> itemFlags;
  555. DS_DRAW_ITEM_BASE* item = nullptr;
  556. for( size_t i = 0; i < m_drawItems.size(); ++i )
  557. {
  558. item = m_drawItems[ i ];
  559. itemFlags[ i ] = item->GetFlags();
  560. if( aCollector )
  561. aCollector->Remove( item );
  562. if( aView )
  563. aView->Remove( item );
  564. delete item;
  565. }
  566. if( aCollector )
  567. {
  568. double pix_size_iu = aCollector->GetMilsToIUfactor() * 1000 / m_ImageBitmap->GetPPI();
  569. m_ImageBitmap->SetPixelSizeIu( pix_size_iu );
  570. }
  571. m_drawItems.clear();
  572. for( int j = 0; j < m_RepeatCount; j++ )
  573. {
  574. if( j && !IsInsidePage( j ) )
  575. continue;
  576. DS_DRAW_ITEM_BITMAP* bitmap = new DS_DRAW_ITEM_BITMAP( this, j, GetStartPosUi( j ) );
  577. bitmap->SetFlags( itemFlags[ j ] );
  578. m_drawItems.push_back( bitmap );
  579. if( aCollector )
  580. aCollector->Append( bitmap );
  581. if( aView )
  582. aView->Add( bitmap );
  583. }
  584. }
  585. int DS_DATA_ITEM_BITMAP::GetPPI() const
  586. {
  587. if( m_ImageBitmap )
  588. return m_ImageBitmap->GetPPI() / m_ImageBitmap->GetScale();
  589. return 300;
  590. }
  591. void DS_DATA_ITEM_BITMAP::SetPPI( int aBitmapPPI )
  592. {
  593. if( m_ImageBitmap )
  594. m_ImageBitmap->SetScale( (double) m_ImageBitmap->GetPPI() / aBitmapPPI );
  595. }