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