From 47700d2856585714a337195650ad6482d72b2bf4 Mon Sep 17 00:00:00 2001 From: workgroupengineering Date: Fri, 16 Feb 2024 06:21:56 +0100 Subject: [PATCH] feat(DevTools): Add to Events View visual feedback (#14467) --- .../Controls/ControlHighlightAdorner.cs | 59 +++++++++++- .../ViewModels/EventsPageViewModel.cs | 2 + .../Diagnostics/Views/EventsPageView.xaml | 10 +- .../Diagnostics/Views/EventsPageView.xaml.cs | 17 ++++ .../Diagnostics/Views/TreePageView.xaml.cs | 92 +++---------------- 5 files changed, 96 insertions(+), 84 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Controls/ControlHighlightAdorner.cs b/src/Avalonia.Diagnostics/Diagnostics/Controls/ControlHighlightAdorner.cs index 56c933cfbd..47c4455b8b 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Controls/ControlHighlightAdorner.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Controls/ControlHighlightAdorner.cs @@ -9,7 +9,24 @@ namespace Avalonia.Diagnostics.Controls; internal class ControlHighlightAdorner : Control { - + private static readonly Panel _layoutHighlightAdorner; + static ControlHighlightAdorner() + { + _layoutHighlightAdorner = new Panel + { + ClipToBounds = false, + Children = + { + //Padding frame + new Border { BorderBrush = new SolidColorBrush(Colors.Green, 0.5) }, + //Content frame + new Border { Background = new SolidColorBrush(Color.FromRgb(160, 197, 232), 0.5) }, + //Margin frame + new Border { BorderBrush = new SolidColorBrush(Colors.Yellow, 0.5) } + }, + }; + AdornerLayer.SetIsClipEnabled(_layoutHighlightAdorner, false); + } readonly IPen _pen; private ControlHighlightAdorner(IPen pen) @@ -44,4 +61,44 @@ internal class ControlHighlightAdorner : Control context.DrawRectangle(_pen, Bounds.Deflate(2)); } + internal static IDisposable? Add(Visual visual, bool visualizeMarginPadding) + { + if (AdornerLayer.GetAdornerLayer(visual) is { } layer) + { + if (layer.Children.Contains(_layoutHighlightAdorner)) + { + return default; + } + layer.Children.Add(_layoutHighlightAdorner); + AdornerLayer.SetAdornedElement(_layoutHighlightAdorner, visual); + var paddingBorder = (Border)_layoutHighlightAdorner.Children[0]; + var contentBorder = (Border)_layoutHighlightAdorner.Children[1]; + var marginBorder = (Border)_layoutHighlightAdorner.Children[2]; + if (visualizeMarginPadding) + { + paddingBorder.BorderThickness = visual.GetValue(TemplatedControl.PaddingProperty); + contentBorder.Margin = visual.GetValue(TemplatedControl.PaddingProperty); + marginBorder.BorderThickness = visual.GetValue(MarginProperty); + marginBorder.Margin = InvertThickness(visual.GetValue(TemplatedControl.MarginProperty)); + } + else + { + paddingBorder.BorderThickness = default; + contentBorder.Margin = default; + marginBorder.BorderThickness = default; + marginBorder.Margin = default; + } + return Disposable.Create((Layer: layer, Adorner: _layoutHighlightAdorner), state => + { + state.Layer.Children.Remove(state.Adorner); + }); + } + return default; + } + + + private static Thickness InvertThickness(Thickness input) + { + return new Thickness(-input.Left, -input.Top, -input.Right, -input.Bottom); + } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventsPageViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventsPageViewModel.cs index c5868e0e0c..2704a8184b 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventsPageViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventsPageViewModel.cs @@ -171,5 +171,7 @@ namespace Avalonia.Diagnostics.ViewModels return node.IsVisible; } } + + public MainViewModel MainView => _mainViewModel; } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml index c18b8cf003..88b57e1747 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml @@ -113,14 +113,20 @@ - + - + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs index 954b75fb23..1a64b871d0 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs @@ -15,6 +15,7 @@ namespace Avalonia.Diagnostics.Views internal class EventsPageView : UserControl { private readonly ListBox _events; + private IDisposable? _adorner; public EventsPageView() { @@ -72,5 +73,21 @@ namespace Avalonia.Diagnostics.Views { AvaloniaXamlLoader.Load(this); } + + private void ListBoxItem_PointerEntered(object? sender, PointerEventArgs e) + { + if (DataContext is EventsPageViewModel vm + && sender is ListBoxItem control + && control.DataContext is EventChainLink chainLink + && chainLink.Handler is Visual visual) + { + _adorner = Controls.ControlHighlightAdorner.Add(visual, vm.MainView.ShouldVisualizeMarginPadding); + } + } + + private void ListBoxItem_PointerExited(object? sender, PointerEventArgs e) + { + _adorner?.Dispose(); + } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs index 485216234d..f85a61d930 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs @@ -1,99 +1,21 @@ -using System.Linq; using Avalonia.Controls; -using Avalonia.Controls.Primitives; using Avalonia.Diagnostics.ViewModels; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; -using Avalonia.Media; namespace Avalonia.Diagnostics.Views { internal class TreePageView : UserControl { - private readonly Panel _adorner; - private AdornerLayer? _currentLayer; private TreeViewItem? _hovered; private TreeView _tree; + private System.IDisposable? _adorner; public TreePageView() { InitializeComponent(); _tree = this.GetControl("tree"); - - _adorner = new Panel - { - ClipToBounds = false, - Children = - { - //Padding frame - new Border { BorderBrush = new SolidColorBrush(Colors.Green, 0.5) }, - //Content frame - new Border { Background = new SolidColorBrush(Color.FromRgb(160, 197, 232), 0.5) }, - //Margin frame - new Border { BorderBrush = new SolidColorBrush(Colors.Yellow, 0.5) } - }, - }; - AdornerLayer.SetIsClipEnabled(_adorner, false); - } - - private static Thickness InvertThickness(Thickness input) - { - return new Thickness(-input.Left, -input.Top, -input.Right, -input.Bottom); - } - - protected void AddAdorner(object? sender, PointerEventArgs e) - { - var node = (TreeNode?)((Control)sender!).DataContext; - var vm = (TreePageViewModel?)DataContext; - if (node is null || vm is null) - { - return; - } - - var visual = node.Visual as Visual; - - if (visual is null) - { - return; - } - - _currentLayer = AdornerLayer.GetAdornerLayer(visual); - - if (_currentLayer == null || - _currentLayer.Children.Contains(_adorner)) - { - return; - } - - _currentLayer.Children.Add(_adorner); - AdornerLayer.SetAdornedElement(_adorner, visual); - - if (vm.MainView.ShouldVisualizeMarginPadding) - { - var paddingBorder = (Border)_adorner.Children[0]; - paddingBorder.BorderThickness = visual.GetValue(PaddingProperty); - - var contentBorder = (Border)_adorner.Children[1]; - contentBorder.Margin = visual.GetValue(PaddingProperty); - - var marginBorder = (Border)_adorner.Children[2]; - marginBorder.BorderThickness = visual.GetValue(MarginProperty); - marginBorder.Margin = InvertThickness(visual.GetValue(MarginProperty)); - } - } - - protected void RemoveAdorner(object? sender, PointerEventArgs e) - { - foreach (var border in _adorner.Children.OfType()) - { - border.Margin = default; - border.Padding = default; - border.BorderThickness = default; - } - - _currentLayer?.Children.Remove(_adorner); - _currentLayer = null; } protected void UpdateAdorner(object? sender, PointerEventArgs e) @@ -109,7 +31,7 @@ namespace Avalonia.Diagnostics.Views return; } - RemoveAdorner(sender, e); + _adorner?.Dispose(); if (item is null || item.TreeViewOwner != _tree) { @@ -118,7 +40,15 @@ namespace Avalonia.Diagnostics.Views } _hovered = item; - AddAdorner(item, e); + + var visual = (item.DataContext as TreeNode)?.Visual as Visual; + var shouldVisualizeMarginPadding = (DataContext as TreePageViewModel)?.MainView.ShouldVisualizeMarginPadding; + if (visual is null || shouldVisualizeMarginPadding is null) + { + return; + } + + _adorner = Controls.ControlHighlightAdorner.Add(visual, visualizeMarginPadding: shouldVisualizeMarginPadding == true); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)