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 <hans@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/121945
This commit is contained in:
Jacques Lucke
2024-05-30 10:41:05 +02:00
parent 7a11fad380
commit cd5eb4aa03
8 changed files with 87 additions and 9 deletions

View File

@@ -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;

View File

@@ -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<PointerRNA *>(&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;
}
}

View File

@@ -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<ItemDeclaration>;
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<ImplicitInputValueFn> 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<SocketNameRNA> 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;

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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<SocketNameRNA>();
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 *>(id),
const_cast<StructRNA *>(srna),
const_cast<void *>(data)),
property_name);
}
OutputFieldDependency OutputFieldDependency::ForFieldSource()
{
OutputFieldDependency field_dependency;