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 <bitmap_base.h>
30#include <connection_graph.h>
32#include <callback_gal.h>
34#include <geometry/shape_rect.h>
36#include <gr_text.h>
37#include <sch_pin.h>
38#include <math/util.h>
39#include <pgm_base.h>
40#include <sch_bitmap.h>
41#include <sch_bus_entry.h>
42#include <sch_symbol.h>
43#include <sch_edit_frame.h>
44#include <sch_field.h>
45#include <sch_junction.h>
46#include <sch_line.h>
47#include <sch_shape.h>
48#include <sch_marker.h>
49#include <sch_no_connect.h>
50#include <sch_sheet.h>
51#include <sch_sheet_pin.h>
52#include <sch_text.h>
53#include <sch_textbox.h>
54#include <sch_table.h>
55#include <schematic.h>
57#include <view/view.h>
58#include <kiface_base.h>
59#include <default_values.h>
60#include <advanced_config.h>
62#include <stroke_params.h>
63#include "sch_painter.h"
64#include "common.h"
65
67
68namespace KIGFX
69{
70
72{
73 return dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
74}
75
76
77std::vector<KICAD_T> SCH_PAINTER::g_ScaledSelectionTypes = {
96};
97
98
113{
114 static LIB_SYMBOL* symbol;
115
116 if( !symbol )
117 {
118 symbol = new LIB_SYMBOL( wxEmptyString );
119
120 SCH_SHAPE* square = new SCH_SHAPE( SHAPE_T::RECTANGLE, LAYER_DEVICE );
121
122 square->SetPosition( VECTOR2I( schIUScale.MilsToIU( -200 ), schIUScale.MilsToIU( 200 ) ) );
123 square->SetEnd( VECTOR2I( schIUScale.MilsToIU( 200 ), schIUScale.MilsToIU( -200 ) ) );
124 symbol->AddDrawItem( square );
125
126 SCH_TEXT* text = new SCH_TEXT( { 0, 0 }, wxT( "??" ), LAYER_DEVICE );
127
128 text->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 150 ), schIUScale.MilsToIU( 150 ) ) );
129 symbol->AddDrawItem( text );
130 }
131
132 return symbol;
133}
134
135
137 KIGFX::PAINTER( aGal ),
138 m_schematic( nullptr )
139{ }
140
141
142bool SCH_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
143{
144 const EDA_ITEM* item = dynamic_cast<const EDA_ITEM*>( aItem );
145
146 if( !item )
147 return false;
148
149 draw( item, aLayer, false );
150
151 return false;
152}
153
154void SCH_PAINTER::draw( const EDA_ITEM* aItem, int aLayer, bool aDimmed )
155{
156
157#ifdef CONNECTIVITY_DEBUG
158
159 auto sch_item = dynamic_cast<const SCH_ITEM*>( aItem );
160 auto conn = sch_item ? sch_item->Connection( *g_CurrentSheet ) : nullptr;
161
162 if( conn )
163 {
164 auto pos = aItem->GetBoundingBox().Centre();
165 auto label = conn->Name( true );
166
170 m_gal->SetLineWidth( Mils2ui( 2 ) );
171 m_gal->SetGlyphSize( VECTOR2D( Mils2ui( 20 ), Mils2ui( 20 ) ) );
172 m_gal->StrokeText( *m_gal, conn->Name( true ), pos, 0.0, 0 );
173 }
174
175#endif
176
177 // Enable draw bounding box on request. Some bboxes are handled locally.
178 bool drawBoundingBox = m_schSettings.GetDrawBoundingBoxes();
179
180 switch( aItem->Type() )
181 {
182 case LIB_SYMBOL_T:
183 draw( static_cast<const LIB_SYMBOL*>( aItem ), aLayer );
184 break;
185 case SCH_PIN_T:
186 drawBoundingBox = false;
187 draw( static_cast<const SCH_PIN*>( aItem ), aLayer, aDimmed );
188 break;
189 case SCH_SYMBOL_T:
190 draw( static_cast<const SCH_SYMBOL*>( aItem ), aLayer );
191 break;
192 case SCH_JUNCTION_T:
193 draw( static_cast<const SCH_JUNCTION*>( aItem ), aLayer );
194 break;
195 case SCH_LINE_T:
196 draw( static_cast<const SCH_LINE*>( aItem ), aLayer );
197 break;
198 case SCH_SHAPE_T:
199 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
200 break;
201 case SCH_RULE_AREA_T:
202 draw( static_cast<const SCH_SHAPE*>( aItem ), aLayer, aDimmed );
203 break;
204 case SCH_TEXT_T:
205 draw( static_cast<const SCH_TEXT*>( aItem ), aLayer, aDimmed );
206 break;
207 case SCH_TEXTBOX_T:
208 draw( static_cast<const SCH_TEXTBOX*>( aItem ), aLayer, aDimmed );
209 break;
210 case SCH_TABLE_T:
211 draw( static_cast<const SCH_TABLE*>( aItem ), aLayer, aDimmed );
212 break;
213 case SCH_LABEL_T:
214 draw( static_cast<const SCH_LABEL*>( aItem ), aLayer );
215 break;
217 draw( static_cast<const SCH_DIRECTIVE_LABEL*>( aItem ), aLayer );
218 break;
219 case SCH_FIELD_T:
220 draw( static_cast<const SCH_FIELD*>( aItem ), aLayer, aDimmed );
221 break;
222 case SCH_HIER_LABEL_T:
223 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer, aDimmed );
224 break;
226 draw( static_cast<const SCH_GLOBALLABEL*>( aItem ), aLayer );
227 break;
228 case SCH_SHEET_T:
229 draw( static_cast<const SCH_SHEET*>( aItem ), aLayer );
230 break;
231 case SCH_SHEET_PIN_T:
232 draw( static_cast<const SCH_HIERLABEL*>( aItem ), aLayer, aDimmed );
233 break;
234 case SCH_NO_CONNECT_T:
235 draw( static_cast<const SCH_NO_CONNECT*>( aItem ), aLayer );
236 break;
238 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
239 break;
241 draw( static_cast<const SCH_BUS_ENTRY_BASE*>( aItem ), aLayer );
242 break;
243 case SCH_BITMAP_T:
244 draw( static_cast<const SCH_BITMAP*>( aItem ), aLayer );
245 break;
246 case SCH_MARKER_T:
247 draw( static_cast<const SCH_MARKER*>( aItem ), aLayer );
248 break;
249
250 default: return;
251 }
252
253 if( drawBoundingBox )
254 drawItemBoundingBox( aItem );
255}
256
257
259{
260 if( const SCH_ITEM* item = dynamic_cast<const SCH_ITEM*>( aItem ) )
261 {
262 if( item->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
263 return;
264 }
265
266 BOX2I box = aItem->GetBoundingBox();
267
268 if( aItem->Type() == SCH_SYMBOL_T )
269 box = static_cast<const SCH_SYMBOL*>( aItem )->GetBodyBoundingBox();
270
271 m_gal->SetIsFill( false );
272 m_gal->SetIsStroke( true );
273 m_gal->SetStrokeColor( aItem->IsSelected() ? COLOR4D( 1.0, 0.2, 0.2, 1 )
274 : COLOR4D( 0.2, 0.2, 0.2, 1 ) );
276 m_gal->DrawRectangle( box.GetOrigin(), box.GetEnd() );
277}
278
279
281{
282 // TODO: it would be nice to have a more definitive test for this, but we've currently got
283 // no access to the VIEW_GROUP to see if it's cached or not.
284 return aItem->IsSelected();
285}
286
287
289{
290 if( m_schSettings.m_ShowUnit // showing a specific unit
291 && aItem->GetUnit() // item is unit-specific
292 && aItem->GetUnit() != m_schSettings.m_ShowUnit )
293 {
294 return false;
295 }
296
297 if( m_schSettings.m_ShowBodyStyle // showing a specific body style
298 && aItem->GetBodyStyle() // item is body-style-specific
300 {
301 return false;
302 }
303
304 return true;
305}
306
307
309{
310 if( KIFONT::FONT* font = aItem->GetFont() )
311 return font;
312
314 aItem->IsItalic() );
315}
316
317
318float SCH_PAINTER::getShadowWidth( bool aForHighlight ) const
319{
320 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
321
322 int milsWidth = aForHighlight ? eeconfig()->m_Selection.highlight_thickness
324
325 // For best visuals the selection width must be a cross between the zoom level and the
326 // default line width.
327 return (float) std::fabs( matrix.GetScale().x * milsWidth ) + schIUScale.MilsToIU( milsWidth );
328}
329
330
331COLOR4D SCH_PAINTER::getRenderColor( const SCH_ITEM* aItem, int aLayer, bool aDrawingShadows,
332 bool aDimmed ) const
333{
335 // Graphic items of a SYMBOL frequently use the LAYER_DEVICE layer color
336 // (i.e. when no specific color is set)
337 bool isSymbolChild = aItem->GetParentSymbol() != nullptr;
338
340 {
341 if( aItem->Type() == SCH_LINE_T )
342 {
343 color = static_cast<const SCH_LINE*>( aItem )->GetLineColor();
344 }
345 else if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
346 {
347 color = static_cast<const SCH_BUS_WIRE_ENTRY*>( aItem )->GetBusEntryColor();
348 }
349 else if( aItem->Type() == SCH_JUNCTION_T )
350 {
351 color = static_cast<const SCH_JUNCTION*>( aItem )->GetJunctionColor();
352 }
353 else if( aItem->Type() == SCH_SHEET_T )
354 {
355 const SCH_SHEET* sheet = static_cast<const SCH_SHEET*>( aItem );
356
357 if( aLayer == LAYER_SHEET_BACKGROUND )
358 color = sheet->GetBackgroundColor();
359 else
360 color = sheet->GetBorderColor();
361 }
362 else if( aItem->Type() == SCH_SHAPE_T || aItem->Type() == SCH_RULE_AREA_T )
363 {
364 const SCH_SHAPE* shape = static_cast<const SCH_SHAPE*>( aItem );
365
366 if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
367 {
368 if( !isSymbolChild || shape->GetFillColor() != COLOR4D::UNSPECIFIED )
369 color = shape->GetFillColor();
370
371 if( isSymbolChild )
372 {
373 if( shape->GetFillMode() == FILL_T::FILLED_SHAPE )
374 color = shape->GetStroke().GetColor();
375 else if( shape->GetFillMode() == FILL_T::FILLED_WITH_BG_BODYCOLOR )
377 }
378 }
379 else
380 {
381 if( !isSymbolChild || shape->GetStroke().GetColor() != COLOR4D::UNSPECIFIED )
382 color = shape->GetStroke().GetColor();
383 }
384
385 // A filled shape means filled; if they didn't specify a fill colour then use the
386 // border colour.
388 {
389 if( aItem->Type() == SCH_RULE_AREA_T )
390 {
392 }
393 else
394 {
396 : LAYER_NOTES );
397 }
398 }
399 }
400 else if( aItem->IsType( { SCH_LABEL_LOCATE_ANY_T } ) )
401 {
402 color = static_cast<const SCH_LABEL_BASE*>( aItem )->GetLabelColor();
403 }
404 else if( aItem->Type() == SCH_FIELD_T )
405 {
406 color = static_cast<const SCH_FIELD*>( aItem )->GetFieldColor();
407 }
408 else if( aItem->Type() == SCH_TEXTBOX_T || aItem->Type() == SCH_TABLECELL_T )
409 {
410 const SCH_TEXTBOX* textBox = dynamic_cast<const SCH_TEXTBOX*>( aItem );
411
412 if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
413 color = textBox->GetFillColor();
414 else if( !isSymbolChild || textBox->GetTextColor() != COLOR4D::UNSPECIFIED )
415 color = textBox->GetTextColor();
416 }
417 else if( const EDA_TEXT* otherTextItem = dynamic_cast<const EDA_TEXT*>( aItem ) )
418 {
419 if( !isSymbolChild || otherTextItem->GetTextColor() != COLOR4D::UNSPECIFIED )
420 color = otherTextItem->GetTextColor();
421 }
422 }
423
425 color = m_schSettings.GetLayerColor( aLayer );
426
427 if( aItem->IsBrightened() ) // Selection disambiguation, net highlighting, etc.
428 {
429 color = m_schSettings.GetLayerColor( LAYER_BRIGHTENED );
430
431 if( aDrawingShadows )
432 {
433 if( aItem->IsSelected() )
434 color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
435 else
436 color = color.WithAlpha( 0.15 );
437 }
438 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_SHEET_BACKGROUND )
439 {
440 color = color.WithAlpha( 0.2 );
441 }
442 }
443 else if( aItem->IsSelected() && aDrawingShadows )
444 {
445 color = m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS );
446 }
447 else if( aItem->IsSelected() && ( aLayer == LAYER_DEVICE_BACKGROUND
448 || aLayer == LAYER_SHEET_BACKGROUND
449 || aLayer == LAYER_NOTES_BACKGROUND ) )
450 {
451 // Selected items will be painted over all other items, so make backgrounds translucent so
452 // that non-selected overlapping objects are visible
453 color = color.WithAlpha( 0.5 );
454 }
455
456 if( m_schSettings.m_ShowDisabled
457 || ( m_schSettings.m_ShowGraphicsDisabled && aItem->Type() != SCH_FIELD_T ) )
458 {
459 color = color.Darken( 0.5f );
460 }
461
462 if( aDimmed && !( aItem->IsSelected() && aDrawingShadows ) )
463 {
464 COLOR4D sheetColour = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
465 color.Desaturate();
466 color = color.Mix( sheetColour, 0.5f );
467 }
468
469 if( aItem->GetForcedTransparency() > 0.0 )
470 color = color.WithAlpha( color.a * ( 1.0 - aItem->GetForcedTransparency() ) );
471
472 return color;
473}
474
475
476float SCH_PAINTER::getLineWidth( const SCH_ITEM* aItem, bool aDrawingShadows,
477 bool aDrawingWireColorHighlights ) const
478{
479 wxCHECK( aItem, static_cast<float>( schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS ) ) );
480
481 int pen = aItem->GetEffectivePenWidth( &m_schSettings );
482 float width = pen;
483
484 if( aItem->IsBrightened() || aItem->IsSelected() )
485 {
486 if( aDrawingShadows && aItem->IsType( g_ScaledSelectionTypes ) )
487 width += getShadowWidth( aItem->IsBrightened() );
488 }
489
490 if( aDrawingWireColorHighlights )
491 {
492 float colorHighlightWidth = schIUScale.MilsToIU( 15.0 );
493 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
494
495 if( eeschemaCfg )
496 {
497 colorHighlightWidth = schIUScale.MilsToIU(
499 }
500
501 width += colorHighlightWidth;
502 }
503
504 return width;
505}
506
507
508float SCH_PAINTER::getTextThickness( const SCH_ITEM* aItem ) const
509{
510 int pen = m_schSettings.GetDefaultPenWidth();
511
512 switch( aItem->Type() )
513 {
514 case SCH_FIELD_T:
515 pen = static_cast<const SCH_FIELD*>( aItem )->GetEffectiveTextPenWidth( pen );
516 break;
517
518 case SCH_TEXT_T:
519 pen = static_cast<const SCH_TEXT*>( aItem )->GetEffectiveTextPenWidth( pen );
520 break;
521
522 case SCH_LABEL_T:
525 case SCH_HIER_LABEL_T:
526 case SCH_SHEET_PIN_T:
527 pen = static_cast<const SCH_LABEL_BASE*>( aItem )->GetEffectiveTextPenWidth( pen );
528 break;
529
530 case SCH_TEXTBOX_T:
531 case SCH_TABLECELL_T:
532 pen = static_cast<const SCH_TEXTBOX*>( aItem )->GetEffectiveTextPenWidth( pen );
533 break;
534
535 default:
536 UNIMPLEMENTED_FOR( aItem->GetClass() );
537 }
538
539 return (float) pen;
540}
541
542
543int SCH_PAINTER::getOperatingPointTextSize() const
544{
545 int docTextSize = schIUScale.MilsToIU( 50 );
546 int screenTextSize = std::abs( (int) m_gal->GetScreenWorldMatrix().GetScale().y * 7 );
547
548 // 66% zoom-relative
549 return KiROUND( ( docTextSize + screenTextSize * 2 ) / 3 );
550}
551
552
553static bool isFieldsLayer( int aLayer )
554{
555 return aLayer == LAYER_REFERENCEPART
556 || aLayer == LAYER_VALUEPART
557 || aLayer == LAYER_INTERSHEET_REFS
558 || aLayer == LAYER_NETCLASS_REFS
559 || aLayer == LAYER_FIELDS
560 || aLayer == LAYER_SHEETNAME
561 || aLayer == LAYER_SHEETFILENAME
562 || aLayer == LAYER_SHEETFIELDS;
563}
564
565
566static BOX2I GetTextExtents( const wxString& aText, const VECTOR2D& aPosition, KIFONT::FONT& aFont,
567 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
568{
569 const VECTOR2I extents =
570 aFont.StringBoundaryLimits( aText, aAttrs.m_Size, aAttrs.m_StrokeWidth, aAttrs.m_Bold,
571 aAttrs.m_Italic, aFontMetrics );
572 BOX2I box( aPosition, VECTOR2I( extents.x, aAttrs.m_Size.y ) );
573
574 switch( aAttrs.m_Halign )
575 {
576 case GR_TEXT_H_ALIGN_LEFT: break;
577 case GR_TEXT_H_ALIGN_CENTER: box.SetX( box.GetX() - box.GetWidth() / 2 ); break;
578 case GR_TEXT_H_ALIGN_RIGHT: box.SetX( box.GetX() - box.GetWidth() ); break;
579 case GR_TEXT_H_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
580 }
581
582 switch( aAttrs.m_Valign )
583 {
584 case GR_TEXT_V_ALIGN_TOP: break;
585 case GR_TEXT_V_ALIGN_CENTER: box.SetY( box.GetY() - box.GetHeight() / 2 ); break;
586 case GR_TEXT_V_ALIGN_BOTTOM: box.SetY( box.GetY() - box.GetHeight() ); break;
587 case GR_TEXT_V_ALIGN_INDETERMINATE: wxFAIL_MSG( wxT( "Legal only in dialogs" ) ); break;
588 }
589
590 box.Normalize(); // Make h and v sizes always >= 0
591 box = box.GetBoundingBoxRotated( aPosition, aAttrs.m_Angle );
592
593 return box;
594}
595
596
597static void strokeText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
598 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
599{
600 KIFONT::FONT* font = aAttrs.m_Font;
601
602 if( !font )
603 {
604 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
605 aAttrs.m_Italic );
606 }
607
608 aGal.SetIsFill( font->IsOutline() );
609 aGal.SetIsStroke( font->IsStroke() );
610
611 font->Draw( &aGal, aText, aPosition, aAttrs, aFontMetrics );
612}
613
614
615static void bitmapText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
616 const TEXT_ATTRIBUTES& aAttrs )
617{
618 // Bitmap font has different metrics from the stroke font so we compensate a bit before
619 // stroking
620 aGal.SetGlyphSize( VECTOR2I( aAttrs.m_Size.x, KiROUND( aAttrs.m_Size.y * 1.05 ) ) );
621 aGal.SetLineWidth( (float) aAttrs.m_StrokeWidth * 1.35f );
622
623 aGal.SetHorizontalJustify( aAttrs.m_Halign );
624 aGal.SetVerticalJustify( aAttrs.m_Valign );
625
626 aGal.BitmapText( aText, aPosition, aAttrs.m_Angle );
627}
628
629
630static void knockoutText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
631 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
632{
633 TEXT_ATTRIBUTES attrs( aAttrs );
634 KIFONT::FONT* font = aAttrs.m_Font;
635
636 if( !font )
637 {
638 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, attrs.m_Bold,
639 attrs.m_Italic );
640 }
641
643 SHAPE_POLY_SET knockouts;
644
645 CALLBACK_GAL callback_gal( empty_opts,
646 // Polygon callback
647 [&]( const SHAPE_LINE_CHAIN& aPoly )
648 {
649 knockouts.AddOutline( aPoly );
650 } );
651
652 callback_gal.SetIsFill( false );
653 callback_gal.SetIsStroke( true );
654 callback_gal.SetLineWidth( (float) attrs.m_StrokeWidth );
655 font->Draw( &callback_gal, aText, aPosition, attrs, aFontMetrics );
656
657 BOX2I bbox = knockouts.BBox( attrs.m_StrokeWidth * 2 );
658 SHAPE_POLY_SET finalPoly;
659
660 finalPoly.NewOutline();
661 finalPoly.Append( bbox.GetLeft(), bbox.GetTop() );
662 finalPoly.Append( bbox.GetRight(), bbox.GetTop() );
663 finalPoly.Append( bbox.GetRight(), bbox.GetBottom() );
664 finalPoly.Append( bbox.GetLeft(), bbox.GetBottom() );
665
666 finalPoly.BooleanSubtract( knockouts, SHAPE_POLY_SET::PM_FAST );
668
669 aGal.SetIsStroke( false );
670 aGal.SetIsFill( true );
671 aGal.SetFillColor( attrs.m_Color );
672 aGal.DrawPolygon( finalPoly );
673}
674
675
676static void boxText( KIGFX::GAL& aGal, const wxString& aText, const VECTOR2D& aPosition,
677 const TEXT_ATTRIBUTES& aAttrs, const KIFONT::METRICS& aFontMetrics )
678{
679 KIFONT::FONT* font = aAttrs.m_Font;
680
681 if( !font )
682 {
683 font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font, aAttrs.m_Bold,
684 aAttrs.m_Italic );
685 }
686
687 BOX2I box = GetTextExtents( aText, aPosition, *font, aAttrs, aFontMetrics );
688
689 // Give the highlight a bit of margin.
690 box.Inflate( 0, aAttrs.m_StrokeWidth * 2 );
691
692 aGal.SetIsFill( true );
693 aGal.SetIsStroke( false );
694 aGal.DrawRectangle( box.GetOrigin(), box.GetEnd() );
695}
696
697
698void SCH_PAINTER::triLine( const VECTOR2D& a, const VECTOR2D& b, const VECTOR2D& c )
699{
700 m_gal->DrawLine( a, b );
701 m_gal->DrawLine( b, c );
702}
703
704
705void SCH_PAINTER::draw( const LIB_SYMBOL* aSymbol, int aLayer, bool aDrawFields, int aUnit,
706 int aBodyStyle, bool aDimmed )
707{
708 if( !aUnit )
709 aUnit = m_schSettings.m_ShowUnit;
710
711 if( !aBodyStyle )
712 aBodyStyle = m_schSettings.m_ShowBodyStyle;
713
714 std::unique_ptr< LIB_SYMBOL > tmpSymbol;
715 const LIB_SYMBOL* drawnSymbol = aSymbol;
716
717 if( aSymbol->IsAlias() )
718 {
719 tmpSymbol = aSymbol->Flatten();
720 drawnSymbol = tmpSymbol.get();
721 }
722
723 // The parent must exist on the union of all its children's draw layers. But that doesn't
724 // mean we want to draw each child on the union.
725 auto childOnLayer =
726 []( const SCH_ITEM& item, int layer )
727 {
728 int layers[512], layers_count;
729 item.ViewGetLayers( layers, layers_count );
730
731 for( int ii = 0; ii < layers_count; ++ii )
732 {
733 if( layers[ii] == layer )
734 return true;
735 }
736
737 return false;
738 };
739
740 for( const SCH_ITEM& item : drawnSymbol->GetDrawItems() )
741 {
742 if( !aDrawFields && item.Type() == SCH_FIELD_T )
743 continue;
744
745 if( !childOnLayer( item, aLayer ) )
746 continue;
747
748 if( aUnit && item.GetUnit() && aUnit != item.GetUnit() )
749 continue;
750
751 if( aBodyStyle && item.GetBodyStyle() && aBodyStyle != item.GetBodyStyle() )
752 continue;
753
754 draw( &item, aLayer, aDimmed );
755 }
756}
757
758
759int SCH_PAINTER::internalPinDecoSize( const SCH_PIN &aPin )
760{
761 if( m_schSettings.m_PinSymbolSize > 0 )
762 return m_schSettings.m_PinSymbolSize;
763
764 return aPin.GetNameTextSize() != 0 ? aPin.GetNameTextSize() / 2 : aPin.GetNumberTextSize() / 2;
765}
766
767
768// Utility for getting the size of the 'external' pin decorators (as a radius)
769// i.e. the negation circle, the polarity 'slopes' and the nonlogic marker
770int SCH_PAINTER::externalPinDecoSize( const SCH_PIN &aPin )
771{
772 if( m_schSettings.m_PinSymbolSize > 0 )
773 return m_schSettings.m_PinSymbolSize;
774
775 return aPin.GetNumberTextSize() / 2;
776}
777
778
779// Draw the target (an open circle) for a pin which has no connection or is being moved.
780void SCH_PAINTER::drawPinDanglingIndicator( const VECTOR2I& aPos, const COLOR4D& aColor,
781 bool aDrawingShadows, bool aBrightened )
782{
783 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
784 // they overlap with a junction dot.
785 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
786
787 m_gal->SetIsFill( false );
788 m_gal->SetIsStroke( true );
789 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( aBrightened )
790 : m_schSettings.GetDanglingIndicatorThickness() );
791
792 m_gal->DrawCircle( aPos, TARGET_PIN_RADIUS );
793}
794
795
799static void drawAltPinModesIcon( GAL& aGal, const VECTOR2D& aPos, double aSize, bool aBaseSelected,
800 bool aRotate, int aExtraLineWidth, const COLOR4D& aColor )
801{
802 aGal.Save();
803
804 aGal.Translate( aPos );
805 if( aRotate )
806 {
807 aGal.Rotate( ANGLE_270.AsRadians() );
808 }
809
810 aGal.SetIsFill( false );
811 aGal.SetIsStroke( true );
812 aGal.SetLineWidth( KiROUND( aSize / 10.0 + aExtraLineWidth ) );
813 aGal.SetStrokeColor( aColor );
814
815 /*
816 * ----------->
817 * + <--center
818 * \------->
819 *
820 * or
821 *
822 * ----- ---->
823 * \
824 * \------>
825 */
826
827 const double lineYOffset = aSize / 4;
828 const double arrowHead = aSize / 8;
829
830 const VECTOR2D topLineREnd = VECTOR2D{ aSize / 2, -lineYOffset };
831 const VECTOR2D btmLineREnd = VECTOR2D{ aSize / 2, lineYOffset };
832
833 // Top line and arrowhead
834 if( aBaseSelected )
835 {
836 // Full top line
837 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ aSize, 0 } );
838 }
839 else
840 {
841 // Line with a gap
842 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ aSize / 2, 0 } );
843 aGal.DrawLine( topLineREnd - VECTOR2D{ aSize, 0 },
844 topLineREnd - VECTOR2D{ aSize * 0.7, 0 } );
845 }
846 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ arrowHead * 1.2, arrowHead } );
847 aGal.DrawLine( topLineREnd, topLineREnd - VECTOR2D{ arrowHead * 1.2, -arrowHead } );
848
849 // Bottom line and arrowhead
850 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ aSize / 2, 0 } );
851 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ arrowHead * 1.2, arrowHead } );
852 aGal.DrawLine( btmLineREnd, btmLineREnd - VECTOR2D{ arrowHead * 1.2, -arrowHead } );
853
854 // Top and bottom 'S' arcs
855 if( !aBaseSelected )
856 {
857 aGal.DrawArc( topLineREnd - VECTOR2D{ aSize, -lineYOffset },
858 lineYOffset, ANGLE_0, -ANGLE_90 );
859 }
860 aGal.DrawArc( topLineREnd - VECTOR2D{ aSize - lineYOffset * 2, -lineYOffset },
861 lineYOffset, ANGLE_180, -ANGLE_90 );
862
863 aGal.Restore();
864};
865
866
872{
873public:
874
879 const KIFONT::METRICS& aFontMetrics, const double aShadowWidth,
880 const double aIconSize = 0 ) :
881 m_gal( aGal ), m_attrs( aAttrs ), m_fontMetrics( aFontMetrics ),
882 m_iconSize( aIconSize ), m_iconGap( aIconSize / 4.0 ), m_shadowWidth( aShadowWidth )
883 {
884 // Due to the fact a shadow text in position INSIDE or OUTSIDE is drawn left or right aligned,
885 // it needs an offset = shadowWidth/2 to be drawn at the same place as normal text
886 // texts drawn as GR_TEXT_H_ALIGN_CENTER do not need a specific offset.
887 // this offset is shadowWidth/2 but for some reason we need to slightly modify this offset
888 // for a better look (better alignment of shadow shape), for KiCad font only
889 if( !KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font )->IsOutline() )
890 {
891 const float adjust = 1.2f; // Value chosen after tests
892 m_shadowOffset = m_shadowWidth / 2.0f * adjust;
893 }
894 }
895
897 {
898 // Adjusted text pos to include shadow offsets
901 std::vector<VECTOR2I> IconPos;
902 };
903
910 LOCATIONS getTextLayout( const wxString& aText, const VECTOR2I& aPos,
911 GR_TEXT_H_ALIGN_T aIconSide, std::size_t aNIcons, bool aDrawShadow )
912 {
913 LOCATIONS locs{
914 aPos,
915 aPos,
916 {},
917 };
918
919 BOX2I extents = GetTextExtents( aText, aPos, *m_attrs.m_Font, m_attrs, m_fontMetrics );
920
922
923 if( m_attrs.m_Angle == ANGLE_HORIZONTAL )
924 {
925 if( aIconSide == GR_TEXT_H_ALIGN_LEFT )
926 iconDir = DIRECTION_45::W;
927 else
928 iconDir = DIRECTION_45::E;
929 }
930 else
931 {
932 if( aIconSide == GR_TEXT_H_ALIGN_LEFT )
933 iconDir = DIRECTION_45::S;
934 else
935 iconDir = DIRECTION_45::N;
936 }
937
938 int offset = m_iconSize / 2 + m_iconGap;
939 for( std::size_t i = 0; i < aNIcons; ++i )
940 {
941 locs.IconPos.push_back( KIGEOM::GetPoint( extents, iconDir, offset ) );
942 offset += m_iconGap + m_iconSize;
943 }
944
945 // Apply shadow offsets
946 if( m_attrs.m_Halign != GR_TEXT_H_ALIGN_CENTER )
947 {
948 if( m_attrs.m_Angle == ANGLE_HORIZONTAL )
949 {
950 locs.ShadowPos.x -=
951 m_shadowOffset * ( m_attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT ? 1 : -1 );
952 }
953 else
954 {
955 locs.ShadowPos.y +=
956 m_shadowOffset * ( m_attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT ? 1 : -1 );
957 }
958 }
959
960 return locs;
961 }
962
963private:
968 double m_iconGap;
971};
972
973
983{
984public:
986 {
991 };
992
993 enum class SLOT_ROLE
994 {
995 NAME = 0,
996 NUMBER,
997 ELECTRICAL_TYPE,
998 };
999
1000 // Information about the placement of a single text label for a pin
1001 // This is independent of the actual text content.
1003 {
1004 // Nominal text anchor position
1006 // Text alignment relative to anchor
1009 // H/V text?
1011 // Is the icon on the left or right (in the text axis)?
1013 };
1014
1015 struct SLOT
1016 {
1018 size( 0 ),
1019 thickness( 0 ),
1020 colour( COLOR4D::UNSPECIFIED ),
1021 role( SLOT_ROLE::NAME )
1022 {
1023 }
1024
1025 const bool ShouldDraw() const
1026 {
1027 return size > 0 && colour != COLOR4D::UNSPECIFIED && !text.IsEmpty();
1028 }
1029
1030 int size;
1033 wxString text;
1035 };
1036
1037 PIN_TEXTS( const SCH_PIN& aPin, float aPenWidth, float aPinTextMargin ) :
1038 m_pin( aPin ), m_offsets{ 0, 0, 0, 0 }, m_penWidth( aPenWidth ),
1039 m_pinTextMargin( aPinTextMargin )
1040 {
1041 }
1042
1043 // Const slot iterator
1044 using const_iterator = std::array<SLOT, 4>::const_iterator;
1045
1046 const_iterator begin() const { return m_slots.begin(); }
1047
1048 const_iterator end() const { return m_slots.end(); }
1049
1050 SLOT& GetSlot( SLOT_ID aSlot ) { return m_slots[aSlot]; }
1051 const SLOT& GetSlot( SLOT_ID aSlot ) const { return m_slots[aSlot]; }
1052
1053 const void ComputeOffsets()
1054 {
1055 float textOffset = m_pin.GetParentSymbol()->GetPinNameOffset();
1056
1057 m_offsets[INSIDE] = textOffset - m_slots[INSIDE].thickness / 2.0;
1058 m_offsets[OUTSIDE] = m_pinTextMargin + TARGET_PIN_RADIUS - m_slots[OUTSIDE].thickness / 2.0;
1059 m_offsets[ABOVE] = m_pinTextMargin + m_penWidth / 2.0 + m_slots[ABOVE].thickness / 2.0;
1060 m_offsets[BELOW] = m_pinTextMargin + m_penWidth / 2.0 + m_slots[BELOW].thickness / 2.0;
1061
1062 if( m_pin.IsDangling() )
1063 m_offsets[OUTSIDE] += TARGET_PIN_RADIUS / 2.0f;
1064 }
1065
1066 bool SlotRendersAsBitmap( const SLOT& aSlot, KIGFX::GAL& aGal ) const
1067 {
1068 // Rendering text is expensive (particularly when using outline fonts). At small effective
1069 // sizes (ie: zoomed out) the visual differences between outline and/or stroke fonts and the
1070 // bitmap font becomes immaterial, and there's often more to draw when zoomed out so the
1071 // performance gain becomes more significant.
1072 static const float BITMAP_FONT_SIZE_THRESHOLD = 3.5;
1073
1074 // Any text non bitmappable?
1075 return aSlot.size * aGal.GetWorldScale() < BITMAP_FONT_SIZE_THRESHOLD;
1076 }
1077
1081 void SetColorOverride( const COLOR4D& aColor )
1082 {
1083 for( SLOT& slot : m_slots )
1084 {
1085 slot.colour = aColor;
1086 }
1087 }
1088
1090 PIN_ORIENTATION aPinOrientation ) const
1091 {
1092 // Work out which slot it is
1093 SLOT_ID slotId = INSIDE;
1094 for( int i = 0; i < 4; ++i )
1095 {
1096 if( &aSlot == &m_slots[i] )
1097 {
1098 slotId = static_cast<SLOT_ID>( i );
1099 break;
1100 }
1101 // Should not pass a slot that isn't in the list
1102 wxASSERT( i < 4 );
1103 }
1104
1105 TEXT_PLACEMENT placement;
1106 const float len = m_pin.GetLength();
1107
1108 // For PIN_LEFT
1109 switch( slotId )
1110 {
1111 case PIN_TEXTS::SLOT_ID::INSIDE:
1112 placement = {
1113 VECTOR2D( -m_offsets[INSIDE] - len, 0 ),
1118 };
1119 break;
1120 case PIN_TEXTS::SLOT_ID::OUTSIDE:
1121 placement = {
1122 VECTOR2D( m_offsets[OUTSIDE], 0 ),
1127 };
1128 break;
1129 case PIN_TEXTS::SLOT_ID::ABOVE:
1130 placement = {
1131 VECTOR2D( -len / 2.0, -m_offsets[ABOVE] ),
1136 };
1137 break;
1138 case PIN_TEXTS::SLOT_ID::BELOW:
1139 placement = {
1140 VECTOR2D( -len / 2.0, m_offsets[BELOW] ),
1145 };
1146 break;
1147 }
1148
1149 switch( aPinOrientation )
1150 {
1151 case PIN_ORIENTATION::PIN_LEFT:
1152 break;
1153 case PIN_ORIENTATION::PIN_RIGHT:
1154 placement.Pos = { -placement.Pos.x, placement.Pos.y };
1155 placement.HAlign = GetFlippedAlignment( placement.HAlign );
1156 placement.IconSide = GetFlippedAlignment( placement.IconSide );
1157 break;
1158 case PIN_ORIENTATION::PIN_UP:
1159 placement.Pos = { placement.Pos.y, placement.Pos.x };
1160 placement.Angle = ANGLE_VERTICAL;
1161 placement.HAlign = GetFlippedAlignment( placement.HAlign );
1162 placement.IconSide = GetFlippedAlignment( placement.IconSide );
1163 break;
1164 case PIN_ORIENTATION::PIN_DOWN:
1165 placement.Pos = { placement.Pos.y, -placement.Pos.x };
1166 placement.Angle = ANGLE_VERTICAL;
1167 break;
1168 case PIN_ORIENTATION::INHERIT:
1169 wxFAIL_MSG( "Unknown pin orientation" );
1170 break;
1171 }
1172
1173 placement.Pos += m_pin.GetPosition();
1174 return placement;
1175 };
1176
1177private:
1179 std::array<SLOT, 4> m_slots;
1180 std::array<int, 4> m_offsets;
1181 const float m_penWidth;
1182 const float m_pinTextMargin;
1183};
1184
1185
1186void SCH_PAINTER::draw( const SCH_PIN* aPin, int aLayer, bool aDimmed )
1187{
1188 // Don't draw pins from a selection view-group. Pins in a schematic must always be drawn
1189 // from their parent symbol's m_part.
1190 if( dynamic_cast<const SCH_SYMBOL*>( aPin->GetParentSymbol() ) )
1191 return;
1192
1193 if( !isUnitAndConversionShown( aPin ) )
1194 return;
1195
1196 const bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1197
1198 if( m_schSettings.IsPrinting() && drawingShadows )
1199 return;
1200
1201 const bool drawingDangling = aLayer == LAYER_DANGLING;
1202 const bool drawingOP = aLayer == LAYER_OP_CURRENTS;
1203 const bool isDangling = m_schSettings.m_IsSymbolEditor || aPin->HasFlag( IS_DANGLING );
1204
1205 if( drawingShadows && !( aPin->IsBrightened() || aPin->IsSelected() ) )
1206 return;
1207
1208 const VECTOR2I pos = aPin->GetPosition();
1209 COLOR4D color = getRenderColor( aPin, LAYER_PIN, drawingShadows, aDimmed );
1210
1211 if( !aPin->IsVisible() )
1212 {
1213 if( m_schSettings.IsPrinting() )
1214 return;
1215
1216 bool force_show = m_schematic ? eeconfig()->m_Appearance.show_hidden_pins
1217 : m_schSettings.m_ShowHiddenPins;
1218
1219 if( force_show )
1220 {
1221 color = getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed );
1222 }
1223 else
1224 {
1225 if( drawingDangling && isDangling && aPin->IsGlobalPower() )
1226 drawPinDanglingIndicator( pos, color, drawingShadows, aPin->IsBrightened() );
1227
1228 return;
1229 }
1230 }
1231
1232 if( drawingDangling )
1233 {
1234 if( isDangling )
1235 drawPinDanglingIndicator( pos, color, drawingShadows, aPin->IsBrightened() );
1236
1237 return;
1238 }
1239
1240 if( m_schSettings.GetDrawBoundingBoxes() )
1241 drawItemBoundingBox( aPin );
1242
1243 const VECTOR2I p0 = aPin->GetPinRoot();
1244 const VECTOR2I dir( sign( pos.x - p0.x ), sign( pos.y - p0.y ) );
1245 const int len = aPin->GetLength();
1246
1247 if( drawingOP && !aPin->GetOperatingPoint().IsEmpty() )
1248 {
1249 int textSize = getOperatingPointTextSize();
1250 VECTOR2I mid = ( p0 + pos ) / 2;
1251 int textOffset = KiROUND( textSize * 0.22 );
1252 TEXT_ATTRIBUTES attrs;
1253
1254 if( len > textSize )
1255 {
1256 if( dir.x == 0 )
1257 {
1258 mid.x += KiROUND( textOffset * 1.2 );
1259 attrs.m_Angle = ANGLE_HORIZONTAL;
1260 }
1261 else
1262 {
1263 mid.y -= KiROUND( textOffset * 1.2 );
1264 attrs.m_Angle = ANGLE_VERTICAL;
1265 }
1266
1269
1270 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
1271 attrs.m_Size = VECTOR2I( textSize, textSize );
1272 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
1273 attrs.m_Color = m_schSettings.GetLayerColor( LAYER_OP_CURRENTS );
1274
1275 knockoutText( *m_gal, aPin->GetOperatingPoint(), mid, attrs, aPin->GetFontMetrics() );
1276 }
1277 }
1278
1279 if( drawingOP )
1280 return;
1281
1282 VECTOR2D pc;
1283
1284 m_gal->SetIsStroke( true );
1285 m_gal->SetIsFill( false );
1286 m_gal->SetLineWidth( getLineWidth( aPin, drawingShadows ) );
1287 m_gal->SetStrokeColor( color );
1288 m_gal->SetFontBold( false );
1289 m_gal->SetFontUnderlined( false );
1290 m_gal->SetFontItalic( false );
1291
1292 const int radius = externalPinDecoSize( *aPin );
1293 const int diam = radius*2;
1294 const int clock_size = internalPinDecoSize( *aPin );
1295
1296 if( aPin->GetType() == ELECTRICAL_PINTYPE::PT_NC ) // Draw a N.C. symbol
1297 {
1298 m_gal->DrawLine( p0, pos );
1299
1300 m_gal->DrawLine( pos + VECTOR2D( -1, -1 ) * TARGET_PIN_RADIUS,
1301 pos + VECTOR2D( 1, 1 ) * TARGET_PIN_RADIUS );
1302 m_gal->DrawLine( pos + VECTOR2D( 1, -1 ) * TARGET_PIN_RADIUS ,
1303 pos + VECTOR2D( -1, 1 ) * TARGET_PIN_RADIUS );
1304 }
1305 else
1306 {
1307 switch( aPin->GetShape() )
1308 {
1309 default:
1311 m_gal->DrawLine( p0, pos );
1312 break;
1313
1315 m_gal->DrawCircle( p0 + dir * radius, radius );
1316 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1317 break;
1318
1320 pc = p0 - dir * clock_size ;
1321
1322 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1323 pc,
1324 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1325
1326 m_gal->DrawCircle( p0 + dir * radius, radius );
1327 m_gal->DrawLine( p0 + dir * ( diam ), pos );
1328 break;
1329
1332 pc = p0 - dir * clock_size ;
1333
1334 triLine( p0 + VECTOR2D( dir.y, -dir.x) * clock_size,
1335 pc,
1336 p0 + VECTOR2D( -dir.y, dir.x) * clock_size );
1337
1338 if( !dir.y )
1339 {
1340 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1341 p0 + VECTOR2D(dir.x, -1) * diam,
1342 p0 );
1343 }
1344 else /* MapX1 = 0 */
1345 {
1346 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1347 p0 + VECTOR2D(-1, dir.y) * diam,
1348 p0 );
1349 }
1350
1351 m_gal->DrawLine( p0, pos );
1352 break;
1353
1355 m_gal->DrawLine( p0, pos );
1356
1357 if( !dir.y )
1358 {
1359 triLine( p0 + VECTOR2D( 0, clock_size ),
1360 p0 + VECTOR2D( -dir.x * clock_size, 0 ),
1361 p0 + VECTOR2D( 0, -clock_size ) );
1362 }
1363 else
1364 {
1365 triLine( p0 + VECTOR2D( clock_size, 0 ),
1366 p0 + VECTOR2D( 0, -dir.y * clock_size ),
1367 p0 + VECTOR2D( -clock_size, 0 ) );
1368 }
1369 break;
1370
1372 m_gal->DrawLine( p0, pos );
1373
1374 if( !dir.y )
1375 {
1376 triLine( p0 + VECTOR2D(dir.x, 0) * diam,
1377 p0 + VECTOR2D(dir.x, -1) * diam,
1378 p0 );
1379 }
1380 else /* MapX1 = 0 */
1381 {
1382 triLine( p0 + VECTOR2D( 0, dir.y) * diam,
1383 p0 + VECTOR2D(-1, dir.y) * diam,
1384 p0 );
1385 }
1386 break;
1387
1388 case GRAPHIC_PINSHAPE::OUTPUT_LOW: // IEEE symbol "Active Low Output"
1389 m_gal->DrawLine( p0, pos );
1390
1391 if( !dir.y ) // Horizontal pin
1392 m_gal->DrawLine( p0 - VECTOR2D( 0, diam ), p0 + VECTOR2D( dir.x, 0 ) * diam );
1393 else // Vertical pin
1394 m_gal->DrawLine( p0 - VECTOR2D( diam, 0 ), p0 + VECTOR2D( 0, dir.y ) * diam );
1395 break;
1396
1397 case GRAPHIC_PINSHAPE::NONLOGIC: // NonLogic pin symbol
1398 m_gal->DrawLine( p0, pos );
1399
1400 m_gal->DrawLine( p0 - VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius,
1401 p0 + VECTOR2D( dir.x + dir.y, dir.y - dir.x ) * radius );
1402 m_gal->DrawLine( p0 - VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius,
1403 p0 + VECTOR2D( dir.x - dir.y, dir.x + dir.y ) * radius );
1404 break;
1405 }
1406 }
1407
1408 if( drawingShadows && !eeconfig()->m_Selection.draw_selected_children )
1409 return;
1410
1411 // Draw the labels
1412 const SYMBOL* symbol = aPin->GetParentSymbol();
1413 float penWidth = (float) m_schSettings.GetDefaultPenWidth();
1414 float nameStrokeWidth = getLineWidth( aPin, false );
1415 float numStrokeWidth = getLineWidth( aPin, false );
1416 bool showPinNames = symbol->GetShowPinNames();
1417 bool showPinNumbers = m_schSettings.m_ShowPinNumbers || symbol->GetShowPinNumbers();
1418
1419 nameStrokeWidth = Clamp_Text_PenSize( nameStrokeWidth, aPin->GetNameTextSize(), true );
1420 numStrokeWidth = Clamp_Text_PenSize( numStrokeWidth, aPin->GetNumberTextSize(), true );
1421
1422 float PIN_TEXT_MARGIN = schIUScale.MilsToIU( KiROUND( 24 * m_schSettings.m_TextOffsetRatio ) );
1423
1424 PIN_TEXTS pinTexts( *aPin, penWidth, PIN_TEXT_MARGIN );
1425
1426 const auto assignNameToSlot = [&]( PIN_TEXTS::SLOT_ID aSlot )
1427 {
1428 PIN_TEXTS::SLOT& slot = pinTexts.GetSlot( aSlot );
1429 slot.size = aPin->GetNameTextSize();
1430 slot.thickness = nameStrokeWidth;
1431 slot.colour = getRenderColor( aPin, LAYER_PINNAM, drawingShadows, aDimmed );
1432 slot.text = aPin->GetShownName();
1433 slot.role = PIN_TEXTS::SLOT_ROLE::NAME;
1434 };
1435
1436 const auto assignNumberToSlot = [&]( PIN_TEXTS::SLOT_ID aSlot )
1437 {
1438 PIN_TEXTS::SLOT& slot = pinTexts.GetSlot( aSlot );
1439 slot.size = aPin->GetNumberTextSize();
1440 slot.thickness = numStrokeWidth;
1441 slot.colour = getRenderColor( aPin, LAYER_PINNUM, drawingShadows, aDimmed );
1442 slot.text = aPin->GetShownNumber();
1443 slot.role = PIN_TEXTS::SLOT_ROLE::NUMBER;
1444 };
1445
1446 // TextOffset > 0 means pin NAMES on inside, pin NUMBERS above and nothing below
1447 if( symbol->GetPinNameOffset() > 0 )
1448 {
1449 if( showPinNames )
1450 assignNameToSlot( PIN_TEXTS::SLOT_ID::INSIDE );
1451 if( showPinNumbers )
1452 assignNumberToSlot( PIN_TEXTS::SLOT_ID::ABOVE );
1453 }
1454 // Otherwise if both are shown pin NAMES go above and pin NUMBERS go below
1455 else if( showPinNames && showPinNumbers )
1456 {
1457 assignNameToSlot( PIN_TEXTS::SLOT_ID::ABOVE );
1458 assignNumberToSlot( PIN_TEXTS::SLOT_ID::BELOW );
1459 }
1460 else if( showPinNames )
1461 {
1462 assignNameToSlot( PIN_TEXTS::SLOT_ID::ABOVE );
1463 }
1464 else if( showPinNumbers )
1465 {
1466 assignNumberToSlot( PIN_TEXTS::SLOT_ID::ABOVE );
1467 }
1468
1469 if( m_schSettings.m_ShowPinsElectricalType )
1470 {
1471 PIN_TEXTS::SLOT& outside = pinTexts.GetSlot( PIN_TEXTS::SLOT_ID::OUTSIDE );
1472 outside.size = std::max( aPin->GetNameTextSize() * 3 / 4, schIUScale.mmToIU( 0.7 ) );
1473 outside.thickness = float( outside.size ) / 8.0f;
1474 outside.colour = getRenderColor( aPin, LAYER_PRIVATE_NOTES, drawingShadows, aDimmed );
1475 outside.text = aPin->GetElectricalTypeName();
1476 outside.role = PIN_TEXTS::SLOT_ROLE::ELECTRICAL_TYPE;
1477 }
1478
1479 // Now we have set the slot content, we can compute things
1480 pinTexts.ComputeOffsets();
1481
1482 if( !aPin->IsVisible() )
1483 {
1484 pinTexts.SetColorOverride( getRenderColor( aPin, LAYER_HIDDEN, drawingShadows, aDimmed ) );
1485 }
1486
1487 float shadowWidth = 0.0f;
1488
1489 if( drawingShadows )
1490 {
1491 shadowWidth = getShadowWidth( aPin->IsBrightened() );
1492 }
1493
1494 // Draw one text slot, either "real" or the shadow
1495 const auto drawText = [&]( const PIN_TEXTS::SLOT& slot )
1496 {
1497 if( !slot.ShouldDraw() )
1498 return;
1499
1500 const double iconSize = std::min( aPin->GetNameTextSize(), schIUScale.mmToIU( 1.5 ) );
1501 const bool renderTextAsBitmap = pinTexts.SlotRendersAsBitmap( slot, *m_gal );
1502
1503 const PIN_TEXTS::TEXT_PLACEMENT placement =
1504 pinTexts.GetTextPlacement( slot, aPin->GetOrientation() );
1505
1506 // Which of these gets used depends on the font technology, so set both
1507 m_gal->SetStrokeColor( slot.colour );
1508 m_gal->SetFillColor( slot.colour );
1509
1510 TEXT_ATTRIBUTES attrs;
1511 attrs.m_Font = KIFONT::FONT::GetFont( eeconfig()->m_Appearance.default_font );
1512 attrs.m_Size = VECTOR2I( slot.size, slot.size );
1513 attrs.m_Halign = placement.HAlign;
1514 attrs.m_Valign = placement.VAlign;
1515 attrs.m_Angle = placement.Angle;
1516 attrs.m_StrokeWidth = KiROUND( slot.thickness );
1517
1518 // This object (and a quite lot of other code here) could actually be
1519 // re-used - probably many pins will use these exact parameters. But pin
1520 // paints are already cached, so it's unlikely to be much help.
1521 TEXT_AND_ICON_LAYOUT tiLayout( *m_gal, attrs, aPin->GetFontMetrics(), shadowWidth,
1522 iconSize );
1523
1525 slot.text, placement.Pos, placement.IconSide, 1, drawingShadows );
1526
1527 if( drawingShadows )
1528 {
1529 attrs.m_StrokeWidth += KiROUND( shadowWidth );
1530
1531 if( !attrs.m_Font->IsOutline() )
1532 {
1533 strokeText( *m_gal, slot.text, locs.ShadowPos, attrs, aPin->GetFontMetrics() );
1534 }
1535 else
1536 {
1537 boxText( *m_gal, slot.text, locs.ShadowPos, attrs, aPin->GetFontMetrics() );
1538 }
1539 }
1540 else if( nonCached( aPin ) && renderTextAsBitmap )
1541 {
1542 bitmapText( *m_gal, slot.text, locs.NormalPos, attrs );
1543 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1544 }
1545 else
1546 {
1547 strokeText( *m_gal, slot.text, locs.NormalPos, attrs, aPin->GetFontMetrics() );
1548 const_cast<SCH_PIN*>( aPin )->SetFlags( IS_SHOWN_AS_BITMAP );
1549 }
1550
1551 const bool hasAltIcon =
1552 ( slot.role == PIN_TEXTS::SLOT_ROLE::NAME ) && !aPin->GetAlternates().empty()
1553 && GetSettings()->m_ShowPinAltIcons && !renderTextAsBitmap;
1554
1555 if( hasAltIcon )
1556 {
1557 wxASSERT( locs.IconPos.size() >= 1 );
1558
1559 drawAltPinModesIcon( *m_gal, locs.IconPos[0], iconSize,
1560 // Icon style doesn't work due to the tempPin having no alt
1561 // but maybe it's better with just one style anyway.
1562 true,
1563 placement.Angle == ANGLE_VERTICAL, shadowWidth, slot.colour );
1564 }
1565 };
1566
1567 for( const PIN_TEXTS::SLOT& slot : pinTexts )
1568 {
1569 drawText( slot );
1570 }
1571}
1572
1573
1574// Draw anchor indicating the anchor position of text objects, local labels, or fields.
1575void SCH_PAINTER::drawAnchor( const VECTOR2I& aPos, bool aDrawingShadows )
1576{
1577 if( m_schSettings.IsPrinting() )
1578 return;
1579
1580 // In order for the anchors to be visible but unobtrusive, their size must factor in the
1581 // current zoom level.
1582 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
1583 int radius = KiROUND( std::fabs( matrix.GetScale().x * TEXT_ANCHOR_SIZE ) / 25 )
1585
1586 COLOR4D color = aDrawingShadows ? m_schSettings.GetLayerColor( LAYER_SELECTION_SHADOWS )
1587 : m_schSettings.GetLayerColor( LAYER_SCHEMATIC_ANCHOR );
1588
1589 m_gal->SetStrokeColor( color );
1590 m_gal->SetIsStroke( true );
1591 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( false )
1592 : m_schSettings.GetDanglingIndicatorThickness() );
1593
1594 m_gal->DrawLine( aPos - VECTOR2I( radius, 0 ), aPos + VECTOR2I( radius, 0 ) );
1595 m_gal->DrawLine( aPos - VECTOR2I( 0, radius ), aPos + VECTOR2I( 0, radius ) );
1596}
1597
1598
1599// Draw the target (an open square) for a wire or label which has no connection or is
1600// being moved.
1601void SCH_PAINTER::drawDanglingIndicator( const VECTOR2I& aPos, const COLOR4D& aColor, int aWidth,
1602 bool aDangling, bool aDrawingShadows, bool aBrightened )
1603{
1604 if( m_schSettings.IsPrinting() )
1605 return;
1606
1607 int size = aDangling ? DANGLING_SYMBOL_SIZE : UNSELECTED_END_SIZE;
1608
1609 if( !aDangling )
1610 aWidth /= 2;
1611
1612 VECTOR2I radius( aWidth + schIUScale.MilsToIU( size / 2 ),
1613 aWidth + schIUScale.MilsToIU( size / 2 ) );
1614
1615 // Dangling symbols must be drawn in a slightly different colour so they can be seen when
1616 // they overlap with a junction dot.
1617 m_gal->SetStrokeColor( aColor.Brightened( 0.3 ) );
1618 m_gal->SetIsStroke( true );
1619 m_gal->SetIsFill( false );
1620 m_gal->SetLineWidth( aDrawingShadows ? getShadowWidth( aBrightened )
1621 : m_schSettings.GetDanglingIndicatorThickness() );
1622
1623 m_gal->DrawRectangle( aPos - radius, aPos + radius );
1624}
1625
1626
1627void SCH_PAINTER::draw( const SCH_JUNCTION* aJct, int aLayer )
1628{
1629 bool highlightNetclassColors = false;
1630 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
1631
1632 if( eeschemaCfg )
1633 {
1634 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
1635 }
1636
1637 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1638
1639 if( m_schSettings.IsPrinting() && drawingShadows )
1640 return;
1641
1642 if( drawingShadows && !( aJct->IsBrightened() || aJct->IsSelected() ) )
1643 return;
1644
1645 COLOR4D color;
1646
1647 if( highlightNetclassColors && aLayer == aJct->GetLayer() )
1648 color = m_schSettings.GetLayerColor( aJct->GetLayer() );
1649 else
1650 color = getRenderColor( aJct, aJct->GetLayer(), drawingShadows );
1651
1652 int junctionSize = aJct->GetEffectiveDiameter() / 2;
1653
1654 if( junctionSize > 1 )
1655 {
1656 m_gal->SetIsStroke( drawingShadows );
1657 m_gal->SetLineWidth( getLineWidth( aJct, drawingShadows ) );
1658 m_gal->SetStrokeColor( color );
1659 m_gal->SetIsFill( !drawingShadows );
1660 m_gal->SetFillColor( color );
1661 m_gal->DrawCircle( aJct->GetPosition(), junctionSize );
1662 }
1663}
1664
1665
1666void SCH_PAINTER::draw( const SCH_LINE* aLine, int aLayer )
1667{
1668 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1669 bool drawingNetColorHighlights = aLayer == LAYER_NET_COLOR_HIGHLIGHT;
1670 bool drawingWires = aLayer == LAYER_WIRE;
1671 bool drawingBusses = aLayer == LAYER_BUS;
1672 bool drawingDangling = aLayer == LAYER_DANGLING;
1673 bool drawingOP = aLayer == LAYER_OP_VOLTAGES;
1674
1675 bool highlightNetclassColors = false;
1676 double highlightAlpha = 0.6;
1677 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
1678
1679 if( eeschemaCfg )
1680 {
1681 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
1682 highlightAlpha = eeschemaCfg->m_Selection.highlight_netclass_colors_alpha;
1683 }
1684
1685 if( !highlightNetclassColors && drawingNetColorHighlights )
1686 return;
1687
1688 if( m_schSettings.m_OverrideItemColors && drawingNetColorHighlights )
1689 return;
1690
1691 if( m_schSettings.IsPrinting() && drawingShadows )
1692 return;
1693
1694 if( drawingShadows && !( aLine->IsBrightened() || aLine->IsSelected() ) )
1695 return;
1696
1697 // Line end dangling status isn't updated until the line is finished drawing, so don't warn
1698 // them about ends that are probably connected
1699 if( aLine->IsNew() && drawingDangling )
1700 return;
1701
1702 COLOR4D color = getRenderColor( aLine, aLine->GetLayer(), drawingShadows );
1703 float width = getLineWidth( aLine, drawingShadows, drawingNetColorHighlights );
1704 LINE_STYLE lineStyle = aLine->GetEffectiveLineStyle();
1705
1706 if( highlightNetclassColors )
1707 {
1708 // Force default color for nets we are going to highlight
1709 if( drawingWires )
1710 color = m_schSettings.GetLayerColor( LAYER_WIRE );
1711 else if( drawingBusses )
1712 color = m_schSettings.GetLayerColor( LAYER_BUS );
1713 }
1714
1715 if( drawingNetColorHighlights )
1716 {
1717 // Don't draw highlights for default-colored nets
1718 if( ( aLine->IsWire() && color == m_schSettings.GetLayerColor( LAYER_WIRE ) )
1719 || ( aLine->IsBus() && color == m_schSettings.GetLayerColor( LAYER_BUS ) ) )
1720 {
1721 return;
1722 }
1723
1724 color = color.WithAlpha( color.a * highlightAlpha );
1725 }
1726
1727 if( ( drawingDangling || drawingShadows ) && !aLine->IsNew() )
1728 {
1729 if( ( aLine->IsWire() && aLine->IsStartDangling() )
1730 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( STARTPOINT ) ) )
1731 {
1732 COLOR4D indicatorColor( color );
1733
1734 if( drawingShadows && !aLine->HasFlag( STARTPOINT ) )
1735 indicatorColor.Invert();
1736
1737 drawDanglingIndicator( aLine->GetStartPoint(), indicatorColor, KiROUND( width ),
1738 aLine->IsWire() && aLine->IsStartDangling(), drawingShadows,
1739 aLine->IsBrightened() );
1740 }
1741
1742 if( ( aLine->IsWire() && aLine->IsEndDangling() )
1743 || ( drawingShadows && aLine->IsSelected() && !aLine->HasFlag( ENDPOINT ) ) )
1744 {
1745 COLOR4D indicatorColor( color );
1746
1747 if( drawingShadows && !aLine->HasFlag( ENDPOINT ) )
1748 indicatorColor.Invert();
1749
1750 drawDanglingIndicator( aLine->GetEndPoint(), indicatorColor, KiROUND( width ),
1751 aLine->IsWire() && aLine->IsEndDangling(), drawingShadows,
1752 aLine->IsBrightened() );
1753 }
1754 }
1755
1756 if( drawingDangling )
1757 return;
1758
1759 if( drawingOP && !aLine->GetOperatingPoint().IsEmpty() )
1760 {
1761 int textSize = getOperatingPointTextSize();
1762 VECTOR2I pos = aLine->GetMidPoint();
1763 int textOffset = KiROUND( textSize * 0.22 );
1764 TEXT_ATTRIBUTES attrs;
1765
1766 if( aLine->GetStartPoint().y == aLine->GetEndPoint().y )
1767 {
1768 pos.y -= textOffset;
1771 }
1772 else
1773 {
1774 pos.x += KiROUND( textOffset * 1.2 );
1777 }
1778
1779 attrs.m_Font = KIFONT::FONT::GetFont(); // always use stroke font for performance
1780 attrs.m_Size = VECTOR2I( textSize, textSize );
1781 attrs.m_StrokeWidth = GetPenSizeForDemiBold( textSize );
1782 attrs.m_Color = m_schSettings.GetLayerColor( LAYER_OP_VOLTAGES );
1783
1784 knockoutText( *m_gal, aLine->GetOperatingPoint(), pos, attrs, aLine->GetFontMetrics() );
1785 }
1786
1787 if( drawingOP )
1788 return;
1789
1790 m_gal->SetIsStroke( true );
1791 m_gal->SetStrokeColor( color );
1792 m_gal->SetLineWidth( width );
1793
1794 if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
1795 {
1796 m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() );
1797 }
1798 else
1799 {
1800 SHAPE_SEGMENT line( aLine->GetStartPoint(), aLine->GetEndPoint() );
1801
1802 STROKE_PARAMS::Stroke( &line, lineStyle, KiROUND( width ), &m_schSettings,
1803 [&]( const VECTOR2I& a, const VECTOR2I& b )
1804 {
1805 // DrawLine has problem with 0 length lines so enforce minimum
1806 if( a == b )
1807 m_gal->DrawLine( a+1, b );
1808 else
1809 m_gal->DrawLine( a, b );
1810 } );
1811 }
1812}
1813
1814
1815void SCH_PAINTER::draw( const SCH_SHAPE* aShape, int aLayer, bool aDimmed )
1816{
1817 if( !isUnitAndConversionShown( aShape ) )
1818 return;
1819
1820 if( aShape->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
1821 return;
1822
1823 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
1824
1825 if( m_schSettings.IsPrinting() && drawingShadows )
1826 return;
1827
1828 LINE_STYLE lineStyle = aShape->GetEffectiveLineStyle();
1829 COLOR4D color = getRenderColor( aShape, aLayer, drawingShadows, aDimmed );
1830
1831 if( drawingShadows && !( aShape->IsBrightened() || aShape->IsSelected() ) )
1832 return;
1833
1834 auto drawShape =
1835 [&]( const SCH_SHAPE* shape )
1836 {
1837 switch( shape->GetShape() )
1838 {
1839 case SHAPE_T::ARC:
1840 {
1841 VECTOR2D start = shape->GetStart();
1842 VECTOR2D mid = shape->GetArcMid();
1843 VECTOR2D end = shape->GetEnd();
1844 VECTOR2D center = CalcArcCenter( start, mid, end );
1845
1846 EDA_ANGLE startAngle( start - center );
1847 EDA_ANGLE midAngle( mid - center );
1848 EDA_ANGLE endAngle( end - center );
1849
1850 EDA_ANGLE angle1 = midAngle - startAngle;
1851 EDA_ANGLE angle2 = endAngle - midAngle;
1852
1853 EDA_ANGLE angle = angle1.Normalize180() + angle2.Normalize180();
1854
1855 m_gal->DrawArc( center, ( start - center ).EuclideanNorm(), startAngle, angle );
1856 break;
1857 }
1858
1859 case SHAPE_T::CIRCLE:
1860 m_gal->DrawCircle( shape->GetPosition(), shape->GetRadius() );
1861 break;
1862
1863 case SHAPE_T::RECTANGLE:
1864 m_gal->DrawRectangle( shape->GetPosition(), shape->GetEnd() );
1865 break;
1866
1867 case SHAPE_T::POLY:
1868 {
1869 const std::vector<SHAPE*> polySegments = shape->MakeEffectiveShapes( true );
1870
1871 if( !polySegments.empty() )
1872 {
1873 std::deque<VECTOR2D> pts;
1874
1875 for( SHAPE* polySegment : polySegments )
1876 pts.push_back( static_cast<SHAPE_SEGMENT*>( polySegment )->GetSeg().A );
1877
1878 pts.push_back(
1879 static_cast<SHAPE_SEGMENT*>( polySegments.back() )->GetSeg().B );
1880
1881 for( SHAPE* polySegment : polySegments )
1882 delete polySegment;
1883
1884 m_gal->DrawPolygon( pts );
1885 }
1886 break;
1887 }
1888
1889 case SHAPE_T::BEZIER:
1890 {
1891 m_gal->DrawCurve( shape->GetStart(), shape->GetBezierC1(),
1892 shape->GetBezierC2(), shape->GetEnd() );
1893 break;
1894 }
1895
1896 default:
1897 UNIMPLEMENTED_FOR( shape->SHAPE_T_asString() );
1898 }
1899 };
1900
1901 if( aLayer == LAYER_SELECTION_SHADOWS )
1902 {
1903 if( eeconfig()->m_Selection.fill_shapes )
1904 {
1905 // Consider a NAND gate. We have no idea which side of the arc is "inside"
1906 // so we can't reliably fill.
1907 if( aShape->GetShape() == SHAPE_T::ARC )
1908 m_gal->SetIsFill( aShape->IsFilled() );
1909 else
1910 m_gal->SetIsFill( true );
1911
1912 m_gal->SetIsStroke( false );
1913 m_gal->SetFillColor( color );
1914 }
1915 else
1916 {
1917 m_gal->SetIsStroke( true );
1918 m_gal->SetIsFill( false );
1919 m_gal->SetLineWidth( getLineWidth( aShape, true ) );
1920 m_gal->SetStrokeColor( color );
1921 }
1922
1923 drawShape( aShape );
1924 }
1925 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
1926 {
1927 switch( aShape->GetFillMode() )
1928 {
1929 case FILL_T::NO_FILL:
1930 break;
1931
1933 // Fill in the foreground layer
1934 break;
1935
1938 // Do not fill the shape in B&W print mode, to avoid to visible items inside the shape
1939 if( !m_schSettings.PrintBlackAndWhiteReq() )
1940 {
1941 m_gal->SetIsFill( true );
1942 m_gal->SetIsStroke( false );
1943 m_gal->SetFillColor( color );
1944
1945 drawShape( aShape );
1946 }
1947 break;
1948 }
1949 }
1950 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES
1951 || aLayer == LAYER_RULE_AREAS )
1952 {
1953 // Shapes filled with the device colour must be filled in the foreground
1954 if( aShape->GetFillMode() == FILL_T::FILLED_SHAPE )
1955 {
1956 m_gal->SetIsFill( true );
1957 m_gal->SetIsStroke( false );
1958 m_gal->SetFillColor( color );
1959
1960 drawShape( aShape );
1961 }
1962
1963 float lineWidth = getLineWidth( aShape, drawingShadows );
1964
1965 if( lineWidth > 0 )
1966 {
1967 m_gal->SetIsFill( false );
1968 m_gal->SetIsStroke( true );
1969 m_gal->SetLineWidth( lineWidth );
1970 m_gal->SetStrokeColor( color );
1971
1972 if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
1973 {
1974 drawShape( aShape );
1975 }
1976 else
1977 {
1978 std::vector<SHAPE*> shapes = aShape->MakeEffectiveShapes( true );
1979
1980 for( SHAPE* shape : shapes )
1981 {
1982 STROKE_PARAMS::Stroke( shape, lineStyle, KiROUND( lineWidth ), &m_schSettings,
1983 [this]( const VECTOR2I& a, const VECTOR2I& b )
1984 {
1985 // DrawLine has problem with 0 length lines so enforce minimum
1986 if( a == b )
1987 m_gal->DrawLine( a+1, b );
1988 else
1989 m_gal->DrawLine( a, b );
1990 } );
1991 }
1992
1993 for( SHAPE* shape : shapes )
1994 delete shape;
1995 }
1996 }
1997 }
1998}
1999
2000
2001void SCH_PAINTER::draw( const SCH_TEXT* aText, int aLayer, bool aDimmed )
2002{
2003 if( !isUnitAndConversionShown( aText ) )
2004 return;
2005
2006 if( aText->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
2007 return;
2008
2009 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2010
2011 if( m_schSettings.IsPrinting() && drawingShadows )
2012 return;
2013
2014 if( drawingShadows && !( aText->IsBrightened() || aText->IsSelected() ) )
2015 return;
2016
2017 switch( aText->Type() )
2018 {
2019 case SCH_SHEET_PIN_T: aLayer = LAYER_SHEETLABEL; break;
2020 case SCH_HIER_LABEL_T: aLayer = LAYER_HIERLABEL; break;
2021 case SCH_GLOBAL_LABEL_T: aLayer = LAYER_GLOBLABEL; break;
2022 case SCH_DIRECTIVE_LABEL_T: aLayer = LAYER_NETCLASS_REFS; break;
2023 case SCH_LABEL_T: aLayer = LAYER_LOCLABEL; break;
2024 case SCH_TEXT_T: aLayer = aText->GetParentSymbol() ? LAYER_DEVICE
2025 : LAYER_NOTES; break;
2026 default: aLayer = LAYER_NOTES; break;
2027 }
2028
2029 COLOR4D color = getRenderColor( aText, aLayer, drawingShadows, aDimmed );
2030
2031 if( m_schematic )
2032 {
2033 SCH_CONNECTION* conn = nullptr;
2034
2035 if( !aText->IsConnectivityDirty() )
2036 conn = aText->Connection();
2037
2038 if( conn && conn->IsBus() )
2039 color = getRenderColor( aText, LAYER_BUS, drawingShadows );
2040 }
2041
2042 if( !( aText->IsVisible() || aText->IsForceVisible() ) )
2043 {
2044 if( m_schSettings.m_IsSymbolEditor || eeconfig()->m_Appearance.show_hidden_fields )
2045 color = getRenderColor( aText, LAYER_HIDDEN, drawingShadows );
2046 else
2047 return;
2048 }
2049
2050 m_gal->SetStrokeColor( color );
2051 m_gal->SetFillColor( color );
2052
2053 wxString shownText( aText->GetShownText( true ) );
2054 VECTOR2I text_offset = aText->GetSchematicTextOffset( &m_schSettings );
2055 TEXT_ATTRIBUTES attrs = aText->GetAttributes();
2056 KIFONT::FONT* font = getFont( aText );
2057
2058 attrs.m_Angle = aText->GetDrawRotation();
2059 attrs.m_StrokeWidth = KiROUND( getTextThickness( aText ) );
2060
2061 if( drawingShadows && font->IsOutline() )
2062 {
2063 BOX2I bBox = aText->GetBoundingBox();
2064 bBox.Inflate( KiROUND( getTextThickness( aText ) * 2 ) );
2065
2066 m_gal->SetIsStroke( false );
2067 m_gal->SetIsFill( true );
2068 m_gal->DrawRectangle( bBox.GetPosition(), bBox.GetEnd() );
2069 }
2070 else if( aText->GetLayer() == LAYER_DEVICE )
2071 {
2072 BOX2I bBox = aText->GetBoundingBox();
2073 VECTOR2D pos = bBox.Centre();
2074
2075 // Due to the fact a shadow text can be drawn left or right aligned, it needs to be
2076 // offset by shadowWidth/2 to be drawn at the same place as normal text.
2077 // For some reason we need to slightly modify this offset for a better look (better
2078 // alignment of shadow shape), for KiCad font only.
2079 double shadowOffset = 0.0;
2080
2081 if( drawingShadows )
2082 {
2083 double shadowWidth = getShadowWidth( !aText->IsSelected() );
2084 attrs.m_StrokeWidth += getShadowWidth( !aText->IsSelected() );
2085
2086 const double adjust = 1.2f; // Value chosen after tests
2087 shadowOffset = shadowWidth/2.0f * adjust;
2088 }
2089
2090 if( attrs.m_Angle == ANGLE_VERTICAL )
2091 {
2092 switch( attrs.m_Halign )
2093 {
2095 pos.y = bBox.GetBottom() + shadowOffset;
2096 break;
2098 pos.y = ( bBox.GetTop() + bBox.GetBottom() ) / 2.0;
2099 break;
2101 pos.y = bBox.GetTop() - shadowOffset;
2102 break;
2104 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
2105 break;
2106 }
2107 }
2108 else
2109 {
2110 switch( attrs.m_Halign )
2111 {
2113 pos.x = bBox.GetLeft() - shadowOffset;
2114 break;
2116 pos.x = ( bBox.GetLeft() + bBox.GetRight() ) / 2.0;
2117 break;
2119 pos.x = bBox.GetRight() + shadowOffset;
2120 break;
2122 wxFAIL_MSG( wxT( "Indeterminate state legal only in dialogs." ) );
2123 break;
2124 }
2125 }
2126
2127 // Because the text vertical position is the bounding box center, the text is drawn as
2128 // vertically centered.
2130
2131 strokeText( *m_gal, shownText, pos, attrs, aText->GetFontMetrics() );
2132 }
2133 else if( drawingShadows )
2134 {
2135 m_gal->SetIsFill( false );
2136 m_gal->SetIsStroke( true );
2137 attrs.m_StrokeWidth += KiROUND( getShadowWidth( !aText->IsSelected() ) );
2138 attrs.m_Underlined = false;
2139
2140 // Fudge factors to match 6.0 positioning
2141 // New text stroking has width dependent offset but we need to center the shadow on the
2142 // stroke. NB this offset is in font.cpp also.
2143 int fudge = KiROUND( getShadowWidth( !aText->IsSelected() ) / 1.52 );
2144
2145 if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_0 )
2146 text_offset.x -= fudge;
2147 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_90 )
2148 text_offset.y -= fudge;
2149 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_RIGHT && attrs.m_Angle == ANGLE_0 )
2150 text_offset.x += fudge;
2151 else if( attrs.m_Halign == GR_TEXT_H_ALIGN_LEFT && attrs.m_Angle == ANGLE_90 )
2152 text_offset.y += fudge;
2153
2154 strokeText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs,
2155 aText->GetFontMetrics() );
2156 }
2157 else
2158 {
2159 if( aText->IsHypertext() && aText->IsRollover() )
2160 {
2161 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2162 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2163 attrs.m_Underlined = true;
2164 }
2165
2166 // Adjust text drawn in an outline font to more closely mimic the positioning of
2167 // SCH_FIELD text.
2168 if( font->IsOutline() && aText->Type() == SCH_TEXT_T )
2169 {
2170 BOX2I firstLineBBox = aText->GetTextBox( 0 );
2171 int sizeDiff = firstLineBBox.GetHeight() - aText->GetTextSize().y;
2172 int adjust = KiROUND( sizeDiff * 0.4 );
2173 VECTOR2I adjust_offset( 0, - adjust );
2174
2175 RotatePoint( adjust_offset, aText->GetDrawRotation() );
2176 text_offset += adjust_offset;
2177 }
2178
2179 if( nonCached( aText )
2180 && aText->RenderAsBitmap( m_gal->GetWorldScale() )
2181 && !shownText.Contains( wxT( "\n" ) ) )
2182 {
2183 bitmapText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs );
2184 const_cast<SCH_TEXT*>( aText )->SetFlags( IS_SHOWN_AS_BITMAP );
2185 }
2186 else
2187 {
2188 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2189
2190 if( !aText->IsHypertext() && font->IsOutline() )
2191 cache = aText->GetRenderCache( font, shownText, text_offset );
2192
2193 if( cache )
2194 {
2195 m_gal->SetLineWidth( attrs.m_StrokeWidth );
2196 m_gal->DrawGlyphs( *cache );
2197 }
2198 else
2199 {
2200 strokeText( *m_gal, shownText, aText->GetDrawPos() + text_offset, attrs,
2201 aText->GetFontMetrics() );
2202 }
2203
2204 const_cast<SCH_TEXT*>( aText )->ClearFlags( IS_SHOWN_AS_BITMAP );
2205 }
2206 }
2207
2208 // Draw anchor
2209 if( aText->IsSelected() )
2210 {
2211 bool showAnchor;
2212
2213 switch( aText->Type() )
2214 {
2215 case SCH_TEXT_T:
2216 showAnchor = true;
2217 break;
2218
2219 case SCH_LABEL_T:
2220 // Don't clutter things up if we're already showing a dangling indicator
2221 showAnchor = !static_cast<const SCH_LABEL*>( aText )->IsDangling();
2222 break;
2223
2225 case SCH_HIER_LABEL_T:
2226 case SCH_GLOBAL_LABEL_T:
2227 case SCH_SHEET_PIN_T:
2228 // These all have shapes and so don't need anchors
2229 showAnchor = false;
2230 break;
2231
2232 default:
2233 showAnchor = false;
2234 break;
2235 }
2236
2237 if( showAnchor )
2238 drawAnchor( aText->GetPosition(), drawingShadows );
2239 }
2240}
2241
2242
2243void SCH_PAINTER::draw( const SCH_TEXTBOX* aTextBox, int aLayer, bool aDimmed )
2244{
2245 if( aTextBox->Type() == SCH_TABLECELL_T )
2246 {
2247 const SCH_TABLECELL* cell = static_cast<const SCH_TABLECELL*>( aTextBox );
2248
2249 if( cell->GetColSpan() == 0 || cell->GetRowSpan() == 0 )
2250 return;
2251 }
2252
2253 if( !isUnitAndConversionShown( aTextBox ) )
2254 return;
2255
2256 if( aTextBox->IsPrivate() && !m_schSettings.m_IsSymbolEditor )
2257 return;
2258
2259 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2260
2261 if( m_schSettings.IsPrinting() && drawingShadows )
2262 return;
2263
2264 COLOR4D color = getRenderColor( aTextBox, aLayer, drawingShadows, aDimmed );
2265 COLOR4D bg = m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND );
2266 float borderWidth = getLineWidth( aTextBox, drawingShadows );
2267 KIFONT::FONT* font = getFont( aTextBox );
2268
2269 auto drawText =
2270 [&]()
2271 {
2272 wxString shownText = aTextBox->GetShownText( true );
2273 TEXT_ATTRIBUTES attrs = aTextBox->GetAttributes();
2274
2275 attrs.m_Angle = aTextBox->GetDrawRotation();
2276 attrs.m_StrokeWidth = KiROUND( getTextThickness( aTextBox ) );
2277
2278 if( aTextBox->IsHypertext() && aTextBox->IsRollover() )
2279 {
2280 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2281 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2282 attrs.m_Underlined = true;
2283 }
2284
2285 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2286
2287 if( !aTextBox->IsHypertext() && font->IsOutline() )
2288 cache = aTextBox->GetRenderCache( font, shownText );
2289
2290 if( cache )
2291 {
2292 m_gal->SetLineWidth( attrs.m_StrokeWidth );
2293 m_gal->DrawGlyphs( *cache );
2294 }
2295 else
2296 {
2297 strokeText( *m_gal, shownText, aTextBox->GetDrawPos(), attrs,
2298 aTextBox->GetFontMetrics() );
2299 }
2300 };
2301
2302 if( drawingShadows && !( aTextBox->IsBrightened() || aTextBox->IsSelected() ) )
2303 return;
2304
2305 m_gal->SetFillColor( color );
2306 m_gal->SetStrokeColor( color );
2307
2308 if( aLayer == LAYER_SELECTION_SHADOWS )
2309 {
2310 m_gal->SetIsFill( true );
2311 m_gal->SetIsStroke( false );
2312 m_gal->SetLineWidth( borderWidth );
2313
2314 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2315 }
2316 else if( aLayer == LAYER_DEVICE_BACKGROUND || aLayer == LAYER_NOTES_BACKGROUND )
2317 {
2318 // Do not fill the shape in B&W print mode, to avoid to visible items
2319 // inside the shape
2320 if( aTextBox->IsFilled() && !m_schSettings.PrintBlackAndWhiteReq() )
2321 {
2322 m_gal->SetIsFill( true );
2323 m_gal->SetIsStroke( false );
2324 m_gal->SetLineWidth( borderWidth );
2325
2326 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2327 }
2328 }
2329 else if( aLayer == LAYER_DEVICE || aLayer == LAYER_NOTES || aLayer == LAYER_PRIVATE_NOTES )
2330 {
2331 drawText();
2332
2333 if( aTextBox->Type() != SCH_TABLECELL_T && borderWidth > 0 )
2334 {
2335 COLOR4D borderColor = aTextBox->GetStroke().GetColor();
2336 LINE_STYLE borderStyle = aTextBox->GetEffectiveLineStyle();
2337 double transparency = aTextBox->GetForcedTransparency();
2338
2339 if( m_schSettings.m_OverrideItemColors || aTextBox->IsBrightened()
2340 || borderColor == COLOR4D::UNSPECIFIED )
2341 {
2342 borderColor = m_schSettings.GetLayerColor( aLayer );
2343 }
2344
2345 if( transparency > 0.0 )
2346 borderColor = borderColor.WithAlpha( borderColor.a * ( 1.0 - transparency ) );
2347
2348 if( aDimmed )
2349 {
2350 borderColor = borderColor.Mix( bg, 0.5f );
2351 borderColor.Desaturate( );
2352 }
2353
2354 m_gal->SetIsFill( false );
2355 m_gal->SetIsStroke( true );
2356 m_gal->SetStrokeColor( borderColor );
2357 m_gal->SetLineWidth( borderWidth );
2358
2359 if( borderStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
2360 {
2361 m_gal->DrawRectangle( aTextBox->GetPosition(), aTextBox->GetEnd() );
2362 }
2363 else
2364 {
2365 std::vector<SHAPE*> shapes = aTextBox->MakeEffectiveShapes( true );
2366
2367 for( SHAPE* shape : shapes )
2368 {
2369 STROKE_PARAMS::Stroke( shape, borderStyle, KiROUND( borderWidth ),
2370 &m_schSettings,
2371 [this]( const VECTOR2I& a, const VECTOR2I& b )
2372 {
2373 // DrawLine has problem with 0 length lines so enforce minimum
2374 if( a == b )
2375 m_gal->DrawLine( a+1, b );
2376 else
2377 m_gal->DrawLine( a, b );
2378 } );
2379 }
2380
2381 for( SHAPE* shape : shapes )
2382 delete shape;
2383 }
2384 }
2385 }
2386}
2387
2388
2389void SCH_PAINTER::draw( const SCH_TABLE* aTable, int aLayer, bool aDimmed )
2390{
2391 for( SCH_TABLECELL* cell : aTable->GetCells() )
2392 draw( cell, aLayer, aDimmed );
2393
2394 if( aLayer == LAYER_SELECTION_SHADOWS )
2395 return;
2396
2397 VECTOR2I pos = aTable->GetPosition();
2398 VECTOR2I end = aTable->GetEnd();
2399
2400 int lineWidth;
2401 COLOR4D color;
2402 LINE_STYLE lineStyle;
2403
2404 auto setupStroke =
2405 [&]( const STROKE_PARAMS& stroke )
2406 {
2407 lineWidth = stroke.GetWidth();
2408 color = stroke.GetColor();
2409 lineStyle = stroke.GetLineStyle();
2410
2411 if( lineWidth == 0 )
2412 lineWidth = m_schSettings.GetDefaultPenWidth();
2413
2415 color = m_schSettings.GetLayerColor( LAYER_NOTES );
2416
2417 if( lineStyle == LINE_STYLE::DEFAULT )
2418 lineStyle = LINE_STYLE::SOLID;
2419
2420 m_gal->SetIsFill( false );
2421 m_gal->SetIsStroke( true );
2422 m_gal->SetStrokeColor( color );
2423 m_gal->SetLineWidth( (float) lineWidth );
2424 };
2425
2426 auto strokeShape =
2427 [&]( const SHAPE& shape )
2428 {
2429 STROKE_PARAMS::Stroke( &shape, lineStyle, lineWidth, &m_schSettings,
2430 [&]( const VECTOR2I& a, const VECTOR2I& b )
2431 {
2432 // DrawLine has problem with 0 length lines so enforce minimum
2433 if( a == b )
2434 m_gal->DrawLine( a+1, b );
2435 else
2436 m_gal->DrawLine( a, b );
2437 } );
2438 };
2439
2440 auto strokeLine =
2441 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
2442 {
2443 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2444 {
2445 m_gal->DrawLine( ptA, ptB );
2446 }
2447 else
2448 {
2449 SHAPE_SEGMENT seg( ptA, ptB );
2450 strokeShape( seg );
2451 }
2452 };
2453
2454 auto strokeRect =
2455 [&]( const VECTOR2I& ptA, const VECTOR2I& ptB )
2456 {
2457 if( lineStyle <= LINE_STYLE::FIRST_TYPE )
2458 {
2459 m_gal->DrawRectangle( ptA, ptB );
2460 }
2461 else
2462 {
2463 SHAPE_RECT rect( BOX2I( ptA, ptB - ptA ) );
2464 strokeShape( rect );
2465 }
2466 };
2467
2468 if( aTable->GetSeparatorsStroke().GetWidth() >= 0 )
2469 {
2470 setupStroke( aTable->GetSeparatorsStroke() );
2471
2472 if( aTable->StrokeColumns() )
2473 {
2474 for( int col = 0; col < aTable->GetColCount() - 1; ++col )
2475 {
2476 for( int row = 0; row < aTable->GetRowCount(); ++row )
2477 {
2478 SCH_TABLECELL* cell = aTable->GetCell( row, col );
2479 VECTOR2I topRight( cell->GetEndX(), cell->GetStartY() );
2480
2481 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2482 strokeLine( topRight, cell->GetEnd() );
2483 }
2484 }
2485 }
2486
2487 if( aTable->StrokeRows() )
2488 {
2489 for( int row = 0; row < aTable->GetRowCount() - 1; ++row )
2490 {
2491 for( int col = 0; col < aTable->GetColCount(); ++col )
2492 {
2493 SCH_TABLECELL* cell = aTable->GetCell( row, col );
2494 VECTOR2I botLeft( cell->GetStartX(), cell->GetEndY() );
2495
2496 if( cell->GetColSpan() > 0 && cell->GetRowSpan() > 0 )
2497 strokeLine( botLeft, cell->GetEnd() );
2498 }
2499 }
2500 }
2501 }
2502
2503 if( aTable->GetBorderStroke().GetWidth() >= 0 )
2504 {
2505 setupStroke( aTable->GetBorderStroke() );
2506
2507 if( aTable->StrokeHeader() )
2508 {
2509 SCH_TABLECELL* cell = aTable->GetCell( 0, 0 );
2510 strokeLine( VECTOR2I( pos.x, cell->GetEndY() ), VECTOR2I( end.x, cell->GetEndY() ) );
2511 }
2512
2513 if( aTable->StrokeExternal() )
2514 strokeRect( pos, end );
2515 }
2516}
2517
2518
2519wxString SCH_PAINTER::expandLibItemTextVars( const wxString& aSourceText,
2520 const SCH_SYMBOL* aSymbolContext )
2521{
2522 std::function<bool( wxString* )> symbolResolver =
2523 [&]( wxString* token ) -> bool
2524 {
2525 if( !m_schematic )
2526 return false;
2527
2528 return aSymbolContext->ResolveTextVar( &m_schematic->CurrentSheet(), token );
2529 };
2530
2531 return ExpandTextVars( aSourceText, &symbolResolver );
2532}
2533
2534
2535void SCH_PAINTER::draw( const SCH_SYMBOL* aSymbol, int aLayer )
2536{
2537 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2538 bool DNP = aSymbol->GetDNP();
2539 bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions
2540 && aSymbol->GetExcludedFromSim();
2541
2542 if( m_schSettings.IsPrinting() && drawingShadows )
2543 return;
2544
2545 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2546 {
2547 for( const SCH_FIELD& field : aSymbol->GetFields() )
2548 draw( &field, aLayer, DNP || markExclusion );
2549 }
2550
2551 if( isFieldsLayer( aLayer ) )
2552 return;
2553
2554 if( drawingShadows && !( aSymbol->IsBrightened() || aSymbol->IsSelected() ) )
2555 {
2556 // Don't exit here; symbol may still have selected pins
2557 // return;
2558 }
2559
2560 int unit = m_schematic ? aSymbol->GetUnitSelection( &m_schematic->CurrentSheet() ) : 1;
2561 int bodyStyle = aSymbol->GetBodyStyle();
2562
2563 // Use dummy symbol if the actual couldn't be found (or couldn't be locked).
2564 LIB_SYMBOL* originalSymbol = aSymbol->GetLibSymbolRef() ? aSymbol->GetLibSymbolRef().get()
2565 : dummy();
2566 std::vector<SCH_PIN*> originalPins = originalSymbol->GetPins( unit, bodyStyle );
2567
2568 // Copy the source so we can re-orient and translate it.
2569 LIB_SYMBOL tempSymbol( *originalSymbol );
2570 std::vector<SCH_PIN*> tempPins = tempSymbol.GetPins( unit, bodyStyle );
2571
2572 tempSymbol.SetFlags( aSymbol->GetFlags() );
2573
2574 OrientAndMirrorSymbolItems( &tempSymbol, aSymbol->GetOrientation() );
2575
2576 for( SCH_ITEM& tempItem : tempSymbol.GetDrawItems() )
2577 {
2578 tempItem.SetFlags( aSymbol->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2579 tempItem.Move( aSymbol->GetPosition() );
2580
2581 if( tempItem.Type() == SCH_TEXT_T )
2582 {
2583 SCH_TEXT* textItem = static_cast<SCH_TEXT*>( &tempItem );
2584
2585 if( textItem->HasTextVars() )
2586 textItem->SetText( expandLibItemTextVars( textItem->GetText(), aSymbol ) );
2587 }
2588 else if( tempItem.Type() == SCH_TEXTBOX_T )
2589 {
2590 SCH_TEXTBOX* textboxItem = static_cast<SCH_TEXTBOX*>( &tempItem );
2591
2592 if( textboxItem->HasTextVars() )
2593 textboxItem->SetText( expandLibItemTextVars( textboxItem->GetText(), aSymbol ) );
2594 }
2595 }
2596
2597 // Copy the pin info from the symbol to the temp pins
2598 for( unsigned i = 0; i < tempPins.size(); ++ i )
2599 {
2600 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2601 SCH_PIN* tempPin = tempPins[ i ];
2602
2603 tempPin->ClearFlags();
2604 tempPin->SetFlags( symbolPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2605 // IS_SHOWN_AS_BITMAP
2606
2607 tempPin->SetName( expandLibItemTextVars( symbolPin->GetShownName(), aSymbol ) );
2608 tempPin->SetType( symbolPin->GetType() );
2609 tempPin->SetShape( symbolPin->GetShape() );
2610
2611 if( symbolPin->IsDangling() )
2612 tempPin->SetFlags( IS_DANGLING );
2613 else
2614 tempPin->ClearFlags( IS_DANGLING );
2615
2616 tempPin->SetOperatingPoint( symbolPin->GetOperatingPoint() );
2617 }
2618
2619 draw( &tempSymbol, aLayer, false, aSymbol->GetUnit(), aSymbol->GetBodyStyle(),
2620 DNP || markExclusion );
2621
2622 for( unsigned i = 0; i < tempPins.size(); ++i )
2623 {
2624 SCH_PIN* symbolPin = aSymbol->GetPin( originalPins[ i ] );
2625 SCH_PIN* tempPin = tempPins[ i ];
2626
2627 symbolPin->ClearFlags();
2628 tempPin->ClearFlags( IS_DANGLING ); // Clear this temporary flag
2629 symbolPin->SetFlags( tempPin->GetFlags() ); // SELECTED, HIGHLIGHTED, BRIGHTENED,
2630 // IS_SHOWN_AS_BITMAP
2631 }
2632
2633 if( DNP || markExclusion )
2634 {
2635 int layer = DNP ? LAYER_DNP_MARKER : LAYER_EXCLUDED_FROM_SIM;
2636 BOX2I bbox = aSymbol->GetBodyBoundingBox();
2637 BOX2I pins = aSymbol->GetBodyAndPinsBoundingBox();
2638 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
2639 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
2640 int strokeWidth = 3 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
2641
2642 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
2643 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
2644 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
2645
2646 VECTOR2I pt1 = bbox.GetOrigin();
2647 VECTOR2I pt2 = bbox.GetEnd();
2648
2649 m_gal->PushDepth();
2650 m_gal->AdvanceDepth();
2651 m_gal->SetIsStroke( true );
2652 m_gal->SetIsFill( true );
2653 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ) );
2654 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ) );
2655
2656 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2657 std::swap( pt1.x, pt2.x );
2658 m_gal->DrawSegment( pt1, pt2, strokeWidth );
2659 m_gal->PopDepth();
2660 }
2661}
2662
2663
2664void SCH_PAINTER::draw( const SCH_FIELD* aField, int aLayer, bool aDimmed )
2665{
2666 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2667
2668 if( m_schSettings.IsPrinting() && drawingShadows )
2669 return;
2670
2671 if( drawingShadows && !( aField->IsBrightened() || aField->IsSelected() ) )
2672 return;
2673
2674 if( !isUnitAndConversionShown( aField ) )
2675 return;
2676
2677 // Must check layer as fields are sometimes drawn by their parent rather than directly
2678 // from the view.
2679 int layers[KIGFX::VIEW::VIEW_MAX_LAYERS];
2680 int layers_count;
2681 bool foundLayer = false;
2682
2683 aField->ViewGetLayers( layers, layers_count );
2684
2685 for( int i = 0; i < layers_count; ++i )
2686 {
2687 if( layers[i] == aLayer )
2688 foundLayer = true;
2689 }
2690
2691 if( !foundLayer )
2692 return;
2693
2694 aLayer = aField->GetLayer();
2695
2696 COLOR4D color = getRenderColor( aField, aLayer, drawingShadows, aDimmed );
2697
2698 if( !( aField->IsVisible() || aField->IsForceVisible() ) )
2699 {
2700 bool force_show = m_schematic ? eeconfig()->m_Appearance.show_hidden_fields
2701 : m_schSettings.m_ShowHiddenFields;
2702
2703 if( force_show )
2704 color = getRenderColor( aField, LAYER_HIDDEN, drawingShadows, aDimmed );
2705 else
2706 return;
2707 }
2708
2709 wxString shownText = aField->GetShownText( true );
2710
2711 if( shownText.IsEmpty() )
2712 return;
2713
2714 // Calculate the text orientation according to the parent orientation.
2715 EDA_ANGLE orient = aField->GetTextAngle();
2716
2717 if( aField->GetParent() && aField->GetParent()->Type() == SCH_SYMBOL_T )
2718 {
2719 if( static_cast<SCH_SYMBOL*>( aField->GetParent() )->GetTransform().y1 )
2720 {
2721 // Rotate symbol 90 degrees.
2722 if( orient.IsHorizontal() )
2723 orient = ANGLE_VERTICAL;
2724 else
2725 orient = ANGLE_HORIZONTAL;
2726 }
2727 }
2728
2729 /*
2730 * Calculate the text justification, according to the symbol orientation/mirror.
2731 * This is a bit complicated due to cumulative calculations:
2732 * - numerous cases (mirrored or not, rotation)
2733 * - the DrawGraphicText function recalculate also H and H justifications according to the
2734 * text orientation.
2735 * - when symbol is mirrored, the text is not mirrored and justifications are complicated
2736 * to calculate so the easier way is to use no justifications (centered text) and use
2737 * GetBoundingBox to know the text coordinate considered as centered
2738 */
2739 BOX2I bbox = aField->GetBoundingBox();
2740
2741 if( aField->GetParent() && aField->GetParent()->Type() == SCH_GLOBAL_LABEL_T )
2742 {
2743 SCH_GLOBALLABEL* label = static_cast<SCH_GLOBALLABEL*>( aField->GetParent() );
2744 bbox.Offset( label->GetSchematicTextOffset( &m_schSettings ) );
2745 }
2746
2747 if( m_schSettings.GetDrawBoundingBoxes() )
2748 drawItemBoundingBox( aField );
2749
2750 m_gal->SetStrokeColor( color );
2751 m_gal->SetFillColor( color );
2752
2753 if( drawingShadows && getFont( aField )->IsOutline() )
2754 {
2755 BOX2I shadow_box = bbox;
2756 shadow_box.Inflate( KiROUND( getTextThickness( aField ) * 2 ) );
2757
2758 m_gal->SetIsStroke( false );
2759 m_gal->SetIsFill( true );
2760 m_gal->DrawRectangle( shadow_box.GetPosition(), shadow_box.GetEnd() );
2761 }
2762 else
2763 {
2764 VECTOR2I textpos = bbox.Centre();
2765 TEXT_ATTRIBUTES attributes = aField->GetAttributes();
2766
2767 attributes.m_Halign = GR_TEXT_H_ALIGN_CENTER;
2768 attributes.m_Valign = GR_TEXT_V_ALIGN_CENTER;
2769 attributes.m_StrokeWidth = KiROUND( getTextThickness( aField ) );
2770 attributes.m_Angle = orient;
2771
2772 if( drawingShadows )
2773 attributes.m_StrokeWidth += getShadowWidth( !aField->IsSelected() );
2774
2775 if( aField->IsHypertext() && aField->IsRollover() )
2776 {
2777 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2778 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_HOVERED ) );
2779 attributes.m_Underlined = true;
2780 }
2781
2782 if( nonCached( aField ) && aField->RenderAsBitmap( m_gal->GetWorldScale() ) )
2783 {
2784 bitmapText( *m_gal, shownText, textpos, attributes );
2785 const_cast<SCH_FIELD*>( aField )->SetFlags( IS_SHOWN_AS_BITMAP );
2786 }
2787 else
2788 {
2789 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = nullptr;
2790
2791 if( !aField->IsHypertext() )
2792 cache = aField->GetRenderCache( shownText, textpos, attributes );
2793
2794 if( cache )
2795 {
2796 m_gal->SetLineWidth( attributes.m_StrokeWidth );
2797 m_gal->DrawGlyphs( *cache );
2798 }
2799 else
2800 {
2801 strokeText( *m_gal, shownText, textpos, attributes, aField->GetFontMetrics() );
2802 }
2803
2804 const_cast<SCH_FIELD*>( aField )->ClearFlags( IS_SHOWN_AS_BITMAP );
2805 }
2806 }
2807
2808 // Draw anchor or umbilical line
2809 if( aField->IsMoving() && m_schematic )
2810 {
2811 VECTOR2I parentPos = aField->GetParentPosition();
2812
2813 m_gal->SetLineWidth( m_schSettings.GetOutlineWidth() );
2814 m_gal->SetStrokeColor( getRenderColor( aField, LAYER_SCHEMATIC_ANCHOR, drawingShadows ) );
2815 m_gal->DrawLine( aField->GetPosition(), parentPos );
2816 }
2817 else if( aField->IsSelected() )
2818 {
2819 drawAnchor( aField->GetPosition(), drawingShadows );
2820 }
2821}
2822
2823
2824void SCH_PAINTER::draw( const SCH_GLOBALLABEL* aLabel, int aLayer )
2825{
2826 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2827
2828 if( m_schSettings.IsPrinting() && drawingShadows )
2829 return;
2830
2831 bool drawingDangling = aLayer == LAYER_DANGLING;
2832
2833 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2834 {
2835 for( const SCH_FIELD& field : aLabel->GetFields() )
2836 draw( &field, aLayer, false );
2837 }
2838
2839 if( isFieldsLayer( aLayer ) )
2840 return;
2841
2842 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2843 return;
2844
2845 COLOR4D color = getRenderColor( aLabel, LAYER_GLOBLABEL, drawingShadows );
2846
2847 if( drawingDangling )
2848 {
2849 if( aLabel->IsDangling() )
2850 {
2851 drawDanglingIndicator( aLabel->GetTextPos(), color,
2853 drawingShadows, aLabel->IsBrightened() );
2854 }
2855
2856 return;
2857 }
2858
2859 std::vector<VECTOR2I> pts;
2860 std::deque<VECTOR2D> pts2;
2861
2862 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
2863
2864 for( const VECTOR2I& p : pts )
2865 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2866
2867 m_gal->SetIsStroke( true );
2868 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2869 m_gal->SetStrokeColor( color );
2870
2871 if( drawingShadows )
2872 {
2873 m_gal->SetIsFill( eeconfig()->m_Selection.fill_shapes );
2874 m_gal->SetFillColor( color );
2875 m_gal->DrawPolygon( pts2 );
2876 }
2877 else
2878 {
2879 m_gal->SetIsFill( false );
2880 m_gal->DrawPolyline( pts2 );
2881 }
2882
2883 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2884}
2885
2886
2887void SCH_PAINTER::draw( const SCH_LABEL* aLabel, int aLayer )
2888{
2889 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2890
2891 if( m_schSettings.IsPrinting() && drawingShadows )
2892 return;
2893
2894 bool drawingDangling = aLayer == LAYER_DANGLING;
2895
2896 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
2897 {
2898 for( const SCH_FIELD& field : aLabel->GetFields() )
2899 draw( &field, aLayer, false );
2900 }
2901
2902 if( isFieldsLayer( aLayer ) )
2903 return;
2904
2905 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2906 return;
2907
2908 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows );
2909
2910 if( drawingDangling )
2911 {
2912 if( aLabel->IsDangling() )
2913 {
2914 drawDanglingIndicator( aLabel->GetTextPos(), color,
2916 drawingShadows, aLabel->IsBrightened() );
2917 }
2918
2919 return;
2920 }
2921
2922 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2923}
2924
2925
2926void SCH_PAINTER::draw( const SCH_HIERLABEL* aLabel, int aLayer, bool aDimmed )
2927{
2928 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2929
2930 if( m_schSettings.IsPrinting() && drawingShadows )
2931 return;
2932
2933 bool drawingDangling = aLayer == LAYER_DANGLING;
2934
2935 if( !( drawingShadows || drawingDangling ) || eeconfig()->m_Selection.draw_selected_children )
2936 {
2937 for( const SCH_FIELD& field : aLabel->GetFields() )
2938 draw( &field, aLayer, false );
2939 }
2940
2941 if( isFieldsLayer( aLayer ) )
2942 return;
2943
2944 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
2945 return;
2946
2947 COLOR4D color = getRenderColor( aLabel, LAYER_HIERLABEL, drawingShadows, aDimmed );
2948
2949 if( drawingDangling )
2950 {
2951 if( aLabel->IsDangling() )
2952 {
2953 drawDanglingIndicator( aLabel->GetTextPos(), color,
2955 drawingShadows, aLabel->IsBrightened() );
2956 }
2957
2958 return;
2959 }
2960
2961 if( m_schematic )
2962 {
2963 SCH_CONNECTION* conn = nullptr;
2964
2965 if( !aLabel->IsConnectivityDirty() )
2966 conn = aLabel->Connection();
2967
2968 if( conn && conn->IsBus() )
2969 color = getRenderColor( aLabel, LAYER_BUS, drawingShadows, aDimmed );
2970 }
2971
2972 std::vector<VECTOR2I> pts;
2973 std::deque<VECTOR2D> pts2;
2974
2975 aLabel->CreateGraphicShape( &m_schSettings, pts, (VECTOR2I)aLabel->GetTextPos() );
2976
2977 for( const VECTOR2I& p : pts )
2978 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
2979
2980 m_gal->SetIsFill( true );
2981 m_gal->SetFillColor( m_schSettings.GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
2982 m_gal->SetIsStroke( true );
2983 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
2984 m_gal->SetStrokeColor( color );
2985 m_gal->DrawPolyline( pts2 );
2986
2987 draw( static_cast<const SCH_TEXT*>( aLabel ), aLayer, false );
2988}
2989
2990
2991void SCH_PAINTER::draw( const SCH_DIRECTIVE_LABEL* aLabel, int aLayer )
2992{
2993 if( !eeconfig()->m_Appearance.show_directive_labels && !aLabel->IsSelected() )
2994 return;
2995
2996 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
2997
2998 if( m_schSettings.IsPrinting() && drawingShadows )
2999 return;
3000
3001 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
3002 {
3003 for( const SCH_FIELD& field : aLabel->GetFields() )
3004 draw( &field, aLayer, false );
3005 }
3006
3007 if( isFieldsLayer( aLayer ) )
3008 return;
3009
3010 if( drawingShadows && !( aLabel->IsBrightened() || aLabel->IsSelected() ) )
3011 return;
3012
3013 COLOR4D color = getRenderColor( aLabel, LAYER_NETCLASS_REFS, drawingShadows );
3014
3015 if( aLayer == LAYER_DANGLING )
3016 {
3017 if( aLabel->IsDangling() )
3018 {
3019 drawDanglingIndicator( aLabel->GetTextPos(), color,
3021 drawingShadows, aLabel->IsBrightened() );
3022 }
3023
3024 return;
3025 }
3026
3027 std::vector<VECTOR2I> pts;
3028 std::deque<VECTOR2D> pts2;
3029
3030 aLabel->CreateGraphicShape( &m_schSettings, pts, aLabel->GetTextPos() );
3031
3032 for( const VECTOR2I& p : pts )
3033 pts2.emplace_back( VECTOR2D( p.x, p.y ) );
3034
3035 m_gal->SetIsFill( false );
3036 m_gal->SetFillColor( color );
3037 m_gal->SetIsStroke( true );
3038 m_gal->SetLineWidth( getLineWidth( aLabel, drawingShadows ) );
3039 m_gal->SetStrokeColor( color );
3040
3041 if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_DOT )
3042 {
3043 m_gal->DrawLine( pts2[0], pts2[1] );
3044 m_gal->SetIsFill( true );
3045 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
3046 }
3047 else if( aLabel->GetShape() == LABEL_FLAG_SHAPE::F_ROUND )
3048 {
3049 m_gal->DrawLine( pts2[0], pts2[1] );
3050 m_gal->DrawCircle( pts2[2], ( pts2[2] - pts2[1] ).EuclideanNorm() );
3051 }
3052 else
3053 {
3054 m_gal->DrawPolyline( pts2 );
3055 }
3056}
3057
3058
3059void SCH_PAINTER::draw( const SCH_SHEET* aSheet, int aLayer )
3060{
3061 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
3062 bool DNP = aSheet->GetDNP();
3063 bool markExclusion = eeconfig()->m_Appearance.mark_sim_exclusions
3064 && aSheet->GetExcludedFromSim();
3065
3066 if( m_schSettings.IsPrinting() && drawingShadows )
3067 return;
3068
3069 if( !drawingShadows || eeconfig()->m_Selection.draw_selected_children )
3070 {
3071 for( const SCH_FIELD& field : aSheet->GetFields() )
3072 draw( &field, aLayer, DNP || markExclusion );
3073
3074 for( SCH_SHEET_PIN* sheetPin : aSheet->GetPins() )
3075 draw( static_cast<SCH_HIERLABEL*>( sheetPin ), aLayer, DNP || markExclusion );
3076 }
3077
3078 if( isFieldsLayer( aLayer ) )
3079 return;
3080
3081 VECTOR2D pos = aSheet->GetPosition();
3082 VECTOR2D size = aSheet->GetSize();
3083
3084 if( aLayer == LAYER_SHEET_BACKGROUND )
3085 {
3086 // Do not fill the shape in B&W print mode, to avoid to visible items
3087 // inside the shape
3088 if( !m_schSettings.PrintBlackAndWhiteReq() )
3089 {
3090 m_gal->SetFillColor( getRenderColor( aSheet, LAYER_SHEET_BACKGROUND, true ) );
3091 m_gal->SetIsFill( true );
3092 m_gal->SetIsStroke( false );
3093
3094 m_gal->DrawRectangle( pos, pos + size );
3095 }
3096 }
3097
3098 if( aLayer == LAYER_SHEET || aLayer == LAYER_SELECTION_SHADOWS )
3099 {
3100 m_gal->SetStrokeColor( getRenderColor( aSheet, LAYER_SHEET, drawingShadows ) );
3101 m_gal->SetIsStroke( true );
3102 m_gal->SetLineWidth( getLineWidth( aSheet, drawingShadows ) );
3103 m_gal->SetIsFill( false );
3104
3105 m_gal->DrawRectangle( pos, pos + size );
3106 }
3107
3108 if( DNP || markExclusion )
3109 {
3110 int layer = DNP ? LAYER_DNP_MARKER : LAYER_EXCLUDED_FROM_SIM;
3111 BOX2I bbox = aSheet->GetBodyBoundingBox();
3112 BOX2I pins = aSheet->GetBoundingBox();
3113 VECTOR2D margins( std::max( bbox.GetX() - pins.GetX(), pins.GetEnd().x - bbox.GetEnd().x ),
3114 std::max( bbox.GetY() - pins.GetY(), pins.GetEnd().y - bbox.GetEnd().y ) );
3115 int strokeWidth = 3 * schIUScale.MilsToIU( DEFAULT_LINE_WIDTH_MILS );
3116
3117 margins.x = std::max( margins.x * 0.6, margins.y * 0.3 );
3118 margins.y = std::max( margins.y * 0.6, margins.x * 0.3 );
3119 bbox.Inflate( KiROUND( margins.x ), KiROUND( margins.y ) );
3120
3121 VECTOR2I pt1 = bbox.GetOrigin();
3122 VECTOR2I pt2 = bbox.GetEnd();
3123
3124 m_gal->PushDepth();
3125 m_gal->AdvanceDepth();
3126 m_gal->SetIsStroke( true );
3127 m_gal->SetIsFill( true );
3128 m_gal->SetStrokeColor( m_schSettings.GetLayerColor( layer ) );
3129 m_gal->SetFillColor( m_schSettings.GetLayerColor( layer ) );
3130
3131 m_gal->DrawSegment( pt1, pt2, strokeWidth );
3132 std::swap( pt1.x, pt2.x );
3133 m_gal->DrawSegment( pt1, pt2, strokeWidth );
3134 m_gal->PopDepth();
3135 }
3136}
3137
3138
3139void SCH_PAINTER::draw( const SCH_NO_CONNECT* aNC, int aLayer )
3140{
3141 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
3142
3143 if( m_schSettings.IsPrinting() && drawingShadows )
3144 return;
3145
3146 if( drawingShadows && !( aNC->IsBrightened() || aNC->IsSelected() ) )
3147 return;
3148
3149 m_gal->SetIsStroke( true );
3150 m_gal->SetLineWidth( getLineWidth( aNC, drawingShadows ) );
3151 m_gal->SetStrokeColor( getRenderColor( aNC, LAYER_NOCONNECT, drawingShadows ) );
3152 m_gal->SetIsFill( false );
3153
3154 VECTOR2D p = aNC->GetPosition();
3155 int delta = std::max( aNC->GetSize(), m_schSettings.GetDefaultPenWidth() * 3 ) / 2;
3156
3157 m_gal->DrawLine( p + VECTOR2D( -delta, -delta ), p + VECTOR2D( delta, delta ) );
3158 m_gal->DrawLine( p + VECTOR2D( -delta, delta ), p + VECTOR2D( delta, -delta ) );
3159}
3160
3161
3162void SCH_PAINTER::draw( const SCH_BUS_ENTRY_BASE *aEntry, int aLayer )
3163{
3165 SCH_LINE line( VECTOR2I(), layer );
3166 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
3167 bool drawingNetColorHighlights = aLayer == LAYER_NET_COLOR_HIGHLIGHT;
3168 bool drawingDangling = aLayer == LAYER_DANGLING;
3169 bool drawingWires = aLayer == LAYER_WIRE;
3170 bool drawingBusses = aLayer == LAYER_BUS;
3171
3172 if( m_schSettings.IsPrinting() && drawingShadows )
3173 return;
3174
3175 bool highlightNetclassColors = false;
3176 EESCHEMA_SETTINGS* eeschemaCfg = eeconfig();
3177
3178 if( eeschemaCfg )
3179 {
3180 highlightNetclassColors = eeschemaCfg->m_Selection.highlight_netclass_colors;
3181 }
3182
3183 if( !highlightNetclassColors && drawingNetColorHighlights )
3184 return;
3185
3186 if( m_schSettings.m_OverrideItemColors && drawingNetColorHighlights )
3187 return;
3188
3189 if( drawingShadows && !( aEntry->IsBrightened() || aEntry->IsSelected() ) )
3190 return;
3191
3192 if( aEntry->IsSelected() )
3193 {
3194 line.SetSelected();
3195 // Never show unselected endpoints on bus entries
3196 line.SetFlags( STARTPOINT | ENDPOINT );
3197 }
3198 else if( aEntry->IsBrightened() )
3199 line.SetBrightened();
3200
3201 line.SetStartPoint( aEntry->GetPosition() );
3202 line.SetEndPoint( aEntry->GetEnd() );
3203 line.SetStroke( aEntry->GetStroke() );
3204 line.SetLineWidth( KiROUND( getLineWidth( aEntry, false ) ) );
3205
3206 COLOR4D color = getRenderColor( aEntry, LAYER_WIRE, drawingShadows );
3207
3208 if( aEntry->Type() == SCH_BUS_BUS_ENTRY_T )
3209 color = getRenderColor( aEntry, LAYER_BUS, drawingShadows );
3210
3211 if( highlightNetclassColors )
3212 {
3213 // Force default color for nets we are going to highlight
3214 if( drawingWires )
3215 color = m_schSettings.GetLayerColor( LAYER_WIRE );
3216 else if( drawingBusses )
3217 color = m_schSettings.GetLayerColor( LAYER_BUS );
3218 }
3219
3220 if( drawingNetColorHighlights )
3221 {
3222 // Don't draw highlights for default-colored nets
3223 if( ( aEntry->Type() == SCH_BUS_WIRE_ENTRY_T
3224 && color == m_schSettings.GetLayerColor( LAYER_WIRE ) )
3225 || ( aEntry->Type() == SCH_BUS_BUS_ENTRY_T
3226 && color == m_schSettings.GetLayerColor( LAYER_BUS ) ) )
3227 {
3228 return;
3229 }
3230 }
3231
3232 if( drawingDangling )
3233 {
3234 m_gal->SetIsFill( false );
3235 m_gal->SetIsStroke( true );
3236 m_gal->SetStrokeColor( color.Brightened( 0.3 ) );
3237 m_gal->SetLineWidth( m_schSettings.GetDanglingIndicatorThickness() );
3238
3239 if( aEntry->IsDanglingStart() )
3240 {
3241 m_gal->DrawCircle( aEntry->GetPosition(),
3242 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
3243 }
3244
3245 if( aEntry->IsDanglingEnd() )
3246 {
3247 m_gal->DrawCircle( aEntry->GetEnd(),
3248 aEntry->GetPenWidth() + KiROUND( TARGET_BUSENTRY_RADIUS / 2.0 ) );
3249 }
3250 }
3251 else
3252 {
3253 line.SetLineColor( color );
3254 line.SetLineStyle( aEntry->GetLineStyle() );
3255
3256 draw( &line, aLayer );
3257 }
3258}
3259
3260
3261void SCH_PAINTER::draw( const SCH_BITMAP* aBitmap, int aLayer )
3262{
3263 m_gal->Save();
3264 m_gal->Translate( aBitmap->GetPosition() );
3265
3266 const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
3267
3268 // When the image scale factor is not 1.0, we need to modify the actual as the image scale
3269 // factor is similar to a local zoom
3270 const double img_scale = refImage.GetImageScale();
3271
3272 if( img_scale != 1.0 )
3273 m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
3274
3275 if( aLayer == LAYER_DRAW_BITMAPS )
3276 {
3277 m_gal->DrawBitmap( refImage.GetImage() );
3278 }
3279
3280 if( aLayer == LAYER_SELECTION_SHADOWS )
3281 {
3282 if( aBitmap->IsSelected() || aBitmap->IsBrightened() )
3283 {
3284 const COLOR4D color = getRenderColor( aBitmap, LAYER_DRAW_BITMAPS, true );
3285 m_gal->SetIsStroke( true );
3286 m_gal->SetStrokeColor( color );
3287 m_gal->SetLineWidth ( getShadowWidth( aBitmap->IsBrightened() ) );
3288 m_gal->SetIsFill( false );
3289
3290 // Draws a bounding box.
3291 VECTOR2D bm_size( refImage.GetSize() );
3292 // bm_size is the actual image size in UI.
3293 // but m_gal scale was previously set to img_scale
3294 // so recalculate size relative to this image size.
3295 bm_size.x /= img_scale;
3296 bm_size.y /= img_scale;
3297 const VECTOR2D origin( -bm_size.x / 2.0, -bm_size.y / 2.0 );
3298 const VECTOR2D end = origin + bm_size;
3299
3300 m_gal->DrawRectangle( origin, end );
3301 }
3302 }
3303
3304 m_gal->Restore();
3305}
3306
3307
3308void SCH_PAINTER::draw( const SCH_MARKER* aMarker, int aLayer )
3309{
3310 bool drawingShadows = aLayer == LAYER_SELECTION_SHADOWS;
3311
3312 if( m_schSettings.IsPrinting() && drawingShadows )
3313 return;
3314
3315 if( drawingShadows && !( aMarker->IsBrightened() || aMarker->IsSelected() ) )
3316 return;
3317
3318 COLOR4D color = getRenderColor( aMarker, aMarker->GetColorLayer(), drawingShadows );
3319
3320 m_gal->Save();
3321 m_gal->Translate( aMarker->GetPosition() );
3322 m_gal->SetIsFill( !drawingShadows );
3323 m_gal->SetFillColor( color );
3324 m_gal->SetIsStroke( drawingShadows );
3325 m_gal->SetLineWidth( getLineWidth( aMarker, drawingShadows ) );
3326 m_gal->SetStrokeColor( color );
3327
3328 SHAPE_LINE_CHAIN polygon;
3329 aMarker->ShapeToPolygon( polygon );
3330
3331 m_gal->DrawPolygon( polygon );
3332 m_gal->Restore();
3333}
3334
3335
3336}; // 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:922
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr const Vec GetEnd() const
Definition: box2.h:212
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:146
constexpr coord_type GetY() const
Definition: box2.h:208
constexpr size_type GetWidth() const
Definition: box2.h:214
constexpr Vec Centre() const
Definition: box2.h:97
constexpr coord_type GetX() const
Definition: box2.h:207
constexpr size_type GetHeight() const
Definition: box2.h:215
constexpr coord_type GetLeft() const
Definition: box2.h:228
constexpr void SetX(coord_type val)
Definition: box2.h:277
constexpr const Vec & GetOrigin() const
Definition: box2.h:210
constexpr void SetY(coord_type val)
Definition: box2.h:282
const BOX2< Vec > GetBoundingBoxRotated(const VECTOR2I &aRotCenter, const EDA_ANGLE &aAngle) const
Useful to calculate bounding box of rotated items, when rotation is not cardinal.
Definition: box2.h:720
constexpr coord_type GetRight() const
Definition: box2.h:217
constexpr coord_type GetTop() const
Definition: box2.h:229
constexpr void Offset(coord_type dx, coord_type dy)
Definition: box2.h:259
constexpr coord_type GetBottom() const
Definition: box2.h:222
Directions
Available directions, there are 8 of them, as on a rectilinear map (north = up) + an extra undefined ...
Definition: direction45.h:49
bool IsHorizontal() const
Definition: eda_angle.h:138
EDA_ANGLE Normalize180()
Definition: eda_angle.h:260
double AsRadians() const
Definition: eda_angle.h:117
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:77
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:253
COLOR4D GetTextColor() const
Definition: eda_text.h:250
bool IsItalic() const
Definition: eda_text.h:152
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:170
KIFONT::FONT * GetFont() const
Definition: eda_text.h:230
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:601
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:542
virtual EDA_ANGLE GetDrawRotation() const
Definition: eda_text.h:359
virtual VECTOR2I GetDrawPos() const
Definition: eda_text.h:360
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:214
bool IsBold() const
Definition: eda_text.h:167
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:182
VECTOR2I GetTextSize() const
Definition: eda_text.h:241
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
FONT is an abstract base class for both outline and stroke fonts.
Definition: font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition: font.cpp:146
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:258
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:435
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 DrawPolygon(const std::deque< VECTOR2D > &aPointList)
Draw a polygon.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void Rotate(double aAngle)
Rotate the context.
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a rectangle.
void SetVerticalJustify(const GR_TEXT_V_ALIGN_T aVerticalJustify)
void SetHorizontalJustify(const GR_TEXT_H_ALIGN_T aHorizontalJustify)
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void Translate(const VECTOR2D &aTranslation)
Translate the context.
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
virtual void Restore()
Restore the context.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
void SetGlyphSize(const VECTOR2I aSize)
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle)
Draw an arc.
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
virtual void Save()
Save the context.
double GetWorldScale() const
Get the world scale.
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
Helper class to gather logic relating to the positioning of text in the four pin "slots":
const_iterator begin() const
void SetColorOverride(const COLOR4D &aColor)
Replace all slot colours with a new colour.
std::array< int, 4 > m_offsets
const_iterator end() const
TEXT_PLACEMENT GetTextPlacement(const PIN_TEXTS::SLOT &aSlot, PIN_ORIENTATION aPinOrientation) const
std::array< SLOT, 4 >::const_iterator const_iterator
SLOT & GetSlot(SLOT_ID aSlot)
const SCH_PIN & m_pin
std::array< SLOT, 4 > m_slots
bool SlotRendersAsBitmap(const SLOT &aSlot, KIGFX::GAL &aGal) const
const SLOT & GetSlot(SLOT_ID aSlot) const
const float m_pinTextMargin
const void ComputeOffsets()
PIN_TEXTS(const SCH_PIN &aPin, float aPenWidth, float aPinTextMargin)
const float m_penWidth
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:133
SCH_RENDER_SETTINGS m_schSettings
Definition: sch_painter.h:136
bool nonCached(const EDA_ITEM *aItem)
SCH_PAINTER(GAL *aGal)
void drawItemBoundingBox(const EDA_ITEM *aItem)
bool isUnitAndConversionShown(const SCH_ITEM *aItem) const
Small helper class to figure out the layout of text and text-adjacent icons, including text shadows a...
const KIFONT::METRICS & m_fontMetrics
LOCATIONS getTextLayout(const wxString &aText, const VECTOR2I &aPos, GR_TEXT_H_ALIGN_T aIconSide, std::size_t aNIcons, bool aDrawShadow)
Get the layout of text and icons for a given text string at a position.
TEXT_AND_ICON_LAYOUT(KIGFX::GAL &aGal, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics, const double aShadowWidth, const double aIconSize=0)
Create a new layout helper.
const TEXT_ATTRIBUTES & m_attrs
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:161
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:810
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
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
VECTOR2I GetSize() const
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
Object to handle a bitmap image that can be inserted in a schematic.
Definition: sch_bitmap.h:40
VECTOR2I GetPosition() const override
Definition: sch_bitmap.cpp:115
REFERENCE_IMAGE & GetReferenceImage()
Definition: sch_bitmap.h:51
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:1808
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:616
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:558
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1485
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:209
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const wxString &forResolvedText, const VECTOR2I &forPosition, TEXT_ATTRIBUTES &aAttrs) const
Definition: sch_field.cpp:382
VECTOR2I GetParentPosition() const
Definition: sch_field.cpp:1501
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:1960
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:1850
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:2070
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:977
bool IsStartDangling() const
Definition: sch_line.h:261
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:249
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:321
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_line.cpp:308
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
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:983
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:292
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:307
VECTOR2I GetPosition() const override
Definition: sch_marker.h:106
int GetSize() const
VECTOR2I GetPosition() const override
int GetNumberTextSize() const
Definition: sch_pin.cpp:507
int GetLength() const
Definition: sch_pin.cpp:279
const std::map< wxString, ALT > & GetAlternates() const
Definition: sch_pin.h:125
wxString GetShownNumber() const
Definition: sch_pin.cpp:466
const wxString & GetOperatingPoint() const
Definition: sch_pin.h:293
void SetName(const wxString &aName)
Definition: sch_pin.cpp:372
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:189
bool IsVisible() const
Definition: sch_pin.cpp:341
VECTOR2I GetPinRoot() const
Definition: sch_pin.cpp:529
wxString GetElectricalTypeName() const
Definition: sch_pin.cpp:327
bool IsDangling() const override
Definition: sch_pin.h:270
PIN_ORIENTATION GetOrientation() const
Definition: sch_pin.cpp:246
void SetShape(GRAPHIC_PINSHAPE aShape)
Definition: sch_pin.h:87
VECTOR2I GetPosition() const override
Definition: sch_pin.cpp:238
int GetNameTextSize() const
Definition: sch_pin.cpp:485
wxString GetShownName() const
Definition: sch_pin.cpp:452
void SetOperatingPoint(const wxString &aText)
Definition: sch_pin.h:294
void SetType(ELECTRICAL_PINTYPE aType)
Definition: sch_pin.h:100
GRAPHIC_PINSHAPE GetShape() const
Definition: sch_pin.cpp:259
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:292
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:104
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:820
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:288
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:861
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:983
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition: sch_symbol.h:212
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:80
int GetWidth() const
Definition: stroke_params.h:90
KIGFX::COLOR4D GetColor() const
Definition: stroke_params.h:96
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
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:406
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
#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:225
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:352
@ LAYER_DANGLING
Definition: layer_ids.h:380
@ LAYER_SHEETNAME
Definition: layer_ids.h:375
@ LAYER_SCHEMATIC_ANCHOR
Definition: layer_ids.h:401
@ LAYER_SHEETLABEL
Definition: layer_ids.h:378
@ LAYER_PINNUM
Definition: layer_ids.h:361
@ LAYER_RULE_AREAS
Definition: layer_ids.h:368
@ LAYER_DEVICE
Definition: layer_ids.h:369
@ LAYER_SHEET_BACKGROUND
Definition: layer_ids.h:387
@ LAYER_EXCLUDED_FROM_SIM
Definition: layer_ids.h:385
@ LAYER_BRIGHTENED
Definition: layer_ids.h:393
@ LAYER_HIDDEN
Definition: layer_ids.h:394
@ LAYER_HIERLABEL
Definition: layer_ids.h:360
@ LAYER_PINNAM
Definition: layer_ids.h:362
@ LAYER_PRIVATE_NOTES
Definition: layer_ids.h:371
@ LAYER_HOVERED
Definition: layer_ids.h:392
@ LAYER_GLOBLABEL
Definition: layer_ids.h:359
@ LAYER_WIRE
Definition: layer_ids.h:355
@ LAYER_NOTES
Definition: layer_ids.h:370
@ LAYER_NET_COLOR_HIGHLIGHT
Definition: layer_ids.h:395
@ LAYER_PIN
Definition: layer_ids.h:373
@ LAYER_VALUEPART
Definition: layer_ids.h:364
@ LAYER_BUS
Definition: layer_ids.h:356
@ LAYER_FIELDS
Definition: layer_ids.h:365
@ LAYER_DEVICE_BACKGROUND
Definition: layer_ids.h:386
@ LAYER_LOCLABEL
Definition: layer_ids.h:358
@ LAYER_SHEETFIELDS
Definition: layer_ids.h:377
@ LAYER_REFERENCEPART
Definition: layer_ids.h:363
@ LAYER_NETCLASS_REFS
Definition: layer_ids.h:367
@ LAYER_NOTES_BACKGROUND
Definition: layer_ids.h:372
@ LAYER_OP_CURRENTS
Definition: layer_ids.h:403
@ LAYER_SHEET
Definition: layer_ids.h:374
@ LAYER_SELECTION_SHADOWS
Definition: layer_ids.h:396
@ LAYER_SCHEMATIC_BACKGROUND
Definition: layer_ids.h:390
@ LAYER_INTERSHEET_REFS
Definition: layer_ids.h:366
@ LAYER_OP_VOLTAGES
Definition: layer_ids.h:402
@ LAYER_SHEETFILENAME
Definition: layer_ids.h:376
@ LAYER_DNP_MARKER
Definition: layer_ids.h:381
@ LAYER_NOCONNECT
Definition: layer_ids.h:379
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:96
VECTOR2I GetPoint(const SHAPE_RECT &aRect, DIRECTION_45::Directions aDir, int aOutset=0)
Get the point on a rectangle that corresponds to a given direction.
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.
static void boxText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void bitmapText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs)
EESCHEMA_SETTINGS * eeconfig()
Definition: sch_painter.cpp:71
static void strokeText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void knockoutText(KIGFX::GAL &aGal, const wxString &aText, const VECTOR2D &aPosition, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
static void drawAltPinModesIcon(GAL &aGal, const VECTOR2D &aPos, double aSize, bool aBaseSelected, bool aRotate, int aExtraLineWidth, const COLOR4D &aColor)
Draw an alternate pin mode indicator icon.
static bool isFieldsLayer(int aLayer)
static BOX2I GetTextExtents(const wxString &aText, const VECTOR2D &aPosition, KIFONT::FONT &aFont, const TEXT_ATTRIBUTES &aAttrs, const KIFONT::METRICS &aFontMetrics)
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)
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:78
#define TARGET_BUSENTRY_RADIUS
Definition: sch_bus_entry.h:31
#define BITMAP_FONT_SIZE_THRESHOLD
Definition: sch_item.cpp:49
@ F_DOT
Definition: sch_label.h:106
@ F_ROUND
Definition: sch_label.h:107
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
Utility functions for working with shapes.
std::vector< FAB_LAYER_COLOR > dummy
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:47
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
const bool ShouldDraw() const
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
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
Definition: trigo.cpp:521
@ SCH_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
constexpr int sign(T val)
Definition: util.h:159
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690