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.

1782 lines
56 KiB

7 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014 CERN
  5. * Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <sch_item.h>
  27. #include <bezier_curves.h>
  28. #include <class_libentry.h>
  29. #include <class_library.h>
  30. #include <connection_graph.h>
  31. #include <gal/graphics_abstraction_layer.h>
  32. #include <geometry/geometry_utils.h>
  33. #include <geometry/shape_line_chain.h>
  34. #include <gr_text.h>
  35. #include <lib_arc.h>
  36. #include <lib_bezier.h>
  37. #include <lib_circle.h>
  38. #include <lib_field.h>
  39. #include <lib_item.h>
  40. #include <lib_pin.h>
  41. #include <lib_polyline.h>
  42. #include <lib_rectangle.h>
  43. #include <lib_text.h>
  44. #include <math/util.h>
  45. #include <plotter.h>
  46. #include <sch_bitmap.h>
  47. #include <sch_bus_entry.h>
  48. #include <sch_component.h>
  49. #include <sch_edit_frame.h>
  50. #include <sch_field.h>
  51. #include <sch_junction.h>
  52. #include <sch_line.h>
  53. #include <sch_marker.h>
  54. #include <sch_no_connect.h>
  55. #include <sch_sheet.h>
  56. #include <sch_text.h>
  57. #include <settings/color_settings.h>
  58. #include <view/view.h>
  59. #include <kiface_i.h>
  60. #include <default_values.h>
  61. #include "sch_painter.h"
  62. namespace KIGFX
  63. {
  64. SCH_RENDER_SETTINGS::SCH_RENDER_SETTINGS() :
  65. m_ShowUnit( 0 ),
  66. m_ShowConvert( 0 ),
  67. m_ShowHiddenText( true ),
  68. m_ShowHiddenPins( true ),
  69. m_ShowPinsElectricalType( true ),
  70. m_ShowDisabled( false ),
  71. m_ShowUmbilicals( true ),
  72. m_OverrideItemColors( false ),
  73. m_TextOffsetRatio( 0.08 ),
  74. m_DefaultWireThickness( DEFAULT_WIRE_THICKNESS * IU_PER_MILS ),
  75. m_DefaultBusThickness( DEFAULT_BUS_THICKNESS * IU_PER_MILS ),
  76. m_PinSymbolSize( DEFAULT_TEXT_SIZE * IU_PER_MILS / 2 )
  77. {
  78. SetDefaultPenWidth( DEFAULT_LINE_THICKNESS * IU_PER_MILS );
  79. }
  80. void SCH_RENDER_SETTINGS::LoadColors( const COLOR_SETTINGS* aSettings )
  81. {
  82. for( int layer = SCH_LAYER_ID_START; layer < SCH_LAYER_ID_END; layer ++)
  83. m_layerColors[ layer ] = aSettings->GetColor( layer );
  84. for( int layer = GAL_LAYER_ID_START; layer < GAL_LAYER_ID_END; layer ++)
  85. m_layerColors[ layer ] = aSettings->GetColor( layer );
  86. m_backgroundColor = aSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
  87. m_OverrideItemColors = aSettings->GetOverrideSchItemColors();
  88. }
  89. const COLOR4D& SCH_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
  90. {
  91. return m_layerColors[ aLayer ];
  92. }
  93. EESCHEMA_SETTINGS* eeconfig()
  94. {
  95. return dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  96. }
  97. /**
  98. * Used when a LIB_PART is not found in library to draw a dummy shape.
  99. * This component is a 400 mils square with the text "??"
  100. *
  101. * DEF DUMMY U 0 40 Y Y 1 0 N
  102. * F0 "U" 0 -350 60 H V
  103. * F1 "DUMMY" 0 350 60 H V
  104. * DRAW
  105. * T 0 0 0 150 0 0 0 ??
  106. * S -200 200 200 -200 0 1 0
  107. * ENDDRAW
  108. * ENDDEF
  109. */
  110. static LIB_PART* dummy()
  111. {
  112. static LIB_PART* part;
  113. if( !part )
  114. {
  115. part = new LIB_PART( wxEmptyString );
  116. LIB_RECTANGLE* square = new LIB_RECTANGLE( part );
  117. square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
  118. square->SetEndPosition( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
  119. LIB_TEXT* text = new LIB_TEXT( part );
  120. text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
  121. text->SetText( wxString( wxT( "??" ) ) );
  122. part->AddDrawItem( square );
  123. part->AddDrawItem( text );
  124. }
  125. return part;
  126. }
  127. SCH_PAINTER::SCH_PAINTER( GAL* aGal ) :
  128. KIGFX::PAINTER( aGal )
  129. { }
  130. #define HANDLE_ITEM( type_id, type_name ) \
  131. case type_id: draw( (type_name *) item, aLayer ); break
  132. bool SCH_PAINTER::Draw( const VIEW_ITEM *aItem, int aLayer )
  133. {
  134. auto item2 = static_cast<const EDA_ITEM*>( aItem );
  135. auto item = const_cast<EDA_ITEM*>( item2 );
  136. #ifdef CONNECTIVITY_DEBUG
  137. auto sch_item = dynamic_cast<SCH_ITEM*>( item );
  138. auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
  139. if( conn )
  140. {
  141. auto pos = item->GetBoundingBox().Centre();
  142. auto label = conn->Name( true );
  143. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  144. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  145. m_gal->SetStrokeColor( COLOR4D( LIGHTRED ) );
  146. m_gal->SetLineWidth( Mils2ui( 2 ) );
  147. m_gal->SetGlyphSize( VECTOR2D( Mils2ui( 20 ), Mils2ui( 20 ) ) );
  148. m_gal->StrokeText( conn->Name( true ), pos, 0.0, 0 );
  149. }
  150. #endif
  151. switch( item->Type() )
  152. {
  153. HANDLE_ITEM( LIB_PART_T, LIB_PART );
  154. HANDLE_ITEM( LIB_RECTANGLE_T, LIB_RECTANGLE );
  155. HANDLE_ITEM( LIB_POLYLINE_T, LIB_POLYLINE );
  156. HANDLE_ITEM( LIB_CIRCLE_T, LIB_CIRCLE );
  157. HANDLE_ITEM( LIB_PIN_T, LIB_PIN );
  158. HANDLE_ITEM( LIB_ARC_T, LIB_ARC );
  159. HANDLE_ITEM( LIB_FIELD_T, LIB_FIELD );
  160. HANDLE_ITEM( LIB_TEXT_T, LIB_TEXT );
  161. HANDLE_ITEM( LIB_BEZIER_T, LIB_BEZIER );
  162. HANDLE_ITEM( SCH_COMPONENT_T, SCH_COMPONENT );
  163. HANDLE_ITEM( SCH_JUNCTION_T, SCH_JUNCTION );
  164. HANDLE_ITEM( SCH_LINE_T, SCH_LINE );
  165. HANDLE_ITEM( SCH_TEXT_T, SCH_TEXT );
  166. HANDLE_ITEM( SCH_LABEL_T, SCH_TEXT );
  167. HANDLE_ITEM( SCH_FIELD_T, SCH_FIELD );
  168. HANDLE_ITEM( SCH_HIER_LABEL_T, SCH_HIERLABEL );
  169. HANDLE_ITEM( SCH_GLOBAL_LABEL_T, SCH_GLOBALLABEL );
  170. HANDLE_ITEM( SCH_SHEET_T, SCH_SHEET );
  171. HANDLE_ITEM( SCH_SHEET_PIN_T, SCH_HIERLABEL );
  172. HANDLE_ITEM( SCH_NO_CONNECT_T, SCH_NO_CONNECT );
  173. HANDLE_ITEM( SCH_BUS_WIRE_ENTRY_T, SCH_BUS_ENTRY_BASE );
  174. HANDLE_ITEM( SCH_BUS_BUS_ENTRY_T, SCH_BUS_ENTRY_BASE );
  175. HANDLE_ITEM( SCH_BITMAP_T, SCH_BITMAP );
  176. HANDLE_ITEM( SCH_MARKER_T, SCH_MARKER );
  177. default: return false;
  178. }
  179. return false;
  180. }
  181. bool SCH_PAINTER::isUnitAndConversionShown( const LIB_ITEM* aItem )
  182. {
  183. if( m_schSettings.m_ShowUnit // showing a specific unit
  184. && aItem->GetUnit() // item is unit-specific
  185. && aItem->GetUnit() != m_schSettings.m_ShowUnit )
  186. {
  187. return false;
  188. }
  189. if( m_schSettings.m_ShowConvert // showing a specific conversion
  190. && aItem->GetConvert() // item is conversion-specific
  191. && aItem->GetConvert() != m_schSettings.m_ShowConvert )
  192. {
  193. return false;
  194. }
  195. return true;
  196. }
  197. float SCH_PAINTER::getShadowWidth()
  198. {
  199. const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
  200. // For best visuals the selection width must be a cross between the zoom level and the
  201. // default line width.
  202. return (float) fabs( matrix.GetScale().x * 2.75 ) + Mils2iu( eeconfig()->m_Selection.thickness );
  203. }
  204. COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aDrawingShadows )
  205. {
  206. COLOR4D color = m_schSettings.GetLayerColor( aLayer );
  207. if( aItem->Type() == SCH_LINE_T )
  208. {
  209. COLOR4D lineColor = static_cast<const SCH_LINE*>( aItem )->GetLineColor();
  210. if( lineColor != COLOR4D::UNSPECIFIED )
  211. color = lineColor;
  212. }
  213. else if( aItem->Type() == SCH_SHEET_T )
  214. {
  215. SCH_SHEET* sheet = (SCH_SHEET*) aItem;
  216. // Lazy fixup of legacy sheets with no color specifications
  217. if( sheet->GetBorderColor() == COLOR4D::UNSPECIFIED )
  218. sheet->SetBorderColor( m_schSettings.GetLayerColor( LAYER_SHEET ) );
  219. if( sheet->GetBackgroundColor() == COLOR4D::UNSPECIFIED )
  220. sheet->SetBackgroundColor( m_schSettings.GetLayerColor( LAYER_SHEET_BACKGROUND ) );
  221. if( m_schSettings.m_OverrideItemColors )
  222. color = m_schSettings.GetLayerColor( aLayer );
  223. else if( aLayer == LAYER_SHEET )
  224. color = sheet->GetBorderColor();
  225. else if( aLayer == LAYER_SHEET_BACKGROUND )
  226. color = sheet->GetBackgroundColor();
  227. }
  228. if( aItem->IsBrightened() && !aDrawingShadows ) // Selection disambiguation, etc.
  229. {
  230. color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
  231. if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_SHEET_BACKGROUND )
  232. color = color.WithAlpha( 0.2 );
  233. }
  234. else if( aItem->IsSelected() )
  235. {
  236. if( aDrawingShadows )
  237. color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS ).WithAlpha( 0.8 );
  238. }
  239. if( m_schSettings.m_ShowDisabled )
  240. color = color.Darken( 0.5f );
  241. return color;
  242. }
  243. float SCH_PAINTER::getLineWidth( const LIB_ITEM* aItem, bool aDrawingShadows )
  244. {
  245. float width = (float) std::max( aItem->GetPenWidth(), m_schSettings.GetDefaultPenWidth() );
  246. if( aItem->IsSelected() && aDrawingShadows )
  247. width += getShadowWidth();
  248. return width;
  249. }
  250. float SCH_PAINTER::getLineWidth( const SCH_ITEM* aItem, bool aDrawingShadows )
  251. {
  252. float width;
  253. if( aItem->GetLayer() == LAYER_WIRE )
  254. width = (float) m_schSettings.m_DefaultWireThickness;
  255. else if( aItem->GetLayer() == LAYER_BUS )
  256. width = (float) m_schSettings.m_DefaultBusThickness;
  257. else
  258. width = (float) std::max( aItem->GetPenWidth(), m_schSettings.GetDefaultPenWidth() );
  259. if( aItem->IsSelected() && aDrawingShadows )
  260. width += getShadowWidth();
  261. return width;
  262. }
  263. float SCH_PAINTER::getTextThickness( const SCH_TEXT* aItem, bool aDrawingShadows )
  264. {
  265. float width = (float) aItem->GetEffectiveTextPenWidth( m_schSettings.GetDefaultPenWidth() );
  266. if( aItem->IsSelected() && aDrawingShadows )
  267. width += getShadowWidth();
  268. return width;
  269. }
  270. float SCH_PAINTER::getTextThickness( const SCH_FIELD* aItem, bool aDrawingShadows )
  271. {
  272. float width = (float) aItem->GetEffectiveTextPenWidth( m_schSettings.GetDefaultPenWidth() );
  273. if( aItem->IsSelected() && aDrawingShadows )
  274. width += getShadowWidth();
  275. return width;
  276. }
  277. float SCH_PAINTER::getTextThickness( const LIB_FIELD* aItem, bool aDrawingShadows )
  278. {
  279. float width = (float) std::max( aItem->GetEffectiveTextPenWidth(),
  280. m_schSettings.GetDefaultPenWidth() );
  281. if( aItem->IsSelected() && aDrawingShadows )
  282. width += getShadowWidth();
  283. return width;
  284. }
  285. float SCH_PAINTER::getTextThickness( const LIB_TEXT* aItem, bool aDrawingShadows )
  286. {
  287. float width = (float) std::max( aItem->GetEffectiveTextPenWidth(),
  288. m_schSettings.GetDefaultPenWidth() );
  289. if( aItem->IsSelected() && aDrawingShadows )
  290. width += getShadowWidth();
  291. return width;
  292. }
  293. void SCH_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition, double aAngle )
  294. {
  295. m_gal->StrokeText( aText, aPosition, aAngle );
  296. }
  297. void SCH_PAINTER::draw( LIB_PART *aPart, int aLayer, bool aDrawFields, int aUnit, int aConvert )
  298. {
  299. if( !aUnit )
  300. aUnit = m_schSettings.m_ShowUnit;
  301. if( !aConvert )
  302. aConvert = m_schSettings.m_ShowConvert;
  303. std::unique_ptr< LIB_PART > tmpPart;
  304. LIB_PART* drawnPart = aPart;
  305. if( aPart->IsAlias() )
  306. {
  307. tmpPart = aPart->Flatten();
  308. drawnPart = tmpPart.get();
  309. }
  310. for( auto& item : drawnPart->GetDrawItems() )
  311. {
  312. if( !aDrawFields && item.Type() == LIB_FIELD_T )
  313. continue;
  314. if( aUnit && item.GetUnit() && aUnit != item.GetUnit() )
  315. continue;
  316. if( aConvert && item.GetConvert() && aConvert != item.GetConvert() )
  317. continue;
  318. Draw( &item, aLayer );
  319. }
  320. }
  321. static VECTOR2D mapCoords( const wxPoint& aCoord )
  322. {
  323. return VECTOR2D( aCoord.x, -aCoord.y );
  324. }
  325. void SCH_PAINTER::triLine( const VECTOR2D &a, const VECTOR2D &b, const VECTOR2D &c )
  326. {
  327. m_gal->DrawLine( a, b );
  328. m_gal->DrawLine( b, c );
  329. }
  330. bool SCH_PAINTER::setDeviceColors( const LIB_ITEM* aItem, int aLayer )
  331. {
  332. switch( aLayer )
  333. {
  334. case LAYER_SELECTION_SHADOWS:
  335. if( aItem->IsSelected() )
  336. {
  337. m_gal->SetIsFill( false );
  338. m_gal->SetIsStroke( true );
  339. m_gal->SetLineWidth( getLineWidth( aItem, true ) );
  340. m_gal->SetStrokeColor( getRenderColor( aItem, LAYER_DEVICE, true ) );
  341. m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, true ) );
  342. return true;
  343. }
  344. return false;
  345. case LAYER_DEVICE_BACKGROUND:
  346. if( aItem->GetFillMode() == FILLED_WITH_BG_BODYCOLOR )
  347. {
  348. COLOR4D fillColor = getRenderColor( aItem, LAYER_DEVICE_BACKGROUND, false );
  349. // These actions place the item over others, so allow a modest transparency here
  350. if( aItem->IsMoving() || aItem->IsDragging() || aItem->IsResized() )
  351. fillColor = fillColor.WithAlpha( 0.75 );
  352. m_gal->SetIsFill( aItem->GetFillMode() == FILLED_WITH_BG_BODYCOLOR );
  353. m_gal->SetFillColor( fillColor );
  354. m_gal->SetIsStroke( false );
  355. return true;
  356. }
  357. return false;
  358. case LAYER_DEVICE:
  359. m_gal->SetIsFill( aItem->GetFillMode() == FILLED_SHAPE );
  360. m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, false ) );
  361. if( aItem->GetPenWidth() > 0 || aItem->GetFillMode() == NO_FILL )
  362. {
  363. m_gal->SetIsStroke( true );
  364. m_gal->SetLineWidth( getLineWidth( aItem, false ) );
  365. m_gal->SetStrokeColor( getRenderColor( aItem, LAYER_DEVICE, false ) );
  366. }
  367. else
  368. {
  369. m_gal->SetIsStroke( false );
  370. }
  371. return true;
  372. default:
  373. return false;
  374. }
  375. }
  376. void SCH_PAINTER::fillIfSelection( int aLayer )
  377. {
  378. if( aLayer == LAYER_SELECTION_SHADOWS && eeconfig()->m_Selection.fill_shapes )
  379. m_gal->SetIsFill( true );
  380. }
  381. void SCH_PAINTER::draw( LIB_RECTANGLE *aRect, int aLayer )
  382. {
  383. if( !isUnitAndConversionShown( aRect ) )
  384. return;
  385. if( setDeviceColors( aRect, aLayer ) )
  386. {
  387. fillIfSelection( aLayer );
  388. m_gal->DrawRectangle( mapCoords( aRect->GetPosition() ), mapCoords( aRect->GetEnd() ) );
  389. }
  390. }
  391. void SCH_PAINTER::draw( LIB_CIRCLE *aCircle, int aLayer )
  392. {
  393. if( !isUnitAndConversionShown( aCircle ) )
  394. return;
  395. if( setDeviceColors( aCircle, aLayer ) )
  396. {
  397. fillIfSelection( aLayer );
  398. m_gal->DrawCircle( mapCoords( aCircle->GetPosition() ), aCircle->GetRadius() );
  399. }
  400. }
  401. void SCH_PAINTER::draw( LIB_ARC *aArc, int aLayer )
  402. {
  403. if( !isUnitAndConversionShown( aArc ) )
  404. return;
  405. if( setDeviceColors( aArc, aLayer ) )
  406. {
  407. int sai = aArc->GetFirstRadiusAngle();
  408. int eai = aArc->GetSecondRadiusAngle();
  409. /**
  410. * This accounts for an oddity in the old library format, where the symbol
  411. * is overdefined. The previous draw (based on wxwidgets) used start point and end
  412. * point and always drew counter-clockwise. The new GAL draw takes center, radius and
  413. * start/end angles. All of these points were stored in the file, so we need to mimic the
  414. * swapping of start/end points rather than using the stored angles in order to properly map
  415. * edge cases.
  416. *
  417. * todo(v6): Remove this hack when we update the file format and do translation on loading.
  418. */
  419. if( !TRANSFORM().MapAngles( &sai, &eai ) )
  420. {
  421. LIB_ARC new_arc( *aArc );
  422. new_arc.SetStart( aArc->GetEnd() );
  423. new_arc.SetEnd( aArc->GetStart() );
  424. new_arc.CalcRadiusAngles();
  425. sai = new_arc.GetFirstRadiusAngle();
  426. eai = new_arc.GetSecondRadiusAngle();
  427. TRANSFORM().MapAngles( &sai, &eai );
  428. }
  429. double sa = (double) sai * M_PI / 1800.0;
  430. double ea = (double) eai * M_PI / 1800.0 ;
  431. VECTOR2D pos = mapCoords( aArc->GetPosition() );
  432. m_gal->DrawArc( pos, aArc->GetRadius(), sa, ea );
  433. }
  434. }
  435. void SCH_PAINTER::draw( LIB_POLYLINE *aLine, int aLayer )
  436. {
  437. if( !isUnitAndConversionShown( aLine ) )
  438. return;
  439. if( setDeviceColors( aLine, aLayer ) )
  440. {
  441. const std::vector<wxPoint>& pts = aLine->GetPolyPoints();
  442. std::deque<VECTOR2D> vtx;
  443. for( auto p : pts )
  444. vtx.push_back( mapCoords( p ) );
  445. fillIfSelection( aLayer );
  446. m_gal->DrawPolygon( vtx );
  447. }
  448. }
  449. void SCH_PAINTER::draw( LIB_FIELD *aField, int aLayer )
  450. {
  451. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  452. if( drawingShadows && !aField->IsSelected() )
  453. return;
  454. if( !isUnitAndConversionShown( aField ) )
  455. return;
  456. // Must check layer as fields are sometimes drawn by their parent rather than
  457. // directly from the view.
  458. int layers[KIGFX::VIEW::VIEW_MAX_LAYERS];
  459. int layers_count;
  460. bool foundLayer = false;
  461. aField->ViewGetLayers( layers, layers_count );
  462. for( int i = 0; i < layers_count; ++i )
  463. {
  464. if( layers[i] == aLayer )
  465. foundLayer = true;
  466. }
  467. if( !foundLayer )
  468. return;
  469. COLOR4D color = getRenderColor( aField, aLayer, drawingShadows );
  470. if( !( aField->IsVisible() || aField->IsForceVisible() ) )
  471. {
  472. if( m_schSettings.m_ShowHiddenText )
  473. color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows );
  474. else
  475. return;
  476. }
  477. m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
  478. m_gal->SetIsFill( false );
  479. m_gal->SetIsStroke( true );
  480. m_gal->SetStrokeColor( color );
  481. auto pos = mapCoords( aField->GetPosition() );
  482. if( drawingShadows && eeconfig()->m_Selection.text_as_box )
  483. {
  484. EDA_RECT boundaryBox = aField->GetBoundingBox();
  485. m_gal->SetIsFill( true );
  486. m_gal->SetFillColor( color );
  487. m_gal->SetLineWidth( m_gal->GetLineWidth() * 0.5 );
  488. boundaryBox.RevertYAxis();
  489. m_gal->DrawRectangle( mapCoords( boundaryBox.GetPosition() ),
  490. mapCoords( boundaryBox.GetEnd() ) );
  491. }
  492. else
  493. {
  494. m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
  495. m_gal->SetFontItalic( aField->IsItalic() );
  496. m_gal->SetHorizontalJustify( aField->GetHorizJustify() );
  497. m_gal->SetVerticalJustify( aField->GetVertJustify() );
  498. double orient = aField->GetTextAngleRadians();
  499. strokeText( aField->GetText(), pos, orient );
  500. }
  501. // Draw the umbilical line
  502. if( aField->IsMoving() && m_schSettings.m_ShowUmbilicals )
  503. {
  504. m_gal->SetLineWidth( m_schSettings.m_outlineWidth );
  505. m_gal->SetStrokeColor( COLOR4D( 0.0, 0.0, 1.0, 1.0 ) );
  506. m_gal->DrawLine( pos, wxPoint( 0, 0 ) );
  507. }
  508. }
  509. void SCH_PAINTER::draw( LIB_TEXT *aText, int aLayer )
  510. {
  511. if( !isUnitAndConversionShown( aText ) )
  512. return;
  513. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  514. if( drawingShadows && !aText->IsSelected() )
  515. return;
  516. COLOR4D color = getRenderColor( aText, LAYER_DEVICE, drawingShadows );
  517. if( !aText->IsVisible() )
  518. {
  519. if( m_schSettings.m_ShowHiddenText )
  520. color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
  521. else
  522. return;
  523. }
  524. EDA_RECT bBox = aText->GetBoundingBox();
  525. bBox.RevertYAxis();
  526. VECTOR2D pos = mapCoords( bBox.Centre() );
  527. double orient = aText->GetTextAngleRadians();
  528. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  529. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  530. m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
  531. m_gal->SetIsFill( false );
  532. m_gal->SetIsStroke( true );
  533. m_gal->SetStrokeColor( color );
  534. m_gal->SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
  535. m_gal->SetFontBold( aText->IsBold() );
  536. m_gal->SetFontItalic( aText->IsItalic() );
  537. strokeText( aText->GetText(), pos, orient );
  538. }
  539. int SCH_PAINTER::internalPinDecoSize( const LIB_PIN &aPin )
  540. {
  541. if( m_schSettings.m_PinSymbolSize > 0 )
  542. return m_schSettings.m_PinSymbolSize;
  543. return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
  544. }
  545. // Utility for getting the size of the 'external' pin decorators (as a radius)
  546. // i.e. the negation circle, the polarity 'slopes' and the nonlogic marker
  547. int SCH_PAINTER::externalPinDecoSize( const LIB_PIN &aPin )
  548. {
  549. if( m_schSettings.m_PinSymbolSize > 0 )
  550. return m_schSettings.m_PinSymbolSize;
  551. return aPin.GetNumberTextSize() / 2;
  552. }
  553. // Draw the target (an open circle) for a pin which has no connection or is being moved.
  554. void SCH_PAINTER::drawPinDanglingSymbol( const VECTOR2I& aPos, bool aDrawingShadows )
  555. {
  556. m_gal->SetIsFill( false );
  557. m_gal->SetIsStroke( true );
  558. m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth() : 1.0F );
  559. m_gal->DrawCircle( aPos, TARGET_PIN_RADIUS );
  560. }
  561. void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
  562. {
  563. if( !isUnitAndConversionShown( aPin ) )
  564. return;
  565. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  566. if( drawingShadows && !aPin->IsSelected() )
  567. return;
  568. VECTOR2I pos = mapCoords( aPin->GetPosition() );
  569. COLOR4D color = getRenderColor( aPin, LAYER_PIN, drawingShadows );
  570. if( !aPin->IsVisible() )
  571. {
  572. if( m_schSettings.m_ShowHiddenPins )
  573. {
  574. color = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows );
  575. }
  576. else
  577. {
  578. if( aPin->HasFlag( IS_DANGLING ) && aPin->IsPowerConnection() )
  579. drawPinDanglingSymbol( pos, drawingShadows );
  580. return;
  581. }
  582. }
  583. VECTOR2I p0;
  584. VECTOR2I dir;
  585. int len = aPin->GetLength();
  586. int orient = aPin->GetOrientation();
  587. switch( orient )
  588. {
  589. case PIN_UP:
  590. p0 = VECTOR2I( pos.x, pos.y - len );
  591. dir = VECTOR2I( 0, 1 );
  592. break;
  593. case PIN_DOWN:
  594. p0 = VECTOR2I( pos.x, pos.y + len );
  595. dir = VECTOR2I( 0, -1 );
  596. break;
  597. case PIN_LEFT:
  598. p0 = VECTOR2I( pos.x - len, pos.y );
  599. dir = VECTOR2I( 1, 0 );
  600. break;
  601. default:
  602. case PIN_RIGHT:
  603. p0 = VECTOR2I( pos.x + len, pos.y );
  604. dir = VECTOR2I( -1, 0 );
  605. break;
  606. }
  607. VECTOR2D pc;
  608. m_gal->SetIsStroke( true );
  609. m_gal->SetIsFill( false );
  610. m_gal->SetLineWidth( getLineWidth( aPin, drawingShadows ) );
  611. m_gal->SetStrokeColor( color );
  612. m_gal->SetFontBold( false );
  613. m_gal->SetFontItalic( false );
  614. const int radius = externalPinDecoSize( *aPin );
  615. const int diam = radius*2;
  616. const int clock_size = internalPinDecoSize( *aPin );
  617. if( aPin->GetType() == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
  618. {
  619. m_gal->DrawLine( p0, pos );
  620. m_gal->DrawLine( pos + VECTOR2D( -1, -1 ) * TARGET_PIN_RADIUS,
  621. pos + VECTOR2D( 1, 1 ) * TARGET_PIN_RADIUS );
  622. m_gal->DrawLine( pos + VECTOR2D( 1, -1 ) * TARGET_PIN_RADIUS ,
  623. pos + VECTOR2D( -1, 1 ) * TARGET_PIN_RADIUS );
  624. aPin->ClearFlags( IS_DANGLING ); // PIN_NC pin type is always not connected and dangling.
  625. }
  626. else
  627. {
  628. switch( aPin->GetShape() )
  629. {
  630. case GRAPHIC_PINSHAPE::LINE:
  631. m_gal->DrawLine( p0, pos );
  632. break;
  633. case GRAPHIC_PINSHAPE::INVERTED:
  634. m_gal->DrawCircle( p0 + dir * radius, radius );
  635. m_gal->DrawLine( p0 + dir * ( diam ), pos );
  636. break;
  637. case GRAPHIC_PINSHAPE::INVERTED_CLOCK:
  638. pc = p0 - dir * clock_size ;
  639. triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
  640. pc,
  641. p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
  642. m_gal->DrawCircle( p0 + dir * radius, radius );
  643. m_gal->DrawLine( p0 + dir * ( diam ), pos );
  644. break;
  645. case GRAPHIC_PINSHAPE::CLOCK_LOW:
  646. case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK:
  647. pc = p0 - dir * clock_size ;
  648. triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
  649. pc,
  650. p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
  651. if( !dir.y )
  652. {
  653. triLine( p0 + VECTOR2D(dir.x, 0) * diam,
  654. p0 + VECTOR2D(dir.x, -1) * diam,
  655. p0 );
  656. }
  657. else /* MapX1 = 0 */
  658. {
  659. triLine( p0 + VECTOR2D( 0, dir.y) * diam,
  660. p0 + VECTOR2D(-1, dir.y) * diam,
  661. p0 );
  662. }
  663. m_gal->DrawLine( p0, pos );
  664. break;
  665. case GRAPHIC_PINSHAPE::CLOCK:
  666. m_gal->DrawLine( p0, pos );
  667. if( !dir.y )
  668. {
  669. triLine( p0 + VECTOR2D( 0, clock_size ),
  670. p0 + VECTOR2D( -dir.x * clock_size, 0 ),
  671. p0 + VECTOR2D( 0, -clock_size ) );
  672. }
  673. else
  674. {
  675. triLine( p0 + VECTOR2D( clock_size, 0 ),
  676. p0 + VECTOR2D( 0, -dir.y * clock_size ),
  677. p0 + VECTOR2D( -clock_size, 0 ) );
  678. }
  679. break;
  680. case GRAPHIC_PINSHAPE::INPUT_LOW:
  681. m_gal->DrawLine( p0, pos );
  682. if( !dir.y )
  683. {
  684. triLine( p0 + VECTOR2D(dir.x, 0) * diam,
  685. p0 + VECTOR2D(dir.x, -1) * diam,
  686. p0 );
  687. }
  688. else /* MapX1 = 0 */
  689. {
  690. triLine( p0 + VECTOR2D( 0, dir.y) * diam,
  691. p0 + VECTOR2D(-1, dir.y) * diam,
  692. p0 );
  693. }
  694. break;
  695. case GRAPHIC_PINSHAPE::OUTPUT_LOW: // IEEE symbol "Active Low Output"
  696. m_gal->DrawLine( p0, pos );
  697. if( !dir.y ) // Horizontal pin
  698. m_gal->DrawLine( p0 - VECTOR2D( 0, diam ), p0 + VECTOR2D( dir.x, 0 ) * diam );
  699. else // Vertical pin
  700. m_gal->DrawLine( p0 - VECTOR2D( diam, 0 ), p0 + VECTOR2D( 0, dir.y ) * diam );
  701. break;
  702. case GRAPHIC_PINSHAPE::NONLOGIC: // NonLogic pin symbol
  703. m_gal->DrawLine( p0, pos );
  704. m_gal->DrawLine( p0 - VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius,
  705. p0 + VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius );
  706. m_gal->DrawLine( p0 - VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius,
  707. p0 + VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius );
  708. break;
  709. }
  710. }
  711. if( aPin->HasFlag( IS_DANGLING ) && ( aPin->IsVisible() || aPin->IsPowerConnection() ) )
  712. drawPinDanglingSymbol( pos, drawingShadows );
  713. LIB_PART* libEntry = aPin->GetParent();
  714. // Draw the labels
  715. if( drawingShadows && ( libEntry->Type() == LIB_PART_T || libEntry->IsSelected() )
  716. && !eeconfig()->m_Selection.draw_selected_children )
  717. return;
  718. int textOffset = libEntry->GetPinNameOffset();
  719. float nameLineWidth = getLineWidth( aPin, drawingShadows );
  720. nameLineWidth = Clamp_Text_PenSize( nameLineWidth, aPin->GetNameTextSize(), false );
  721. float numLineWidth = getLineWidth( aPin, drawingShadows );
  722. numLineWidth = Clamp_Text_PenSize( numLineWidth, aPin->GetNumberTextSize(), false );
  723. #define PIN_TEXT_MARGIN 4.0
  724. // Four locations around a pin where text can be drawn
  725. enum { INSIDE = 0, OUTSIDE, ABOVE, BELOW };
  726. int size[4] = { 0, 0, 0, 0 };
  727. float thickness[4] = { numLineWidth, numLineWidth, numLineWidth, numLineWidth };
  728. COLOR4D colour[4];
  729. wxString text[4];
  730. // TextOffset > 0 means pin NAMES on inside, pin NUMBERS above and nothing below
  731. if( textOffset )
  732. {
  733. size [INSIDE] = libEntry->ShowPinNames() ? aPin->GetNameTextSize() : 0;
  734. thickness[INSIDE] = nameLineWidth;
  735. colour [INSIDE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows );
  736. text [INSIDE] = aPin->GetName();
  737. size [ABOVE] = libEntry->ShowPinNumbers() ? aPin->GetNumberTextSize() : 0;
  738. thickness[ABOVE] = numLineWidth;
  739. colour [ABOVE] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows );
  740. text [ABOVE] = aPin->GetNumber();
  741. }
  742. // Otherwise pin NAMES go above and pin NUMBERS go below
  743. else
  744. {
  745. size [ABOVE] = libEntry->ShowPinNames() ? aPin->GetNameTextSize() : 0;
  746. thickness[ABOVE] = nameLineWidth;
  747. colour [ABOVE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows );
  748. text [ABOVE] = aPin->GetName();
  749. size [BELOW] = libEntry->ShowPinNumbers() ? aPin->GetNumberTextSize() : 0;
  750. thickness[BELOW] = numLineWidth;
  751. colour [BELOW] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows );
  752. text [BELOW] = aPin->GetNumber();
  753. }
  754. if( m_schSettings.m_ShowPinsElectricalType )
  755. {
  756. size [OUTSIDE] = std::max( aPin->GetNameTextSize() * 3 / 4, Millimeter2iu( 0.7 ) );
  757. thickness[OUTSIDE] = float( size[OUTSIDE] ) / 6.0F;
  758. colour [OUTSIDE] = getRenderColor( aPin, LAYER_NOTES, drawingShadows );
  759. text [OUTSIDE] = aPin->GetElectricalTypeName();
  760. }
  761. if( !aPin->IsVisible() )
  762. {
  763. for( COLOR4D& c : colour )
  764. c = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows );
  765. }
  766. int insideOffset = textOffset;
  767. int outsideOffset = 10;
  768. float lineThickness = (float) m_schSettings.GetDefaultPenWidth();
  769. float aboveOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[ABOVE] + lineThickness ) / 2.0;
  770. float belowOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[BELOW] + lineThickness ) / 2.0;
  771. if( drawingShadows )
  772. {
  773. for( float& t : thickness )
  774. t += getShadowWidth();
  775. insideOffset -= KiROUND( getShadowWidth() / 2 );
  776. outsideOffset -= KiROUND( getShadowWidth() / 2 );
  777. }
  778. #define SET_DC( i ) \
  779. m_gal->SetGlyphSize( VECTOR2D( size[i], size[i] ) ); \
  780. m_gal->SetLineWidth( thickness[i] ); \
  781. m_gal->SetStrokeColor( colour[i] )
  782. switch( orient )
  783. {
  784. case PIN_LEFT:
  785. if( size[INSIDE] )
  786. {
  787. SET_DC( INSIDE );
  788. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  789. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  790. strokeText( text[INSIDE], pos + VECTOR2D( -insideOffset - len, 0 ), 0 );
  791. }
  792. if( size[OUTSIDE] )
  793. {
  794. SET_DC( OUTSIDE );
  795. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  796. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  797. strokeText( text[OUTSIDE], pos + VECTOR2D( outsideOffset, 0 ), 0 );
  798. }
  799. if( size[ABOVE] )
  800. {
  801. SET_DC( ABOVE );
  802. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  803. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  804. strokeText( text[ABOVE], pos + VECTOR2D( -len / 2.0, -aboveOffset ), 0 );
  805. }
  806. if( size[BELOW] )
  807. {
  808. SET_DC( BELOW );
  809. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  810. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  811. strokeText( text[BELOW], pos + VECTOR2D( -len / 2.0, belowOffset ), 0 );
  812. }
  813. break;
  814. case PIN_RIGHT:
  815. if( size[INSIDE] )
  816. {
  817. SET_DC( INSIDE );
  818. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  819. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  820. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  821. strokeText( text[INSIDE], pos + VECTOR2D( insideOffset + len, 0 ), 0 );
  822. }
  823. if( size[OUTSIDE] )
  824. {
  825. SET_DC( OUTSIDE );
  826. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  827. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  828. strokeText( text[OUTSIDE], pos + VECTOR2D( -outsideOffset, 0 ), 0 );
  829. }
  830. if( size[ABOVE] )
  831. {
  832. SET_DC( ABOVE );
  833. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  834. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  835. strokeText( text[ABOVE], pos + VECTOR2D( len / 2.0, -aboveOffset ), 0 );
  836. }
  837. if( size[BELOW] )
  838. {
  839. SET_DC( BELOW );
  840. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  841. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  842. strokeText( text[BELOW], pos + VECTOR2D( len / 2.0, belowOffset ), 0 );
  843. }
  844. break;
  845. case PIN_DOWN:
  846. if( size[INSIDE] )
  847. {
  848. SET_DC( INSIDE );
  849. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  850. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  851. strokeText( text[INSIDE], pos + VECTOR2D( 0, insideOffset + len ), M_PI / 2 );
  852. }
  853. if( size[OUTSIDE] )
  854. {
  855. SET_DC( OUTSIDE );
  856. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  857. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  858. strokeText( text[OUTSIDE], pos + VECTOR2D( 0, -outsideOffset ), M_PI / 2 );
  859. }
  860. if( size[ABOVE] )
  861. {
  862. SET_DC( ABOVE );
  863. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  864. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  865. strokeText( text[ABOVE], pos + VECTOR2D( -aboveOffset, len / 2.0 ), M_PI / 2 );
  866. }
  867. if( size[BELOW] )
  868. {
  869. SET_DC( BELOW );
  870. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  871. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  872. strokeText( text[BELOW], pos + VECTOR2D( belowOffset, len / 2.0 ), M_PI / 2 );
  873. }
  874. break;
  875. case PIN_UP:
  876. if( size[INSIDE] )
  877. {
  878. SET_DC( INSIDE );
  879. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  880. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  881. strokeText( text[INSIDE], pos + VECTOR2D( 0, -insideOffset - len ), M_PI / 2 );
  882. }
  883. if( size[OUTSIDE] )
  884. {
  885. SET_DC( OUTSIDE );
  886. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  887. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  888. strokeText( text[OUTSIDE], pos + VECTOR2D( 0, outsideOffset ), M_PI / 2 );
  889. }
  890. if( size[ABOVE] )
  891. {
  892. SET_DC( ABOVE );
  893. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  894. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  895. strokeText( text[ABOVE], pos + VECTOR2D( -aboveOffset, -len / 2.0 ), M_PI / 2 );
  896. }
  897. if( size[BELOW] )
  898. {
  899. SET_DC( BELOW );
  900. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  901. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  902. strokeText( text[BELOW], pos + VECTOR2D( belowOffset, -len / 2.0 ), M_PI / 2 );
  903. }
  904. break;
  905. default:
  906. wxFAIL_MSG( "Unknown pin orientation" );
  907. }
  908. }
  909. void SCH_PAINTER::draw( LIB_BEZIER *aCurve, int aLayer )
  910. {
  911. if( !isUnitAndConversionShown( aCurve ) )
  912. return;
  913. if( setDeviceColors( aCurve, aLayer ) )
  914. {
  915. BEZIER_POLY poly ( aCurve->GetPoints() );
  916. std::vector<wxPoint> pts;
  917. std::deque<VECTOR2D> pts_xformed;
  918. poly.GetPoly( pts );
  919. for( const auto &p : pts )
  920. pts_xformed.push_back( mapCoords( p ) );
  921. m_gal->DrawPolygon( pts_xformed );
  922. }
  923. }
  924. // Draw the target (an open square) for a wire or label which has no connection or is
  925. // being moved.
  926. void SCH_PAINTER::drawDanglingSymbol( const wxPoint& aPos, bool aDrawingShadows )
  927. {
  928. wxPoint radius( Mils2iu( DANGLING_SYMBOL_SIZE ), Mils2iu( DANGLING_SYMBOL_SIZE ) );
  929. m_gal->SetIsStroke( true );
  930. m_gal->SetIsFill( false );
  931. m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth() : 1.0F );
  932. m_gal->DrawRectangle( aPos - radius, aPos + radius );
  933. }
  934. void SCH_PAINTER::draw( SCH_JUNCTION *aJct, int aLayer )
  935. {
  936. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  937. if( drawingShadows && !aJct->IsSelected() )
  938. return;
  939. COLOR4D color = getRenderColor( aJct, aJct->GetLayer(), drawingShadows );
  940. m_gal->SetIsStroke( drawingShadows );
  941. m_gal->SetLineWidth( getLineWidth( aJct, drawingShadows ) );
  942. m_gal->SetStrokeColor( color );
  943. m_gal->SetIsFill( !drawingShadows );
  944. m_gal->SetFillColor( color );
  945. m_gal->DrawCircle( aJct->GetPosition(), SCH_JUNCTION::GetSymbolSize() / 2.0 );
  946. }
  947. void SCH_PAINTER::draw( SCH_LINE *aLine, int aLayer )
  948. {
  949. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  950. if( drawingShadows && !aLine->IsSelected() )
  951. return;
  952. COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
  953. float width = getLineWidth( aLine, drawingShadows );
  954. m_gal->SetIsStroke( true );
  955. m_gal->SetStrokeColor( color );
  956. m_gal->SetLineWidth( width );
  957. if( aLine->GetLineStyle() <= PLOT_DASH_TYPE::FIRST_TYPE || drawingShadows )
  958. {
  959. m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() );
  960. }
  961. else
  962. {
  963. VECTOR2D start = aLine->GetStartPoint();
  964. VECTOR2D end = aLine->GetEndPoint();
  965. EDA_RECT clip( (wxPoint)start, wxSize( end.x - start.x, end.y - start.y ) );
  966. clip.Normalize();
  967. double theta = atan2( end.y - start.y, end.x - start.x );
  968. double strokes[] = { 1.0, DASH_GAP_LEN( width ), 1.0, DASH_GAP_LEN( width ) };
  969. switch( aLine->GetLineStyle() )
  970. {
  971. default:
  972. case PLOT_DASH_TYPE::DASH:
  973. strokes[0] = strokes[2] = DASH_MARK_LEN( width );
  974. break;
  975. case PLOT_DASH_TYPE::DOT:
  976. strokes[0] = strokes[2] = DOT_MARK_LEN( width );
  977. break;
  978. case PLOT_DASH_TYPE::DASHDOT:
  979. strokes[0] = DASH_MARK_LEN( width );
  980. strokes[2] = DOT_MARK_LEN( width );
  981. break;
  982. }
  983. for( size_t i = 0; i < 10000; ++i )
  984. {
  985. // Calculations MUST be done in doubles to keep from accumulating rounding
  986. // errors as we go.
  987. VECTOR2D next( start.x + strokes[ i % 4 ] * cos( theta ),
  988. start.y + strokes[ i % 4 ] * sin( theta ) );
  989. // Drawing each segment can be done rounded to ints.
  990. wxPoint segStart( KiROUND( start.x ), KiROUND( start.y ) );
  991. wxPoint segEnd( KiROUND( next.x ), KiROUND( next.y ) );
  992. if( ClipLine( &clip, segStart.x, segStart.y, segEnd.x, segEnd.y ) )
  993. break;
  994. else if( i % 2 == 0 )
  995. m_gal->DrawLine( segStart, segEnd );
  996. start = next;
  997. }
  998. }
  999. if( aLine->IsStartDangling() )
  1000. drawDanglingSymbol( aLine->GetStartPoint(), drawingShadows );
  1001. if( aLine->IsEndDangling() )
  1002. drawDanglingSymbol( aLine->GetEndPoint(), drawingShadows );
  1003. }
  1004. void SCH_PAINTER::draw( SCH_TEXT *aText, int aLayer )
  1005. {
  1006. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1007. if( drawingShadows && !aText->IsSelected() )
  1008. return;
  1009. switch( aText->Type() )
  1010. {
  1011. case SCH_SHEET_PIN_T: aLayer = LAYER_SHEETLABEL; break;
  1012. case SCH_HIER_LABEL_T: aLayer = LAYER_HIERLABEL; break;
  1013. case SCH_GLOBAL_LABEL_T: aLayer = LAYER_GLOBLABEL; break;
  1014. case SCH_LABEL_T: aLayer = LAYER_LOCLABEL; break;
  1015. default: aLayer = LAYER_NOTES; break;
  1016. }
  1017. COLOR4D color = getRenderColor( aText, aLayer, drawingShadows );
  1018. SCH_CONNECTION* conn = aText->Connection( *g_CurrentSheet );
  1019. if( conn && conn->IsBus() )
  1020. color = getRenderColor( aText, LAYER_BUS, drawingShadows );
  1021. if( !( aText->IsVisible() || aText->IsForceVisible() ) )
  1022. {
  1023. if( m_schSettings.m_ShowHiddenText )
  1024. color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
  1025. else
  1026. return;
  1027. }
  1028. m_gal->SetIsFill( false );
  1029. m_gal->SetIsStroke( true );
  1030. m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
  1031. m_gal->SetStrokeColor( color );
  1032. m_gal->SetTextAttributes( aText );
  1033. VECTOR2D text_offset = aText->GetTextPos() + aText->GetSchematicTextOffset( &m_schSettings );
  1034. wxString shownText( aText->GetShownText() );
  1035. if( drawingShadows )
  1036. {
  1037. if( eeconfig()->m_Selection.text_as_box )
  1038. {
  1039. EDA_RECT bBox = aText->GetBoundingBox();
  1040. m_gal->SetIsFill( true );
  1041. m_gal->SetFillColor( color );
  1042. m_gal->SetLineWidth( m_gal->GetLineWidth() * 0.5 );
  1043. bBox.RevertYAxis();
  1044. m_gal->DrawRectangle( mapCoords( bBox.GetPosition() ), mapCoords( bBox.GetEnd() ) );
  1045. return;
  1046. }
  1047. switch( aText->GetLabelSpinStyle() )
  1048. {
  1049. case LABEL_SPIN_STYLE::LEFT:
  1050. text_offset.x += getShadowWidth() / 2;
  1051. break;
  1052. case LABEL_SPIN_STYLE::UP:
  1053. text_offset.y += getShadowWidth() / 2;
  1054. break;
  1055. case LABEL_SPIN_STYLE::RIGHT:
  1056. text_offset.x -= getShadowWidth() / 2;
  1057. break;
  1058. case LABEL_SPIN_STYLE::BOTTOM:
  1059. text_offset.y -= getShadowWidth() / 2;
  1060. break;
  1061. }
  1062. }
  1063. if( !shownText.IsEmpty() )
  1064. {
  1065. strokeText( shownText, text_offset, aText->GetTextAngleRadians() );
  1066. }
  1067. if( aText->IsDangling() )
  1068. drawDanglingSymbol( aText->GetTextPos(), drawingShadows );
  1069. }
  1070. static void orientPart( LIB_PART* part, int orientation )
  1071. {
  1072. struct ORIENT
  1073. {
  1074. int flag;
  1075. int n_rots;
  1076. int mirror_x;
  1077. int mirror_y;
  1078. }
  1079. orientations[] =
  1080. {
  1081. { CMP_ORIENT_0, 0, 0, 0 },
  1082. { CMP_ORIENT_90, 1, 0, 0 },
  1083. { CMP_ORIENT_180, 2, 0, 0 },
  1084. { CMP_ORIENT_270, 3, 0, 0 },
  1085. { CMP_MIRROR_X + CMP_ORIENT_0, 0, 1, 0 },
  1086. { CMP_MIRROR_X + CMP_ORIENT_90, 1, 1, 0 },
  1087. { CMP_MIRROR_Y, 0, 0, 1 },
  1088. { CMP_MIRROR_X + CMP_ORIENT_270, 3, 1, 0 },
  1089. { CMP_MIRROR_Y + CMP_ORIENT_0, 0, 0, 1 },
  1090. { CMP_MIRROR_Y + CMP_ORIENT_90, 1, 0, 1 },
  1091. { CMP_MIRROR_Y + CMP_ORIENT_180, 2, 0, 1 },
  1092. { CMP_MIRROR_Y + CMP_ORIENT_270, 3, 0, 1 }
  1093. };
  1094. ORIENT o = orientations[ 0 ];
  1095. for( auto& i : orientations )
  1096. {
  1097. if( i.flag == orientation )
  1098. {
  1099. o = i;
  1100. break;
  1101. }
  1102. }
  1103. for( auto& item : part->GetDrawItems() )
  1104. {
  1105. for( int i = 0; i < o.n_rots; i++ )
  1106. item.Rotate( wxPoint(0, 0 ), true );
  1107. if( o.mirror_x )
  1108. item.MirrorVertical( wxPoint( 0, 0 ) );
  1109. if( o.mirror_y )
  1110. item.MirrorHorizontal( wxPoint( 0, 0 ) );
  1111. }
  1112. }
  1113. void SCH_PAINTER::draw( SCH_COMPONENT *aComp, int aLayer )
  1114. {
  1115. // Use dummy part if the actual couldn't be found (or couldn't be locked).
  1116. LIB_PART* originalPart = aComp->GetPartRef() ? aComp->GetPartRef().get() : dummy();
  1117. // Copy the source so we can re-orient and translate it.
  1118. LIB_PART tempPart( *originalPart );
  1119. tempPart.SetFlags( aComp->GetFlags() );
  1120. orientPart( &tempPart, aComp->GetOrientation() );
  1121. for( auto& tempItem : tempPart.GetDrawItems() )
  1122. {
  1123. tempItem.SetFlags( aComp->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED
  1124. tempItem.MoveTo( tempItem.GetPosition() + (wxPoint) mapCoords( aComp->GetPosition() ) );
  1125. }
  1126. // Copy the pin info from the component to the temp pins
  1127. LIB_PINS tempPins;
  1128. tempPart.GetPins( tempPins, aComp->GetUnit(), aComp->GetConvert() );
  1129. const SCH_PIN_PTRS compPins = aComp->GetSchPins();
  1130. for( unsigned i = 0; i < tempPins.size() && i < compPins.size(); ++ i )
  1131. {
  1132. LIB_PIN* tempPin = tempPins[ i ];
  1133. const SCH_PIN* compPin = compPins[ i ];
  1134. tempPin->ClearFlags();
  1135. tempPin->SetFlags( compPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED
  1136. if( compPin->IsDangling() )
  1137. tempPin->SetFlags( IS_DANGLING );
  1138. }
  1139. draw( &tempPart, aLayer, false, aComp->GetUnit(), aComp->GetConvert() );
  1140. // The fields are SCH_COMPONENT-specific so don't need to be copied/oriented/translated
  1141. for( SCH_FIELD& field : aComp->GetFields() )
  1142. draw( &field, aLayer );
  1143. }
  1144. void SCH_PAINTER::draw( SCH_FIELD *aField, int aLayer )
  1145. {
  1146. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1147. if( drawingShadows && !aField->IsSelected() )
  1148. return;
  1149. aLayer = aField->GetLayer();
  1150. COLOR4D color = getRenderColor( aField, aLayer, drawingShadows );
  1151. if( !( aField->IsVisible() || aField->IsForceVisible() ) )
  1152. {
  1153. if( m_schSettings.m_ShowHiddenText )
  1154. color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows );
  1155. else
  1156. return;
  1157. }
  1158. if( aField->IsVoid() )
  1159. return;
  1160. if( drawingShadows && aField->GetParent()->IsSelected()
  1161. && !eeconfig()->m_Selection.draw_selected_children )
  1162. {
  1163. return;
  1164. }
  1165. // Calculate the text orientation according to the parent orientation.
  1166. int orient = (int) aField->GetTextAngle();
  1167. if( aField->GetParent() && aField->GetParent()->Type() == SCH_COMPONENT_T )
  1168. {
  1169. if( static_cast<SCH_COMPONENT*>( aField->GetParent() )->GetTransform().y1 )
  1170. {
  1171. // Rotate component 90 degrees.
  1172. if( orient == TEXT_ANGLE_HORIZ )
  1173. orient = TEXT_ANGLE_VERT;
  1174. else
  1175. orient = TEXT_ANGLE_HORIZ;
  1176. }
  1177. }
  1178. /* Calculate the text justification, according to the component orientation/mirror.
  1179. * This is a bit complicated due to cumulative calculations:
  1180. * - numerous cases (mirrored or not, rotation)
  1181. * - the DrawGraphicText function recalculate also H and H justifications according to the
  1182. * text orientation.
  1183. * - When a component is mirrored, the text is not mirrored and justifications are
  1184. * complicated to calculate
  1185. * so the easier way is to use no justifications (centered text) and use GetBoundingBox
  1186. * to know the text coordinate considered as centered
  1187. */
  1188. EDA_RECT boundaryBox = aField->GetBoundingBox();
  1189. wxPoint textpos = boundaryBox.Centre();
  1190. m_gal->SetStrokeColor( color );
  1191. m_gal->SetIsStroke( true );
  1192. if( drawingShadows && eeconfig()->m_Selection.text_as_box )
  1193. {
  1194. m_gal->SetIsFill( true );
  1195. m_gal->SetFillColor( color );
  1196. m_gal->SetLineWidth( m_gal->GetLineWidth() * 0.5 );
  1197. boundaryBox.RevertYAxis();
  1198. m_gal->DrawRectangle( mapCoords( boundaryBox.GetPosition() ),
  1199. mapCoords( boundaryBox.GetEnd() ) );
  1200. }
  1201. else
  1202. {
  1203. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  1204. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  1205. m_gal->SetIsFill( false );
  1206. m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
  1207. m_gal->SetFontBold( aField->IsBold() );
  1208. m_gal->SetFontItalic( aField->IsItalic() );
  1209. m_gal->SetTextMirrored( aField->IsMirrored() );
  1210. m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
  1211. strokeText( aField->GetShownText(), textpos, orient == TEXT_ANGLE_VERT ? M_PI / 2 : 0 );
  1212. }
  1213. // Draw the umbilical line
  1214. if( aField->IsMoving() )
  1215. {
  1216. wxPoint parentPos = aField->GetParentPosition();
  1217. m_gal->SetLineWidth( m_schSettings.m_outlineWidth );
  1218. m_gal->SetStrokeColor( COLOR4D( 0.0, 0.0, 1.0, 1.0 ) );
  1219. m_gal->DrawLine( textpos, parentPos );
  1220. }
  1221. }
  1222. void SCH_PAINTER::draw( SCH_GLOBALLABEL *aLabel, int aLayer )
  1223. {
  1224. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1225. if( drawingShadows && !aLabel->IsSelected() )
  1226. return;
  1227. COLOR4D color = getRenderColor( aLabel, LAYER_GLOBLABEL, drawingShadows );
  1228. std::vector<wxPoint> pts;
  1229. std::deque<VECTOR2D> pts2;
  1230. aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
  1231. for( auto p : pts )
  1232. pts2.emplace_back( VECTOR2D( p.x, p.y ) );
  1233. // the text is drawn inside the graphic shape.
  1234. // On Cairo the graphic shape is filled by the background
  1235. // before drawing the text ().
  1236. // However if the text is selected, it is draw twice:
  1237. // first, on LAYER_SELECTION_SHADOWS
  1238. // second, on the text layer.
  1239. // the second must not erase the first drawing.
  1240. bool fillBg = ( aLayer == LAYER_SELECTION_SHADOWS ) || !aLabel->IsSelected();
  1241. m_gal->SetIsFill( fillBg );
  1242. m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  1243. m_gal->SetIsStroke( true );
  1244. m_gal->SetLineWidth( getTextThickness( aLabel, drawingShadows ) );
  1245. m_gal->SetStrokeColor( color );
  1246. m_gal->DrawPolyline( pts2 );
  1247. draw( static_cast<SCH_TEXT*>( aLabel ), aLayer );
  1248. }
  1249. void SCH_PAINTER::draw( SCH_HIERLABEL *aLabel, int aLayer )
  1250. {
  1251. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1252. if( drawingShadows && !aLabel->IsSelected() )
  1253. return;
  1254. COLOR4D color = getRenderColor( aLabel, LAYER_SHEETLABEL, drawingShadows );
  1255. SCH_CONNECTION* conn = aLabel->Connection( *g_CurrentSheet );
  1256. if( conn && conn->IsBus() )
  1257. color = getRenderColor( aLabel, LAYER_BUS, drawingShadows );
  1258. std::vector<wxPoint> pts;
  1259. std::deque<VECTOR2D> pts2;
  1260. aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
  1261. for( auto p : pts )
  1262. pts2.emplace_back( VECTOR2D( p.x, p.y ) );
  1263. m_gal->SetIsFill( true );
  1264. m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  1265. m_gal->SetIsStroke( true );
  1266. m_gal->SetLineWidth( getTextThickness( aLabel, drawingShadows ) );
  1267. m_gal->SetStrokeColor( color );
  1268. m_gal->DrawPolyline( pts2 );
  1269. draw( static_cast<SCH_TEXT*>( aLabel ), aLayer );
  1270. }
  1271. void SCH_PAINTER::draw( SCH_SHEET *aSheet, int aLayer )
  1272. {
  1273. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1274. if( aLayer == LAYER_HIERLABEL || aLayer == LAYER_SELECTION_SHADOWS )
  1275. {
  1276. for( SCH_SHEET_PIN* sheetPin : aSheet->GetPins() )
  1277. {
  1278. if( drawingShadows && !aSheet->IsSelected() && !sheetPin->IsSelected() )
  1279. continue;
  1280. if( drawingShadows && aSheet->IsSelected()
  1281. && !eeconfig()->m_Selection.draw_selected_children )
  1282. {
  1283. break;
  1284. }
  1285. int width = std::max( aSheet->GetPenWidth(), m_schSettings.GetDefaultPenWidth() );
  1286. wxPoint initial_pos = sheetPin->GetTextPos();
  1287. wxPoint offset_pos = initial_pos;
  1288. // For aesthetic reasons, the SHEET_PIN is drawn with a small offset of width / 2
  1289. switch( sheetPin->GetEdge() )
  1290. {
  1291. case SHEET_TOP_SIDE: offset_pos.y += KiROUND( width / 2.0 ); break;
  1292. case SHEET_BOTTOM_SIDE: offset_pos.y -= KiROUND( width / 2.0 ); break;
  1293. case SHEET_RIGHT_SIDE: offset_pos.x -= KiROUND( width / 2.0 ); break;
  1294. case SHEET_LEFT_SIDE: offset_pos.x += KiROUND( width / 2.0 ); break;
  1295. default: break;
  1296. }
  1297. sheetPin->SetTextPos( offset_pos );
  1298. draw( static_cast<SCH_HIERLABEL*>( sheetPin ), aLayer );
  1299. m_gal->DrawLine( offset_pos, initial_pos );
  1300. sheetPin->SetTextPos( initial_pos );
  1301. }
  1302. }
  1303. VECTOR2D pos = aSheet->GetPosition();
  1304. VECTOR2D size = aSheet->GetSize();
  1305. if( aLayer == LAYER_SHEET_BACKGROUND )
  1306. {
  1307. m_gal->SetFillColor( getRenderColor( aSheet, LAYER_SHEET_BACKGROUND, true ) );
  1308. m_gal->SetIsFill( true );
  1309. m_gal->SetIsStroke( false );
  1310. m_gal->DrawRectangle( pos, pos + size );
  1311. }
  1312. if( aLayer == LAYER_SHEET || aLayer == LAYER_SELECTION_SHADOWS )
  1313. {
  1314. m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, drawingShadows ) );
  1315. m_gal->SetIsStroke( true );
  1316. m_gal->SetLineWidth( getLineWidth( aSheet, drawingShadows ) );
  1317. m_gal->SetIsFill( false );
  1318. m_gal->DrawRectangle( pos, pos + size );
  1319. if( drawingShadows && !eeconfig()->m_Selection.draw_selected_children && aSheet->IsSelected() )
  1320. return;
  1321. for( SCH_FIELD& field : aSheet->GetFields() )
  1322. draw( &field, aLayer );
  1323. }
  1324. }
  1325. void SCH_PAINTER::draw( SCH_NO_CONNECT *aNC, int aLayer )
  1326. {
  1327. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1328. if( drawingShadows && !aNC->IsSelected() )
  1329. return;
  1330. m_gal->SetIsStroke( true );
  1331. m_gal->SetLineWidth( getLineWidth( aNC, drawingShadows ) );
  1332. m_gal->SetStrokeColor( getRenderColor( aNC, LAYER_NOCONNECT, drawingShadows ) );
  1333. m_gal->SetIsFill( false );
  1334. VECTOR2D p = aNC->GetPosition();
  1335. int delta = std::max( aNC->GetSize(), m_schSettings.GetDefaultPenWidth() * 3 ) / 2;
  1336. m_gal->DrawLine( p + VECTOR2D( -delta, -delta ), p + VECTOR2D( delta, delta ) );
  1337. m_gal->DrawLine( p + VECTOR2D( -delta, delta ), p + VECTOR2D( delta, -delta ) );
  1338. }
  1339. void SCH_PAINTER::draw( SCH_BUS_ENTRY_BASE *aEntry, int aLayer )
  1340. {
  1341. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1342. if( drawingShadows && !aEntry->IsSelected() )
  1343. return;
  1344. COLOR4D color = getRenderColor( aEntry, LAYER_WIRE, drawingShadows );
  1345. if( aEntry->Type() == SCH_BUS_BUS_ENTRY_T )
  1346. color = getRenderColor( aEntry, LAYER_BUS, drawingShadows );
  1347. m_gal->SetIsStroke( true );
  1348. m_gal->SetLineWidth( getLineWidth( aEntry, drawingShadows ) );
  1349. m_gal->SetStrokeColor( color );
  1350. m_gal->SetIsFill( false );
  1351. VECTOR2D pos = aEntry->GetPosition();
  1352. VECTOR2D endPos = aEntry->m_End();
  1353. m_gal->DrawLine( pos, endPos );
  1354. // Draw dangling symbols:
  1355. m_gal->SetLineWidth ( getLineWidth( aEntry, drawingShadows ) );
  1356. if( aEntry->IsDanglingStart() )
  1357. m_gal->DrawCircle( pos, TARGET_BUSENTRY_RADIUS );
  1358. if( aEntry->IsDanglingEnd() )
  1359. m_gal->DrawCircle( endPos, TARGET_BUSENTRY_RADIUS );
  1360. }
  1361. void SCH_PAINTER::draw( SCH_BITMAP *aBitmap, int aLayer )
  1362. {
  1363. m_gal->Save();
  1364. m_gal->Translate( aBitmap->GetPosition() );
  1365. // When the image scale factor is not 1.0, we need to modify the actual as the image scale
  1366. // factor is similar to a local zoom
  1367. double img_scale = aBitmap->GetImageScale();
  1368. if( img_scale != 1.0 )
  1369. m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
  1370. if( aLayer == LAYER_DRAW_BITMAPS )
  1371. {
  1372. m_gal->DrawBitmap( *aBitmap->GetImage() );
  1373. }
  1374. if( aLayer == LAYER_SELECTION_SHADOWS )
  1375. {
  1376. if( aBitmap->IsSelected() || aBitmap->IsBrightened() || aBitmap->IsHighlighted() )
  1377. {
  1378. COLOR4D color = getRenderColor( aBitmap, LAYER_DRAW_BITMAPS, true );
  1379. m_gal->SetIsStroke( true );
  1380. m_gal->SetStrokeColor( color );
  1381. m_gal->SetLineWidth ( getShadowWidth() );
  1382. m_gal->SetIsFill( false );
  1383. // Draws a bounding box.
  1384. VECTOR2D bm_size( aBitmap->GetSize() );
  1385. // bm_size is the actual image size in UI.
  1386. // but m_gal scale was previously set to img_scale
  1387. // so recalculate size relative to this image size.
  1388. bm_size.x /= img_scale;
  1389. bm_size.y /= img_scale;
  1390. VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
  1391. VECTOR2D end = origin + bm_size;
  1392. m_gal->DrawRectangle( origin, end );
  1393. }
  1394. }
  1395. m_gal->Restore();
  1396. }
  1397. void SCH_PAINTER::draw( SCH_MARKER *aMarker, int aLayer )
  1398. {
  1399. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1400. if( drawingShadows && !aMarker->IsSelected() )
  1401. return;
  1402. COLOR4D color = getRenderColor( aMarker, aMarker->GetColorLayer(), drawingShadows );
  1403. m_gal->Save();
  1404. m_gal->Translate( aMarker->GetPosition() );
  1405. m_gal->SetIsFill( !drawingShadows );
  1406. m_gal->SetFillColor( color );
  1407. m_gal->SetIsStroke( drawingShadows );
  1408. m_gal->SetLineWidth( getLineWidth( aMarker, drawingShadows ) );
  1409. m_gal->SetStrokeColor( color );
  1410. SHAPE_LINE_CHAIN polygon;
  1411. aMarker->ShapeToPolygon( polygon );
  1412. m_gal->DrawPolygon( polygon );
  1413. m_gal->Restore();
  1414. }
  1415. }; // namespace KIGFX