namespace Zinnia.Data.Type
{
#if ZINNIA_IGNORE_CUSTOM_COLLAPSIBLE_DRAWER
#else
using System.Collections;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
///
/// Displays a custom inspector collection in a collapsible drawer.
///
[CustomPropertyDrawer(typeof(UnityEventBase), true)]
[CustomPropertyDrawer(typeof(UnityEvent), true)]
[CustomPropertyDrawer(typeof(UnityEvent<>), true)]
[CustomPropertyDrawer(typeof(UnityEvent), true)]
public class CollapsibleUnityEventDrawer : UnityEventDrawer
{
///
/// The height of the header.
///
protected const float headerHeight = 20f;
///
/// The padding for the drawer.
///
protected const float padding = 6f;
///
/// The offset of the drawer height.
///
protected const float heightOffset = 2f;
///
/// The header background style.
///
protected readonly GUIStyle headerBackground = new GUIStyle("RL Header");
///
/// Whether the `base.OnGUI` was called.
///
protected bool wasBaseOnGuiCalled = false;
///
/// Replaces the default inspector drawer with this custom drawer.
///
[InitializeOnLoadMethod]
public static void ReplaceDefaultDrawer()
{
System.Type utilityType = System.Type.GetType("UnityEditor.ScriptAttributeUtility, UnityEditor");
if (utilityType == null)
{
return;
}
MethodInfo buildMethod = utilityType.GetMethod("BuildDrawerTypeForTypeDictionary", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, System.Type.EmptyTypes, null);
FieldInfo dictionaryField = utilityType.GetField("s_DrawerTypeForType", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
System.Type drawerKeySet = utilityType.GetNestedType("DrawerKeySet", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (drawerKeySet == null)
{
return;
}
FieldInfo drawerField = drawerKeySet.GetField("drawer", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
// Ensure the key set is populated.
buildMethod.Invoke(null, null);
IDictionary dictionary = (IDictionary)dictionaryField.GetValue(null);
System.Type[] types = dictionary.Keys.OfType()
.Where(
type => typeof(UnityEventBase).IsAssignableFrom(type)
&& typeof(UnityEventDrawer) == (System.Type)drawerField.GetValue(dictionary[type]))
.ToArray();
foreach (System.Type type in types)
{
object keySet = dictionary[type];
drawerField.SetValue(keySet, typeof(CollapsibleUnityEventDrawer));
// DrawerKeySet is a struct, so set it again after modifying it.
dictionary[type] = keySet;
}
}
///
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!wasBaseOnGuiCalled)
{
base.OnGUI(position, property, label);
wasBaseOnGuiCalled = true;
return;
}
Rect foldoutPosition = new Rect(position.x, position.y + heightOffset, position.width, headerHeight);
property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, GUIContent.none, true);
if (property.isExpanded)
{
base.OnGUI(position, property, label);
}
else
{
DrawHeader(position);
}
}
///
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) =>
property.isExpanded
? base.GetPropertyHeight(property, label)
: EditorGUIUtility.singleLineHeight + heightOffset * 2f;
///
/// Draws the drawer header.
///
/// The position to draw at.
protected virtual void DrawHeader(Rect position)
{
if (Event.current.type == EventType.Repaint)
{
headerBackground.Draw(position, false, false, false, false);
}
Rect headerRect = new Rect(position.x, position.y, position.width, headerHeight);
headerRect.xMin += padding;
headerRect.xMax -= padding;
headerRect.height -= heightOffset;
headerRect.y += heightOffset * 0.5f;
DrawEventHeader(headerRect);
}
}
#endif
}