Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeverin <eiseljulian@gmail.com>2018-07-02 15:19:49 +0300
committerSeverin <eiseljulian@gmail.com>2018-07-02 15:19:49 +0300
commit9887b38692e3bcf7ba613ca947fd76e299c58cbd (patch)
treeee03c74f7ea6180ef78f47a4f735ef43033d3acb
parent9b2a4c67656ebc40a1026dd0e5f59b40446a5a1a (diff)
Cleanup: Refactor button-group code
* Split generic button-group code from specific application * Move button-group API to interface.c. * Avoid struct abuse by using wrapper structs * Naming, comments, etc.
-rw-r--r--source/blender/blenkernel/BKE_screen.h2
-rw-r--r--source/blender/editors/include/UI_interface.h3
-rw-r--r--source/blender/editors/interface/interface.c151
-rw-r--r--source/blender/editors/interface/interface_templates.c163
-rw-r--r--source/blender/makesdna/DNA_screen_types.h5
5 files changed, 189 insertions, 135 deletions
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index b1777cb77d7..3f3eca7d34b 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -259,7 +259,7 @@ typedef struct uiListType {
} uiListType;
typedef bool (*uiButtonGroupIdentifyFunc)(struct uiButtonGroup *, void *);
-typedef void (*uiButtonGroupItemsFunc)(struct uiButtonGroup *, void *, ListBase *);
+typedef void (*uiButtonGroupItemsFunc)(void *, ListBase *);
typedef void (*uiButtonGroupItemDrawFunc)(struct uiBlock *, void *, struct uiButtonGroupItemInfo *);
typedef struct uiButtonGroupType {
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7fef72b7484..946c1822da3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -810,6 +810,9 @@ 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);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 3eb8f3d6bb5..5673bc2535c 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4756,6 +4756,157 @@ 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(&region->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);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b890e8b38b0..b70468dd508 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -103,14 +103,10 @@ void UI_template_fix_linking(void)
{
}
-
typedef struct TemplateID {
PointerRNA ptr;
PropertyRNA *prop;
- wmOperatorType *unlink_ot; // XXX tmp!
- PointerRNA active_ptr;
-
ListBase *idlb;
short idcode;
short filter;
@@ -118,123 +114,13 @@ typedef struct TemplateID {
bool preview;
} TemplateID;
-static 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(uiButtonGroup), __func__);
- group->type = WM_uibuttongrouptype_find(name, false);
- BLI_addtail(&region->button_groups, group);
-
- return group;
-}
-
-static int ui_button_group_items_cmp(const void *a, const void *b)
-{
- const uiButtonGroupItemInfo *item_a = a, *item_b = b;
- return item_a->position_index > item_b->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++) {
- uiButtonGroupItemInfo *sort_item = MEM_dupallocN(item);
-
- sort_item->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_new_items(
- const uiButtonGroup *group, const ListBase *current_items, const int prev_tot_items,
- ListBase *r_new_items)
-{
- const int difference = group->tot_items - prev_tot_items;
-
- if (difference == 0) {
- return;
- }
-
- if (difference > 0) {
- for (uiButtonGroupItemInfo *item = current_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_new_items, item_new);
- }
- }
- }
-}
-
+typedef struct SortableIDTabsData {
+ TemplateID *template_id;
-/* XXX split this up into generic and sortable_id_tabs functions */
-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);
- const int old_tot_items = group->tot_items;
- ListBase items = {NULL, NULL};
-
- template_ui->unlink_ot = unlink_ot;
- template_ui->active_ptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
-
- group->type->items(group, template_ui, &items);
-
- if (!group->reordered_indices || (group->tot_items != old_tot_items)) {
- ListBase new_items = {NULL, NULL};
-
- group->reordered_indices = MEM_recallocN(
- group->reordered_indices, sizeof(*group->reordered_indices) * group->tot_items);
- ui_button_group_find_new_items(group, &items, old_tot_items, &new_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(&new_items) == tot_new_items);
- int i = 0;
- for (uiButtonGroupItemInfo *new_item = new_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(&new_items);
-
- /* TODO support removing items */
- }
-
- ListBase sorted_items = {NULL, NULL};
- ui_button_group_sort(group, &items, &sorted_items);
-
- UI_block_button_group_begin(block, group);
- for (uiButtonGroupItemInfo *item = sorted_items.first; item; item = item->next) {
- group->type->item_draw(block, template_ui, item);
- }
- UI_block_button_group_end(block);
+ wmOperatorType *unlink_ot;
+ PointerRNA active_ptr;
+} SortableIDTabsData;
- BLI_freelistN(&sorted_items);
- BLI_freelistN(&group->items);
- group->items = items;
-}
-
-static void ui_buttong_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;
-}
/* 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))
@@ -247,29 +133,25 @@ static bool ui_sortable_id_tabs_button_group_identify(uiButtonGroup *group, void
return false;
}
-static void ui_sortable_id_tabs_items(
- uiButtonGroup *group, void *custom_data,
- ListBase *r_items)
+static void ui_sortable_id_tabs_items(void *custom_data, ListBase *r_items)
{
- TemplateID *template_ui = custom_data;
-
- group->tot_items = BLI_listbase_count(template_ui->idlb);
+ SortableIDTabsData *data = custom_data;
- for (ID *id = template_ui->idlb->first; id; id = id->next) {
- ui_buttong_group_item_add(id, r_items);
+ 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_draw(
+static void ui_sortable_id_tab_item_draw(
uiBlock *block, void *custom_data, uiButtonGroupItemInfo *item)
{
+ SortableIDTabsData *data = custom_data;
ID *id = item->data;
- TemplateID *template_ui = custom_data;
uiStyle *style = UI_style_get_dpi();
- const bool is_active = template_ui->active_ptr.data == id;
+ 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;
@@ -277,13 +159,13 @@ static void ui_sortable_id_tab_draw(
uiButTab *tab = (uiButTab *)uiDefButR_prop(
block, UI_BTYPE_TAB, 0, "", 0, 0, but_width, UI_UNIT_Y,
- &template_ui->ptr, template_ui->prop, 0, 0.0f,
+ &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(template_ui), id);
+ 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 = template_ui->unlink_ot;
+ tab->unlink_ot = data->unlink_ot;
if (is_active) {
UI_but_flag_enable(&tab->but, UI_BUT_VALUE_CLEAR);
}
@@ -296,11 +178,24 @@ uiButtonGroupType *UI_BGT_sortable_id_tabs(void)
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_draw;
+ 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.
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 0034b88eec8..56d1dd57b89 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -225,6 +225,11 @@ typedef struct uiButtonGroupItemInfo {
void *data;
} uiButtonGroupItemInfo;
+/* TODO Better name for this? Alternatives:
+ * * uiSortedButtonGenerator
+ * * uiButtonGroupGenerator
+ * * uiStorableItems
+ */
typedef struct uiButtonGroup {
struct uiButtonGroup *next, *prev;