Files
2026-08-30 22:25:23 +08:00

212 lines
8.3 KiB
C#

using System.Collections.Generic;
using SepCore.UI;
using UnityEditor;
using UnityEngine;
namespace SepCore.Editor
{
[CustomEditor(typeof(UISerializationRoot))]
internal sealed class UISerializationRootEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var root = (UISerializationRoot)target;
root.RefreshItems();
serializedObject.UpdateIfRequiredOrScript();
int referenceCount = 0;
bool hasValidationError = false;
var selectedNames = new HashSet<string>();
for (int i = 0; i < root.SerializationItems.Count; i++)
{
UISerializationItem item = root.SerializationItems[i];
if (item == null)
{
continue;
}
for (int j = 0; j < item.ComponentReferences.Count; j++)
{
UISerializationItem.ComponentReference reference = item.ComponentReferences[j];
if (reference.GenerateReference)
{
referenceCount++;
string variableName = reference.VariableName == null ? string.Empty : reference.VariableName.Trim();
if (!UIAssetsTools.IsValidIdentifier(variableName) || !selectedNames.Add(variableName))
{
hasValidationError = true;
}
}
}
}
SerializedProperty nestedForms = serializedObject.FindProperty("nestedFormReferences");
for (int i = 0; i < nestedForms.arraySize; i++)
{
SerializedProperty entry = nestedForms.GetArrayElementAtIndex(i);
if (entry.FindPropertyRelative("generateReference").boolValue)
{
referenceCount++;
}
}
EditorGUILayout.LabelField("View Class", UIAssetsTools.GetViewClassName(root));
EditorGUILayout.LabelField("Form Class", UIAssetsTools.GetFormClassName(root));
EditorGUILayout.LabelField("Owned Items", root.SerializationItems.Count.ToString());
EditorGUILayout.LabelField("Nested Forms", nestedForms.arraySize.ToString());
EditorGUILayout.LabelField("Generated References", referenceCount.ToString());
EditorGUILayout.Space(4f);
EditorGUILayout.LabelField("Owned Items", EditorStyles.boldLabel);
for (int i = 0; i < root.SerializationItems.Count; i++)
{
UISerializationItem item = root.SerializationItems[i];
if (item == null)
{
continue;
}
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
EditorGUILayout.LabelField(GetRelativePath(root.transform, item.transform));
if (GUILayout.Button("Select", GUILayout.Width(56f)))
{
Selection.activeGameObject = item.gameObject;
EditorGUIUtility.PingObject(item.gameObject);
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space(4f);
EditorGUILayout.LabelField("Nested Forms", EditorStyles.boldLabel);
if (nestedForms.arraySize == 0)
{
EditorGUILayout.HelpBox("Nested UISerializationRoot components will appear here as child Form references and form serialization boundaries.", MessageType.Info);
}
for (int i = 0; i < nestedForms.arraySize; i++)
{
SerializedProperty entry = nestedForms.GetArrayElementAtIndex(i);
SerializedProperty nestedRootProperty = entry.FindPropertyRelative("root");
SerializedProperty generate = entry.FindPropertyRelative("generateReference");
SerializedProperty variableName = entry.FindPropertyRelative("variableName");
var nestedRoot = nestedRootProperty.objectReferenceValue as UISerializationRoot;
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
generate.boolValue = EditorGUILayout.Toggle(generate.boolValue, GUILayout.Width(18f));
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.ObjectField(nestedRoot, typeof(UISerializationRoot), true);
}
if (nestedRoot != null && GUILayout.Button("Select", GUILayout.Width(56f)))
{
Selection.activeGameObject = nestedRoot.gameObject;
EditorGUIUtility.PingObject(nestedRoot.gameObject);
}
EditorGUILayout.EndHorizontal();
if (nestedRoot != null)
{
EditorGUILayout.LabelField("Form Class", UIAssetsTools.GetFormClassName(nestedRoot));
}
if (generate.boolValue)
{
variableName.stringValue = EditorGUILayout.TextField("Variable Name", variableName.stringValue);
string normalized = variableName.stringValue == null ? string.Empty : variableName.stringValue.Trim();
if (!UIAssetsTools.IsValidIdentifier(normalized))
{
hasValidationError = true;
EditorGUILayout.HelpBox("Enter a valid C# field name.", MessageType.Error);
}
else if (!selectedNames.Add(normalized))
{
hasValidationError = true;
EditorGUILayout.HelpBox("This field name conflicts with another generated reference.", MessageType.Error);
}
}
EditorGUILayout.EndVertical();
}
if (hasValidationError)
{
EditorGUILayout.HelpBox("Fix invalid or duplicate generated field names before creating View scripts.", MessageType.Error);
}
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space(4f);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Refresh Items"))
{
Undo.RecordObject(root, "Refresh UI serialization items");
root.RefreshItems();
}
using (new EditorGUI.DisabledScope(hasValidationError))
{
if (GUILayout.Button("Create View & Form Scripts"))
{
UIAssetsTools.GenerateWithDialog(root);
}
}
EditorGUILayout.EndHorizontal();
}
private static string GetRelativePath(Transform root, Transform target)
{
if (target == root)
{
return root.name;
}
string path = target.name;
Transform current = target.parent;
while (current != null && current != root)
{
path = current.name + "/" + path;
current = current.parent;
}
return path;
}
}
[InitializeOnLoad]
internal static class UISerializationRootWatcher
{
private static bool refreshQueued;
static UISerializationRootWatcher()
{
EditorApplication.hierarchyChanged += QueueRefresh;
}
private static void QueueRefresh()
{
if (refreshQueued || EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
refreshQueued = true;
EditorApplication.delayCall += RefreshLoadedRoots;
}
private static void RefreshLoadedRoots()
{
refreshQueued = false;
UISerializationRoot[] roots = Resources.FindObjectsOfTypeAll<UISerializationRoot>();
for (int i = 0; i < roots.Length; i++)
{
UISerializationRoot root = roots[i];
if (root == null || EditorUtility.IsPersistent(root) || !root.gameObject.scene.IsValid() || !root.gameObject.scene.isLoaded)
{
continue;
}
root.RefreshItems();
}
}
}
}