chore: initial commit
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2026 Kybernetik //
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static Animancer.Editor.AnimancerGUI;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Animancer.Editor
|
||||
{
|
||||
/// <summary>[Editor-Only] A custom Inspector for <see cref="StringAsset"/> fields.</summary>
|
||||
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/StringAssetDrawer
|
||||
[CustomPropertyDrawer(typeof(StringAsset), true)]
|
||||
public class StringAssetDrawer : PropertyDrawer
|
||||
{
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
=> LineHeight;
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnGUI(Rect area, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
label = EditorGUI.BeginProperty(area, label, property);
|
||||
|
||||
property.objectReferenceValue = DrawGUI(
|
||||
area,
|
||||
label,
|
||||
property,
|
||||
out var exitGUI);
|
||||
|
||||
if (exitGUI)
|
||||
{
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
private static readonly Func<Object[]> GetCurrentPropertyValues =
|
||||
() => _CurrentProperty != null ? Serialization.GetValues<Object>(_CurrentProperty) : null;
|
||||
|
||||
private static SerializedProperty _CurrentProperty;
|
||||
|
||||
/// <summary>Draws the GUI for a <see cref="StringAsset"/>.</summary>
|
||||
public static Object DrawGUI(
|
||||
Rect area,
|
||||
GUIContent label,
|
||||
SerializedProperty property,
|
||||
out bool exitGUI)
|
||||
{
|
||||
var showMixedValue = EditorGUI.showMixedValue;
|
||||
if (property != null && property.hasMultipleDifferentValues)
|
||||
EditorGUI.showMixedValue = true;
|
||||
|
||||
_CurrentProperty = property;
|
||||
var value = DrawGUI(
|
||||
area,
|
||||
label,
|
||||
property?.objectReferenceValue,
|
||||
property?.serializedObject?.targetObject,
|
||||
out exitGUI,
|
||||
GetCurrentPropertyValues);
|
||||
_CurrentProperty = null;
|
||||
|
||||
EditorGUI.showMixedValue = showMixedValue;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
private static readonly int ButtonHash = "Button".GetHashCode();
|
||||
private static readonly int ObjectFieldHash = "s_ObjectFieldHash".GetHashCode();
|
||||
|
||||
/// <summary>Draws the GUI for a <see cref="StringAsset"/>.</summary>
|
||||
public static Object DrawGUI(
|
||||
Rect area,
|
||||
GUIContent label,
|
||||
Object value,
|
||||
Object context,
|
||||
out bool exitGUI,
|
||||
Func<Object[]> getAllValues = null)
|
||||
{
|
||||
var currentEvent = Event.current;
|
||||
if (currentEvent.type == EventType.Repaint &&
|
||||
!area.Contains(currentEvent.mousePosition) &&
|
||||
!IsDraggingStringAsset())
|
||||
{
|
||||
GUIUtility.GetControlID(ButtonHash, FocusType.Passive);// Button.
|
||||
GUIUtility.GetControlID(ButtonHash, FocusType.Passive);// Button.
|
||||
GUIUtility.GetControlID(DragHint, FocusType.Passive, area);// DragAndDrop.
|
||||
|
||||
var iconSize = EditorGUIUtility.GetIconSize();
|
||||
var newIconSize = LineHeight * 2 / 3;
|
||||
EditorGUIUtility.SetIconSize(new(newIconSize, newIconSize));
|
||||
|
||||
var controlID = GUIUtility.GetControlID(ObjectFieldHash, FocusType.Keyboard, area);// Object.
|
||||
|
||||
var valueArea = EditorGUI.PrefixLabel(area, controlID, label);
|
||||
|
||||
using (var content = PooledGUIContent.Acquire())
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
content.text = value.name;
|
||||
content.image = AnimancerIcons.ScriptableObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
content.text = "";
|
||||
content.image = AssetPreview.GetMiniTypeThumbnail(typeof(StringAsset));
|
||||
}
|
||||
|
||||
EditorStyles.objectField.Draw(valueArea, content, false, false, false, false);
|
||||
}
|
||||
|
||||
EditorGUIUtility.SetIconSize(iconSize);
|
||||
|
||||
exitGUI = false;
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
var buttonArea = StealFromRight(ref area, area.height, StandardSpacing);
|
||||
|
||||
var content = AnimancerIcons.AddIcon("Create and save a new String Asset");
|
||||
if (GUI.Button(buttonArea, content, NoPaddingButtonStyle))
|
||||
{
|
||||
exitGUI = true;
|
||||
return CreateNewInstance(label.text, context);
|
||||
}
|
||||
|
||||
GUIUtility.GetControlID(ButtonHash, FocusType.Passive);
|
||||
}
|
||||
else
|
||||
{
|
||||
var clearArea = StealFromRight(ref area, area.height, StandardSpacing);
|
||||
var copyArea = StealFromRight(ref area, area.height, StandardSpacing);
|
||||
|
||||
var content = AnimancerIcons.CopyIcon("Copy string to clipboard");
|
||||
if (GUI.Button(copyArea, content, NoPaddingButtonStyle))
|
||||
GUIUtility.systemCopyBuffer = value.name;
|
||||
|
||||
content = AnimancerIcons.ClearIcon("Clear reference");
|
||||
if (GUI.Button(clearArea, content, NoPaddingButtonStyle))
|
||||
value = null;
|
||||
}
|
||||
|
||||
HandleDragAndDrop(area, currentEvent, value, getAllValues);
|
||||
|
||||
exitGUI = false;
|
||||
return EditorGUI.ObjectField(area, label, value, typeof(StringAsset), false);
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
private static readonly int DragHint = "Drag".GetHashCode();
|
||||
|
||||
private static void HandleDragAndDrop(
|
||||
Rect area,
|
||||
Event currentEvent,
|
||||
Object value,
|
||||
Func<Object[]> getAllValues)
|
||||
{
|
||||
var id = GUIUtility.GetControlID(DragHint, FocusType.Passive, area);
|
||||
|
||||
switch (currentEvent.type)
|
||||
{
|
||||
// Drag out of object field.
|
||||
case EventType.MouseDrag:
|
||||
if (GUIUtility.keyboardControl == id + 1 &&
|
||||
currentEvent.button == 0 &&
|
||||
area.Contains(currentEvent.mousePosition) &&
|
||||
value != null)
|
||||
{
|
||||
var values = getAllValues?.Invoke() ?? new Object[] { value };
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.objectReferences = values;
|
||||
DragAndDrop.StartDrag("Objects");
|
||||
currentEvent.Use();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Is a <see cref="StringAsset"/> currently being dragged?</summary>
|
||||
private static bool IsDraggingStringAsset()
|
||||
{
|
||||
var dragging = DragAndDrop.objectReferences;
|
||||
if (dragging.IsNullOrEmpty())
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < dragging.Length; i++)
|
||||
if (dragging[i] is not StringAsset)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
private const string FolderPathKey = nameof(StringAsset) + ".FolderPath";
|
||||
|
||||
/// <summary>Asks where to save a new <see cref="StringAsset"/>.</summary>
|
||||
private static Object CreateNewInstance(string name, Object targetObject)
|
||||
{
|
||||
var folderPath = GetSaveFolder(targetObject);
|
||||
|
||||
var path = EditorUtility.SaveFilePanelInProject(
|
||||
"Create String Asset",
|
||||
name,
|
||||
"asset",
|
||||
"Where yould you like to save the new String Asset?",
|
||||
folderPath);
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return null;
|
||||
|
||||
EditorPrefs.SetString(FolderPathKey, Path.GetDirectoryName(path));
|
||||
|
||||
var instance = ScriptableObject.CreateInstance<StringAsset>();
|
||||
|
||||
AssetDatabase.CreateAsset(instance, path);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static string GetSaveFolder(Object targetObject)
|
||||
{
|
||||
var getActiveFolderPath = typeof(ProjectWindowUtil).GetMethod(
|
||||
"GetActiveFolderPath",
|
||||
AnimancerReflection.StaticBindings,
|
||||
null,
|
||||
Type.EmptyTypes,
|
||||
null);
|
||||
if (getActiveFolderPath != null &&
|
||||
getActiveFolderPath.ReturnType == typeof(string))
|
||||
{
|
||||
var activeFolderPath = getActiveFolderPath.Invoke(null, Array.Empty<object>())?.ToString();
|
||||
if (!string.IsNullOrEmpty(activeFolderPath))
|
||||
return activeFolderPath;
|
||||
}
|
||||
|
||||
var folderPath = AssetDatabase.GetAssetPath(targetObject);
|
||||
if (!string.IsNullOrEmpty(folderPath))
|
||||
folderPath = Path.GetDirectoryName(folderPath);
|
||||
|
||||
if (string.IsNullOrEmpty(folderPath))
|
||||
{
|
||||
folderPath = EditorPrefs.GetString(FolderPathKey);
|
||||
if (folderPath == null || !folderPath.StartsWith("Assets/"))
|
||||
folderPath = "Assets/";
|
||||
}
|
||||
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user