UI: Make uiBut safe for non-trivial construction

No user-visible changes expected.

Essentially, this makes it possible to use C++ types like `std::function`
inside `uiBut`. This has plenty of benefits, for example this should help
significantly reducing unsafe `void *` use (since a `std::function` can hold
arbitrary data while preserving types).

----

I wanted to use a non-trivially-constructible C++ type (`std::function`) inside
`uiBut`. But this would mean we can't use `MEM_cnew()` like allocation anymore.

Rather than writing worse code, allow non-trivial construction for `uiBut`.
Member-initializing all members is annoying since there are so many, but rather
safe than sorry. As we use more C++ types (e.g. convert callbacks to use
`std::function`), this should become less since they initialize properly on
default construction.

Also use proper C++ inheritance for `uiBut` subtypes, the old way to allocate
based on size isn't working anymore.

Differential Revision: https://developer.blender.org/D17164

Reviewed by: Hans Goudey
This commit is contained in:
2023-02-03 16:12:14 +01:00
parent ebe8f8ce71
commit d204830107
14 changed files with 244 additions and 304 deletions

View File

@@ -322,6 +322,8 @@ enum {
* - bit 9-15: button type (now 6 bits, 64 types) * - bit 9-15: button type (now 6 bits, 64 types)
*/ */
typedef enum { typedef enum {
UI_BUT_POIN_NONE = 0,
UI_BUT_POIN_CHAR = 32, UI_BUT_POIN_CHAR = 32,
UI_BUT_POIN_SHORT = 64, UI_BUT_POIN_SHORT = 64,
UI_BUT_POIN_INT = 96, UI_BUT_POIN_INT = 96,

View File

@@ -3474,7 +3474,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
BLI_assert(UI_butstore_is_registered(but->block, but) == false); BLI_assert(UI_butstore_is_registered(but->block, but) == false);
MEM_freeN(but); MEM_delete(but);
} }
void UI_block_free(const bContext *C, uiBlock *block) void UI_block_free(const bContext *C, uiBlock *block)
@@ -3975,89 +3975,57 @@ void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3])
IMB_colormanagement_scene_linear_to_display_v3(pixel, display); IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
} }
static void ui_but_alloc_info(const eButType type, /**
size_t *r_alloc_size, * Factory function: Allocate button and set #uiBut.type.
const char **r_alloc_str, */
bool *r_has_custom_type) static uiBut *ui_but_new(const eButType type)
{ {
size_t alloc_size; uiBut *but = nullptr;
const char *alloc_str;
bool has_custom_type = true;
switch (type) { switch (type) {
case UI_BTYPE_NUM: case UI_BTYPE_NUM:
alloc_size = sizeof(uiButNumber); but = MEM_new<uiButNumber>("uiButNumber");
alloc_str = "uiButNumber";
break; break;
case UI_BTYPE_COLOR: case UI_BTYPE_COLOR:
alloc_size = sizeof(uiButColor); but = MEM_new<uiButColor>("uiButColor");
alloc_str = "uiButColor";
break; break;
case UI_BTYPE_DECORATOR: case UI_BTYPE_DECORATOR:
alloc_size = sizeof(uiButDecorator); but = MEM_new<uiButDecorator>("uiButDecorator");
alloc_str = "uiButDecorator";
break; break;
case UI_BTYPE_TAB: case UI_BTYPE_TAB:
alloc_size = sizeof(uiButTab); but = MEM_new<uiButTab>("uiButTab");
alloc_str = "uiButTab";
break; break;
case UI_BTYPE_SEARCH_MENU: case UI_BTYPE_SEARCH_MENU:
alloc_size = sizeof(uiButSearch); but = MEM_new<uiButSearch>("uiButSearch");
alloc_str = "uiButSearch";
break; break;
case UI_BTYPE_PROGRESS_BAR: case UI_BTYPE_PROGRESS_BAR:
alloc_size = sizeof(uiButProgressbar); but = MEM_new<uiButProgressbar>("uiButProgressbar");
alloc_str = "uiButProgressbar";
break; break;
case UI_BTYPE_HSVCUBE: case UI_BTYPE_HSVCUBE:
alloc_size = sizeof(uiButHSVCube); but = MEM_new<uiButHSVCube>("uiButHSVCube");
alloc_str = "uiButHSVCube";
break; break;
case UI_BTYPE_COLORBAND: case UI_BTYPE_COLORBAND:
alloc_size = sizeof(uiButColorBand); but = MEM_new<uiButColorBand>("uiButColorBand");
alloc_str = "uiButColorBand";
break; break;
case UI_BTYPE_CURVE: case UI_BTYPE_CURVE:
alloc_size = sizeof(uiButCurveMapping); but = MEM_new<uiButCurveMapping>("uiButCurveMapping");
alloc_str = "uiButCurveMapping";
break; break;
case UI_BTYPE_CURVEPROFILE: case UI_BTYPE_CURVEPROFILE:
alloc_size = sizeof(uiButCurveProfile); but = MEM_new<uiButCurveProfile>("uiButCurveProfile");
alloc_str = "uiButCurveProfile";
break; break;
case UI_BTYPE_HOTKEY_EVENT: case UI_BTYPE_HOTKEY_EVENT:
alloc_size = sizeof(uiButHotkeyEvent); but = MEM_new<uiButHotkeyEvent>("uiButHotkeyEvent");
alloc_str = "uiButHotkeyEvent";
break; break;
case UI_BTYPE_VIEW_ITEM: case UI_BTYPE_VIEW_ITEM:
alloc_size = sizeof(uiButViewItem); but = MEM_new<uiButViewItem>("uiButViewItem");
alloc_str = "uiButViewItem";
break; break;
default: default:
alloc_size = sizeof(uiBut); but = MEM_new<uiBut>("uiBut");
alloc_str = "uiBut";
has_custom_type = false;
break; break;
} }
if (r_alloc_size) { but->type = type;
*r_alloc_size = alloc_size; return but;
}
if (r_alloc_str) {
*r_alloc_str = alloc_str;
}
if (r_has_custom_type) {
*r_has_custom_type = has_custom_type;
}
}
static uiBut *ui_but_alloc(const eButType type)
{
size_t alloc_size;
const char *alloc_str;
ui_but_alloc_info(type, &alloc_size, &alloc_str, nullptr);
return static_cast<uiBut *>(MEM_callocN(alloc_size, alloc_str));
} }
uiBut *ui_but_change_type(uiBut *but, eButType new_type) uiBut *ui_but_change_type(uiBut *but, eButType new_type)
@@ -4067,25 +4035,19 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
return but; return but;
} }
size_t alloc_size;
const char *alloc_str;
uiBut *insert_after_but = but->prev; uiBut *insert_after_but = but->prev;
bool new_has_custom_type, old_has_custom_type;
/* Remove old button address */ /* Remove old button address */
BLI_remlink(&but->block->buttons, but); BLI_remlink(&but->block->buttons, but);
ui_but_alloc_info(but->type, nullptr, nullptr, &old_has_custom_type);
ui_but_alloc_info(new_type, &alloc_size, &alloc_str, &new_has_custom_type);
if (new_has_custom_type || old_has_custom_type) {
const uiBut *old_but_ptr = but; const uiBut *old_but_ptr = but;
/* Button may have pointer to a member within itself, this will have to be updated. */ /* Button may have pointer to a member within itself, this will have to be updated. */
const bool has_str_ptr_to_self = but->str == but->strdata; const bool has_str_ptr_to_self = but->str == but->strdata;
const bool has_poin_ptr_to_self = but->poin == (char *)but; const bool has_poin_ptr_to_self = but->poin == (char *)but;
but = static_cast<uiBut *>(MEM_recallocN_id(but, alloc_size, alloc_str)); /* Copy construct button with the new type. */
but->type = new_type; but = ui_but_new(new_type);
*but = *old_but_ptr;
if (has_str_ptr_to_self) { if (has_str_ptr_to_self) {
but->str = but->strdata; but->str = but->strdata;
} }
@@ -4106,7 +4068,8 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
UI_editsource_but_replace(old_but_ptr, but); UI_editsource_but_replace(old_but_ptr, but);
} }
#endif #endif
}
MEM_delete(old_but_ptr);
return but; return but;
} }
@@ -4152,14 +4115,11 @@ static uiBut *ui_def_but(uiBlock *block,
} }
} }
uiBut *but = ui_but_alloc((eButType)(type & BUTTYPE)); uiBut *but = ui_but_new((eButType)(type & BUTTYPE));
but->type = (eButType)(type & BUTTYPE);
but->pointype = (eButPointerType)(type & UI_BUT_POIN_TYPES); but->pointype = (eButPointerType)(type & UI_BUT_POIN_TYPES);
but->bit = type & UI_BUT_POIN_BIT; but->bit = type & UI_BUT_POIN_BIT;
but->bitnr = type & 31; but->bitnr = type & 31;
but->icon = ICON_NONE;
but->iconadd = 0;
but->retval = retval; but->retval = retval;
@@ -4180,7 +4140,6 @@ static uiBut *ui_def_but(uiBlock *block,
but->disabled_info = block->lockstr; but->disabled_info = block->lockstr;
but->emboss = block->emboss; but->emboss = block->emboss;
but->pie_dir = UI_RADIAL_NONE;
but->block = block; /* pointer back, used for front-buffer status, and picker. */ but->block = block; /* pointer back, used for front-buffer status, and picker. */
@@ -6310,7 +6269,7 @@ void UI_but_func_search_set(uiBut *but,
if (search_exec_fn) { if (search_exec_fn) {
#ifdef DEBUG #ifdef DEBUG
if (search_but->but.func) { if (but->func) {
/* watch this, can be cause of much confusion, see: T47691 */ /* watch this, can be cause of much confusion, see: T47691 */
printf("%s: warning, overwriting button callback with search function callback!\n", printf("%s: warning, overwriting button callback with search function callback!\n",
__func__); __func__);

View File

@@ -113,41 +113,38 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context)
} }
} }
static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate) static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but)
{ {
uiBut *but_iter = nullptr; uiBut *but_iter = nullptr;
BLI_assert(UI_but_is_decorator(&but_decorate->but)); BLI_assert(UI_but_is_decorator(but));
BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop); BLI_assert(but->decorated_rnapoin.data && but->decorated_rnaprop);
LISTBASE_CIRCULAR_BACKWARD_BEGIN ( LISTBASE_CIRCULAR_BACKWARD_BEGIN (uiBut *, &but->block->buttons, but_iter, but->prev) {
uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { if (but_iter != but &&
if (but_iter != (uiBut *)but_decorate &&
ui_but_rna_equals_ex( ui_but_rna_equals_ex(
but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) { but_iter, &but->decorated_rnapoin, but->decorated_rnaprop, but->decorated_rnaindex)) {
return but_iter; return but_iter;
} }
} }
LISTBASE_CIRCULAR_BACKWARD_END( LISTBASE_CIRCULAR_BACKWARD_END(uiBut *, &but->block->buttons, but_iter, but->prev);
uiBut *, &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev);
return nullptr; return nullptr;
} }
void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but) void ui_but_anim_decorate_update_from_flag(uiButDecorator *but)
{ {
if (!decorator_but->rnapoin.data || !decorator_but->rnaprop) { if (!but->decorated_rnapoin.data || !but->decorated_rnaprop) {
/* Nothing to do. */ /* Nothing to do. */
return; return;
} }
const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(decorator_but); const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but);
uiBut *but = &decorator_but->but;
if (!but_anim) { if (!but_anim) {
printf("Could not find button with matching property to decorate (%s.%s)\n", printf("Could not find button with matching property to decorate (%s.%s)\n",
RNA_struct_identifier(decorator_but->rnapoin.type), RNA_struct_identifier(but->decorated_rnapoin.type),
RNA_property_identifier(decorator_but->rnaprop)); RNA_property_identifier(but->decorated_rnaprop));
return; return;
} }
@@ -326,7 +323,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void * /*arg_dummy*/)
} }
/* FIXME(@campbellbarton): swapping active pointer is weak. */ /* FIXME(@campbellbarton): swapping active pointer is weak. */
std::swap(but_anim->active, but_decorate->but.active); std::swap(but_anim->active, but_decorate->active);
wm->op_undo_depth++; wm->op_undo_depth++;
if (but_anim->flag & UI_BUT_DRIVEN) { if (but_anim->flag & UI_BUT_DRIVEN) {
@@ -350,6 +347,6 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void * /*arg_dummy*/)
WM_operator_properties_free(&props_ptr); WM_operator_properties_free(&props_ptr);
} }
std::swap(but_anim->active, but_decorate->but.active); std::swap(but_anim->active, but_decorate->active);
wm->op_undo_depth--; wm->op_undo_depth--;
} }

View File

@@ -934,7 +934,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
uiButViewItem *view_item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region, uiButViewItem *view_item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region,
event->xy); event->xy);
if (view_item_but) { if (view_item_but) {
BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM); BLI_assert(view_item_but->type == UI_BTYPE_VIEW_ITEM);
UI_view_item_context_menu_build(C, view_item_but->view_item, uiLayoutColumn(layout, false)); UI_view_item_context_menu_build(C, view_item_but->view_item, uiLayoutColumn(layout, false));
uiItemS(layout); uiItemS(layout);
} }

View File

@@ -4752,7 +4752,7 @@ static int ui_do_but_VIEW_ITEM(bContext *C,
const wmEvent *event) const wmEvent *event)
{ {
uiButViewItem *view_item_but = (uiButViewItem *)but; uiButViewItem *view_item_but = (uiButViewItem *)but;
BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM); BLI_assert(view_item_but->type == UI_BTYPE_VIEW_ITEM);
if (data->state == BUTTON_STATE_HIGHLIGHT) { if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) { if (event->type == LEFTMOUSE) {
@@ -4961,14 +4961,13 @@ static float ui_numedit_apply_snap(int temp,
return temp; return temp;
} }
static bool ui_numedit_but_NUM(uiButNumber *number_but, static bool ui_numedit_but_NUM(uiButNumber *but,
uiHandleButtonData *data, uiHandleButtonData *data,
int mx, int mx,
const bool is_motion, const bool is_motion,
const enum eSnapType snap, const enum eSnapType snap,
float fac) float fac)
{ {
uiBut *but = &number_but->but;
float deler, tempf; float deler, tempf;
int lvalue, temp; int lvalue, temp;
bool changed = false; bool changed = false;
@@ -4990,13 +4989,13 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but,
const float log_min = (scale_type == PROP_SCALE_LOG) ? const float log_min = (scale_type == PROP_SCALE_LOG) ?
max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN),
powf(10, -number_but->precision) * 0.5f) : powf(10, -but->precision) * 0.5f) :
0; 0;
/* Mouse location isn't screen clamped to the screen so use a linear mapping /* Mouse location isn't screen clamped to the screen so use a linear mapping
* 2px == 1-int, or 1px == 1-ClickStep */ * 2px == 1-int, or 1px == 1-ClickStep */
if (is_float) { if (is_float) {
fac *= 0.01f * number_but->step_size; fac *= 0.01f * but->step_size;
switch (scale_type) { switch (scale_type) {
case PROP_SCALE_LINEAR: { case PROP_SCALE_LINEAR: {
tempf = float(data->startvalue) + float(mx - data->dragstartx) * fac; tempf = float(data->startvalue) + float(mx - data->dragstartx) * fac;
@@ -5170,7 +5169,7 @@ static bool ui_numedit_but_NUM(uiButNumber *number_but,
} }
case PROP_SCALE_LOG: { case PROP_SCALE_LOG: {
const float log_min = max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN), const float log_min = max_ff(max_ff(softmin, UI_PROP_SCALE_LOG_MIN),
powf(10.0f, -number_but->precision) * 0.5f); powf(10.0f, -but->precision) * 0.5f);
const float base = softmax / log_min; const float base = softmax / log_min;
tempf = powf(base, data->dragf) * log_min; tempf = powf(base, data->dragf) * log_min;
if (tempf <= log_min) { if (tempf <= log_min) {
@@ -6148,8 +6147,8 @@ static bool ui_numedit_but_UNITVEC(
static void ui_palette_set_active(uiButColor *color_but) static void ui_palette_set_active(uiButColor *color_but)
{ {
if (color_but->is_pallete_color) { if (color_but->is_pallete_color) {
Palette *palette = (Palette *)color_but->but.rnapoin.owner_id; Palette *palette = (Palette *)color_but->rnapoin.owner_id;
PaletteColor *color = static_cast<PaletteColor *>(color_but->but.rnapoin.data); PaletteColor *color = static_cast<PaletteColor *>(color_but->rnapoin.data);
palette->active_color = BLI_findindex(&palette->colors, color); palette->active_color = BLI_findindex(&palette->colors, color);
} }
} }

View File

@@ -152,24 +152,25 @@ enum {
#define PIE_MAX_ITEMS 8 #define PIE_MAX_ITEMS 8
struct uiBut { struct uiBut {
uiBut *next, *prev; uiBut *next = nullptr, *prev = nullptr;
/** Pointer back to the layout item holding this button. */ /** Pointer back to the layout item holding this button. */
uiLayout *layout; uiLayout *layout = nullptr;
int flag, drawflag; int flag = 0;
eButType type; int drawflag = 0;
eButPointerType pointype; eButType type = eButType(0);
short bit, bitnr, retval, strwidth, alignnr; eButPointerType pointype = UI_BUT_POIN_NONE;
short ofs, pos, selsta, selend; short bit = 0, bitnr = 0, retval = 0, strwidth = 0, alignnr = 0;
short ofs = 0, pos = 0, selsta = 0, selend = 0;
char *str; char *str = nullptr;
char strdata[UI_MAX_NAME_STR]; char strdata[UI_MAX_NAME_STR] = "";
char drawstr[UI_MAX_DRAW_STR]; char drawstr[UI_MAX_DRAW_STR] = "";
rctf rect; /* block relative coords */ rctf rect = {}; /* block relative coords */
char *poin; char *poin = nullptr;
float hardmin, hardmax, softmin, softmax; float hardmin = 0, hardmax = 0, softmin = 0, softmax = 0;
/* both these values use depends on the button type /* both these values use depends on the button type
* (polymorphic struct or union would be nicer for this stuff) */ * (polymorphic struct or union would be nicer for this stuff) */
@@ -180,7 +181,7 @@ struct uiBut {
* - UI_BTYPE_SCROLL: Use as scroll size. * - UI_BTYPE_SCROLL: Use as scroll size.
* - UI_BTYPE_SEARCH_MENU: Use as number or rows. * - UI_BTYPE_SEARCH_MENU: Use as number or rows.
*/ */
float a1; float a1 = 0;
/** /**
* For #uiBut.type: * For #uiBut.type:
@@ -188,210 +189,195 @@ struct uiBut {
* - UI_BTYPE_LABEL: If `(a1 == 1.0f)` use a2 as a blending factor. * - UI_BTYPE_LABEL: If `(a1 == 1.0f)` use a2 as a blending factor.
* - UI_BTYPE_SEARCH_MENU: Use as number or columns. * - UI_BTYPE_SEARCH_MENU: Use as number or columns.
*/ */
float a2; float a2 = 0;
uchar col[4]; uchar col[4] = {0};
/** See \ref UI_but_func_identity_compare_set(). */ /** See \ref UI_but_func_identity_compare_set(). */
uiButIdentityCompareFunc identity_cmp_func; uiButIdentityCompareFunc identity_cmp_func = nullptr;
uiButHandleFunc func; uiButHandleFunc func = nullptr;
void *func_arg1; void *func_arg1 = nullptr;
void *func_arg2; void *func_arg2 = nullptr;
uiButHandleNFunc funcN; uiButHandleNFunc funcN = nullptr;
void *func_argN; void *func_argN = nullptr;
bContextStore *context; bContextStore *context = nullptr;
uiButCompleteFunc autocomplete_func; uiButCompleteFunc autocomplete_func = nullptr;
void *autofunc_arg; void *autofunc_arg = nullptr;
uiButHandleRenameFunc rename_func; uiButHandleRenameFunc rename_func = nullptr;
void *rename_arg1; void *rename_arg1 = nullptr;
void *rename_orig; void *rename_orig = nullptr;
/** Run an action when holding the button down. */ /** Run an action when holding the button down. */
uiButHandleHoldFunc hold_func; uiButHandleHoldFunc hold_func = nullptr;
void *hold_argN; void *hold_argN = nullptr;
const char *tip; const char *tip = nullptr;
uiButToolTipFunc tip_func; uiButToolTipFunc tip_func = nullptr;
void *tip_arg; void *tip_arg = nullptr;
uiFreeArgFunc tip_arg_free; uiFreeArgFunc tip_arg_free = nullptr;
/** info on why button is disabled, displayed in tooltip */ /** info on why button is disabled, displayed in tooltip */
const char *disabled_info; const char *disabled_info = nullptr;
BIFIconID icon; BIFIconID icon = ICON_NONE;
/** Copied from the #uiBlock.emboss */ /** Copied from the #uiBlock.emboss */
eUIEmbossType emboss; eUIEmbossType emboss = UI_EMBOSS;
/** direction in a pie menu, used for collision detection. */ /** direction in a pie menu, used for collision detection. */
RadialDirection pie_dir; RadialDirection pie_dir = UI_RADIAL_NONE;
/** could be made into a single flag */ /** could be made into a single flag */
bool changed; bool changed = false;
/** so buttons can support unit systems which are not RNA */ /** so buttons can support unit systems which are not RNA */
uchar unit_type; uchar unit_type = 0;
short iconadd; short iconadd = 0;
/** #UI_BTYPE_BLOCK data */ /** #UI_BTYPE_BLOCK data */
uiBlockCreateFunc block_create_func; uiBlockCreateFunc block_create_func = nullptr;
/** #UI_BTYPE_PULLDOWN / #UI_BTYPE_MENU data */ /** #UI_BTYPE_PULLDOWN / #UI_BTYPE_MENU data */
uiMenuCreateFunc menu_create_func; uiMenuCreateFunc menu_create_func = nullptr;
uiMenuStepFunc menu_step_func; uiMenuStepFunc menu_step_func = nullptr;
/* RNA data */ /* RNA data */
PointerRNA rnapoin; PointerRNA rnapoin = {};
PropertyRNA *rnaprop; PropertyRNA *rnaprop = nullptr;
int rnaindex; int rnaindex = 0;
/* Operator data */ /* Operator data */
wmOperatorType *optype; wmOperatorType *optype = nullptr;
PointerRNA *opptr; PointerRNA *opptr = nullptr;
wmOperatorCallContext opcontext; wmOperatorCallContext opcontext = WM_OP_INVOKE_DEFAULT;
/** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */ /** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */
uchar menu_key; uchar menu_key = 0;
ListBase extra_op_icons; /** #uiButExtraOpIcon */ ListBase extra_op_icons = {nullptr, nullptr}; /** #uiButExtraOpIcon */
/* Drag-able data, type is WM_DRAG_... */ /* Drag-able data, type is WM_DRAG_... */
char dragtype; char dragtype = WM_DRAG_ID;
short dragflag; short dragflag = 0;
void *dragpoin; void *dragpoin = nullptr;
ImBuf *imb; ImBuf *imb = nullptr;
float imb_scale; float imb_scale = 0;
/** Active button data (set when the user is hovering or interacting with a button). */ /** Active button data (set when the user is hovering or interacting with a button). */
uiHandleButtonData *active; uiHandleButtonData *active = nullptr;
/** Custom button data (borrowed, not owned). */ /** Custom button data (borrowed, not owned). */
void *custom_data; void *custom_data = nullptr;
char *editstr; char *editstr = nullptr;
double *editval; double *editval = nullptr;
float *editvec; float *editvec = nullptr;
uiButPushedStateFunc pushed_state_func; uiButPushedStateFunc pushed_state_func = nullptr;
const void *pushed_state_arg; const void *pushed_state_arg = nullptr;
/** Little indicator (e.g., counter) displayed on top of some icons. */ /** Little indicator (e.g., counter) displayed on top of some icons. */
IconTextOverlay icon_overlay_text; IconTextOverlay icon_overlay_text = {};
/* pointer back */ /* pointer back */
uiBlock *block; uiBlock *block = nullptr;
uiBut() = default;
/** Performs a mostly shallow copy for now. Only contained C++ types are deep copied. */
uiBut(const uiBut &other) = default;
/** Mostly shallow copy, just like copy constructor above. */
uiBut &operator=(const uiBut &other) = default;
}; };
/** Derived struct for #UI_BTYPE_NUM */ /** Derived struct for #UI_BTYPE_NUM */
struct uiButNumber { struct uiButNumber : public uiBut {
uiBut but; float step_size = 0;
float precision = 0;
float step_size;
float precision;
}; };
/** Derived struct for #UI_BTYPE_COLOR */ /** Derived struct for #UI_BTYPE_COLOR */
struct uiButColor { struct uiButColor : public uiBut {
uiBut but; bool is_pallete_color = false;
int palette_color_index = -1;
bool is_pallete_color;
int palette_color_index;
}; };
/** Derived struct for #UI_BTYPE_TAB */ /** Derived struct for #UI_BTYPE_TAB */
struct uiButTab { struct uiButTab : public uiBut {
uiBut but; struct MenuType *menu = nullptr;
struct MenuType *menu;
}; };
/** Derived struct for #UI_BTYPE_SEARCH_MENU */ /** Derived struct for #UI_BTYPE_SEARCH_MENU */
struct uiButSearch { struct uiButSearch : public uiBut {
uiBut but; uiButSearchCreateFn popup_create_fn = nullptr;
uiButSearchUpdateFn items_update_fn = nullptr;
uiButSearchListenFn listen_fn = nullptr;
uiButSearchCreateFn popup_create_fn; void *item_active = nullptr;
uiButSearchUpdateFn items_update_fn;
uiButSearchListenFn listen_fn;
void *item_active; void *arg = nullptr;
uiFreeArgFunc arg_free_fn = nullptr;
void *arg; uiButSearchContextMenuFn item_context_menu_fn = nullptr;
uiFreeArgFunc arg_free_fn; uiButSearchTooltipFn item_tooltip_fn = nullptr;
uiButSearchContextMenuFn item_context_menu_fn; const char *item_sep_string = nullptr;
uiButSearchTooltipFn item_tooltip_fn;
const char *item_sep_string; PointerRNA rnasearchpoin = {};
PropertyRNA *rnasearchprop = nullptr;
PointerRNA rnasearchpoin;
PropertyRNA *rnasearchprop;
/** /**
* The search box only provides suggestions, it does not force * The search box only provides suggestions, it does not force
* the string to match one of the search items when applying. * the string to match one of the search items when applying.
*/ */
bool results_are_suggestions; bool results_are_suggestions = false;
}; };
/** Derived struct for #UI_BTYPE_DECORATOR */ /** Derived struct for #UI_BTYPE_DECORATOR
struct uiButDecorator { * Decorators have own RNA data, using the normal #uiBut RNA members has many side-effects.
uiBut but; */
struct uiButDecorator : public uiBut {
struct PointerRNA rnapoin; struct PointerRNA decorated_rnapoin = {};
struct PropertyRNA *rnaprop; struct PropertyRNA *decorated_rnaprop = nullptr;
int rnaindex; int decorated_rnaindex = -1;
}; };
/** Derived struct for #UI_BTYPE_PROGRESS_BAR. */ /** Derived struct for #UI_BTYPE_PROGRESS_BAR. */
struct uiButProgressbar { struct uiButProgressbar : public uiBut {
uiBut but;
/* 0..1 range */ /* 0..1 range */
float progress; float progress = 0;
}; };
struct uiButViewItem { struct uiButViewItem : public uiBut {
uiBut but;
/* C-Handle to the view item this button was created for. */ /* C-Handle to the view item this button was created for. */
uiViewItemHandle *view_item; uiViewItemHandle *view_item = nullptr;
}; };
/** Derived struct for #UI_BTYPE_HSVCUBE. */ /** Derived struct for #UI_BTYPE_HSVCUBE. */
struct uiButHSVCube { struct uiButHSVCube : public uiBut {
uiBut but; eButGradientType gradient_type = UI_GRAD_SV;
eButGradientType gradient_type;
}; };
/** Derived struct for #UI_BTYPE_COLORBAND. */ /** Derived struct for #UI_BTYPE_COLORBAND. */
struct uiButColorBand { struct uiButColorBand : public uiBut {
uiBut but; ColorBand *edit_coba = nullptr;
ColorBand *edit_coba;
}; };
/** Derived struct for #UI_BTYPE_CURVEPROFILE. */ /** Derived struct for #UI_BTYPE_CURVEPROFILE. */
struct uiButCurveProfile { struct uiButCurveProfile : public uiBut {
uiBut but; struct CurveProfile *edit_profile = nullptr;
struct CurveProfile *edit_profile;
}; };
/** Derived struct for #UI_BTYPE_CURVE. */ /** Derived struct for #UI_BTYPE_CURVE. */
struct uiButCurveMapping { struct uiButCurveMapping : public uiBut {
uiBut but; struct CurveMapping *edit_cumap = nullptr;
eButGradientType gradient_type = UI_GRAD_SV;
struct CurveMapping *edit_cumap;
eButGradientType gradient_type;
}; };
/** Derived struct for #UI_BTYPE_HOTKEY_EVENT. */ /** Derived struct for #UI_BTYPE_HOTKEY_EVENT. */
struct uiButHotkeyEvent { struct uiButHotkeyEvent : public uiBut {
uiBut but; short modifier_key = 0;
short modifier_key;
}; };
/** /**

View File

@@ -3139,7 +3139,7 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop,
/* Loop for the array-case, but only do in case of an expanded array. */ /* Loop for the array-case, but only do in case of an expanded array. */
for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) { for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
uiButDecorator *decorator_but = (uiButDecorator *)uiDefIconBut(block, uiButDecorator *but = (uiButDecorator *)uiDefIconBut(block,
UI_BTYPE_DECORATOR, UI_BTYPE_DECORATOR,
0, 0,
ICON_DOT, ICON_DOT,
@@ -3154,13 +3154,13 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop,
0.0, 0.0,
TIP_("Animate property")); TIP_("Animate property"));
UI_but_func_set(&decorator_but->but, ui_but_anim_decorate_cb, decorator_but, nullptr); UI_but_func_set(but, ui_but_anim_decorate_cb, but, nullptr);
decorator_but->but.flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK; but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
/* Reusing RNA search members, setting actual RNA data has many side-effects. */ /* Decorators have own RNA data, using the normal #uiBut RNA members has many side-effects. */
decorator_but->rnapoin = *ptr; but->decorated_rnapoin = *ptr;
decorator_but->rnaprop = prop; but->decorated_rnaprop = prop;
/* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */ /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
decorator_but->rnaindex = (!is_array || is_expand) ? i : index; but->decorated_rnaindex = (!is_array || is_expand) ? i : index;
} }
} }

View File

@@ -1658,8 +1658,8 @@ static void ui_editsource_active_but_set(uiBut *but)
{ {
BLI_assert(ui_editsource_info == nullptr); BLI_assert(ui_editsource_info == nullptr);
ui_editsource_info = MEM_cnew<uiEditSourceStore>(__func__); ui_editsource_info = MEM_new<uiEditSourceStore>(__func__);
memcpy(&ui_editsource_info->but_orig, but, sizeof(uiBut)); ui_editsource_info->but_orig = *but;
ui_editsource_info->hash = BLI_ghash_ptr_new(__func__); ui_editsource_info->hash = BLI_ghash_ptr_new(__func__);
} }

View File

@@ -397,7 +397,7 @@ static void ui_colorpicker_circle(uiBlock *block,
0, 0,
"Lightness"); "Lightness");
hsv_but->gradient_type = UI_GRAD_L_ALT; hsv_but->gradient_type = UI_GRAD_L_ALT;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, nullptr); UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
} }
else { else {
hsv_but = (uiButHSVCube *)uiDefButR_prop(block, hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
@@ -417,9 +417,9 @@ static void ui_colorpicker_circle(uiBlock *block,
0, 0,
TIP_("Value")); TIP_("Value"));
hsv_but->gradient_type = UI_GRAD_V_ALT; hsv_but->gradient_type = UI_GRAD_V_ALT;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, nullptr); UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
} }
hsv_but->but.custom_data = cpicker; hsv_but->custom_data = cpicker;
} }
static void ui_colorpicker_square(uiBlock *block, static void ui_colorpicker_square(uiBlock *block,
@@ -450,8 +450,8 @@ static void ui_colorpicker_square(uiBlock *block,
0, 0,
TIP_("Color")); TIP_("Color"));
hsv_but->gradient_type = type; hsv_but->gradient_type = type;
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, nullptr); UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
hsv_but->but.custom_data = cpicker; hsv_but->custom_data = cpicker;
/* value */ /* value */
hsv_but = (uiButHSVCube *)uiDefButR_prop(block, hsv_but = (uiButHSVCube *)uiDefButR_prop(block,
@@ -471,8 +471,8 @@ static void ui_colorpicker_square(uiBlock *block,
0, 0,
TIP_("Value")); TIP_("Value"));
hsv_but->gradient_type = (eButGradientType)(type + 3); hsv_but->gradient_type = (eButGradientType)(type + 3);
UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, nullptr); UI_but_func_set(hsv_but, ui_colorpicker_rgba_update_cb, hsv_but, nullptr);
hsv_but->but.custom_data = cpicker; hsv_but->custom_data = cpicker;
} }
/* a HS circle, V slider, rgb/hsv/hex sliders */ /* a HS circle, V slider, rgb/hsv/hex sliders */

View File

@@ -433,17 +433,17 @@ bool ui_searchbox_event(
/** Wrap #uiButSearchUpdateFn callback. */ /** Wrap #uiButSearchUpdateFn callback. */
static void ui_searchbox_update_fn(bContext *C, static void ui_searchbox_update_fn(bContext *C,
uiButSearch *search_but, uiButSearch *but,
const char *str, const char *str,
uiSearchItems *items) uiSearchItems *items)
{ {
/* While the button is in text editing mode (searchbox open), remove tooltips on every update. */ /* While the button is in text editing mode (searchbox open), remove tooltips on every update. */
if (search_but->but.editstr) { if (but->editstr) {
wmWindow *win = CTX_wm_window(C); wmWindow *win = CTX_wm_window(C);
WM_tooltip_clear(C, win); WM_tooltip_clear(C, win);
} }
const bool is_first_search = !search_but->but.changed; const bool is_first_search = !but->changed;
search_but->items_update_fn(C, search_but->arg, str, items, is_first_search); but->items_update_fn(C, but->arg, str, items, is_first_search);
} }
void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset)
@@ -464,7 +464,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
data->active = -1; data->active = -1;
/* On init, find and center active item. */ /* On init, find and center active item. */
const bool is_first_search = !search_but->but.changed; const bool is_first_search = !but->changed;
if (is_first_search && search_but->items_update_fn && search_but->item_active) { if (is_first_search && search_but->items_update_fn && search_but->item_active) {
data->items.active = search_but->item_active; data->items.active = search_but->item_active;
ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); ui_searchbox_update_fn(C, search_but, but->editstr, &data->items);
@@ -704,12 +704,11 @@ static void ui_searchbox_region_listen_fn(const wmRegionListenerParams *params)
static ARegion *ui_searchbox_create_generic_ex(bContext *C, static ARegion *ui_searchbox_create_generic_ex(bContext *C,
ARegion *butregion, ARegion *butregion,
uiButSearch *search_but, uiButSearch *but,
const bool use_shortcut_sep) const bool use_shortcut_sep)
{ {
wmWindow *win = CTX_wm_window(C); wmWindow *win = CTX_wm_window(C);
const uiStyle *style = UI_style_get(); const uiStyle *style = UI_style_get();
uiBut *but = &search_but->but;
const float aspect = but->block->aspect; const float aspect = but->block->aspect;
const int margin = UI_POPUP_MARGIN; const int margin = UI_POPUP_MARGIN;
@@ -726,8 +725,8 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
/* Create search-box data. */ /* Create search-box data. */
uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__); uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
data->search_arg = search_but->arg; data->search_arg = but->arg;
data->search_listener = search_but->listen_fn; data->search_listener = but->listen_fn;
/* Set font, get the bounding-box. */ /* Set font, get the bounding-box. */
data->fstyle = style->widget; /* copy struct */ data->fstyle = style->widget; /* copy struct */
@@ -751,7 +750,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
if (but->optype != nullptr || use_shortcut_sep) { if (but->optype != nullptr || use_shortcut_sep) {
data->use_shortcut_sep = true; data->use_shortcut_sep = true;
} }
data->sep_string = search_but->item_sep_string; data->sep_string = but->item_sep_string;
/* compute position */ /* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) { if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
@@ -1013,10 +1012,8 @@ ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *
return region; return region;
} }
void ui_but_search_refresh(uiButSearch *search_but) void ui_but_search_refresh(uiButSearch *but)
{ {
uiBut *but = &search_but->but;
/* possibly very large lists (such as ID datablocks) only /* possibly very large lists (such as ID datablocks) only
* only validate string RNA buts (not pointers) */ * only validate string RNA buts (not pointers) */
if (but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) { if (but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) {
@@ -1033,9 +1030,9 @@ void ui_but_search_refresh(uiButSearch *search_but)
items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__); items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__);
} }
ui_searchbox_update_fn((bContext *)but->block->evil_C, search_but, but->drawstr, items); ui_searchbox_update_fn((bContext *)but->block->evil_C, but, but->drawstr, items);
if (!search_but->results_are_suggestions) { if (!but->results_are_suggestions) {
/* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */
if (items->totitem == 0) { if (items->totitem == 0) {
UI_but_flag_enable(but, UI_BUT_REDALERT); UI_but_flag_enable(but, UI_BUT_REDALERT);

View File

@@ -1677,12 +1677,12 @@ static void template_ID_tabs(const bContext *C,
0.0f, 0.0f,
0.0f, 0.0f,
""); "");
UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template_id), id); UI_but_funcN_set(tab, template_ID_set_property_exec_fn, MEM_dupallocN(template_id), id);
UI_but_drag_set_id(&tab->but, id); UI_but_drag_set_id(tab, id);
tab->but.custom_data = (void *)id; tab->custom_data = (void *)id;
tab->menu = mt; tab->menu = mt;
UI_but_drawflag_enable(&tab->but, but_align); UI_but_drawflag_enable(tab, but_align);
} }
BLI_freelistN(&ordered); BLI_freelistN(&ordered);
@@ -5639,7 +5639,7 @@ void uiTemplateColorPicker(uiLayout *layout,
hsv_but->gradient_type = UI_GRAD_HV; hsv_but->gradient_type = UI_GRAD_HV;
break; break;
} }
but = &hsv_but->but; but = hsv_but;
break; break;
/* user default */ /* user default */
@@ -5785,7 +5785,7 @@ void uiTemplateColorPicker(uiLayout *layout,
break; break;
} }
hsv_but->but.custom_data = cpicker; hsv_but->custom_data = cpicker;
} }
} }
@@ -6286,7 +6286,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
nullptr); nullptr);
but_progress->progress = progress; but_progress->progress = progress;
UI_but_func_tooltip_set(&but_progress->but, progress_tooltip_func, tip_arg, MEM_freeN); UI_but_func_tooltip_set(but_progress, progress_tooltip_func, tip_arg, MEM_freeN);
} }
if (!wm->is_interface_locked) { if (!wm->is_interface_locked) {

View File

@@ -3152,7 +3152,7 @@ void ui_hsvcube_pos_from_vals(
case UI_GRAD_V_ALT: case UI_GRAD_V_ALT:
x = 0.5f; x = 0.5f;
/* exception only for value strip - use the range set in but->min/max */ /* exception only for value strip - use the range set in but->min/max */
y = (hsv[2] - hsv_but->but.softmin) / (hsv_but->but.softmax - hsv_but->but.softmin); y = (hsv[2] - hsv_but->softmin) / (hsv_but->softmax - hsv_but->softmin);
break; break;
} }

View File

@@ -130,7 +130,7 @@ void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
""); "");
view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this); view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
UI_but_func_set(&view_item_but_->but, grid_tile_click_fn, view_item_but_, nullptr); UI_but_func_set(view_item_but_, grid_tile_click_fn, view_item_but_, nullptr);
} }
void AbstractGridViewItem::on_activate() void AbstractGridViewItem::on_activate()

View File

@@ -136,7 +136,7 @@ void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
&block, UI_BTYPE_VIEW_ITEM, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, ""); &block, UI_BTYPE_VIEW_ITEM, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this); view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
UI_but_func_set(&view_item_but_->but, tree_row_click_fn, view_item_but_, nullptr); UI_but_func_set(view_item_but_, tree_row_click_fn, view_item_but_, nullptr);
} }
void AbstractTreeViewItem::add_indent(uiLayout &row) const void AbstractTreeViewItem::add_indent(uiLayout &row) const
@@ -322,8 +322,8 @@ bool AbstractTreeViewItem::is_hovered() const
/* The new layout hasn't finished construction yet, so the final state of the button is unknown. /* The new layout hasn't finished construction yet, so the final state of the button is unknown.
* Get the matching button from the previous redraw instead. */ * Get the matching button from the previous redraw instead. */
uiButViewItem *old_item_but = ui_block_view_find_matching_view_item_but_in_old_block( uiButViewItem *old_item_but = ui_block_view_find_matching_view_item_but_in_old_block(
view_item_but_->but.block, this_item_handle); view_item_but_->block, this_item_handle);
return old_item_but && (old_item_but->but.flag & UI_ACTIVE); return old_item_but && (old_item_but->flag & UI_ACTIVE);
} }
bool AbstractTreeViewItem::is_collapsed() const bool AbstractTreeViewItem::is_collapsed() const