UI: Move button groups from layout to block level

For a future patch (D9006) we need these groups for longer than just the
the layout process, in order to differentiate buttons in panel headers.
It may also be helpful in the future to have a way to access related
buttons added in the same uiLayout.prop call. With this commit, the
groups are stored in and destructed with the uiBlock.
This commit is contained in:
Hans Goudey 2020-10-02 17:00:41 -05:00
parent 28a2c84948
commit 3eab2248c3
5 changed files with 125 additions and 98 deletions

View File

@ -38,6 +38,7 @@ set(SRC
interface.c
interface_align.c
interface_anim.c
interface_button_group.c
interface_context_menu.c
interface_draw.c
interface_eyedropper.c

View File

@ -3392,6 +3392,8 @@ void UI_block_free(const bContext *C, uiBlock *block)
BLI_freelistN(&block->saferct);
BLI_freelistN(&block->color_pickers.list);
ui_block_free_button_groups(block);
MEM_freeN(block);
}
@ -3473,6 +3475,9 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, ch
block->emboss = emboss;
block->evil_C = (void *)C; /* XXX */
BLI_listbase_clear(&block->button_groups);
ui_block_new_button_group(block);
if (scene) {
/* store display device name, don't lookup for transformations yet
* block could be used for non-color displays where looking up for transformation
@ -3944,7 +3949,7 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr, but);
BLI_assert(found_layout);
UNUSED_VARS_NDEBUG(found_layout);
ui_button_group_replace_but_ptr(but->layout, old_but_ptr, but);
ui_button_group_replace_but_ptr(uiLayoutGetBlock(but->layout), old_but_ptr, but);
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.
*/
/** \file
* \ingroup edinterface
*/
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
#include "interface_intern.h"
/* -------------------------------------------------------------------- */
/** \name Button Groups
* \{ */
/**
* Every function that adds a set of buttons must create another group,
* then #ui_def_but adds buttons to the current group (the last).
*/
void ui_block_new_button_group(uiBlock *block)
{
uiButtonGroup *new_group = MEM_mallocN(sizeof(uiButtonGroup), __func__);
BLI_listbase_clear(&new_group->buttons);
BLI_addtail(&block->button_groups, new_group);
}
void ui_button_group_add_but(uiBlock *block, uiBut *but)
{
BLI_assert(block != NULL);
uiButtonGroup *current_button_group = block->button_groups.last;
BLI_assert(current_button_group != NULL);
/* We can't use the button directly because adding it to
* this list would mess with its prev and next pointers. */
LinkData *button_link = BLI_genericNodeN(but);
BLI_addtail(&current_button_group->buttons, button_link);
}
static void button_group_free(uiButtonGroup *button_group)
{
BLI_freelistN(&button_group->buttons);
MEM_freeN(button_group);
}
void ui_block_free_button_groups(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (uiButtonGroup *, button_group, &block->button_groups) {
button_group_free(button_group);
}
}
/* This function should be removed whenever #ui_layout_replace_but_ptr is removed. */
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but)
{
LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) {
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
if (link->data == old_but_ptr) {
link->data = new_but;
return;
}
}
}
/* The button should be in a group. */
BLI_assert(false);
}
/** \} */

View File

@ -417,6 +417,17 @@ enum eBlockContentHints {
UI_BLOCK_CONTAINS_SUBMENU_BUT = (1 << 0),
};
/**
* A group of button references, used by property search to keep track of sets of buttons that
* should be searched together. For example, in property split layouts number buttons and their
* labels (and even their decorators) are separate buttons, but they must be searched and
* highlighted together.
*/
typedef struct uiButtonGroup {
void *next, *prev;
ListBase buttons; /* #LinkData with #uiBut data field. */
} uiButtonGroup;
struct uiBlock {
uiBlock *next, *prev;
@ -426,6 +437,8 @@ struct uiBlock {
ListBase butstore; /* UI_butstore_* runtime function */
ListBase button_groups; /* #uiButtonGroup. */
ListBase layouts;
struct uiLayout *curlayout;
@ -999,7 +1012,6 @@ void ui_resources_free(void);
/* interface_layout.c */
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);
void ui_button_group_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but);
uiBut *ui_but_add_search(uiBut *but,
PointerRNA *ptr,
PropertyRNA *prop,
@ -1010,6 +1022,12 @@ void ui_layout_list_set_labels_active(uiLayout *layout);
void ui_item_menutype_func(struct bContext *C, struct uiLayout *layout, void *arg_mt);
void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *arg_pt);
/* interface_button_group.c */
void ui_block_new_button_group(uiBlock *block);
void ui_button_group_add_but(uiBlock *block, uiBut *but);
void ui_button_group_replace_but_ptr(uiBlock *block, const void *old_but_ptr, uiBut *new_but);
void ui_block_free_button_groups(uiBlock *block);
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;

View File

@ -79,17 +79,6 @@
/* uiLayoutRoot */
/**
* A group of button references, used by property search to keep track of sets of buttons that
* should be searched together. For example, in property split layouts number buttons and their
* labels (and even their decorators) are separate buttons, but they must be searched and
* highlighted together.
*/
typedef struct uiButtonGroup {
void *next, *prev;
ListBase buttons; /* #LinkData with #uiBut data field. */
} uiButtonGroup;
typedef struct uiLayoutRoot {
struct uiLayoutRoot *next, *prev;
@ -103,8 +92,6 @@ typedef struct uiLayoutRoot {
*/
bool search_only;
ListBase button_groups; /* #uiButtonGroup. */
int emw, emh;
int padding;
@ -430,58 +417,6 @@ static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Button Groups
* \{ */
/**
* Every function that adds a set of buttons must create another group,
* then #ui_def_but adds buttons to the current group (the last).
*/
static void layout_root_new_button_group(uiLayoutRoot *root)
{
uiButtonGroup *new_group = MEM_mallocN(sizeof(uiButtonGroup), __func__);
BLI_listbase_clear(&new_group->buttons);
BLI_addtail(&root->button_groups, new_group);
}
static void button_group_add_but(uiLayoutRoot *root, uiBut *but)
{
BLI_assert(root != NULL);
uiButtonGroup *current_button_group = root->button_groups.last;
BLI_assert(current_button_group != NULL);
/* We can't use the button directly because adding it to
* this list would mess with its prev and next pointers. */
LinkData *button_link = BLI_genericNodeN(but);
BLI_addtail(&current_button_group->buttons, button_link);
}
static void button_group_free(uiButtonGroup *button_group)
{
BLI_freelistN(&button_group->buttons);
MEM_freeN(button_group);
}
/* This function should be removed whenever #ui_layout_replace_but_ptr is removed. */
void ui_button_group_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
{
LISTBASE_FOREACH (uiButtonGroup *, button_group, &layout->root->button_groups) {
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
if (link->data == old_but_ptr) {
link->data = new_but;
return;
}
}
}
/* The button should be in a group. */
BLI_assert(false);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Special RNA Items
* \{ */
@ -2051,7 +1986,7 @@ void uiItemFullR(uiLayout *layout,
#endif /* UI_PROP_DECORATE */
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
ui_block_new_button_group(block);
/* retrieve info */
const PropertyType type = RNA_property_type(prop);
@ -2789,7 +2724,7 @@ void uiItemPointerR_prop(uiLayout *layout,
{
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
layout_root_new_button_group(layout->root);
ui_block_new_button_group(uiLayoutGetBlock(layout));
const PropertyType type = RNA_property_type(prop);
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
@ -2895,7 +2830,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
uiLayout *heading_layout = ui_layout_heading_find(layout);
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
ui_block_new_button_group(block);
if (!name) {
name = "";
@ -3161,7 +3096,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
uiBlock *block = layout->root->block;
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
ui_block_new_button_group(block);
if (!name) {
name = "";
@ -5131,9 +5066,6 @@ static void layout_free_and_hide_buttons(uiLayout *layout)
MEM_freeN(layout);
}
/* Prototype of function below. */
static void layout_root_free(uiLayoutRoot *root);
/**
* Remove layouts used only for search and hide their buttons.
* (See comment for #uiLayoutRootSetSearchOnly and in #uiLayoutRoot).
@ -5144,7 +5076,7 @@ static void block_search_remove_search_only_roots(uiBlock *block)
if (root->search_only) {
layout_free_and_hide_buttons(root->layout);
BLI_remlink(&block->layouts, root);
layout_root_free(root);
MEM_freeN(root);
}
}
}
@ -5236,16 +5168,14 @@ static bool button_group_has_search_match(uiButtonGroup *button_group, const cha
static bool block_search_filter_tag_buttons(uiBlock *block, const char *search_filter)
{
bool has_result = false;
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
LISTBASE_FOREACH (uiButtonGroup *, button_group, &root->button_groups) {
if (button_group_has_search_match(button_group, search_filter)) {
has_result = true;
}
else {
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
uiBut *but = link->data;
but->flag |= UI_SEARCH_FILTER_NO_MATCH;
}
LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) {
if (button_group_has_search_match(button_group, search_filter)) {
has_result = true;
}
else {
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
uiBut *but = link->data;
but->flag |= UI_SEARCH_FILTER_NO_MATCH;
}
}
}
@ -5527,14 +5457,6 @@ static void ui_layout_free(uiLayout *layout)
MEM_freeN(layout);
}
static void layout_root_free(uiLayoutRoot *root)
{
LISTBASE_FOREACH_MUTABLE (uiButtonGroup *, button_group, &root->button_groups) {
button_group_free(button_group);
}
MEM_freeN(root);
}
static void ui_layout_add_padding_button(uiLayoutRoot *root)
{
if (root->padding) {
@ -5569,9 +5491,6 @@ uiLayout *UI_block_layout(uiBlock *block,
root->padding = padding;
root->opcontext = WM_OP_INVOKE_REGION_WIN;
BLI_listbase_clear(&root->button_groups);
layout_root_new_button_group(root);
layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT;
@ -5657,7 +5576,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
but->emboss = layout->emboss;
}
button_group_add_but(layout->root, but);
ui_button_group_add_but(uiLayoutGetBlock(layout), but);
}
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
@ -5732,7 +5651,7 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
/* NULL in advance so we don't interfere when adding button */
ui_layout_end(block, root->layout, r_x, r_y);
ui_layout_free(root->layout);
layout_root_free(root);
MEM_freeN(root);
}
BLI_listbase_clear(&block->layouts);