Unity Editor: Enum Flags as Toggle Buttons

Note: We’ve since cleaned up this code, added view options and released it as a cheap plugin on the Unity Asset Store.

Working on the content tools for our current project I needed enum flags, unfortunately the Unity Editor doesn’t natively support those. Looking around I found a few implementations of enum flags as dropdowns similar to the layer mask dropdown in Unity itself. While that’s pretty neat it has the disadvantage that you don’t have a quick overview over which flags are on and which are off. To that end I’ve built a new custom PropertyDrawer that displays EnumFlags as a neat row of toggle buttons:

Toggle Buttons in Action

Toggle Buttons in Action

All you need is two scripts and an attribute. Also note that your enum needs to start with 1, not 0 and that each value needs to be a power of two (1, 2, 4, 8 etc.)

And here’s the code:

EnumFlagAttribute.cs

This file needs to go in a regular scripts folder (not Editor!). It creates the [EnumFlags] attribute.

using UnityEngine;

public class EnumFlagAttribute : PropertyAttribute
{
	public EnumFlagAttribute() {}
}

EnumFlagDrawer.cs

This one goes into an Editor folder. It manages the display of fields that have the [EnumFlags] attribute.

using System;
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
public class EnumFlagsAttributeDrawer : PropertyDrawer
{

	public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
	{
		int buttonsIntValue = 0;
		int enumLength = _property.enumNames.Length;
		bool[] buttonPressed = new bool[enumLength];
		float buttonWidth = (_position.width - EditorGUIUtility.labelWidth) / enumLength;

		EditorGUI.LabelField(new Rect(_position.x, _position.y, EditorGUIUtility.labelWidth, _position.height), _label);

		EditorGUI.BeginChangeCheck ();

		for (int i = 0; i < enumLength; i++) {

			// Check if the button is/was pressed 
			if ( ( _property.intValue & (1 << i) ) == 1 << i ) {
				buttonPressed[i] = true;
			}

			Rect buttonPos = new Rect (_position.x + EditorGUIUtility.labelWidth + buttonWidth * i, _position.y, buttonWidth, _position.height);

			buttonPressed[i] = GUI.Toggle(buttonPos, buttonPressed[i], _property.enumNames[i],  "Button");

			if (buttonPressed[i])
				buttonsIntValue += 1 << i;
		}

		if (EditorGUI.EndChangeCheck()) {
			_property.intValue = buttonsIntValue;
		}
	}
}

I hope you enjoy it. And if you’ve got comments or ideas, let me know!

– Martin

Update: Note about the Unity Asset Store release of an updated version of this code added.


  • Pingback: Enum, Flags and bitwise operators - Alan Zucconi()

  • LeafyBug

    This is absolutely fantastic. I’m new to coding with C#, and this helps a ton. Thank you very much :)

    • Martin Nerurkar

      Glad it helped. It took a while to make it work the way I wanted and it’s always nice to be able to help someone :D

  • Miyth

    Thanks for posting this! Looks way more user-friendly than the way we’ve been doing it. But as someone else fairly new to editor scripting, I’m having trouble figuring out how to access the data once its been set.

    I can see that the flags can be set/unset– but I’m stumped trying to figure out how to grab hold of that via script in some way. Is there a way to recast the enum as a bitmask or something similar?

    • Martin Nerurkar

      Well, basically the enum is just a number, with the different enum values corresponding to different numbers (vertical = 0, horizontal = 1 etc.). You can cast an enum to an int and back.

      With that you can check if the current number value saved in the enum contains a specific enum value or not.

      This may help:

      http://stackoverflow.com/questions/1339976/how-to-check-if-any-flags-of-a-flag-combination-are-set

      • Miyth

        The link helped a bunch, thanks!

        For anyone else- the step I was missing here that was implied by the original post is being sure to treat the enum entries as bits and not integer assignments.

  • Pingback: » Sean: Coding is AwesomeNamespace Studio()

  • Tom

    To be compatible with Unity’s built-in enum flag Dropdown (using EditorGUILayout.EnumMaskField), it’s better to make sure that your enum definition also uses power-of-two values.


    enum MyEnum
    {
    First = 1,
    Second = 1 << 1,
    Third = 1 << 2,
    // etc
    }

    Your script just overwrites the field with the flag bits, correct? But if the enum is not defined correctly, you won’t be able to test for a value using a bitwise operator.

    • Tom

      Ah but there is a snag, isn’t there..

      There is no way to get the actual System.Type (the enum type) from a SerializedProperty? So we can’t do any Enum.GetValues() magic?

      • Martin Nerurkar

        Yeah you’re right in that it requires the enum as bits. Won’t work otherwise. And no, I don’t think you can get the enum Type from a SerializedProperty.

        • Martin Nerurkar

          actually yes you can. I just added support for enum definitions that skip some bit flags and still work. And to get that to work I had to get the type. I think it’s somewhere in SerializedProperty.fieldInfo – can’t recall from the top of my head. Either there or some field on SerializedProperty.

          Ah got it. fieldInfo.FieldType is it. You can check the latest version fo the unity asset store asset for an example use.

  • Nick Cellini

    Thanks so much for this!
    I made a few modifications to your code to get the layout of the buttons to be a little nicer.


    using System;
    using UnityEditor;
    using UnityEngine;

    [CustomPropertyDrawer(typeof(EnumFlagAttribute))]
    public class EnumFlagsAttributeDrawer : PropertyDrawer
    {

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
    int enumLength = property.enumNames.Length;
    return enumLength * 28f;
    }

    public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label) {
    int buttonsIntValue = 0;
    int enumLength = _property.enumNames.Length;
    bool[] buttonPressed = new bool[enumLength];
    float buttonWidth = EditorGUIUtility.currentViewWidth - (EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth);

    EditorGUI.LabelField(new Rect(_position.x, _position.y, EditorGUIUtility.labelWidth, _position.height), _label);

    EditorGUI.BeginChangeCheck ();

    float buttonHeight = _position.height / enumLength;
    for (int i = 0; i < enumLength; i++) {

    // Check if the button is/was pressed
    if ( ( _property.intValue & (1 << i) ) == 1 << i ) {
    buttonPressed[i] = true;
    }

    Rect buttonPos = new Rect (
    _position.x + EditorGUIUtility.labelWidth,
    _position.y + (i * buttonHeight),
    buttonWidth,
    buttonHeight - 4);

    buttonPressed[i] = GUI.Toggle(buttonPos, buttonPressed[i], _property.enumNames[i], "Button");

    if (buttonPressed[i])
    buttonsIntValue += 1 << i;
    }

    if (EditorGUI.EndChangeCheck()) {
    _property.intValue = buttonsIntValue;
    }
    }
    }

    • Martin

      Thanks for the update! We’ve actually built just that for our Asset Store release of Enum Flags as Buttons. Check it out. It now contians multi-editing infos and we may even expand it to offer more visual options (such as a dropdown etc.)

  • Nick Cellini

    Thanks so much for this!
    I made a few modifications to your code to get the layout of the buttons to be a little nicer. The height of your property will be larger depending on how many property names you have in your Enum, and the buttons will stack instead of being squished next to each other. Should help if you have Enums with a lot of values. I also added a little margin between each button ^.^

    https://uploads.disquscdn.com/images/a11d581a1aea2cb4de95b13131b7e39e44886be9b5a4717218734af6c5f043db.png


    using System;
    using UnityEditor;
    using UnityEngine;

    [CustomPropertyDrawer(typeof(EnumFlagAttribute))]
    public class EnumFlagsAttributeDrawer : PropertyDrawer
    {

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
    int enumLength = property.enumNames.Length;
    return enumLength * 28f;
    }

    public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label) {
    int buttonsIntValue = 0;
    int enumLength = _property.enumNames.Length;
    bool[] buttonPressed = new bool[enumLength];
    float buttonWidth = EditorGUIUtility.currentViewWidth - (EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth);

    EditorGUI.LabelField(new Rect(_position.x, _position.y, EditorGUIUtility.labelWidth, _position.height), _label);

    EditorGUI.BeginChangeCheck ();

    float buttonHeight = _position.height / enumLength;
    for (int i = 0; i < enumLength; i++) {

    // Check if the button is/was pressed
    if ( ( _property.intValue & (1 << i) ) == 1 << i ) {
    buttonPressed[i] = true;
    }

    Rect buttonPos = new Rect (
    _position.x + EditorGUIUtility.labelWidth,
    _position.y + (i * buttonHeight),
    buttonWidth,
    buttonHeight - 4);

    buttonPressed[i] = GUI.Toggle(buttonPos, buttonPressed[i], _property.enumNames[i], "Button");

    if (buttonPressed[i])
    buttonsIntValue += 1 << i;
    }

    if (EditorGUI.EndChangeCheck()) {
    _property.intValue = buttonsIntValue;
    }
    }
    }

    • Jesse Busch

      Thanks to everyone for sharing this great snippet of functionality. I’ve further modified the code to allow for a grid shape, where the programmer can specify the number of columns they want horizontally. The attribute drawer then draws the EnumFlag with as many rows as needed.


      using UnityEngine;

      public class EnumFlagAttribute : PropertyAttribute
      {
      public int columnCount;
      public EnumFlagAttribute(int rowCount)
      {
      this.columnCount = rowCount;
      }
      }


      using System;
      using UnityEditor;
      using UnityEngine;

      [CustomPropertyDrawer(typeof(EnumFlagAttribute))]
      public class EnumFlagsAttributeDrawer : PropertyDrawer
      {

      public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
      {
      EnumFlagAttribute flagAttribute = attribute as EnumFlagAttribute;
      int enumLength = Mathf.CeilToInt(property.enumNames.Length * 1.0f / flagAttribute.columnCount);
      return (enumLength * (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing));
      }

      public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
      {
      EnumFlagAttribute flagAttribute = attribute as EnumFlagAttribute;

      int buttonsIntValue = 0;
      int enumLength = _property.enumNames.Length;
      bool[] buttonPressed = new bool[enumLength];
      float buttonWidth = (_position.width - EditorGUIUtility.labelWidth) / flagAttribute.columnCount;
      float buttonHeight = (_position.height / Mathf.Ceil (enumLength * 1.0f / flagAttribute.columnCount));

      EditorGUI.LabelField(new Rect(_position.x, _position.y, EditorGUIUtility.labelWidth, _position.height), _label);

      EditorGUI.BeginChangeCheck ();

      for (int i = 0; i < enumLength; i++)
      {

      // Check if the button is/was pressed
      if ( ( _property.intValue & (1 << i) ) == 1 << i ) {
      buttonPressed[i] = true;
      }
      float rowIndex = Mathf.Floor (i / flagAttribute.columnCount);
      Rect buttonPos = new Rect (_position.x + EditorGUIUtility.labelWidth + buttonWidth * (i % flagAttribute.columnCount), _position.y + (rowIndex * buttonHeight), buttonWidth, buttonHeight);

      buttonPressed[i] = GUI.Toggle(buttonPos, buttonPressed[i], _property.enumNames[i], "Button");

      if (buttonPressed[i])
      buttonsIntValue += 1 << i;
      }

      if (EditorGUI.EndChangeCheck()) {
      _property.intValue = buttonsIntValue;
      }
      }
      }

      • Martin Nerurkar

        Hey! Thanks for the improvement. Funnily enough we’ve added the same functionality for our Asset Store release of the plugin. It’s improved with some multi-editing support and expanded view options. In fact that’s something we want to work on some more, adding the option to view the flags as a dropdown for example.

        You can find the asset store version for real cheap here:

        https://www.assetstore.unity3d.com/en/#!/content/74356

  • Matthew Harmon

    A good mod would be to support “sparse” bitflag enums. Right now, if I “skip” a power-of-two, the system breaks. I’ll see if I can add support for this.

    • Martin Nerurkar

      Yeah, I was thinking about making the asset store a bit more robust in that regard but haven’t really found time to do so yet. How would you approach that? My current thought is to iterate over the enum, and build an array of the values and then use that to display content instead. Not sure if that’s easily doable with the setup.

      • Martin Nerurkar

        Y’know what? I just built it and added it to the Unity Asset :D Thanks for the idea :)

        • Matthew Harmon

          Hey, thanks! I was going to give it a try next week. I’ll check it out today

          Other note: Many old-timers like me use all caps for ENUM values, and this breaks the text processing you do. (inserts spaces between each character!) Maybe provide an option for the text processing.

          • Martin Nerurkar

            I actually think that should be fixed in the new version too. I did some text parsing myself but later found out that unity already gives you a cleaned up version of the enum value names, which I presume is flexible enough to deal with all caps enum value names. That is now being used instead of my own camel-case-thingy.

            Might be a bit till it’s gone through the asset store validation, but since I’ve bumped up the price a tiny bit you might want to get it before that happens. It’s still up there for $1 instead of $2 ;)