Created
November 18, 2018 13:59
-
-
Save figgleforth/e460ce70b9373924b840eb27c78dc9cc to your computer and use it in GitHub Desktop.
Helpful script for displaying uints in the Unity inspector
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
/* | |
Written by: Lucas Antunes (aka ItsaMeTuni), [email protected] | |
In: 2/15/2018 | |
The only thing that you cannot do with this script is sell it by itself without substantially modifying it. | |
*/ | |
using System; | |
using UnityEngine; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
[CustomPropertyDrawer(typeof(EnumMaskAttribute))] | |
public class EnumMaskPropertyDrawer : PropertyDrawer { | |
bool foldoutOpen = true; | |
object theEnum; | |
Array enumValues; | |
Type enumUnderlyingType; | |
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { | |
if (foldoutOpen) | |
return EditorGUIUtility.singleLineHeight * (Enum.GetValues(fieldInfo.FieldType).Length + 2); | |
else | |
return EditorGUIUtility.singleLineHeight; | |
} | |
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { | |
theEnum = fieldInfo.GetValue(property.serializedObject.targetObject); | |
enumValues = Enum.GetValues(theEnum.GetType()); | |
enumUnderlyingType = Enum.GetUnderlyingType(theEnum.GetType()); | |
//We need to convert the enum to its underlying type, if we don't it will be boxed | |
//into an object later and then we would need to unbox it like (UnderlyingType)(EnumType)theEnum. | |
//If we do this here we can just do (UnderlyingType)theEnum later (plus we can visualize the value of theEnum in VS when debugging) | |
theEnum = Convert.ChangeType(theEnum, enumUnderlyingType); | |
EditorGUI.BeginProperty(position, label, property); | |
foldoutOpen = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), foldoutOpen, label); | |
if (foldoutOpen) { | |
//Draw the All button | |
if (GUI.Button(new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * 1, 30, 15), "All")) { | |
for (int i = 0; i < Enum.GetNames(fieldInfo.FieldType).Length; i++) { | |
ToggleIndex(i, true); | |
} | |
} | |
//Draw the None button | |
if (GUI.Button(new Rect(position.x + 32, position.y + EditorGUIUtility.singleLineHeight * 1, 40, 15), "None")) { | |
for (int i = 0; i < Enum.GetNames(fieldInfo.FieldType).Length; i++) { | |
ToggleIndex(i, false); | |
} | |
} | |
//Draw the list | |
for (int i = 0; i < Enum.GetNames(fieldInfo.FieldType).Length; i++) { | |
if (EditorGUI.Toggle(new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * (2 + i), position.width, EditorGUIUtility.singleLineHeight), Enum.GetNames(fieldInfo.FieldType)[i], IsSet(i))) { | |
ToggleIndex(i, true); | |
} else { | |
ToggleIndex(i, false); | |
} | |
} | |
} | |
fieldInfo.SetValue(property.serializedObject.targetObject, theEnum); | |
property.serializedObject.ApplyModifiedProperties(); | |
} | |
/// <summary> | |
/// Get the value of an enum element at the specified index (i.e. at the index of the name of the element in the names array) | |
/// </summary> | |
object GetEnumValue(int _index) { | |
return Convert.ChangeType(enumValues.GetValue(_index), enumUnderlyingType); | |
} | |
/// <summary> | |
/// Sets or unsets a bit in theEnum based on the index of the enum element (i.e. the index of the element in the names array) | |
/// </summary> | |
/// <param name="_set">If true the flag will be set, if false the flag will be unset.</param> | |
void ToggleIndex(int _index, bool _set) { | |
if (_set) { | |
//enum = enum | val | |
theEnum = DoOrOperator(theEnum, GetEnumValue(_index), enumUnderlyingType); | |
} else { | |
object val = GetEnumValue(_index); | |
object notVal = DoNotOperator(val, enumUnderlyingType); | |
//enum = enum & ~val | |
theEnum = DoAndOperator(theEnum, notVal, enumUnderlyingType); | |
} | |
} | |
/// <summary> | |
/// Checks if a bit flag is set at the provided index of the enum element (i.e. the index of the element in the names array) | |
/// </summary> | |
bool IsSet(int _index) { | |
object val = DoAndOperator(theEnum, GetEnumValue(_index), enumUnderlyingType); | |
if (enumUnderlyingType == typeof(int)) { | |
return (int)val != 0; | |
} else if (enumUnderlyingType == typeof(uint)) { | |
return (uint)val != 0; | |
} else if (enumUnderlyingType == typeof(short)) { | |
return (short)val != 0; | |
} else if (enumUnderlyingType == typeof(ushort)) { | |
return (ushort)val != 0; | |
} else if (enumUnderlyingType == typeof(long)) { | |
return (long)val != 0; | |
} else if (enumUnderlyingType == typeof(ulong)) { | |
return (ulong)val != 0; | |
} else if (enumUnderlyingType == typeof(byte)) { | |
return (byte)val != 0; | |
} else if (enumUnderlyingType == typeof(sbyte)) { | |
return (sbyte)val != 0; | |
} else { | |
throw new System.ArgumentException("Type " + enumUnderlyingType.GetType().FullName + " not supported."); | |
} | |
} | |
/// <summary> | |
/// Call the bitwise OR operator (|) on _lhs and _rhs given their types. | |
/// Will basically return _lhs | _rhs | |
/// </summary> | |
/// <param name="_lhs">Left-hand side of the operation.</param> | |
/// <param name="_rhs">Right-hand side of the operation.</param> | |
/// <param name="_type">Type of the objects.</param> | |
/// <returns>Result of the operation</returns> | |
static object DoOrOperator(object _lhs, object _rhs, Type _type) { | |
if (_type == typeof(int)) { | |
return ((int)_lhs) | ((int)_rhs); | |
} else if (_type == typeof(uint)) { | |
return ((uint)_lhs) | ((uint)_rhs); | |
} else if (_type == typeof(short)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((short)((short)_lhs | (short)_rhs)); | |
} else if (_type == typeof(ushort)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((ushort)((ushort)_lhs | (ushort)_rhs)); | |
} else if (_type == typeof(long)) { | |
return ((long)_lhs) | ((long)_rhs); | |
} else if (_type == typeof(ulong)) { | |
return ((ulong)_lhs) | ((ulong)_rhs); | |
} else if (_type == typeof(byte)) { | |
//byte and sbyte don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((byte)((byte)_lhs | (byte)_rhs)); | |
} else if (_type == typeof(sbyte)) { | |
//byte and sbyte don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((sbyte)((sbyte)_lhs | (sbyte)_rhs)); | |
} else { | |
throw new System.ArgumentException("Type " + _type.FullName + " not supported."); | |
} | |
} | |
/// <summary> | |
/// Call the bitwise AND operator (&) on _lhs and _rhs given their types. | |
/// Will basically return _lhs & _rhs | |
/// </summary> | |
/// <param name="_lhs">Left-hand side of the operation.</param> | |
/// <param name="_rhs">Right-hand side of the operation.</param> | |
/// <param name="_type">Type of the objects.</param> | |
/// <returns>Result of the operation</returns> | |
static object DoAndOperator(object _lhs, object _rhs, Type _type) { | |
if (_type == typeof(int)) { | |
return ((int)_lhs) & ((int)_rhs); | |
} else if (_type == typeof(uint)) { | |
return ((uint)_lhs) & ((uint)_rhs); | |
} else if (_type == typeof(short)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((short)((short)_lhs & (short)_rhs)); | |
} else if (_type == typeof(ushort)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((ushort)((ushort)_lhs & (ushort)_rhs)); | |
} else if (_type == typeof(long)) { | |
return ((long)_lhs) & ((long)_rhs); | |
} else if (_type == typeof(ulong)) { | |
return ((ulong)_lhs) & ((ulong)_rhs); | |
} else if (_type == typeof(byte)) { | |
return unchecked((byte)((short)_lhs & (short)_rhs)); | |
} else if (_type == typeof(sbyte)) { | |
//byte and sbyte don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((sbyte)((sbyte)_lhs & (sbyte)_rhs)); | |
} else { | |
throw new System.ArgumentException("Type " + _type.FullName + " not supported."); | |
} | |
} | |
/// <summary> | |
/// Call the bitwise NOT operator (~) on _lhs given its type. | |
/// Will basically return ~_lhs | |
/// </summary> | |
/// <param name="_lhs">Left-hand side of the operation.</param> | |
/// <param name="_type">Type of the object.</param> | |
/// <returns>Result of the operation</returns> | |
static object DoNotOperator(object _lhs, Type _type) { | |
if (_type == typeof(int)) { | |
return ~(int)_lhs; | |
} else if (_type == typeof(uint)) { | |
return ~(uint)_lhs; | |
} else if (_type == typeof(short)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((short)~(short)_lhs); | |
} else if (_type == typeof(ushort)) { | |
//ushort and short don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((ushort)~(ushort)_lhs); | |
} else if (_type == typeof(long)) { | |
return ~(long)_lhs; | |
} else if (_type == typeof(ulong)) { | |
return ~(ulong)_lhs; | |
} else if (_type == typeof(byte)) { | |
//byte and sbyte don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return (byte)~(byte)_lhs; | |
} else if (_type == typeof(sbyte)) { | |
//byte and sbyte don't have bitwise operators, it is automatically converted to an int, so we convert it back | |
return unchecked((sbyte)~(sbyte)_lhs); | |
} else { | |
throw new System.ArgumentException("Type " + _type.FullName + " not supported."); | |
} | |
} | |
} | |
#endif | |
[System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false)] | |
public class EnumMaskAttribute : PropertyAttribute { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment