522 lines
19 KiB
C#
522 lines
19 KiB
C#
#if UNITY_EDITOR
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using AlicizaX.UI.Extension.Editor.Editor.Editor_Handlers;
|
|
using UnityEditor;
|
|
using UnityEditorInternal;
|
|
using UnityEditor.UI;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
[CanEditMultipleObjects]
|
|
[CustomEditor(typeof(UXButton), true)]
|
|
public class UXButtonEditor : Editor
|
|
{
|
|
private enum TabType
|
|
{
|
|
Image,
|
|
Sound,
|
|
Event
|
|
}
|
|
|
|
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 UXGroup group;
|
|
private int m_ButtonMode;
|
|
private SerializedProperty m_SelectionState;
|
|
|
|
private ReorderableList m_ChildTransitionList;
|
|
|
|
private static Color darkZebraEven = new Color(0.22f, 0.22f, 0.22f);
|
|
private static Color darkZebraOdd = new Color(0.27f, 0.27f, 0.27f);
|
|
|
|
|
|
private TabType currentTab = TabType.Image;
|
|
private GUISkin customSkin;
|
|
|
|
private SerializedProperty hoverAudioClip;
|
|
private SerializedProperty clickAudioClip;
|
|
|
|
private void OnEnable()
|
|
{
|
|
customSkin = (GUISkin)AssetDatabase.LoadAssetAtPath<GUISkin>("Packages/com.alicizax.unity.ui.extension/Editor/Res/HeatUIEditor-Dark.guiskin");
|
|
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_SelectionState = serializedObject.FindProperty("m_SelectionState");
|
|
|
|
group = (UXGroup)m_UXGroup.objectReferenceValue;
|
|
m_ButtonMode = m_Mode.enumValueIndex;
|
|
|
|
hoverAudioClip = serializedObject.FindProperty("hoverAudioClip");
|
|
clickAudioClip = serializedObject.FindProperty("clickAudioClip");
|
|
|
|
CreateChildTransitionList();
|
|
}
|
|
|
|
private void CreateChildTransitionList()
|
|
{
|
|
m_ChildTransitionList = new ReorderableList(serializedObject, m_ChildTransitions, true, false, true, true);
|
|
// m_ChildTransitionList.drawHeaderCallback = (rect) => { EditorGUI.LabelField(rect, "Other Transitions"); };
|
|
|
|
m_ChildTransitionList.drawElementBackgroundCallback = (rect, index, isActive, isFocused) =>
|
|
{
|
|
var background = index % 2 == 0 ? darkZebraEven : darkZebraOdd;
|
|
EditorGUI.DrawRect(rect, background);
|
|
};
|
|
|
|
m_ChildTransitionList.drawElementCallback = (rect, index, isActive, isFocused) =>
|
|
{
|
|
var element = m_ChildTransitionList.serializedProperty.GetArrayElementAtIndex(index);
|
|
rect.y += 2;
|
|
|
|
// 绘制折叠框标题(仅显示名称)
|
|
string elementTitle = $"Null Transition";
|
|
var targetProp = element.FindPropertyRelative("targetGraphic");
|
|
if (targetProp.objectReferenceValue != null)
|
|
elementTitle = targetProp.objectReferenceValue.name;
|
|
|
|
EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight),
|
|
elementTitle, EditorStyles.boldLabel);
|
|
|
|
// 直接绘制完整内容(无折叠状态)
|
|
rect.y += EditorGUIUtility.singleLineHeight + 2;
|
|
DrawTransitionData(new Rect(rect.x, rect.y, rect.width, 0), element, true);
|
|
};
|
|
|
|
// 设置元素高度
|
|
m_ChildTransitionList.elementHeightCallback = (index) =>
|
|
{
|
|
return EditorGUIUtility.singleLineHeight +
|
|
CalculateTransitionDataHeight(m_ChildTransitionList.serializedProperty.GetArrayElementAtIndex(index)) +
|
|
10;
|
|
};
|
|
|
|
m_ChildTransitionList.onAddCallback = (list) =>
|
|
{
|
|
list.serializedProperty.arraySize++;
|
|
serializedObject.ApplyModifiedProperties();
|
|
};
|
|
|
|
// 添加删除按钮
|
|
m_ChildTransitionList.onRemoveCallback = (list) => { ReorderableList.defaultBehaviours.DoRemoveButton(list); };
|
|
}
|
|
|
|
private void ResetEventProperty(SerializedProperty property)
|
|
{
|
|
SerializedProperty persistentCalls = property.FindPropertyRelative("m_PersistentCalls");
|
|
SerializedProperty calls = persistentCalls.FindPropertyRelative("m_Calls");
|
|
calls.arraySize = 0;
|
|
property.serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
private void DrawTabButton(TabType tabType, string label, string iconName)
|
|
{
|
|
bool isActive = currentTab == tabType;
|
|
var style = new GUIStyle(EditorStyles.toolbarButton)
|
|
{
|
|
fixedHeight = 25,
|
|
fontSize = 11,
|
|
fontStyle = isActive ? FontStyle.Bold : FontStyle.Normal
|
|
};
|
|
|
|
var content = new GUIContent(
|
|
EditorGUIUtility.IconContent(iconName).image,
|
|
label
|
|
);
|
|
|
|
if (GUILayout.Button(content, style))
|
|
{
|
|
currentTab = tabType;
|
|
}
|
|
|
|
// 高亮当前选中的标签页
|
|
if (isActive)
|
|
{
|
|
Rect rect = GUILayoutUtility.GetLastRect();
|
|
EditorGUI.DrawRect(new Rect(rect.x, rect.yMax - 2, rect.width, 2),
|
|
new Color(0.1f, 0.5f, 0.9f));
|
|
}
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
serializedObject.Update();
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
|
|
// 图像标签页按钮
|
|
DrawTabButton(TabType.Image, "Image", "d_Texture Icon");
|
|
|
|
// 声音标签页按钮
|
|
DrawTabButton(TabType.Sound, "Sound", "d_AudioSource Icon");
|
|
|
|
// 事件标签页按钮
|
|
DrawTabButton(TabType.Event, "Event", "EventTrigger Icon");
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
switch (currentTab)
|
|
{
|
|
case TabType.Image:
|
|
DrawGraphicsTab();
|
|
break;
|
|
case TabType.Sound:
|
|
DrawAudioTab();
|
|
break;
|
|
case TabType.Event:
|
|
DrawEventTab();
|
|
break;
|
|
}
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
private void DrawGraphicsTab()
|
|
{
|
|
EditorGUI.BeginDisabledGroup(EditorApplication.isPlaying);
|
|
EditorGUILayout.PropertyField(m_Mode);
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
var interactable = UIEditorSkinHelper.DrawToggle(m_Interactable.boolValue, customSkin, "Interactable");
|
|
m_Interactable.boolValue = interactable;
|
|
|
|
GUILayout.Space(1);
|
|
DrawSelfTransition();
|
|
|
|
GUILayout.Space(5);
|
|
DrawChildTransitions();
|
|
GUILayout.Space(1);
|
|
|
|
DrawBasicSettings();
|
|
}
|
|
|
|
private void DrawEventTab()
|
|
{
|
|
if (m_Mode.enumValueIndex == (int)ButtonModeType.Toggle)
|
|
{
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.PropertyField(m_OnValueChanged);
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.Space();
|
|
EditorGUILayout.PropertyField(m_OnClick);
|
|
}
|
|
}
|
|
|
|
private void DrawAudioTab()
|
|
{
|
|
UIEditorSkinHelper.DrawProperty(hoverAudioClip, customSkin, "Hover Sound", "Play", () =>
|
|
{
|
|
if (hoverAudioClip.objectReferenceValue != null)
|
|
{
|
|
PlayAudio((AudioClip)hoverAudioClip.objectReferenceValue);
|
|
}
|
|
});
|
|
UIEditorSkinHelper.DrawProperty(clickAudioClip, customSkin, "Click Sound", "Play", () =>
|
|
{
|
|
if (hoverAudioClip.objectReferenceValue != null)
|
|
{
|
|
PlayAudio((AudioClip)hoverAudioClip.objectReferenceValue);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void DrawBasicSettings()
|
|
{
|
|
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)
|
|
{
|
|
UIEditorSkinHelper.DrawProperty(m_UXGroup, customSkin, "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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PlayAudio(AudioClip clip)
|
|
{
|
|
if (clip != null)
|
|
{
|
|
ExtensionHelper.PreviewAudioClip(clip);
|
|
}
|
|
}
|
|
|
|
private void DrawChildTransitions()
|
|
{
|
|
m_ChildTransitionList.DoLayoutList();
|
|
}
|
|
|
|
|
|
private float CalculateTransitionDataHeight(SerializedProperty transitionData)
|
|
{
|
|
float height = 0;
|
|
SerializedProperty transition = transitionData.FindPropertyRelative("transition");
|
|
var currentTransition = GetTransition(transition);
|
|
|
|
height += EditorGUIUtility.singleLineHeight * 1.5f;
|
|
height += EditorGUIUtility.singleLineHeight;
|
|
|
|
SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic");
|
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
|
var animation = graphic != null ? graphic.GetComponent<Animation>() : null;
|
|
|
|
switch (currentTransition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
if (graphic == null) height += EditorGUIUtility.singleLineHeight;
|
|
break;
|
|
case Selectable.Transition.SpriteSwap:
|
|
if (!(graphic is Image)) height += EditorGUIUtility.singleLineHeight;
|
|
break;
|
|
case Selectable.Transition.Animation:
|
|
if (animation == null) height += EditorGUIUtility.singleLineHeight;
|
|
break;
|
|
}
|
|
|
|
|
|
switch (currentTransition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("colors"));
|
|
break;
|
|
case Selectable.Transition.SpriteSwap:
|
|
height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("spriteState"));
|
|
break;
|
|
case Selectable.Transition.Animation:
|
|
height += EditorGUI.GetPropertyHeight(transitionData.FindPropertyRelative("animationTriggers"));
|
|
break;
|
|
}
|
|
|
|
return height;
|
|
}
|
|
|
|
private void DrawTransitionData(Rect position, SerializedProperty transitionData, bool isChild = false)
|
|
{
|
|
SerializedProperty targetGraphic = transitionData.FindPropertyRelative("targetGraphic");
|
|
SerializedProperty transition = transitionData.FindPropertyRelative("transition");
|
|
SerializedProperty colorBlock = transitionData.FindPropertyRelative("colors");
|
|
SerializedProperty spriteState = transitionData.FindPropertyRelative("spriteState");
|
|
SerializedProperty animationTriggers = transitionData.FindPropertyRelative("animationTriggers");
|
|
|
|
EditorGUI.indentLevel++;
|
|
float lineHeight = EditorGUIUtility.singleLineHeight;
|
|
float spacing = 2f;
|
|
float y = position.y;
|
|
|
|
Rect targetRect = new Rect(position.x, y, position.width, lineHeight);
|
|
EditorGUI.PropertyField(targetRect, targetGraphic);
|
|
y += lineHeight + spacing;
|
|
|
|
var currentTransition = GetTransition(transition);
|
|
|
|
Rect transitionRect = new Rect(position.x, y, position.width, lineHeight);
|
|
EditorGUI.PropertyField(transitionRect, transition);
|
|
y += lineHeight + spacing;
|
|
|
|
var graphic = targetGraphic.objectReferenceValue as Graphic;
|
|
var animation = graphic != null ? graphic.GetComponent<Animation>() : null;
|
|
|
|
switch (currentTransition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
if (graphic == null)
|
|
{
|
|
Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
|
|
EditorGUI.HelpBox(warningRect, "需要Graphic组件来使用颜色过渡", MessageType.Warning);
|
|
y += lineHeight + spacing;
|
|
}
|
|
|
|
break;
|
|
|
|
case Selectable.Transition.SpriteSwap:
|
|
if (!(graphic is Image))
|
|
{
|
|
Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
|
|
EditorGUI.HelpBox(warningRect, "需要Image组件来使用精灵切换", MessageType.Warning);
|
|
y += lineHeight + spacing;
|
|
}
|
|
|
|
break;
|
|
case Selectable.Transition.Animation:
|
|
if (animation == null)
|
|
{
|
|
Rect warningRect = new Rect(position.x, y, position.width, lineHeight);
|
|
EditorGUI.HelpBox(warningRect, "需要Animation || Animator组件来使用动画切换", MessageType.Warning);
|
|
y += lineHeight + spacing;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
switch (currentTransition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
CheckAndSetColorDefaults(colorBlock, targetGraphic);
|
|
Rect colorRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(colorBlock));
|
|
EditorGUI.PropertyField(colorRect, colorBlock);
|
|
break;
|
|
|
|
case Selectable.Transition.SpriteSwap:
|
|
Rect spriteRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(spriteState));
|
|
EditorGUI.PropertyField(spriteRect, spriteState);
|
|
break;
|
|
case Selectable.Transition.Animation:
|
|
Rect animRect = new Rect(position.x, y, position.width, EditorGUI.GetPropertyHeight(animationTriggers));
|
|
EditorGUI.PropertyField(animRect, animationTriggers);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void DrawSelfTransition()
|
|
{
|
|
GUILayout.BeginVertical(EditorStyles.helpBox);
|
|
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;
|
|
}
|
|
|
|
|
|
EditorGUILayout.PropertyField(targetGraphic);
|
|
|
|
SerializedProperty transition = m_TransitionData.FindPropertyRelative("transition");
|
|
EditorGUILayout.PropertyField(transition);
|
|
|
|
var currentTransition = GetTransition(transition);
|
|
|
|
var animation = graphic != null ? graphic.GetComponent<Animation>() : null;
|
|
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;
|
|
case Selectable.Transition.Animation:
|
|
if (animation == null)
|
|
EditorGUILayout.HelpBox("需要Animation || Animator组件来使用动画切换", MessageType.Warning);
|
|
break;
|
|
}
|
|
|
|
switch (currentTransition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
CheckAndSetColorDefaults(m_TransitionData.FindPropertyRelative("colors"), targetGraphic);
|
|
EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("colors"));
|
|
break;
|
|
case Selectable.Transition.SpriteSwap:
|
|
EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("spriteState"));
|
|
break;
|
|
case Selectable.Transition.Animation:
|
|
EditorGUILayout.PropertyField(m_TransitionData.FindPropertyRelative("animationTriggers"));
|
|
break;
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
EditorGUILayout.Space();
|
|
GUILayout.EndVertical();
|
|
}
|
|
|
|
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);
|
|
}
|
|
else if (m_SelectionState.enumValueIndex == 0)
|
|
{
|
|
Color color = colorBlock.FindPropertyRelative("m_NormalColor").colorValue;
|
|
graphic.canvasRenderer.SetColor(color);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Selectable.Transition GetTransition(SerializedProperty transition)
|
|
{
|
|
return (Selectable.Transition)transition.enumValueIndex;
|
|
}
|
|
}
|
|
|
|
#endif
|