Blender V4.5
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{
30 if (!snode) {
31 return PointerRNA_NULL;
32 }
33 if (!snode->edittree) {
34 return PointerRNA_NULL;
35 }
36 if (!ID_IS_EDITABLE(snode->edittree)) {
37 return PointerRNA_NULL;
38 }
39 const bke::bNodeTreeZones *zones = snode->edittree->zones();
40 if (!zones) {
41 return PointerRNA_NULL;
42 }
43 bNode *active_node = bke::node_get_active(*snode->edittree);
44 if (!active_node) {
45 return PointerRNA_NULL;
46 }
47 if (const bke::bNodeTreeZone *zone = zones->get_zone_by_node(active_node->identifier)) {
48 if (zone->input_node() == active_node) {
49 /* Assume the data is generally stored on the output and not the input node. */
50 active_node = const_cast<bNode *>(zone->output_node());
51 }
52 }
53 if (active_node->idname != node_idname) {
54 return PointerRNA_NULL;
55 }
56 return RNA_pointer_create_discrete(&snode->edittree->id, &RNA_Node, active_node);
57}
58
59inline void update_after_node_change(bContext *C, const PointerRNA node_ptr)
60{
61 bNode *node = static_cast<bNode *>(node_ptr.data);
62 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(node_ptr.owner_id);
63
67}
68
69template<typename Accessor> inline bool editable_node_active_poll(bContext *C)
70{
71 return get_active_node_to_operate_on(C, Accessor::node_idname).data != nullptr;
72}
73
74template<typename Accessor>
76 const char *name,
77 const char *idname,
78 const char *description)
79{
80 ot->name = name;
81 ot->idname = idname;
82 ot->description = description;
84 ot->flag = OPTYPE_UNDO;
85
86 ot->exec = [](bContext *C, wmOperator * /*op*/) -> wmOperatorStatus {
87 PointerRNA node_ptr = get_active_node_to_operate_on(C, Accessor::node_idname);
88 bNode &node = *static_cast<bNode *>(node_ptr.data);
89 SocketItemsRef ref = Accessor::get_items_from_node(node);
90 if (*ref.items_num > 0) {
92 ref.items, ref.items_num, ref.active_index, *ref.active_index, Accessor::destruct_item);
93 update_after_node_change(C, node_ptr);
94 }
95 return OPERATOR_FINISHED;
96 };
97}
98
99template<typename Accessor>
101 const char *name,
102 const char *idname,
103 const char *description)
104{
105 ot->name = name;
106 ot->idname = idname;
107 ot->description = description;
109 ot->flag = OPTYPE_UNDO;
110
111 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
112 PointerRNA node_ptr = get_active_node_to_operate_on(C, Accessor::node_idname);
113 bNode &node = *static_cast<bNode *>(node_ptr.data);
114 const int index_to_remove = RNA_int_get(op->ptr, "index");
115 SocketItemsRef ref = Accessor::get_items_from_node(node);
117 ref.items, ref.items_num, ref.active_index, index_to_remove, Accessor::destruct_item);
118
119 update_after_node_change(C, node_ptr);
120 return OPERATOR_FINISHED;
121 };
122
123 RNA_def_int(ot->srna, "index", 0, 0, INT32_MAX, "Index", "Index to remove", 0, INT32_MAX);
124}
125
126template<typename Accessor>
128 const char *name,
129 const char *idname,
130 const char *description)
131{
132 ot->name = name;
133 ot->idname = idname;
134 ot->description = description;
136 ot->flag = OPTYPE_UNDO;
137
138 ot->exec = [](bContext *C, wmOperator * /*op*/) -> wmOperatorStatus {
139 PointerRNA node_ptr = get_active_node_to_operate_on(C, Accessor::node_idname);
140 bNode &node = *static_cast<bNode *>(node_ptr.data);
141 SocketItemsRef ref = Accessor::get_items_from_node(node);
142 const typename Accessor::ItemT *active_item = nullptr;
143 int dst_index = *ref.items_num;
144 if (ref.active_index) {
145 const int old_active_index = *ref.active_index;
146 if (old_active_index >= 0 && old_active_index < *ref.items_num) {
147 active_item = &(*ref.items)[old_active_index];
148 dst_index = active_item ? old_active_index + 1 : *ref.items_num;
149 }
150 }
151
152 if constexpr (Accessor::has_type && Accessor::has_name) {
153 std::string name = active_item ? active_item->name : "";
154 if constexpr (Accessor::has_custom_initial_name) {
155 name = Accessor::custom_initial_name(node, name);
156 }
158 node,
159 active_item ?
160 Accessor::get_socket_type(*active_item) :
161 (Accessor::supports_socket_type(SOCK_GEOMETRY) ? SOCK_GEOMETRY : SOCK_FLOAT),
162 /* Empty name so it is based on the type. */
163 name.c_str());
164 }
165 else if constexpr (!Accessor::has_type && Accessor::has_name) {
166 socket_items::add_item_with_name<Accessor>(node, active_item ? active_item->name : "");
167 }
168 else if constexpr (!Accessor::has_type && !Accessor::has_name) {
170 }
171 else {
173 }
174
175 dna::array::move_index(*ref.items, *ref.items_num, *ref.items_num - 1, dst_index);
176 if (ref.active_index) {
177 *ref.active_index = dst_index;
178 }
179
180 update_after_node_change(C, node_ptr);
181 return OPERATOR_FINISHED;
182 };
183}
184
185enum class MoveDirection {
186 Up = 0,
187 Down = 1,
188};
189
190template<typename Accessor>
192 const char *name,
193 const char *idname,
194 const char *description)
195{
196 ot->name = name;
197 ot->idname = idname;
198 ot->description = description;
200 ot->flag = OPTYPE_UNDO;
201
202 ot->exec = [](bContext *C, wmOperator *op) -> wmOperatorStatus {
203 PointerRNA node_ptr = get_active_node_to_operate_on(C, Accessor::node_idname);
204 bNode &node = *static_cast<bNode *>(node_ptr.data);
205 const MoveDirection direction = MoveDirection(RNA_enum_get(op->ptr, "direction"));
206
207 SocketItemsRef ref = Accessor::get_items_from_node(node);
208 const int old_active_index = *ref.active_index;
209 if (direction == MoveDirection::Up && old_active_index > 0) {
210 dna::array::move_index(*ref.items, *ref.items_num, old_active_index, old_active_index - 1);
211 *ref.active_index -= 1;
212 }
213 else if (direction == MoveDirection::Down && old_active_index < *ref.items_num - 1) {
214 dna::array::move_index(*ref.items, *ref.items_num, old_active_index, old_active_index + 1);
215 *ref.active_index += 1;
216 }
217
218 update_after_node_change(C, node_ptr);
219 return OPERATOR_FINISHED;
220 };
221
222 static const EnumPropertyItem direction_items[] = {
223 {int(MoveDirection::Up), "UP", 0, "Up", ""},
224 {int(MoveDirection::Down), "DOWN", 0, "Down", ""},
225 {0, nullptr, 0, nullptr, nullptr},
226 };
227
228 RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Move direction");
229}
230
236template<typename Accessor> inline void make_common_operators()
237{
240 "Add Item",
241 Accessor::operator_idnames::add_item.c_str(),
242 "Add item below active item");
243 });
246 ot, "Remove Item", Accessor::operator_idnames::remove_item.c_str(), "Remove active item");
247 });
250 ot, "Move Item", Accessor::operator_idnames::move_item.c_str(), "Move active item");
251 });
252}
253
254} // 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
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
#define NC_NODE
Definition WM_types.hh:391
#define NA_EDITED
Definition WM_types.hh:581
@ OPTYPE_UNDO
Definition WM_types.hh:182
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
#define INT32_MAX
#define ID_IS_EDITABLE(_id)
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4957
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 move_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
PointerRNA get_active_node_to_operate_on(bContext *C, const StringRef node_idname)
void remove_active_item(wmOperatorType *ot, const char *name, const char *idname, const char *description)
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(bNode &node, const eNodeSocketDatatype socket_type, const char *name)
const PointerRNA PointerRNA_NULL
int RNA_int_get(PointerRNA *ptr, const char *name)
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]
char idname[64]
int32_t identifier
void WM_main_add_notifier(uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))