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

425 lines
14 KiB
C#
Raw Normal View History

2025-12-01 16:44:19 +08:00
using UnityEditor;
using UnityEngine;
using AlicizaX.UI;
using System.Collections.Generic;
2025-12-01 16:44:19 +08:00
namespace AlicizaX.UI
2025-12-01 16:44:19 +08:00
{
[CustomEditor(typeof(UXController))]
public class UXControllerEditor : UnityEditor.Editor
2025-12-01 16:44:19 +08:00
{
private SerializedProperty _controllersProp;
private bool _showRecorders = true;
private bool _previewMode = false;
private Dictionary<int, bool> _controllerFoldouts = new Dictionary<int, bool>();
2025-12-01 16:44:19 +08:00
private GUIStyle _headerStyle;
private GUIStyle _toolbarStyle;
private GUIStyle _controllerHeaderStyle;
private void OnEnable()
{
_controllersProp = serializedObject.FindProperty("_controllers");
}
private void InitStyles()
{
if (_headerStyle == null)
{
_headerStyle = new GUIStyle(EditorStyles.boldLabel)
{
fontSize = 13,
fontStyle = FontStyle.Bold
};
}
2025-12-01 16:44:19 +08:00
if (_toolbarStyle == null)
{
_toolbarStyle = new GUIStyle(EditorStyles.toolbar)
{
fixedHeight = 25
};
}
if (_controllerHeaderStyle == null)
{
_controllerHeaderStyle = new GUIStyle(EditorStyles.foldout)
{
fontStyle = FontStyle.Bold
};
}
}
2025-12-01 16:44:19 +08:00
public override void OnInspectorGUI()
2025-12-01 16:44:19 +08:00
{
InitStyles();
serializedObject.Update();
var controller = target as UXController;
// Header
DrawHeader();
EditorGUILayout.Space(5);
// Preview Mode
DrawPreviewMode(controller);
EditorGUILayout.Space(5);
// Toolbar
DrawToolbar();
EditorGUILayout.Space(5);
2025-12-01 16:44:19 +08:00
// Controllers List
DrawControllersList(controller);
EditorGUILayout.Space(5);
// Recorders Section
DrawRecorders(controller);
serializedObject.ApplyModifiedProperties();
}
private void DrawHeader()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
2025-12-01 16:44:19 +08:00
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("UX Controller", _headerStyle, GUILayout.Width(130));
EditorGUILayout.LabelField($"Controllers: {_controllersProp.arraySize}", EditorStyles.miniLabel);
GUILayout.FlexibleSpace();
if (GUILayout.Button("+ Add Controller", GUILayout.Width(110)))
2025-12-01 16:44:19 +08:00
{
AddNewController();
2025-12-01 16:44:19 +08:00
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
private void DrawPreviewMode(UXController controller)
{
Color oldColor = GUI.backgroundColor;
if (_previewMode) GUI.backgroundColor = new Color(0.5f, 1f, 0.5f);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
GUI.backgroundColor = oldColor;
2025-12-01 16:44:19 +08:00
EditorGUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
_previewMode = EditorGUILayout.Toggle("Preview Mode", _previewMode);
if (EditorGUI.EndChangeCheck())
{
if (!_previewMode)
{
ResetAllControllers(controller);
}
}
if (_previewMode)
{
GUILayout.FlexibleSpace();
if (GUILayout.Button("Reset All", GUILayout.Width(80)))
{
ResetAllControllers(controller);
}
}
2025-12-01 16:44:19 +08:00
EditorGUILayout.EndHorizontal();
if (_previewMode)
{
EditorGUILayout.HelpBox("Preview mode active. Click state buttons to preview.", MessageType.Info);
}
EditorGUILayout.EndVertical();
}
private void DrawToolbar()
{
EditorGUILayout.BeginHorizontal(_toolbarStyle);
if (GUILayout.Button("Expand All", EditorStyles.toolbarButton, GUILayout.Width(70)))
{
for (int i = 0; i < _controllersProp.arraySize; i++)
{
_controllerFoldouts[i] = true;
}
}
if (GUILayout.Button("Collapse All", EditorStyles.toolbarButton, GUILayout.Width(75)))
{
_controllerFoldouts.Clear();
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
private void DrawControllersList(UXController controller)
{
if (_controllersProp.arraySize == 0)
{
EditorGUILayout.HelpBox("No controllers defined. Click '+ Add Controller' to create one.", MessageType.Info);
return;
}
for (int i = 0; i < _controllersProp.arraySize; i++)
{
DrawControllerEntry(controller, i);
EditorGUILayout.Space(3);
}
}
private void DrawControllerEntry(UXController controller, int index)
{
var element = _controllersProp.GetArrayElementAtIndex(index);
var nameProp = element.FindPropertyRelative("_name");
var lengthProp = element.FindPropertyRelative("_length");
var descProp = element.FindPropertyRelative("_description");
if (!_controllerFoldouts.ContainsKey(index))
{
_controllerFoldouts[index] = false;
}
2025-12-01 16:44:19 +08:00
bool isFolded = _controllerFoldouts[index];
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
// Header
DrawControllerHeader(index, nameProp, ref isFolded);
_controllerFoldouts[index] = isFolded;
// Expanded Content
if (isFolded)
2025-12-01 16:44:19 +08:00
{
EditorGUI.indentLevel++;
// Name
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Name", GUILayout.Width(70));
nameProp.stringValue = EditorGUILayout.TextField(nameProp.stringValue);
EditorGUILayout.EndHorizontal();
// Length
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Length", GUILayout.Width(70));
lengthProp.intValue = Mathf.Max(1, EditorGUILayout.IntField(lengthProp.intValue));
EditorGUILayout.EndHorizontal();
// Description
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Description", GUILayout.Width(70));
descProp.stringValue = EditorGUILayout.TextField(descProp.stringValue);
EditorGUILayout.EndHorizontal();
// Preview
if (_previewMode && !Application.isPlaying)
{
EditorGUILayout.Space(5);
DrawControllerPreview(controller, index, lengthProp.intValue);
}
EditorGUI.indentLevel--;
2025-12-01 16:44:19 +08:00
}
EditorGUILayout.EndVertical();
}
private void DrawControllerHeader(int index, SerializedProperty nameProp, ref bool isFolded)
{
EditorGUILayout.BeginHorizontal();
// Foldout
isFolded = EditorGUILayout.Foldout(isFolded, $"[{index}] {nameProp.stringValue}", true, _controllerHeaderStyle);
GUILayout.FlexibleSpace();
// Buttons
if (GUILayout.Button("▲", EditorStyles.miniButtonLeft, GUILayout.Width(25)) && index > 0)
{
_controllersProp.MoveArrayElement(index, index - 1);
GUIUtility.ExitGUI();
}
if (GUILayout.Button("▼", EditorStyles.miniButtonMid, GUILayout.Width(25)) && index < _controllersProp.arraySize - 1)
{
_controllersProp.MoveArrayElement(index, index + 1);
GUIUtility.ExitGUI();
}
if (GUILayout.Button("⎘", EditorStyles.miniButtonMid, GUILayout.Width(25)))
{
DuplicateController(index);
GUIUtility.ExitGUI();
}
if (GUILayout.Button("×", EditorStyles.miniButtonRight, GUILayout.Width(25)))
{
if (EditorUtility.DisplayDialog("Delete Controller",
$"Delete controller '{nameProp.stringValue}'?", "Delete", "Cancel"))
{
DeleteController(index);
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawControllerPreview(UXController controller, int controllerIndex, int length)
2025-12-01 16:44:19 +08:00
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
var handle = controller.GetControllerAt(controllerIndex);
if (handle != null)
2025-12-01 16:44:19 +08:00
{
int currentIndex = handle.SelectedIndex;
2025-12-01 16:44:19 +08:00
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField($"State: {currentIndex}", GUILayout.Width(60));
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, 6));
if (EditorGUI.EndChangeCheck())
{
controller.SetControllerIndexInternal(controllerIndex, newIndex);
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
2025-12-01 16:44:19 +08:00
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
}
private void DrawRecorders(UXController controller)
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
_showRecorders = EditorGUILayout.Foldout(_showRecorders, $"State Recorders ({controller.Recorders.Count})", true);
EditorGUILayout.EndHorizontal();
if (_showRecorders)
{
if (controller.Recorders.Count == 0)
{
EditorGUILayout.HelpBox("No state recorders attached.", MessageType.Info);
}
else
{
EditorGUI.indentLevel++;
for (int i = 0; i < controller.Recorders.Count; i++)
{
DrawRecorderEntry(controller.Recorders[i], i);
}
EditorGUI.indentLevel--;
}
}
EditorGUILayout.EndVertical();
}
private void DrawRecorderEntry(UXControllerStateRecorder recorder, int index)
{
if (recorder == null) return;
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
EditorGUILayout.LabelField($"[{index}]", GUILayout.Width(30));
EditorGUILayout.LabelField($"ID: {recorder.ID}", GUILayout.Width(100));
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(recorder, typeof(UXControllerStateRecorder), true);
EditorGUI.EndDisabledGroup();
EditorGUILayout.LabelField($"States: {recorder.StateEntries.Count}", GUILayout.Width(60));
if (GUILayout.Button("Select", GUILayout.Width(60)))
{
Selection.activeGameObject = recorder.gameObject;
}
EditorGUILayout.EndHorizontal();
}
private void AddNewController()
{
_controllersProp.arraySize++;
var newElement = _controllersProp.GetArrayElementAtIndex(_controllersProp.arraySize - 1);
newElement.FindPropertyRelative("_name").stringValue = $"Controller{_controllersProp.arraySize}";
newElement.FindPropertyRelative("_length").intValue = 2;
newElement.FindPropertyRelative("_description").stringValue = "";
_controllerFoldouts[_controllersProp.arraySize - 1] = true;
}
private void DuplicateController(int index)
{
_controllersProp.InsertArrayElementAtIndex(index);
var newProp = _controllersProp.GetArrayElementAtIndex(index + 1);
var nameProp = newProp.FindPropertyRelative("_name");
nameProp.stringValue += " Copy";
_controllerFoldouts[index + 1] = true;
}
private void DeleteController(int index)
{
if (index < 0 || index >= _controllersProp.arraySize)
{
return;
}
Undo.RecordObject(serializedObject.targetObject, "Delete Controller");
_controllersProp.DeleteArrayElementAtIndex(index);
_controllerFoldouts.Remove(index);
// Rebuild foldout dictionary with corrected indices
var newFoldouts = new Dictionary<int, bool>();
foreach (var kvp in _controllerFoldouts)
{
if (kvp.Key < index)
{
newFoldouts[kvp.Key] = kvp.Value;
}
else if (kvp.Key > index)
{
newFoldouts[kvp.Key - 1] = kvp.Value;
}
}
_controllerFoldouts = newFoldouts;
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(serializedObject.targetObject);
GUIUtility.ExitGUI();
2025-12-01 16:44:19 +08:00
}
private void ResetAllControllers(UXController controller)
{
for (int i = 0; i < controller.ControllerCount; i++)
{
controller.SetControllerIndexInternal(i, 0);
}
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
2025-12-01 16:44:19 +08:00
}
}