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: {