Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Unity3d property drawer for automatically making enums flags into mask fields in the inspector.
Unity3d property drawer for automatically making enums flags into mask fields in the inspector.
Usage: Put the .cs files somewhere in your project. When you have an enum field you want to turn into a mask field in the inspector, add the EnumFlag attribute over the field. Eg:
[EnumFlag]
MyCustomEnum thisEnum;
// This lets you give the field a custom name in the inspector.
[EnumFlag("Custom Inspector Name")]
MyCustomEnum anotherEnum;
using UnityEngine;
public class EnumFlagAttribute : PropertyAttribute
{
public string enumName;
public EnumFlagAttribute() {}
public EnumFlagAttribute(string name)
{
enumName = name;
}
}
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
public class EnumFlagDrawer : PropertyDrawer {
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EnumFlagAttribute flagSettings = (EnumFlagAttribute)attribute;
Enum targetEnum = GetBaseProperty<Enum>(property);
string propName = flagSettings.enumName;
if (string.IsNullOrEmpty(propName))
propName = property.name;
EditorGUI.BeginProperty(position, label, property);
Enum enumNew = EditorGUI.EnumMaskField(position, propName, targetEnum);
property.intValue = (int) Convert.ChangeType(enumNew, targetEnum.GetType());
EditorGUI.EndProperty();
}
static T GetBaseProperty<T>(SerializedProperty prop)
{
// Separate the steps it takes to get to this property
string[] separatedPaths = prop.propertyPath.Split('.');
// Go down to the root of this serialized property
System.Object reflectionTarget = prop.serializedObject.targetObject as object;
// Walk down the path to get the target object
foreach (var path in separatedPaths)
{
FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path);
reflectionTarget = fieldInfo.GetValue(reflectionTarget);
}
return (T) reflectionTarget;
}
}
@MrMatthias

This comment has been minimized.

Copy link

@MrMatthias MrMatthias commented Aug 21, 2014

i would use the label if no propName is set:

public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
    EnumFlagAttribute flagSettings = (EnumFlagAttribute)attribute;
    Enum targetEnum = GetBaseProperty<Enum> (property);
    EditorGUI.BeginProperty (position, label, property);
    Enum enumNew;
    string propName = flagSettings.enumName;
    if (string.IsNullOrEmpty (propName)) {
        enumNew = EditorGUI.EnumMaskField (position, label, targetEnum);
    } else {
        enumNew = EditorGUI.EnumMaskField (position, propName, targetEnum); 
    }
    property.intValue = (int)Convert.ChangeType (enumNew, targetEnum.GetType ());
    EditorGUI.EndProperty ();
}
@emanuelmaues

This comment has been minimized.

Copy link

@emanuelmaues emanuelmaues commented Jul 18, 2015

Hey man, thank you so much for providing this snippet. I managed to make it shown in inspector even if the attribute is private or protected. I just had to change this line:

FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path);

To this:

FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

// This is how it looks
[SerializeField, EnumFlag]
private Axis _axis;

[SerializeField, EnumFlag]
protected Axis _axis;
@ikriz

This comment has been minimized.

Copy link

@ikriz ikriz commented Aug 10, 2015

When the propertyPath contains an array it breaks for me,
my enum property is contained in a serializable class named Route
my monobehaviour has a List which breaks this method.

Fixed it in my fork

@nicekei

This comment has been minimized.

Copy link

@nicekei nicekei commented Nov 4, 2017

It definitely breaks when multiple objects are selected. This would overwrite the values :(

@FFouetil

This comment has been minimized.

Copy link

@FFouetil FFouetil commented Jan 11, 2018

Found a workaround for your problem nicekei:

                EditorGUI.BeginChangeCheck(); //new line
		EditorGUI.BeginProperty(position, label, property);
		Enum enumNew = EditorGUI.EnumMaskField(position, propName, targetEnum);
                if (!property.hasMultipleDifferentValues || EditorGUI.EndChangeCheck()) //new line
		             property.intValue = (int) Convert.ChangeType(enumNew, targetEnum.GetType());
		EditorGUI.EndProperty();

Forked it

@codiemorgan

This comment has been minimized.

Copy link

@codiemorgan codiemorgan commented Aug 3, 2020

You don't neeed this in modern Unity if you use the '[System.Flags]` attribute as Unity will use a mask field for any enum serialized with this attribute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.