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 97 additions and 56 deletions

View File

@ -1722,6 +1722,22 @@ enum uiTooltipColorID {
UI_TIP_LC_MAX
};
enum class uiTooltipImageBackground {
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, }; ```
None = 0,
Checkerboard_Themed,
Checkerboard_Fixed,
};
struct uiTooltipImage {
ImBuf *ibuf = nullptr;
short width = 0;
short height = 0;
bool premultiplied = false;
bool border = false;
bool text_color = false;
uiTooltipImageBackground background = uiTooltipImageBackground::None;
};
void UI_but_func_tooltip_custom_set(uiBut *but,
uiButToolTipCustomFunc func,
void *arg,
@ -1742,8 +1758,7 @@ 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 uiTooltipImage &image_data);
/**
* Recreate tool-tip (use to update dynamic tips)

View File

@ -90,8 +90,7 @@ struct uiTooltipField {
uint lines;
} geom;
uiTooltipFormat format;
ImBuf *image;
short image_size[2];
std::optional<uiTooltipImage> 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.
};
struct uiTooltipData {
@ -124,13 +123,12 @@ void UI_tooltip_text_field_add(uiTooltipData *data,
data->fields.append(std::move(field));
}
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 uiTooltipImage &image_data)
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
{
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.image = image_data;
field.image->ibuf = IMB_dupImBuf(image_data.ibuf);
data->fields.append(std::move(field));
}
@ -255,55 +253,69 @@ static void ui_tooltip_region_draw_cb(const bContext * /*C*/, ARegion *region)
UI_fontstyle_draw(
&fstyle_mono, &bbox, field->text.c_str(), field->text.size(), drawcol, &fs_params);
}
else if (field->format.style == UI_TIP_STYLE_IMAGE) {
else if (field->format.style == UI_TIP_STYLE_IMAGE && field->image.has_value()) {
bbox.ymax -= field->image_size[1];
bbox.ymax -= field->image->height;
/* 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->image->background == uiTooltipImageBackground::Checkerboard_Themed) {
imm_draw_box_checker_2d(float(bbox.xmin),
float(bbox.ymax),
float(bbox.xmin + field->image->width),
float(bbox.ymax + field->image->height));
}
else if (field->image->background == uiTooltipImageBackground::Checkerboard_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->width),
float(bbox.ymax + field->image->height),
color1,
color2,
8);
}
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
GPU_blend((field->image->premultiplied) ? GPU_BLEND_ALPHA_PREMULT : GPU_BLEND_ALPHA);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR);
immDrawPixelsTexScaledFullSize(&state,
bbox.xmin,
bbox.ymax,
field->image->x,
field->image->y,
field->image->ibuf->x,
field->image->ibuf->y,
GPU_RGBA8,
true,
field->image->byte_buffer.data,
field->image->ibuf->byte_buffer.data,
1.0f,
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);
float(field->image->width) / float(field->image->ibuf->x),
float(field->image->height) / float(field->image->ibuf->y),
(field->image->text_color) ? 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->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->width),
float(bbox.ymax + field->image->height));
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;
@ -332,8 +344,8 @@ static void ui_tooltip_region_free_cb(ARegion *region)
{
uiTooltipData *data = static_cast<uiTooltipData *>(region->regiondata);
for (uiTooltipField &field : data->fields) {
if (field.image) {
IMB_freeImBuf(field.image);
if (field.image && field.image->ibuf) {
IMB_freeImBuf(field.image->ibuf);
}
}
MEM_delete(data);
@ -1212,9 +1224,9 @@ static ARegion *ui_tooltip_create_with_data(bContext *C,
fonth += h * UI_TIP_SPACER;
}
if (field->format.style == UI_TIP_STYLE_IMAGE) {
fonth += field->image_size[1];
w = max_ii(w, field->image_size[0]);
if (field->format.style == UI_TIP_STYLE_IMAGE && field->image) {
fonth += field->image->height;
w = max_ii(w, field->image->width);
}
fontw = max_ii(fontw, w);

View File

@ -6895,11 +6895,18 @@ static void uiTemplateRecentFiles_tooltip_func(bContext * /*C*/, uiTooltipData *
}
if (thumb) {
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);
uiTooltipImage image_data;
float scale = (72.0f * UI_SCALE_FAC) / float(std::max(thumb->x, thumb->y));
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);
image_data.ibuf = thumb;
image_data.width = short(float(thumb->x) * scale);
image_data.height = short(float(thumb->y) * scale);
image_data.border = true;
image_data.background = uiTooltipImageBackground::Checkerboard_Themed;
image_data.premultiplied = true;
UI_tooltip_image_field_add(tip, image_data);
IMB_freeImBuf(thumb);
}
}

View File

@ -309,11 +309,18 @@ static void file_draw_tooltip_custom_func(bContext * /*C*/, uiTooltipData *tip,
}
if (thumb && params->display != FILE_IMGDISPLAY) {
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);
uiTooltipImage image_data;
float scale = (96.0f * UI_SCALE_FAC) / float(std::max(thumb->x, thumb->y));
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);
image_data.ibuf = thumb;
image_data.width = short(float(thumb->x) * scale);
image_data.height = short(float(thumb->y) * scale);
image_data.border = true;
image_data.background = uiTooltipImageBackground::Checkerboard_Themed;
image_data.premultiplied = true;
UI_tooltip_image_field_add(tip, image_data);
}
if (thumb && free_imbuf) {