Blender V5.0
node_geometry_volume_grid_search.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_string_ref.hh"
6#include "BLI_string_utf8.h"
7
8#include "BLT_translation.hh"
9#include "DNA_node_types.h"
10#include "DNA_space_types.h"
11
12#include "BKE_context.hh"
13#include "BKE_node_runtime.hh"
15
16#include "RNA_access.hh"
17#include "RNA_enum_types.hh"
18
19#include "ED_node.hh"
20#include "ED_screen.hh"
21#include "ED_undo.hh"
22
24#include "UI_resources.hh"
25
27
28#include "UI_string_search.hh"
29
30#include "node_intern.hh"
31
32#include <fmt/format.h>
33
36
38
44
45/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
46BLI_STATIC_ASSERT(std::is_trivially_destructible_v<GridSearchData>, "");
47
50{
51 using namespace nodes::geo_eval_log;
52
53 SpaceNode *snode = CTX_wm_space_node(&C);
54 if (!snode) {
56 return {};
57 }
58 bNodeTree *node_tree = snode->edittree;
59 if (node_tree == nullptr) {
61 return {};
62 }
63 const bNode *node = node_tree->node_by_id(data.node_id);
64 if (node == nullptr) {
66 return {};
67 }
68 const bke::bNodeTreeZones *tree_zones = node_tree->zones();
69 if (!tree_zones) {
70 return {};
71 }
72 const ContextualGeoTreeLogs tree_logs = GeoNodesLog::get_contextual_tree_logs(*snode);
73
74 Set<StringRef> names;
75
76 GeoTreeLog *tree_log = tree_logs.get_main_tree_log(*node);
77 if (!tree_log) {
78 return {};
79 }
80 tree_log->ensure_socket_values();
81 GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
82 if (node_log == nullptr) {
83 return {};
84 }
85
87 for (const bNodeSocket *input_socket : node->input_sockets()) {
88 if (input_socket->type != SOCK_GEOMETRY) {
89 continue;
90 }
91 const ValueLog *value_log = tree_log->find_socket_value_log(*input_socket);
92 if (value_log == nullptr) {
93 continue;
94 }
95 if (const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(value_log)) {
96 if (const std::optional<GeometryInfoLog::VolumeInfo> &volume_info = geo_log->volume_info) {
97 for (const VolumeGridInfo &info : volume_info->grids) {
98 if (names.add(info.name)) {
99 grids.append(&info);
100 }
101 }
102 }
103 }
104 }
105 return grids;
106}
107
109{
110 const char *name = nullptr;
112 return IFACE_(StringRef(name));
113}
114
115static bool grid_search_item_add(uiSearchItems &items, const VolumeGridInfo &item)
116{
117 std::string text = fmt::format(
118 "{}" UI_SEP_CHAR_S "{}", item.name, grid_data_type_string(item.grid_type));
119 return UI_search_item_add(&items, text, (void *)&item, ICON_NONE, UI_BUT_HAS_SEP_CHAR, 0);
120}
121
123 const bool can_create_grid,
125 uiSearchItems &seach_items,
126 const bool is_first)
127{
128 static std::string dummy_str;
129
130 /* Any string may be valid, so add the current search string along with the hints. */
131 if (!str.is_empty()) {
132 bool contained = false;
133 for (const VolumeGridInfo *info : grids) {
134 if (info->name == str) {
135 contained = true;
136 }
137 }
138 if (!contained) {
139 dummy_str = str;
141 &seach_items, str, &dummy_str, can_create_grid ? ICON_ADD : ICON_NONE, 0, 0);
142 }
143 }
144
145 if (str.is_empty() && !is_first) {
146 /* Allow clearing the text field when the string is empty, but not on the first pass,
147 * or opening a name field for the first time would show this search item. */
148 dummy_str = str;
149 UI_search_item_add(&seach_items, str, &dummy_str, ICON_X, 0, 0);
150 }
151
152 /* Don't filter when the menu is first opened, but still run the search
153 * so the items are in the same order they will appear in while searching. */
154 const StringRef string = is_first ? "" : str;
155
157 for (const VolumeGridInfo *info : grids) {
158 search.add(info->name, info);
159 }
160
161 const Vector<const VolumeGridInfo *> filtered_names = search.query(string);
162 for (const VolumeGridInfo *info : filtered_names) {
163 if (!grid_search_item_add(seach_items, *info)) {
164 break;
165 }
166 }
167}
168
170 const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
171{
173 return;
174 }
175
176 GridSearchData *data = static_cast<GridSearchData *>(arg);
177
179
180 BLI_assert(items);
181 volume_grid_search_add_items(str, data->can_create_grid, grids, *items, is_first);
182}
183
184static void grid_search_exec_fn(bContext *C, void *data_v, void *item_v)
185{
187 return;
188 }
189 std::string *item = static_cast<std::string *>(item_v);
190 if (item == nullptr) {
191 return;
192 }
193 SpaceNode *snode = CTX_wm_space_node(C);
194 if (!snode) {
196 return;
197 }
198 bNodeTree *node_tree = snode->edittree;
199 if (node_tree == nullptr) {
201 return;
202 }
203 GridSearchData *data = static_cast<GridSearchData *>(data_v);
204 bNode *node = node_tree->node_by_id(data->node_id);
205 if (node == nullptr) {
207 return;
208 }
209
210 bNodeSocket *socket = bke::node_find_enabled_input_socket(*node, data->socket_identifier);
211 if (socket == nullptr) {
213 return;
214 }
215 BLI_assert(socket->type == SOCK_STRING);
216
217 bNodeSocketValueString *value = static_cast<bNodeSocketValueString *>(socket->default_value);
218 BLI_strncpy_utf8(value->value, item->c_str(), MAX_NAME);
219
220 ED_undo_push(C, "Assign Grid Name");
221}
222
224 const bNode &node,
225 PointerRNA &socket_ptr,
226 uiLayout &layout,
227 const StringRef placeholder)
228{
229 uiBlock *block = layout.block();
230 uiBut *but = uiDefIconTextButR(block,
232 0,
233 ICON_NONE,
234 "",
235 0,
236 0,
237 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
238 UI_UNIT_Y,
239 &socket_ptr,
240 "default_value",
241 0,
242 "");
243 UI_but_placeholder_set(but, placeholder);
244
245 const bNodeSocket &socket = *static_cast<const bNodeSocket *>(socket_ptr.data);
247 data->node_id = node.identifier;
248 data->can_create_grid = node.is_type("GeometryNodeStoreNamedGrid");
249 STRNCPY_UTF8(data->socket_identifier, socket.identifier);
250
254 nullptr,
256 static_cast<void *>(data),
257 true,
258 nullptr,
260 nullptr);
261}
262
263} // namespace blender::ed::space_node
SpaceNode * CTX_wm_space_node(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
VolumeGridType
#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)
#define IFACE_(msgid)
#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
#define UI_SEP_CHAR_S
void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value)
@ UI_BUT_HAS_SEP_CHAR
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)
bool UI_search_item_add(uiSearchItems *items, blender::StringRef name, void *poin, int iconid, int but_flag, uint8_t name_prefix_offset)
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)
void add(const StringRef str, T *user_data, const int weight=0)
Vector< T * > query(const StringRef query) const
#define str(s)
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:2566
static void grid_search_update_fn(const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
static void grid_search_exec_fn(bContext *C, void *data_v, void *item_v)
NodeLinkData data[NODELINK_GROUP_SIZE]
Definition drawnode.cc:1863
static StringRef grid_data_type_string(const VolumeGridType type)
static bool grid_search_item_add(uiSearchItems &items, const VolumeGridInfo &item)
static void volume_grid_search_add_items(const StringRef str, const bool can_create_grid, const Span< const VolumeGridInfo * > grids, uiSearchItems &seach_items, const bool is_first)
static Vector< const VolumeGridInfo * > get_grid_names_from_context(const bContext &C, GridSearchData &data)
void node_geometry_add_volume_grid_search_button(const bContext &, const bNode &node, PointerRNA &socket_ptr, uiLayout &layout, const StringRef placeholder)
const char * name
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
const EnumPropertyItem rna_enum_volume_grid_data_type_items[]
Definition rna_volume.cc:25
#define UI_MENU_ARROW_SEP
void * data
Definition RNA_types.hh:53
struct bNodeTree * edittree
void * default_value
char identifier[64]
int32_t identifier
uiBlock * block() const