com.alicizax.unity.ui.exten.../Editor/UX/Group/UXGroupEditor.cs
陈思海 551423f09d 大优化
大优化 懒得写了 重构了分离了 UXButton UXToggle UXSelectable UXGroup
2025-12-19 20:26:22 +08:00

271 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
namespace UnityEditor.UI
{
[CustomEditor(typeof(UXGroup))]
public class UXGroupInspector : Editor
{
private SerializedProperty m_Toggles;
private SerializedProperty m_AllowSwitchOff;
private SerializedProperty m_DefaultToggle;
private UXGroup _target;
private ReorderableList _reorderableList;
private void OnEnable()
{
_target = (UXGroup)target;
m_Toggles = serializedObject.FindProperty("m_Toggles");
m_AllowSwitchOff = serializedObject.FindProperty("m_AllowSwitchOff");
m_DefaultToggle = serializedObject.FindProperty("m_DefaultToggle");
_reorderableList = new ReorderableList(serializedObject, m_Toggles, true, true, true, true)
{
drawHeaderCallback = DrawHeader,
drawElementCallback = DrawElement,
onRemoveCallback = OnRemoveList,
onChangedCallback = OnChanged,
displayAdd = false,
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_AllowSwitchOff);
// Default selector: only show toggles that are currently in the group's m_Toggles list
DrawDefaultToggleSelector();
bool isPlaying = Application.isPlaying || EditorApplication.isPlaying;
_reorderableList.draggable = !isPlaying;
_reorderableList.displayAdd = !isPlaying;
_reorderableList.displayRemove = !isPlaying;
bool prevEnabled = GUI.enabled;
if (isPlaying) GUI.enabled = false;
_reorderableList.DoLayoutList();
GUI.enabled = prevEnabled;
serializedObject.ApplyModifiedProperties();
// 在编辑器下尽量实时同步状态
if (!Application.isPlaying)
{
// 保证序列化数据写入后同步 group 状态
_target.EnsureValidState();
}
}
private void DrawDefaultToggleSelector()
{
// Build a list of current toggles (non-null)
List<UXToggle> toggles = new List<UXToggle>();
for (int i = 0; i < m_Toggles.arraySize; i++)
{
var elem = m_Toggles.GetArrayElementAtIndex(i);
var t = elem.objectReferenceValue as UXToggle;
if (t != null)
toggles.Add(t);
}
// Prepare options array with a "None" entry
string[] options = new string[toggles.Count + 1];
options[0] = "<None>";
for (int i = 0; i < toggles.Count; i++)
{
options[i + 1] = string.Format("[{0}] {1}", i, toggles[i] != null ? toggles[i].name : "Null");
}
// Determine current index
UXToggle currentDefault = m_DefaultToggle.objectReferenceValue as UXToggle;
int currentIndex = 0;
if (currentDefault != null)
{
int found = toggles.IndexOf(currentDefault);
if (found >= 0)
currentIndex = found + 1; // +1 because 0 is <None>
else
{
// Current default is not in the list -> clear it
m_DefaultToggle.objectReferenceValue = null;
serializedObject.ApplyModifiedProperties();
currentIndex = 0;
}
}
EditorGUI.BeginChangeCheck();
int newIndex = EditorGUILayout.Popup("Default Toggle", currentIndex, options);
if (EditorGUI.EndChangeCheck())
{
UXToggle newDefault = null;
if (newIndex > 0)
newDefault = toggles[newIndex - 1];
m_DefaultToggle.objectReferenceValue = newDefault;
serializedObject.ApplyModifiedProperties();
// 如果选择了一个非空默认项,则在 allowSwitchOff == false 时将其设为选中状态(并通知组)
if (newDefault != null)
{
// 确保该 toggle 在 group 中(理论上应该如此)
if (!_target.ContainsToggle(newDefault))
{
_target.RegisterToggle(newDefault);
}
if (!_target.allowSwitchOff)
{
// 通过 SerializedObject 修改 UXToggle 的 m_IsOn避免触发不必要的回调
SerializedObject so = new SerializedObject(newDefault);
var isOnProp = so.FindProperty("m_IsOn");
isOnProp.boolValue = true;
so.ApplyModifiedProperties();
// 通知组同步其余项
_target.NotifyToggleOn(newDefault);
}
}
else
{
// 选择 None不自动切换状态。但如果组不允许 all-off则会在 EnsureValidState 中被处理
}
}
}
private void DrawHeader(Rect rect)
{
EditorGUI.LabelField(rect, "Toggles", EditorStyles.boldLabel);
}
// 记录旧的引用用于侦测变化
private UXToggle previousRef;
private void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
SerializedProperty element = m_Toggles.GetArrayElementAtIndex(index);
rect.y += 2;
Rect fieldRect = new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight);
UXToggle oldButton = element.objectReferenceValue as UXToggle;
string label = $"[{index}] {(oldButton != null ? oldButton.name : "Null")}";
EditorGUI.BeginChangeCheck();
var newRef = EditorGUI.ObjectField(fieldRect, label, oldButton, typeof(UXToggle), true) as UXToggle;
if (EditorGUI.EndChangeCheck())
{
// 先处理 Remove旧值存在且不同
if (oldButton != null && oldButton != newRef)
{
OnRemove(oldButton);
}
// 再处理 Add新值非空
if (newRef != null && oldButton != newRef)
{
OnAdd(newRef);
}
// 最后把引用写回去
element.objectReferenceValue = newRef;
serializedObject.ApplyModifiedProperties();
}
}
private void OnAddList(ReorderableList list)
{
int newIndex = m_Toggles.arraySize;
m_Toggles.arraySize++;
serializedObject.ApplyModifiedProperties();
var newElem = m_Toggles.GetArrayElementAtIndex(newIndex);
newElem.objectReferenceValue = null;
serializedObject.ApplyModifiedProperties();
}
private void OnRemoveList(ReorderableList list)
{
if (list.index < 0 || list.index >= m_Toggles.arraySize)
return;
var oldButton = m_Toggles.GetArrayElementAtIndex(list.index).objectReferenceValue as UXToggle;
if (oldButton)
{
OnRemove(oldButton);
}
m_Toggles.DeleteArrayElementAtIndex(list.index);
serializedObject.ApplyModifiedProperties();
}
private void OnChanged(ReorderableList list)
{
serializedObject.ApplyModifiedProperties();
// 编辑器变动后同步 group 状态和默认项
if (!Application.isPlaying)
_target.EnsureValidState();
}
// ========================
// 自动调用的新增方法
// ========================
private void OnAdd(UXToggle toggle)
{
if (toggle == null)
return;
SerializedObject so = new SerializedObject(toggle);
var groupProp = so.FindProperty("m_Group");
groupProp.objectReferenceValue = target;
so.ApplyModifiedProperties();
UXGroup group = (UXGroup)target;
group.RegisterToggle(toggle);
// 添加后尽量同步组状态(处理默认项或冲突)
if (!Application.isPlaying)
group.EnsureValidState();
}
private void OnRemove(UXToggle toggle)
{
if (toggle == null)
return;
SerializedObject so = new SerializedObject(toggle);
var groupProp = so.FindProperty("m_Group");
UXGroup group = groupProp.objectReferenceValue as UXGroup;
if (group != null)
group.UnregisterToggle(toggle);
groupProp.objectReferenceValue = null;
so.ApplyModifiedProperties();
// 如果移除的正好是默认项,则清空默认选项
if (m_DefaultToggle != null && m_DefaultToggle.objectReferenceValue == toggle)
{
m_DefaultToggle.objectReferenceValue = null;
serializedObject.ApplyModifiedProperties();
}
if (!Application.isPlaying && _target != null)
_target.EnsureValidState();
}
}
}