Fix T87567: Crash adding item in empty attribute search

The function applying the search used the dummy search info for when
the item doesn't exist even when there was no UI data associated with
the node at all.

A fix is to only add the search menu when there is attribute info
stored for the node. This is something I wanted to do anyway, since
it makes it look more purposeful when there are no attribute info
for a node, less like a bug.

Differential Revision: https://developer.blender.org/D11016
This commit is contained in:
Hans Goudey 2021-04-19 12:31:18 -05:00
parent b8b7b47a00
commit d7caae56c4
Notes: blender-bot 2023-02-14 11:28:39 +01:00
Referenced by issue #87567, Crash when typing in attribute to a node that doesn't have a linkage in Geometry Node.
4 changed files with 32 additions and 24 deletions

View File

@ -3458,7 +3458,7 @@ static void std_node_socket_draw(
const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
if (node_tree->type == NTREE_GEOMETRY) {
node_geometry_add_attribute_search_button(node_tree, node, ptr, row);
node_geometry_add_attribute_search_button(C, node_tree, node, ptr, row);
}
else {
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);

View File

@ -46,8 +46,8 @@ using blender::Set;
using blender::StringRef;
struct AttributeSearchData {
const bNodeTree &node_tree;
const bNode &node;
AvailableAttributeInfo &dummy_info_for_search;
const NodeUIStorage &ui_storage;
bNodeSocket &socket;
};
@ -82,37 +82,31 @@ static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttri
items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
}
static void attribute_search_update_fn(
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static void attribute_search_update_fn(const bContext *UNUSED(C),
void *arg,
const char *str,
uiSearchItems *items,
const bool is_first)
{
AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
NodeTreeUIStorage *tree_ui_storage = data->node_tree.ui_storage;
if (tree_ui_storage == nullptr) {
return;
}
const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context(
C, data->node_tree, data->node);
if (ui_storage == nullptr) {
return;
}
const Set<AvailableAttributeInfo> &attribute_hints = ui_storage->attribute_hints;
const Set<AvailableAttributeInfo> &attribute_hints = data->ui_storage.attribute_hints;
/* Any string may be valid, so add the current search string along with the hints. */
if (str[0] != '\0') {
/* Note that the attribute domain and data type are dummies, since
* #AvailableAttributeInfo equality is only based on the string. */
if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) {
tree_ui_storage->dummy_info_for_search.name = std::string(str);
UI_search_item_add(items, str, &tree_ui_storage->dummy_info_for_search, ICON_ADD, 0, 0);
data->dummy_info_for_search.name = std::string(str);
UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0);
}
}
if (str[0] == '\0' && !is_first) {
/* Allow clearing the text field when the string is empty, but not on the first pass,
* or opening an attribute field for the first time would show this search item. */
tree_ui_storage->dummy_info_for_search.name = std::string(str);
UI_search_item_add(items, str, &tree_ui_storage->dummy_info_for_search, ICON_X, 0, 0);
data->dummy_info_for_search.name = std::string(str);
UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_X, 0, 0);
}
/* Don't filter when the menu is first opened, but still run the search
@ -148,11 +142,22 @@ static void attribute_search_exec_fn(bContext *UNUSED(C), void *data_v, void *it
BLI_strncpy(value->value, item->name.c_str(), MAX_NAME);
}
void node_geometry_add_attribute_search_button(const bNodeTree *node_tree,
void node_geometry_add_attribute_search_button(const bContext *C,
const bNodeTree *node_tree,
const bNode *node,
PointerRNA *socket_ptr,
uiLayout *layout)
{
const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context(
C, *node_tree, *node);
if (ui_storage == nullptr) {
uiItemR(layout, socket_ptr, "default_value", 0, "", 0);
return;
}
const NodeTreeUIStorage *tree_ui_storage = node_tree->ui_storage;
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but = uiDefIconTextButR(block,
UI_BTYPE_SEARCH_MENU,
@ -172,8 +177,10 @@ void node_geometry_add_attribute_search_button(const bNodeTree *node_tree,
0.0f,
"");
AttributeSearchData *data = OBJECT_GUARDED_NEW(
AttributeSearchData, {*node_tree, *node, *static_cast<bNodeSocket *>(socket_ptr->data)});
AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData,
{tree_ui_storage->dummy_info_for_search,
*ui_storage,
*static_cast<bNodeSocket *>(socket_ptr->data)});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, MENU_SEP);

View File

@ -310,7 +310,8 @@ void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot);
void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot);
/* node_geometry_attribute_search.cc */
void node_geometry_add_attribute_search_button(const struct bNodeTree *node_tree,
void node_geometry_add_attribute_search_button(const struct bContext *C,
const struct bNodeTree *node_tree,
const struct bNode *node,
struct PointerRNA *socket_ptr,
struct uiLayout *layout);

View File

@ -846,7 +846,7 @@ static void ui_node_draw_input(
case SOCK_STRING: {
const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
if (node_tree->type == NTREE_GEOMETRY) {
node_geometry_add_attribute_search_button(node_tree, node, &inputptr, row);
node_geometry_add_attribute_search_button(C, node_tree, node, &inputptr, row);
}
else {
uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);