Blender V4.3
node_geo_menu_switch.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 <algorithm>
6
8
9#include "DNA_node_types.h"
10
11#include "BLI_string.h"
12
13#include "FN_multi_function.hh"
14
15#include "UI_interface.hh"
16#include "UI_resources.hh"
17
19#include "NOD_rna_define.hh"
20#include "NOD_socket.hh"
23
24#include "BLO_read_write.hh"
25
26#include "RNA_enum_types.hh"
27#include "RNA_prototypes.hh"
28
29#include "BKE_screen.hh"
30
31#include "WM_api.hh"
32
34
36
54
56{
57 const bNodeTree *ntree = b.tree_or_null();
58 const bNode *node = b.node_or_null();
59 if (node == nullptr) {
60 return;
61 }
62 const NodeMenuSwitch &storage = node_storage(*node);
63 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.data_type);
64 const bool supports_fields = socket_type_supports_fields(data_type);
65
66 auto &menu = b.add_input<decl::Menu>("Menu");
67 if (supports_fields) {
68 menu.supports_field();
69 }
70
71 for (const NodeEnumItem &enum_item : storage.enum_definition.items()) {
72 const std::string identifier = MenuSwitchItemsAccessor::socket_identifier_for_item(enum_item);
73 auto &input = b.add_input(data_type, enum_item.name, std::move(identifier))
74 .socket_name_ptr(
75 &ntree->id, MenuSwitchItemsAccessor::item_srna, &enum_item, "name");
76 ;
77 if (supports_fields) {
78 input.supports_field();
79 }
80 /* Labels are ugly in combination with data-block pickers and are usually disabled. */
81 input.hide_label(ELEM(data_type, SOCK_OBJECT, SOCK_IMAGE, SOCK_COLLECTION, SOCK_MATERIAL));
82 }
83
84 auto &output = b.add_output(data_type, "Output");
85 if (supports_fields) {
86 output.dependent_field().reference_pass_all();
87 }
88 else if (data_type == SOCK_GEOMETRY) {
89 output.propagate_all();
90 }
91
92 b.add_input<decl::Extend>("", "__extend__");
93}
94
95static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
96{
97 uiItemR(layout, ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
98}
99
100static void node_init(bNodeTree * /*tree*/, bNode *node)
101{
102 NodeMenuSwitch *data = MEM_cnew<NodeMenuSwitch>(__func__);
103 data->data_type = SOCK_GEOMETRY;
104 data->enum_definition.next_identifier = 0;
105 data->enum_definition.items_array = nullptr;
106 data->enum_definition.items_num = 0;
107 node->storage = data;
108
111}
112
113static void node_free_storage(bNode *node)
114{
116 MEM_freeN(node->storage);
117}
118
119static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
120{
121 const NodeMenuSwitch &src_storage = node_storage(*src_node);
122 NodeMenuSwitch *dst_storage = MEM_cnew<NodeMenuSwitch>(__func__, src_storage);
123 dst_node->storage = dst_storage;
124
126}
127
129{
130 const eNodeSocketDatatype data_type = eNodeSocketDatatype(params.other_socket().type);
131 if (params.in_out() == SOCK_IN) {
132 if (data_type == SOCK_MENU) {
133 params.add_item(IFACE_("Menu"), [](LinkSearchOpParams &params) {
134 bNode &node = params.add_node("GeometryNodeMenuSwitch");
135 params.update_and_connect_available_socket(node, "Menu");
136 });
137 }
138 }
139 else {
140 if (data_type != SOCK_MENU) {
141 params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
142 bNode &node = params.add_node("GeometryNodeMenuSwitch");
143 node_storage(node).data_type = params.socket.type;
144 params.update_and_connect_available_socket(node, "Output");
145 });
146 }
147 }
148}
149
155 const NodeEnumDefinition &enum_def_;
156 const CPPType &type_;
157 mf::Signature signature_;
158
159 public:
160 MenuSwitchFn(const NodeEnumDefinition &enum_def, const CPPType &type)
161 : enum_def_(enum_def), type_(type)
162 {
163 mf::SignatureBuilder builder{"Menu Switch", signature_};
164 builder.single_input<int>("Menu");
165 for (const NodeEnumItem &enum_item : enum_def.items()) {
166 builder.single_input(enum_item.name, type);
167 }
168 builder.single_output("Output", type);
169
170 this->set_signature(&signature_);
171 }
172
173 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const
174 {
175 const int value_inputs_start = 1;
176 const int inputs_num = enum_def_.items_num;
177 const VArray<int> values = params.readonly_single_input<int>(0, "Menu");
178 /* Use one extra mask at the end for invalid indices. */
179 const int invalid_index = inputs_num;
180
181 GMutableSpan output = params.uninitialized_single_output(
182 signature_.params.index_range().last(), "Output");
183
184 auto find_item_index = [&](const int value) -> int {
185 for (const int i : enum_def_.items().index_range()) {
186 const NodeEnumItem &item = enum_def_.items()[i];
187 if (item.identifier == value) {
188 return i;
189 }
190 }
191 return invalid_index;
192 };
193
194 if (const std::optional<int> value = values.get_if_single()) {
195 const int index = find_item_index(*value);
196 if (index < inputs_num) {
197 const GVArray inputs = params.readonly_single_input(value_inputs_start + index);
198 inputs.materialize_to_uninitialized(mask, output.data());
199 }
200 else {
201 type_.fill_construct_indices(type_.default_value(), output.data(), mask);
202 }
203 return;
204 }
205
206 IndexMaskMemory memory;
207 Array<IndexMask> masks(inputs_num + 1);
209 mask, memory, [&](const int64_t i) { return find_item_index(values[i]); }, masks);
210
211 for (const int i : IndexRange(inputs_num)) {
212 if (!masks[i].is_empty()) {
213 const GVArray inputs = params.readonly_single_input(value_inputs_start + i);
214 inputs.materialize_to_uninitialized(masks[i], output.data());
215 }
216 }
217
218 type_.fill_construct_indices(type_.default_value(), output.data(), masks[invalid_index]);
219 }
220};
221
223 private:
224 const bNode &node_;
225 bool can_be_field_ = false;
226 const NodeEnumDefinition &enum_def_;
227 const CPPType *cpp_type_;
228 const CPPType *field_base_type_;
229
230 public:
233 : node_(node), enum_def_(node_storage(node).enum_definition)
234 {
235 const NodeMenuSwitch &storage = node_storage(node);
236 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.data_type);
237 can_be_field_ = socket_type_supports_fields(data_type);
240 BLI_assert(socket_type != nullptr);
241 cpp_type_ = socket_type->geometry_nodes_cpp_type;
242 field_base_type_ = socket_type->base_cpp_type;
243
244 MutableSpan<int> lf_index_by_bsocket = lf_graph_info.mapping.lf_index_by_bsocket;
245 debug_name_ = node.name;
246 lf_index_by_bsocket[node.input_socket(0).index_in_tree()] = inputs_.append_and_get_index_as(
247 "Switch", CPPType::get<SocketValueVariant>(), lf::ValueUsage::Used);
248 for (const int i : enum_def_.items().index_range()) {
249 const NodeEnumItem &enum_item = enum_def_.items()[i];
250 lf_index_by_bsocket[node.input_socket(i + 1).index_in_tree()] =
251 inputs_.append_and_get_index_as(enum_item.name, *cpp_type_, lf::ValueUsage::Maybe);
252 }
253 lf_index_by_bsocket[node.output_socket(0).index_in_tree()] = outputs_.append_and_get_index_as(
254 "Value", *cpp_type_);
255 }
256
257 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
258 {
259 SocketValueVariant condition_variant = params.get_input<SocketValueVariant>(0);
260 if (condition_variant.is_context_dependent_field() && can_be_field_) {
261 this->execute_field(condition_variant.get<Field<int>>(), params);
262 }
263 else {
264 this->execute_single(condition_variant.get<int>(), params);
265 }
266 }
267
268 void execute_single(const int condition, lf::Params &params) const
269 {
270 for (const int i : IndexRange(enum_def_.items_num)) {
271 const NodeEnumItem &enum_item = enum_def_.items_array[i];
272 const int input_index = i + 1;
273 if (enum_item.identifier == condition) {
274 void *value_to_forward = params.try_get_input_data_ptr_or_request(input_index);
275 if (value_to_forward == nullptr) {
276 /* Try again when the value is available. */
277 return;
278 }
279
280 void *output_ptr = params.get_output_data_ptr(0);
281 cpp_type_->move_construct(value_to_forward, output_ptr);
282 params.output_set(0);
283 }
284 else {
285 params.set_input_unused(input_index);
286 }
287 }
288 /* No guarantee that the switch input matches any enum,
289 * set default outputs to ensure valid state. */
291 }
292
294 {
295 /* When the condition is a non-constant field, we need all inputs. */
296 const int values_num = this->enum_def_.items_num;
297 Array<SocketValueVariant *, 8> input_values(values_num);
298 for (const int i : IndexRange(values_num)) {
299 const int input_index = i + 1;
300 input_values[i] = params.try_get_input_data_ptr_or_request<SocketValueVariant>(input_index);
301 }
302 if (input_values.as_span().contains(nullptr)) {
303 /* Try again when inputs are available. */
304 return;
305 }
306
307 Vector<GField> item_fields(enum_def_.items_num + 1);
308 item_fields[0] = std::move(condition);
309 for (const int i : IndexRange(enum_def_.items_num)) {
310 item_fields[i + 1] = input_values[i]->extract<GField>();
311 }
312 std::unique_ptr<MultiFunction> multi_function = std::make_unique<MenuSwitchFn>(
313 enum_def_, *field_base_type_);
314 GField output_field{FieldOperation::Create(std::move(multi_function), std::move(item_fields))};
315
316 void *output_ptr = params.get_output_data_ptr(0);
317 new (output_ptr) SocketValueVariant(std::move(output_field));
318 params.output_set(0);
319 }
320};
321
328 const NodeEnumDefinition &enum_def_;
329
330 public:
332 : enum_def_(node_storage(node).enum_definition)
333 {
334 debug_name_ = "Menu Switch Socket Usage";
335 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
336 for (const int i : IndexRange(enum_def_.items_num)) {
337 const NodeEnumItem &enum_item = enum_def_.items()[i];
338 outputs_.append_as(enum_item.name, CPPType::get<bool>());
339 }
340 }
341
342 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
343 {
344 const SocketValueVariant &condition_variant = params.get_input<SocketValueVariant>(0);
345 if (condition_variant.is_context_dependent_field()) {
346 for (const int i : IndexRange(enum_def_.items_num)) {
347 params.set_output(i, true);
348 }
349 }
350 else {
351 const int32_t value = condition_variant.get<int>();
352 for (const int i : IndexRange(enum_def_.items_num)) {
353 const NodeEnumItem &enum_item = enum_def_.items()[i];
354 params.set_output(i, value == enum_item.identifier);
355 }
356 }
357 }
358};
359
360static void draw_menu_switch_item(uiList * /*ui_list*/,
361 const bContext * /*C*/,
362 uiLayout *layout,
363 PointerRNA * /*idataptr*/,
364 PointerRNA *itemptr,
365 int /*icon*/,
366 PointerRNA * /*active_dataptr*/,
367 const char * /*active_propname*/,
368 int /*index*/,
369 int /*flt_flag*/)
370{
372 uiItemR(layout, itemptr, "name", UI_ITEM_NONE, "", ICON_NONE);
373}
374
376{
377 bNode &node = *static_cast<bNode *>(ptr->data);
378
379 static const uiListType *menu_items_list = []() {
380 uiListType *list = MEM_cnew<uiListType>(__func__);
381 STRNCPY(list->idname, "NODE_UL_enum_definition_items");
382 list->draw_item = draw_menu_switch_item;
383 WM_uilisttype_add(list);
384 return list;
385 }();
386
387 uiItemR(layout, ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
388
389 if (uiLayout *panel = uiLayoutPanel(C, layout, "menu_switch_items", false, TIP_("Menu Items"))) {
390 uiLayout *row = uiLayoutRow(panel, false);
391 uiTemplateList(row,
392 C,
393 menu_items_list->idname,
394 "",
395 ptr,
396 "enum_items",
397 ptr,
398 "active_index",
399 nullptr,
400 3,
401 5,
403 0,
405 {
406 uiLayout *ops_col = uiLayoutColumn(row, false);
407 {
408 uiLayout *add_remove_col = uiLayoutColumn(ops_col, true);
409 uiItemO(add_remove_col, "", ICON_ADD, "node.enum_definition_item_add");
410 uiItemO(add_remove_col, "", ICON_REMOVE, "node.enum_definition_item_remove");
411 }
412 {
413 uiLayout *up_down_col = uiLayoutColumn(ops_col, true);
415 up_down_col, "node.enum_definition_item_move", "", ICON_TRIA_UP, "direction", 0);
417 up_down_col, "node.enum_definition_item_move", "", ICON_TRIA_DOWN, "direction", 1);
418 }
419 }
420
421 auto &storage = node_storage(node);
422 if (storage.enum_definition.active_index >= 0 &&
423 storage.enum_definition.active_index < storage.enum_definition.items_num)
424 {
425 NodeEnumItem &active_item =
426 storage.enum_definition.items_array[storage.enum_definition.active_index];
429 uiLayoutSetPropSep(panel, true);
430 uiLayoutSetPropDecorate(panel, false);
431 uiItemR(panel, &item_ptr, "description", UI_ITEM_NONE, nullptr, ICON_NONE);
432 }
433 }
434}
435
437{
439 ot, "Add Menu Item", __func__, "Add menu item");
440}
441
443{
445 ot, "Remove Menu Item", __func__, "Remove active menu item");
446}
447
449{
451 ot, "Move Menu Item", __func__, "Move active menu item");
452}
453
460
461static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
462{
464 *ntree, *node, *node, *link);
465}
466
467static void node_rna(StructRNA *srna)
468{
470 srna,
471 "data_type",
472 "Data Type",
473 "",
477 [](bContext * /*C*/, PointerRNA * /*ptr*/, PropertyRNA * /*prop*/, bool *r_free) {
478 *r_free = true;
479 return enum_items_filter(
482 });
483 });
484}
485
486static void register_node()
487{
488 static blender::bke::bNodeType ntype;
489
490 geo_node_type_base(&ntype, GEO_NODE_MENU_SWITCH, "Menu Switch", NODE_CLASS_CONVERTER);
491 ntype.declare = node_declare;
492 ntype.initfunc = node_init;
500
501 node_rna(ntype.rna_ext.srna);
502}
504
505} // namespace blender::nodes::node_geo_menu_switch_cc
506
507namespace blender::nodes {
508
509std::unique_ptr<LazyFunction> get_menu_switch_node_lazy_function(
510 const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
511{
512 using namespace node_geo_menu_switch_cc;
513 BLI_assert(node.type == GEO_NODE_MENU_SWITCH);
514 return std::make_unique<LazyFunctionForMenuSwitchNode>(node, lf_graph_info);
515}
516
517std::unique_ptr<LazyFunction> get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
518{
519 using namespace node_geo_menu_switch_cc;
520 BLI_assert(node.type == GEO_NODE_MENU_SWITCH);
521 return std::make_unique<LazyFunctionForMenuSwitchSocketUsage>(node);
522}
523
526
528{
529 const NodeMenuSwitch &storage = *static_cast<const NodeMenuSwitch *>(node.storage);
534 for (const NodeEnumItem &item : storage.enum_definition.items()) {
535 BLO_write_string(writer, item.name);
536 BLO_write_string(writer, item.description);
537 }
538}
539
541{
542 NodeMenuSwitch &storage = *static_cast<NodeMenuSwitch *>(node.storage);
547 for (NodeEnumItem &item : storage.enum_definition.items()) {
548 BLO_read_string(reader, &item.name);
549 BLO_read_string(reader, &item.description);
550 }
551}
552
553} // namespace blender::nodes
#define GEO_NODE_MENU_SWITCH
Definition BKE_node.hh:1354
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:410
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define BLI_assert(a)
Definition BLI_assert.h:50
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define ELEM(...)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
#define TIP_(msgid)
#define IFACE_(msgid)
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
@ UILST_LAYOUT_DEFAULT
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
@ PROP_NONE
Definition RNA_types.hh:136
@ UI_EMBOSS_NONE
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
void uiTemplateList(uiLayout *layout, const bContext *C, const char *listtype_name, const char *list_id, PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr, const char *active_propname, const char *item_dyntip_propname, int rows, int maxrows, int layout_type, int columns, enum uiTemplateListFlags flags)
#define UI_ITEM_NONE
PanelLayout uiLayoutPanel(const bContext *C, uiLayout *layout, const char *idname, bool default_closed)
void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss)
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
@ UI_TEMPLATE_LIST_FLAG_NONE
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
Span< T > as_span() const
Definition BLI_array.hh:232
void fill_construct_indices(const void *value, void *dst, const IndexMask &mask) const
static const CPPType & get()
const void * default_value() const
void move_construct(void *src, void *dst) const
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
void set_signature(const Signature *signature)
static void from_groups(const IndexMask &universe, IndexMaskMemory &memory, Fn &&get_group_index, MutableSpan< IndexMask > r_masks)
void execute_field(Field< int > condition, lf::Params &params) const
void execute_impl(lf::Params &params, const lf::Context &) const override
LazyFunctionForMenuSwitchNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
void execute_single(const int condition, lf::Params &params) const
void execute_impl(lf::Params &params, const lf::Context &) const override
void call(const IndexMask &mask, mf::Params params, mf::Context) const
MenuSwitchFn(const NodeEnumDefinition &enum_def, const CPPType &type)
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bNodeSocketType * node_socket_type_find(const char *idname)
Definition node.cc:1763
const char * node_static_socket_type(int type, int subtype)
Definition node.cc:2126
void node_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static void node_init(bNodeTree *, bNode *node)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void NODE_OT_enum_definition_item_remove(wmOperatorType *ot)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void draw_menu_switch_item(uiList *, const bContext *, uiLayout *layout, PointerRNA *, PointerRNA *itemptr, int, PointerRNA *, const char *, int, int)
static void node_declare(blender::nodes::NodeDeclarationBuilder &b)
static bool is_supported_socket_type(const eNodeSocketDatatype data_type)
static void NODE_OT_enum_definition_item_add(wmOperatorType *ot)
static void NODE_OT_enum_definition_item_move(wmOperatorType *ot)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
void move_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void remove_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void add_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
Accessor::ItemT * add_item_with_name(bNode &node, const char *name)
void copy_array(const bNode &src_node, bNode &dst_node)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
std::unique_ptr< LazyFunction > get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
std::unique_ptr< LazyFunction > get_menu_switch_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
StructRNA * srna
Definition RNA_types.hh:780
NodeEnumItem * items_array
NodeEnumDefinition enum_definition
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
void * storage
Defines a socket type.
Definition BKE_node.hh:151
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:195
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:191
Defines a node type.
Definition BKE_node.hh:218
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:240
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:309
NodeDeclareFunction declare
Definition BKE_node.hh:347
void(* register_operators)()
Definition BKE_node.hh:392
static std::string socket_identifier_for_item(const NodeEnumItem &item)
static void blend_read_data(BlendDataReader *reader, bNode &node)
static void blend_write(BlendWriter *writer, const bNode &node)
char idname[BKE_ST_MAXNAME]
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_uilisttype_add(uiListType *ult)