diff options
Diffstat (limited to 'source/blender')
12 files changed, 383 insertions, 172 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 184032df3c6..4a98d72a463 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -57,6 +57,7 @@ struct bNodeSocket; struct bNodeTree; struct bScreen; struct rcti; +struct uiButSearch; struct uiFontStyle; struct uiList; struct uiStyle; @@ -371,6 +372,7 @@ typedef enum { UI_BTYPE_SEPR_SPACER = 56 << 9, /** Resize handle (resize uilist). */ UI_BTYPE_GRIP = 57 << 9, + UI_BTYPE_DECORATOR = 58 << 9, } eButType; #define BUTTYPE (63 << 9) @@ -500,7 +502,7 @@ typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg); /* Search types. */ typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C, struct ARegion *butregion, - uiBut *but); + struct uiButSearch *search_but); typedef void (*uiButSearchUpdateFn)(const struct bContext *C, void *arg, const char *str, @@ -537,7 +539,7 @@ typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1); bool UI_but_has_tooltip_label(const uiBut *but); bool UI_but_is_tool(const uiBut *but); bool UI_but_is_utf8(const uiBut *but); -#define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb) +#define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR) bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title); bool UI_block_is_empty(const uiBlock *block); @@ -1929,8 +1931,6 @@ uiLayout *uiLayoutGridFlow(uiLayout *layout, uiLayout *uiLayoutBox(uiLayout *layout); uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, - struct PointerRNA *ptr, - struct PropertyRNA *prop, struct PointerRNA *actptr, struct PropertyRNA *actprop); uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index c5d5fbb90c0..9a4eb73c20e 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -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]) */ @@ -1773,7 +1778,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x 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); } @@ -2021,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: @@ -2945,10 +2951,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 @@ -2956,12 +2962,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); } @@ -3231,6 +3241,28 @@ void ui_but_range_set_soft(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) { @@ -3251,13 +3283,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, @@ -3736,14 +3762,99 @@ 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_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; 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; } /** @@ -3891,6 +4002,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, @@ -6385,54 +6497,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; } /** @@ -6441,14 +6554,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. */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 8d12a1dd1ad..cc58082cb02 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -120,35 +120,41 @@ void ui_but_anim_flag(uiBut *but, const AnimationEvalContext *anim_eval_context) } } -static uiBut *ui_but_anim_decorate_find_attached_button(uiBut *but_decorate) +static uiBut *ui_but_anim_decorate_find_attached_button(uiButDecorator *but_decorate) { uiBut *but_iter = NULL; - BLI_assert(UI_but_is_decorator(but_decorate)); - BLI_assert(but_decorate->rnasearchpoin.data && but_decorate->rnasearchprop); + BLI_assert(UI_but_is_decorator(&but_decorate->but)); + BLI_assert(but_decorate->rnapoin.data && but_decorate->rnaprop); - LISTBASE_CIRCULAR_BACKWARD_BEGIN (&but_decorate->block->buttons, but_iter, but_decorate->prev) { - if (but_iter != but_decorate && - ui_but_rna_equals_ex(but_iter, - &but_decorate->rnasearchpoin, - but_decorate->rnasearchprop, - POINTER_AS_INT(but_decorate->custom_data))) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN ( + &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev) { + if (but_iter != (uiBut *)but_decorate && + ui_but_rna_equals_ex( + but_iter, &but_decorate->rnapoin, but_decorate->rnaprop, but_decorate->rnaindex)) { return but_iter; } } - LISTBASE_CIRCULAR_BACKWARD_END(&but_decorate->block->buttons, but_iter, but_decorate->prev); + LISTBASE_CIRCULAR_BACKWARD_END( + &but_decorate->but.block->buttons, but_iter, but_decorate->but.prev); return NULL; } -void ui_but_anim_decorate_update_from_flag(uiBut *but) +void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but) { - const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but); + if (!decorator_but->rnapoin.data || !decorator_but->rnaprop) { + /* Nothing to do. */ + return; + } + + const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(decorator_but); + uiBut *but = &decorator_but->but; if (!but_anim) { printf("Could not find button with matching property to decorate (%s.%s)\n", - RNA_struct_identifier(but->rnasearchpoin.type), - RNA_property_identifier(but->rnasearchprop)); + RNA_struct_identifier(decorator_but->rnapoin.type), + RNA_property_identifier(decorator_but->rnaprop)); return; } @@ -325,7 +331,7 @@ void ui_but_anim_paste_driver(bContext *C) void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)) { wmWindowManager *wm = CTX_wm_manager(C); - uiBut *but_decorate = arg_but; + uiButDecorator *but_decorate = arg_but; uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate); if (!but_anim) { @@ -333,7 +339,7 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) } /* FIXME(campbell), swapping active pointer is weak. */ - SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active); + SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->but.active); wm->op_undo_depth++; if (but_anim->flag & UI_BUT_DRIVEN) { @@ -357,6 +363,6 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) WM_operator_properties_free(&props_ptr); } - SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active); + SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->but.active); wm->op_undo_depth--; } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index aaa5e1c0cf1..46876fca9a5 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -962,7 +962,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const PropertyType prop_type = RNA_property_type(but->rnaprop); if (((prop_type == PROP_POINTER) || (prop_type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU && - but->search->update_fn == ui_rna_collection_search_update_fn)) && + ((uiButSearch *)but)->items_update_fn == ui_rna_collection_search_update_fn)) && ui_jump_to_target_button_poll(C)) { uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"), diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 7ea64d36d48..f55d8d5ccc6 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -767,11 +767,12 @@ static void ui_apply_but_func(bContext *C, uiBut *but) after->rnapoin = but->rnapoin; after->rnaprop = but->rnaprop; - if (but->search != NULL) { - after->search_arg_free_fn = but->search->arg_free_fn; - after->search_arg = but->search->arg; - but->search->arg_free_fn = NULL; - but->search->arg = NULL; + if (but->type == UI_BTYPE_SEARCH_MENU) { + uiButSearch *search_but = (uiButSearch *)but; + after->search_arg_free_fn = search_but->arg_free_fn; + after->search_arg = search_but->arg; + search_but->arg_free_fn = NULL; + search_but->arg = NULL; } if (but->context) { @@ -1047,8 +1048,19 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data) but->rename_orig = data->origstr; data->origstr = NULL; } + + void *orig_arg2 = but->func_arg2; + + /* If arg2 isn't in use already, pass the active search item through it. */ + if ((but->func_arg2 == NULL) && (but->type == UI_BTYPE_SEARCH_MENU)) { + uiButSearch *search_but = (uiButSearch *)but; + but->func_arg2 = search_but->item_active; + } + ui_apply_but_func(C, but); + but->func_arg2 = orig_arg2; + data->retval = but->retval; data->applied = true; } @@ -2087,6 +2099,7 @@ static void ui_apply_but( /* handle different types */ switch (but->type) { case UI_BTYPE_BUT: + case UI_BTYPE_DECORATOR: ui_apply_but_BUT(C, but, data); break; case UI_BTYPE_TEXT: @@ -3321,7 +3334,9 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) /* optional searchbox */ if (but->type == UI_BTYPE_SEARCH_MENU) { - data->searchbox = but->search->create_fn(C, data->region, but); + uiButSearch *search_but = (uiButSearch *)but; + + data->searchbox = search_but->popup_create_fn(C, data->region, search_but); ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */ } @@ -7522,6 +7537,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * switch (but->type) { case UI_BTYPE_BUT: + case UI_BTYPE_DECORATOR: retval = ui_do_but_BUT(C, but, data, event); break; case UI_BTYPE_KEY_EVENT: @@ -8430,7 +8446,7 @@ void UI_context_update_anim_flag(const bContext *C) 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); } ED_region_tag_redraw(region); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index bf2971f93df..0dfa23a4332 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -147,19 +147,11 @@ enum { /* max amount of items a radial menu (pie menu) can contain */ #define PIE_MAX_ITEMS 8 -struct uiButSearchData { - uiButSearchCreateFn create_fn; - uiButSearchUpdateFn update_fn; - void *arg; - uiButSearchArgFreeFn arg_free_fn; - uiButSearchContextMenuFn context_menu_fn; - uiButSearchTooltipFn tooltip_fn; - - const char *sep_string; -}; - struct uiBut { struct uiBut *next, *prev; + + /* Pointer back to the layout item holding this button. */ + uiLayout *layout; int flag, drawflag; eButType type; eButPointerType pointype; @@ -214,8 +206,6 @@ struct uiBut { uiButCompleteFunc autocomplete_func; void *autofunc_arg; - struct uiButSearchData *search; - uiButHandleRenameFunc rename_func; void *rename_arg1; void *rename_orig; @@ -256,9 +246,6 @@ struct uiBut { struct PropertyRNA *rnaprop; int rnaindex; - struct PointerRNA rnasearchpoin; - struct PropertyRNA *rnasearchprop; - /* Operator data */ struct wmOperatorType *optype; struct PointerRNA *opptr; @@ -294,11 +281,41 @@ struct uiBut { uiBlock *block; }; +/** Derived struct for #UI_BTYPE_TAB */ typedef struct uiButTab { uiBut but; struct MenuType *menu; } uiButTab; +/** Derived struct for #UI_BTYPE_SEARCH_MENU */ +typedef struct uiButSearch { + uiBut but; + + uiButSearchCreateFn popup_create_fn; + uiButSearchUpdateFn items_update_fn; + void *item_active; + + void *arg; + uiButSearchArgFreeFn arg_free_fn; + + uiButSearchContextMenuFn item_context_menu_fn; + uiButSearchTooltipFn item_tooltip_fn; + + const char *item_sep_string; + + struct PointerRNA rnasearchpoin; + struct PropertyRNA *rnasearchprop; +} uiButSearch; + +/** Derived struct for #UI_BTYPE_DECORATOR */ +typedef struct uiButDecorator { + uiBut but; + + struct PointerRNA rnapoin; + struct PropertyRNA *rnaprop; + int rnaindex; +} uiButDecorator; + /** * Additional, superimposed icon for a button, invoking an operator. */ @@ -493,6 +510,8 @@ extern void ui_window_to_region_rcti(const struct ARegion *region, extern void ui_region_to_window(const struct ARegion *region, int *x, int *y); extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect); +uiBut *ui_but_change_type(uiBut *but, eButType new_type); + extern double ui_but_value_get(uiBut *but); extern void ui_but_value_set(uiBut *but, double value); extern void ui_but_hsv_set(uiBut *but); @@ -662,13 +681,13 @@ ColorPicker *ui_block_colorpicker_create(struct uiBlock *block); /* Searchbox for string button */ struct ARegion *ui_searchbox_create_generic(struct bContext *C, struct ARegion *butregion, - uiBut *but); + uiButSearch *search_but); struct ARegion *ui_searchbox_create_operator(struct bContext *C, struct ARegion *butregion, - uiBut *but); + uiButSearch *search_but); struct ARegion *ui_searchbox_create_menu(struct bContext *C, struct ARegion *butregion, - uiBut *but); + uiButSearch *search_but); bool ui_searchbox_inside(struct ARegion *region, int x, int y); int ui_searchbox_find_index(struct ARegion *region, const char *name); @@ -681,7 +700,7 @@ bool ui_searchbox_event(struct bContext *C, const struct wmEvent *event); bool ui_searchbox_apply(uiBut *but, struct ARegion *region); void ui_searchbox_free(struct bContext *C, struct ARegion *region); -void ui_but_search_refresh(uiBut *but); +void ui_but_search_refresh(uiButSearch *but); /* interface_region_menu_popup.c */ int ui_but_menu_step(uiBut *but, int step); @@ -925,11 +944,12 @@ void ui_resources_free(void); /* interface_layout.c */ void ui_layout_add_but(uiLayout *layout, uiBut *but); -void ui_but_add_search(uiBut *but, - PointerRNA *ptr, - PropertyRNA *prop, - PointerRNA *searchptr, - PropertyRNA *searchprop); +bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but); +uiBut *ui_but_add_search(uiBut *but, + PointerRNA *ptr, + PropertyRNA *prop, + PointerRNA *searchptr, + PropertyRNA *searchprop); void ui_layout_list_set_labels_active(uiLayout *layout); /* menu callback */ void ui_item_menutype_func(struct bContext *C, struct uiLayout *layout, void *arg_mt); @@ -950,7 +970,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str); void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra); void ui_but_anim_decorate_cb(struct bContext *C, void *arg_but, void *arg_dummy); -void ui_but_anim_decorate_update_from_flag(uiBut *but); +void ui_but_anim_decorate_update_from_flag(uiButDecorator *but); /* interface_query.c */ bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 98408156f4b..888cacb64eb 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -2278,7 +2278,7 @@ void uiItemFullR(uiLayout *layout, /* property with separate label */ else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) { but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag); - ui_but_add_search(but, ptr, prop, NULL, NULL); + but = ui_but_add_search(but, ptr, prop, NULL, NULL); if (layout->redalert) { UI_but_flag_enable(but, UI_BUT_REDALERT); @@ -2651,7 +2651,10 @@ static void ui_rna_collection_search_arg_free_fn(void *ptr) MEM_freeN(ptr); } -void ui_but_add_search( +/** + * \note May reallocate \a but, so the possibly new address is returned. + */ +uiBut *ui_but_add_search( uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop) { StructRNA *ptype; @@ -2669,11 +2672,13 @@ void ui_but_add_search( /* turn button into search button */ if (searchprop) { uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__); + uiButSearch *search_but; - but->type = UI_BTYPE_SEARCH_MENU; + but = ui_but_change_type(but, UI_BTYPE_SEARCH_MENU); + search_but = (uiButSearch *)but; + search_but->rnasearchpoin = *searchptr; + search_but->rnasearchprop = searchprop; but->hardmax = MAX2(but->hardmax, 256.0f); - but->rnasearchpoin = *searchptr; - but->rnasearchprop = searchprop; but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT; if (RNA_property_is_unlink(prop)) { but->flag |= UI_BUT_VALUE_CLEAR; @@ -2707,6 +2712,8 @@ void ui_but_add_search( * so other code might have already set but->type to search menu... */ but->flag |= UI_BUT_DISABLED; } + + return but; } void uiItemPointerR_prop(uiLayout *layout, @@ -2939,29 +2946,28 @@ void uiItemMContents(uiLayout *layout, const char *menuname) void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) { uiBlock *block = layout->root->block; - uiBut *but = NULL; - uiLayout *col; + UI_block_layout_set_current(block, layout); col = uiLayoutColumn(layout, false); col->space = 0; col->emboss = UI_EMBOSS_NONE; if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_BLANK1, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - ""); + uiBut *but = uiDefIconBut(block, + UI_BTYPE_DECORATOR, + 0, + ICON_BLANK1, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + ""); but->flag |= UI_BUT_DISABLED; return; } @@ -2971,27 +2977,28 @@ void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, /* 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++) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_DOT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Animate property")); - UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL); - but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK; + uiButDecorator *decorator_but = (uiButDecorator *)uiDefIconBut(block, + UI_BTYPE_DECORATOR, + 0, + ICON_DOT, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Animate property")); + + UI_but_func_set(&decorator_but->but, ui_but_anim_decorate_cb, decorator_but, NULL); + decorator_but->but.flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK; /* Reusing RNA search members, setting actual RNA data has many side-effects. */ - but->rnasearchpoin = *ptr; - but->rnasearchprop = prop; + decorator_but->rnapoin = *ptr; + decorator_but->rnaprop = prop; /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */ - but->custom_data = POINTER_FROM_INT((!is_array || is_expand) ? i : index); + decorator_but->rnaindex = (!is_array || is_expand) ? i : index; } } @@ -4819,8 +4826,6 @@ void ui_layout_list_set_labels_active(uiLayout *layout) uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, - PointerRNA *ptr, - PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop) { @@ -4829,8 +4834,6 @@ uiLayout *uiLayoutListBox(uiLayout *layout, but->custom_data = ui_list; - but->rnasearchpoin = *ptr; - but->rnasearchprop = prop; but->rnapoin = *actptr; but->rnaprop = actprop; @@ -5407,6 +5410,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) else { BLI_addtail(&layout->items, bitem); } + but->layout = layout; if (layout->context) { but->context = layout->context; @@ -5418,6 +5422,30 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but) } } +bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but) +{ + ListBase *child_list = layout->child_items_layout ? &layout->child_items_layout->items : + &layout->items; + + LISTBASE_FOREACH (uiItem *, item, child_list) { + if (item->type == ITEM_BUTTON) { + uiButtonItem *bitem = (uiButtonItem *)item; + + if (bitem->but == old_but_ptr) { + bitem->but = new_but; + return true; + } + } + else { + if (ui_layout_replace_but_ptr((uiLayout *)item, old_but_ptr, new_but)) { + return true; + } + } + } + + return false; +} + void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size) { if (fixed_size) { diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 7ac3c90dcd2..5a49f3e70d0 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1148,10 +1148,11 @@ static bool jump_to_target_button(bContext *C, bool poll) /* For string properties with prop_search, look up the search collection item. */ if (type == PROP_STRING) { const uiBut *but = UI_context_active_but_get(C); + const uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but : + NULL; - if (but->type == UI_BTYPE_SEARCH_MENU && but->search && - but->search->update_fn == ui_rna_collection_search_update_fn) { - uiRNACollectionSearch *coll_search = but->search->arg; + if (search_but && search_but->items_update_fn == ui_rna_collection_search_update_fn) { + uiRNACollectionSearch *coll_search = search_but->arg; char str_buf[MAXBONENAME]; char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL); diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 10b219202e5..edb5d51a392 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -113,7 +113,7 @@ bool UI_but_is_utf8(const uiBut *but) #ifdef USE_UI_POPOVER_ONCE bool ui_but_is_popover_once_compat(const uiBut *but) { - return ((but->type == UI_BTYPE_BUT) || ui_but_is_toggle(but)); + return (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR) || ui_but_is_toggle(but)); } #endif diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 80155e3e871..2010d89165e 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -302,8 +302,11 @@ bool ui_searchbox_inside(ARegion *region, int x, int y) bool ui_searchbox_apply(uiBut *but, ARegion *region) { uiSearchboxData *data = region->regiondata; + uiButSearch *search_but = (uiButSearch *)but; - but->func_arg2 = NULL; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + + search_but->item_active = NULL; if (data->active != -1) { const char *name = data->items.names[data->active] + @@ -316,7 +319,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region) BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) + 1 : data->items.maxstrlen); - but->func_arg2 = data->items.pointers[data->active]; + search_but->item_active = data->items.pointers[data->active]; return true; } @@ -340,8 +343,13 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - if (but->search && but->search->tooltip_fn) { - return but->search->tooltip_fn(C, region, but->search->arg, but->func_arg2); + if (but->type != UI_BTYPE_SEARCH_MENU) { + continue; + } + + uiButSearch *search_but = (uiButSearch *)but; + if (search_but->item_tooltip_fn) { + return search_but->item_tooltip_fn(C, region, search_but->arg, search_but->item_active); } } } @@ -352,10 +360,13 @@ bool ui_searchbox_event( bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event) { uiSearchboxData *data = region->regiondata; + uiButSearch *search_but = (uiButSearch *)but; int type = event->type, val = event->val; bool handled = false; bool tooltip_timer_started = false; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + if (type == MOUSEPAN) { ui_pan_to_scroll(event, &type, &val); } @@ -373,7 +384,7 @@ bool ui_searchbox_event( break; case RIGHTMOUSE: if (val) { - if (but->search->context_menu_fn) { + if (search_but->item_context_menu_fn) { if (data->active != -1) { /* Check the cursor is over the active element * (a little confusing if this isn't the case, although it does work). */ @@ -383,7 +394,7 @@ bool ui_searchbox_event( &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) { void *active = data->items.pointers[data->active]; - if (but->search->context_menu_fn(C, but->search->arg, active, event)) { + if (search_but->item_context_menu_fn(C, search_but->arg, active, event)) { handled = true; } } @@ -417,7 +428,7 @@ bool ui_searchbox_event( if (is_inside) { if (data->active != -1) { ScrArea *area = CTX_wm_area(C); - but->func_arg2 = data->items.pointers[data->active]; + search_but->item_active = data->items.pointers[data->active]; WM_tooltip_timer_init(C, CTX_wm_window(C), area, butregion, wm_searchbox_tooltip_init); tooltip_timer_started = true; } @@ -437,18 +448,24 @@ bool ui_searchbox_event( } /** Wrap #uiButSearchUpdateFn callback. */ -static void ui_searchbox_update_fn(bContext *C, uiBut *but, const char *str, uiSearchItems *items) +static void ui_searchbox_update_fn(bContext *C, + uiButSearch *search_but, + const char *str, + uiSearchItems *items) { wmWindow *win = CTX_wm_window(C); WM_tooltip_clear(C, win); - but->search->update_fn(C, but->search->arg, str, items); + search_but->items_update_fn(C, search_but->arg, str, items); } /* region is the search box itself */ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) { + uiButSearch *search_but = (uiButSearch *)but; uiSearchboxData *data = region->regiondata; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + /* reset vars */ data->items.totitem = 0; data->items.more = 0; @@ -460,9 +477,9 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re data->active = -1; /* handle active */ - if (but->search->update_fn && but->func_arg2) { - data->items.active = but->func_arg2; - ui_searchbox_update_fn(C, but, but->editstr, &data->items); + if (search_but->items_update_fn && search_but->item_active) { + data->items.active = search_but->item_active; + ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); data->items.active = NULL; /* found active item, calculate real offset by centering it */ @@ -491,8 +508,8 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re } /* callback */ - if (but->search->update_fn) { - ui_searchbox_update_fn(C, but, but->editstr, &data->items); + if (search_but->items_update_fn) { + ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); } /* handle case where editstr is equal to one of items */ @@ -523,13 +540,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str) { + uiButSearch *search_but = (uiButSearch *)but; uiSearchboxData *data = region->regiondata; int match = AUTOCOMPLETE_NO_MATCH; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + if (str[0]) { data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but)); - ui_searchbox_update_fn(C, but, but->editstr, &data->items); + ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); match = UI_autocomplete_end(data->items.autocpl, str); data->items.autocpl = NULL; @@ -673,10 +693,11 @@ static void ui_searchbox_region_free_cb(ARegion *region) region->regiondata = NULL; } -ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but) +ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiButSearch *search_but) { wmWindow *win = CTX_wm_window(C); const uiStyle *style = UI_style_get(); + uiBut *but = &search_but->but; static ARegionType type; ARegion *region; uiSearchboxData *data; @@ -725,7 +746,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) { data->use_sep = true; } - data->sep_string = but->search->sep_string; + data->sep_string = search_but->item_sep_string; /* compute position */ if (but->block->flag & UI_BLOCK_SEARCH_MENU) { @@ -945,12 +966,12 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe } } -ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiBut *but) +ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiButSearch *search_but) { ARegion *region; - UI_but_drawflag_enable(but, UI_BUT_HAS_SHORTCUT); - region = ui_searchbox_create_generic(C, butregion, but); + UI_but_drawflag_enable(&search_but->but, UI_BUT_HAS_SHORTCUT); + region = ui_searchbox_create_generic(C, butregion, search_but); region->type->draw = ui_searchbox_region_draw_cb__operator; @@ -967,12 +988,12 @@ static void ui_searchbox_region_draw_cb__menu(const bContext *UNUSED(C), ARegion /* Currently unused. */ } -ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiBut *but) +ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiButSearch *search_but) { ARegion *region; - UI_but_drawflag_enable(but, UI_BUT_HAS_SHORTCUT); - region = ui_searchbox_create_generic(C, butregion, but); + UI_but_drawflag_enable(&search_but->but, UI_BUT_HAS_SHORTCUT); + region = ui_searchbox_create_generic(C, butregion, search_but); if (false) { region->type->draw = ui_searchbox_region_draw_cb__menu; @@ -983,8 +1004,9 @@ ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiBut *but) /* sets red alert if button holds a string it can't find */ /* XXX weak: search_func adds all partial matches... */ -void ui_but_search_refresh(uiBut *but) +void ui_but_search_refresh(uiButSearch *search_but) { + uiBut *but = &search_but->but; uiSearchItems *items; int x1; @@ -1004,7 +1026,7 @@ void ui_but_search_refresh(uiBut *but) items->names[x1] = MEM_callocN(but->hardmax + 1, "search names"); } - ui_searchbox_update_fn(but->block->evil_C, but, but->drawstr, items); + ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items); /* only redalert when we are sure of it, this can miss cases when >10 matches */ if (items->totitem == 0) { diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index fcafa88a806..8c1d070b5e4 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -6210,7 +6210,7 @@ void uiTemplateList(uiLayout *layout, switch (layout_type) { case UILST_LAYOUT_DEFAULT: /* layout */ - box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); + box = uiLayoutListBox(layout, ui_list, active_dataptr, activeprop); glob = uiLayoutColumn(box, true); row = uiLayoutRow(glob, false); col = uiLayoutColumn(row, true); @@ -6348,7 +6348,7 @@ void uiTemplateList(uiLayout *layout, } break; case UILST_LAYOUT_GRID: - box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop); + box = uiLayoutListBox(layout, ui_list, active_dataptr, activeprop); glob = uiLayoutColumn(box, true); row = uiLayoutRow(glob, false); col = uiLayoutColumn(row, true); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index bbf29365710..01f89a8bdb1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1400,7 +1400,7 @@ static void widget_draw_icon( alpha *= but->a2; } } - else if (ELEM(but->type, UI_BTYPE_BUT)) { + else if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR)) { if (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) { alpha *= 0.5f; } @@ -4552,6 +4552,7 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu break; case UI_BTYPE_BUT: + case UI_BTYPE_DECORATOR: #ifdef USE_UI_TOOLBAR_HACK if ((but->icon != ICON_NONE) && UI_but_is_tool(but)) { wt = widget_type(UI_WTYPE_TOOLBAR_ITEM); |