From 693b41eb17557ba12e7c64c5ba589c499ff45c4d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 25 Jan 2018 16:17:25 +1100 Subject: UI: change tool-tips to be stored in the screen Move timer and tip out of button code, now the only requests a tooltip, passing a creation callback to run. Needed for manipulators in 2.8, also helps de-duplicate logic - since we never want multiple tool-tips showing at once. --- source/blender/blenkernel/intern/screen.c | 3 + source/blender/blenloader/intern/readfile.c | 1 + source/blender/editors/include/UI_interface.h | 4 +- .../blender/editors/interface/interface_handlers.c | 70 ++++++-------- .../editors/interface/interface_region_tooltip.c | 4 +- source/blender/makesdna/DNA_screen_types.h | 3 + source/blender/windowmanager/CMakeLists.txt | 1 + source/blender/windowmanager/WM_api.h | 11 +++ source/blender/windowmanager/WM_types.h | 9 ++ .../blender/windowmanager/intern/wm_event_system.c | 19 +++- source/blender/windowmanager/intern/wm_tooltip.c | 106 +++++++++++++++++++++ 11 files changed, 187 insertions(+), 44 deletions(-) create mode 100644 source/blender/windowmanager/intern/wm_tooltip.c (limited to 'source') diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index df47b89fadc..78caf1fe1f3 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -381,6 +381,9 @@ void BKE_screen_free(bScreen *sc) BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); + + /* Region and timer are freed by the window manager. */ + MEM_SAFE_FREE(sc->tool_tip); } /* for depsgraph */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 775eafb8fe2..4c1beb78bbf 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6410,6 +6410,7 @@ static void lib_link_screen(FileData *fd, Main *main) sc->scene = main->scene.first; sc->animtimer = NULL; /* saved in rare cases */ + sc->tool_tip = NULL; sc->scrubbing = false; for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index c07fa2913b6..d6c6f0a2eb6 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1081,6 +1081,8 @@ void UI_context_active_but_prop_get_templateID( struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); +uiBut *UI_region_active_but_get(struct ARegion *ar); + /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex( @@ -1124,7 +1126,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p); /* ui_interface_region_tooltip.c */ struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but); -void UI_tooltip_free(struct bContext *C, struct ARegion *ar); +void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar); /* How long before a tool-tip shows. */ #define UI_TOOLTIP_DELAY 0.5 diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e6b91233f4a..2f7359da308 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -295,8 +295,6 @@ typedef struct uiHandleButtonData { ColorBand *coba; /* tooltip */ - ARegion *tooltip; - wmTimer *tooltiptimer; unsigned int tooltip_force : 1; /* auto open */ @@ -7652,12 +7650,12 @@ static bool button_modal_state(uiHandleButtonState state) */ void UI_but_tooltip_refresh(bContext *C, uiBut *but) { - uiHandleButtonData *data; - - data = but->active; - if (data && data->tooltip) { - UI_tooltip_free(C, data->tooltip); - data->tooltip = UI_tooltip_create_from_button(C, data->region, but); + uiHandleButtonData *data = but->active; + if (data) { + bScreen *sc = data->window->screen; + if (sc->tool_tip && sc->tool_tip->region) { + WM_tooltip_refresh(C, data->window); + } } } @@ -7668,39 +7666,36 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but) data = but->active; if (data) { - - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } - if (data->tooltip) { - UI_tooltip_free(C, data->tooltip); - data->tooltip = NULL; - } - if (data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; } + + WM_tooltip_clear(C, data->window); } } +static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event) +{ + uiBut *but = UI_region_active_but_get(ar); + *r_exit_on_event = false; + if (but) { + return UI_tooltip_create_from_button(C, ar, but); + } + return NULL; +} + static void button_tooltip_timer_reset(bContext *C, uiBut *but) { wmWindowManager *wm = CTX_wm_manager(C); - uiHandleButtonData *data; - - data = but->active; + uiHandleButtonData *data = but->active; - if (data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - } + WM_tooltip_timer_clear(C, data->window); if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, UI_TOOLTIP_DELAY); + WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init); } } } @@ -8060,12 +8055,10 @@ void ui_but_active_free(const bContext *C, uiBut *but) } /* returns the active button with an optional checking function */ -static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *)) +static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *)) { uiBut *but_found = NULL; - ARegion *ar = CTX_wm_region(C); - while (ar) { uiBlock *block; uiBut *but, *activebut = NULL; @@ -8108,12 +8101,17 @@ static bool ui_context_rna_button_active_test(uiBut *but) } static uiBut *ui_context_rna_button_active(const bContext *C) { - return ui_context_button_active(C, ui_context_rna_button_active_test); + return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); } uiBut *UI_context_active_but_get(const struct bContext *C) { - return ui_context_button_active(C, NULL); + return ui_context_button_active(CTX_wm_region(C), NULL); +} + +uiBut *UI_region_active_but_get(ARegion *ar) +{ + return ui_context_button_active(ar, NULL); } /** @@ -8395,16 +8393,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) } case TIMER: { - /* handle tooltip timer */ - if (event->customdata == data->tooltiptimer) { - WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); - data->tooltiptimer = NULL; - - if (!data->tooltip) - data->tooltip = UI_tooltip_create_from_button(C, data->region, but); - } /* handle menu auto open timer */ - else if (event->customdata == data->autoopentimer) { + if (event->customdata == data->autoopentimer) { WM_event_remove_timer(data->wm, data->window, data->autoopentimer); data->autoopentimer = NULL; diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index bc271d0a9fe..1eec3737215 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -756,9 +756,9 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b return ui_tooltip_create_with_data(C, data, init_position, aspect); } -void UI_tooltip_free(bContext *C, ARegion *ar) +void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) { - ui_region_temp_remove(C, CTX_wm_screen(C), ar); + ui_region_temp_remove(C, sc, ar); } /** \} */ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index a33aad4f343..a7718883438 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -44,6 +44,7 @@ struct PanelType; struct Scene; struct uiLayout; struct wmTimer; +struct wmTooltipState; typedef struct bScreen { ID id; @@ -76,6 +77,8 @@ typedef struct bScreen { struct wmTimer *animtimer; /* if set, screen has timer handler added in window */ void *context; /* context callback */ + + struct wmTooltipState *tool_tip; /* runtime */ } bScreen; typedef struct ScrVert { diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index a8b3c994d24..c9278822b9a 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -67,6 +67,7 @@ set(SRC intern/wm_operator_props.c intern/wm_operators.c intern/wm_subwindow.c + intern/wm_tooltip.c intern/wm_window.c intern/wm_stereo.c diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e84239f1c67..965eb2b258a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -536,6 +536,17 @@ bool WM_event_is_tablet(const struct wmEvent *event); bool WM_event_is_ime_switch(const struct wmEvent *event); #endif +/* wm_tooltip.c */ +typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *); + +void WM_tooltip_timer_init( + struct bContext *C, struct wmWindow *win, struct ARegion *ar, + wmTooltipInitFn init); +void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_clear(struct bContext *C, struct wmWindow *win); +void WM_tooltip_init(struct bContext *C, struct wmWindow *win); +void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win); + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index cd78a519dbf..ded96619a88 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -690,6 +690,15 @@ typedef struct wmDropBox { } wmDropBox; +typedef struct wmTooltipState { + struct wmTimer *timer; + struct ARegion *region_from; + struct ARegion *region; + struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event); + /* Exit on any event, not needed for buttons since their highlight state is used. */ + bool exit_on_event; +} wmTooltipState; + /* *************** migrated stuff, clean later? ************** */ typedef struct RecentFile { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 61c144a63d4..d36702b4df7 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2474,6 +2474,13 @@ void wm_event_do_handlers(bContext *C) CTX_wm_window_set(C, win); + /* Clear tool-tip on mouse move. */ + if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) { + if (ISMOUSE(event->type)) { + WM_tooltip_clear(C, win); + } + } + /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ CTX_wm_area_set(C, area_event_inside(C, &event->x)); CTX_wm_region_set(C, region_event_inside(C, &event->x)); @@ -2490,7 +2497,17 @@ void wm_event_do_handlers(bContext *C) /* fileread case */ if (CTX_wm_window(C) == NULL) return; - + + /* check for a tooltip */ + { + bScreen *screen = CTX_wm_window(C)->screen; + if (screen->tool_tip && screen->tool_tip->timer) { + if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) { + WM_tooltip_init(C, win); + } + } + } + /* check dragging, creates new event or frees, adds draw tag */ wm_event_drag_test(wm, win, event); diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c new file mode 100644 index 00000000000..86ca95ef377 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_tooltip.c @@ -0,0 +1,106 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_tooltip.c + * \ingroup wm + * + * Manages a per-window tool-tip. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +void WM_tooltip_timer_init( + bContext *C, wmWindow *win, ARegion *ar, + wmTooltipInitFn init) +{ + bScreen *screen = win->screen; + wmWindowManager *wm = CTX_wm_manager(C); + if (screen->tool_tip == NULL) { + screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__); + } + screen->tool_tip->region_from = ar; + screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY); + screen->tool_tip->init = init; +} + +void WM_tooltip_timer_clear(bContext *C, wmWindow *win) +{ + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = win->screen; + if (screen->tool_tip != NULL) { + if (screen->tool_tip->timer != NULL) { + WM_event_remove_timer(wm, win, screen->tool_tip->timer); + screen->tool_tip->timer = NULL; + } + } +} + +void WM_tooltip_clear(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = win->screen; + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + MEM_freeN(screen->tool_tip); + screen->tool_tip = NULL; + } +} + +void WM_tooltip_init(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = win->screen; + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + screen->tool_tip->region = screen->tool_tip->init( + C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event); + if (screen->tool_tip->region == NULL) { + WM_tooltip_clear(C, win); + } +} + +void WM_tooltip_refresh(bContext *C, wmWindow *win) +{ + WM_tooltip_timer_clear(C, win); + bScreen *screen = win->screen; + if (screen->tool_tip != NULL) { + if (screen->tool_tip->region) { + UI_tooltip_free(C, screen, screen->tool_tip->region); + screen->tool_tip->region = NULL; + } + WM_tooltip_init(C, win); + } +} -- cgit v1.2.3