-
-
Notifications
You must be signed in to change notification settings - Fork 228
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
176 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
#if UNITY_EDITOR | ||
using Plugins.MyBox.Tools; | ||
|
||
namespace MyBox.Internal | ||
{ | ||
using UnityEditor; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// ---------------------------------------------------------------------------- | ||
// Author: ByronMayne | ||
// https://gist.github.com/ByronMayne/70a46e73f3af7fb9fec7437174dd4858 | ||
// https://gist.github.com/ByronMayne | ||
// https://github.com/ByronMayne | ||
// ---------------------------------------------------------------------------- | ||
|
||
#if UNITY_EDITOR | ||
namespace MyBox.Internal | ||
{ | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using UnityEditor; | ||
using UnityEditorInternal; | ||
using UnityEngine; | ||
using UnityEngine.Events; | ||
|
||
[CustomPropertyDrawer(typeof(UnityEvent))] | ||
public class CollapsableEventDrawer : UnityEventDrawer | ||
{ | ||
private class Styles | ||
{ | ||
public readonly GUIStyle preButton = "RL FooterButton"; | ||
public GUIContent iconToolbarPlus = EditorGUIUtility.IconContent("Toolbar Plus", "|Add to list"); | ||
} | ||
|
||
private const string CALLS_PROPERTY_PATH = "m_PersistentCalls.m_Calls"; | ||
private const string GET_STATE_METHOD_NAME = "GetState"; | ||
private const string REORDERABLE_LIST_FIELD_NAME = "m_ReorderableList"; | ||
private const float BUTTON_WIDTH = 30; | ||
private const float BUTTON_SPACING = 30; | ||
private static readonly BindingFlags NON_PULIC_INSTANCE_FLAGS = BindingFlags.NonPublic | BindingFlags.Instance; | ||
|
||
|
||
// Points the field inside Sate which has the reorderable list. | ||
private static FieldInfo _stateReorderableListFieldInfo; | ||
|
||
// Points to the GetState method defined in UnityEventDrawer. | ||
private static MethodInfo _getStateMethod; | ||
|
||
// Cached array for using reflection | ||
private static object[] _getStateArgs = new object[1]; | ||
|
||
// A class that contains all the custom styling we need | ||
private static Styles _styles; | ||
|
||
|
||
// True if we have persistent calls and false if we don't. | ||
private bool _hasPersistentCalls; | ||
|
||
// Holds all our reorderable lists that belong to our state | ||
private IDictionary<State, ReorderableList> _lists; | ||
|
||
|
||
/// <summary> | ||
/// Used to initialize our values. | ||
/// </summary> | ||
public CollapsableEventDrawer() | ||
{ | ||
_lists = new Dictionary<State, ReorderableList>(); | ||
} | ||
|
||
|
||
/// <summary> | ||
/// A wrapper around the GetState function that is private in <see cref="UnityEventDrawer"/> | ||
/// </summary> | ||
private State GetState(SerializedProperty property) | ||
{ | ||
if (_getStateMethod == null) | ||
{ | ||
_getStateMethod = typeof(UnityEventDrawer).GetMethod(GET_STATE_METHOD_NAME, NON_PULIC_INSTANCE_FLAGS); | ||
} | ||
|
||
_getStateArgs[0] = property; | ||
return (State) _getStateMethod.Invoke(this, _getStateArgs); | ||
} | ||
|
||
/// <summary> | ||
/// Tries to get the cached ReorderableList from the state. | ||
/// </summary> | ||
private ReorderableList GetList(SerializedProperty property) | ||
{ | ||
State state = GetState(property); | ||
if (_lists.ContainsKey(state)) | ||
{ | ||
return _lists[state]; | ||
} | ||
|
||
ReorderableList list = GetReorderableListFromState(state); | ||
list.draggable = true; | ||
_lists[state] = list; | ||
return list; | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Returns back the number of calls that are currently in the Unity Event. | ||
/// </summary> | ||
private bool HasPersistentCalls(SerializedProperty property) | ||
{ | ||
return property.FindPropertyRelative(CALLS_PROPERTY_PATH).arraySize > 0; | ||
} | ||
|
||
/// <summary> | ||
/// Returns to Unity to tell it how much space we should use to draw. If we | ||
/// have one element we only reserve 32 units. 16 for the element itself and | ||
/// 16 for spacing from the next element. If we any calls we let Unity | ||
/// draw the default. | ||
/// </summary> | ||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) | ||
{ | ||
_hasPersistentCalls = HasPersistentCalls(property); | ||
|
||
ReorderableList list = GetList(property); | ||
|
||
if (!_hasPersistentCalls) | ||
{ | ||
list.elementHeight = 0; | ||
list.displayAdd = false; | ||
list.displayRemove = false; | ||
return EditorGUIUtility.singleLineHeight * 2f; | ||
} | ||
|
||
list.elementHeight = 43; | ||
list.displayAdd = true; | ||
list.displayRemove = true; | ||
return base.GetPropertyHeight(property, label); | ||
} | ||
|
||
/// <summary> | ||
/// Used to draw our element override a bit of the Unity logic in the case | ||
/// of having no elements. | ||
/// </summary> | ||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) | ||
{ | ||
if (_styles == null) | ||
{ | ||
_styles = new Styles(); | ||
} | ||
|
||
base.OnGUI(position, property, label); | ||
|
||
if (!_hasPersistentCalls) | ||
{ | ||
position.x += position.width - BUTTON_SPACING; | ||
position.width = BUTTON_WIDTH; | ||
if (GUI.Button(position, _styles.iconToolbarPlus, _styles.preButton)) | ||
{ | ||
State state = GetState(property); | ||
ReorderableList list = GetReorderableListFromState(state); | ||
list.onAddCallback(list); | ||
state.lastSelectedIndex = 0; | ||
} | ||
} | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Gets the internal instance of the <see cref="ReorderableList"/> that exists | ||
/// in the state. | ||
/// </summary> | ||
private static ReorderableList GetReorderableListFromState(State state) | ||
{ | ||
if (_stateReorderableListFieldInfo == null) | ||
{ | ||
_stateReorderableListFieldInfo = typeof(State).GetField(REORDERABLE_LIST_FIELD_NAME, NON_PULIC_INSTANCE_FLAGS); | ||
} | ||
|
||
return (ReorderableList) _stateReorderableListFieldInfo.GetValue(state); | ||
} | ||
} | ||
} | ||
#endif |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.