Property Search: Build button groups for Search

This is needed for property search (upcoming patch D8856) where a
buttons labels are often separate buttons, but we need to highlight
the label to show that a property is a search result. This is
especially important in "property split" layouts where the label is
almost always another button in a separate column.

The button groups here are basically a flattened view of the buttons
in the layout tree. Every function that adds a new set of buttons
creates a new button group, and the new buttons are automatically
added to the most recent group. Then, each group is searched
separately in the property search phase. It's important that every
function adding a new button set calls layout_root_new_button_group.

Note that this won't be disabled when property search isn't active.
It may be useful for other things in the future, and trying to pass
that information to layout functions didn't feel worth it to me.

Differential Revision: https://developer.blender.org/D8783
This commit is contained in:
Hans Goudey 2020-09-15 09:38:19 -05:00
parent f886e13836
commit 67e630609b
Notes: blender-bot 2023-02-14 07:25:46 +01:00
Referenced by issue #77824, Properties Search Implementation
3 changed files with 90 additions and 3 deletions

View File

@ -3943,6 +3943,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);
}
}
}

View File

@ -994,6 +994,7 @@ 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,

View File

@ -80,12 +80,25 @@
/* 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;
int type;
int opcontext;
ListBase button_groups; /* #uiButtonGroup. */
int emw, emh;
int padding;
@ -414,6 +427,58 @@ 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
* \{ */
@ -2019,6 +2084,7 @@ void uiItemFullR(uiLayout *layout,
#endif /* UI_PROP_DECORATE */
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
/* retrieve info */
const PropertyType type = RNA_property_type(prop);
@ -2769,6 +2835,8 @@ void uiItemPointerR_prop(uiLayout *layout,
char namestr[UI_MAX_NAME_STR];
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
layout_root_new_button_group(layout->root);
type = RNA_property_type(prop);
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
RNA_warning("Property %s.%s must be a pointer, string or enum",
@ -2874,6 +2942,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
int w, h;
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
if (!name) {
name = "";
@ -3141,6 +3210,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
int w;
UI_block_layout_set_current(block, layout);
layout_root_new_button_group(layout->root);
if (!name) {
name = "";
@ -5306,6 +5376,16 @@ static void ui_layout_free(uiLayout *layout)
MEM_freeN(layout);
}
static void layout_root_free(uiLayoutRoot *root)
{
ui_layout_free(root->layout);
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) {
@ -5340,6 +5420,9 @@ 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;
@ -5424,6 +5507,8 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
if (layout->emboss != UI_EMBOSS_UNDEFINED) {
but->emboss = layout->emboss;
}
button_group_add_but(layout->root, but);
}
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
@ -5489,15 +5574,15 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
block->curlayout = NULL;
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
ui_layout_add_padding_button(root);
/* 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);
}
BLI_freelistN(&block->layouts);
BLI_listbase_clear(&block->layouts);
/* XXX silly trick, interface_templates.c doesn't get linked
* because it's not used by other files in this module? */