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
60 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 <trigo.h>
  28. #include <bezier_curves.h>
  29. #include <symbol_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_shape.h>
  36. #include <lib_field.h>
  37. #include <lib_item.h>
  38. #include <lib_pin.h>
  39. #include <lib_text.h>
  40. #include <math/util.h>
  41. #include <plotters/plotter.h>
  42. #include <sch_bitmap.h>
  43. #include <sch_bus_entry.h>
  44. #include <sch_symbol.h>
  45. #include <sch_edit_frame.h>
  46. #include <sch_field.h>
  47. #include <sch_junction.h>
  48. #include <sch_line.h>
  49. #include <sch_marker.h>
  50. #include <sch_no_connect.h>
  51. #include <sch_sheet.h>
  52. #include <sch_sheet_pin.h>
  53. #include <sch_text.h>
  54. #include <schematic.h>
  55. #include <settings/color_settings.h>
  56. #include <view/view.h>
  57. #include <kiface_base.h>
  58. #include <default_values.h>
  59. #include <advanced_config.h>
  60. #include <string_utils.h>
  61. #include "sch_painter.h"
  62. namespace KIGFX
  63. {
  64. SCH_RENDER_SETTINGS::SCH_RENDER_SETTINGS() :
  65. m_IsSymbolEditor( false ),
  66. m_ShowUnit( 0 ),
  67. m_ShowConvert( 0 ),
  68. m_ShowHiddenText( true ),
  69. m_ShowHiddenPins( true ),
  70. m_ShowPinsElectricalType( true ),
  71. m_ShowDisabled( false ),
  72. m_ShowGraphicsDisabled( false ),
  73. m_ShowUmbilicals( true ),
  74. m_OverrideItemColors( false ),
  75. m_LabelSizeRatio( DEFAULT_LABEL_SIZE_RATIO ),
  76. m_TextOffsetRatio( DEFAULT_TEXT_OFFSET_RATIO ),
  77. m_DefaultWireThickness( DEFAULT_WIRE_WIDTH_MILS * IU_PER_MILS ),
  78. m_DefaultBusThickness( DEFAULT_BUS_WIDTH_MILS * IU_PER_MILS ),
  79. m_PinSymbolSize( DEFAULT_TEXT_SIZE * IU_PER_MILS / 2 ),
  80. m_JunctionSize( DEFAULT_JUNCTION_DIAM * IU_PER_MILS )
  81. {
  82. SetDefaultPenWidth( DEFAULT_LINE_WIDTH_MILS * IU_PER_MILS );
  83. m_minPenWidth = ADVANCED_CFG::GetCfg().m_MinPlotPenWidth * IU_PER_MM;
  84. }
  85. void SCH_RENDER_SETTINGS::LoadColors( const COLOR_SETTINGS* aSettings )
  86. {
  87. for( int layer = SCH_LAYER_ID_START; layer < SCH_LAYER_ID_END; layer ++)
  88. m_layerColors[ layer ] = aSettings->GetColor( layer );
  89. for( int layer = GAL_LAYER_ID_START; layer < GAL_LAYER_ID_END; layer ++)
  90. m_layerColors[ layer ] = aSettings->GetColor( layer );
  91. m_backgroundColor = aSettings->GetColor( LAYER_SCHEMATIC_BACKGROUND );
  92. m_layerColors[LAYER_AUX_ITEMS] = m_layerColors[LAYER_SCHEMATIC_AUX_ITEMS];
  93. m_OverrideItemColors = aSettings->GetOverrideSchItemColors();
  94. }
  95. COLOR4D SCH_RENDER_SETTINGS::GetColor( const VIEW_ITEM* aItem, int aLayer ) const
  96. {
  97. return m_layerColors[ aLayer ];
  98. }
  99. EESCHEMA_SETTINGS* eeconfig()
  100. {
  101. return dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
  102. }
  103. /**
  104. * Used when a LIB_SYMBOL is not found in library to draw a dummy shape.
  105. * This symbol is a 400 mils square with the text "??"
  106. *
  107. * DEF DUMMY U 0 40 Y Y 1 0 N
  108. * F0 "U" 0 -350 60 H V
  109. * F1 "DUMMY" 0 350 60 H V
  110. * DRAW
  111. * T 0 0 0 150 0 0 0 ??
  112. * S -200 200 200 -200 0 1 0
  113. * ENDDRAW
  114. * ENDDEF
  115. */
  116. static LIB_SYMBOL* dummy()
  117. {
  118. static LIB_SYMBOL* symbol;
  119. if( !symbol )
  120. {
  121. symbol = new LIB_SYMBOL( wxEmptyString );
  122. LIB_SHAPE* square = new LIB_SHAPE( symbol, SHAPE_T::RECT );
  123. square->MoveTo( wxPoint( Mils2iu( -200 ), Mils2iu( 200 ) ) );
  124. square->SetEnd( wxPoint( Mils2iu( 200 ), Mils2iu( -200 ) ) );
  125. LIB_TEXT* text = new LIB_TEXT( symbol );
  126. text->SetTextSize( wxSize( Mils2iu( 150 ), Mils2iu( 150 ) ) );
  127. text->SetText( wxString( wxT( "??" ) ) );
  128. symbol->AddDrawItem( square );
  129. symbol->AddDrawItem( text );
  130. }
  131. return symbol;
  132. }
  133. SCH_PAINTER::SCH_PAINTER( GAL* aGal ) :
  134. KIGFX::PAINTER( aGal ),
  135. m_schematic( nullptr )
  136. { }
  137. #define HANDLE_ITEM( type_id, type_name ) \
  138. case type_id: draw( (type_name *) item, aLayer ); break
  139. bool SCH_PAINTER::Draw( const VIEW_ITEM *aItem, int aLayer )
  140. {
  141. const auto item = dynamic_cast<const EDA_ITEM*>( aItem );
  142. if( !item )
  143. return false;
  144. #ifdef CONNECTIVITY_DEBUG
  145. auto sch_item = dynamic_cast<const SCH_ITEM*>( item );
  146. auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
  147. if( conn )
  148. {
  149. auto pos = item->GetBoundingBox().Centre();
  150. auto label = conn->Name( true );
  151. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  152. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  153. m_gal->SetStrokeColor( COLOR4D( LIGHTRED ) );
  154. m_gal->SetLineWidth( Mils2ui( 2 ) );
  155. m_gal->SetGlyphSize( VECTOR2D( Mils2ui( 20 ), Mils2ui( 20 ) ) );
  156. m_gal->StrokeText( conn->Name( true ), pos, 0.0, 0 );
  157. }
  158. #endif
  159. if( ADVANCED_CFG::GetCfg().m_DrawBoundingBoxes )
  160. {
  161. BOX2I box = item->GetBoundingBox();
  162. if( item->Type() == SCH_SYMBOL_T )
  163. box = static_cast<const SCH_SYMBOL*>( item )->GetBodyBoundingBox();
  164. m_gal->SetIsFill( false );
  165. m_gal->SetIsStroke( true );
  166. m_gal->SetStrokeColor( item->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 )
  167. : COLOR4D( 0.2, 0.2, 0.2, 1 ) );
  168. m_gal->SetLineWidth( Mils2iu( 3 ) );
  169. m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
  170. }
  171. switch( item->Type() )
  172. {
  173. HANDLE_ITEM( LIB_SYMBOL_T, LIB_SYMBOL );
  174. HANDLE_ITEM( LIB_SHAPE_T, LIB_SHAPE );
  175. HANDLE_ITEM( LIB_PIN_T, LIB_PIN );
  176. HANDLE_ITEM( LIB_FIELD_T, LIB_FIELD );
  177. HANDLE_ITEM( LIB_TEXT_T, LIB_TEXT );
  178. HANDLE_ITEM( SCH_SYMBOL_T, SCH_SYMBOL );
  179. HANDLE_ITEM( SCH_JUNCTION_T, SCH_JUNCTION );
  180. HANDLE_ITEM( SCH_LINE_T, SCH_LINE );
  181. HANDLE_ITEM( SCH_TEXT_T, SCH_TEXT );
  182. HANDLE_ITEM( SCH_LABEL_T, SCH_TEXT );
  183. HANDLE_ITEM( SCH_FIELD_T, SCH_FIELD );
  184. HANDLE_ITEM( SCH_HIER_LABEL_T, SCH_HIERLABEL );
  185. HANDLE_ITEM( SCH_GLOBAL_LABEL_T, SCH_GLOBALLABEL );
  186. HANDLE_ITEM( SCH_SHEET_T, SCH_SHEET );
  187. HANDLE_ITEM( SCH_SHEET_PIN_T, SCH_HIERLABEL );
  188. HANDLE_ITEM( SCH_NO_CONNECT_T, SCH_NO_CONNECT );
  189. HANDLE_ITEM( SCH_BUS_WIRE_ENTRY_T, SCH_BUS_ENTRY_BASE );
  190. HANDLE_ITEM( SCH_BUS_BUS_ENTRY_T, SCH_BUS_ENTRY_BASE );
  191. HANDLE_ITEM( SCH_BITMAP_T, SCH_BITMAP );
  192. HANDLE_ITEM( SCH_MARKER_T, SCH_MARKER );
  193. default: return false;
  194. }
  195. return false;
  196. }
  197. bool SCH_PAINTER::isUnitAndConversionShown( const LIB_ITEM* aItem ) const
  198. {
  199. if( m_schSettings.m_ShowUnit // showing a specific unit
  200. && aItem->GetUnit() // item is unit-specific
  201. && aItem->GetUnit() != m_schSettings.m_ShowUnit )
  202. {
  203. return false;
  204. }
  205. if( m_schSettings.m_ShowConvert // showing a specific conversion
  206. && aItem->GetConvert() // item is conversion-specific
  207. && aItem->GetConvert() != m_schSettings.m_ShowConvert )
  208. {
  209. return false;
  210. }
  211. return true;
  212. }
  213. float SCH_PAINTER::getShadowWidth() const
  214. {
  215. const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
  216. // For best visuals the selection width must be a cross between the zoom level and the
  217. // default line width.
  218. return (float) std::fabs( matrix.GetScale().x * 2.75 ) +
  219. Mils2iu( eeconfig()->m_Selection.thickness );
  220. }
  221. COLOR4D SCH_PAINTER::getRenderColor( const EDA_ITEM* aItem, int aLayer, bool aDrawingShadows ) const
  222. {
  223. COLOR4D color = m_schSettings.GetLayerColor( aLayer );
  224. if( aItem->Type() == SCH_LINE_T )
  225. {
  226. COLOR4D lineColor = static_cast<const SCH_LINE*>( aItem )->GetLineColor();
  227. if( lineColor != COLOR4D::UNSPECIFIED )
  228. color = lineColor;
  229. }
  230. else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
  231. {
  232. COLOR4D busEntryColor = static_cast<const SCH_BUS_WIRE_ENTRY*>( aItem )->GetStrokeColor();
  233. if( busEntryColor != COLOR4D::UNSPECIFIED )
  234. color = busEntryColor;
  235. }
  236. else if( aItem->Type() == SCH_JUNCTION_T )
  237. {
  238. COLOR4D junctionColor = static_cast<const SCH_JUNCTION*>( aItem )->GetJunctionColor();
  239. if( junctionColor != COLOR4D::UNSPECIFIED )
  240. color = junctionColor;
  241. }
  242. else if( aItem->Type() == SCH_SHEET_T )
  243. {
  244. SCH_SHEET* sheet = (SCH_SHEET*) aItem;
  245. if( m_schSettings.m_OverrideItemColors )
  246. color = m_schSettings.GetLayerColor( aLayer );
  247. else if( aLayer == LAYER_SHEET )
  248. color = sheet->GetBorderColor();
  249. else if( aLayer == LAYER_SHEET_BACKGROUND )
  250. color = sheet->GetBackgroundColor();
  251. if( color == COLOR4D::UNSPECIFIED )
  252. color = m_schSettings.GetLayerColor( aLayer );
  253. }
  254. if( aItem->IsBrightened() && !aDrawingShadows ) // Selection disambiguation, etc.
  255. {
  256. color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
  257. if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_SHEET_BACKGROUND )
  258. color = color.WithAlpha( 0.2 );
  259. }
  260. else if( aItem->IsSelected() )
  261. {
  262. if( aDrawingShadows )
  263. color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
  264. }
  265. if( m_schSettings.m_ShowDisabled
  266. || ( m_schSettings.m_ShowGraphicsDisabled && aItem->Type() != LIB_FIELD_T ) )
  267. {
  268. color = color.Darken( 0.5f );
  269. }
  270. return color;
  271. }
  272. float SCH_PAINTER::getLineWidth( const LIB_ITEM* aItem, bool aDrawingShadows ) const
  273. {
  274. float width = (float) aItem->GetEffectivePenWidth( &m_schSettings );
  275. if( aItem->IsSelected() && aDrawingShadows )
  276. width += getShadowWidth();
  277. return width;
  278. }
  279. float SCH_PAINTER::getLineWidth( const SCH_ITEM* aItem, bool aDrawingShadows ) const
  280. {
  281. wxCHECK( aItem, static_cast<float>( m_schSettings.m_DefaultWireThickness ) );
  282. float width = (float) aItem->GetPenWidth();
  283. if( aItem->IsSelected() && aDrawingShadows )
  284. width += getShadowWidth();
  285. return std::max( width, 1.0f );
  286. }
  287. float SCH_PAINTER::getTextThickness( const SCH_TEXT* aItem, bool aDrawingShadows ) const
  288. {
  289. float width = (float) aItem->GetEffectiveTextPenWidth( m_schSettings.GetDefaultPenWidth() );
  290. if( aItem->IsSelected() && aDrawingShadows )
  291. width += getShadowWidth();
  292. return width;
  293. }
  294. float SCH_PAINTER::getTextThickness( const SCH_FIELD* aItem, bool aDrawingShadows ) const
  295. {
  296. float width = (float) aItem->GetEffectiveTextPenWidth( m_schSettings.GetDefaultPenWidth() );
  297. if( aItem->IsSelected() && aDrawingShadows )
  298. width += getShadowWidth();
  299. return width;
  300. }
  301. float SCH_PAINTER::getTextThickness( const LIB_FIELD* aItem, bool aDrawingShadows ) const
  302. {
  303. float width = (float) std::max( aItem->GetEffectiveTextPenWidth(),
  304. m_schSettings.GetDefaultPenWidth() );
  305. if( aItem->IsSelected() && aDrawingShadows )
  306. width += getShadowWidth();
  307. return width;
  308. }
  309. float SCH_PAINTER::getTextThickness( const LIB_TEXT* aItem, bool aDrawingShadows ) const
  310. {
  311. float width = (float) std::max( aItem->GetEffectiveTextPenWidth(),
  312. m_schSettings.GetDefaultPenWidth() );
  313. if( aItem->IsSelected() && aDrawingShadows )
  314. width += getShadowWidth();
  315. return width;
  316. }
  317. static VECTOR2D mapCoords( const wxPoint& aCoord )
  318. {
  319. return VECTOR2D( aCoord.x, -aCoord.y );
  320. }
  321. void SCH_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition, double aAngle )
  322. {
  323. m_gal->StrokeText( aText, VECTOR2D( aPosition.x, aPosition.y ), aAngle );
  324. }
  325. void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition, double aAngle )
  326. {
  327. const STROKE_FONT& font = m_gal->GetStrokeFont();
  328. VECTOR2D extents = font.ComputeStringBoundaryLimits( aText, m_gal->GetGlyphSize(),
  329. m_gal->GetLineWidth() );
  330. EDA_RECT box( (wxPoint) aPosition, wxSize( extents.x, extents.y ) );
  331. if( m_gal->GetHorizontalJustify() == GR_TEXT_HJUSTIFY_CENTER )
  332. box.SetX( box.GetX() - ( box.GetWidth() / 2) );
  333. else if( m_gal->GetHorizontalJustify() == GR_TEXT_HJUSTIFY_RIGHT )
  334. box.SetX( box.GetX() - box.GetWidth() );
  335. if( m_gal->GetVerticalJustify() == GR_TEXT_VJUSTIFY_CENTER )
  336. box.SetY( box.GetY() - ( box.GetHeight() / 2) );
  337. else if( m_gal->GetVerticalJustify() == GR_TEXT_VJUSTIFY_BOTTOM )
  338. box.SetY( box.GetY() - box.GetHeight() );
  339. box.Normalize(); // Make h and v sizes always >= 0
  340. box = box.GetBoundingBoxRotated((wxPoint) aPosition, RAD2DECIDEG( aAngle ) );
  341. box.RevertYAxis();
  342. m_gal->DrawRectangle( mapCoords( box.GetOrigin() ), mapCoords( box.GetEnd() ) );
  343. }
  344. void SCH_PAINTER::triLine( const VECTOR2D &a, const VECTOR2D &b, const VECTOR2D &c )
  345. {
  346. m_gal->DrawLine( a, b );
  347. m_gal->DrawLine( b, c );
  348. }
  349. void SCH_PAINTER::draw( const LIB_SYMBOL *aSymbol, int aLayer, bool aDrawFields, int aUnit, int aConvert )
  350. {
  351. if( !aUnit )
  352. aUnit = m_schSettings.m_ShowUnit;
  353. if( !aConvert )
  354. aConvert = m_schSettings.m_ShowConvert;
  355. std::unique_ptr< LIB_SYMBOL > tmpSymbol;
  356. const LIB_SYMBOL* drawnSymbol = aSymbol;
  357. if( aSymbol->IsAlias() )
  358. {
  359. tmpSymbol = aSymbol->Flatten();
  360. drawnSymbol = tmpSymbol.get();
  361. }
  362. for( const LIB_ITEM& item : drawnSymbol->GetDrawItems() )
  363. {
  364. if( !aDrawFields && item.Type() == LIB_FIELD_T )
  365. continue;
  366. if( aUnit && item.GetUnit() && aUnit != item.GetUnit() )
  367. continue;
  368. if( aConvert && item.GetConvert() && aConvert != item.GetConvert() )
  369. continue;
  370. Draw( &item, aLayer );
  371. }
  372. }
  373. bool SCH_PAINTER::setDeviceColors( const LIB_ITEM* aItem, int aLayer )
  374. {
  375. const EDA_SHAPE* shape = dynamic_cast<const EDA_SHAPE*>( aItem );
  376. switch( aLayer )
  377. {
  378. case LAYER_SELECTION_SHADOWS:
  379. if( aItem->IsSelected() )
  380. {
  381. m_gal->SetIsFill( false );
  382. m_gal->SetIsStroke( true );
  383. m_gal->SetLineWidth( getLineWidth( aItem, true ) );
  384. m_gal->SetStrokeColor( getRenderColor( aItem, LAYER_DEVICE, true ) );
  385. m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, true ) );
  386. return true;
  387. }
  388. return false;
  389. case LAYER_DEVICE_BACKGROUND:
  390. if( shape && shape->GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR )
  391. {
  392. COLOR4D fillColor = getRenderColor( aItem, LAYER_DEVICE_BACKGROUND, false );
  393. m_gal->SetIsFill( shape->GetFillType() == FILL_T::FILLED_WITH_BG_BODYCOLOR );
  394. m_gal->SetFillColor( fillColor );
  395. m_gal->SetIsStroke( false );
  396. return true;
  397. }
  398. return false;
  399. case LAYER_DEVICE:
  400. m_gal->SetIsFill( shape && shape->GetFillType() == FILL_T::FILLED_SHAPE );
  401. m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, false ) );
  402. if( aItem->GetPenWidth() >= 0 || !shape || !shape->IsFilled() )
  403. {
  404. m_gal->SetIsStroke( true );
  405. m_gal->SetLineWidth( getLineWidth( aItem, false ) );
  406. m_gal->SetStrokeColor( getRenderColor( aItem, LAYER_DEVICE, false ) );
  407. }
  408. else
  409. {
  410. m_gal->SetIsStroke( false );
  411. }
  412. return true;
  413. default:
  414. return false;
  415. }
  416. }
  417. void SCH_PAINTER::fillIfSelection( int aLayer )
  418. {
  419. if( aLayer == LAYER_SELECTION_SHADOWS && eeconfig()->m_Selection.fill_shapes )
  420. m_gal->SetIsFill( true );
  421. }
  422. void SCH_PAINTER::draw( const LIB_SHAPE *aShape, int aLayer )
  423. {
  424. if( !isUnitAndConversionShown( aShape ) )
  425. return;
  426. if( setDeviceColors( aShape, aLayer ) )
  427. {
  428. fillIfSelection( aLayer );
  429. switch( aShape->GetShape() )
  430. {
  431. case SHAPE_T::ARC:
  432. {
  433. int startAngle;
  434. int endAngle;
  435. aShape->CalcArcAngles( startAngle, endAngle );
  436. TRANSFORM().MapAngles( &startAngle, &endAngle );
  437. m_gal->DrawArc( mapCoords( aShape->GetCenter() ), aShape->GetRadius(),
  438. DECIDEG2RAD( startAngle ), DECIDEG2RAD( endAngle ) );
  439. }
  440. break;
  441. case SHAPE_T::CIRCLE:
  442. m_gal->DrawCircle( mapCoords( aShape->GetPosition() ), aShape->GetRadius() );
  443. break;
  444. case SHAPE_T::RECT:
  445. m_gal->DrawRectangle( mapCoords( aShape->GetPosition() ),
  446. mapCoords( aShape->GetEnd() ) );
  447. break;
  448. case SHAPE_T::POLY:
  449. {
  450. const SHAPE_LINE_CHAIN poly = aShape->GetPolyShape().Outline( 0 );
  451. std::deque<VECTOR2D> mappedPts;
  452. for( const VECTOR2I& pt : poly.CPoints() )
  453. mappedPts.push_back( mapCoords( (wxPoint) pt ) );
  454. fillIfSelection( aLayer );
  455. m_gal->DrawPolygon( mappedPts );
  456. }
  457. break;
  458. case SHAPE_T::BEZIER:
  459. {
  460. std::deque<VECTOR2D> mappedPts;
  461. for( const VECTOR2I &p : aShape->GetPolyShape().Outline( 0 ).CPoints() )
  462. mappedPts.push_back( mapCoords( (wxPoint) p ) );
  463. m_gal->DrawPolygon( mappedPts );
  464. }
  465. break;
  466. default:
  467. wxFAIL_MSG( "SCH_PAINTER::draw not implemented for " + aShape->SHAPE_T_asString() );
  468. }
  469. }
  470. }
  471. void SCH_PAINTER::draw( const LIB_FIELD *aField, int aLayer )
  472. {
  473. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  474. if( drawingShadows && !aField->IsSelected() )
  475. return;
  476. if( !isUnitAndConversionShown( aField ) )
  477. return;
  478. // Must check layer as fields are sometimes drawn by their parent rather than
  479. // directly from the view.
  480. int layers[KIGFX::VIEW::VIEW_MAX_LAYERS];
  481. int layers_count;
  482. bool foundLayer = false;
  483. aField->ViewGetLayers( layers, layers_count );
  484. for( int i = 0; i < layers_count; ++i )
  485. {
  486. if( layers[i] == aLayer )
  487. foundLayer = true;
  488. }
  489. if( !foundLayer )
  490. return;
  491. COLOR4D color = getRenderColor( aField, aLayer, drawingShadows );
  492. if( !( aField->IsVisible() || aField->IsForceVisible() ) )
  493. {
  494. if( m_schSettings.m_ShowHiddenText )
  495. color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows );
  496. else
  497. return;
  498. }
  499. m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
  500. m_gal->SetIsFill( false );
  501. m_gal->SetIsStroke( true );
  502. m_gal->SetStrokeColor( color );
  503. EDA_RECT bbox = aField->GetBoundingBox();
  504. wxPoint textpos = bbox.Centre();
  505. if( drawingShadows && eeconfig()->m_Selection.text_as_box )
  506. {
  507. m_gal->SetIsFill( true );
  508. m_gal->SetFillColor( color );
  509. m_gal->SetLineWidth( m_gal->GetLineWidth() * 0.5 );
  510. bbox.RevertYAxis();
  511. m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) );
  512. }
  513. else
  514. {
  515. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  516. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  517. m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
  518. m_gal->SetFontItalic( aField->IsItalic() );
  519. strokeText( UnescapeString( aField->GetText() ), textpos, aField->GetTextAngleRadians() );
  520. }
  521. // Draw the umbilical line
  522. if( aField->IsMoving() && m_schSettings.m_ShowUmbilicals )
  523. {
  524. m_gal->SetLineWidth( m_schSettings.m_outlineWidth );
  525. m_gal->SetStrokeColor( getRenderColor( aField, LAYER_SCHEMATIC_ANCHOR, drawingShadows ) );
  526. m_gal->DrawLine( textpos, wxPoint( 0, 0 ) );
  527. }
  528. }
  529. void SCH_PAINTER::draw( const LIB_TEXT *aText, int aLayer )
  530. {
  531. if( !isUnitAndConversionShown( aText ) )
  532. return;
  533. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  534. if( drawingShadows && !aText->IsSelected() )
  535. return;
  536. COLOR4D color = getRenderColor( aText, LAYER_DEVICE, drawingShadows );
  537. if( !aText->IsVisible() )
  538. {
  539. if( m_schSettings.m_ShowHiddenText )
  540. color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
  541. else
  542. return;
  543. }
  544. EDA_RECT bBox = aText->GetBoundingBox();
  545. bBox.RevertYAxis();
  546. VECTOR2D pos = mapCoords( bBox.Centre() );
  547. double orient = aText->GetTextAngleRadians();
  548. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  549. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  550. m_gal->SetLineWidth( getTextThickness( aText, drawingShadows ) );
  551. m_gal->SetIsFill( false );
  552. m_gal->SetIsStroke( true );
  553. m_gal->SetStrokeColor( color );
  554. m_gal->SetGlyphSize( VECTOR2D( aText->GetTextSize() ) );
  555. m_gal->SetFontBold( aText->IsBold() );
  556. m_gal->SetFontItalic( aText->IsItalic() );
  557. m_gal->SetFontUnderlined( false );
  558. strokeText( aText->GetText(), pos, orient );
  559. }
  560. int SCH_PAINTER::internalPinDecoSize( const LIB_PIN &aPin )
  561. {
  562. if( m_schSettings.m_PinSymbolSize > 0 )
  563. return m_schSettings.m_PinSymbolSize;
  564. return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
  565. }
  566. // Utility for getting the size of the 'external' pin decorators (as a radius)
  567. // i.e. the negation circle, the polarity 'slopes' and the nonlogic marker
  568. int SCH_PAINTER::externalPinDecoSize( const LIB_PIN &aPin )
  569. {
  570. if( m_schSettings.m_PinSymbolSize > 0 )
  571. return m_schSettings.m_PinSymbolSize;
  572. return aPin.GetNumberTextSize() / 2;
  573. }
  574. // Draw the target (an open circle) for a pin which has no connection or is being moved.
  575. void SCH_PAINTER::drawPinDanglingSymbol( const VECTOR2I& aPos, bool aDrawingShadows )
  576. {
  577. m_gal->SetIsFill( false );
  578. m_gal->SetIsStroke( true );
  579. m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth()
  580. : m_schSettings.GetDanglineSymbolThickness() );
  581. m_gal->DrawCircle( aPos, TARGET_PIN_RADIUS );
  582. }
  583. void SCH_PAINTER::draw( LIB_PIN *aPin, int aLayer )
  584. {
  585. if( !isUnitAndConversionShown( aPin ) )
  586. return;
  587. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  588. bool dangling = m_schSettings.m_IsSymbolEditor || aPin->HasFlag( IS_DANGLING );
  589. if( drawingShadows && !aPin->IsSelected() )
  590. return;
  591. VECTOR2I pos = mapCoords( aPin->GetPosition() );
  592. COLOR4D color = getRenderColor( aPin, LAYER_PIN, drawingShadows );
  593. if( !aPin->IsVisible() )
  594. {
  595. if( m_schSettings.m_ShowHiddenPins )
  596. {
  597. color = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows );
  598. }
  599. else
  600. {
  601. if( dangling && aPin->IsPowerConnection() )
  602. drawPinDanglingSymbol( pos, drawingShadows );
  603. return;
  604. }
  605. }
  606. VECTOR2I p0;
  607. VECTOR2I dir;
  608. int len = aPin->GetLength();
  609. int orient = aPin->GetOrientation();
  610. switch( orient )
  611. {
  612. case PIN_UP:
  613. p0 = VECTOR2I( pos.x, pos.y - len );
  614. dir = VECTOR2I( 0, 1 );
  615. break;
  616. case PIN_DOWN:
  617. p0 = VECTOR2I( pos.x, pos.y + len );
  618. dir = VECTOR2I( 0, -1 );
  619. break;
  620. case PIN_LEFT:
  621. p0 = VECTOR2I( pos.x - len, pos.y );
  622. dir = VECTOR2I( 1, 0 );
  623. break;
  624. default:
  625. case PIN_RIGHT:
  626. p0 = VECTOR2I( pos.x + len, pos.y );
  627. dir = VECTOR2I( -1, 0 );
  628. break;
  629. }
  630. VECTOR2D pc;
  631. m_gal->SetIsStroke( true );
  632. m_gal->SetIsFill( false );
  633. m_gal->SetLineWidth( getLineWidth( aPin, drawingShadows ) );
  634. m_gal->SetStrokeColor( color );
  635. m_gal->SetFontBold( false );
  636. m_gal->SetFontUnderlined( false );
  637. m_gal->SetFontItalic( false );
  638. const int radius = externalPinDecoSize( *aPin );
  639. const int diam = radius*2;
  640. const int clock_size = internalPinDecoSize( *aPin );
  641. if( aPin->GetType() == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
  642. {
  643. m_gal->DrawLine( p0, pos );
  644. m_gal->DrawLine( pos + VECTOR2D( -1, -1 ) * TARGET_PIN_RADIUS,
  645. pos + VECTOR2D( 1, 1 ) * TARGET_PIN_RADIUS );
  646. m_gal->DrawLine( pos + VECTOR2D( 1, -1 ) * TARGET_PIN_RADIUS ,
  647. pos + VECTOR2D( -1, 1 ) * TARGET_PIN_RADIUS );
  648. aPin->ClearFlags( IS_DANGLING ); // PIN_NC pin type is always not connected and dangling.
  649. }
  650. else
  651. {
  652. switch( aPin->GetShape() )
  653. {
  654. case GRAPHIC_PINSHAPE::LINE:
  655. m_gal->DrawLine( p0, pos );
  656. break;
  657. case GRAPHIC_PINSHAPE::INVERTED:
  658. m_gal->DrawCircle( p0 + dir * radius, radius );
  659. m_gal->DrawLine( p0 + dir * ( diam ), pos );
  660. break;
  661. case GRAPHIC_PINSHAPE::INVERTED_CLOCK:
  662. pc = p0 - dir * clock_size ;
  663. triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
  664. pc,
  665. p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
  666. m_gal->DrawCircle( p0 + dir * radius, radius );
  667. m_gal->DrawLine( p0 + dir * ( diam ), pos );
  668. break;
  669. case GRAPHIC_PINSHAPE::CLOCK_LOW:
  670. case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK:
  671. pc = p0 - dir * clock_size ;
  672. triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
  673. pc,
  674. p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
  675. if( !dir.y )
  676. {
  677. triLine( p0 + VECTOR2D(dir.x, 0) * diam,
  678. p0 + VECTOR2D(dir.x, -1) * diam,
  679. p0 );
  680. }
  681. else /* MapX1 = 0 */
  682. {
  683. triLine( p0 + VECTOR2D( 0, dir.y) * diam,
  684. p0 + VECTOR2D(-1, dir.y) * diam,
  685. p0 );
  686. }
  687. m_gal->DrawLine( p0, pos );
  688. break;
  689. case GRAPHIC_PINSHAPE::CLOCK:
  690. m_gal->DrawLine( p0, pos );
  691. if( !dir.y )
  692. {
  693. triLine( p0 + VECTOR2D( 0, clock_size ),
  694. p0 + VECTOR2D( -dir.x * clock_size, 0 ),
  695. p0 + VECTOR2D( 0, -clock_size ) );
  696. }
  697. else
  698. {
  699. triLine( p0 + VECTOR2D( clock_size, 0 ),
  700. p0 + VECTOR2D( 0, -dir.y * clock_size ),
  701. p0 + VECTOR2D( -clock_size, 0 ) );
  702. }
  703. break;
  704. case GRAPHIC_PINSHAPE::INPUT_LOW:
  705. m_gal->DrawLine( p0, pos );
  706. if( !dir.y )
  707. {
  708. triLine( p0 + VECTOR2D(dir.x, 0) * diam,
  709. p0 + VECTOR2D(dir.x, -1) * diam,
  710. p0 );
  711. }
  712. else /* MapX1 = 0 */
  713. {
  714. triLine( p0 + VECTOR2D( 0, dir.y) * diam,
  715. p0 + VECTOR2D(-1, dir.y) * diam,
  716. p0 );
  717. }
  718. break;
  719. case GRAPHIC_PINSHAPE::OUTPUT_LOW: // IEEE symbol "Active Low Output"
  720. m_gal->DrawLine( p0, pos );
  721. if( !dir.y ) // Horizontal pin
  722. m_gal->DrawLine( p0 - VECTOR2D( 0, diam ), p0 + VECTOR2D( dir.x, 0 ) * diam );
  723. else // Vertical pin
  724. m_gal->DrawLine( p0 - VECTOR2D( diam, 0 ), p0 + VECTOR2D( 0, dir.y ) * diam );
  725. break;
  726. case GRAPHIC_PINSHAPE::NONLOGIC: // NonLogic pin symbol
  727. m_gal->DrawLine( p0, pos );
  728. m_gal->DrawLine( p0 - VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius,
  729. p0 + VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius );
  730. m_gal->DrawLine( p0 - VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius,
  731. p0 + VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius );
  732. break;
  733. }
  734. }
  735. if( dangling )
  736. drawPinDanglingSymbol( pos, drawingShadows );
  737. LIB_SYMBOL* libEntry = aPin->GetParent();
  738. // Draw the labels
  739. if( drawingShadows
  740. && ( libEntry->Type() == LIB_SYMBOL_T || libEntry->IsSelected() )
  741. && !eeconfig()->m_Selection.draw_selected_children )
  742. {
  743. return;
  744. }
  745. float penWidth = (float) m_schSettings.GetDefaultPenWidth();
  746. int textOffset = libEntry->GetPinNameOffset();
  747. float nameStrokeWidth = getLineWidth( aPin, drawingShadows );
  748. float numStrokeWidth = getLineWidth( aPin, drawingShadows );
  749. nameStrokeWidth = Clamp_Text_PenSize( nameStrokeWidth, aPin->GetNameTextSize(), false );
  750. numStrokeWidth = Clamp_Text_PenSize( numStrokeWidth, aPin->GetNumberTextSize(), false );
  751. int PIN_TEXT_MARGIN = KiROUND( 24 * m_schSettings.m_TextOffsetRatio );
  752. // Four locations around a pin where text can be drawn
  753. enum { INSIDE = 0, OUTSIDE, ABOVE, BELOW };
  754. int size[4] = { 0, 0, 0, 0 };
  755. float thickness[4] = { numStrokeWidth, numStrokeWidth, numStrokeWidth, numStrokeWidth };
  756. COLOR4D colour[4];
  757. wxString text[4];
  758. // TextOffset > 0 means pin NAMES on inside, pin NUMBERS above and nothing below
  759. if( textOffset )
  760. {
  761. size [INSIDE] = libEntry->ShowPinNames() ? aPin->GetNameTextSize() : 0;
  762. thickness[INSIDE] = nameStrokeWidth;
  763. colour [INSIDE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows );
  764. text [INSIDE] = aPin->GetShownName();
  765. size [ABOVE] = libEntry->ShowPinNumbers() ? aPin->GetNumberTextSize() : 0;
  766. thickness[ABOVE] = numStrokeWidth;
  767. colour [ABOVE] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows );
  768. text [ABOVE] = aPin->GetShownNumber();
  769. }
  770. // Otherwise pin NAMES go above and pin NUMBERS go below
  771. else
  772. {
  773. size [ABOVE] = libEntry->ShowPinNames() ? aPin->GetNameTextSize() : 0;
  774. thickness[ABOVE] = nameStrokeWidth;
  775. colour [ABOVE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows );
  776. text [ABOVE] = aPin->GetShownName();
  777. size [BELOW] = libEntry->ShowPinNumbers() ? aPin->GetNumberTextSize() : 0;
  778. thickness[BELOW] = numStrokeWidth;
  779. colour [BELOW] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows );
  780. text [BELOW] = aPin->GetShownNumber();
  781. }
  782. if( m_schSettings.m_ShowPinsElectricalType )
  783. {
  784. size [OUTSIDE] = std::max( aPin->GetNameTextSize() * 3 / 4, Millimeter2iu( 0.7 ) );
  785. thickness[OUTSIDE] = float( size[OUTSIDE] ) / 6.0F;
  786. colour [OUTSIDE] = getRenderColor( aPin, LAYER_NOTES, drawingShadows );
  787. text [OUTSIDE] = aPin->GetElectricalTypeName();
  788. }
  789. if( !aPin->IsVisible() )
  790. {
  791. for( COLOR4D& c : colour )
  792. c = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows );
  793. }
  794. float insideOffset = textOffset - thickness[INSIDE] / 2.0;
  795. float outsideOffset = 2 * Mils2iu( PIN_TEXT_MARGIN ) - thickness[OUTSIDE] / 2.0;
  796. float aboveOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[ABOVE] + penWidth ) / 2.0;
  797. float belowOffset = Mils2iu( PIN_TEXT_MARGIN ) + ( thickness[BELOW] + penWidth ) / 2.0;
  798. if( dangling )
  799. outsideOffset += TARGET_PIN_RADIUS / 2.0;
  800. if( drawingShadows )
  801. {
  802. float shadowWidth = getShadowWidth();
  803. if( eeconfig()->m_Selection.text_as_box )
  804. {
  805. insideOffset -= thickness[INSIDE] / 2.0;
  806. outsideOffset -= thickness[OUTSIDE] / 2.0;
  807. aboveOffset -= thickness[ABOVE] + penWidth;
  808. belowOffset -= thickness[BELOW] + penWidth;
  809. }
  810. for( float& t : thickness )
  811. t += shadowWidth;
  812. insideOffset -= shadowWidth / 2.0;
  813. outsideOffset -= shadowWidth / 2.0;
  814. }
  815. auto setupDC =
  816. [&]( int i )
  817. {
  818. m_gal->SetGlyphSize( VECTOR2D( size[i], size[i] ) );
  819. m_gal->SetIsStroke( !( drawingShadows && eeconfig()->m_Selection.text_as_box ) );
  820. m_gal->SetLineWidth( thickness[i] );
  821. m_gal->SetStrokeColor( colour[i] );
  822. m_gal->SetIsFill( drawingShadows && eeconfig()->m_Selection.text_as_box );
  823. m_gal->SetFillColor( colour[i] );
  824. };
  825. auto drawText =
  826. [&]( const wxString& aText, const VECTOR2D& aPos, double aAngle )
  827. {
  828. if( aText.IsEmpty() )
  829. return;
  830. if( drawingShadows && eeconfig()->m_Selection.text_as_box )
  831. boxText( aText, aPos, aAngle );
  832. else
  833. strokeText( aText, aPos, aAngle );
  834. };
  835. switch( orient )
  836. {
  837. case PIN_LEFT:
  838. if( size[INSIDE] )
  839. {
  840. setupDC( INSIDE );
  841. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  842. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  843. drawText( text[INSIDE], pos + VECTOR2D( -insideOffset - len, 0 ), 0 );
  844. }
  845. if( size[OUTSIDE] )
  846. {
  847. setupDC( OUTSIDE );
  848. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  849. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  850. drawText( text[OUTSIDE], pos + VECTOR2D( outsideOffset, 0 ), 0 );
  851. }
  852. if( size[ABOVE] )
  853. {
  854. setupDC( ABOVE );
  855. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  856. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  857. drawText( text[ABOVE], pos + VECTOR2D( -len / 2.0, -aboveOffset ), 0 );
  858. }
  859. if( size[BELOW] )
  860. {
  861. setupDC( BELOW );
  862. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  863. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  864. drawText( text[BELOW], pos + VECTOR2D( -len / 2.0, belowOffset ), 0 );
  865. }
  866. break;
  867. case PIN_RIGHT:
  868. if( size[INSIDE] )
  869. {
  870. setupDC( INSIDE );
  871. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  872. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  873. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  874. drawText( text[INSIDE], pos + VECTOR2D( insideOffset + len, 0 ), 0 );
  875. }
  876. if( size[OUTSIDE] )
  877. {
  878. setupDC( OUTSIDE );
  879. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  880. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  881. drawText( text[OUTSIDE], pos + VECTOR2D( -outsideOffset, 0 ), 0 );
  882. }
  883. if( size[ABOVE] )
  884. {
  885. setupDC( ABOVE );
  886. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  887. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  888. drawText( text[ABOVE], pos + VECTOR2D( len / 2.0, -aboveOffset ), 0 );
  889. }
  890. if( size[BELOW] )
  891. {
  892. setupDC( BELOW );
  893. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  894. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  895. drawText( text[BELOW], pos + VECTOR2D( len / 2.0, belowOffset ), 0 );
  896. }
  897. break;
  898. case PIN_DOWN:
  899. if( size[INSIDE] )
  900. {
  901. setupDC( INSIDE );
  902. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  903. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  904. drawText( text[INSIDE], pos + VECTOR2D( 0, insideOffset + len ), M_PI / 2 );
  905. }
  906. if( size[OUTSIDE] )
  907. {
  908. setupDC( OUTSIDE );
  909. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  910. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  911. drawText( text[OUTSIDE], pos + VECTOR2D( 0, -outsideOffset ), M_PI / 2 );
  912. }
  913. if( size[ABOVE] )
  914. {
  915. setupDC( ABOVE );
  916. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  917. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  918. drawText( text[ABOVE], pos + VECTOR2D( -aboveOffset, len / 2.0 ), M_PI / 2 );
  919. }
  920. if( size[BELOW] )
  921. {
  922. setupDC( BELOW );
  923. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  924. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  925. drawText( text[BELOW], pos + VECTOR2D( belowOffset, len / 2.0 ), M_PI / 2 );
  926. }
  927. break;
  928. case PIN_UP:
  929. if( size[INSIDE] )
  930. {
  931. setupDC( INSIDE );
  932. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_LEFT );
  933. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  934. drawText( text[INSIDE], pos + VECTOR2D( 0, -insideOffset - len ), M_PI / 2 );
  935. }
  936. if( size[OUTSIDE] )
  937. {
  938. setupDC( OUTSIDE );
  939. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_RIGHT );
  940. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  941. drawText( text[OUTSIDE], pos + VECTOR2D( 0, outsideOffset ), M_PI / 2 );
  942. }
  943. if( size[ABOVE] )
  944. {
  945. setupDC( ABOVE );
  946. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  947. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  948. drawText( text[ABOVE], pos + VECTOR2D( -aboveOffset, -len / 2.0 ), M_PI / 2 );
  949. }
  950. if( size[BELOW] )
  951. {
  952. setupDC( BELOW );
  953. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  954. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_TOP );
  955. drawText( text[BELOW], pos + VECTOR2D( belowOffset, -len / 2.0 ), M_PI / 2 );
  956. }
  957. break;
  958. default:
  959. wxFAIL_MSG( "Unknown pin orientation" );
  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->GetEffectiveDiameter() / 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 bbox = aField->GetBoundingBox();
  1253. wxPoint textpos = bbox.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. bbox.RevertYAxis();
  1262. m_gal->DrawRectangle( mapCoords( bbox.GetPosition() ), mapCoords( bbox.GetEnd() ) );
  1263. }
  1264. else
  1265. {
  1266. m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
  1267. m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
  1268. m_gal->SetIsFill( false );
  1269. m_gal->SetGlyphSize( VECTOR2D( aField->GetTextSize() ) );
  1270. m_gal->SetFontBold( aField->IsBold() );
  1271. m_gal->SetFontItalic( aField->IsItalic() );
  1272. m_gal->SetFontUnderlined( underline );
  1273. m_gal->SetTextMirrored( aField->IsMirrored() );
  1274. m_gal->SetLineWidth( getTextThickness( aField, drawingShadows ) );
  1275. strokeText( aField->GetShownText(), textpos, orient == TEXT_ANGLE_VERT ? M_PI / 2 : 0 );
  1276. }
  1277. // Draw the umbilical line
  1278. if( aField->IsMoving() )
  1279. {
  1280. wxPoint parentPos = aField->GetParentPosition();
  1281. m_gal->SetLineWidth( m_schSettings.m_outlineWidth );
  1282. m_gal->SetStrokeColor( getRenderColor( aField, LAYER_SCHEMATIC_ANCHOR, drawingShadows ) );
  1283. m_gal->DrawLine( textpos, parentPos );
  1284. }
  1285. }
  1286. void SCH_PAINTER::draw( SCH_GLOBALLABEL *aLabel, int aLayer )
  1287. {
  1288. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1289. if( !drawingShadows || aLabel->IsSelected() )
  1290. {
  1291. COLOR4D color = getRenderColor( aLabel, LAYER_GLOBLABEL, drawingShadows );
  1292. std::vector<wxPoint> pts;
  1293. std::deque<VECTOR2D> pts2;
  1294. aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
  1295. for( const wxPoint& p : pts )
  1296. pts2.emplace_back( VECTOR2D( p.x, p.y ) );
  1297. // The text is drawn inside the graphic shape.
  1298. // On Cairo the graphic shape is filled by the background before drawing the text.
  1299. // However if the text is selected, it is draw twice: first on LAYER_SELECTION_SHADOWS
  1300. // and second on the text layer. The second must not erase the first drawing.
  1301. bool fillBg = ( aLayer == LAYER_SELECTION_SHADOWS ) || !aLabel->IsSelected();
  1302. m_gal->SetIsFill( fillBg );
  1303. m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  1304. m_gal->SetIsStroke( true );
  1305. m_gal->SetLineWidth( getTextThickness( aLabel, drawingShadows ) );
  1306. m_gal->SetStrokeColor( color );
  1307. m_gal->DrawPolyline( pts2 );
  1308. draw( static_cast<SCH_TEXT*>( aLabel ), aLayer );
  1309. }
  1310. if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children || !aLabel->IsSelected() )
  1311. {
  1312. draw( aLabel->GetIntersheetRefs(), aLayer );
  1313. }
  1314. }
  1315. void SCH_PAINTER::draw( SCH_HIERLABEL *aLabel, int aLayer )
  1316. {
  1317. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1318. if( drawingShadows && !aLabel->IsSelected() )
  1319. return;
  1320. COLOR4D color = getRenderColor( aLabel, LAYER_SHEETLABEL, drawingShadows );
  1321. if( m_schematic )
  1322. {
  1323. SCH_CONNECTION* conn = aLabel->Connection();
  1324. if( conn && conn->IsBus() )
  1325. color = getRenderColor( aLabel, LAYER_BUS, drawingShadows );
  1326. }
  1327. std::vector<wxPoint> pts;
  1328. std::deque<VECTOR2D> pts2;
  1329. aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
  1330. for( const wxPoint& p : pts )
  1331. pts2.emplace_back( VECTOR2D( p.x, p.y ) );
  1332. m_gal->SetIsFill( true );
  1333. m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  1334. m_gal->SetIsStroke( true );
  1335. m_gal->SetLineWidth( getTextThickness( aLabel, drawingShadows ) );
  1336. m_gal->SetStrokeColor( color );
  1337. m_gal->DrawPolyline( pts2 );
  1338. draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer );
  1339. }
  1340. void SCH_PAINTER::draw( const SCH_SHEET *aSheet, int aLayer )
  1341. {
  1342. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1343. if( aLayer == LAYER_HIERLABEL || aLayer == LAYER_SELECTION_SHADOWS )
  1344. {
  1345. for( SCH_SHEET_PIN* sheetPin : aSheet->GetPins() )
  1346. {
  1347. if( drawingShadows && !aSheet->IsSelected() && !sheetPin->IsSelected() )
  1348. continue;
  1349. if( drawingShadows && aSheet->IsSelected()
  1350. && !eeconfig()->m_Selection.draw_selected_children )
  1351. {
  1352. break;
  1353. }
  1354. int width = std::max( aSheet->GetPenWidth(), m_schSettings.GetDefaultPenWidth() );
  1355. wxPoint initial_pos = sheetPin->GetTextPos();
  1356. wxPoint offset_pos = initial_pos;
  1357. // For aesthetic reasons, the SHEET_PIN is drawn with a small offset of width / 2
  1358. switch( sheetPin->GetEdge() )
  1359. {
  1360. case SHEET_SIDE::TOP: offset_pos.y += KiROUND( width / 2.0 ); break;
  1361. case SHEET_SIDE::BOTTOM: offset_pos.y -= KiROUND( width / 2.0 ); break;
  1362. case SHEET_SIDE::RIGHT: offset_pos.x -= KiROUND( width / 2.0 ); break;
  1363. case SHEET_SIDE::LEFT: offset_pos.x += KiROUND( width / 2.0 ); break;
  1364. default: break;
  1365. }
  1366. sheetPin->SetTextPos( offset_pos );
  1367. draw( static_cast<SCH_HIERLABEL*>( sheetPin ), aLayer );
  1368. m_gal->DrawLine( offset_pos, initial_pos );
  1369. sheetPin->SetTextPos( initial_pos );
  1370. }
  1371. }
  1372. VECTOR2D pos = aSheet->GetPosition();
  1373. VECTOR2D size = aSheet->GetSize();
  1374. if( aLayer == LAYER_SHEET_BACKGROUND )
  1375. {
  1376. m_gal->SetFillColor( getRenderColor( aSheet, LAYER_SHEET_BACKGROUND, true ) );
  1377. m_gal->SetIsFill( true );
  1378. m_gal->SetIsStroke( false );
  1379. m_gal->DrawRectangle( pos, pos + size );
  1380. }
  1381. if( aLayer == LAYER_SHEET || aLayer == LAYER_SELECTION_SHADOWS )
  1382. {
  1383. m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, drawingShadows ) );
  1384. m_gal->SetIsStroke( true );
  1385. m_gal->SetLineWidth( getLineWidth( aSheet, drawingShadows ) );
  1386. m_gal->SetIsFill( false );
  1387. m_gal->DrawRectangle( pos, pos + size );
  1388. if( drawingShadows && !eeconfig()->m_Selection.draw_selected_children && aSheet->IsSelected() )
  1389. return;
  1390. for( const SCH_FIELD& field : aSheet->GetFields() )
  1391. draw( &field, aLayer );
  1392. }
  1393. }
  1394. void SCH_PAINTER::draw( const SCH_NO_CONNECT *aNC, int aLayer )
  1395. {
  1396. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1397. if( drawingShadows && !aNC->IsSelected() )
  1398. return;
  1399. m_gal->SetIsStroke( true );
  1400. m_gal->SetLineWidth( getLineWidth( aNC, drawingShadows ) );
  1401. m_gal->SetStrokeColor( getRenderColor( aNC, LAYER_NOCONNECT, drawingShadows ) );
  1402. m_gal->SetIsFill( false );
  1403. VECTOR2D p = aNC->GetPosition();
  1404. int delta = std::max( aNC->GetSize(), m_schSettings.GetDefaultPenWidth() * 3 ) / 2;
  1405. m_gal->DrawLine( p + VECTOR2D( -delta, -delta ), p + VECTOR2D( delta, delta ) );
  1406. m_gal->DrawLine( p + VECTOR2D( -delta, delta ), p + VECTOR2D( delta, -delta ) );
  1407. }
  1408. void SCH_PAINTER::draw( const SCH_BUS_ENTRY_BASE *aEntry, int aLayer )
  1409. {
  1410. SCH_LAYER_ID layer = aEntry->Type() == SCH_BUS_WIRE_ENTRY_T ? LAYER_WIRE : LAYER_BUS;
  1411. SCH_LINE line( wxPoint(), layer );
  1412. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1413. if( drawingShadows && !aEntry->IsSelected() )
  1414. return;
  1415. if( aEntry->IsSelected() )
  1416. line.SetSelected();
  1417. else if( aEntry->IsBrightened() )
  1418. line.SetBrightened();
  1419. line.SetStartPoint( aEntry->GetPosition() );
  1420. line.SetEndPoint( aEntry->GetEnd() );
  1421. line.SetStroke( aEntry->GetStroke() );
  1422. line.SetLineWidth( getLineWidth( aEntry, drawingShadows ) );
  1423. COLOR4D color = getRenderColor( aEntry, LAYER_WIRE, drawingShadows );
  1424. if( aEntry->Type() == SCH_BUS_BUS_ENTRY_T )
  1425. color = getRenderColor( aEntry, LAYER_BUS, drawingShadows );
  1426. line.SetLineColor( color );
  1427. line.SetLineStyle( aEntry->GetStrokeStyle() );
  1428. draw( &line, aLayer );
  1429. m_gal->SetIsFill( false );
  1430. m_gal->SetIsStroke( true );
  1431. m_gal->SetLineWidth( drawingShadows ? getShadowWidth() : 1.0F );
  1432. if( aEntry->IsDanglingStart() )
  1433. {
  1434. m_gal->DrawCircle( aEntry->GetPosition(),
  1435. aEntry->GetPenWidth() + ( TARGET_BUSENTRY_RADIUS / 2 ) );
  1436. }
  1437. if( aEntry->IsDanglingEnd() )
  1438. {
  1439. m_gal->DrawCircle( aEntry->GetEnd(),
  1440. aEntry->GetPenWidth() + ( TARGET_BUSENTRY_RADIUS / 2 ) );
  1441. }
  1442. }
  1443. void SCH_PAINTER::draw( const SCH_BITMAP *aBitmap, int aLayer )
  1444. {
  1445. m_gal->Save();
  1446. m_gal->Translate( aBitmap->GetPosition() );
  1447. // When the image scale factor is not 1.0, we need to modify the actual as the image scale
  1448. // factor is similar to a local zoom
  1449. double img_scale = aBitmap->GetImageScale();
  1450. if( img_scale != 1.0 )
  1451. m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
  1452. if( aLayer == LAYER_DRAW_BITMAPS )
  1453. {
  1454. m_gal->DrawBitmap( *aBitmap->GetImage() );
  1455. }
  1456. if( aLayer == LAYER_SELECTION_SHADOWS )
  1457. {
  1458. if( aBitmap->IsSelected() || aBitmap->IsBrightened() )
  1459. {
  1460. COLOR4D color = getRenderColor( aBitmap, LAYER_DRAW_BITMAPS, true );
  1461. m_gal->SetIsStroke( true );
  1462. m_gal->SetStrokeColor( color );
  1463. m_gal->SetLineWidth ( getShadowWidth() );
  1464. m_gal->SetIsFill( false );
  1465. // Draws a bounding box.
  1466. VECTOR2D bm_size( aBitmap->GetSize() );
  1467. // bm_size is the actual image size in UI.
  1468. // but m_gal scale was previously set to img_scale
  1469. // so recalculate size relative to this image size.
  1470. bm_size.x /= img_scale;
  1471. bm_size.y /= img_scale;
  1472. VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
  1473. VECTOR2D end = origin + bm_size;
  1474. m_gal->DrawRectangle( origin, end );
  1475. }
  1476. }
  1477. m_gal->Restore();
  1478. }
  1479. void SCH_PAINTER::draw( const SCH_MARKER *aMarker, int aLayer )
  1480. {
  1481. bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
  1482. if( drawingShadows && !aMarker->IsSelected() )
  1483. return;
  1484. COLOR4D color = getRenderColor( aMarker, aMarker->GetColorLayer(), drawingShadows );
  1485. m_gal->Save();
  1486. m_gal->Translate( aMarker->GetPosition() );
  1487. m_gal->SetIsFill( !drawingShadows );
  1488. m_gal->SetFillColor( color );
  1489. m_gal->SetIsStroke( drawingShadows );
  1490. m_gal->SetLineWidth( getLineWidth( aMarker, drawingShadows ) );
  1491. m_gal->SetStrokeColor( color );
  1492. SHAPE_LINE_CHAIN polygon;
  1493. aMarker->ShapeToPolygon( polygon );
  1494. m_gal->DrawPolygon( polygon );
  1495. m_gal->Restore();
  1496. }
  1497. }; // namespace KIGFX