Blender V4.5
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
10#include "DNA_node_types.h"
11#include "DNA_space_types.h"
12
13#include "BKE_context.hh"
16#include "BKE_node_runtime.hh"
19
20#include "RNA_access.hh"
21#include "RNA_enum_types.hh"
22
23#include "ED_node.hh"
24#include "ED_screen.hh"
25#include "ED_undo.hh"
26
27#include "UI_interface.hh"
28#include "UI_resources.hh"
29
31#include "NOD_socket.hh"
32
33#include "node_intern.hh"
34
36
38
43
44/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
45BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
46
49{
50 using namespace nodes::geo_eval_log;
51
52 SpaceNode *snode = CTX_wm_space_node(&C);
53 if (!snode) {
55 return {};
56 }
57 bNodeTree *node_tree = snode->edittree;
58 if (node_tree == nullptr) {
60 return {};
61 }
62 const bNode *node = node_tree->node_by_id(data.node_id);
63 if (node == nullptr) {
65 return {};
66 }
67 const bke::bNodeTreeZones *tree_zones = node_tree->zones();
68 if (!tree_zones) {
69 return {};
70 }
71 const ContextualGeoTreeLogs tree_logs = GeoNodesLog::get_contextual_tree_logs(*snode);
72
73 Set<StringRef> names;
74
75 /* For the attribute input node, collect attribute information from all nodes in the group. */
78 tree_logs.foreach_tree_log([&](GeoTreeLog &tree_log) {
79 tree_log.ensure_socket_values();
80 tree_log.ensure_existing_attributes();
81 for (const GeometryAttributeInfo *attribute : tree_log.existing_attributes) {
82 if (!names.add(attribute->name)) {
83 continue;
84 }
86 continue;
87 }
88 attributes.append(attribute);
89 }
90 });
91 return attributes;
92 }
93 GeoTreeLog *tree_log = tree_logs.get_main_tree_log(*node);
94 if (!tree_log) {
95 return {};
96 }
97 tree_log->ensure_socket_values();
98 GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
99 if (node_log == nullptr) {
100 return {};
101 }
102
104 for (const bNodeSocket *input_socket : node->input_sockets()) {
105 if (input_socket->type != SOCK_GEOMETRY) {
106 continue;
107 }
108 const ValueLog *value_log = tree_log->find_socket_value_log(*input_socket);
109 if (value_log == nullptr) {
110 continue;
111 }
112 if (const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(value_log)) {
113 for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
115 if (names.add(attribute.name)) {
116 attributes.append(&attribute);
117 }
118 }
119 }
120 }
121 }
122 return attributes;
123}
124
126 const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
127{
129 return;
130 }
131
132 AttributeSearchData *data = static_cast<AttributeSearchData *>(arg);
133
135
136 ui::attribute_search_add_items(str, true, infos, items, is_first);
137}
138
144{
145 switch (type) {
146 case CD_PROP_FLOAT:
147 case CD_PROP_INT32:
148 case CD_PROP_FLOAT3:
149 case CD_PROP_COLOR:
150 case CD_PROP_BOOL:
152 case CD_PROP_FLOAT4X4:
153 return type;
155 return CD_PROP_COLOR;
156 case CD_PROP_STRING:
157 /* Unsupported currently. */
158 return CD_PROP_FLOAT;
159 case CD_PROP_FLOAT2:
160 case CD_PROP_INT16_2D:
161 case CD_PROP_INT32_2D:
162 /* No 2D vector sockets currently. */
163 return CD_PROP_FLOAT3;
164 case CD_PROP_INT8:
165 return CD_PROP_INT32;
166 default:
167 return CD_PROP_FLOAT;
168 }
169}
170
171static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
172{
174 return;
175 }
177 if (item == nullptr) {
178 return;
179 }
180 SpaceNode *snode = CTX_wm_space_node(C);
181 if (!snode) {
183 return;
184 }
185 bNodeTree *node_tree = snode->edittree;
186 if (node_tree == nullptr) {
188 return;
189 }
190 AttributeSearchData *data = static_cast<AttributeSearchData *>(data_v);
191 bNode *node = node_tree->node_by_id(data->node_id);
192 if (node == nullptr) {
194 return;
195 }
196
197 /* For the attribute input node, also adjust the type and links connected to the output. */
198 if (node->type_legacy == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) {
200 node->storage);
202 if (new_type != storage.data_type) {
203 storage.data_type = new_type;
204 /* Make the output socket with the new type on the attribute input node active. */
206 BKE_ntree_update_tag_node_property(node_tree, node);
208 }
209 }
210
211 bNodeSocket *socket = bke::node_find_enabled_input_socket(*node, data->socket_identifier);
212 if (socket == nullptr) {
214 return;
215 }
216 BLI_assert(socket->type == SOCK_STRING);
217
218 bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket->default_value);
219 BLI_strncpy(value->value, item->name.c_str(), MAX_NAME);
220
221 ED_undo_push(C, "Assign Attribute Name");
222}
223
225 const bNode &node,
226 PointerRNA &socket_ptr,
227 uiLayout &layout,
228 const StringRef placeholder)
229{
230 uiBlock *block = uiLayoutGetBlock(&layout);
231 uiBut *but = uiDefIconTextButR(block,
233 0,
234 ICON_NONE,
235 "",
236 0,
237 0,
238 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
239 UI_UNIT_Y,
240 &socket_ptr,
241 "default_value",
242 0,
243 0.0f,
244 0.0f,
245 "");
246 UI_but_placeholder_set(but, placeholder);
247
248 const bNodeSocket &socket = *static_cast<const bNodeSocket *>(socket_ptr.data);
250 data->node_id = node.identifier;
251 STRNCPY(data->socket_identifier, socket.identifier);
252
256 nullptr,
258 static_cast<void *>(data),
259 true,
260 nullptr,
262 nullptr);
263}
264
265} // 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 * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
@ 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
@ 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:99
#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)
uiBut * uiDefIconTextButR(uiBlock *block, int 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, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
#define UI_UNIT_X
@ UI_BTYPE_SEARCH_MENU
uiBlock * uiLayoutGetBlock(uiLayout *layout)
BMesh const char void * data
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
#define str(s)
#define MAX_NAME
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
bNodeSocket * node_find_enabled_input_socket(bNode &node, StringRef name)
Definition node.cc:2898
bool allow_procedural_attribute_access(StringRef attribute_name)
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