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