#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("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(); } } 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 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 controllers) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("UX Controllers", EditorStyles.boldLabel); GUILayout.FlexibleSpace(); 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 GetSceneControllers() { var results = new List(); UXController[] allControllers = Resources.FindObjectsOfTypeAll(); 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