diff options
Diffstat (limited to 'source/blender/editors/interface/interface.c')
-rw-r--r-- | source/blender/editors/interface/interface.c | 324 |
1 files changed, 254 insertions, 70 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 28b86674fdd..22fbffa9030 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -44,6 +44,7 @@ #include "BLI_utildefines.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_idprop.h" #include "BKE_main.h" @@ -51,7 +52,6 @@ #include "BKE_screen.h" #include "BKE_unit.h" -#include "GPU_glew.h" #include "GPU_matrix.h" #include "GPU_state.h" @@ -807,7 +807,12 @@ static bool ui_but_update_from_old_block(const bContext *C, SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); - SWAP(struct uiButSearchData *, oldbut->search, but->search); + if (oldbut->type == UI_BTYPE_SEARCH_MENU) { + uiButSearch *search_oldbut = (uiButSearch *)oldbut, *search_but = (uiButSearch *)but; + + SWAP(uiButSearchArgFreeFn, search_oldbut->arg_free_fn, search_but->arg_free_fn); + SWAP(void *, search_oldbut->arg, search_but->arg); + } /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ @@ -815,10 +820,10 @@ static bool ui_but_update_from_old_block(const bContext *C, oldbut->hardmax = but->hardmax; } - /* Selectively copy a1, a2 since their use differs across all button types - * (and we'll probably split these out later) */ - if (ELEM(oldbut->type, UI_BTYPE_PROGRESS_BAR)) { - oldbut->a1 = but->a1; + if (oldbut->type == UI_BTYPE_PROGRESS_BAR) { + uiButProgressbar *progress_oldbut = (uiButProgressbar *)oldbut; + uiButProgressbar *progress_but = (uiButProgressbar *)but; + progress_oldbut->progress = progress_but->progress; } if (!BLI_listbase_is_empty(&block->butstore)) { @@ -892,6 +897,12 @@ bool UI_but_active_only_ex( } } if ((activate == true) || (found == false)) { + /* There might still be another active button. */ + uiBut *old_active = ui_region_find_active_but(region); + if (old_active) { + ui_but_active_free(C, old_active); + } + ui_but_activate_event((bContext *)C, region, but); } else if ((found == true) && (isactive == false)) { @@ -1486,7 +1497,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) continue; } } - else if (but->dt != UI_EMBOSS_PULLDOWN) { + else if (but->emboss != UI_EMBOSS_PULLDOWN) { continue; } @@ -1733,6 +1744,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x wmWindow *window = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); ARegion *region = CTX_wm_region(C); + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); uiBut *but; BLI_assert(block->active); @@ -1761,10 +1773,12 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x } } - ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); + const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( + depsgraph, (scene) ? scene->r.cfra : 0.0f); + ui_but_anim_flag(but, &anim_eval_context); ui_but_override_flag(CTX_data_main(C), but); if (UI_but_is_decorator(but)) { - ui_but_anim_decorate_update_from_flag(but); + ui_but_anim_decorate_update_from_flag((uiButDecorator *)but); } ui_but_predefined_extra_operator_icons_add(but); } @@ -2012,6 +2026,7 @@ int ui_but_is_pushed_ex(uiBut *but, double *value) case UI_BTYPE_HOTKEY_EVENT: case UI_BTYPE_KEY_EVENT: case UI_BTYPE_COLOR: + case UI_BTYPE_DECORATOR: is_push = -1; break; case UI_BTYPE_BUT_TOGGLE: @@ -2314,7 +2329,8 @@ bool ui_but_supports_cycling(const uiBut *but) { return ((ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX)) || (but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) || - (but->type == UI_BTYPE_COLOR && but->a1 != -1) || (but->menu_step_func != NULL)); + (but->type == UI_BTYPE_COLOR && ((uiButColor *)but)->is_pallete_color) || + (but->menu_step_func != NULL)); } double ui_but_value_get(uiBut *but) @@ -2797,25 +2813,39 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size) return str; } -static bool ui_set_but_string_eval_num_unit(bContext *C, - uiBut *but, - const char *str, - double *r_value) +/** + * Report a generic error prefix when evaluating a string with #BPY_execute_string_as_number + * as the Python error on it's own doesn't provide enough context. + */ +#define UI_NUMBER_EVAL_ERROR_PREFIX IFACE_("Error evaluating number, see Info editor for details") + +static bool ui_number_from_string_units( + bContext *C, const char *str, const int unit_type, const UnitSettings *unit, double *r_value) +{ + return user_string_to_number(C, str, unit, unit_type, UI_NUMBER_EVAL_ERROR_PREFIX, r_value); +} + +static bool ui_number_from_string_units_with_but(bContext *C, + const char *str, + const uiBut *but, + double *r_value) { + const int unit_type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but)); const UnitSettings *unit = but->block->unit; - int type = RNA_SUBTYPE_UNIT_VALUE(UI_but_unit_type_get(but)); - return user_string_to_number(C, str, unit, type, r_value); + return ui_number_from_string_units(C, str, unit_type, unit, r_value); } static bool ui_number_from_string(bContext *C, const char *str, double *r_value) { + bool ok; #ifdef WITH_PYTHON - return BPY_execute_string_as_number(C, NULL, str, true, r_value); + ok = BPY_execute_string_as_number(C, NULL, str, UI_NUMBER_EVAL_ERROR_PREFIX, r_value); #else UNUSED_VARS(C); *r_value = atof(str); - return true; + ok = true; #endif + return ok; } static bool ui_number_from_string_factor(bContext *C, const char *str, double *r_value) @@ -2849,7 +2879,7 @@ static bool ui_number_from_string_percentage(bContext *C, const char *str, doubl return ui_number_from_string(C, str, r_value); } -bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double *r_value) +bool ui_but_string_eval_number(bContext *C, const uiBut *but, const char *str, double *r_value) { if (str[0] == '\0') { *r_value = 0.0; @@ -2863,7 +2893,7 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double if (ui_but_is_float(but)) { if (ui_but_is_unit(but)) { - return ui_set_but_string_eval_num_unit(C, but, str, r_value); + return ui_number_from_string_units_with_but(C, str, but, r_value); } if (subtype == PROP_FACTOR) { return ui_number_from_string_factor(C, str, r_value); @@ -2922,10 +2952,10 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL, NULL); return true; } + + uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but : NULL; /* RNA pointer */ PointerRNA rptr; - PointerRNA ptr = but->rnasearchpoin; - PropertyRNA *prop = but->rnasearchprop; /* This is kind of hackish, in theory think we could only ever use the second member of * this if/else, since ui_searchbox_apply() is supposed to always set that pointer when @@ -2933,12 +2963,16 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) * to try to break as little as possible existing code. All this is band-aids anyway. * Fact remains, using editstr as main 'reference' over whole search button thingy * is utterly weak and should be redesigned imho, but that's not a simple task. */ - if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr)) { + if (search_but && search_but->rnasearchprop && + RNA_property_collection_lookup_string( + &search_but->rnasearchpoin, search_but->rnasearchprop, str, &rptr)) { RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } - else if (but->func_arg2 != NULL) { - RNA_pointer_create( - NULL, RNA_property_pointer_type(&but->rnapoin, but->rnaprop), but->func_arg2, &rptr); + else if (search_but->item_active != NULL) { + RNA_pointer_create(NULL, + RNA_property_pointer_type(&but->rnapoin, but->rnaprop), + search_but->item_active, + &rptr); RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); } @@ -3003,7 +3037,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str) /* number editing */ double value; - if (ui_but_string_set_eval_num(C, but, str, &value) == false) { + if (ui_but_string_eval_number(C, but, str, &value) == false) { WM_report_banner_show(); return false; } @@ -3075,8 +3109,38 @@ static double soft_range_round_down(double value, double max) return newmax; } +void ui_but_range_set_hard(uiBut *but) +{ + if (but->rnaprop) { + const PropertyType type = RNA_property_type(but->rnaprop); + double hardmin, hardmax; + + /* clamp button range to something reasonable in case + * we get -inf/inf from RNA properties */ + if (type == PROP_INT) { + int imin, imax; + + RNA_property_int_range(&but->rnapoin, but->rnaprop, &imin, &imax); + hardmin = (imin == INT_MIN) ? -1e4 : imin; + hardmax = (imin == INT_MAX) ? 1e4 : imax; + } + else if (type == PROP_FLOAT) { + float fmin, fmax; + + RNA_property_float_range(&but->rnapoin, but->rnaprop, &fmin, &fmax); + hardmin = (fmin == -FLT_MAX) ? (float)-1e4 : fmin; + hardmax = (fmax == FLT_MAX) ? (float)1e4 : fmax; + } + else { + return; + } + but->hardmin = hardmin; + but->hardmax = hardmax; + } +} + /* note: this could be split up into functions which handle arrays and not */ -static void ui_set_but_soft_range(uiBut *but) +void ui_but_range_set_soft(uiBut *but) { /* ideally we would not limit this but practically, its more than * enough worst case is very long vectors wont use a smart soft-range @@ -3178,6 +3242,28 @@ static void ui_set_but_soft_range(uiBut *but) /* ******************* Free ********************/ +/** + * Free data specific to a certain button type. + * For now just do in a switch-case, we could instead have a callback stored in #uiBut and set that + * in #ui_but_alloc_info(). + */ +static void ui_but_free_type_specific(uiBut *but) +{ + switch (but->type) { + case UI_BTYPE_SEARCH_MENU: { + uiButSearch *search_but = (uiButSearch *)but; + + if (search_but->arg_free_fn) { + search_but->arg_free_fn(search_but->arg); + search_but->arg = NULL; + } + break; + } + default: + break; + } +} + /* can be called with C==NULL */ static void ui_but_free(const bContext *C, uiBut *but) { @@ -3198,13 +3284,7 @@ static void ui_but_free(const bContext *C, uiBut *but) MEM_freeN(but->hold_argN); } - if (but->search != NULL) { - if (but->search->arg_free_fn) { - but->search->arg_free_fn(but->search->arg); - but->search->arg = NULL; - } - MEM_freeN(but->search); - } + ui_but_free_type_specific(but); if (but->active) { /* XXX solve later, buttons should be free-able without context ideally, @@ -3337,7 +3417,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) block->oldblock = oldblock; } -uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, short dt) +uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, char emboss) { uiBlock *block; wmWindow *window; @@ -3348,7 +3428,7 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh block = MEM_callocN(sizeof(uiBlock), "uiBlock"); block->active = 1; - block->dt = dt; + block->emboss = emboss; block->evil_C = (void *)C; /* XXX */ if (scn) { @@ -3387,12 +3467,12 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh char UI_block_emboss_get(uiBlock *block) { - return block->dt; + return block->emboss; } -void UI_block_emboss_set(uiBlock *block, char dt) +void UI_block_emboss_set(uiBlock *block, char emboss) { - block->dt = dt; + block->emboss = emboss; } void UI_block_theme_style_set(uiBlock *block, char theme_style) @@ -3480,7 +3560,7 @@ static void ui_but_update_ex(uiBut *but, const bool validate) /* only update soft range while not editing */ if (!ui_but_is_editing(but)) { if ((but->rnaprop != NULL) || (but->poin && (but->pointype & UI_BUT_POIN_TYPES))) { - ui_set_but_soft_range(but); + ui_but_range_set_soft(but); } } @@ -3683,14 +3763,111 @@ void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]) IMB_colormanagement_scene_linear_to_display_v3(pixel, display); } -static uiBut *ui_but_alloc(const eButType type) +static void ui_but_alloc_info(const eButType type, + size_t *r_alloc_size, + const char **r_alloc_str, + bool *r_has_custom_type) { + size_t alloc_size; + const char *alloc_str; + bool has_custom_type = true; + switch (type) { + case UI_BTYPE_COLOR: + alloc_size = sizeof(uiButColor); + alloc_str = "uiButColor"; + break; + case UI_BTYPE_DECORATOR: + alloc_size = sizeof(uiButDecorator); + alloc_str = "uiButDecorator"; + break; case UI_BTYPE_TAB: - return MEM_callocN(sizeof(uiButTab), "uiButTab"); + alloc_size = sizeof(uiButTab); + alloc_str = "uiButTab"; + break; + case UI_BTYPE_SEARCH_MENU: + alloc_size = sizeof(uiButSearch); + alloc_str = "uiButSearch"; + break; + case UI_BTYPE_PROGRESS_BAR: + alloc_size = sizeof(uiButProgressbar); + alloc_str = "uiButProgressbar"; + break; + case UI_BTYPE_HSVCUBE: + alloc_size = sizeof(uiButHSVCube); + alloc_str = "uiButHSVCube"; + break; default: - return MEM_callocN(sizeof(uiBut), "uiBut"); + alloc_size = sizeof(uiBut); + alloc_str = "uiBut"; + has_custom_type = false; + break; + } + + if (r_alloc_size) { + *r_alloc_size = alloc_size; + } + 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, NULL); + + return MEM_callocN(alloc_size, alloc_str); +} + +/** + * Reallocate the button (new address is returned) for a new button type. + * This should generally be avoided and instead the correct type be created right away. + * + * \note Only the #uiBut data can be kept. If the old button used a derived type (e.g. #uiButTab), + * the data that is not inside #uiBut will be lost. + */ +uiBut *ui_but_change_type(uiBut *but, eButType new_type) +{ + if (but->type != new_type) { + size_t alloc_size; + const char *alloc_str; + uiBut *insert_after_but = but->prev; + bool new_has_custom_type, old_has_custom_type; + + /* Remove old button address */ + BLI_remlink(&but->block->buttons, but); + + ui_but_alloc_info(but->type, NULL, NULL, &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 void *old_but_ptr = but; + /* 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; + + but = MEM_recallocN_id(but, alloc_size, alloc_str); + but->type = new_type; + if (has_str_ptr_to_self) { + but->str = but->strdata; + } + + BLI_insertlinkafter(&but->block->buttons, insert_after_but, but); + + if (but->layout) { + const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr, but); + BLI_assert(found_layout); + UNUSED_VARS_NDEBUG(found_layout); + } + } } + + return but; } /** @@ -3772,7 +3949,7 @@ static uiBut *ui_def_but(uiBlock *block, but->tip = tip; but->disabled_info = block->lockstr; - but->dt = block->dt; + but->emboss = block->emboss; but->pie_dir = UI_RADIAL_NONE; but->block = block; /* pointer back, used for frontbuffer status, and picker */ @@ -3838,6 +4015,7 @@ static uiBut *ui_def_but(uiBlock *block, if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_BUT, + UI_BTYPE_DECORATOR, UI_BTYPE_LABEL, UI_BTYPE_PULLDOWN, UI_BTYPE_ROUNDBOX, @@ -4305,7 +4483,7 @@ static uiBut *ui_def_but_rna(uiBlock *block, } if (type == UI_BTYPE_MENU) { - if (but->dt == UI_EMBOSS_PULLDOWN) { + if (but->emboss == UI_EMBOSS_PULLDOWN) { ui_but_submenu_enable(block, but); } } @@ -6332,54 +6510,55 @@ void UI_but_func_search_set(uiBut *but, uiButHandleFunc search_exec_fn, void *active) { + uiButSearch *search_but = (uiButSearch *)but; + + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + /* needed since callers don't have access to internal functions * (as an alternative we could expose it) */ if (search_create_fn == NULL) { search_create_fn = ui_searchbox_create_generic; } - struct uiButSearchData *search = but->search; - if (search != NULL) { - if (search->arg_free_fn != NULL) { - search->arg_free_fn(but->search->arg); - search->arg = NULL; - } - } - else { - search = MEM_callocN(sizeof(*but->search), __func__); - but->search = search; + if (search_but->arg_free_fn != NULL) { + search_but->arg_free_fn(search_but->arg); + search_but->arg = NULL; } - search->create_fn = search_create_fn; - search->update_fn = search_update_fn; + search_but->popup_create_fn = search_create_fn; + search_but->items_update_fn = search_update_fn; + search_but->item_active = active; - search->arg = arg; - search->arg_free_fn = search_arg_free_fn; + search_but->arg = arg; + search_but->arg_free_fn = search_arg_free_fn; if (search_exec_fn) { #ifdef DEBUG - if (but->func) { + if (search_but->but.func) { /* watch this, can be cause of much confusion, see: T47691 */ printf("%s: warning, overwriting button callback with search function callback!\n", __func__); } #endif - UI_but_func_set(but, search_exec_fn, search->arg, active); + /* Handling will pass the active item as arg2 later, so keep it NULL here. */ + UI_but_func_set(but, search_exec_fn, search_but->arg, NULL); } /* search buttons show red-alert if item doesn't exist, not for menus */ if (0 == (but->block->flag & UI_BLOCK_LOOP)) { /* skip empty buttons, not all buttons need input, we only show invalid */ if (but->drawstr[0]) { - ui_but_search_refresh(but); + ui_but_search_refresh(search_but); } } } void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn) { - struct uiButSearchData *search = but->search; - search->context_menu_fn = context_menu_fn; + uiButSearch *but_search = (uiButSearch *)but; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + + but_search->item_context_menu_fn = context_menu_fn; } /** @@ -6388,14 +6567,18 @@ void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn co */ void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string) { - struct uiButSearchData *search = but->search; - search->sep_string = search_sep_string; + uiButSearch *but_search = (uiButSearch *)but; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + + but_search->item_sep_string = search_sep_string; } void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn) { - struct uiButSearchData *search = but->search; - search->tooltip_fn = tooltip_fn; + uiButSearch *but_search = (uiButSearch *)but; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + + but_search->item_tooltip_fn = tooltip_fn; } /* Callbacks for operator search button. */ @@ -6427,7 +6610,8 @@ static void operator_enum_search_update_fn(const struct bContext *C, /* note: need to give the index rather than the * identifier because the enum can be freed */ if (BLI_strcasestr(item->name, str)) { - if (!UI_search_item_add(items, item->name, POINTER_FROM_INT(item->value), item->icon, 0)) { + if (!UI_search_item_add( + items, item->name, POINTER_FROM_INT(item->value), item->icon, 0, 0)) { break; } } |