[Bf-blender-cvs] [89aae4ac82e] master: Node Editor: Controlled node link swapping

Leon Schittek noreply at git.blender.org
Sat Jan 28 10:11:22 CET 2023


Commit: 89aae4ac82e0f58c79b70d1faaa37fa8a5877cf5
Author: Leon Schittek
Date:   Sat Jan 28 10:07:29 2023 +0100
Branches: master
https://developer.blender.org/rB89aae4ac82e0f58c79b70d1faaa37fa8a5877cf5

Node Editor: Controlled node link swapping

Allow to explicitly swap node links by pressing the alt-key while
reconnecting node links. This replaces the old auto-swapping based on
matching prefixes in socket names.

The new behavior works as follows:

* By default plugging links into already occupied (single input)
  sockets will connect the dragged link and remove the existing one.
* Pressing the alt-key while dragging an existing node link from one
  socket to another socket that is already connected will swap the
  links' destinations.
* Pressing the alt-key while dragging a new node link into an already
  linked socket will try to reconnect the existing links into another
  socket of the same type and remove the links, if no matching socket
  is found on the node. This is similar to the old auto-swapping.

Swapping links from or to multi input sockets is not supported.

This commit also makes the link drag tooltip better visible, when using
light themes by using the text theme color.

Reviewed By: Hans Goudey, Simon Thommes

Differential Revision: https://developer.blender.org/D16244

===================================================================

M	source/blender/blenkernel/BKE_node.h
M	source/blender/editors/space_node/node_intern.hh
M	source/blender/editors/space_node/node_relationships.cc
M	source/blender/nodes/intern/node_util.cc
M	source/blender/nodes/intern/node_util.h

===================================================================

diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d57857bfdf3..c358f56c0d9 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -298,7 +298,7 @@ typedef struct bNodeType {
                         const struct bNodeTree *nodetree,
                         const char **r_disabled_hint);
 
-  /* optional handling of link insertion. Returns false if the link shouldn't be created. */
+  /* Optional handling of link insertion. Returns false if the link shouldn't be created. */
   bool (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
 
   void (*free_self)(struct bNodeType *ntype);
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index f9804144fb0..5be29e6f336 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -44,18 +44,24 @@ struct bNodeLinkDrag {
   Vector<bNodeLink> links;
   eNodeSocketInOut in_out;
 
-  /** Draw handler for the "+" icon when dragging a link in empty space. */
+  /** Draw handler for the tooltip icon when dragging a link in empty space. */
   void *draw_handle;
 
   /** Temporarily stores the last picked link from multi-input socket operator. */
   bNodeLink *last_picked_multi_input_socket_link;
 
   /**
-   * Temporarily stores the last hovered socket for multi-input socket operator.
+   * Temporarily stores the last hovered node for multi-input socket operator.
    * Store it to recalculate sorting after it is no longer hovered.
    */
   bNode *last_node_hovered_while_dragging_a_link;
 
+  /**
+   * Temporarily stores the currently hovered socket for link swapping to allow reliably swap links
+   * even when dragging multiple links at once. `nullptr`, when no socket is hovered.
+   */
+  bNodeSocket *hovered_socket;
+
   /* The cursor position, used for drawing a + icon when dragging a node link. */
   std::array<int, 2> cursor;
 
@@ -66,6 +72,8 @@ struct bNodeLinkDrag {
   /** The number of links connected to the #start_socket when the drag started. */
   int start_link_count;
 
+  bool swap_links = false;
+
   /* Data for edge panning */
   View2DEdgePanData pan_data;
 };
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index a591c8308a4..9f37233840b 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -785,6 +785,9 @@ static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
   if (!dragged_links_are_detached(nldrag)) {
     return false;
   }
+  if (nldrag.swap_links) {
+    return false;
+  }
   /* Don't create the search menu if the drag is disconnecting a link from an input node. */
   if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) {
     return false;
@@ -799,18 +802,29 @@ static bool should_create_drag_link_search_menu(const bNodeTree &node_tree,
   return true;
 }
 
+static bool need_drag_link_tooltip(const bNodeTree &node_tree, const bNodeLinkDrag &nldrag)
+{
+  return nldrag.swap_links || should_create_drag_link_search_menu(node_tree, nldrag);
+}
+
 static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/, void *arg)
 {
   bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg);
 
-  const uchar text_col[4] = {255, 255, 255, 255};
+  uchar text_col[4];
+  UI_GetThemeColor4ubv(TH_TEXT, text_col);
+
   const int padding = 4 * UI_DPI_FAC;
   const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding :
                                               nldrag->cursor[0];
   const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC;
 
-  UI_icon_draw_ex(
-      x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT);
+  const bool new_link = nldrag->in_out == nldrag->start_socket->in_out;
+  const bool swap_links = nldrag->swap_links;
+
+  const int icon = !swap_links ? ICON_ADD : (new_link ? ICON_ANIM : ICON_UV_SYNC_SELECT);
+
+  UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT);
 }
 
 static void draw_draglink_tooltip_activate(const ARegion &region, bNodeLinkDrag &nldrag)
@@ -833,11 +847,21 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag & /*nldrag*/)
 {
   char header[UI_MAX_DRAW_STR];
 
-  BLI_strncpy(header, TIP_("LMB: drag node link, RMB: cancel"), sizeof(header));
+  const char *str_lmb = WM_key_event_string(LEFTMOUSE, true);
+  const char *str_rmb = WM_key_event_string(RIGHTMOUSE, true);
+  const char *str_alt = WM_key_event_string(EVT_LEFTALTKEY, true);
+
+  BLI_snprintf(header,
+               sizeof(header),
+               TIP_("%s: drag node link, %s: cancel, %s: swap node links"),
+               str_lmb,
+               str_rmb,
+               str_alt);
+
   ED_workspace_status_text(C, header);
 }
 
-static int node_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
+static int node_socket_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
 {
   int count = 0;
   LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
@@ -848,41 +872,139 @@ static int node_count_links(const bNodeTree &ntree, const bNodeSocket &socket)
   return count;
 }
 
-static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link)
+static bNodeSocket *node_find_linkable_socket(const bNodeTree &ntree,
+                                              const bNode *node,
+                                              bNodeSocket *socket_to_match)
 {
-  bNodeTree &ntree = *snode.edittree;
-  bNodeSocket &from = *link.fromsock;
-  bNodeSocket &to = *link.tosock;
-  int to_count = node_count_links(ntree, to);
-  int from_count = node_count_links(ntree, from);
-  int to_link_limit = nodeSocketLinkLimit(&to);
-  int from_link_limit = nodeSocketLinkLimit(&from);
-
-  LISTBASE_FOREACH_MUTABLE (bNodeLink *, tlink, &ntree.links) {
-    if (tlink == &link) {
-      continue;
+  bNodeSocket *first_socket = socket_to_match->in_out == SOCK_IN ?
+                                  static_cast<bNodeSocket *>(node->inputs.first) :
+                                  static_cast<bNodeSocket *>(node->outputs.first);
+
+  bNodeSocket *socket = socket_to_match->next ? socket_to_match->next : first_socket;
+  while (socket != socket_to_match) {
+    if (!socket->is_hidden() && socket->is_available()) {
+      const bool sockets_are_compatible = socket->typeinfo == socket_to_match->typeinfo;
+      if (sockets_are_compatible) {
+        const int link_count = node_socket_count_links(ntree, *socket);
+        const bool socket_has_capacity = link_count < nodeSocketLinkLimit(socket);
+        if (socket_has_capacity) {
+          /* Found a valid free socket we can swap to. */
+          return socket;
+        }
+      }
     }
+    /* Wrap around the list end. */
+    socket = socket->next ? socket->next : first_socket;
+  }
 
-    if (tlink && tlink->fromsock == &from) {
-      if (from_count > from_link_limit) {
-        nodeRemLink(&ntree, tlink);
-        tlink = nullptr;
-        from_count--;
+  return nullptr;
+}
+
+static void displace_links(bNodeTree *ntree, const bNode *node, bNodeLink *inserted_link)
+{
+  bNodeSocket *linked_socket = node == inserted_link->tonode ? inserted_link->tosock :
+                                                               inserted_link->fromsock;
+  bNodeSocket *replacement_socket = node_find_linkable_socket(*ntree, node, linked_socket);
+
+  if (linked_socket->is_input()) {
+    if (linked_socket->limit + 1 < nodeSocketLinkLimit(linked_socket)) {
+      return;
+    }
+
+    LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+      if (link->tosock == linked_socket) {
+        if (!replacement_socket) {
+          nodeRemLink(ntree, link);
+          BKE_ntree_update_tag_link_removed(ntree);
+          return;
+        }
+
+        link->tosock = replacement_socket;
+        if (replacement_socket->is_multi_input()) {
+          link->multi_input_socket_index = node_socket_count_links(*ntree, *replacement_socket) -
+                                           1;
+        }
+        BKE_ntree_update_tag_link_changed(ntree);
+        return;
       }
     }
+  }
 
-    if (tlink && tlink->tosock == &to) {
-      if (to_count > to_link_limit) {
-        nodeRemLink(&ntree, tlink);
-        tlink = nullptr;
-        to_count--;
+  LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+    if (link->fromsock == linked_socket) {
+      if (replacement_socket) {
+        link->fromsock = replacement_socket;
+        BKE_ntree_update_tag_link_changed(ntree);
       }
-      else if (tlink->fromsock == &from) {
-        /* Also remove link if it comes from the same output. */
-        nodeRemLink(&ntree, tlink);
-        tlink = nullptr;
-        to_count--;
-        from_count--;
+      else {
+        nodeRemLink(ntree, link);
+        BKE_ntree_update_tag_link_removed(ntree);
+      }
+    }
+  }
+}
+
+static void node_displace_existing_links(bNodeLinkDrag &nldrag, bNodeTree &ntree)
+{
+  bNodeLink &link = nldrag.links.first();
+  if (nldrag.start_socket->is_input()) {
+    displace_links(&ntree, link.fromnode, &link);
+  }
+  else {
+    displace_links(&ntree, link.tonode, &link);
+  }
+}
+
+static void node_swap_links(bNodeLinkDrag &nldrag, bNodeTree &ntree)
+{
+  bNodeSocket &linked_socket = *nldrag.hovered_socket;
+  bNodeSocket *start_socket = nldrag.start_socket;
+  bNode *start_node = nldrag.start_node;
+
+  if (linked_socket.is_input()) {
+    LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+      if (link->tosock == &linked_socket) {
+        link->tosock = start_socket;
+        link->tonode = start_node;
+      }
+    }
+  }
+  else {
+    LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+      if (link->fromsock == &linked_socket) {
+        link->fromsock = start_socket;
+        link->fromnode = start_node;
+      }
+    }
+  }
+
+  BKE_ntree_update_tag_link_changed(&ntree);
+}
+
+static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTree &ntree)
+{
+  

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list