UI: Add Optional Flags for Tooltip Image Fields #119437

Merged
Harley Acheson merged 5 commits from Harley/blender:TooltipImageFlags into main 2024-03-18 22:17:59 +01:00
4 changed files with 79 additions and 33 deletions
Showing only changes of commit 93d62db382 - Show all commits

View File

@ -1722,6 +1722,21 @@ enum uiTooltipColorID {
UI_TIP_LC_MAX
};
enum uiTooltipFlag {
Harley marked this conversation as resolved Outdated

How about this :)

enum class uiTooltipImageBackground {
  None = 0,
  Themed = 1,
  Fixed = 2,
};
How about this :) ``` enum class uiTooltipImageBackground { None = 0, Themed = 1, Fixed = 2, }; ```
UI_TIP_FLAG_NONE = 0,
/* Regular checkerboard pattern, with themed colors. */
UI_TIP_FLAG_IMAGE_CHECKER = 1 << 0,
/* Checkerboard pattern with fixed colors used for themes. */
UI_TIP_FLAG_IMAGE_CHECKER_FIXED = 1 << 1,
/* Border around the image. */
UI_TIP_FLAG_IMAGE_BORDER = 1 << 2,
/* Blend as premultiplied alpha. */
UI_TIP_FLAG_IMAGE_PREMULTIPLIED = 1 << 3,
/* Recolor the image with text color. */
UI_TIP_FLAG_IMAGE_TEXTCOLOR = 1 << 4,
};
ENUM_OPERATORS(uiTooltipFlag, UI_TIP_FLAG_IMAGE_TEXTCOLOR)
void UI_but_func_tooltip_custom_set(uiBut *but,
uiButToolTipCustomFunc func,
void *arg,
@ -1742,8 +1757,10 @@ void UI_tooltip_text_field_add(uiTooltipData *data,
* \param image: Image buffer (duplicated, ownership is *not* transferred to `data`).
* \param image_size: Display size for the image (pixels without UI scale applied).
*/
void UI_tooltip_image_field_add(uiTooltipData *data, const ImBuf *image, const short image_size[2])
ATTR_NONNULL(1, 2, 3);
void UI_tooltip_image_field_add(uiTooltipData *data,
const ImBuf *image,
const short image_size[2],
uiTooltipFlag flag = UI_TIP_FLAG_NONE) ATTR_NONNULL(1, 2, 3);
/**
* Recreate tool-tip (use to update dynamic tips)

View File

@ -92,6 +92,7 @@ struct uiTooltipField {
uiTooltipFormat format;
ImBuf *image;
Harley marked this conversation as resolved Outdated

std::optional seems simpler here than allocating a struct. I don't see a matching delete in this PR, so I'd expect a memory leak currently.

`std::optional` seems simpler here than allocating a struct. I don't see a matching `delete` in this PR, so I'd expect a memory leak currently.
short image_size[2];
uiTooltipFlag flag = UI_TIP_FLAG_NONE;
};
struct uiTooltipData {
@ -124,13 +125,17 @@ void UI_tooltip_text_field_add(uiTooltipData *data,
data->fields.append(std::move(field));
}
Harley marked this conversation as resolved Outdated

Think I'd pass this by const reference, it's not a small struct and it's not being std::moved here

Think I'd pass this by const reference, it's not a small struct and it's not being `std::move`d here
void UI_tooltip_image_field_add(uiTooltipData *data, const ImBuf *image, const short image_size[2])
void UI_tooltip_image_field_add(uiTooltipData *data,
const ImBuf *image,
const short image_size[2],
uiTooltipFlag flag)
{
uiTooltipField field{};
field.format.style = UI_TIP_STYLE_IMAGE;
field.image = IMB_dupImBuf(image);
field.image_size[0] = std::min(image_size[0], short(UI_TIP_MAXIMAGEWIDTH * UI_SCALE_FAC));
field.image_size[1] = std::min(image_size[1], short(UI_TIP_MAXIMAGEHEIGHT * UI_SCALE_FAC));
field.flag = flag;
data->fields.append(std::move(field));
}
@ -259,13 +264,28 @@ static void ui_tooltip_region_draw_cb(const bContext * /*C*/, ARegion *region)
bbox.ymax -= field->image_size[1];
/* Draw checker pattern behind the image in case is has transparency. */
imm_draw_box_checker_2d(float(bbox.xmin),
float(bbox.ymax),
float(bbox.xmin + field->image_size[0]),
float(bbox.ymax + field->image_size[1]));
if (field->flag & UI_TIP_FLAG_IMAGE_CHECKER) {
imm_draw_box_checker_2d(float(bbox.xmin),
float(bbox.ymax),
float(bbox.xmin + field->image_size[0]),
float(bbox.ymax + field->image_size[1]));
}
else if (field->flag & UI_TIP_FLAG_IMAGE_CHECKER_FIXED) {
const float checker_dark = UI_ALPHA_CHECKER_DARK / 255.0f;
const float checker_light = UI_ALPHA_CHECKER_LIGHT / 255.0f;
const float color1[4] = {checker_dark, checker_dark, checker_dark, 1.0f};
const float color2[4] = {checker_light, checker_light, checker_light, 1.0f};
imm_draw_box_checker_2d_ex(float(bbox.xmin + U.pixelsize),
float(bbox.ymax + U.pixelsize),
float(bbox.xmin + field->image_size[0]),
float(bbox.ymax + field->image_size[1]),
color1,
color2,
8);
}
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
GPU_blend((field->flag & UI_TIP_FLAG_IMAGE_PREMULTIPLIED) ? GPU_BLEND_ALPHA_PREMULT :
GPU_BLEND_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexScaledFullSize(&state,
@ -280,30 +300,31 @@ static void ui_tooltip_region_draw_cb(const bContext * /*C*/, ARegion *region)
1.0f,
float(field->image_size[0]) / float(field->image->x),
float(field->image_size[1]) / float(field->image->y),
nullptr);
GPU_blend(GPU_BLEND_ALPHA);
(field->flag & UI_TIP_FLAG_IMAGE_TEXTCOLOR) ? main_color :
nullptr);
/* Draw border around it. */
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float border_color[4] = {1.0f, 1.0f, 1.0f, 0.15f};
float bgcolor[4];
UI_GetThemeColor4fv(TH_BACK, bgcolor);
if (rgb_to_grayscale(bgcolor) > 0.5f) {
border_color[0] = 0.0f;
border_color[1] = 0.0f;
border_color[2] = 0.0f;
if (field->flag & UI_TIP_FLAG_IMAGE_BORDER) {
GPU_blend(GPU_BLEND_ALPHA);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
float border_color[4] = {1.0f, 1.0f, 1.0f, 0.15f};
float bgcolor[4];
UI_GetThemeColor4fv(TH_BACK, bgcolor);
if (rgb_to_grayscale(bgcolor) > 0.5f) {
border_color[0] = 0.0f;
border_color[1] = 0.0f;
border_color[2] = 0.0f;
}
immUniformColor4fv(border_color);
imm_draw_box_wire_2d(pos,
float(bbox.xmin),
float(bbox.ymax),
float(bbox.xmin + field->image_size[0]),
float(bbox.ymax + field->image_size[1]));
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
immUniformColor4fv(border_color);
imm_draw_box_wire_2d(pos,
float(bbox.xmin),
float(bbox.ymax),
float(bbox.xmin + field->image_size[0]),
float(bbox.ymax + field->image_size[1]));
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
else if (field->format.style == UI_TIP_STYLE_SPACER) {
bbox.ymax -= data->lineh * UI_TIP_SPACER;

View File

@ -6899,7 +6899,11 @@ static void uiTemplateRecentFiles_tooltip_func(bContext * /*C*/, uiTooltipData *
short size[2] = {short(float(thumb->x) * scale), short(float(thumb->y) * scale)};
UI_tooltip_text_field_add(tip, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
UI_tooltip_text_field_add(tip, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
UI_tooltip_image_field_add(tip, thumb, size);
UI_tooltip_image_field_add(tip,
thumb,
size,
UI_TIP_FLAG_IMAGE_CHECKER | UI_TIP_FLAG_IMAGE_PREMULTIPLIED |
UI_TIP_FLAG_IMAGE_BORDER);
IMB_freeImBuf(thumb);
}
}

View File

@ -313,7 +313,11 @@ static void file_draw_tooltip_custom_func(bContext * /*C*/, uiTooltipData *tip,
short size[2] = {short(float(thumb->x) * scale), short(float(thumb->y) * scale)};
UI_tooltip_text_field_add(tip, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
UI_tooltip_text_field_add(tip, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
UI_tooltip_image_field_add(tip, thumb, size);
UI_tooltip_image_field_add(tip,
thumb,
size,
UI_TIP_FLAG_IMAGE_CHECKER | UI_TIP_FLAG_IMAGE_PREMULTIPLIED |
UI_TIP_FLAG_IMAGE_BORDER);
}
if (thumb && free_imbuf) {