// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2023 Kybernetik //
#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Animancer.Editor
{
/// [Editor-Only] A custom Inspector for s.
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/NamedAnimancerComponentEditor
///
[CustomEditor(typeof(NamedAnimancerComponent), true), CanEditMultipleObjects]
public class NamedAnimancerComponentEditor : AnimancerComponentEditor
{
/************************************************************************************************************************/
/// [Editor-Only]
/// Draws any custom GUI for the `property`. The return value indicates whether the GUI should replace the
/// regular call to or not.
///
protected override bool DoOverridePropertyGUI(string path, SerializedProperty property, GUIContent label)
{
switch (path)
{
case "_PlayAutomatically":
if (ShouldShowAnimationFields())
DoDefaultAnimationField(property);
return true;
case "_Animations":
if (ShouldShowAnimationFields())
{
DoAnimationsField(property);
}
return true;
default:
return base.DoOverridePropertyGUI(path, property, label);
}
}
/************************************************************************************************************************/
///
/// The and
/// fields are only used on startup, so we don't need to show
/// them in Play Mode after the object is already enabled.
///
private bool ShouldShowAnimationFields()
{
if (!EditorApplication.isPlaying)
return true;
for (int i = 0; i < Targets.Length; i++)
{
if (!Targets[i].IsPlayableInitialized)
return true;
}
return false;
}
/************************************************************************************************************************/
private void DoDefaultAnimationField(SerializedProperty playAutomatically)
{
var area = AnimancerGUI.LayoutSingleLineRect();
var playAutomaticallyWidth = EditorGUIUtility.labelWidth + AnimancerGUI.ToggleWidth;
var playAutomaticallyArea = AnimancerGUI.StealFromLeft(ref area, playAutomaticallyWidth);
using (ObjectPool.Disposable.AcquireContent(out var label, playAutomatically))
EditorGUI.PropertyField(playAutomaticallyArea, playAutomatically, label);
SerializedProperty firstElement;
AnimationClip clip;
var animations = serializedObject.FindProperty("_Animations");
if (animations.arraySize > 0)
{
firstElement = animations.GetArrayElementAtIndex(0);
clip = (AnimationClip)firstElement.objectReferenceValue;
EditorGUI.BeginProperty(area, null, firstElement);
}
else
{
firstElement = null;
clip = null;
EditorGUI.BeginProperty(area, null, animations);
}
EditorGUI.BeginChangeCheck();
var indentLevel = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
clip = (AnimationClip)EditorGUI.ObjectField(area, GUIContent.none, clip, typeof(AnimationClip), true);
EditorGUI.indentLevel = indentLevel;
if (EditorGUI.EndChangeCheck())
{
if (clip != null)
{
if (firstElement == null)
{
animations.arraySize = 1;
firstElement = animations.GetArrayElementAtIndex(0);
}
firstElement.objectReferenceValue = clip;
}
else
{
if (firstElement == null || animations.arraySize == 1)
animations.arraySize = 0;
else
firstElement.objectReferenceValue = clip;
}
}
EditorGUI.EndProperty();
}
/************************************************************************************************************************/
private ReorderableList _Animations;
private static int _RemoveAnimationIndex;
private void DoAnimationsField(SerializedProperty property)
{
GUILayout.Space(AnimancerGUI.StandardSpacing - 1);
if (_Animations == null)
{
_Animations = new ReorderableList(property.serializedObject, property.Copy())
{
drawHeaderCallback = DrawAnimationsHeader,
drawElementCallback = DrawAnimationElement,
elementHeight = AnimancerGUI.LineHeight,
onRemoveCallback = RemoveSelectedElement,
};
}
_RemoveAnimationIndex = -1;
GUILayout.BeginVertical();
_Animations.DoLayoutList();
GUILayout.EndVertical();
if (_RemoveAnimationIndex >= 0)
{
property.DeleteArrayElementAtIndex(_RemoveAnimationIndex);
}
AnimancerGUI.HandleDragAndDropAnimations(GUILayoutUtility.GetLastRect(), (clip) =>
{
var index = property.arraySize;
property.arraySize = index + 1;
var element = property.GetArrayElementAtIndex(index);
element.objectReferenceValue = clip;
property.serializedObject.ApplyModifiedProperties();
});
}
/************************************************************************************************************************/
private SerializedProperty _AnimationsArraySize;
private void DrawAnimationsHeader(Rect area)
{
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth -= 6;
area.width += 5;
var property = _Animations.serializedProperty;
using (ObjectPool.Disposable.AcquireContent(out var label, property))
{
label = EditorGUI.BeginProperty(area, label, property);
if (_AnimationsArraySize == null)
{
_AnimationsArraySize = property.Copy();
_AnimationsArraySize.Next(true);
_AnimationsArraySize.Next(true);
}
EditorGUI.PropertyField(area, _AnimationsArraySize, label);
EditorGUI.EndProperty();
}
EditorGUIUtility.labelWidth = labelWidth;
}
/************************************************************************************************************************/
private static readonly HashSet