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