Best way to have icons in an EnumProperty

What would be the best way to designate icons for the items I am using in a enumproperty, define a function outside the class? or within? or is there a better alternative, I am not entirely sure how to go about this or if it is even possible, any advise would be appreciated, or if you could simply point me to a script that does something similar so I can give it a quick glance over.

As of r54055 it is possible:

Fix #31338: python enum properties can now specify icons for items, in the following
order: (identifier, name, description, icon, unique number)

This also works without the icon still, for compatibility.

Note that the unique numbers are mendatory if you define icons

Example:

import bpy





class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


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


        obj = context.object


        row = layout.row()
        row.prop(context.scene, "my_enum", expand=True)




def register():
    bpy.utils.register_class(HelloWorldPanel)
    bpy.types.Scene.my_enum = bpy.props.EnumProperty(
        items=(
            ('1','One','desc1', 'FILESEL', 1),
            ('2','Two','desc2', 'X', 2),
            ('3','Three','desc3', 'MESH_DATA', 3)
        )
    )




def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)




if __name__ == "__main__":
    register()

1 Like

ahh, man thanks, now that I have seen the list item I remember reading this somewhere (more then likely the online api reference mmm? :)). lol thanks for the reminder!

noticed what you threw in the register tag, is this a better thing to do rather then using the class it is used in, such as an operator.

no, if you use an operator class, you can put the properties inside there. But as I added a prop for a panel only, i really had to register the prop elsewhere, as props can’t be registered inside of panel classes.

no, this isn’t in the docs yet, but maybe you saw it in SVN commit log / tracker email?

items (sequence of string triplets or a function)
–sequence of enum items formatted: [(identifier, name, description, number), …]

yeah the commit log sounds right, didn’t know that parameters could not be stored within panels, i normally use a property group but its to much the same effect, i do like using window_manager to store the properties, seems proper, but everyone else uses scene so hard to say on that one :stuck_out_tongue:

This brings me to my next question, I am actually trying essentially to recreate the add modifier menu and the add constraint menu, how would I do that with enumproperty? note that I am using the identifier to check if the context is in the respective type, if you would like a more accurate idea of what I am going for check out my item panel and batch naming add-on, its in my dropbox so you don’t have to even download to review the code. the link in my signature will take you there.

I am trying to do this just for the sake of usability, not that it is necessary but so that the menus in the batch naming operator will appear to be the same as the ones that are available within the properties window.

The prime thing I am looking for is the categories/headers within these menus, such as modify, generate, deform, simulate. within the modifier menu, would I have to create separate lists for this effect?

you can’t recreate such, they use built-in layout templates:

http://www.blender.org/documentation/blender_python_api_2_65_9/bpy.types.UILayout.html?highlight=template_constraint#bpy.types.UILayout.template_modifier

layout.column doesn’t really work for menus

alright, thanks

sorry proxe, it actually works. You just have to be careful, only a certain combination works while others mess up the menu - you may put columns into row elements only, don’t ever use box’es in menues:

import bpy



class SimpleCustomMenu(bpy.types.Menu):
    bl_label = ""
    bl_idname = "OBJECT_MT_simple_custom_menu"


    def draw(self, context):
        layout = self.layout
        
        row = layout.row()
        
        sub = row.column()
        sub.label("Generate")
        sub.operator("object.modifier_add", text="Array", icon='MOD_ARRAY').type = 'ARRAY'
        sub.operator("object.modifier_add", text="Bevel", icon='MOD_BEVEL').type = 'BEVEL'
        sub.operator("object.modifier_add", text="Boolean", icon='MOD_BOOLEAN').type = 'BOOLEAN'
        sub.operator("object.modifier_add", text="Build", icon='MOD_BUILD').type = 'BUILD'
        
        sub = row.column()
        sub.label("Deform")
        sub.operator("object.modifier_add", text="Armature", icon='MOD_ARMATURE').type = 'ARMATURE'
        sub.operator("object.modifier_add", text="Cast", icon='MOD_CAST').type = 'CAST'
        sub.operator("object.modifier_add", text="Curve", icon='MOD_CURVE').type = 'CURVE'
        sub.operator("object.modifier_add", text="Displace", icon='MOD_DISPLACE').type = 'DISPLACE'
        sub.operator("object.modifier_add", text="Hook", icon='HOOK').type = 'HOOK'
        sub.operator("object.modifier_add", text="Laplacian Smooth", icon='MOD_SMOOTH').type = 'LAPLACIANSMOOTH'


def register():
    bpy.utils.register_class(SimpleCustomMenu)




def unregister():
    bpy.utils.unregister_class(SimpleCustomMenu)


if __name__ == "__main__":
    register()


    # The menu can also be called from scripts
    bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)

There is just a tiny difference: the column labels are indented like the operators, the original modifiers menu has them way less indented. I couldn’t fix this with icon=‘NONE’ or sub layout elements, but i bet you don’t care.

1 Like

hey man, thanks for the help, horrible timing, I’m in the middle of a project and I feel like dropping everything to finalize my add-on, haha, I’ll wait until 2.66 though, this way the add-on will work in trunk.

hmm, I am wondering if it is worth the time to create operators for the menu items that would properly set the object.type target.

would you explain that a little more in detail?

Whoa, forgive me, operator is not what I meant, I’m feeling a little under the weather, would be a bit crazy if i created 60+ classes in order to cover each item in the enumProperty available in the operator class, not to mention bad, just bad.

I was simply over thinking this, thinking I would have to create functions for each enumProperty item and return that function value (a function referred to as a method in python?), I can think of two ways to pull this off;

props = self.properties # for clarification, erhm, as if self.properties wasnt clear (>.> | <.< | >.<)

prop = sub.prop(props, enumProperty, text, icon) # shorthanding it
prop.item = whatever enumProperty item

well now that I see it I think that should do the trick, cant remember the second regardless, I have been off all day, I really should just be resting, so I can get over this cold quicker, this isn’t the first time I have made an odd mistake today, earlier today I was trying to set up pydrivers in a script for something that was already easily possible from within blenders default driver functionality.

O.o -_- o.O

I did just think of something though, where would I stick this if I wanted to write the draw function within the operator class?, man am I off, I write the question then think of the answer, just name it something else and call it in draw should work fine, at least I think it should, man I am going to bed lol.

CoDEmanX, what editors do you use other then blender itself for coding?

Programmer’s Notepad is my favorite :slight_smile:

Still not sure what you actually wanna do… cloning the modifiers dropdown list without typing all the .type = … lines manually?

I didn’t even know what I wanted, lol no I know that I will have to type out the .type =, not a big deal, I think I have it figured out now, bit to busy to develop my add-on atm, but I will get around to it.

Im a notepad++ user myself, with the plugins it becomes essentially a light weight IDE with one of the best editors available, been thinking about using emacs or vim but haven’t got around to it yet.

you could probably improve the code by using a dict/list/tuple to add an entry per modifier, if you actually wanna re-create a modifier dropdown list, then just use the template_modifiers()

Using a tuple:

modifiers = (
    ("Array", "MOD_ARRAY", "ARRAY"),
    ("Bevel", "MOD_BEVEL", "BEVEL")
)
for text, icon, modtype in modifiers:
    sub.operator("object.modifier_add", text=text, icon=icon).type = modtype

Instead of reading text, icon and modtype from a tuple, it might also be possible to retrieve them via bpy.types.*bl_rna, at least for the names it’s possible:

[i.name for i in bpy.types.Modifier.bl_rna.properties['type'].enum_items]

cool that should help a bit, I am not trying to add the modifier through my add-on, using it to dictate what type of modifier gets renamed in the batch naming process, but I would like the menu to mirror the modifier menu just for the familiarity, but a lot of what you have told me in this thread is translatable to what I need, thanks for all the pointers and tips!

check out the source for my add-on will help you get a better understanding, link is in my signature.

generally, UILayout elements return an object you can use for operator parameters, like:

props = col.operator("object.select_all")
props.action = 'DESELECT'
but if you wanna use a single parameter only, you can use the shorthand
col.operator("object.select_all").action = 'DESELECT'

interesting way to achieve this, thanks for your help codeman, i can tell that you enjoy helping people.