KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_painter.cpp
Go to the documentation of this file.
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-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
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
27
28#include <trigo.h>
29#include <connection_graph.h>
31#include <callback_gal.h>
33#include <geometry/shape_rect.h>
34#include <gr_text.h>
35#include <sch_pin.h>
36#include <math/util.h>
37#include <pgm_base.h>
38#include <sch_bitmap.h>
39#include <sch_bus_entry.h>
40#include <sch_symbol.h>
41#include <sch_edit_frame.h>
42#include <sch_field.h>
43#include <sch_junction.h>
44#include <sch_line.h>
45#include <sch_shape.h>
46#include <sch_marker.h>
47#include <sch_no_connect.h>
48#include <sch_sheet.h>
49#include <sch_sheet_pin.h>
50#include <sch_text.h>
51#include <sch_textbox.h>
52#include <sch_table.h>
53#include <schematic.h>
55#include <view/view.h>
56#include <kiface_base.h>
57#include <default_values.h>
58#include <advanced_config.h>
60#include <stroke_params.h>
61#include "sch_painter.h"
62#include "common.h"
63
64
65namespace KIGFX
66{
67
69{
70 return dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
71}
72
73
74std::vector<KICAD_T> SCH_PAINTER::g_ScaledSelectionTypes = {
93};
94
95
110{
111 static LIB_SYMBOL* symbol;
112
113 if( !symbol )
114 {
115 symbol = new LIB_SYMBOL( wxEmptyString );
116
117 SCH_SHAPE* square = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
118
119 square->SetPosition( VECTOR2I( schIUScale.MilsToIU( -200 ), schIUScale.MilsToIU( 200 ) ) );
120 square->SetEnd( VECTOR2I( schIUScale.MilsToIU( 200 ), schIUScale.MilsToIU( -200 ) ) );
121 symbol->AddDrawItem( square );
122
123 SCH_TEXT* text = new SCH_TEXT( { 0, 0 }, wxT( "??" ), LAYER_DEVICE );
124
125 text->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 150 ), schIUScale.MilsToIU( 150 ) ) );
126 symbol->AddDrawItem( text );
127 }
128
129 return symbol;
130}
131
132
134 KIGFX::PAINTER( aGal ),
135 m_schematic( nullptr )
136{ }
137
138
139bool SCH_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
140{
141 const EDA_ITEM* item = dynamic_cast<const EDA_ITEM*>( aItem );
142
143 if( !item )
144 return false;
145
146 draw( item, aLayer, false );
147
148 return false;
149}
150
151void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed )
152{
153
154#ifdef CONNECTIVITY_DEBUG
155
156 auto sch_item = dynamic_cast<const SCH_ITEM*>( aItem );
157 auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
158
159 if( conn )
160 {
161 auto pos = aItem->GetBoundingBox().Centre();
162 auto label = conn->Name( true );
163
167 m_gal->SetLineWidth( Mils2ui( 2 ) );
168 m_gal->SetGlyphSize( VECTOR2D( Mils2ui( 20 ), Mils2ui( 20 ) ) );
169 m_gal->StrokeText( conn->Name( true ), pos, 0.0, 0 );
170 }
171
172#endif
173
174 // Enable draw bounding box on request. Some bboxes are handled locally.
175 bool drawBoundingBox = m_schSettings.GetDrawBoundingBoxes();
176
177 switch( aItem->Type() )
178 {
179 case LIB_SYMBOL_T:
180 draw( static_cast<const LIB_SYMBOL*>( aItem ), aLayer );
181 break;
182 case SCH_PIN_T:
183 drawBoundingBox = false;
184 draw( static_cast<const SCH_PIN*>( aItem ), aLayer, aDimmed );
185 break;
186 case SCH_SYMBOL_T:
187 draw( static_cast<const SCH_SYMBOL*>( aItem ), aLayer );
188 break;
189 case SCH_JUNCTION_T:
190 draw( static_cast<const SCH_JUNCTION*>( aItem ), aLayer );
191 break;
192 case SCH_LINE_T:
193 draw( static_cast<const SCH_LINE*>( aItem ), aLayer );
194 break;
195 case SCH_SHAPE_T:
196 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
197 break;
198 case SCH_RULE_AREA_T:
199 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
200 break;
201 case SCH_TEXT_T:
202 draw( static_cast<const SCH_TEXT*>( aItem ), aLayer, aDimmed );
203 break;
204 case SCH_TEXTBOX_T:
205 draw( static_cast<const SCH_TEXTBOX*>( aItem ), aLayer, aDimmed );
206 break;
207 case SCH_TABLE_T:
208 draw( static_cast<const SCH_TABLE*>( aItem ), aLayer, aDimmed );
209 break;
210 case SCH_LABEL_T:
211 draw( static_cast<const SCH_LABEL*>( aItem ), aLayer );
212 break;
214 draw( static_cast<const SCH_DIRECTIVE_LABEL*>( aItem ), aLayer );
215 break;
216 case SCH_FIELD_T:
217 draw( static_cast<const SCH_FIELD*>( aItem ), aLayer, aDimmed );
218 break;
219 case SCH_HIER_LABEL_T:
220 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer );
221 break;
223 draw( static_cast<const SCH_GLOBALLABEL*>( aItem ), aLayer );
224 break;
225 case SCH_SHEET_T:
226 draw( static_cast<const SCH_SHEET*>( aItem ), aLayer );
227 break;
228 case SCH_SHEET_PIN_T:
229 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer );
230 break;
231 case SCH_NO_CONNECT_T:
232 draw( static_cast<const SCH_NO_CONNECT*>( aItem ), aLayer );
233 break;
235 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
236 break;
238 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
239 break;
240 case SCH_BITMAP_T:
241 draw( static_cast<const SCH_BITMAP*>( aItem ), aLayer );
242 break;
243 case SCH_MARKER_T:
244 draw( static_cast<const SCH_MARKER*>( aItem ), aLayer );
245 break;
246
247 default: return;
248 }
249
250 if( drawBoundingBox )
251 drawItemBoundingBox( aItem );
252}
253
254
256{
257 if( const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( aItem ) )
258 {
259 if( item->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
260 return;
261 }
262
263 BOX2I box = aItem->GetBoundingBox();
264
265 if( aItem->Type() == SCH_SYMBOL_T )
266 box = static_cast<const SCH_SYMBOL*>( aItem )->GetBodyBoundingBox();
267
268 m_gal->SetIsFill( false );
269 m_gal->SetIsStroke( true );
270 m_gal->SetStrokeColor( aItem->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 )
271 : COLOR4D( 0.2, 0.2, 0.2, 1 ) );
273 m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
274}
275
276
278{
279 // TODO: it would be nice to have a more definitive test for this, but we've currently got
280 // no access to the VIEW_GROUP to see if it's cached or not.
281 return aItem->IsSelected();
282}
283
284
286{
287 if( m_schSettings.m_ShowUnit // showing a specific unit
288 && aItem->GetUnit() // item is unit-specific
289 && aItem->GetUnit() != m_schSettings.m_ShowUnit )
290 {
291 return false;
292 }
293
294 if( m_schSettings.m_ShowBodyStyle // showing a specific body style
295 && aItem->GetBodyStyle() // item is body-style-specific
297 {
298 return false;
299 }
300
301 return true;
302}
303
304
306{
307 if( KIFONT::FONT* font = aItem->GetFont() )
308 return font;
309
311 aItem->IsItalic() );
312}
313
314
315float SCH_PAINTER::getShadowWidth( bool aForHighlight ) const
316{
317 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
318
319 int milsWidth = aForHighlight ? eeconfig()->m_Selection.highlight_thickness
321
322 // For best visuals the selection width must be a cross between the zoom level and the
323 // default line width.
324 return (float) std::fabs( matrix.GetScale().x * milsWidth ) + schIUScale.MilsToIU( milsWidth );
325}
326
327
328COLOR4D SCH_PAINTER::getRenderColor( const SCH_ITEM* aItem, int aLayer, bool aDrawingShadows,
329 bool aDimmed ) const
330{
332 // Graphic items of a SYMBOL frequently use the LAYER_DEVICE layer color
333 // (i.e. when no specific color is set)
334 bool isSymbolChild = aItem->GetParentSymbol() != nullptr;
335
336 if( aItem->Type() == SCH_LINE_T )
337 {
338 color = static_cast<const SCH_LINE*>( aItem )->GetLineColor();
339 }
340 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
341 {
342 color = static_cast<const SCH_BUS_WIRE_ENTRY*>( aItem )->GetBusEntryColor();
343 }
344 else if( aItem->Type() == SCH_JUNCTION_T )
345 {
346 color = static_cast<const SCH_JUNCTION*>( aItem )->GetJunctionColor();
347 }
349 {
350 if( aItem->Type() == SCH_SHEET_T )
351 {
352 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( aItem );
353
354 if( aLayer == LAYER_SHEET_BACKGROUND )
355 color = sheet->GetBackgroundColor();
356 else
357 color = sheet->GetBorderColor();
358 }
359 else if( aItem->Type() == SCH_SHAPE_T || aItem->Type() == SCH_RULE_AREA_T )
360 {
361 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem );
362
363 if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
364 {
365 if( !isSymbolChild || shape->GetFillColor() != COLOR4D::UNSPECIFIED )
366 color = shape->GetFillColor();
367
368 if( isSymbolChild && shape->GetFillMode() == FILL_T::FILLED_SHAPE )
369 color = shape->GetStroke().GetColor();
370 }
371 else
372 {
373 if( !isSymbolChild || shape->GetStroke().GetColor() != COLOR4D::UNSPECIFIED )
374 color = shape->GetStroke().GetColor();
375 }
376
377 // A filled shape means filled; if they didn't specify a fill colour then use the
378 // border colour.
380 {
381 if( aItem->Type() == SCH_RULE_AREA_T )
382 {
384 }
385 else
386 {
388 : LAYER_NOTES );
389 }
390 }
391 }
392 else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
393 {
394 color = static_cast<const SCH_LABEL_BASE*>( aItem )->GetLabelColor();
395 }
396 else if( aItem->Type() == SCH_FIELD_T )
397 {
398 color = static_cast<const SCH_FIELD*>( aItem )->GetFieldColor();
399 }
400 else if( aItem->Type() == SCH_TEXTBOX_T || aItem->Type() == SCH_TABLECELL_T )
401 {
402 const SCH_TEXTBOX* textBox = dynamic_cast<const SCH_TEXTBOX*>( aItem );
403
404 if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
405 color = textBox->GetFillColor();
406 else if( !isSymbolChild || textBox->GetTextColor() != COLOR4D::UNSPECIFIED )
407 color = textBox->GetTextColor();
408 }
409 else if( const EDA_TEXT* otherTextItem = dynamic_cast<const EDA_TEXT*>( aItem ) )
410 {
411 if( !isSymbolChild || otherTextItem->GetTextColor() != COLOR4D::UNSPECIFIED )
412 color = otherTextItem->GetTextColor();
413 }
414 }
415
417 color = m_schSettings.GetLayerColor( aLayer );
418
419 if( aItem->IsBrightened() ) // Selection disambiguation, net highlighting, etc.
420 {
421 color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
422
423 if( aDrawingShadows )
424 {
425 if( aItem->IsSelected() )
426 color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
427 else
428 color = color.WithAlpha( 0.15 );
429 }
430 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_SHEET_BACKGROUND )
431 {
432 color = color.WithAlpha( 0.2 );
433 }
434 }
435 else if( aItem->IsSelected() && aDrawingShadows )
436 {
437 if( aDrawingShadows )
438 color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
439 }
440 else if( aItem->IsSelected() && ( aLayer == LAYER_DEVICE_BACKGROUND
441 || aLayer == LAYER_SHEET_BACKGROUND ) )
442 {
443 // Selected items will be painted over all other items, so make backgrounds translucent so
444 // that non-selected overlapping objects are visible
445 color = color.WithAlpha( 0.5 );
446 }
447
448 if( m_schSettings.m_ShowDisabled
449 || ( m_schSettings.m_ShowGraphicsDisabled && aItem->Type() != SCH_FIELD_T ) )
450 {
451 color = color.Darken( 0.5f );
452 }
453
454 if( aDimmed && !( aItem->IsSelected() && aDrawingShadows ) )
455 {
456 COLOR4D sheetColour = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
457 color.Desaturate();
458 color = color.Mix( sheetColour, 0.5f );
459 }
460
461 if( aItem->GetForcedTransparency() > 0.0 )
462 color = color.WithAlpha( color.a * ( 1.0 - aItem->GetForcedTransparency() ) );
463
464 return color;
465}
466
467
468float SCH_PAINTER::getLineWidth( const SCH_ITEM* aItem, bool aDrawingShadows ) const
469{
470 wxCHECK( aItem, static_cast<float>( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ) ) );
471
472 int pen = aItem->GetEffectivePenWidth( &m_schSettings );
473 float width = pen;
474
475 if( aItem->IsBrightened() || aItem->IsSelected() )
476 {
477 if( aDrawingShadows && aItem->IsType( g_ScaledSelectionTypes ) )
478 width += getShadowWidth( aItem->IsBrightened() );
479 }
480
481 return width;
482}
483
484
485float SCH_PAINTER::getTextThickness( const SCH_ITEM* aItem ) const
486{
487 int pen = m_schSettings.GetDefaultPenWidth();
488
489 switch( aItem->Type() )
490 {
491 case SCH_FIELD_T:
492 pen = static_cast<const SCH_FIELD*>( aItem )->GetEffectiveTextPenWidth( pen );
493 break;
494
495 case SCH_TEXT_T:
496 pen = static_cast<const SCH_TEXT*>( aItem )->GetEffectiveTextPenWidth( pen );
497 break;
498
499 case SCH_LABEL_T:
502 case SCH_HIER_LABEL_T:
503 case SCH_SHEET_PIN_T:
504 pen = static_cast<const SCH_LABEL_BASE*>( aItem )->GetEffectiveTextPenWidth( pen );
505 break;
506
507 case SCH_TEXTBOX_T:
508 case SCH_TABLECELL_T:
509 pen = static_cast<const SCH_TEXTBOX*>( aItem )->GetEffectiveTextPenWidth( pen );
510 break;
511
512 default:
513 UNIMPLEMENTED_FOR( aItem->GetClass() );
514 }
515
516 return (float) pen;
517}
518
519
520int SCH_PAINTER::getOperatingPointTextSize() const
521{
522 int docTextSize = schIUScale.MilsToIU( 50 );
523 int screenTextSize = std::abs( (int) m_gal->GetScreenWorldMatrix().GetScale().y * 7 );
524
525 // 66% zoom-relative
526 return KiROUND( ( docTextSize + screenTextSize * 2 ) / 3 );
527}
528
529
530//
531// TODO: nuke symbol editor's upside-down coordinate system
532//
533#define MAP_COORDS( aCoord ) VECTOR2D( aCoord.x, invertY ? -aCoord.y : aCoord.y )
534
535
536static bool isFieldsLayer( int aLayer )
537{
538 return aLayer == LAYER_REFERENCEPART
539 || aLayer == LAYER_VALUEPART
540 || aLayer == LAYER_INTERSHEET_REFS
541 || aLayer == LAYER_NETCLASS_REFS
542 || aLayer == LAYER_FIELDS
543 || aLayer == LAYER_SHEETNAME
544 || aLayer == LAYER_SHEETFILENAME
545 || aLayer == LAYER_SHEETFIELDS;
546}
547
548
549void SCH_PAINTER::strokeText( const wxString& aText, const VECTOR2D& aPosition,
550 const TEXT_ATTRIBUTES& aAttrs,
551 const KIFONT::METRICS& aFontMetrics )
552{
553 KIFONT::FONT* font = aAttrs.m_Font;
554
555 if( !font )
556 {
557 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
558 aAttrs.m_Italic );
559 }
560
561 m_gal->SetIsFill( font->IsOutline() );
562 m_gal->SetIsStroke( font->IsStroke() );
563
564 font->Draw( m_gal, aText, aPosition, aAttrs, aFontMetrics );
565}
566
567
568void SCH_PAINTER::bitmapText( const wxString& aText, const VECTOR2D& aPosition,
569 const TEXT_ATTRIBUTES& aAttrs )
570{
571 // Bitmap font has different metrics from the stroke font so we compensate a bit before
572 // stroking
573 m_gal->SetGlyphSize( VECTOR2I( aAttrs.m_Size.x, KiROUND( aAttrs.m_Size.y * 1.05 ) ) );
574 m_gal->SetLineWidth( (float) aAttrs.m_StrokeWidth * 1.35f );
575
576 m_gal->SetHorizontalJustify( aAttrs.m_Halign );
577 m_gal->SetVerticalJustify( aAttrs.m_Valign );
578
579 m_gal->BitmapText( aText, aPosition, aAttrs.m_Angle );
580}
581
582
583void SCH_PAINTER::knockoutText( const wxString& aText, const VECTOR2D& aPosition,
584 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
585{
586 TEXT_ATTRIBUTES attrs( aAttrs );
587 KIFONT::FONT* font = aAttrs.m_Font;
588
589 if( !font )
590 {
591 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, attrs.m_Bold,
592 attrs.m_Italic );
593 }
594
596 SHAPE_POLY_SET knockouts;
597
598 CALLBACK_GAL callback_gal( empty_opts,
599 // Polygon callback
600 [&]( const SHAPE_LINE_CHAIN& aPoly )
601 {
602 knockouts.AddOutline( aPoly );
603 } );
604
605 callback_gal.SetIsFill( false );
606 callback_gal.SetIsStroke( true );
607 callback_gal.SetLineWidth( (float) attrs.m_StrokeWidth );
608 font->Draw( &callback_gal, aText, aPosition, attrs, aFontMetrics );
609
610 BOX2I bbox = knockouts.BBox( attrs.m_StrokeWidth * 2 );
611 SHAPE_POLY_SET finalPoly;
612
613 finalPoly.NewOutline();
614 finalPoly.Append( bbox.GetLeft(), bbox.GetTop() );
615 finalPoly.Append( bbox.GetRight(), bbox.GetTop() );
616 finalPoly.Append( bbox.GetRight(), bbox.GetBottom() );
617 finalPoly.Append( bbox.GetLeft(), bbox.GetBottom() );
618
619 finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
621
622 m_gal->SetIsStroke( false );
623 m_gal->SetIsFill( true );
624 m_gal->SetFillColor( attrs.m_Color );
625 m_gal->DrawPolygon( finalPoly );
626}
627
628
629void SCH_PAINTER::boxText( const wxString& aText, const VECTOR2D& aPosition,
630 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics,
631 bool aInvertY )
632{
633 bool invertY = aInvertY;
634
635 KIFONT::FONT* font = aAttrs.m_Font;
636
637 if( !font )
638 {
639 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
640 aAttrs.m_Italic );
641 }
642
643 VECTOR2I extents = font->StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth,
644 aAttrs.m_Bold, aAttrs.m_Italic, aFontMetrics );
645 BOX2I box( aPosition, VECTOR2I( extents.x, aAttrs.m_Size.y ) );
646
647 switch( aAttrs.m_Halign )
648 {
649 case GR_TEXT_H_ALIGN_LEFT: break;
650 case GR_TEXT_H_ALIGN_CENTER: box.SetX( box.GetX() - box.GetWidth() / 2 ); break;
651 case GR_TEXT_H_ALIGN_RIGHT: box.SetX( box.GetX() - box.GetWidth() ); break;
652 case GR_TEXT_H_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
653 }
654
655 switch( aAttrs.m_Valign )
656 {
657 case GR_TEXT_V_ALIGN_TOP: break;
658 case GR_TEXT_V_ALIGN_CENTER: box.SetY( box.GetY() - box.GetHeight() / 2 ); break;
659 case GR_TEXT_V_ALIGN_BOTTOM: box.SetY( box.GetY() - box.GetHeight() ); break;
660 case GR_TEXT_V_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
661 }
662
663 // Give the highlight a bit of margin.
664 box.Inflate( 0, aAttrs.m_StrokeWidth * 2 );
665
666 box.Normalize(); // Make h and v sizes always >= 0
667 box = box.GetBoundingBoxRotated( aPosition, aAttrs.m_Angle );
668 box.RevertYAxis();
669
670 m_gal->SetIsFill( true );
671 m_gal->SetIsStroke( false );
672 m_gal->DrawRectangle( MAP_COORDS( box.GetOrigin() ), MAP_COORDS( box.GetEnd() ) );
673}
674
675
676void SCH_PAINTER::triLine( const VECTOR2D &a, const VECTOR2D &b, const VECTOR2D &c )
677{
678 m_gal->DrawLine( a, b );
679 m_gal->DrawLine( b, c );
680}
681
682
683void SCH_PAINTER::draw( const LIB_SYMBOL* aSymbol, int aLayer, bool aDrawFields, int aUnit,
684 int aBodyStyle, bool aDimmed )
685{
686 if( !aUnit )
687 aUnit = m_schSettings.m_ShowUnit;
688
689 if( !aBodyStyle )
690 aBodyStyle = m_schSettings.m_ShowBodyStyle;
691
692 std::unique_ptr< LIB_SYMBOL > tmpSymbol;
693 const LIB_SYMBOL* drawnSymbol = aSymbol;
694
695 if( aSymbol->IsAlias() )
696 {
697 tmpSymbol = aSymbol->Flatten();
698 drawnSymbol = tmpSymbol.get();
699 }
700
701 // The parent must exist on the union of all its children's draw layers. But that doesn't
702 // mean we want to draw each child on the union.
703 auto childOnLayer =
704 []( const SCH_ITEM& item, int layer )
705 {
706 int layers[512], layers_count;
707 item.ViewGetLayers( layers, layers_count );
708
709 for( int ii = 0; ii < layers_count; ++ii )
710 {
711 if( layers[ii] == layer )
712 return true;
713 }
714
715 return false;
716 };
717
718 for( const SCH_ITEM& item : drawnSymbol->GetDrawItems() )
719 {
720 if( !aDrawFields && item.Type() == SCH_FIELD_T )
721 continue;
722
723 if( !childOnLayer( item, aLayer ) )
724 continue;
725
726 if( aUnit && item.GetUnit() && aUnit != item.GetUnit() )
727 continue;
728
729 if( aBodyStyle && item.GetBodyStyle() && aBodyStyle != item.GetBodyStyle() )
730 continue;
731
732 draw( &item, aLayer, aDimmed );
733 }
734}
735
736
737bool SCH_PAINTER::setDeviceColors( const SCH_ITEM* aItem, int aLayer, bool aDimmed )
738{
739 COLOR4D bg = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
740 const EDA_SHAPE* shape = dynamic_cast<const EDA_SHAPE*>( aItem );
741
742 switch( aLayer )
743 {
745 if( aItem->IsBrightened() || aItem->IsSelected() )
746 {
747 m_gal->SetIsFill( false );
748 m_gal->SetIsStroke( true );
749 m_gal->SetLineWidth( getLineWidth( aItem, true ) );
750 m_gal->SetStrokeColor( getRenderColor( aItem, LAYER_DEVICE, true, aDimmed ) );
751 m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, true, aDimmed ) );
752 return true;
753 }
754
755 return false;
756
759 if( shape )
760 {
762 {
763 return false; // FILLED_SHAPE and FILLED_WITH_COLOR rendered below on
764 // LAYER_NOTES or LAYER_DEVICE
765 }
766
767 m_gal->SetIsFill( true );
768 m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE_BACKGROUND, false, aDimmed ) );
769 m_gal->SetIsStroke( false );
770 return true;
771 }
772
773 return false;
774
775 case LAYER_NOTES:
777 case LAYER_DEVICE:
778 m_gal->SetIsFill( shape && ( shape->GetFillMode() == FILL_T::FILLED_SHAPE
779 || shape->GetFillMode() == FILL_T::FILLED_WITH_COLOR ) );
780
781 if( shape && shape->GetFillMode() == FILL_T::FILLED_SHAPE )
782 {
783 m_gal->SetFillColor( getRenderColor( aItem, LAYER_DEVICE, false, aDimmed ) );
784 }
785 else if( shape && shape->GetFillMode() == FILL_T::FILLED_WITH_COLOR )
786 {
787 COLOR4D fillColour = shape->GetFillColor();
788 double transparency = aItem->GetForcedTransparency();
789
790 if( transparency > 0.0 )
791 fillColour = fillColour.WithAlpha( fillColour.a * ( 1.0 - transparency ) );
792
793 if( m_schSettings.m_OverrideItemColors )
794 {
795 fillColour = getRenderColor( aItem, LAYER_DEVICE_BACKGROUND, false, aDimmed );
796 }
797 else if( aDimmed )
798 {
799 fillColour = fillColour.Mix( bg, 0.5f );
800 fillColour.Desaturate();
801 }
802
803 m_gal->SetFillColor( fillColour );
804 }
805
806 if( aItem->GetPenWidth() >= 0 || !shape || !shape->IsFilled() )
807 {
808 m_gal->SetIsStroke( true );
809 m_gal->SetLineWidth( getLineWidth( aItem, false ) );
810 m_gal->SetStrokeColor( getRenderColor( aItem, aLayer, false, aDimmed ) );
811 }
812 else
813 {
814 m_gal->SetIsStroke( false );
815 }
816
817 return true;
818
819 default:
820 return false;
821 }
822}
823
824
825int SCH_PAINTER::internalPinDecoSize( const SCH_PIN &aPin )
826{
827 if( m_schSettings.m_PinSymbolSize > 0 )
828 return m_schSettings.m_PinSymbolSize;
829
830 return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
831}
832
833
834// Utility for getting the size of the 'external' pin decorators (as a radius)
835// i.e. the negation circle, the polarity 'slopes' and the nonlogic marker
836int SCH_PAINTER::externalPinDecoSize( const SCH_PIN &aPin )
837{
838 if( m_schSettings.m_PinSymbolSize > 0 )
839 return m_schSettings.m_PinSymbolSize;
840
841 return aPin.GetNumberTextSize() / 2;
842}
843
844
845// Draw the target (an open circle) for a pin which has no connection or is being moved.
846void SCH_PAINTER::drawPinDanglingIndicator( const VECTOR2I& aPos, const COLOR4D& aColor,
847 bool aDrawingShadows, bool aBrightened )
848{
849 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
850 // they overlap with a junction dot.
851 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
852
853 m_gal->SetIsFill( false );
854 m_gal->SetIsStroke( true );
855 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( aBrightened )
856 : m_schSettings.GetDanglingIndicatorThickness() );
857
858 m_gal->DrawCircle( aPos, TARGET_PIN_RADIUS );
859}
860
861
862void SCH_PAINTER::draw( const SCH_PIN* aPin, int aLayer, bool aDimmed )
863{
864 if( !isUnitAndConversionShown( aPin ) )
865 return;
866
867 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
868
869 if( m_schSettings.IsPrinting() && drawingShadows )
870 return;
871
872 bool drawingDangling = aLayer == LAYER_DANGLING;
873 bool drawingOP = aLayer == LAYER_OP_CURRENTS;
874 bool isDangling = m_schSettings.m_IsSymbolEditor || aPin->HasFlag( IS_DANGLING );
875 bool invertY = true;
876
877 if( drawingShadows && !( aPin->IsBrightened() || aPin->IsSelected() ) )
878 return;
879
880 VECTOR2I pos = MAP_COORDS( aPin->GetPosition() );
881 COLOR4D color = getRenderColor( aPin, LAYER_PIN, drawingShadows, aDimmed );
882
883 if( !aPin->IsVisible() )
884 {
885 if( m_schSettings.IsPrinting() )
886 return;
887
888 bool force_show = m_schematic ? eeconfig()->m_Appearance.show_hidden_pins
889 : m_schSettings.m_ShowHiddenPins;
890
891 if( force_show )
892 {
893 color = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed );
894 }
895 else
896 {
897 if( drawingDangling && isDangling && aPin->IsGlobalPower() )
898 drawPinDanglingIndicator( pos, color, drawingShadows, aPin->IsBrightened() );
899
900 return;
901 }
902 }
903
904 if( drawingDangling )
905 {
906 if( isDangling )
907 drawPinDanglingIndicator( pos, color, drawingShadows, aPin->IsBrightened() );
908
909 return;
910 }
911
912 if( m_schSettings.GetDrawBoundingBoxes() )
913 drawItemBoundingBox( aPin );
914
915 VECTOR2I p0;
916 VECTOR2I dir;
917 int len = aPin->GetLength();
918 PIN_ORIENTATION orient = aPin->GetOrientation();
919
920 switch( orient )
921 {
923 p0 = VECTOR2I( pos.x, pos.y - len );
924 dir = VECTOR2I( 0, 1 );
925 break;
926
928 p0 = VECTOR2I( pos.x, pos.y + len );
929 dir = VECTOR2I( 0, -1 );
930 break;
931
933 p0 = VECTOR2I( pos.x - len, pos.y );
934 dir = VECTOR2I( 1, 0 );
935 break;
936
937 default:
939 p0 = VECTOR2I( pos.x + len, pos.y );
940 dir = VECTOR2I( -1, 0 );
941 break;
942 }
943
944 if( drawingOP && !aPin->GetOperatingPoint().IsEmpty() )
945 {
946 int textSize = getOperatingPointTextSize();
947 VECTOR2I mid = ( p0 + pos ) / 2;
948 int textOffset = KiROUND( textSize * 0.22 );
949 TEXT_ATTRIBUTES attrs;
950
951 if( len > textSize )
952 {
953 if( dir.x == 0 )
954 {
955 mid.x += KiROUND( textOffset * 1.2 );
957 }
958 else
959 {
960 mid.y -= KiROUND( textOffset * 1.2 );
961 attrs.m_Angle = ANGLE_VERTICAL;
962 }
963
966
967 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
968 attrs.m_Size = VECTOR2I( textSize, textSize );
969 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
970 attrs.m_Color = m_schSettings.GetLayerColor( LAYER_OP_CURRENTS );
971
972 knockoutText( aPin->GetOperatingPoint(), mid, attrs, aPin->GetFontMetrics() );
973 }
974 }
975
976 if( drawingOP )
977 return;
978
979 VECTOR2D pc;
980
981 m_gal->SetIsStroke( true );
982 m_gal->SetIsFill( false );
983 m_gal->SetLineWidth( getLineWidth( aPin, drawingShadows ) );
984 m_gal->SetStrokeColor( color );
985 m_gal->SetFontBold( false );
986 m_gal->SetFontUnderlined( false );
987 m_gal->SetFontItalic( false );
988
989 const int radius = externalPinDecoSize( *aPin );
990 const int diam = radius*2;
991 const int clock_size = internalPinDecoSize( *aPin );
992
993 if( aPin->GetType() == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
994 {
995 m_gal->DrawLine( p0, pos );
996
997 m_gal->DrawLine( pos + VECTOR2D( -1, -1 ) * TARGET_PIN_RADIUS,
998 pos + VECTOR2D( 1, 1 ) * TARGET_PIN_RADIUS );
999 m_gal->DrawLine( pos + VECTOR2D( 1, -1 ) * TARGET_PIN_RADIUS ,
1000 pos + VECTOR2D( -1, 1 ) * TARGET_PIN_RADIUS );
1001 }
1002 else
1003 {
1004 switch( aPin->GetShape() )
1005 {
1006 default:
1008 m_gal->DrawLine( p0, pos );
1009 break;
1010
1012 m_gal->DrawCircle( p0 + dir * radius, radius );
1013 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1014 break;
1015
1017 pc = p0 - dir * clock_size ;
1018
1019 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1020 pc,
1021 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1022
1023 m_gal->DrawCircle( p0 + dir * radius, radius );
1024 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1025 break;
1026
1029 pc = p0 - dir * clock_size ;
1030
1031 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1032 pc,
1033 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1034
1035 if( !dir.y )
1036 {
1037 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1038 p0 + VECTOR2D(dir.x, -1) * diam,
1039 p0 );
1040 }
1041 else /* MapX1 = 0 */
1042 {
1043 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1044 p0 + VECTOR2D(-1, dir.y) * diam,
1045 p0 );
1046 }
1047
1048 m_gal->DrawLine( p0, pos );
1049 break;
1050
1052 m_gal->DrawLine( p0, pos );
1053
1054 if( !dir.y )
1055 {
1056 triLine( p0 + VECTOR2D( 0, clock_size ),
1057 p0 + VECTOR2D( -dir.x * clock_size, 0 ),
1058 p0 + VECTOR2D( 0, -clock_size ) );
1059 }
1060 else
1061 {
1062 triLine( p0 + VECTOR2D( clock_size, 0 ),
1063 p0 + VECTOR2D( 0, -dir.y * clock_size ),
1064 p0 + VECTOR2D( -clock_size, 0 ) );
1065 }
1066 break;
1067
1069 m_gal->DrawLine( p0, pos );
1070
1071 if( !dir.y )
1072 {
1073 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1074 p0 + VECTOR2D(dir.x, -1) * diam,
1075 p0 );
1076 }
1077 else /* MapX1 = 0 */
1078 {
1079 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1080 p0 + VECTOR2D(-1, dir.y) * diam,
1081 p0 );
1082 }
1083 break;
1084
1085 case GRAPHIC_PINSHAPE::OUTPUT_LOW: // IEEE symbol "Active Low Output"
1086 m_gal->DrawLine( p0, pos );
1087
1088 if( !dir.y ) // Horizontal pin
1089 m_gal->DrawLine( p0 - VECTOR2D( 0, diam ), p0 + VECTOR2D( dir.x, 0 ) * diam );
1090 else // Vertical pin
1091 m_gal->DrawLine( p0 - VECTOR2D( diam, 0 ), p0 + VECTOR2D( 0, dir.y ) * diam );
1092 break;
1093
1094 case GRAPHIC_PINSHAPE::NONLOGIC: // NonLogic pin symbol
1095 m_gal->DrawLine( p0, pos );
1096
1097 m_gal->DrawLine( p0 - VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius,
1098 p0 + VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius );
1099 m_gal->DrawLine( p0 - VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius,
1100 p0 + VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius );
1101 break;
1102 }
1103 }
1104
1105 if( drawingShadows && !eeconfig()->m_Selection.draw_selected_children )
1106 return;
1107
1108 // Draw the labels
1109 const SYMBOL* symbol = aPin->GetParentSymbol();
1110 float penWidth = (float) m_schSettings.GetDefaultPenWidth();
1111 int textOffset = symbol->GetPinNameOffset();
1112 float nameStrokeWidth = getLineWidth( aPin, false );
1113 float numStrokeWidth = getLineWidth( aPin, false );
1114 bool showPinNames = symbol->GetShowPinNames();
1115 bool showPinNumbers = m_schSettings.m_ShowPinNumbers || symbol->GetShowPinNumbers();
1116
1117 nameStrokeWidth = Clamp_Text_PenSize( nameStrokeWidth, aPin->GetNameTextSize(), true );
1118 numStrokeWidth = Clamp_Text_PenSize( numStrokeWidth, aPin->GetNumberTextSize(), true );
1119
1120 float PIN_TEXT_MARGIN = schIUScale.MilsToIU( KiROUND( 24 * m_schSettings.m_TextOffsetRatio ) );
1121
1122 // Four locations around a pin where text can be drawn
1123 enum { INSIDE = 0, OUTSIDE, ABOVE, BELOW };
1124 int size[4] = { 0, 0, 0, 0 };
1125 float thickness[4] = { numStrokeWidth, numStrokeWidth, numStrokeWidth, numStrokeWidth };
1126 COLOR4D colour[4];
1127 wxString text[4];
1128
1129 // TextOffset > 0 means pin NAMES on inside, pin NUMBERS above and nothing below
1130 if( textOffset )
1131 {
1132 size [INSIDE] = showPinNames ? aPin->GetNameTextSize() : 0;
1133 thickness[INSIDE] = nameStrokeWidth;
1134 colour [INSIDE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows, aDimmed );
1135 text [INSIDE] = aPin->GetShownName();
1136
1137 size [ABOVE] = showPinNumbers ? aPin->GetNumberTextSize() : 0;
1138 thickness[ABOVE] = numStrokeWidth;
1139 colour [ABOVE] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows, aDimmed );
1140 text [ABOVE] = aPin->GetShownNumber();
1141 }
1142 // Otherwise if both are shown pin NAMES go above and pin NUMBERS go below
1143 else if( showPinNames && showPinNumbers )
1144 {
1145 size [ABOVE] = aPin->GetNameTextSize();
1146 thickness[ABOVE] = nameStrokeWidth;
1147 colour [ABOVE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows, aDimmed );
1148 text [ABOVE] = aPin->GetShownName();
1149
1150 size [BELOW] = aPin->GetNumberTextSize();
1151 thickness[BELOW] = numStrokeWidth;
1152 colour [BELOW] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows, aDimmed );
1153 text [BELOW] = aPin->GetShownNumber();
1154 }
1155 else if( showPinNames )
1156 {
1157 size [ABOVE] = aPin->GetNameTextSize();
1158 thickness[ABOVE] = nameStrokeWidth;
1159 colour [ABOVE] = getRenderColor( aPin, LAYER_PINNAM, drawingShadows, aDimmed );
1160 text [ABOVE] = aPin->GetShownName();
1161 }
1162 else if( showPinNumbers )
1163 {
1164 size [ABOVE] = aPin->GetNumberTextSize();
1165 thickness[ABOVE] = numStrokeWidth;
1166 colour [ABOVE] = getRenderColor( aPin, LAYER_PINNUM, drawingShadows, aDimmed );
1167 text [ABOVE] = aPin->GetShownNumber();
1168 }
1169
1170 if( m_schSettings.m_ShowPinsElectricalType )
1171 {
1172 size [OUTSIDE] = std::max( aPin->GetNameTextSize() * 3 / 4, schIUScale.mmToIU( 0.7 ) );
1173 thickness[OUTSIDE] = float( size[OUTSIDE] ) / 8.0f;
1174 colour [OUTSIDE] = getRenderColor( aPin, LAYER_PRIVATE_NOTES, drawingShadows, aDimmed );
1176 }
1177
1178 // Rendering text is expensive (particularly when using outline fonts). At small effective
1179 // sizes (ie: zoomed out) the visual differences between outline and/or stroke fonts and the
1180 // bitmap font becomes immaterial, and there's often more to draw when zoomed out so the
1181 // performance gain becomes more significant.
1182 #define BITMAP_FONT_SIZE_THRESHOLD 3.5
1183
1184 bool renderTextAsBitmap = size[0] * m_gal->GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD
1185 && size[1] * m_gal->GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD
1186 && size[2] * m_gal->GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD
1187 && size[3] * m_gal->GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD;
1188
1189 if( !aPin->IsVisible() )
1190 {
1191 for( COLOR4D& c : colour )
1192 c = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed );
1193 }
1194
1195 float insideOffset = (float) textOffset - thickness[INSIDE] / 2.0f;
1196 float outsideOffset = PIN_TEXT_MARGIN + TARGET_PIN_RADIUS - thickness[OUTSIDE] / 2.0f;
1197 float aboveOffset = PIN_TEXT_MARGIN + penWidth / 2.0f + thickness[ABOVE] / 2.0f;
1198 float belowOffset = PIN_TEXT_MARGIN + penWidth / 2.0f + thickness[BELOW] / 2.0f;
1199
1200 if( isDangling )
1201 outsideOffset += TARGET_PIN_RADIUS / 2.0f;
1202
1203 if( drawingShadows )
1204 {
1205 float shadowWidth = getShadowWidth( aPin->IsBrightened() );
1206
1207 for( float& t : thickness )
1208 t += shadowWidth;
1209
1210 // Due to the fact a shadow text in position INSIDE or OUTSIDE is drawn left or right aligned,
1211 // it needs an offset = shadowWidth/2 to be drawn at the same place as normal text
1212 // texts drawn as GR_TEXT_H_ALIGN_CENTER do not need a specific offset.
1213 // this offset is shadowWidth/2 but for some reason we need to slightly modify this offset
1214 // for a better look (better alignment of shadow shape), for KiCad font only
1215 if( !KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font )->IsOutline() )
1216 {
1217 const float adjust = 1.2f; // Value chosen after tests
1218 float shadowOffset = shadowWidth/2.0f * adjust;
1219 insideOffset -= shadowOffset;
1220 outsideOffset -= shadowOffset;
1221 }
1222 }
1223
1224 auto drawText =
1225 [&]( int i, const VECTOR2D& aPos, GR_TEXT_H_ALIGN_T hAlign, GR_TEXT_V_ALIGN_T vAlign,
1226 const EDA_ANGLE& aAngle )
1227 {
1228 if( text[i].IsEmpty() )
1229 return;
1230
1231 // Which of these gets used depends on the font technology, so set both
1232 m_gal->SetStrokeColor( colour[i] );
1233 m_gal->SetFillColor( colour[i] );
1234
1235 TEXT_ATTRIBUTES attrs;
1236 attrs.m_Font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font );
1237 attrs.m_Size = VECTOR2I( size[i], size[i] );
1238 attrs.m_Halign = hAlign;
1239 attrs.m_Valign = vAlign;
1240 attrs.m_Angle = aAngle;
1241 attrs.m_StrokeWidth = KiROUND( thickness[i] );
1242
1243 if( drawingShadows && !attrs.m_Font->IsOutline() )
1244 {
1245 strokeText( text[i], aPos, attrs, aPin->GetFontMetrics() );
1246 }
1247 else if( drawingShadows )
1248 {
1249 boxText( text[i], aPos, attrs, aPin->GetFontMetrics(), invertY );
1250 }
1251 else if( nonCached( aPin ) && renderTextAsBitmap )
1252 {
1253 bitmapText( text[i], aPos, attrs );
1254 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1255 }
1256 else
1257 {
1258 strokeText( text[i], aPos, attrs, aPin->GetFontMetrics() );
1259 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1260 }
1261 };
1262
1263 switch( orient )
1264 {
1266 if( size[INSIDE] )
1267 {
1268 drawText( INSIDE, pos + VECTOR2D( -insideOffset - (float) len, 0 ),
1270 }
1271 if( size[OUTSIDE] )
1272 {
1273 drawText( OUTSIDE, pos + VECTOR2D( outsideOffset, 0 ),
1275 }
1276 if( size[ABOVE] )
1277 {
1278 drawText( ABOVE, pos + VECTOR2D( -len / 2.0, -aboveOffset ),
1280 }
1281 if( size[BELOW] )
1282 {
1283 drawText( BELOW, pos + VECTOR2D( -len / 2.0, belowOffset ),
1285 }
1286 break;
1287
1289 if( size[INSIDE] )
1290 {
1291 drawText( INSIDE, pos + VECTOR2D( insideOffset + (float) len, 0 ),
1293 }
1294 if( size[OUTSIDE] )
1295 {
1296 drawText( OUTSIDE, pos + VECTOR2D( -outsideOffset, 0 ),
1298 }
1299 if( size[ABOVE] )
1300 {
1301 drawText( ABOVE, pos + VECTOR2D( len / 2.0, -aboveOffset ),
1303 }
1304 if( size[BELOW] )
1305 {
1306 drawText( BELOW, pos + VECTOR2D( len / 2.0, belowOffset ),
1308 }
1309 break;
1310
1312 if( size[INSIDE] )
1313 {
1314 drawText( INSIDE, pos + VECTOR2D( 0, insideOffset + (float) len ),
1316 }
1317 if( size[OUTSIDE] )
1318 {
1319 drawText( OUTSIDE, pos + VECTOR2D( 0, -outsideOffset ),
1321 }
1322 if( size[ABOVE] )
1323 {
1324 drawText( ABOVE, pos + VECTOR2D( -aboveOffset, len / 2.0 ),
1326 }
1327 if( size[BELOW] )
1328 {
1329 drawText( BELOW, pos + VECTOR2D( belowOffset, len / 2.0 ),
1331 }
1332 break;
1333
1335 if( size[INSIDE] )
1336 {
1337 drawText( INSIDE, pos + VECTOR2D( 0, -insideOffset - (float) len ),
1339 }
1340 if( size[OUTSIDE] )
1341 {
1342 drawText( OUTSIDE, pos + VECTOR2D( 0, outsideOffset ),
1344 }
1345 if( size[ABOVE] )
1346 {
1347 drawText( ABOVE, pos + VECTOR2D( -aboveOffset, -len / 2.0 ),
1349 }
1350 if( size[BELOW] )
1351 {
1352 drawText( BELOW, pos + VECTOR2D( belowOffset, -len / 2.0 ),
1354 }
1355 break;
1356
1357 default:
1358 wxFAIL_MSG( "Unknown pin orientation" );
1359 }
1360}
1361
1362
1363// Draw the target (an open square) for a wire or label which has no connection or is
1364// being moved.
1365void SCH_PAINTER::drawDanglingIndicator( const VECTOR2I& aPos, const COLOR4D& aColor, int aWidth,
1366 bool aDangling, bool aDrawingShadows, bool aBrightened )
1367{
1368 if( m_schSettings.IsPrinting() )
1369 return;
1370
1371 int size = aDangling ? DANGLING_SYMBOL_SIZE : UNSELECTED_END_SIZE;
1372
1373 if( !aDangling )
1374 aWidth /= 2;
1375
1376 VECTOR2I radius( aWidth + schIUScale.MilsToIU( size / 2 ),
1377 aWidth + schIUScale.MilsToIU( size / 2 ) );
1378
1379 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
1380 // they overlap with a junction dot.
1381 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
1382 m_gal->SetIsStroke( true );
1383 m_gal->SetIsFill( false );
1384 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( aBrightened )
1385 : m_schSettings.GetDanglingIndicatorThickness() );
1386
1387 m_gal->DrawRectangle( aPos - radius, aPos + radius );
1388}
1389
1390
1391void SCH_PAINTER::draw( const SCH_JUNCTION* aJct, int aLayer )
1392{
1393 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1394
1395 if( m_schSettings.IsPrinting() && drawingShadows )
1396 return;
1397
1398 if( drawingShadows && !( aJct->IsBrightened() || aJct->IsSelected() ) )
1399 return;
1400
1401 COLOR4D color = getRenderColor( aJct, aJct->GetLayer(), drawingShadows );
1402
1403 int junctionSize = aJct->GetEffectiveDiameter() / 2;
1404
1405 if( junctionSize > 1 )
1406 {
1407 m_gal->SetIsStroke( drawingShadows );
1408 m_gal->SetLineWidth( getLineWidth( aJct, drawingShadows ) );
1409 m_gal->SetStrokeColor( color );
1410 m_gal->SetIsFill( !drawingShadows );
1411 m_gal->SetFillColor( color );
1412 m_gal->DrawCircle( aJct->GetPosition(), junctionSize );
1413 }
1414}
1415
1416
1417void SCH_PAINTER::draw( const SCH_LINE* aLine, int aLayer )
1418{
1419 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1420
1421 if( m_schSettings.IsPrinting() && drawingShadows )
1422 return;
1423
1424 bool drawingDangling = aLayer == LAYER_DANGLING;
1425 bool drawingOP = aLayer == LAYER_OP_VOLTAGES;
1426
1427 if( drawingShadows && !( aLine->IsBrightened() || aLine->IsSelected() ) )
1428 return;
1429
1430 // Line end dangling status isn't updated until the line is finished drawing, so don't warn
1431 // them about ends that are probably connected
1432 if( aLine->IsNew() && drawingDangling )
1433 return;
1434
1435 COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
1436 float width = getLineWidth( aLine, drawingShadows );
1437 LINE_STYLE lineStyle = aLine->GetEffectiveLineStyle();
1438
1439 if( ( drawingDangling || drawingShadows ) && !aLine->IsNew() )
1440 {
1441 if( ( aLine->IsWire() && aLine->IsStartDangling() )
1442 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( STARTPOINT ) ) )
1443 {
1444 COLOR4D indicatorColor( color );
1445
1446 if( drawingShadows && !aLine->HasFlag( STARTPOINT ) )
1447 indicatorColor.Invert();
1448
1449 drawDanglingIndicator( aLine->GetStartPoint(), indicatorColor, KiROUND( width ),
1450 aLine->IsWire() && aLine->IsStartDangling(), drawingShadows,
1451 aLine->IsBrightened() );
1452 }
1453
1454 if( ( aLine->IsWire() && aLine->IsEndDangling() )
1455 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( ENDPOINT ) ) )
1456 {
1457 COLOR4D indicatorColor( color );
1458
1459 if( drawingShadows && !aLine->HasFlag( ENDPOINT ) )
1460 indicatorColor.Invert();
1461
1462 drawDanglingIndicator( aLine->GetEndPoint(), indicatorColor, KiROUND( width ),
1463 aLine->IsWire() && aLine->IsEndDangling(), drawingShadows,
1464 aLine->IsBrightened() );
1465 }
1466 }
1467
1468 if( drawingDangling )
1469 return;
1470
1471 if( drawingOP && !aLine->GetOperatingPoint().IsEmpty() )
1472 {
1473 int textSize = getOperatingPointTextSize();
1474 VECTOR2I pos = aLine->GetMidPoint();
1475 int textOffset = KiROUND( textSize * 0.22 );
1476 TEXT_ATTRIBUTES attrs;
1477
1478 if( aLine->GetStartPoint().y == aLine->GetEndPoint().y )
1479 {
1480 pos.y -= textOffset;
1483 }
1484 else
1485 {
1486 pos.x += KiROUND( textOffset * 1.2 );
1489 }
1490
1491 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
1492 attrs.m_Size = VECTOR2I( textSize, textSize );
1493 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
1494 attrs.m_Color = m_schSettings.GetLayerColor( LAYER_OP_VOLTAGES );
1495
1496 knockoutText( aLine->GetOperatingPoint(), pos, attrs, aLine->GetFontMetrics() );
1497 }
1498
1499 if( drawingOP )
1500 return;
1501
1502 m_gal->SetIsStroke( true );
1503 m_gal->SetStrokeColor( color );
1504 m_gal->SetLineWidth( width );
1505
1506 if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
1507 {
1508 m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() );
1509 }
1510 else
1511 {
1512 SHAPE_SEGMENT line( aLine->GetStartPoint(), aLine->GetEndPoint() );
1513
1514 STROKE_PARAMS::Stroke( &line, lineStyle, KiROUND( width ), &m_schSettings,
1515 [&]( const VECTOR2I& a, const VECTOR2I& b )
1516 {
1517 // DrawLine has problem with 0 length lines so enforce minimum
1518 if( a == b )
1519 m_gal->DrawLine( a+1, b );
1520 else
1521 m_gal->DrawLine( a, b );
1522 } );
1523 }
1524}
1525
1526
1527void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
1528{
1529 if( !isUnitAndConversionShown( aShape ) )
1530 return;
1531
1532 if( aShape->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1533 return;
1534
1535 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1536
1537 if( m_schSettings.IsPrinting() && drawingShadows )
1538 return;
1539
1540 LINE_STYLE lineStyle = aShape->GetEffectiveLineStyle();
1541 COLOR4D color = getRenderColor( aShape, aLayer, drawingShadows );
1542 bool invertY = aShape->GetLayer() == LAYER_DEVICE;
1543
1544 if( drawingShadows && !( aShape->IsBrightened() || aShape->IsSelected() ) )
1545 return;
1546
1547 auto drawShape =
1548 [&]( const SCH_SHAPE* shape )
1549 {
1550 switch( shape->GetShape() )
1551 {
1552 case SHAPE_T::ARC:
1553 {
1554 VECTOR2D start = MAP_COORDS( shape->GetStart() );
1555 VECTOR2D mid = MAP_COORDS( shape->GetArcMid() );
1556 VECTOR2D end = MAP_COORDS( shape->GetEnd() );
1557 VECTOR2D center = CalcArcCenter( start, mid, end );
1558
1559 EDA_ANGLE startAngle( start - center );
1560 EDA_ANGLE midAngle( mid - center );
1561 EDA_ANGLE endAngle( end - center );
1562
1563 EDA_ANGLE angle1 = midAngle - startAngle;
1564 EDA_ANGLE angle2 = endAngle - midAngle;
1565
1566 EDA_ANGLE angle = angle1.Normalize180() + angle2.Normalize180();
1567
1568 m_gal->DrawArc( center, ( start - center ).EuclideanNorm(), startAngle, angle );
1569 break;
1570 }
1571
1572 case SHAPE_T::CIRCLE:
1573 m_gal->DrawCircle( MAP_COORDS( shape->GetPosition() ), shape->GetRadius() );
1574 break;
1575
1576 case SHAPE_T::RECTANGLE:
1577 m_gal->DrawRectangle( MAP_COORDS( shape->GetPosition() ),
1578 MAP_COORDS( shape->GetEnd() ) );
1579 break;
1580
1581 case SHAPE_T::POLY:
1582 {
1583 const std::vector<SHAPE*> polySegments = shape->MakeEffectiveShapes( true );
1584 std::deque<VECTOR2D> mappedPts;
1585
1586 for( SHAPE* polySegment : polySegments )
1587 {
1588 mappedPts.push_back( MAP_COORDS(
1589 static_cast<SHAPE_SEGMENT*>( polySegment )->GetSeg().A ) );
1590 }
1591
1592 mappedPts.push_back( MAP_COORDS(
1593 static_cast<SHAPE_SEGMENT*>( polySegments.back() )->GetSeg().B ) );
1594
1595 for( SHAPE* polySegment : polySegments )
1596 delete polySegment;
1597
1598 m_gal->DrawPolygon( mappedPts );
1599 break;
1600 }
1601
1602 case SHAPE_T::BEZIER:
1603 {
1604 m_gal->DrawCurve( MAP_COORDS( shape->GetStart() ),
1605 MAP_COORDS( shape->GetBezierC1() ),
1606 MAP_COORDS( shape->GetBezierC2() ),
1607 MAP_COORDS( shape->GetEnd() ) );
1608 break;
1609 }
1610
1611 default:
1612 UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
1613 }
1614 };
1615
1616 if( aLayer == LAYER_SELECTION_SHADOWS )
1617 {
1618 if( eeconfig()->m_Selection.fill_shapes )
1619 {
1620 // Consider a NAND gate. We have no idea which side of the arc is "inside"
1621 // so we can't reliably fill.
1622 if( aShape->GetShape() == SHAPE_T::ARC )
1623 m_gal->SetIsFill( aShape->IsFilled() );
1624 else
1625 m_gal->SetIsFill( true );
1626
1627 m_gal->SetIsStroke( false );
1628 m_gal->SetFillColor( color );
1629 }
1630 else
1631 {
1632 m_gal->SetIsStroke( true );
1633 m_gal->SetIsFill( false );
1634 m_gal->SetLineWidth( getLineWidth( aShape, true ) );
1635 m_gal->SetStrokeColor( color );
1636 }
1637
1638 drawShape( aShape );
1639 }
1640 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
1641 {
1642 // Do not fill the shape in B&W print mode, to avoid to visible items inside the shape
1643 if( aShape->IsFilled() && !m_schSettings.PrintBlackAndWhiteReq() )
1644 {
1646 color = m_schSettings.GetLayerColor( LAYER_DEVICE_BACKGROUND );
1647
1648 m_gal->SetIsFill( true );
1649 m_gal->SetIsStroke( false );
1650 m_gal->SetFillColor( color );
1651
1652 drawShape( aShape );
1653 }
1654 }
1655 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES
1656 || aLayer == LAYER_RULE_AREAS )
1657 {
1658 float lineWidth = getLineWidth( aShape, drawingShadows );
1659
1660 if( lineWidth > 0 )
1661 {
1662 m_gal->SetIsFill( false );
1663 m_gal->SetIsStroke( true );
1664 m_gal->SetLineWidth( lineWidth );
1665 m_gal->SetStrokeColor( color );
1666
1667 if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
1668 {
1669 drawShape( aShape );
1670 }
1671 else
1672 {
1673 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
1674
1675 for( SHAPE* shape : shapes )
1676 {
1677 STROKE_PARAMS::Stroke( shape, lineStyle, KiROUND( lineWidth ), &m_schSettings,
1678 [this, invertY]( const VECTOR2I& a, const VECTOR2I& b )
1679 {
1680 // DrawLine has problem with 0 length lines so enforce minimum
1681 if( a == b )
1682 m_gal->DrawLine( MAP_COORDS( (a+1) ), MAP_COORDS( b ) );
1683 else
1684 m_gal->DrawLine( MAP_COORDS( a ), MAP_COORDS( b ) );
1685 } );
1686 }
1687
1688 for( SHAPE* shape : shapes )
1689 delete shape;
1690 }
1691 }
1692 }
1693}
1694
1695
1696void SCH_PAINTER::draw( const SCH_TEXT* aText, int aLayer, bool aDimmed )
1697{
1698 if( !isUnitAndConversionShown( aText ) )
1699 return;
1700
1701 if( aText->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1702 return;
1703
1704 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1705
1706 if( m_schSettings.IsPrinting() && drawingShadows )
1707 return;
1708
1709 if( drawingShadows && !( aText->IsBrightened() || aText->IsSelected() ) )
1710 return;
1711
1712 switch( aText->Type() )
1713 {
1714 case SCH_SHEET_PIN_T: aLayer = LAYER_SHEETLABEL; break;
1715 case SCH_HIER_LABEL_T: aLayer = LAYER_HIERLABEL; break;
1716 case SCH_GLOBAL_LABEL_T: aLayer = LAYER_GLOBLABEL; break;
1717 case SCH_DIRECTIVE_LABEL_T: aLayer = LAYER_NETCLASS_REFS; break;
1718 case SCH_LABEL_T: aLayer = LAYER_LOCLABEL; break;
1719 case SCH_TEXT_T: aLayer = aText->GetParentSymbol() ? LAYER_DEVICE
1720 : LAYER_NOTES; break;
1721 default: aLayer = LAYER_NOTES; break;
1722 }
1723
1724 COLOR4D color = getRenderColor( aText, aLayer, drawingShadows, aDimmed );
1725
1726 if( m_schematic )
1727 {
1728 SCH_CONNECTION* conn = nullptr;
1729
1730 if( !aText->IsConnectivityDirty() )
1731 conn = aText->Connection();
1732
1733 if( conn && conn->IsBus() )
1734 color = getRenderColor( aText, LAYER_BUS, drawingShadows );
1735 }
1736
1737 if( !( aText->IsVisible() || aText->IsForceVisible() ) )
1738 {
1739 if( m_schSettings.m_IsSymbolEditor || eeconfig()->m_Appearance.show_hidden_fields )
1740 color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
1741 else
1742 return;
1743 }
1744
1745 m_gal->SetStrokeColor( color );
1746 m_gal->SetFillColor( color );
1747
1748 wxString shownText( aText->GetShownText( true ) );
1749 VECTOR2I text_offset = aText->GetSchematicTextOffset( &m_schSettings );
1750 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
1751 KIFONT::FONT* font = getFont( aText );
1752 bool invertY = aText->GetLayer() == LAYER_DEVICE;
1753
1754 attrs.m_Angle = aText->GetDrawRotation();
1755 attrs.m_StrokeWidth = KiROUND( getTextThickness( aText ) );
1756
1757 if( drawingShadows && font->IsOutline() )
1758 {
1759 BOX2I bBox = aText->GetBoundingBox();
1760 bBox.Inflate( KiROUND( getTextThickness( aText ) * 2 ) );
1761 bBox.RevertYAxis();
1762
1763 m_gal->SetIsStroke( false );
1764 m_gal->SetIsFill( true );
1765 m_gal->DrawRectangle( MAP_COORDS( bBox.GetPosition() ), MAP_COORDS( bBox.GetEnd() ) );
1766 }
1767 else if( aText->GetLayer() == LAYER_DEVICE )
1768 {
1769 BOX2I bBox = aText->GetBoundingBox();
1770 VECTOR2D pos = bBox.Centre();
1771
1772 // Due to the fact a shadow text can be drawn left or right aligned, it needs to be
1773 // offset by shadowWidth/2 to be drawn at the same place as normal text.
1774 // For some reason we need to slightly modify this offset for a better look (better
1775 // alignment of shadow shape), for KiCad font only.
1776 double shadowOffset = 0.0;
1777
1778 if( drawingShadows )
1779 {
1780 double shadowWidth = getShadowWidth( !aText->IsSelected() );
1781 attrs.m_StrokeWidth += getShadowWidth( !aText->IsSelected() );
1782
1783 const double adjust = 1.2f; // Value chosen after tests
1784 shadowOffset = shadowWidth/2.0f * adjust;
1785 }
1786
1787 if( attrs.m_Angle == ANGLE_VERTICAL )
1788 {
1789 switch( attrs.m_Halign )
1790 {
1792 pos.y = bBox.GetBottom() + shadowOffset;
1793 break;
1795 pos.y = ( bBox.GetTop() + bBox.GetBottom() ) / 2.0;
1796 break;
1798 pos.y = bBox.GetTop() - shadowOffset;
1799 break;
1801 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
1802 break;
1803 }
1804 }
1805 else
1806 {
1807 switch( attrs.m_Halign )
1808 {
1810 pos.x = bBox.GetLeft() - shadowOffset;
1811 break;
1813 pos.x = ( bBox.GetLeft() + bBox.GetRight() ) / 2.0;
1814 break;
1816 pos.x = bBox.GetRight() + shadowOffset;
1817 break;
1819 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
1820 break;
1821 }
1822 }
1823
1824 // Because the text vertical position is the bounding box center, the text is drawn as
1825 // vertically centered.
1827
1828 strokeText( shownText, pos, attrs, aText->GetFontMetrics() );
1829 }
1830 else if( drawingShadows )
1831 {
1832 m_gal->SetIsFill( false );
1833 m_gal->SetIsStroke( true );
1834 attrs.m_StrokeWidth += KiROUND( getShadowWidth( !aText->IsSelected() ) );
1835 attrs.m_Underlined = false;
1836
1837 // Fudge factors to match 6.0 positioning
1838 // New text stroking has width dependent offset but we need to center the shadow on the
1839 // stroke. NB this offset is in font.cpp also.
1840 int fudge = KiROUND( getShadowWidth( !aText->IsSelected() ) / 1.52 );
1841
1842 if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_0 )
1843 text_offset.x -= fudge;
1844 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_90 )
1845 text_offset.y -= fudge;
1846 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_0 )
1847 text_offset.x += fudge;
1848 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_90 )
1849 text_offset.y += fudge;
1850
1851 strokeText( shownText, aText->GetDrawPos() + text_offset, attrs, aText->GetFontMetrics() );
1852 }
1853 else
1854 {
1855 if( aText->IsHypertext() && aText->IsRollover() )
1856 {
1857 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
1858 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
1859 attrs.m_Underlined = true;
1860 }
1861
1862 // Adjust text drawn in an outline font to more closely mimic the positioning of
1863 // SCH_FIELD text.
1864 if( font->IsOutline() && aText->Type() == SCH_TEXT_T )
1865 {
1866 BOX2I firstLineBBox = aText->GetTextBox( 0 );
1867 int sizeDiff = firstLineBBox.GetHeight() - aText->GetTextSize().y;
1868 int adjust = KiROUND( sizeDiff * 0.4 );
1869 VECTOR2I adjust_offset( 0, - adjust );
1870
1871 RotatePoint( adjust_offset, aText->GetDrawRotation() );
1872 text_offset += adjust_offset;
1873 }
1874
1875 if( nonCached( aText )
1876 && aText->RenderAsBitmap( m_gal->GetWorldScale() )
1877 && !shownText.Contains( wxT( "\n" ) ) )
1878 {
1879 bitmapText( shownText, aText->GetDrawPos() + text_offset, attrs );
1880 const_cast<SCH_TEXT*>( aText )->SetFlags( IS_SHOWN_AS_BITMAP );
1881 }
1882 else
1883 {
1884 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
1885
1886 if( !aText->IsHypertext() && font->IsOutline() )
1887 cache = aText->GetRenderCache( font, shownText, text_offset );
1888
1889 if( cache )
1890 {
1891 m_gal->SetLineWidth( attrs.m_StrokeWidth );
1892 m_gal->DrawGlyphs( *cache );
1893 }
1894 else
1895 {
1896 strokeText( shownText, aText->GetDrawPos() + text_offset, attrs,
1897 aText->GetFontMetrics() );
1898 }
1899
1900 const_cast<SCH_TEXT*>( aText )->ClearFlags( IS_SHOWN_AS_BITMAP );
1901 }
1902 }
1903}
1904
1905
1906void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer, bool aDimmed )
1907{
1908 if( aTextBox->Type() == SCH_TABLECELL_T )
1909 {
1910 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aTextBox );
1911
1912 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
1913 return;
1914 }
1915
1916 if( !isUnitAndConversionShown( aTextBox ) )
1917 return;
1918
1919 if( aTextBox->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1920 return;
1921
1922 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1923
1924 if( m_schSettings.IsPrinting() && drawingShadows )
1925 return;
1926
1927 COLOR4D color = getRenderColor( aTextBox, aLayer, drawingShadows, aDimmed );
1928 COLOR4D bg = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
1929 float borderWidth = getLineWidth( aTextBox, drawingShadows );
1930 KIFONT::FONT* font = getFont( aTextBox );
1931 bool invertY = aTextBox->GetLayer() == LAYER_DEVICE;
1932
1933 auto drawText =
1934 [&]()
1935 {
1936 wxString shownText = aTextBox->GetShownText( true );
1937 TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes();
1938
1939 attrs.m_Angle = aTextBox->GetDrawRotation();
1940 attrs.m_StrokeWidth = KiROUND( getTextThickness( aTextBox ) );
1941
1942 if( aTextBox->IsHypertext() && aTextBox->IsRollover() )
1943 {
1944 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
1945 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
1946 attrs.m_Underlined = true;
1947 }
1948
1949 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
1950
1951 if( !aTextBox->IsHypertext() && font->IsOutline() )
1952 cache = aTextBox->GetRenderCache( font, shownText );
1953
1954 if( cache )
1955 {
1956 m_gal->SetLineWidth( attrs.m_StrokeWidth );
1957 m_gal->DrawGlyphs( *cache );
1958 }
1959 else
1960 {
1961 strokeText( shownText, aTextBox->GetDrawPos(), attrs, aTextBox->GetFontMetrics() );
1962 }
1963 };
1964
1965 if( drawingShadows && !( aTextBox->IsBrightened() || aTextBox->IsSelected() ) )
1966 return;
1967
1968 m_gal->SetFillColor( color );
1969 m_gal->SetStrokeColor( color );
1970
1971 if( aLayer == LAYER_SELECTION_SHADOWS )
1972 {
1973 m_gal->SetIsFill( true );
1974 m_gal->SetIsStroke( false );
1975 m_gal->SetLineWidth( borderWidth );
1976
1977 m_gal->DrawRectangle( MAP_COORDS( aTextBox->GetPosition() ),
1978 MAP_COORDS( aTextBox->GetEnd() ) );
1979 }
1980 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
1981 {
1982 // Do not fill the shape in B&W print mode, to avoid to visible items
1983 // inside the shape
1984 if( aTextBox->IsFilled() && !m_schSettings.PrintBlackAndWhiteReq() )
1985 {
1986 m_gal->SetIsFill( true );
1987 m_gal->SetIsStroke( false );
1988 m_gal->SetLineWidth( borderWidth );
1989
1990 m_gal->DrawRectangle( MAP_COORDS( aTextBox->GetPosition() ),
1991 MAP_COORDS( aTextBox->GetEnd() ) );
1992 }
1993 }
1994 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES )
1995 {
1996 drawText();
1997
1998 if( aTextBox->Type() != SCH_TABLECELL_T && borderWidth > 0 )
1999 {
2000 COLOR4D borderColor = aTextBox->GetStroke().GetColor();
2001 LINE_STYLE borderStyle = aTextBox->GetEffectiveLineStyle();
2002 double transparency = aTextBox->GetForcedTransparency();
2003
2004 if( m_schSettings.m_OverrideItemColors || aTextBox->IsBrightened()
2005 || borderColor == COLOR4D::UNSPECIFIED )
2006 {
2007 borderColor = m_schSettings.GetLayerColor( aLayer );
2008 }
2009
2010 if( transparency > 0.0 )
2011 borderColor = borderColor.WithAlpha( borderColor.a * ( 1.0 - transparency ) );
2012
2013 if( aDimmed )
2014 {
2015 borderColor = borderColor.Mix( bg, 0.5f );
2016 borderColor.Desaturate( );
2017 }
2018
2019 m_gal->SetIsFill( false );
2020 m_gal->SetIsStroke( true );
2021 m_gal->SetStrokeColor( borderColor );
2022 m_gal->SetLineWidth( borderWidth );
2023
2024 if( borderStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
2025 {
2026 m_gal->DrawRectangle( MAP_COORDS( aTextBox->GetPosition() ),
2027 MAP_COORDS( aTextBox->GetEnd() ) );
2028 }
2029 else
2030 {
2031 std::vector<SHAPE*> shapes = aTextBox->MakeEffectiveShapes( true );
2032
2033 for( SHAPE* shape : shapes )
2034 {
2035 STROKE_PARAMS::Stroke( shape, borderStyle, KiROUND( borderWidth ),
2036 &m_schSettings,
2037 [this, invertY]( const VECTOR2I& a, const VECTOR2I& b )
2038 {
2039 // DrawLine has problem with 0 length lines so enforce minimum
2040 if( a == b )
2041 m_gal->DrawLine( MAP_COORDS( (a+1) ), MAP_COORDS( b ) );
2042 else
2043 m_gal->DrawLine( MAP_COORDS( a ), MAP_COORDS( b ) );
2044 } );
2045 }
2046
2047 for( SHAPE* shape : shapes )
2048 delete shape;
2049 }
2050 }
2051 }
2052}
2053
2054
2055void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
2056{
2057 for( SCH_TABLECELL* cell : aTable->GetCells() )
2058 draw( cell, aLayer, aDimmed );
2059
2060 if( aLayer == LAYER_SELECTION_SHADOWS )
2061 return;
2062
2063 VECTOR2I pos = aTable->GetPosition();
2064 VECTOR2I end = aTable->GetEnd();
2065
2066 int lineWidth;
2067 COLOR4D color;
2068 LINE_STYLE lineStyle;
2069
2070 auto setupStroke =
2071 [&]( const STROKE_PARAMS& stroke )
2072 {
2073 lineWidth = stroke.GetWidth();
2074 color = stroke.GetColor();
2075 lineStyle = stroke.GetLineStyle();
2076
2077 if( lineWidth == 0 )
2078 lineWidth = m_schSettings.GetDefaultPenWidth();
2079
2081 color = m_schSettings.GetLayerColor( LAYER_NOTES );
2082
2083 if( lineStyle == LINE_STYLE::DEFAULT )
2084 lineStyle = LINE_STYLE::SOLID;
2085
2086 m_gal->SetIsFill( false );
2087 m_gal->SetIsStroke( true );
2088 m_gal->SetStrokeColor( color );
2089 m_gal->SetLineWidth( (float) lineWidth );
2090 };
2091
2092 auto strokeShape =
2093 [&]( const SHAPE& shape )
2094 {
2095 STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_schSettings,
2096 [&]( const VECTOR2I& a, const VECTOR2I& b )
2097 {
2098 // DrawLine has problem with 0 length lines so enforce minimum
2099 if( a == b )
2100 m_gal->DrawLine( a+1, b );
2101 else
2102 m_gal->DrawLine( a, b );
2103 } );
2104 };
2105
2106 auto strokeLine =
2107 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
2108 {
2109 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2110 {
2111 m_gal->DrawLine( ptA, ptB );
2112 }
2113 else
2114 {
2115 SHAPE_SEGMENT seg( ptA, ptB );
2116 strokeShape( seg );
2117 }
2118 };
2119
2120 auto strokeRect =
2121 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
2122 {
2123 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2124 {
2125 m_gal->DrawRectangle( ptA, ptB );
2126 }
2127 else
2128 {
2129 SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
2130 strokeShape( rect );
2131 }
2132 };
2133
2134 if( aTable->GetSeparatorsStroke().GetWidth() >= 0 )
2135 {
2136 setupStroke( aTable->GetSeparatorsStroke() );
2137
2138 if( aTable->StrokeColumns() )
2139 {
2140 for( int col = 0; col < aTable->GetColCount() - 1; ++col )
2141 {
2142 for( int row = 0; row < aTable->GetRowCount(); ++row )
2143 {
2144 SCH_TABLECELL* cell = aTable->GetCell( row, col );
2145 VECTOR2I topRight( cell->GetEndX(), cell->GetStartY() );
2146
2147 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2148 strokeLine( topRight, cell->GetEnd() );
2149 }
2150 }
2151 }
2152
2153 if( aTable->StrokeRows() )
2154 {
2155 for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
2156 {
2157 for( int col = 0; col < aTable->GetColCount(); ++col )
2158 {
2159 SCH_TABLECELL* cell = aTable->GetCell( row, col );
2160 VECTOR2I botLeft( cell->GetStartX(), cell->GetEndY() );
2161
2162 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2163 strokeLine( botLeft, cell->GetEnd() );
2164 }
2165 }
2166 }
2167 }
2168
2169 if( aTable->GetBorderStroke().GetWidth() >= 0 )
2170 {
2171 setupStroke( aTable->GetBorderStroke() );
2172
2173 if( aTable->StrokeHeader() )
2174 {
2175 SCH_TABLECELL* cell = aTable->GetCell( 0, 0 );
2176 strokeLine( VECTOR2I( pos.x, cell->GetEndY() ), VECTOR2I( end.x, cell->GetEndY() ) );
2177 }
2178
2179 if( aTable->StrokeExternal() )
2180 strokeRect( pos, end );
2181 }
2182}
2183
2184
2185static void orientSymbol( LIB_SYMBOL* symbol, int orientation )
2186{
2187 struct ORIENT
2188 {
2189 int flag;
2190 int n_rots;
2191 int mirror_x;
2192 int mirror_y;
2193 }
2194 orientations[] =
2195 {
2196 { SYM_ORIENT_0, 0, 0, 0 },
2197 { SYM_ORIENT_90, 1, 0, 0 },
2198 { SYM_ORIENT_180, 2, 0, 0 },
2199 { SYM_ORIENT_270, 3, 0, 0 },
2200 { SYM_MIRROR_X + SYM_ORIENT_0, 0, 1, 0 },
2201 { SYM_MIRROR_X + SYM_ORIENT_90, 1, 1, 0 },
2202 { SYM_MIRROR_Y, 0, 0, 1 },
2203 { SYM_MIRROR_X + SYM_ORIENT_270, 3, 1, 0 },
2204 { SYM_MIRROR_Y + SYM_ORIENT_0, 0, 0, 1 },
2205 { SYM_MIRROR_Y + SYM_ORIENT_90, 1, 0, 1 },
2206 { SYM_MIRROR_Y + SYM_ORIENT_180, 2, 0, 1 },
2207 { SYM_MIRROR_Y + SYM_ORIENT_270, 3, 0, 1 }
2208 };
2209
2210 ORIENT o = orientations[ 0 ];
2211
2212 for( ORIENT& i : orientations )
2213 {
2214 if( i.flag == orientation )
2215 {
2216 o = i;
2217 break;
2218 }
2219 }
2220
2221 for( SCH_ITEM& item : symbol->GetDrawItems() )
2222 {
2223 for( int i = 0; i < o.n_rots; i++ )
2224 item.Rotate( VECTOR2I( 0, 0 ), true );
2225
2226 if( o.mirror_x )
2227 item.MirrorVertically( 0 );
2228
2229 if( o.mirror_y )
2230 item.MirrorHorizontally( 0 );
2231 }
2232}
2233
2234
2235wxString SCH_PAINTER::expandLibItemTextVars( const wxString& aSourceText,
2236 const SCH_SYMBOL* aSymbolContext )
2237{
2238 std::function<bool( wxString* )> symbolResolver =
2239 [&]( wxString* token ) -> bool
2240 {
2241 return aSymbolContext->ResolveTextVar( &m_schematic->CurrentSheet(), token );
2242 };
2243
2244 return ExpandTextVars( aSourceText, &symbolResolver );
2245}
2246
2247
2248void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
2249{
2250 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2251
2252 if( m_schSettings.IsPrinting() && drawingShadows )
2253 return;
2254
2255 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2256 {
2257 for( const SCH_FIELD& field : aSymbol->GetFields() )
2258 draw( &field, aLayer, aSymbol->GetDNP() );
2259 }
2260
2261 if( isFieldsLayer( aLayer ) )
2262 return;
2263
2264 if( drawingShadows && !( aSymbol->IsBrightened() || aSymbol->IsSelected() ) )
2265 {
2266 // Don't exit here; symbol may still have selected pins
2267 // return;
2268 }
2269
2270 int unit = aSymbol->GetUnitSelection( &m_schematic->CurrentSheet() );
2271 int bodyStyle = aSymbol->GetBodyStyle();
2272
2273 // Use dummy symbol if the actual couldn't be found (or couldn't be locked).
2274 LIB_SYMBOL* originalSymbol = aSymbol->GetLibSymbolRef() ? aSymbol->GetLibSymbolRef().get()
2275 : dummy();
2276 bool invertY = true;
2277
2278 std::vector<SCH_PIN*> originalPins = originalSymbol->GetPins( unit, bodyStyle );
2279
2280 // Copy the source so we can re-orient and translate it.
2281 LIB_SYMBOL tempSymbol( *originalSymbol );
2282 std::vector<SCH_PIN*> tempPins = tempSymbol.GetPins( unit, bodyStyle );
2283
2284 tempSymbol.SetFlags( aSymbol->GetFlags() );
2285
2286 orientSymbol( &tempSymbol, aSymbol->GetOrientation() );
2287
2288 for( SCH_ITEM& tempItem : tempSymbol.GetDrawItems() )
2289 {
2290 tempItem.SetFlags( aSymbol->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2291 tempItem.Move( MAP_COORDS( aSymbol->GetPosition() ) );
2292
2293 if( tempItem.Type() == SCH_TEXT_T )
2294 {
2295 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( &tempItem );
2296
2297 if( textItem->HasTextVars() )
2298 textItem->SetText( expandLibItemTextVars( textItem->GetText(), aSymbol ) );
2299 }
2300 else if( tempItem.Type() == SCH_TEXTBOX_T )
2301 {
2302 SCH_TEXTBOX* textboxItem = static_cast<SCH_TEXTBOX*>( &tempItem );
2303
2304 if( textboxItem->HasTextVars() )
2305 textboxItem->SetText( expandLibItemTextVars( textboxItem->GetText(), aSymbol ) );
2306 }
2307 }
2308
2309 // Copy the pin info from the symbol to the temp pins
2310 for( unsigned i = 0; i < tempPins.size(); ++ i )
2311 {
2312 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2313 SCH_PIN* tempPin = tempPins[ i ];
2314
2315 tempPin->ClearFlags();
2316 tempPin->SetFlags( symbolPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2317 // IS_SHOWN_AS_BITMAP
2318
2319 tempPin->SetName( expandLibItemTextVars( symbolPin->GetShownName(), aSymbol ) );
2320 tempPin->SetType( symbolPin->GetType() );
2321 tempPin->SetShape( symbolPin->GetShape() );
2322
2323 if( symbolPin->IsDangling() )
2324 tempPin->SetFlags( IS_DANGLING );
2325 else
2326 tempPin->ClearFlags( IS_DANGLING );
2327
2328 tempPin->SetOperatingPoint( symbolPin->GetOperatingPoint() );
2329 }
2330
2331 draw( &tempSymbol, aLayer, false, aSymbol->GetUnit(), aSymbol->GetBodyStyle(), aSymbol->GetDNP() );
2332
2333 for( unsigned i = 0; i < tempPins.size(); ++i )
2334 {
2335 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2336 SCH_PIN* tempPin = tempPins[ i ];
2337
2338 symbolPin->ClearFlags();
2339 tempPin->ClearFlags( IS_DANGLING ); // Clear this temporary flag
2340 symbolPin->SetFlags( tempPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2341 // IS_SHOWN_AS_BITMAP
2342 }
2343
2344 if( aSymbol->GetDNP() )
2345 {
2346 BOX2I bbox = aSymbol->GetBodyBoundingBox();
2347 BOX2I pins = aSymbol->GetBodyAndPinsBoundingBox();
2348 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
2349 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
2350
2351 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
2352 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
2353 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
2354
2355 VECTOR2I pt1 = bbox.GetOrigin();
2356 VECTOR2I pt2 = bbox.GetEnd();
2357
2358 m_gal->PushDepth();
2359 m_gal->AdvanceDepth();
2360 m_gal->SetIsStroke( true );
2361 m_gal->SetIsFill( true );
2362 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_DNP_MARKER ) );
2363 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_DNP_MARKER ) );
2364
2365 m_gal->DrawSegment( pt1, pt2, 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ) );
2366 std::swap( pt1.x, pt2.x );
2367 m_gal->DrawSegment( pt1, pt2, 3.0 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ) );
2368 m_gal->PopDepth();
2369 }
2370}
2371
2372
2373void SCH_PAINTER::draw( const SCH_FIELD* aField, int aLayer, bool aDimmed )
2374{
2375 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2376
2377 if( m_schSettings.IsPrinting() && drawingShadows )
2378 return;
2379
2380 if( drawingShadows && !( aField->IsBrightened() || aField->IsSelected() ) )
2381 return;
2382
2383 if( !isUnitAndConversionShown( aField ) )
2384 return;
2385
2386 // Must check layer as fields are sometimes drawn by their parent rather than directly
2387 // from the view.
2388 int layers[KIGFX::VIEW::VIEW_MAX_LAYERS];
2389 int layers_count;
2390 bool foundLayer = false;
2391
2392 aField->ViewGetLayers( layers, layers_count );
2393
2394 for( int i = 0; i < layers_count; ++i )
2395 {
2396 if( layers[i] == aLayer )
2397 foundLayer = true;
2398 }
2399
2400 if( !foundLayer )
2401 return;
2402
2403 aLayer = aField->GetLayer();
2404
2405 COLOR4D color = getRenderColor( aField, aLayer, drawingShadows, aDimmed );
2406
2407 if( !( aField->IsVisible() || aField->IsForceVisible() ) )
2408 {
2409 bool force_show = m_schematic ? eeconfig()->m_Appearance.show_hidden_fields
2410 : m_schSettings.m_ShowHiddenFields;
2411
2412 if( force_show )
2413 color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows, aDimmed );
2414 else
2415 return;
2416 }
2417
2418 wxString shownText = aField->GetShownText( true );
2419
2420 if( shownText.IsEmpty() )
2421 return;
2422
2423 // Calculate the text orientation according to the parent orientation.
2424 EDA_ANGLE orient = aField->GetTextAngle();
2425
2426 if( aField->GetParent() && aField->GetParent()->Type() == SCH_SYMBOL_T )
2427 {
2428 if( static_cast<SCH_SYMBOL*>( aField->GetParent() )->GetTransform().y1 )
2429 {
2430 // Rotate symbol 90 degrees.
2431 if( orient.IsHorizontal() )
2432 orient = ANGLE_VERTICAL;
2433 else
2434 orient = ANGLE_HORIZONTAL;
2435 }
2436 }
2437
2438 /*
2439 * Calculate the text justification, according to the symbol orientation/mirror.
2440 * This is a bit complicated due to cumulative calculations:
2441 * - numerous cases (mirrored or not, rotation)
2442 * - the DrawGraphicText function recalculate also H and H justifications according to the
2443 * text orientation.
2444 * - when symbol is mirrored, the text is not mirrored and justifications are complicated
2445 * to calculate so the easier way is to use no justifications (centered text) and use
2446 * GetBoundingBox to know the text coordinate considered as centered
2447 */
2448 BOX2I bbox = aField->GetBoundingBox();
2449
2450 if( aField->GetParent() && aField->GetParent()->Type() == SCH_GLOBAL_LABEL_T )
2451 {
2452 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( aField->GetParent() );
2453 bbox.Offset( label->GetSchematicTextOffset( &m_schSettings ) );
2454 }
2455
2456 if( m_schSettings.GetDrawBoundingBoxes() )
2457 drawItemBoundingBox( aField );
2458
2459 m_gal->SetStrokeColor( color );
2460 m_gal->SetFillColor( color );
2461
2462 if( drawingShadows && getFont( aField )->IsOutline() )
2463 {
2464 BOX2I shadow_box = bbox;
2465 bool invertY = true;
2466 shadow_box.Inflate( KiROUND( getTextThickness( aField ) * 2 ) );
2467 shadow_box.RevertYAxis();
2468
2469 m_gal->SetIsStroke( false );
2470 m_gal->SetIsFill( true );
2471 m_gal->DrawRectangle( MAP_COORDS( shadow_box.GetPosition() ),
2472 MAP_COORDS( shadow_box.GetEnd() ) );
2473 }
2474 else
2475 {
2476 VECTOR2I textpos = bbox.Centre();
2477 TEXT_ATTRIBUTES attributes = aField->GetAttributes();
2478
2479 attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
2480 attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
2481 attributes.m_StrokeWidth = KiROUND( getTextThickness( aField ) );
2482 attributes.m_Angle = orient;
2483
2484 if( drawingShadows )
2485 attributes.m_StrokeWidth += getShadowWidth( !aField->IsSelected() );
2486
2487 if( aField->IsHypertext() && aField->IsRollover() )
2488 {
2489 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2490 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2491 attributes.m_Underlined = true;
2492 }
2493
2494 if( nonCached( aField ) && aField->RenderAsBitmap( m_gal->GetWorldScale() ) )
2495 {
2496 bitmapText( shownText, textpos, attributes );
2497 const_cast<SCH_FIELD*>( aField )->SetFlags( IS_SHOWN_AS_BITMAP );
2498 }
2499 else
2500 {
2501 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2502
2503 if( !aField->IsHypertext() )
2504 cache = aField->GetRenderCache( shownText, textpos, attributes );
2505
2506 if( cache )
2507 {
2508 m_gal->SetLineWidth( attributes.m_StrokeWidth );
2509 m_gal->DrawGlyphs( *cache );
2510 }
2511 else
2512 {
2513 strokeText( shownText, textpos, attributes, aField->GetFontMetrics() );
2514 }
2515
2516 const_cast<SCH_FIELD*>( aField )->ClearFlags( IS_SHOWN_AS_BITMAP );
2517 }
2518 }
2519
2520 // Draw the umbilical line
2521 if( aField->IsMoving() && m_schematic )
2522 {
2523 VECTOR2I parentPos = aField->GetParentPosition();
2524
2525 m_gal->SetLineWidth( m_schSettings.GetOutlineWidth() );
2526 m_gal->SetStrokeColor( getRenderColor( aField, LAYER_SCHEMATIC_ANCHOR, drawingShadows ) );
2527 m_gal->DrawLine( bbox.Centre(), parentPos );
2528 }
2529}
2530
2531
2532void SCH_PAINTER::draw( const SCH_GLOBALLABEL* aLabel, int aLayer )
2533{
2534 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2535
2536 if( m_schSettings.IsPrinting() && drawingShadows )
2537 return;
2538
2539 bool drawingDangling = aLayer == LAYER_DANGLING;
2540
2541 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2542 {
2543 for( const SCH_FIELD& field : aLabel->GetFields() )
2544 draw( &field, aLayer, false );
2545 }
2546
2547 if( isFieldsLayer( aLayer ) )
2548 return;
2549
2550 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2551 return;
2552
2553 COLOR4D color = getRenderColor( aLabel, LAYER_GLOBLABEL, drawingShadows );
2554
2555 if( drawingDangling )
2556 {
2557 if( aLabel->IsDangling() )
2558 {
2559 drawDanglingIndicator( aLabel->GetTextPos(), color,
2561 drawingShadows, aLabel->IsBrightened() );
2562 }
2563
2564 return;
2565 }
2566
2567 std::vector<VECTOR2I> pts;
2568 std::deque<VECTOR2D> pts2;
2569
2570 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
2571
2572 for( const VECTOR2I& p : pts )
2573 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2574
2575 m_gal->SetIsStroke( true );
2576 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2577 m_gal->SetStrokeColor( color );
2578
2579 if( drawingShadows )
2580 {
2581 m_gal->SetIsFill( eeconfig()->m_Selection.fill_shapes );
2582 m_gal->SetFillColor( color );
2583 m_gal->DrawPolygon( pts2 );
2584 }
2585 else
2586 {
2587 m_gal->SetIsFill( false );
2588 m_gal->DrawPolyline( pts2 );
2589 }
2590
2591 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2592}
2593
2594
2595void SCH_PAINTER::draw( const SCH_LABEL* aLabel, int aLayer )
2596{
2597 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2598
2599 if( m_schSettings.IsPrinting() && drawingShadows )
2600 return;
2601
2602 bool drawingDangling = aLayer == LAYER_DANGLING;
2603
2604 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2605 {
2606 for( const SCH_FIELD& field : aLabel->GetFields() )
2607 draw( &field, aLayer, false );
2608 }
2609
2610 if( isFieldsLayer( aLayer ) )
2611 return;
2612
2613 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2614 return;
2615
2616 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows );
2617
2618 if( drawingDangling )
2619 {
2620 if( aLabel->IsDangling() )
2621 {
2622 drawDanglingIndicator( aLabel->GetTextPos(), color,
2624 drawingShadows, aLabel->IsBrightened() );
2625 }
2626
2627 return;
2628 }
2629
2630 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2631}
2632
2633
2634void SCH_PAINTER::draw( const SCH_HIERLABEL* aLabel, int aLayer )
2635{
2636 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2637
2638 if( m_schSettings.IsPrinting() && drawingShadows )
2639 return;
2640
2641 bool drawingDangling = aLayer == LAYER_DANGLING;
2642
2643 if( !( drawingShadows || drawingDangling ) || eeconfig()->m_Selection.draw_selected_children )
2644 {
2645 for( const SCH_FIELD& field : aLabel->GetFields() )
2646 draw( &field, aLayer, false );
2647 }
2648
2649 if( isFieldsLayer( aLayer ) )
2650 return;
2651
2652 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2653 return;
2654
2655 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows );
2656
2657 if( drawingDangling )
2658 {
2659 if( aLabel->IsDangling() )
2660 {
2661 drawDanglingIndicator( aLabel->GetTextPos(), color,
2663 drawingShadows, aLabel->IsBrightened() );
2664 }
2665
2666 return;
2667 }
2668
2669 if( m_schematic )
2670 {
2671 SCH_CONNECTION* conn = nullptr;
2672
2673 if( !aLabel->IsConnectivityDirty() )
2674 conn = aLabel->Connection();
2675
2676 if( conn && conn->IsBus() )
2677 color = getRenderColor( aLabel, LAYER_BUS, drawingShadows );
2678 }
2679
2680 std::vector<VECTOR2I> pts;
2681 std::deque<VECTOR2D> pts2;
2682
2683 aLabel->CreateGraphicShape( &m_schSettings, pts, (VECTOR2I)aLabel->GetTextPos() );
2684
2685 for( const VECTOR2I& p : pts )
2686 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2687
2688 m_gal->SetIsFill( true );
2689 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
2690 m_gal->SetIsStroke( true );
2691 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2692 m_gal->SetStrokeColor( color );
2693 m_gal->DrawPolyline( pts2 );
2694
2695 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2696}
2697
2698
2699void SCH_PAINTER::draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer )
2700{
2701 if( !eeconfig()->m_Appearance.show_directive_labels && !aLabel->IsSelected() )
2702 return;
2703
2704 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2705
2706 if( m_schSettings.IsPrinting() && drawingShadows )
2707 return;
2708
2709 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2710 {
2711 for( const SCH_FIELD& field : aLabel->GetFields() )
2712 draw( &field, aLayer, false );
2713 }
2714
2715 if( isFieldsLayer( aLayer ) )
2716 return;
2717
2718 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2719 return;
2720
2721 COLOR4D color = getRenderColor( aLabel, LAYER_NETCLASS_REFS, drawingShadows );
2722
2723 if( aLayer == LAYER_DANGLING )
2724 {
2725 if( aLabel->IsDangling() )
2726 {
2727 drawDanglingIndicator( aLabel->GetTextPos(), color,
2729 drawingShadows, aLabel->IsBrightened() );
2730 }
2731
2732 return;
2733 }
2734
2735 std::vector<VECTOR2I> pts;
2736 std::deque<VECTOR2D> pts2;
2737
2738 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
2739
2740 for( const VECTOR2I& p : pts )
2741 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2742
2743 m_gal->SetIsFill( false );
2744 m_gal->SetFillColor( color );
2745 m_gal->SetIsStroke( true );
2746 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2747 m_gal->SetStrokeColor( color );
2748
2749 if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_DOT )
2750 {
2751 m_gal->DrawLine( pts2[0], pts2[1] );
2752 m_gal->SetIsFill( true );
2753 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
2754 }
2755 else if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
2756 {
2757 m_gal->DrawLine( pts2[0], pts2[1] );
2758 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
2759 }
2760 else
2761 {
2762 m_gal->DrawPolyline( pts2 );
2763 }
2764}
2765
2766
2767void SCH_PAINTER::draw( const SCH_SHEET* aSheet, int aLayer )
2768{
2769 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2770
2771 if( m_schSettings.IsPrinting() && drawingShadows )
2772 return;
2773
2774 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2775 {
2776 for( const SCH_FIELD& field : aSheet->GetFields() )
2777 draw( &field, aLayer, false );
2778
2779 for( SCH_SHEET_PIN* sheetPin : aSheet->GetPins() )
2780 draw( static_cast<SCH_HIERLABEL*>( sheetPin ), aLayer );
2781 }
2782
2783 if( isFieldsLayer( aLayer ) )
2784 return;
2785
2786 VECTOR2D pos = aSheet->GetPosition();
2787 VECTOR2D size = aSheet->GetSize();
2788
2789 if( aLayer == LAYER_SHEET_BACKGROUND )
2790 {
2791 // Do not fill the shape in B&W print mode, to avoid to visible items
2792 // inside the shape
2793 if( !m_schSettings.PrintBlackAndWhiteReq() )
2794 {
2795 m_gal->SetFillColor( getRenderColor( aSheet, LAYER_SHEET_BACKGROUND, true ) );
2796 m_gal->SetIsFill( true );
2797 m_gal->SetIsStroke( false );
2798
2799 m_gal->DrawRectangle( pos, pos + size );
2800 }
2801 }
2802
2803 if( aLayer == LAYER_SHEET || aLayer == LAYER_SELECTION_SHADOWS )
2804 {
2805 m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, drawingShadows ) );
2806 m_gal->SetIsStroke( true );
2807 m_gal->SetLineWidth( getLineWidth( aSheet, drawingShadows ) );
2808 m_gal->SetIsFill( false );
2809
2810 m_gal->DrawRectangle( pos, pos + size );
2811 }
2812}
2813
2814
2815void SCH_PAINTER::draw( const SCH_NO_CONNECT* aNC, int aLayer )
2816{
2817 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2818
2819 if( m_schSettings.IsPrinting() && drawingShadows )
2820 return;
2821
2822 if( drawingShadows && !( aNC->IsBrightened() || aNC->IsSelected() ) )
2823 return;
2824
2825 m_gal->SetIsStroke( true );
2826 m_gal->SetLineWidth( getLineWidth( aNC, drawingShadows ) );
2827 m_gal->SetStrokeColor( getRenderColor( aNC, LAYER_NOCONNECT, drawingShadows ) );
2828 m_gal->SetIsFill( false );
2829
2830 VECTOR2D p = aNC->GetPosition();
2831 int delta = std::max( aNC->GetSize(), m_schSettings.GetDefaultPenWidth() * 3 ) / 2;
2832
2833 m_gal->DrawLine( p + VECTOR2D( -delta, -delta ), p + VECTOR2D( delta, delta ) );
2834 m_gal->DrawLine( p + VECTOR2D( -delta, delta ), p + VECTOR2D( delta, -delta ) );
2835}
2836
2837
2838void SCH_PAINTER::draw( const SCH_BUS_ENTRY_BASE *aEntry, int aLayer )
2839{
2841 SCH_LINE line( VECTOR2I(), layer );
2842 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2843
2844 if( m_schSettings.IsPrinting() && drawingShadows )
2845 return;
2846
2847 bool drawingDangling = aLayer == LAYER_DANGLING;
2848
2849 if( drawingShadows && !( aEntry->IsBrightened() || aEntry->IsSelected() ) )
2850 return;
2851
2852 if( aEntry->IsSelected() )
2853 {
2854 line.SetSelected();
2855 // Never show unselected endpoints on bus entries
2856 line.SetFlags( STARTPOINT | ENDPOINT );
2857 }
2858 else if( aEntry->IsBrightened() )
2859 line.SetBrightened();
2860
2861 line.SetStartPoint( aEntry->GetPosition() );
2862 line.SetEndPoint( aEntry->GetEnd() );
2863 line.SetStroke( aEntry->GetStroke() );
2864 line.SetLineWidth( KiROUND( getLineWidth( aEntry, false ) ) );
2865
2866 COLOR4D color = getRenderColor( aEntry, LAYER_WIRE, drawingShadows );
2867
2868 if( aEntry->Type() == SCH_BUS_BUS_ENTRY_T )
2869 color = getRenderColor( aEntry, LAYER_BUS, drawingShadows );
2870
2871 if( drawingDangling )
2872 {
2873 m_gal->SetIsFill( false );
2874 m_gal->SetIsStroke( true );
2875 m_gal->SetStrokeColor( color.Brightened( 0.3 ) );
2876 m_gal->SetLineWidth( m_schSettings.GetDanglingIndicatorThickness() );
2877
2878 if( aEntry->IsDanglingStart() )
2879 {
2880 m_gal->DrawCircle( aEntry->GetPosition(),
2881 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
2882 }
2883
2884 if( aEntry->IsDanglingEnd() )
2885 {
2886 m_gal->DrawCircle( aEntry->GetEnd(),
2887 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
2888 }
2889 }
2890 else
2891 {
2892 line.SetLineColor( color );
2893 line.SetLineStyle( aEntry->GetLineStyle() );
2894
2895 draw( &line, aLayer );
2896 }
2897}
2898
2899
2900void SCH_PAINTER::draw( const SCH_BITMAP* aBitmap, int aLayer )
2901{
2902 m_gal->Save();
2903 m_gal->Translate( aBitmap->GetPosition() );
2904
2905 // When the image scale factor is not 1.0, we need to modify the actual as the image scale
2906 // factor is similar to a local zoom
2907 double img_scale = aBitmap->GetImageScale();
2908
2909 if( img_scale != 1.0 )
2910 m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
2911
2912 if( aLayer == LAYER_DRAW_BITMAPS )
2913 {
2914 m_gal->DrawBitmap( *aBitmap->GetImage() );
2915 }
2916
2917 if( aLayer == LAYER_SELECTION_SHADOWS )
2918 {
2919 if( aBitmap->IsSelected() || aBitmap->IsBrightened() )
2920 {
2921 COLOR4D color = getRenderColor( aBitmap, LAYER_DRAW_BITMAPS, true );
2922 m_gal->SetIsStroke( true );
2923 m_gal->SetStrokeColor( color );
2924 m_gal->SetLineWidth ( getShadowWidth( aBitmap->IsBrightened() ) );
2925 m_gal->SetIsFill( false );
2926
2927 // Draws a bounding box.
2928 VECTOR2D bm_size( aBitmap->GetSize() );
2929 // bm_size is the actual image size in UI.
2930 // but m_gal scale was previously set to img_scale
2931 // so recalculate size relative to this image size.
2932 bm_size.x /= img_scale;
2933 bm_size.y /= img_scale;
2934 VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
2935 VECTOR2D end = origin + bm_size;
2936
2937 m_gal->DrawRectangle( origin, end );
2938 }
2939 }
2940
2941 m_gal->Restore();
2942}
2943
2944
2945void SCH_PAINTER::draw( const SCH_MARKER* aMarker, int aLayer )
2946{
2947 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2948
2949 if( m_schSettings.IsPrinting() && drawingShadows )
2950 return;
2951
2952 if( drawingShadows && !( aMarker->IsBrightened() || aMarker->IsSelected() ) )
2953 return;
2954
2955 COLOR4D color = getRenderColor( aMarker, aMarker->GetColorLayer(), drawingShadows );
2956
2957 m_gal->Save();
2958 m_gal->Translate( aMarker->GetPosition() );
2959 m_gal->SetIsFill( !drawingShadows );
2960 m_gal->SetFillColor( color );
2961 m_gal->SetIsStroke( drawingShadows );
2962 m_gal->SetLineWidth( getLineWidth( aMarker, drawingShadows ) );
2963 m_gal->SetStrokeColor( color );
2964
2965 SHAPE_LINE_CHAIN polygon;
2966 aMarker->ShapeToPolygon( polygon );
2967
2968 m_gal->DrawPolygon( polygon );
2969 m_gal->Restore();
2970}
2971
2972
2973}; // namespace KIGFX
int color
Definition: DXF_plotter.cpp:58
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:110
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
double square(double x)
BOX2< VECTOR2I > BOX2I
Definition: box2.h:887
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
const Vec & GetPosition() const
Definition: box2.h:201
const Vec & GetOrigin() const
Definition: box2.h:200
void Offset(coord_type dx, coord_type dy)
Definition: box2.h:249
void RevertYAxis()
Mirror the rectangle from the X axis (negate Y pos and size).
Definition: box2.h:724
size_type GetHeight() const
Definition: box2.h:205
void SetX(coord_type val)
Definition: box2.h:260
void SetY(coord_type val)
Definition: box2.h:265
coord_type GetTop() const
Definition: box2.h:219
size_type GetWidth() const
Definition: box2.h:204
coord_type GetY() const
Definition: box2.h:198
const Vec GetEnd() const
Definition: box2.h:202
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
coord_type GetX() const
Definition: box2.h:197
Vec Centre() const
Definition: box2.h:87
coord_type GetRight() const
Definition: box2.h:207
coord_type GetLeft() const
Definition: box2.h:218
const BOX2< Vec > GetBoundingBoxRotated(const VECTOR2I &aRotCenter, const EDA_ANGLE &aAngle) const
Useful to calculate bounding box of rotated items, when rotation is not cardinal.
Definition: box2.h:685
coord_type GetBottom() const
Definition: box2.h:212
bool IsHorizontal() const
Definition: eda_angle.h:180
EDA_ANGLE Normalize180()
Definition: eda_angle.h:294
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:74
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:126
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:128
bool IsSelected() const
Definition: eda_item.h:109
void SetSelected()
Definition: eda_item.h:118
void SetBrightened()
Definition: eda_item.h:119
EDA_ITEM * GetParent() const
Definition: eda_item.h:102
bool IsRollover() const
Definition: eda_item.h:113
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:130
bool IsBrightened() const
Definition: eda_item.h:111
bool IsForceVisible() const
Definition: eda_item.h:194
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:129
bool IsMoving() const
Definition: eda_item.h:107
bool IsNew() const
Definition: eda_item.h:106
int GetStartY() const
Definition: eda_shape.h:126
FILL_T GetFillMode() const
Definition: eda_shape.h:102
int GetEndX() const
Definition: eda_shape.h:152
bool IsFilled() const
Definition: eda_shape.h:91
SHAPE_T GetShape() const
Definition: eda_shape.h:120
int GetEndY() const
Definition: eda_shape.h:151
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:150
COLOR4D GetFillColor() const
Definition: eda_shape.h:106
int GetStartX() const
Definition: eda_shape.h:127
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:83
BOX2I GetTextBox(int aLine=-1, bool aInvertY=false) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:567
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:234
COLOR4D GetTextColor() const
Definition: eda_text.h:231
bool IsItalic() const
Definition: eda_text.h:144
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:134
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
virtual bool IsVisible() const
Definition: eda_text.h:151
KIFONT::FONT * GetFont() const
Definition: eda_text.h:211
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const KIFONT::FONT *aFont, const wxString &forResolvedText, const VECTOR2I &aOffset={ 0, 0 }) const
Definition: eda_text.cpp:512
virtual EDA_ANGLE GetDrawRotation() const
Definition: eda_text.h:341
virtual VECTOR2I GetDrawPos() const
Definition: eda_text.h:342
bool HasTextVars() const
Indicates the ShownText has text var references which need to be processed.
Definition: eda_text.h:117
const TEXT_ATTRIBUTES & GetAttributes() const
Definition: eda_text.h:195
bool IsBold() const
Definition: eda_text.h:148
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:183
VECTOR2I GetTextSize() const
Definition: eda_text.h:222
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false)
Definition: font.cpp:146
virtual bool IsStroke() const
Definition: font.h:138
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
Definition: font.cpp:257
virtual bool IsOutline() const
Definition: font.h:139
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
Definition: font.cpp:434
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
COLOR4D & Invert()
Makes the color inverted, alpha remains the same.
Definition: color4d.h:242
double a
Alpha component.
Definition: color4d.h:395
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition: color4d.h:268
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition: color4d.h:398
COLOR4D & Desaturate()
Removes color (in HSL model)
Definition: color4d.cpp:511
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
Definition: color4d.h:295
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
void SetVerticalJustify(const GR_TEXT_V_ALIGN_T aVerticalJustify)
void SetHorizontalJustify(const GR_TEXT_H_ALIGN_T aHorizontalJustify)
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
void SetGlyphSize(const VECTOR2I aSize)
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition: painter.h:59
GAL * m_gal
Instance of graphic abstraction layer that gives an interface to call commands used to draw (eg.
Definition: painter.h:102
const wxString & GetDefaultFont() const
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
bool GetDrawBoundingBoxes() const
virtual bool Draw(const VIEW_ITEM *, int) override
Takes an instance of VIEW_ITEM and passes it to a function that knows how to draw the item.
COLOR4D getRenderColor(const SCH_ITEM *aItem, int aLayer, bool aDrawingShadows, bool aDimmed=false) const
float getShadowWidth(bool aForHighlight) const
KIFONT::FONT * getFont(const EDA_TEXT *aText) const
void draw(const EDA_ITEM *, int, bool aDimmed)
static std::vector< KICAD_T > g_ScaledSelectionTypes
Definition: sch_painter.h:142
SCH_RENDER_SETTINGS m_schSettings
Definition: sch_painter.h:145
bool nonCached(const EDA_ITEM *aItem)
SCH_PAINTER(GAL *aGal)
void drawItemBoundingBox(const EDA_ITEM *aItem)
bool isUnitAndConversionShown(const SCH_ITEM *aItem) const
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:84
double GetForcedTransparency() const
Definition: view_item.h:157
static constexpr int VIEW_MAX_LAYERS
Rendering order modifier for layers that are marked as top layers.
Definition: view.h:729
Define a library symbol object.
Definition: lib_symbol.h:77
std::vector< SCH_PIN * > GetPins(int aUnit=0, int aBodyStyle=0) const
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:982
bool IsAlias() const
Definition: lib_symbol.h:194
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:486
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:579
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
Definition: lib_symbol.cpp:969
void ShapeToPolygon(SHAPE_LINE_CHAIN &aPolygon, int aScale=-1) const
Return the shape polygon in internal units in a SHAPE_LINE_CHAIN the coordinates are relatives to the...
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:295
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:41
double GetImageScale() const
Definition: sch_bitmap.h:67
VECTOR2I GetPosition() const override
Definition: sch_bitmap.h:145
BITMAP_BASE * GetImage() const
Definition: sch_bitmap.h:54
VECTOR2I GetSize() const
Definition: sch_bitmap.cpp:146
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:38
LINE_STYLE GetLineStyle() const
VECTOR2I GetPosition() const override
bool IsDanglingStart() const
Definition: sch_bus_entry.h:43
virtual STROKE_PARAMS GetStroke() const override
Definition: sch_bus_entry.h:81
bool IsDanglingEnd() const
Definition: sch_bus_entry.h:44
int GetPenWidth() const override
VECTOR2I GetEnd() const
Class for a wire to bus entry.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const
void CreateGraphicShape(const RENDER_SETTINGS *aSettings, std::vector< VECTOR2I > &aPoints, const VECTOR2I &aPos) const override
Calculate the graphic shape (a polygon) associated to the text.
Definition: sch_label.cpp:1676
virtual bool IsDangling() const override
Determines dangling state from connectivity and cached connected rule areas.
Definition: sch_label.cpp:1829
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:586
void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: sch_field.cpp:528
bool IsHypertext() const override
Allow items to support hypertext actions when hovered/clicked.
Definition: sch_field.h:101
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:197
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const wxString &forResolvedText, const VECTOR2I &forPosition, TEXT_ATTRIBUTES &aAttrs) const
Definition: sch_field.cpp:352
VECTOR2I GetParentPosition() const
Definition: sch_field.cpp:1423
void CreateGraphicShape(const RENDER_SETTINGS *aRenderSettings, std::vector< VECTOR2I > &aPoints, const VECTOR2I &aPos) const override
Calculate the graphic shape (a polygon) associated to the text.
Definition: sch_label.cpp:1981
VECTOR2I GetSchematicTextOffset(const RENDER_SETTINGS *aSettings) const override
This offset depends on the orientation, the type of text, and the area required to draw the associate...
Definition: sch_label.cpp:1871
void CreateGraphicShape(const RENDER_SETTINGS *aSettings, std::vector< VECTOR2I > &aPoints, const VECTOR2I &aPos) const override
Calculate the graphic shape (a polygon) associated to the text.
Definition: sch_label.cpp:2091
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:174
virtual int GetPenWidth() const
Definition: sch_item.h:300
const SYMBOL * GetParentSymbol() const
Definition: sch_item.cpp:155
int GetBodyStyle() const
Definition: sch_item.h:240
int GetUnit() const
Definition: sch_item.h:237
bool IsPrivate() const
Definition: sch_item.h:243
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:289
bool RenderAsBitmap(double aWorldScale) const override
Definition: sch_item.cpp:478
bool IsConnectivityDirty() const
Definition: sch_item.h:518
void ViewGetLayers(int aLayers[], int &aCount) const override
Return the layers the item is drawn on (which may be more than its "home" layer)
Definition: sch_item.cpp:191
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:210
wxString GetClass() const override
Return the class name.
Definition: sch_item.h:184
const KIFONT::METRICS & GetFontMetrics() const
Definition: sch_item.cpp:455
int GetEffectivePenWidth(const SCH_RENDER_SETTINGS *aSettings) const
Definition: sch_item.cpp:464
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:189
int GetEffectiveDiameter() const
VECTOR2I GetPosition() const override
Definition: sch_junction.h:107
bool IsDangling() const override
Definition: sch_label.h:319
LABEL_FLAG_SHAPE GetShape() const
Definition: sch_label.h:172
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:196
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:136
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:1011
bool IsStartDangling() const
Definition: sch_line.h:254
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:249
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:321
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_line.cpp:308
VECTOR2I GetMidPoint() const
Definition: sch_line.h:138
VECTOR2I GetEndPoint() const
Definition: sch_line.h:140
VECTOR2I GetStartPoint() const
Definition: sch_line.h:135
bool IsEndDangling() const
Definition: sch_line.h:255
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:292
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_line.h:176
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:141
const wxString & GetOperatingPoint() const
Definition: sch_line.h:302
SCH_LAYER_ID GetColorLayer() const
Definition: sch_marker.cpp:222
VECTOR2I GetPosition() const override
Definition: sch_marker.h:106
int GetSize() const
VECTOR2I GetPosition() const override
int GetNumberTextSize() const
Definition: sch_pin.cpp:497
int GetLength() const
Definition: sch_pin.cpp:276
wxString GetShownNumber() const
Definition: sch_pin.cpp:456
const wxString & GetOperatingPoint() const
Definition: sch_pin.h:273
void SetName(const wxString &aName)
Definition: sch_pin.cpp:362
bool IsGlobalPower() const
Return whether this pin forms a global power connection: i.e., is part of a power symbol and of type ...
Definition: sch_pin.h:179
bool IsVisible() const
Definition: sch_pin.cpp:338
wxString GetElectricalTypeName() const
Definition: sch_pin.cpp:324
bool IsDangling() const override
Definition: sch_pin.h:250
PIN_ORIENTATION GetOrientation() const
Definition: sch_pin.cpp:243
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition: sch_pin.h:87
VECTOR2I GetPosition() const override
Definition: sch_pin.cpp:235
int GetNameTextSize() const
Definition: sch_pin.cpp:475
wxString GetShownName() const
Definition: sch_pin.cpp:442
void SetOperatingPoint(const wxString &aText)
Definition: sch_pin.h:274
void SetType(ELECTRICAL_PINTYPE aType)
Definition: sch_pin.h:100
GRAPHIC_PINSHAPE GetShape() const
Definition: sch_pin.cpp:256
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:289
std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const override
Make a set of SHAPE objects representing the SCH_SHAPE.
Definition: sch_shape.h:97
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_shape.h:60
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:55
VECTOR2I GetPosition() const override
Definition: sch_shape.h:70
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet_pin.h:66
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:93
VECTOR2I GetSize() const
Definition: sch_sheet.h:112
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:376
KIGFX::COLOR4D GetBorderColor() const
Definition: sch_sheet.h:118
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:181
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:121
Schematic symbol object.
Definition: sch_symbol.h:108
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:782
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
TRANSFORM & GetTransform()
Definition: sch_symbol.h:285
int GetOrientation() const
Get the display symbol orientation.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:836
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:958
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:216
BOX2I GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
int GetColSpan() const
Definition: sch_tablecell.h:61
int GetRowSpan() const
Definition: sch_tablecell.h:64
const STROKE_PARAMS & GetSeparatorsStroke() const
Definition: sch_table.h:72
bool StrokeExternal() const
Definition: sch_table.h:54
std::vector< SCH_TABLECELL * > GetCells() const
Definition: sch_table.h:141
const STROKE_PARAMS & GetBorderStroke() const
Definition: sch_table.h:60
VECTOR2I GetPosition() const override
Definition: sch_table.cpp:115
VECTOR2I GetEnd() const
Definition: sch_table.cpp:121
int GetColCount() const
Definition: sch_table.h:104
SCH_TABLECELL * GetCell(int aRow, int aCol) const
Definition: sch_table.h:131
bool StrokeColumns() const
Definition: sch_table.h:84
bool StrokeRows() const
Definition: sch_table.h:87
int GetRowCount() const
Definition: sch_table.h:106
bool StrokeHeader() const
Definition: sch_table.h:57
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
VECTOR2I GetDrawPos() const override
bool IsHypertext() const override
Allow items to support hypertext actions when hovered/clicked.
Definition: sch_textbox.h:86
bool IsHypertext() const override
Allow items to support hypertext actions when hovered/clicked.
Definition: sch_text.h:78
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_text.cpp:422
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_text.cpp:466
virtual VECTOR2I GetSchematicTextOffset(const RENDER_SETTINGS *aSettings) const
This offset depends on the orientation, the type of text, and the area required to draw the associate...
Definition: sch_text.cpp:71
VECTOR2I B
Definition: seg.h:50
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
const SEG & GetSeg() const
An abstract shape on 2D plane.
Definition: shape.h:126
Simple container to manage line stroke parameters.
Definition: stroke_params.h:81
int GetWidth() const
Definition: stroke_params.h:91
KIGFX::COLOR4D GetColor() const
Definition: stroke_params.h:97
static void Stroke(const SHAPE *aShape, LINE_STYLE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, const std::function< void(const VECTOR2I &a, const VECTOR2I &b)> &aStroker)
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition: symbol.h:34
int GetPinNameOffset() const
Definition: symbol.h:118
bool GetDNP() const
Set or clear the 'Do Not Populate' flaga.
Definition: symbol.h:153
virtual bool GetShowPinNames() const
Definition: symbol.h:124
virtual bool GetShowPinNumbers() const
Definition: symbol.h:130
KIGFX::COLOR4D m_Color
GR_TEXT_H_ALIGN_T m_Halign
GR_TEXT_V_ALIGN_T m_Valign
KIFONT::FONT * m_Font
int y1
Definition: transform.h:49
@ LIGHTRED
Definition: color4d.h:65
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject)
Definition: common.cpp:58
The common library.
#define DANGLING_SYMBOL_SIZE
< The size of the rectangle indicating an unconnected wire or label
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
#define UNSELECTED_END_SIZE
The default pin len value when creating pins(can be changed in preference menu)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:432
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:431
#define IS_SHOWN_AS_BITMAP
#define ENDPOINT
ends. (Used to support dragging.)
#define IS_DANGLING
indicates a pin is dangling
#define STARTPOINT
When a line is selected, these flags indicate which.
@ ARC
use RECTANGLE instead of RECT to avoid collision in a Windows header
@ FILLED_WITH_COLOR
@ FILLED_WITH_BG_BODYCOLOR
@ FILLED_SHAPE
int GetPenSizeForDemiBold(int aTextSize)
Definition: gr_text.cpp:46
int Clamp_Text_PenSize(int aPenSize, int aSize, bool aStrict)
Pen width should not allow characters to become cluttered up in their own fatness.
Definition: gr_text.cpp:87
@ LAYER_DRAW_BITMAPS
to handle and draw images bitmaps
Definition: layer_ids.h:227
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:353
@ LAYER_DANGLING
Definition: layer_ids.h:381
@ LAYER_SHEETNAME
Definition: layer_ids.h:376
@ LAYER_SCHEMATIC_ANCHOR
Definition: layer_ids.h:400
@ LAYER_SHEETLABEL
Definition: layer_ids.h:379
@ LAYER_PINNUM
Definition: layer_ids.h:362
@ LAYER_RULE_AREAS
Definition: layer_ids.h:369
@ LAYER_DEVICE
Definition: layer_ids.h:370
@ LAYER_SHEET_BACKGROUND
Definition: layer_ids.h:387
@ LAYER_BRIGHTENED
Definition: layer_ids.h:393
@ LAYER_HIDDEN
Definition: layer_ids.h:394
@ LAYER_HIERLABEL
Definition: layer_ids.h:361
@ LAYER_PINNAM
Definition: layer_ids.h:363
@ LAYER_PRIVATE_NOTES
Definition: layer_ids.h:372
@ LAYER_HOVERED
Definition: layer_ids.h:392
@ LAYER_GLOBLABEL
Definition: layer_ids.h:360
@ LAYER_WIRE
Definition: layer_ids.h:356
@ LAYER_NOTES
Definition: layer_ids.h:371
@ LAYER_PIN
Definition: layer_ids.h:374
@ LAYER_VALUEPART
Definition: layer_ids.h:365
@ LAYER_BUS
Definition: layer_ids.h:357
@ LAYER_FIELDS
Definition: layer_ids.h:366
@ LAYER_DEVICE_BACKGROUND
Definition: layer_ids.h:386
@ LAYER_LOCLABEL
Definition: layer_ids.h:359
@ LAYER_SHEETFIELDS
Definition: layer_ids.h:378
@ LAYER_REFERENCEPART
Definition: layer_ids.h:364
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:368
@ LAYER_NOTES_BACKGROUND
Definition: layer_ids.h:373
@ LAYER_OP_CURRENTS
Definition: layer_ids.h:402
@ LAYER_SHEET
Definition: layer_ids.h:375
@ LAYER_SELECTION_SHADOWS
Definition: layer_ids.h:395
@ LAYER_SCHEMATIC_BACKGROUND
Definition: layer_ids.h:390
@ LAYER_INTERSHEET_REFS
Definition: layer_ids.h:367
@ LAYER_OP_VOLTAGES
Definition: layer_ids.h:401
@ LAYER_SHEETFILENAME
Definition: layer_ids.h:377
@ LAYER_DNP_MARKER
Definition: layer_ids.h:382
@ LAYER_NOCONNECT
Definition: layer_ids.h:380
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:96
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:247
static LIB_SYMBOL * dummy()
Used when a LIB_SYMBOL is not found in library to draw a dummy shape.
EESCHEMA_SETTINGS * eeconfig()
Definition: sch_painter.cpp:68
static bool isFieldsLayer(int aLayer)
static void orientSymbol(LIB_SYMBOL *symbol, int orientation)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
@ OUTSIDE
Text appears outside the dimension line (default)
see class PGM_BASE
@ PT_NC
not connected (must be left open)
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:77
#define TARGET_BUSENTRY_RADIUS
Definition: sch_bus_entry.h:31
@ F_DOT
Definition: sch_label.h:101
@ F_ROUND
Definition: sch_label.h:102
#define BITMAP_FONT_SIZE_THRESHOLD
#define MAP_COORDS(aCoord)
static int externalPinDecoSize(const RENDER_SETTINGS *aSettings, const SCH_PIN &aPin)
Utility for getting the size of the 'external' pin decorators (as a radius)
Definition: sch_pin.cpp:87
#define PIN_TEXT_MARGIN
Definition: sch_pin.cpp:42
static int internalPinDecoSize(const RENDER_SETTINGS *aSettings, const SCH_PIN &aPin)
Utility for getting the size of the 'internal' pin decorators (as a radius)
Definition: sch_pin.cpp:74
#define TARGET_PIN_RADIUS
Definition: sch_pin.h:35
@ SYM_ORIENT_270
Definition: sch_symbol.h:87
@ SYM_MIRROR_Y
Definition: sch_symbol.h:89
@ SYM_ORIENT_180
Definition: sch_symbol.h:86
@ SYM_MIRROR_X
Definition: sch_symbol.h:88
@ SYM_ORIENT_90
Definition: sch_symbol.h:85
@ SYM_ORIENT_0
Definition: sch_symbol.h:84
std::vector< FAB_LAYER_COLOR > dummy
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:48
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
constexpr int delta
GR_TEXT_H_ALIGN_T
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_H_ALIGN_INDETERMINATE
GR_TEXT_V_ALIGN_T
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_INDETERMINATE
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:228
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:520
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128
@ SCH_TABLE_T
Definition: typeinfo.h:165
@ SCH_LINE_T
Definition: typeinfo.h:163
@ LIB_SYMBOL_T
Definition: typeinfo.h:148
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:160
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_TABLECELL_T
Definition: typeinfo.h:166
@ SCH_FIELD_T
Definition: typeinfo.h:150
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:171
@ SCH_LABEL_T
Definition: typeinfo.h:167
@ SCH_SHEET_T
Definition: typeinfo.h:174
@ SCH_MARKER_T
Definition: typeinfo.h:158
@ SCH_SHAPE_T
Definition: typeinfo.h:149
@ SCH_RULE_AREA_T
Definition: typeinfo.h:170
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:169
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:162
@ SCH_LABEL_LOCATE_ANY_T
Definition: typeinfo.h:190
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:173
@ SCH_TEXT_T
Definition: typeinfo.h:151
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:161
@ SCH_BITMAP_T
Definition: typeinfo.h:164
@ SCH_TEXTBOX_T
Definition: typeinfo.h:152
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:168
@ SCH_JUNCTION_T
Definition: typeinfo.h:159
@ SCH_PIN_T
Definition: typeinfo.h:153
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588