Adding an Operator to the Context Menu of a UIList

Hello,
How may I add an operator to the Context Menu of a UI List?

Context menus seem to be defined per Spaces (e.g. NODE_MT_context_menu in the below code). Could this be set for the menu of a region? Thank you!

def draw_menu(self, context):
    layout = self.layout
    layout.separator()
    layout.operator("node.duplicate_move", text="My new context menu item")

def register():
    bpy.types.NODE_MT_context_menu.append(draw_menu)

def unregister():
    bpy.types.NODE_MT_context_menu.remove(draw_menu)

I’m not aware of a way to do this, typically uilist context menus are shown via a button to the right of the list (including all of the uilists native to Blender)

2 Likes

Thank you for the reply!

You can override the context menus for buttons and ui list items.
See Add Operator to Right Click Menu for Operators - #2 by iceythe

Here’s an example that adds a label to the context menu when a vertex group is right clicked.

import bpy


class WM_MT_button_context(bpy.types.Menu):
    bl_label = ""
    # Leave empty for compatibility.
    def draw(self, context): pass


# Your draw function.
def draw(self, context):
    if hasattr(context, "button_pointer"):
        print("Clicked: ", context.button_pointer)

        if isinstance(context.button_pointer, bpy.types.VertexGroups):
            layout = self.layout
            layout.label(text="I'm in vertex groups context menu!")

    if hasattr(context, "button_prop"):
        print("Property:", context.button_prop.identifier)

    if hasattr(context, "ui_list") and context.ui_list is not None:
        print("UI List: ", context.ui_list.bl_idname)


if __name__ == "__main__":
    # Register menu only if it doesn't already exist.
    rcmenu = getattr(bpy.types, "WM_MT_button_context", None)
    if rcmenu is None:
        bpy.utils.register_class(WM_MT_button_context)
        rcmenu = WM_MT_button_context

    # Retrieve a python list for inserting draw functions.
    draw_funcs = rcmenu._dyn_ui_initialize()
    draw_funcs.append(draw)

2 Likes

@iceythe Thank you for this! It works with Vertex Groups as “Clicked” prints <bpy_struct, VertexGroups at 0x000001AC0DAF3908>

However, when I right click in my UIList, it prints <bpy_struct, Scene("Scene") at 0x000001AC0DBC2048>

Have I set something up incorrectly, context-wise, in my UIList/Panel?

Thank you

If your ui list is at context.scene.mylist, then context.button_pointer points to context.scene, so that seems correct.

The draw function prints a few things from context, if they exist:

context.button_pointer: The object you registered your ui list on. The scene in this case.
context.button_prop: The name of your ui list e.g mylist in context.scene.mylist.
context.ui_list: The ui list object itself, if Blender finds it. Otherwise None.

Using these values, and assuming the context holds any of these, you should be able to build a predicate in the draw function, so that your custom entry only is drawn when the right click menu is invoked on your ui list specifically.

Examples

def draw(self, context):
    ui_list = getattr(context, "ui_list", None)
    if ui_list is not None and ui_list == context.scene.mylist:
        # Draw operator here
def draw(self, context):
    if hasattr(context, "button_pointer"):
        if getattr(context.button_pointer, "mylist"):
            # Draw operator here
1 Like

You have been a wonderful help as always, @iceythe . Thank you so much!

1 Like