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_DCLICK, &WIDGET_DIFF_CANVAS::onDoubleClick, this );
108 Bind( wxEVT_MOTION, &WIDGET_DIFF_CANVAS::onMotion, this );
109 Bind( wxEVT_LEAVE_WINDOW, &WIDGET_DIFF_CANVAS::onLeave, this );
110 Bind( wxEVT_CHAR_HOOK, &WIDGET_DIFF_CANVAS::onChar, this );
111 Bind( wxEVT_SIZE, &WIDGET_DIFF_CANVAS::onSize, this );
112
113 SetEvtHandlerEnabled( true );
114 Show( true );
115 StartDrawing();
116}
117
118
120{
121 StopDrawing();
122
124 {
125 if( item )
126 m_view->Remove( item );
127 }
128
129 m_view->Remove( m_contextGroup.get() );
130 // m_view owns the overlay since MakeOverlay() — no manual Remove needed.
131}
132
133
135{
136 m_scene = std::move( aScene );
137 m_highlight = std::nullopt;
138
141 ZoomToFit();
142}
143
144
145void WIDGET_DIFF_CANVAS::SetWorldUnitLength( double aWorldUnitLength )
146{
147 m_gal->SetWorldUnitLength( aWorldUnitLength );
148 m_gal->ComputeWorldScreenMatrix();
149 ZoomToFit();
150}
151
152
153void WIDGET_DIFF_CANVAS::SetContextPainter( std::unique_ptr<KIGFX::PAINTER> aPainter )
154{
155 if( !aPainter )
156 return;
157
158 m_painter = std::move( aPainter );
159 m_view->SetPainter( m_painter.get() );
160 m_view->MarkDirty();
161 Refresh();
162}
163
164
165void WIDGET_DIFF_CANVAS::SetContextItems( const std::vector<KIGFX::VIEW_ITEM*>& aItems )
166{
167 if( !m_contextGroup )
168 return;
169
171 {
172 if( item )
173 m_view->Remove( item );
174 }
175
176 m_contextGroupItems.clear();
177 m_itemCategories.clear();
178 m_hasNativeContext = false;
179
180 for( KIGFX::VIEW_ITEM* item : aItems )
181 {
182 if( !item )
183 continue;
184
185 m_view->Add( item );
186 m_contextGroupItems.push_back( item );
187 m_hasNativeContext = true;
188 }
189
192}
193
194
195void WIDGET_DIFF_CANVAS::HighlightChange( std::optional<KIID_PATH> aChangeId )
196{
197 if( m_highlight == aChangeId )
198 return;
199
200 m_highlight = std::move( aChangeId );
201
202 const std::optional<KIID> focusKiid =
203 m_highlight && !m_highlight->empty() ? std::optional( m_highlight->back() ) : std::nullopt;
204
205 // Dimming depends only on the hidden set, not the highlight, so it does not
206 // need re-applying here. Re-running it would REPAINT every board item on
207 // each click, which is the source of the highlight lag.
208
209 m_highlightBox->shown = false;
210
211 // The committed selection takes over from any active hover so the rect
212 // doesn't double-draw on the next mouse move.
213 if( focusKiid && m_hover == m_highlight )
214 {
215 m_hover.reset();
216 m_hoverBox->shown = false;
217 }
218
219 if( focusKiid )
220 {
222
224 {
225 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
226
227 if( !eda || eda->m_Uuid != *focusKiid )
228 continue;
229
230 const BOX2I bb = item->ViewBBox();
231
232 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
233 break;
234
235 auto catIt = m_itemCategories.find( item );
236 KIGFX::COLOR4D base = catIt != m_itemCategories.end() ? KICAD_DIFF::ThemeColorFor( theme, catIt->second )
237 : theme.modified;
238
239 base.a = 0.35;
240
241 m_highlightBox->bbox = bb;
242 m_highlightBox->color = base;
243 m_highlightBox->shown = true;
244 break;
245 }
246 }
247
248 rebuildOverlay( /*aOverlayOnly=*/true );
249}
250
251
253{
254 const std::size_t idx = static_cast<std::size_t>( aCategory );
255
256 wxCHECK_RET( idx < m_categoryVisible.size(), wxS( "Invalid CATEGORY" ) );
257
258 if( m_categoryVisible[idx] == aVisible )
259 return;
260
261 m_categoryVisible[idx] = aVisible;
262
263 for( const auto& [item, cat] : m_itemCategories )
264 {
265 if( cat != aCategory )
266 continue;
267
268 m_view->SetVisible( item, aVisible );
269
270 // Force a full repaint so per-item color overrides re-apply.
271 if( aVisible )
272 m_view->Update( item, KIGFX::REPAINT );
273 }
274
276}
277
278
279void WIDGET_DIFF_CANVAS::SetItemCategories( std::map<KIGFX::VIEW_ITEM*, KICAD_DIFF::CATEGORY> aMap )
280{
281 m_itemCategories = std::move( aMap );
282
283 for( const auto& [item, cat] : m_itemCategories )
284 {
285 const std::size_t idx = static_cast<std::size_t>( cat );
286
287 if( idx < m_categoryVisible.size() )
288 m_view->SetVisible( item, m_categoryVisible[idx] );
289 }
290}
291
292
294{
295 const std::size_t idx = static_cast<std::size_t>( aCategory );
296
297 wxCHECK( idx < m_categoryVisible.size(), false );
298
299 return m_categoryVisible[idx];
300}
301
302
303void WIDGET_DIFF_CANVAS::SetHiddenChanges( std::set<KIID_PATH> aHidden )
304{
305 if( m_hiddenChanges == aHidden )
306 return;
307
308 m_hiddenChanges = std::move( aHidden );
311}
312
313
314bool WIDGET_DIFF_CANVAS::IsChangeHidden( const KIID_PATH& aChangeId ) const
315{
316 return m_hiddenChanges.count( aChangeId ) > 0;
317}
318
319
321{
322 if( !m_itemDimmer )
323 return;
324
325 // Item Uuids of the hidden changes (a change id's last element is its item).
326 std::set<KIID> hiddenItems;
327
328 for( const KIID_PATH& path : m_hiddenChanges )
329 {
330 if( !path.empty() )
331 hiddenItems.insert( path.back() );
332 }
333
335 {
336 if( !item )
337 continue;
338
339 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
340 const bool hidden = eda && hiddenItems.count( eda->m_Uuid ) > 0;
341
342 m_itemDimmer( item, hidden );
343 m_view->Update( item, KIGFX::REPAINT );
344 }
345}
346
347
349{
350 if( aLayer < 0 || aLayer >= PCB_LAYER_ID_COUNT )
351 return;
352
353 if( m_layerVisible.Contains( aLayer ) == aVisible )
354 return;
355
356 m_layerVisible.set( aLayer, aVisible );
357 m_view->SetLayerVisible( aLayer, aVisible );
360}
361
362
364{
365 return m_layerVisible.Contains( aLayer );
366}
367
368
373
374
376{
377 m_holdRebuild = false;
379
381 ZoomToFit();
382}
383
384
386{
387 if( m_holdRebuild )
388 {
389 m_zoomToFitPending = true;
390 return;
391 }
392
393 BOX2I bb = m_scene.documentBBox;
394 bool haveBox = bb.GetWidth() > 0 && bb.GetHeight() > 0;
395
396 // Also frame the context items so the whole board fits, not just the changes.
398 {
399 if( !item )
400 continue;
401
402 BOX2I ib = item->ViewBBox();
403
404 if( ib.GetWidth() <= 0 || ib.GetHeight() <= 0 )
405 continue;
406
407 if( haveBox )
408 {
409 bb.Merge( ib );
410 }
411 else
412 {
413 bb = ib;
414 haveBox = true;
415 }
416 }
417
418 if( !haveBox )
419 {
420 m_zoomToFitPending = false;
421 return;
422 }
423
424 // VIEW::SetViewport silently no-ops when the GAL has no screen size, so
425 // defer the fit until we've been sized at least once.
426 const wxSize client = GetClientSize();
427
428 if( client.x <= 0 || client.y <= 0 )
429 {
430 m_zoomToFitPending = true;
431 return;
432 }
433
434 ZoomToBBox( bb );
435 m_zoomToFitPending = false;
436}
437
438
440{
441 if( !aBBox.GetWidth() || !aBBox.GetHeight() )
442 return;
443
444 BOX2D viewport( VECTOR2D( aBBox.GetLeft(), aBBox.GetTop() ), VECTOR2D( aBBox.GetWidth(), aBBox.GetHeight() ) );
445
446 // Inflate slightly so the outermost shape isn't flush with the edge.
447 viewport.Inflate( aBBox.GetWidth() * 0.05, aBBox.GetHeight() * 0.05 );
448
449 m_view->SetViewport( viewport );
450 Refresh();
451}
452
453
455{
456 std::optional<BOX2I> bb = highlightedBBox();
457
458 if( !bb || bb->GetWidth() <= 0 || bb->GetHeight() <= 0 )
459 return;
460
461 const VECTOR2I center = bb->GetCenter();
462 m_view->SetCenter( VECTOR2D( center.x, center.y ) );
463 m_view->MarkDirty();
464 Refresh();
465}
466
467
469{
471
473 {
474 m_renderScene.referenceGeometry = {};
475 m_renderScene.comparisonGeometry = {};
476 }
477 else
478 {
479 m_renderScene.referenceGeometry =
481 m_renderScene.comparisonGeometry =
483 }
484}
485
486
487void WIDGET_DIFF_CANVAS::rebuildOverlay( bool aOverlayOnly )
488{
489 if( m_holdRebuild )
490 return;
491
493
494 auto drawBox = [&]( const HIGHLIGHT_BOX_ITEM* aBox )
495 {
496 if( !aBox || !aBox->shown || aBox->bbox.GetWidth() <= 0 || aBox->bbox.GetHeight() <= 0 )
497 return;
498
499 m_overlay->SetIsFill( true );
500 m_overlay->SetIsStroke( false );
501 m_overlay->SetFillColor( aBox->color );
502 m_overlay->Rectangle( aBox->bbox.GetOrigin(), aBox->bbox.GetEnd() );
503 };
504
505 drawBox( m_hoverBox.get() );
506 drawBox( m_highlightBox.get() );
507
508 if( aOverlayOnly )
509 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
510 else
511 m_view->MarkDirty();
512
513 Refresh();
514}
515
516
517const KICAD_DIFF::SCENE_SHAPE* WIDGET_DIFF_CANVAS::shapeAt( const wxPoint& aScreenPoint ) const
518{
519 if( !m_view )
520 return nullptr;
521
522 // Convert from screen to document coordinates.
523 const VECTOR2D doc = m_view->ToWorld( VECTOR2D( aScreenPoint.x, aScreenPoint.y ) );
524
525 // Walk PAINT_ORDER in reverse so topmost shape wins, mirroring the
526 // thumbnail's hit-test order.
527 for( auto it = KICAD_DIFF::PAINT_ORDER.rbegin(); it != KICAD_DIFF::PAINT_ORDER.rend(); ++it )
528 {
529 if( !IsCategoryVisible( *it ) )
530 continue;
531
532 const std::vector<KICAD_DIFF::SCENE_SHAPE>& list = KICAD_DIFF::ShapesFor( m_scene, *it );
533
534 for( auto sIt = list.rbegin(); sIt != list.rend(); ++sIt )
535 {
536 // Muted changes let clicks fall through to what is underneath.
537 if( m_hiddenChanges.count( sIt->changeId ) > 0 )
538 continue;
539
540 if( sIt->bbox.Contains( VECTOR2I( KiROUND( doc.x ), KiROUND( doc.y ) ) ) )
541 return &*sIt;
542 }
543 }
544
545 return nullptr;
546}
547
548
549void WIDGET_DIFF_CANVAS::onLeftDown( wxMouseEvent& aEvent )
550{
551 std::optional<KIID_PATH> picked;
552
553 if( const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() ) )
554 picked = shape->changeId;
555
556 SetFocus();
557 aEvent.Skip();
558
559 if( m_pickHandler )
560 m_pickHandler( picked );
561}
562
563
564void WIDGET_DIFF_CANVAS::onDoubleClick( wxMouseEvent& aEvent )
565{
566 aEvent.Skip();
567
568 if( !m_dclickHandler || m_contextGroupItems.empty() )
569 return;
570
571 const VECTOR2D world = m_view->ToWorld( VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y ) );
572 const VECTOR2I worldI( KiROUND( world.x ), KiROUND( world.y ) );
573
574 KIGFX::VIEW_ITEM* hit = nullptr;
575 BOX2I hitBBox;
576
577 // Reverse so the topmost item wins if bboxes overlap.
578 for( auto it = m_contextGroupItems.rbegin(); it != m_contextGroupItems.rend(); ++it )
579 {
580 KIGFX::VIEW_ITEM* item = *it;
581
582 if( !item )
583 continue;
584
585 const BOX2I bb = item->ViewBBox();
586
587 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
588 continue;
589
590 if( !bb.Contains( worldI ) )
591 continue;
592
593 // Prefer the smallest matching bbox so a nested sheet wins over its parent.
594 if( !hit || bb.GetArea() < hitBBox.GetArea() )
595 {
596 hit = item;
597 hitBBox = bb;
598 }
599 }
600
601 if( hit )
602 m_dclickHandler( hit );
603}
604
605
606void WIDGET_DIFF_CANVAS::onMotion( wxMouseEvent& aEvent )
607{
608 aEvent.Skip();
609
610 std::optional<KIID_PATH> hovered;
611 const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() );
612
613 // Suppress hover when it would land on the already-selected change so the
614 // committed highlight stays clean.
615 if( shape && ( !m_highlight || shape->changeId != *m_highlight ) )
616 hovered = shape->changeId;
617
618 if( hovered == m_hover )
619 return;
620
621 m_hover = hovered;
622 m_hoverBox->shown = false;
623
624 if( shape && hovered )
625 {
626 KIGFX::COLOR4D base = shape->color;
627 base.a = 0.20;
628 m_hoverBox->bbox = shape->bbox;
629 m_hoverBox->color = base;
630 m_hoverBox->shown = true;
631 }
632
633 rebuildOverlay( /*aOverlayOnly=*/true );
634}
635
636
637void WIDGET_DIFF_CANVAS::onLeave( wxMouseEvent& aEvent )
638{
639 aEvent.Skip();
640
641 if( !m_hover && !m_hoverBox->shown )
642 return;
643
644 m_hover.reset();
645 m_hoverBox->shown = false;
646 rebuildOverlay( /*aOverlayOnly=*/true );
647}
648
649
650void WIDGET_DIFF_CANVAS::onChar( wxKeyEvent& aEvent )
651{
652 switch( aEvent.GetKeyCode() )
653 {
654 case WXK_HOME:
655 if( m_scene.documentBBox.GetWidth() || m_scene.documentBBox.GetHeight() )
656 {
657 ZoomToFit();
658 return;
659 }
660
661 aEvent.Skip();
662 return;
663
664 case 'F':
665 case 'f':
666 if( std::optional<BOX2I> bbox = highlightedBBox() )
667 {
668 ZoomToBBox( *bbox );
669 return;
670 }
671
672 aEvent.Skip();
673 return;
674
675 case WXK_ESCAPE:
677 {
678 m_pickHandler( std::nullopt );
679 return;
680 }
681
682 aEvent.Skip();
683 return;
684
685 default: aEvent.Skip(); return;
686 }
687}
688
689
690void WIDGET_DIFF_CANVAS::onSize( wxSizeEvent& aEvent )
691{
692 aEvent.Skip();
693
695 ZoomToFit();
696}
697
698
699std::optional<BOX2I> WIDGET_DIFF_CANVAS::highlightedBBox() const
700{
701 if( !m_highlight.has_value() )
702 return std::nullopt;
703
705}
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:995
BOX2< VECTOR2D > BOX2D
Definition box2.h:928
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:653
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:756
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.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
@ GAL_TYPE_OPENGL
OpenGL implementation.
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:597
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double a
Alpha component.
Definition color4d.h:393
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:63
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:773
An implementation of class VIEW_CONTROLS for wxWidgets library.
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)
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.
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 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.
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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682
WX_VIEW_CONTROLS class definition.
#define ZOOM_MIN_LIMIT_DIFF
#define ZOOM_MAX_LIMIT_DIFF