157 lines
5.6 KiB
C#
157 lines
5.6 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
using System;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace Animancer.Editor
|
|
{
|
|
/// <summary>[Editor-Only]
|
|
/// A <see cref="PropertyDrawer"/> for <see cref="IPolymorphic"/> and <see cref="PolymorphicAttribute"/>.
|
|
/// </summary>
|
|
/// https://kybernetik.com.au/animancer/api/Animancer.Editor/PolymorphicDrawer
|
|
[CustomPropertyDrawer(typeof(IPolymorphic), true)]
|
|
[CustomPropertyDrawer(typeof(PolymorphicAttribute), true)]
|
|
public sealed class PolymorphicDrawer : PropertyDrawer
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
private bool _DrawerThrewException;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
|
{
|
|
var height = 0f;
|
|
|
|
if (property.propertyType == SerializedPropertyType.ManagedReference)
|
|
{
|
|
GetDetails(property, out var value, out var drawer, out var details);
|
|
|
|
if (value == null)
|
|
return AnimancerGUI.LineHeight;
|
|
|
|
if (drawer != null)
|
|
{
|
|
if (details.SeparateHeader)
|
|
{
|
|
if (!property.isExpanded)
|
|
return AnimancerGUI.LineHeight;
|
|
|
|
height += AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing;
|
|
}
|
|
|
|
try
|
|
{
|
|
height += drawer.GetPropertyHeight(property, label);
|
|
return height;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_DrawerThrewException = true;
|
|
Debug.LogException(exception, property.serializedObject.targetObject);
|
|
// Continue to the regular calculation.
|
|
}
|
|
}
|
|
}
|
|
|
|
height += EditorGUI.GetPropertyHeight(property, label, true);
|
|
|
|
return height;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override void OnGUI(Rect area, SerializedProperty property, GUIContent label)
|
|
{
|
|
if (property.propertyType != SerializedPropertyType.ManagedReference)
|
|
{
|
|
EditorGUI.PropertyField(area, property, label, true);
|
|
return;
|
|
}
|
|
|
|
GetDetails(property, out _, out var drawer, out var details);
|
|
|
|
var drawTypeSelectionButton = drawer == null || drawer is not IPolymorphic;
|
|
|
|
var button = drawTypeSelectionButton
|
|
? new TypeSelectionButton(area, property, true)
|
|
: default;
|
|
|
|
if (drawer != null)
|
|
{
|
|
if (details.SeparateHeader)
|
|
{
|
|
var foldoutArea = area;
|
|
foldoutArea.width = EditorGUIUtility.labelWidth;
|
|
foldoutArea.height = AnimancerGUI.LineHeight;
|
|
|
|
label = EditorGUI.BeginProperty(foldoutArea, label, property);
|
|
|
|
property.isExpanded = EditorGUI.Foldout(foldoutArea, property.isExpanded, label, true);
|
|
|
|
EditorGUI.EndProperty();
|
|
|
|
area.yMin += AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing;
|
|
}
|
|
|
|
// If drawing a separate header, don't draw the body if it's collapsed.
|
|
if (!details.SeparateHeader || property.isExpanded)
|
|
{
|
|
try
|
|
{
|
|
#pragma warning disable UNT0027 // Do not call PropertyDrawer.OnGUI(). Should only apply to calling base.OnGUI.
|
|
drawer.OnGUI(area, property, label);
|
|
#pragma warning restore UNT0027 // Do not call PropertyDrawer.OnGUI().
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_DrawerThrewException = true;
|
|
Debug.LogException(exception, property.serializedObject.targetObject);
|
|
// Continue to PropertyField.
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EditorGUI.PropertyField(area, property, label, true);
|
|
}
|
|
|
|
if (drawTypeSelectionButton)
|
|
button.DoGUI();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private void GetDetails(
|
|
SerializedProperty property,
|
|
out object value,
|
|
out PropertyDrawer drawer,
|
|
out PolymorphicDrawerDetails details)
|
|
{
|
|
value = property.managedReferenceValue;
|
|
|
|
if (_DrawerThrewException || value == null)
|
|
{
|
|
drawer = null;
|
|
details = PolymorphicDrawerDetails.Default;
|
|
return;
|
|
}
|
|
|
|
if (PropertyDrawers.TryGetDrawer(value.GetType(), fieldInfo, attribute, out drawer) &&
|
|
drawer is PolymorphicDrawer)
|
|
drawer = null;
|
|
|
|
details = PolymorphicDrawerDetails.Get(value);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|
|
|
|
#endif
|