[Bf-blender-cvs] [4d8c49b] master: Reimplemented the earlier feature of swapping existing links to neighboring sockets when connecting to an occupied input.

Lukas Tönne noreply at git.blender.org
Tue Apr 29 11:40:02 CEST 2014


Commit: 4d8c49bfd0d1e2b8d365493e9a73f9aba2da5861
Author: Lukas Tönne
Date:   Tue Apr 29 11:28:16 2014 +0200
https://developer.blender.org/rB4d8c49bfd0d1e2b8d365493e9a73f9aba2da5861

Reimplemented the earlier feature of swapping existing links to
neighboring sockets when connecting to an occupied input.

This now works based on socket names rather than types, which helps to
avoid unwanted connections to arbitrary sockets. Sockets are considered
swappable when their names match, based on an alphabetic prefix followed
by non-alphabetic suffix.

For example:
Image - Image : matches
Color1 - Color2 : matches (used e.g. in cycles mix nodes)
Roughness - Rotation : does not match (suffix is still alphabetic)

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

M	source/blender/editors/space_node/node_relationships.c

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

diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index e1d66b9..e8c4f7f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -29,6 +29,8 @@
  *  \ingroup spnode
  */
 
+#include <ctype.h>
+
 #include "MEM_guardedalloc.h"
 
 #include "DNA_node_types.h"
@@ -54,6 +56,8 @@
 
 #include "UI_view2d.h"
 
+#include "BLF_translation.h"
+
 #include "node_intern.h"  /* own include */
 #include "NOD_common.h"
 
@@ -395,12 +399,87 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
 
 /* *************************** add link op ******************** */
 
-static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
+static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
+{
+#define HEADER_LENGTH 256
+	char header[HEADER_LENGTH];
+
+	BLI_snprintf(header, HEADER_LENGTH, IFACE_("LMB: drag node link, RMB: cancel"));
+	ED_area_headerprint(CTX_wm_area(C), header);
+#undef HEADER_LENGTH
+}
+
+/* update link_count fields to avoid repeated link counting */
+static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
+{
+	bNodeLink *link;
+	int count = 0;
+	for (link = ntree->links.first; link; link = link->next) {
+		if (link->fromsock == sock)
+			++count;
+		if (link->tosock == sock)
+			++count;
+	}
+	return count;
+}
+
+/* test if two sockets are interchangeable
+ * XXX this could be made into a tree-type callback for flexibility
+ */
+static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
+{
+	/* tests if alphabetic prefix matches
+	 * this allows for imperfect matches, such as numeric suffixes,
+	 * like Color1/Color2
+	 */
+	int prefix_len = 0;
+	char *ca = a->name, *cb = b->name;
+	for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) {
+		/* end of common prefix? */
+		if (*ca != *cb) {
+			/* prefix delimited by non-alphabetic char */
+			if (isalpha(*ca) || isalpha(*cb))
+				return false;
+			break;
+		}
+		++prefix_len;
+	}
+	return prefix_len > 0;
+}
+
+/* find an eligible socket for linking */
+static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur, bool use_swap)
+{
+	int cur_link_count = node_count_links(ntree, cur);
+	if (cur_link_count <= cur->limit) {
+		/* current socket is fine, use it */
+		return cur;
+	}
+	else if (use_swap) {
+		/* link swapping: try to find a free slot with a matching name */
+		
+		bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
+		bNodeSocket *sock;
+		
+		sock = cur->next ? cur->next : first; /* wrap around the list end */
+		while (sock != cur) {
+			if (node_link_socket_match(sock, cur)) {
+				int link_count = node_count_links(ntree, sock);
+				/* take +1 into account since we would add a new link */
+				if (link_count + 1 <= sock->limit)
+					return sock; /* found a valid free socket we can swap to */
+			}
+			
+			sock = sock->next ? sock->next : first; /* wrap around the list end */
+		}
+	}
+	return NULL;
+}
+
+static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_swap)
 {
 	bNodeTree *ntree = snode->edittree;
 	bNodeSocket *from = link->fromsock, *to = link->tosock;
-	int max_from = from->limit, max_to = to->limit;
-	int count_from = 1, count_to = 1; /* start at 1, link is included */
 	bNodeLink *tlink, *tlink_next;
 	
 	for (tlink = ntree->links.first; tlink; tlink = tlink_next) {
@@ -409,16 +488,28 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
 			continue;
 		
 		if (tlink && tlink->fromsock == from) {
-			++count_from;
-			if (count_from > max_from) {
+			bNodeSocket *new_from = node_find_linkable_socket(ntree, tlink->fromnode, from, use_swap);
+			if (new_from && new_from != from) {
+				/* redirect existing link */
+				tlink->fromsock = new_from;
+				new_from->flag &= ~SOCK_HIDDEN;
+			}
+			else if (!new_from) {
+				/* no possible replacement, remove tlink */
 				nodeRemLink(ntree, tlink);
 				tlink = NULL;
 			}
 		}
 		
 		if (tlink && tlink->tosock == to) {
-			++count_to;
-			if (count_to > max_to) {
+			bNodeSocket *new_to = node_find_linkable_socket(ntree, tlink->tonode, to, use_swap);
+			if (new_to && new_to != to) {
+				/* redirect existing link */
+				tlink->tosock = new_to;
+				new_to->flag &= ~SOCK_HIDDEN;
+			}
+			else if (!new_to) {
+				/* no possible replacement, remove tlink */
 				nodeRemLink(ntree, tlink);
 				tlink = NULL;
 			}
@@ -426,82 +517,120 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
 	}
 }
 
-/* loop that adds a nodelink, called by function below  */
-/* in_out = starting socket */
-static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
+static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
 {
 	SpaceNode *snode = CTX_wm_space_node(C);
-	ARegion *ar = CTX_wm_region(C);
-	bNodeLinkDrag *nldrag = op->customdata;
 	bNodeTree *ntree = snode->edittree;
+	bNodeLinkDrag *nldrag = op->customdata;
+	LinkData *linkdata;
+	
+	for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
+		bNodeLink *link = linkdata->data;
+		
+		if (apply_links && link->tosock && link->fromsock) {
+			/* add link to the node tree */
+			BLI_addtail(&ntree->links, link);
+			
+			ntree->update |= NTREE_UPDATE_LINKS;
+			
+			/* tag tonode for update */
+			link->tonode->update |= NODE_UPDATE;
+			
+			/* we might need to remove a link */
+			node_remove_extra_links(snode, link, true);
+		}
+		else
+			nodeRemLink(ntree, link);
+	}
+	
+	ntreeUpdateTree(CTX_data_main(C), ntree);
+	snode_notify(C, snode);
+	snode_dag_update(C, snode);
+	
+	BLI_remlink(&snode->linkdrag, nldrag);
+	/* links->data pointers are either held by the tree or freed already */
+	BLI_freelistN(&nldrag->links);
+	MEM_freeN(nldrag);
+}
+
+static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2])
+{
+	SpaceNode *snode = CTX_wm_space_node(C);
+	bNodeLinkDrag *nldrag = op->customdata;
 	bNode *tnode;
 	bNodeSocket *tsock = NULL;
-	bNodeLink *link;
 	LinkData *linkdata;
-	float cursor[2];
-	int in_out;
 
-	in_out = nldrag->in_out;
+	if (nldrag->in_out == SOCK_OUT) {
+		if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
+			for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
+				bNodeLink *link = linkdata->data;
+				
+				/* skip if this is already the target socket */
+				if (link->tosock == tsock)
+					continue;
+				/* skip if socket is on the same node as the fromsock */
+				if (tnode && link->fromnode == tnode)
+					continue;
+				
+				/* attach links to the socket */
+				link->tonode = tnode;
+				link->tosock = tsock;
+			}
+		}
+		else {
+			for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
+				bNodeLink *link = linkdata->data;
+				
+				link->tonode = NULL;
+				link->tosock = NULL;
+			}
+		}
+	}
+	else {
+		if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
+			for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
+				bNodeLink *link = linkdata->data;
+				
+				/* skip if this is already the target socket */
+				if (link->fromsock == tsock)
+					continue;
+				/* skip if socket is on the same node as the fromsock */
+				if (tnode && link->tonode == tnode)
+					continue;
+				
+				/* attach links to the socket */
+				link->fromnode = tnode;
+				link->fromsock = tsock;
+			}
+		}
+		else {
+			for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
+				bNodeLink *link = linkdata->data;
+				
+				link->fromnode = NULL;
+				link->fromsock = NULL;
+			}
+		}
+	}
+}
+
+/* loop that adds a nodelink, called by function below  */
+/* in_out = starting socket */
+static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+	bNodeLinkDrag *nldrag = op->customdata;
+	ARegion *ar = CTX_wm_region(C);
+	float cursor[2];
 	
 	UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
 	                         &cursor[0], &cursor[1]);
-
+	
 	switch (event->type) {
 		case MOUSEMOVE:
+			node_link_find_socket(C, op, cursor);
 			
-			if (in_out == SOCK_OUT) {
-				if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) {
-					for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
-						link = linkdata->data;
-						
-						/* skip if this is already the target socket */
-						if (link->tosock == tsock)
-							continue;
-						/* skip if socket is on the same node as the fromsock */
-						if (tnode && link->fromnode == tnode)
-							continue;
-						
-						/* attach links to the socket */
-						link->tonode = tnode;
-						link->tosock = tsock;
-					}
-				}
-				else {
-					for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
-						link = linkdata->data;
-						
-						link->tonode = NULL;
-						link->tosock = NULL;
-					}
-				}
-			}
-			else {
-				if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) {
-					for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
-						link = linkdata->data;
-						
-						/* skip if this is already the target socket */
-						if (link->fromsock == tsock)
-							continue;
-						/* skip if socket is on the same node as the fromsock */
-						if (tnode && link->tonode == tnode)
-							continue;
-						
-						/* attach links to the socket */
-						link->fromnode = tnode;
-						link->fromsock = tsock;
-					}
-				}
-				else {
-					for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
-						link = linkdata->data;
-						
-						link->fromnode = NULL;
-						link->fromsock = NULL;
-					}
-				}
-			}
-			
+			node_link_update_header(C, nldrag);
 			ED_region_tag_redraw(ar);
 			break;
 			
@@ -509,34 +638,10 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
 		case RIGHTMOUSE:
 		case MIDDLEMOUSE:
 		{
-			for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
-				link = linkdata->data;
-				
-				if (link->tosock && link->fromsock) {
-					/* add link to the node tree */
-					BLI_addtail(&n

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list