123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 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.Tools
- {
- partial class AnimancerToolsWindow
- {
- /// <summary>[Editor-Only] [Pro-Only] Base class for tools in the <see cref="AnimancerToolsWindow"/>.</summary>
- /// <remarks>
- /// <strong>Documentation:</strong>
- /// <see href="https://kybernetik.com.au/animancer/docs/manual/tools">
- /// Animancer Tools</see>
- /// </remarks>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor.Tools/Tool
- ///
- [Serializable]
- public abstract class Tool : IComparable<Tool>
- {
- /************************************************************************************************************************/
- private AnimBool _FullAnimator;
- private AnimBool _BodyAnimator;
- private int _Index;
- /************************************************************************************************************************/
- /// <summary>Is this tool currently visible?</summary>
- public bool IsVisible => Instance._CurrentTool == _Index || Instance._CurrentTool < 0;
- /************************************************************************************************************************/
- /// <summary>Is the body of this tool currently visible?</summary>
- public bool IsExpanded
- {
- get { return Instance._CurrentTool == _Index; }
- set
- {
- if (value)
- Instance._CurrentTool = _Index;
- else if (IsExpanded)
- Instance._CurrentTool = -1;
- }
- }
- /************************************************************************************************************************/
- /// <summary>Lower numbers display first.</summary>
- public abstract int DisplayOrder { get; }
- /// <summary>Compares the <see cref="DisplayOrder"/> to put lower numbers first.</summary>
- public int CompareTo(Tool other)
- => DisplayOrder.CompareTo(other.DisplayOrder);
- /************************************************************************************************************************/
- /// <summary>The display name of this tool.</summary>
- public abstract string Name { get; }
- /// <summary>The usage instructions to display at the top of this tool.</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 = new(IsVisible);
- _BodyAnimator = new(IsExpanded);
- }
- /// <summary>Called by <see cref="AnimancerToolsWindow.OnDisable"/>.</summary>
- public virtual void OnDisable() { }
- /************************************************************************************************************************/
- /// <summary>Draws the GUI for this tool.</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 tool 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 tool 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[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 tool header.</summary>
- public static Texture HelpIcon
- {
- get
- {
- if (_HelpIcon == null)
- _HelpIcon = AnimancerIcons.Load("_Help");
- return _HelpIcon;
- }
- }
- /************************************************************************************************************************/
- /// <summary>Adds any objects dropped in the `area` to the `list`.</summary>
- protected void HandleDragAndDropIntoList<T>(
- Rect area,
- IList<T> list,
- bool overwrite)
- where T : Object
- {
- var dropIndex = 0;
- // No easy way to avoid this closure.
- AnimancerGUI.Handle<T>((obj, isDrop) =>
- {
- if (!isDrop)
- return true;
- if (overwrite)
- {
- RecordUndo();
- if (dropIndex < list.Count)
- {
- list[dropIndex++] = obj;
- }
- else
- {
- list.Add(obj);
- }
- }
- else
- {
- list.Add(obj);
- }
- return true;
- }, area);
- }
- /************************************************************************************************************************/
- }
- }
- }
- #endif
|