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.

1847 lines
58 KiB

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