// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik // #if UNITY_EDITOR using Animancer.TransitionLibraries; using System; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace Animancer.Editor.TransitionLibraries { /// [Editor-Only] /// A custom Inspector for . /// /// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibrarySelectionEditor [CustomEditor(typeof(TransitionLibrarySelection), true)] public class TransitionLibrarySelectionEditor : UnityEditor.Editor { /************************************************************************************************************************/ /// Casts the . public TransitionLibrarySelection Target => target as TransitionLibrarySelection; /************************************************************************************************************************/ /// public override void OnInspectorGUI() { var target = Target; if (target == null || !target.Validate()) return; EditorGUI.BeginChangeCheck(); switch (target.Type) { case TransitionLibrarySelection.SelectionType.Library: DoNestedEditorGUI(target.Selected as TransitionLibraryAsset, "Transition Library"); break; case TransitionLibrarySelection.SelectionType.FromTransition: case TransitionLibrarySelection.SelectionType.ToTransition: DoTransitionGUI(target.Selected as TransitionAssetBase); break; case TransitionLibrarySelection.SelectionType.Modifier: DoModifierGUI(target, (TransitionModifierDefinition)target.Selected); break; case TransitionLibrarySelection.SelectionType.Group: DoGroupGUI(target, (TransitionGroup)target.Selected); break; default: target.Deselect(); break; } if (EditorGUI.EndChangeCheck()) target.Window.Repaint(); } /************************************************************************************************************************/ #region Nested Editor /************************************************************************************************************************/ [NonSerialized] private readonly CachedEditor NestedEditor = new(); [NonSerialized] private readonly CachedEditor NestedEditor2 = new(); /************************************************************************************************************************/ /// Draws the for the `target`. private void DoNestedEditorGUI(T target, string referenceLabel) where T : Object { using (new EditorGUI.DisabledScope(true)) AnimancerGUI.DoObjectFieldGUI(referenceLabel, target, false); var editor = NestedEditor.GetEditor(target); if (editor != null) editor.OnInspectorGUI(); } /************************************************************************************************************************/ /// Cleans up any nested editors. protected virtual void OnDestroy() { NestedEditor.Dispose(); NestedEditor2.Dispose(); } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Transitions /************************************************************************************************************************/ /// Draws the GUI for the `transition`. private void DoTransitionGUI( TransitionAssetBase transition) { DoTransitionNameGUI(transition); DoNestedEditorGUI(transition, "Transition Asset"); } /************************************************************************************************************************/ /// Draws a field for editing the name of the `transition`. private void DoTransitionNameGUI( TransitionAssetBase transition) { var isSubAsset = AssetDatabase.IsSubAsset(transition); var isMainAsset = !isSubAsset && AssetDatabase.IsMainAsset(transition); var label = isSubAsset ? "Sub-Asset Name" : isMainAsset ? "File Name" : "Name"; EditorGUI.BeginChangeCheck(); var name = TransitionModifierTableGUI.GetTransitionName(transition); name = EditorGUILayout.DelayedTextField(label, name); if (EditorGUI.EndChangeCheck() && transition != null) { transition.SetName(name); if (isSubAsset) { AssetDatabase.SaveAssets(); } else if (isMainAsset) { AssetDatabase.RenameAsset( AssetDatabase.GetAssetPath(transition), name); } } } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Modifiers /************************************************************************************************************************/ private static readonly BoolPref IsFromExpanded = new($"{nameof(TransitionLibrarySelectionEditor)}.{nameof(IsFromExpanded)}"), IsToExpanded = new($"{nameof(TransitionLibrarySelectionEditor)}.{nameof(IsToExpanded)}"); /************************************************************************************************************************/ /// Draws the GUI for the `modifier`. private void DoModifierGUI( TransitionLibrarySelection selection, TransitionModifierDefinition modifier) { var library = selection.Window.Data; DoTransitionField(library, NestedEditor, IsFromExpanded, modifier.FromIndex, "From"); DoTransitionField(library, NestedEditor2, IsToExpanded, modifier.ToIndex, "To"); if (selection.Window.TryGetPage(out var fadeDurations)) { var area = AnimancerGUI.LayoutSingleLineRect(); TransitionModifierTableGUI.DoModifierValueGUI( area, selection.Window, fadeDurations, modifier.FromIndex, modifier.ToIndex, "Fade Duration", false); } if (selection.Window.TryGetPage(out var startTimes)) { var area = AnimancerGUI.LayoutSingleLineRect(); TransitionModifierTableGUI.DoModifierValueGUI( area, selection.Window, startTimes, modifier.FromIndex, modifier.ToIndex, "Start Time", false); } } /************************************************************************************************************************/ /// Draws the GUI for a transition. private TransitionAssetBase DoTransitionField( TransitionLibraryDefinition library, CachedEditor cachedEditor, BoolPref isExpanded, int transitionIndex, string label) { library.TryGetTransition(transitionIndex, out var transition); var area = AnimancerGUI.LayoutSingleLineRect(AnimancerGUI.SpacingMode.After); var labelArea = area; labelArea.width = EditorGUIUtility.labelWidth; isExpanded.Value = EditorGUI.Foldout(labelArea, isExpanded, GUIContent.none, true); var enabled = GUI.enabled; GUI.enabled = false; AnimancerGUI.DoObjectFieldGUI(area, label, transition, false); GUI.enabled = enabled; if (isExpanded) { GUILayout.BeginVertical(GUI.skin.box); var editor = cachedEditor.GetEditor(transition); editor.OnInspectorGUI(); GUILayout.EndVertical(); } return transition; } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Groups /************************************************************************************************************************/ /// Draws the GUI for the `group`. private void DoGroupGUI( TransitionLibrarySelection selection, TransitionGroup group) { group.Name = EditorGUILayout.TextField("Group Name", group.Name); var enabled = GUI.enabled; GUI.enabled = false; EditorGUILayout.LabelField("Transition Count", group.TransitionIndices.Count.ToStringCached()); var transitions = selection.Window.Data.Transitions; for (int i = 0; i < group.TransitionIndices.Count; i++) { var index = group.TransitionIndices[i]; if (!transitions.TryGetObject(index, out var transition)) continue; EditorGUILayout.ObjectField( $"Transition {i.ToStringCached()}", transition, typeof(TransitionAssetBase), false); } GUI.enabled = enabled; } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ } } #endif