From e7895bac07f32d4f66184aff2ed2c08956daaac7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 20 May 2018 22:34:18 +0200 Subject: [PATCH] UI: support for custom keymaps for popovers --- release/scripts/modules/bpy_types.py | 4 +- source/blender/editors/include/UI_interface.h | 5 ++- .../interface/interface_region_popover.c | 37 +++++++++++++++++-- source/blender/makesrna/intern/rna_wm_api.c | 5 ++- source/blender/windowmanager/WM_api.h | 5 +++ .../windowmanager/intern/wm_event_system.c | 12 ++++++ .../blender/windowmanager/intern/wm_keymap.c | 8 +++- .../blender/windowmanager/wm_event_system.h | 3 ++ 8 files changed, 68 insertions(+), 11 deletions(-) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 04bb6495ece..3a9704b12e9 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -144,14 +144,14 @@ class WindowManager(bpy_types.ID): finally: self.popmenu_end__internal(popup) - def popover(self, draw_func): + def popover(self, draw_func, keymap=None): import bpy popup = self.popover_begin__internal() try: draw_func(popup, bpy.context) finally: - self.popover_end__internal(popup) + self.popover_end__internal(popup, keymap) def popup_menu_pie(self, event, draw_func, title="", icon='NONE'): import bpy diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 417aca1210e..47ecbca227b 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -74,6 +74,7 @@ struct wmDrag; struct wmEvent; struct wmManipulator; struct wmMsgBus; +struct wmKeyMap; typedef struct uiBut uiBut; typedef struct uiBlock uiBlock; @@ -427,8 +428,8 @@ void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *b typedef struct uiPopover uiPopover; -uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL(); -void UI_popover_end(struct bContext *C, struct uiPopover *head); +uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL(1); +void UI_popover_end(struct bContext *C, struct uiPopover *head, struct wmKeyMap *keymap); struct uiLayout *UI_popover_layout(uiPopover *head); void UI_popover_once_clear(uiPopover *pup); diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 2f654b4f7cd..4aeb9a6d00b 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -77,6 +77,11 @@ struct uiPopover { uiLayout *layout; uiBut *but; + /* Needed for keymap removal. */ + wmWindow *window; + wmKeyMap *keymap; + struct wmEventHandler *keymap_handler; + uiMenuCreateFunc menu_func; void *menu_arg; @@ -204,6 +209,10 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup) { uiPopover *pup = arg_pup; + if (pup->keymap != NULL) { + wmWindow *window = pup->window; + WM_event_remove_keymap_handler(&window->modalhandlers, pup->keymap); + } MEM_freeN(pup); } @@ -261,22 +270,44 @@ uiPopover *UI_popover_begin(bContext *C) return pup; } -/* set the whole structure to work */ -void UI_popover_end(bContext *C, uiPopover *pup) +static void popover_keymap_fn(wmKeyMap *UNUSED(keymap), wmKeyMapItem *UNUSEDF(kmi), void *user_data) { + uiPopover *pup = user_data; + pup->block->handle->menuretval = UI_RETURN_OK; +} + +/* set the whole structure to work */ +void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap) +{ + wmWindow *window = CTX_wm_window(C); /* Create popup block. No refresh support since the buttons were created * between begin/end and we have no callback to recreate them. */ uiPopupBlockHandle *handle; + if (keymap) { + /* Add so we get keymaps shown in the buttons. */ + UI_block_flag_enable(pup->block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS); + pup->keymap = keymap; + pup->keymap_handler = WM_event_add_keymap_handler_priority(&window->modalhandlers, keymap, 0); + WM_event_set_keymap_handler_callback(pup->keymap_handler, popover_keymap_fn, pup); + } + handle = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPOVER, pup); handle->popup_create_vars.free_func = ui_block_free_func_POPOVER; /* Add handlers. */ - wmWindow *window = CTX_wm_window(C); UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); WM_event_add_mousemove(C); handle->popup = true; + /* Re-add so it gets priority. */ + if (keymap) { + BLI_remlink(&window->modalhandlers, pup->keymap_handler); + BLI_addhead(&window->modalhandlers, pup->keymap_handler); + } + + pup->window = window; + /* TODO(campbell): we may want to make this configurable. * The begin/end stype of calling popups doesn't allow to 'can_refresh' to be set. * For now close this style of popvers when accessed. */ diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index a08a1846c5b..dc9c0223f6b 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -361,9 +361,9 @@ static PointerRNA rna_PopoverBegin(bContext *C) return r_ptr; } -static void rna_PopoverEnd(bContext *C, PointerRNA *handle) +static void rna_PopoverEnd(bContext *C, PointerRNA *handle, wmKeyMap *keymap) { - UI_popover_end(C, handle->data); + UI_popover_end(C, handle->data, keymap); } /* pie menu wrapper */ @@ -585,6 +585,7 @@ void RNA_api_wm(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "menu", "UIPopover", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); + RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Active key map"); /* wrap uiPieMenuBegin */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e6b045bc249..050edb980e9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -191,6 +191,11 @@ struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers, void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap); +void WM_event_set_keymap_handler_callback( + struct wmEventHandler *handler, + void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data), + void *user_data); + typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata); typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index d38416e490d..46ea5bc137e 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2262,6 +2262,9 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers if (action & WM_HANDLER_BREAK) { /* not always_pass here, it denotes removed handler */ CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname); + if (handler->keymap_callback != NULL) { + handler->keymap_callback(keymap, kmi, handler->keymap_callback_user_data); + } break; } else { @@ -3166,6 +3169,15 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) } } +void WM_event_set_keymap_handler_callback( + wmEventHandler *handler, + void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data), + void *user_data) +{ + handler->keymap_callback = keymap_tag; + handler->keymap_callback_user_data = user_data; +} + wmEventHandler *WM_event_add_ui_handler( const bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 63f81ca66c9..9d26c7e92d5 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1214,8 +1214,12 @@ static wmKeyMapItem *wm_keymap_item_find_props( wmKeyMapItem *found = NULL; /* look into multiple handler lists to find the item */ - if (win) - found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); + if (win) { + found = wm_keymap_item_find_handlers(C, &win->modalhandlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); + if (found == NULL) { + found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); + } + } if (sa && found == NULL) found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index c14517f1662..452fe377665 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -51,6 +51,9 @@ typedef struct wmEventHandler { /* keymap handler */ wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ const rcti *bblocal, *bbwin; /* optional local and windowspace bb */ + /* Run after the keymap item runs. */ + void (*keymap_callback)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data); + void *keymap_callback_user_data; /* modal operator handler */ wmOperator *op; /* for derived/modal handlers */