From 78315faf8fbd4e700933ec2b4cfb49657905c23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 19 Sep 2023 10:47:21 +0200 Subject: [PATCH] Fix #112490: Always draw socket icons in "hidden" nodes In #112326 the socket visibility functions were updated to take the open/closed state of panels into account for visibility of the socket icon. However, in "hidden" (collapsed) nodes the panels should be ignored entirely, drawing all sockets on the root level. This requires looking at the node flags to determine socket icon visibility, so a simple method of `bNodeSocket` is not sufficient. This patch moves the more complex visibility queries for sockets into `bNode`, where both node and socket flags can be accessed. These should be used for actual visibility rather than the plain flag accessors on `bNodeSocket`. Renamed `is_visible_or_panel_closed` back to just `is_visible`, the other `is_visible` variant is now integrated in `bNode::is_socket_drawn`. Pull Request: https://projects.blender.org/blender/blender/pulls/112520 --- source/blender/blenkernel/BKE_node_runtime.hh | 17 +++++++---- source/blender/blenkernel/intern/node.cc | 3 +- .../blender/editors/space_node/node_draw.cc | 28 ++++++++++--------- .../blender/editors/space_node/node_edit.cc | 4 +-- .../editors/space_node/node_relationships.cc | 16 +++++------ source/blender/makesdna/DNA_node_types.h | 6 +++- .../nodes/geometry/nodes/node_geo_viewer.cc | 2 +- 7 files changed, 43 insertions(+), 33 deletions(-) diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index eeaf7ab1a96..2f4d29f44e3 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -704,6 +704,16 @@ inline blender::Span bNode::internal_links() const return this->runtime->internal_links; } +inline bool bNode::is_socket_drawn(const bNodeSocket &socket) const +{ + return socket.is_visible(); +} + +inline bool bNode::is_socket_icon_drawn(const bNodeSocket &socket) const +{ + return socket.is_visible() && (this->flag & NODE_HIDDEN || !socket.is_panel_collapsed()); +} + inline blender::Span bNode::direct_children_in_frame() const { BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); @@ -794,14 +804,9 @@ inline bool bNodeSocket::is_panel_collapsed() const return (this->flag & SOCK_PANEL_COLLAPSED) != 0; } -inline bool bNodeSocket::is_visible_or_panel_collapsed() const -{ - return !this->is_hidden() && this->is_available(); -} - inline bool bNodeSocket::is_visible() const { - return this->is_visible_or_panel_collapsed() && !this->is_panel_collapsed(); + return !this->is_hidden() && this->is_available(); } inline bNode &bNodeSocket::owner_node() diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a075f7b7ad6..075f455f7e1 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -2756,8 +2756,7 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) bool nodeLinkIsHidden(const bNodeLink *link) { - return !(link->fromsock->is_visible_or_panel_collapsed() && - link->tosock->is_visible_or_panel_collapsed()); + return !(link->fromsock->is_visible() && link->tosock->is_visible()); } namespace blender::bke { diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index cbe2c0f9e64..512e5de5ed6 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -407,8 +407,8 @@ static bool node_update_basis_socket(const bContext &C, const int &locx, int &locy) { - if ((!input_socket || !input_socket->is_visible_or_panel_collapsed()) && - (!output_socket || !output_socket->is_visible_or_panel_collapsed())) + if ((!input_socket || !input_socket->is_visible()) && + (!output_socket || !output_socket->is_visible())) { return false; } @@ -701,7 +701,7 @@ static void node_update_basis_from_declaration( } else { /* Space between items. */ - if (!is_first && item.input->is_visible_or_panel_collapsed()) { + if (!is_first && item.input->is_visible()) { locy -= NODE_SOCKDY; } } @@ -714,7 +714,7 @@ static void node_update_basis_from_declaration( } else { /* Space between items. */ - if (!is_first && item.output->is_visible_or_panel_collapsed()) { + if (!is_first && item.output->is_visible()) { locy -= NODE_SOCKDY; } } @@ -865,12 +865,12 @@ static void node_update_hidden(bNode &node, uiBlock &block) /* Calculate minimal radius. */ for (const bNodeSocket *socket : node.input_sockets()) { - if (socket->is_visible_or_panel_collapsed()) { + if (socket->is_visible()) { totin++; } } for (const bNodeSocket *socket : node.output_sockets()) { - if (socket->is_visible_or_panel_collapsed()) { + if (socket->is_visible()) { totout++; } } @@ -891,7 +891,7 @@ static void node_update_hidden(bNode &node, uiBlock &block) float drad = rad; for (bNodeSocket *socket : node.output_sockets()) { - if (socket->is_visible_or_panel_collapsed()) { + if (socket->is_visible()) { /* Round the socket location to stop it from jiggling. */ socket->runtime->location = { round(node.runtime->totr.xmax - hiddenrad + sinf(rad) * hiddenrad), @@ -904,7 +904,7 @@ static void node_update_hidden(bNode &node, uiBlock &block) rad = drad = -float(M_PI) / (1.0f + float(totin)); for (bNodeSocket *socket : node.input_sockets()) { - if (socket->is_visible_or_panel_collapsed()) { + if (socket->is_visible()) { /* Round the socket location to stop it from jiggling. */ socket->runtime->location = { round(node.runtime->totr.xmin + hiddenrad + sinf(rad) * hiddenrad), @@ -1751,7 +1751,8 @@ static void node_draw_sockets(const View2D &v2d, /* Socket inputs. */ int selected_input_len = 0; for (const bNodeSocket *sock : node.input_sockets()) { - if (!sock->is_visible()) { + /* In "hidden" nodes: draw sockets even when panels are collapsed. */ + if (!node.is_socket_icon_drawn(*sock)) { continue; } if (select_all || (sock->flag & SELECT)) { @@ -1774,7 +1775,8 @@ static void node_draw_sockets(const View2D &v2d, int selected_output_len = 0; if (draw_outputs) { for (const bNodeSocket *sock : node.output_sockets()) { - if (!sock->is_visible()) { + /* In "hidden" nodes: draw sockets even when panels are collapsed. */ + if (!node.is_socket_icon_drawn(*sock)) { continue; } if (select_all || (sock->flag & SELECT)) { @@ -1802,7 +1804,7 @@ static void node_draw_sockets(const View2D &v2d, if (selected_input_len) { /* Socket inputs. */ for (const bNodeSocket *sock : node.input_sockets()) { - if (!sock->is_visible()) { + if (!node.is_socket_icon_drawn(*sock)) { continue; } /* Don't draw multi-input sockets here since they are drawn in a different batch. */ @@ -1831,7 +1833,7 @@ static void node_draw_sockets(const View2D &v2d, if (selected_output_len) { /* Socket outputs. */ for (const bNodeSocket *sock : node.output_sockets()) { - if (!sock->is_visible()) { + if (!node.is_socket_icon_drawn(*sock)) { continue; } if (select_all || (sock->flag & SELECT)) { @@ -1864,7 +1866,7 @@ static void node_draw_sockets(const View2D &v2d, /* Draw multi-input sockets after the others because they are drawn with `UI_draw_roundbox` * rather than with `GL_POINT`. */ for (const bNodeSocket *socket : node.input_sockets()) { - if (!socket->is_visible()) { + if (!node.is_socket_icon_drawn(*socket)) { continue; } if (!(socket->flag & SOCK_MULTI_INPUT)) { diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 661369d284d..98c9abdf549 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -1191,7 +1191,7 @@ bNodeSocket *node_find_indicated_socket(SpaceNode &snode, if (in_out & SOCK_IN) { for (bNodeSocket *sock : node.input_sockets()) { - if (sock->is_visible()) { + if (node.is_socket_icon_drawn(*sock)) { const float2 location = sock->runtime->location; if (sock->flag & SOCK_MULTI_INPUT && !(node.flag & NODE_HIDDEN)) { if (cursor_isect_multi_input_socket(cursor, *sock)) { @@ -1210,7 +1210,7 @@ bNodeSocket *node_find_indicated_socket(SpaceNode &snode, } if (in_out & SOCK_OUT) { for (bNodeSocket *sock : node.output_sockets()) { - if (sock->is_visible()) { + if (node.is_socket_icon_drawn(*sock)) { const float2 location = sock->runtime->location; if (BLI_rctf_isect_pt(&rect, location.x, location.y)) { if (!socket_is_occluded(location, node, snode)) { diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index a832e0fae86..fc1071ecc06 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -170,7 +170,7 @@ static void pick_input_link_by_link_intersect(const bContext &C, static bool socket_is_available(bNodeTree * /*ntree*/, bNodeSocket *sock, const bool allow_used) { - if (!sock->is_visible_or_panel_collapsed()) { + if (!sock->is_visible()) { return false; } @@ -414,9 +414,9 @@ namespace viewer_linking { * \{ */ /* Depending on the node tree type, different socket types are supported by viewer nodes. */ -static bool socket_can_be_viewed(const bNodeSocket &socket) +static bool socket_can_be_viewed(const bNode &node, const bNodeSocket &socket) { - if (!socket.is_visible()) { + if (!node.is_socket_icon_drawn(socket)) { return false; } if (STREQ(socket.idname, "NodeSocketVirtual")) { @@ -530,7 +530,7 @@ static bNodeSocket *determine_socket_to_view(bNode &node_to_view) int last_linked_data_socket_index = -1; bool has_linked_geometry_socket = false; for (bNodeSocket *socket : node_to_view.output_sockets()) { - if (!socket_can_be_viewed(*socket)) { + if (!socket_can_be_viewed(node_to_view, *socket)) { continue; } for (bNodeLink *link : socket->directly_linked_links()) { @@ -554,7 +554,7 @@ static bNodeSocket *determine_socket_to_view(bNode &node_to_view) if (last_linked_data_socket_index == -1 && !has_linked_geometry_socket) { /* Return the first socket that can be viewed. */ for (bNodeSocket *socket : node_to_view.output_sockets()) { - if (socket_can_be_viewed(*socket)) { + if (socket_can_be_viewed(node_to_view, *socket)) { return socket; } } @@ -566,7 +566,7 @@ static bNodeSocket *determine_socket_to_view(bNode &node_to_view) for (const int offset : IndexRange(1, tot_outputs)) { const int index = (last_linked_data_socket_index + offset) % tot_outputs; bNodeSocket &output_socket = node_to_view.output_socket(index); - if (!socket_can_be_viewed(output_socket)) { + if (!socket_can_be_viewed(node_to_view, output_socket)) { continue; } if (has_linked_geometry_socket && output_socket.type == SOCK_GEOMETRY) { @@ -2264,7 +2264,7 @@ bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_ int index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { const nodes::SocketDeclaration &socket_decl = *socket_decls[index]; - if (!socket->is_visible_or_panel_collapsed()) { + if (!socket->is_visible()) { continue; } if (socket_decl.is_default_link_socket) { @@ -2285,7 +2285,7 @@ bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_ /* Try all priorities, starting from 'highest'. */ for (int priority = maxpriority; priority >= 0; priority--) { LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { - if (!!sock->is_visible_or_panel_collapsed() && priority == get_main_socket_priority(sock)) { + if (!!sock->is_visible() && priority == get_main_socket_priority(sock)) { return sock; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4919f607cdc..463df977389 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -189,7 +189,6 @@ typedef struct bNodeSocket { bool is_hidden() const; bool is_available() const; bool is_panel_collapsed() const; - bool is_visible_or_panel_collapsed() const; bool is_visible() const; bool is_multi_input() const; bool is_input() const; @@ -428,6 +427,11 @@ typedef struct bNode { /** A span containing all internal links when the node is muted. */ blender::Span internal_links() const; + /* True if the socket is visible and has a valid location. The icon may not be visible. */ + bool is_socket_drawn(const bNodeSocket &socket) const; + /* True if the socket is drawn and the icon is visible. */ + bool is_socket_icon_drawn(const bNodeSocket &socket) const; + /* The following methods are only available when #bNodeTree.ensure_topology_cache has been * called. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 2d29cfda79e..fb0ddc69b84 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -124,7 +124,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) /* If the source node has a geometry socket, connect it to the new viewer node as well. */ LISTBASE_FOREACH (bNodeSocket *, socket, ¶ms.node.outputs) { - if (socket->type == SOCK_GEOMETRY && socket->is_visible_or_panel_collapsed()) { + if (socket->type == SOCK_GEOMETRY && socket->is_visible()) { nodeAddLink(¶ms.node_tree, ¶ms.node, socket,