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