// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using static Animancer.Editor.AnimancerGUI;
using static Animancer.Editor.TransitionLibraries.TransitionLibrarySelection;
namespace Animancer.Editor.TransitionLibraries
{
/// [Editor-Only]
/// A for editing transition aliases.
///
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryAliasesPage
[Serializable]
public class TransitionLibraryAliasesPage : TransitionLibraryWindowPage
{
/************************************************************************************************************************/
[SerializeField]
private Vector2 _ScrollPosition;
[NonSerialized]
private bool _HasSorted;
/************************************************************************************************************************/
///
public override string DisplayName
=> "Transition Aliases";
///
public override string HelpTooltip
=> "Aliases are custom names which can be used to refer to transitions instead of direct references.";
///
public override int Index
=> 2;
/************************************************************************************************************************/
private static readonly List
TransitionAreas = new();
private static float ButtonWidth
=> LineHeight * 4;
/************************************************************************************************************************/
///
public override void OnGUI(Rect area)
{
var definition = Window.Data;
if (!_HasSorted)
{
_HasSorted = true;
definition.SortAliases();
}
var currentEvent = Event.current;
var isRepaint = currentEvent.type == EventType.Repaint;
if (isRepaint)
TransitionAreas.Clear();
area.yMin += StandardSpacing;
area.xMin += StandardSpacing;
area.xMax -= StandardSpacing;
var items = Window.Items;
var aliases = definition.Aliases;
var viewArea = new Rect(
0,
0,
area.width,
CalculateHeight(1 + items.Count + aliases.Length) + StandardSpacing);
if (viewArea.height > area.height)
viewArea.width -= GUI.skin.verticalScrollbar.fixedWidth;
_ScrollPosition = GUI.BeginScrollView(area, _ScrollPosition, viewArea);
viewArea.height = LineHeight;
DoAliasAllGUI(viewArea);
NextVerticalArea(ref viewArea);
for (int i = 0; i < items.Count; i++)
{
if (isRepaint)
TransitionAreas.Add(viewArea);
DoItemGUI(ref viewArea, i, currentEvent);
}
GUI.EndScrollView();
}
/************************************************************************************************************************/
private void DoItemGUI(
ref Rect area,
int itemIndex,
Event currentEvent)
{
var totalTransitionArea = area;
var items = Window.Items;
var item = items.GetItem(itemIndex);
if (item is TransitionAssetBase transition)
{
var hasGroup = items.GetGroup(itemIndex) != null;
if (hasGroup)
area.xMin += IndentSize;
var transitions = Window.Data.Transitions;
var transitionIndex = Array.IndexOf(transitions, transition);
DoTransitionGUI(area, transition, transitionIndex);
NextVerticalArea(ref area);
DoAliasGUI(ref area, transitionIndex);
if (hasGroup)
area.xMin -= IndentSize;
}
else if (item is TransitionGroup group)
{
var groupArea = area;
NextVerticalArea(ref area);
var foldoutArea = StealFromLeft(ref groupArea, LineHeight, StandardSpacing);
TransitionModifierTableGUI.HandleTransitionLabelInput(
ref groupArea,
Window,
group,
SelectionType.Group,
CalculateTarget);
GUI.Label(groupArea, group.Name);
EditorGUI.BeginChangeCheck();
group.IsExpanded = EditorGUI.Foldout(foldoutArea, group.IsExpanded, GUIContent.none);
if (EditorGUI.EndChangeCheck())
Window.Selection.Select(Window, group, group.Index, SelectionType.Group);
}
// Highlights.
totalTransitionArea.yMax = area.yMin - StandardSpacing;
var selected = Window.Selection.Selected == item;
var hover = totalTransitionArea.Contains(currentEvent.mousePosition);
Window.Highlighter.DrawHighlightGUI(totalTransitionArea, selected, hover);
}
/************************************************************************************************************************/
/// Draws .
private void DoAliasAllGUI(Rect area)
{
var definition = Window.Data;
using (var label = PooledGUIContent.Acquire(
"Alias All Transitions",
TransitionLibraryDefinition.AliasAllTransitionsTooltip))
definition.AliasAllTransitions = EditorGUI.Toggle(area, label, definition.AliasAllTransitions);
if (TryUseClickEvent(area, 0))
definition.AliasAllTransitions = !definition.AliasAllTransitions;
}
/************************************************************************************************************************/
/// Draws a `transition`.
private void DoTransitionGUI(Rect area, TransitionAssetBase transition, int index)
{
var addArea = StealFromLeft(ref area, ButtonWidth, StandardSpacing);
TransitionModifierTableGUI.HandleTransitionLabelInput(
ref area,
Window,
transition,
SelectionType.ToTransition,
CalculateTarget);
var typeArea = StealFromRight(ref area, area.width * 0.5f, StandardSpacing);
var label = transition.GetCachedName();
GUI.Label(area, label);
var wrappedTransition = transition.GetTransition();
var type = wrappedTransition != null
? wrappedTransition.GetType().GetNameCS(false)
: "Null";
GUI.Label(typeArea, type);
if (GUI.Button(addArea, "Add"))
{
var alias = new NamedIndex(null, index);
Window.RecordUndo().AddAlias(alias);
}
}
/************************************************************************************************************************/
/// Calculates the target index for a drag and drop operation.
private static ListTargetCalculation CalculateTarget(
Rect area,
int index,
Event currentEvent)
{
var y = currentEvent.mousePosition.y;
for (int i = 0; i < TransitionAreas.Count; i++)
{
area = TransitionAreas[i];
var yMax = area.yMax;
if (y > yMax)
continue;
return new(
i,
Mathf.InverseLerp(area.y, yMax, y));
}
return new(TransitionAreas.Count, 1);
}
/************************************************************************************************************************/
/// Draws all aliases for the specified `transitionIndex`.
private void DoAliasGUI(ref Rect area, int transitionIndex)
{
var aliases = Window.Data.Aliases;
for (int i = 0; i < aliases.Length; i++)
{
var alias = aliases[i];
if (alias.Index != transitionIndex)
continue;
DoAliasGUI(area, alias, i);
NextVerticalArea(ref area);
}
}
/// Draws an `alias`.
private void DoAliasGUI(Rect area, NamedIndex alias, int aliasIndex)
{
var removeArea = StealFromLeft(ref area, ButtonWidth, StandardSpacing);
EditorGUI.BeginChangeCheck();
var name = StringAssetDrawer.DrawGUI(area, GUIContent.none, alias.Name, Window.SourceObject, out _);
if (EditorGUI.EndChangeCheck())
{
Window.RecordUndo().Aliases[aliasIndex] = alias.With(name as StringAsset);
}
if (GUI.Button(removeArea, "Remove"))
{
Window.RecordUndo().RemoveAlias(aliasIndex);
}
}
/************************************************************************************************************************/
}
}
#endif