diff options
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 9 | ||||
-rw-r--r-- | source/blender/editors/interface/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/interface/interface.c | 189 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_handlers.c | 127 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_init_exit.c | 57 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_intern.h | 9 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_templates.c | 132 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_ops.c | 1 | ||||
-rw-r--r-- | source/blender/editors/screen/workspace_edit.c | 1 |
10 files changed, 484 insertions, 44 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index e5218e287d4..9204f9b62f5 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -75,6 +75,7 @@ struct wmDrag; struct wmEvent; struct wmManipulator; struct wmMsgBus; +struct uiButtonGroup; struct wmKeyMap; typedef struct uiBut uiBut; @@ -551,6 +552,7 @@ void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free); void UI_but_drag_set_name(uiBut *but, const char *name); void UI_but_drag_set_value(uiBut *but); +void UI_but_drag_set_reorder(uiBut *but); void UI_but_drag_set_image( uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale, const bool use_free); @@ -664,6 +666,7 @@ enum { BUT_GET_RNA_LABEL, BUT_GET_RNAENUM_LABEL, BUT_GET_RNA_LABEL_CONTEXT, /* Context specified in CTX_XXX_ macros are just unreachable! */ + BUT_GET_VALUE, BUT_GET_TIP, BUT_GET_RNA_TIP, BUT_GET_RNAENUM_TIP, @@ -807,6 +810,12 @@ void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but); void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN); +struct uiButtonGroup *UI_button_group_ensure(struct ARegion *region, const char *name, void *custom_data); +void UI_button_group_add_sorted_items(struct uiButtonGroup *group, uiBlock *block, void *custom_data); +void UI_button_group_item_add(void *data, ListBase *items); +void UI_block_button_group_begin(uiBlock *block, struct uiButtonGroup *group); +void UI_block_button_group_end(uiBlock *block); + /* Autocomplete * * Tab complete helper functions, for use in uiButCompleteFunc callbacks. diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index ee18f956cac..869c91f69eb 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -54,6 +54,7 @@ set(SRC interface_eyedropper_driver.c interface_handlers.c interface_icons.c + interface_init_exit.c interface_layout.c interface_ops.c interface_panel.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 3b2a2e9d3ed..4199a7c0fdd 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -3296,8 +3296,12 @@ static uiBut *ui_def_but( BLI_addtail(&block->buttons, but); - if (block->curlayout) + if (block->curlayout) { ui_layout_add_but(block->curlayout, but); + } + if (block->current_group) { + but->group = block->current_group; + } #ifdef WITH_PYTHON /* if the 'UI_OT_editsource' is running, extract the source info from the button */ @@ -4155,6 +4159,12 @@ void UI_but_drag_set_value(uiBut *but) but->dragtype = WM_DRAG_VALUE; } +void UI_but_drag_set_reorder(uiBut *but) +{ + but->dragtype = WM_DRAG_BUT_REORDER; + but->dragpoin = but; /* Assign the button itself, later wmDrag can access it then. */ +} + void UI_but_drag_set_image(uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free) { but->dragtype = WM_DRAG_PATH; @@ -4574,21 +4584,23 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) int type = si->type; char *tmp = NULL; - if (type == BUT_GET_LABEL) { - if (but->str) { + if (ELEM(type, BUT_GET_LABEL, BUT_GET_VALUE)) { + char *but_str = (type == BUT_GET_LABEL) ? but->str : but->drawstr; + + if (but_str && but_str[0]) { const char *str_sep; size_t str_len; if ((but->flag & UI_BUT_HAS_SEP_CHAR) && - (str_sep = strrchr(but->str, UI_SEP_CHAR))) + (str_sep = strrchr(but_str, UI_SEP_CHAR))) { - str_len = (str_sep - but->str); + str_len = (str_sep - but_str); } else { - str_len = strlen(but->str); + str_len = strlen(but_str); } - tmp = BLI_strdupn(but->str, str_len); + tmp = BLI_strdupn(but_str, str_len); } else { type = BUT_GET_RNA_LABEL; /* Fail-safe solution... */ @@ -4749,11 +4761,173 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } } + +/* -------------------------------------------------------------------- */ +/** + * \name Button Group + * \brief Generate buttons with custom, storable order. + * + * Button groups have the following key characteristics: + * * Sortable: Contained buttons can be sorted. + * * Generates: They in fact do not contain buttons, but manage info on how to + * create and sort buttons on runtime. + * * Storable: The mapping for custom sorting is written into files, alongside + * an identifier for this specific group. That way the group can be + * identified and the custom sorting re-applied after reading files. + * + * Maybe button group is a bit of a misleading term, since it doesn't actually + * store the buttons itself. + * Via a callback a button-group gathers information from which another + * callback can create the buttons then. In-between those two callbacks the + * items are sorted in a customizable way. + * + * \{ */ + +uiButtonGroup *UI_button_group_ensure(ARegion *region, const char *name, void *custom_data) +{ + uiButtonGroup *group; + + for (group = region->button_groups.first; group; group = group->next) { + if (STREQ(group->type->idname, name) && group->type->identify(group, custom_data)) { + return group; + } + } + + group = MEM_callocN(sizeof(*group), __func__); + group->type = WM_uibuttongrouptype_find(name, false); + BLI_addtail(®ion->button_groups, group); + + return group; +} + +typedef struct SortedButtonGroupItemInfo { + struct SortedButtonGroupItemInfo *next, *prev; + + uiButtonGroupItemInfo *item; + int new_position_index; +} SortedButtonGroupItemInfo; + +static int ui_button_group_items_cmp(const void *a, const void *b) +{ + const SortedButtonGroupItemInfo *item_a = a, *item_b = b; + return item_a->new_position_index > item_b->new_position_index ? 1 : 0; +} + +static void ui_button_group_sort( + const uiButtonGroup *group, const ListBase *items, + ListBase *r_sorted_items) +{ + int i = 0; + for (uiButtonGroupItemInfo *item = items->first; item; item = item->next, i++) { + SortedButtonGroupItemInfo *sort_item = MEM_callocN(sizeof(*sort_item), __func__); + + sort_item->item = item; + sort_item->new_position_index = group->reordered_indices[i]; + BLI_addtail(r_sorted_items, sort_item); + } + BLI_listbase_sort(r_sorted_items, ui_button_group_items_cmp); +} + +static void ui_button_group_find_added_items( + const uiButtonGroup *group, const ListBase *items, + const int prev_tot_items, + ListBase *r_added_items) +{ + const int difference = group->tot_items - prev_tot_items; + + if (difference == 0) { + return; + } + + if (difference > 0) { + for (uiButtonGroupItemInfo *item = items->first; item; item = item->next) { + const bool has_item = BLI_findptr(&group->items, item->data, + offsetof(uiButtonGroupItemInfo, data)) != NULL; + if (!has_item) { + uiButtonGroupItemInfo *item_new = MEM_dupallocN(item); + BLI_addtail(r_added_items, item_new); + } + } + } +} + +static void ui_button_group_handle_added_or_removed_items( + uiButtonGroup *group, const ListBase *new_items, + int old_tot_items) +{ + ListBase added_items = {NULL, NULL}; + + group->reordered_indices = MEM_recallocN( + group->reordered_indices, sizeof(*group->reordered_indices) * group->tot_items); + ui_button_group_find_added_items(group, new_items, old_tot_items, &added_items); + + /* Add new items at the end of the list. */ + const int tot_new_items = group->tot_items - old_tot_items; + + BLI_assert(BLI_listbase_count(&added_items) == tot_new_items); + int i = 0; + for (uiButtonGroupItemInfo *new_item = added_items.first; new_item; new_item = new_item->next, i++) { + for (int j = group->tot_items - tot_new_items + i; j > new_item->position_index; j--) { + group->reordered_indices[j] = group->reordered_indices[j - 1]; + } + group->reordered_indices[new_item->position_index] = group->tot_items - tot_new_items + i; + } + BLI_freelistN(&added_items); + + /* TODO support removing items */ +} + +void UI_button_group_add_sorted_items(uiButtonGroup *group, uiBlock *block, void *custom_data) +{ + const int old_tot_items = group->tot_items; + ListBase new_items = {NULL, NULL}; + ListBase sorted_items = {NULL, NULL}; + + group->type->items(custom_data, &new_items); + group->tot_items = BLI_listbase_count(&new_items); + + if (!group->reordered_indices || (group->tot_items != old_tot_items)) { + ui_button_group_handle_added_or_removed_items(group, &new_items, old_tot_items); + } + + ui_button_group_sort(group, &new_items, &sorted_items); + + UI_block_button_group_begin(block, group); + for (SortedButtonGroupItemInfo *sorted_item = sorted_items.first; sorted_item; sorted_item = sorted_item->next) { + group->type->item_draw(block, custom_data, sorted_item->item); + } + UI_block_button_group_end(block); + + BLI_freelistN(&sorted_items); + BLI_freelistN(&group->items); + group->items = new_items; +} + +void UI_button_group_item_add(void *data, ListBase *items) +{ + uiButtonGroupItemInfo *item = MEM_callocN(sizeof(*item), __func__); + + BLI_addtail(items, item); + item->data = data; + item->position_index = item->prev ? ((uiButtonGroupItemInfo *)item->prev)->position_index + 1 : 0; +} + +void UI_block_button_group_begin(uiBlock *block, uiButtonGroup *group) +{ + BLI_assert(block->current_group == NULL); + block->current_group = group; +} +void UI_block_button_group_end(uiBlock *block) +{ + block->current_group = NULL; +} + /* Program Init/Exit */ void UI_init(void) { ui_resources_init(); + ui_init_button_group_types(); } /* after reading userdef file */ @@ -4773,4 +4947,5 @@ void UI_exit(void) { ui_resources_free(); ui_but_clipboard_free(); + ui_exit_button_group_types(); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index ac7ed3d5106..fc0550c37b9 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1713,6 +1713,12 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent return BLI_rcti_isect_pt(&rect, x, y); } +static void ui_but_drop_handler(wmDrag *drag, const wmEvent *event); +struct uiButDrag { + uiBut *dragged_but; + uiButStore *but_store; + int drag_start_xy[2]; +}; static bool ui_but_drag_init( bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) @@ -1782,6 +1788,22 @@ static bool ui_but_drag_init( return false; } } + /* Allow reordering buttons via drag & drop */ + else if (but->group) { + ListBase *dropbox_list = WM_dropboxmap_find("User Interface", 0, 0); + struct uiButDrag *but_drag = MEM_mallocN(sizeof(*but_drag), "uiButDrag"); + + but_drag->dragged_but = but; + but_drag->but_store = UI_butstore_create(but->block); + copy_v2_v2_int(but_drag->drag_start_xy, &event->x); + + UI_butstore_register(but_drag->but_store, &but_drag->dragged_but); + WM_event_start_drag(C, but->icon, but->dragtype, but_drag, ui_but_value_get(but), + WM_DRAG_FREE_DATA | WM_DRAG_NOP); + WM_dropbox_add_custom_drop_handler(dropbox_list, ui_but_drop_handler); + + return true; + } else { wmDrag *drag = WM_event_start_drag( C, but->icon, but->dragtype, but->dragpoin, @@ -2007,6 +2029,98 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton /* ******************* drop event ******************** */ +enum ReinsertPosition { + BUT_REINSERT_BEFORE, + BUT_REINSERT_AFTER, +}; +static void ui_but_find_to_reinsert_next_to( + const wmEvent *event, const uiBut *dragged_but, const int drag_start_xy[2], + uiBut **r_but, enum ReinsertPosition *r_reinsert_position) +{ + uiBut *but_candidate = NULL; + + if (event->x < drag_start_xy[0]) { + for (uiBut *but_iter = dragged_but->prev; but_iter; but_iter = but_iter->prev) { + if ((but_iter->group == dragged_but->group) && (event->x < BLI_rctf_cent_x(&but_iter->rect))) { + but_candidate = but_iter; + } + } + + *r_reinsert_position = BUT_REINSERT_BEFORE; + } + else { + for (uiBut *but_iter = dragged_but->next; but_iter; but_iter = but_iter->next) { + if ((but_iter->group == dragged_but->group) && (event->x > BLI_rctf_cent_x(&but_iter->rect))) { + but_candidate = but_iter; + } + } + + *r_reinsert_position = BUT_REINSERT_AFTER; + } + + *r_but = but_candidate; +} + +static uiButtonGroupItemInfo *ui_block_button_group_find_item_from_data( + const uiButtonGroup *group, + const void *data) +{ + return BLI_findptr(&group->items, data, offsetof(uiButtonGroupItemInfo, data)); +} + +static void ui_but_drop_handler(wmDrag *drag, const wmEvent *event) +{ + if (drag->type == WM_DRAG_BUT_REORDER) { + struct uiButDrag *but_drag = drag->poin; + uiBut *dragged_but = but_drag->dragged_but; + uiBut *drop_neighbor; + enum ReinsertPosition reinsert_pos; + + ui_but_find_to_reinsert_next_to(event, dragged_but, but_drag->drag_start_xy, + &drop_neighbor, &reinsert_pos); + if (drop_neighbor) { + uiButtonGroup *group = dragged_but->group; + uiButtonGroupItemInfo *dragged_item = ui_block_button_group_find_item_from_data( + group, dragged_but->custom_data); + uiButtonGroupItemInfo *drop_neighbor_item = ui_block_button_group_find_item_from_data( + group, drop_neighbor->custom_data); + /* New index of the dragged item is the old reorder index of the neighbor */ + const int item_new_index = group->reordered_indices[drop_neighbor_item->position_index]; + + BLI_assert(!ELEM(NULL, dragged_item, drop_neighbor_item)); + + if (reinsert_pos == BUT_REINSERT_AFTER) { + /* modify the reorder index of all items in a certain range */ + const int min = group->reordered_indices[dragged_item->position_index] + 1; + const int max = group->reordered_indices[drop_neighbor_item->position_index]; + + for (int i = 0; i < group->tot_items; i++) { + if (IN_RANGE_INCL(group->reordered_indices[i], min, max)) { + group->reordered_indices[i]--; + } + } + } + else if (reinsert_pos == BUT_REINSERT_BEFORE) { + const int min = group->reordered_indices[drop_neighbor_item->position_index]; + const int max = group->reordered_indices[dragged_item->position_index] - 1; + + for (int i = 0; i < group->tot_items; i++) { + if (IN_RANGE_INCL(group->reordered_indices[i], min, max)) { + group->reordered_indices[i]++; + } + } + } + else { + BLI_assert(0); + } + group->reordered_indices[dragged_item->position_index] = item_new_index; + } + + UI_butstore_free(but_drag->dragged_but->block, but_drag->but_store); + ED_region_tag_redraw(drag->init_region); + } +} + /* only call if event type is EVT_DROP */ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleButtonData *data) { @@ -3756,8 +3870,14 @@ static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, c static int ui_do_but_TAB(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { - if ((event->type == LEFTMOUSE) && - ((event->val == KM_DBL_CLICK) || event->ctrl)) + if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); + data->dragstartx = event->x; + data->dragstarty = event->y; + return WM_UI_HANDLER_BREAK; + } + else if ((event->type == LEFTMOUSE) && + ((event->val == KM_DBL_CLICK) || event->ctrl)) { button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); return WM_UI_HANDLER_BREAK; @@ -3778,6 +3898,9 @@ static int ui_do_but_TAB(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return WM_UI_HANDLER_BREAK; } } + else if (data->state == BUTTON_STATE_WAIT_DRAG) { + return ui_do_but_EXIT(C, but, data, event); + } else if (data->state == BUTTON_STATE_TEXT_EDITING) { ui_do_but_textedit(C, block, but, data, event); return WM_UI_HANDLER_BREAK; diff --git a/source/blender/editors/interface/interface_init_exit.c b/source/blender/editors/interface/interface_init_exit.c new file mode 100644 index 00000000000..fb24553e7b0 --- /dev/null +++ b/source/blender/editors/interface/interface_init_exit.c @@ -0,0 +1,57 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_init_exit.h + * \ingroup edinterface + */ + +#include "BLI_rect.h" + +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_screen.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "interface_intern.h" + + + +void ui_init_button_group_types(void) +{ + WM_uibuttongrouptype_init(); + WM_uibuttongrouptype_add(UI_BGT_sortable_id_tabs()); +} + +void ui_exit_button_group_types(void) +{ + WM_uibuttongrouptype_free(); +} diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 04e9e2b18b4..23a7718ead0 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -317,6 +317,7 @@ struct uiBut { /* pointer back */ uiBlock *block; + uiButtonGroup *group; }; typedef struct uiButTab { @@ -355,6 +356,7 @@ struct uiBlock { ListBase buttons; Panel *panel; uiBlock *oldblock; + uiButtonGroup *current_group; ListBase butstore; /* UI_butstore_* runtime function */ @@ -792,6 +794,13 @@ void ui_layout_list_set_labels_active(uiLayout *layout); /* menu callback */ void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt); +/* interface_templates.c */ +struct uiButtonGroupType *UI_BGT_sortable_id_tabs(void); + +/* interface_init_exit.c */ +void ui_init_button_group_types(void); +void ui_exit_button_group_types(void); + /* interface_align.c */ bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT; void ui_block_align_calc(uiBlock *block, const ARegion *region); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 3457d2e2eeb..8c8fe181387 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1399,4 +1399,6 @@ void ED_keymap_ui(wmKeyConfig *keyconf) eyedropper_modal_keymap(keyconf); eyedropper_colorband_modal_keymap(keyconf); + + WM_dropboxmap_find("User Interface", 0, 0); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index fbfa64cbdbd..3e28b5ee20c 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -103,6 +103,100 @@ void UI_template_fix_linking(void) { } +typedef struct TemplateID { + PointerRNA ptr; + PropertyRNA *prop; + + ListBase *idlb; + short idcode; + short filter; + int prv_rows, prv_cols; + bool preview; +} TemplateID; + +typedef struct SortableIDTabsData { + TemplateID *template_id; + + wmOperatorType *unlink_ot; + PointerRNA active_ptr; +} SortableIDTabsData; + + +/* TODO After file read, we need to be able to identify button groups. That's what should later happen here. */ +static bool ui_sortable_id_tabs_button_group_identify(uiButtonGroup *group, void *UNUSED(custom_data)) +{ + if (STREQ(group->type->idname, "UI_BGT_sortable_id_tabs")) { + // XXX + return true; + } + + return false; +} + +static void ui_sortable_id_tabs_items(void *custom_data, ListBase *r_items) +{ + SortableIDTabsData *data = custom_data; + + for (ID *id = data->template_id->idlb->first; id; id = id->next) { + UI_button_group_item_add(id, r_items); + } +} + +static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item); + +static void ui_sortable_id_tab_item_draw( + uiBlock *block, void *custom_data, uiButtonGroupItemInfo *item) +{ + SortableIDTabsData *data = custom_data; + ID *id = item->data; + + uiStyle *style = UI_style_get_dpi(); + const bool is_active = data->active_ptr.data == id; + const unsigned int but_width = UI_fontstyle_string_width(&style->widgetlabel, id->name + 2) + UI_UNIT_X + + (is_active ? ICON_DEFAULT_WIDTH_SCALE : 0); +// const int but_align = (region->alignment == RGN_ALIGN_TOP) ? UI_BUT_ALIGN_DOWN : UI_BUT_ALIGN_TOP; + + + uiButTab *tab = (uiButTab *)uiDefButR_prop( + block, UI_BTYPE_TAB, 0, "", 0, 0, but_width, UI_UNIT_Y, + &data->template_id->ptr, data->template_id->prop, 0, 0.0f, + sizeof(id->name) - 2, 0.0f, 0.0f, ""); + UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(data->template_id), id); + UI_but_drawflag_enable(&tab->but, UI_BUT_ALIGN_DOWN); /* TODO fixed alignment - should be based on region alignment */ + UI_but_drag_set_reorder(&tab->but); + tab->but.custom_data = (void *)id; + tab->unlink_ot = data->unlink_ot; + if (is_active) { + UI_but_flag_enable(&tab->but, UI_BUT_VALUE_CLEAR); + } +} + +uiButtonGroupType *UI_BGT_sortable_id_tabs(void) +{ + uiButtonGroupType *group_type = MEM_callocN(sizeof(uiButtonGroupType), __func__); + + group_type->idname = "UI_BGT_sortable_id_tabs"; // TODO not needed? + group_type->identify = ui_sortable_id_tabs_button_group_identify; + group_type->items = ui_sortable_id_tabs_items; + group_type->item_draw = ui_sortable_id_tab_item_draw; + + return group_type; +} + +static void ui_template_sortable_id_tabs( + ARegion *region, uiBlock *block, TemplateID *template_ui, wmOperatorType *unlink_ot) +{ + uiButtonGroup *group = UI_button_group_ensure(region, "UI_BGT_sortable_id_tabs", template_ui); + SortableIDTabsData data; + + data.template_id = template_ui; + data.unlink_ot = unlink_ot; + data.active_ptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + + UI_button_group_add_sorted_items(group, block, &data); +} + + /** * Add a block button for the search menu for templateID and templateSearch. */ @@ -228,17 +322,6 @@ void uiTemplateHeader(uiLayout *layout, bContext *C) /********************** Search Callbacks *************************/ -typedef struct TemplateID { - PointerRNA ptr; - PropertyRNA *prop; - - ListBase *idlb; - short idcode; - short filter; - int prv_rows, prv_cols; - bool preview; -} TemplateID; - /* Search browse menu, assign */ static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item) { @@ -826,36 +909,15 @@ static void template_ID_tabs( bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, const char *newop, const char *UNUSED(openop), const char *unlinkop) { - const ARegion *region = CTX_wm_region(C); + ARegion *region = CTX_wm_region(C); const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop); const int but_align = (region->alignment == RGN_ALIGN_TOP) ? UI_BUT_ALIGN_DOWN : UI_BUT_ALIGN_TOP; + wmOperatorType *unlink_ot = WM_operatortype_find(unlinkop, false); const int but_height = UI_UNIT_Y * 1.1; uiBlock *block = uiLayoutGetBlock(layout); - uiStyle *style = UI_style_get_dpi(); - - for (ID *id = template->idlb->first; id; id = id->next) { - wmOperatorType *unlink_ot = WM_operatortype_find(unlinkop, false); - const bool is_active = active_ptr.data == id; - const unsigned int but_width = ( - UI_fontstyle_string_width(&style->widgetlabel, id->name + 2) + UI_UNIT_X + - (is_active ? ICON_DEFAULT_WIDTH_SCALE : 0)); - uiButTab *tab; - - tab = (uiButTab *)uiDefButR_prop( - block, UI_BTYPE_TAB, 0, "", 0, 0, but_width, UI_UNIT_Y * 1.1, - &template->ptr, template->prop, 0, 0.0f, - sizeof(id->name) - 2, 0.0f, 0.0f, ""); - UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id); - tab->but.custom_data = (void *)id; - tab->unlink_ot = unlink_ot; - - if (is_active) { - UI_but_flag_enable(&tab->but, UI_BUT_VALUE_CLEAR); - } - UI_but_drawflag_enable(&tab->but, but_align); - } + ui_template_sortable_id_tabs(region, block, template, unlink_ot); if (flag & UI_ID_ADD_NEW) { const bool editable = RNA_property_editable(&template->ptr, template->prop); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index e21f328ddf9..d8588d7014d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1135,6 +1135,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) layout_new = ED_workspace_layout_add(bmain, workspace, newwin, BKE_workspace_layout_name_get(layout_old)); newsc = BKE_workspace_layout_screen_get(layout_new); WM_window_set_active_layout(newwin, workspace, layout_new); + ED_screen_global_areas_create(newwin); /* copy area to new screen */ ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 9d329355500..df05cc07352 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -370,6 +370,7 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "directory", directory); if (workspace_append(C, directory, idname) != OPERATOR_CANCELLED) { + /* XXX broken, name may have been changed */ WorkSpace *appended_workspace = BLI_findstring(&bmain->workspaces, idname, offsetof(ID, name) + 2); BLI_assert(appended_workspace != NULL); |