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.

560 lines
14 KiB

  1. /********************************************************/
  2. /* class_module.cpp : TEXT_MODULE class implementation. */
  3. /********************************************************/
  4. #include "fctsys.h"
  5. #include "gr_basic.h"
  6. #include "wxstruct.h"
  7. #include "common.h"
  8. #include "pcbnew.h"
  9. #include "trigo.h"
  10. #include "class_drawpanel.h"
  11. #include "drawtxt.h"
  12. #include "kicad_string.h"
  13. #include "pcbcommon.h"
  14. #include "class_board_design_settings.h"
  15. #include "colors_selection.h"
  16. /*******************************************************************/
  17. /* Class TEXTE_MODULE base class type of text elements in a module */
  18. /*******************************************************************/
  19. TEXTE_MODULE::TEXTE_MODULE( MODULE* parent, int text_type ) :
  20. BOARD_ITEM( parent, TYPE_TEXTE_MODULE ), EDA_TextStruct()
  21. {
  22. MODULE* Module = (MODULE*) m_Parent;
  23. m_Type = text_type; /* Reference */
  24. if( (m_Type != TEXT_is_REFERENCE) && (m_Type != TEXT_is_VALUE) )
  25. m_Type = TEXT_is_DIVERS;
  26. m_NoShow = false;
  27. m_Size.x = m_Size.y = 400;
  28. m_Width = 120; /* Set default dimension to a reasonable value. */
  29. SetLayer( SILKSCREEN_N_FRONT );
  30. if( Module && ( Module->Type() == TYPE_MODULE ) )
  31. {
  32. m_Pos = Module->m_Pos;
  33. int moduleLayer = Module->GetLayer();
  34. if( moduleLayer == LAYER_N_BACK )
  35. SetLayer( SILKSCREEN_N_BACK );
  36. else if( moduleLayer == LAYER_N_FRONT )
  37. SetLayer( SILKSCREEN_N_FRONT );
  38. else
  39. SetLayer( moduleLayer );
  40. if( moduleLayer == SILKSCREEN_N_BACK
  41. || moduleLayer == ADHESIVE_N_BACK
  42. || moduleLayer == LAYER_N_BACK )
  43. {
  44. m_Mirror = true;
  45. }
  46. }
  47. }
  48. TEXTE_MODULE::~TEXTE_MODULE()
  49. {
  50. }
  51. /**
  52. * Function Save
  53. * writes the data structures for this object out to a FILE in "*.brd" format.
  54. * @param aFile The FILE to write to.
  55. * @return bool - true if success writing else false.
  56. */
  57. bool TEXTE_MODULE::Save( FILE* aFile ) const
  58. {
  59. MODULE* parent = (MODULE*) GetParent();
  60. int orient = m_Orient;
  61. // Due to the pcbnew history, m_Orient is saved in screen value
  62. // but it is handled as relative to its parent footprint
  63. if( parent )
  64. orient += parent->m_Orient;
  65. int ret = fprintf( aFile, "T%d %d %d %d %d %d %d %c %c %d %c\"%s\"\n",
  66. m_Type,
  67. m_Pos0.x, m_Pos0.y,
  68. m_Size.y, m_Size.x,
  69. orient,
  70. m_Width,
  71. m_Mirror ? 'M' : 'N', m_NoShow ? 'I' : 'V',
  72. GetLayer(),
  73. m_Italic ? 'I' : 'N',
  74. CONV_TO_UTF8( m_Text ) );
  75. return ret > 20;
  76. }
  77. /**
  78. * Function ReadLineDescr
  79. * Read description from a given line in "*.brd" format.
  80. * @param aLine The current line which contains the first line of description.
  81. * @param aLine The FILE to read next lines (currently not used).
  82. * @param LineNum a point to the line count (currently not used).
  83. * @return int - > 0 if success reading else 0.
  84. */
  85. int TEXTE_MODULE::ReadDescr( char* aLine, FILE* aFile, int* aLineNum )
  86. {
  87. int success = true;
  88. int type;
  89. int layer;
  90. char BufCar1[128], BufCar2[128], BufCar3[128], BufLine[256];
  91. layer = SILKSCREEN_N_FRONT;
  92. BufCar1[0] = 0;
  93. BufCar2[0] = 0;
  94. BufCar3[0] = 0;
  95. if( sscanf( aLine + 1, "%d %d %d %d %d %d %d %s %s %d %s",
  96. &type,
  97. &m_Pos0.x, &m_Pos0.y,
  98. &m_Size.y, &m_Size.x,
  99. &m_Orient, &m_Width,
  100. BufCar1, BufCar2, &layer, BufCar3 ) >= 10 )
  101. success = true;
  102. if( (type != TEXT_is_REFERENCE) && (type != TEXT_is_VALUE) )
  103. type = TEXT_is_DIVERS;
  104. m_Type = type;
  105. // Due to the pcbnew history, .m_Orient is saved in screen value
  106. // but it is handled as relative to its parent footprint
  107. m_Orient -= ( (MODULE*) m_Parent )->m_Orient;
  108. if( BufCar1[0] == 'M' )
  109. m_Mirror = true;
  110. else
  111. m_Mirror = false;
  112. if( BufCar2[0] == 'I' )
  113. m_NoShow = true;
  114. else
  115. m_NoShow = false;
  116. if( BufCar3[0] == 'I' )
  117. m_Italic = true;
  118. else
  119. m_Italic = false;
  120. // Test for a reasonable layer:
  121. if( layer < 0 )
  122. layer = 0;
  123. if( layer > LAST_NO_COPPER_LAYER )
  124. layer = LAST_NO_COPPER_LAYER;
  125. if( layer == LAYER_N_BACK )
  126. layer = SILKSCREEN_N_BACK;
  127. else if( layer == LAYER_N_FRONT )
  128. layer = SILKSCREEN_N_FRONT;
  129. SetLayer( layer );
  130. /* Calculate the true position. */
  131. SetDrawCoord();
  132. /* Read the "text" string. */
  133. ReadDelimitedText( BufLine, aLine, sizeof(BufLine) );
  134. m_Text = CONV_FROM_UTF8( BufLine );
  135. // Test for a reasonable size:
  136. if( m_Size.x < TEXTS_MIN_SIZE )
  137. m_Size.x = TEXTS_MIN_SIZE;
  138. if( m_Size.y < TEXTS_MIN_SIZE )
  139. m_Size.y = TEXTS_MIN_SIZE;
  140. // Set a reasonable width:
  141. if( m_Width < 1 )
  142. m_Width = 1;
  143. m_Width = Clamp_Text_PenSize( m_Width, m_Size );
  144. return success;
  145. }
  146. void TEXTE_MODULE::Copy( TEXTE_MODULE* source )
  147. {
  148. if( source == NULL )
  149. return;
  150. m_Pos = source->m_Pos;
  151. SetLayer( source->GetLayer() );
  152. m_Mirror = source->m_Mirror;
  153. m_NoShow = source->m_NoShow;
  154. m_Type = source->m_Type;
  155. m_Orient = source->m_Orient;
  156. m_Pos0 = source->m_Pos0;
  157. m_Size = source->m_Size;
  158. m_Width = source->m_Width;
  159. m_Italic = source->m_Italic;
  160. m_Bold = source->m_Bold;
  161. m_Text = source->m_Text;
  162. }
  163. int TEXTE_MODULE:: GetLength()
  164. {
  165. return m_Text.Len();
  166. }
  167. void TEXTE_MODULE:: SetWidth( int new_width )
  168. {
  169. m_Width = new_width;
  170. }
  171. // Update draw coordinates
  172. void TEXTE_MODULE:: SetDrawCoord()
  173. {
  174. MODULE* Module = (MODULE*) m_Parent;
  175. m_Pos = m_Pos0;
  176. if( Module == NULL )
  177. return;
  178. int angle = Module->m_Orient;
  179. NORMALIZE_ANGLE_POS( angle );
  180. RotatePoint( &m_Pos.x, &m_Pos.y, angle );
  181. m_Pos += Module->m_Pos;
  182. }
  183. // Update "local" coordinates (coordinates relatives to the footprint
  184. // anchor point)
  185. void TEXTE_MODULE:: SetLocalCoord()
  186. {
  187. MODULE* Module = (MODULE*) m_Parent;
  188. if( Module == NULL )
  189. {
  190. m_Pos0 = m_Pos;
  191. return;
  192. }
  193. m_Pos0 = m_Pos - Module->m_Pos;
  194. int angle = Module->m_Orient;
  195. NORMALIZE_ANGLE_POS( angle );
  196. RotatePoint( &m_Pos0.x, &m_Pos0.y, -angle );
  197. }
  198. /**
  199. * Function GetTextRect
  200. * @return an EDA_Rect which gives the position and size of the text area
  201. * (for the footprint orientation)
  202. */
  203. EDA_Rect TEXTE_MODULE::GetTextRect( void )
  204. {
  205. EDA_Rect area;
  206. int dx, dy;
  207. dx = ( m_Size.x * GetLength() ) / 2;
  208. dx = (dx * 10) / 9; /* letter size = 10/9 */
  209. dx += m_Width / 2;
  210. dy = ( m_Size.y + m_Width ) / 2;
  211. wxPoint Org = m_Pos; // This is the position of the center of the area
  212. Org.x -= dx;
  213. Org.y -= dy;
  214. area.SetOrigin( Org );
  215. area.SetHeight( 2 * dy );
  216. area.SetWidth( 2 * dx );
  217. area.Normalize();
  218. return area;
  219. }
  220. /**
  221. * Function HitTest
  222. * tests if the given wxPoint is within the bounds of this object.
  223. * @param refPos A wxPoint to test
  224. * @return bool - true if a hit, else false
  225. */
  226. bool TEXTE_MODULE::HitTest( const wxPoint& refPos )
  227. {
  228. wxPoint rel_pos;
  229. EDA_Rect area = GetTextRect();
  230. /* Rotate refPos to - angle
  231. * to test if refPos is within area (which is relative to an horizontal
  232. * text)
  233. */
  234. rel_pos = refPos;
  235. RotatePoint( &rel_pos, m_Pos, -GetDrawRotation() );
  236. if( area.Inside( rel_pos ) )
  237. return true;
  238. return false;
  239. }
  240. /**
  241. * Function GetBoundingBox
  242. * returns the bounding box of this Text (according to text and footprint
  243. * orientation)
  244. */
  245. EDA_Rect TEXTE_MODULE::GetBoundingBox()
  246. {
  247. // Calculate area without text fields:
  248. EDA_Rect text_area;
  249. int angle = GetDrawRotation();
  250. wxPoint textstart, textend;
  251. text_area = GetTextRect();
  252. textstart = text_area.GetOrigin();
  253. textend = text_area.GetEnd();
  254. RotatePoint( &textstart, m_Pos, angle );
  255. RotatePoint( &textend, m_Pos, angle );
  256. text_area.SetOrigin( textstart );
  257. text_area.SetEnd( textend );
  258. text_area.Normalize();
  259. return text_area;
  260. }
  261. /**
  262. * Function Draw
  263. * Draw the text according to the footprint pos and orient
  264. * @param panel = draw panel, Used to know the clip box
  265. * @param DC = Current Device Context
  266. * @param offset = draw offset (usually wxPoint(0,0)
  267. * @param draw_mode = GR_OR, GR_XOR..
  268. */
  269. void TEXTE_MODULE::Draw( WinEDA_DrawPanel* panel, wxDC* DC, int draw_mode,
  270. const wxPoint& offset )
  271. {
  272. int width, color, orient;
  273. wxSize size;
  274. wxPoint pos; // Center of text
  275. PCB_SCREEN* screen;
  276. WinEDA_BasePcbFrame* frame;
  277. MODULE* Module = (MODULE*) m_Parent; /* parent must *not* be null
  278. * (a module text without a footprint parent has no sense)
  279. */
  280. if( panel == NULL )
  281. return;
  282. screen = (PCB_SCREEN*) panel->GetScreen();
  283. frame = (WinEDA_BasePcbFrame*) panel->GetParent();
  284. pos.x = m_Pos.x - offset.x;
  285. pos.y = m_Pos.y - offset.y;
  286. size = m_Size;
  287. orient = GetDrawRotation();
  288. width = m_Width;
  289. if( ( frame->m_DisplayModText == FILAIRE )
  290. #ifdef USE_WX_ZOOM
  291. || ( DC->LogicalToDeviceXRel( width ) < L_MIN_DESSIN ) )
  292. #else
  293. || ( screen->Scale( width ) < L_MIN_DESSIN ) )
  294. #endif
  295. width = 0;
  296. else if( frame->m_DisplayModText == SKETCH )
  297. width = -width;
  298. GRSetDrawMode( DC, draw_mode );
  299. BOARD * brd = GetBoard( );
  300. if( brd->IsElementVisible( ANCHOR_VISIBLE ) )
  301. {
  302. color = brd->GetVisibleElementColor(ANCHOR_VISIBLE);
  303. #ifdef USE_WX_ZOOM
  304. int anchor_size = DC->DeviceToLogicalXRel( 2 );
  305. #else
  306. int anchor_size = screen->Unscale( 2 );
  307. #endif
  308. GRLine( &panel->m_ClipBox, DC,
  309. pos.x - anchor_size, pos.y,
  310. pos.x + anchor_size, pos.y, 0, color );
  311. GRLine( &panel->m_ClipBox, DC,
  312. pos.x, pos.y - anchor_size,
  313. pos.x, pos.y + anchor_size, 0, color );
  314. }
  315. color = brd->GetLayerColor(Module->GetLayer());
  316. if( Module->GetLayer() == LAYER_N_BACK )
  317. {
  318. if( brd->IsElementVisible( MOD_TEXT_BK_VISIBLE ) == false )
  319. return;
  320. color = brd->GetVisibleElementColor(MOD_TEXT_BK_VISIBLE);
  321. }
  322. else if( Module->GetLayer() == LAYER_N_FRONT )
  323. {
  324. if( brd->IsElementVisible( MOD_TEXT_FR_VISIBLE ) == false )
  325. return;
  326. color = brd->GetVisibleElementColor(MOD_TEXT_FR_VISIBLE);
  327. }
  328. if( m_NoShow )
  329. {
  330. if( brd->IsElementVisible( MOD_TEXT_INVISIBLE ) == false )
  331. return;
  332. color = brd->GetVisibleElementColor(MOD_TEXT_INVISIBLE);
  333. }
  334. /* If the text is mirrored : negate size.x (mirror / Y axis) */
  335. if( m_Mirror )
  336. size.x = -size.x;
  337. DrawGraphicText( panel, DC, pos, (enum EDA_Colors) color, m_Text, orient,
  338. size, m_HJustify, m_VJustify, width, m_Italic, m_Bold );
  339. }
  340. /* Return text rotation for drawings and plotting
  341. */
  342. int TEXTE_MODULE::GetDrawRotation()
  343. {
  344. int rotation;
  345. MODULE* Module = (MODULE*) m_Parent;
  346. rotation = m_Orient;
  347. if( Module )
  348. rotation += Module->m_Orient;
  349. NORMALIZE_ANGLE_POS( rotation );
  350. // For angle = 0 .. 180 deg
  351. while( rotation > 900 )
  352. rotation -= 1800;
  353. return rotation;
  354. }
  355. // see class_text_mod.h
  356. void TEXTE_MODULE::DisplayInfo( WinEDA_DrawFrame* frame )
  357. {
  358. MODULE* module = (MODULE*) m_Parent;
  359. if( module == NULL ) // Happens in modedit, and for new texts
  360. return;
  361. wxString msg, Line;
  362. int ii;
  363. static const wxString text_type_msg[3] =
  364. {
  365. _( "Ref." ), _( "Value" ), _( "Text" )
  366. };
  367. frame->ClearMsgPanel();
  368. Line = module->m_Reference->m_Text;
  369. frame->AppendMsgPanel( _( "Module" ), Line, DARKCYAN );
  370. Line = m_Text;
  371. frame->AppendMsgPanel( _( "Text" ), Line, BROWN );
  372. ii = m_Type;
  373. if( ii > 2 )
  374. ii = 2;
  375. frame->AppendMsgPanel( _( "Type" ), text_type_msg[ii], DARKGREEN );
  376. if( m_NoShow )
  377. msg = _( "No" );
  378. else
  379. msg = _( "Yes" );
  380. frame->AppendMsgPanel( _( "Display" ), msg, DARKGREEN );
  381. // Display text layer (use layer name if possible)
  382. BOARD* board = NULL;
  383. board = (BOARD*) module->GetParent();
  384. if( m_Layer < NB_LAYERS && board )
  385. msg = board->GetLayerName( m_Layer );
  386. else
  387. msg.Printf( wxT( "%d" ), m_Layer );
  388. frame->AppendMsgPanel( _( "Layer" ), msg, DARKGREEN );
  389. msg = _( " No" );
  390. if( m_Mirror )
  391. msg = _( " Yes" );
  392. frame->AppendMsgPanel( _( "Mirror" ), msg, DARKGREEN );
  393. msg.Printf( wxT( "%.1f" ), (float) m_Orient / 10 );
  394. frame->AppendMsgPanel( _( "Orient" ), msg, DARKGREEN );
  395. valeur_param( m_Width, msg );
  396. frame->AppendMsgPanel( _( "Width" ), msg, DARKGREEN );
  397. valeur_param( m_Size.x, msg );
  398. frame->AppendMsgPanel( _( "H Size" ), msg, RED );
  399. valeur_param( m_Size.y, msg );
  400. frame->AppendMsgPanel( _( "V Size" ), msg, RED );
  401. }
  402. // see class_text_mod.h
  403. bool TEXTE_MODULE::IsOnLayer( int aLayer ) const
  404. {
  405. if( m_Layer == aLayer )
  406. return true;
  407. /* test the parent, which is a MODULE */
  408. if( aLayer == GetParent()->GetLayer() )
  409. return true;
  410. if( aLayer == LAYER_N_BACK )
  411. {
  412. if( m_Layer==ADHESIVE_N_BACK || m_Layer==SILKSCREEN_N_BACK )
  413. return true;
  414. }
  415. else if( aLayer == LAYER_N_FRONT )
  416. {
  417. if( m_Layer==ADHESIVE_N_FRONT || m_Layer==SILKSCREEN_N_FRONT )
  418. return true;
  419. }
  420. return false;
  421. }
  422. /* see class_text_mod.h
  423. * bool TEXTE_MODULE::IsOnOneOfTheseLayers( int aLayerMask ) const
  424. * {
  425. *
  426. * }
  427. */
  428. #if defined(DEBUG)
  429. /**
  430. * Function Show
  431. * is used to output the object tree, currently for debugging only.
  432. * @param nestLevel An aid to prettier tree indenting, and is the level
  433. * of nesting of this object within the overall tree.
  434. * @param os The ostream& to output to.
  435. */
  436. void TEXTE_MODULE::Show( int nestLevel, std::ostream& os )
  437. {
  438. // for now, make it look like XML:
  439. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() <<
  440. " string=\"" << m_Text.mb_str() << "\"/>\n";
  441. // NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str()
  442. // << ">\n";
  443. }
  444. #endif