UI: IDSearch Image Thumbnail Tooltips
Hover tooltips for the Data-block ID selector showing previews for images, movies, and fonts and also showing extra details. Pull Request: https://projects.blender.org/blender/blender/pulls/118945
This commit is contained in:
committed by
Harley Acheson
parent
79244e5632
commit
8937c0bcab
@@ -175,6 +175,15 @@ ImBuf *BKE_image_acquire_multilayer_view_ibuf(const RenderData &render_data,
|
||||
|
||||
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock);
|
||||
|
||||
/**
|
||||
* Return image buffer of preview for given image
|
||||
* r_width & r_height are optional and return the _original size_ of the image.
|
||||
*/
|
||||
struct ImBuf *BKE_image_preview(struct Image *ima,
|
||||
short max_size,
|
||||
short *r_width,
|
||||
short *r_height);
|
||||
|
||||
struct ImagePool *BKE_image_pool_new(void);
|
||||
void BKE_image_pool_free(struct ImagePool *pool);
|
||||
struct ImBuf *BKE_image_pool_acquire_ibuf(struct Image *ima,
|
||||
|
||||
@@ -4902,6 +4902,31 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser)
|
||||
return ibuf != nullptr;
|
||||
}
|
||||
|
||||
ImBuf *BKE_image_preview(Image *ima, const short max_size, short *r_width, short *r_height)
|
||||
{
|
||||
void *lock;
|
||||
ImBuf *image_ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock);
|
||||
if (image_ibuf == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ImBuf *preview = IMB_dupImBuf(image_ibuf);
|
||||
float scale = float(max_size) / float(std::max(image_ibuf->x, image_ibuf->y));
|
||||
if (r_width) {
|
||||
*r_width = image_ibuf->x;
|
||||
}
|
||||
if (r_height) {
|
||||
*r_height = image_ibuf->y;
|
||||
}
|
||||
BKE_image_release_ibuf(ima, image_ibuf, lock);
|
||||
|
||||
/* Resize. */
|
||||
IMB_scaleImBuf(preview, scale * image_ibuf->x, scale * image_ibuf->y);
|
||||
IMB_rect_from_float(preview);
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -3322,15 +3322,6 @@ ARegion *UI_tooltip_create_from_button_or_extra_icon(
|
||||
ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz);
|
||||
void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region);
|
||||
|
||||
struct uiSearchItemTooltipData {
|
||||
/** A description for the item, e.g. what happens when selecting it. */
|
||||
char description[UI_MAX_DRAW_STR];
|
||||
/* The full name of the item, without prefixes or suffixes (e.g. hint with UI_SEP_CHARP). */
|
||||
const char *name;
|
||||
/** Additional info about the item (e.g. library name of a linked data-block). */
|
||||
char hint[UI_MAX_DRAW_STR];
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a tooltip from search-item tooltip data \a item_tooltip data.
|
||||
* To be called from a callback set with #UI_but_func_search_set_tooltip().
|
||||
@@ -3338,11 +3329,10 @@ struct uiSearchItemTooltipData {
|
||||
* \param item_rect: Rectangle of the search item in search region space (#ui_searchbox_butrect())
|
||||
* which is passed to the tooltip callback.
|
||||
*/
|
||||
ARegion *UI_tooltip_create_from_search_item_generic(
|
||||
bContext *C,
|
||||
const ARegion *searchbox_region,
|
||||
const rcti *item_rect,
|
||||
const uiSearchItemTooltipData *item_tooltip_data);
|
||||
ARegion *UI_tooltip_create_from_search_item_generic(bContext *C,
|
||||
const ARegion *searchbox_region,
|
||||
const rcti *item_rect,
|
||||
ID *id);
|
||||
|
||||
/* How long before a tool-tip shows. */
|
||||
#define UI_TOOLTIP_DELAY 0.5
|
||||
|
||||
@@ -31,28 +31,35 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_idtype.hh"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_paint.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BIF_glutil.hh"
|
||||
|
||||
#include "DNA_vfont_types.h"
|
||||
|
||||
#include "GPU_immediate.hh"
|
||||
#include "GPU_immediate_util.hh"
|
||||
#include "GPU_state.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_thumbs.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_path.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
@@ -1589,23 +1596,193 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
|
||||
return ui_tooltip_create_with_data(C, data, init_position, nullptr, aspect);
|
||||
}
|
||||
|
||||
static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
|
||||
const uiSearchItemTooltipData *item_tooltip_data)
|
||||
static void ui_tooltip_from_image(Image &ima, uiTooltipData &data)
|
||||
{
|
||||
if (ima.filepath[0]) {
|
||||
char root[FILE_MAX];
|
||||
BLI_path_split_dir_part(ima.filepath, root, FILE_MAX);
|
||||
UI_tooltip_text_field_add(&data, root, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
}
|
||||
|
||||
std::string image_type;
|
||||
switch (ima.source) {
|
||||
case IMA_SRC_FILE:
|
||||
image_type = TIP_("Single Image");
|
||||
break;
|
||||
case IMA_SRC_SEQUENCE:
|
||||
image_type = TIP_("Image Sequence");
|
||||
break;
|
||||
case IMA_SRC_MOVIE:
|
||||
image_type = TIP_("Movie");
|
||||
break;
|
||||
case IMA_SRC_GENERATED:
|
||||
image_type = TIP_("Generated");
|
||||
break;
|
||||
case IMA_SRC_VIEWER:
|
||||
image_type = TIP_("Viewer");
|
||||
break;
|
||||
case IMA_SRC_TILED:
|
||||
image_type = TIP_("UDIM Tiles");
|
||||
break;
|
||||
}
|
||||
UI_tooltip_text_field_add(&data, image_type, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
|
||||
short w;
|
||||
short h;
|
||||
ImBuf *ibuf = BKE_image_preview(&ima, 200.0f * UI_SCALE_FAC, &w, &h);
|
||||
|
||||
if (ibuf) {
|
||||
UI_tooltip_text_field_add(
|
||||
&data, fmt::format("{} \u00D7 {}", w, h), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
}
|
||||
|
||||
if (BKE_image_has_anim(&ima)) {
|
||||
ImBufAnim *anim = static_cast<ImBufAnim *>(ima.anims.first);
|
||||
if (anim) {
|
||||
int duration = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN);
|
||||
UI_tooltip_text_field_add(
|
||||
&data, fmt::format("Frames: {}", duration), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
UI_tooltip_text_field_add(
|
||||
&data, ima.colorspace_settings.name, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
|
||||
UI_tooltip_text_field_add(
|
||||
&data, fmt::format(TIP_("Users: {}"), ima.id.us), {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
|
||||
if (ibuf) {
|
||||
uiTooltipImage image_data;
|
||||
image_data.width = int(ibuf->x);
|
||||
image_data.height = int(ibuf->y);
|
||||
image_data.ibuf = ibuf;
|
||||
image_data.border = true;
|
||||
image_data.background = uiTooltipImageBackground::Checkerboard_Themed;
|
||||
image_data.premultiplied = true;
|
||||
UI_tooltip_text_field_add(&data, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
|
||||
UI_tooltip_text_field_add(&data, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
|
||||
UI_tooltip_image_field_add(&data, image_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_tooltip_from_clip(MovieClip &clip, uiTooltipData &data)
|
||||
{
|
||||
if (clip.filepath[0]) {
|
||||
char root[FILE_MAX];
|
||||
BLI_path_split_dir_part(clip.filepath, root, FILE_MAX);
|
||||
UI_tooltip_text_field_add(&data, root, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
}
|
||||
|
||||
std::string image_type;
|
||||
switch (clip.source) {
|
||||
case IMA_SRC_SEQUENCE:
|
||||
image_type = TIP_("Image Sequence");
|
||||
break;
|
||||
case IMA_SRC_MOVIE:
|
||||
image_type = TIP_("Movie");
|
||||
break;
|
||||
}
|
||||
UI_tooltip_text_field_add(&data, image_type, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL);
|
||||
|
||||
if (clip.anim) {
|
||||
ImBufAnim *anim = clip.anim;
|
||||
|
||||
UI_tooltip_text_field_add(&data,
|
||||
fmt::format("{} \u00D7 {}",
|
||||
IMB_anim_get_image_width(anim),
|
||||
IMB_anim_get_image_height(anim)),
|
||||
{},
|
||||
UI_TIP_STYLE_NORMAL,
|
||||
UI_TIP_LC_NORMAL);
|
||||
|
||||
UI_tooltip_text_field_add(
|
||||
&data,
|
||||
fmt::format("Frames: {}", IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN)),
|
||||
{},
|
||||
UI_TIP_STYLE_NORMAL,
|
||||
UI_TIP_LC_NORMAL);
|
||||
|
||||
ImBuf *ibuf = IMB_anim_previewframe(anim);
|
||||
|
||||
if (ibuf) {
|
||||
/* Resize. */
|
||||
float scale = float(200.0f * UI_SCALE_FAC) / float(std::max(ibuf->x, ibuf->y));
|
||||
IMB_scaleImBuf(ibuf, scale * ibuf->x, scale * ibuf->y);
|
||||
IMB_rect_from_float(ibuf);
|
||||
|
||||
uiTooltipImage image_data;
|
||||
image_data.width = int(ibuf->x);
|
||||
image_data.height = int(ibuf->y);
|
||||
image_data.ibuf = ibuf;
|
||||
image_data.border = true;
|
||||
image_data.background = uiTooltipImageBackground::Checkerboard_Themed;
|
||||
image_data.premultiplied = true;
|
||||
UI_tooltip_text_field_add(&data, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
|
||||
UI_tooltip_text_field_add(&data, {}, {}, UI_TIP_STYLE_SPACER, UI_TIP_LC_NORMAL);
|
||||
UI_tooltip_image_field_add(&data, image_data);
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_tooltip_from_vfont(VFont &font, uiTooltipData &data)
|
||||
{
|
||||
if (!font.filepath[0]) {
|
||||
/* Let's not bother with packed files _for now_.*/
|
||||
return;
|
||||
}
|
||||
|
||||
float color[4];
|
||||
const uiWidgetColors *theme = ui_tooltip_get_theme();
|
||||
rgba_uchar_to_float(color, theme->text);
|
||||
ImBuf *ibuf = IMB_font_preview(font.filepath, 200 * UI_SCALE_FAC, color);
|
||||
if (ibuf) {
|
||||
uiTooltipImage image_data;
|
||||
image_data.width = ibuf->x;
|
||||
image_data.height = ibuf->y;
|
||||
image_data.ibuf = ibuf;
|
||||
image_data.border = false;
|
||||
image_data.background = uiTooltipImageBackground::None;
|
||||
image_data.premultiplied = false;
|
||||
image_data.text_color = true;
|
||||
UI_tooltip_image_field_add(&data, image_data);
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
}
|
||||
|
||||
static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(ID *id)
|
||||
{
|
||||
uiTooltipData *data = MEM_new<uiTooltipData>(__func__);
|
||||
const ID_Type type_id = GS(id->name);
|
||||
|
||||
if (item_tooltip_data->description[0]) {
|
||||
UI_tooltip_text_field_add(
|
||||
data, item_tooltip_data->description, {}, UI_TIP_STYLE_HEADER, UI_TIP_LC_NORMAL, true);
|
||||
UI_tooltip_text_field_add(data, id->name + 2, {}, UI_TIP_STYLE_HEADER, UI_TIP_LC_MAIN);
|
||||
|
||||
if (type_id == ID_IM) {
|
||||
ui_tooltip_from_image(*reinterpret_cast<Image *>(id), *data);
|
||||
}
|
||||
else if (type_id == ID_MC) {
|
||||
ui_tooltip_from_clip(*reinterpret_cast<MovieClip *>(id), *data);
|
||||
}
|
||||
else if (type_id == ID_VF) {
|
||||
ui_tooltip_from_vfont(*reinterpret_cast<VFont *>(id), *data);
|
||||
}
|
||||
else {
|
||||
UI_tooltip_text_field_add(data,
|
||||
fmt::format(TIP_("Choose {} data-block to be assigned to this user"),
|
||||
BKE_idtype_idcode_to_name(GS(id->name))),
|
||||
{},
|
||||
UI_TIP_STYLE_NORMAL,
|
||||
UI_TIP_LC_NORMAL);
|
||||
}
|
||||
|
||||
if (item_tooltip_data->name && item_tooltip_data->name[0]) {
|
||||
/** Additional info about the item (e.g. library name of a linked data-block). */
|
||||
if (ID_IS_LINKED(id)) {
|
||||
UI_tooltip_text_field_add(
|
||||
data, item_tooltip_data->name, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_VALUE, true);
|
||||
}
|
||||
if (item_tooltip_data->hint[0]) {
|
||||
UI_tooltip_text_field_add(
|
||||
data, item_tooltip_data->hint, {}, UI_TIP_STYLE_NORMAL, UI_TIP_LC_NORMAL, true);
|
||||
data,
|
||||
fmt::format(TIP_("Source library: {}\n{}"), id->lib->id.name + 2, id->lib->filepath),
|
||||
{},
|
||||
UI_TIP_STYLE_NORMAL,
|
||||
UI_TIP_LC_NORMAL);
|
||||
}
|
||||
|
||||
if (data->fields.is_empty()) {
|
||||
@@ -1615,13 +1792,12 @@ static uiTooltipData *ui_tooltip_data_from_search_item_tooltip_data(
|
||||
return data;
|
||||
}
|
||||
|
||||
ARegion *UI_tooltip_create_from_search_item_generic(
|
||||
bContext *C,
|
||||
const ARegion *searchbox_region,
|
||||
const rcti *item_rect,
|
||||
const uiSearchItemTooltipData *item_tooltip_data)
|
||||
ARegion *UI_tooltip_create_from_search_item_generic(bContext *C,
|
||||
const ARegion *searchbox_region,
|
||||
const rcti *item_rect,
|
||||
ID *id)
|
||||
{
|
||||
uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(item_tooltip_data);
|
||||
uiTooltipData *data = ui_tooltip_data_from_search_item_tooltip_data(id);
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -498,26 +498,10 @@ static void id_search_cb_objects_from_scene(const bContext *C,
|
||||
}
|
||||
|
||||
static ARegion *template_ID_search_menu_item_tooltip(
|
||||
bContext *C, ARegion *region, const rcti *item_rect, void *arg, void *active)
|
||||
bContext *C, ARegion *region, const rcti *item_rect, void * /*arg*/, void *active)
|
||||
{
|
||||
TemplateID *template_ui = static_cast<TemplateID *>(arg);
|
||||
ID *active_id = static_cast<ID *>(active);
|
||||
StructRNA *type = RNA_property_pointer_type(&template_ui->ptr, template_ui->prop);
|
||||
|
||||
uiSearchItemTooltipData tooltip_data = {{0}};
|
||||
|
||||
tooltip_data.name = active_id->name + 2;
|
||||
SNPRINTF(tooltip_data.description,
|
||||
TIP_("Choose %s data-block to be assigned to this user"),
|
||||
RNA_struct_ui_name(type));
|
||||
if (ID_IS_LINKED(active_id)) {
|
||||
SNPRINTF(tooltip_data.hint,
|
||||
TIP_("Source library: %s\n%s"),
|
||||
active_id->lib->id.name + 2,
|
||||
active_id->lib->filepath);
|
||||
}
|
||||
|
||||
return UI_tooltip_create_from_search_item_generic(C, region, item_rect, &tooltip_data);
|
||||
return UI_tooltip_create_from_search_item_generic(C, region, item_rect, active_id);
|
||||
}
|
||||
|
||||
/* ID Search browse menu, open */
|
||||
|
||||
@@ -91,6 +91,8 @@ ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const
|
||||
ImBuf *IMB_thumb_load_font(const char *filename, unsigned int x, unsigned int y);
|
||||
bool IMB_thumb_load_font_get_hash(char *r_hash);
|
||||
|
||||
ImBuf *IMB_font_preview(const char *filename, unsigned int width, float color[4]);
|
||||
|
||||
/* Threading */
|
||||
|
||||
void IMB_thumb_locks_acquire();
|
||||
|
||||
@@ -45,3 +45,40 @@ bool IMB_thumb_load_font_get_hash(char *r_hash)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ImBuf *IMB_font_preview(const char *filename, unsigned int width, float color[4])
|
||||
{
|
||||
int font_id = (filename[0] != '<') ? BLF_load(filename) : 0;
|
||||
const char sample[] = "ABCDEFGH\nabcdefg123";
|
||||
|
||||
BLF_buffer_col(font_id, color);
|
||||
|
||||
BLF_size(font_id, 50.0f);
|
||||
BLF_enable(font_id, BLF_WORD_WRAP);
|
||||
float name_w;
|
||||
float name_h;
|
||||
BLF_width_and_height(font_id, sample, sizeof(sample), &name_w, &name_h);
|
||||
float scale = float(width) / name_w;
|
||||
BLF_size(font_id, scale * 50.0f);
|
||||
name_w *= scale;
|
||||
name_h *= scale;
|
||||
|
||||
int height = int(name_h * 1.3f);
|
||||
ImBuf *ibuf = IMB_allocImBuf(width, height, 32, IB_rect);
|
||||
/* fill with white and zero alpha */
|
||||
const float col[4] = {1.0f, 1.0f, 1.0f, 0.0f};
|
||||
IMB_rectfill(ibuf, col);
|
||||
|
||||
BLF_buffer(font_id, ibuf->float_buffer.data, ibuf->byte_buffer.data, width, height, nullptr);
|
||||
|
||||
BLF_position(font_id, 0.0f, name_h * 0.8f, 0.0f);
|
||||
BLF_draw_buffer(font_id, sample, 1024);
|
||||
|
||||
BLF_buffer(font_id, nullptr, nullptr, 0, 0, nullptr);
|
||||
|
||||
if (font_id != 0) {
|
||||
BLF_unload_id(font_id);
|
||||
}
|
||||
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user