|
|
|
@ -1,5 +1,11 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using Avalonia.Controls; |
|
|
|
using Avalonia.Controls.Primitives; |
|
|
|
using Avalonia.LogicalTree; |
|
|
|
using Avalonia.Metadata; |
|
|
|
using Avalonia.Styling; |
|
|
|
using Avalonia.VisualTree; |
|
|
|
|
|
|
|
namespace Avalonia.Diagnostics.ViewModels |
|
|
|
@ -21,6 +27,8 @@ namespace Avalonia.Diagnostics.ViewModels |
|
|
|
SettersFilter.RefreshFilter += (s, e) => Details?.UpdateStyleFilters(); |
|
|
|
} |
|
|
|
|
|
|
|
public event EventHandler<string>? ClipboardCopyRequested; |
|
|
|
|
|
|
|
public MainViewModel MainView { get; } |
|
|
|
|
|
|
|
public FilterViewModel PropertiesFilter { get; } |
|
|
|
@ -106,6 +114,105 @@ namespace Avalonia.Diagnostics.ViewModels |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void CopySelector() |
|
|
|
{ |
|
|
|
var currentVisual = SelectedNode?.Visual as Visual; |
|
|
|
if (currentVisual is not null) |
|
|
|
{ |
|
|
|
var selector = GetVisualSelector(currentVisual); |
|
|
|
|
|
|
|
ClipboardCopyRequested?.Invoke(this, selector); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void CopySelectorFromTemplateParent() |
|
|
|
{ |
|
|
|
var parts = new List<string>(); |
|
|
|
|
|
|
|
var currentVisual = SelectedNode?.Visual as Visual; |
|
|
|
while (currentVisual is not null) |
|
|
|
{ |
|
|
|
parts.Add(GetVisualSelector(currentVisual)); |
|
|
|
|
|
|
|
currentVisual = currentVisual.TemplatedParent as Visual; |
|
|
|
} |
|
|
|
|
|
|
|
if (parts.Any()) |
|
|
|
{ |
|
|
|
parts.Reverse(); |
|
|
|
var selector = string.Join(" /template/ ", parts); |
|
|
|
|
|
|
|
ClipboardCopyRequested?.Invoke(this, selector); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void ExpandRecursively() |
|
|
|
{ |
|
|
|
if (SelectedNode is { } selectedNode) |
|
|
|
{ |
|
|
|
ExpandNode(selectedNode); |
|
|
|
|
|
|
|
var stack = new Stack<TreeNode>(); |
|
|
|
stack.Push(selectedNode); |
|
|
|
|
|
|
|
while (stack.Count > 0) |
|
|
|
{ |
|
|
|
var item = stack.Pop(); |
|
|
|
item.IsExpanded = true; |
|
|
|
foreach (var child in item.Children) |
|
|
|
{ |
|
|
|
stack.Push(child); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void CollapseChildren() |
|
|
|
{ |
|
|
|
if (SelectedNode is { } selectedNode) |
|
|
|
{ |
|
|
|
var stack = new Stack<TreeNode>(); |
|
|
|
stack.Push(selectedNode); |
|
|
|
|
|
|
|
while (stack.Count > 0) |
|
|
|
{ |
|
|
|
var item = stack.Pop(); |
|
|
|
item.IsExpanded = false; |
|
|
|
foreach (var child in item.Children) |
|
|
|
{ |
|
|
|
stack.Push(child); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void CaptureNodeScreenshot() |
|
|
|
{ |
|
|
|
MainView.Shot(null); |
|
|
|
} |
|
|
|
|
|
|
|
public void BringIntoView() |
|
|
|
{ |
|
|
|
(SelectedNode?.Visual as Control)?.BringIntoView(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void Focus() |
|
|
|
{ |
|
|
|
(SelectedNode?.Visual as Control)?.Focus(); |
|
|
|
} |
|
|
|
|
|
|
|
private static string GetVisualSelector(Visual visual) |
|
|
|
{ |
|
|
|
var name = string.IsNullOrEmpty(visual.Name) ? "" : $"#{visual.Name}"; |
|
|
|
var classes = string.Concat(visual.Classes |
|
|
|
.Where(c => !c.StartsWith(":")) |
|
|
|
.Select(c => '.' + c)); |
|
|
|
var typeName = ((IStyleable)visual).StyleKey.Name; |
|
|
|
|
|
|
|
return $"{typeName}{name}{classes}"; |
|
|
|
} |
|
|
|
|
|
|
|
private void ExpandNode(TreeNode? node) |
|
|
|
{ |
|
|
|
if (node != null) |
|
|
|
|