Blender V5.0
node_geometry_attribute_search.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_map.hh"
6#include "BLI_set.hh"
7#include "BLI_string.h"
8#include "BLI_string_ref.hh"
9#include "BLI_string_utf8.h"
10
11#include "DNA_node_types.h"
12#include "DNA_space_types.h"
13
15#include "BKE_context.hh"
18#include "BKE_node_runtime.hh"
21
22#include "RNA_access.hh"
23#include "RNA_enum_types.hh"
24
25#include "ED_node.hh"
26#include "ED_screen.hh"
27#include "ED_undo.hh"
28
29#include "UI_interface.hh"
31#include "UI_resources.hh"
32
34#include "NOD_socket.hh"
35
36#include "node_intern.hh"
37
39
41
46
47/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
48BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
49
52{
53 using namespace nodes::geo_eval_log;
54
55 SpaceNode *snode = CTX_wm_space_node(&C);
56 if (!snode) {
58 return {};
59 }
60 bNodeTree *node_tree = snode->edittree;
61 if (node_tree == nullptr) {
63 return {};
64 }
65 const bNode *node = node_tree->node_by_id(data.node_id);
66 if (node == nullptr) {
68 return {};
69 }
70 const bke::bNodeTreeZones *tree_zones = node_tree->zones();
71 if (!tree_zones) {
72 return {};
73 }
74 const ContextualGeoTreeLogs tree_logs = GeoNodesLog::get_contextual_tree_logs(*snode);
75
76 Set<StringRef> names;
77
78 /* For the attribute input node, collect attribute information from all nodes in the group. */
81 tree_logs.foreach_tree_log([&](GeoTreeLog &tree_log) {
82 tree_log.ensure_socket_values();
83 tree_log.ensure_existing_attributes();
84 for (const GeometryAttributeInfo *attribute : tree_log.existing_attributes) {
85 if (!names.add(attribute->name)) {
86 continue;
87 }
89 continue;
90 }
91 attributes.append(attribute);
92 }
93 });
94 return attributes;
95 }
96 GeoTreeLog *tree_log = tree_logs.get_main_tree_log(*node);
97 if (!tree_log) {
98 return {};
99 }
100 tree_log->ensure_socket_values();
101 GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
102 if (node_log == nullptr) {
103 return {};
104 }
105
107 for (const bNodeSocket *input_socket : node->input_sockets()) {
108 if (input_socket->type != SOCK_GEOMETRY) {
109 continue;
110 }
111 const ValueLog *value_log = tree_log->find_socket_value_log(*input_socket);
112 if (value_log == nullptr) {
113 continue;
114 }
115 if (const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(value_log)) {
116 for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
118 if (names.add(attribute.name)) {
119 attributes.append(&attribute);
120 }
121 }
122 }
123 }
124 }
125 return attributes;
126}
127
129 const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
130{
132 return;
133 }
134
135 AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
136
138
139 ui::attribute_search_add_items(str, true, infos, items, is_first);
140}
141
147{
148 switch (type) {
149 case CD_PROP_FLOAT:
150 case CD_PROP_INT32:
151 case CD_PROP_FLOAT3:
152 case CD_PROP_COLOR:
153 case CD_PROP_BOOL:
155 case CD_PROP_FLOAT4X4:
156 return type;
158 return CD_PROP_COLOR;
159 case CD_PROP_STRING:
160 /* Unsupported currently. */
161 return CD_PROP_FLOAT;
162 case CD_PROP_FLOAT2:
163 case CD_PROP_INT16_2D:
164 case CD_PROP_INT32_2D:
165 /* No 2D vector sockets currently. */
166 return CD_PROP_FLOAT3;
167 case CD_PROP_INT8:
168 return CD_PROP_INT32;
169 default:
170 return CD_PROP_FLOAT;
171 }
172}
173
174static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
175{
177 return;
178 }
180 if (item == nullptr) {
181 return;
182 }
183 SpaceNode *snode = CTX_wm_space_node(C);
184 if (!snode) {
186 return;
187 }
188 bNodeTree *node_tree = snode->edittree;
189 if (node_tree == nullptr) {
191 return;
192 }
193 AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v);
194 bNode *node = node_tree->node_by_id(data->node_id);
195 if (node == nullptr) {
197 return;
198 }
199
200 /* For the attribute input node, also adjust the type and links connected to the output. */
201 if (node->type_legacy == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) {
203 node->storage);
206 if (new_type != storage.data_type) {
207 storage.data_type = new_type;
208 /* Make the output socket with the new type on the attribute input node active. */
210 BKE_ntree_update_tag_node_property(node_tree, node);
212 }
213 }
214
215 bNodeSocket *socket = bke::node_find_enabled_input_socket(*node, data->socket_identifier);
216 if (socket == nullptr) {
218 return;
219 }
220 BLI_assert(socket->type == SOCK_STRING);
221
222 bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket->default_value);
223 BLI_strncpy_utf8(value->value, item->name.c_str(), MAX_NAME);
224
225 ED_undo_push(C, "Assign Attribute Name");
226}
227
229 const bNode &node,
230 PointerRNA &socket_ptr,
231 uiLayout &layout,
232 const StringRef placeholder)
233{
234 uiBlock *block = layout.block();
235 uiBut *but = uiDefIconTextButR(block,
237 0,
238 ICON_NONE,
239 "",
240 0,
241 0,
242 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
243 UI_UNIT_Y,
244 &socket_ptr,
245 "default_value",
246 0,
247 "");
248 UI_but_placeholder_set(but, placeholder);
249
250 const bNodeSocket &socket = *static_cast<const bNodeSocket *>(socket_ptr.data);
252 data->node_id = node.identifier;
253 STRNCPY_UTF8(data->socket_identifier, socket.identifier);
254
258 nullptr,
260 static_cast<void *>(data),
261 true,
262 nullptr,
264 nullptr);
265}
266
267} // namespace blender::ed::space_node
SpaceNode * CTX_wm_space_node(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
#define GEO_NODE_INPUT_NAMED_ATTRIBUTE
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
@ CD_PROP_BYTE_COLOR
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_COLOR
@ CD_PROP_QUATERNION
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_INT16_2D
@ CD_PROP_STRING
@ CD_PROP_FLOAT4X4
#define MAX_NAME
Definition DNA_defs.h:50
@ SOCK_GEOMETRY
@ SOCK_STRING
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
#define C
Definition RandGen.cpp:29
void UI_but_placeholder_set(uiBut *but, blender::StringRef placeholder_text)
#define UI_UNIT_Y
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
uiBut * uiDefIconTextButR(uiBlock *block, ButType type, int retval, int icon, std::optional< blender::StringRefNull > str, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, std::optional< blender::StringRef > tip)
#define UI_UNIT_X
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
#define str(s)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
std::optional< eCustomDataType > attr_type_to_custom_data_type(AttrType attr_type)
bNodeSocket * node_find_enabled_input_socket(bNode &node, StringRef name)
Definition node.cc:2566
bool allow_procedural_attribute_access(StringRef attribute_name)
NodeLinkData data[NODELINK_GROUP_SIZE]
Definition drawnode.cc:1863
static Vector< const GeometryAttributeInfo * > get_attribute_info_from_context(const bContext &C, AttributeSearchData &data)
void node_geometry_add_attribute_search_button(const bContext &, const bNode &node, PointerRNA &socket_ptr, uiLayout &layout, const StringRef placeholder)
static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType type)
static void attribute_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
void attribute_search_add_items(StringRef str, bool can_create_attribute, Span< const nodes::geo_eval_log::GeometryAttributeInfo * > infos, uiSearchItems *items, bool is_first)
#define UI_MENU_ARROW_SEP
void * data
Definition RNA_types.hh:53
struct bNodeTree * edittree
void * default_value
char identifier[64]
int16_t type_legacy
void * storage
int32_t identifier
uiBlock * block() const