diff options
-rw-r--r-- | release/scripts/startup/bl_ui/__init__.py | 24 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_context_menu.c | 16 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 2 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 2 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_template_search_menu.c | 4 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_context.c | 11 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_ui.c | 31 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 1 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_uilist_type.c | 14 |
9 files changed, 98 insertions, 7 deletions
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index ef705f8fe37..25484e905c3 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -117,13 +117,15 @@ def register(): for cls in mod.classes: register_class(cls) - # space_userprefs.py from bpy.props import ( EnumProperty, StringProperty, ) - from bpy.types import WindowManager + from bpy.types import ( + WindowManager, + ) + # space_userprefs.py def addon_filter_items(_self, _context): import addon_utils @@ -234,3 +236,21 @@ class UI_UL_list(bpy.types.UIList): bpy.utils.register_class(UI_UL_list) + + +class UI_MT_list_item_context_menu(bpy.types.Menu): + """ + UI List item context menu definition. Scripts can append/prepend this to + add own operators to the context menu. They must check context though, so + their items only draw in a valid context and for the correct UI list. + """ + + bl_label = "List Item" + bl_idname = "UI_MT_list_item_context_menu" + + def draw(self, context): + # Dummy function. This type is just for scripts to append their own + # context menu items. + pass + +bpy.utils.register_class(UI_MT_list_item_context_menu) diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 2a7611eabb1..3049e2bd7b8 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -494,7 +494,7 @@ static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, Pr RNA_string_set(&props_ptr, "filepath", dir); } -bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) +bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *event) { /* ui_but_is_interactive() may let some buttons through that should not get a context menu - it * doesn't make sense for them. */ @@ -1226,6 +1226,20 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } } + /* UI List item context menu. Scripts can add items to it, by default there's nothing shown. */ + ARegion *region = CTX_wm_region(C); + const bool is_inside_listbox = ui_list_find_mouse_over(region, event) != NULL; + const bool is_inside_listrow = is_inside_listbox ? + ui_list_row_find_mouse_over(region, event->x, event->y) != + NULL : + false; + if (is_inside_listrow) { + MenuType *mt = WM_menutype_find("UI_MT_list_item_context_menu", true); + if (mt) { + UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); + } + } + MenuType *mt = WM_menutype_find("WM_MT_button_context", true); if (mt) { UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 2f03539873f..cd975e97613 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -7909,7 +7909,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * if ((event->type == RIGHTMOUSE) && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) && (event->val == KM_PRESS)) { /* RMB has two options now */ - if (ui_popup_context_menu_for_button(C, but)) { + if (ui_popup_context_menu_for_button(C, but, event)) { return WM_UI_HANDLER_BREAK; } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index ab76de8bdba..efc94b89046 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -1191,7 +1191,7 @@ struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen, const struct wmEvent *event); /* interface_context_menu.c */ -bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but); +bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but, const struct wmEvent *event); void ui_popup_context_menu_for_panel(struct bContext *C, struct ARegion *region, struct Panel *panel); diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index f01dca7712c..3105891142f 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -1037,7 +1037,7 @@ static void menu_search_update_fn(const bContext *UNUSED(C), static bool ui_search_menu_create_context_menu(struct bContext *C, void *arg, void *active, - const struct wmEvent *UNUSED(event)) + const struct wmEvent *event) { struct MenuSearch_Data *data = arg; struct MenuSearch_Item *item = active; @@ -1058,7 +1058,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, CTX_wm_region_set(C, item->wm_context->region); } - if (ui_popup_context_menu_for_button(C, but)) { + if (ui_popup_context_menu_for_button(C, but, event)) { has_menu = true; } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index ece6ba986f3..3ce2f326dca 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -112,6 +112,7 @@ const char *screen_context_dir[] = { "selected_editable_fcurves", "active_editable_fcurve", "selected_editable_keyframes", + "ui_list", "asset_library", NULL, }; @@ -1034,6 +1035,15 @@ static eContextResult screen_ctx_asset_library(const bContext *C, bContextDataRe return CTX_RESULT_OK; } +static eContextResult screen_ctx_ui_list(const bContext *C, bContextDataResult *result) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *region = CTX_wm_region(C); + uiList *list = UI_list_find_mouse_over(region, win->eventstate); + CTX_data_pointer_set(result, NULL, &RNA_UIList, list); + return CTX_RESULT_OK; +} + /* Registry of context callback functions. */ typedef eContextResult (*context_callback)(const bContext *C, bContextDataResult *result); @@ -1109,6 +1119,7 @@ static void ensure_ed_screen_context_functions(void) register_context_function("active_editable_fcurve", screen_ctx_active_editable_fcurve); register_context_function("selected_editable_keyframes", screen_ctx_selected_editable_keyframes); register_context_function("asset_library", screen_ctx_asset_library); + register_context_function("ui_list", screen_ctx_ui_list); } /* Entry point for the screen context. */ diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 849bbca16f4..2a076554d03 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -458,6 +458,27 @@ static IDProperty **rna_UIList_idprops(PointerRNA *ptr) return &ui_list->properties; } +static void rna_UIList_list_id_get(PointerRNA *ptr, char *value) +{ + uiList *ui_list = (uiList *)ptr->data; + if (!ui_list->type) { + value[0] = '\0'; + return; + } + + strcpy(value, WM_uilisttype_list_id_get(ui_list->type, ui_list)); +} + +static int rna_UIList_list_id_length(PointerRNA *ptr) +{ + uiList *ui_list = (uiList *)ptr->data; + if (!ui_list->type) { + return 0; + } + + return strlen(WM_uilisttype_list_id_get(ui_list->type, ui_list)); +} + static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, @@ -1535,6 +1556,16 @@ static void rna_def_uilist(BlenderRNA *brna) "script, then bl_idname = \"OBJECT_UL_vgroups\")"); /* Data */ + /* Note that this is the "non-full" list-ID as obtained through #WM_uilisttype_list_id_get(), + * which differs from the (internal) `uiList.list_id`. */ + prop = RNA_def_property(srna, "list_id", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_funcs(prop, "rna_UIList_list_id_get", "rna_UIList_list_id_length", NULL); + RNA_def_property_ui_text(prop, + "List Name", + "Identifier of the list, if any was passed to the \"list_id\" " + "parameter of \"template_list()\""); + prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_uilist_layout_type_items); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 601db427381..c529fef73ef 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -624,6 +624,7 @@ void WM_uilisttype_free(void); void WM_uilisttype_to_full_list_id(const struct uiListType *ult, const char *list_id, char *r_ui_list_id); +const char *WM_uilisttype_list_id_get(const struct uiListType *ult, struct uiList *list); /* wm_menu_type.c */ void WM_menutype_init(void); diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index 434131903fc..6d298ee63f1 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -21,6 +21,7 @@ */ #include <stdio.h> +#include <string.h> #include "BLI_sys_types.h" @@ -109,3 +110,16 @@ void WM_uilisttype_to_full_list_id(const uiListType *ult, /* We tag the list id with the list type... */ BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : ""); } + +/** + * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details. + * + * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()! + */ +const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list) +{ + /* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */ + BLI_assert((list->list_id + strlen(ult->idname))[0] == '_'); + /* +1 to skip the '_' */ + return list->list_id + strlen(ult->idname) + 1; +} |