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 The 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 <bitmap_base.h>
30#include <connection_graph.h>
32#include <callback_gal.h>
34#include <geometry/shape_rect.h>
36#include <gr_text.h>
37#include <sch_pin.h>
38#include <math/util.h>
39#include <pin_layout_cache.h>
40#include <pgm_base.h>
41#include <sch_bitmap.h>
42#include <sch_bus_entry.h>
43#include <sch_symbol.h>
44#include <sch_edit_frame.h>
45#include <sch_field.h>
46#include <sch_group.h>
47#include <sch_junction.h>
48#include <sch_line.h>
49#include <sch_shape.h>
50#include <sch_marker.h>
51#include <sch_no_connect.h>
52#include <sch_sheet.h>
53#include <sch_sheet_pin.h>
54#include <sch_text.h>
55#include <sch_textbox.h>
56#include <sch_table.h>
57#include <schematic.h>
59#include <view/view.h>
60#include <kiface_base.h>
61#include <default_values.h>
62#include <advanced_config.h>
64#include <stroke_params.h>
65#include "sch_painter.h"
66#include "common.h"
67
69
70namespace KIGFX
71{
72
74{
75 return dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
76}
77
78
79std::vector<KICAD_T> SCH_PAINTER::g_ScaledSelectionTypes = {
98};
99
100
102 KIGFX::PAINTER( aGal ),
103 m_schematic( nullptr )
104{ }
105
106
107bool SCH_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
108{
109 const EDA_ITEM* item = dynamic_cast<const EDA_ITEM*>( aItem );
110
111 if( !item )
112 return false;
113
114 draw( item, aLayer, false );
115
116 return false;
117}
118
119
120void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed )
121{
122
123#ifdef CONNECTIVITY_DEBUG
124
125 auto sch_item = dynamic_cast<const SCH_ITEM*>( aItem );
126 auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
127
128 if( conn )
129 {
130 auto pos = aItem->GetBoundingBox().Centre();
131 auto label = conn->Name( true );
132
136 m_gal->SetLineWidth( Mils2ui( 2 ) );
137 m_gal->SetGlyphSize( VECTOR2D( Mils2ui( 20 ), Mils2ui( 20 ) ) );
138 m_gal->StrokeText( *m_gal, conn->Name( true ), pos, 0.0, 0 );
139 }
140
141#endif
142
143 // Enable draw bounding box on request. Some bboxes are handled locally.
144 bool drawBoundingBox = m_schSettings.GetDrawBoundingBoxes();
145
146 switch( aItem->Type() )
147 {
148 case LIB_SYMBOL_T:
149 draw( static_cast<const LIB_SYMBOL*>( aItem ), aLayer );
150 break;
151 case SCH_PIN_T:
152 drawBoundingBox = false;
153 draw( static_cast<const SCH_PIN*>( aItem ), aLayer, aDimmed );
154 break;
155 case SCH_SYMBOL_T:
156 draw( static_cast<const SCH_SYMBOL*>( aItem ), aLayer );
157 break;
158 case SCH_JUNCTION_T:
159 draw( static_cast<const SCH_JUNCTION*>( aItem ), aLayer );
160 break;
161 case SCH_LINE_T:
162 draw( static_cast<const SCH_LINE*>( aItem ), aLayer );
163 break;
164 case SCH_SHAPE_T:
165 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
166 break;
167 case SCH_RULE_AREA_T:
168 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
169 break;
170 case SCH_TEXT_T:
171 draw( static_cast<const SCH_TEXT*>( aItem ), aLayer, aDimmed );
172 break;
173 case SCH_TEXTBOX_T:
174 draw( static_cast<const SCH_TEXTBOX*>( aItem ), aLayer, aDimmed );
175 break;
176 case SCH_TABLE_T:
177 draw( static_cast<const SCH_TABLE*>( aItem ), aLayer, aDimmed );
178 break;
179 case SCH_LABEL_T:
180 draw( static_cast<const SCH_LABEL*>( aItem ), aLayer, aDimmed );
181 break;
183 draw( static_cast<const SCH_DIRECTIVE_LABEL*>( aItem ), aLayer, aDimmed );
184 break;
185 case SCH_FIELD_T:
186 draw( static_cast<const SCH_FIELD*>( aItem ), aLayer, aDimmed );
187 break;
188 case SCH_HIER_LABEL_T:
189 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer, aDimmed );
190 break;
192 draw( static_cast<const SCH_GLOBALLABEL*>( aItem ), aLayer, aDimmed );
193 break;
194 case SCH_SHEET_T:
195 draw( static_cast<const SCH_SHEET*>( aItem ), aLayer );
196 break;
197 case SCH_SHEET_PIN_T:
198 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer, aDimmed );
199 break;
200 case SCH_NO_CONNECT_T:
201 draw( static_cast<const SCH_NO_CONNECT*>( aItem ), aLayer );
202 break;
204 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
205 break;
207 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
208 break;
209 case SCH_BITMAP_T:
210 draw( static_cast<const SCH_BITMAP*>( aItem ), aLayer );
211 break;
212 case SCH_MARKER_T:
213 draw( static_cast<const SCH_MARKER*>( aItem ), aLayer );
214 break;
215 case SCH_GROUP_T:
216 draw( static_cast<const SCH_GROUP*>( aItem ), aLayer );
217 break;
218
219 default: return;
220 }
221
222 if( drawBoundingBox )
223 drawItemBoundingBox( aItem );
224}
225
226
228{
229 if( const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( aItem ) )
230 {
231 if( item->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
232 return;
233 }
234
235 BOX2I box = aItem->GetBoundingBox();
236
237 if( aItem->Type() == SCH_SYMBOL_T )
238 box = static_cast<const SCH_SYMBOL*>( aItem )->GetBodyBoundingBox();
239
240 m_gal->SetIsFill( false );
241 m_gal->SetIsStroke( true );
242 m_gal->SetStrokeColor( aItem->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 )
243 : COLOR4D( 0.2, 0.2, 0.2, 1 ) );
245 m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
246}
247
248
250{
251 // TODO: it would be nice to have a more definitive test for this, but we've currently got
252 // no access to the VIEW_GROUP to see if it's cached or not.
253 return aItem->IsSelected();
254}
255
256
258{
259 if( m_schSettings.m_ShowUnit // showing a specific unit
260 && aItem->GetUnit() // item is unit-specific
261 && aItem->GetUnit() != m_schSettings.m_ShowUnit )
262 {
263 return false;
264 }
265
266 if( m_schSettings.m_ShowBodyStyle // showing a specific body style
267 && aItem->GetBodyStyle() // item is body-style-specific
269 {
270 return false;
271 }
272
273 return true;
274}
275
276
278{
279 if( KIFONT::FONT* font = aItem->GetFont() )
280 return font;
281
283 aItem->IsItalic() );
284}
285
286
287float SCH_PAINTER::getShadowWidth( bool aForHighlight ) const
288{
289 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
290
291 int milsWidth = aForHighlight ? eeconfig()->m_Selection.highlight_thickness
293
294 // For best visuals the selection width must be a cross between the zoom level and the
295 // default line width.
296 return (float) std::fabs( matrix.GetScale().x * milsWidth ) + schIUScale.MilsToIU( milsWidth );
297}
298
299
300COLOR4D SCH_PAINTER::getRenderColor( const SCH_ITEM* aItem, int aLayer, bool aDrawingShadows,
301 bool aDimmed, bool aIgnoreNets ) const
302{
303 auto isBackgroundLayer =
304 []( int layer )
305 {
306 return layer == LAYER_DEVICE_BACKGROUND || layer == LAYER_NOTES_BACKGROUND
307 || layer == LAYER_SHAPES_BACKGROUND || layer == LAYER_SHEET_BACKGROUND;
308 };
309
311
312 // Graphic items of a SYMBOL frequently use the LAYER_DEVICE layer color
313 // (i.e. when no specific color is set)
314 bool isSymbolChild = aItem->GetParentSymbol() != nullptr;
315
317 {
318 if( aItem->Type() == SCH_LINE_T )
319 {
320 color = static_cast<const SCH_LINE*>( aItem )->GetLineColor();
321 }
322 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
323 {
324 color = static_cast<const SCH_BUS_WIRE_ENTRY*>( aItem )->GetBusEntryColor();
325 }
326 else if( aItem->Type() == SCH_JUNCTION_T )
327 {
328 color = static_cast<const SCH_JUNCTION*>( aItem )->GetJunctionColor();
329 }
330 else if( aItem->Type() == SCH_SHEET_T )
331 {
332 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( aItem );
333
334 if( isBackgroundLayer( aLayer ) )
335 color = sheet->GetBackgroundColor();
336 else
337 color = sheet->GetBorderColor();
338 }
339 else if( aItem->Type() == SCH_SHAPE_T || aItem->Type() == SCH_RULE_AREA_T )
340 {
341 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem );
342
343 if( isBackgroundLayer( aLayer ) )
344 {
345 switch( shape->GetFillMode() )
346 {
347 case FILL_T::NO_FILL:
348 break;
349
350 case FILL_T::HATCH:
351 case FILL_T::REVERSE_HATCH:
352 case FILL_T::CROSS_HATCH:
353 case FILL_T::FILLED_SHAPE:
354 color = shape->GetStroke().GetColor();
355 break;
356
357 case FILL_T::FILLED_WITH_COLOR:
358 color = shape->GetFillColor();
359 break;
360
361 case FILL_T::FILLED_WITH_BG_BODYCOLOR:
363 break;
364
365 default:
366 wxFAIL_MSG( wxT( "Unsupported fill type" ) );
367 }
368
369 // A filled shape means filled; if they didn't specify a fill colour then use
370 // the border colour.
371 if( shape->GetFillMode() != FILL_T::NO_FILL && color == COLOR4D::UNSPECIFIED )
372 {
373 if( aItem->Type() == SCH_RULE_AREA_T )
375 else if( isSymbolChild )
377 else
379 }
380 }
381 else
382 {
383 color = shape->GetStroke().GetColor();
384 }
385 }
386 else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
387 {
388 const SCH_LABEL_BASE* label = static_cast<const SCH_LABEL_BASE*>( aItem );
389
390 if( label->GetTextColor() != COLOR4D::UNSPECIFIED )
391 color = label->GetTextColor(); // override color
392 else if( aIgnoreNets )
393 color = m_schSettings.GetLayerColor( aLayer ); // layer color
394 else
395 color = label->GetLabelColor(); // net/netclass color
396 }
397 else if( aItem->Type() == SCH_FIELD_T )
398 {
399 color = static_cast<const SCH_FIELD*>( aItem )->GetFieldColor();
400 }
401 else if( aItem->Type() == SCH_TEXTBOX_T || aItem->Type() == SCH_TABLECELL_T )
402 {
403 const SCH_TEXTBOX* textBox = static_cast<const SCH_TEXTBOX*>( aItem );
404
405 if( isBackgroundLayer( aLayer ) )
406 color = textBox->GetFillColor();
407 else if( !isSymbolChild || textBox->GetTextColor() != COLOR4D::UNSPECIFIED )
408 color = textBox->GetTextColor();
409 }
410 else if( const EDA_TEXT* otherTextItem = dynamic_cast<const EDA_TEXT*>( aItem ) )
411 {
412 if( !isSymbolChild || otherTextItem->GetTextColor() != COLOR4D::UNSPECIFIED )
413 color = otherTextItem->GetTextColor();
414 }
415 }
416 else /* overrideItemColors */
417 {
418 // If we ARE overriding the item colors, what do we do with non-item-color fills?
419 // There are two theories: we should leave them untouched, or we should drop them entirely.
420 // We currently implment the first.
421 if( isBackgroundLayer( aLayer) )
422 {
423 if( aItem->Type() == SCH_SHAPE_T || aItem->Type() == SCH_RULE_AREA_T )
424 {
425 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem );
426
427 if( shape->GetFillMode() == FILL_T::FILLED_WITH_COLOR )
428 color = shape->GetFillColor();
429 }
430 else if( aItem->Type() == SCH_SHEET_T )
431 {
432 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( aItem );
433
434 color = sheet->GetBackgroundColor();
435 }
436 }
437 }
438
441
442 if( aItem->IsBrightened() ) // Selection disambiguation, net highlighting, etc.
443 {
445
446 if( aDrawingShadows )
447 {
448 if( aItem->IsSelected() )
450 else
451 color = color.WithAlpha( 0.15 );
452 }
453 else if( isBackgroundLayer( aLayer ) )
454 {
455 color = color.WithAlpha( 0.2 );
456 }
457 }
458 else if( aItem->IsSelected() && aDrawingShadows )
459 {
461 }
462 else if( aItem->IsSelected() && isBackgroundLayer( aLayer ) )
463 {
464 // Selected items will be painted over all other items, so make backgrounds translucent so
465 // that non-selected overlapping objects are visible
466 color = color.WithAlpha( 0.5 );
467 }
468
471 {
472 color = color.Darken( 0.5f );
473 }
474
475 if( aDimmed && !( aItem->IsSelected() && aDrawingShadows ) )
476 {
478 color.Desaturate();
479 color = color.Mix( sheetColour, 0.5f );
480 }
481
482 if( aItem->GetForcedTransparency() > 0.0 )
483 color = color.WithAlpha( color.a * ( 1.0 - aItem->GetForcedTransparency() ) );
484
485 return color;
486}
487
488
489float SCH_PAINTER::getLineWidth( const SCH_ITEM* aItem, bool aDrawingShadows,
490 bool aDrawingWireColorHighlights ) const
491{
492 wxCHECK( aItem, static_cast<float>( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ) ) );
493
494 int pen = aItem->GetEffectivePenWidth( &m_schSettings );
495 float width = pen;
496
497 if( aItem->IsBrightened() || aItem->IsSelected() )
498 {
499 if( aDrawingShadows && aItem->IsType( g_ScaledSelectionTypes ) )
500 width += getShadowWidth( aItem->IsBrightened() );
501 }
502
503 if( aDrawingWireColorHighlights )
504 {
505 float colorHighlightWidth = schIUScale.MilsToIU( 15.0 );
506 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
507
508 if( eeschemaCfg )
509 {
510 colorHighlightWidth = schIUScale.MilsToIU(
512 }
513
514 width += colorHighlightWidth;
515 }
516
517 return width;
518}
519
520
521float SCH_PAINTER::getTextThickness( const SCH_ITEM* aItem ) const
522{
524
525 switch( aItem->Type() )
526 {
527 case SCH_FIELD_T:
528 pen = static_cast<const SCH_FIELD*>( aItem )->GetEffectiveTextPenWidth( pen );
529 break;
530
531 case SCH_TEXT_T:
532 pen = static_cast<const SCH_TEXT*>( aItem )->GetEffectiveTextPenWidth( pen );
533 break;
534
535 case SCH_LABEL_T:
538 case SCH_HIER_LABEL_T:
539 case SCH_SHEET_PIN_T:
540 pen = static_cast<const SCH_LABEL_BASE*>( aItem )->GetEffectiveTextPenWidth( pen );
541 break;
542
543 case SCH_TEXTBOX_T:
544 case SCH_TABLECELL_T:
545 pen = static_cast<const SCH_TEXTBOX*>( aItem )->GetEffectiveTextPenWidth( pen );
546 break;
547
548 default:
549 UNIMPLEMENTED_FOR( aItem->GetClass() );
550 }
551
552 return (float) pen;
553}
554
555
557{
558 int docTextSize = schIUScale.MilsToIU( 50 );
559 int screenTextSize = std::abs( (int) m_gal->GetScreenWorldMatrix().GetScale().y * 7 );
560
561 // 66% zoom-relative
562 return KiROUND( ( docTextSize + screenTextSize * 2 ) / 3 );
563}
564
565
566static bool isFieldsLayer( int aLayer )
567{
568 return aLayer == LAYER_REFERENCEPART
569 || aLayer == LAYER_VALUEPART
570 || aLayer == LAYER_INTERSHEET_REFS
571 || aLayer == LAYER_NETCLASS_REFS
572 || aLayer == LAYER_FIELDS
573 || aLayer == LAYER_SHEETNAME
574 || aLayer == LAYER_SHEETFILENAME
575 || aLayer == LAYER_SHEETFIELDS;
576}
577
578
579static BOX2I GetTextExtents( const wxString& aText, const VECTOR2D& aPosition, KIFONT::FONT& aFont,
580 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
581{
582 const VECTOR2I extents =
583 aFont.StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth, aAttrs.m_Bold,
584 aAttrs.m_Italic, aFontMetrics );
585 BOX2I box( aPosition, VECTOR2I( extents.x, aAttrs.m_Size.y ) );
586
587 switch( aAttrs.m_Halign )
588 {
589 case GR_TEXT_H_ALIGN_LEFT: break;
590 case GR_TEXT_H_ALIGN_CENTER: box.SetX( box.GetX() - box.GetWidth() / 2 ); break;
591 case GR_TEXT_H_ALIGN_RIGHT: box.SetX( box.GetX() - box.GetWidth() ); break;
592 case GR_TEXT_H_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
593 }
594
595 switch( aAttrs.m_Valign )
596 {
597 case GR_TEXT_V_ALIGN_TOP: break;
598 case GR_TEXT_V_ALIGN_CENTER: box.SetY( box.GetY() - box.GetHeight() / 2 ); break;
599 case GR_TEXT_V_ALIGN_BOTTOM: box.SetY( box.GetY() - box.GetHeight() ); break;
600 case GR_TEXT_V_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
601 }
602
603 box.Normalize(); // Make h and v sizes always >= 0
604 box = box.GetBoundingBoxRotated( aPosition, aAttrs.m_Angle );
605
606 return box;
607}
608
609
610static void strokeText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
611 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
612{
613 KIFONT::FONT* font = aAttrs.m_Font;
614
615 if( !font )
616 {
617 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
618 aAttrs.m_Italic );
619 }
620
621 aGal.SetIsFill( font->IsOutline() );
622 aGal.SetIsStroke( font->IsStroke() );
623
624 font->Draw( &aGal, aText, aPosition, aAttrs, aFontMetrics );
625}
626
627
628static void bitmapText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
629 const TEXT_ATTRIBUTES& aAttrs )
630{
631 // Bitmap font has different metrics from the stroke font so we compensate a bit before
632 // stroking
633 aGal.SetGlyphSize( VECTOR2I( aAttrs.m_Size.x, KiROUND( aAttrs.m_Size.y * 1.05 ) ) );
634 aGal.SetLineWidth( (float) aAttrs.m_StrokeWidth * 1.35f );
635
636 aGal.SetHorizontalJustify( aAttrs.m_Halign );
637 aGal.SetVerticalJustify( aAttrs.m_Valign );
638
639 aGal.BitmapText( aText, aPosition, aAttrs.m_Angle );
640}
641
642
643static void knockoutText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
644 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
645{
646 TEXT_ATTRIBUTES attrs( aAttrs );
647 KIFONT::FONT* font = aAttrs.m_Font;
648
649 if( !font )
650 {
651 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, attrs.m_Bold,
652 attrs.m_Italic );
653 }
654
656 SHAPE_POLY_SET knockouts;
657
658 CALLBACK_GAL callback_gal( empty_opts,
659 // Polygon callback
660 [&]( const SHAPE_LINE_CHAIN& aPoly )
661 {
662 knockouts.AddOutline( aPoly );
663 } );
664
665 callback_gal.SetIsFill( false );
666 callback_gal.SetIsStroke( true );
667 callback_gal.SetLineWidth( (float) attrs.m_StrokeWidth );
668 font->Draw( &callback_gal, aText, aPosition, attrs, aFontMetrics );
669
670 BOX2I bbox = knockouts.BBox( attrs.m_StrokeWidth * 2 );
671 SHAPE_POLY_SET finalPoly;
672
673 finalPoly.NewOutline();
674 finalPoly.Append( bbox.GetLeft(), bbox.GetTop() );
675 finalPoly.Append( bbox.GetRight(), bbox.GetTop() );
676 finalPoly.Append( bbox.GetRight(), bbox.GetBottom() );
677 finalPoly.Append( bbox.GetLeft(), bbox.GetBottom() );
678
679 finalPoly.BooleanSubtract( knockouts );
680 finalPoly.Fracture();
681
682 aGal.SetIsStroke( false );
683 aGal.SetIsFill( true );
684 aGal.SetFillColor( attrs.m_Color );
685 aGal.DrawPolygon( finalPoly );
686}
687
688
689static void boxText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
690 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
691{
692 KIFONT::FONT* font = aAttrs.m_Font;
693
694 if( !font )
695 {
696 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
697 aAttrs.m_Italic );
698 }
699
700 BOX2I box = GetTextExtents( aText, aPosition, *font, aAttrs, aFontMetrics );
701
702 // Give the highlight a bit of margin.
703 box.Inflate( 0, aAttrs.m_StrokeWidth * 2 );
704
705 aGal.SetIsFill( true );
706 aGal.SetIsStroke( false );
707 aGal.DrawRectangle( box.GetOrigin(), box.GetEnd() );
708}
709
710
711void SCH_PAINTER::triLine( const VECTOR2D& a, const VECTOR2D& b, const VECTOR2D& c )
712{
713 m_gal->DrawLine( a, b );
714 m_gal->DrawLine( b, c );
715}
716
717
718void SCH_PAINTER::draw( const LIB_SYMBOL* aSymbol, int aLayer, bool aDrawFields, int aUnit,
719 int aBodyStyle, bool aDimmed )
720{
721 if( !aUnit )
723
724 if( !aBodyStyle )
725 aBodyStyle = m_schSettings.m_ShowBodyStyle;
726
727 std::unique_ptr< LIB_SYMBOL > tmpSymbol;
728 const LIB_SYMBOL* drawnSymbol = aSymbol;
729
730 if( aSymbol->IsDerived() )
731 {
732 tmpSymbol = aSymbol->Flatten();
733 drawnSymbol = tmpSymbol.get();
734 }
735
736 // The parent must exist on the union of all its children's draw layers. But that doesn't
737 // mean we want to draw each child on the union.
738 auto childOnLayer =
739 []( const SCH_ITEM& item, int layer )
740 {
741 return alg::contains( item.ViewGetLayers(), layer );
742 };
743
744 for( const SCH_ITEM& item : drawnSymbol->GetDrawItems() )
745 {
746 if( !aDrawFields && item.Type() == SCH_FIELD_T )
747 continue;
748
749 if( !childOnLayer( item, aLayer ) )
750 continue;
751
752 if( aUnit && item.GetUnit() && aUnit != item.GetUnit() )
753 continue;
754
755 if( aBodyStyle && item.GetBodyStyle() && aBodyStyle != item.GetBodyStyle() )
756 continue;
757
758 draw( &item, aLayer, aDimmed );
759 }
760}
761
762
764{
767
768 return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
769}
770
771
772// Utility for getting the size of the 'external' pin decorators (as a radius)
773// i.e. the negation circle, the polarity 'slopes' and the nonlogic marker
775{
778
779 return aPin.GetNumberTextSize() / 2;
780}
781
782
783// Draw the target (an open circle) for a pin which has no connection or is being moved.
785 bool aDrawingShadows, bool aBrightened )
786{
787 const PIN_LAYOUT_CACHE& plc = aPin.GetLayoutCache();
788 const CIRCLE c = plc.GetDanglingIndicator();
789
790 float lineWidth = aDrawingShadows ? getShadowWidth( aBrightened )
792
793 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
794 // they overlap with a junction dot.
795 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
796
797 m_gal->SetIsFill( false );
798 m_gal->SetIsStroke( true );
799 m_gal->SetLineWidth( lineWidth );
800 m_gal->DrawCircle( c.Center, c.Radius );
801}
802
803
807void SCH_PAINTER::drawLocalPowerIcon( const VECTOR2D& aPos, double aSize, bool aRotate,
808 const COLOR4D& aColor, bool aDrawingShadows,
809 bool aBrightened )
810{
811 m_gal->Save();
812
813 m_gal->Translate( aPos );
814
815 if( aRotate )
817
818 double lineWidth = aSize / 10.0;
819
820 if( aDrawingShadows )
821 lineWidth += getShadowWidth( aBrightened );
822
823 m_gal->SetIsFill( false );
824 m_gal->SetIsStroke( true );
825 m_gal->SetLineWidth( lineWidth );
826 m_gal->SetStrokeColor( aColor );
827
828 double x_right = aSize / 1.6180339887;
829 double x_middle = x_right / 2.0;
830
831 VECTOR2D bottomPt = VECTOR2D{ x_middle, 0 };
832 VECTOR2D leftPt = VECTOR2D{ 0, 2.0 * -aSize / 3.0 };
833 VECTOR2D rightPt = VECTOR2D{ x_right, 2.0 * -aSize / 3.0 };
834
835 VECTOR2D bottomAnchorPt = VECTOR2D{ x_middle, -aSize / 4.0 };
836 VECTOR2D leftSideAnchorPt1 = VECTOR2D{ 0, -aSize / 2.5 };
837 VECTOR2D leftSideAnchorPt2 = VECTOR2D{ 0, -aSize * 1.15 };
838 VECTOR2D rightSideAnchorPt1 = VECTOR2D{ x_right, -aSize / 2.5 };
839 VECTOR2D rightSideAnchorPt2 = VECTOR2D{ x_right, -aSize * 1.15 };
840
841 m_gal->DrawCurve( bottomPt, bottomAnchorPt, leftSideAnchorPt1, leftPt );
842 m_gal->DrawCurve( leftPt, leftSideAnchorPt2, rightSideAnchorPt2, rightPt );
843 m_gal->DrawCurve( rightPt, rightSideAnchorPt1, bottomAnchorPt, bottomPt );
844
845 m_gal->SetIsFill( true );
846 m_gal->SetFillColor( aColor );
847 m_gal->DrawCircle( ( leftPt + rightPt ) / 2.0, aSize / 15.0 );
848
849 m_gal->Restore();
850};
851
852
856static void drawAltPinModesIcon( GAL& aGal, const VECTOR2D& aPos, double aSize, bool aBaseSelected,
857 bool aRotate, int aExtraLineWidth, const COLOR4D& aColor )
858{
859 aGal.Save();
860
861 aGal.Translate( aPos );
862
863 if( aRotate )
864 {
865 aGal.Rotate( ANGLE_270.AsRadians() );
866 }
867
868 aGal.SetIsFill( false );
869 aGal.SetIsStroke( true );
870 aGal.SetLineWidth( KiROUND( aSize / 10.0 + aExtraLineWidth ) );
871 aGal.SetStrokeColor( aColor );
872
873 /*
874 * ----------->
875 * + <--center
876 * \------->
877 *
878 * or
879 *
880 * ----- ---->
881 * \
882 * \------>
883 */
884
885 const double lineYOffset = aSize / 4;
886 const double arrowHead = aSize / 8;
887
888 const VECTOR2D topLineREnd = VECTOR2D{ aSize / 2, -lineYOffset };
889 const VECTOR2D btmLineREnd = VECTOR2D{ aSize / 2, lineYOffset };
890
891 // Top line and arrowhead
892 if( aBaseSelected )
893 {
894 // Full top line
895 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ aSize, 0 } );
896 }
897 else
898 {
899 // Line with a gap
900 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ aSize / 2, 0 } );
901 aGal.DrawLine( topLineREnd - VECTOR2D{ aSize, 0 },
902 topLineREnd - VECTOR2D{ aSize * 0.7, 0 } );
903 }
904
905 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ arrowHead * 1.2, arrowHead } );
906 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ arrowHead * 1.2, -arrowHead } );
907
908 // Bottom line and arrowhead
909 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ aSize / 2, 0 } );
910 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ arrowHead * 1.2, arrowHead } );
911 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ arrowHead * 1.2, -arrowHead } );
912
913 // Top and bottom 'S' arcs
914 if( !aBaseSelected )
915 {
916 aGal.DrawArc( topLineREnd - VECTOR2D{ aSize, -lineYOffset },
917 lineYOffset, ANGLE_0, -ANGLE_90 );
918 }
919
920 aGal.DrawArc( topLineREnd - VECTOR2D{ aSize - lineYOffset * 2, -lineYOffset },
921 lineYOffset, ANGLE_180, -ANGLE_90 );
922
923 aGal.Restore();
924};
925
926
927void SCH_PAINTER::draw( const SCH_PIN* aPin, int aLayer, bool aDimmed )
928{
929 // Don't draw pins from a selection view-group. Pins in a schematic must always be drawn
930 // from their parent symbol's m_part.
931 if( dynamic_cast<const SCH_SYMBOL*>( aPin->GetParentSymbol() ) )
932 return;
933
934 if( !isUnitAndConversionShown( aPin ) )
935 return;
936
937 const bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
938
939 if( m_schSettings.IsPrinting() && drawingShadows )
940 return;
941
942 const bool drawingDangling = aLayer == LAYER_DANGLING;
943 const bool drawingOP = aLayer == LAYER_OP_CURRENTS;
944 const bool isDangling = m_schSettings.m_IsSymbolEditor || aPin->HasFlag( IS_DANGLING );
945
946 if( drawingShadows && !( aPin->IsBrightened() || aPin->IsSelected() ) )
947 return;
948
949 const VECTOR2I pos = aPin->GetPosition();
950 COLOR4D color = getRenderColor( aPin, LAYER_PIN, drawingShadows, aDimmed );
951
952 if( !aPin->IsVisible() )
953 {
955 return;
956
959
960 if( force_show )
961 {
962 color = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed );
963 }
964 else
965 {
966 if( drawingDangling && isDangling && aPin->IsGlobalPower() )
967 drawPinDanglingIndicator( *aPin, color, drawingShadows, aPin->IsBrightened() );
968
969 return;
970 }
971 }
972
973 if( drawingDangling )
974 {
975 if( isDangling )
976 drawPinDanglingIndicator( *aPin, color, drawingShadows, aPin->IsBrightened() );
977
978 return;
979 }
980
982 drawItemBoundingBox( aPin );
983
984 const VECTOR2I p0 = aPin->GetPinRoot();
985 const VECTOR2I dir( sign( pos.x - p0.x ), sign( pos.y - p0.y ) );
986 const int len = aPin->GetLength();
987
988 if( drawingOP && !aPin->GetOperatingPoint().IsEmpty() )
989 {
990 int textSize = getOperatingPointTextSize();
991 VECTOR2I mid = ( p0 + pos ) / 2;
992 int textOffset = KiROUND( textSize * 0.22 );
993 TEXT_ATTRIBUTES attrs;
994
995 if( len > textSize )
996 {
997 if( dir.x == 0 )
998 {
999 mid.x += KiROUND( textOffset * 1.2 );
1000 attrs.m_Angle = ANGLE_HORIZONTAL;
1001 }
1002 else
1003 {
1004 mid.y -= KiROUND( textOffset * 1.2 );
1005 attrs.m_Angle = ANGLE_VERTICAL;
1006 }
1007
1010
1011 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
1012 attrs.m_Size = VECTOR2I( textSize, textSize );
1013 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
1015
1016 knockoutText( *m_gal, aPin->GetOperatingPoint(), mid, attrs, aPin->GetFontMetrics() );
1017 }
1018 }
1019
1020 if( drawingOP )
1021 return;
1022
1023 VECTOR2D pc;
1024
1025 m_gal->SetIsStroke( true );
1026 m_gal->SetIsFill( false );
1027 m_gal->SetLineWidth( getLineWidth( aPin, drawingShadows ) );
1029 m_gal->SetFontBold( false );
1030 m_gal->SetFontUnderlined( false );
1031 m_gal->SetFontItalic( false );
1032
1033 const int radius = externalPinDecoSize( *aPin );
1034 const int diam = radius*2;
1035 const int clock_size = internalPinDecoSize( *aPin );
1036
1037 if( aPin->GetType() == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
1038 {
1039 m_gal->DrawLine( p0, pos );
1040
1041 m_gal->DrawLine( pos + VECTOR2D( -1, -1 ) * TARGET_PIN_RADIUS,
1042 pos + VECTOR2D( 1, 1 ) * TARGET_PIN_RADIUS );
1043 m_gal->DrawLine( pos + VECTOR2D( 1, -1 ) * TARGET_PIN_RADIUS ,
1044 pos + VECTOR2D( -1, 1 ) * TARGET_PIN_RADIUS );
1045 }
1046 else
1047 {
1048 switch( aPin->GetShape() )
1049 {
1050 default:
1051 case GRAPHIC_PINSHAPE::LINE:
1052 m_gal->DrawLine( p0, pos );
1053 break;
1054
1055 case GRAPHIC_PINSHAPE::INVERTED:
1056 m_gal->DrawCircle( p0 + dir * radius, radius );
1057 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1058 break;
1059
1060 case GRAPHIC_PINSHAPE::INVERTED_CLOCK:
1061 pc = p0 - dir * clock_size ;
1062
1063 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1064 pc,
1065 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1066
1067 m_gal->DrawCircle( p0 + dir * radius, radius );
1068 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1069 break;
1070
1071 case GRAPHIC_PINSHAPE::CLOCK_LOW:
1072 case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK:
1073 pc = p0 - dir * clock_size ;
1074
1075 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1076 pc,
1077 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1078
1079 if( !dir.y )
1080 {
1081 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1082 p0 + VECTOR2D(dir.x, -1) * diam,
1083 p0 );
1084 }
1085 else /* MapX1 = 0 */
1086 {
1087 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1088 p0 + VECTOR2D(-1, dir.y) * diam,
1089 p0 );
1090 }
1091
1092 m_gal->DrawLine( p0, pos );
1093 break;
1094
1095 case GRAPHIC_PINSHAPE::CLOCK:
1096 m_gal->DrawLine( p0, pos );
1097
1098 if( !dir.y )
1099 {
1100 triLine( p0 + VECTOR2D( 0, clock_size ),
1101 p0 + VECTOR2D( -dir.x * clock_size, 0 ),
1102 p0 + VECTOR2D( 0, -clock_size ) );
1103 }
1104 else
1105 {
1106 triLine( p0 + VECTOR2D( clock_size, 0 ),
1107 p0 + VECTOR2D( 0, -dir.y * clock_size ),
1108 p0 + VECTOR2D( -clock_size, 0 ) );
1109 }
1110 break;
1111
1112 case GRAPHIC_PINSHAPE::INPUT_LOW:
1113 m_gal->DrawLine( p0, pos );
1114
1115 if( !dir.y )
1116 {
1117 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1118 p0 + VECTOR2D(dir.x, -1) * diam,
1119 p0 );
1120 }
1121 else /* MapX1 = 0 */
1122 {
1123 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1124 p0 + VECTOR2D(-1, dir.y) * diam,
1125 p0 );
1126 }
1127 break;
1128
1129 case GRAPHIC_PINSHAPE::OUTPUT_LOW: // IEEE symbol "Active Low Output"
1130 m_gal->DrawLine( p0, pos );
1131
1132 if( !dir.y ) // Horizontal pin
1133 m_gal->DrawLine( p0 - VECTOR2D( 0, diam ), p0 + VECTOR2D( dir.x, 0 ) * diam );
1134 else // Vertical pin
1135 m_gal->DrawLine( p0 - VECTOR2D( diam, 0 ), p0 + VECTOR2D( 0, dir.y ) * diam );
1136 break;
1137
1138 case GRAPHIC_PINSHAPE::NONLOGIC: // NonLogic pin symbol
1139 m_gal->DrawLine( p0, pos );
1140
1141 m_gal->DrawLine( p0 - VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius,
1142 p0 + VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius );
1143 m_gal->DrawLine( p0 - VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius,
1144 p0 + VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius );
1145 break;
1146 }
1147 }
1148
1149 if( drawingShadows && !eeconfig()->m_Selection.draw_selected_children )
1150 return;
1151
1152 // Draw the labels
1153 float nameStrokeWidth = getLineWidth( aPin, false );
1154 float numStrokeWidth = getLineWidth( aPin, false );
1155
1156 nameStrokeWidth = ClampTextPenSize( nameStrokeWidth, aPin->GetNameTextSize(), true );
1157 numStrokeWidth = ClampTextPenSize( numStrokeWidth, aPin->GetNumberTextSize(), true );
1158
1159 float shadowWidth = 0.0f;
1160
1161 if( drawingShadows )
1162 {
1163 shadowWidth = getShadowWidth( aPin->IsBrightened() );
1164 }
1165
1166 PIN_LAYOUT_CACHE& cache = aPin->GetLayoutCache();
1167 cache.SetRenderParameters( nameStrokeWidth, numStrokeWidth,
1170
1171 const auto textRendersAsBitmap = [&]( KIGFX::GAL& aGal, int aTextSize )
1172 {
1173 // Rendering text is expensive (particularly when using outline fonts). At small effective
1174 // sizes (ie: zoomed out) the visual differences between outline and/or stroke fonts and the
1175 // bitmap font becomes immaterial, and there's often more to draw when zoomed out so the
1176 // performance gain becomes more significant.
1177 static const float BITMAP_FONT_SIZE_THRESHOLD = 3.5;
1178
1179 // Any text non bitmappable?
1180 return aTextSize * aGal.GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD;
1181 };
1182
1183 const auto drawTextInfo =
1184 [&]( const PIN_LAYOUT_CACHE::TEXT_INFO& aTextInfo, const COLOR4D& aColor )
1185 {
1186 // const double iconSize = std::min( aPin->GetNameTextSize(), schIUScale.mmToIU( 1.5 ) );
1187 const bool renderTextAsBitmap = textRendersAsBitmap( *m_gal, aTextInfo.m_TextSize );
1188
1189 // Which of these gets used depends on the font technology, so set both
1190 m_gal->SetStrokeColor( aColor );
1191 m_gal->SetFillColor( aColor );
1192
1193 TEXT_ATTRIBUTES attrs;
1194 attrs.m_Font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font );
1195 attrs.m_Size = VECTOR2I( aTextInfo.m_TextSize, aTextInfo.m_TextSize );
1196 attrs.m_Halign = aTextInfo.m_HAlign;
1197 attrs.m_Valign = aTextInfo.m_VAlign;
1198 attrs.m_Angle = aTextInfo.m_Angle;
1199 attrs.m_StrokeWidth = aTextInfo.m_Thickness;
1200
1201 if( drawingShadows )
1202 {
1203 attrs.m_StrokeWidth += KiROUND( shadowWidth );
1204
1205 if( !attrs.m_Font->IsOutline() )
1206 {
1207 strokeText( *m_gal, aTextInfo.m_Text, aTextInfo.m_TextPosition, attrs,
1208 aPin->GetFontMetrics() );
1209 }
1210 else
1211 {
1212 boxText( *m_gal, aTextInfo.m_Text, aTextInfo.m_TextPosition, attrs,
1213 aPin->GetFontMetrics() );
1214 }
1215 }
1216 else if( nonCached( aPin ) && renderTextAsBitmap )
1217 {
1218 bitmapText( *m_gal, aTextInfo.m_Text, aTextInfo.m_TextPosition, attrs );
1219 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1220 }
1221 else
1222 {
1223 strokeText( *m_gal, aTextInfo.m_Text, aTextInfo.m_TextPosition, attrs,
1224 aPin->GetFontMetrics() );
1225 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1226 }
1227 };
1228
1229 const auto getColorForLayer = [&]( int aDrawnLayer )
1230 {
1231 if( !aPin->IsVisible() )
1232 return getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed );
1233
1234 return getRenderColor( aPin, aDrawnLayer, drawingShadows, aDimmed );
1235 };
1236
1237 // Request text layout info and draw it
1238
1239 if( std::optional<PIN_LAYOUT_CACHE::TEXT_INFO> numInfo = cache.GetPinNumberInfo( shadowWidth ) )
1240 {
1241 drawTextInfo( *numInfo, getColorForLayer( LAYER_PINNUM ) );
1242 }
1243
1244 if( std::optional<PIN_LAYOUT_CACHE::TEXT_INFO> nameInfo = cache.GetPinNameInfo( shadowWidth ) )
1245 {
1246 drawTextInfo( *nameInfo, getColorForLayer( LAYER_PINNAM ) );
1247
1248 if( OPT_BOX2I altIconBox = cache.GetAltIconBBox() )
1249 {
1250 drawAltPinModesIcon( *m_gal, altIconBox->GetCenter(), altIconBox->GetWidth(),
1251 // Icon style doesn't work due to the tempPin having no alt
1252 // but maybe it's better with just one style anyway.
1253 true, nameInfo->m_Angle == ANGLE_VERTICAL, shadowWidth,
1254 getColorForLayer( LAYER_PINNAM ) );
1255 }
1256 }
1257
1258 if( std::optional<PIN_LAYOUT_CACHE::TEXT_INFO> elecTypeInfo =
1259 cache.GetPinElectricalTypeInfo( shadowWidth ) )
1260 {
1261 drawTextInfo( *elecTypeInfo, getColorForLayer( LAYER_PRIVATE_NOTES ) );
1262 }
1263}
1264
1265
1266void SCH_PAINTER::drawAnchor( const VECTOR2I& aPos, bool aDrawingShadows )
1267{
1269 return;
1270
1271 // In order for the anchors to be visible but unobtrusive, their size must factor in the
1272 // current zoom level.
1273 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
1274 int radius = KiROUND( std::fabs( matrix.GetScale().x * TEXT_ANCHOR_SIZE ) / 25 )
1276
1279
1281 m_gal->SetIsStroke( true );
1282 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( false )
1284
1285 m_gal->DrawLine( aPos - VECTOR2I( radius, 0 ), aPos + VECTOR2I( radius, 0 ) );
1286 m_gal->DrawLine( aPos - VECTOR2I( 0, radius ), aPos + VECTOR2I( 0, radius ) );
1287}
1288
1289
1290void SCH_PAINTER::drawDanglingIndicator( const VECTOR2I& aPos, const COLOR4D& aColor, int aWidth,
1291 bool aDangling, bool aDrawingShadows, bool aBrightened )
1292{
1294 return;
1295
1296 int size = aDangling ? DANGLING_SYMBOL_SIZE : UNSELECTED_END_SIZE;
1297
1298 if( !aDangling )
1299 aWidth /= 2;
1300
1301 VECTOR2I radius( aWidth + schIUScale.MilsToIU( size / 2 ),
1302 aWidth + schIUScale.MilsToIU( size / 2 ) );
1303
1304 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
1305 // they overlap with a junction dot.
1306 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
1307 m_gal->SetIsStroke( true );
1308 m_gal->SetIsFill( false );
1309 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( aBrightened )
1311
1312 m_gal->DrawRectangle( aPos - radius, aPos + radius );
1313}
1314
1315
1316void SCH_PAINTER::draw( const SCH_JUNCTION* aJct, int aLayer )
1317{
1318 bool highlightNetclassColors = false;
1319 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
1320
1321 if( eeschemaCfg )
1322 {
1323 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
1324 }
1325
1326 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1327
1328 if( m_schSettings.IsPrinting() && drawingShadows )
1329 return;
1330
1331 if( drawingShadows && !( aJct->IsBrightened() || aJct->IsSelected() ) )
1332 return;
1333
1334 COLOR4D color;
1335
1336 if( highlightNetclassColors && aLayer == aJct->GetLayer() )
1338 else
1339 color = getRenderColor( aJct, aJct->GetLayer(), drawingShadows );
1340
1341 int junctionSize = aJct->GetEffectiveDiameter() / 2;
1342
1343 if( junctionSize > 1 )
1344 {
1345 m_gal->SetIsStroke( drawingShadows );
1346 m_gal->SetLineWidth( getLineWidth( aJct, drawingShadows ) );
1348 m_gal->SetIsFill( !drawingShadows );
1350 m_gal->DrawCircle( aJct->GetPosition(), junctionSize );
1351 }
1352}
1353
1354
1355void SCH_PAINTER::draw( const SCH_LINE* aLine, int aLayer )
1356{
1357 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1358 bool drawingNetColorHighlights = aLayer == LAYER_NET_COLOR_HIGHLIGHT;
1359 bool drawingWires = aLayer == LAYER_WIRE;
1360 bool drawingBusses = aLayer == LAYER_BUS;
1361 bool drawingDangling = aLayer == LAYER_DANGLING;
1362 bool drawingOP = aLayer == LAYER_OP_VOLTAGES;
1363
1364 bool highlightNetclassColors = false;
1365 double highlightAlpha = 0.6;
1366 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
1367 double hopOverScale = 0.0;
1368
1369 if( aLine->Schematic() ) // Can be nullptr when run from the color selection panel
1370 hopOverScale = aLine->Schematic()->Settings().m_HopOverScale;
1371
1372 if( eeschemaCfg )
1373 {
1374 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
1375 highlightAlpha = eeschemaCfg->m_Selection.highlight_netclass_colors_alpha;
1376 }
1377
1378 if( !highlightNetclassColors && drawingNetColorHighlights )
1379 return;
1380
1381 if( m_schSettings.m_OverrideItemColors && drawingNetColorHighlights )
1382 return;
1383
1384 if( m_schSettings.IsPrinting() && drawingShadows )
1385 return;
1386
1387 if( drawingShadows && !( aLine->IsBrightened() || aLine->IsSelected() ) )
1388 return;
1389
1390 // Line end dangling status isn't updated until the line is finished drawing, so don't warn
1391 // them about ends that are probably connected
1392 if( aLine->IsNew() && drawingDangling )
1393 return;
1394
1395 COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
1396 float width = getLineWidth( aLine, drawingShadows, drawingNetColorHighlights );
1397 LINE_STYLE lineStyle = aLine->GetEffectiveLineStyle();
1398
1399 if( highlightNetclassColors )
1400 {
1401 // Force default color for nets we are going to highlight
1402 if( drawingWires )
1404 else if( drawingBusses )
1406 }
1407
1408 if( drawingNetColorHighlights )
1409 {
1410 // Don't draw highlights for default-colored nets
1411 if( ( aLine->IsWire() && color == m_schSettings.GetLayerColor( LAYER_WIRE ) )
1412 || ( aLine->IsBus() && color == m_schSettings.GetLayerColor( LAYER_BUS ) ) )
1413 {
1414 return;
1415 }
1416
1417 color = color.WithAlpha( color.a * highlightAlpha );
1418 }
1419
1420 if( ( drawingDangling || drawingShadows ) && !aLine->IsNew() )
1421 {
1422 if( ( aLine->IsWire() && aLine->IsStartDangling() )
1423 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( STARTPOINT ) ) )
1424 {
1425 COLOR4D indicatorColor( color );
1426
1427 if( drawingShadows && !aLine->HasFlag( STARTPOINT ) )
1428 indicatorColor.Invert();
1429
1430 drawDanglingIndicator( aLine->GetStartPoint(), indicatorColor, KiROUND( width ),
1431 aLine->IsWire() && aLine->IsStartDangling(), drawingShadows,
1432 aLine->IsBrightened() );
1433 }
1434
1435 if( ( aLine->IsWire() && aLine->IsEndDangling() )
1436 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( ENDPOINT ) ) )
1437 {
1438 COLOR4D indicatorColor( color );
1439
1440 if( drawingShadows && !aLine->HasFlag( ENDPOINT ) )
1441 indicatorColor.Invert();
1442
1443 drawDanglingIndicator( aLine->GetEndPoint(), indicatorColor, KiROUND( width ),
1444 aLine->IsWire() && aLine->IsEndDangling(), drawingShadows,
1445 aLine->IsBrightened() );
1446 }
1447 }
1448
1449 if( drawingDangling )
1450 return;
1451
1452 if( drawingOP && !aLine->GetOperatingPoint().IsEmpty() )
1453 {
1454 int textSize = getOperatingPointTextSize();
1455 VECTOR2I pos = aLine->GetMidPoint();
1456 int textOffset = KiROUND( textSize * 0.22 );
1457 TEXT_ATTRIBUTES attrs;
1458
1459 if( aLine->GetStartPoint().y == aLine->GetEndPoint().y )
1460 {
1461 pos.y -= textOffset;
1464 }
1465 else
1466 {
1467 pos.x += KiROUND( textOffset * 1.2 );
1470 }
1471
1472 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
1473 attrs.m_Size = VECTOR2I( textSize, textSize );
1474 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
1476
1477 knockoutText( *m_gal, aLine->GetOperatingPoint(), pos, attrs, aLine->GetFontMetrics() );
1478 }
1479
1480 if( drawingOP )
1481 return;
1482
1483 m_gal->SetIsStroke( true );
1484 m_gal->SetIsFill( false );
1486 m_gal->SetLineWidth( width );
1487
1488 std::vector<VECTOR3I> curr_wire_shape;
1489
1490 if( aLine->IsWire() && hopOverScale > 0.0 )
1491 {
1492 double lineWidth = getLineWidth( aLine, false, drawingNetColorHighlights );
1493 double arcRadius = lineWidth * hopOverScale;
1494 curr_wire_shape = aLine->BuildWireWithHopShape( m_schematic->GetCurrentScreen(), arcRadius );
1495 }
1496 else
1497 {
1498 curr_wire_shape.emplace_back( aLine->GetStartPoint().x, aLine->GetStartPoint().y, 0 );
1499 curr_wire_shape.emplace_back( aLine->GetEndPoint().x, aLine->GetEndPoint().y, 0 );
1500 }
1501
1502 for( size_t ii = 1; ii < curr_wire_shape.size(); ii++ )
1503 {
1504 VECTOR2I start( curr_wire_shape[ii-1].x, curr_wire_shape[ii-1].y );
1505
1506 if( curr_wire_shape[ii-1].z == 0 ) // This is the start point of a segment
1507 // there are always 2 points in list for a segment
1508 {
1509 VECTOR2I end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1510 drawLine( start, end, lineStyle,
1511 ( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows ), width );
1512 }
1513 else // This is the start point of a arc. there are always 3 points in list for an arc
1514 {
1515 // Hop are a small arc, so use a solid line style gives best results
1516 VECTOR2I arc_middle( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1517 ii++;
1518 VECTOR2I arc_end( curr_wire_shape[ii].x, curr_wire_shape[ii].y );
1519 ii++;
1520
1521 VECTOR2D dstart = start;
1522 VECTOR2D dmid = arc_middle;
1523 VECTOR2D dend = arc_end;
1524 VECTOR2D center = CalcArcCenter( dstart, dmid, dend );
1525
1526 EDA_ANGLE startAngle( dstart - center );
1527 EDA_ANGLE midAngle( dmid - center );
1528 EDA_ANGLE endAngle( dend - center );
1529
1530 EDA_ANGLE angle1 = midAngle - startAngle;
1531 EDA_ANGLE angle2 = endAngle - midAngle;
1532
1533 EDA_ANGLE angle = angle1.Normalize180() + angle2.Normalize180();
1534
1535 m_gal->DrawArc( center, ( dstart - center ).EuclideanNorm(), startAngle, angle );
1536 }
1537 }
1538}
1539
1540
1541void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
1542{
1543 if( !isUnitAndConversionShown( aShape ) )
1544 return;
1545
1546 if( aShape->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1547 return;
1548
1549 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1550
1551 if( m_schSettings.IsPrinting() && drawingShadows )
1552 return;
1553
1554 LINE_STYLE lineStyle = aShape->GetEffectiveLineStyle();
1555 COLOR4D color = getRenderColor( aShape, aLayer, drawingShadows, aDimmed );
1556
1557 if( drawingShadows && !( aShape->IsBrightened() || aShape->IsSelected() ) )
1558 return;
1559
1560 auto drawShape =
1561 [&]( const SCH_SHAPE* shape )
1562 {
1563 switch( shape->GetShape() )
1564 {
1565 case SHAPE_T::ARC:
1566 {
1567 VECTOR2D start = shape->GetStart();
1568 VECTOR2D mid = shape->GetArcMid();
1569 VECTOR2D end = shape->GetEnd();
1570 VECTOR2D center = CalcArcCenter( start, mid, end );
1571
1572 EDA_ANGLE startAngle( start - center );
1573 EDA_ANGLE midAngle( mid - center );
1574 EDA_ANGLE endAngle( end - center );
1575
1576 EDA_ANGLE angle1 = midAngle - startAngle;
1577 EDA_ANGLE angle2 = endAngle - midAngle;
1578
1579 EDA_ANGLE angle = angle1.Normalize180() + angle2.Normalize180();
1580
1581 m_gal->DrawArc( center, ( start - center ).EuclideanNorm(), startAngle, angle );
1582 break;
1583 }
1584
1585 case SHAPE_T::CIRCLE:
1586 m_gal->DrawCircle( shape->GetPosition(), shape->GetRadius() );
1587 break;
1588
1589 case SHAPE_T::RECTANGLE:
1590 m_gal->DrawRectangle( shape->GetPosition(), shape->GetEnd() );
1591 break;
1592
1593 case SHAPE_T::POLY:
1594 {
1595 const std::vector<SHAPE*> polySegments = shape->MakeEffectiveShapes( true );
1596
1597 if( !polySegments.empty() )
1598 {
1599 std::deque<VECTOR2D> pts;
1600
1601 for( SHAPE* polySegment : polySegments )
1602 pts.push_back( static_cast<SHAPE_SEGMENT*>( polySegment )->GetSeg().A );
1603
1604 pts.push_back(
1605 static_cast<SHAPE_SEGMENT*>( polySegments.back() )->GetSeg().B );
1606
1607 for( SHAPE* polySegment : polySegments )
1608 delete polySegment;
1609
1610 m_gal->DrawPolygon( pts );
1611 }
1612 break;
1613 }
1614
1615 case SHAPE_T::BEZIER:
1616 {
1617 m_gal->DrawCurve( shape->GetStart(), shape->GetBezierC1(),
1618 shape->GetBezierC2(), shape->GetEnd() );
1619 break;
1620 }
1621
1622 default:
1623 UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
1624 }
1625 };
1626
1627 if( aLayer == LAYER_SELECTION_SHADOWS )
1628 {
1629 if( eeconfig()->m_Selection.fill_shapes )
1630 {
1631 // Consider a NAND gate. We have no idea which side of the arc is "inside"
1632 // so we can't reliably fill.
1633 if( aShape->GetShape() == SHAPE_T::ARC )
1634 m_gal->SetIsFill( aShape->IsSolidFill() );
1635 else
1636 m_gal->SetIsFill( true );
1637
1639 }
1640 else
1641 {
1642 m_gal->SetIsFill( false );
1643 }
1644
1645 // We still always draw the stroke, as otherwise single-segment shapes
1646 // (like a line) don't get a shadow, and special-casing them looks inconsistent.
1647 m_gal->SetIsStroke( true );
1648 m_gal->SetLineWidth( getLineWidth( aShape, true ) );
1650
1651 drawShape( aShape );
1652 }
1653 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND
1654 || aLayer == LAYER_SHAPES_BACKGROUND )
1655 {
1656 switch( aShape->GetFillMode() )
1657 {
1658 case FILL_T::NO_FILL:
1659 break;
1660
1661 case FILL_T::FILLED_SHAPE:
1662 // Fill in the foreground layer
1663 break;
1664
1665 case FILL_T::HATCH:
1666 case FILL_T::REVERSE_HATCH:
1667 case FILL_T::CROSS_HATCH:
1668 if( aShape->IsSelected() )
1669 color.a = color.a * 0.8; // selected items already have reduced-alpha backgrounds
1670 else
1671 color.a = color.a * 0.4;
1672
1673 m_gal->SetIsFill( true );
1674 m_gal->SetIsStroke( false );
1676 m_gal->DrawPolygon( aShape->GetHatching() );
1677 break;
1678
1679 case FILL_T::FILLED_WITH_COLOR:
1680 case FILL_T::FILLED_WITH_BG_BODYCOLOR:
1681 // Do not fill the shape in B&W print mode, to avoid to visible items inside the shape
1683 {
1684 m_gal->SetIsFill( true );
1685 m_gal->SetIsStroke( false );
1687
1688 drawShape( aShape );
1689 }
1690 break;
1691
1692 default:
1693 wxFAIL_MSG( wxT( "Unsupported fill type" ) );
1694 }
1695 }
1696 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES
1697 || aLayer == LAYER_RULE_AREAS )
1698 {
1699 // Shapes filled with the device colour must be filled in the foreground
1700 if( aShape->GetFillMode() == FILL_T::FILLED_SHAPE )
1701 {
1702 m_gal->SetIsFill( true );
1703 m_gal->SetIsStroke( false );
1705
1706 drawShape( aShape );
1707 }
1708
1709 float lineWidth = getLineWidth( aShape, drawingShadows );
1710
1711 if( lineWidth > 0 )
1712 {
1713 m_gal->SetIsFill( false );
1714 m_gal->SetIsStroke( true );
1715 m_gal->SetLineWidth( lineWidth );
1717
1718 if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
1719 {
1720 drawShape( aShape );
1721 }
1722 else
1723 {
1724 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
1725
1726 for( SHAPE* shape : shapes )
1727 {
1728 STROKE_PARAMS::Stroke( shape, lineStyle, KiROUND( lineWidth ), &m_schSettings,
1729 [this]( const VECTOR2I& a, const VECTOR2I& b )
1730 {
1731 // DrawLine has problem with 0 length lines so enforce minimum
1732 if( a == b )
1733 m_gal->DrawLine( a+1, b );
1734 else
1735 m_gal->DrawLine( a, b );
1736 } );
1737 }
1738
1739 for( SHAPE* shape : shapes )
1740 delete shape;
1741 }
1742 }
1743 }
1744}
1745
1746
1747void SCH_PAINTER::draw( const SCH_TEXT* aText, int aLayer, bool aDimmed )
1748{
1749 if( !isUnitAndConversionShown( aText ) )
1750 return;
1751
1752 if( aText->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1753 return;
1754
1755 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1756
1757 if( m_schSettings.IsPrinting() && drawingShadows )
1758 return;
1759
1760 if( drawingShadows && !( aText->IsBrightened() || aText->IsSelected() ) )
1761 return;
1762
1763 switch( aText->Type() )
1764 {
1765 case SCH_SHEET_PIN_T: aLayer = LAYER_SHEETLABEL; break;
1766 case SCH_HIER_LABEL_T: aLayer = LAYER_HIERLABEL; break;
1767 case SCH_GLOBAL_LABEL_T: aLayer = LAYER_GLOBLABEL; break;
1768 case SCH_DIRECTIVE_LABEL_T: aLayer = LAYER_NETCLASS_REFS; break;
1769 case SCH_LABEL_T: aLayer = LAYER_LOCLABEL; break;
1770 case SCH_TEXT_T: aLayer = aText->GetParentSymbol() ? LAYER_DEVICE
1771 : LAYER_NOTES; break;
1772 default: aLayer = LAYER_NOTES; break;
1773 }
1774
1775 COLOR4D color = getRenderColor( aText, aLayer, drawingShadows, aDimmed );
1776
1777 if( m_schematic )
1778 {
1779 SCH_CONNECTION* conn = nullptr;
1780
1781 if( !aText->IsConnectivityDirty() )
1782 conn = aText->Connection();
1783
1784 if( conn && conn->IsBus() )
1785 color = getRenderColor( aText, LAYER_BUS, drawingShadows );
1786 }
1787
1788 if( !( aText->IsVisible() || aText->IsForceVisible() ) )
1789 {
1790 if( m_schSettings.m_IsSymbolEditor || eeconfig()->m_Appearance.show_hidden_fields )
1791 color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
1792 else
1793 return;
1794 }
1795
1798
1799 wxString shownText( aText->GetShownText( true ) );
1800 VECTOR2I text_offset = aText->GetSchematicTextOffset( &m_schSettings );
1801 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
1802 KIFONT::FONT* font = getFont( aText );
1803
1804 attrs.m_Angle = aText->GetDrawRotation();
1805 attrs.m_StrokeWidth = KiROUND( getTextThickness( aText ) );
1806
1807 if( drawingShadows && font->IsOutline() )
1808 {
1809 BOX2I bBox = aText->GetBoundingBox();
1810 bBox.Inflate( KiROUND( getTextThickness( aText ) * 2 ) );
1811
1812 m_gal->SetIsStroke( false );
1813 m_gal->SetIsFill( true );
1814 m_gal->DrawRectangle( bBox.GetPosition(), bBox.GetEnd() );
1815 }
1816 else if( aText->GetLayer() == LAYER_DEVICE )
1817 {
1818 BOX2I bBox = aText->GetBoundingBox();
1819 VECTOR2D pos = bBox.Centre();
1820
1821 // Due to the fact a shadow text can be drawn left or right aligned, it needs to be
1822 // offset by shadowWidth/2 to be drawn at the same place as normal text.
1823 // For some reason we need to slightly modify this offset for a better look (better
1824 // alignment of shadow shape), for KiCad font only.
1825 double shadowOffset = 0.0;
1826
1827 if( drawingShadows )
1828 {
1829 double shadowWidth = getShadowWidth( !aText->IsSelected() );
1830 attrs.m_StrokeWidth += getShadowWidth( !aText->IsSelected() );
1831
1832 const double adjust = 1.2f; // Value chosen after tests
1833 shadowOffset = shadowWidth/2.0f * adjust;
1834 }
1835
1836 if( attrs.m_Angle == ANGLE_VERTICAL )
1837 {
1838 switch( attrs.m_Halign )
1839 {
1841 pos.y = bBox.GetBottom() + shadowOffset;
1842 break;
1844 pos.y = ( bBox.GetTop() + bBox.GetBottom() ) / 2.0;
1845 break;
1847 pos.y = bBox.GetTop() - shadowOffset;
1848 break;
1850 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
1851 break;
1852 }
1853 }
1854 else
1855 {
1856 switch( attrs.m_Halign )
1857 {
1859 pos.x = bBox.GetLeft() - shadowOffset;
1860 break;
1862 pos.x = ( bBox.GetLeft() + bBox.GetRight() ) / 2.0;
1863 break;
1865 pos.x = bBox.GetRight() + shadowOffset;
1866 break;
1868 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
1869 break;
1870 }
1871 }
1872
1873 // Because the text vertical position is the bounding box center, the text is drawn as
1874 // vertically centered.
1876
1877 strokeText( *m_gal, shownText, pos, attrs, aText->GetFontMetrics() );
1878 }
1879 else if( drawingShadows )
1880 {
1881 m_gal->SetIsFill( false );
1882 m_gal->SetIsStroke( true );
1883 attrs.m_StrokeWidth += KiROUND( getShadowWidth( !aText->IsSelected() ) );
1884 attrs.m_Underlined = false;
1885
1886 // Fudge factors to match 6.0 positioning
1887 // New text stroking has width dependent offset but we need to center the shadow on the
1888 // stroke. NB this offset is in font.cpp also.
1889 int fudge = KiROUND( getShadowWidth( !aText->IsSelected() ) / 1.52 );
1890
1891 if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_0 )
1892 text_offset.x -= fudge;
1893 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_90 )
1894 text_offset.y -= fudge;
1895 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_0 )
1896 text_offset.x += fudge;
1897 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_90 )
1898 text_offset.y += fudge;
1899
1900 strokeText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs,
1901 aText->GetFontMetrics() );
1902 }
1903 else
1904 {
1905 if( aText->IsHypertext() && aText->IsRollover() && !aText->IsMoving() )
1906 {
1909 attrs.m_Underlined = true;
1910 }
1911
1912 // Adjust text drawn in an outline font to more closely mimic the positioning of
1913 // SCH_FIELD text.
1914 if( font->IsOutline() && aText->Type() == SCH_TEXT_T )
1915 {
1916 BOX2I firstLineBBox = aText->GetTextBox( 0 );
1917 int sizeDiff = firstLineBBox.GetHeight() - aText->GetTextSize().y;
1918 int adjust = KiROUND( sizeDiff * 0.4 );
1919 VECTOR2I adjust_offset( 0, - adjust );
1920
1921 RotatePoint( adjust_offset, aText->GetDrawRotation() );
1922 text_offset += adjust_offset;
1923 }
1924
1925 if( nonCached( aText )
1926 && aText->RenderAsBitmap( m_gal->GetWorldScale() )
1927 && !shownText.Contains( wxT( "\n" ) ) )
1928 {
1929 bitmapText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs );
1930 const_cast<SCH_TEXT*>( aText )->SetFlags( IS_SHOWN_AS_BITMAP );
1931 }
1932 else
1933 {
1934 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
1935
1936 if( !aText->IsHypertext() && font->IsOutline() )
1937 cache = aText->GetRenderCache( font, shownText, text_offset );
1938
1939 if( cache )
1940 {
1942 m_gal->DrawGlyphs( *cache );
1943 }
1944 else
1945 {
1946 strokeText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs,
1947 aText->GetFontMetrics() );
1948 }
1949
1950 const_cast<SCH_TEXT*>( aText )->ClearFlags( IS_SHOWN_AS_BITMAP );
1951 }
1952 }
1953
1954 // Draw anchor
1955 if( aText->IsSelected() )
1956 {
1957 bool showAnchor;
1958
1959 switch( aText->Type() )
1960 {
1961 case SCH_TEXT_T:
1962 showAnchor = true;
1963 break;
1964
1965 case SCH_LABEL_T:
1966 // Don't clutter things up if we're already showing a dangling indicator
1967 showAnchor = !static_cast<const SCH_LABEL*>( aText )->IsDangling();
1968 break;
1969
1971 case SCH_HIER_LABEL_T:
1972 case SCH_GLOBAL_LABEL_T:
1973 case SCH_SHEET_PIN_T:
1974 // These all have shapes and so don't need anchors
1975 showAnchor = false;
1976 break;
1977
1978 default:
1979 showAnchor = false;
1980 break;
1981 }
1982
1983 if( showAnchor )
1984 drawAnchor( aText->GetPosition(), drawingShadows );
1985 }
1986}
1987
1988
1989void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer, bool aDimmed )
1990{
1991 if( aTextBox->Type() == SCH_TABLECELL_T )
1992 {
1993 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aTextBox );
1994
1995 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
1996 return;
1997 }
1998
1999 if( !isUnitAndConversionShown( aTextBox ) )
2000 return;
2001
2002 if( aTextBox->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
2003 return;
2004
2005 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2006
2007 if( m_schSettings.IsPrinting() && drawingShadows )
2008 return;
2009
2010 COLOR4D color = getRenderColor( aTextBox, aLayer, drawingShadows, aDimmed );
2012 float borderWidth = getLineWidth( aTextBox, drawingShadows );
2013 KIFONT::FONT* font = getFont( aTextBox );
2014
2015 auto drawText =
2016 [&]()
2017 {
2018 wxString shownText = aTextBox->GetShownText( true );
2019 TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes();
2020
2021 attrs.m_Angle = aTextBox->GetDrawRotation();
2022 attrs.m_StrokeWidth = KiROUND( getTextThickness( aTextBox ) );
2023
2024 if( aTextBox->IsHypertext() && aTextBox->IsRollover() && !aTextBox->IsMoving() )
2025 {
2028 attrs.m_Underlined = true;
2029 }
2030
2031 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2032
2033 if( !aTextBox->IsHypertext() && font->IsOutline() )
2034 cache = aTextBox->GetRenderCache( font, shownText );
2035
2036 if( cache )
2037 {
2039 m_gal->DrawGlyphs( *cache );
2040 }
2041 else
2042 {
2043 strokeText( *m_gal, shownText, aTextBox->GetDrawPos(), attrs,
2044 aTextBox->GetFontMetrics() );
2045 }
2046 };
2047
2048 if( drawingShadows && !( aTextBox->IsBrightened() || aTextBox->IsSelected() ) )
2049 return;
2050
2053
2054 if( aLayer == LAYER_SELECTION_SHADOWS )
2055 {
2056 m_gal->SetIsFill( true );
2057 m_gal->SetIsStroke( false );
2058 m_gal->SetLineWidth( borderWidth );
2059
2060 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2061 }
2062 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND
2063 || aLayer == LAYER_SHAPES_BACKGROUND )
2064 {
2065 // Do not fill the shape in B&W print mode, to avoid to visible items
2066 // inside the shape
2067 if( aTextBox->IsSolidFill() && !m_schSettings.PrintBlackAndWhiteReq() )
2068 {
2069 m_gal->SetIsFill( true );
2070 m_gal->SetIsStroke( false );
2071 m_gal->SetLineWidth( borderWidth );
2072
2073 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2074 }
2075 }
2076 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES )
2077 {
2078 drawText();
2079
2080 if( aTextBox->Type() != SCH_TABLECELL_T && borderWidth > 0 )
2081 {
2082 COLOR4D borderColor = aTextBox->GetStroke().GetColor();
2083 LINE_STYLE borderStyle = aTextBox->GetEffectiveLineStyle();
2084 double transparency = aTextBox->GetForcedTransparency();
2085
2087 || borderColor == COLOR4D::UNSPECIFIED )
2088 {
2089 borderColor = m_schSettings.GetLayerColor( aLayer );
2090 }
2091
2092 if( transparency > 0.0 )
2093 borderColor = borderColor.WithAlpha( borderColor.a * ( 1.0 - transparency ) );
2094
2095 if( aDimmed )
2096 {
2097 borderColor = borderColor.Mix( bg, 0.5f );
2098 borderColor.Desaturate( );
2099 }
2100
2101 m_gal->SetIsFill( false );
2102 m_gal->SetIsStroke( true );
2103 m_gal->SetStrokeColor( borderColor );
2104 m_gal->SetLineWidth( borderWidth );
2105
2106 if( borderStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
2107 {
2108 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2109 }
2110 else
2111 {
2112 std::vector<SHAPE*> shapes = aTextBox->MakeEffectiveShapes( true );
2113
2114 for( SHAPE* shape : shapes )
2115 {
2116 STROKE_PARAMS::Stroke( shape, borderStyle, KiROUND( borderWidth ),
2118 [this]( const VECTOR2I& a, const VECTOR2I& b )
2119 {
2120 // DrawLine has problem with 0 length lines so enforce minimum
2121 if( a == b )
2122 m_gal->DrawLine( a+1, b );
2123 else
2124 m_gal->DrawLine( a, b );
2125 } );
2126 }
2127
2128 for( SHAPE* shape : shapes )
2129 delete shape;
2130 }
2131 }
2132 }
2133}
2134
2135
2136void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
2137{
2138 if( aTable->GetCells().empty() )
2139 return;
2140
2141 for( SCH_TABLECELL* cell : aTable->GetCells() )
2142 draw( cell, aLayer, aDimmed );
2143
2144 if( aLayer == LAYER_SELECTION_SHADOWS )
2145 return;
2146
2147 aTable->DrawBorders(
2148 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB, const STROKE_PARAMS& stroke )
2149 {
2150 int lineWidth = stroke.GetWidth();
2151 COLOR4D color = stroke.GetColor();
2152 LINE_STYLE lineStyle = stroke.GetLineStyle();
2153
2154 if( lineWidth == 0 )
2155 lineWidth = m_schSettings.GetDefaultPenWidth();
2156
2159
2160 if( lineStyle == LINE_STYLE::DEFAULT )
2161 lineStyle = LINE_STYLE::SOLID;
2162
2163 m_gal->SetIsFill( false );
2164 m_gal->SetIsStroke( true );
2166 m_gal->SetLineWidth( (float) lineWidth );
2167
2168 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2169 {
2170 m_gal->DrawLine( ptA, ptB );
2171 }
2172 else
2173 {
2174 SHAPE_SEGMENT seg( ptA, ptB );
2175 STROKE_PARAMS::Stroke( &seg, lineStyle, lineWidth, &m_schSettings,
2176 [&]( const VECTOR2I& a, const VECTOR2I& b )
2177 {
2178 // DrawLine has problem with 0 length lines so enforce minimum
2179 if( a == b )
2180 m_gal->DrawLine( a+1, b );
2181 else
2182 m_gal->DrawLine( a, b );
2183 } );
2184 }
2185 } );
2186}
2187
2188
2189wxString SCH_PAINTER::expandLibItemTextVars( const wxString& aSourceText,
2190 const SCH_SYMBOL* aSymbolContext )
2191{
2192 std::function<bool( wxString* )> symbolResolver =
2193 [&]( wxString* token ) -> bool
2194 {
2195 if( !m_schematic )
2196 return false;
2197
2198 return aSymbolContext->ResolveTextVar( &m_schematic->CurrentSheet(), token );
2199 };
2200
2201 return ExpandTextVars( aSourceText, &symbolResolver );
2202}
2203
2204
2205void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
2206{
2207 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2208 bool DNP = aSymbol->GetDNP();
2209 bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions
2210 && aSymbol->GetExcludedFromSim();
2211
2212 if( m_schSettings.IsPrinting() && drawingShadows )
2213 return;
2214
2215 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2216 {
2217 for( const SCH_FIELD& field : aSymbol->GetFields() )
2218 draw( &field, aLayer, DNP );
2219 }
2220
2221 if( isFieldsLayer( aLayer ) )
2222 return;
2223
2224 if( drawingShadows && !( aSymbol->IsBrightened() || aSymbol->IsSelected() ) )
2225 {
2226 // Don't exit here; symbol may still have selected pins
2227 // return;
2228 }
2229
2230 int unit = m_schematic ? aSymbol->GetUnitSelection( &m_schematic->CurrentSheet() ) : 1;
2231 int bodyStyle = aSymbol->GetBodyStyle();
2232
2233 // Use dummy symbol if the actual couldn't be found (or couldn't be locked).
2234 LIB_SYMBOL* originalSymbol =
2235 aSymbol->GetLibSymbolRef() ? aSymbol->GetLibSymbolRef().get() : LIB_SYMBOL::GetDummy();
2236 std::vector<SCH_PIN*> originalPins = originalSymbol->GetPins( unit, bodyStyle );
2237
2238 // Copy the source so we can re-orient and translate it.
2239 LIB_SYMBOL tempSymbol( *originalSymbol );
2240 std::vector<SCH_PIN*> tempPins = tempSymbol.GetPins( unit, bodyStyle );
2241
2242 tempSymbol.SetFlags( aSymbol->GetFlags() );
2243
2244 OrientAndMirrorSymbolItems( &tempSymbol, aSymbol->GetOrientation() );
2245
2246 for( SCH_ITEM& tempItem : tempSymbol.GetDrawItems() )
2247 {
2248 tempItem.SetFlags( aSymbol->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2249 tempItem.Move( aSymbol->GetPosition() );
2250
2251 if( tempItem.Type() == SCH_TEXT_T )
2252 {
2253 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( &tempItem );
2254
2255 if( textItem->HasTextVars() )
2256 textItem->SetText( expandLibItemTextVars( textItem->GetText(), aSymbol ) );
2257 }
2258 else if( tempItem.Type() == SCH_TEXTBOX_T )
2259 {
2260 SCH_TEXTBOX* textboxItem = static_cast<SCH_TEXTBOX*>( &tempItem );
2261
2262 if( textboxItem->HasTextVars() )
2263 textboxItem->SetText( expandLibItemTextVars( textboxItem->GetText(), aSymbol ) );
2264 }
2265 }
2266
2267 // Copy the pin info from the symbol to the temp pins
2268 for( unsigned i = 0; i < tempPins.size(); ++ i )
2269 {
2270 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2271 SCH_PIN* tempPin = tempPins[ i ];
2272
2273 tempPin->ClearFlags();
2274 tempPin->SetFlags( symbolPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2275 // IS_SHOWN_AS_BITMAP
2276
2277 tempPin->SetName( expandLibItemTextVars( symbolPin->GetShownName(), aSymbol ) );
2278 tempPin->SetType( symbolPin->GetType() );
2279 tempPin->SetShape( symbolPin->GetShape() );
2280
2281 if( symbolPin->IsDangling() )
2282 tempPin->SetFlags( IS_DANGLING );
2283 else
2284 tempPin->ClearFlags( IS_DANGLING );
2285
2286 tempPin->SetOperatingPoint( symbolPin->GetOperatingPoint() );
2287 }
2288
2289 draw( &tempSymbol, aLayer, false, aSymbol->GetUnit(), aSymbol->GetBodyStyle(),
2290 DNP );
2291
2292 for( unsigned i = 0; i < tempPins.size(); ++i )
2293 {
2294 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2295 SCH_PIN* tempPin = tempPins[ i ];
2296
2297 symbolPin->ClearFlags();
2298 tempPin->ClearFlags( IS_DANGLING ); // Clear this temporary flag
2299 symbolPin->SetFlags( tempPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2300 // IS_SHOWN_AS_BITMAP
2301 }
2302
2303 if( DNP )
2304 {
2305 int layer = LAYER_DNP_MARKER;
2306 BOX2I bbox = aSymbol->GetBodyBoundingBox();
2307 BOX2I pins = aSymbol->GetBodyAndPinsBoundingBox();
2308 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
2309 std::max( bbox.GetY() - pins.GetY(),
2310 pins.GetEnd().y - bbox.GetEnd().y ) );
2311 int strokeWidth = 3 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
2312
2313 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
2314 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
2315 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
2316
2317 VECTOR2I pt1 = bbox.GetOrigin();
2318 VECTOR2I pt2 = bbox.GetEnd();
2319
2320 GAL_SCOPED_ATTRS scopedAttrs( *m_gal, GAL_SCOPED_ATTRS::ALL_ATTRS );
2321 m_gal->AdvanceDepth();
2322 m_gal->SetIsStroke( true );
2323 m_gal->SetIsFill( true );
2324 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ) );
2325 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ) );
2326
2327 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2328 std::swap( pt1.x, pt2.x );
2329 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2330 }
2331
2332 if( markExclusion )
2333 {
2334 int layer = LAYER_EXCLUDED_FROM_SIM;
2335 BOX2I bbox = aSymbol->GetBodyBoundingBox();
2336 int strokeWidth = schIUScale.MilsToIU( ADVANCED_CFG::GetCfg().m_ExcludeFromSimulationLineWidth );
2337
2338 bbox.Inflate( KiROUND( strokeWidth * 0.5 ) );
2339
2340 GAL_SCOPED_ATTRS scopedAttrs( *m_gal, GAL_SCOPED_ATTRS::ALL_ATTRS );
2341 m_gal->AdvanceDepth();
2342 m_gal->SetIsStroke( true );
2343 m_gal->SetIsFill( true );
2344 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2345 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2346
2347 m_gal->DrawSegment( bbox.GetPosition(), VECTOR2D( bbox.GetEnd().x, bbox.GetY() ), strokeWidth );
2348 m_gal->DrawSegment( VECTOR2D( bbox.GetEnd().x, bbox.GetY() ), bbox.GetEnd(), strokeWidth );
2349 m_gal->DrawSegment( bbox.GetEnd(), VECTOR2D( bbox.GetX(), bbox.GetEnd().y ), strokeWidth );
2350 m_gal->DrawSegment( VECTOR2D( bbox.GetX(), bbox.GetEnd().y ), bbox.GetPosition(), strokeWidth );
2351
2352 int offset = 2 * strokeWidth;
2353 VECTOR2D center = bbox.GetEnd() + VECTOR2D( offset + strokeWidth, -offset );
2354 VECTOR2D left = center + VECTOR2D( -offset, 0 );
2355 VECTOR2D right = center + VECTOR2D( offset, 0 );
2356 VECTOR2D top = center + VECTOR2D( 0, offset );
2357 VECTOR2D bottom = center + VECTOR2D( 0, -offset );
2358
2359 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.1 ) );
2360 m_gal->DrawCircle( center, offset );
2361 m_gal->AdvanceDepth();
2362 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2363 m_gal->DrawCurve( left, top, bottom, right, 1 );
2364 }
2365}
2366
2367
2368void SCH_PAINTER::draw( const SCH_FIELD* aField, int aLayer, bool aDimmed )
2369{
2370 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2371
2372 if( m_schSettings.IsPrinting() && drawingShadows )
2373 return;
2374
2375 if( drawingShadows && !( aField->IsBrightened() || aField->IsSelected() ) )
2376 return;
2377
2378 if( !isUnitAndConversionShown( aField ) )
2379 return;
2380
2381 if( aField->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
2382 return;
2383
2384 // Must check layer as fields are sometimes drawn by their parent rather than directly
2385 // from the view.
2386 std::vector<int> layers = aField->ViewGetLayers();
2387
2388 if( std::find( layers.begin(), layers.end(), aLayer ) == layers.end() )
2389 return;
2390
2391 aLayer = aField->GetLayer();
2392
2393 COLOR4D color = getRenderColor( aField, aLayer, drawingShadows, aDimmed );
2394
2395 if( !( aField->IsVisible() || aField->IsForceVisible() ) )
2396 {
2397 bool force_show = m_schematic ? eeconfig()->m_Appearance.show_hidden_fields
2398 : m_schSettings.m_ShowHiddenFields;
2399
2400 if( force_show )
2401 color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows, aDimmed );
2402 else
2403 return;
2404 }
2405
2406 wxString shownText = aField->GetShownText( true );
2407
2408 if( shownText.IsEmpty() )
2409 return;
2410
2411 // Calculate the text orientation according to the parent orientation.
2412 EDA_ANGLE orient = aField->GetTextAngle();
2413
2414 if( aField->GetParent() && aField->GetParent()->Type() == SCH_SYMBOL_T )
2415 {
2416 if( static_cast<SCH_SYMBOL*>( aField->GetParent() )->GetTransform().y1 )
2417 {
2418 // Rotate symbol 90 degrees.
2419 if( orient.IsHorizontal() )
2420 orient = ANGLE_VERTICAL;
2421 else
2422 orient = ANGLE_HORIZONTAL;
2423 }
2424 }
2425
2426 /*
2427 * Calculate the text justification, according to the symbol orientation/mirror.
2428 * This is a bit complicated due to cumulative calculations:
2429 * - numerous cases (mirrored or not, rotation)
2430 * - the DrawGraphicText function recalculate also H and H justifications according to the
2431 * text orientation.
2432 * - when symbol is mirrored, the text is not mirrored and justifications are complicated
2433 * to calculate so the easier way is to use no justifications (centered text) and use
2434 * GetBoundingBox to know the text coordinate considered as centered
2435 */
2436 BOX2I bbox = aField->GetBoundingBox();
2437
2438 if( aField->GetParent() && aField->GetParent()->Type() == SCH_GLOBAL_LABEL_T )
2439 {
2440 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( aField->GetParent() );
2441 bbox.Offset( label->GetSchematicTextOffset( &m_schSettings ) );
2442 }
2443
2444 if( m_schSettings.GetDrawBoundingBoxes() )
2445 drawItemBoundingBox( aField );
2446
2447 m_gal->SetStrokeColor( color );
2448 m_gal->SetFillColor( color );
2449
2450 if( drawingShadows && getFont( aField )->IsOutline() )
2451 {
2452 BOX2I shadow_box = bbox;
2453 shadow_box.Inflate( KiROUND( getTextThickness( aField ) * 2 ) );
2454
2455 m_gal->SetIsStroke( false );
2456 m_gal->SetIsFill( true );
2457 m_gal->DrawRectangle( shadow_box.GetPosition(), shadow_box.GetEnd() );
2458 }
2459 else
2460 {
2461 VECTOR2I textpos = bbox.Centre();
2462 TEXT_ATTRIBUTES attributes = aField->GetAttributes();
2463
2464 attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
2465 attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
2466 attributes.m_StrokeWidth = KiROUND( getTextThickness( aField ) );
2467 attributes.m_Angle = orient;
2468
2469 if( drawingShadows )
2470 attributes.m_StrokeWidth += getShadowWidth( !aField->IsSelected() );
2471
2472 if( aField->IsHypertext() && aField->IsRollover() && !aField->IsMoving() )
2473 {
2474 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2475 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2476 attributes.m_Underlined = true;
2477 }
2478
2479 if( nonCached( aField ) && aField->RenderAsBitmap( m_gal->GetWorldScale() ) )
2480 {
2481 bitmapText( *m_gal, shownText, textpos, attributes );
2482 const_cast<SCH_FIELD*>( aField )->SetFlags( IS_SHOWN_AS_BITMAP );
2483 }
2484 else
2485 {
2486 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2487
2488 if( !aField->IsHypertext() )
2489 cache = aField->GetRenderCache( shownText, textpos, attributes );
2490
2491 if( cache )
2492 {
2493 m_gal->SetLineWidth( attributes.m_StrokeWidth );
2494 m_gal->DrawGlyphs( *cache );
2495 }
2496 else
2497 {
2498 strokeText( *m_gal, shownText, textpos, attributes, aField->GetFontMetrics() );
2499 }
2500
2501 const_cast<SCH_FIELD*>( aField )->ClearFlags( IS_SHOWN_AS_BITMAP );
2502 }
2503 }
2504
2505 if( aField->GetParent() && aField->GetParent()->Type() == SCH_SYMBOL_T )
2506 {
2507 SCH_SYMBOL* parent = static_cast<SCH_SYMBOL*>( aField->GetParent() );
2508 bool rotated = !orient.IsHorizontal() && !aField->CanAutoplace();
2509
2510 VECTOR2D pos;
2511 double size = bbox.GetHeight() / 1.5;
2512
2513 if( rotated )
2514 {
2515 pos = VECTOR2D( bbox.GetRight() - bbox.GetWidth() / 6.0,
2516 bbox.GetBottom() + bbox.GetWidth() / 2.0 );
2517 size = bbox.GetWidth() / 1.5;
2518 }
2519 else
2520 {
2521 pos = VECTOR2D( bbox.GetLeft() - bbox.GetHeight() / 2.0,
2522 bbox.GetBottom() - bbox.GetHeight() / 6.0 );
2523 }
2524
2525 if( parent->IsSymbolLikePowerLocalLabel() )
2526 drawLocalPowerIcon( pos, size, rotated, color, drawingShadows, aField->IsBrightened() );
2527 }
2528
2529 // Draw anchor or umbilical line
2530 if( aField->IsMoving() && m_schematic )
2531 {
2532 VECTOR2I parentPos = aField->GetParentPosition();
2533
2534 m_gal->SetLineWidth( m_schSettings.GetOutlineWidth() );
2535 m_gal->SetStrokeColor( getRenderColor( aField, LAYER_SCHEMATIC_ANCHOR, drawingShadows ) );
2536 m_gal->DrawLine( aField->GetPosition(), parentPos );
2537 }
2538 else if( aField->IsSelected() )
2539 {
2540 drawAnchor( aField->GetPosition(), drawingShadows );
2541 }
2542}
2543
2544
2545void SCH_PAINTER::draw( const SCH_GLOBALLABEL* aLabel, int aLayer, bool aDimmed )
2546{
2547 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2548
2549 if( m_schSettings.IsPrinting() && drawingShadows )
2550 return;
2551
2552 bool drawingDangling = aLayer == LAYER_DANGLING;
2553
2554 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2555 {
2556 for( const SCH_FIELD& field : aLabel->GetFields() )
2557 draw( &field, aLayer, false );
2558 }
2559
2560 if( isFieldsLayer( aLayer ) )
2561 return;
2562
2563 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2564 return;
2565
2566 COLOR4D color = getRenderColor( aLabel, LAYER_GLOBLABEL, drawingShadows, aDimmed, true );
2567
2568 if( drawingDangling )
2569 {
2570 if( aLabel->IsDangling() )
2571 {
2572 drawDanglingIndicator( aLabel->GetTextPos(), color,
2574 drawingShadows, aLabel->IsBrightened() );
2575 }
2576
2577 return;
2578 }
2579
2580 std::vector<VECTOR2I> pts;
2581 std::deque<VECTOR2D> pts2;
2582
2583 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
2584
2585 for( const VECTOR2I& p : pts )
2586 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2587
2588 m_gal->SetIsStroke( true );
2589 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2590 m_gal->SetStrokeColor( color );
2591
2592 if( drawingShadows )
2593 {
2594 m_gal->SetIsFill( eeconfig()->m_Selection.fill_shapes );
2595 m_gal->SetFillColor( color );
2596 m_gal->DrawPolygon( pts2 );
2597 }
2598 else
2599 {
2600 m_gal->SetIsFill( false );
2601 m_gal->DrawPolyline( pts2 );
2602 }
2603
2604 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2605}
2606
2607
2608void SCH_PAINTER::draw( const SCH_LABEL* aLabel, int aLayer, bool aDimmed )
2609{
2610 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2611
2612 if( m_schSettings.IsPrinting() && drawingShadows )
2613 return;
2614
2615 bool drawingDangling = aLayer == LAYER_DANGLING;
2616
2617 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2618 {
2619 for( const SCH_FIELD& field : aLabel->GetFields() )
2620 draw( &field, aLayer, false );
2621 }
2622
2623 if( isFieldsLayer( aLayer ) )
2624 return;
2625
2626 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2627 return;
2628
2629 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows, aDimmed, true );
2630
2631 if( drawingDangling )
2632 {
2633 if( aLabel->IsDangling() )
2634 {
2635 drawDanglingIndicator( aLabel->GetTextPos(), color,
2637 drawingShadows, aLabel->IsBrightened() );
2638 }
2639
2640 return;
2641 }
2642
2643 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2644}
2645
2646
2647void SCH_PAINTER::draw( const SCH_HIERLABEL* aLabel, int aLayer, bool aDimmed )
2648{
2649 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2650
2651 if( m_schSettings.IsPrinting() && drawingShadows )
2652 return;
2653
2654 bool drawingDangling = aLayer == LAYER_DANGLING;
2655
2656 if( !( drawingShadows || drawingDangling ) || eeconfig()->m_Selection.draw_selected_children )
2657 {
2658 for( const SCH_FIELD& field : aLabel->GetFields() )
2659 draw( &field, aLayer, false );
2660 }
2661
2662 if( isFieldsLayer( aLayer ) )
2663 return;
2664
2665 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2666 return;
2667
2668 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows, aDimmed, true );
2669
2670 if( drawingDangling )
2671 {
2672 if( aLabel->IsDangling() )
2673 {
2674 drawDanglingIndicator( aLabel->GetTextPos(), color,
2676 drawingShadows, aLabel->IsBrightened() );
2677 }
2678
2679 return;
2680 }
2681
2682 std::vector<VECTOR2I> i_pts;
2683 std::deque<VECTOR2D> d_pts;
2684
2685 aLabel->CreateGraphicShape( &m_schSettings, i_pts, (VECTOR2I)aLabel->GetTextPos() );
2686
2687 for( const VECTOR2I& i_pt : i_pts )
2688 d_pts.emplace_back( VECTOR2D( i_pt.x, i_pt.y ) );
2689
2690 m_gal->SetIsFill( true );
2691 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
2692 m_gal->SetIsStroke( true );
2693 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2694 m_gal->SetStrokeColor( color );
2695 m_gal->DrawPolyline( d_pts );
2696
2697 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2698}
2699
2700
2701void SCH_PAINTER::draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer, bool aDimmed )
2702{
2703 if( !eeconfig()->m_Appearance.show_directive_labels && !aLabel->IsSelected() )
2704 return;
2705
2706 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2707
2708 if( m_schSettings.IsPrinting() && drawingShadows )
2709 return;
2710
2711 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2712 {
2713 for( const SCH_FIELD& field : aLabel->GetFields() )
2714 draw( &field, aLayer, false );
2715 }
2716
2717 if( isFieldsLayer( aLayer ) )
2718 return;
2719
2720 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2721 return;
2722
2723 COLOR4D color = getRenderColor( aLabel, LAYER_NETCLASS_REFS, drawingShadows, aDimmed, true );
2724
2725 if( aLayer == LAYER_DANGLING )
2726 {
2727 if( aLabel->IsDangling() )
2728 {
2729 drawDanglingIndicator( aLabel->GetTextPos(), color,
2731 drawingShadows, aLabel->IsBrightened() );
2732 }
2733
2734 return;
2735 }
2736
2737 std::vector<VECTOR2I> pts;
2738 std::deque<VECTOR2D> pts2;
2739
2740 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
2741
2742 for( const VECTOR2I& p : pts )
2743 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2744
2745 m_gal->SetIsFill( false );
2746 m_gal->SetFillColor( color );
2747 m_gal->SetIsStroke( true );
2748 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2749 m_gal->SetStrokeColor( color );
2750
2751 if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_DOT )
2752 {
2753 m_gal->DrawLine( pts2[0], pts2[1] );
2754 m_gal->SetIsFill( true );
2755 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
2756 }
2757 else if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
2758 {
2759 m_gal->DrawLine( pts2[0], pts2[1] );
2760 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
2761 }
2762 else
2763 {
2764 m_gal->DrawPolyline( pts2 );
2765 }
2766}
2767
2768
2769void SCH_PAINTER::draw( const SCH_SHEET* aSheet, int aLayer )
2770{
2771 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2772 bool DNP = aSheet->GetDNP();
2773 bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions
2774 && aSheet->GetExcludedFromSim();
2775
2776 if( m_schSettings.IsPrinting() && drawingShadows )
2777 return;
2778
2779 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2780 {
2781 for( const SCH_FIELD& field : aSheet->GetFields() )
2782 draw( &field, aLayer, DNP );
2783
2784 for( SCH_SHEET_PIN* sheetPin : aSheet->GetPins() )
2785 draw( static_cast<SCH_HIERLABEL*>( sheetPin ), aLayer, DNP );
2786 }
2787
2788 if( isFieldsLayer( aLayer ) )
2789 return;
2790
2791 VECTOR2D pos = aSheet->GetPosition();
2792 VECTOR2D size = aSheet->GetSize();
2793
2794 if( aLayer == LAYER_SHEET_BACKGROUND )
2795 {
2796 // Do not fill the shape in B&W print mode, to avoid to visible items
2797 // inside the shape
2798 if( !m_schSettings.PrintBlackAndWhiteReq() )
2799 {
2800 m_gal->SetFillColor( getRenderColor( aSheet, LAYER_SHEET_BACKGROUND, true ) );
2801 m_gal->SetIsFill( true );
2802 m_gal->SetIsStroke( false );
2803
2804 m_gal->DrawRectangle( pos, pos + size );
2805 }
2806 }
2807
2808 if( aLayer == LAYER_SHEET || aLayer == LAYER_SELECTION_SHADOWS )
2809 {
2810 m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, drawingShadows ) );
2811 m_gal->SetIsStroke( true );
2812 m_gal->SetLineWidth( getLineWidth( aSheet, drawingShadows ) );
2813 m_gal->SetIsFill( false );
2814
2815 m_gal->DrawRectangle( pos, pos + size );
2816 }
2817
2818 if( DNP )
2819 {
2820 int layer = LAYER_DNP_MARKER;
2821 BOX2I bbox = aSheet->GetBodyBoundingBox();
2822 BOX2I pins = aSheet->GetBoundingBox();
2823 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
2824 std::max( bbox.GetY() - pins.GetY(),
2825 pins.GetEnd().y - bbox.GetEnd().y ) );
2826 int strokeWidth = 3 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
2827
2828 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
2829 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
2830 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
2831
2832 VECTOR2I pt1 = bbox.GetOrigin();
2833 VECTOR2I pt2 = bbox.GetEnd();
2834
2835 GAL_SCOPED_ATTRS scopedAttrs( *m_gal, GAL_SCOPED_ATTRS::ALL_ATTRS );
2836 m_gal->SetIsStroke( true );
2837 m_gal->SetIsFill( true );
2838 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ) );
2839 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ) );
2840
2841 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2842 std::swap( pt1.x, pt2.x );
2843 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2844 }
2845
2846 if( markExclusion )
2847 {
2848 int layer = LAYER_EXCLUDED_FROM_SIM;
2849 BOX2I bbox = aSheet->GetBodyBoundingBox();
2850 int strokeWidth = schIUScale.MilsToIU( ADVANCED_CFG::GetCfg().m_ExcludeFromSimulationLineWidth );
2851
2852 bbox.Inflate( KiROUND( strokeWidth * 0.5 ) );
2853
2854 GAL_SCOPED_ATTRS scopedAttrs( *m_gal, GAL_SCOPED_ATTRS::ALL_ATTRS );
2855 m_gal->AdvanceDepth();
2856 m_gal->SetIsStroke( true );
2857 m_gal->SetIsFill( true );
2858 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2859 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2860
2861 m_gal->DrawSegment( bbox.GetPosition(), VECTOR2D( bbox.GetEnd().x, bbox.GetY() ), strokeWidth );
2862 m_gal->DrawSegment( VECTOR2D( bbox.GetEnd().x, bbox.GetY() ), bbox.GetEnd(), strokeWidth );
2863 m_gal->DrawSegment( bbox.GetEnd(), VECTOR2D( bbox.GetX(), bbox.GetEnd().y ), strokeWidth );
2864 m_gal->DrawSegment( VECTOR2D( bbox.GetX(), bbox.GetEnd().y ), bbox.GetPosition(), strokeWidth );
2865
2866 int offset = 2 * strokeWidth;
2867 VECTOR2D center = bbox.GetEnd() + VECTOR2D( offset + strokeWidth, -offset );
2868 VECTOR2D left = center + VECTOR2D( -offset, 0 );
2869 VECTOR2D right = center + VECTOR2D( offset, 0 );
2870 VECTOR2D top = center + VECTOR2D( 0, offset );
2871 VECTOR2D bottom = center + VECTOR2D( 0, -offset );
2872
2873 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.1 ) );
2874 m_gal->DrawCircle( center, offset );
2875 m_gal->AdvanceDepth();
2876 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ).WithAlpha( 0.5 ) );
2877 m_gal->DrawCurve( left, top, bottom, right, 1 );
2878 }
2879}
2880
2881
2882void SCH_PAINTER::draw( const SCH_NO_CONNECT* aNC, int aLayer )
2883{
2884 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2885
2886 if( m_schSettings.IsPrinting() && drawingShadows )
2887 return;
2888
2889 if( drawingShadows && !( aNC->IsBrightened() || aNC->IsSelected() ) )
2890 return;
2891
2892 m_gal->SetIsStroke( true );
2893 m_gal->SetLineWidth( getLineWidth( aNC, drawingShadows ) );
2894 m_gal->SetStrokeColor( getRenderColor( aNC, LAYER_NOCONNECT, drawingShadows ) );
2895 m_gal->SetIsFill( false );
2896
2897 VECTOR2D p = aNC->GetPosition();
2898 int delta = std::max( aNC->GetSize(), m_schSettings.GetDefaultPenWidth() * 3 ) / 2;
2899
2900 m_gal->DrawLine( p + VECTOR2D( -delta, -delta ), p + VECTOR2D( delta, delta ) );
2901 m_gal->DrawLine( p + VECTOR2D( -delta, delta ), p + VECTOR2D( delta, -delta ) );
2902}
2903
2904
2905void SCH_PAINTER::draw( const SCH_BUS_ENTRY_BASE *aEntry, int aLayer )
2906{
2908 SCH_LINE line( VECTOR2I(), layer );
2909 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2910 bool drawingNetColorHighlights = aLayer == LAYER_NET_COLOR_HIGHLIGHT;
2911 bool drawingDangling = aLayer == LAYER_DANGLING;
2912 bool drawingWires = aLayer == LAYER_WIRE;
2913 bool drawingBusses = aLayer == LAYER_BUS;
2914
2915 if( m_schSettings.IsPrinting() && drawingShadows )
2916 return;
2917
2918 bool highlightNetclassColors = false;
2919 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
2920
2921 if( eeschemaCfg )
2922 {
2923 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
2924 }
2925
2926 if( !highlightNetclassColors && drawingNetColorHighlights )
2927 return;
2928
2929 if( m_schSettings.m_OverrideItemColors && drawingNetColorHighlights )
2930 return;
2931
2932 if( drawingShadows && !( aEntry->IsBrightened() || aEntry->IsSelected() ) )
2933 return;
2934
2935 if( aEntry->IsSelected() )
2936 {
2937 line.SetSelected();
2938
2939 // Never show unselected endpoints on bus entries
2940 line.SetFlags( STARTPOINT | ENDPOINT );
2941 }
2942 else if( aEntry->IsBrightened() )
2943 {
2944 line.SetBrightened();
2945 }
2946
2947 line.SetStartPoint( aEntry->GetPosition() );
2948 line.SetEndPoint( aEntry->GetEnd() );
2949 line.SetStroke( aEntry->GetStroke() );
2950 line.SetLineWidth( KiROUND( getLineWidth( aEntry, false ) ) );
2951
2952 COLOR4D color = getRenderColor( aEntry, LAYER_WIRE, drawingShadows );
2953
2954 if( aEntry->Type() == SCH_BUS_BUS_ENTRY_T )
2955 color = getRenderColor( aEntry, LAYER_BUS, drawingShadows );
2956
2957 if( highlightNetclassColors )
2958 {
2959 // Force default color for nets we are going to highlight
2960 if( drawingWires )
2961 color = m_schSettings.GetLayerColor( LAYER_WIRE );
2962 else if( drawingBusses )
2963 color = m_schSettings.GetLayerColor( LAYER_BUS );
2964 }
2965
2966 if( drawingNetColorHighlights )
2967 {
2968 // Don't draw highlights for default-colored nets
2969 if( ( aEntry->Type() == SCH_BUS_WIRE_ENTRY_T
2970 && color == m_schSettings.GetLayerColor( LAYER_WIRE ) )
2971 || ( aEntry->Type() == SCH_BUS_BUS_ENTRY_T
2972 && color == m_schSettings.GetLayerColor( LAYER_BUS ) ) )
2973 {
2974 return;
2975 }
2976 }
2977
2978 if( drawingDangling )
2979 {
2980 m_gal->SetIsFill( false );
2981 m_gal->SetIsStroke( true );
2982 m_gal->SetStrokeColor( color.Brightened( 0.3 ) );
2983 m_gal->SetLineWidth( m_schSettings.GetDanglingIndicatorThickness() );
2984
2985 if( aEntry->IsStartDangling() )
2986 {
2987 m_gal->DrawCircle( aEntry->GetPosition(),
2988 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
2989 }
2990
2991 if( aEntry->IsEndDangling() )
2992 {
2993 m_gal->DrawCircle( aEntry->GetEnd(),
2994 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
2995 }
2996 }
2997 else
2998 {
2999 line.SetLineColor( color );
3000 line.SetLineStyle( aEntry->GetEffectiveLineStyle() );
3001
3002 draw( &line, aLayer );
3003 }
3004}
3005
3006
3007void SCH_PAINTER::draw( const SCH_BITMAP* aBitmap, int aLayer )
3008{
3009 m_gal->Save();
3010 m_gal->Translate( aBitmap->GetPosition() );
3011
3012 const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
3013
3014 // When the image scale factor is not 1.0, we need to modify the actual as the image scale
3015 // factor is similar to a local zoom
3016 const double img_scale = refImage.GetImageScale();
3017
3018 if( img_scale != 1.0 )
3019 m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
3020
3021 if( aLayer == LAYER_DRAW_BITMAPS )
3022 {
3023 m_gal->DrawBitmap( refImage.GetImage() );
3024 }
3025
3026 if( aLayer == LAYER_SELECTION_SHADOWS )
3027 {
3028 if( aBitmap->IsSelected() || aBitmap->IsBrightened() )
3029 {
3030 const COLOR4D color = getRenderColor( aBitmap, LAYER_DRAW_BITMAPS, true );
3031 m_gal->SetIsStroke( true );
3032 m_gal->SetStrokeColor( color );
3033 m_gal->SetLineWidth ( getShadowWidth( aBitmap->IsBrightened() ) );
3034 m_gal->SetIsFill( false );
3035
3036 // Draws a bounding box.
3037 VECTOR2D bm_size( refImage.GetSize() );
3038
3039 // bm_size is the actual image size in UI.
3040 // but m_gal scale was previously set to img_scale
3041 // so recalculate size relative to this image size.
3042 bm_size.x /= img_scale;
3043 bm_size.y /= img_scale;
3044 const VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
3045 const VECTOR2D end = origin + bm_size;
3046
3047 m_gal->DrawRectangle( origin, end );
3048 }
3049 }
3050
3051 m_gal->Restore();
3052}
3053
3054
3055void SCH_PAINTER::draw( const SCH_MARKER* aMarker, int aLayer )
3056{
3057 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
3058
3059 if( m_schSettings.IsPrinting() && drawingShadows )
3060 return;
3061
3062 if( drawingShadows && !( aMarker->IsBrightened() || aMarker->IsSelected() ) )
3063 return;
3064
3065 COLOR4D color = getRenderColor( aMarker, aMarker->GetColorLayer(), drawingShadows );
3066
3067 m_gal->Save();
3068 m_gal->Translate( aMarker->GetPosition() );
3069 m_gal->SetIsFill( !drawingShadows );
3070 m_gal->SetFillColor( color );
3071 m_gal->SetIsStroke( drawingShadows );
3072 m_gal->SetLineWidth( getLineWidth( aMarker, drawingShadows ) );
3073 m_gal->SetStrokeColor( color );
3074
3075 SHAPE_LINE_CHAIN polygon;
3076 aMarker->ShapeToPolygon( polygon );
3077
3078 m_gal->DrawPolygon( polygon );
3079 m_gal->Restore();
3080}
3081
3082
3083void SCH_PAINTER::draw( const SCH_GROUP* aGroup, int aLayer )
3084{
3085 const bool drawingShadows = false;
3086
3087 if( aLayer == LAYER_SCHEMATIC_ANCHOR )
3088 {
3089 if( aGroup->IsSelected() && !( aGroup->GetParent() && aGroup->GetParent()->IsSelected() ) )
3090 {
3091 // Selected on our own; draw enclosing box
3092 }
3093 else if( aGroup->IsEntered() )
3094 {
3095 // Entered group; draw enclosing box
3096 }
3097 else
3098 {
3099 // Neither selected nor entered; draw nothing at the group level (ie: only draw
3100 // its members)
3101 return;
3102 }
3103
3104 const COLOR4D color = getRenderColor( aGroup, LAYER_SCHEMATIC_ANCHOR, drawingShadows );
3105
3106 m_gal->SetStrokeColor( color );
3107 m_gal->SetLineWidth( m_schSettings.GetOutlineWidth() * 2.0f );
3108
3109 BOX2I bbox = aGroup->GetBoundingBox();
3110 VECTOR2I topLeft = bbox.GetPosition();
3111 VECTOR2I width = VECTOR2I( bbox.GetWidth(), 0 );
3112 VECTOR2I height = VECTOR2I( 0, bbox.GetHeight() );
3113
3114 m_gal->DrawLine( topLeft, topLeft + width );
3115 m_gal->DrawLine( topLeft + width, topLeft + width + height );
3116 m_gal->DrawLine( topLeft + width + height, topLeft + height );
3117 m_gal->DrawLine( topLeft + height, topLeft );
3118
3119 wxString name = aGroup->GetName();
3120
3121 if( name.IsEmpty() )
3122 return;
3123
3124 int ptSize = 12;
3125 int scaledSize = abs( KiROUND( m_gal->GetScreenWorldMatrix().GetScale().x * ptSize ) );
3126 int unscaledSize = schIUScale.MilsToIU( ptSize );
3127
3128 // Scale by zoom a bit, but not too much
3129 int textSize = ( scaledSize + ( unscaledSize * 2 ) ) / 3;
3130 VECTOR2I textOffset = VECTOR2I( width.x / 2, -KiROUND( textSize * 0.5 ) );
3131 VECTOR2I titleHeight = VECTOR2I( 0, KiROUND( textSize * 2.0 ) );
3132
3133 if( PrintableCharCount( name ) * textSize < bbox.GetWidth() )
3134 {
3135 m_gal->DrawLine( topLeft, topLeft - titleHeight );
3136 m_gal->DrawLine( topLeft - titleHeight, topLeft + width - titleHeight );
3137 m_gal->DrawLine( topLeft + width - titleHeight, topLeft + width );
3138
3139 TEXT_ATTRIBUTES attrs;
3140 attrs.m_Italic = true;
3143 attrs.m_Size = VECTOR2I( textSize, textSize );
3144 attrs.m_StrokeWidth = GetPenSizeForNormal( textSize );
3145
3146 KIFONT::FONT::GetFont()->Draw( m_gal, aGroup->GetName(), topLeft + textOffset, attrs,
3147 aGroup->GetFontMetrics() );
3148 }
3149 }
3150}
3151
3152void SCH_PAINTER::drawLine( const VECTOR2I& aStartPoint, const VECTOR2I& aEndPoint,
3153 LINE_STYLE aLineStyle, bool aDrawDirectLine, int aWidth )
3154{
3155 if( aDrawDirectLine )
3156 {
3157 m_gal->DrawLine( aStartPoint, aEndPoint );
3158 }
3159 else
3160 {
3161 SHAPE_SEGMENT segment( aStartPoint, aEndPoint );
3162
3163 STROKE_PARAMS::Stroke( &segment, aLineStyle, KiROUND( aWidth ), &m_schSettings,
3164 [&]( const VECTOR2I& start, const VECTOR2I& end )
3165 {
3166 if( start == end )
3167 m_gal->DrawLine( start + 1, end );
3168 else
3169 m_gal->DrawLine( start, end );
3170 } );
3171 }
3172}
3173
3174}; // namespace KIGFX
int color
Definition: DXF_plotter.cpp:63
const char * name
Definition: DXF_plotter.cpp:62
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
std::optional< BOX2I > OPT_BOX2I
Definition: box2.h:926
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr coord_type GetY() const
Definition: box2.h:208
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr coord_type GetX() const
Definition: box2.h:207
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr void SetX(coord_type val)
Definition: box2.h:277
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr void SetY(coord_type val)
Definition: box2.h:282
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:720
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr void Offset(coord_type dx, coord_type dy)
Definition: box2.h:259
constexpr coord_type GetBottom() const
Definition: box2.h:222
Represent basic circle geometry with utility geometry functions.
Definition: circle.h:33
VECTOR2I Center
Public to make access simpler.
Definition: circle.h:130
int Radius
Public to make access simpler.
Definition: circle.h:129
bool IsHorizontal() const
Definition: eda_angle.h:141
EDA_ANGLE Normalize180()
Definition: eda_angle.h:263
double AsRadians() const
Definition: eda_angle.h:120
wxString GetName() const
Definition: eda_group.h:51
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:97
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition: eda_item.cpp:110
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:141
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:109
bool IsEntered() const
Definition: eda_item.h:127
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:143
bool IsSelected() const
Definition: eda_item.h:126
void SetSelected()
Definition: eda_item.h:133
void SetBrightened()
Definition: eda_item.h:134
EDA_ITEM * GetParent() const
Definition: eda_item.h:111
bool IsRollover() const
Definition: eda_item.h:130
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:145
bool IsBrightened() const
Definition: eda_item.h:128
bool IsForceVisible() const
Definition: eda_item.h:210
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:144
bool IsMoving() const
Definition: eda_item.h:124
bool IsNew() const
Definition: eda_item.h:123
const SHAPE_POLY_SET & GetHatching() const
Definition: eda_shape.h:148
FILL_T GetFillMode() const
Definition: eda_shape.h:142
SHAPE_T GetShape() const
Definition: eda_shape.h:168
bool IsSolidFill() const
Definition: eda_shape.h:117
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:215
COLOR4D GetFillColor() const
Definition: eda_shape.h:152
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:79
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:270
COLOR4D GetTextColor() const
Definition: eda_text.h:267
bool IsItalic() const
Definition: eda_text.h:166
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:144
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:97
virtual bool IsVisible() const
Definition: eda_text.h:184
KIFONT::FONT * GetFont() const
Definition: eda_text.h:244
BOX2I GetTextBox(int aLine=-1) const
Useful in multiline texts to calculate the full text or a line area (for zones filling,...
Definition: eda_text.cpp:730
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:671
virtual EDA_ANGLE GetDrawRotation() const
Definition: eda_text.h:373
virtual VECTOR2I GetDrawPos() const
Definition: eda_text.h:374
bool HasTextVars() const
Indicates the ShownText has text var references which need to be processed.
Definition: eda_text.h:116
const TEXT_ATTRIBUTES & GetAttributes() const
Definition: eda_text.h:228
bool IsBold() const
Definition: eda_text.h:181
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:270
VECTOR2I GetTextSize() const
Definition: eda_text.h:258
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, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition: font.cpp:147
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:250
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:427
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
Attribute save/restore for GAL attributes.
Abstract interface for drawing on a 2D-surface.
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList)
Draw a polygon.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void Rotate(double aAngle)
Rotate the context.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
void SetVerticalJustify(const GR_TEXT_V_ALIGN_T aVerticalJustify)
void SetFontBold(const bool aBold)
void SetFontUnderlined(bool aUnderlined)
void SetHorizontalJustify(const GR_TEXT_H_ALIGN_T aHorizontalJustify)
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void Translate(const VECTOR2D &aTranslation)
Translate the context.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius)
Draw a circle using world coordinates.
virtual void Restore()
Restore the context.
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.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
void SetGlyphSize(const VECTOR2I aSize)
virtual void DrawGlyphs(const std::vector< std::unique_ptr< KIFONT::GLYPH > > &aGlyphs)
Draw polygons representing font glyphs.
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint, double aFilterValue=0.0)
Draw a cubic bezier spline.
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle)
Draw an arc.
void SetFontItalic(bool aItalic)
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
virtual void Save()
Save the context.
double GetWorldScale() const
Get the world scale.
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
int GetDefaultPenWidth() const
const wxString & GetDefaultFont() const
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
bool PrintBlackAndWhiteReq() const
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.
void drawPinDanglingIndicator(const SCH_PIN &aPin, const COLOR4D &aColor, bool aDrawingShadows, bool aBrightened)
float getTextThickness(const SCH_ITEM *aItem) const
void drawLocalPowerIcon(const VECTOR2D &aPos, double aSize, bool aRotate, const COLOR4D &aColor, bool aDrawingShadows, bool aBrightened)
Draw an local power pin indicator icon.
float getShadowWidth(bool aForHighlight) const
COLOR4D getRenderColor(const SCH_ITEM *aItem, int aLayer, bool aDrawingShadows, bool aDimmed=false, bool aIgnoreNets=false) const
int externalPinDecoSize(const SCH_PIN &aPin)
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:147
SCHEMATIC * m_schematic
Definition: sch_painter.h:151
void drawLine(const VECTOR2I &aStartPoint, const VECTOR2I &aEndPoint, LINE_STYLE aLineStyle, bool aDrawDirectLine=false, int aWidth=0)
int getOperatingPointTextSize() const
float getLineWidth(const SCH_ITEM *aItem, bool aDrawingShadows, bool aDrawingWireColorHighlights=false) const
void triLine(const VECTOR2D &a, const VECTOR2D &b, const VECTOR2D &c)
SCH_RENDER_SETTINGS m_schSettings
Definition: sch_painter.h:150
void drawAnchor(const VECTOR2I &aPos, bool aDrawingShadows)
Draw anchor indicating the anchor position of text objects, local labels, or fields.
bool nonCached(const EDA_ITEM *aItem)
Indicates the item is drawn on a non-cached layer in OpenGL.
SCH_PAINTER(GAL *aGal)
void drawDanglingIndicator(const VECTOR2I &aPos, const COLOR4D &aColor, int aWidth, bool aDangling, bool aDrawingShadows, bool aBrightened)
Draw the target (an open square) for a wire or label which has no connection or is being moved.
void drawItemBoundingBox(const EDA_ITEM *aItem)
int internalPinDecoSize(const SCH_PIN &aPin)
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:86
double GetForcedTransparency() const
Definition: view_item.h:165
Define a library symbol object.
Definition: lib_symbol.h:85
std::vector< SCH_PIN * > GetPins(int aUnit, int aBodyStyle) const
Return a list of pin object pointers from the draw item list.
Definition: lib_symbol.cpp:800
bool IsDerived() const
Definition: lib_symbol.h:207
static LIB_SYMBOL * GetDummy()
Returns a dummy LIB_SYMBOL, used when one is missing in the schematic.
Definition: lib_symbol.cpp:237
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition: lib_symbol.h:519
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:345
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
A pin layout helper is a class that manages the layout of the parts of a pin on a schematic symbol:
OPT_BOX2I GetAltIconBBox()
Get the box of the alt mode icon, if there is one.
std::optional< TEXT_INFO > GetPinNameInfo(int aShadowWidth)
Get the text info for the pin name.
std::optional< TEXT_INFO > GetPinElectricalTypeInfo(int aShadowWidth)
CIRCLE GetDanglingIndicator() const
Gets the dangling indicator geometry for this pin, if the pin were to be dangling.
std::optional< TEXT_INFO > GetPinNumberInfo(int aShadowWidth)
void SetRenderParameters(int aNameThickness, int aNumberThickness, bool aShowElectricalType, bool aShowAltIcons)
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
VECTOR2I GetSize() const
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:317
SCH_SCREEN * GetCurrentScreen() const
Definition: schematic.h:177
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:40
VECTOR2I GetPosition() const override
Definition: sch_bitmap.cpp:103
REFERENCE_IMAGE & GetReferenceImage()
Definition: sch_bitmap.h:51
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:38
bool IsStartDangling() const
Definition: sch_bus_entry.h:43
VECTOR2I GetPosition() const override
bool IsEndDangling() const
Definition: sch_bus_entry.h:44
virtual STROKE_PARAMS GetStroke() const override
Definition: sch_bus_entry.h:81
int GetPenWidth() const override
VECTOR2I GetEnd() const
LINE_STYLE GetEffectiveLineStyle() 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:1690
virtual bool IsDangling() const override
Determines dangling state from connectivity and cached connected rule areas.
Definition: sch_label.cpp:1854
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:492
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1344
bool IsHypertext() const override
Allow items to support hypertext actions when hovered/clicked.
Definition: sch_field.cpp:1021
std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition: sch_field.cpp:440
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:191
bool CanAutoplace() const
Definition: sch_field.h:210
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const wxString &forResolvedText, const VECTOR2I &forPosition, TEXT_ATTRIBUTES &aAttrs) const
Definition: sch_field.cpp:348
VECTOR2I GetParentPosition() const
Definition: sch_field.cpp:1360
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:2023
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:1913
A set of SCH_ITEMs (i.e., without duplicates).
Definition: sch_group.h:52
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_group.cpp:198
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:2133
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
const SYMBOL * GetParentSymbol() const
Definition: sch_item.cpp:218
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:212
int GetBodyStyle() const
Definition: sch_item.h:246
std::vector< int > ViewGetLayers() const override
Return the layers the item is drawn on (which may be more than its "home" layer)
Definition: sch_item.cpp:302
int GetUnit() const
Definition: sch_item.h:242
bool IsPrivate() const
Definition: sch_item.h:250
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:309
bool RenderAsBitmap(double aWorldScale) const override
Definition: sch_item.cpp:613
bool IsConnectivityDirty() const
Definition: sch_item.h:555
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:318
wxString GetClass() const override
Return the class name.
Definition: sch_item.h:178
const KIFONT::METRICS & GetFontMetrics() const
Definition: sch_item.cpp:581
int GetEffectivePenWidth(const SCH_RENDER_SETTINGS *aSettings) const
Definition: sch_item.cpp:590
bool IsType(const std::vector< KICAD_T > &aScanTypes) const override
Check whether the item is one of the listed types.
Definition: sch_item.h:183
int GetEffectiveDiameter() const
VECTOR2I GetPosition() const override
Definition: sch_junction.h:107
bool IsDangling() const override
Definition: sch_label.h:329
COLOR4D GetLabelColor() const
Definition: sch_label.cpp:292
LABEL_FLAG_SHAPE GetShape() const
Definition: sch_label.h:176
std::vector< SCH_FIELD > & GetFields()
Definition: sch_label.h:205
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:42
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:140
std::vector< VECTOR3I > BuildWireWithHopShape(const SCH_SCREEN *aScreen, double aArcRadius) const
For wires only: build the list of points to draw the shape using segments and 180 deg arcs Points are...
Definition: sch_line.cpp:1037
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:937
bool IsStartDangling() const
Definition: sch_line.h:288
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:249
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:315
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_line.cpp:302
VECTOR2I GetMidPoint() const
Definition: sch_line.h:142
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
bool IsEndDangling() const
Definition: sch_line.h:289
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:943
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:286
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition: sch_line.h:194
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:145
const wxString & GetOperatingPoint() const
Definition: sch_line.h:331
SCH_LAYER_ID GetColorLayer() const
Definition: sch_marker.cpp:313
VECTOR2I GetPosition() const override
Definition: sch_marker.h:102
int GetSize() const
VECTOR2I GetPosition() const override
int GetNumberTextSize() const
Definition: sch_pin.cpp:591
int GetLength() const
Definition: sch_pin.cpp:281
const wxString & GetOperatingPoint() const
Definition: sch_pin.h:310
void SetName(const wxString &aName)
Definition: sch_pin.cpp:405
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.cpp:353
bool IsVisible() const
Definition: sch_pin.cpp:373
VECTOR2I GetPinRoot() const
Definition: sch_pin.cpp:615
bool IsDangling() const override
Definition: sch_pin.cpp:438
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition: sch_pin.h:95
VECTOR2I GetPosition() const override
Definition: sch_pin.cpp:238
int GetNameTextSize() const
Definition: sch_pin.cpp:567
wxString GetShownName() const
Definition: sch_pin.cpp:537
PIN_LAYOUT_CACHE & GetLayoutCache() const
Get the layout cache associated with this pin.
Definition: sch_pin.h:324
void SetOperatingPoint(const wxString &aText)
Definition: sch_pin.h:311
void SetType(ELECTRICAL_PINTYPE aType)
Definition: sch_pin.cpp:315
GRAPHIC_PINSHAPE GetShape() const
Definition: sch_pin.cpp:260
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:295
float GetDanglingIndicatorThickness() const
std::vector< SHAPE * > MakeEffectiveShapes(bool aEdgeOnly=false) const override
Make a set of SHAPE objects representing the SCH_SHAPE.
Definition: sch_shape.h:111
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_shape.h:62
STROKE_PARAMS GetStroke() const override
Definition: sch_shape.h:57
VECTOR2I GetPosition() const override
Definition: sch_shape.h:84
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:47
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition: sch_sheet.h:87
VECTOR2I GetSize() const
Definition: sch_sheet.h:118
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:415
const BOX2I GetBodyBoundingBox() const
Return a bounding box for the sheet body but not the fields.
Definition: sch_sheet.cpp:690
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_sheet.cpp:711
KIGFX::COLOR4D GetBorderColor() const
Definition: sch_sheet.h:124
bool GetExcludedFromSim() const override
Definition: sch_sheet.h:385
std::vector< SCH_SHEET_PIN * > & GetPins()
Definition: sch_sheet.h:187
bool GetDNP() const override
Set or clear the 'Do Not Populate' flags.
Definition: sch_sheet.h:402
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:127
Schematic symbol object.
Definition: sch_symbol.h:75
BOX2I GetBodyAndPinsBoundingBox() const override
Return a bounding box for the symbol body and pins but not the fields.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
Definition: sch_symbol.cpp:780
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:777
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
Definition: sch_symbol.cpp:678
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
int GetOrientation() const override
Get the display symbol orientation.
bool IsSymbolLikePowerLocalLabel() const
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:183
BOX2I GetBodyBoundingBox() const override
Return a bounding box for the symbol body but not the pins or fields.
int GetColSpan() const
Definition: sch_tablecell.h:64
int GetRowSpan() const
Definition: sch_tablecell.h:67
std::vector< SCH_TABLECELL * > GetCells() const
Definition: sch_table.h:156
void DrawBorders(const std::function< void(const VECTOR2I &aPt1, const VECTOR2I &aPt2, const STROKE_PARAMS &aStroke)> &aCallback) const
Definition: sch_table.cpp:330
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.
bool IsHypertext() const override
Allow items to support hypertext actions when hovered/clicked.
Definition: sch_text.h:78
VECTOR2I GetPosition() const override
Definition: sch_text.h:139
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_text.cpp:297
virtual wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_text.cpp:318
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:72
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.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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.
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
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:94
int GetWidth() const
LINE_STYLE GetLineStyle() const
KIGFX::COLOR4D GetColor() const
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)
const TRANSFORM & GetTransform() const
Definition: symbol.h:197
bool GetDNP() const override
Set or clear the 'Do Not Populate' flag.
Definition: symbol.h:192
bool GetExcludedFromSim() const override
Definition: symbol.h:175
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, int aFlags)
Definition: common.cpp:59
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 size of the rectangle indicating the anchor of a text object (including fields)
#define TEXT_ANCHOR_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:404
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:406
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:400
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:409
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:408
#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.
int GetPenSizeForDemiBold(int aTextSize)
Definition: gr_text.cpp:42
int GetPenSizeForNormal(int aTextSize)
Definition: gr_text.cpp:60
int ClampTextPenSize(int aPenSize, int aSize, bool aStrict)
Pen width should not allow characters to become cluttered up in their own fatness.
Definition: gr_text.cpp:72
@ LAYER_DRAW_BITMAPS
Draw images.
Definition: layer_ids.h:283
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:439
@ LAYER_DANGLING
Definition: layer_ids.h:467
@ LAYER_SHAPES_BACKGROUND
Definition: layer_ids.h:473
@ LAYER_SHEETNAME
Definition: layer_ids.h:462
@ LAYER_SCHEMATIC_ANCHOR
Definition: layer_ids.h:489
@ LAYER_SHEETLABEL
Definition: layer_ids.h:465
@ LAYER_PINNUM
Definition: layer_ids.h:448
@ LAYER_RULE_AREAS
Definition: layer_ids.h:455
@ LAYER_DEVICE
Definition: layer_ids.h:456
@ LAYER_SHEET_BACKGROUND
Definition: layer_ids.h:475
@ LAYER_EXCLUDED_FROM_SIM
Definition: layer_ids.h:472
@ LAYER_BRIGHTENED
Definition: layer_ids.h:481
@ LAYER_HIDDEN
Definition: layer_ids.h:482
@ LAYER_HIERLABEL
Definition: layer_ids.h:447
@ LAYER_PINNAM
Definition: layer_ids.h:449
@ LAYER_PRIVATE_NOTES
Definition: layer_ids.h:458
@ LAYER_HOVERED
Definition: layer_ids.h:480
@ LAYER_GLOBLABEL
Definition: layer_ids.h:446
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_NET_COLOR_HIGHLIGHT
Definition: layer_ids.h:483
@ LAYER_PIN
Definition: layer_ids.h:460
@ LAYER_VALUEPART
Definition: layer_ids.h:451
@ LAYER_BUS
Definition: layer_ids.h:443
@ LAYER_FIELDS
Definition: layer_ids.h:452
@ LAYER_DEVICE_BACKGROUND
Definition: layer_ids.h:474
@ LAYER_LOCLABEL
Definition: layer_ids.h:445
@ LAYER_SHEETFIELDS
Definition: layer_ids.h:464
@ LAYER_REFERENCEPART
Definition: layer_ids.h:450
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:454
@ LAYER_NOTES_BACKGROUND
Definition: layer_ids.h:459
@ LAYER_OP_CURRENTS
Definition: layer_ids.h:491
@ LAYER_SHEET
Definition: layer_ids.h:461
@ LAYER_SELECTION_SHADOWS
Definition: layer_ids.h:484
@ LAYER_SCHEMATIC_BACKGROUND
Definition: layer_ids.h:478
@ LAYER_INTERSHEET_REFS
Definition: layer_ids.h:453
@ LAYER_OP_VOLTAGES
Definition: layer_ids.h:490
@ LAYER_SHEETFILENAME
Definition: layer_ids.h:463
@ LAYER_DNP_MARKER
Definition: layer_ids.h:468
@ LAYER_NOCONNECT
Definition: layer_ids.h:466
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:96
The Cairo implementation of the graphics abstraction layer.
Definition: eda_group.h:33
static void boxText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void bitmapText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs)
EESCHEMA_SETTINGS * eeconfig()
Definition: sch_painter.cpp:73
static void strokeText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void knockoutText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void drawAltPinModesIcon(GAL &aGal, const VECTOR2D &aPos, double aSize, bool aBaseSelected, bool aRotate, int aExtraLineWidth, const COLOR4D &aColor)
Draw an alternate pin mode indicator icon.
static bool isFieldsLayer(int aLayer)
static BOX2I GetTextExtents(const wxString &aText, const VECTOR2D &aPosition, KIFONT::FONT &aFont, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition: kicad_algo.h:100
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:393
see class PGM_BASE
#define TARGET_BUSENTRY_RADIUS
Definition: sch_bus_entry.h:31
Class to handle a set of SCH_ITEMs.
#define BITMAP_FONT_SIZE_THRESHOLD
Definition: sch_item.cpp:45
@ F_DOT
Definition: sch_label.h:107
@ F_ROUND
Definition: sch_label.h:108
#define TARGET_PIN_RADIUS
Definition: sch_pin.h:36
Utility functions for working with shapes.
int PrintableCharCount(const wxString &aString)
Return the number of printable (ie: non-formatting) chars.
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
void OrientAndMirrorSymbolItems(LIB_SYMBOL *aSymbol, int aOrientation)
Rotate and/or mirror graphic objects of LIB_SYMBOL aSymbol according to aOrientMirror.
VECTOR2I center
int radius
VECTOR2I end
constexpr int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_H_ALIGN_INDETERMINATE
@ 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:229
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:521
@ SCH_GROUP_T
Definition: typeinfo.h:174
@ SCH_TABLE_T
Definition: typeinfo.h:166
@ SCH_LINE_T
Definition: typeinfo.h:164
@ LIB_SYMBOL_T
Definition: typeinfo.h:149
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:161
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
@ SCH_TABLECELL_T
Definition: typeinfo.h:167
@ SCH_FIELD_T
Definition: typeinfo.h:151
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:172
@ SCH_LABEL_T
Definition: typeinfo.h:168
@ SCH_SHEET_T
Definition: typeinfo.h:176
@ SCH_MARKER_T
Definition: typeinfo.h:159
@ SCH_SHAPE_T
Definition: typeinfo.h:150
@ SCH_RULE_AREA_T
Definition: typeinfo.h:171
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:170
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:163
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:175
@ SCH_TEXT_T
Definition: typeinfo.h:152
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:162
@ SCH_BITMAP_T
Definition: typeinfo.h:165
@ SCH_TEXTBOX_T
Definition: typeinfo.h:153
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:169
@ SCH_JUNCTION_T
Definition: typeinfo.h:160
@ SCH_PIN_T
Definition: typeinfo.h:154
constexpr int sign(T val)
Definition: util.h:159
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
VECTOR2< double > VECTOR2D
Definition: vector2d.h:694