UI: Use vector instead of linked list for block button groups
This simplifies some memory management, ammortizes some of the many small allocations when building UI layouts, and simplifies the code that deals with the groups. `uiBlock` is no longer a trivial type. In my testing this saved a few ms when drawing a large node tree.
This commit is contained in:
@@ -3478,10 +3478,9 @@ void UI_block_free(const bContext *C, uiBlock *block)
|
||||
BLI_freelistN(&block->color_pickers.list);
|
||||
BLI_freelistN(&block->dynamic_listeners);
|
||||
|
||||
ui_block_free_button_groups(block);
|
||||
ui_block_free_views(block);
|
||||
|
||||
MEM_freeN(block);
|
||||
MEM_delete(block);
|
||||
}
|
||||
|
||||
void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
|
||||
@@ -3597,13 +3596,11 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, eU
|
||||
wmWindow *window = CTX_wm_window(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
uiBlock *block = MEM_cnew<uiBlock>(__func__);
|
||||
uiBlock *block = MEM_new<uiBlock>(__func__);
|
||||
block->active = true;
|
||||
block->emboss = emboss;
|
||||
block->evil_C = (void *)C; /* XXX */
|
||||
|
||||
BLI_listbase_clear(&block->button_groups);
|
||||
|
||||
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
|
||||
@@ -4058,7 +4055,7 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_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;
|
||||
const uiBut *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;
|
||||
const bool has_poin_ptr_to_self = but->poin == (char *)but;
|
||||
@@ -4082,7 +4079,7 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
|
||||
}
|
||||
#ifdef WITH_PYTHON
|
||||
if (UI_editsource_enable_check()) {
|
||||
UI_editsource_but_replace(static_cast<const uiBut *>(old_but_ptr), but);
|
||||
UI_editsource_but_replace(old_but_ptr, but);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -17,54 +17,35 @@
|
||||
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag)
|
||||
{
|
||||
/* Don't create a new group if there is a "lock" on new groups. */
|
||||
if (!BLI_listbase_is_empty(&block->button_groups)) {
|
||||
uiButtonGroup *last_button_group = static_cast<uiButtonGroup *>(block->button_groups.last);
|
||||
if (last_button_group->flag & UI_BUTTON_GROUP_LOCK) {
|
||||
if (!block->button_groups.is_empty()) {
|
||||
uiButtonGroup &last_group = block->button_groups.last();
|
||||
if (last_group.flag & UI_BUTTON_GROUP_LOCK) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uiButtonGroup *new_group = MEM_cnew<uiButtonGroup>(__func__);
|
||||
new_group->flag = flag;
|
||||
BLI_addtail(&block->button_groups, new_group);
|
||||
block->button_groups.append({});
|
||||
block->button_groups.last().flag = flag;
|
||||
}
|
||||
|
||||
void ui_button_group_add_but(uiBlock *block, uiBut *but)
|
||||
{
|
||||
if (BLI_listbase_is_empty(&block->button_groups)) {
|
||||
if (block->button_groups.is_empty()) {
|
||||
ui_block_new_button_group(block, uiButtonGroupFlag(0));
|
||||
}
|
||||
|
||||
uiButtonGroup *current_button_group = static_cast<uiButtonGroup *>(block->button_groups.last);
|
||||
|
||||
/* 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(¤t_button_group->buttons, button_link);
|
||||
uiButtonGroup ¤t_group = block->button_groups.last();
|
||||
current_group.buttons.append(but);
|
||||
}
|
||||
|
||||
static void button_group_free(uiButtonGroup *button_group)
|
||||
void ui_button_group_replace_but_ptr(uiBlock *block, const uiBut *old_but_ptr, uiBut *new_but)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
for (uiButtonGroup &group : block->button_groups) {
|
||||
std::replace_if(
|
||||
group.buttons.begin(),
|
||||
group.buttons.end(),
|
||||
[&](const uiBut *ptr) { return ptr == old_but_ptr; },
|
||||
new_but);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "RNA_types.h"
|
||||
@@ -456,18 +457,6 @@ 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.
|
||||
*/
|
||||
struct uiButtonGroup {
|
||||
void *next, *prev;
|
||||
ListBase buttons; /* #LinkData with #uiBut data field. */
|
||||
short flag;
|
||||
};
|
||||
|
||||
/* #uiButtonGroup.flag. */
|
||||
enum uiButtonGroupFlag {
|
||||
/** While this flag is set, don't create new button groups for layout item calls. */
|
||||
@@ -477,6 +466,17 @@ enum uiButtonGroupFlag {
|
||||
};
|
||||
ENUM_OPERATORS(uiButtonGroupFlag, UI_BUTTON_GROUP_PANEL_HEADER);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
struct uiButtonGroup {
|
||||
blender::Vector<uiBut *> buttons;
|
||||
uiButtonGroupFlag flag;
|
||||
};
|
||||
|
||||
struct uiBlockDynamicListener {
|
||||
struct uiBlockDynamicListener *next, *prev;
|
||||
|
||||
@@ -493,7 +493,7 @@ struct uiBlock {
|
||||
/** Used for `UI_butstore_*` runtime function. */
|
||||
ListBase butstore;
|
||||
|
||||
ListBase button_groups; /* #uiButtonGroup. */
|
||||
blender::Vector<uiButtonGroup> button_groups;
|
||||
|
||||
ListBase layouts;
|
||||
uiLayout *curlayout;
|
||||
@@ -1273,8 +1273,7 @@ void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt);
|
||||
*/
|
||||
void ui_block_new_button_group(uiBlock *block, uiButtonGroupFlag flag);
|
||||
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);
|
||||
void ui_button_group_replace_but_ptr(uiBlock *block, const uiBut *old_but_ptr, uiBut *new_but);
|
||||
|
||||
/* interface_drag.cc */
|
||||
|
||||
|
||||
@@ -5227,10 +5227,9 @@ static bool button_matches_search_filter(uiBut *but, const char *search_filter)
|
||||
/**
|
||||
* Test for a search result within a specific button group.
|
||||
*/
|
||||
static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter)
|
||||
static bool button_group_has_search_match(const uiButtonGroup &group, const char *search_filter)
|
||||
{
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
uiBut *but = static_cast<uiBut *>(link->data);
|
||||
for (uiBut *but : group.buttons) {
|
||||
if (button_matches_search_filter(but, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
@@ -5251,13 +5250,12 @@ 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 (uiButtonGroup *, button_group, &block->button_groups) {
|
||||
if (button_group_has_search_match(button_group, search_filter)) {
|
||||
for (const uiButtonGroup &group : block->button_groups) {
|
||||
if (button_group_has_search_match(group, search_filter)) {
|
||||
has_result = true;
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
uiBut *but = static_cast<uiBut *>(link->data);
|
||||
for (uiBut *but : group.buttons) {
|
||||
but->flag |= UI_SEARCH_FILTER_NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -754,18 +754,16 @@ void UI_panel_header_buttons_end(Panel *panel)
|
||||
uiBlock *block = panel->runtime.block;
|
||||
|
||||
/* A button group should always be created in #UI_panel_header_buttons_begin. */
|
||||
BLI_assert(!BLI_listbase_is_empty(&block->button_groups));
|
||||
BLI_assert(!block->button_groups.is_empty());
|
||||
|
||||
uiButtonGroup *button_group = static_cast<uiButtonGroup *>(block->button_groups.last);
|
||||
|
||||
button_group->flag &= ~UI_BUTTON_GROUP_LOCK;
|
||||
uiButtonGroup &button_group = block->button_groups.last();
|
||||
button_group.flag &= ~UI_BUTTON_GROUP_LOCK;
|
||||
|
||||
/* Repurpose the first header button group if it is empty, in case the first button added to
|
||||
* the panel doesn't add a new group (if the button is created directly rather than through an
|
||||
* interface layout call). */
|
||||
if (BLI_listbase_is_single(&block->button_groups) &&
|
||||
BLI_listbase_is_empty(&button_group->buttons)) {
|
||||
button_group->flag &= ~UI_BUTTON_GROUP_PANEL_HEADER;
|
||||
if (block->button_groups.size() > 0) {
|
||||
button_group.flag &= ~UI_BUTTON_GROUP_PANEL_HEADER;
|
||||
}
|
||||
else {
|
||||
/* Always add a new button group. Although this may result in many empty groups, without it,
|
||||
@@ -940,12 +938,11 @@ static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *
|
||||
/* If sub-panels have no search results but the parent panel does, then the parent panel open
|
||||
* and the sub-panels will close. In that case there must be a way to hide the buttons in the
|
||||
* panel but keep the header buttons. */
|
||||
LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) {
|
||||
if (button_group->flag & UI_BUTTON_GROUP_PANEL_HEADER) {
|
||||
for (const uiButtonGroup &button_group : block->button_groups) {
|
||||
if (button_group.flag & UI_BUTTON_GROUP_PANEL_HEADER) {
|
||||
continue;
|
||||
}
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
uiBut *but = static_cast<uiBut *>(link->data);
|
||||
for (uiBut *but : button_group.buttons) {
|
||||
but->flag |= UI_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1040,7 +1040,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C,
|
||||
MenuSearch_Item *item = (MenuSearch_Item *)active;
|
||||
bool has_menu = false;
|
||||
|
||||
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
|
||||
new (&data->context_menu_data.but) uiBut();
|
||||
new (&data->context_menu_data.block) uiBlock();
|
||||
uiBut *but = &data->context_menu_data.but;
|
||||
uiBlock *block = &data->context_menu_data.block;
|
||||
|
||||
@@ -1083,7 +1084,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
|
||||
MenuSearch_Data *data = (MenuSearch_Data *)arg;
|
||||
MenuSearch_Item *item = (MenuSearch_Item *)active;
|
||||
|
||||
memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
|
||||
new (&data->context_menu_data.but) uiBut();
|
||||
new (&data->context_menu_data.block) uiBlock();
|
||||
uiBut *but = &data->context_menu_data.but;
|
||||
uiBlock *block = &data->context_menu_data.block;
|
||||
unit_m4(block->winmat);
|
||||
|
||||
Reference in New Issue
Block a user