Blender V5.0
interface_template_node_inputs.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
8
9#include "BLI_vector.hh"
10
11#include "BKE_context.hh"
12#include "BKE_node.hh"
13#include "BKE_node_runtime.hh"
14#include "BKE_screen.hh"
15
16#include "BLT_translation.hh"
17
19
20#include "RNA_access.hh"
21#include "RNA_prototypes.hh"
22
23#include "UI_interface.hh"
25#include "UI_resources.hh"
26
27/* -------------------------------------------------------------------- */
30
36
38
40
42 uiLayout *layout,
43 PointerRNA *node_ptr,
44 bNodeSocket &socket)
45{
46 BLI_assert(socket.typeinfo != nullptr);
47 /* Ignore disabled sockets and linked sockets and sockets without a `draw` callback. */
48 if (!socket.is_available()) {
49 return;
50 }
51 if (socket.is_directly_linked()) {
52 return;
53 }
54 if (socket.flag & SOCK_HIDE_VALUE) {
55 return;
56 }
57 if (socket.typeinfo->draw == nullptr) {
58 return;
59 }
61 return;
62 }
63 const bNode &node = *static_cast<bNode *>(node_ptr->data);
64 if (node.is_reroute()) {
65 return;
66 }
67 if (socket.idname == StringRef("NodeSocketVirtual")) {
68 return;
69 }
70
72 node_ptr->owner_id, &RNA_NodeSocket, &socket);
75 uiLayout *row = &layout->row(true);
76 socket.typeinfo->draw(C, row, &socket_ptr, node_ptr, text);
77}
78
79static bool panel_has_used_inputs(const bNode &node,
80 const blender::nodes::PanelDeclaration &panel_decl)
81{
82 for (const blender::nodes::ItemDeclaration *item_decl : panel_decl.items) {
83 if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
84 if (socket_decl->in_out == SOCK_OUT) {
85 continue;
86 }
87 const bNodeSocket &socket = node.socket_by_decl(*socket_decl);
88 if (!socket.is_inactive()) {
89 return true;
90 }
91 }
92 else if (const auto *sub_panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
93 if (panel_has_used_inputs(node, *sub_panel_decl)) {
94 return true;
95 }
96 }
97 }
98 return false;
99}
100
102 uiLayout *layout,
103 bNode &node,
104 PointerRNA *node_ptr,
105 const blender::nodes::PanelDeclaration &panel_decl)
106{
107 /* TODO: Use flag on the panel state instead which is better for dynamic panel amounts. */
108 const std::string panel_idname = "NodePanel" + std::to_string(panel_decl.identifier);
109 PanelLayout panel = layout->panel(C, panel_idname, panel_decl.default_collapsed);
110 const bool has_used_inputs = panel_has_used_inputs(node, panel_decl);
111 panel.header->active_set(has_used_inputs);
112
113 const char *panel_translation_context = (panel_decl.translation_context.has_value() ?
114 panel_decl.translation_context->c_str() :
115 nullptr);
116 panel.header->label(CTX_IFACE_(panel_translation_context, panel_decl.name), ICON_NONE);
117 if (!panel.body) {
118 return;
119 }
120 for (const ItemDeclaration *item_decl : panel_decl.items) {
121 if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
122 if (socket_decl->in_out == SOCK_IN) {
123 draw_node_input(C, panel.body, node_ptr, node.socket_by_decl(*socket_decl));
124 }
125 }
126 else if (const auto *sub_panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
127 draw_node_inputs_recursive(C, panel.body, node, node_ptr, *sub_panel_decl);
128 }
129 else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
130 if (!layout_decl->is_default) {
131 layout_decl->draw(panel.body, C, node_ptr);
132 }
133 }
134 }
135}
136
137} // namespace blender::ui::nodes
138
140{
141 using namespace blender::nodes;
142 bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
143 bNode &node = *static_cast<bNode *>(ptr->data);
144
145 tree.ensure_topology_cache();
146
147 BLI_assert(node.typeinfo != nullptr);
148 /* Draw top-level node buttons. */
149 if (node.typeinfo->draw_buttons_ex) {
150 node.typeinfo->draw_buttons_ex(layout, C, ptr);
151 }
152 else if (node.typeinfo->draw_buttons) {
153 node.typeinfo->draw_buttons(layout, C, ptr);
154 }
155
156 if (node.declaration()) {
157 /* Draw socket inputs and panel buttons in the order of declaration panels. */
158 const NodeDeclaration &node_decl = *node.declaration();
159 for (const ItemDeclaration *item_decl : node_decl.root_items) {
160 if (const auto *panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
161 blender::ui::nodes::draw_node_inputs_recursive(C, layout, node, ptr, *panel_decl);
162 }
163 else if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
164 bNodeSocket &socket = node.socket_by_decl(*socket_decl);
165 if (socket_decl->custom_draw_fn) {
166 uiLayout &row = layout->row(false);
168 *C,
169 row,
170 tree,
171 node,
172 socket,
173 *ptr,
174 RNA_pointer_create_discrete(ptr->owner_id, &RNA_NodeSocket, &socket)};
175 (*socket_decl->custom_draw_fn)(params);
176 }
177 else if (socket_decl->in_out == SOCK_IN) {
178 blender::ui::nodes::draw_node_input(C, layout, ptr, socket);
179 }
180 }
181 else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
182 if (!layout_decl->is_default) {
183 layout_decl->draw(layout, C, ptr);
184 }
185 }
186 }
187 }
188 else {
189 /* Draw socket values using the flat inputs list. */
190 for (bNodeSocket *input : node.runtime->inputs) {
192 }
193 }
194}
195
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#define CTX_IFACE_(context, msgid)
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
@ SOCK_CLOSURE
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
#define C
Definition RandGen.cpp:29
const T * const_iterator
Definition BLI_vector.hh:84
Vector< ItemDeclaration * > root_items
std::optional< std::string > translation_context
Vector< ItemDeclaration * > items
KDTree_3d * tree
#define input
blender::Vector< blender::nodes::ItemDeclarationPtr >::const_iterator ItemIterator
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
const char * node_socket_translation_context(const bNodeSocket &sock)
Definition node.cc:5001
StringRefNull node_socket_label(const bNodeSocket &sock)
Definition node.cc:4996
static void draw_node_input(bContext *C, uiLayout *layout, PointerRNA *node_ptr, bNodeSocket &socket)
static bool panel_has_used_inputs(const bNode &node, const blender::nodes::PanelDeclaration &panel_decl)
static void draw_node_inputs_recursive(bContext *C, uiLayout *layout, bNode &node, PointerRNA *node_ptr, const blender::nodes::PanelDeclaration &panel_decl)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
bNodeSocketTypeHandle * typeinfo
char idname[64]
bNodeTypeHandle * typeinfo
bNodeRuntimeHandle * runtime
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
void active_set(bool active)
uiLayout & row(bool align)
PointerRNA * ptr
Definition wm_files.cc:4238