Blender V4.5
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"
24#include "UI_resources.hh"
25
26/* -------------------------------------------------------------------- */
29
35
37
39
41 uiLayout *layout,
42 PointerRNA *node_ptr,
43 bNodeSocket &socket)
44{
45 BLI_assert(socket.typeinfo != nullptr);
46 /* Ignore disabled sockets and linked sockets and sockets without a `draw` callback. */
47 if (!socket.is_available()) {
48 return;
49 }
50 if (socket.is_directly_linked()) {
51 return;
52 }
53 if (socket.flag & SOCK_HIDE_VALUE) {
54 return;
55 }
56 if (socket.typeinfo->draw == nullptr) {
57 return;
58 }
60 return;
61 }
62 const bNode &node = *static_cast<bNode *>(node_ptr->data);
63 if (node.is_reroute()) {
64 return;
65 }
66 if (socket.idname == StringRef("NodeSocketVirtual")) {
67 return;
68 }
69
71 node_ptr->owner_id, &RNA_NodeSocket, &socket);
72 const StringRefNull text(IFACE_(bke::node_socket_label(socket).c_str()));
73 uiLayout *row = &layout->row(true);
74 socket.typeinfo->draw(C, row, &socket_ptr, node_ptr, text);
75}
76
77static bool panel_has_used_inputs(const bNode &node,
78 const blender::nodes::PanelDeclaration &panel_decl)
79{
80 for (const blender::nodes::ItemDeclaration *item_decl : panel_decl.items) {
81 if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
82 if (socket_decl->in_out == SOCK_OUT) {
83 continue;
84 }
85 const bNodeSocket &socket = node.socket_by_decl(*socket_decl);
86 if (!socket.is_inactive()) {
87 return true;
88 }
89 }
90 else if (const auto *sub_panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
91 if (panel_has_used_inputs(node, *sub_panel_decl)) {
92 return true;
93 }
94 }
95 }
96 return false;
97}
98
100 uiLayout *layout,
101 bNode &node,
102 PointerRNA *node_ptr,
103 const blender::nodes::PanelDeclaration &panel_decl)
104{
105 /* TODO: Use flag on the panel state instead which is better for dynamic panel amounts. */
106 const std::string panel_idname = "NodePanel" + std::to_string(panel_decl.identifier);
107 PanelLayout panel = layout->panel(C, panel_idname, panel_decl.default_collapsed);
108 const bool has_used_inputs = panel_has_used_inputs(node, panel_decl);
109 uiLayoutSetActive(panel.header, has_used_inputs);
110
111 const char *panel_translation_context = (panel_decl.translation_context.has_value() ?
112 panel_decl.translation_context->c_str() :
113 nullptr);
114 panel.header->label(CTX_IFACE_(panel_translation_context, panel_decl.name), ICON_NONE);
115 if (!panel.body) {
116 return;
117 }
118 for (const ItemDeclaration *item_decl : panel_decl.items) {
119 if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
120 if (socket_decl->in_out == SOCK_IN) {
121 draw_node_input(C, panel.body, node_ptr, node.socket_by_decl(*socket_decl));
122 }
123 }
124 else if (const auto *sub_panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
125 draw_node_inputs_recursive(C, panel.body, node, node_ptr, *sub_panel_decl);
126 }
127 else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
128 if (!layout_decl->is_default) {
129 layout_decl->draw(panel.body, C, node_ptr);
130 }
131 }
132 }
133}
134
135} // namespace blender::ui::nodes
136
138{
139 using namespace blender::nodes;
140 bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
141 bNode &node = *static_cast<bNode *>(ptr->data);
142
143 tree.ensure_topology_cache();
144
145 BLI_assert(node.typeinfo != nullptr);
146 /* Draw top-level node buttons. */
147 if (node.typeinfo->draw_buttons_ex) {
148 node.typeinfo->draw_buttons_ex(layout, C, ptr);
149 }
150 else if (node.typeinfo->draw_buttons) {
151 node.typeinfo->draw_buttons(layout, C, ptr);
152 }
153
154 if (node.declaration()) {
155 /* Draw socket inputs and panel buttons in the order of declaration panels. */
156 const NodeDeclaration &node_decl = *node.declaration();
157 for (const ItemDeclaration *item_decl : node_decl.root_items) {
158 if (const auto *panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
159 blender::ui::nodes::draw_node_inputs_recursive(C, layout, node, ptr, *panel_decl);
160 }
161 else if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
162 bNodeSocket &socket = node.socket_by_decl(*socket_decl);
163 if (socket_decl->custom_draw_fn) {
165 *C,
166 *layout,
167 tree,
168 node,
169 socket,
170 *ptr,
171 RNA_pointer_create_discrete(ptr->owner_id, &RNA_NodeSocket, &socket)};
172 (*socket_decl->custom_draw_fn)(params);
173 }
174 else if (socket_decl->in_out == SOCK_IN) {
175 blender::ui::nodes::draw_node_input(C, layout, ptr, socket);
176 }
177 }
178 else if (const auto *layout_decl = dynamic_cast<const LayoutDeclaration *>(item_decl)) {
179 if (!layout_decl->is_default) {
180 layout_decl->draw(layout, C, ptr);
181 }
182 }
183 }
184 }
185 else {
186 /* Draw socket values using the flat inputs list. */
187 for (bNodeSocket *input : node.runtime->inputs) {
189 }
190 }
191}
192
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
@ SOCK_CLOSURE
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
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]
StringRefNull node_socket_label(const bNodeSocket &sock)
Definition node.cc:5268
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)
uiLayout & row(bool align)
PointerRNA * ptr
Definition wm_files.cc:4226