From 571aead323dd4cb84d2a39894172c119d6dfbab5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 4 Sep 2018 17:57:59 +1000 Subject: UI: support immediate non-overlapping tooltips Use these for the toolbar, since they're non-overlapping the interface, showing them quickly isn't a problem. --- source/blender/editors/include/UI_interface.h | 3 + .../blender/editors/interface/interface_handlers.c | 3 +- source/blender/editors/interface/interface_query.c | 8 ++ .../editors/interface/interface_region_tooltip.c | 135 ++++++++++++++++++--- source/blender/windowmanager/WM_api.h | 2 +- .../blender/windowmanager/intern/wm_event_system.c | 2 +- source/blender/windowmanager/intern/wm_tooltip.c | 5 +- 7 files changed, 135 insertions(+), 23 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index e739308bd1e..51cff1c9440 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -407,6 +407,7 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1); /* interface_query.c */ +bool UI_but_is_tooltip_no_overlap(const uiBut *but); bool UI_but_is_tool(const uiBut *but); #define UI_but_is_decorator(but) \ ((but)->func == ui_but_anim_decorate_cb) @@ -1281,6 +1282,8 @@ 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 +/* For cases when the tooltips don't overlap, use an 'instant' tip. */ +#define UI_TOOLTIP_DELAY_QUICK 0.05 /* Float precision helpers */ #define UI_PRECISION_FLOAT_MAX 6 diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a1e3117e3a5..8805907b337 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -7066,7 +7066,8 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but) if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) { if (!but->block->tooltipdisabled) { if (!wm->drags.first) { - WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init); + bool quick = UI_but_is_tooltip_no_overlap(but); + WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init, quick); } } } diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index d0f7e1341de..ba4fdf43875 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -96,6 +96,14 @@ bool UI_but_is_tool(const uiBut *but) return false; } +bool UI_but_is_tooltip_no_overlap(const uiBut *but) +{ + if (!ui_block_is_popover(but->block)) { + return UI_but_is_tool(but); + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 6f4e48a9793..ae98798dd7b 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -962,7 +962,7 @@ static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) static ARegion *ui_tooltip_create_with_data( bContext *C, uiTooltipData *data, - const float init_position[2], + const float init_position[2], const rcti *init_rect_overlap, const float aspect) { const float pad_px = UI_TIP_PADDING; @@ -1066,19 +1066,98 @@ static ARegion *ui_tooltip_create_with_data( #undef TIP_BORDER_X #undef TIP_BORDER_Y + /* Clamp to window bounds. */ { /* Ensure at least 5 px above screen bounds * UI_UNIT_Y is just a guess to be above the menu item */ - const int pad = max_ff(1.0f, U.pixelsize) * 5; - const rcti rect_clamp = { - .xmin = pad, - .xmax = winx - pad, - .ymin = pad + (UI_UNIT_Y * 2), - .ymax = winy - pad, - }; - int offset_dummy[2]; - BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy); + if (init_rect_overlap != NULL) { + const int pad = max_ff(1.0f, U.pixelsize) * 5; + const rcti init_rect = { + .xmin = init_rect_overlap->xmin - pad, + .xmax = init_rect_overlap->xmax + pad, + .ymin = init_rect_overlap->ymin - pad, + .ymax = init_rect_overlap->ymax + pad, + }; + const rcti rect_clamp = { + .xmin = 0, + .xmax = winx, + .ymin = 0, + .ymax = winy, + }; + /* try right. */ + const int size_x = BLI_rcti_size_x(&rect_i); + const int size_y = BLI_rcti_size_y(&rect_i); + const int cent_overlap_x = BLI_rcti_cent_x(&init_rect); + const int cent_overlap_y = BLI_rcti_cent_y(&init_rect); + struct { + rcti xpos; + rcti xneg; + rcti ypos; + rcti yneg; + } rect; + + { /* xpos */ + rcti r = rect_i; + r.xmin = init_rect.xmax; + r.xmax = r.xmin + size_x; + r.ymin = cent_overlap_y - (size_y / 2); + r.ymax = r.ymin + size_y; + rect.xpos = r; + } + { /* xneg */ + rcti r = rect_i; + r.xmin = init_rect.xmin - size_x; + r.xmax = r.xmin + size_x; + r.ymin = cent_overlap_y - (size_y / 2); + r.ymax = r.ymin + size_y; + rect.xneg = r; + } + { /* ypos */ + rcti r = rect_i; + r.xmin = cent_overlap_x - (size_x / 2); + r.xmax = r.xmin + size_x; + r.ymin = init_rect.ymax; + r.ymax = r.ymin + size_y; + rect.ypos = r; + } + { /* yneg */ + rcti r = rect_i; + r.xmin = cent_overlap_x - (size_x / 2); + r.xmax = r.xmin + size_x; + r.ymin = init_rect.ymin - size_y; + r.ymax = r.ymin + size_y; + rect.yneg = r; + } + + bool found = false; + for (int j = 0; j < 4; j++) { + const rcti *r = (&rect.xpos) + j; + if (BLI_rcti_inside_rcti(&rect_clamp, r)) { + rect_i = *r; + found = true; + break; + } + } + if (!found) { + /* Fallback, we could pick the best fallback, for now just use xpos. */ + int offset_dummy[2]; + rect_i = rect.xpos; + BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy); + } + + } + else { + const int pad = max_ff(1.0f, U.pixelsize) * 5; + const rcti rect_clamp = { + .xmin = pad, + .xmax = winx - pad, + .ymin = pad + (UI_UNIT_Y * 2), + .ymax = winy - pad, + }; + int offset_dummy[2]; + BLI_rcti_clamp(&rect_i, &rect_clamp, offset_dummy); + } } /* add padding */ @@ -1088,7 +1167,9 @@ static ARegion *ui_tooltip_create_with_data( /* widget rect, in region coords */ { + /* Compensate for margin offset, visually this corrects the position. */ const int margin = UI_POPUP_MARGIN; + BLI_rcti_translate(&rect_i, margin, margin / 2); data->bbox.xmin = margin; data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin; @@ -1142,15 +1223,33 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b return NULL; } - init_position[0] = BLI_rctf_cent_x(&but->rect); - init_position[1] = but->rect.ymin; - - if (butregion) { - ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); - init_position[0] = win->eventstate->x; + const bool is_no_overlap = UI_but_is_tooltip_no_overlap(but); + rcti init_rect; + if (is_no_overlap) { + rctf overlap_rect_fl; + init_position[0] = BLI_rctf_cent_x(&but->rect); + init_position[1] = BLI_rctf_cent_y(&but->rect); + if (butregion) { + ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); + ui_block_to_window_rctf(butregion, but->block, &overlap_rect_fl, &but->rect); + } + else { + overlap_rect_fl = but->rect; + } + BLI_rcti_rctf_copy_round(&init_rect, &overlap_rect_fl); + } + else { + init_position[0] = BLI_rctf_cent_x(&but->rect); + init_position[1] = but->rect.ymin - (UI_POPUP_MARGIN / 2); + if (butregion) { + ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]); + init_position[0] = win->eventstate->x; + } } - return ui_tooltip_create_with_data(C, data, init_position, aspect); + ARegion *ar = ui_tooltip_create_with_data(C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect); + + return ar; } ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) @@ -1167,7 +1266,7 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) init_position[0] = win->eventstate->x; init_position[1] = win->eventstate->y; - return ui_tooltip_create_with_data(C, data, init_position, aspect); + return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); } void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 66e3a77a66a..36f030e4eac 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -628,7 +628,7 @@ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, void WM_tooltip_timer_init( struct bContext *C, struct wmWindow *win, struct ARegion *ar, - wmTooltipInitFn init); + wmTooltipInitFn init, bool quick); 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); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index cd1357e85b1..f074c083b31 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2422,7 +2422,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers int part; gz = wm_gizmomap_highlight_find(gzmap, C, event, &part); if (wm_gizmomap_highlight_set(gzmap, C, gz, part) && gz != NULL) { - WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_gizmomap_tooltip_init); + WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_gizmomap_tooltip_init, false); } } else { diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c index 94a44a97afd..0953351de2b 100644 --- a/source/blender/windowmanager/intern/wm_tooltip.c +++ b/source/blender/windowmanager/intern/wm_tooltip.c @@ -39,7 +39,7 @@ void WM_tooltip_timer_init( bContext *C, wmWindow *win, ARegion *ar, - wmTooltipInitFn init) + wmTooltipInitFn init, bool quick) { WM_tooltip_timer_clear(C, win); @@ -49,7 +49,8 @@ void WM_tooltip_timer_init( 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->timer = WM_event_add_timer( + wm, win, TIMER, quick ? UI_TOOLTIP_DELAY_QUICK : UI_TOOLTIP_DELAY); screen->tool_tip->init = init; } -- cgit v1.2.3