From 8a42e2b59a732af425b01a4ea0b0a7150b13a024 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 8 May 2025 04:31:09 +0200 Subject: [PATCH] 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 --- source/blender/editors/geometry/node_group_operator.cc | 9 +++++++++ source/blender/editors/space_node/drawnode.cc | 10 ++++++++++ .../blender/makesdna/DNA_node_tree_interface_types.h | 2 ++ .../blender/makesrna/intern/rna_node_tree_interface.cc | 7 +++++++ source/blender/modifiers/intern/MOD_nodes.cc | 9 +++++++++ source/blender/nodes/NOD_socket_declarations.hh | 10 ++++++++++ source/blender/nodes/intern/node_common.cc | 4 +++- 7 files changed, 50 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/geometry/node_group_operator.cc b/source/blender/editors/geometry/node_group_operator.cc index f26af1472c9..9ad1473dbe1 100644 --- a/source/blender/editors/geometry/node_group_operator.cc +++ b/source/blender/editors/geometry/node_group_operator.cc @@ -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); diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index cba43fea24c..967b48d1d87 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -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( + 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: diff --git a/source/blender/makesdna/DNA_node_tree_interface_types.h b/source/blender/makesdna/DNA_node_tree_interface_types.h index d060c2613d1..e9d55905175 100644 --- a/source/blender/makesdna/DNA_node_tree_interface_types.h +++ b/source/blender/makesdna/DNA_node_tree_interface_types.h @@ -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); diff --git a/source/blender/makesrna/intern/rna_node_tree_interface.cc b/source/blender/makesrna/intern/rna_node_tree_interface.cc index 1df1fd64d75..58684776322 100644 --- a/source/blender/makesrna/intern/rna_node_tree_interface.cc +++ b/source/blender/makesrna/intern/rna_node_tree_interface.cc @@ -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( diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index ca3b5465058..d3913c34a62 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -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); diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh index d2e13fcc66c..6a9386962c6 100644 --- a/source/blender/nodes/NOD_socket_declarations.hh +++ b/source/blender/nodes/NOD_socket_declarations.hh @@ -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 { 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; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index 64521b0e65f..b0f16b81707 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -325,7 +325,9 @@ static BaseSocketDeclarationBuilder &build_interface_socket_declaration( } case SOCK_MENU: { const auto &value = node_interface::get_socket_data_as(io_socket); - decl = &b.add_socket(name, identifier, in_out).default_value(value.value); + decl = &b.add_socket(name, identifier, in_out) + .default_value(value.value) + .expanded(io_socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED); break; } case SOCK_OBJECT: {