3
$\begingroup$

Is there any way to extract an int value from one of Blender's ENUM_FLAG properties? Here are the definitions I have:

# binary flag values
class OpFlag:
    GA = 1<<0 # activator for asset mode
    LP = 1<<1 # activator for low poly mode
    HP = 1<<2 # activator for high poly mode
    CU = 1<<3 # activator for custom mode

# string based flag values for Blender controls
opflags=[
            ('GA', "Asset", "desc", OpFlag.GA ),
            ('LP', "Low", "desc", OpFlag.LP ),
            ('HP', "High", "desc", OpFlag.HP ),
            ('CU', "Custom", "desc", OpFlag.CU )
        ]

# property using flags
modes : EnumProperty(
    name = "Modes",
    options = {'ENUM_FLAG'},
    items = opflags,
    default={'GA','LP','HP','CU'}
    )

This is what I would like to be able to do, if possible:

control_op_flags = int( 0 ) # just to make it obvious this is an int
control_op_flags |= int( modes )

I read somewhere online that you can cast a Blender string-based enum value to int, but it doesn't seem to work with an enum-flags set. This is the error I get:

TypeError: int() argument must be a string, a bytes-like object or a number, not 'set'

Does anyone know how to convert an enum-flags set into a single int? I didn't consider it until just now, but is it possible to iterate the set and convert/OR all of the values together myself? Would that be the proper way to handle this? I've never iterated a set before, so going to investigate that now.

Edit Update: When I try to iterate the set and OR in one entry from it, I get the error ValueError: invalid literal for int() with base 10: 'GA'.. Sounds like it is dealing with it purely as a string. I'm not sure how to associate it with my opflags list.

Thanks for any advice

$\endgroup$

1 Answer 1

4
$\begingroup$

You can access the value through the RNA properties. Assuming that you have stored modes in a PointerProperty and assigned to bpy.types.Scene.demo_tool (just an example), you can access it in the following way:

The first step is to get access to the RNA properties of demo_tool or in general the object that contains your EnumProperty. This will give us access to the underlying data structure of modes which contains the mapping to the integer values.

demo_tool = bpy.context.scene.demo_tool
items = demo_tool.bl_rna.properties["modes"].enum_items

The enum_items give you access to a collection (bpy_prop_collection) of EnumProperties which represent the valid (single) flags you can use. It allows a look-up with a key. For example the following code gives you the integer value for your 'LP' flag, by accessing the EnumPropertyItem.

items['LP'].value

Since you have a set of strings stored in modes when using options={'ENUM_FLAG'} you must iterate through it to get the integer value for each flag.

for flag in demo_tool.modes:
    print(f"{items[flag].value}")

Once you have the integers you can perform the boolean logic operations to create a single value.


import bpy


class DemoSettings(bpy.types.PropertyGroup):
    GA = 1 << 0  # activator for asset mode
    LP = 1 << 1  # activator for low poly mode
    HP = 1 << 2  # activator for high poly mode
    CU = 1 << 3  # activator for custom mode

    # string based flag values for Blender controls
    opflags = [
        ('GA', "Asset", "desc", GA),
        ('LP', "Low", "desc", LP),
        ('HP', "High", "desc", HP),
        ('CU', "Custom", "desc", CU)
    ]

    # property using flags
    modes: bpy.props.EnumProperty(
        name="Modes",
        options={'ENUM_FLAG'},
        items=opflags,
        default={'GA', 'LP', 'HP', 'CU'}
    )


class DEMO_PT_panel(bpy.types.Panel):
    """Creates a Panel in the scene context of the properties editor"""
    bl_label = "My own addon"
    bl_category = "Name of your tab"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout
        demo_tool = context.scene.demo_tool

        row = layout.row()
        row.prop(demo_tool, "modes")

        items = demo_tool.bl_rna.properties["modes"].enum_items

        flag_value = 0

        for flag in demo_tool.modes:
            flag_value |= items[flag].value

        row.label(text=str(flag_value))


classes = (DemoSettings,
           DEMO_PT_panel)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.demo_tool = bpy.props.PointerProperty(type=DemoSettings)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()
$\endgroup$
2
  • $\begingroup$ Your knowledge (and/or ability to find information) is really impressive. Thanks for this detailed answer. For some reason, I keep getting the error bpy_prop_collection[key]: key "modes" not found. Would this be because I'm storing "modes" inside of an operator class? Using properties inside of operators is very new for me, so I may be doing something else wrong. I am able to access modes normally, but self.bl_rna.properties["modes"] throws this error. Would there be an obvious reason? $\endgroup$
    – Robert
    Sep 21, 2019 at 17:42
  • $\begingroup$ @Robert Thank you! I'd have to look into that. $\endgroup$
    – Robert Gützkow
    Sep 22, 2019 at 9:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .