UI: Tooltip for data-block selector menus, showing full name and library info

Long data-block names are clipped to fit into data-block selector menus. For
linked data-blocks, there's also a hint indicating the source library, which
takes further space and may get clipped too.

So this commit adds a tooltip to the menu items, which displays the full,
unclipped data-block name and the unclipped library name. Plus, the library
path is shown too, which is also useful info.

Adds helper functions for search menu item tooltips, so these are easier to add
to other search menus in future.

Part of T84188.
This commit is contained in:
Julian Eisel 2021-01-26 22:06:45 +01:00
parent 656f6ae643
commit d096d9c4d6
6 changed files with 137 additions and 2 deletions

View File

@ -508,6 +508,7 @@ typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
const struct wmEvent *event);
typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C,
struct ARegion *region,
const struct rcti *item_rect,
void *arg,
void *active);
@ -2485,6 +2486,7 @@ uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct r
uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region,
const int xy[2],
bool only_clip);
struct ARegion *UI_region_searchbox_region_get(const struct ARegion *button_region);
/* uiFontStyle.align */
typedef enum eFontStyle_Align {
@ -2564,6 +2566,21 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
typedef struct {
/** A description for the item, e.g. what happens when selecting it. */
char description[UI_MAX_DRAW_STR];
/* The full name of the item, without prefixes or suffixes (e.g. hint with UI_SEP_CHARP). */
const char *name;
/** Additional info about the item (e.g. library name of a linked data-block). */
char hint[UI_MAX_DRAW_STR];
} uiSearchItemTooltipData;
struct ARegion *UI_tooltip_create_from_search_item_generic(
struct bContext *C,
const struct ARegion *searchbox_region,
const struct rcti *item_rect,
const uiSearchItemTooltipData *item_tooltip_data);
/* How long before a tool-tip shows. */
#define UI_TOOLTIP_DELAY 0.5
#define UI_TOOLTIP_DELAY_LABEL 0.2

View File

@ -8481,6 +8481,15 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
return NULL;
}
/**
* Try to find a search-box region opened from a button in \a button_region.
*/
ARegion *UI_region_searchbox_region_get(const ARegion *button_region)
{
uiBut *but = UI_region_active_but_get(button_region);
return (but != NULL) ? but->active->searchbox : NULL;
}
/* helper function for insert keyframe, reset to default, etc operators */
void UI_context_update_anim_flag(const bContext *C)
{

View File

@ -347,9 +347,20 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
}
uiButSearch *search_but = (uiButSearch *)but;
if (search_but->item_tooltip_fn) {
return search_but->item_tooltip_fn(C, region, search_but->arg, search_but->item_active);
if (!search_but->item_tooltip_fn) {
continue;
}
ARegion *searchbox_region = UI_region_searchbox_region_get(region);
uiSearchboxData *data = searchbox_region->regiondata;
BLI_assert(data->items.pointers[data->active] == search_but->item_active);
rcti rect;
ui_searchbox_butrect(&rect, data, data->active);
return search_but->item_tooltip_fn(
C, region, &rect, search_but->arg, search_but->item_active);
}
}
return NULL;

View File

@ -1477,6 +1477,74 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
const uiSearchItemTooltipData *item_tooltip_data)
{
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
if (item_tooltip_data->description[0]) {
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
.style = UI_TIP_STYLE_HEADER,
.color_id = UI_TIP_LC_NORMAL,
.is_pad = true,
});
field->text = BLI_strdup(item_tooltip_data->description);
}
if (item_tooltip_data->name && item_tooltip_data->name[0]) {
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
.style = UI_TIP_STYLE_NORMAL,
.color_id = UI_TIP_LC_VALUE,
.is_pad = true,
});
field->text = BLI_strdup(item_tooltip_data->name);
}
if (item_tooltip_data->hint[0]) {
uiTooltipField *field = text_field_add(data,
&(uiTooltipFormat){
.style = UI_TIP_STYLE_NORMAL,
.color_id = UI_TIP_LC_NORMAL,
.is_pad = true,
});
field->text = BLI_strdup(item_tooltip_data->hint);
}
if (data->fields_len == 0) {
MEM_freeN(data);
return NULL;
}
return data;
}
/**
* Create a tooltip from search-item tooltip data \a item_tooltip data.
* To be called from a callback set with #UI_but_func_search_set_tooltip().
*
* \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
* which is passed to the tooltip callback.
*/
ARegion *UI_tooltip_create_from_search_item_generic(
bContext *C,
const ARegion *searchbox_region,
const rcti *item_rect,
const uiSearchItemTooltipData *item_tooltip_data)
{
uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data);
if (data == NULL) {
return NULL;
}
const float aspect = 1.0f;
const wmWindow *win = CTX_wm_window(C);
float init_position[2];
init_position[0] = win->eventstate->x;
init_position[1] = item_rect->ymin + searchbox_region->winrct.ymin - (UI_POPUP_MARGIN / 2);
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
{
ui_region_temp_remove(C, screen, region);

View File

@ -1069,6 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
struct ARegion *region,
const rcti *UNUSED(item_rect),
void *arg,
void *active)
{

View File

@ -208,6 +208,7 @@ static uiBlock *template_common_search_menu(const bContext *C,
void *search_arg,
uiButHandleFunc search_exec_fn,
void *active_item,
uiButSearchTooltipFn item_tooltip_fn,
const int preview_rows,
const int preview_cols,
float scale)
@ -284,6 +285,7 @@ static uiBlock *template_common_search_menu(const bContext *C,
NULL,
search_exec_fn,
active_item);
UI_but_func_search_set_tooltip(but, item_tooltip_fn);
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
@ -485,6 +487,31 @@ static void id_search_cb_objects_from_scene(const bContext *C,
id_search_cb_tagged(C, arg_template, str, items);
}
static ARegion *template_ID_search_menu_item_tooltip(
bContext *C, ARegion *region, const rcti *item_rect, void *arg, void *active)
{
TemplateID *template_ui = arg;
ID *active_id = active;
StructRNA *type = RNA_property_pointer_type(&template_ui->ptr, template_ui->prop);
uiSearchItemTooltipData tooltip_data = {0};
tooltip_data.name = active_id->name + 2;
BLI_snprintf(tooltip_data.description,
sizeof(tooltip_data.description),
TIP_("Choose %s data-block to be assigned to this user"),
RNA_struct_ui_name(type));
if (ID_IS_LINKED(active_id)) {
BLI_snprintf(tooltip_data.hint,
sizeof(tooltip_data.hint),
TIP_("Source library: %s\n%s"),
active_id->lib->id.name + 2,
active_id->lib->filepath);
}
return UI_tooltip_create_from_search_item_generic(C, region, item_rect, &tooltip_data);
}
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
{
@ -512,6 +539,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
&template_ui,
template_ID_set_property_exec_fn,
active_item_ptr.data,
template_ID_search_menu_item_tooltip,
template_ui.prv_rows,
template_ui.prv_cols,
template_ui.scale);
@ -1632,6 +1660,7 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem
&template_search,
template_search_exec_fn,
active_ptr.data,
NULL,
template_search.preview_rows,
template_search.preview_cols,
1.0f);