Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface')
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface.cc20
-rw-r--r--source/blender/editors/interface/interface_context_path.cc14
-rw-r--r--source/blender/editors/interface/interface_handlers.c6
-rw-r--r--source/blender/editors/interface/interface_icons.c121
-rw-r--r--source/blender/editors/interface/interface_intern.h14
-rw-r--r--source/blender/editors/interface/interface_layout.c12
-rw-r--r--source/blender/editors/interface/interface_ops.cc5
-rw-r--r--source/blender/editors/interface/interface_panel.cc6
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.cc298
-rw-r--r--source/blender/editors/interface/interface_widgets.c15
-rw-r--r--source/blender/editors/interface/views/interface_view.cc2
12 files changed, 371 insertions, 144 deletions
diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
index 3fb5a74944b..c6d950112b9 100644
--- a/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
@@ -162,7 +162,7 @@ static void depthdropper_depth_sample_pt(bContext *C,
View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
/* weak, we could pass in some reference point */
- const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
+ const float *view_co = v3d->camera ? v3d->camera->object_to_world[3] : rv3d->viewinv[3];
const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
copy_v2_v2_int(ddr->name_pos, mval);
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index 422fc34aa50..331d1581db5 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -3474,6 +3474,7 @@ void UI_block_free(const bContext *C, uiBlock *block)
BLI_freelistN(&block->saferct);
BLI_freelistN(&block->color_pickers.list);
+ BLI_freelistN(&block->dynamic_listeners);
ui_block_free_button_groups(block);
ui_block_free_views(block);
@@ -3481,6 +3482,20 @@ void UI_block_free(const bContext *C, uiBlock *block)
MEM_freeN(block);
}
+void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+{
+ /* Don't need to let invisible blocks (old blocks from previous redraw) listen. */
+ if (!block->active) {
+ return;
+ }
+
+ LISTBASE_FOREACH (uiBlockDynamicListener *, listener, &block->dynamic_listeners) {
+ listener->listener_func(listener_params);
+ }
+
+ ui_block_views_listen(block, listener_params);
+}
+
void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
{
ARegion *region = CTX_wm_region(C);
@@ -6452,6 +6467,11 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string)
ui_but_add_shortcut(but, string, false);
}
+void UI_but_icon_indicator_number_set(uiBut *but, const int indicator_number)
+{
+ UI_icon_text_overlay_init_from_count(&but->icon_overlay_text, indicator_number);
+}
+
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
{
but->flag |= UI_BUT_NODE_LINK;
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
index e8f552e26a3..74a07d6edc8 100644
--- a/source/blender/editors/interface/interface_context_path.cc
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -17,6 +17,8 @@
#include "UI_interface.hh"
#include "UI_resources.h"
+#include "RNA_prototypes.h"
+
#include "WM_api.h"
namespace blender::ui {
@@ -41,7 +43,13 @@ void context_path_add_generic(Vector<ContextPathItem> &path,
static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
icon_override;
- path.append({name, int(icon)});
+ if (&rna_type == &RNA_NodeTree) {
+ ID *id = (ID *)ptr;
+ path.append({name, int(icon), ID_REAL_USERS(id)});
+ }
+ else {
+ path.append({name, int(icon), 1});
+ }
}
/* -------------------------------------------------------------------- */
@@ -60,7 +68,9 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
if (i > 0) {
uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
}
- uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ uiBut *but = uiItemL_ex(
+ sub_row, context_path[i].name.c_str(), context_path[i].icon, false, false);
+ UI_but_icon_indicator_number_set(but, context_path[i].icon_indicator_number);
}
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 34f33b71fb8..ac16d41dabe 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3519,7 +3519,7 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
{
- /* label and roundbox can overlap real buttons (backdrops...) */
+ /* Label and round-box can overlap real buttons (backdrops...). */
if (ELEM(actbut->type,
UI_BTYPE_LABEL,
UI_BTYPE_SEPR,
@@ -3551,7 +3551,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data)
{
- /* label and roundbox can overlap real buttons (backdrops...) */
+ /* Label and round-box can overlap real buttons (backdrops...). */
if (ELEM(actbut->type,
UI_BTYPE_LABEL,
UI_BTYPE_SEPR,
@@ -3894,7 +3894,7 @@ static void ui_do_but_textedit(
}
if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) {
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
- strcmp(ime_data->str_result, "\xE3\x80\x82") == 0) {
+ STREQ(ime_data->str_result, "\xE3\x80\x82")) {
/* Convert Ideographic Full Stop (U+3002) to decimal point when entering numbers. */
ui_textedit_insert_ascii(but, data, '.');
}
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index c080dce0f08..9a4f98ebcd6 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -415,8 +415,15 @@ static void vicon_collection_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_OUTLINER_COLLECTION, aspect, 1.0f, 0.0f, collection_color->color, true);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_OUTLINER_COLLECTION,
+ aspect,
+ 1.0f,
+ 0.0f,
+ collection_color->color,
+ true,
+ UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \
@@ -444,7 +451,8 @@ static void vicon_strip_color_draw(
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true);
+ UI_icon_draw_ex(
+ x, y, ICON_SNAP_FACE, aspect, 1.0f, 0.0f, strip_color->color, true, UI_NO_ICON_OVERLAY_TEXT);
}
# define DEF_ICON_STRIP_COLOR_DRAW(index, color) \
@@ -472,8 +480,15 @@ static void vicon_strip_color_draw_library_data_indirect(
{
const float aspect = (float)ICON_DEFAULT_WIDTH / (float)w;
- UI_icon_draw_ex(
- x, y, ICON_LIBRARY_DATA_DIRECT, aspect, ICON_INDIRECT_DATA_ALPHA * alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x,
+ y,
+ ICON_LIBRARY_DATA_DIRECT,
+ aspect,
+ ICON_INDIRECT_DATA_ALPHA * alpha,
+ 0.0f,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
static void vicon_strip_color_draw_library_data_override_noneditable(
@@ -488,7 +503,8 @@ static void vicon_strip_color_draw_library_data_override_noneditable(
ICON_INDIRECT_DATA_ALPHA * alpha * 0.75f,
0.0f,
NULL,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
/* Dynamically render icon instead of rendering a plain color to a texture/buffer
@@ -923,7 +939,7 @@ static void init_internal_icons(void)
char iconfilestr[FILE_MAX];
if (icondir) {
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
/* if the image is missing bbuf will just be NULL */
bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL);
@@ -1047,7 +1063,7 @@ static void init_iconfile_list(struct ListBase *list)
/* check to see if the image is the right size, continue if not */
/* copying strings here should go ok, assuming that we never get back
* a complete path to file longer than 256 chars */
- BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename);
+ BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, filename);
bbuf = IMB_loadiffname(iconfilestr, IB_rect);
if (bbuf) {
@@ -1716,9 +1732,47 @@ static void icon_draw_texture(float x,
int ih,
float alpha,
const float rgb[3],
- bool with_border)
-{
- if (g_icon_draw_cache.enabled) {
+ bool with_border,
+ const IconTextOverlay *text_overlay)
+{
+ const float zoom_factor = w / UI_DPI_ICON_SIZE;
+ float text_width = 0.0f;
+
+ /* No need to show if too zoomed out, otherwise it just adds noise. */
+ const bool show_indicator = (text_overlay && text_overlay->text[0] != '\0') &&
+ (zoom_factor > 0.7f);
+
+ if (show_indicator) {
+ /* Handle the little numbers on top of the icon. */
+ uchar text_color[4];
+ UI_GetThemeColor3ubv(TH_TEXT, text_color);
+ text_color[3] = 255;
+
+ uiFontStyle fstyle_small = *UI_FSTYLE_WIDGET;
+ fstyle_small.points *= zoom_factor;
+ fstyle_small.points *= 0.8f;
+
+ rcti text_rect = {
+ .xmax = x + UI_UNIT_X * zoom_factor,
+ .xmin = x,
+ .ymax = y,
+ .ymin = y,
+ };
+
+ UI_fontstyle_draw(&fstyle_small,
+ &text_rect,
+ text_overlay->text,
+ sizeof(text_overlay->text),
+ text_color,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_RIGHT,
+ });
+ text_width = (float)UI_fontstyle_string_width(&fstyle_small, text_overlay->text) / UI_UNIT_X /
+ zoom_factor;
+ }
+
+ /* Draw the actual icon. */
+ if (!show_indicator && g_icon_draw_cache.enabled) {
icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border);
return;
}
@@ -1735,7 +1789,7 @@ static void icon_draw_texture(float x,
GPUTexture *texture = with_border ? icongltex.tex[1] : icongltex.tex[0];
- GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_ICON);
GPU_shader_bind(shader);
const int img_binding = GPU_shader_get_texture_binding(shader, "image");
@@ -1752,6 +1806,7 @@ static void icon_draw_texture(float x,
GPU_shader_uniform_vector(shader, rect_tex_loc, 4, 1, (float[4]){x1, y1, x2, y2});
GPU_shader_uniform_vector(shader, rect_geom_loc, 4, 1, (float[4]){x, y, x + w, y + h});
+ GPU_shader_uniform_1f(shader, "text_width", text_width);
GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false);
@@ -1786,7 +1841,8 @@ static void icon_draw_size(float x,
int draw_size,
const float desaturate,
const uchar mono_rgba[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
bTheme *btheme = UI_GetTheme();
const float fdraw_size = (float)draw_size;
@@ -1874,7 +1930,8 @@ static void icon_draw_size(float x,
di->data.texture.h,
alpha,
NULL,
- false);
+ false,
+ text_overlay);
}
else if (di->type == ICON_TYPE_MONO_TEXTURE) {
/* Monochrome icon that uses text or theme color. */
@@ -1908,7 +1965,8 @@ static void icon_draw_size(float x,
di->data.texture.h + 2 * border_texel,
color[3],
color,
- with_border);
+ with_border,
+ text_overlay);
}
else if (di->type == ICON_TYPE_BUFFER) {
@@ -2425,17 +2483,27 @@ int UI_icon_color_from_collection(const Collection *collection)
void UI_icon_draw(float x, float y, int icon_id)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
{
- UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
+ UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false, UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
{
- icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
+ icon_draw_size(x,
+ y,
+ icon_id,
+ aspect,
+ alpha,
+ ICON_SIZE_PREVIEW,
+ size,
+ false,
+ NULL,
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
}
void UI_icon_draw_ex(float x,
@@ -2445,7 +2513,8 @@ void UI_icon_draw_ex(float x,
float alpha,
float desaturate,
const uchar mono_color[4],
- const bool mono_border)
+ const bool mono_border,
+ const IconTextOverlay *text_overlay)
{
const int draw_size = get_draw_size(ICON_SIZE_ICON);
icon_draw_size(x,
@@ -2457,7 +2526,19 @@ void UI_icon_draw_ex(float x,
draw_size,
desaturate,
mono_color,
- mono_border);
+ mono_border,
+ text_overlay);
+}
+
+void UI_icon_text_overlay_init_from_count(IconTextOverlay *text_overlay,
+ const int icon_indicator_number)
+{
+ /* The icon indicator is used as an aggregator, no need to show if it is 1. */
+ if (icon_indicator_number < 2) {
+ text_overlay->text[0] = '\0';
+ return;
+ }
+ BLI_str_format_integer_unit(text_overlay->text, icon_indicator_number);
}
/* ********** Alert Icons ********** */
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 6ef7d346418..982ac1753e1 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -23,6 +23,7 @@ struct ARegion;
struct AnimationEvalContext;
struct CurveMapping;
struct CurveProfile;
+struct IconTextOverlay;
struct ID;
struct ImBuf;
struct Main;
@@ -275,6 +276,9 @@ struct uiBut {
uiButPushedStateFunc pushed_state_func;
const void *pushed_state_arg;
+ /** Little indicator (e.g., counter) displayed on top of some icons. */
+ struct IconTextOverlay icon_overlay_text;
+
/* pointer back */
uiBlock *block;
};
@@ -473,6 +477,12 @@ typedef enum uiButtonGroupFlag {
} uiButtonGroupFlag;
ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER);
+typedef struct uiBlockDynamicListener {
+ struct uiBlockDynamicListener *next, *prev;
+
+ void (*listener_func)(const struct wmRegionListenerParams *params);
+} uiBlockDynamicListener;
+
struct uiBlock {
uiBlock *next, *prev;
@@ -495,6 +505,8 @@ struct uiBlock {
* state that is persistent over redraws (e.g. collapsed tree-view items). */
ListBase views;
+ ListBase dynamic_listeners; /* #uiBlockDynamicListener */
+
char name[UI_MAX_NAME_STR];
float winmat[4][4];
@@ -1536,6 +1548,8 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
+void ui_block_views_listen(const uiBlock *block,
+ const struct wmRegionListenerParams *listener_params);
uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiViewHandle *new_view);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c906a5b36f1..a456cef7be6 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -3235,7 +3235,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
return but;
}
-void uiItemL_ex(
+uiBut *uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert)
{
uiBut *but = uiItemL_(layout, name, icon);
@@ -3248,6 +3248,8 @@ void uiItemL_ex(
if (redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
+
+ return but;
}
void uiItemL(uiLayout *layout, const char *name, int icon)
@@ -5812,6 +5814,14 @@ void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
}
+ if (mt->listener) {
+ /* Forward the menu type listener to the block we're drawing in. */
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiBlockDynamicListener *listener = MEM_mallocN(sizeof(*listener), "uiBlockDynamicListener");
+ listener->listener_func = mt->listener;
+ BLI_addtail(&block->dynamic_listeners, listener);
+ }
+
if (layout->context) {
CTX_store_set(C, layout->context);
}
diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc
index 8b29f1075b8..2d06dd2c465 100644
--- a/source/blender/editors/interface/interface_ops.cc
+++ b/source/blender/editors/interface/interface_ops.cc
@@ -1859,8 +1859,7 @@ static void edittranslation_find_po_file(const char *root,
/* First, full lang code. */
BLI_snprintf(tstr, sizeof(tstr), "%s.po", uilng);
- BLI_join_dirfile(path, maxlen, root, uilng);
- BLI_path_append(path, maxlen, tstr);
+ BLI_path_join(path, maxlen, root, uilng, tstr);
if (BLI_is_file(path)) {
return;
}
@@ -1885,7 +1884,7 @@ static void edittranslation_find_po_file(const char *root,
BLI_strncpy(tstr + szt, tc, sizeof(tstr) - szt);
}
- BLI_join_dirfile(path, maxlen, root, tstr);
+ BLI_path_join(path, maxlen, root, tstr);
strcat(tstr, ".po");
BLI_path_append(path, maxlen, tstr);
if (BLI_is_file(path)) {
diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc
index 7a69e2f9b2f..24d8281aad8 100644
--- a/source/blender/editors/interface/interface_panel.cc
+++ b/source/blender/editors/interface/interface_panel.cc
@@ -1112,7 +1112,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
0.7f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
@@ -1140,7 +1141,8 @@ static void panel_draw_aligned_widgets(const uiStyle *style,
1.0f,
0.0f,
title_color,
- false);
+ false,
+ UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc
index 569f657a544..0d19390d508 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.cc
+++ b/source/blender/editors/interface/interface_region_menu_popup.cc
@@ -10,6 +10,7 @@
#include <cstdarg>
#include <cstdlib>
#include <cstring>
+#include <functional>
#include "MEM_guardedalloc.h"
@@ -166,28 +167,80 @@ struct uiPopupMenu {
uiBut *but;
ARegion *butregion;
+ /* Menu hash is created from this, to keep a memory of recently opened menus. */
+ const char *title;
+
int mx, my;
bool popup, slideout;
- uiMenuCreateFunc menu_func;
- void *menu_arg;
+ std::function<void(bContext *C, uiLayout *layout)> menu_func;
};
+/**
+ * \param title: Optional. If set, it will be used to store recently opened menus so they can be
+ * opened with the mouse over the last chosen entry again.
+ */
+static void ui_popup_menu_create_block(bContext *C,
+ uiPopupMenu *pup,
+ const char *title,
+ const char *block_name)
+{
+ const uiStyle *style = UI_style_get_dpi();
+
+ pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN);
+ if (!pup->but) {
+ pup->block->flag |= UI_BLOCK_IS_FLIP | UI_BLOCK_NO_FLIP;
+ }
+ if (title && title[0]) {
+ pup->block->flag |= UI_BLOCK_POPUP_MEMORY;
+ pup->block->puphash = ui_popup_menu_hash(title);
+ }
+ pup->layout = UI_block_layout(
+ pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+
+ /* NOTE: this intentionally differs from the menu & sub-menu default because many operators
+ * use popups like this to select one of their options -
+ * where having invoke doesn't make sense.
+ * When the menu was opened from a button, use invoke still for compatibility. This used to be
+ * the default and changing now could cause issues. */
+ const wmOperatorCallContext opcontext = pup->but ? WM_OP_INVOKE_REGION_WIN :
+ WM_OP_EXEC_REGION_WIN;
+
+ uiLayoutSetOperatorContext(pup->layout, opcontext);
+
+ if (pup->but) {
+ if (pup->but->context) {
+ uiLayoutContextCopy(pup->layout, pup->but->context);
+ }
+ }
+}
+
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup);
- if (pup->menu_func) {
- pup->block->handle = handle;
- pup->menu_func(C, pup->layout, pup->menu_arg);
- pup->block->handle = nullptr;
+ int minwidth = 0;
+
+ if (!pup->layout) {
+ ui_popup_menu_create_block(C, pup, pup->title, __func__);
+
+ if (pup->menu_func) {
+ pup->block->handle = handle;
+ pup->menu_func(C, pup->layout);
+ pup->block->handle = nullptr;
+ }
+
+ if (uiLayoutGetUnitsX(pup->layout) != 0.0f) {
+ /* Use the minimum width from the layout if it's set. */
+ minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X;
+ }
+
+ pup->layout = nullptr;
}
/* Find block minimum width. */
- int minwidth;
- if (uiLayoutGetUnitsX(pup->layout) != 0.0f) {
- /* Use the minimum width from the layout if it's set. */
- minwidth = uiLayoutGetUnitsX(pup->layout) * UI_UNIT_X;
+ if (minwidth) {
+ /* Skip. */
}
else if (pup->but) {
/* Minimum width to enforce. */
@@ -236,7 +289,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
if (pup->popup) {
- int offset[2];
+ int offset[2] = {0, 0};
uiBut *but_activate = nullptr;
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT);
@@ -244,36 +297,42 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
UI_block_direction_set(block, direction);
/* offset the mouse position, possibly based on earlier selection */
- uiBut *bt;
- if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) {
- /* position mouse on last clicked item, at 0.8*width of the
- * button, so it doesn't overlap the text too much, also note
- * the offset is negative because we are inverse moving the
- * block to be under the mouse */
- offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect));
- offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
-
- if (ui_but_is_editable(bt)) {
- but_activate = bt;
- }
- }
- else {
- /* position mouse at 0.8*width of the button and below the tile
- * on the first item */
- offset[0] = 0;
- LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
- offset[0] = min_ii(offset[0],
- -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect)));
+ if (!handle->refresh) {
+ uiBut *bt;
+ if ((block->flag & UI_BLOCK_POPUP_MEMORY) && (bt = ui_popup_menu_memory_get(block))) {
+ /* position mouse on last clicked item, at 0.8*width of the
+ * button, so it doesn't overlap the text too much, also note
+ * the offset is negative because we are inverse moving the
+ * block to be under the mouse */
+ offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect));
+ offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
+
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ }
}
+ else {
+ /* position mouse at 0.8*width of the button and below the tile
+ * on the first item */
+ offset[0] = 0;
+ LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
+ offset[0] = min_ii(offset[0],
+ -(but_iter->rect.xmin + 0.8f * BLI_rctf_size_x(&but_iter->rect)));
+ }
- offset[1] = 2.1 * UI_UNIT_Y;
+ offset[1] = 2.1 * UI_UNIT_Y;
- LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
- if (ui_but_is_editable(but_iter)) {
- but_activate = but_iter;
- break;
+ LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
+ if (ui_but_is_editable(but_iter)) {
+ but_activate = but_iter;
+ break;
+ }
}
}
+ copy_v2_v2_int(handle->prev_bounds_offset, offset);
+ }
+ else {
+ copy_v2_v2_int(offset, handle->prev_bounds_offset);
}
/* in rare cases this is needed since moving the popup
@@ -312,27 +371,35 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
return pup->block;
}
-uiPopupBlockHandle *ui_popup_menu_create(
- bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg)
+static void ui_block_free_func_POPUP(void *arg_pup)
+{
+ uiPopupMenu *pup = static_cast<uiPopupMenu *>(arg_pup);
+ MEM_delete(pup);
+}
+
+static uiPopupBlockHandle *ui_popup_menu_create(
+ bContext *C,
+ ARegion *butregion,
+ uiBut *but,
+ const char *title,
+ std::function<void(bContext *, uiLayout *)> menu_func)
{
wmWindow *window = CTX_wm_window(C);
- const uiStyle *style = UI_style_get_dpi();
- uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
- pup->block = UI_block_begin(C, nullptr, __func__, UI_EMBOSS_PULLDOWN);
- pup->block->flag |= UI_BLOCK_NUMSELECT; /* Default menus to numeric-selection. */
- pup->layout = UI_block_layout(
- pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
- pup->slideout = but ? ui_block_is_menu(but->block) : false;
- pup->but = but;
- uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN);
+ uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__);
+ pup->title = title;
+ /* menu is created from a callback */
+ pup->menu_func = menu_func;
+ if (but) {
+ pup->slideout = ui_block_is_menu(but->block);
+ pup->but = but;
+ }
if (!but) {
/* no button to start from, means we are a popup */
pup->mx = window->eventstate->xy[0];
pup->my = window->eventstate->xy[1];
pup->popup = true;
- pup->block->flag |= UI_BLOCK_NO_FLIP;
}
/* some enums reversing is strange, currently we have no good way to
* reverse some enum's but not others, so reverse all so the first menu
@@ -346,17 +413,10 @@ uiPopupBlockHandle *ui_popup_menu_create(
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
#endif
- if (but->context) {
- uiLayoutContextCopy(pup->layout, but->context);
- }
}
- /* menu is created from a callback */
- pup->menu_func = menu_func;
- pup->menu_arg = arg;
-
uiPopupBlockHandle *handle = ui_popup_block_create(
- C, butregion, but, nullptr, ui_block_func_POPUP, pup, nullptr);
+ C, butregion, but, nullptr, ui_block_func_POPUP, pup, ui_block_free_func_POPUP);
if (!but) {
handle->popup = true;
@@ -365,68 +425,73 @@ uiPopupBlockHandle *ui_popup_menu_create(
WM_event_add_mousemove(window);
}
- MEM_freeN(pup);
-
return handle;
}
+uiPopupBlockHandle *ui_popup_menu_create(
+ bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg)
+{
+ return ui_popup_menu_create(
+ C, butregion, but, nullptr, [menu_func, arg](bContext *C, uiLayout *layout) {
+ menu_func(C, layout, arg);
+ });
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Popup Menu API with begin & end
* \{ */
+static void create_title_button(uiLayout *layout, const char *title, int icon)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ char titlestr[256];
+
+ if (icon) {
+ BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
+ uiDefIconTextBut(block,
+ UI_BTYPE_LABEL,
+ 0,
+ icon,
+ titlestr,
+ 0,
+ 0,
+ 200,
+ UI_UNIT_Y,
+ nullptr,
+ 0.0,
+ 0.0,
+ 0,
+ 0,
+ "");
+ }
+ else {
+ uiBut *but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, "");
+ but->drawflag = UI_BUT_TEXT_LEFT;
+ }
+
+ uiItemS(layout);
+}
+
+/* Used to directly create a popup menu that is not refreshed on redraw. */
uiPopupMenu *UI_popup_menu_begin_ex(bContext *C,
const char *title,
const char *block_name,
int icon)
{
- const uiStyle *style = UI_style_get_dpi();
- uiPopupMenu *pup = MEM_cnew<uiPopupMenu>(__func__);
+ uiPopupMenu *pup = MEM_new<uiPopupMenu>(__func__);
- pup->block = UI_block_begin(C, nullptr, block_name, UI_EMBOSS_PULLDOWN);
- pup->block->flag |= UI_BLOCK_POPUP_MEMORY | UI_BLOCK_IS_FLIP;
- pup->block->puphash = ui_popup_menu_hash(title);
- pup->layout = UI_block_layout(
- pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+ pup->title = title;
- /* NOTE: this intentionally differs from the menu & sub-menu default because many operators
- * use popups like this to select one of their options -
- * where having invoke doesn't make sense */
- uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN);
+ ui_popup_menu_create_block(C, pup, title, block_name);
/* create in advance so we can let buttons point to retval already */
pup->block->handle = MEM_cnew<uiPopupBlockHandle>(__func__);
- /* create title button */
if (title[0]) {
- char titlestr[256];
-
- if (icon) {
- BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
- uiDefIconTextBut(pup->block,
- UI_BTYPE_LABEL,
- 0,
- icon,
- titlestr,
- 0,
- 0,
- 200,
- UI_UNIT_Y,
- nullptr,
- 0.0,
- 0.0,
- 0,
- 0,
- "");
- }
- else {
- uiBut *but = uiDefBut(
- pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, nullptr, 0.0, 0.0, 0, 0, "");
- but->drawflag = UI_BUT_TEXT_LEFT;
- }
-
- uiItemS(pup->layout);
+ create_title_button(pup->layout, title, icon);
}
return pup;
@@ -465,7 +530,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(window);
- MEM_freeN(pup);
+ MEM_delete(pup);
}
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
@@ -477,7 +542,7 @@ bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
UI_block_layout_resolve(pup->block, nullptr, nullptr);
MEM_freeN(pup->block->handle);
UI_block_free(C, pup->block);
- MEM_freeN(pup);
+ MEM_delete(pup);
return false;
}
@@ -541,6 +606,20 @@ void UI_popup_menu_reports(bContext *C, ReportList *reports)
}
}
+static void ui_popup_menu_create_from_menutype(bContext *C,
+ MenuType *mt,
+ const char *title,
+ const int icon)
+{
+ uiPopupBlockHandle *handle = ui_popup_menu_create(
+ C, nullptr, nullptr, title, [mt, title, icon](bContext *C, uiLayout *layout) -> void {
+ create_title_button(layout, title, icon);
+ ui_item_menutype_func(C, layout, mt);
+ });
+
+ handle->can_refresh = true;
+}
+
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
{
MenuType *mt = WM_menutype_find(idname, true);
@@ -554,14 +633,21 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
/* cancel but allow event to pass through, just like operators do */
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
+ /* For now always recreate menus on redraw that were invoked with this function. Maybe we want to
+ * make that optional somehow. */
+ const bool allow_refresh = true;
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, CTX_IFACE_(mt->translation_context, mt->label), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
-
- UI_menutype_draw(C, mt, layout);
-
- UI_popup_menu_end(C, pup);
+ const char *title = CTX_IFACE_(mt->translation_context, mt->label);
+ if (allow_refresh) {
+ ui_popup_menu_create_from_menutype(C, mt, title, ICON_NONE);
+ }
+ else {
+ /* If no refresh is needed, create the block directly. */
+ uiPopupMenu *pup = UI_popup_menu_begin(C, title, ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+ UI_menutype_draw(C, mt, layout);
+ UI_popup_menu_end(C, pup);
+ }
return OPERATOR_INTERFACE;
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 6ba80e2e0d9..1bad9b34a72 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1420,21 +1420,25 @@ static void widget_draw_icon(
/* to indicate draggable */
if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW)) {
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
if (has_theme) {
alpha *= 0.8f;
}
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, 0.0f, color, has_theme, &but->icon_overlay_text);
}
else {
const bTheme *btheme = UI_GetTheme();
const float desaturate = 1.0 - btheme->tui.icon_saturation;
- UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme);
+ UI_icon_draw_ex(
+ xs, ys, icon, aspect, alpha, desaturate, color, has_theme, &but->icon_overlay_text);
}
}
@@ -5426,7 +5430,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
GPU_blend(GPU_BLEND_ALPHA);
/* XXX scale weak get from fstyle? */
- UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
+ UI_icon_draw_ex(
+ xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false, UI_NO_ICON_OVERLAY_TEXT);
GPU_blend(GPU_BLEND_NONE);
}
diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc
index c568a8cab74..71974b4d2f9 100644
--- a/source/blender/editors/interface/views/interface_view.cc
+++ b/source/blender/editors/interface/views/interface_view.cc
@@ -81,7 +81,7 @@ void ui_block_free_views(uiBlock *block)
}
}
-void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
{
ARegion *region = listener_params->region;