From cd5eb4aa03ee93279d16d4f36ca09a2fc7717dff Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 30 May 2024 10:41:05 +0200 Subject: [PATCH] Geometry Nodes: support renaming some sockets in the node directly This adds support for renaming some sockets in the node UI directly by Ctrl+Clicking on them. This is sometimes more convenient than going to the sidebar. It affects the Menu Switch and Bake node as well as the Simulation and Repeat zone. Some related notes: * The Group Input and Group Output node are not yet supported, because it currently breaks the right-alignment on the Group Input node. I couldn't find a workaround for this yet. * Double-clicking on the socket name does not trigger renaming yet. This seems to be a deeper issue in the interface code. * The highlighting when hovering over sockets that can be renamed is very dim making it hard to see. Alternatives like drawing a box around the label when hovering it (like in list views) have been discussed but seem to be much more difficult to get to work. Despite these limitations, it seems reasonable to add this already, as it shouldn't affect anyone negatively. The nodes still look like before. Co-authored-by: Hans Goudey Pull Request: https://projects.blender.org/blender/blender/pulls/121945 --- .../editors/interface/interface_widgets.cc | 1 + source/blender/editors/space_node/drawnode.cc | 21 +++++++++++++++-- source/blender/nodes/NOD_node_declaration.hh | 23 ++++++++++++++++++- .../nodes/geometry/nodes/node_geo_bake.cc | 5 +++- .../geometry/nodes/node_geo_menu_switch.cc | 6 ++++- .../nodes/geometry/nodes/node_geo_repeat.cc | 9 ++++++-- .../geometry/nodes/node_geo_simulation.cc | 9 ++++++-- .../blender/nodes/intern/node_declaration.cc | 22 ++++++++++++++++++ 8 files changed, 87 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc index ddb829cd41d..37a4f60da06 100644 --- a/source/blender/editors/interface/interface_widgets.cc +++ b/source/blender/editors/interface/interface_widgets.cc @@ -4829,6 +4829,7 @@ void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, * #UI_EMBOSS_NONE_OR_STATUS will blend state colors if they apply. */ switch (but->type) { case UI_BTYPE_LABEL: + case UI_BTYPE_TEXT: wt = widget_type(UI_WTYPE_ICON_LABEL); if (!(but->flag & UI_HAS_ICON)) { but->drawflag |= UI_BUT_NO_TEXT_PADDING; diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 6c482b20a98..0d9937de184 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1305,6 +1305,23 @@ static bool socket_needs_attribute_search(bNode &node, bNodeSocket &socket) return node_decl->inputs[socket_index]->is_attribute_name; } +static void draw_node_socket_without_value(uiLayout *layout, bNodeSocket *sock, const char *text) +{ + if (sock->runtime->declaration) { + if (sock->runtime->declaration->socket_name_rna) { + uiLayoutSetEmboss(layout, UI_EMBOSS_NONE); + uiItemR(layout, + const_cast(&sock->runtime->declaration->socket_name_rna->owner), + sock->runtime->declaration->socket_name_rna->property_name.c_str(), + UI_ITEM_NONE, + "", + ICON_NONE); + return; + } + } + uiItemL(layout, text, ICON_NONE); +} + static void std_node_socket_draw( bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *node_ptr, const char *text) { @@ -1322,7 +1339,7 @@ static void std_node_socket_draw( if ((sock->in_out == SOCK_OUT) || (sock->flag & SOCK_HIDE_VALUE) || ((sock->flag & SOCK_IS_LINKED) && !all_links_muted(*sock))) { - node_socket_button_label(C, layout, ptr, node_ptr, text); + draw_node_socket_without_value(layout, sock, text); return; } @@ -1474,7 +1491,7 @@ static void std_node_socket_draw( break; } default: - node_socket_button_label(C, layout, ptr, node_ptr, text); + draw_node_socket_without_value(layout, sock, text); break; } } diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index 76d8e13d1f2..178b698e9ef 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -16,9 +16,10 @@ #include "DNA_node_types.h" +#include "RNA_types.hh" + struct bContext; struct bNode; -struct PointerRNA; struct uiLayout; namespace blender::nodes { @@ -158,6 +159,11 @@ class ItemDeclaration { using ItemDeclarationPtr = std::unique_ptr; +struct SocketNameRNA { + PointerRNA owner = PointerRNA_NULL; + std::string property_name; +}; + /** * Describes a single input or output socket. This is subclassed for different socket types. */ @@ -206,6 +212,11 @@ class SocketDeclaration : public ItemDeclaration { /** Some input sockets can have non-trivial values in the case when they are unlinked. This * callback computes the default input of a values in geometry nodes when nothing is linked. */ std::unique_ptr implicit_input_fn; + /** + * Property that stores the name of the socket so that it can be modified directly from the + * node without going to the side-bar. + */ + std::unique_ptr socket_name_rna; friend NodeDeclarationBuilder; friend class BaseSocketDeclarationBuilder; @@ -363,6 +374,16 @@ class BaseSocketDeclarationBuilder { */ BaseSocketDeclarationBuilder &align_with_previous(bool value = true); + /** + * Set a function that retrieves an RNA pointer to the name of the socket. This can be used to be + * able to rename the socket within the node. + */ + BaseSocketDeclarationBuilder &socket_name_ptr(PointerRNA ptr, StringRef property_name); + BaseSocketDeclarationBuilder &socket_name_ptr(const ID *id, + const StructRNA *srna, + const void *data, + StringRef property_name); + /** Index in the list of inputs or outputs. */ int index() const; diff --git a/source/blender/nodes/geometry/nodes/node_geo_bake.cc b/source/blender/nodes/geometry/nodes/node_geo_bake.cc index 2dc1693230c..f3af3cc8c14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bake.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bake.cc @@ -45,6 +45,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.use_custom_socket_order(); b.allow_any_socket_order(); + const bNodeTree *ntree = b.tree_or_null(); const bNode *node = b.node_or_null(); if (!node) { return; @@ -56,7 +57,9 @@ static void node_declare(NodeDeclarationBuilder &b) const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type); const StringRef name = item.name; const std::string identifier = BakeItemsAccessor::socket_identifier_for_item(item); - auto &input_decl = b.add_input(socket_type, name, identifier); + auto &input_decl = b.add_input(socket_type, name, identifier) + .socket_name_ptr( + &ntree->id, BakeItemsAccessor::item_srna, &item, "name"); auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous(); if (socket_type_supports_fields(socket_type)) { input_decl.supports_field(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_menu_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_menu_switch.cc index 9ba153303b1..94758f7214a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_menu_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_menu_switch.cc @@ -54,6 +54,7 @@ static bool is_supported_socket_type(const eNodeSocketDatatype data_type) static void node_declare(blender::nodes::NodeDeclarationBuilder &b) { + const bNodeTree *ntree = b.tree_or_null(); const bNode *node = b.node_or_null(); if (node == nullptr) { return; @@ -69,7 +70,10 @@ static void node_declare(blender::nodes::NodeDeclarationBuilder &b) for (const NodeEnumItem &enum_item : storage.enum_definition.items()) { const std::string identifier = MenuSwitchItemsAccessor::socket_identifier_for_item(enum_item); - auto &input = b.add_input(data_type, enum_item.name, std::move(identifier)); + auto &input = b.add_input(data_type, enum_item.name, std::move(identifier)) + .socket_name_ptr( + &ntree->id, MenuSwitchItemsAccessor::item_srna, &enum_item, "name"); + ; if (supports_fields) { input.supports_field(); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_repeat.cc b/source/blender/nodes/geometry/nodes/node_geo_repeat.cc index a8ea212e8fc..d30df4566e3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_repeat.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_repeat.cc @@ -140,7 +140,9 @@ static void node_declare(NodeDeclarationBuilder &b) const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type); const StringRef name = item.name ? item.name : ""; const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item); - auto &input_decl = b.add_input(socket_type, name, identifier); + auto &input_decl = b.add_input(socket_type, name, identifier) + .socket_name_ptr( + &tree->id, RepeatItemsAccessor::item_srna, &item, "name"); auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous(); if (socket_type_supports_fields(socket_type)) { input_decl.supports_field(); @@ -206,6 +208,7 @@ static void node_declare(NodeDeclarationBuilder &b) { b.use_custom_socket_order(); b.allow_any_socket_order(); + const bNodeTree *tree = b.tree_or_null(); const bNode *node = b.node_or_null(); if (node) { const NodeGeometryRepeatOutput &storage = node_storage(*node); @@ -214,7 +217,9 @@ static void node_declare(NodeDeclarationBuilder &b) const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type); const StringRef name = item.name ? item.name : ""; const std::string identifier = RepeatItemsAccessor::socket_identifier_for_item(item); - auto &input_decl = b.add_input(socket_type, name, identifier); + auto &input_decl = b.add_input(socket_type, name, identifier) + .socket_name_ptr( + &tree->id, RepeatItemsAccessor::item_srna, &item, "name"); auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous(); if (socket_type_supports_fields(socket_type)) { input_decl.supports_field(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_simulation.cc b/source/blender/nodes/geometry/nodes/node_geo_simulation.cc index 4f98f83813d..67da84ff592 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_simulation.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_simulation.cc @@ -633,7 +633,9 @@ static void node_declare(NodeDeclarationBuilder &b) const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type); const StringRef name = item.name; const std::string identifier = SimulationItemsAccessor::socket_identifier_for_item(item); - auto &input_decl = b.add_input(socket_type, name, identifier); + auto &input_decl = b.add_input(socket_type, name, identifier) + .socket_name_ptr( + &node_tree->id, SimulationItemsAccessor::item_srna, &item, "name"); auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous(); if (socket_type_supports_fields(socket_type)) { input_decl.supports_field(); @@ -960,6 +962,7 @@ static void node_declare(NodeDeclarationBuilder &b) "Forward the output of the simulation input node directly to the output node and ignore " "the nodes in the simulation zone"); + const bNodeTree *tree = b.tree_or_null(); const bNode *node = b.node_or_null(); if (node == nullptr) { return; @@ -972,7 +975,9 @@ static void node_declare(NodeDeclarationBuilder &b) const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type); const StringRef name = item.name; const std::string identifier = SimulationItemsAccessor::socket_identifier_for_item(item); - auto &input_decl = b.add_input(socket_type, name, identifier); + auto &input_decl = b.add_input(socket_type, name, identifier) + .socket_name_ptr( + &tree->id, SimulationItemsAccessor::item_srna, &item, "name"); auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous(); if (socket_type_supports_fields(socket_type)) { input_decl.supports_field(); diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index 53036cd56d7..df2c2c874b2 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -14,6 +14,8 @@ #include "BKE_node_runtime.hh" #include "BKE_node_socket_value.hh" +#include "RNA_access.hh" + namespace blender::nodes { static void reset_declaration(NodeDeclaration &declaration) @@ -734,6 +736,26 @@ BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::align_with_previous( return *this; } +BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder ::socket_name_ptr( + const PointerRNA ptr, const StringRef property_name) +{ + decl_base_->socket_name_rna = std::make_unique(); + decl_base_->socket_name_rna->owner = ptr; + decl_base_->socket_name_rna->property_name = property_name; + return *this; +} + +BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder::socket_name_ptr( + const ID *id, const StructRNA *srna, const void *data, StringRef property_name) +{ + /* Doing const-casts here because this data is generally only available as const when creating + * the declaration, but it's still valid to modify later. */ + return this->socket_name_ptr(RNA_pointer_create(const_cast(id), + const_cast(srna), + const_cast(data)), + property_name); +} + OutputFieldDependency OutputFieldDependency::ForFieldSource() { OutputFieldDependency field_dependency;