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.
This commit is contained in:
Campbell Barton 2018-09-04 17:57:59 +10:00
parent e913e79fb5
commit 571aead323
7 changed files with 135 additions and 23 deletions

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -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)

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}