Files
test/Assets/Plugins/Animancer/Internal/Editor/Animancer Tools/AnimancerToolsWindow.Panel.cs
2025-09-16 18:07:13 +07:00

231 lines
8.9 KiB
C#

// Animancer // https://kybernetik.com.au/animancer // Copyright 2021 Kybernetik //
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Animancer.Editor
{
partial class AnimancerToolsWindow
{
/// <summary>[Editor-Only] [Pro-Only] Base class for panels in the <see cref="AnimancerToolsWindow"/>.</summary>
/// <remarks>
/// Documentation: <see href="https://kybernetik.com.au/animancer/docs/manual/tools">Animancer Tools</see>
/// </remarks>
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/Panel
///
public abstract class Panel
{
/************************************************************************************************************************/
private readonly AnimBool FullAnimator = new AnimBool();
private readonly AnimBool BodyAnimator = new AnimBool();
private int _Index;
/************************************************************************************************************************/
/// <summary>Is this panel currently visible?</summary>
public bool IsVisible => Instance._CurrentPanel == _Index || Instance._CurrentPanel < 0;
/************************************************************************************************************************/
/// <summary>Is the body of this panel currently visible?</summary>
public bool IsExpanded
{
get { return Instance._CurrentPanel == _Index; }
set
{
if (value)
Instance._CurrentPanel = _Index;
else if (IsExpanded)
Instance._CurrentPanel = -1;
}
}
/************************************************************************************************************************/
/// <summary>The display name of this panel.</summary>
public abstract string Name { get; }
/// <summary>The usage instructions to display at the top of this panel.</summary>
public abstract string Instructions { get; }
/// <summary>The URL for the help button in the header to open.</summary>
public virtual string HelpURL => Strings.DocsURLs.AnimancerTools;
/// <summary>Called whenever the <see cref="Selection"/> changes.</summary>
public virtual void OnSelectionChanged() { }
/************************************************************************************************************************/
/// <summary>Called by <see cref="AnimancerToolsWindow.OnEnable"/>.</summary>
public virtual void OnEnable(int index)
{
_Index = index;
FullAnimator.value = FullAnimator.target = IsVisible;
BodyAnimator.value = BodyAnimator.target = IsExpanded;
}
/// <summary>Called by <see cref="AnimancerToolsWindow.OnDisable"/>.</summary>
public virtual void OnDisable() { }
/************************************************************************************************************************/
/// <summary>Draws the GUI for this panel.</summary>
public virtual void DoGUI()
{
var enabled = GUI.enabled;
FullAnimator.target = IsVisible;
if (EditorGUILayout.BeginFadeGroup(FullAnimator.faded))
{
GUILayout.BeginVertical(EditorStyles.helpBox);
DoHeaderGUI();
BodyAnimator.target = IsExpanded;
if (EditorGUILayout.BeginFadeGroup(BodyAnimator.faded))
{
var instructions = Instructions;
if (!string.IsNullOrEmpty(instructions))
EditorGUILayout.HelpBox(instructions, MessageType.Info);
DoBodyGUI();
}
EditorGUILayout.EndFadeGroup();
GUILayout.EndVertical();
}
EditorGUILayout.EndFadeGroup();
if (FullAnimator.isAnimating || BodyAnimator.isAnimating)
Repaint();
GUI.enabled = enabled;
}
/************************************************************************************************************************/
/// <summary>
/// Draws the Header GUI for this panel which is displayed regardless of whether it is expanded or not.
/// </summary>
public virtual void DoHeaderGUI()
{
var area = AnimancerGUI.LayoutSingleLineRect(AnimancerGUI.SpacingMode.BeforeAndAfter);
var click = GUI.Button(area, Name, EditorStyles.boldLabel);
area.xMin = area.xMax - area.height;
GUI.DrawTexture(area, HelpIcon);
if (click)
{
if (area.Contains(Event.current.mousePosition))
{
Application.OpenURL(HelpURL);
return;
}
else
{
IsExpanded = !IsExpanded;
}
}
}
/************************************************************************************************************************/
/// <summary>Draws the Body GUI for this panel which is only displayed while it is expanded.</summary>
public abstract void DoBodyGUI();
/************************************************************************************************************************/
/// <summary>Asks the user where they want to save a modified asset, calls `modify` on it, and saves it.</summary>
public static bool SaveModifiedAsset<T>(string saveTitle, string saveMessage,
T obj, Action<T> modify) where T : Object
{
var originalPath = AssetDatabase.GetAssetPath(obj);
var extension = Path.GetExtension(originalPath);
if (extension[0] == '.')
extension = extension.Substring(1, extension.Length - 1);
var directory = Path.GetDirectoryName(originalPath);
var newName = Path.GetFileNameWithoutExtension(AssetDatabase.GenerateUniqueAssetPath(originalPath));
var savePath = EditorUtility.SaveFilePanelInProject(saveTitle, newName, extension, saveMessage, directory);
if (string.IsNullOrEmpty(savePath))
return false;
if (originalPath != savePath)
{
obj = Instantiate(obj);
AssetDatabase.CreateAsset(obj, savePath);
}
modify(obj);
AssetDatabase.SaveAssets();
return true;
}
/************************************************************************************************************************/
private static Texture _HelpIcon;
/// <summary>The help icon image used in the panel header.</summary>
public static Texture HelpIcon
{
get
{
if (_HelpIcon == null)
_HelpIcon = AnimancerGUI.LoadIcon("_Help");
return _HelpIcon;
}
}
/************************************************************************************************************************/
private static int _DropIndex;
/// <summary>Adds any objects dropped in the `area` to the `list`.</summary>
protected void HandleDragAndDropIntoList<T>(Rect area, IList<T> list, bool overwrite,
Func<T, bool> validate = null) where T : Object
{
if (overwrite)
{
_DropIndex = 0;
AnimancerGUI.HandleDragAndDrop(area, validate, (drop) =>
{
if (_DropIndex < list.Count)
{
RecordUndo();
list[_DropIndex++] = drop;
}
});
}
else
{
AnimancerGUI.HandleDragAndDrop(area, validate, (drop) =>
{
list.Add(drop);
});
}
}
/************************************************************************************************************************/
}
}
}
#endif