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

267 lines
9.9 KiB
C#
Raw Normal View History

#if UNITY_EDITOR
using System.Collections.Generic;
2025-12-01 16:44:19 +08:00
using UnityEditor;
using UnityEngine;
namespace UnityEngine.UI
2025-12-01 16:44:19 +08:00
{
[CustomEditor(typeof(UXController))]
public sealed class UXControllerEditor : UnityEditor.Editor
2025-12-01 16:44:19 +08:00
{
private SerializedProperty _controllersProp;
private SerializedProperty _bindingsProp;
private readonly Dictionary<int, bool> _foldouts = new Dictionary<int, bool>();
private void OnEnable()
{
_controllersProp = serializedObject.FindProperty("_controllers");
_bindingsProp = serializedObject.FindProperty("_bindings");
}
2025-12-01 16:44:19 +08:00
public override void OnInspectorGUI()
2025-12-01 16:44:19 +08:00
{
serializedObject.Update();
var controller = (UXController)target;
DrawHeader(controller);
EditorGUILayout.Space(6f);
DrawControllers(controller);
EditorGUILayout.Space(6f);
DrawBindings();
serializedObject.ApplyModifiedProperties();
}
private void DrawHeader(UXController controller)
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("UX Controller", EditorStyles.boldLabel);
EditorGUILayout.LabelField($"Controllers: {_controllersProp.arraySize}", EditorStyles.miniLabel);
EditorGUILayout.LabelField($"Bindings: {_bindingsProp.arraySize}", EditorStyles.miniLabel);
2025-12-01 16:44:19 +08:00
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Add Controller"))
{
AddController();
}
if (GUILayout.Button("Reset Preview"))
{
controller.ResetAllControllers();
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
2025-12-01 16:44:19 +08:00
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
private void DrawControllers(UXController controller)
{
if (_controllersProp.arraySize == 0)
{
EditorGUILayout.HelpBox("No controllers yet. Add one to start driving bindings.", MessageType.Info);
return;
}
for (int i = 0; i < _controllersProp.arraySize; i++)
{
DrawController(controller, i);
EditorGUILayout.Space(4f);
}
}
private void DrawController(UXController controller, int index)
{
SerializedProperty entryProp = _controllersProp.GetArrayElementAtIndex(index);
SerializedProperty idProp = entryProp.FindPropertyRelative("_id");
SerializedProperty nameProp = entryProp.FindPropertyRelative("_name");
SerializedProperty lengthProp = entryProp.FindPropertyRelative("_length");
SerializedProperty descriptionProp = entryProp.FindPropertyRelative("_description");
2025-12-01 16:44:19 +08:00
bool expanded = _foldouts.ContainsKey(index) && _foldouts[index];
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
expanded = EditorGUILayout.Foldout(expanded, $"[{index}] {nameProp.stringValue}", true);
GUILayout.FlexibleSpace();
if (GUILayout.Button("Up", EditorStyles.miniButtonLeft, GUILayout.Width(34f)) && index > 0)
{
_controllersProp.MoveArrayElement(index, index - 1);
GUIUtility.ExitGUI();
}
if (GUILayout.Button("Down", EditorStyles.miniButtonMid, GUILayout.Width(44f)) && index < _controllersProp.arraySize - 1)
{
_controllersProp.MoveArrayElement(index, index + 1);
GUIUtility.ExitGUI();
}
if (GUILayout.Button("X", EditorStyles.miniButtonRight, GUILayout.Width(24f)))
{
DeleteController(controller, index);
}
EditorGUILayout.EndHorizontal();
_foldouts[index] = expanded;
if (expanded)
{
EditorGUILayout.PropertyField(nameProp, new GUIContent("Name"));
lengthProp.intValue = Mathf.Max(1, EditorGUILayout.IntField("Length", Mathf.Max(1, lengthProp.intValue)));
EditorGUILayout.PropertyField(descriptionProp, new GUIContent("Description"));
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.TextField("Id", idProp.stringValue);
EditorGUI.EndDisabledGroup();
UXController.ControllerDefinition definition = controller.GetControllerAt(index);
if (definition != null)
{
DrawPreview(controller, definition);
}
}
EditorGUILayout.EndVertical();
}
private void DrawPreview(UXController controller, UXController.ControllerDefinition definition)
2025-12-01 16:44:19 +08:00
{
EditorGUILayout.Space(4f);
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
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++)
2025-12-01 16:44:19 +08:00
{
options[i] = i.ToString();
2025-12-01 16:44:19 +08:00
}
EditorGUI.BeginChangeCheck();
int newIndex = GUILayout.SelectionGrid(currentIndex, options, Mathf.Min(length, 6));
if (EditorGUI.EndChangeCheck())
{
controller.SetControllerIndex(definition.Id, newIndex);
EditorUtility.SetDirty(controller);
SceneView.RepaintAll();
}
}
private void DrawBindings()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("Registered Bindings", EditorStyles.boldLabel);
if (_bindingsProp.arraySize == 0)
{
EditorGUILayout.HelpBox("No UXBinding components are registered under this controller.", MessageType.Info);
}
else
{
for (int i = 0; i < _bindingsProp.arraySize; i++)
{
SerializedProperty bindingProp = _bindingsProp.GetArrayElementAtIndex(i);
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField($"Binding {i}", bindingProp.objectReferenceValue, typeof(UXBinding), true);
EditorGUI.EndDisabledGroup();
}
}
EditorGUILayout.EndVertical();
}
private void AddController()
{
int index = _controllersProp.arraySize;
_controllersProp.InsertArrayElementAtIndex(index);
SerializedProperty entryProp = _controllersProp.GetArrayElementAtIndex(index);
entryProp.FindPropertyRelative("_id").stringValue = string.Empty;
entryProp.FindPropertyRelative("_name").stringValue = $"Controller {index + 1}";
entryProp.FindPropertyRelative("_length").intValue = 2;
entryProp.FindPropertyRelative("_description").stringValue = string.Empty;
_foldouts[index] = true;
}
private void DeleteController(UXController controller, int index)
{
if (index < 0 || index >= _controllersProp.arraySize)
{
return;
}
SerializedProperty entryProp = _controllersProp.GetArrayElementAtIndex(index);
string deletedControllerId = entryProp.FindPropertyRelative("_id").stringValue;
Undo.RecordObject(controller, "Delete UX Controller");
_controllersProp.DeleteArrayElementAtIndex(index);
CleanupFoldouts(index);
serializedObject.ApplyModifiedProperties();
ClearBindingReferences(controller, deletedControllerId);
EditorUtility.SetDirty(controller);
GUIUtility.ExitGUI();
}
private void CleanupFoldouts(int removedIndex)
{
_foldouts.Remove(removedIndex);
var remapped = new Dictionary<int, bool>();
foreach (var pair in _foldouts)
{
int nextIndex = pair.Key > removedIndex ? pair.Key - 1 : pair.Key;
remapped[nextIndex] = pair.Value;
}
_foldouts.Clear();
foreach (var pair in remapped)
{
_foldouts[pair.Key] = pair.Value;
}
}
private static void ClearBindingReferences(UXController controller, string deletedControllerId)
{
if (controller == null || string.IsNullOrEmpty(deletedControllerId))
{
return;
}
IReadOnlyList<UXBinding> bindings = controller.Bindings;
for (int i = 0; i < bindings.Count; i++)
{
UXBinding binding = bindings[i];
if (binding == null)
{
continue;
}
var so = new SerializedObject(binding);
SerializedProperty entriesProp = so.FindProperty("_entries");
bool changed = false;
for (int entryIndex = 0; entryIndex < entriesProp.arraySize; entryIndex++)
{
SerializedProperty bindingEntry = entriesProp.GetArrayElementAtIndex(entryIndex);
SerializedProperty controllerIdProp = bindingEntry.FindPropertyRelative("_controllerId");
if (controllerIdProp.stringValue == deletedControllerId)
{
controllerIdProp.stringValue = string.Empty;
changed = true;
}
}
2025-12-01 16:44:19 +08:00
if (changed)
{
so.ApplyModifiedProperties();
EditorUtility.SetDirty(binding);
}
}
}
2025-12-01 16:44:19 +08:00
}
}
#endif