com.alicizax.unity.framework/Editor/UI/Inspector/UIComponentInspector.cs

349 lines
13 KiB
C#

using System;
using AlicizaX.Editor;
using AlicizaX.UI.Runtime;
using UnityEditor;
using UnityEngine;
namespace AlicizaX.UI.Editor
{
[CustomEditor(typeof(UIComponent))]
internal sealed class UIComponentInspector : GameFrameworkInspector
{
private const int CacheDebugInfoCapacity = 64;
private static readonly Color SectionColor = new Color(0.18f, 0.18f, 0.18f, 1f);
private static readonly Color OkColor = new Color(0.3f, 0.75f, 0.35f, 1f);
private static readonly Color WarningColor = new Color(1f, 0.72f, 0.18f, 1f);
private static readonly Color ErrorColor = new Color(1f, 0.32f, 0.28f, 1f);
private static readonly Color MutedColor = new Color(0.62f, 0.62f, 0.62f, 1f);
private readonly UIServiceDebugInfo _serviceInfo = new UIServiceDebugInfo();
private readonly UILayerDebugInfo _layerInfo = new UILayerDebugInfo();
private readonly UIWindowDebugInfo _windowInfo = new UIWindowDebugInfo();
private readonly UIWindowDebugInfo[] _cacheInfos = new UIWindowDebugInfo[CacheDebugInfoCapacity];
private SerializedProperty uiRoot;
private SerializedProperty _isOrthographic;
private bool _showRuntimeDebug = true;
private bool _showReferences;
private bool _showLayers = true;
private bool _showCache = true;
private bool _showEmptyLayers;
private Vector2 _runtimeScroll;
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
{
if (uiRoot.objectReferenceValue == null)
{
EditorGUILayout.HelpBox("uiroot can not be null!", MessageType.Error);
}
EditorGUILayout.BeginHorizontal();
GameObject rootPrefab = (GameObject)EditorGUILayout.ObjectField("UI Root Prefab", uiRoot.objectReferenceValue, typeof(GameObject), false);
if (rootPrefab != uiRoot.objectReferenceValue)
{
uiRoot.objectReferenceValue = rootPrefab;
}
if (uiRoot.objectReferenceValue == null)
{
if (GUILayout.Button("Set Default"))
{
GameObject defaultPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(UIGlobalPath.UIPrefabPath);
uiRoot.objectReferenceValue = defaultPrefab;
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.PropertyField(_isOrthographic);
}
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
DrawRuntimeDebugInfo();
if (EditorApplication.isPlaying)
{
Repaint();
}
}
private void OnEnable()
{
uiRoot = serializedObject.FindProperty("uiRoot");
_isOrthographic = serializedObject.FindProperty("_isOrthographic");
for (int i = 0; i < _cacheInfos.Length; i++)
{
_cacheInfos[i] = new UIWindowDebugInfo();
}
}
private void DrawRuntimeDebugInfo()
{
EditorGUILayout.Space();
_showRuntimeDebug = EditorGUILayout.Foldout(_showRuntimeDebug, "Runtime Debug", true, EditorStyles.foldoutHeader);
if (!_showRuntimeDebug)
{
return;
}
if (!EditorApplication.isPlaying)
{
EditorGUILayout.HelpBox("Enter Play Mode to inspect runtime UI state.", MessageType.Info);
return;
}
if (!AppServices.TryGet<IUIService>(out IUIService uiService) || uiService is not IUIDebugService debugService)
{
EditorGUILayout.HelpBox("UI service is not initialized.", MessageType.Warning);
return;
}
debugService.FillServiceDebugInfo(_serviceInfo);
DrawServiceSummary();
DrawRuntimeOptions();
_runtimeScroll = EditorGUILayout.BeginScrollView(_runtimeScroll, GUILayout.MinHeight(260f), GUILayout.MaxHeight(720f));
DrawReferences();
DrawLayerDebugInfo(debugService);
DrawCacheDebugInfo(debugService);
EditorGUILayout.EndScrollView();
}
private void DrawRuntimeOptions()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
_showLayers = GUILayout.Toggle(_showLayers, "Layers", EditorStyles.toolbarButton);
_showCache = GUILayout.Toggle(_showCache, "Cache", EditorStyles.toolbarButton);
_showReferences = GUILayout.Toggle(_showReferences, "References", EditorStyles.toolbarButton);
_showEmptyLayers = GUILayout.Toggle(_showEmptyLayers, "Empty Layers", EditorStyles.toolbarButton);
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
private void DrawServiceSummary()
{
DrawSectionBegin("Service Summary");
EditorGUILayout.BeginHorizontal();
DrawCounter("Initialized", _serviceInfo.Initialized ? "Yes" : "No", _serviceInfo.Initialized ? OkColor : ErrorColor);
DrawCounter("Mode", _serviceInfo.Orthographic ? "Orthographic" : "Perspective", Color.white);
DrawCounter("Layers", _serviceInfo.LayerCount.ToString(), Color.white);
DrawCounter("Open", _serviceInfo.OpenWindowCount.ToString(), _serviceInfo.OpenWindowCount > 0 ? OkColor : MutedColor);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
DrawCounter("Cache", _serviceInfo.CacheWindowCount.ToString(), _serviceInfo.CacheWindowCount > 0 ? WarningColor : MutedColor);
DrawCounter("Update", _serviceInfo.UpdateWindowCount.ToString(), _serviceInfo.UpdateWindowCount > 0 ? OkColor : MutedColor);
DrawCounter("Block", _serviceInfo.BlockActive ? "Active" : "Inactive", _serviceInfo.BlockActive ? WarningColor : MutedColor);
DrawCounter("Block Timer", _serviceInfo.BlockTimerHandle.ToString(), _serviceInfo.BlockTimerHandle != 0UL ? WarningColor : MutedColor);
EditorGUILayout.EndHorizontal();
DrawSectionEnd();
}
private void DrawReferences()
{
if (!_showReferences)
{
return;
}
DrawSectionBegin("References");
EditorGUILayout.ObjectField("Root", _serviceInfo.Root, typeof(Transform), true);
EditorGUILayout.ObjectField("Canvas Root", _serviceInfo.CanvasRoot, typeof(Transform), true);
EditorGUILayout.ObjectField("Canvas", _serviceInfo.Canvas, typeof(Canvas), true);
EditorGUILayout.ObjectField("Camera", _serviceInfo.Camera, typeof(Camera), true);
DrawSectionEnd();
}
private void DrawLayerDebugInfo(IUIDebugService debugService)
{
if (!_showLayers)
{
return;
}
DrawSectionBegin("Open Windows");
bool hasWindow = false;
for (int layerIndex = 0; layerIndex < debugService.LayerCount; layerIndex++)
{
if (!debugService.FillLayerDebugInfo(layerIndex, _layerInfo))
{
continue;
}
if (_layerInfo.WindowCount == 0 && !_showEmptyLayers)
{
continue;
}
hasWindow |= _layerInfo.WindowCount > 0;
DrawLayerHeader(_layerInfo);
EditorGUI.indentLevel++;
for (int windowIndex = 0; windowIndex < _layerInfo.WindowCount; windowIndex++)
{
if (debugService.FillWindowDebugInfo(layerIndex, windowIndex, _windowInfo))
{
DrawWindowDebugInfo(_windowInfo, false);
}
}
EditorGUI.indentLevel--;
}
if (!hasWindow && !_showEmptyLayers)
{
DrawEmptyLabel("No open UI windows.");
}
DrawSectionEnd();
}
private void DrawCacheDebugInfo(IUIDebugService debugService)
{
if (!_showCache)
{
return;
}
DrawSectionBegin("Cached Windows");
int count = debugService.FillCacheDebugInfo(_cacheInfos, _cacheInfos.Length);
if (count == 0)
{
DrawEmptyLabel("No cached UI windows.");
}
for (int i = 0; i < count; i++)
{
DrawWindowDebugInfo(_cacheInfos[i], true);
}
if (debugService.CacheWindowCount > _cacheInfos.Length)
{
EditorGUILayout.HelpBox("Cache list is truncated by inspector buffer capacity.", MessageType.Warning);
}
DrawSectionEnd();
}
private static void DrawLayerHeader(UILayerDebugInfo info)
{
Rect rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight + 4f);
EditorGUI.DrawRect(rect, SectionColor);
rect.x += 6f;
rect.width -= 12f;
rect.y += 2f;
EditorGUI.LabelField(
rect,
info.Layer.ToString(),
"Windows " + info.WindowCount + " | Last Fullscreen " + info.LastFullscreenIndex,
EditorStyles.boldLabel);
}
private static void DrawWindowDebugInfo(UIWindowDebugInfo info, bool cached)
{
Rect rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight + 4f);
Color color = GetWindowColor(info, cached);
EditorGUI.DrawRect(new Rect(rect.x, rect.y + 2f, 4f, rect.height - 4f), color);
rect.x += 8f;
rect.width -= 8f;
EditorGUI.ObjectField(rect, GetWindowTitle(info, cached), info.HolderTransform, typeof(Transform), true);
EditorGUI.indentLevel++;
EditorGUILayout.LabelField("State", GetStateLine(info));
EditorGUILayout.LabelField("Flags", GetFlagLine(info));
if (cached || info.CacheTime > 0f || info.CacheTimerHandle != 0UL)
{
EditorGUILayout.LabelField("Cache", GetCacheLine(info));
}
EditorGUILayout.LabelField("Holder", string.IsNullOrEmpty(info.HolderTypeName) ? "None" : info.HolderTypeName);
EditorGUI.indentLevel--;
}
private static string GetWindowTitle(UIWindowDebugInfo info, bool cached)
{
string logicName = string.IsNullOrEmpty(info.LogicTypeName) ? "Unknown" : info.LogicTypeName;
string prefix = cached ? "[Cache] " : "";
return prefix + "#" + info.OrderIndex + " L" + info.LayerIndex + " " + logicName;
}
private static string GetStateLine(UIWindowDebugInfo info)
{
return info.State + " | Visible " + info.Visible + " | Depth " + info.Depth + " | FullScreen " + info.FullScreen;
}
private static string GetFlagLine(UIWindowDebugInfo info)
{
return "Update " + info.NeedUpdate + " | InCache " + info.InCache + " | ShowOp " + info.ShowInProgress + " | CloseOp " + info.CloseInProgress;
}
private static string GetCacheLine(UIWindowDebugInfo info)
{
return "Time " + info.CacheTime.ToString("F2") + " | Timer " + info.CacheTimerHandle;
}
private static Color GetWindowColor(UIWindowDebugInfo info, bool cached)
{
if (info.ShowInProgress || info.CloseInProgress)
{
return WarningColor;
}
if (cached || info.InCache)
{
return MutedColor;
}
if (!info.Visible)
{
return ErrorColor;
}
return info.FullScreen ? OkColor : Color.cyan;
}
private static void DrawCounter(string label, string value, Color valueColor)
{
EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.MinWidth(82f));
EditorGUILayout.LabelField(label, EditorStyles.miniLabel);
Color oldColor = GUI.color;
GUI.color = valueColor;
EditorGUILayout.LabelField(value, EditorStyles.boldLabel);
GUI.color = oldColor;
EditorGUILayout.EndVertical();
}
private static void DrawSectionBegin(string title)
{
EditorGUILayout.Space(4f);
Rect rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight + 6f);
EditorGUI.DrawRect(rect, SectionColor);
rect.x += 6f;
rect.y += 3f;
rect.width -= 12f;
EditorGUI.LabelField(rect, title, EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(GUI.skin.box);
}
private static void DrawSectionEnd()
{
EditorGUILayout.EndVertical();
}
private static void DrawEmptyLabel(string text)
{
Color oldColor = GUI.color;
GUI.color = MutedColor;
EditorGUILayout.LabelField(text, EditorStyles.miniLabel);
GUI.color = oldColor;
}
}
}