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, wxWindowID aId ) :
51 WIDGET_DIFF_CANVAS( aParent, aId, std::make_unique<KIGFX::GAL_DISPLAY_OPTIONS>() )
52{
53}
54
55
56WIDGET_DIFF_CANVAS::WIDGET_DIFF_CANVAS( wxWindow* aParent, wxWindowID aId,
57 std::unique_ptr<KIGFX::GAL_DISPLAY_OPTIONS> aGalOptions ) :
58 EDA_DRAW_PANEL_GAL( aParent, aId, wxDefaultPosition, wxDefaultSize, *aGalOptions, GAL_FALLBACK ),
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
65 // Until a module installs a native context painter, the canvas renders only
66 // VIEW_OVERLAY commands, which bypass the painter. Reuse the drawing-sheet
67 // pair (also used by PL_DRAW_PANEL_GAL) rather than a private stub. Force
68 // the historical near-white background the diff canvas expects;
69 // DS_RENDER_SETTINGS otherwise defaults to pure white.
70 m_painter = std::make_unique<KIGFX::DS_PAINTER>( m_gal );
71 m_painter->GetSettings()->SetBackgroundColor( KIGFX::COLOR4D( 0.97, 0.97, 0.97, 1.0 ) );
72 m_view->SetPainter( m_painter.get() );
73
75 m_view->SetMirror( false, false );
76
77 m_contextGroup = std::make_unique<KIGFX::VIEW_GROUP>();
79 m_view->Add( m_contextGroup.get(), 0 );
80
81 // The overlay needs to live on a layer the view is willing to draw.
82 // LAYER_GP_OVERLAY is a general-purpose overlay slot used elsewhere in
83 // KiCad GAL panels for non-cached annotation.
85 m_view->SetLayerDisplayOnly( LAYER_GP_OVERLAY );
86 m_view->SetLayerVisible( LAYER_GP_OVERLAY, true );
87
88 m_overlay = m_view->MakeOverlay();
89
90 m_highlightBox = std::make_unique<HIGHLIGHT_BOX_ITEM>();
91 m_hoverBox = std::make_unique<HIGHLIGHT_BOX_ITEM>();
92
94
95 m_gal->SetCursorEnabled( false );
96
97 // Matches DIFF_THUMBNAIL so existing dialog layouts don't collapse the
98 // canvas when sizers are tight.
99 SetMinSize( wxSize( -1, 100 ) );
100
101 Bind( wxEVT_LEFT_DOWN, &WIDGET_DIFF_CANVAS::onLeftDown, this );
102 Bind( wxEVT_LEFT_DCLICK, &WIDGET_DIFF_CANVAS::onDoubleClick, this );
103 Bind( wxEVT_MOTION, &WIDGET_DIFF_CANVAS::onMotion, this );
104 Bind( wxEVT_LEAVE_WINDOW, &WIDGET_DIFF_CANVAS::onLeave, this );
105 Bind( wxEVT_CHAR_HOOK, &WIDGET_DIFF_CANVAS::onChar, this );
106 Bind( wxEVT_SIZE, &WIDGET_DIFF_CANVAS::onSize, this );
107
108 SetEvtHandlerEnabled( true );
109 Show( true );
110 StartDrawing();
111}
112
113
115{
116 StopDrawing();
117
119 {
120 if( item )
121 m_view->Remove( item );
122 }
123
124 m_view->Remove( m_contextGroup.get() );
125 // m_view owns the overlay since MakeOverlay() — no manual Remove needed.
126}
127
128
130{
131 m_scene = std::move( aScene );
132 m_highlight = std::nullopt;
133
136 ZoomToFit();
137}
138
139
140void WIDGET_DIFF_CANVAS::SetWorldUnitLength( double aWorldUnitLength )
141{
142 m_gal->SetWorldUnitLength( aWorldUnitLength );
143 m_gal->ComputeWorldScreenMatrix();
144 ZoomToFit();
145}
146
147
148void WIDGET_DIFF_CANVAS::SetContextPainter( std::unique_ptr<KIGFX::PAINTER> aPainter )
149{
150 if( !aPainter )
151 return;
152
153 m_painter = std::move( aPainter );
154 m_view->SetPainter( m_painter.get() );
155 m_view->MarkDirty();
156 Refresh();
157}
158
159
160void WIDGET_DIFF_CANVAS::SetContextItems( const std::vector<KIGFX::VIEW_ITEM*>& aItems )
161{
162 if( !m_contextGroup )
163 return;
164
166 {
167 if( item )
168 m_view->Remove( item );
169 }
170
171 m_contextGroupItems.clear();
172 m_itemCategories.clear();
173 m_hasNativeContext = false;
174
175 for( KIGFX::VIEW_ITEM* item : aItems )
176 {
177 if( !item )
178 continue;
179
180 m_view->Add( item );
181 m_contextGroupItems.push_back( item );
182 m_hasNativeContext = true;
183 }
184
187}
188
189
190void WIDGET_DIFF_CANVAS::HighlightChange( std::optional<KIID_PATH> aChangeId )
191{
192 if( m_highlight == aChangeId )
193 return;
194
195 m_highlight = std::move( aChangeId );
196
197 const std::optional<KIID> focusKiid =
198 m_highlight && !m_highlight->empty() ? std::optional( m_highlight->back() ) : std::nullopt;
199
200 // Dimming depends only on the hidden set, not the highlight, so it does not
201 // need re-applying here. Re-running it would REPAINT every board item on
202 // each click, which is the source of the highlight lag.
203
204 m_highlightBox->shown = false;
205
206 // The committed selection takes over from any active hover so the rect
207 // doesn't double-draw on the next mouse move.
208 if( focusKiid && m_hover == m_highlight )
209 {
210 m_hover.reset();
211 m_hoverBox->shown = false;
212 }
213
214 if( focusKiid )
215 {
217
219 {
220 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
221
222 if( !eda || eda->m_Uuid != *focusKiid )
223 continue;
224
225 const BOX2I bb = item->ViewBBox();
226
227 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
228 break;
229
230 auto catIt = m_itemCategories.find( item );
231 KIGFX::COLOR4D base = catIt != m_itemCategories.end() ? KICAD_DIFF::ThemeColorFor( theme, catIt->second )
232 : theme.modified;
233
234 base.a = 0.35;
235
236 m_highlightBox->bbox = bb;
237 m_highlightBox->color = base;
238 m_highlightBox->shown = true;
239 break;
240 }
241 }
242
243 rebuildOverlay( /*aOverlayOnly=*/true );
244}
245
246
248{
249 const std::size_t idx = static_cast<std::size_t>( aCategory );
250
251 wxCHECK_RET( idx < m_categoryVisible.size(), wxS( "Invalid CATEGORY" ) );
252
253 if( m_categoryVisible[idx] == aVisible )
254 return;
255
256 m_categoryVisible[idx] = aVisible;
257
258 for( const auto& [item, cat] : m_itemCategories )
259 {
260 if( cat != aCategory )
261 continue;
262
263 m_view->SetVisible( item, aVisible );
264
265 // Force a full repaint so per-item color overrides re-apply.
266 if( aVisible )
267 m_view->Update( item, KIGFX::REPAINT );
268 }
269
271}
272
273
274void WIDGET_DIFF_CANVAS::SetItemCategories( std::map<KIGFX::VIEW_ITEM*, KICAD_DIFF::CATEGORY> aMap )
275{
276 m_itemCategories = std::move( aMap );
277
278 for( const auto& [item, cat] : m_itemCategories )
279 {
280 const std::size_t idx = static_cast<std::size_t>( cat );
281
282 if( idx < m_categoryVisible.size() )
283 m_view->SetVisible( item, m_categoryVisible[idx] );
284 }
285}
286
287
289{
290 const std::size_t idx = static_cast<std::size_t>( aCategory );
291
292 wxCHECK( idx < m_categoryVisible.size(), false );
293
294 return m_categoryVisible[idx];
295}
296
297
298void WIDGET_DIFF_CANVAS::SetHiddenChanges( std::set<KIID_PATH> aHidden )
299{
300 if( m_hiddenChanges == aHidden )
301 return;
302
303 m_hiddenChanges = std::move( aHidden );
306}
307
308
309bool WIDGET_DIFF_CANVAS::IsChangeHidden( const KIID_PATH& aChangeId ) const
310{
311 return m_hiddenChanges.count( aChangeId ) > 0;
312}
313
314
316{
317 if( !m_itemDimmer )
318 return;
319
320 // Item Uuids of the hidden changes (a change id's last element is its item).
321 std::set<KIID> hiddenItems;
322
323 for( const KIID_PATH& path : m_hiddenChanges )
324 {
325 if( !path.empty() )
326 hiddenItems.insert( path.back() );
327 }
328
330 {
331 if( !item )
332 continue;
333
334 EDA_ITEM* eda = dynamic_cast<EDA_ITEM*>( item );
335 const bool hidden = eda && hiddenItems.count( eda->m_Uuid ) > 0;
336
337 m_itemDimmer( item, hidden );
338 m_view->Update( item, KIGFX::REPAINT );
339 }
340}
341
342
344{
345 if( aLayer < 0 || aLayer >= PCB_LAYER_ID_COUNT )
346 return;
347
348 if( m_layerVisible.Contains( aLayer ) == aVisible )
349 return;
350
351 m_layerVisible.set( aLayer, aVisible );
352 m_view->SetLayerVisible( aLayer, aVisible );
355}
356
357
359{
360 return m_layerVisible.Contains( aLayer );
361}
362
363
368
369
371{
372 m_holdRebuild = false;
374
376 ZoomToFit();
377}
378
379
381{
382 if( m_holdRebuild )
383 {
384 m_zoomToFitPending = true;
385 return;
386 }
387
388 BOX2I bb = m_scene.documentBBox;
389 bool haveBox = bb.GetWidth() > 0 && bb.GetHeight() > 0;
390
391 // Also frame the context items so the whole board fits, not just the changes.
393 {
394 if( !item )
395 continue;
396
397 BOX2I ib = item->ViewBBox();
398
399 if( ib.GetWidth() <= 0 || ib.GetHeight() <= 0 )
400 continue;
401
402 if( haveBox )
403 {
404 bb.Merge( ib );
405 }
406 else
407 {
408 bb = ib;
409 haveBox = true;
410 }
411 }
412
413 if( !haveBox )
414 {
415 m_zoomToFitPending = false;
416 return;
417 }
418
419 // VIEW::SetViewport silently no-ops when the GAL has no screen size, so
420 // defer the fit until we've been sized at least once.
421 const wxSize client = GetClientSize();
422
423 if( client.x <= 0 || client.y <= 0 )
424 {
425 m_zoomToFitPending = true;
426 return;
427 }
428
429 ZoomToBBox( bb );
430 m_zoomToFitPending = false;
431}
432
433
435{
436 if( !aBBox.GetWidth() || !aBBox.GetHeight() )
437 return;
438
439 BOX2D viewport( VECTOR2D( aBBox.GetLeft(), aBBox.GetTop() ), VECTOR2D( aBBox.GetWidth(), aBBox.GetHeight() ) );
440
441 // Inflate slightly so the outermost shape isn't flush with the edge.
442 viewport.Inflate( aBBox.GetWidth() * 0.05, aBBox.GetHeight() * 0.05 );
443
444 m_view->SetViewport( viewport );
445 Refresh();
446}
447
448
450{
451 std::optional<BOX2I> bb = highlightedBBox();
452
453 if( !bb || bb->GetWidth() <= 0 || bb->GetHeight() <= 0 )
454 return;
455
456 const VECTOR2I center = bb->GetCenter();
457 m_view->SetCenter( VECTOR2D( center.x, center.y ) );
458 m_view->MarkDirty();
459 Refresh();
460}
461
462
464{
466
468 {
469 m_renderScene.referenceGeometry = {};
470 m_renderScene.comparisonGeometry = {};
471 }
472 else
473 {
474 m_renderScene.referenceGeometry =
476 m_renderScene.comparisonGeometry =
478 }
479}
480
481
482void WIDGET_DIFF_CANVAS::rebuildOverlay( bool aOverlayOnly )
483{
484 if( m_holdRebuild )
485 return;
486
488
489 auto drawBox = [&]( const HIGHLIGHT_BOX_ITEM* aBox )
490 {
491 if( !aBox || !aBox->shown || aBox->bbox.GetWidth() <= 0 || aBox->bbox.GetHeight() <= 0 )
492 return;
493
494 m_overlay->SetIsFill( true );
495 m_overlay->SetIsStroke( false );
496 m_overlay->SetFillColor( aBox->color );
497 m_overlay->Rectangle( aBox->bbox.GetOrigin(), aBox->bbox.GetEnd() );
498 };
499
500 drawBox( m_hoverBox.get() );
501 drawBox( m_highlightBox.get() );
502
503 if( aOverlayOnly )
504 m_view->MarkTargetDirty( KIGFX::TARGET_OVERLAY );
505 else
506 m_view->MarkDirty();
507
508 Refresh();
509}
510
511
512const KICAD_DIFF::SCENE_SHAPE* WIDGET_DIFF_CANVAS::shapeAt( const wxPoint& aScreenPoint ) const
513{
514 if( !m_view )
515 return nullptr;
516
517 // Convert from screen to document coordinates.
518 const VECTOR2D doc = m_view->ToWorld( VECTOR2D( aScreenPoint.x, aScreenPoint.y ) );
519
520 // Walk PAINT_ORDER in reverse so topmost shape wins, mirroring the
521 // thumbnail's hit-test order.
522 for( auto it = KICAD_DIFF::PAINT_ORDER.rbegin(); it != KICAD_DIFF::PAINT_ORDER.rend(); ++it )
523 {
524 if( !IsCategoryVisible( *it ) )
525 continue;
526
527 const std::vector<KICAD_DIFF::SCENE_SHAPE>& list = KICAD_DIFF::ShapesFor( m_scene, *it );
528
529 for( auto sIt = list.rbegin(); sIt != list.rend(); ++sIt )
530 {
531 // Muted changes let clicks fall through to what is underneath.
532 if( m_hiddenChanges.count( sIt->changeId ) > 0 )
533 continue;
534
535 if( sIt->bbox.Contains( VECTOR2I( KiROUND( doc.x ), KiROUND( doc.y ) ) ) )
536 return &*sIt;
537 }
538 }
539
540 return nullptr;
541}
542
543
544void WIDGET_DIFF_CANVAS::onLeftDown( wxMouseEvent& aEvent )
545{
546 std::optional<KIID_PATH> picked;
547
548 if( const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() ) )
549 picked = shape->changeId;
550
551 SetFocus();
552 aEvent.Skip();
553
554 if( m_pickHandler )
555 m_pickHandler( picked );
556}
557
558
559void WIDGET_DIFF_CANVAS::onDoubleClick( wxMouseEvent& aEvent )
560{
561 aEvent.Skip();
562
563 if( !m_dclickHandler || m_contextGroupItems.empty() )
564 return;
565
566 const VECTOR2D world = m_view->ToWorld( VECTOR2D( aEvent.GetPosition().x, aEvent.GetPosition().y ) );
567 const VECTOR2I worldI( KiROUND( world.x ), KiROUND( world.y ) );
568
569 KIGFX::VIEW_ITEM* hit = nullptr;
570 BOX2I hitBBox;
571
572 // Reverse so the topmost item wins if bboxes overlap.
573 for( auto it = m_contextGroupItems.rbegin(); it != m_contextGroupItems.rend(); ++it )
574 {
575 KIGFX::VIEW_ITEM* item = *it;
576
577 if( !item )
578 continue;
579
580 const BOX2I bb = item->ViewBBox();
581
582 if( bb.GetWidth() <= 0 || bb.GetHeight() <= 0 )
583 continue;
584
585 if( !bb.Contains( worldI ) )
586 continue;
587
588 // Prefer the smallest matching bbox so a nested sheet wins over its parent.
589 if( !hit || bb.GetArea() < hitBBox.GetArea() )
590 {
591 hit = item;
592 hitBBox = bb;
593 }
594 }
595
596 if( hit )
597 m_dclickHandler( hit );
598}
599
600
601void WIDGET_DIFF_CANVAS::onMotion( wxMouseEvent& aEvent )
602{
603 aEvent.Skip();
604
605 std::optional<KIID_PATH> hovered;
606 const KICAD_DIFF::SCENE_SHAPE* shape = shapeAt( aEvent.GetPosition() );
607
608 // Suppress hover when it would land on the already-selected change so the
609 // committed highlight stays clean.
610 if( shape && ( !m_highlight || shape->changeId != *m_highlight ) )
611 hovered = shape->changeId;
612
613 if( hovered == m_hover )
614 return;
615
616 m_hover = hovered;
617 m_hoverBox->shown = false;
618
619 if( shape && hovered )
620 {
621 KIGFX::COLOR4D base = shape->color;
622 base.a = 0.20;
623 m_hoverBox->bbox = shape->bbox;
624 m_hoverBox->color = base;
625 m_hoverBox->shown = true;
626 }
627
628 rebuildOverlay( /*aOverlayOnly=*/true );
629}
630
631
632void WIDGET_DIFF_CANVAS::onLeave( wxMouseEvent& aEvent )
633{
634 aEvent.Skip();
635
636 if( !m_hover && !m_hoverBox->shown )
637 return;
638
639 m_hover.reset();
640 m_hoverBox->shown = false;
641 rebuildOverlay( /*aOverlayOnly=*/true );
642}
643
644
645void WIDGET_DIFF_CANVAS::onChar( wxKeyEvent& aEvent )
646{
647 switch( aEvent.GetKeyCode() )
648 {
649 case WXK_HOME:
650 if( m_scene.documentBBox.GetWidth() || m_scene.documentBBox.GetHeight() )
651 {
652 ZoomToFit();
653 return;
654 }
655
656 aEvent.Skip();
657 return;
658
659 case 'F':
660 case 'f':
661 if( std::optional<BOX2I> bbox = highlightedBBox() )
662 {
663 ZoomToBBox( *bbox );
664 return;
665 }
666
667 aEvent.Skip();
668 return;
669
670 case WXK_ESCAPE:
672 {
673 m_pickHandler( std::nullopt );
674 return;
675 }
676
677 aEvent.Skip();
678 return;
679
680 default: aEvent.Skip(); return;
681 }
682}
683
684
685void WIDGET_DIFF_CANVAS::onSize( wxSizeEvent& aEvent )
686{
687 aEvent.Skip();
688
690 ZoomToFit();
691}
692
693
694std::optional<BOX2I> WIDGET_DIFF_CANVAS::highlightedBBox() const
695{
696 if( !m_highlight.has_value() )
697 return std::nullopt;
698
700}
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
BOX2< VECTOR2D > BOX2D
Definition box2.h:919
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:554
constexpr size_type GetWidth() const
Definition box2.h:210
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr ecoord_type GetArea() const
Return the area of the rectangle.
Definition box2.h:757
constexpr size_type GetHeight() const
Definition box2.h:211
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:164
constexpr coord_type GetTop() const
Definition box2.h:225
static constexpr GAL_TYPE GAL_FALLBACK
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
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.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
const KIID m_Uuid
Definition eda_item.h:531
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double a
Alpha component.
Definition color4d.h:392
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
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 ...
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
WIDGET_DIFF_CANVAS(wxWindow *aParent, wxWindowID aId=wxID_ANY)
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:29
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ 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