diff options
Diffstat (limited to 'source/blender/editors/interface/interface_layout.c')
-rw-r--r-- | source/blender/editors/interface/interface_layout.c | 638 |
1 files changed, 405 insertions, 233 deletions
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index a37f87e593b..df7fd3dee0e 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -18,7 +18,6 @@ * \ingroup edinterface */ -#include <assert.h> #include <limits.h> #include <math.h> #include <stdlib.h> @@ -41,6 +40,7 @@ #include "BLT_translation.h" #include "BKE_anim_data.h" +#include "BKE_armature.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_idprop.h" @@ -50,8 +50,6 @@ #include "UI_interface.h" -#include "ED_armature.h" - #include "WM_api.h" #include "WM_types.h" @@ -293,16 +291,13 @@ static bool ui_layout_variable_size(uiLayout *layout) /* estimated size of text + icon */ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact) { - bool variable; const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f); if (icon && !name[0]) { return unit_x; /* icon only */ } - variable = ui_layout_variable_size(layout); - - if (variable) { + if (ui_layout_variable_size(layout)) { if (!icon && !name[0]) { return unit_x; /* No icon or name. */ } @@ -439,7 +434,6 @@ int uiLayoutGetLocalDir(const uiLayout *layout) static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, bool align) { uiLayout *sub; - if (uiLayoutGetLocalDir(test) == UI_LAYOUT_HORIZONTAL) { sub = uiLayoutRow(layout, align); } @@ -498,17 +492,12 @@ static void ui_item_array(uiLayout *layout, bool show_text) { const uiStyle *style = layout->root->style; - uiBut *but; - PropertyType type; - PropertySubType subtype; - uiLayout *sub; - uint a, b; /* retrieve type and subtype */ - type = RNA_property_type(prop); - subtype = RNA_property_subtype(prop); + const PropertyType type = RNA_property_type(prop); + const PropertySubType subtype = RNA_property_subtype(prop); - sub = ui_item_local_sublayout(layout, layout, 1); + uiLayout *sub = ui_item_local_sublayout(layout, layout, 1); UI_block_layout_set_current(block, sub); /* create label */ @@ -519,17 +508,15 @@ static void ui_item_array(uiLayout *layout, /* create buttons */ if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) { /* special check for layer layout */ - int butw, buth, unit; const int cols = (len >= 20) ? 2 : 1; - const uint colbuts = len / (2 * cols); + const int colbuts = len / (2 * cols); uint layer_used = 0; uint layer_active = 0; UI_block_layout_set_current(block, uiLayoutAbsolute(layout, false)); - unit = UI_UNIT_X * 0.75; - butw = unit; - buth = unit; + const int butw = UI_UNIT_X * 0.75; + const int buth = UI_UNIT_X * 0.75; if (ptr->type == &RNA_Armature) { bArmature *arm = ptr->data; @@ -548,10 +535,10 @@ static void ui_item_array(uiLayout *layout, } } - for (b = 0; b < cols; b++) { + for (int b = 0; b < cols; b++) { UI_block_align_begin(block); - for (a = 0; a < colbuts; a++) { + for (int a = 0; a < colbuts; a++) { const int layer_num = a + b * colbuts; const uint layer_flag = (1u << layer_num); @@ -567,13 +554,13 @@ static void ui_item_array(uiLayout *layout, icon = ICON_BLANK1; } - but = uiDefAutoButR( + uiBut *but = uiDefAutoButR( block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth); if (subtype == PROP_LAYER_MEMBER) { UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num)); } } - for (a = 0; a < colbuts; a++) { + for (int a = 0; a < colbuts; a++) { const int layer_num = a + len / 2 + b * colbuts; const uint layer_flag = (1u << layer_num); @@ -589,7 +576,8 @@ static void ui_item_array(uiLayout *layout, icon = ICON_BLANK1; } - but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth); + uiBut *but = uiDefAutoButR( + block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth); if (subtype == PROP_LAYER_MEMBER) { UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num)); } @@ -614,20 +602,20 @@ static void ui_item_array(uiLayout *layout, w /= dim_size[0]; /* h /= dim_size[1]; */ /* UNUSED */ - for (a = 0; a < len; a++) { + for (int a = 0; a < len; a++) { col = a % dim_size[0]; row = a / dim_size[0]; - but = uiDefAutoButR(block, - ptr, - prop, - a, - "", - ICON_NONE, - x + w * col, - y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y), - w, - UI_UNIT_Y); + uiBut *but = uiDefAutoButR(block, + ptr, + prop, + a, + "", + ICON_NONE, + x + w * col, + y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y), + w, + UI_UNIT_Y); if (slider && but->type == UI_BTYPE_NUM) { uiButNumber *number_but = (uiButNumber *)but; @@ -663,8 +651,6 @@ static void ui_item_array(uiLayout *layout, uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y); } else { - bool *boolarr = NULL; - /* even if 'expand' is fale, expanding anyway */ /* layout for known array subtypes */ @@ -677,6 +663,7 @@ static void ui_item_array(uiLayout *layout, } /* show checkboxes for rna on a non-emboss block (menu for eg) */ + bool *boolarr = NULL; if (type == PROP_BOOLEAN && ELEM(layout->root->block->emboss, UI_EMBOSS_NONE, UI_EMBOSS_PULLDOWN)) { boolarr = MEM_callocN(sizeof(bool) * len, __func__); @@ -684,9 +671,7 @@ static void ui_item_array(uiLayout *layout, } const char *str_buf = show_text ? str : ""; - for (a = 0; a < len; a++) { - int width_item; - + for (int a = 0; a < len; a++) { if (!icon_only && show_text) { str[0] = RNA_property_array_item_char(prop, a); } @@ -694,11 +679,12 @@ static void ui_item_array(uiLayout *layout, icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; } - width_item = ((compact && type == PROP_BOOLEAN) ? - min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) : - w); + const int width_item = ((compact && type == PROP_BOOLEAN) ? + min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) : + w); - but = uiDefAutoButR(block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y); + uiBut *but = uiDefAutoButR( + block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y); if (slider && but->type == UI_BTYPE_NUM) { uiButNumber *number_but = (uiButNumber *)but; @@ -761,7 +747,6 @@ static void ui_item_enum_expand_elem_exec(uiLayout *layout, const int itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0); uiBut *but; - if (icon && name[0] && !icon_only) { but = uiDefIconTextButR_prop( block, but_type, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL); @@ -815,13 +800,12 @@ static void ui_item_enum_expand_exec(uiLayout *layout, * - mont29 */ - const EnumPropertyItem *item, *item_array; - bool free; - BLI_assert(RNA_property_type(prop) == PROP_ENUM); - uiLayout *layout_radial = NULL; const bool radial = (layout->root->type == UI_LAYOUT_PIEMENU); + + bool free; + const EnumPropertyItem *item_array; if (radial) { RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free); } @@ -830,6 +814,7 @@ static void ui_item_enum_expand_exec(uiLayout *layout, } /* we dont want nested rows, cols in menus */ + uiLayout *layout_radial = NULL; if (radial) { if (layout->root->layout == layout) { layout_radial = uiLayoutRadial(layout); @@ -850,7 +835,7 @@ static void ui_item_enum_expand_exec(uiLayout *layout, UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1)); } - for (item = item_array; item->identifier; item++) { + for (const EnumPropertyItem *item = item_array; item->identifier; item++) { const bool is_first = item == item_array; if (!item->identifier[0]) { @@ -901,6 +886,8 @@ static void ui_item_enum_expand_tabs(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, + PointerRNA *ptr_highlight, + PropertyRNA *prop_highlight, const char *uiname, const int h, const bool icon_only) @@ -909,9 +896,24 @@ static void ui_item_enum_expand_tabs(uiLayout *layout, ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only); BLI_assert(last != block->buttons.last); + for (uiBut *tab = last ? last->next : block->buttons.first; tab; tab = tab->next) { UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C))); } + + const bool use_custom_highlight = (prop_highlight != NULL); + + if (use_custom_highlight) { + const int highlight_array_len = RNA_property_array_length(ptr_highlight, prop_highlight); + bool *highlight_array = alloca(sizeof(bool) * highlight_array_len); + RNA_property_boolean_get_array(ptr_highlight, prop_highlight, highlight_array); + int i = 0; + for (uiBut *tab_but = last ? last->next : block->buttons.first; + (tab_but != NULL) && (i < highlight_array_len); + tab_but = tab_but->next, i++) { + SET_FLAG_FROM_TEST(tab_but->flag, !highlight_array[i], UI_BUT_INACTIVE); + } + } } /* callback for keymap item change button */ @@ -945,9 +947,6 @@ static uiBut *ui_item_with_label(uiLayout *layout, int flag) { uiLayout *sub = layout; - uiBut *but = NULL; - PropertyType type; - PropertySubType subtype; int prop_but_width = w_hint; #ifdef UI_PROP_DECORATE uiLayout *layout_prop_decorate = NULL; @@ -956,10 +955,20 @@ static uiBut *ui_item_with_label(uiLayout *layout, (layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0; #endif + const bool is_keymapitem_ptr = RNA_struct_is_a(ptr->type, &RNA_KeyMapItem); + if ((flag & flag & UI_ITEM_R_FULL_EVENT) && !is_keymapitem_ptr) { + RNA_warning("Data is not a keymap item struct: %s. Ignoring 'full_event' option.", + RNA_struct_identifier(ptr->type)); + } + UI_block_layout_set_current(block, layout); /* Only add new row if more than 1 item will be added. */ - if (name[0] || use_prop_decorate) { + if (name[0] +#ifdef UI_PROP_DECORATE + || use_prop_decorate +#endif + ) { /* Also avoid setting 'align' if possible. Set the space to zero instead as aligning a large * number of labels can end up aligning thousands of buttons when displaying key-map search (a * heavy operation), see: T78636. */ @@ -967,8 +976,8 @@ static uiBut *ui_item_with_label(uiLayout *layout, sub->space = 0; } -#ifdef UI_PROP_DECORATE if (name[0]) { +#ifdef UI_PROP_DECORATE if (use_prop_sep) { layout_prop_decorate = uiItemL_respect_property_split(layout, name, 0); } @@ -976,7 +985,6 @@ static uiBut *ui_item_with_label(uiLayout *layout, #endif { int w_label; - if (ui_layout_variable_size(layout)) { /* w_hint is width for label in this case. * Use a default width for property button(s) */ @@ -990,10 +998,11 @@ static uiBut *ui_item_with_label(uiLayout *layout, } } - type = RNA_property_type(prop); - subtype = RNA_property_subtype(prop); + const PropertyType type = RNA_property_type(prop); + const PropertySubType subtype = RNA_property_subtype(prop); - if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) { + uiBut *but; + if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) { UI_block_layout_set_current(block, uiLayoutRow(sub, true)); but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h); @@ -1028,32 +1037,30 @@ static uiBut *ui_item_with_label(uiLayout *layout, -1, NULL); } - else if (flag & UI_ITEM_R_FULL_EVENT) { - if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) { - char buf[128]; - - WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf)); - - but = uiDefButR_prop(block, - UI_BTYPE_HOTKEY_EVENT, - 0, - buf, - x, - y, - prop_but_width, - h, - ptr, - prop, - 0, - 0, - 0, - -1, - -1, - NULL); - UI_but_func_set(but, ui_keymap_but_cb, but, NULL); - if (flag & UI_ITEM_R_IMMEDIATE) { - UI_but_flag_enable(but, UI_BUT_IMMEDIATE); - } + else if ((flag & UI_ITEM_R_FULL_EVENT) && is_keymapitem_ptr) { + char buf[128]; + + WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf)); + + but = uiDefButR_prop(block, + UI_BTYPE_HOTKEY_EVENT, + 0, + buf, + x, + y, + prop_but_width, + h, + ptr, + prop, + 0, + 0, + 0, + -1, + -1, + NULL); + UI_but_func_set(but, ui_keymap_but_cb, but, NULL); + if (flag & UI_ITEM_R_IMMEDIATE) { + UI_but_flag_enable(but, UI_BUT_IMMEDIATE); } } else { @@ -1133,8 +1140,6 @@ static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item) static void ui_item_disabled(uiLayout *layout, const char *name) { uiBlock *block = layout->root->block; - uiBut *but; - int w; UI_block_layout_set_current(block, layout); @@ -1142,9 +1147,10 @@ static void ui_item_disabled(uiLayout *layout, const char *name) name = ""; } - w = ui_text_icon_width(layout, name, 0, 0); + const int w = ui_text_icon_width(layout, name, 0, 0); - but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + uiBut *but = uiDefBut( + block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); UI_but_disable(but, ""); } @@ -1164,8 +1170,6 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, { /* Take care to fill 'r_opptr' whatever happens. */ uiBlock *block = layout->root->block; - uiBut *but; - int w; if (!name) { if (ot && ot->srna && (flag & UI_ITEM_R_ICON_ONLY) == 0) { @@ -1180,10 +1184,10 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, icon = ICON_BLANK1; } - /* create button */ UI_block_layout_set_current(block, layout); + ui_block_new_button_group(block, 0); - w = ui_text_icon_width(layout, name, icon, 0); + const int w = ui_text_icon_width(layout, name, icon, 0); const int prev_emboss = layout->emboss; if (flag & UI_ITEM_R_NO_BG) { @@ -1191,6 +1195,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, } /* create the button */ + uiBut *but; if (icon) { if (name[0]) { but = uiDefIconTextButO_ptr( @@ -1204,7 +1209,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL); } - assert(but->optype != NULL); + BLI_assert(but->optype != NULL); if (flag & UI_ITEM_R_NO_BG) { layout->emboss = prev_emboss; @@ -1214,6 +1219,10 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, but->flag |= UI_SELECT_DRAW; } + if (flag & UI_ITEM_R_ICON_ONLY) { + UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); + } + if (layout->redalert) { UI_but_flag_enable(but, UI_BUT_REDALERT); } @@ -1334,11 +1343,11 @@ static const char *ui_menu_enumpropname(uiLayout *layout, PropertyRNA *prop, int retval) { - const EnumPropertyItem *item; bool free; - const char *name; - + const EnumPropertyItem *item; RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free); + + const char *name; if (RNA_enum_name(item, retval, &name)) { name = CTX_IFACE_(RNA_property_translation_context(prop), name); } @@ -1361,14 +1370,10 @@ void uiItemEnumO_ptr(uiLayout *layout, int value) { PointerRNA ptr; - PropertyRNA *prop; - WM_operator_properties_create_ptr(&ptr, ot); - if ((prop = RNA_struct_find_property(&ptr, propname))) { - /* pass */ - } - else { + PropertyRNA *prop = RNA_struct_find_property(&ptr, propname); + if (prop == NULL) { RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname); return; } @@ -1427,22 +1432,40 @@ void uiItemsFullEnumO_items(uiLayout *layout, } uiLayout *target, *split = NULL; - const EnumPropertyItem *item; uiBlock *block = layout->root->block; const bool radial = ui_layout_is_radial(layout); if (radial) { target = uiLayoutRadial(layout); } + else if ((uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) && (flag & UI_ITEM_R_ICON_ONLY)) { + target = layout; + UI_block_layout_set_current(block, target); + + /* Add a blank button to the beginning of the row. */ + uiDefIconBut(block, + UI_BTYPE_LABEL, + 0, + ICON_BLANK1, + 0, + 0, + 1.25f * UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + NULL); + } else { split = uiLayoutSplit(layout, 0.0f, false); target = uiLayoutColumn(split, layout->align); } - int i; bool last_iter = false; - - for (i = 1, item = item_array; item->identifier && !last_iter; i++, item++) { + const EnumPropertyItem *item = item_array; + for (int i = 1; item->identifier && !last_iter; i++, item++) { /* handle oversized pies */ if (radial && (totitem > PIE_MAX_ITEMS) && (i >= PIE_MAX_ITEMS)) { if (item->name) { /* only visible items */ @@ -1471,7 +1494,6 @@ void uiItemsFullEnumO_items(uiLayout *layout, if (item->identifier[0]) { PointerRNA tptr; - WM_operator_properties_create_ptr(&tptr, ot); if (properties) { if (tptr.data) { @@ -1481,21 +1503,27 @@ void uiItemsFullEnumO_items(uiLayout *layout, } RNA_property_enum_set(&tptr, prop, item->value); - uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag, NULL); + uiItemFullO_ptr(target, + ot, + (flag & UI_ITEM_R_ICON_ONLY) ? NULL : item->name, + item->icon, + tptr.data, + context, + flag, + NULL); ui_but_tip_from_enum_item(block->buttons.last, item); } else { if (item->name) { - uiBut *but; - - if (item != item_array && !radial) { + if (item != item_array && !radial && split != NULL) { target = uiLayoutColumn(split, layout->align); /* inconsistent, but menus with labels do not look good flipped */ block->flag |= UI_BLOCK_NO_FLIP; } + uiBut *but; if (item->icon || radial) { uiItemL(target, item->name, item->icon); @@ -1518,6 +1546,7 @@ void uiItemsFullEnumO_items(uiLayout *layout, 0, 0, ""); + uiItemS(target); } ui_but_tip_from_enum_item(but, item); } @@ -1545,24 +1574,22 @@ void uiItemsFullEnumO(uiLayout *layout, { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; - PropertyRNA *prop; - uiBlock *block = layout->root->block; - if (!ot || !ot->srna) { ui_item_disabled(layout, opname); RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname); return; } + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); /* so the context is passed to itemf functions (some need it) */ WM_operator_properties_sanitize(&ptr, false); - prop = RNA_struct_find_property(&ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(&ptr, propname); /* don't let bad properties slip through */ BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM)); + uiBlock *block = layout->root->block; if (prop && RNA_property_type(prop) == PROP_ENUM) { const EnumPropertyItem *item_array = NULL; int totitem; @@ -1619,18 +1646,14 @@ void uiItemEnumO_value(uiLayout *layout, int value) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; - PropertyRNA *prop; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); /* enum lookup */ - if ((prop = RNA_struct_find_property(&ptr, propname))) { - /* pass */ - } - else { + PropertyRNA *prop = RNA_struct_find_property(&ptr, propname); + if (prop == NULL) { RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname); return; } @@ -1653,39 +1676,36 @@ void uiItemEnumO_string(uiLayout *layout, const char *value_str) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; - PropertyRNA *prop; - - const EnumPropertyItem *item; - int value; - bool free; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); + PropertyRNA *prop = RNA_struct_find_property(&ptr, propname); + if (prop == NULL) { + RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname); + return; + } + /* enum lookup */ - if ((prop = RNA_struct_find_property(&ptr, propname))) { - /* no need for translations here */ - RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free); - if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) { - if (free) { - MEM_freeN((void *)item); - } - RNA_warning( - "%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str); - return; - } + /* no need for translations here */ + const EnumPropertyItem *item; + bool free; + RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free); + int value; + if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) { if (free) { MEM_freeN((void *)item); } - } - else { - RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname); + RNA_warning("%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str); return; } + if (free) { + MEM_freeN((void *)item); + } + RNA_property_enum_set(&ptr, prop, value); /* same as uiItemEnumO */ @@ -1704,10 +1724,9 @@ void uiItemBooleanO(uiLayout *layout, int value) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_boolean_set(&ptr, propname, value); @@ -1722,10 +1741,9 @@ void uiItemIntO(uiLayout *layout, int value) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; - UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_int_set(&ptr, propname, value); @@ -1740,10 +1758,10 @@ void uiItemFloatO(uiLayout *layout, float value) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_float_set(&ptr, propname, value); @@ -1758,10 +1776,10 @@ void uiItemStringO(uiLayout *layout, const char *value) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ - PointerRNA ptr; UI_OPERATOR_ERROR_RET(ot, opname, return ); + PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, propname, value); @@ -1786,16 +1804,14 @@ static void ui_item_rna_size(uiLayout *layout, int *r_w, int *r_h) { - PropertyType type; - PropertySubType subtype; - int len, w = 0, h; - bool is_checkbox_only = false; + int w = 0, h; /* arbitrary extended width by type */ - type = RNA_property_type(prop); - subtype = RNA_property_subtype(prop); - len = RNA_property_array_length(ptr, prop); + PropertyType type = RNA_property_type(prop); + PropertySubType subtype = RNA_property_subtype(prop); + const int len = RNA_property_array_length(ptr, prop); + bool is_checkbox_only = false; if (!name[0] && !icon_only) { if (ELEM(type, PROP_STRING, PROP_POINTER)) { name = "non-empty text"; @@ -1809,12 +1825,12 @@ static void ui_item_rna_size(uiLayout *layout, } else if (type == PROP_ENUM) { /* Find the longest enum item name, instead of using a dummy text! */ - const EnumPropertyItem *item, *item_array; + const EnumPropertyItem *item_array; bool free; - RNA_property_enum_items_gettexted( layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free); - for (item = item_array; item->identifier; item++) { + + for (const EnumPropertyItem *item = item_array; item->identifier; item++) { if (item->identifier[0]) { w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact)); } @@ -1870,7 +1886,7 @@ static void ui_item_rna_size(uiLayout *layout, else if (type == PROP_ENUM && !icon_only) { w += UI_UNIT_X / 4; } - else if (type == PROP_FLOAT || type == PROP_INT) { + else if (ELEM(type, PROP_FLOAT, PROP_INT)) { w += UI_UNIT_X * 3; } } @@ -1988,6 +2004,7 @@ void uiItemFullR(uiLayout *layout, #endif /* UI_PROP_DECORATE */ UI_block_layout_set_current(block, layout); + ui_block_new_button_group(block, 0); /* retrieve info */ const PropertyType type = RNA_property_type(prop); @@ -2135,7 +2152,6 @@ void uiItemFullR(uiLayout *layout, uiLayout *layout_split = uiLayoutSplit( layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true); bool label_added = false; - layout_split->space = 0; uiLayout *layout_sub = uiLayoutColumn(layout_split, true); layout_sub->space = 0; @@ -2279,7 +2295,7 @@ void uiItemFullR(uiLayout *layout, ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only); } /* property with separate label */ - else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) { + else if (ELEM(type, PROP_ENUM, PROP_STRING, PROP_POINTER)) { but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag); but = ui_but_add_search(but, ptr, prop, NULL, NULL); @@ -2503,10 +2519,6 @@ void uiItemEnumR_string_prop(uiLayout *layout, const char *name, int icon) { - const EnumPropertyItem *item; - int ivalue, a; - bool free; - if (UNLIKELY(RNA_property_type(prop) != PROP_ENUM)) { const char *propname = RNA_property_identifier(prop); ui_item_disabled(layout, propname); @@ -2514,8 +2526,11 @@ void uiItemEnumR_string_prop(uiLayout *layout, return; } + const EnumPropertyItem *item; + bool free; RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free); + int ivalue; if (!RNA_enum_value_from_id(item, value, &ivalue)) { const char *propname = RNA_property_identifier(prop); if (free) { @@ -2526,7 +2541,7 @@ void uiItemEnumR_string_prop(uiLayout *layout, return; } - for (a = 0; item[a].identifier; a++) { + for (int a = 0; item[a].identifier; a++) { if (item[a].identifier[0] == '\0') { /* Skip enum item separators. */ continue; @@ -2566,11 +2581,9 @@ void uiItemEnumR_string(uiLayout *layout, void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname) { - PropertyRNA *prop; uiBlock *block = layout->root->block; - uiBut *bt; - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { ui_item_disabled(layout, propname); @@ -2583,12 +2596,12 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname return; } - const EnumPropertyItem *item; - int totitem; - bool free; uiLayout *split = uiLayoutSplit(layout, 0.0f, false); uiLayout *column = uiLayoutColumn(split, false); + int totitem; + const EnumPropertyItem *item; + bool free; RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free); for (int i = 0; i < totitem; i++) { @@ -2605,7 +2618,7 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname } uiItemL(column, item[i].name, ICON_NONE); - bt = block->buttons.last; + uiBut *bt = block->buttons.last; bt->drawflag = UI_BUT_TEXT_LEFT; ui_but_tip_from_enum_item(bt, &item[i]); @@ -2628,8 +2641,6 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRNA **r_prop) { - StructRNA *srna; - /* look for collection property in Main */ /* Note: using global Main is OK-ish here, UI shall not access other Mains anyay... */ RNA_main_pointer_create(G_MAIN, r_ptr); @@ -2639,7 +2650,7 @@ static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRN RNA_STRUCT_BEGIN (r_ptr, iprop) { /* if it's a collection and has same pointer type, we've got it */ if (RNA_property_type(iprop) == PROP_COLLECTION) { - srna = RNA_property_pointer_type(r_ptr, iprop); + StructRNA *srna = RNA_property_pointer_type(r_ptr, iprop); if (ptype == srna) { *r_prop = iprop; @@ -2663,13 +2674,11 @@ static void ui_rna_collection_search_arg_free_fn(void *ptr) uiBut *ui_but_add_search( uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop) { - StructRNA *ptype; - PointerRNA sptr; - /* for ID's we do automatic lookup */ + PointerRNA sptr; if (!searchprop) { if (RNA_property_type(prop) == PROP_POINTER) { - ptype = RNA_property_pointer_type(ptr, prop); + StructRNA *ptype = RNA_property_pointer_type(ptr, prop); search_id_collection(ptype, &sptr, &searchprop); searchptr = &sptr; } @@ -2730,15 +2739,11 @@ void uiItemPointerR_prop(uiLayout *layout, const char *name, int icon) { - PropertyType type; - uiBut *but; - uiBlock *block; - StructRNA *icontype; - int w, h; - char namestr[UI_MAX_NAME_STR]; const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); - type = RNA_property_type(prop); + ui_block_new_button_group(uiLayoutGetBlock(layout), 0); + + const PropertyType type = RNA_property_type(prop); if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) { RNA_warning("Property %s.%s must be a pointer, string or enum", RNA_struct_identifier(ptr->type), @@ -2754,6 +2759,7 @@ void uiItemPointerR_prop(uiLayout *layout, /* get icon & name */ if (icon == ICON_NONE) { + StructRNA *icontype; if (type == PROP_POINTER) { icontype = RNA_property_pointer_type(ptr, prop); } @@ -2767,16 +2773,18 @@ void uiItemPointerR_prop(uiLayout *layout, name = RNA_property_ui_name(prop); } + char namestr[UI_MAX_NAME_STR]; if (use_prop_sep == false) { name = ui_item_name_add_colon(name, namestr); } /* create button */ - block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(layout); + int w, h; ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, false, &w, &h); w += UI_UNIT_X; /* X icon needs more space */ - but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0); + uiBut *but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0); ui_but_add_search(but, ptr, prop, searchptr, searchprop); } @@ -2789,15 +2797,13 @@ void uiItemPointerR(uiLayout *layout, const char *name, int icon) { - PropertyRNA *prop, *searchprop; - /* validate arguments */ - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); return; } - searchprop = RNA_struct_find_property(searchptr, searchpropname); + PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname); if (!searchprop) { RNA_warning("search collection property not found: %s.%s", RNA_struct_identifier(searchptr->type), @@ -2839,10 +2845,9 @@ static uiBut *ui_item_menu(uiLayout *layout, { uiBlock *block = layout->root->block; uiLayout *heading_layout = ui_layout_heading_find(layout); - uiBut *but; - int w, h; UI_block_layout_set_current(block, layout); + ui_block_new_button_group(block, 0); if (!name) { name = ""; @@ -2851,8 +2856,8 @@ static uiBut *ui_item_menu(uiLayout *layout, icon = ICON_BLANK1; } - w = ui_text_icon_width(layout, name, icon, 1); - h = UI_UNIT_Y; + int w = ui_text_icon_width(layout, name, icon, 1); + int h = UI_UNIT_Y; if (layout->root->type == UI_LAYOUT_HEADER) { /* ugly .. */ if (icon == ICON_NONE && force_menu) { @@ -2872,6 +2877,7 @@ static uiBut *ui_item_menu(uiLayout *layout, ui_layout_heading_label_add(layout, heading_layout, true, true); } + uiBut *but; if (name[0] && icon) { but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip); } @@ -2894,7 +2900,7 @@ static uiBut *ui_item_menu(uiLayout *layout, } if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) || - /* We never want a dropdown in menu! */ + /* We never want a drop-down in menu! */ (force_menu && layout->root->type != UI_LAYOUT_MENU)) { UI_but_type_set_menu_from_pulldown(but); } @@ -2952,10 +2958,9 @@ void uiItemMContents(uiLayout *layout, const char *menuname) void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) { uiBlock *block = layout->root->block; - uiLayout *col; UI_block_layout_set_current(block, layout); - col = uiLayoutColumn(layout, false); + uiLayout *col = uiLayoutColumn(layout, false); col->space = 0; col->emboss = UI_EMBOSS_NONE; @@ -3106,10 +3111,9 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout, static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon) { uiBlock *block = layout->root->block; - uiBut *but; - int w; UI_block_layout_set_current(block, layout); + ui_block_new_button_group(block, 0); if (!name) { name = ""; @@ -3118,8 +3122,9 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon) icon = ICON_BLANK1; } - w = ui_text_icon_width(layout, name, icon, 0); + const int w = ui_text_icon_width(layout, name, icon, 0); + uiBut *but; if (icon && name[0]) { but = uiDefIconTextBut( block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL); @@ -3184,7 +3189,6 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout) uiLayout *layout_row = uiLayoutRow(parent_layout, true); uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true); - layout_split->space = 0; split_wrapper.label_column = uiLayoutColumn(layout_split, true); split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT; split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split); @@ -3235,7 +3239,6 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval) /* label */ uiBlock *block = layout->root->block; int *retvalue = (block->handle) ? &block->handle->retvalue : NULL; - int w; UI_block_layout_set_current(block, layout); @@ -3246,7 +3249,7 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval) icon = ICON_BLANK1; } - w = ui_text_icon_width(layout, name, icon, 0); + const int w = ui_text_icon_width(layout, name, icon, 0); if (icon && name[0]) { uiDefIconTextButI(block, @@ -3368,7 +3371,7 @@ void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc typedef struct MenuItemLevel { int opcontext; /* don't use pointers to the strings because python can dynamically - * allocate strings and free before the menu draws, see [#27304] */ + * allocate strings and free before the menu draws, see T27304. */ char opname[OP_MAX_TYPENAME]; char propname[MAX_IDPROP_NAME]; PointerRNA rnapoin; @@ -3394,9 +3397,6 @@ void uiItemMenuEnumO_ptr(uiLayout *layout, const char *name, int icon) { - MenuItemLevel *lvl; - uiBut *but; - /* Caller must check */ BLI_assert(ot->srna != NULL); @@ -3408,12 +3408,12 @@ void uiItemMenuEnumO_ptr(uiLayout *layout, icon = ICON_BLANK1; } - lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); + MenuItemLevel *lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); BLI_strncpy(lvl->opname, ot->idname, sizeof(lvl->opname)); BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname)); lvl->opcontext = layout->root->opcontext; - but = ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl, NULL, true); + uiBut *but = ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl, NULL, true); /* add hotkey here, lower UI code can't detect it */ if ((layout->root->block->flag & UI_BLOCK_LOOP) && (ot->prop && ot->invoke)) { @@ -3484,9 +3484,7 @@ void uiItemMenuEnumR_prop( void uiItemMenuEnumR( uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon) { - PropertyRNA *prop; - - prop = RNA_struct_find_property(ptr, propname); + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { ui_item_disabled(layout, propname); RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); @@ -3496,13 +3494,19 @@ void uiItemMenuEnumR( uiItemMenuEnumR_prop(layout, ptr, prop, name, icon); } -void uiItemTabsEnumR_prop( - uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool icon_only) +void uiItemTabsEnumR_prop(uiLayout *layout, + bContext *C, + PointerRNA *ptr, + PropertyRNA *prop, + PointerRNA *ptr_highlight, + PropertyRNA *prop_highlight, + bool icon_only) { uiBlock *block = layout->root->block; UI_block_layout_set_current(block, layout); - ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only); + ui_item_enum_expand_tabs( + layout, C, block, ptr, prop, ptr_highlight, prop_highlight, NULL, UI_UNIT_Y, icon_only); } /** \} */ @@ -3718,18 +3722,18 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box) } } -static void ui_litem_layout_column(uiLayout *litem, bool is_box) +static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu) { - int itemh, x, y; + int itemw, itemh, x, y; x = litem->x; y = litem->y; LISTBASE_FOREACH (uiItem *, item, &litem->items) { - ui_item_size(item, NULL, &itemh); + ui_item_size(item, &itemw, &itemh); y -= itemh; - ui_item_position(item, x, y, litem->w, itemh); + ui_item_position(item, x, y, is_menu ? itemw : litem->w, itemh); if (item->next && (!is_box || item != litem->items.first)) { y -= litem->space; @@ -3890,8 +3894,11 @@ static void ui_litem_layout_root(uiLayout *litem) else if (litem->root->type == UI_LAYOUT_PIEMENU) { ui_litem_layout_root_radial(litem); } + else if (litem->root->type == UI_LAYOUT_MENU) { + ui_litem_layout_column(litem, false, true); + } else { - ui_litem_layout_column(litem, false); + ui_litem_layout_column(litem, false, false); } } @@ -3935,7 +3942,7 @@ static void ui_litem_layout_box(uiLayout *litem) litem->h -= 2 * boxspace; } - ui_litem_layout_column(litem, true); + ui_litem_layout_column(litem, true, false); litem->x -= boxspace; litem->y -= boxspace; @@ -5034,6 +5041,152 @@ int uiLayoutGetEmboss(uiLayout *layout) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Block Layout Search Filtering + * \{ */ + +/* Disabled for performance reasons, but this could be turned on in the future. */ +// #define PROPERTY_SEARCH_USE_TOOLTIPS + +static bool block_search_panel_label_matches(const uiBlock *block, const char *search_string) +{ + if ((block->panel != NULL) && (block->panel->type != NULL)) { + if (BLI_strcasestr(block->panel->type->label, search_string)) { + return true; + } + } + return false; +} + +/** + * Returns true if a button or the data / operator it represents matches the search filter. + */ +static bool button_matches_search_filter(uiBut *but, const char *search_filter) +{ + /* Do the shorter checks first for better performance in case there is a match. */ + if (BLI_strcasestr(but->str, search_filter)) { + return true; + } + + if (but->optype != NULL) { + if (BLI_strcasestr(but->optype->name, search_filter)) { + return true; + } + } + + if (but->rnaprop != NULL) { + if (BLI_strcasestr(RNA_property_ui_name(but->rnaprop), search_filter)) { + return true; + } +#ifdef PROPERTY_SEARCH_USE_TOOLTIPS + if (BLI_strcasestr(RNA_property_description(but->rnaprop), search_filter)) { + return true; + } +#endif + + /* Search through labels of enum property items if they are in a drop-down menu. + * Unfortunately we have no #bContext here so we cannot search through RNA enums + * with dynamic entries (or "itemf" functions) which require context. */ + if (but->type == UI_BTYPE_MENU) { + PointerRNA *ptr = &but->rnapoin; + PropertyRNA *enum_prop = but->rnaprop; + + int items_len; + const EnumPropertyItem *items_array = NULL; + bool free; + RNA_property_enum_items_gettexted(NULL, ptr, enum_prop, &items_array, &items_len, &free); + + if (items_array == NULL) { + return false; + } + + for (int i = 0; i < items_len; i++) { + /* Check for NULL name field which enums use for separators. */ + if (items_array[i].name == NULL) { + continue; + } + if (BLI_strcasestr(items_array[i].name, search_filter)) { + return true; + } + } + if (free) { + MEM_freeN((EnumPropertyItem *)items_array); + } + } + } + + return false; +} + +/** + * Test for a search result within a specific button group. + */ +static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter) +{ + LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) { + uiBut *but = link->data; + if (button_matches_search_filter(but, search_filter)) { + return true; + } + } + + return false; +} + +/** + * Apply the search filter, tagging all buttons with whether they match or not. + * Tag every button in the group as a result if any button in the group matches. + * + * \note It would be great to return early here if we found a match, but because + * the results may be visible we have to continue searching the entire block. + * + * \return True if the block has any search results. + */ +static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_filter) +{ + bool has_result = false; + LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) { + if (button_group_has_search_match(button_group, search_filter)) { + has_result = true; + } + else { + LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) { + uiBut *but = link->data; + but->flag |= UI_SEARCH_FILTER_NO_MATCH; + } + } + } + return has_result; +} + +/** + * Apply property search behavior, setting panel flags and deactivating buttons that don't match. + * + * \note Must not be run after #UI_block_layout_resolve. + */ +bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter) +{ + if (search_filter == NULL || search_filter[0] == '\0') { + return false; + } + + const bool panel_label_matches = block_search_panel_label_matches(block, search_filter); + + const bool has_result = (panel_label_matches) ? + true : + block_search_filter_tag_buttons(block, search_filter); + + if (block->panel != NULL) { + if (has_result) { + ui_panel_tag_search_filter_match(block->panel); + } + } + + return has_result; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Layout * \{ */ @@ -5196,7 +5349,7 @@ static void ui_item_layout(uiItem *item) switch (litem->item.type) { case ITEM_LAYOUT_COLUMN: - ui_litem_layout_column(litem, false); + ui_litem_layout_column(litem, false, false); break; case ITEM_LAYOUT_COLUMN_FLOW: ui_litem_layout_column_flow(litem); @@ -5265,6 +5418,9 @@ static void ui_layout_free(uiLayout *layout) { LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) { if (item->type == ITEM_BUTTON) { + uiButtonItem *bitem = (uiButtonItem *)item; + + bitem->but->layout = NULL; MEM_freeN(item); } else { @@ -5324,7 +5480,7 @@ uiLayout *UI_block_layout(uiBlock *block, layout->context = NULL; layout->emboss = UI_EMBOSS_UNDEFINED; - if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU) { + if (ELEM(type, UI_LAYOUT_MENU, UI_LAYOUT_PIEMENU)) { layout->space = 0; } @@ -5393,6 +5549,8 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) if (layout->emboss != UI_EMBOSS_UNDEFINED) { but->emboss = layout->emboss; } + + ui_button_group_add_but(uiLayoutGetBlock(layout), but); } bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but) @@ -5445,6 +5603,19 @@ void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv) layout->root->argv = argv; } +/** + * Used for property search when the layout process needs to be cancelled in order to avoid + * computing the locations for buttons, but the layout items created while adding the buttons + * must still be freed. + */ +void UI_block_layout_free(uiBlock *block) +{ + LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) { + ui_layout_free(root->layout); + MEM_freeN(root); + } +} + void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y) { BLI_assert(block->active); @@ -5458,15 +5629,16 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y) block->curlayout = NULL; - LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) { + LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) { ui_layout_add_padding_button(root); /* NULL in advance so we don't interfere when adding button */ ui_layout_end(block, root->layout, r_x, r_y); ui_layout_free(root->layout); + MEM_freeN(root); } - BLI_freelistN(&block->layouts); + BLI_listbase_clear(&block->layouts); /* XXX silly trick, interface_templates.c doesn't get linked * because it's not used by other files in this module? */ |