com.alicizax.unity.ui.exten.../Editor/UX/Controller/UXControllerSceneOverlayWindow.cs

275 lines
9.3 KiB
C#
Raw Normal View History

#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace UnityEngine.UI
{
public sealed class UXControllerSceneOverlayWindow : EditorWindow
{
private const string OverlayEnabledKey = "AlicizaX.UI.UXControllerSceneOverlay.Enabled";
private const string OverlayAutoFocusKey = "AlicizaX.UI.UXControllerSceneOverlay.AutoFocus";
private const float OverlayWidth = 360f;
private const float OverlayMargin = 12f;
private static bool s_overlayEnabled;
private static bool s_autoFocusSceneView;
private static Vector2 s_scrollPosition;
private static bool s_registered;
[MenuItem("Window/UX/Controller Scene Overlay")]
public static void ShowWindow()
{
var window = GetWindow<UXControllerSceneOverlayWindow>("UX Controller Overlay");
window.minSize = new Vector2(320f, 140f);
window.Show();
EnsureRegistered();
}
[InitializeOnLoadMethod]
private static void Initialize()
{
s_overlayEnabled = EditorPrefs.GetBool(OverlayEnabledKey, false);
s_autoFocusSceneView = EditorPrefs.GetBool(OverlayAutoFocusKey, false);
EnsureRegistered();
}
private static void EnsureRegistered()
{
if (s_registered)
{
return;
}
SceneView.duringSceneGui += OnSceneGui;
s_registered = true;
}
private void OnGUI()
{
EditorGUILayout.LabelField("Scene View Overlay", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
"When enabled, the Scene View will display all UXController components in the current loaded scenes and let you preview them directly.",
MessageType.Info);
EditorGUI.BeginChangeCheck();
bool overlayEnabled = EditorGUILayout.Toggle("Enable Overlay", s_overlayEnabled);
bool autoFocus = EditorGUILayout.Toggle("Focus SceneView On Open", s_autoFocusSceneView);
if (EditorGUI.EndChangeCheck())
{
s_overlayEnabled = overlayEnabled;
s_autoFocusSceneView = autoFocus;
EditorPrefs.SetBool(OverlayEnabledKey, s_overlayEnabled);
EditorPrefs.SetBool(OverlayAutoFocusKey, s_autoFocusSceneView);
SceneView.RepaintAll();
}
EditorGUILayout.Space(8f);
if (GUILayout.Button("Repaint Scene View"))
{
SceneView.RepaintAll();
}
if (GUILayout.Button("Open Scene View"))
{
SceneView.FocusWindowIfItsOpen<SceneView>();
}
}
private static void OnSceneGui(SceneView sceneView)
{
if (!s_overlayEnabled)
{
return;
}
if (s_autoFocusSceneView && sceneView != null)
{
s_autoFocusSceneView = false;
EditorPrefs.SetBool(OverlayAutoFocusKey, false);
sceneView.Focus();
}
List<UXController> controllers = GetSceneControllers();
Handles.BeginGUI();
float height = Mathf.Max(160f, sceneView.position.height - OverlayMargin * 2f);
Rect area = new Rect(
sceneView.position.width - OverlayWidth - OverlayMargin,
OverlayMargin,
OverlayWidth,
height);
GUILayout.BeginArea(area, EditorStyles.helpBox);
DrawOverlayContent(controllers);
GUILayout.EndArea();
Handles.EndGUI();
}
private static void DrawOverlayContent(List<UXController> controllers)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("UX Controllers", EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
2026-03-22 13:28:15 +08:00
if (GUILayout.Button("Hide", GUILayout.Width(64f)))
{
s_overlayEnabled = false;
EditorPrefs.SetBool(OverlayEnabledKey, s_overlayEnabled);
SceneView.RepaintAll();
}
if (GUILayout.Button("Refresh", GUILayout.Width(64f)))
{
SceneView.RepaintAll();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(4f);
if (controllers.Count == 0)
{
EditorGUILayout.HelpBox("No UXController found in the current loaded scenes.", MessageType.Info);
return;
}
s_scrollPosition = EditorGUILayout.BeginScrollView(s_scrollPosition);
for (int i = 0; i < controllers.Count; i++)
{
DrawControllerCard(controllers[i], i);
EditorGUILayout.Space(4f);
}
EditorGUILayout.EndScrollView();
}
private static void DrawControllerCard(UXController controller, int index)
{
if (controller == null)
{
return;
}
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField($"{index + 1}. {controller.gameObject.name}", EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
if (GUILayout.Button("Select", GUILayout.Width(52f)))
{
Selection.activeGameObject = controller.gameObject;
EditorGUIUtility.PingObject(controller.gameObject);
}
if (GUILayout.Button("Reset", GUILayout.Width(52f)))
{
controller.ResetAllControllers();
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.LabelField(GetHierarchyPath(controller.transform), EditorStyles.miniLabel);
EditorGUILayout.LabelField($"Bindings: {controller.Bindings.Count}", EditorStyles.miniLabel);
for (int controllerIndex = 0; controllerIndex < controller.ControllerCount; controllerIndex++)
{
UXController.ControllerDefinition definition = controller.GetControllerAt(controllerIndex);
if (definition == null)
{
continue;
}
DrawDefinitionPreview(controller, definition);
}
EditorGUILayout.EndVertical();
}
private static void DrawDefinitionPreview(UXController controller, UXController.ControllerDefinition definition)
{
EditorGUILayout.Space(3f);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField(definition.Name, EditorStyles.boldLabel);
if (!string.IsNullOrWhiteSpace(definition.Description))
{
EditorGUILayout.LabelField(definition.Description, EditorStyles.miniLabel);
}
int currentIndex = Mathf.Max(0, definition.SelectedIndex);
int length = Mathf.Max(1, definition.Length);
string[] options = new string[length];
for (int i = 0; i < length; i++)
{
options[i] = i.ToString();
}
EditorGUI.BeginChangeCheck();
int newIndex = GUILayout.SelectionGrid(currentIndex, options, Mathf.Min(length, 5));
if (EditorGUI.EndChangeCheck())
{
controller.SetControllerIndex(definition.Id, newIndex);
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
EditorGUILayout.EndVertical();
}
private static List<UXController> GetSceneControllers()
{
var results = new List<UXController>();
UXController[] allControllers = Resources.FindObjectsOfTypeAll<UXController>();
for (int i = 0; i < allControllers.Length; i++)
{
UXController controller = allControllers[i];
if (controller == null)
{
continue;
}
if (EditorUtility.IsPersistent(controller))
{
continue;
}
if (!controller.gameObject.scene.IsValid() || !controller.gameObject.scene.isLoaded)
{
continue;
}
if ((controller.hideFlags & HideFlags.HideInHierarchy) != 0)
{
continue;
}
results.Add(controller);
}
results.Sort((left, right) => string.CompareOrdinal(GetHierarchyPath(left.transform), GetHierarchyPath(right.transform)));
return results;
}
private static string GetHierarchyPath(Transform target)
{
if (target == null)
{
return string.Empty;
}
string path = target.name;
Transform current = target.parent;
while (current != null)
{
path = $"{current.name}/{path}";
current = current.parent;
}
return path;
}
}
}
#endif