Custom inspector multi-select enum dropdown?

I want to make a drop-down in a custom inspector that allows me to select multiple enums from a popup, exactly like the popups you get when selecting a camera’s culling mask, a projector’s “ignore” layers, or a layermask. (see picture)

Am I missing a simple way to do this? What would the returned result of a change be? A List or array of FooEnum elements? I can jury-rig an equivalent alternative, but since this GUI element does exactly what I want, I’d love to use one if I could find out how!

7528-flags.jpg

I’ve written a “wrapper” function, mainly for a general PropertyDrawer, which actual uses the enum values. However, this changes the Nothing and Everything behaviour, but all enum values work fine, even combined values.

//C#

// Have to be defined somewhere in a runtime script file
public class BitMaskAttribute : PropertyAttribute
{
    public System.Type propType;
    public BitMaskAttribute(System.Type aType)
    {
        propType = aType;
    }
}

This should go into an editor script:

using UnityEngine;
using UnityEditor;
using System.Collections;

public static class EditorExtension
{
    public static int DrawBitMaskField (Rect aPosition, int aMask, System.Type aType, GUIContent aLabel)
    {
        var itemNames = System.Enum.GetNames(aType);
        var itemValues = System.Enum.GetValues(aType) as int[];
        
        int val = aMask;
        int maskVal = 0;
        for(int i = 0; i < itemValues.Length; i++)
        {
            if (itemValues *!= 0)*

{
if ((val & itemValues_) == itemValues*)
maskVal |= 1 << i;
}
else if (val == 0)
maskVal |= 1 << i;
}*
int newMaskVal = EditorGUI.MaskField(aPosition, aLabel, maskVal, itemNames);
int changes = maskVal ^ newMaskVal;_

for(int i = 0; i < itemValues.Length; i++)
{
if ((changes & (1 << i)) != 0) // has this list item changed?
{
if ((newMaskVal & (1 << i)) != 0) // has it been set?
{
if (itemValues == 0) // special case: if “0” is set, just set the val to 0
{
val = 0;
break;
}
else
val |= itemValues*;*
}
else // it has been reset
{
val &= ~itemValues*;*
}
}
}
return val;
}
}

[CustomPropertyDrawer(typeof(BitMaskAttribute))]
public class EnumBitMaskPropertyDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty prop, GUIContent label)
{
var typeAttr = attribute as BitMaskAttribute;
// Add the actual int value behind the field name
label.text = label.text + “(”+prop.intValue+“)”;
prop.intValue = EditorExtension.DrawBitMaskField(position, prop.intValue, typeAttr.propType, label);
}
}
Now just imagine this example:
public enum EMyEnum
{
None = 0x00,
Cow = 0x01,
Chicken = 0x02,
Cat = 0x04,
Dog = 0x08,
CowChicken = 0x03,
CatDog = 0x0C,
All = 0x0F,
}

public class Example : MonoBehaviour
{
[BitMask(typeof(EMyEnum))]
public EMyEnum someMask;
}
This will automatically draw my modified enum-mask field.

You need to use EnumMaskField and make sure your enum is decorated with the [Flags] attribute.

@AlwaysSunny @Bunny83 @whydoidoit @Aqibsadiq :

A clean solution for current versions of Unity.

EnumFlagAttributePropertyDrawer.cs

using System;
using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
class EnumFlagAttributePropertyDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        label = EditorGUI.BeginProperty(position, label, property);

        var oldValue = (Enum)fieldInfo.GetValue(property.serializedObject.targetObject);
        var newValue = EditorGUI.EnumFlagsField(position, label, oldValue);
        if (!newValue.Equals(oldValue))
        {
            property.intValue = (int)Convert.ChangeType(newValue, fieldInfo.FieldType);
        }

        EditorGUI.EndProperty();
    }
}

EnumFlagAttribute.cs

using UnityEngine;

/// <summary>
/// Display multi-select popup for Flags enum correctly.
/// </summary>
public class EnumFlagAttribute : PropertyAttribute
{
}

Usage example:

public class MyFlagHolder : MonoBehaviour
{
    [SerializeField, EnumFlag]
    private MyFlag flags;
}

[Flags]
public enum MyFlag
{
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8
}

@Bunny83 @AlwaysSunny @whydoidoit

Here is a simpler way

Simple 4 Steps

Step 1 : Make a new Script “EnumFlagsAttribute”

using UnityEngine;
using System.Collections;
public class EnumFlagsAttribute : PropertyAttribute
 {
     public EnumFlagsAttribute() { }
 }

Step 2 : Make another Script “EnumFlagsAttributeDrawer”

using UnityEngine;
using System.Collections;
using System;
using UnityEditor;

[CustomPropertyDrawer(typeof(EnumFlagsAttribute))]
 public class EnumFlagsAttributeDrawer : PropertyDrawer
 {
     public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
     {
         _property.intValue = EditorGUI.MaskField( _position, _label, _property.intValue, _property.enumNames );
     }
 }

Step 3: Enum Declaration

[System.Flags]
	public enum FurnitureType
	{
		None , SofaPrefab , Curtains , Table , Chairs 
        }

 [EnumFlagsAttribute]
	public  FurnitureType   enumType;

Step 4: Getting Selected Elements

List<int> ReturnSelectedElements()
	{

		List<int> selectedElements = new List<int>();
		for (int i = 0; i < System.Enum.GetValues(typeof(FurnitureType)).Length; i++)
		{
		    int layer = 1 << i;
			if (((int) enumType & layer) != 0)
		    {
		    	selectedElements.Add(i);
		    }
		}

		return selectedElements;

	}

Instead of Add(i) it should be:

selectedElements.Add(
    (int) Enum.GetValues( typeof(FurnitureType) ).GetValue(i)
);