I’m trying to do a dynamic operator_menu_enum assignment without global variables and at the time of the layout.
I have adapted a piece of CoDEmanX gold and it works almost completely (even the tooltips) except for the final assignment. The Show info bit is just to show that it works.
Has anyone any ideas.
import bpy
class ShowInfo(bpy.types.Operator):
bl_idname = "object.showinfo"
bl_label = "Report Information"
info = bpy.props.StringProperty()
def execute(self, context):
self.report({'INFO'}, "{:}".format(self.info))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
class SimpleOperator(bpy.types.Operator):
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
enum_items = (('ONE','One','First'),('TWO','Two','Second'))
myprop = bpy.props.EnumProperty(items=enum_items)
@classmethod
def poll(cls, context):
return context.active_object is not None
def execute(self, context):
enum_items_dict = {id: name for id, name, desc in self.enum_items}
self.__class__.bl_label = enum_items_dict[self.myprop]
self.__class__.bl_description = enum_items_dict[self.myprop]
return {'FINISHED'}
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
op = layout.operator(ShowInfo.bl_idname, text = 'Say Hi', icon='HAND' )
op.info = "Hello"
op = layout.operator(ShowInfo.bl_idname, text = 'Say Yes', icon='HAND' )
op.info = "No"
op2 = layout.operator_menu_enum(SimpleOperator.bl_idname, "myprop", text=SimpleOperator.bl_label)
op2.enum_items = (('1','One','First'),('2','Two','Second'),('THREE','Three','Third'))
def register():
bpy.utils.register_class(ShowInfo)
bpy.utils.register_class(SimpleCustomMenu)
bpy.utils.register_class(SimpleOperator)
if __name__ == "__main__":
register()
# The menu can also be called from scripts
bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)
import bpy
class ShowInfo(bpy.types.Operator):
bl_idname = "object.showinfo"
bl_label = "Report Information"
info = bpy.props.StringProperty()
def execute(self, context):
self.report({'INFO'}, "{:}".format(self.info))
return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
def enum_items_cb(self, context):
l = (('ONE','One','First'), ('TWO','Two','Second'), ('THREE', 'Three', 'Third'))
enum_items_cb.lookup = {id: name for id, name, desc in l}
return l
class SimpleOperator(bpy.types.Operator):
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
myprop = bpy.props.EnumProperty(items=enum_items_cb)
def execute(self, context):
self.report({'INFO'}, enum_items_cb.lookup[self.myprop])
return {'FINISHED'}
class SimpleCustomMenu(bpy.types.Menu):
bl_label = "Simple Custom Menu"
bl_idname = "OBJECT_MT_simple_custom_menu"
def draw(self, context):
layout = self.layout
op = layout.operator(ShowInfo.bl_idname, text = 'Say Hi', icon='HAND' )
op.info = "Hello"
op = layout.operator(ShowInfo.bl_idname, text = 'Say Yes', icon='HAND' )
op.info = "No"
op = layout.operator_menu_enum(SimpleOperator.bl_idname, "myprop", text=SimpleOperator.bl_label)
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
# The menu can also be called from scripts
bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname)
There’s a hidden global variable, which is the callback function for enum items. I use it to store a lookup dictionary of enum entries, so I can map the IDs to their names without a second call to enum_items_cb(), which could possibly return a different sequence of triples if the callback generated a real dynamic sequence.
I know this is probably a dumb python question but why doesn’t this work as well
def enum_items_cb(self, context, l=(('ONE','One','First'), ('TWO','Two','Second'), ('THREE', 'Three', 'Third'))):
enum_items_cb.lookup = {id: name for id, name, desc in l}
return l
I know it really hasn’t got anything to do with the solution but I’m just curious what I got wrong in the assignment.
I will work that out one day, I’m still learning.
I am having trouble getting a handle on the scope in this case.
I want to be able to pass a variable to the enum_items_cb function.
Debugging is really hard as print() doesn’t seem to be run inside the function even though the code runs and fails.
(that is for anything other than actual python errors that break the whole code)
I still can’t work out how to assign a variable to a scope that can be read dynamically to the enum.
I would like to utilize the onmouseover effect of operator_menu_enum so that one button/operator shows one list and the next button/operator shows a different list from the same data.
AFAIK this would need to be attached to the individual button/operator. However changing something at draw time is different to setting it at the time of the call.
The only way I can think of is to build individual classes for each situation on the fly and eval them into existence. That seems a bit over the top and unnecessary for this task.
you can’t pass anything to the callback function, why would you?
If necessary, use global variables that you can check inside the callback. You shouldn’t use one and the same callback for two different sets of entries for two different menus however.
Thanks CoDEmanX
I now realise that what I was after would also the problems associated with changing stuff from the draw function.
What I have created so far is not completely what I was after however it will do for now.
My addon is functional and basically does what is required so I will get back to actually learning Blender.
Thanks you very much for all your help and good luck in all your endeavors.
Thanks again Yardie