Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface.c
| Show First 20 Lines • Show All 801 Lines • ▼ Show 20 Lines | #endif | ||||
| SWAP(uiButToolTipFunc, oldbut->tip_func, but->tip_func); | SWAP(uiButToolTipFunc, oldbut->tip_func, but->tip_func); | ||||
| SWAP(void *, oldbut->tip_argN, but->tip_argN); | SWAP(void *, oldbut->tip_argN, but->tip_argN); | ||||
| oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy); | oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy); | ||||
| oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy); | oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy); | ||||
| SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); | SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); | ||||
| SWAP(uiButSearchArgFreeFunc, oldbut->search_arg_free_func, but->search_arg_free_func); | if (oldbut->type == UI_BTYPE_SEARCH_MENU) { | ||||
| SWAP(void *, oldbut->search_arg, but->search_arg); | uiButSearch *search_oldbut = (uiButSearch *)oldbut, *search_but = (uiButSearch *)but; | ||||
| SWAP(uiButSearchArgFreeFunc, | |||||
| search_oldbut->item_collect_arg_free_func, | |||||
| search_but->item_collect_arg_free_func); | |||||
| SWAP(void *, search_oldbut->item_collect_arg, search_but->item_collect_arg); | |||||
| } | |||||
| /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position | /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position | ||||
| * when scrolling without moving mouse (see [#28432]) */ | * when scrolling without moving mouse (see [#28432]) */ | ||||
| if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { | if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) { | ||||
| oldbut->hardmax = but->hardmax; | oldbut->hardmax = but->hardmax; | ||||
| } | } | ||||
| /* Selectively copy a1, a2 since their use differs across all button types | /* Selectively copy a1, a2 since their use differs across all button types | ||||
| ▲ Show 20 Lines • Show All 942 Lines • ▼ Show 20 Lines | if (but->optype) { | ||||
| if (but->context) { | if (but->context) { | ||||
| CTX_store_set((bContext *)C, NULL); | CTX_store_set((bContext *)C, NULL); | ||||
| } | } | ||||
| } | } | ||||
| ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); | ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); | ||||
| ui_but_override_flag(but); | ui_but_override_flag(but); | ||||
| if (UI_but_is_decorator(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); | ui_but_predefined_extra_operator_icons_add(but); | ||||
| } | } | ||||
| /* handle pending stuff */ | /* handle pending stuff */ | ||||
| if (block->layouts.first) { | if (block->layouts.first) { | ||||
| UI_block_layout_resolve(block, NULL, NULL); | UI_block_layout_resolve(block, NULL, NULL); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 231 Lines • ▼ Show 20 Lines | if (but->bit) { | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| switch (but->type) { | switch (but->type) { | ||||
| case UI_BTYPE_BUT: | case UI_BTYPE_BUT: | ||||
| case UI_BTYPE_HOTKEY_EVENT: | case UI_BTYPE_HOTKEY_EVENT: | ||||
| case UI_BTYPE_KEY_EVENT: | case UI_BTYPE_KEY_EVENT: | ||||
| case UI_BTYPE_COLOR: | case UI_BTYPE_COLOR: | ||||
| case UI_BTYPE_DECORATOR: | |||||
| is_push = -1; | is_push = -1; | ||||
| break; | break; | ||||
| case UI_BTYPE_BUT_TOGGLE: | case UI_BTYPE_BUT_TOGGLE: | ||||
| case UI_BTYPE_TOGGLE: | case UI_BTYPE_TOGGLE: | ||||
| case UI_BTYPE_ICON_TOGGLE: | case UI_BTYPE_ICON_TOGGLE: | ||||
| case UI_BTYPE_CHECKBOX: | case UI_BTYPE_CHECKBOX: | ||||
| UI_GET_BUT_VALUE_INIT(but, *value); | UI_GET_BUT_VALUE_INIT(but, *value); | ||||
| if (*value != (double)but->hardmin) { | if (*value != (double)but->hardmin) { | ||||
| ▲ Show 20 Lines • Show All 910 Lines • ▼ Show 20 Lines | if (RNA_property_editable(&but->rnapoin, but->rnaprop)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| else if (type == PROP_POINTER) { | else if (type == PROP_POINTER) { | ||||
| if (str[0] == '\0') { | if (str[0] == '\0') { | ||||
| RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL, NULL); | RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL, NULL); | ||||
| return true; | return true; | ||||
| } | } | ||||
| else { | else { | ||||
| uiButSearch *search_but = (but->type == UI_BTYPE_SEARCH_MENU) ? (uiButSearch *)but : | |||||
| NULL; | |||||
| /* RNA pointer */ | /* RNA pointer */ | ||||
| PointerRNA rptr; | 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 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 | * this if/else, since ui_searchbox_apply() is supposed to always set that pointer when | ||||
| * we are storing pointers... But keeping str search first for now, | * we are storing pointers... But keeping str search first for now, | ||||
| * to try to break as little as possible existing code. All this is band-aids anyway. | * 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 | * 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. */ | * 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); | RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); | ||||
| } | } | ||||
| else if (but->func_arg2 != NULL) { | else if (but->func_arg2 != NULL) { | ||||
| RNA_pointer_create(NULL, | RNA_pointer_create(NULL, | ||||
| RNA_property_pointer_type(&but->rnapoin, but->rnaprop), | RNA_property_pointer_type(&but->rnapoin, but->rnaprop), | ||||
| but->func_arg2, | but->func_arg2, | ||||
| &rptr); | &rptr); | ||||
| RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); | RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr, NULL); | ||||
| ▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | static void ui_set_but_soft_range(uiBut *but) | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| } | } | ||||
| } | } | ||||
| /* ******************* Free ********************/ | /* ******************* 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->item_collect_arg_free_func) { | |||||
| search_but->item_collect_arg_free_func(search_but->item_collect_arg); | |||||
| search_but->item_collect_arg = NULL; | |||||
| } | |||||
| break; | |||||
| } | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* can be called with C==NULL */ | /* can be called with C==NULL */ | ||||
| static void ui_but_free(const bContext *C, uiBut *but) | static void ui_but_free(const bContext *C, uiBut *but) | ||||
| { | { | ||||
| if (but->opptr) { | if (but->opptr) { | ||||
| WM_operator_properties_free(but->opptr); | WM_operator_properties_free(but->opptr); | ||||
| MEM_freeN(but->opptr); | MEM_freeN(but->opptr); | ||||
| } | } | ||||
| if (but->func_argN) { | if (but->func_argN) { | ||||
| MEM_freeN(but->func_argN); | MEM_freeN(but->func_argN); | ||||
| } | } | ||||
| if (but->tip_argN) { | if (but->tip_argN) { | ||||
| MEM_freeN(but->tip_argN); | MEM_freeN(but->tip_argN); | ||||
| } | } | ||||
| if (but->hold_argN) { | if (but->hold_argN) { | ||||
| MEM_freeN(but->hold_argN); | MEM_freeN(but->hold_argN); | ||||
| } | } | ||||
| if (but->search_arg_free_func) { | ui_but_free_type_specific(but); | ||||
| but->search_arg_free_func(but->search_arg); | |||||
| but->search_arg = NULL; | |||||
| } | |||||
| if (but->active) { | if (but->active) { | ||||
| /* XXX solve later, buttons should be free-able without context ideally, | /* XXX solve later, buttons should be free-able without context ideally, | ||||
| * however they may have open tooltips or popup windows, which need to | * however they may have open tooltips or popup windows, which need to | ||||
| * be closed using a context pointer */ | * be closed using a context pointer */ | ||||
| if (C) { | if (C) { | ||||
| ui_but_active_free(C, but); | ui_but_active_free(C, but); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 462 Lines • ▼ Show 20 Lines | |||||
| void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]) | void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]) | ||||
| { | { | ||||
| struct ColorManagedDisplay *display = ui_block_cm_display_get(block); | struct ColorManagedDisplay *display = ui_block_cm_display_get(block); | ||||
| IMB_colormanagement_scene_linear_to_display_v3(pixel, display); | 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) { | switch (type) { | ||||
| case UI_BTYPE_DECORATOR: | |||||
| alloc_size = sizeof(uiButDecorator); | |||||
| alloc_str = "uiButDecorator"; | |||||
| break; | |||||
| case UI_BTYPE_TAB: | 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: | 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); | |||||
| const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr, but); | |||||
Severin: Should do a `NULL`-check for `but->layout` in case the button isn't inside any layout. | |||||
| BLI_assert(found_layout); | |||||
| UNUSED_VARS_NDEBUG(found_layout); | |||||
| } | |||||
| } | |||||
| return but; | |||||
| } | } | ||||
| /** | /** | ||||
| * \brief ui_def_but is the function that draws many button types | * \brief ui_def_but is the function that draws many button types | ||||
| * | * | ||||
| * \param x, y: The lower left hand corner of the button (X axis) | * \param x, y: The lower left hand corner of the button (X axis) | ||||
| * \param width, height: The size of the button. | * \param width, height: The size of the button. | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | #endif | ||||
| if (block->lock == true) { | if (block->lock == true) { | ||||
| but->flag |= UI_BUT_DISABLED; | but->flag |= UI_BUT_DISABLED; | ||||
| } | } | ||||
| /* keep track of UI_interface.h */ | /* keep track of UI_interface.h */ | ||||
| if (ELEM(but->type, | if (ELEM(but->type, | ||||
| UI_BTYPE_BLOCK, | UI_BTYPE_BLOCK, | ||||
| UI_BTYPE_BUT, | UI_BTYPE_BUT, | ||||
| UI_BTYPE_DECORATOR, | |||||
| UI_BTYPE_LABEL, | UI_BTYPE_LABEL, | ||||
| UI_BTYPE_PULLDOWN, | UI_BTYPE_PULLDOWN, | ||||
| UI_BTYPE_ROUNDBOX, | UI_BTYPE_ROUNDBOX, | ||||
| UI_BTYPE_LISTBOX, | UI_BTYPE_LISTBOX, | ||||
| UI_BTYPE_BUT_MENU, | UI_BTYPE_BUT_MENU, | ||||
| UI_BTYPE_SCROLL, | UI_BTYPE_SCROLL, | ||||
| UI_BTYPE_GRIP, | UI_BTYPE_GRIP, | ||||
| UI_BTYPE_SEPR, | UI_BTYPE_SEPR, | ||||
| ▲ Show 20 Lines • Show All 2,476 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * \param search_func, bfunc: both get it as \a arg. | * \param search_func, bfunc: both get it as \a arg. | ||||
| * \param arg: user value, | * \param arg: user value, | ||||
| * \param active: when set, button opens with this item visible and selected. | * \param active: when set, button opens with this item visible and selected. | ||||
| * \param separator_string: when not NULL, this string is used as a separator, | * \param separator_string: when not NULL, this string is used as a separator, | ||||
| * showing the icon and highlighted text after the last instance of this string. | * showing the icon and highlighted text after the last instance of this string. | ||||
| */ | */ | ||||
| void UI_but_func_search_set(uiBut *but, | void UI_but_func_search_set(uiBut *but, | ||||
| uiButSearchCreateFunc search_create_func, | uiButSearchCreateFunc popup_create_func, | ||||
| uiButSearchFunc search_func, | uiButSearchFunc search_func, | ||||
| void *arg, | void *arg, | ||||
| uiButSearchArgFreeFunc search_arg_free_func, | uiButSearchArgFreeFunc search_arg_free_func, | ||||
| uiButHandleFunc bfunc, | uiButHandleFunc bfunc, | ||||
| const char *search_sep_string, | const char *search_sep_string, | ||||
| void *active) | void *active) | ||||
| { | { | ||||
| uiButSearch *but_search = (uiButSearch *)but; | |||||
| BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); | |||||
| /* needed since callers don't have access to internal functions | /* needed since callers don't have access to internal functions | ||||
| * (as an alternative we could expose it) */ | * (as an alternative we could expose it) */ | ||||
| if (search_create_func == NULL) { | if (popup_create_func == NULL) { | ||||
| search_create_func = ui_searchbox_create_generic; | popup_create_func = ui_searchbox_create_generic; | ||||
| } | } | ||||
| if (but->search_arg_free_func != NULL) { | if (but_search->item_collect_arg_free_func != NULL) { | ||||
| but->search_arg_free_func(but->search_arg); | but_search->item_collect_arg_free_func(but_search->item_collect_arg); | ||||
| but->search_arg = NULL; | but_search->item_collect_arg = NULL; | ||||
| } | } | ||||
| but->search_create_func = search_create_func; | but_search->popup_create_func = popup_create_func; | ||||
| but->search_func = search_func; | but_search->item_collect_func = search_func; | ||||
| but->search_arg = arg; | but_search->item_collect_arg = arg; | ||||
| but->search_arg_free_func = search_arg_free_func; | but_search->item_collect_arg_free_func = search_arg_free_func; | ||||
| but->search_sep_string = search_sep_string; | but_search->item_sep_string = search_sep_string; | ||||
| if (bfunc) { | if (bfunc) { | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| if (but->func) { | if (but_search->but.func) { | ||||
| /* watch this, can be cause of much confusion, see: T47691 */ | /* watch this, can be cause of much confusion, see: T47691 */ | ||||
| printf("%s: warning, overwriting button callback with search function callback!\n", | printf("%s: warning, overwriting button callback with search function callback!\n", | ||||
| __func__); | __func__); | ||||
| } | } | ||||
| #endif | #endif | ||||
| UI_but_func_set(but, bfunc, arg, active); | UI_but_func_set(but, bfunc, arg, active); | ||||
| } | } | ||||
| /* search buttons show red-alert if item doesn't exist, not for menus */ | /* search buttons show red-alert if item doesn't exist, not for menus */ | ||||
| if (0 == (but->block->flag & UI_BLOCK_LOOP)) { | if (0 == (but->block->flag & UI_BLOCK_LOOP)) { | ||||
| /* skip empty buttons, not all buttons need input, we only show invalid */ | /* skip empty buttons, not all buttons need input, we only show invalid */ | ||||
| if (but->drawstr[0]) { | if (but->drawstr[0]) { | ||||
| ui_but_search_refresh(but); | ui_but_search_refresh(but_search); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Callbacks for operator search button. */ | /* Callbacks for operator search button. */ | ||||
| static void operator_enum_search_cb(const struct bContext *C, | static void operator_enum_search_cb(const struct bContext *C, | ||||
| void *but, | void *but, | ||||
| const char *str, | const char *str, | ||||
| ▲ Show 20 Lines • Show All 393 Lines • Show Last 20 Lines | |||||
Should do a NULL-check for but->layout in case the button isn't inside any layout.