// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // #if UNITY_EDITOR using System; using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using UnityEngine; using Object = UnityEngine.Object; namespace Animancer.Editor.Tools { /// [Editor-Only] [Pro-Only] /// An with various utilities for managing sprites and generating animations. /// /// /// Documentation: /// /// Animancer Tools /// /// https://kybernetik.com.au/animancer/api/Animancer.Editor.Tools/AnimancerToolsWindow /// public sealed partial class AnimancerToolsWindow : EditorWindow { /************************************************************************************************************************/ /// The display name of this window. public const string Name = "Animancer Tools"; /// The singleton instance of this window. public static AnimancerToolsWindow Instance { get; private set; } [SerializeReference] private List _Tools; [SerializeField] private Vector2 _Scroll; [SerializeField] private int _CurrentTool = -1; /************************************************************************************************************************/ private SerializedObject _SerializedObject; private SerializedObject SerializedObject => _SerializedObject ??= new(this); /// Returns the which represents the specified `tool`. public SerializedProperty FindSerializedPropertyForTool(Tool tool) { var index = _Tools.IndexOf(tool); var property = SerializedObject.FindProperty(nameof(_Tools)); return property.GetArrayElementAtIndex(index); } /************************************************************************************************************************/ private void OnEnable() { titleContent = new(Name); Instance = this; InitializeTools(); Undo.undoRedoPerformed += Repaint; OnSelectionChange(); } /************************************************************************************************************************/ private void InitializeTools() { AnimancerEditorUtilities.InstantiateDerivedTypes(ref _Tools); for (int i = 0; i < _Tools.Count; i++) _Tools[i].OnEnable(i); } /************************************************************************************************************************/ private int IndexOfTool(Type type) { for (int i = 0; i < _Tools.Count; i++) if (_Tools[i].GetType() == type) return i; return -1; } /************************************************************************************************************************/ private void OnDisable() { Undo.undoRedoPerformed -= Repaint; for (int i = 0; i < _Tools.Count; i++) _Tools[i].OnDisable(); if (_SerializedObject != null) { _SerializedObject.Dispose(); _SerializedObject = null; } } /************************************************************************************************************************/ private void OnSelectionChange() { for (int i = 0; i < _Tools.Count; i++) _Tools[i].OnSelectionChanged(); Repaint(); } /************************************************************************************************************************/ private void OnGUI() { EditorGUIUtility.labelWidth = Mathf.Min(EditorGUIUtility.labelWidth, position.width * 0.5f); EditorGUIUtility.wideMode = true; _Scroll = GUILayout.BeginScrollView(_Scroll); GUILayout.BeginVertical(); GUILayout.EndVertical(); for (int i = 0; i < _Tools.Count; i++) _Tools[i].DoGUI(); GUILayout.EndScrollView(); } /************************************************************************************************************************/ /// Causes the to redraw its GUI. public static new void Repaint() { if (Instance != null) ((EditorWindow)Instance).Repaint(); } /// Calls for this window. public static void RecordUndo() => Undo.RecordObject(Instance, Name); /************************************************************************************************************************/ /// Calls . public static void BeginChangeCheck() => EditorGUI.BeginChangeCheck(); /// Calls and if it returned true. public static bool EndChangeCheck() { if (!EditorGUI.EndChangeCheck()) return false; RecordUndo(); return true; } /// Calls and sets the field = value if it returned true. public static bool EndChangeCheck(ref T field, T value) { if (!EndChangeCheck()) return false; field = value; return true; } /************************************************************************************************************************/ /// Creates and initializes a new . public static ReorderableList CreateReorderableList( List list, string name, ReorderableList.ElementCallbackDelegate drawElementCallback, bool showFooter = false) { var reorderableList = new ReorderableList(list, typeof(T)) { drawHeaderCallback = (area) => GUI.Label(area, name), drawElementCallback = drawElementCallback, elementHeight = AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing, }; if (!showFooter) { reorderableList.footerHeight = 0; reorderableList.displayAdd = false; reorderableList.displayRemove = false; } return reorderableList; } /************************************************************************************************************************/ /// Creates and initializes a new for s. public static ReorderableList CreateReorderableObjectList( List objects, string name, bool showFooter = false) where T : Object { var reorderableList = CreateReorderableList(objects, name, (area, index, isActive, isFocused) => { area.y = Mathf.Ceil(area.y + AnimancerGUI.StandardSpacing * 0.5f); area.height = AnimancerGUI.LineHeight; BeginChangeCheck(); var obj = AnimancerGUI.DoObjectFieldGUI(area, "", objects[index], false); if (EndChangeCheck()) { objects[index] = obj; } }, showFooter); if (showFooter) { reorderableList.onAddCallback = (list) => list.list.Add(null); } return reorderableList; } /************************************************************************************************************************/ /// Creates a new for s. public static ReorderableList CreateReorderableStringList( List strings, string name, Func doElementGUI) { return CreateReorderableList(strings, name, (area, index, isActive, isFocused) => { area.y = Mathf.Ceil(area.y + AnimancerGUI.StandardSpacing * 0.5f); area.height = AnimancerGUI.LineHeight; BeginChangeCheck(); var str = doElementGUI(area, index); if (EndChangeCheck()) { strings[index] = str; } }); } /// Creates a new for s. public static ReorderableList CreateReorderableStringList( List strings, string name) { return CreateReorderableStringList(strings, name, (area, index) => { return EditorGUI.TextField(area, strings[index]); }); } /************************************************************************************************************************/ /// Opens the . [MenuItem(Strings.AnimancerToolsMenuPath)] public static void Open() => GetWindow(); /// Opens the showing the specified `tool`. public static void Open(Type toolType) { var window = GetWindow(); window._CurrentTool = AnimancerEditorUtilities.IndexOfType(window._Tools, toolType); } /************************************************************************************************************************/ } } #endif