Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Tue, 4 Sep 2018 05:29:27 +0000 (15:29 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 4 Sep 2018 05:29:27 +0000 (15:29 +1000)
1  2 
source/blender/editors/interface/interface_region_tooltip.c

index 6f78fb09ff149638f3da6971e0b944f63c71b3e4,7bb0a02bbf686458e0174bc20326fbc081cc94ec..6f4e48a9793ffe5b01e61da9044626d4e405a317
@@@ -45,7 -45,6 +45,7 @@@
  #include "MEM_guardedalloc.h"
  
  #include "DNA_userdef_types.h"
 +#include "DNA_brush_types.h"
  
  #include "BLI_math.h"
  #include "BLI_string.h"
@@@ -55,7 -54,6 +55,7 @@@
  
  #include "BKE_context.h"
  #include "BKE_screen.h"
 +#include "BKE_library.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
  #include "BLF_api.h"
  #include "BLT_translation.h"
  
 +#ifdef WITH_PYTHON
 +#  include "BPY_extern.h"
 +#endif
 +
  #include "ED_screen.h"
  
  #include "interface_intern.h"
@@@ -170,7 -164,6 +170,7 @@@ static void ui_tooltip_region_draw_cb(c
        uiWidgetColors *theme = ui_tooltip_get_theme();
        rcti bbox = data->bbox;
        float tip_colors[UI_TIP_LC_MAX][3];
 +      unsigned char 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 background_color[3];
        float tone_bg;
 -      int i, multisample_enabled;
 -
 -      /* disable AA, makes widgets too blurry */
 -      multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
 -      if (multisample_enabled)
 -              glDisable(GL_MULTISAMPLE);
 +      int i;
  
        wmOrtho2_region_pixelspace(ar);
  
                        fstyle_header.shadowalpha = 1.0f;
                        fstyle_header.word_wrap = true;
  
 +                      rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]);
                        UI_fontstyle_set(&fstyle_header);
 -                      glColor3fv(tip_colors[UI_TIP_LC_MAIN]);
 -                      UI_fontstyle_draw(&fstyle_header, &bbox, field->text);
 +                      UI_fontstyle_draw(&fstyle_header, &bbox, field->text, drawcol);
  
                        fstyle_header.shadow = 0;
  
                                bbox.xmin += xofs;
                                bbox.ymax -= yofs;
  
 -                              glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]);
 -                              UI_fontstyle_draw(&fstyle_header, &bbox, field->text_suffix);
 +                              rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]);
 +                              UI_fontstyle_draw(&fstyle_header, &bbox, field->text_suffix, drawcol);
  
                                /* undo offset */
                                bbox.xmin -= xofs;
                        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);
 -                      glColor3fv(tip_colors[field->format.color_id]);
 -                      UI_fontstyle_draw(&fstyle_mono, &bbox, field->text);
 +                      rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
 +                      UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol);
                }
                else {
                        uiFontStyle fstyle_normal = data->fstyle;
                        fstyle_normal.word_wrap = true;
  
                        /* draw remaining data */
 +                      rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]);
                        UI_fontstyle_set(&fstyle_normal);
 -                      glColor3fv(tip_colors[field->format.color_id]);
 -                      UI_fontstyle_draw(&fstyle_normal, &bbox, field->text);
 +                      UI_fontstyle_draw(&fstyle_normal, &bbox, field->text, drawcol);
                }
  
                bbox.ymax -= data->lineh * field->geom.lines;
  
        BLF_disable(data->fstyle.uifont_id, BLF_WORD_WRAP);
        BLF_disable(blf_mono_font, BLF_WORD_WRAP);
 -
 -      if (multisample_enabled)
 -              glEnable(GL_MULTISAMPLE);
  }
  
  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)
 +{
 +      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[0] ? 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)
 +{
 +      if (but->optype == NULL) {
 +              return NULL;
 +      }
 +
 +      if (!STREQ(but->optype->idname, "WM_OT_tool_set_by_name")) {
 +              return NULL;
 +      }
 +
 +      char tool_name[MAX_NAME];
 +      RNA_string_get(but->opptr, "name", tool_name);
 +      BLI_assert(tool_name[0] != '\0');
 +
 +      /* 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') {
 +              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(tool_name);
 +      }
 +
 +      /* Tip. */
 +      {
 +              const char *expr_imports[] = {"bpy", "bl_ui", NULL};
 +              char expr[256];
 +              SNPRINTF(
 +                      expr,
 +                      "bl_ui.space_toolsystem_common.description_from_name("
 +                      "bpy.context, "
 +                      "bpy.context.space_data.type, "
 +                      "'%s') + '.'",
 +                      tool_name);
 +
 +              char *expr_result = NULL;
 +              if (BPY_execute_string_as_string(C, expr_imports, expr, true, &expr_result)) {
 +                      if (!STREQ(expr_result, ".")) {
 +                              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;
 +                      }
 +                      else {
 +                              MEM_freeN(expr_result);
 +                      }
 +              }
 +              else {
 +                      BLI_assert(0);
 +              }
 +      }
 +
 +      /* Shortcut. */
 +      {
 +              /* 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) {
 +                      int mode = CTX_data_mode_enum(C);
 +                      const char *tool_attr = NULL;
 +                      uint tool_offset = 0;
 +
 +                      switch (mode) {
 +                              case CTX_MODE_SCULPT:
 +                                      tool_attr = "sculpt_tool";
 +                                      tool_offset = offsetof(Brush, sculpt_tool);
 +                                      break;
 +                              case CTX_MODE_PAINT_VERTEX:
 +                                      tool_attr = "vertex_paint_tool";
 +                                      tool_offset = offsetof(Brush, vertexpaint_tool);
 +                                      break;
 +                              case CTX_MODE_PAINT_WEIGHT:
 +                                      tool_attr = "weight_paint_tool";
 +                                      tool_offset = offsetof(Brush, vertexpaint_tool);
 +                                      break;
 +                              case CTX_MODE_PAINT_TEXTURE:
 +                                      tool_attr = "texture_paint_tool";
 +                                      tool_offset = offsetof(Brush, imagepaint_tool);
 +                                      break;
 +                              default:
 +                                      break;
 +                      }
 +
 +                      if (tool_attr != NULL) {
 +                              struct Main *bmain = CTX_data_main(C);
 +                              Brush *brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, tool_name);
 +                              if (brush) {
 +                                      Object *ob = CTX_data_active_object(C);
 +                                      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, "paint_mode", ob->mode);
 +                                      RNA_enum_set(&op_props, tool_attr, *(((char *)brush) + tool_offset));
 +
 +                                      /* 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_ui", NULL};
 +                              const char *expr = (
 +                                      "getattr("
 +                                      "bl_ui.space_toolsystem_common.keymap_from_context("
 +                                      "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_name_test[MAX_NAME];
 +                                                              RNA_string_get(kmi->ptr, "name", tool_name_test);
 +                                                              if (STREQ(tool_name, tool_name_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 (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_name("
 +                      "bpy.context, "
 +                      "bpy.context.space_data.type, "
 +                      "'%s'), "
 +                      "'as_pointer', lambda: 0)()",
 +                      tool_name);
 +
 +              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};
                WM_operator_pystring_abbreviate(str, 32);
  
                /* operator info */
 -              if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) {
 +              if (U.flag & USER_TOOLTIPS_PYTHON) {
                        uiTooltipField *field = text_field_add(
                                data, &(uiTooltipFormat){
                                    .style = UI_TIP_STYLE_MONO,
                }
        }
  
 -      if ((U.flag & USER_TOOLTIPS_PYTHON) == 0 && !but->optype && rna_struct.strinfo) {
 +      if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) {
                {
                        uiTooltipField *field = text_field_add(
                                data, &(uiTooltipFormat){
        }
  }
  
 +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;
 +              } mpop_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(mpop_actions); i++) {
 +                      wmGizmoOpElem *mpop = (mpop_actions[i].part != -1) ? WM_gizmo_operator_get(gz, mpop_actions[i].part) : NULL;
 +                      if (mpop != NULL) {
 +                              /* Description */
 +                              const char *info = RNA_struct_ui_description(mpop->type->srna);
 +                              if (!(info && info[0])) {
 +                                      info  = RNA_struct_ui_name(mpop->type->srna);
 +                              }
 +
 +                              if (info && info[0]) {
 +                                      char *text = NULL;
 +                                      if (mpop_actions[i].prefix != NULL) {
 +                                              text = BLI_sprintfN("%s: %s", mpop_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 */
 +                              {
 +                                      bool found = false;
 +                                      IDProperty *prop = mpop->ptr.data;
 +                                      char buf[128];
 +                                      if (WM_key_event_operator_string(
 +                                                  C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true,
 +                                                  buf, ARRAY_SIZE(buf)))
 +                                      {
 +                                              found = true;
 +                                      }
 +                                      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"), found ? buf : "None");
 +                              }
 +                      }
 +              }
 +      }
 +
 +      /* 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 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;
-       rctf rect_fl;
        rcti rect_i;
        int font_flag = 0;
  
        data->toth = fonth;
        data->lineh = h;
  
-       /* compute position */
-       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);
+       /* 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
  
-       /* clip with window boundaries */
-       if (rect_i.xmax > winx) {
-               /* super size */
-               if (rect_i.xmax > winx + rect_i.xmin) {
-                       rect_i.xmax = winx;
-                       rect_i.xmin = 0;
-               }
-               else {
-                       rect_i.xmin -= rect_i.xmax - winx;
-                       rect_i.xmax = winx;
-               }
-       }
-       /* ensure at least 5 px above screen bounds
-        * 25 is just a guess to be above the menu item */
-       if (rect_i.ymin < 5) {
-               rect_i.ymax += (-rect_i.ymin) + 30;
-               rect_i.ymin = 30;
+       /* 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);
        }
  
        /* add padding */
        }
  
        /* adds subwindow */
 -      ED_region_init(C, ar);
 +      ED_region_init(ar);
  
        /* notify change and redraw */
        ED_region_tag_redraw(ar);
@@@ -1133,14 -735,9 +1130,14 @@@ ARegion *UI_tooltip_create_from_button(
        }
        uiTooltipData *data = NULL;
  
 +      if (data == NULL) {
 +              data = ui_tooltip_data_from_tool(C, but);
 +      }
 +
        if (data == NULL) {
                data = ui_tooltip_data_from_button(C, but);
        }
 +
        if (data == NULL) {
                return NULL;
        }
        return ui_tooltip_create_with_data(C, data, init_position, aspect);
  }
  
 +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];
 +
 +      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;
 +
 +      return ui_tooltip_create_with_data(C, data, init_position, aspect);
 +}
 +
  void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar)
  {
        ui_region_temp_remove(C, sc, ar);