DummySerializableCallback.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
  2. #if UNITY_EDITOR
  3. #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
  4. using UnityEditor;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. namespace Animancer.Editor
  8. {
  9. /// <summary>
  10. /// An object that holds a serialized callback (a <see cref="UnityEvent"/> by default) so that empty ones can be
  11. /// drawn in the GUI without allocating array space for them until they actually contain something.
  12. /// </summary>
  13. internal class DummySerializableCallback : ScriptableObject
  14. {
  15. /************************************************************************************************************************/
  16. [SerializeField] private SerializableCallbackHolder _Holder;
  17. /************************************************************************************************************************/
  18. private static SerializedProperty _CallbackProperty;
  19. private static SerializedProperty CallbackProperty
  20. {
  21. get
  22. {
  23. if (_CallbackProperty == null)
  24. {
  25. var instance = CreateInstance<DummySerializableCallback>();
  26. instance.hideFlags = HideFlags.HideInHierarchy | HideFlags.DontSave;
  27. var serializedObject = new SerializedObject(instance);
  28. _CallbackProperty = serializedObject.FindProperty(
  29. $"{nameof(_Holder)}.{SerializableCallbackHolder.CallbackField}");
  30. AssemblyReloadEvents.beforeAssemblyReload += () =>
  31. {
  32. serializedObject.Dispose();
  33. DestroyImmediate(instance);
  34. };
  35. }
  36. return _CallbackProperty;
  37. }
  38. }
  39. /************************************************************************************************************************/
  40. public static float Height => EditorGUI.GetPropertyHeight(CallbackProperty);
  41. /************************************************************************************************************************/
  42. public static bool DoCallbackGUI(ref Rect area, GUIContent label, SerializedProperty property,
  43. out object callback)
  44. {
  45. var callbackProperty = CallbackProperty;
  46. callbackProperty.serializedObject.Update();
  47. callbackProperty.prefabOverride = property.prefabOverride;
  48. area.height = Height;
  49. EditorGUI.BeginChangeCheck();
  50. label = EditorGUI.BeginProperty(area, label, property);
  51. // UnityEvents ignore the proper indentation which makes them look terrible in a list.
  52. // So we force the area to be indented.
  53. var indentedArea = EditorGUI.IndentedRect(area);
  54. var indentLevel = EditorGUI.indentLevel;
  55. EditorGUI.indentLevel = 0;
  56. EditorGUI.PropertyField(indentedArea, callbackProperty, label, false);
  57. EditorGUI.indentLevel = indentLevel;
  58. EditorGUI.EndProperty();
  59. if (EditorGUI.EndChangeCheck())
  60. {
  61. callbackProperty.serializedObject.ApplyModifiedProperties();
  62. callback = callbackProperty.GetValue();
  63. callbackProperty.SetValue(null);
  64. callbackProperty.serializedObject.Update();
  65. if (AnimancerEvent.Sequence.Serializable.HasPersistentCalls(callback))
  66. return true;
  67. }
  68. callback = null;
  69. return false;
  70. }
  71. /************************************************************************************************************************/
  72. }
  73. }
  74. #endif