Files
AIC-Project/Client/PackageLocal/com.unity.pipeline@0.4.0-exp.1/Editor/Commands/CaptureEditorElementCommand.cs
T

78 lines
4.0 KiB
C#

#if UNITY_6000_7_OR_NEWER
using System.IO;
using System.Linq;
using Unity.Pipeline.Commands;
using Unity.Pipeline.Runtime.Commands;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.Pipeline.Editor.Commands
{
/// <summary>
/// Captures a UI Toolkit <see cref="VisualElement"/> from an <see cref="EditorWindow"/> to a PNG
/// and returns it base64-encoded (and writes it to disk). The element is located by a USS-like
/// selector within the window's <see cref="EditorWindow.rootVisualElement"/>.
///
/// Selection, capture, and encoding are shared with the runtime command via
/// <see cref="VisualElementCaptureSupport"/>; this command only resolves the target window.
/// </summary>
public static class CaptureEditorElementCommand
{
[CliCommand("capture_editor_element",
"Capture a UI Toolkit VisualElement (by selector) from an EditorWindow to a PNG; returns path + base64.",
MainThreadRequired = true)]
public static CaptureElementResponse CaptureEditorElement(
[CliArg("window", "EditorWindow type name (e.g. InspectorWindow) or window title to capture from.", Required = true)] string window = "",
[CliArg("selector", "Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)).", Required = true)] string selector = "",
[CliArg("output", "Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under <project>/Temp/pipeline-screenshots/.")] string output = "")
{
if (string.IsNullOrWhiteSpace(window))
return CaptureElementResponse.Fail("A 'window' (EditorWindow type name or title) is required.");
if (string.IsNullOrWhiteSpace(selector))
return CaptureElementResponse.Fail("A 'selector' is required.");
var target = ResolveWindow(window);
if (target == null)
return CaptureElementResponse.Fail(
$"No open EditorWindow matched '{window}' (by type name or title). Open the window first.");
var root = target.rootVisualElement;
if (root == null)
return CaptureElementResponse.Fail($"EditorWindow '{window}' has no rootVisualElement.");
var element = VisualElementCaptureSupport.ResolveElement(root, selector);
if (element == null)
return CaptureElementResponse.Fail(
$"No element matched selector '{selector}' in window '{window}'.");
var projectRoot = Path.GetDirectoryName(Application.dataPath);
var defaultDir = Path.Combine(projectRoot, "Temp", "pipeline-screenshots");
return VisualElementCaptureSupport.CaptureAndRespond(
element, selector, $"window:{window}", output,
relativeBaseDir: projectRoot, defaultDir: defaultDir, prefix: "element");
}
/// <summary>
/// Find an open EditorWindow whose runtime type name or title matches <paramref name="window"/>.
/// Uses <c>Resources.FindObjectsOfTypeAll</c> so hidden/utility windows are included too, but
/// prefers a match whose root is actually attached to a panel — <c>FindObjectsOfTypeAll</c> can
/// also return stale/backup window instances whose <c>rootVisualElement</c> has no panel (and
/// therefore cannot be captured).
/// </summary>
static EditorWindow ResolveWindow(string window)
{
var windows = Resources.FindObjectsOfTypeAll<EditorWindow>();
bool Matches(EditorWindow w) =>
w.GetType().Name == window ||
(w.titleContent != null && w.titleContent.text == window);
return windows.FirstOrDefault(w => Matches(w)
&& w.rootVisualElement != null && w.rootVisualElement.panel != null)
?? windows.FirstOrDefault(Matches);
}
}
}
#endif