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