123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEditorInternal;
- using UnityEngine;
- using Object = UnityEngine.Object;
- namespace Animancer.Editor
- {
- /// <summary>[Editor-Only] A custom Inspector for <see cref="NamedAnimancerComponent"/>s.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/NamedAnimancerComponentEditor
- ///
- [CustomEditor(typeof(NamedAnimancerComponent), true), CanEditMultipleObjects]
- public class NamedAnimancerComponentEditor : AnimancerComponentEditor
- {
- /************************************************************************************************************************/
- /// <inheritdoc/>
- 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);
- }
- }
- /************************************************************************************************************************/
- /// <summary>
- /// The <see cref="NamedAnimancerComponent.PlayAutomatically"/> and
- /// <see cref="NamedAnimancerComponent.Animations"/> fields are only used on startup, so we don't need to show
- /// them in Play Mode after the object is already enabled.
- /// </summary>
- private bool ShouldShowAnimationFields()
- {
- if (!EditorApplication.isPlayingOrWillChangePlaymode)
- return true;
- for (int i = 0; i < Targets.Length; i++)
- if (!Targets[i].IsGraphInitialized)
- 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 (var label = PooledGUIContent.Acquire(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 = AnimancerGUI.DoObjectFieldGUI(area, GUIContent.none, clip, 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);
- _Animations ??= new(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);
- HandleDragAndDropToAddAnimations(GUILayoutUtility.GetLastRect(), property);
- }
- /************************************************************************************************************************/
- private SerializedProperty _AnimationsArraySize;
- private void DrawAnimationsHeader(Rect area)
- {
- var labelWidth = EditorGUIUtility.labelWidth;
- EditorGUIUtility.labelWidth -= 6;
- area.width += 5;
- var property = _Animations.serializedProperty;
- using (var label = PooledGUIContent.Acquire(property))
- {
- var propertyLabel = EditorGUI.BeginProperty(area, label, property);
- if (_AnimationsArraySize == null)
- {
- _AnimationsArraySize = property.Copy();
- _AnimationsArraySize.Next(true);
- _AnimationsArraySize.Next(true);
- }
- EditorGUI.PropertyField(area, _AnimationsArraySize, propertyLabel);
- EditorGUI.EndProperty();
- }
- EditorGUIUtility.labelWidth = labelWidth;
- }
- /************************************************************************************************************************/
- private static readonly HashSet<Object>
- PreviousAnimations = new();
- private void DrawAnimationElement(Rect area, int index, bool isActive, bool isFocused)
- {
- if (index == 0)
- PreviousAnimations.Clear();
- var labelWidth = EditorGUIUtility.labelWidth;
- EditorGUIUtility.labelWidth -= 20;
- var element = _Animations.serializedProperty.GetArrayElementAtIndex(index);
- var color = GUI.color;
- var animation = element.objectReferenceValue;
- if (animation == null || PreviousAnimations.Contains(animation))
- GUI.color = AnimancerGUI.WarningFieldColor;
- else
- PreviousAnimations.Add(animation);
- EditorGUI.BeginChangeCheck();
- EditorGUI.ObjectField(area, element, GUIContent.none);
- if (EditorGUI.EndChangeCheck() && element.objectReferenceValue == null)
- _RemoveAnimationIndex = index;
- GUI.color = color;
- EditorGUIUtility.labelWidth = labelWidth;
- }
- /************************************************************************************************************************/
- private static void RemoveSelectedElement(ReorderableList list)
- {
- var property = list.serializedProperty;
- var element = property.GetArrayElementAtIndex(list.index);
- // Deleting a non-null element sets it to null, so we make sure it's null to actually remove it.
- if (element.objectReferenceValue != null)
- element.objectReferenceValue = null;
- property.DeleteArrayElementAtIndex(list.index);
- if (list.index >= property.arraySize - 1)
- list.index = property.arraySize - 1;
- }
- /************************************************************************************************************************/
- private static DragAndDropHandler<object> _DropToAddAnimations;
- private static SerializedProperty _DropToAddAnimationsProperty;
- private static void HandleDragAndDropToAddAnimations(Rect area, SerializedProperty property)
- {
- _DropToAddAnimationsProperty = property;
- _DropToAddAnimations ??= (obj, isDrop) =>
- {
- using (ListPool<AnimationClip>.Instance.Acquire(out var clips))
- {
- clips.GatherFromSource(obj);
- var anyValid = false;
- for (int i = 0; i < clips.Count; i++)
- {
- var clip = clips[i];
- if (clip.legacy)
- continue;
- if (!isDrop)
- return true;
- anyValid = true;
- var targetProperty = _DropToAddAnimationsProperty;
- var index = targetProperty.arraySize;
- targetProperty.arraySize = index + 1;
- var element = targetProperty.GetArrayElementAtIndex(index);
- element.objectReferenceValue = clip;
- targetProperty.serializedObject.ApplyModifiedProperties();
- }
- return anyValid;
- }
- };
- _DropToAddAnimations.Handle(area);
- }
- /************************************************************************************************************************/
- }
- }
- #endif
|