Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/node_geometry_attribute_search.cc
| Show All 40 Lines | |||||
| #include "node_intern.h" | #include "node_intern.h" | ||||
| using blender::IndexRange; | using blender::IndexRange; | ||||
| using blender::Map; | using blender::Map; | ||||
| using blender::Set; | using blender::Set; | ||||
| using blender::StringRef; | using blender::StringRef; | ||||
| struct AttributeSearchData { | struct AttributeSearchData { | ||||
| const bNodeTree &node_tree; | AvailableAttributeInfo &dummy_info_for_search; | ||||
| const bNode &node; | const NodeUIStorage &ui_storage; | ||||
| bNodeSocket &socket; | bNodeSocket &socket; | ||||
| }; | }; | ||||
| /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ | /* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */ | ||||
| BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); | BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, ""); | ||||
| static StringRef attribute_data_type_string(const CustomDataType type) | static StringRef attribute_data_type_string(const CustomDataType type) | ||||
| { | { | ||||
| Show All 18 Lines | static bool attribute_search_item_add(uiSearchItems *items, const AvailableAttributeInfo &item) | ||||
| const StringRef domain_name = attribute_domain_string(item.domain); | const StringRef domain_name = attribute_domain_string(item.domain); | ||||
| std::string search_item_text = domain_name + " " + MENU_SEP + item.name + UI_SEP_CHAR + | std::string search_item_text = domain_name + " " + MENU_SEP + item.name + UI_SEP_CHAR + | ||||
| data_type_name; | data_type_name; | ||||
| return UI_search_item_add( | return UI_search_item_add( | ||||
| items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0); | items, search_item_text.c_str(), (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0); | ||||
| } | } | ||||
| static void attribute_search_update_fn( | static void attribute_search_update_fn(const bContext *UNUSED(C), | ||||
| const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) | void *arg, | ||||
| const char *str, | |||||
| uiSearchItems *items, | |||||
| const bool is_first) | |||||
| { | { | ||||
| AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); | 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. */ | /* Any string may be valid, so add the current search string along with the hints. */ | ||||
| if (str[0] != '\0') { | if (str[0] != '\0') { | ||||
| /* Note that the attribute domain and data type are dummies, since | /* Note that the attribute domain and data type are dummies, since | ||||
| * #AvailableAttributeInfo equality is only based on the string. */ | * #AvailableAttributeInfo equality is only based on the string. */ | ||||
| if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) { | if (!attribute_hints.contains(AvailableAttributeInfo{str, ATTR_DOMAIN_AUTO, CD_PROP_BOOL})) { | ||||
| tree_ui_storage->dummy_info_for_search.name = std::string(str); | data->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); | UI_search_item_add(items, str, &data->dummy_info_for_search, ICON_ADD, 0, 0); | ||||
| } | } | ||||
| } | } | ||||
| if (str[0] == '\0' && !is_first) { | if (str[0] == '\0' && !is_first) { | ||||
| /* Allow clearing the text field when the string is empty, but not on the first pass, | /* 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. */ | * 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); | data->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); | 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 | /* Don't filter when the menu is first opened, but still run the search | ||||
| * so the items are in the same order they will appear in while searching. */ | * so the items are in the same order they will appear in while searching. */ | ||||
| const char *string = is_first ? "" : str; | const char *string = is_first ? "" : str; | ||||
| StringSearch *search = BLI_string_search_new(); | StringSearch *search = BLI_string_search_new(); | ||||
| for (const AvailableAttributeInfo &item : attribute_hints) { | for (const AvailableAttributeInfo &item : attribute_hints) { | ||||
| Show All 19 Lines | static void attribute_search_exec_fn(bContext *UNUSED(C), void *data_v, void *item_v) | ||||
| AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v); | AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v); | ||||
| AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v); | AvailableAttributeInfo *item = static_cast<AvailableAttributeInfo *>(item_v); | ||||
| bNodeSocket &socket = data->socket; | bNodeSocket &socket = data->socket; | ||||
| bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value); | bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket.default_value); | ||||
| BLI_strncpy(value->value, item->name.c_str(), MAX_NAME); | 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, | const bNode *node, | ||||
| PointerRNA *socket_ptr, | PointerRNA *socket_ptr, | ||||
| uiLayout *layout) | 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); | uiBlock *block = uiLayoutGetBlock(layout); | ||||
| uiBut *but = uiDefIconTextButR(block, | uiBut *but = uiDefIconTextButR(block, | ||||
| UI_BTYPE_SEARCH_MENU, | UI_BTYPE_SEARCH_MENU, | ||||
| 0, | 0, | ||||
| ICON_NONE, | ICON_NONE, | ||||
| "", | "", | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */ | 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */ | ||||
| UI_UNIT_Y, | UI_UNIT_Y, | ||||
| socket_ptr, | socket_ptr, | ||||
| "default_value", | "default_value", | ||||
| 0, | 0, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| 0.0f, | 0.0f, | ||||
| ""); | ""); | ||||
| AttributeSearchData *data = OBJECT_GUARDED_NEW( | AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData, | ||||
| AttributeSearchData, {*node_tree, *node, *static_cast<bNodeSocket *>(socket_ptr->data)}); | {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_results_are_suggestions(but, true); | ||||
| UI_but_func_search_set_sep_string(but, MENU_SEP); | UI_but_func_search_set_sep_string(but, MENU_SEP); | ||||
| UI_but_func_search_set(but, | UI_but_func_search_set(but, | ||||
| nullptr, | nullptr, | ||||
| attribute_search_update_fn, | attribute_search_update_fn, | ||||
| static_cast<void *>(data), | static_cast<void *>(data), | ||||
| true, | true, | ||||
| nullptr, | nullptr, | ||||
| attribute_search_exec_fn, | attribute_search_exec_fn, | ||||
| nullptr); | nullptr); | ||||
| } | } | ||||