Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2014-04-29 13:28:16 +0400
committerLukas Tönne <lukas.toenne@gmail.com>2014-04-29 13:28:16 +0400
commit4d8c49bfd0d1e2b8d365493e9a73f9aba2da5861 (patch)
tree27a4fe982c61b5dccb428e6fdf551ee4c4f92beb /source/blender/editors/space_node
parent55c720f06e2c2edd738ecb9d1fa45b9ef379e62a (diff)
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)
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r--source/blender/editors/space_node/node_relationships.c307
1 files changed, 206 insertions, 101 deletions
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index e1d66b9f916..e8c4f7fb2ad 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(&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);
- }
- 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);
+ node_link_exit(C, op, true);
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+ ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
}
@@ -545,7 +650,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* return 1 when socket clicked */
-static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], const bool detach)
+static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], bool detach)
{
bNode *node;
bNodeSocket *sock;
@@ -630,7 +735,7 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], const bo
BLI_addtail(&nldrag->links, linkdata);
}
}
-
+
return nldrag;
}
@@ -641,7 +746,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bNodeLinkDrag *nldrag;
float cursor[2];
- const bool detach = RNA_boolean_get(op->ptr, "detach");
+ bool detach = RNA_boolean_get(op->ptr, "detach");
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
&cursor[0], &cursor[1]);
@@ -1329,7 +1434,7 @@ void ED_node_link_insert(ScrArea *sa)
link->tonode = select;
link->tosock = best_input;
- node_remove_extra_links(snode, link);
+ node_remove_extra_links(snode, link, false);
link->flag &= ~NODE_LINKFLAG_HILITE;
nodeAddLink(snode->edittree, select, best_output, node, sockto);