KiCad PCB EDA Suite
Loading...
Searching...
No Matches
widget_diff_canvas.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
27
29#include <eda_item.h>
30#include <gal/color4d.h>
33#include <layer_ids.h>
34#include <view/view.h>
35#include <view/view_group.h>
36#include <view/view_item.h>
37#include <view/view_overlay.h>
39#include <zoom_defines.h>
40
41
48
49
50WIDGET_DIFF_CANVAS::WIDGET_DIFF_CANVAS( wxWindow* aParent, GAL_TYPE aBackend, wxWindowID aId ) :
51 WIDGET_DIFF_CANVAS( aParent, aBackend, aId, std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>() )
52{
53}
54
55
56WIDGET_DIFF_CANVAS::WIDGET_DIFF_CANVAS( wxWindow* aParent, GAL_TYPE aBackend, wxWindowID aId,
57 std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> aGalOptions ) :
58 EDA_DRAW_PANEL_GAL( aParent, aId, wxDefaultPosition, wxDefaultSize, *aGalOptions, aBackend ),
59 m_layerVisible( LSET::AllLayersMask() ),
60 m_galOptions( std::move( aGalOptions ) )
61{
62 m_view = new KIGFX::VIEW();
63 m_view->SetGAL( m_gal );
64
66
67 for( int i = 0; i < KIGFX::VIEW::VIEW_MAX_LAYERS; i++ )
68 m_view->SetLayerTarget( i, target );
69
70 // Until a module installs a native context painter, the canvas renders only
71 // VIEW_OVERLAY commands, which bypass the painter. Reuse the drawing-sheet
72 // pair (also used by PL_DRAW_PANEL_GAL) rather than a private stub. Force
73 // the historical near-white background the diff canvas expects;
74 // DS_RENDER_SETTINGS otherwise defaults to pure white.
75 m_painter = std::make_unique<KIGFX::DS_PAINTER>( m_gal );
76 m_painter->GetSettings()->SetBackgroundColor( KIGFX::COLOR4D( 0.97, 0.97, 0.97, 1.0 ) );
77 m_view->SetPainter( m_painter.get() );
78
80 m_view->SetMirror( false, false );
81
82 m_contextGroup = std::make_unique<KIGFX::VIEW_GROUP>();
84 m_view->Add( m_contextGroup.get(), 0 );
85
86 // The overlay needs to live on a layer the view is willing to draw.
87 // LAYER_GP_OVERLAY is a general-purpose overlay slot used elsewhere in
88 // KiCad GAL panels for non-cached annotation.
90 m_view->SetLayerDisplayOnly( LAYER_GP_OVERLAY );
91 m_view->SetLayerVisible( LAYER_GP_OVERLAY, true );
92
93 m_overlay = m_view->MakeOverlay();
94
95 m_highlightBox = std::make_unique<HIGHLIGHT_BOX_ITEM>();
96 m_hoverBox = std::make_unique<HIGHLIGHT_BOX_ITEM>();
97
99
100 m_gal->SetCursorEnabled( false );
101
102 // Matches DIFF_THUMBNAIL so existing dialog layouts don't collapse the
103 // canvas when sizers are tight.
104 SetMinSize( wxSize( -1, 100 ) );
105
106 Bind( wxEVT_LEFT_DOWN, &WIDGET_DIFF_CANVAS::onLeftDown, this );
107 Bind( wxEVT_LEFT_UP, &WIDGET_DIFF_CANVAS::onLeftUp, this );
108 Bind( wxEVT_LEFT_DCLICK, &WIDGET_DIFF_CANVAS::onDoubleClick, this );
109 Bind( wxEVT_MOTION, &WIDGET_DIFF_CANVAS::onMotion, this );
110 Bind( wxEVT_LEAVE_WINDOW, &WIDGET_DIFF_CANVAS::onLeave, this );
111 Bind( wxEVT_CHAR_HOOK, &WIDGET_DIFF_CANVAS::onChar, this );
112 Bind( wxEVT_SIZE, &WIDGET_DIFF_CANVAS::onSize, this );
113
114 SetEvtHandlerEnabled( true );
115 Show( true );
116 StartDrawing();
117}
118
119
121{
122 StopDrawing();
123
125 {
126 if( item )
127 m_view->Remove( item );
128 }
129
130 m_view->Remove( m_contextGroup.get() );
131 // m_view owns the overlay since MakeOverlay() — no manual Remove needed.
132}
133
134
136{
137 m_scene = std::move( aScene );
138 m_highlight = std::nullopt;
139
142 ZoomToFit();
143}
144
145
146void WIDGET_DIFF_CANVAS::SetWorldUnitLength( double aWorldUnitLength )
147{
148 m_gal->SetWorldUnitLength( aWorldUnitLength );
149 m_gal->ComputeWorldScreenMatrix();
150 ZoomToFit();
151}
152
153
154void WIDGET_DIFF_CANVAS::SetContextPainter( std::unique_ptr<KIGFX::PAINTER> aPainter )
155{
156 if( !aPainter )
157 return;
158
159 m_painter = std::move( aPainter );
160 m_view->SetPainter( m_painter.get() );
161 m_view->MarkDirty();
162 Refresh();
163}
164
165
166void WIDGET_DIFF_CANVAS::SetContextItems( const std::vector<KIGFX::VIEW_ITEM*>& aItems )
167{
168 if( !m_contextGroup )
169 return;
170
172 {
173 if( item )
174 m_view->Remove( item );
175 }
176
177 m_contextGroupItems.clear();
178 m_itemCategories.clear();
179 m_hasNativeContext = false;
180
181 for( KIGFX::VIEW_ITEM* item : aItems )
182 {
183 if( !item )
184 continue;
185
186 m_view->Add( item );
187 m_contextGroupItems.push_back( item );
188 m_hasNativeContext = true;
189 }
190
193}
194
195
196void WIDGET_DIFF_CANVAS::HighlightChange( std::optional<KIID_PATH> aChangeId )
197{
198 if( m_highlight == aChangeId )
199 return;
200
201 m_highlight = std::move( aChangeId );
202
203 const std::optional<KIID> focusKiid =
204 m_highlight && !m_highlight->empty() ? std::optional( m_highlight->back() ) : std::nullopt;
205
206 // Dimming depends only on the hidden set, not the highlight, so it does not
207 // need re-applying here. Re-running it would REPAINT every board item on
208 // each click, which is the source of the highlight lag.
209
210 m_highlightBox->shown = false;
211
212 // The committed selection takes over from any active hover so the rect
213 // doesn't double-draw on the next mouse move.
214 if( focusKiid && m_hover == m_highlight )
215 {
216 m_hover.reset();
217 m_hoverBox->shown = false;
218 }
219
220 if( focusKiid )
221 {
223
225 {
226 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
227
228 if( !eda || getItemId( *eda ) != *focusKiid )
229 continue;
230
231 const BOX2I bb = item->ViewBBox();
232
233 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
234 break;
235
236 auto catIt = m_itemCategories.find( item );
237 KIGFX::COLOR4D base = catIt != m_itemCategories.end() ? KICAD_DIFF::ThemeColorFor( theme, catIt->second )
238 : theme.modified;
239
240 base.a = 0.35;
241
242 m_highlightBox->bbox = bb;
243 m_highlightBox->color = base;
244 m_highlightBox->shown = true;
245 break;
246 }
247 }
248
249 rebuildOverlay( /*aOverlayOnly=*/true );
250}
251
252
254{
255 const std::size_t idx = static_cast<std::size_t>( aCategory );
256
257 wxCHECK_RET( idx < m_categoryVisible.size(), wxS( "Invalid CATEGORY" ) );
258
259 if( m_categoryVisible[idx] == aVisible )
260 return;
261
262 m_categoryVisible[idx] = aVisible;
263
264 for( const auto& [item, cat] : m_itemCategories )
265 {
266 if( cat != aCategory )
267 continue;
268
269 m_view->SetVisible( item, aVisible );
270
271 // Force a full repaint so per-item color overrides re-apply.
272 if( aVisible )
273 m_view->Update( item, KIGFX::REPAINT );
274 }
275
277}
278
279
280void WIDGET_DIFF_CANVAS::SetItemCategories( std::map<KIGFX::VIEW_ITEM*, KICAD_DIFF::CATEGORY> aMap )
281{
282 m_itemCategories = std::move( aMap );
283
284 for( const auto& [item, cat] : m_itemCategories )
285 {
286 const std::size_t idx = static_cast<std::size_t>( cat );
287
288 if( idx < m_categoryVisible.size() )
289 m_view->SetVisible( item, m_categoryVisible[idx] );
290 }
291}
292
293
295{
296 const std::size_t idx = static_cast<std::size_t>( aCategory );
297
298 wxCHECK( idx < m_categoryVisible.size(), false );
299
300 return m_categoryVisible[idx];
301}
302
303
304void WIDGET_DIFF_CANVAS::SetHiddenChanges( std::set<KIID_PATH> aHidden )
305{
306 if( m_hiddenChanges == aHidden )
307 return;
308
309 m_hiddenChanges = std::move( aHidden );
312}
313
314
315bool WIDGET_DIFF_CANVAS::IsChangeHidden( const KIID_PATH& aChangeId ) const
316{
317 return m_hiddenChanges.count( aChangeId ) > 0;
318}
319
320
322{
323 if( !m_itemDimmer )
324 return;
325
326 // Item IDs of the hidden changes (a change id's last element is its item).
327 std::set<KIID> hiddenItems;
328
329 for( const KIID_PATH& path : m_hiddenChanges )
330 {
331 if( !path.empty() )
332 hiddenItems.insert( path.back() );
333 }
334
336 {
337 if( !item )
338 continue;
339
340 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
341 const bool hidden = eda && hiddenItems.count( getItemId( *eda ) ) > 0;
342
343 m_itemDimmer( item, hidden );
344 m_view->Update( item, KIGFX::REPAINT );
345 }
346}
347
348
350{
351 return m_itemIdGetter ? m_itemIdGetter( aItem ) : aItem.m_Uuid;
352}
353
354
356{
357 if( aLayer < 0 || aLayer >= PCB_LAYER_ID_COUNT )
358 return;
359
360 if( m_layerVisible.Contains( aLayer ) == aVisible )
361 return;
362
363 m_layerVisible.set( aLayer, aVisible );
364 m_view->SetLayerVisible( aLayer, aVisible );
367}
368
369
371{
372 return m_layerVisible.Contains( aLayer );
373}
374
375
380
381
383{
384 m_holdRebuild = false;
386
388 ZoomToFit();
389}
390
391
393{
394 if( m_holdRebuild )
395 {
396 m_zoomToFitPending = true;
397 return;
398 }
399
400 BOX2I bb = m_focusBox ? *m_focusBox : m_scene.documentBBox;
401 bool haveBox = bb.GetWidth() > 0 && bb.GetHeight() > 0;
402
403 // Also frame the context items so the whole board fits, not just the changes.
405 {
406 if( !item || m_focusBox )
407 continue;
408
409 BOX2I ib = item->ViewBBox();
410
411 if( ib.GetWidth() <= 0 || ib.GetHeight() <= 0 )
412 continue;
413
414 if( haveBox )
415 {
416 bb.Merge( ib );
417 }
418 else
419 {
420 bb = ib;
421 haveBox = true;
422 }
423 }
424
425 if( !haveBox )
426 {
427 m_zoomToFitPending = false;
428 return;
429 }
430
431 // VIEW::SetViewport silently no-ops when the GAL has no screen size, so
432 // defer the fit until we've been sized at least once.
433 const wxSize client = GetClientSize();
434
435 if( client.x <= 0 || client.y <= 0 )
436 {
437 m_zoomToFitPending = true;
438 return;
439 }
440
441 ZoomToBBox( bb );
442 m_zoomToFitPending = false;
443}
444
445
447{
448 if( !aBBox.GetWidth() || !aBBox.GetHeight() )
449 return;
450
451 BOX2D viewport( VECTOR2D( aBBox.GetLeft(), aBBox.GetTop() ), VECTOR2D( aBBox.GetWidth(), aBBox.GetHeight() ) );
452
453 // Inflate slightly so the outermost shape isn't flush with the edge.
454 viewport.Inflate( aBBox.GetWidth() * 0.05, aBBox.GetHeight() * 0.05 );
455
456 m_view->SetViewport( viewport );
457 Refresh();
458}
459
460
462{
463 std::optional<BOX2I> bb = highlightedBBox();
464
465 if( !bb || bb->GetWidth() <= 0 || bb->GetHeight() <= 0 )
466 return;
467
468 const VECTOR2I center = bb->GetCenter();
469 m_view->SetCenter( VECTOR2D( center.x, center.y ) );
470 m_view->MarkDirty();
471 Refresh();
472}
473
474
476{
478
480 {
481 m_renderScene.referenceGeometry = {};
482 m_renderScene.comparisonGeometry = {};
483 }
484 else
485 {
486 m_renderScene.referenceGeometry =
488 m_renderScene.comparisonGeometry =
490 }
491}
492
493
494void WIDGET_DIFF_CANVAS::rebuildOverlay( bool aOverlayOnly )
495{
496 if( m_holdRebuild )
497 return;
498
500
501 auto drawBox = [&]( const HIGHLIGHT_BOX_ITEM* aBox )
502 {
503 if( !aBox || !aBox->shown || aBox->bbox.GetWidth() <= 0 || aBox->bbox.GetHeight() <= 0 )
504 return;
505
506 m_overlay->SetIsFill( true );
507 m_overlay->SetIsStroke( false );
508 m_overlay->SetFillColor( aBox->color );
509 m_overlay->Rectangle( aBox->bbox.GetOrigin(), aBox->bbox.GetEnd() );
510 };
511
512 drawBox( m_hoverBox.get() );
513 drawBox( m_highlightBox.get() );
514
515 if( aOverlayOnly )
516 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
517 else
518 m_view->MarkDirty();
519
520 Refresh();
521}
522
523
524const KICAD_DIFF::SCENE_SHAPE* WIDGET_DIFF_CANVAS::shapeAt( const wxPoint& aScreenPoint ) const
525{
526 if( !m_view )
527 return nullptr;
528
529 // Convert from screen to document coordinates.
530 const VECTOR2D doc = m_view->ToWorld( VECTOR2D( aScreenPoint.x, aScreenPoint.y ) );
531
532 // Walk PAINT_ORDER in reverse so topmost shape wins, mirroring the
533 // thumbnail's hit-test order.
534 for( auto it = KICAD_DIFF::PAINT_ORDER.rbegin(); it != KICAD_DIFF::PAINT_ORDER.rend(); ++it )
535 {
536 if( !IsCategoryVisible( *it ) )
537 continue;
538
539 const std::vector<KICAD_DIFF::SCENE_SHAPE>& list = KICAD_DIFF::ShapesFor( m_scene, *it );
540
541 for( auto sIt = list.rbegin(); sIt != list.rend(); ++sIt )
542 {
543 // Muted changes let clicks fall through to what is underneath.
544 if( m_hiddenChanges.count( sIt->changeId ) > 0 )
545 continue;
546
547 if( sIt->bbox.Contains( VECTOR2I( KiROUND( doc.x ), KiROUND( doc.y ) ) ) )
548 return &*sIt;
549 }
550 }
551
552 return nullptr;
553}
554
555
556void WIDGET_DIFF_CANVAS::onLeftDown( wxMouseEvent& aEvent )
557{
558 std::optional<KIID_PATH> picked;
559
560 if( const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() ) )
561 picked = shape->changeId;
562
563 SetFocus();
564 aEvent.Skip();
565
566 if( m_leftDragPans )
567 {
568 m_leftPanning = true;
569 m_leftPanLast = VECTOR2D( aEvent.GetX(), aEvent.GetY() );
570 }
571
572 if( m_pickHandler )
573 m_pickHandler( picked );
574}
575
576
577void WIDGET_DIFF_CANVAS::onLeftUp( wxMouseEvent& aEvent )
578{
579 aEvent.Skip();
580 m_leftPanning = false;
581}
582
583
584void WIDGET_DIFF_CANVAS::onDoubleClick( wxMouseEvent& aEvent )
585{
586 aEvent.Skip();
587
588 if( !m_dclickHandler || m_contextGroupItems.empty() )
589 return;
590
591 const VECTOR2D world = m_view->ToWorld( VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y ) );
592 const VECTOR2I worldI( KiROUND( world.x ), KiROUND( world.y ) );
593
594 KIGFX::VIEW_ITEM* hit = nullptr;
595 BOX2I hitBBox;
596
597 // Reverse so the topmost item wins if bboxes overlap.
598 for( auto it = m_contextGroupItems.rbegin(); it != m_contextGroupItems.rend(); ++it )
599 {
600 KIGFX::VIEW_ITEM* item = *it;
601
602 if( !item )
603 continue;
604
605 const BOX2I bb = item->ViewBBox();
606
607 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
608 continue;
609
610 if( !bb.Contains( worldI ) )
611 continue;
612
613 // Prefer the smallest matching bbox so a nested sheet wins over its parent.
614 if( !hit || bb.GetArea() < hitBBox.GetArea() )
615 {
616 hit = item;
617 hitBBox = bb;
618 }
619 }
620
621 if( hit )
622 m_dclickHandler( hit );
623}
624
625
626void WIDGET_DIFF_CANVAS::onMotion( wxMouseEvent& aEvent )
627{
628 aEvent.Skip();
629
630 // The view controls pan on the middle button only, so the left drag is done here.
631 if( m_leftPanning && aEvent.Dragging() && aEvent.LeftIsDown() )
632 {
633 VECTOR2D pos( aEvent.GetX(), aEvent.GetY() );
634 VECTOR2D delta = m_view->ToWorld( pos, false ) - m_view->ToWorld( m_leftPanLast, false );
635
636 m_view->SetCenter( m_view->GetCenter() - delta );
637 m_leftPanLast = pos;
638 Refresh();
639 return;
640 }
641
642 std::optional<KIID_PATH> hovered;
643 const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() );
644
645 // Suppress hover when it would land on the already-selected change so the
646 // committed highlight stays clean.
647 if( shape && ( !m_highlight || shape->changeId != *m_highlight ) )
648 hovered = shape->changeId;
649
650 if( hovered == m_hover )
651 return;
652
653 m_hover = hovered;
654 m_hoverBox->shown = false;
655
656 if( shape && hovered )
657 {
658 KIGFX::COLOR4D base = shape->color;
659 base.a = 0.20;
660 m_hoverBox->bbox = shape->bbox;
661 m_hoverBox->color = base;
662 m_hoverBox->shown = true;
663 }
664
665 rebuildOverlay( /*aOverlayOnly=*/true );
666}
667
668
669void WIDGET_DIFF_CANVAS::onLeave( wxMouseEvent& aEvent )
670{
671 aEvent.Skip();
672 m_leftPanning = false;
673
674 if( !m_hover && !m_hoverBox->shown )
675 return;
676
677 m_hover.reset();
678 m_hoverBox->shown = false;
679 rebuildOverlay( /*aOverlayOnly=*/true );
680}
681
682
683void WIDGET_DIFF_CANVAS::onChar( wxKeyEvent& aEvent )
684{
685 switch( aEvent.GetKeyCode() )
686 {
687 case WXK_HOME:
688 if( m_scene.documentBBox.GetWidth() || m_scene.documentBBox.GetHeight() )
689 {
690 ZoomToFit();
691 return;
692 }
693
694 aEvent.Skip();
695 return;
696
697 case 'F':
698 case 'f':
699 if( std::optional<BOX2I> bbox = highlightedBBox() )
700 {
701 ZoomToBBox( *bbox );
702 return;
703 }
704
705 aEvent.Skip();
706 return;
707
708 case WXK_ESCAPE:
710 {
711 m_pickHandler( std::nullopt );
712 return;
713 }
714
715 aEvent.Skip();
716 return;
717
718 default: aEvent.Skip(); return;
719 }
720}
721
722
723void WIDGET_DIFF_CANVAS::onSize( wxSizeEvent& aEvent )
724{
725 aEvent.Skip();
726
728 ZoomToFit();
729}
730
731
732std::optional<BOX2I> WIDGET_DIFF_CANVAS::highlightedBBox() const
733{
734 if( !m_highlight.has_value() )
735 return std::nullopt;
736
738}
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
BOX2< VECTOR2D > BOX2D
Definition box2.h:915
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:697
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr coord_type GetTop() const
Definition box2.h:226
std::unique_ptr< KIGFX::PAINTER > m_painter
Contains information about how to draw items using GAL.
void StopDrawing()
Prevent the GAL canvas from further drawing until it is recreated or StartDrawing() is called.
KIGFX::GAL * m_gal
Interface for drawing objects on a 2D-surface.
EDA_DRAW_PANEL_GAL(wxWindow *aParentWindow, wxWindowID aWindowId, const wxPoint &aPosition, const wxSize &aSize, KIGFX::GAL_DISPLAY_OPTIONS &aOptions, GAL_TYPE aGalType=GAL_TYPE_OPENGL)
Create a drawing panel that is contained inside aParentWindow.
static bool IsAccelerated(GAL_TYPE aCanvasType)
True for a canvas drawn on the GPU, which keeps cached layers between frames.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
KIGFX::VIEW * m_view
Stores view settings (scale, center, etc.) and items to be drawn.
KIGFX::WX_VIEW_CONTROLS * m_viewControls
Control for VIEW (moving, zooming, etc.)
void SetFocus() override
void StartDrawing()
Begin drawing if it was stopped previously.
GAL_TYPE m_backend
Currently used GAL.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:599
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double a
Alpha component.
Definition color4d.h:394
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:82
virtual const BOX2I ViewBBox() const =0
Return the bounding box of the item covering all its layers.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:68
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:899
An implementation of class VIEW_CONTROLS for wxWidgets library.
Definition kiid.h:46
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
void SetScene(KICAD_DIFF::DIFF_SCENE aScene)
Replace the displayed scene. Pass an empty scene to clear the canvas.
void ZoomToFit()
Center the view on the scene's document bbox.
bool IsChangeHidden(const KIID_PATH &aChangeId) const
bool m_holdRebuild
While true, rebuildOverlay()/ZoomToFit() are held so a batch renders once.
std::map< KIGFX::VIEW_ITEM *, KICAD_DIFF::CATEGORY > m_itemCategories
void ZoomToBBox(const BOX2I &aBBox)
Zoom and center on a specific document-space bbox with a small margin.
void onLeftDown(wxMouseEvent &aEvent)
void SetWorldUnitLength(double aWorldUnitLength)
void SetCategoryVisible(KICAD_DIFF::CATEGORY aCategory, bool aVisible)
Toggle whether shapes of a given change category render.
void SetHiddenChanges(std::set< KIID_PATH > aHidden)
Replace the set of muted changes.
void refreshItemDimming()
Dim context items that are hidden, or unfocused while a highlight is active.
std::unique_ptr< HIGHLIGHT_BOX_ITEM > m_highlightBox
std::optional< KIID_PATH > m_hover
void SetContextItems(const std::vector< KIGFX::VIEW_ITEM * > &aItems)
Replace source document context items.
void SetItemCategories(std::map< KIGFX::VIEW_ITEM *, KICAD_DIFF::CATEGORY > aMap)
Tag context items by change category so SetCategoryVisible can hide / show them in lockstep with the ...
WIDGET_DIFF_CANVAS(wxWindow *aParent, GAL_TYPE aBackend=GAL_FALLBACK, wxWindowID aId=wxID_ANY)
KICAD_DIFF::DIFF_SCENE m_scene
void SetLayerVisible(PCB_LAYER_ID aLayer, bool aVisible)
Toggle whether board-context geometry on a given PCB layer renders.
void onLeave(wxMouseEvent &aEvent)
ITEM_ID_GETTER m_itemIdGetter
void buildRenderScene()
Recompute the cached render scene (layer-filtered geometry, cleared in native-context mode).
std::unique_ptr< HIGHLIGHT_BOX_ITEM > m_hoverBox
const KICAD_DIFF::SCENE_SHAPE * shapeAt(const wxPoint &aScreenPoint) const
Hit test in screen coordinates → topmost SCENE_SHAPE under the cursor.
std::optional< KIID_PATH > m_highlight
void onSize(wxSizeEvent &aEvent)
KICAD_DIFF::DIFF_SCENE m_renderScene
void SetContextPainter(std::unique_ptr< KIGFX::PAINTER > aPainter)
Install the native painter used for drawing source document context.
void CenterOnHighlight()
Pan so the currently highlighted change is at the center of the canvas.
KIID getItemId(const EDA_ITEM &aItem) const
std::unique_ptr< KIGFX::VIEW_GROUP > m_contextGroup
void rebuildOverlay(bool aOverlayOnly=false)
Rebuild the overlay from the render scene + current highlight state.
bool IsCategoryVisible(KICAD_DIFF::CATEGORY aCategory) const
void onDoubleClick(wxMouseEvent &aEvent)
std::unique_ptr< KIGFX::GAL_DISPLAY_OPTIONS > m_galOptions
EDA_DRAW_PANEL_GAL keeps a reference to the options struct, so it must outlive the panel.
std::vector< KIGFX::VIEW_ITEM * > m_contextGroupItems
bool IsLayerVisible(PCB_LAYER_ID aLayer) const
std::array< bool, KICAD_DIFF::CATEGORY_COUNT > m_categoryVisible
std::shared_ptr< KIGFX::VIEW_OVERLAY > m_overlay
void onMotion(wxMouseEvent &aEvent)
void BeginUpdate()
Hold overlay rebuilds/zoom until EndUpdate, so a batch of changes (e.g.
std::optional< BOX2I > highlightedBBox() const
Union bbox of all shapes whose changeId matches the current highlight, honoring per-category visibili...
std::set< KIID_PATH > m_hiddenChanges
bool m_zoomToFitPending
True when a ZoomToFit was requested before the canvas had a real size — the next onSize will retry th...
void onChar(wxKeyEvent &aEvent)
void onLeftUp(wxMouseEvent &aEvent)
std::optional< BOX2I > m_focusBox
void HighlightChange(std::optional< KIID_PATH > aChangeId)
Outline shape(s) whose SCENE_SHAPE::changeId matches the given path.
@ LAYER_GP_OVERLAY
General purpose overlay.
Definition layer_ids.h:275
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
KIGFX::COLOR4D ThemeColorFor(const DIFF_COLOR_THEME &aTheme, CATEGORY aCategory)
Map a CATEGORY to its color in a DIFF_COLOR_THEME.
std::optional< BOX2I > HighlightedBBox(const DIFF_SCENE &aScene, const KIID_PATH &aChangeId, const std::array< bool, CATEGORY_COUNT > &aCategoryVisible)
Union bbox of every visible SCENE_SHAPE whose changeId matches aChangeId.
void RenderSceneToOverlay(KIGFX::VIEW_OVERLAY &aOverlay, const DIFF_SCENE &aScene, const std::array< bool, CATEGORY_COUNT > &aVisible, const std::optional< KIID_PATH > &aHighlight, const std::set< KIID_PATH > &aHidden)
Push a DIFF_SCENE's shapes onto a VIEW_OVERLAY as filled, semi-transparent rectangles,...
CATEGORY
Visual category each ITEM_CHANGE belongs to in the scene.
Definition diff_scene.h:52
const std::vector< SCENE_SHAPE > & ShapesFor(const DIFF_SCENE &aScene, CATEGORY aCategory)
Read-only access to a DIFF_SCENE's shape list for a given category.
constexpr std::array< CATEGORY, 4 > PAINT_ORDER
Paint order.
Definition diff_scene.h:67
DOCUMENT_GEOMETRY FilterGeometryByVisibleLayers(const DOCUMENT_GEOMETRY &aGeometry, const LSET &aVisibleLayers)
Copy geometry primitives whose layer set intersects aVisibleLayers.
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:30
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:34
@ TARGET_CACHED
Main rendering target (cached)
Definition definitions.h:33
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:35
STL namespace.
Diff colors with defaults for light backgrounds.
Definition diff_scene.h:278
Shared rendering model consumed by both the GAL renderer (interactive widget) and the plotter rendere...
Definition diff_scene.h:90
KIGFX::COLOR4D color
Definition diff_scene.h:92
KIID_PATH changeId
Stable identifier of the ITEM_CHANGE that produced this shape.
Definition diff_scene.h:99
std::string path
VECTOR2I center
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
WX_VIEW_CONTROLS class definition.
#define ZOOM_MIN_LIMIT_DIFF
#define ZOOM_MAX_LIMIT_DIFF