Preview: promote selected layer for hit testing
Temporarily raise the selected preview item and prioritize it in the custom hit test without changing scene order. Refresh integration-test expectations for Brand logo layers and explicit thumbnail assets. WPF references: https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.panel.zindex?view=windowsdesktop-10.0 https://learn.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/hit-testing-in-the-visual-layer
This commit is contained in:
@@ -31,6 +31,7 @@ public partial class PreviewPane : UserControl
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += PreviewPane_DataContextChanged;
|
||||
OverlayElements.ItemContainerGenerator.StatusChanged += (_, _) => UpdateSelectedLayerZOrder();
|
||||
}
|
||||
|
||||
private void PreviewPane_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
@@ -45,6 +46,7 @@ public partial class PreviewPane : UserControl
|
||||
newVm.PropertyChanged += ViewModel_PropertyChanged;
|
||||
newVm.PreviewTransition += PlayPreviewTransition;
|
||||
UpdateZoomBox();
|
||||
UpdateSelectedLayerZOrder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,12 +94,27 @@ public partial class PreviewPane : UserControl
|
||||
|
||||
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(MainViewModel.SelectedElement))
|
||||
UpdateSelectedLayerZOrder();
|
||||
if (e.PropertyName == nameof(MainViewModel.IsZoomActive) || e.PropertyName == nameof(MainViewModel.ZoomState) || e.PropertyName == nameof(MainViewModel.ZoomShape))
|
||||
{
|
||||
UpdateZoomBox();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSelectedLayerZOrder()
|
||||
{
|
||||
var selected = (DataContext as MainViewModel)?.SelectedElement;
|
||||
if (selected != null && !IsDraggableElement(selected))
|
||||
selected = null;
|
||||
|
||||
for (var i = 0; i < OverlayElements.Items.Count; i++)
|
||||
{
|
||||
if (OverlayElements.ItemContainerGenerator.ContainerFromIndex(i) is UIElement container)
|
||||
Panel.SetZIndex(container, ReferenceEquals(OverlayElements.Items[i], selected) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Static images and the webcam share the move/resize/selection behavior.
|
||||
@@ -439,7 +456,7 @@ public partial class PreviewPane : UserControl
|
||||
return;
|
||||
}
|
||||
|
||||
var hit = HitElement(vm, p);
|
||||
var hit = HitElementAt(vm, p);
|
||||
if (hit != null)
|
||||
{
|
||||
vm.SelectedElement = hit;
|
||||
@@ -593,23 +610,34 @@ public partial class PreviewPane : UserControl
|
||||
return Math.Abs(mouseScreen.X - corner.X) <= 20 && Math.Abs(mouseScreen.Y - corner.Y) <= 20;
|
||||
}
|
||||
|
||||
private SceneElement? HitElement(MainViewModel vm, Point p)
|
||||
internal SceneElement? HitElementAt(MainViewModel vm, Point p)
|
||||
{
|
||||
var scene = vm.StagedScene;
|
||||
if (scene == null) return null;
|
||||
|
||||
// A layer selected from the list temporarily wins both preview stacking and hit-testing;
|
||||
// the scene's persistent element order remains unchanged.
|
||||
if (vm.SelectedElement is { } selected && IsHitTestable(selected) && Contains(selected, p))
|
||||
return selected;
|
||||
|
||||
for (var i = scene.Elements.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var element = scene.Elements[i];
|
||||
if (!IsDraggableElement(element)) continue;
|
||||
if (element is Source { IsEnabled: false }) continue;
|
||||
if (element is WebcamSceneConfig { IsVisible: false }) continue;
|
||||
if (p.X >= element.X && p.X <= element.X + element.Width &&
|
||||
p.Y >= element.Y && p.Y <= element.Y + element.Height)
|
||||
if (IsHitTestable(element) && Contains(element, p))
|
||||
return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsHitTestable(SceneElement element)
|
||||
=> IsDraggableElement(element)
|
||||
&& element is not Source { IsEnabled: false }
|
||||
&& element is not WebcamSceneConfig { IsVisible: false };
|
||||
|
||||
private static bool Contains(SceneElement element, Point point)
|
||||
=> point.X >= element.X && point.X <= element.X + element.Width
|
||||
&& point.Y >= element.Y && point.Y <= element.Y + element.Height;
|
||||
|
||||
private void UpdateZoomBox()
|
||||
{
|
||||
if (DataContext is not MainViewModel vm) return;
|
||||
@@ -645,4 +673,4 @@ public partial class PreviewPane : UserControl
|
||||
ZoomVisualBrush.Visual = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user