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.

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