I’m working with a short script and am currently appending an item to the Object menu (VIEW3D_MT_object). When I use it by calling it through that menu, the dialog comes up and everything works fine. But when I attach it to the object context menu (VIEW3D_MT_object_context_menu), and call it through that menu, the dialog does not come up.
The object context menu is a lot more convenient for me, so it’d be nice if the dialog would work from there. Is there a reason it won’t work from the object context menu? (Yes, currently that part of the register() function is commented out, but even when it’s not, and the item is appended to the object context menu, it won’t work.)
import bpy
class ShrinkageScaler(bpy.types.Operator):
bl_idname = "object.dialog_operator"
bl_label = "Shrinkage Scaler"
shrink_rate: bpy.props.IntProperty(name="Clay Shrink Rate",
description="Shrinkage rate for clay body",
default=10, min=0, max=90)
def execute(self, context):
expand = 100 / (100 - self.shrink_rate)
message = "Using shrinkage rate of %s and expansion rate of %s" % (self.shrink_rate, expand)
self.report({'INFO'}, message)
sel_objs = [obj for obj in bpy.context.selected_objects if obj.type == 'MESH']
# bpy.ops.object.select_all(action='DESELECT')
for obj in sel_objs:
s = obj.scale
obj.scale = (s[0] * expand, s[1] * expand, s[2] * expand)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self)
# Only needed if you want to add into a dynamic menu.
def menu_func(self, context):
self.layout.operator(ShrinkageScaler.bl_idname, text=ShrinkageScaler.bl_label)
def register():
bpy.utils.register_class(ShrinkageScaler)
bpy.types.VIEW3D_MT_object.append(menu_func)
# bpy.types.VIEW3D_MT_object_context_menu.append(menu_func)
def unregister():
bpy.utils.unregister_class(ShrinkageScaler)
bpy.types.VIEW3D_MT_object.remove(menu_func)
# bpy.types.VIEW3D_MT_object_context_menu.remove(menu_func)
if __name__ == "__main__":
register()
# unregister()```
It seems invoke is not called from context menus, only from menus.
Therefore I don’t think it’s possible to achieve what you want with a single operator. But in theory you can use in the context menu some second utility operator that will call your main operator with INVOKE_DEFAULT (see https://docs.blender.org/api/current/bpy.ops.html)
Tomorrow Blender will change the draw function adding some other operator_context that’s required for the last operator and it will affect all functions that other addons added after it.
Oh, actually, I think I was wrong. Just tried to add layout.operator_context = 'INVOKE_REGION_WIN' to the draw() I’ve mentioned above and next function call is still using EXEC_REGION_WIN. It seems to be just a default way for all context menus.
I appreciate all the help and discussion and have not yet had time to review it.
I apologize for bringing this up on another thread. I was summarizing what was left that I’d want to fix in a comment there and listed this issue - without thinking that would lead to discussion there and here.
I’ve gone over the posts here, but haven’t had time to read them carefully and think through it all. @Secrop, it looks to me like what you wrote in the other thread summarized what I need to do. Am I right that I need to:
add INVOKE_DEFAULT (and I’m not quite sure how to do that - is it a separate function to call?)
And, since that includes referencing “INVOKE_DEFAULT”, is that all I need to do to get it to work from the context menu?
I’m going by what I think I’ve seen on a read-through, but it’ll be a couple days before I can sit and read this thread carefully and make sure I understand it all, so I may be making things too simple.
Okay, that I can work with now. I still want to understand the rest, but making the change and making it easier to work with will be nice.
So I need to include INVOKE_DEFAULT in the menu_func() function, but then, if I use that, don’t I need to include an actual INVOKE_DEFAULT() function and then have it call my execute() function? Or is that what using INVOKE_DEFAULT in the menu_func() function does? (Sets it up to use execute() as the default?)
The INVOKE_* operator contexts will define that the operator should be invoked prior to execution (i.e. for user input). If the operator doesn’t have an invoke function, then the system will jump to the execute function.
Note that some operators can be called directly with EXEC_* context, even if they have an invoke method (for example, when calling an operator with all needed parameters)…
Other operators require the invoke call (like modal operators), and cannot work without it.