310 lines
10 KiB
C#
310 lines
10 KiB
C#
|
// UXButtonEditor.cs
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using Sirenix.OdinInspector.Editor;
|
||
|
using UnityEditor;
|
||
|
using UnityEditor.AnimatedValues;
|
||
|
using UnityEditor.UI;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
|
||
|
[CanEditMultipleObjects]
|
||
|
[CustomEditor(typeof(UXButton), true)]
|
||
|
public class UXButtonEditor : Editor
|
||
|
{
|
||
|
private SerializedProperty m_Interactable;
|
||
|
private SerializedProperty m_Mode;
|
||
|
private SerializedProperty m_OnValueChanged;
|
||
|
private SerializedProperty m_OnClick;
|
||
|
private SerializedProperty m_UXGroup;
|
||
|
|
||
|
private SerializedProperty m_TransitionData;
|
||
|
|
||
|
private SerializedProperty m_ChildTransitions;
|
||
|
|
||
|
private SerializedProperty m_ButtonUISounds;
|
||
|
|
||
|
private bool m_ShowChildTransitions = true;
|
||
|
private Dictionary<int, bool> m_ChildTransitionFoldouts = new Dictionary<int, bool>();
|
||
|
private UXGroup group;
|
||
|
private int m_ButtonMode;
|
||
|
|
||
|
private void OnEnable()
|
||
|
{
|
||
|
m_Interactable = serializedObject.FindProperty("m_Interactable");
|
||
|
m_UXGroup = serializedObject.FindProperty("m_UXGroup");
|
||
|
m_Mode = serializedObject.FindProperty("m_Mode");
|
||
|
m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
|
||
|
m_OnClick = serializedObject.FindProperty("m_OnClick");
|
||
|
m_TransitionData = serializedObject.FindProperty("m_TransitionData");
|
||
|
m_ChildTransitions = serializedObject.FindProperty("m_ChildTransitions");
|
||
|
m_ButtonUISounds = serializedObject.FindProperty("m_ButtonUISounds");
|
||
|
m_ChildTransitionFoldouts.Clear();
|
||
|
group = (UXGroup)m_UXGroup.objectReferenceValue;
|
||
|
m_ButtonMode = m_Mode.enumValueIndex;
|
||
|
}
|
||
|
|
||
|
private void ResetEventProperty(SerializedProperty property)
|
||
|
{
|
||
|
SerializedProperty persistentCalls = property.FindPropertyRelative("m_PersistentCalls");
|
||
|
SerializedProperty calls = persistentCalls.FindPropertyRelative("m_Calls");
|
||
|
calls.arraySize = 0;
|
||
|
property.serializedObject.ApplyModifiedProperties();
|
||
|
}
|
||
|
public override void OnInspectorGUI()
|
||
|
{
|
||
|
serializedObject.Update();
|
||
|
|
||
|
EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying);
|
||
|
EditorGUILayout.PropertyField(m_Mode);
|
||
|
EditorGUI.EndDisabledGroup();
|
||
|
EditorGUILayout.PropertyField(m_Interactable);
|
||
|
|
||
|
GUILayout.Space(1);
|
||
|
DrawSelfTransition();
|
||
|
|
||
|
GUILayout.Space(5);
|
||
|
DrawChildTransitions();
|
||
|
|
||
|
|
||
|
EditorGUILayout.PropertyField(m_ButtonUISounds);
|
||
|
EditorGUILayout.Space();
|
||
|
|
||
|
if (m_Mode.enumValueIndex != m_ButtonMode)
|
||
|
{
|
||
|
if (m_ButtonMode == (int)ButtonModeType.Normal)
|
||
|
{
|
||
|
ResetEventProperty(m_OnValueChanged);
|
||
|
m_UXGroup.objectReferenceValue = null;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ResetEventProperty((m_OnClick));
|
||
|
}
|
||
|
|
||
|
m_ButtonMode = m_Mode.enumValueIndex;
|
||
|
}
|
||
|
|
||
|
if (m_Mode.enumValueIndex == (int)ButtonModeType.Toggle)
|
||
|
{
|
||
|
EditorGUILayout.PropertyField(m_UXGroup);
|
||
|
UXGroup newGroup = (UXGroup)m_UXGroup.objectReferenceValue;
|
||
|
if (newGroup != group)
|
||
|
{
|
||
|
UXButton self = target as UXButton;
|
||
|
if (group != null)
|
||
|
{
|
||
|
group.UnregisterButton(self);
|
||
|
}
|
||
|
|
||
|
group = newGroup;
|
||
|
if (newGroup != null)
|
||
|
{
|
||
|
newGroup.RegisterButton(self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EditorGUILayout.Space();
|
||
|
EditorGUILayout.PropertyField(m_OnValueChanged);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EditorGUILayout.Space();
|
||
|
EditorGUILayout.PropertyField(m_OnClick);
|
||
|
}
|
||
|
|
||
|
|
||
|
serializedObject.ApplyModifiedProperties();
|
||
|
}
|
||
|
|
||
|
private void DrawChildTransitions()
|
||
|
{
|
||
|
m_ShowChildTransitions = EditorGUILayout.Foldout(m_ShowChildTransitions, "Child Transitions", true);
|
||
|
if (!m_ShowChildTransitions)
|
||
|
return;
|
||
|
|
||
|
EditorGUI.indentLevel++;
|
||
|
|
||
|
// 列表控制按钮
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
GUILayout.FlexibleSpace();
|
||
|
|
||
|
if (GUILayout.Button("Add Child Transition", GUILayout.Width(150)))
|
||
|
{
|
||
|
m_ChildTransitions.arraySize++;
|
||
|
serializedObject.ApplyModifiedProperties();
|
||
|
}
|
||
|
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
// 遍历列表元素
|
||
|
for (int i = 0; i < m_ChildTransitions.arraySize; i++)
|
||
|
{
|
||
|
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||
|
|
||
|
// 获取当前元素的SerializedProperty
|
||
|
SerializedProperty element = m_ChildTransitions.GetArrayElementAtIndex(i);
|
||
|
|
||
|
// 初始化折叠状态
|
||
|
if (!m_ChildTransitionFoldouts.ContainsKey(i))
|
||
|
m_ChildTransitionFoldouts[i] = true;
|
||
|
|
||
|
// 折叠标题
|
||
|
string elementTitle = $"Child Transition {i}";
|
||
|
if (element.FindPropertyRelative("targetGraphic").objectReferenceValue != null)
|
||
|
elementTitle += $" ({element.FindPropertyRelative("targetGraphic").objectReferenceValue.name})";
|
||
|
|
||
|
m_ChildTransitionFoldouts[i] = EditorGUILayout.Foldout(m_ChildTransitionFoldouts[i], elementTitle, true);
|
||
|
|
||
|
if (m_ChildTransitionFoldouts[i])
|
||
|
{
|
||
|
// 绘制单个TransitionData
|
||
|
DrawTransitionData(element);
|
||
|
|
||
|
// 删除按钮
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
GUILayout.FlexibleSpace();
|
||
|
var orginColor = GUI.backgroundColor;
|
||
|
GUI.backgroundColor = Color.red;
|
||
|
if (GUILayout.Button("Remove", GUILayout.Width(80)))
|
||
|
{
|
||
|
m_ChildTransitions.DeleteArrayElementAtIndex(i);
|
||
|
m_ChildTransitionFoldouts.Remove(i);
|
||
|
serializedObject.ApplyModifiedProperties();
|
||
|
break; // 删除后退出当前循环
|
||
|
}
|
||
|
|
||
|
GUI.backgroundColor = orginColor;
|
||
|
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
}
|
||
|
|
||
|
EditorGUILayout.EndVertical();
|
||
|
EditorGUILayout.Space(5);
|
||
|
}
|
||
|
|
||
|
EditorGUI.indentLevel--;
|
||
|
}
|
||
|
|
||
|
private void DrawTransitionData(SerializedProperty transitionData)
|
||
|
{
|
||
|
SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic");
|
||
|
SerializedProperty transition = transitionData.FindPropertyRelative("transition");
|
||
|
SerializedProperty colorBlock = transitionData.FindPropertyRelative("colors");
|
||
|
SerializedProperty spriteState = transitionData.FindPropertyRelative("spriteState");
|
||
|
|
||
|
EditorGUI.indentLevel++;
|
||
|
|
||
|
// 绘制目标图形
|
||
|
EditorGUILayout.PropertyField(targetGraphic);
|
||
|
|
||
|
// 获取当前transition类型
|
||
|
var currentTransition = GetTransition(transition);
|
||
|
|
||
|
// 绘制transition类型
|
||
|
EditorGUILayout.PropertyField(transition);
|
||
|
|
||
|
// 显示警告信息
|
||
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
||
|
switch (currentTransition)
|
||
|
{
|
||
|
case Selectable.Transition.ColorTint:
|
||
|
if (graphic == null)
|
||
|
EditorGUILayout.HelpBox("需要Graphic组件来使用颜色过渡", MessageType.Warning);
|
||
|
break;
|
||
|
|
||
|
case Selectable.Transition.SpriteSwap:
|
||
|
if (!(graphic is Image))
|
||
|
EditorGUILayout.HelpBox("需要Image组件来使用精灵切换", MessageType.Warning);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// 绘制对应类型的属性
|
||
|
switch (currentTransition)
|
||
|
{
|
||
|
case Selectable.Transition.ColorTint:
|
||
|
CheckAndSetColorDefaults(colorBlock, targetGraphic);
|
||
|
EditorGUILayout.PropertyField(colorBlock);
|
||
|
break;
|
||
|
|
||
|
case Selectable.Transition.SpriteSwap:
|
||
|
EditorGUILayout.PropertyField(spriteState);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
EditorGUI.indentLevel--;
|
||
|
}
|
||
|
|
||
|
void CheckAndSetColorDefaults(SerializedProperty colorBlock, SerializedProperty targetGraphic)
|
||
|
{
|
||
|
bool isDirty = false;
|
||
|
string[] colorProps = new string[] { "m_NormalColor", "m_HighlightedColor", "m_PressedColor", "m_SelectedColor", "m_DisabledColor" };
|
||
|
foreach (var propName in colorProps)
|
||
|
{
|
||
|
SerializedProperty prop = colorBlock.FindPropertyRelative(propName);
|
||
|
Color color = prop.colorValue;
|
||
|
if (color.r == 0 && color.g == 0 && color.b == 0 && color.a == 0)
|
||
|
{
|
||
|
isDirty = true;
|
||
|
if (prop.name == "m_PressedColor")
|
||
|
{
|
||
|
prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 1.0f);
|
||
|
}
|
||
|
else if (prop.name == "m_DisabledColor")
|
||
|
{
|
||
|
prop.colorValue = new Color(0.7843137f, 0.7843137f, 0.7843137f, 0.5f);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
prop.colorValue = Color.white;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SerializedProperty fadeDuration = colorBlock.FindPropertyRelative("m_FadeDuration");
|
||
|
SerializedProperty m_ColorMultiplier = colorBlock.FindPropertyRelative("m_ColorMultiplier");
|
||
|
if (isDirty)
|
||
|
{
|
||
|
m_ColorMultiplier.floatValue = 1f;
|
||
|
fadeDuration.floatValue = 0.1f;
|
||
|
}
|
||
|
|
||
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
||
|
if (graphic != null)
|
||
|
{
|
||
|
if (!EditorApplication.isPlaying)
|
||
|
{
|
||
|
Color color = colorBlock.FindPropertyRelative("m_NormalColor").colorValue;
|
||
|
graphic.canvasRenderer.SetColor(color);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void DrawSelfTransition()
|
||
|
{
|
||
|
EditorGUILayout.LabelField("Main Transition", EditorStyles.boldLabel);
|
||
|
SerializedProperty targetGraphic = m_TransitionData.FindPropertyRelative("targetGraphic");
|
||
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
||
|
if (graphic == null)
|
||
|
{
|
||
|
graphic = (target as UXButton).GetComponent<Graphic>();
|
||
|
targetGraphic.objectReferenceValue = graphic;
|
||
|
}
|
||
|
|
||
|
EditorGUI.indentLevel++;
|
||
|
DrawTransitionData(m_TransitionData);
|
||
|
EditorGUI.indentLevel--;
|
||
|
EditorGUILayout.Space();
|
||
|
}
|
||
|
|
||
|
|
||
|
static Selectable.Transition GetTransition(SerializedProperty transition)
|
||
|
{
|
||
|
return (Selectable.Transition)transition.enumValueIndex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|