Guest User

Untitled

a guest
Jan 20th, 2018
125
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.07 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System.Reflection;
  3. using UnityEditor;
  4. using UnityEditorInternal;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7.  
  8. [CustomPropertyDrawer(typeof(UnityEvent))]
  9. public class CollapsableEventDrawer : UnityEventDrawer
  10. {
  11. private class Styles
  12. {
  13. public readonly GUIStyle preButton = "RL FooterButton";
  14. public GUIContent iconToolbarPlus = EditorGUIUtility.IconContent("Toolbar Plus", "|Add to list");
  15. }
  16.  
  17. private const string CALLS_PROPERTY_PATH = "m_PersistentCalls.m_Calls";
  18. private const string GET_STATE_METHOD_NAME = "GetState";
  19. private const string REORDERABLE_LIST_FIELD_NAME = "m_ReorderableList";
  20. private const float BUTTON_WIDTH = 30;
  21. private const float BUTTON_SPACING = 30;
  22. private static readonly BindingFlags NON_PULIC_INSTANCE_FLAGS = BindingFlags.NonPublic | BindingFlags.Instance;
  23.  
  24.  
  25. // Points the field inside Sate which has the reorderable list.
  26. private static FieldInfo _stateReorderableListFieldInfo;
  27. // Points to the GetState method defined in UnityEventDrawer.
  28. private static MethodInfo _getStateMethod;
  29. // Cached array for using reflection
  30. private static object[] _getStateArgs = new object[1];
  31. // A class that contains all the custom styling we need
  32. private static Styles _styles;
  33.  
  34.  
  35. // True if we have persistent calls and false if we don't.
  36. private bool _hasPersistentCalls;
  37. // Holds all our reorderable lists that belong to our state
  38. private IDictionary<State, ReorderableList> _lists;
  39.  
  40.  
  41. /// <summary>
  42. /// Used to initialize our values.
  43. /// </summary>
  44. public CollapsableEventDrawer()
  45. {
  46. _lists = new Dictionary<State, ReorderableList>();
  47. }
  48.  
  49.  
  50. /// <summary>
  51. /// A wrapper around the GetState function that is private in <see cref="UnityEventDrawer"/>
  52. /// </summary>
  53. private State GetState(SerializedProperty property)
  54. {
  55. if (_getStateMethod == null)
  56. {
  57. _getStateMethod = typeof(UnityEventDrawer).GetMethod(GET_STATE_METHOD_NAME, NON_PULIC_INSTANCE_FLAGS);
  58. }
  59. _getStateArgs[0] = property;
  60. return (State)_getStateMethod.Invoke(this, _getStateArgs);
  61. }
  62.  
  63. /// <summary>
  64. /// Tries to get the cached ReorderableList from the state.
  65. /// </summary>
  66. private ReorderableList GetList(SerializedProperty property)
  67. {
  68. State state = GetState(property);
  69. if(_lists.ContainsKey(state))
  70. {
  71. return _lists[state];
  72. }
  73. ReorderableList list = GetReorderableListFromState(state);
  74. _lists[state] = list;
  75. return list;
  76. }
  77.  
  78.  
  79. /// <summary>
  80. /// Returns back the number of calls that are currently in the Unity Event.
  81. /// </summary>
  82. private bool HasPersistentCalls(SerializedProperty property)
  83. {
  84. return property.FindPropertyRelative(CALLS_PROPERTY_PATH).arraySize > 0;
  85. }
  86.  
  87. /// <summary>
  88. /// Returns to Unity to tell it how much space we should use to draw. If we
  89. /// have one element we only reserve 32 units. 16 for the element itself and
  90. /// 16 for spacing from the next element. If we any calls we let Unity
  91. /// draw the default.
  92. /// </summary>
  93. public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
  94. {
  95. _hasPersistentCalls = HasPersistentCalls(property);
  96.  
  97. ReorderableList list = GetList(property);
  98.  
  99. if (!_hasPersistentCalls)
  100. {
  101. list.elementHeight = 0;
  102. list.displayAdd = false;
  103. list.displayRemove = false;
  104. return EditorGUIUtility.singleLineHeight * 2f;
  105. }
  106.  
  107. list.elementHeight = 43;
  108. list.displayAdd = true;
  109. list.displayRemove = true;
  110. return base.GetPropertyHeight(property, label);
  111. }
  112.  
  113. /// <summary>
  114. /// Used to draw our element override a bit of the Unity logic in the case
  115. /// of having no elements.
  116. /// </summary>
  117. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
  118. {
  119. if(_styles == null)
  120. {
  121. _styles = new Styles();
  122. }
  123.  
  124. base.OnGUI(position, property, label);
  125.  
  126. if (!_hasPersistentCalls)
  127. {
  128. position.x += position.width - BUTTON_SPACING;
  129. position.width = BUTTON_WIDTH;
  130. if(GUI.Button(position, _styles.iconToolbarPlus, _styles.preButton))
  131. {
  132. State state = GetState(property);
  133. ReorderableList list = GetReorderableListFromState(state);
  134. list.onAddCallback(list);
  135. state.lastSelectedIndex = 0;
  136. }
  137. }
  138. }
  139.  
  140.  
  141. /// <summary>
  142. /// Gets the internal instance of the <see cref="ReorderableList"/> that exists
  143. /// in the state.
  144. /// </summary>
  145. private static ReorderableList GetReorderableListFromState(State state)
  146. {
  147. if (_stateReorderableListFieldInfo == null)
  148. {
  149. _stateReorderableListFieldInfo = typeof(State).GetField(REORDERABLE_LIST_FIELD_NAME, NON_PULIC_INSTANCE_FLAGS);
  150. }
  151. return (ReorderableList)_stateReorderableListFieldInfo.GetValue(state);
  152. }
  153. }
Add Comment
Please, Sign In to add comment