Fix #115727: Draw panel buttons in the node editor side bar #116936

Merged
Lukas Tönne merged 4 commits from LukasTonne/blender:node-sidebar-panel-buttons into main 2024-01-16 13:38:07 +01:00
6 changed files with 206 additions and 24 deletions
Showing only changes of commit 24d8a47f68 - Show all commits

View File

@ -705,31 +705,32 @@ class NODE_PT_active_node_properties(Panel):
def draw(self, context):
layout = self.layout
node = context.active_node
# set "node" context pointer for the panel layout
layout.context_pointer_set("node", node)
layout.template_node_inputs(node)
# # set "node" context pointer for the panel layout
# layout.context_pointer_set("node", node)
if hasattr(node, "draw_buttons_ext"):
node.draw_buttons_ext(context, layout)
elif hasattr(node, "draw_buttons"):
node.draw_buttons(context, layout)
# if hasattr(node, "draw_buttons_ext"):
# node.draw_buttons_ext(context, layout, draw_panel_buttons=True)
# elif hasattr(node, "draw_buttons"):
# node.draw_buttons(context, layout, draw_panel_buttons=True)
# XXX this could be filtered further to exclude socket types
# which don't have meaningful input values (e.g. cycles shader)
value_inputs = [socket for socket in node.inputs if self.show_socket_input(socket)]
if value_inputs:
layout.separator()
layout.label(text="Inputs:")
for socket in value_inputs:
row = layout.row()
socket.draw(
context,
row,
node,
iface_(socket.label if socket.label else socket.name, socket.bl_rna.translation_context),
)
# # XXX this could be filtered further to exclude socket types
# # which don't have meaningful input values (e.g. cycles shader)
# value_inputs = [socket for socket in node.inputs if self.show_socket_input(socket)]
# if value_inputs:
# layout.separator()
# layout.label(text="Inputs:")
# for socket in value_inputs:
# row = layout.row()
# socket.draw(
# context,
# row,
# node,
# iface_(socket.label if socket.label else socket.name, socket.bl_rna.translation_context),
# )
def show_socket_input(self, socket):
return hasattr(socket, "draw") and socket.enabled and not socket.is_linked
# def show_socket_input(self, socket):
# return hasattr(socket, "draw") and socket.enabled and not socket.is_linked
class NODE_PT_texture_mapping(Panel):

View File

@ -2712,6 +2712,10 @@ void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C);
#endif
void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr);
/**
* Draw all node buttons and socket default values with the same panel structure used by the node.
*/
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr);
/**
* \return: A RNA pointer for the operator properties.

View File

@ -70,6 +70,7 @@ set(SRC
interface_template_bone_collection_tree.cc
interface_template_light_linking.cc
interface_template_list.cc
interface_template_node_inputs.cc
interface_template_node_tree_interface.cc
interface_template_search_menu.cc
interface_template_search_operator.cc

View File

@ -0,0 +1,128 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edinterface
*/
#include "BLI_vector.hh"
#include "BKE_context.hh"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BLT_translation.h"
#include "NOD_node_declaration.hh"
#include "RNA_access.hh"
#include "RNA_prototypes.h"
#include "UI_interface.hh"
#include "UI_resources.hh"
/* -------------------------------------------------------------------- */
/** \name Node Input Buttons Template
* \{ */
using blender::nodes::ItemDeclaration;
using blender::nodes::NodeDeclaration;
using blender::nodes::PanelDeclaration;
using blender::nodes::SocketDeclaration;
using ItemIterator = blender::Vector<blender::nodes::ItemDeclarationPtr>::const_iterator;
namespace blender::ui::nodes {
static void draw_node_input(bContext *C,
uiLayout *layout,
PointerRNA *node_ptr,
bNodeSocket &socket)
{
BLI_assert(socket.typeinfo != nullptr);
/* Ignore disabled sockets and linked sockets and sockets without a `draw` callback. */
if (!socket.is_available() || (socket.flag & SOCK_IS_LINKED) || socket.typeinfo->draw == nullptr)
{
return;
}
PointerRNA socket_ptr = RNA_pointer_create(node_ptr->owner_id, &RNA_NodeSocket, &socket);
const char *text = IFACE_(bke::nodeSocketLabel(&socket));
socket.typeinfo->draw(C, layout, &socket_ptr, node_ptr, text);
}
static void draw_node_input(bContext *C,
uiLayout *layout,
PointerRNA *node_ptr,
StringRefNull identifier)
{
bNode &node = *static_cast<bNode *>(node_ptr->data);
bNodeSocket *socket = node.runtime->inputs_by_identifier.lookup(identifier);
draw_node_input(C, layout, node_ptr, *socket);
}
static void draw_node_declaration_items(bContext *C,
uiLayout *layout,
PointerRNA *node_ptr,
ItemIterator &item_iter,
const ItemIterator item_end)
{
while (item_iter != item_end) {
const ItemDeclaration *item_decl = item_iter->get();
++item_iter;
if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl))
{
if (socket_decl->in_out == SOCK_IN) {
draw_node_input(C, layout, node_ptr, socket_decl->identifier);
}
}
else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
item_decl))
{
/* Draw panel buttons at the top of each panel section. */
if (panel_decl->draw_buttons) {
panel_decl->draw_buttons(layout, C, node_ptr);
}
const ItemIterator panel_item_end = item_iter + panel_decl->num_child_decls;
BLI_assert(panel_item_end <= item_end);
draw_node_declaration_items(C, layout, node_ptr, item_iter, panel_item_end);
}
}
}
} // namespace blender::ui::nodes
void uiTemplateNodeInputs(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
bNode &node = *static_cast<bNode *>(ptr->data);
tree.ensure_topology_cache();
BLI_assert(node.typeinfo != nullptr);
/* Draw top-level node buttons. */
if (node.typeinfo->draw_buttons_ex) {
node.typeinfo->draw_buttons_ex(layout, C, ptr);
}
else if (node.typeinfo->draw_buttons) {
node.typeinfo->draw_buttons(layout, C, ptr);
}
if (node.declaration()) {
/* Draw socket inputs and panel buttons in the order of declaration panels. */
ItemIterator item_iter = node.declaration()->items.begin();
const ItemIterator item_end = node.declaration()->items.end();
blender::ui::nodes::draw_node_declaration_items(C, layout, ptr, item_iter, item_end);
}
else {
/* Draw socket values using the flat inputs list. */
for (bNodeSocket *input : node.runtime->inputs) {
blender::ui::nodes::draw_node_input(C, layout, ptr, *input);
}
}
}
/** \} */

View File

@ -602,8 +602,10 @@ static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
# include "NOD_common.h"
# include "NOD_composite.hh"
# include "NOD_geometry.hh"
# include "NOD_node_declaration.hh"
# include "NOD_shader.h"
# include "NOD_socket.hh"
# include "NOD_socket_declarations.hh"
# include "NOD_socket_items.hh"
# include "NOD_texture.h"
# include "NOD_zone_socket_items.hh"
@ -2515,15 +2517,43 @@ static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain)
ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
static void rna_NodeInternal_draw_buttons(ID *id, bNode *node, bContext *C, uiLayout *layout)
static void rna_NodeInternal_draw_panel_buttons(ID *id, bNode *node, bContext *C, uiLayout *layout)
{
using blender::nodes::ItemDeclarationPtr;
using blender::nodes::NodeDeclaration;
using blender::nodes::PanelDeclaration;
if (!node->declaration()) {
return;
}
PointerRNA ptr = RNA_pointer_create(id, &RNA_Node, node);
for (const ItemDeclarationPtr &item_decl : node->declaration()->items) {
if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
item_decl.get()))
{
if (panel_decl->draw_buttons) {
panel_decl->draw_buttons(layout, C, &ptr);
}
}
}
}
static void rna_NodeInternal_draw_buttons(
ID *id, bNode *node, bContext *C, uiLayout *layout, bool draw_panel_buttons)
{
if (node->typeinfo->draw_buttons) {
PointerRNA ptr = RNA_pointer_create(id, &RNA_Node, node);
node->typeinfo->draw_buttons(layout, C, &ptr);
}
if (draw_panel_buttons) {
rna_NodeInternal_draw_panel_buttons(id, node, C, layout);
}
}
static void rna_NodeInternal_draw_buttons_ext(ID *id, bNode *node, bContext *C, uiLayout *layout)
static void rna_NodeInternal_draw_buttons_ext(
ID *id, bNode *node, bContext *C, uiLayout *layout, bool draw_panel_buttons)
{
if (node->typeinfo->draw_buttons_ex) {
PointerRNA ptr = RNA_pointer_create(id, &RNA_Node, node);
@ -2533,6 +2563,10 @@ static void rna_NodeInternal_draw_buttons_ext(ID *id, bNode *node, bContext *C,
PointerRNA ptr = RNA_pointer_create(id, &RNA_Node, node);
node->typeinfo->draw_buttons(layout, C, &ptr);
}
if (draw_panel_buttons) {
rna_NodeInternal_draw_panel_buttons(id, node, C, layout);
}
}
static StructRNA *rna_NodeCustomGroup_register(Main *bmain,
@ -9606,6 +9640,10 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "draw_panel_buttons", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_default(parm, false);
RNA_def_property_ui_text(
parm, "Draw Panel Buttons", "Draw buttons from panels as well as top-level buttons");
/* draw buttons extended */
func = RNA_def_function(srna, "draw_buttons_ext", "rna_NodeInternal_draw_buttons_ext");
@ -9617,6 +9655,10 @@ static void rna_def_internal_node(BlenderRNA *brna)
RNA_def_property_struct_type(parm, "UILayout");
RNA_def_property_ui_text(parm, "Layout", "Layout in the UI");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_property(func, "draw_panel_buttons", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_default(parm, false);
RNA_def_property_ui_text(
parm, "Draw Panel Buttons", "Draw buttons from panels as well as top-level buttons");
}
static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out)

View File

@ -2205,6 +2205,12 @@ void RNA_api_ui_layout(StructRNA *srna)
"Node Tree Interface",
"Interface of a node tree to display");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_node_inputs", "uiTemplateNodeInputs");
RNA_def_function_ui_description(func, "Show a node settings and input socket values");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "node", "Node", "Node", "Display inputs of this node");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
#endif