Skip to content

Commit

Permalink
feat(DevTools): Add to Events View visual feedback (#14467)
Browse files Browse the repository at this point in the history
  • Loading branch information
workgroupengineering authored Feb 16, 2024
1 parent 59f8c68 commit 47700d2
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -44,4 +61,44 @@ public override void Render(DrawingContext context)
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,7 @@ bool FilterNode(EventTreeNodeBase node, bool isParentVisible)
return node.IsVisible;
}
}

public MainViewModel MainView => _mainViewModel;
}
}
10 changes: 8 additions & 2 deletions src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,20 @@
<ListBox ItemsSource="{Binding SelectedEvent.EventChain}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem Classes.handled="{Binding Handled}">
<ListBoxItem Classes.handled="{Binding Handled}"
PointerEntered="ListBoxItem_PointerEntered"
PointerExited="ListBoxItem_PointerExited"
>
<StackPanel Orientation="Vertical">

<Rectangle IsVisible="{Binding BeginsNewRoute}" StrokeDashArray="2,2" StrokeThickness="1" Stroke="Gray" />

<StackPanel Orientation="Horizontal" Spacing="2">
<TextBlock Text="{Binding Route}" FontWeight="Bold" />
<TextBlock Tag="{Binding}" DoubleTapped="NavigateTo" Text="{Binding HandlerName}" Classes="nav" />
<TextBlock Tag="{Binding}"
DoubleTapped="NavigateTo"
Text="{Binding HandlerName}"
Classes="nav" />
</StackPanel>

</StackPanel>
Expand Down
17 changes: 17 additions & 0 deletions src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace Avalonia.Diagnostics.Views
internal class EventsPageView : UserControl
{
private readonly ListBox _events;
private IDisposable? _adorner;

public EventsPageView()
{
Expand Down Expand Up @@ -72,5 +73,21 @@ private void InitializeComponent()
{
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();
}
}
}
92 changes: 11 additions & 81 deletions src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs
Original file line number Diff line number Diff line change
@@ -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<TreeView>("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>())
{
border.Margin = default;
border.Padding = default;
border.BorderThickness = default;
}

_currentLayer?.Children.Remove(_adorner);
_currentLayer = null;
}

protected void UpdateAdorner(object? sender, PointerEventArgs e)
Expand All @@ -109,7 +31,7 @@ protected void UpdateAdorner(object? sender, PointerEventArgs e)
return;
}

RemoveAdorner(sender, e);
_adorner?.Dispose();

if (item is null || item.TreeViewOwner != _tree)
{
Expand All @@ -118,7 +40,15 @@ protected void UpdateAdorner(object? sender, PointerEventArgs e)
}

_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)
Expand Down

0 comments on commit 47700d2

Please sign in to comment.