// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
#if UNITY_EDITOR
using Animancer.TransitionLibraries;
using System;
using UnityEditor;
using UnityEngine;
using static Animancer.Editor.AnimancerGUI;
using static Animancer.Editor.TransitionLibraries.TransitionLibrarySelection;
namespace Animancer.Editor.TransitionLibraries
{
/// [Editor-Only]
/// Operations for modifying a .
///
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.TransitionLibraries/TransitionLibraryOperations
public static class TransitionLibraryOperations
{
/************************************************************************************************************************/
/// Handles input events for the background of the `window`.
public static void HandleBackgroundInput(
Rect area,
TransitionLibraryWindow window)
{
// Click to select the library.
if (TryUseClickEvent(area, 0))
window.Selection.Select(window, window.SourceObject, -1, SelectionType.Library);
var currentEvent = Event.current;
switch (currentEvent.type)
{
// Drag and drop to add transition.
case EventType.DragUpdated:
case EventType.DragPerform:
HandleDragAndDrop(currentEvent, window);
break;
case EventType.ValidateCommand:
case EventType.ExecuteCommand:
switch (currentEvent.commandName)
{
// Delete to remove the selection.
case Commands.Delete:
case Commands.SoftDelete:
HandleDelete(currentEvent, window);
break;
}
break;
}
}
/************************************************************************************************************************/
/// Handles drag and drop events to add transitions to the `window`.
private static void HandleDragAndDrop(
Event currentEvent,
TransitionLibraryWindow window)
{
var dragging = DragAndDrop.objectReferences;
TransitionAssetBase dropped = null;
int index = -1;
for (int i = dragging.Length - 1; i >= 0; i--)
{
var transition = TryCreateTransitionAttribute.TryCreateTransitionAsset(dragging[i]);
if (transition != null &&
Array.IndexOf(window.Data.Transitions, transition) >= 0)
continue;
switch (currentEvent.type)
{
case EventType.DragUpdated:
DragAndDrop.visualMode = DragAndDropVisualMode.Link;
currentEvent.Use();
return;
case EventType.DragPerform:
dropped = transition;
index = window.Data.Transitions.Length;
window.RecordUndo().AddTransition(transition);
break;
}
}
if (dropped != null)
{
window.Selection.Select(
window,
dropped,
index,
SelectionType.ToTransition);
DragAndDrop.AcceptDrag();
currentEvent.Use();
}
}
/************************************************************************************************************************/
/// Creates a new transition as a sub-asset of the `window`'s library.
public static TransitionAssetBase CreateTransition(
TransitionLibraryWindow window)
{
var createInstance = TransitionAssetBase.CreateInstance;
if (createInstance == null)
{
Debug.LogError(
$"{nameof(CreateTransition)} failed because " +
$"{nameof(TransitionAssetBase)}.{nameof(TransitionAssetBase.CreateInstance)}" +
$" hasn't been assigned." +
$" It should be automatically initialized by TransitionAsset.");
return null;
}
var definition = window.RecordUndo();
var transition = createInstance(null);
transition.name = "Transition " + (definition.Transitions.Length + 1);
AnimancerReflection.TryInvoke(transition, "Reset");
definition.AddTransition(transition);
var index = definition.Transitions.Length;
window.Selection.Select(window, transition, index, SelectionType.ToTransition);
return transition;
}
/************************************************************************************************************************/
/// Handles a delete event.
private static void HandleDelete(
Event currentEvent,
TransitionLibraryWindow window)
{
if (!window.Selection.Validate())
return;
switch (window.Selection.Type)
{
case SelectionType.FromTransition:
if (currentEvent.type == EventType.ExecuteCommand &&
window.Selection.Selected is TransitionAssetBase fromTransition)
AskHowToDeleteTransition(
fromTransition,
window.Selection.FromIndex,
window);
break;
case SelectionType.ToTransition:
if (currentEvent.type == EventType.ExecuteCommand &&
window.Selection.Selected is TransitionAssetBase toTransition)
AskHowToDeleteTransition(
toTransition,
window.Selection.ToIndex,
window);
break;
case SelectionType.Modifier:
if (currentEvent.type == EventType.ExecuteCommand &&
window.Selection.Selected is TransitionModifierDefinition modifier)
window.RecordUndo().RemoveModifier(modifier);
break;
default:
return;
}
currentEvent.Use();
}
/************************************************************************************************************************/
/// Asks if the user wants to delete a transition asset or just remove it from the library.
public static void AskHowToDeleteTransition(
TransitionAssetBase transition,
int index,
TransitionLibraryWindow window)
{
var assetPath = AssetDatabase.GetAssetPath(transition);
if (string.IsNullOrEmpty(assetPath))
{
if (transition != null)
Undo.DestroyObjectImmediate(transition);
window.RecordUndo().RemoveTransition(index);
return;
}
var isMainAsset = AssetDatabase.IsMainAsset(transition);
var assetType = isMainAsset ? "Asset" : "Sub-Asset";
var isSubAssetOfLibrary =
!isMainAsset &&
assetPath == AssetDatabase.GetAssetPath(window.SourceObject);
var message = assetPath;
if (!isSubAssetOfLibrary)
message += "\n\nRemove Transition: removes it from this Transition Library.";
message += $"\n\nDelete {assetType}: deletes the Transition {assetType} from your project (cannot be undone).";
int choice;
if (isSubAssetOfLibrary)
{
if (EditorUtility.DisplayDialog(
"Delete transition?",
message,
"Delete " + assetType,
"Cancel"))
choice = 2;
else
return;
}
else
{
choice = EditorUtility.DisplayDialogComplex(
"Remove or Delete transition?",
message,
"Remove Transition",
"Cancel",
"Delete " + assetType);
}
switch (choice)
{
case 0:// Remove.
window.RecordUndo().RemoveTransition(index);
break;
case 2:// Delete.
if (isMainAsset)
{
AssetDatabase.DeleteAsset(assetPath);
}
else
{
AnimancerEditorUtilities.DeleteSubAsset(transition);
}
window.Data.RemoveTransition(index);
Undo.ClearUndo(window);
break;
default:
return;
}
}
/************************************************************************************************************************/
}
}
#endif