diff options
author | Lukas Toenne <lukas.toenne@googlemail.com> | 2012-05-15 16:40:43 +0400 |
---|---|---|
committer | Lukas Toenne <lukas.toenne@googlemail.com> | 2012-05-15 16:40:43 +0400 |
commit | 324b22f701e1b3bc33ed48d30e13b0ca419baa81 (patch) | |
tree | 706c3220689d87bf4e5119c816c6d940f8edfa6a /source/blender/editors/space_node | |
parent | 8242f624a1d10649946f9db6994dc8b07a1c8218 (diff) |
A generalization of the modal node linking operator (for dragging from socket to socket).
This operator still had some built-in assumptions about the connectivity of input/output sockets (1-to-n in all current node systems). For future node systems (e.g. flow-based particles) and for general customizable nodes the operator is now fully symmetric and supports all kinds of connectivity limits (1:1, 1:n, m:1, m:n).
The operator data can also store a list of node links as opposed to a single link now, so that multiple links can be redirected at once. Holding the CTRL key when clicking a socket, all links from/to that socket are detached and can be moved to a different socket. This is useful for quickly appending a node without moving every individual link.
Diffstat (limited to 'source/blender/editors/space_node')
-rw-r--r-- | source/blender/editors/space_node/node_draw.c | 7 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 326 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_intern.h | 8 | ||||
-rw-r--r-- | source/blender/editors/space_node/node_ops.c | 2 |
4 files changed, 200 insertions, 143 deletions
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 3a920e16f8a..d93b1b1fcc8 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -914,6 +914,7 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) Scene *scene= CTX_data_scene(C); int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; bNodeLinkDrag *nldrag; + LinkData *linkdata; UI_ThemeClearColor(TH_BACK); glClear(GL_COLOR_BUFFER_BIT); @@ -965,8 +966,10 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) /* temporary links */ glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); - for (nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) - node_draw_link(&ar->v2d, snode, nldrag->link); + for (nldrag= snode->linkdrag.first; nldrag; nldrag= nldrag->next) { + for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) + node_draw_link(&ar->v2d, snode, (bNodeLink *)linkdata->data); + } glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index ae6c09b0339..c23f6c76650 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2324,15 +2324,13 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) SpaceNode *snode= CTX_wm_space_node(C); ARegion *ar= CTX_wm_region(C); bNodeLinkDrag *nldrag= op->customdata; - bNode *tnode, *node; - bNodeSocket *tsock= NULL, *sock; + bNode *tnode; + bNodeSocket *tsock= NULL; bNodeLink *link; + LinkData *linkdata; int in_out; - in_out= nldrag->in_out; - node= nldrag->node; - sock= nldrag->sock; - link= nldrag->link; + in_out = nldrag->in_out; UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->mx, &snode->my); @@ -2342,57 +2340,86 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) if (in_out==SOCK_OUT) { if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) { - if (nodeFindLink(snode->edittree, sock, tsock)==NULL) { - if ( link->tosock!= tsock && (!tnode || (tnode!=node && link->tonode!=tnode)) ) { - link->tonode= tnode; - link->tosock= tsock; - if (link->prev==NULL && link->next==NULL) { - BLI_addtail(&snode->edittree->links, link); - } - - snode->edittree->update |= NTREE_UPDATE_LINKS; - ntreeUpdateTree(snode->edittree); - } + 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; + /* add it to the node tree temporarily */ + if (link->prev==NULL && link->next==NULL) + BLI_addtail(&snode->edittree->links, link); + + snode->edittree->update |= NTREE_UPDATE_LINKS; } + ntreeUpdateTree(snode->edittree); } else { - if (link->tonode || link->tosock) { - BLI_remlink(&snode->edittree->links, link); - link->prev = link->next = NULL; - link->tonode= NULL; - link->tosock= NULL; + int do_update = 0; + for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) { + link = linkdata->data; - snode->edittree->update |= NTREE_UPDATE_LINKS; - ntreeUpdateTree(snode->edittree); + if (link->tonode || link->tosock) { + BLI_remlink(&snode->edittree->links, link); + link->prev = link->next = NULL; + link->tonode= NULL; + link->tosock= NULL; + + snode->edittree->update |= NTREE_UPDATE_LINKS; + do_update = 1; + } } + if (do_update) + ntreeUpdateTree(snode->edittree); } } else { if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) { - if (nodeFindLink(snode->edittree, sock, tsock)==NULL) { - if (nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) { - if ( link->fromsock!= tsock && (!tnode || (tnode!=node && link->fromnode!=tnode)) ) { - link->fromnode= tnode; - link->fromsock= tsock; - if (link->prev==NULL && link->next==NULL) { - BLI_addtail(&snode->edittree->links, link); - } - - snode->edittree->update |= NTREE_UPDATE_LINKS; - ntreeUpdateTree(snode->edittree); - } - } + 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; + /* add it to the node tree temporarily */ + if (link->prev==NULL && link->next==NULL) + BLI_addtail(&snode->edittree->links, link); + + snode->edittree->update |= NTREE_UPDATE_LINKS; } + ntreeUpdateTree(snode->edittree); } else { - if (link->tonode || link->tosock) { - BLI_remlink(&snode->edittree->links, link); - link->prev = link->next = NULL; - link->fromnode= NULL; - link->fromsock= NULL; - snode->edittree->update |= NTREE_UPDATE_LINKS; - ntreeUpdateTree(snode->edittree); + int do_update = 0; + for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) { + link = linkdata->data; + + if (link->fromnode || link->fromsock) { + BLI_remlink(&snode->edittree->links, link); + link->prev = link->next = NULL; + link->fromnode= NULL; + link->fromsock= NULL; + + snode->edittree->update |= NTREE_UPDATE_LINKS; + do_update = 1; + } } + if (do_update) + ntreeUpdateTree(snode->edittree); } } @@ -2401,139 +2428,161 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) case LEFTMOUSE: case RIGHTMOUSE: - case MIDDLEMOUSE: - if (link->tosock && link->fromsock) { - /* send changed events for original tonode and new */ - snode_update(snode, link->tonode); + case MIDDLEMOUSE: { + for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) { + link = linkdata->data; - /* we might need to remove a link */ - if (in_out==SOCK_OUT) - node_remove_extra_links(snode, link->tosock, link); - - /* when linking to group outputs, update the socket type */ - /* XXX this should all be part of a generic update system */ - if (!link->tonode) { - if(link->tosock->type != link->fromsock->type) - nodeSocketSetType(link->tosock, link->fromsock->type); - } - } - else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { - /* automatically add new group socket */ - if (link->tonode && link->tosock) { - link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN); - link->fromnode = NULL; - if (link->prev==NULL && link->next==NULL) { - BLI_addtail(&snode->edittree->links, link); + if (link->tosock && link->fromsock) { + /* send changed events for original tonode and new */ + if (link->tonode) + snode_update(snode, link->tonode); + + /* we might need to remove a link */ + if (in_out==SOCK_OUT) + node_remove_extra_links(snode, link->tosock, link); + + /* when linking to group outputs, update the socket type */ + /* XXX this should all be part of a generic update system */ + if (!link->tonode) { + if(link->tosock->type != link->fromsock->type) + nodeSocketSetType(link->tosock, link->fromsock->type); } - snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS; } - else if (link->fromnode && link->fromsock) { - link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT); - link->tonode = NULL; - if (link->prev==NULL && link->next==NULL) { - BLI_addtail(&snode->edittree->links, link); + else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { + /* automatically add new group socket */ + if (link->tonode && link->tosock) { + link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN); + link->fromnode = NULL; + if (link->prev==NULL && link->next==NULL) + BLI_addtail(&snode->edittree->links, link); + + snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS; + } + else if (link->fromnode && link->fromsock) { + link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT); + link->tonode = NULL; + if (link->prev==NULL && link->next==NULL) + BLI_addtail(&snode->edittree->links, link); + + snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS; } - snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS; } + else + nodeRemLink(snode->edittree, link); } - else - nodeRemLink(snode->edittree, link); ntreeUpdateTree(snode->edittree); 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); return OPERATOR_FINISHED; + } } return OPERATOR_RUNNING_MODAL; } /* return 1 when socket clicked */ -static int node_link_init(SpaceNode *snode, bNodeLinkDrag *nldrag) +static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach) { - bNodeLink *link; - int in_out = 0; - + bNode *node; + bNodeSocket *sock; + bNodeLink *link, *link_next, *oplink; + bNodeLinkDrag *nldrag = NULL; + LinkData *linkdata; + int num_links; + /* output indicated? */ - if (node_find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_OUT)) { - if (nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit) - in_out = SOCK_OUT; - else { - /* find if we break a link */ - for (link= snode->edittree->links.first; link; link= link->next) { - if (link->fromsock==nldrag->sock) - break; - } - if (link) { - nldrag->node= link->tonode; - nldrag->sock= link->tosock; - nodeRemLink(snode->edittree, link); - in_out = SOCK_IN; + if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) { + nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + + num_links = nodeCountSocketLinks(snode->edittree, sock); + if (num_links > 0 && (num_links >= sock->limit || detach)) { + /* dragged links are fixed on input side */ + nldrag->in_out = SOCK_IN; + /* detach current links and store them in the operator data */ + for (link= snode->edittree->links.first; link; link= link_next) { + link_next = link->next; + if (link->fromsock==sock) { + linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); + linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); + *oplink = *link; + BLI_addtail(&nldrag->links, linkdata); + nodeRemLink(snode->edittree, link); + } } } + else { + /* dragged links are fixed on output side */ + nldrag->in_out = SOCK_OUT; + /* create a new link */ + linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); + linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); + oplink->fromnode = node; + oplink->fromsock = sock; + BLI_addtail(&nldrag->links, linkdata); + } } /* or an input? */ - else if (node_find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_IN)) { - if (nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit) - in_out = SOCK_IN; - else { - /* find if we break a link */ - for (link= snode->edittree->links.first; link; link= link->next) { - if (link->tosock==nldrag->sock) - break; - } - if (link) { - /* send changed event to original tonode */ - if (link->tonode) - snode_update(snode, link->tonode); - - nldrag->node= link->fromnode; - nldrag->sock= link->fromsock; - nodeRemLink(snode->edittree, link); - in_out = SOCK_OUT; + else if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) { + nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + + num_links = nodeCountSocketLinks(snode->edittree, sock); + if (num_links > 0 && (num_links >= sock->limit || detach)) { + /* dragged links are fixed on output side */ + nldrag->in_out = SOCK_OUT; + /* detach current links and store them in the operator data */ + for (link= snode->edittree->links.first; link; link= link_next) { + link_next = link->next; + if (link->tosock==sock) { + linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); + linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); + *oplink = *link; + BLI_addtail(&nldrag->links, linkdata); + nodeRemLink(snode->edittree, link); + + /* send changed event to original link->tonode */ + if (node) + snode_update(snode, node); + } } } + else { + /* dragged links are fixed on input side */ + nldrag->in_out = SOCK_IN; + /* create a new link */ + linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data"); + linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link"); + oplink->tonode = node; + oplink->tosock = sock; + BLI_addtail(&nldrag->links, linkdata); + } } - return in_out; + return nldrag; } static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) { SpaceNode *snode= CTX_wm_space_node(C); ARegion *ar= CTX_wm_region(C); - bNodeLinkDrag *nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); - + bNodeLinkDrag *nldrag; + int detach = RNA_boolean_get(op->ptr, "detach"); UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->mx, &snode->my); ED_preview_kill_jobs(C); - nldrag->in_out= node_link_init(snode, nldrag); + nldrag = node_link_init(snode, detach); - if (nldrag->in_out) { + if (nldrag) { op->customdata= nldrag; - - /* we make a temporal link */ - if (nldrag->in_out==SOCK_OUT) { - nldrag->link= MEM_callocN(sizeof(bNodeLink), "link"); - nldrag->link->fromnode= nldrag->node; - nldrag->link->fromsock= nldrag->sock; - nldrag->link->tonode= NULL; - nldrag->link->tosock= NULL; - } - else { - nldrag->link= MEM_callocN(sizeof(bNodeLink), "link"); - nldrag->link->fromnode= NULL; - nldrag->link->fromsock= NULL; - nldrag->link->tonode= nldrag->node; - nldrag->link->tosock= nldrag->sock; - } BLI_addtail(&snode->linkdrag, nldrag); /* add modal handler */ @@ -2541,21 +2590,20 @@ static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } - else { - MEM_freeN(nldrag); + else return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH; - } } static int node_link_cancel(bContext *C, wmOperator *op) { SpaceNode *snode= CTX_wm_space_node(C); bNodeLinkDrag *nldrag= op->customdata; - - nodeRemLink(snode->edittree, nldrag->link); + BLI_remlink(&snode->linkdrag, nldrag); + + BLI_freelistN(&nldrag->links); MEM_freeN(nldrag); - + return OPERATOR_CANCELLED; } @@ -2575,6 +2623,8 @@ void NODE_OT_link(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; + + RNA_def_boolean(ot->srna, "detach", FALSE, "Detach", "Detach and redirect existing links"); } /* ********************** Make Link operator ***************** */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 17078443987..802c471c7aa 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -52,9 +52,11 @@ typedef struct bNodeLinkDrag { struct bNodeLinkDrag *next, *prev; - struct bNode *node; - struct bNodeSocket *sock; - struct bNodeLink *link; + /* List of links dragged by the operator. + * Note: This is a list of LinkData structs on top of the actual bNodeLinks. + * This way the links can be added to the node tree while being stored in this list. + */ + ListBase links; int in_out; } bNodeLinkDrag; diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 7d9d7d736f6..5d586f08eb0 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -171,6 +171,8 @@ void node_keymap(struct wmKeyConfig *keyconf) /* each of these falls through if not handled... */ WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "NODE_OT_link", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "detach", TRUE); WM_keymap_add_item(keymap, "NODE_OT_resize", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_links_cut", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); |