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 || getItemId( *eda ) != *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 IDs 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( getItemId( *eda ) ) > 0;
341
342 m_itemDimmer( item, hidden );
343 m_view->Update( item, KIGFX::REPAINT );
344 }
345}
346
347
349{
350 return m_itemIdGetter ? m_itemIdGetter( aItem ) : aItem.m_Uuid;
351}
352
353
355{
356 if( aLayer < 0 || aLayer >= PCB_LAYER_ID_COUNT )
357 return;
358
359 if( m_layerVisible.Contains( aLayer ) == aVisible )
360 return;
361
362 m_layerVisible.set( aLayer, aVisible );
363 m_view->SetLayerVisible( aLayer, aVisible );
366}
367
368
370{
371 return m_layerVisible.Contains( aLayer );
372}
373
374
379
380
382{
383 m_holdRebuild = false;
385
387 ZoomToFit();
388}
389
390
392{
393 if( m_holdRebuild )
394 {
395 m_zoomToFitPending = true;
396 return;
397 }
398
399 BOX2I bb = m_scene.documentBBox;
400 bool haveBox = bb.GetWidth() > 0 && bb.GetHeight() > 0;
401
402 // Also frame the context items so the whole board fits, not just the changes.
404 {
405 if( !item )
406 continue;
407
408 BOX2I ib = item->ViewBBox();
409
410 if( ib.GetWidth() <= 0 || ib.GetHeight() <= 0 )
411 continue;
412
413 if( haveBox )
414 {
415 bb.Merge( ib );
416 }
417 else
418 {
419 bb = ib;
420 haveBox = true;
421 }
422 }
423
424 if( !haveBox )
425 {
426 m_zoomToFitPending = false;
427 return;
428 }
429
430 // VIEW::SetViewport silently no-ops when the GAL has no screen size, so
431 // defer the fit until we've been sized at least once.
432 const wxSize client = GetClientSize();
433
434 if( client.x <= 0 || client.y <= 0 )
435 {
436 m_zoomToFitPending = true;
437 return;
438 }
439
440 ZoomToBBox( bb );
441 m_zoomToFitPending = false;
442}
443
444
446{
447 if( !aBBox.GetWidth() || !aBBox.GetHeight() )
448 return;
449
450 BOX2D viewport( VECTOR2D( aBBox.GetLeft(), aBBox.GetTop() ), VECTOR2D( aBBox.GetWidth(), aBBox.GetHeight() ) );
451
452 // Inflate slightly so the outermost shape isn't flush with the edge.
453 viewport.Inflate( aBBox.GetWidth() * 0.05, aBBox.GetHeight() * 0.05 );
454
455 m_view->SetViewport( viewport );
456 Refresh();
457}
458
459
461{
462 std::optional<BOX2I> bb = highlightedBBox();
463
464 if( !bb || bb->GetWidth() <= 0 || bb->GetHeight() <= 0 )
465 return;
466
467 const VECTOR2I center = bb->GetCenter();
468 m_view->SetCenter( VECTOR2D( center.x, center.y ) );
469 m_view->MarkDirty();
470 Refresh();
471}
472
473
475{
477
479 {
480 m_renderScene.referenceGeometry = {};
481 m_renderScene.comparisonGeometry = {};
482 }
483 else
484 {
485 m_renderScene.referenceGeometry =
487 m_renderScene.comparisonGeometry =
489 }
490}
491
492
493void WIDGET_DIFF_CANVAS::rebuildOverlay( bool aOverlayOnly )
494{
495 if( m_holdRebuild )
496 return;
497
499
500 auto drawBox = [&]( const HIGHLIGHT_BOX_ITEM* aBox )
501 {
502 if( !aBox || !aBox->shown || aBox->bbox.GetWidth() <= 0 || aBox->bbox.GetHeight() <= 0 )
503 return;
504
505 m_overlay->SetIsFill( true );
506 m_overlay->SetIsStroke( false );
507 m_overlay->SetFillColor( aBox->color );
508 m_overlay->Rectangle( aBox->bbox.GetOrigin(), aBox->bbox.GetEnd() );
509 };
510
511 drawBox( m_hoverBox.get() );
512 drawBox( m_highlightBox.get() );
513
514 if( aOverlayOnly )
515 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
516 else
517 m_view->MarkDirty();
518
519 Refresh();
520}
521
522
523const KICAD_DIFF::SCENE_SHAPE* WIDGET_DIFF_CANVAS::shapeAt( const wxPoint& aScreenPoint ) const
524{
525 if( !m_view )
526 return nullptr;
527
528 // Convert from screen to document coordinates.
529 const VECTOR2D doc = m_view->ToWorld( VECTOR2D( aScreenPoint.x, aScreenPoint.y ) );
530
531 // Walk PAINT_ORDER in reverse so topmost shape wins, mirroring the
532 // thumbnail's hit-test order.
533 for( auto it = KICAD_DIFF::PAINT_ORDER.rbegin(); it != KICAD_DIFF::PAINT_ORDER.rend(); ++it )
534 {
535 if( !IsCategoryVisible( *it ) )
536 continue;
537
538 const std::vector<KICAD_DIFF::SCENE_SHAPE>& list = KICAD_DIFF::ShapesFor( m_scene, *it );
539
540 for( auto sIt = list.rbegin(); sIt != list.rend(); ++sIt )
541 {
542 // Muted changes let clicks fall through to what is underneath.
543 if( m_hiddenChanges.count( sIt->changeId ) > 0 )
544 continue;
545
546 if( sIt->bbox.Contains( VECTOR2I( KiROUND( doc.x ), KiROUND( doc.y ) ) ) )
547 return &*sIt;
548 }
549 }
550
551 return nullptr;
552}
553
554
555void WIDGET_DIFF_CANVAS::onLeftDown( wxMouseEvent& aEvent )
556{
557 std::optional<KIID_PATH> picked;
558
559 if( const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() ) )
560 picked = shape->changeId;
561
562 SetFocus();
563 aEvent.Skip();
564
565 if( m_pickHandler )
566 m_pickHandler( picked );
567}
568
569
570void WIDGET_DIFF_CANVAS::onDoubleClick( wxMouseEvent& aEvent )
571{
572 aEvent.Skip();
573
574 if( !m_dclickHandler || m_contextGroupItems.empty() )
575 return;
576
577 const VECTOR2D world = m_view->ToWorld( VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y ) );
578 const VECTOR2I worldI( KiROUND( world.x ), KiROUND( world.y ) );
579
580 KIGFX::VIEW_ITEM* hit = nullptr;
581 BOX2I hitBBox;
582
583 // Reverse so the topmost item wins if bboxes overlap.
584 for( auto it = m_contextGroupItems.rbegin(); it != m_contextGroupItems.rend(); ++it )
585 {
586 KIGFX::VIEW_ITEM* item = *it;
587
588 if( !item )
589 continue;
590
591 const BOX2I bb = item->ViewBBox();
592
593 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
594 continue;
595
596 if( !bb.Contains( worldI ) )
597 continue;
598
599 // Prefer the smallest matching bbox so a nested sheet wins over its parent.
600 if( !hit || bb.GetArea() < hitBBox.GetArea() )
601 {
602 hit = item;
603 hitBBox = bb;
604 }
605 }
606
607 if( hit )
608 m_dclickHandler( hit );
609}
610
611
612void WIDGET_DIFF_CANVAS::onMotion( wxMouseEvent& aEvent )
613{
614 aEvent.Skip();
615
616 std::optional<KIID_PATH> hovered;
617 const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() );
618
619 // Suppress hover when it would land on the already-selected change so the
620 // committed highlight stays clean.
621 if( shape && ( !m_highlight || shape->changeId != *m_highlight ) )
622 hovered = shape->changeId;
623
624 if( hovered == m_hover )
625 return;
626
627 m_hover = hovered;
628 m_hoverBox->shown = false;
629
630 if( shape && hovered )
631 {
632 KIGFX::COLOR4D base = shape->color;
633 base.a = 0.20;
634 m_hoverBox->bbox = shape->bbox;
635 m_hoverBox->color = base;
636 m_hoverBox->shown = true;
637 }
638
639 rebuildOverlay( /*aOverlayOnly=*/true );
640}
641
642
643void WIDGET_DIFF_CANVAS::onLeave( wxMouseEvent& aEvent )
644{
645 aEvent.Skip();
646
647 if( !m_hover && !m_hoverBox->shown )
648 return;
649
650 m_hover.reset();
651 m_hoverBox->shown = false;
652 rebuildOverlay( /*aOverlayOnly=*/true );
653}
654
655
656void WIDGET_DIFF_CANVAS::onChar( wxKeyEvent& aEvent )
657{
658 switch( aEvent.GetKeyCode() )
659 {
660 case WXK_HOME:
661 if( m_scene.documentBBox.GetWidth() || m_scene.documentBBox.GetHeight() )
662 {
663 ZoomToFit();
664 return;
665 }
666
667 aEvent.Skip();
668 return;
669
670 case 'F':
671 case 'f':
672 if( std::optional<BOX2I> bbox = highlightedBBox() )
673 {
674 ZoomToBBox( *bbox );
675 return;
676 }
677
678 aEvent.Skip();
679 return;
680
681 case WXK_ESCAPE:
683 {
684 m_pickHandler( std::nullopt );
685 return;
686 }
687
688 aEvent.Skip();
689 return;
690
691 default: aEvent.Skip(); return;
692 }
693}
694
695
696void WIDGET_DIFF_CANVAS::onSize( wxSizeEvent& aEvent )
697{
698 aEvent.Skip();
699
701 ZoomToFit();
702}
703
704
705std::optional<BOX2I> WIDGET_DIFF_CANVAS::highlightedBBox() const
706{
707 if( !m_highlight.has_value() )
708 return std::nullopt;
709
711}
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.
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: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:63
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:775
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 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:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
WX_VIEW_CONTROLS class definition.
#define ZOOM_MIN_LIMIT_DIFF
#define ZOOM_MAX_LIMIT_DIFF