Nodes: support expanded menus in node group interface

Previously, menu sockets were always drawn as dropdown. This patch adds the
ability to draw them expanded instead.

As before, in the node editor, only the expanded menu is drawn, without the
label. There is simply not enough space for both. However, in the modifier and
operator settings the label is drawn currently. We'll probably need to add a
separate `Hide Label` option (similar to `Hide Value`) for group inputs that
support it. That would also help a lot with e.g. object sockets.

Pull Request: https://projects.blender.org/blender/blender/pulls/138387
This commit is contained in:
Jacques Lucke
2025-05-08 04:31:09 +02:00
parent 156a405dd5
commit 8a42e2b59a
7 changed files with 50 additions and 1 deletions

View File

@@ -892,6 +892,15 @@ static void draw_property_for_socket(const bNodeTree &node_tree,
case SOCK_IMAGE:
uiItemPointerR(row, op_ptr, rna_path, bmain_ptr, "images", name, ICON_IMAGE);
break;
case SOCK_MENU: {
if (socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED) {
uiItemR(row, op_ptr, rna_path, UI_ITEM_R_EXPAND, name, ICON_NONE);
}
else {
uiItemR(row, op_ptr, rna_path, UI_ITEM_NONE, name, ICON_NONE);
}
break;
}
default:
if (nodes::input_has_attribute_toggle(node_tree, socket_index)) {
add_attribute_search_or_value_buttons(row, op_ptr, socket_id_esc, rna_path, socket);

View File

@@ -68,6 +68,7 @@
#include "NOD_node_declaration.hh"
#include "NOD_partial_eval.hh"
#include "NOD_socket.hh"
#include "NOD_socket_declarations.hh"
#include "node_intern.hh" /* own include */
namespace blender::ed::space_node {
@@ -1374,6 +1375,14 @@ static void std_node_socket_draw(
uiItemL(row, IFACE_("No Items"), ICON_NONE);
}
else {
if (const auto *socket_decl = dynamic_cast<const nodes::decl::Menu *>(
sock->runtime->declaration))
{
if (socket_decl->is_expanded) {
uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
break;
}
}
uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
}
@@ -1496,6 +1505,7 @@ static void std_node_socket_interface_draw(ID *id,
}
case SOCK_MENU: {
uiItemR(col, &ptr, "default_value", DEFAULT_FLAGS, IFACE_("Default"), ICON_NONE);
uiItemR(col, &ptr, "menu_expanded", DEFAULT_FLAGS, IFACE_("Expanded"), ICON_NONE);
break;
}
case SOCK_SHADER:

View File

@@ -67,6 +67,8 @@ typedef enum NodeTreeInterfaceSocketFlag {
NODE_INTERFACE_SOCKET_INSPECT = 1 << 7,
/* Socket is used in the panel header as a toggle. */
NODE_INTERFACE_SOCKET_PANEL_TOGGLE = 1 << 8,
/* Menu socket should be drawn expanded instead of as drop-down menu. */
NODE_INTERFACE_SOCKET_MENU_EXPANDED = 1 << 9,
} NodeTreeInterfaceSocketFlag;
ENUM_OPERATORS(NodeTreeInterfaceSocketFlag, NODE_INTERFACE_SOCKET_PANEL_TOGGLE);

View File

@@ -1054,6 +1054,13 @@ static void rna_def_node_interface_socket(BlenderRNA *brna)
prop, "Layer Selection", "Take Grease Pencil Layer or Layer Group as selection field");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeTreeInterfaceItem_update");
prop = RNA_def_property(srna, "menu_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flag", NODE_INTERFACE_SOCKET_MENU_EXPANDED);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop, "Menu Expanded", "Draw the menu socket as an expanded drop-down menu");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeTreeInterfaceItem_update");
prop = RNA_def_property(srna, "attribute_domain", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
RNA_def_property_enum_funcs(

View File

@@ -2387,6 +2387,15 @@ static void draw_property_for_socket(DrawGroupInputsContext &ctx,
name);
break;
}
case SOCK_MENU: {
if (socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED) {
uiItemR(row, ctx.md_ptr, rna_path, UI_ITEM_R_EXPAND, name, ICON_NONE);
}
else {
uiItemR(row, ctx.md_ptr, rna_path, UI_ITEM_NONE, name, ICON_NONE);
}
break;
}
case SOCK_BOOLEAN: {
if (is_layer_selection_field(socket)) {
add_layer_name_search_button(ctx, row, socket_id_esc, socket);

View File

@@ -222,6 +222,7 @@ class Menu : public SocketDeclaration {
static constexpr eNodeSocketDatatype static_socket_type = SOCK_MENU;
int32_t default_value;
bool is_expanded = false;
friend MenuBuilder;
@@ -236,6 +237,9 @@ class Menu : public SocketDeclaration {
class MenuBuilder : public SocketDeclarationBuilder<Menu> {
public:
MenuBuilder &default_value(int32_t value);
/** Draw the menu items next to each other instead of as a drop-down menu. */
MenuBuilder &expanded(bool value = true);
};
class BundleBuilder;
@@ -561,6 +565,12 @@ inline MenuBuilder &MenuBuilder::default_value(const int32_t value)
return *this;
}
inline MenuBuilder &MenuBuilder::expanded(const bool value)
{
decl_->is_expanded = value;
return *this;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -325,7 +325,9 @@ static BaseSocketDeclarationBuilder &build_interface_socket_declaration(
}
case SOCK_MENU: {
const auto &value = node_interface::get_socket_data_as<bNodeSocketValueMenu>(io_socket);
decl = &b.add_socket<decl::Menu>(name, identifier, in_out).default_value(value.value);
decl = &b.add_socket<decl::Menu>(name, identifier, in_out)
.default_value(value.value)
.expanded(io_socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED);
break;
}
case SOCK_OBJECT: {