Blender V5.0
NOD_socket_items_ops.hh
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#pragma once
6
7#include "NOD_socket_items.hh"
8
9#include "WM_api.hh"
10
11#include "BKE_context.hh"
12#include "BKE_library.hh"
16
17#include "RNA_access.hh"
18#include "RNA_define.hh"
19#include "RNA_prototypes.hh"
20
21#include "ED_node.hh"
22
23#include "DNA_space_types.h"
24
26
28 wmOperator *op,
29 const StringRef node_idname)
30{
32 if (!snode) {
33 return PointerRNA_NULL;
34 }
35 if (!snode->edittree) {
36 return PointerRNA_NULL;
37 }
38 if (!ID_IS_EDITABLE(snode->edittree)) {
39 return PointerRNA_NULL;
40 }
41
42 bNode *node = nullptr;
43 if (RNA_struct_property_is_set(op->ptr, "node_identifier")) {
44 const int id = RNA_int_get(op->ptr, "node_identifier");
45 node = snode->edittree->node_by_id(id);
46 }
47 else {
48 node = bke::node_get_active(*snode->edittree);
49 }
50 if (!node) {
51 return PointerRNA_NULL;
52 }
53
54 if (bke::zone_type_by_node_type(node->type_legacy) != nullptr) {
55 const bke::bNodeTreeZones *zones = snode->edittree->zones();
56 if (!zones) {
57 return PointerRNA_NULL;
58 }
59 if (const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node->identifier)) {
60 if (zone->input_node() == node) {
61 /* Assume the data is generally stored on the output and not the input node. */
62 node = const_cast<bNode *>(zone->output_node());
63 }
64 }
65 }
66
67 if (node->idname != node_idname) {
68 return PointerRNA_NULL;
69 }
70 return RNA_pointer_create_discrete(&snode->edittree->id, &RNA_Node, node);
71}
72
73inline void update_after_node_change(bContext *C, const PointerRNA node_ptr)
74{
75 bNode *node = static_cast<bNode *>(node_ptr.data);
76 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(node_ptr.owner_id);
77
81}
82
83template<typename Accessor> inline bool editable_node_active_poll(bContext *C)
84{
86 if (!snode) {
87 return false;
88 }
89 if (!snode->edittree) {
90 return false;
91 }
92 if (!ID_IS_EDITABLE(snode->edittree)) {
93 return false;
94 }
95 return true;
96}
97
99{
100 RNA_def_int(ot->srna,
101 "node_identifier",
102 0,
103 0,
104 INT32_MAX,
105 "Node Identifier",
106 "Optional identifier of the node to operate on",
107 0,
108 INT32_MAX);
109}
110
111template<typename Accessor>
113 const char *name,
114 const char *idname,
115 const char *description)
116{
117 ot->name = name;
118 ot->idname = idname;
119 ot->description = description;
121 ot->flag = OPTYPE_UNDO;
122
123 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
124 PointerRNA node_ptr = get_active_node_to_operate_on(C, op, Accessor::node_idname);
125 bNode &node = *static_cast<bNode *>(node_ptr.data);
126 SocketItemsRef ref = Accessor::get_items_from_node(node);
127 if (*ref.items_num > 0) {
129 ref.items, ref.items_num, ref.active_index, *ref.active_index, Accessor::destruct_item);
130 update_after_node_change(C, node_ptr);
131 }
132 return OPERATOR_FINISHED;
133 };
134
136}
137
138template<typename Accessor>
140 const char *name,
141 const char *idname,
142 const char *description)
143{
144 ot->name = name;
145 ot->idname = idname;
146 ot->description = description;
148 ot->flag = OPTYPE_UNDO;
149
150 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
151 PointerRNA node_ptr = get_active_node_to_operate_on(C, op, Accessor::node_idname);
152 bNode &node = *static_cast<bNode *>(node_ptr.data);
153 const int index_to_remove = RNA_int_get(op->ptr, "index");
154 SocketItemsRef ref = Accessor::get_items_from_node(node);
156 ref.items, ref.items_num, ref.active_index, index_to_remove, Accessor::destruct_item);
157
158 update_after_node_change(C, node_ptr);
159 return OPERATOR_FINISHED;
160 };
161
162 RNA_def_int(ot->srna, "index", 0, 0, INT32_MAX, "Index", "Index to remove", 0, INT32_MAX);
163}
164
165template<typename Accessor>
167 const char *name,
168 const char *idname,
169 const char *description)
170{
171 ot->name = name;
172 ot->idname = idname;
173 ot->description = description;
175 ot->flag = OPTYPE_UNDO;
176
177 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
178 PointerRNA node_ptr = get_active_node_to_operate_on(C, op, Accessor::node_idname);
179 if (node_ptr.data == nullptr) {
180 return OPERATOR_CANCELLED;
181 }
182 bNode &node = *static_cast<bNode *>(node_ptr.data);
183 SocketItemsRef ref = Accessor::get_items_from_node(node);
184 const typename Accessor::ItemT *active_item = nullptr;
185 int dst_index = *ref.items_num;
186 if (ref.active_index) {
187 const int old_active_index = *ref.active_index;
188 if (old_active_index >= 0 && old_active_index < *ref.items_num) {
189 active_item = &(*ref.items)[old_active_index];
190 dst_index = active_item ? old_active_index + 1 : *ref.items_num;
191 }
192 }
193
194 if constexpr (Accessor::has_type && Accessor::has_name) {
195 std::string name = active_item ? active_item->name : "";
196 if constexpr (Accessor::has_custom_initial_name) {
197 name = Accessor::custom_initial_name(node, name);
198 }
199 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(node_ptr.owner_id);
201 *ntree,
202 node,
203 active_item ?
204 Accessor::get_socket_type(*active_item) :
205 (Accessor::supports_socket_type(SOCK_GEOMETRY, ntree->type) ? SOCK_GEOMETRY :
206 SOCK_FLOAT),
207 /* Empty name so it is based on the type. */
208 name.c_str());
209 }
210 else if constexpr (!Accessor::has_type && Accessor::has_name) {
211 socket_items::add_item_with_name<Accessor>(node, active_item ? active_item->name : "");
212 }
213 else if constexpr (!Accessor::has_type && !Accessor::has_name) {
215 }
216 else {
218 }
219
220 dna::array::move_index(*ref.items, *ref.items_num, *ref.items_num - 1, dst_index);
221 if (ref.active_index) {
222 *ref.active_index = dst_index;
223 }
224
225 update_after_node_change(C, node_ptr);
226 return OPERATOR_FINISHED;
227 };
228
230}
231
232enum class MoveDirection {
233 Up = 0,
234 Down = 1,
235};
236
237template<typename Accessor>
239 const char *name,
240 const char *idname,
241 const char *description)
242{
243 ot->name = name;
244 ot->idname = idname;
245 ot->description = description;
247 ot->flag = OPTYPE_UNDO;
248
249 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
250 PointerRNA node_ptr = get_active_node_to_operate_on(C, op, Accessor::node_idname);
251 bNode &node = *static_cast<bNode *>(node_ptr.data);
252 const MoveDirection direction = MoveDirection(RNA_enum_get(op->ptr, "direction"));
253
254 SocketItemsRef ref = Accessor::get_items_from_node(node);
255 const int old_active_index = *ref.active_index;
256 if (direction == MoveDirection::Up && old_active_index > 0) {
257 dna::array::move_index(*ref.items, *ref.items_num, old_active_index, old_active_index - 1);
258 *ref.active_index -= 1;
259 }
260 else if (direction == MoveDirection::Down && old_active_index < *ref.items_num - 1) {
261 dna::array::move_index(*ref.items, *ref.items_num, old_active_index, old_active_index + 1);
262 *ref.active_index += 1;
263 }
264
265 update_after_node_change(C, node_ptr);
266 return OPERATOR_FINISHED;
267 };
268
269 static const EnumPropertyItem direction_items[] = {
270 {int(MoveDirection::Up), "UP", 0, "Up", ""},
271 {int(MoveDirection::Down), "DOWN", 0, "Down", ""},
272 {0, nullptr, 0, nullptr, nullptr},
273 };
274
275 RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Move direction");
277}
278
284template<typename Accessor> inline void make_common_operators()
285{
288 "Add Item",
289 Accessor::operator_idnames::add_item.c_str(),
290 "Add item below active item");
291 });
294 ot, "Remove Item", Accessor::operator_idnames::remove_item.c_str(), "Remove active item");
295 });
298 ot, "Move Item", Accessor::operator_idnames::move_item.c_str(), "Move active item");
299 });
300}
301
302} // namespace blender::nodes::socket_items::ops
SpaceNode * CTX_wm_space_node(const bContext *C)
Main * CTX_data_main(const bContext *C)
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
#define NC_NODE
Definition WM_types.hh:394
@ OPTYPE_UNDO
Definition WM_types.hh:182
#define NA_EDITED
Definition WM_types.hh:584
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
#define INT32_MAX
const bNodeZoneType * zone_type_by_node_type(const int node_type)
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4685
void remove_index(T **items, int *items_num, int *active_index, const int index, void(*destruct_item)(T *))
void move_index(T *items, const int items_num, const int from_index, const int to_index)
void remove_item_by_index(wmOperatorType *ot, const char *name, const char *idname, const char *description)
void add_node_identifier_property(wmOperatorType *ot)
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)
PointerRNA get_active_node_to_operate_on(bContext *C, wmOperator *op, const StringRef node_idname)
void update_after_node_change(bContext *C, const PointerRNA node_ptr)
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)
Accessor::ItemT * add_item(bNode &node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNodeTree &ntree, bNode &node, const eNodeSocketDatatype socket_type, const char *name, std::optional< int > dimensions=std::nullopt)
const char * name
const PointerRNA PointerRNA_NULL
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
struct bNodeTree * edittree
char name[64]
int16_t type_legacy
char idname[64]
int32_t identifier
struct PointerRNA * ptr
void WM_main_add_notifier(uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))