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