From effe750ec103d56ff96f12ce64ac977a8ae51909 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Feb 2019 14:29:29 +1100 Subject: WM: support dynamic keymap handlers Add getter callback support for 'WM_HANDLER_TYPE_KEYMAP' type handlers this is needed for key-maps which change based on the active tool. Replaces 'sneaky_handler' hack which temporarily inserted a handler. --- source/blender/editors/include/ED_screen.h | 13 +- source/blender/editors/screen/area.c | 3 + source/blender/editors/space_image/space_image.c | 2 +- source/blender/editors/space_node/space_node.c | 2 +- source/blender/editors/space_view3d/space_view3d.c | 2 +- source/blender/windowmanager/WM_api.h | 8 ++ .../blender/windowmanager/intern/wm_event_system.c | 146 ++++++++++----------- source/blender/windowmanager/intern/wm_keymap.c | 3 +- source/blender/windowmanager/wm_event_system.h | 6 + 9 files changed, 100 insertions(+), 85 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index c20d8e0555f..5d4f0919c44 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -356,12 +356,13 @@ void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *sa); enum { ED_KEYMAP_UI = (1 << 1), ED_KEYMAP_GIZMO = (1 << 2), - ED_KEYMAP_VIEW2D = (1 << 3), - ED_KEYMAP_MARKERS = (1 << 4), - ED_KEYMAP_ANIMATION = (1 << 5), - ED_KEYMAP_FRAMES = (1 << 6), - ED_KEYMAP_HEADER = (1 << 7), - ED_KEYMAP_GPENCIL = (1 << 8), + ED_KEYMAP_TOOL = (1 << 3), + ED_KEYMAP_VIEW2D = (1 << 4), + ED_KEYMAP_MARKERS = (1 << 5), + ED_KEYMAP_ANIMATION = (1 << 6), + ED_KEYMAP_FRAMES = (1 << 7), + ED_KEYMAP_HEADER = (1 << 8), + ED_KEYMAP_GPENCIL = (1 << 9), }; /* SCREEN_OT_space_context_cycle direction */ diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 6df0702b126..32b85b40950 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1474,6 +1474,9 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ARegion *ar, L WM_gizmomap_add_handlers(ar, ar->gizmo_map); } } + if (flag & ED_KEYMAP_TOOL) { + WM_event_add_keymap_handler_dynamic(&ar->handlers, WM_event_get_keymap_from_toolsystem, sa); + } if (flag & ED_KEYMAP_VIEW2D) { /* 2d-viewport handling+manipulation */ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", 0, 0); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 9171b923bad..6ae4eb9767b 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -1028,7 +1028,7 @@ void ED_spacetype_image(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_WINDOW; - art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; + art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_TOOL | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; art->init = image_main_region_init; art->draw = image_main_region_draw; art->listener = image_main_region_listener; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 0c15a6c2a7d..0039fb1e2ab 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -975,7 +975,7 @@ void ED_spacetype_node(void) art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_GIZMO | ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; art->listener = node_region_listener; art->cursor = node_cursor; art->event_cursor = true; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index f312dc971f3..10fadd9aaec 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1473,7 +1473,7 @@ void ED_spacetype_view3d(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; - art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_GPENCIL; + art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_TOOL | ED_KEYMAP_GPENCIL; art->draw = view3d_main_region_draw; art->init = view3d_main_region_init; art->exit = view3d_main_region_exit; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ae4f4cb338c..4b4473da625 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -198,12 +198,20 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_bb( struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority( ListBase *handlers, wmKeyMap *keymap, int priority); +typedef struct wmKeyMap *(wmEventHandler_KeymapDynamicFn)(wmWindowManager *wm, struct wmEventHandler_Keymap *handler) ATTR_WARN_UNUSED_RESULT; + +struct wmKeyMap *WM_event_get_keymap_from_toolsystem(struct wmWindowManager *wm, struct wmEventHandler_Keymap *handler); + +struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( + ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data); + void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap); void WM_event_set_keymap_handler_callback( struct wmEventHandler_Keymap *handler, void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data), void *user_data); +wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, struct wmEventHandler_Keymap *handler); 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 605d4fc24cc..ecc4d369afe 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2378,16 +2378,19 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers /* Handle all types here. */ if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; - wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap); - wmKeyMapItem *kmi; + wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler); PRINT("%s: checking '%s' ...", __func__, keymap->idname); - if (WM_keymap_poll(C, keymap)) { + if (keymap == NULL) { + /* Only callback is allowed to have NULL keymaps. */ + BLI_assert(handler->dynamic.keymap_fn); + } + else if (WM_keymap_poll(C, keymap)) { PRINT("pass\n"); - for (kmi = keymap->items.first; kmi; kmi = kmi->next) { + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (wm_eventmatch(event, kmi)) { struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback; @@ -2903,46 +2906,6 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event) } } -#ifdef USE_WORKSPACE_TOOL -static void wm_event_temp_tool_handler_apply( - bContext *C, ScrArea *sa, ARegion *ar, wmEventHandler_Keymap *sneaky_handler) -{ - if (ar->regiontype == RGN_TYPE_WINDOW) { - bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; - if (tref_rt && tref_rt->keymap[0]) { - wmKeyMap *km = WM_keymap_find_all_spaceid_or_empty( - C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW); - /* We shouldn't use keymaps from unrelated spaces. */ - if (km != NULL) { - // printf("Keymap: '%s' -> '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); - sneaky_handler->head.type = WM_HANDLER_TYPE_KEYMAP; - sneaky_handler->keymap = km; - sneaky_handler->keymap_tool = sa->runtime.tool; - - /* Handle widgets first. */ - wmEventHandler *handler_last = ar->handlers.last; - while (handler_last && handler_last->type != WM_HANDLER_TYPE_GIZMO) { - handler_last = handler_last->prev; - } - /* Head of list or after last gizmo. */ - BLI_insertlinkafter(&ar->handlers, handler_last, sneaky_handler); - } - else { - printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); - } - } - } -} - -static void wm_event_temp_tool_handler_clear( - bContext *UNUSED(C), ScrArea *UNUSED(sa), ARegion *ar, wmEventHandler_Keymap *sneaky_handler) -{ - if (sneaky_handler->keymap) { - BLI_remlink(&ar->handlers, sneaky_handler); - } -} -#endif /* USE_WORKSPACE_TOOL */ - /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -3115,27 +3078,8 @@ void wm_event_do_handlers(bContext *C) } } -#ifdef USE_WORKSPACE_TOOL - /* How to solve properly? - * - * Handlers are stored in each region, - * however the tool-system swaps keymaps often and isn't stored - * per region. - * - * Need to investigate how this could be done better. - * We might need to add a more dynamic handler type that uses a callback - * to fetch its current keymap. - */ - wmEventHandler_Keymap sneaky_handler = {NULL}; - wm_event_temp_tool_handler_apply(C, sa, ar, &sneaky_handler); -#endif /* USE_WORKSPACE_TOOL */ - action |= wm_handlers_do(C, event, &ar->handlers); -#ifdef USE_WORKSPACE_TOOL - wm_event_temp_tool_handler_clear(C, sa, ar, &sneaky_handler); -#endif /* USE_WORKSPACE_TOOL */ - /* fileread case (python), [#29489] */ if (CTX_wm_window(C) == NULL) return; @@ -3394,6 +3338,56 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap return handler; } +/** Follow #wmEventHandler_KeymapDynamicFn signiture. */ +wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandler_Keymap *handler) +{ + ScrArea *sa = handler->dynamic.user_data; + handler->keymap_tool = NULL; + bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; + if (tref_rt && tref_rt->keymap[0]) { + wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( + &wm->userconf->keymaps, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW); + /* We shouldn't use keymaps from unrelated spaces. */ + if (km != NULL) { + handler->keymap_tool = sa->runtime.tool; + return km; + } + else { + printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); + } + } + return NULL; +} + +struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( + ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data) +{ + if (!keymap_fn) { + CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn"); + return NULL; + } + + /* only allow same keymap once */ + LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) { + if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { + wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; + if (handler->dynamic.keymap_fn == keymap_fn) { + /* Maximizing the view needs to update the area. */ + handler->dynamic.user_data = user_data; + return handler; + } + } + } + + wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__); + handler->head.type = WM_HANDLER_TYPE_KEYMAP; + BLI_addtail(handlers, handler); + handler->dynamic.keymap_fn = keymap_fn; + handler->dynamic.user_data = user_data; + + return handler; +} + /* priorities not implemented yet, for time being just insert in begin of list */ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority)) { @@ -4471,6 +4465,19 @@ bool WM_event_is_ime_switch(const struct wmEvent *event) /** \} */ +wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_Keymap *handler) +{ + wmKeyMap *keymap; + if (handler->dynamic.keymap_fn != NULL) { + keymap = handler->dynamic.keymap_fn(wm, handler); + BLI_assert(handler->keymap == NULL); + } + else { + keymap = WM_keymap_active(wm, handler->keymap); + BLI_assert(keymap != NULL); + } + return keymap; +} static wmKeyMapItem *wm_kmi_from_event( bContext *C, wmWindowManager *wm, @@ -4484,8 +4491,8 @@ static wmKeyMapItem *wm_kmi_from_event( else if (handler_boundbox_test(handler_base, event)) { /* optional boundbox */ if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; - wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap); - if (WM_keymap_poll(C, keymap)) { + wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler); + if (keymap && WM_keymap_poll(C, keymap)) { for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (wm_eventmatch(event, kmi)) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); @@ -4688,11 +4695,6 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) CTX_wm_area_set(C, sa); CTX_wm_region_set(C, ar); -#ifdef USE_WORKSPACE_TOOL - wmEventHandler_Keymap sneaky_handler = {NULL}; - wm_event_temp_tool_handler_apply(C, sa, ar, &sneaky_handler); -#endif - ListBase *handlers[] = { &ar->handlers, &sa->handlers, @@ -4723,10 +4725,6 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) } } -#ifdef USE_WORKSPACE_TOOL - wm_event_temp_tool_handler_clear(C, sa, ar, &sneaky_handler); -#endif - if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) { ED_area_tag_redraw(sa_statusbar); } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index c522378ae32..16e4913a206 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1226,13 +1226,12 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( wmKeyMap **r_keymap) { wmWindowManager *wm = CTX_wm_manager(C); - wmKeyMap *keymap; /* find keymap item in handlers */ LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) { if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; - keymap = WM_keymap_active(wm, handler->keymap); + wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler); if (keymap && WM_keymap_poll((bContext *)C, keymap)) { wmKeyMapItem *kmi = wm_keymap_item_find_in_keymap( keymap, opname, properties, is_strict, params); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index ab59f52f125..cd7a5102809 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -68,6 +68,12 @@ typedef struct wmEventHandler_Keymap { /** Run after the keymap item runs. */ struct wmEventHandler_KeymapFn keymap_callback; + /** Support for a getter function that looks up the keymap each access. */ + struct { + wmEventHandler_KeymapDynamicFn *keymap_fn; + void *user_data; + } dynamic; + struct bToolRef *keymap_tool; } wmEventHandler_Keymap; -- cgit v1.2.3