From 0ae36f98ba4deefce188e1bd8026f523d2570e20 Mon Sep 17 00:00:00 2001
From: Stephen Monaco <1782158+stevemonaco@users.noreply.github.com>
Date: Tue, 14 May 2024 06:01:00 -0400
Subject: [PATCH] Add HotKeys Page to DevTools (#15700)
* Add HotKeys Page to DevTools
* Centralize hotkeys and hoist into DevToolsOptions
---
.../Diagnostics/DevToolsOptions.cs | 5 +
.../Diagnostics/HotKeyConfiguration.cs | 32 +++++
.../ViewModels/HotKeyPageViewModel.cs | 40 ++++++
.../Diagnostics/ViewModels/MainViewModel.cs | 12 ++
.../Diagnostics/Views/HotKeyPageView.axaml | 36 +++++
.../Diagnostics/Views/HotKeyPageView.axaml.cs | 18 +++
.../Diagnostics/Views/MainView.xaml | 2 +
.../Diagnostics/Views/MainWindow.xaml | 3 -
.../Diagnostics/Views/MainWindow.xaml.cs | 135 +++++++++++-------
9 files changed, 231 insertions(+), 52 deletions(-)
create mode 100644 src/Avalonia.Diagnostics/Diagnostics/HotKeyConfiguration.cs
create mode 100644 src/Avalonia.Diagnostics/Diagnostics/ViewModels/HotKeyPageViewModel.cs
create mode 100644 src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml
create mode 100644 src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml.cs
diff --git a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
index b2d1ab98c9..6993935aca 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs
@@ -57,5 +57,10 @@ namespace Avalonia.Diagnostics
/// Set the kind of diagnostic view that show at launch of DevTools
///
public DevToolsViewKind LaunchView { get; init; }
+
+ ///
+ /// Gets or inits the used to activate DevTools features
+ ///
+ internal HotKeyConfiguration HotKeys { get; init; } = new();
}
}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/HotKeyConfiguration.cs b/src/Avalonia.Diagnostics/Diagnostics/HotKeyConfiguration.cs
new file mode 100644
index 0000000000..85d88a5a59
--- /dev/null
+++ b/src/Avalonia.Diagnostics/Diagnostics/HotKeyConfiguration.cs
@@ -0,0 +1,32 @@
+using Avalonia.Input;
+
+namespace Avalonia.Diagnostics
+{
+ internal class HotKeyConfiguration
+ {
+ ///
+ /// Freezes refreshing the Value Frames inspector for the selected Control
+ ///
+ public KeyGesture ValueFramesFreeze { get; init; } = new(Key.S, KeyModifiers.Alt);
+
+ ///
+ /// Resumes refreshing the Value Frames inspector for the selected Control
+ ///
+ public KeyGesture ValueFramesUnfreeze { get; init; } = new(Key.D, KeyModifiers.Alt);
+
+ ///
+ /// Inspects the hovered Control in the Logical or Visual Tree Page
+ ///
+ public KeyGesture InspectHoveredControl { get; init; } = new(Key.None, KeyModifiers.Shift | KeyModifiers.Control);
+
+ ///
+ /// Toggles the freezing of Popups which prevents visible Popups from closing so they can be inspected
+ ///
+ public KeyGesture TogglePopupFreeze { get; init; } = new(Key.F, KeyModifiers.Alt | KeyModifiers.Control);
+
+ ///
+ /// Saves a Screenshot of the Selected Control in the Logical or Visual Tree Page
+ ///
+ public KeyGesture ScreenshotSelectedControl { get; init; } = new(Key.F8);
+ }
+}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/HotKeyPageViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/HotKeyPageViewModel.cs
new file mode 100644
index 0000000000..5fdcc689ca
--- /dev/null
+++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/HotKeyPageViewModel.cs
@@ -0,0 +1,40 @@
+using System.Collections.ObjectModel;
+using Avalonia.Input;
+
+namespace Avalonia.Diagnostics.ViewModels
+{
+ internal record HotKeyDescription(string Gesture, string BriefDescription, string? DetailedDescription = null);
+
+ internal class HotKeyPageViewModel : ViewModelBase
+ {
+ private ObservableCollection? _hotKeyDescriptions;
+ public ObservableCollection? HotKeyDescriptions
+ {
+ get => _hotKeyDescriptions;
+ private set => RaiseAndSetIfChanged(ref _hotKeyDescriptions, value);
+ }
+
+ public void SetOptions(DevToolsOptions options)
+ {
+ var hotKeys = options.HotKeys;
+
+ HotKeyDescriptions = new()
+ {
+ new(CreateDescription(options.Gesture), "Launch DevTools", "Launches DevTools to inspect the TopLevel that received the hotkey input"),
+ new(CreateDescription(hotKeys.ValueFramesFreeze), "Freeze Value Frames", "Pauses refreshing the Value Frames inspector for the selected Control"),
+ new(CreateDescription(hotKeys.ValueFramesUnfreeze), "Unfreeze Value Frames", "Resumes refreshing the Value Frames inspector for the selected Control"),
+ new(CreateDescription(hotKeys.InspectHoveredControl), "Inspect Control Under Pointer", "Inspects the hovered Control in the Logical or Visual Tree Page"),
+ new(CreateDescription(hotKeys.TogglePopupFreeze), "Toggle Popup Freeze", "Prevents visible Popups from closing so they can be inspected"),
+ new(CreateDescription(hotKeys.ScreenshotSelectedControl), "Screenshot Selected Control", "Saves a Screenshot of the Selected Control in the Logical or Visual Tree Page")
+ };
+ }
+
+ private string CreateDescription(KeyGesture gesture)
+ {
+ if (gesture.Key == Key.None && gesture.KeyModifiers != KeyModifiers.None)
+ return gesture.ToString().Replace("+None", "");
+ else
+ return gesture.ToString();
+ }
+ }
+}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
index eaa5802aa5..36e0cf5ebc 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
+++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
@@ -18,6 +18,7 @@ namespace Avalonia.Diagnostics.ViewModels
private readonly TreePageViewModel _logicalTree;
private readonly TreePageViewModel _visualTree;
private readonly EventsPageViewModel _events;
+ private readonly HotKeyPageViewModel _hotKeys;
private readonly IDisposable _pointerOverSubscription;
private ViewModelBase? _content;
private int _selectedTab;
@@ -40,6 +41,7 @@ namespace Avalonia.Diagnostics.ViewModels
_logicalTree = new TreePageViewModel(this, LogicalTreeNode.Create(root), _pinnedProperties);
_visualTree = new TreePageViewModel(this, VisualTreeNode.Create(root), _pinnedProperties);
_events = new EventsPageViewModel(this);
+ _hotKeys = new HotKeyPageViewModel();
UpdateFocusedControl();
@@ -194,6 +196,9 @@ namespace Avalonia.Diagnostics.ViewModels
case 2:
Content = _events;
break;
+ case 3:
+ Content = _hotKeys;
+ break;
default:
Content = _logicalTree;
break;
@@ -231,6 +236,11 @@ namespace Avalonia.Diagnostics.ViewModels
private set => RaiseAndSetIfChanged(ref _pointerOverElementName, value);
}
+ public void ShowHotKeys()
+ {
+ SelectedTab = 3;
+ }
+
public void SelectControl(Control control)
{
var tree = Content as TreePageViewModel;
@@ -333,6 +343,8 @@ namespace Avalonia.Diagnostics.ViewModels
ShowImplementedInterfaces = options.ShowImplementedInterfaces;
FocusHighlighter = options.FocusHighlighterBrush;
SelectedTab = (int)options.LaunchView;
+
+ _hotKeys.SetOptions(options);
}
public bool ShowImplementedInterfaces
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml b/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml
new file mode 100644
index 0000000000..381cd7fba6
--- /dev/null
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml.cs
new file mode 100644
index 0000000000..df50bfadf0
--- /dev/null
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/HotKeyPageView.axaml.cs
@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Avalonia.Diagnostics.Views
+{
+ internal class HotKeyPageView : UserControl
+ {
+ public HotKeyPageView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml
index bcb1e56d20..c36ccde8c0 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml
@@ -72,6 +72,7 @@
+