// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // #if UNITY_EDITOR using System.Collections.Generic; using UnityEditor; using UnityEditor.Animations; using UnityEngine; using static Animancer.Editor.AnimancerGUI; namespace Animancer.Editor { /// for . /// https://kybernetik.com.au/animancer/api/Animancer.Editor/SerializableParameterBindingsDrawer [CustomPropertyDrawer(typeof(ControllerState.SerializableParameterBindings), true)] public class SerializableParameterBindingsDrawer : PropertyDrawer { /************************************************************************************************************************/ /// public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (!property.isExpanded) return LineHeight; GetFields(property, out var mode, out var bindings); var count = bindings.arraySize; if (count > 0 && mode.boolValue) count = 1 + Mathf.CeilToInt(count * 0.5f); return CalculateHeight(count + 3); } /************************************************************************************************************************/ /// public override void OnGUI(Rect area, SerializedProperty property, GUIContent label) { area.height = LineHeight; var isExpanded = EditorGUI.PropertyField(area, property, label, false); if (!isExpanded) return; EditorGUI.indentLevel++; NextVerticalArea(ref area); GetFields(property, out var mode, out var bindings); var parameterList = GetContextParameterList(property); var bindingCount = bindings.arraySize; DoModeGUI(ref area, mode, bindingCount, parameterList); var modeValue = mode.boolValue; DoBindingCountGUI(ref area, bindings, modeValue, ref bindingCount, parameterList); DoBindingsGUI(area, bindings, modeValue, bindingCount, parameterList); EditorGUI.indentLevel--; } /************************************************************************************************************************/ private void DoModeGUI( ref Rect area, SerializedProperty mode, int bindingCount, string parameterList) { using var label = PooledGUIContent.Acquire(); if (bindingCount == 0) { label.text = "Bind All Parameters"; label.tooltip = "If enabled, all parameters in the Animator Controller will be bound" + " to Animancer parameters with the same name and the Bindings array can be left empty." + parameterList; } else { label.text = "Rebind Names"; label.tooltip = "If enabled, the Bindings array will be taken in pairs so that each" + " Animator Controller parameter can be bound to an Animancer Parameter with different name." + parameterList; } EditorGUI.PropertyField(area, mode, label, false); NextVerticalArea(ref area); } /************************************************************************************************************************/ private void DoBindingCountGUI( ref Rect area, SerializedProperty bindings, bool mode, ref int bindingCount, string parameterList) { using var label = PooledGUIContent.Acquire( "Bindings", "The names of parameters in the Animator Controller to bind to Animancer parameters." + "\n� Leave this array empty and enable the toggle if you want to bind all parameters." + parameterList); var newCount = bindingCount; if (mode && bindingCount > 0) newCount /= 2; newCount = EditorGUI.DelayedIntField(area, label, newCount); if (newCount < 0) newCount = 0; else if (mode && newCount > 0) newCount *= 2; if (bindingCount != newCount) { bindingCount = newCount; bindings.arraySize = newCount; } NextVerticalArea(ref area); } /************************************************************************************************************************/ private void DoBindingsGUI( Rect area, SerializedProperty bindings, bool mode, int bindingCount, string parameterList) { if (bindingCount <= 0) return; using var label = PooledGUIContent.Acquire(); if (mode) { var controllerArea = EditorGUI.IndentedRect(area); controllerArea.xMin -= 1;// Not sure why. var animancerArea = StealFromRight(ref controllerArea, controllerArea.width * 0.5f, StandardSpacing); label.text = "Controller"; label.tooltip = "The name of the Animator Controller parameter" + parameterList; GUI.Label(controllerArea, label); label.text = "Animancer"; label.tooltip = "The name of the Animancer parameter"; GUI.Label(animancerArea, label); NextVerticalArea(ref controllerArea); NextVerticalArea(ref animancerArea); for (int i = 0; i < bindingCount; i++) { DoBindingGUI(ref controllerArea, bindings, i, GUIContent.none); i++; DoBindingGUI(ref animancerArea, bindings, i, GUIContent.none); } } else { EditorGUI.indentLevel++; label.tooltip = ""; for (int i = 0; i < bindingCount; i++) { label.text = "Binding " + i; DoBindingGUI(ref area, bindings, i, label); } EditorGUI.indentLevel--; } } /************************************************************************************************************************/ private static void DoBindingGUI(ref Rect area, SerializedProperty bindings, int index, GUIContent label) { var indentLevel = EditorGUI.indentLevel; if (string.IsNullOrEmpty(label.text)) EditorGUI.indentLevel = 0; var binding = bindings.GetArrayElementAtIndex(index); EditorGUI.PropertyField(area, binding, label); NextVerticalArea(ref area); EditorGUI.indentLevel = indentLevel; } /************************************************************************************************************************/ private void GetFields( SerializedProperty root, out SerializedProperty mode, out SerializedProperty bindings) { mode = root.FindPropertyRelative(ControllerState.SerializableParameterBindings.ModeFieldName); bindings = root.FindPropertyRelative(ControllerState.SerializableParameterBindings.BindingsFieldName); } /************************************************************************************************************************/ private string GetContextParameterList(SerializedProperty property) { var path = property.propertyPath; var lastDot = path.LastIndexOf('.'); if (lastDot < 0) return null; path = path[..(lastDot + 1)] + ControllerTransition.ControllerFieldName; property = property.serializedObject.FindProperty(path); if (property == null || property.objectReferenceValue is not AnimatorController animatorController) return null; return GetParameterList(animatorController); } private readonly Dictionary ControllerToParameterList = new(); private string GetParameterList(AnimatorController animatorController) { if (animatorController == null) return null; if (ControllerToParameterList.TryGetValue(animatorController, out var parameterList)) return parameterList; var text = StringBuilderPool.Instance.Acquire(); var parameters = animatorController.parameters; if (parameters.Length > 0) { text.Append("\n\nParameters in ") .Append(animatorController.name) .Append(':'); for (int i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; text.Append("\n� ") .Append(parameter.type) .Append(' ') .Append(parameter.name); } } parameterList = text.ReleaseToString(); ControllerToParameterList.Add(animatorController, parameterList); return parameterList; } /************************************************************************************************************************/ } } #endif