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.

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