// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
#if UNITY_EDITOR && UNITY_IMGUI
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Animancer.Editor
{
/// [Editor-Only] Draws the Inspector GUI for an .
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/ParametizedAnimancerStateDrawer_1
[CustomGUI(typeof(ManualMixerState))]
public class ParametizedAnimancerStateDrawer : AnimancerStateDrawer
where T : AnimancerState, IParametizedState
{
/************************************************************************************************************************/
///
protected override void DoDetailsGUI()
{
base.DoDetailsGUI();
if (!IsExpanded)
return;
EditorGUI.indentLevel++;
var parameters = ListPool.Acquire();
Value.GetParameters(parameters);
DoParametersGUI(parameters);
ListPool.Release(parameters);
EditorGUI.indentLevel--;
}
/************************************************************************************************************************/
/// Draws fields for all `parameters`.
private void DoParametersGUI(List parameters)
{
if (parameters.Count == 0)
return;
var labelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth -= AnimancerGUI.IndentSize;
EditorGUI.BeginChangeCheck();
for (int i = 0; i < parameters.Count; i++)
parameters[i] = DoParameterGUI(i, parameters[i]);
EditorGUIUtility.labelWidth = labelWidth;
if (EditorGUI.EndChangeCheck())
Value.SetParameters(parameters);
}
/************************************************************************************************************************/
/// Draws fields for the `parameter`.
private StateParameterDetails DoParameterGUI(int index, StateParameterDetails parameter)
{
var area = AnimancerGUI.LayoutSingleLineRect(AnimancerGUI.SpacingMode.Before);
var indentLevel = EditorGUI.indentLevel;
var labelWidth = EditorGUIUtility.labelWidth;
var label = parameter.label;
if (parameter.SupportsBinding && Value.Graph.HasParameters)
{
area = EditorGUI.IndentedRect(area);
EditorGUI.indentLevel = 0;
parameter = DoBindingGUI(ref area, index, parameter, ref label);
}
else
{
EditorGUIUtility.labelWidth += AnimancerGUI.IndentSize;
}
switch (parameter.type)
{
case AnimatorControllerParameterType.Float:
parameter.value = EditorGUI.FloatField(area, label, (float)parameter.value);
break;
case AnimatorControllerParameterType.Int:
parameter.value = EditorGUI.IntField(area, label, (int)parameter.value);
break;
case AnimatorControllerParameterType.Bool:
parameter.value = EditorGUI.Toggle(area, label, (bool)parameter.value);
break;
case AnimatorControllerParameterType.Trigger:
parameter.value = EditorGUI.Toggle(area, label, (bool)parameter.value, EditorStyles.radioButton);
break;
default:
EditorGUI.LabelField(area, label, "Unsupported Type: " + parameter.type);
break;
}
EditorGUI.indentLevel = indentLevel;
EditorGUIUtility.labelWidth = labelWidth;
return parameter;
}
/************************************************************************************************************************/
/// Draws a dropdown for the `parameter`'s name binding.
private StateParameterDetails DoBindingGUI(
ref Rect area,
int index,
StateParameterDetails parameter,
ref string fieldLabel)
{
if (!parameter.SupportsBinding)
return parameter;
var spacing = AnimancerGUI.StandardSpacing;
float width;
if (string.IsNullOrEmpty(parameter.name))
{
width = area.height + spacing;
EditorGUIUtility.labelWidth -= width + AnimancerGUI.IndentSize + spacing;
}
else
{
width = EditorGUIUtility.labelWidth - AnimancerGUI.IndentSize;
fieldLabel = "";
}
var labelArea = AnimancerGUI.StealFromLeft(
ref area,
width,
spacing);
using (var label = PooledGUIContent.Acquire(parameter.name))
{
if (EditorGUI.DropdownButton(labelArea, label, FocusType.Passive))
ShowBindingSelectionMenu(labelArea, index, parameter.name);
}
return parameter;
}
/************************************************************************************************************************/
/// Shows a context menu for selecting the parameter binding.
private void ShowBindingSelectionMenu(Rect area, int index, string currentName)
{
var menu = new GenericMenu();
menu.AddItem(
new("None"),
string.IsNullOrEmpty(currentName),
() => SetParameterName(index, null));
menu.AddSeparator("");
foreach (var parameter in Value.Graph.Parameters)
{
if (parameter.ValueType != typeof(float))
continue;
var name = parameter.Key;
menu.AddItem(
new(name),
name == currentName,
() => SetParameterName(index, name));
}
menu.DropDown(area);
}
/************************************************************************************************************************/
/// Sets the name binding of the specified parameter.
private void SetParameterName(int index, string name)
{
var parameters = ListPool.Acquire();
Value.GetParameters(parameters);
var modify = parameters[index];
modify.name = name;
parameters[index] = modify;
Value.SetParameters(parameters);
ListPool.Release(parameters);
}
/************************************************************************************************************************/
}
}
#endif