diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/interface/interface_region_tooltip.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/interface/interface_region_tooltip.c')
-rw-r--r-- | source/blender/editors/interface/interface_region_tooltip.c | 2257 |
1 files changed, 1129 insertions, 1128 deletions
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 4bde694b5da..c8029a2b21a 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -55,7 +55,6 @@ #include "RNA_access.h" - #include "UI_interface.h" #include "BLF_api.h" @@ -70,46 +69,45 @@ #include "interface_intern.h" #include "interface_regions_intern.h" -#define UI_TIP_PAD_FAC 1.3f -#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) -#define UI_TIP_MAXWIDTH 600 - +#define UI_TIP_PAD_FAC 1.3f +#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) +#define UI_TIP_MAXWIDTH 600 typedef struct uiTooltipFormat { - enum { - UI_TIP_STYLE_NORMAL = 0, - UI_TIP_STYLE_HEADER, - UI_TIP_STYLE_MONO, - } style : 3; - enum { - UI_TIP_LC_MAIN = 0, /* primary text */ - UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */ - UI_TIP_LC_ACTIVE, /* titles of active enum values */ - UI_TIP_LC_NORMAL, /* regular text */ - UI_TIP_LC_PYTHON, /* Python snippet */ - UI_TIP_LC_ALERT, /* description of why operator can't run */ - } color_id : 4; - int is_pad : 1; + enum { + UI_TIP_STYLE_NORMAL = 0, + UI_TIP_STYLE_HEADER, + UI_TIP_STYLE_MONO, + } style : 3; + enum { + UI_TIP_LC_MAIN = 0, /* primary text */ + UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */ + UI_TIP_LC_ACTIVE, /* titles of active enum values */ + UI_TIP_LC_NORMAL, /* regular text */ + UI_TIP_LC_PYTHON, /* Python snippet */ + UI_TIP_LC_ALERT, /* description of why operator can't run */ + } color_id : 4; + int is_pad : 1; } uiTooltipFormat; typedef struct uiTooltipField { - char *text; - char *text_suffix; - struct { - uint x_pos; /* x cursor position at the end of the last line */ - uint lines; /* number of lines, 1 or more with word-wrap */ - } geom; - uiTooltipFormat format; + char *text; + char *text_suffix; + struct { + uint x_pos; /* x cursor position at the end of the last line */ + uint lines; /* number of lines, 1 or more with word-wrap */ + } geom; + uiTooltipFormat format; } uiTooltipField; typedef struct uiTooltipData { - rcti bbox; - uiTooltipField *fields; - uint fields_len; - uiFontStyle fstyle; - int wrap_width; - int toth, lineh; + rcti bbox; + uiTooltipField *fields; + uint fields_len; + uiFontStyle fstyle; + int wrap_width; + int toth, lineh; } uiTooltipData; #define UI_TIP_LC_MAX 6 @@ -117,183 +115,177 @@ typedef struct uiTooltipData { BLI_STATIC_ASSERT(UI_TIP_LC_MAX == UI_TIP_LC_ALERT + 1, "invalid lc-max"); BLI_STATIC_ASSERT(sizeof(uiTooltipFormat) <= sizeof(int), "oversize"); -static uiTooltipField *text_field_add_only( - uiTooltipData *data) +static uiTooltipField *text_field_add_only(uiTooltipData *data) { - data->fields_len += 1; - data->fields = MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len); - return &data->fields[data->fields_len - 1]; + data->fields_len += 1; + data->fields = MEM_recallocN(data->fields, sizeof(*data->fields) * data->fields_len); + return &data->fields[data->fields_len - 1]; } -static uiTooltipField *text_field_add( - uiTooltipData *data, - const uiTooltipFormat *format) +static uiTooltipField *text_field_add(uiTooltipData *data, const uiTooltipFormat *format) { - uiTooltipField *field = text_field_add_only(data); - field->format = *format; - return field; + uiTooltipField *field = text_field_add_only(data); + field->format = *format; + return field; } /* -------------------------------------------------------------------- */ /** \name ToolTip Callbacks (Draw & Free) * \{ */ -static void rgb_tint( - float col[3], - float h, float h_strength, - float v, float v_strength) +static void rgb_tint(float col[3], float h, float h_strength, float v, float v_strength) { - float col_hsv_from[3]; - float col_hsv_to[3]; + float col_hsv_from[3]; + float col_hsv_to[3]; - rgb_to_hsv_v(col, col_hsv_from); + rgb_to_hsv_v(col, col_hsv_from); - col_hsv_to[0] = h; - col_hsv_to[1] = h_strength; - col_hsv_to[2] = (col_hsv_from[2] * (1.0f - v_strength)) + (v * v_strength); + col_hsv_to[0] = h; + col_hsv_to[1] = h_strength; + col_hsv_to[2] = (col_hsv_from[2] * (1.0f - v_strength)) + (v * v_strength); - hsv_to_rgb_v(col_hsv_to, col); + hsv_to_rgb_v(col_hsv_to, col); } static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) { - const float pad_px = UI_TIP_PADDING; - uiTooltipData *data = ar->regiondata; - const uiWidgetColors *theme = ui_tooltip_get_theme(); - rcti bbox = data->bbox; - float tip_colors[UI_TIP_LC_MAX][3]; - uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */ - - float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */ - float *value_color = tip_colors[UI_TIP_LC_VALUE]; - float *active_color = tip_colors[UI_TIP_LC_ACTIVE]; - float *normal_color = tip_colors[UI_TIP_LC_NORMAL]; - float *python_color = tip_colors[UI_TIP_LC_PYTHON]; - float *alert_color = tip_colors[UI_TIP_LC_ALERT]; - - float background_color[3]; - float tone_bg; - int i; - - wmOrtho2_region_pixelspace(ar); - - /* draw background */ - ui_draw_tooltip_background(UI_style_get(), NULL, &bbox); - - /* set background_color */ - rgb_uchar_to_float(background_color, (const uchar *)theme->inner); - - /* calculate normal_color */ - rgb_uchar_to_float(main_color, (const uchar *)theme->text); - copy_v3_v3(active_color, main_color); - copy_v3_v3(normal_color, main_color); - copy_v3_v3(python_color, main_color); - copy_v3_v3(alert_color, main_color); - copy_v3_v3(value_color, main_color); - - /* find the brightness difference between background and text colors */ - - tone_bg = rgb_to_grayscale(background_color); - /* tone_fg = rgb_to_grayscale(main_color); */ - - /* mix the colors */ - rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light gray */ - rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* light blue */ - rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* gray */ - rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark gray */ - rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */ - - /* draw text */ - BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); - BLF_wordwrap(blf_mono_font, data->wrap_width); - - bbox.xmin += 0.5f * pad_px; /* add padding to the text */ - bbox.ymax -= 0.25f * pad_px; - - for (i = 0; i < data->fields_len; i++) { - const uiTooltipField *field = &data->fields[i]; - const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; - - bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines); - if (field->format.style == UI_TIP_STYLE_HEADER) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; - /* draw header and active data (is done here to be able to change color) */ - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); - UI_fontstyle_set(&data->fstyle); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); - - /* offset to the end of the last line */ - if (field->text_suffix) { - float xofs = field->geom.x_pos; - float yofs = data->lineh * (field->geom.lines - 1); - bbox.xmin += xofs; - bbox.ymax -= yofs; - - rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params); - - /* undo offset */ - bbox.xmin -= xofs; - bbox.ymax += yofs; - } - } - else if (field->format.style == UI_TIP_STYLE_MONO) { - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; - uiFontStyle fstyle_mono = data->fstyle; - fstyle_mono.uifont_id = blf_mono_font; - - UI_fontstyle_set(&fstyle_mono); - /* XXX, needed because we dont have mono in 'U.uifonts' */ - BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); - UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params); - } - else { - BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL); - const struct uiFontStyleDraw_Params fs_params = { - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }; - - /* draw remaining data */ - rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); - UI_fontstyle_set(&data->fstyle); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); - } - - bbox.ymax -= data->lineh * field->geom.lines; - - if (field_next && field_next->format.is_pad) { - bbox.ymax -= data->lineh * (UI_TIP_PAD_FAC - 1); - } - } - - BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP); - BLF_disable(blf_mono_font, BLF_WORD_WRAP); + const float pad_px = UI_TIP_PADDING; + uiTooltipData *data = ar->regiondata; + const uiWidgetColors *theme = ui_tooltip_get_theme(); + rcti bbox = data->bbox; + float tip_colors[UI_TIP_LC_MAX][3]; + uchar drawcol[4] = {0, 0, 0, 255}; /* to store color in while drawing (alpha is always 255) */ + + float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */ + float *value_color = tip_colors[UI_TIP_LC_VALUE]; + float *active_color = tip_colors[UI_TIP_LC_ACTIVE]; + float *normal_color = tip_colors[UI_TIP_LC_NORMAL]; + float *python_color = tip_colors[UI_TIP_LC_PYTHON]; + float *alert_color = tip_colors[UI_TIP_LC_ALERT]; + + float background_color[3]; + float tone_bg; + int i; + + wmOrtho2_region_pixelspace(ar); + + /* draw background */ + ui_draw_tooltip_background(UI_style_get(), NULL, &bbox); + + /* set background_color */ + rgb_uchar_to_float(background_color, (const uchar *)theme->inner); + + /* calculate normal_color */ + rgb_uchar_to_float(main_color, (const uchar *)theme->text); + copy_v3_v3(active_color, main_color); + copy_v3_v3(normal_color, main_color); + copy_v3_v3(python_color, main_color); + copy_v3_v3(alert_color, main_color); + copy_v3_v3(value_color, main_color); + + /* find the brightness difference between background and text colors */ + + tone_bg = rgb_to_grayscale(background_color); + /* tone_fg = rgb_to_grayscale(main_color); */ + + /* mix the colors */ + rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light gray */ + rgb_tint(active_color, 0.6f, 0.2f, tone_bg, 0.2f); /* light blue */ + rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.4f); /* gray */ + rgb_tint(python_color, 0.0f, 0.0f, tone_bg, 0.5f); /* dark gray */ + rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */ + + /* draw text */ + BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); + BLF_wordwrap(blf_mono_font, data->wrap_width); + + bbox.xmin += 0.5f * pad_px; /* add padding to the text */ + bbox.ymax -= 0.25f * pad_px; + + for (i = 0; i < data->fields_len; i++) { + const uiTooltipField *field = &data->fields[i]; + const uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + + bbox.ymin = bbox.ymax - (data->lineh * field->geom.lines); + if (field->format.style == UI_TIP_STYLE_HEADER) { + const struct uiFontStyleDraw_Params fs_params = { + .align = UI_STYLE_TEXT_LEFT, + .word_wrap = true, + }; + /* draw header and active data (is done here to be able to change color) */ + rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); + UI_fontstyle_set(&data->fstyle); + UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); + + /* offset to the end of the last line */ + if (field->text_suffix) { + float xofs = field->geom.x_pos; + float yofs = data->lineh * (field->geom.lines - 1); + bbox.xmin += xofs; + bbox.ymax -= yofs; + + rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); + UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params); + + /* undo offset */ + bbox.xmin -= xofs; + bbox.ymax += yofs; + } + } + else if (field->format.style == UI_TIP_STYLE_MONO) { + const struct uiFontStyleDraw_Params fs_params = { + .align = UI_STYLE_TEXT_LEFT, + .word_wrap = true, + }; + uiFontStyle fstyle_mono = data->fstyle; + fstyle_mono.uifont_id = blf_mono_font; + + UI_fontstyle_set(&fstyle_mono); + /* XXX, needed because we dont have mono in 'U.uifonts' */ + BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); + rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params); + } + else { + BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL); + const struct uiFontStyleDraw_Params fs_params = { + .align = UI_STYLE_TEXT_LEFT, + .word_wrap = true, + }; + + /* draw remaining data */ + rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); + UI_fontstyle_set(&data->fstyle); + UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); + } + + bbox.ymax -= data->lineh * field->geom.lines; + + if (field_next && field_next->format.is_pad) { + bbox.ymax -= data->lineh * (UI_TIP_PAD_FAC - 1); + } + } + + BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP); + BLF_disable(blf_mono_font, BLF_WORD_WRAP); } static void ui_tooltip_region_free_cb(ARegion *ar) { - uiTooltipData *data; - - data = ar->regiondata; - - for (int i = 0; i < data->fields_len; i++) { - const uiTooltipField *field = &data->fields[i]; - MEM_freeN(field->text); - if (field->text_suffix) { - MEM_freeN(field->text_suffix); - } - } - MEM_freeN(data->fields); - MEM_freeN(data); - ar->regiondata = NULL; + uiTooltipData *data; + + data = ar->regiondata; + + for (int i = 0; i < data->fields_len; i++) { + const uiTooltipField *field = &data->fields[i]; + MEM_freeN(field->text); + if (field->text_suffix) { + MEM_freeN(field->text_suffix); + } + } + MEM_freeN(data->fields); + MEM_freeN(data); + ar->regiondata = NULL; } /** \} */ @@ -302,929 +294,938 @@ static void ui_tooltip_region_free_cb(ARegion *ar) /** \name ToolTip Creation * \{ */ -static bool ui_tooltip_data_append_from_keymap( - bContext *C, uiTooltipData *data, - wmKeyMap *keymap) +static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data, wmKeyMap *keymap) { - const int fields_len_init = data->fields_len; - char buf[512]; - - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); - if (ot != NULL) { - /* Tip */ - { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); - field->text = BLI_strdup(ot->description ? ot->description : ot->name); - } - /* Shortcut */ - { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); - bool found = false; - if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) { - found = true; - } - field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); - } - - /* Python */ - if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_PYTHON, - }); - char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, kmi->ptr); - WM_operator_pystring_abbreviate(str, 32); - field->text = BLI_sprintfN(TIP_("Python: %s"), str); - MEM_freeN(str); - } - } - } - - return (fields_len_init != data->fields_len); + const int fields_len_init = data->fields_len; + char buf[512]; + + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + wmOperatorType *ot = WM_operatortype_find(kmi->idname, true); + if (ot != NULL) { + /* Tip */ + { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_MAIN, + .is_pad = true, + }); + field->text = BLI_strdup(ot->description ? ot->description : ot->name); + } + /* Shortcut */ + { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_NORMAL, + }); + bool found = false; + if (WM_keymap_item_to_string(kmi, false, buf, sizeof(buf))) { + found = true; + } + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None"); + } + + /* Python */ + if (U.flag & USER_TOOLTIPS_PYTHON) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_PYTHON, + }); + char *str = WM_operator_pystring_ex(C, NULL, false, false, ot, kmi->ptr); + WM_operator_pystring_abbreviate(str, 32); + field->text = BLI_sprintfN(TIP_("Python: %s"), str); + MEM_freeN(str); + } + } + } + + return (fields_len_init != data->fields_len); } - /** * Special tool-system exception. */ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is_label) { - if (but->optype == NULL) { - return NULL; - } + if (but->optype == NULL) { + return NULL; + } - if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) { - return NULL; - } + if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_id")) { + return NULL; + } - /* Needed to get the space-data's type (below). */ - if (CTX_wm_space_data(C) == NULL) { - return NULL; - } + /* Needed to get the space-data's type (below). */ + if (CTX_wm_space_data(C) == NULL) { + return NULL; + } - char tool_id[MAX_NAME]; - RNA_string_get(but->opptr, "name", tool_id); - BLI_assert(tool_id[0] != '\0'); + char tool_id[MAX_NAME]; + RNA_string_get(but->opptr, "name", tool_id); + BLI_assert(tool_id[0] != '\0'); - /* We have a tool, now extract the info. */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + /* We have a tool, now extract the info. */ + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); #ifdef WITH_PYTHON - /* it turns out to be most simple to do this via Python since C - * doesn't have access to information about non-active tools. - */ - - /* Title (when icon-only). */ - if (but->drawstr[0] == '\0') { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; - char expr[256]; - SNPRINTF( - expr, - "bl_ui.space_toolsystem_common.item_from_id(" - "bpy.context, " - "bpy.context.space_data.type, " - "'%s').label", - tool_id); - char *expr_result = NULL; - bool is_error = false; - if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) { - if (STREQ(expr_result, "")) { - MEM_freeN(expr_result); - expr_result = NULL; - } - } - else { - /* Note, this is an exceptional case, we could even remove it - * however there have been reports of tooltips failing, so keep it for now. */ - expr_result = BLI_strdup("Internal error!"); - is_error = true; - } - - if (expr_result != NULL) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); - field->text = expr_result; - - if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; - } - } - } - - /* Tip. */ - if (is_label == false) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; - char expr[256]; - SNPRINTF( - expr, - "bl_ui.space_toolsystem_common.description_from_id(" - "bpy.context, " - "bpy.context.space_data.type, " - "'%s') + '.'", - tool_id); - - char *expr_result = NULL; - bool is_error = false; - if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) { - if (STREQ(expr_result, ".")) { - MEM_freeN(expr_result); - expr_result = NULL; - } - } - else { - /* Note, this is an exceptional case, we could even remove it - * however there have been reports of tooltips failing, so keep it for now. */ - expr_result = BLI_strdup("Internal error!"); - is_error = true; - } - - if (expr_result != NULL) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_MAIN, - .is_pad = true, - }); - field->text = expr_result; - - if (UNLIKELY(is_error)) { - field->format.color_id = UI_TIP_LC_ALERT; - } - } - } - - /* Shortcut. */ - if (is_label == false && ((but->block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) == 0)) { - /* There are different kinds of shortcuts: - * - * - Direct access to the tool (as if the toolbar button is pressed). - * - The key is bound to a brush type (not the exact brush name). - * - The key is assigned to the operator it's self (bypassing the tool, executing the operator). - * - * Either way case it's useful to show the shortcut. - */ - char *shortcut = NULL; - - { - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - UI_but_string_info_get(C, but, &op_keymap, NULL); - shortcut = op_keymap.strinfo; - } - - if (shortcut == NULL) { - ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); - const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - if (tool_attr != NULL) { - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - const int i = RNA_enum_from_name(items, tool_id); - if (i != -1) { - wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true); - PointerRNA op_props; - WM_operator_properties_create_ptr(&op_props, ot); - RNA_enum_set(&op_props, tool_attr, items[i].value); - - /* Check for direct access to the tool. */ - char shortcut_brush[128] = ""; - if (WM_key_event_operator_string( - C, ot->idname, WM_OP_INVOKE_REGION_WIN, op_props.data, true, - shortcut_brush, ARRAY_SIZE(shortcut_brush))) - { - shortcut = BLI_strdup(shortcut_brush); - } - WM_operator_properties_free(&op_props); - } - } - } - - if (shortcut == NULL) { - /* Check for direct access to the tool. */ - char shortcut_toolbar[128] = ""; - if (WM_key_event_operator_string( - C, "WM_OT_toolbar", WM_OP_INVOKE_REGION_WIN, NULL, true, - shortcut_toolbar, ARRAY_SIZE(shortcut_toolbar))) - { - /* Generate keymap in order to inspect it. - * Note, we could make a utility to avoid the keymap generation part of this. */ - const char *expr_imports[] = {"bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL}; - const char *expr = ( - "getattr(" - "bl_keymap_utils.keymap_from_toolbar.generate(" - "bpy.context, " - "bpy.context.space_data.type), " - "'as_pointer', lambda: 0)()"); - - intptr_t expr_result = 0; - if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) { - if (expr_result != 0) { - wmKeyMap *keymap = (wmKeyMap *)expr_result; - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { - if (STREQ(kmi->idname, but->optype->idname)) { - char tool_id_test[MAX_NAME]; - RNA_string_get(kmi->ptr, "name", tool_id_test); - if (STREQ(tool_id, tool_id_test)) { - char buf[128]; - WM_keymap_item_to_string(kmi, false, buf, sizeof(buf)); - shortcut = BLI_sprintfN("%s, %s", shortcut_toolbar, buf); - break; - } - } - } - } - } - else { - BLI_assert(0); - } - } - } - - if (shortcut != NULL) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); - field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut); - MEM_freeN(shortcut); - } - } - - /* Keymap */ - - /* This is too handy not to expose somehow, let's be sneaky for now. */ - if ((is_label == false) && CTX_wm_window(C)->eventstate->shift) { - const char *expr_imports[] = {"bpy", "bl_ui", NULL}; - char expr[256]; - SNPRINTF( - expr, - "getattr(" - "bl_ui.space_toolsystem_common.keymap_from_id(" - "bpy.context, " - "bpy.context.space_data.type, " - "'%s'), " - "'as_pointer', lambda: 0)()", - tool_id); - - intptr_t expr_result = 0; - if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) { - if (expr_result != 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("Tool Keymap:"); - } - wmKeyMap *keymap = (wmKeyMap *)expr_result; - ui_tooltip_data_append_from_keymap(C, data, keymap); - } - } - else { - BLI_assert(0); - } - } -#endif /* WITH_PYTHON */ - - if (data->fields_len == 0) { - MEM_freeN(data); - return NULL; - } - else { - return data; - } + /* it turns out to be most simple to do this via Python since C + * doesn't have access to information about non-active tools. + */ + + /* Title (when icon-only). */ + if (but->drawstr[0] == '\0') { + const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + char expr[256]; + SNPRINTF(expr, + "bl_ui.space_toolsystem_common.item_from_id(" + "bpy.context, " + "bpy.context.space_data.type, " + "'%s').label", + tool_id); + char *expr_result = NULL; + bool is_error = false; + if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) { + if (STREQ(expr_result, "")) { + MEM_freeN(expr_result); + expr_result = NULL; + } + } + else { + /* Note, this is an exceptional case, we could even remove it + * however there have been reports of tooltips failing, so keep it for now. */ + expr_result = BLI_strdup("Internal error!"); + is_error = true; + } + + if (expr_result != NULL) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_MAIN, + .is_pad = true, + }); + field->text = expr_result; + + if (UNLIKELY(is_error)) { + field->format.color_id = UI_TIP_LC_ALERT; + } + } + } + + /* Tip. */ + if (is_label == false) { + const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + char expr[256]; + SNPRINTF(expr, + "bl_ui.space_toolsystem_common.description_from_id(" + "bpy.context, " + "bpy.context.space_data.type, " + "'%s') + '.'", + tool_id); + + char *expr_result = NULL; + bool is_error = false; + if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) { + if (STREQ(expr_result, ".")) { + MEM_freeN(expr_result); + expr_result = NULL; + } + } + else { + /* Note, this is an exceptional case, we could even remove it + * however there have been reports of tooltips failing, so keep it for now. */ + expr_result = BLI_strdup("Internal error!"); + is_error = true; + } + + if (expr_result != NULL) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_MAIN, + .is_pad = true, + }); + field->text = expr_result; + + if (UNLIKELY(is_error)) { + field->format.color_id = UI_TIP_LC_ALERT; + } + } + } + + /* Shortcut. */ + if (is_label == false && ((but->block->flag & UI_BLOCK_SHOW_SHORTCUT_ALWAYS) == 0)) { + /* There are different kinds of shortcuts: + * + * - Direct access to the tool (as if the toolbar button is pressed). + * - The key is bound to a brush type (not the exact brush name). + * - The key is assigned to the operator it's self (bypassing the tool, executing the operator). + * + * Either way case it's useful to show the shortcut. + */ + char *shortcut = NULL; + + { + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; + UI_but_string_info_get(C, but, &op_keymap, NULL); + shortcut = op_keymap.strinfo; + } + + if (shortcut == NULL) { + ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C); + const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); + if (tool_attr != NULL) { + const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); + const int i = RNA_enum_from_name(items, tool_id); + if (i != -1) { + wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true); + PointerRNA op_props; + WM_operator_properties_create_ptr(&op_props, ot); + RNA_enum_set(&op_props, tool_attr, items[i].value); + + /* Check for direct access to the tool. */ + char shortcut_brush[128] = ""; + if (WM_key_event_operator_string(C, + ot->idname, + WM_OP_INVOKE_REGION_WIN, + op_props.data, + true, + shortcut_brush, + ARRAY_SIZE(shortcut_brush))) { + shortcut = BLI_strdup(shortcut_brush); + } + WM_operator_properties_free(&op_props); + } + } + } + + if (shortcut == NULL) { + /* Check for direct access to the tool. */ + char shortcut_toolbar[128] = ""; + if (WM_key_event_operator_string(C, + "WM_OT_toolbar", + WM_OP_INVOKE_REGION_WIN, + NULL, + true, + shortcut_toolbar, + ARRAY_SIZE(shortcut_toolbar))) { + /* Generate keymap in order to inspect it. + * Note, we could make a utility to avoid the keymap generation part of this. */ + const char *expr_imports[] = { + "bpy", "bl_keymap_utils", "bl_keymap_utils.keymap_from_toolbar", NULL}; + const char *expr = + ("getattr(" + "bl_keymap_utils.keymap_from_toolbar.generate(" + "bpy.context, " + "bpy.context.space_data.type), " + "'as_pointer', lambda: 0)()"); + + intptr_t expr_result = 0; + if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) { + if (expr_result != 0) { + wmKeyMap *keymap = (wmKeyMap *)expr_result; + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if (STREQ(kmi->idname, but->optype->idname)) { + char tool_id_test[MAX_NAME]; + RNA_string_get(kmi->ptr, "name", tool_id_test); + if (STREQ(tool_id, tool_id_test)) { + char buf[128]; + WM_keymap_item_to_string(kmi, false, buf, sizeof(buf)); + shortcut = BLI_sprintfN("%s, %s", shortcut_toolbar, buf); + break; + } + } + } + } + } + else { + BLI_assert(0); + } + } + } + + if (shortcut != NULL) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), shortcut); + MEM_freeN(shortcut); + } + } + + /* Keymap */ + + /* This is too handy not to expose somehow, let's be sneaky for now. */ + if ((is_label == false) && CTX_wm_window(C)->eventstate->shift) { + const char *expr_imports[] = {"bpy", "bl_ui", NULL}; + char expr[256]; + SNPRINTF(expr, + "getattr(" + "bl_ui.space_toolsystem_common.keymap_from_id(" + "bpy.context, " + "bpy.context.space_data.type, " + "'%s'), " + "'as_pointer', lambda: 0)()", + tool_id); + + intptr_t expr_result = 0; + if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) { + if (expr_result != 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("Tool Keymap:"); + } + wmKeyMap *keymap = (wmKeyMap *)expr_result; + ui_tooltip_data_append_from_keymap(C, data, keymap); + } + } + else { + BLI_assert(0); + } + } +#endif /* WITH_PYTHON */ + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } } static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) { - uiStringInfo but_tip = {BUT_GET_TIP, NULL}; - uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; - uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; - uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL}; - uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; - uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; - - char buf[512]; - - /* create tooltip data */ - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - - UI_but_string_info_get(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL); - - /* Tip */ - if (but_tip.strinfo) { - { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_NORMAL, - }); - if (enum_label.strinfo) { - field->text = BLI_sprintfN("%s: ", but_tip.strinfo); - field->text_suffix = BLI_strdup(enum_label.strinfo); - } - else { - field->text = BLI_sprintfN("%s.", but_tip.strinfo); - } - } - - /* special case enum rna buttons */ - if ((but->type & UI_BTYPE_ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); - field->text = BLI_strdup(IFACE_("(Shift-Click/Drag to select multiple)")); - } - - } - /* Enum field label & tip */ - if (enum_tip.strinfo) { - 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(enum_tip.strinfo); - } - - /* Op shortcut */ - if (op_keymap.strinfo) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); - field->text = BLI_sprintfN(TIP_("Shortcut: %s"), op_keymap.strinfo); - } - - /* Property context-toggle shortcut */ - if (prop_keymap.strinfo) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); - field->text = BLI_sprintfN(TIP_("Shortcut: %s"), prop_keymap.strinfo); - } - - if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { - /* better not show the value of a password */ - if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) { - /* full string */ - ui_but_string_get(but, buf, sizeof(buf)); - if (buf[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_sprintfN(TIP_("Value: %s"), buf); - } - } - } - - if (but->rnaprop) { - int unit_type = UI_but_unit_type_get(but); - - if (unit_type == PROP_UNIT_ROTATION) { - if (RNA_property_type(but->rnaprop) == PROP_FLOAT) { - float value = RNA_property_array_check(but->rnaprop) ? - RNA_property_float_get_index(&but->rnapoin, but->rnaprop, but->rnaindex) : - RNA_property_float_get(&but->rnapoin, but->rnaprop); - - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - }); - field->text = BLI_sprintfN(TIP_("Radians: %f"), value); - } - } - - if (but->flag & UI_BUT_DRIVEN) { - if (ui_but_anim_expression_get(but, buf, sizeof(buf))) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); - field->text = BLI_sprintfN(TIP_("Expression: %s"), buf); - } - } - - if (but->rnapoin.id.data) { - const ID *id = but->rnapoin.id.data; - if (ID_IS_LINKED(id)) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_NORMAL, - }); - field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->name); - } - } - } - else if (but->optype) { - PointerRNA *opptr; - char *str; - opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ - - /* so the context is passed to fieldf functions (some py fieldf functions use it) */ - WM_operator_properties_sanitize(opptr, false); - - str = WM_operator_pystring_ex(C, NULL, false, false, but->optype, opptr); - - /* avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary */ - WM_operator_pystring_abbreviate(str, 32); - - /* operator info */ - if (U.flag & USER_TOOLTIPS_PYTHON) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); - field->text = BLI_sprintfN(TIP_("Python: %s"), str); - } - - MEM_freeN(str); - } - - /* button is disabled, we may be able to tell user why */ - if (but->flag & UI_BUT_DISABLED) { - const char *disabled_msg = NULL; - - /* if operator poll check failed, it can give pretty precise info why */ - if (but->optype) { - CTX_wm_operator_poll_msg_set(C, NULL); - WM_operator_poll_context(C, but->optype, but->opcontext); - disabled_msg = CTX_wm_operator_poll_msg_get(C); - } - /* alternatively, buttons can store some reasoning too */ - else if (but->disabled_info) { - disabled_msg = TIP_(but->disabled_info); - } - - if (disabled_msg && disabled_msg[0]) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_ALERT, - }); - field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg); - } - } - - if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) { - { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - .is_pad = true, - }); - if (rna_prop.strinfo) { - /* Struct and prop */ - field->text = BLI_sprintfN(TIP_("Python: %s.%s"), rna_struct.strinfo, rna_prop.strinfo); - } - else { - /* Only struct (e.g. menus) */ - field->text = BLI_sprintfN(TIP_("Python: %s"), rna_struct.strinfo); - } - } - - if (but->rnapoin.id.data) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_MONO, - .color_id = UI_TIP_LC_PYTHON, - }); - - /* this could get its own 'BUT_GET_...' type */ - - /* never fails */ - /* move ownership (no need for re-alloc) */ - if (but->rnaprop) { - field->text = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true); - } - else { - field->text = RNA_path_full_struct_py(&but->rnapoin); - } - - } - } - - /* Free strinfo's... */ - if (but_tip.strinfo) { - MEM_freeN(but_tip.strinfo); - } - if (enum_label.strinfo) { - MEM_freeN(enum_label.strinfo); - } - if (enum_tip.strinfo) { - MEM_freeN(enum_tip.strinfo); - } - if (op_keymap.strinfo) { - MEM_freeN(op_keymap.strinfo); - } - if (prop_keymap.strinfo) { - MEM_freeN(prop_keymap.strinfo); - } - if (rna_struct.strinfo) { - MEM_freeN(rna_struct.strinfo); - } - if (rna_prop.strinfo) { - MEM_freeN(rna_prop.strinfo); - } - - if (data->fields_len == 0) { - MEM_freeN(data); - return NULL; - } - else { - return data; - } + uiStringInfo but_tip = {BUT_GET_TIP, NULL}; + uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; + uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; + uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; + uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL}; + uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; + uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; + + char buf[512]; + + /* create tooltip data */ + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + + UI_but_string_info_get(C, + but, + &but_tip, + &enum_label, + &enum_tip, + &op_keymap, + &prop_keymap, + &rna_struct, + &rna_prop, + NULL); + + /* Tip */ + if (but_tip.strinfo) { + { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_HEADER, + .color_id = UI_TIP_LC_NORMAL, + }); + if (enum_label.strinfo) { + field->text = BLI_sprintfN("%s: ", but_tip.strinfo); + field->text_suffix = BLI_strdup(enum_label.strinfo); + } + else { + field->text = BLI_sprintfN("%s.", but_tip.strinfo); + } + } + + /* special case enum rna buttons */ + if ((but->type & UI_BTYPE_ROW) && but->rnaprop && + RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_NORMAL, + }); + field->text = BLI_strdup(IFACE_("(Shift-Click/Drag to select multiple)")); + } + } + /* Enum field label & tip */ + if (enum_tip.strinfo) { + 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(enum_tip.strinfo); + } + + /* Op shortcut */ + if (op_keymap.strinfo) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), op_keymap.strinfo); + } + + /* Property context-toggle shortcut */ + if (prop_keymap.strinfo) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), prop_keymap.strinfo); + } + + if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { + /* better not show the value of a password */ + if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) { + /* full string */ + ui_but_string_get(but, buf, sizeof(buf)); + if (buf[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_sprintfN(TIP_("Value: %s"), buf); + } + } + } + + if (but->rnaprop) { + int unit_type = UI_but_unit_type_get(but); + + if (unit_type == PROP_UNIT_ROTATION) { + if (RNA_property_type(but->rnaprop) == PROP_FLOAT) { + float value = RNA_property_array_check(but->rnaprop) ? + RNA_property_float_get_index( + &but->rnapoin, but->rnaprop, but->rnaindex) : + RNA_property_float_get(&but->rnapoin, but->rnaprop); + + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + }); + field->text = BLI_sprintfN(TIP_("Radians: %f"), value); + } + } + + if (but->flag & UI_BUT_DRIVEN) { + if (ui_but_anim_expression_get(but, buf, sizeof(buf))) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_NORMAL, + }); + field->text = BLI_sprintfN(TIP_("Expression: %s"), buf); + } + } + + if (but->rnapoin.id.data) { + const ID *id = but->rnapoin.id.data; + if (ID_IS_LINKED(id)) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_NORMAL, + }); + field->text = BLI_sprintfN(TIP_("Library: %s"), id->lib->name); + } + } + } + else if (but->optype) { + PointerRNA *opptr; + char *str; + opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ + + /* so the context is passed to fieldf functions (some py fieldf functions use it) */ + WM_operator_properties_sanitize(opptr, false); + + str = WM_operator_pystring_ex(C, NULL, false, false, but->optype, opptr); + + /* avoid overly verbose tips (eg, arrays of 20 layers), exact limit is arbitrary */ + WM_operator_pystring_abbreviate(str, 32); + + /* operator info */ + if (U.flag & USER_TOOLTIPS_PYTHON) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_MONO, + .color_id = UI_TIP_LC_PYTHON, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Python: %s"), str); + } + + MEM_freeN(str); + } + + /* button is disabled, we may be able to tell user why */ + if (but->flag & UI_BUT_DISABLED) { + const char *disabled_msg = NULL; + + /* if operator poll check failed, it can give pretty precise info why */ + if (but->optype) { + CTX_wm_operator_poll_msg_set(C, NULL); + WM_operator_poll_context(C, but->optype, but->opcontext); + disabled_msg = CTX_wm_operator_poll_msg_get(C); + } + /* alternatively, buttons can store some reasoning too */ + else if (but->disabled_info) { + disabled_msg = TIP_(but->disabled_info); + } + + if (disabled_msg && disabled_msg[0]) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_ALERT, + }); + field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg); + } + } + + if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) { + { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_MONO, + .color_id = UI_TIP_LC_PYTHON, + .is_pad = true, + }); + if (rna_prop.strinfo) { + /* Struct and prop */ + field->text = BLI_sprintfN(TIP_("Python: %s.%s"), rna_struct.strinfo, rna_prop.strinfo); + } + else { + /* Only struct (e.g. menus) */ + field->text = BLI_sprintfN(TIP_("Python: %s"), rna_struct.strinfo); + } + } + + if (but->rnapoin.id.data) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_MONO, + .color_id = UI_TIP_LC_PYTHON, + }); + + /* this could get its own 'BUT_GET_...' type */ + + /* never fails */ + /* move ownership (no need for re-alloc) */ + if (but->rnaprop) { + field->text = RNA_path_full_property_py_ex( + &but->rnapoin, but->rnaprop, but->rnaindex, true); + } + else { + field->text = RNA_path_full_struct_py(&but->rnapoin); + } + } + } + + /* Free strinfo's... */ + if (but_tip.strinfo) { + MEM_freeN(but_tip.strinfo); + } + if (enum_label.strinfo) { + MEM_freeN(enum_label.strinfo); + } + if (enum_tip.strinfo) { + MEM_freeN(enum_tip.strinfo); + } + if (op_keymap.strinfo) { + MEM_freeN(op_keymap.strinfo); + } + if (prop_keymap.strinfo) { + MEM_freeN(prop_keymap.strinfo); + } + if (rna_struct.strinfo) { + MEM_freeN(rna_struct.strinfo); + } + if (rna_prop.strinfo) { + MEM_freeN(rna_prop.strinfo); + } + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } } static uiTooltipData *ui_tooltip_data_from_gizmo(bContext *C, wmGizmo *gz) { - uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - - /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */ - - /* Operator Actions */ - { - bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part; - - const struct { - int part; - const char *prefix; - } gzop_actions[] = { - { - .part = gz->highlight_part, - .prefix = use_drag ? TIP_("Click") : NULL, - }, { - .part = use_drag ? gz->drag_part : -1, - .prefix = use_drag ? TIP_("Drag") : NULL, - }, - }; - - for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) { - wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ? WM_gizmo_operator_get(gz, gzop_actions[i].part) : NULL; - if (gzop != NULL) { - /* Description */ - const char *info = RNA_struct_ui_description(gzop->type->srna); - if (!(info && info[0])) { - info = RNA_struct_ui_name(gzop->type->srna); - } - - if (info && info[0]) { - char *text = NULL; - if (gzop_actions[i].prefix != NULL) { - text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info); - } - else { - text = BLI_strdup(info); - } - - if (text != NULL) { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_HEADER, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); - field->text = text; - } - } - - /* Shortcut */ - { - IDProperty *prop = gzop->ptr.data; - char buf[128]; - if (WM_key_event_operator_string( - C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, - buf, ARRAY_SIZE(buf))) - { - uiTooltipField *field = text_field_add( - data, &(uiTooltipFormat){ - .style = UI_TIP_STYLE_NORMAL, - .color_id = UI_TIP_LC_VALUE, - .is_pad = true, - }); - field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf); - } - } - } - } - } - - /* Property Actions */ - if (gz->type->target_property_defs_len) { - wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz); - for (int i = 0; i < gz->type->target_property_defs_len; i++) { - /* TODO(campbell): function callback descriptions. */ - wmGizmoProperty *gz_prop = &gz_prop_array[i]; - if (gz_prop->prop != NULL) { - const char *info = RNA_property_ui_description(gz_prop->prop); - if (info && info[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(info); - } - } - } - } - - if (data->fields_len == 0) { - MEM_freeN(data); - return NULL; - } - else { - return data; - } + uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); + + /* TODO(campbell): a way for gizmos to have their own descriptions (low priority). */ + + /* Operator Actions */ + { + bool use_drag = gz->drag_part != -1 && gz->highlight_part != gz->drag_part; + + const struct { + int part; + const char *prefix; + } gzop_actions[] = { + { + .part = gz->highlight_part, + .prefix = use_drag ? TIP_("Click") : NULL, + }, + { + .part = use_drag ? gz->drag_part : -1, + .prefix = use_drag ? TIP_("Drag") : NULL, + }, + }; + + for (int i = 0; i < ARRAY_SIZE(gzop_actions); i++) { + wmGizmoOpElem *gzop = (gzop_actions[i].part != -1) ? + WM_gizmo_operator_get(gz, gzop_actions[i].part) : + NULL; + if (gzop != NULL) { + /* Description */ + const char *info = RNA_struct_ui_description(gzop->type->srna); + if (!(info && info[0])) { + info = RNA_struct_ui_name(gzop->type->srna); + } + + if (info && info[0]) { + char *text = NULL; + if (gzop_actions[i].prefix != NULL) { + text = BLI_sprintfN("%s: %s", gzop_actions[i].prefix, info); + } + else { + text = BLI_strdup(info); + } + + if (text != NULL) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_HEADER, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = text; + } + } + + /* Shortcut */ + { + IDProperty *prop = gzop->ptr.data; + char buf[128]; + if (WM_key_event_operator_string( + C, gzop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true, buf, ARRAY_SIZE(buf))) { + uiTooltipField *field = text_field_add(data, + &(uiTooltipFormat){ + .style = UI_TIP_STYLE_NORMAL, + .color_id = UI_TIP_LC_VALUE, + .is_pad = true, + }); + field->text = BLI_sprintfN(TIP_("Shortcut: %s"), buf); + } + } + } + } + } + + /* Property Actions */ + if (gz->type->target_property_defs_len) { + wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz); + for (int i = 0; i < gz->type->target_property_defs_len; i++) { + /* TODO(campbell): function callback descriptions. */ + wmGizmoProperty *gz_prop = &gz_prop_array[i]; + if (gz_prop->prop != NULL) { + const char *info = RNA_property_ui_description(gz_prop->prop); + if (info && info[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(info); + } + } + } + } + + if (data->fields_len == 0) { + MEM_freeN(data); + return NULL; + } + else { + return data; + } } - -static ARegion *ui_tooltip_create_with_data( - bContext *C, uiTooltipData *data, - const float init_position[2], const rcti *init_rect_overlap, - const float aspect) +static ARegion *ui_tooltip_create_with_data(bContext *C, + uiTooltipData *data, + const float init_position[2], + const rcti *init_rect_overlap, + const float aspect) { - const float pad_px = UI_TIP_PADDING; - wmWindow *win = CTX_wm_window(C); - const int winx = WM_window_pixels_x(win); - const int winy = WM_window_pixels_y(win); - uiStyle *style = UI_style_get(); - static ARegionType type; - ARegion *ar; - int fonth, fontw; - int h, i; - rcti rect_i; - int font_flag = 0; - - /* create area region */ - ar = ui_region_temp_add(CTX_wm_screen(C)); - - memset(&type, 0, sizeof(ARegionType)); - type.draw = ui_tooltip_region_draw_cb; - type.free = ui_tooltip_region_free_cb; - type.regionid = RGN_TYPE_TEMPORARY; - ar->type = &type; - - /* set font, get bb */ - data->fstyle = style->widget; /* copy struct */ - ui_fontscale(&data->fstyle.points, aspect); - - UI_fontstyle_set(&data->fstyle); - - data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, winx - (UI_TIP_PADDING * 2)); - - font_flag |= BLF_WORD_WRAP; - if (data->fstyle.kerning == 1) { - font_flag |= BLF_KERNING_DEFAULT; - } - BLF_enable(data->fstyle.uifont_id, font_flag); - BLF_enable(blf_mono_font, font_flag); - BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); - BLF_wordwrap(blf_mono_font, data->wrap_width); - - /* these defines tweaked depending on font */ + const float pad_px = UI_TIP_PADDING; + wmWindow *win = CTX_wm_window(C); + const int winx = WM_window_pixels_x(win); + const int winy = WM_window_pixels_y(win); + uiStyle *style = UI_style_get(); + static ARegionType type; + ARegion *ar; + int fonth, fontw; + int h, i; + rcti rect_i; + int font_flag = 0; + + /* create area region */ + ar = ui_region_temp_add(CTX_wm_screen(C)); + + memset(&type, 0, sizeof(ARegionType)); + type.draw = ui_tooltip_region_draw_cb; + type.free = ui_tooltip_region_free_cb; + type.regionid = RGN_TYPE_TEMPORARY; + ar->type = &type; + + /* set font, get bb */ + data->fstyle = style->widget; /* copy struct */ + ui_fontscale(&data->fstyle.points, aspect); + + UI_fontstyle_set(&data->fstyle); + + data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, winx - (UI_TIP_PADDING * 2)); + + font_flag |= BLF_WORD_WRAP; + if (data->fstyle.kerning == 1) { + font_flag |= BLF_KERNING_DEFAULT; + } + BLF_enable(data->fstyle.uifont_id, font_flag); + BLF_enable(blf_mono_font, font_flag); + BLF_wordwrap(data->fstyle.uifont_id, data->wrap_width); + BLF_wordwrap(blf_mono_font, data->wrap_width); + + /* these defines tweaked depending on font */ #define TIP_BORDER_X (16.0f / aspect) #define TIP_BORDER_Y (6.0f / aspect) - h = BLF_height_max(data->fstyle.uifont_id); - - for (i = 0, fontw = 0, fonth = 0; i < data->fields_len; i++) { - uiTooltipField *field = &data->fields[i]; - uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; - - struct ResultBLF info; - int w, x_pos = 0; - int font_id; - - if (field->format.style == UI_TIP_STYLE_MONO) { - BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi); - font_id = blf_mono_font; - } - else { - BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER)); - font_id = data->fstyle.uifont_id; - } - w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info); - - /* check for suffix (enum label) */ - if (field->text_suffix && field->text_suffix[0]) { - x_pos = info.width; - w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX)); - } - fontw = max_ii(fontw, w); - - fonth += h * info.lines; - if (field_next && field_next->format.is_pad) { - fonth += h * (UI_TIP_PAD_FAC - 1); - } - - field->geom.lines = info.lines; - field->geom.x_pos = x_pos; - } - - //fontw *= aspect; - - BLF_disable(data->fstyle.uifont_id, font_flag); - BLF_disable(blf_mono_font, font_flag); - - ar->regiondata = data; - - data->toth = fonth; - data->lineh = h; - - /* Compute position. */ - { - rctf rect_fl; - rect_fl.xmin = init_position[0] - TIP_BORDER_X; - rect_fl.xmax = rect_fl.xmin + fontw + pad_px; - rect_fl.ymax = init_position[1] - TIP_BORDER_Y; - rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; - BLI_rcti_rctf_copy(&rect_i, &rect_fl); - } + h = BLF_height_max(data->fstyle.uifont_id); + + for (i = 0, fontw = 0, fonth = 0; i < data->fields_len; i++) { + uiTooltipField *field = &data->fields[i]; + uiTooltipField *field_next = (i + 1) != data->fields_len ? &data->fields[i + 1] : NULL; + + struct ResultBLF info; + int w, x_pos = 0; + int font_id; + + if (field->format.style == UI_TIP_STYLE_MONO) { + BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi); + font_id = blf_mono_font; + } + else { + BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER)); + font_id = data->fstyle.uifont_id; + } + w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info); + + /* check for suffix (enum label) */ + if (field->text_suffix && field->text_suffix[0]) { + x_pos = info.width; + w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX)); + } + fontw = max_ii(fontw, w); + + fonth += h * info.lines; + if (field_next && field_next->format.is_pad) { + fonth += h * (UI_TIP_PAD_FAC - 1); + } + + field->geom.lines = info.lines; + field->geom.x_pos = x_pos; + } + + //fontw *= aspect; + + BLF_disable(data->fstyle.uifont_id, font_flag); + BLF_disable(blf_mono_font, font_flag); + + ar->regiondata = data; + + data->toth = fonth; + data->lineh = h; + + /* Compute position. */ + { + rctf rect_fl; + rect_fl.xmin = init_position[0] - TIP_BORDER_X; + rect_fl.xmax = rect_fl.xmin + fontw + pad_px; + rect_fl.ymax = init_position[1] - TIP_BORDER_Y; + rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y; + BLI_rcti_rctf_copy(&rect_i, &rect_fl); + } #undef TIP_BORDER_X #undef TIP_BORDER_Y -// #define USE_ALIGN_Y_CENTER - - /* 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 */ - 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); + // #define USE_ALIGN_Y_CENTER + + /* 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 */ + 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); #ifdef USE_ALIGN_Y_CENTER - const int cent_overlap_y = BLI_rcti_cent_y(&init_rect); + const int cent_overlap_y = BLI_rcti_cent_y(&init_rect); #endif - 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; + 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; #ifdef USE_ALIGN_Y_CENTER - r.ymin = cent_overlap_y - (size_y / 2); - r.ymax = r.ymin + size_y; + r.ymin = cent_overlap_y - (size_y / 2); + r.ymax = r.ymin + size_y; #else - r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i); - r.ymax = init_rect.ymax; - r.ymin -= UI_POPUP_MARGIN; - r.ymax -= UI_POPUP_MARGIN; + r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i); + r.ymax = init_rect.ymax; + r.ymin -= UI_POPUP_MARGIN; + r.ymax -= UI_POPUP_MARGIN; #endif - rect.xpos = r; - } - { /* xneg */ - rcti r = rect_i; - r.xmin = init_rect.xmin - size_x; - r.xmax = r.xmin + size_x; + rect.xpos = r; + } + { /* xneg */ + rcti r = rect_i; + r.xmin = init_rect.xmin - size_x; + r.xmax = r.xmin + size_x; #ifdef USE_ALIGN_Y_CENTER - r.ymin = cent_overlap_y - (size_y / 2); - r.ymax = r.ymin + size_y; + r.ymin = cent_overlap_y - (size_y / 2); + r.ymax = r.ymin + size_y; #else - r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i); - r.ymax = init_rect.ymax; - r.ymin -= UI_POPUP_MARGIN; - r.ymax -= UI_POPUP_MARGIN; + r.ymin = init_rect.ymax - BLI_rcti_size_y(&rect_i); + r.ymax = init_rect.ymax; + r.ymin -= UI_POPUP_MARGIN; + r.ymax -= UI_POPUP_MARGIN; #endif - 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); - } - } + 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); + } + } #undef USE_ALIGN_Y_CENTER - /* add padding */ - BLI_rcti_resize(&rect_i, - BLI_rcti_size_x(&rect_i) + pad_px, - BLI_rcti_size_y(&rect_i) + pad_px); - - /* widget rect, in region coords */ - { - /* Compensate for margin offset, visually this corrects the position. */ - const int margin = UI_POPUP_MARGIN; - if (init_rect_overlap != NULL) { - BLI_rcti_translate(&rect_i, margin, margin / 2); - } - - data->bbox.xmin = margin; - data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin; - data->bbox.ymin = margin; - data->bbox.ymax = BLI_rcti_size_y(&rect_i); - - /* region bigger for shadow */ - ar->winrct.xmin = rect_i.xmin - margin; - ar->winrct.xmax = rect_i.xmax + margin; - ar->winrct.ymin = rect_i.ymin - margin; - ar->winrct.ymax = rect_i.ymax + margin; - } - - /* adds subwindow */ - ED_region_init(ar); - - /* notify change and redraw */ - ED_region_tag_redraw(ar); - - return ar; + /* add padding */ + BLI_rcti_resize(&rect_i, BLI_rcti_size_x(&rect_i) + pad_px, BLI_rcti_size_y(&rect_i) + pad_px); + + /* widget rect, in region coords */ + { + /* Compensate for margin offset, visually this corrects the position. */ + const int margin = UI_POPUP_MARGIN; + if (init_rect_overlap != NULL) { + BLI_rcti_translate(&rect_i, margin, margin / 2); + } + + data->bbox.xmin = margin; + data->bbox.xmax = BLI_rcti_size_x(&rect_i) - margin; + data->bbox.ymin = margin; + data->bbox.ymax = BLI_rcti_size_y(&rect_i); + + /* region bigger for shadow */ + ar->winrct.xmin = rect_i.xmin - margin; + ar->winrct.xmax = rect_i.xmax + margin; + ar->winrct.ymin = rect_i.ymin - margin; + ar->winrct.ymax = rect_i.ymax + margin; + } + + /* adds subwindow */ + ED_region_init(ar); + + /* notify change and redraw */ + ED_region_tag_redraw(ar); + + return ar; } /** \} */ @@ -1233,80 +1234,80 @@ static ARegion *ui_tooltip_create_with_data( /** \name ToolTip Public API * \{ */ - ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) { - wmWindow *win = CTX_wm_window(C); - /* aspect values that shrink text are likely unreadable */ - const float aspect = min_ff(1.0f, but->block->aspect); - float init_position[2]; - - if (but->drawflag & UI_BUT_NO_TOOLTIP) { - return NULL; - } - uiTooltipData *data = NULL; - - if (data == NULL) { - data = ui_tooltip_data_from_tool(C, but, is_label); - } - - if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); - } - - if (data == NULL) { - return NULL; - } - - const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(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; - } - } - - ARegion *ar = ui_tooltip_create_with_data(C, data, init_position, is_no_overlap ? &init_rect : NULL, aspect); - - return ar; + wmWindow *win = CTX_wm_window(C); + /* aspect values that shrink text are likely unreadable */ + const float aspect = min_ff(1.0f, but->block->aspect); + float init_position[2]; + + if (but->drawflag & UI_BUT_NO_TOOLTIP) { + return NULL; + } + uiTooltipData *data = NULL; + + if (data == NULL) { + data = ui_tooltip_data_from_tool(C, but, is_label); + } + + if (data == NULL) { + data = ui_tooltip_data_from_button(C, but); + } + + if (data == NULL) { + return NULL; + } + + const bool is_no_overlap = UI_but_has_tooltip_label(but) || UI_but_is_tool(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; + } + } + + 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) { - wmWindow *win = CTX_wm_window(C); - const float aspect = 1.0f; - float init_position[2]; + wmWindow *win = CTX_wm_window(C); + const float aspect = 1.0f; + float init_position[2]; - uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz); - if (data == NULL) { - return NULL; - } + uiTooltipData *data = ui_tooltip_data_from_gizmo(C, gz); + if (data == NULL) { + return NULL; + } - init_position[0] = win->eventstate->x; - init_position[1] = win->eventstate->y; + init_position[0] = win->eventstate->x; + init_position[1] = win->eventstate->y; - return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); + return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect); } void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar) { - ui_region_temp_remove(C, sc, ar); + ui_region_temp_remove(C, sc, ar); } /** \} */ |