275 lines
10 KiB
C#
275 lines
10 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 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
|
|
|