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