// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
using UnityEditor;
using UnityEngine;
namespace Animancer.Editor.TransitionLibraries
{
/// [Editor-Only]
/// A dummy object for tracking the selection within the
/// and showing its details in the Inspector.
///
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibrarySelection
[AnimancerHelpUrl(typeof(TransitionLibrarySelection))]
public class TransitionLibrarySelection : ScriptableObject
{
/************************************************************************************************************************/
/// [Editor-Only] Types of objects can be selected.
public enum SelectionType
{
/// Nothing selected.
None,
/// The main library.
Library,
/// A from-transition.
FromTransition,
/// A to-transition.
ToTransition,
/// A fade duration modifier.
Modifier,
}
/************************************************************************************************************************/
[SerializeField] private TransitionLibraryWindow _Window;
[SerializeField] private SelectionType _Type;
[SerializeField] private int _FromIndex = -1;
[SerializeField] private int _ToIndex = -1;
[SerializeField] private int _Version;
/// The window this selection is associated with.
public TransitionLibraryWindow Window
=> _Window;
/// The type of selected object.
public SelectionType Type
=> _Type;
/// The index of the .
public int FromIndex
=> _FromIndex;
/// The index of the .
public int ToIndex
=> _ToIndex;
/// The number of times this selection has been changed.
public int Version
=> _Version;
/************************************************************************************************************************/
/// The transition the current selection is coming from.
public TransitionAssetBase FromTransition { get; private set; }
/// The transition the current selection is going to.
public TransitionAssetBase ToTransition { get; private set; }
/// The of the current selection.
public float FadeDuration { get; private set; }
/// Does the current selection have a modified ?
public bool HasModifier { get; private set; }
/************************************************************************************************************************/
[NonSerialized] private object _Selected;
/// The currently selected object.
public object Selected
{
get
{
Validate();
return _Selected;
}
}
/************************************************************************************************************************/
/// Deselects the current object if it isn't valid.
public bool Validate()
{
if (IsValid())
return true;
Deselect();
return false;
}
/// Is the current selection valid?
public bool IsValid()
{
if (this == null ||
_Window == null ||
Selection.activeObject != this)
return false;
var library = _Window.SourceObject;
if (library == null)
return false;
FromTransition = null;
ToTransition = null;
FadeDuration = float.NaN;
HasModifier = false;
switch (_Type)
{
case SelectionType.Library:
name = "Transition Library";
_Selected = library;
return library != null;
case SelectionType.FromTransition:
name = "From Transition";
if (!_Window.Data.Transitions.TryGet(_FromIndex, out var transition))
return false;
FromTransition = transition;
FadeDuration = transition.TryGetFadeDuration();
_Selected = transition;
return true;
case SelectionType.ToTransition:
name = "To Transition";
if (!_Window.Data.Transitions.TryGet(_ToIndex, out transition))
return false;
ToTransition = transition;
FadeDuration = transition.TryGetFadeDuration();
_Selected = transition;
return true;
case SelectionType.Modifier:
name = "Transition Modifier";
var hasTransitions = _Window.Data.TryGetTransition(_FromIndex, out transition);
FromTransition = transition;
hasTransitions |= _Window.Data.TryGetTransition(_ToIndex, out transition);
ToTransition = transition;
if (_Window.Data.TryGetModifier(_FromIndex, _ToIndex, out var modifier))
{
HasModifier = true;
}
else if (hasTransitions)
{
modifier = modifier.WithFadeDuration(transition.TryGetFadeDuration());
}
else
{
return false;
}
FadeDuration = modifier.FadeDuration;
_Selected = modifier;
return true;
default:
return false;
};
}
/************************************************************************************************************************/
/// Sets the object.
///
/// We can't simply set the
/// because it might not be a
/// and if it is then we don't want the Project window to move to it.
///
/// So instead, we select this dummy object and
/// draws a custom Inspector for the target object.
///
public void Select(
TransitionLibraryWindow window,
object select,
int index,
SelectionType type)
{
switch (type)
{
case SelectionType.Library:
_FromIndex = -1;
_ToIndex = -1;
break;
case SelectionType.FromTransition:
_FromIndex = index;
_ToIndex = -1;
break;
case SelectionType.ToTransition:
_FromIndex = -1;
_ToIndex = index;
break;
case SelectionType.Modifier:
if (select is TransitionModifierDefinition modifier)
{
_FromIndex = modifier.FromIndex;
_ToIndex = modifier.ToIndex;
break;
}
else
{
Deselect();
return;
}
default:
Deselect();
throw new ArgumentException($"Unhandled {nameof(SelectionType)}", nameof(type));
}
_Window = window;
_Type = type;
_Selected = select;
_Version++;
Selection.activeObject = this;
Validate();
}
/************************************************************************************************************************/
/// Clears the object.
public void Deselect()
{
_Window = null;
_Type = default;
_FromIndex = -1;
_ToIndex = -1;
_Selected = null;
_Version++;
if (Selection.activeObject == this)
Selection.activeObject = null;
}
/************************************************************************************************************************/
/// Handles selection changes.
public void OnSelectionChange()
{
if (Selection.activeObject == this)
return;
Deselect();
if (_Window != null)
_Window.Repaint();
}
/************************************************************************************************************************/
/// Selects this object if it contains a valid selection.
protected virtual void OnEnable()
{
if (Selected != null)
Selection.activeObject = this;
}
/************************************************************************************************************************/
}
}
#endif