diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 2ffa1d205da..b9df1e45bae 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -143,6 +143,7 @@ void nodeVerifyType(struct bNodeTree *ntree, struct bNode *node); void nodeAddToPreview(struct bNode *, float *, int, int); +void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node); struct bNode *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup); void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node); struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); @@ -150,6 +151,8 @@ struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node); struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock); void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link); +int nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex); + struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, struct bNodeSocket *from, struct bNodeSocket *to); int nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 651115b7180..4bcacae9fc5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -483,6 +483,20 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) BLI_addtail(&ngroup->nodes, node); node->locx-= 0.5f*(min[0]+max[0]); node->locy-= 0.5f*(min[1]+max[1]); + + /* set selin and selout of the nodetree */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) { + ngroup->selin= sock; + break; + } + } + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) { + ngroup->selout= sock; + break; + } + } } } @@ -653,7 +667,8 @@ void nodeGroupSocketUseFlags(bNodeTree *ngroup) } } -static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex) +/* finds a node based on given socket */ +int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex) { bNode *node; bNodeSocket *tsock; @@ -671,13 +686,15 @@ static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **n if(tsock) break; } + if(node) { *nodep= node; - *sockindex= index; - } - else { - *nodep= NULL; + if(sockindex) *sockindex= index; + return 1; } + + *nodep= NULL; + return 0; } /* returns 1 if its OK */ @@ -717,7 +734,7 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) for(link= ntree->links.first; link; link= link->next) { if(link->tonode==gnode) { /* link->tosock->tosock is on the node we look for */ - find_node_with_socket(ngroup, link->tosock->tosock, &nextn, &index); + nodeFindNode(ngroup, link->tosock->tosock, &nextn, &index); if(nextn==NULL) printf("wrong stuff!\n"); else if(nextn->new_node==NULL) printf("wrong stuff too!\n"); else { @@ -727,7 +744,7 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) } else if(link->fromnode==gnode) { /* link->fromsock->tosock is on the node we look for */ - find_node_with_socket(ngroup, link->fromsock->tosock, &nextn, &index); + nodeFindNode(ngroup, link->fromsock->tosock, &nextn, &index); if(nextn==NULL) printf("1 wrong stuff!\n"); else if(nextn->new_node==NULL) printf("1 wrong stuff too!\n"); else { @@ -898,6 +915,28 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) nnode->flag |= NODE_SELECT; } node->flag &= ~NODE_ACTIVE; + + /* deselect original sockets */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL; + } + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL; + } + + /* set tree selin and selout to new sockets */ + for(sock= nnode->inputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) { + ntree->selin= sock; + break; + } + } + for(sock= nnode->outputs.first; sock; sock= sock->next) { + if(sock->flag & SOCK_SEL) { + ntree->selout= sock; + break; + } + } } if(node==last) break; } @@ -941,7 +980,7 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) /* ************** Free stuff ********** */ /* goes over entire tree */ -static void node_unlink_node(bNodeTree *ntree, bNode *node) +void nodeUnlinkNode(bNodeTree *ntree, bNode *node) { bNodeLink *link, *next; bNodeSocket *sock; @@ -985,7 +1024,7 @@ static void composit_free_node_cache(bNode *node) void nodeFreeNode(bNodeTree *ntree, bNode *node) { - node_unlink_node(ntree, node); + nodeUnlinkNode(ntree, node); BLI_remlink(&ntree->nodes, node); /* since it is called while free database, node->id is undefined */ diff --git a/source/blender/include/BSE_node.h b/source/blender/include/BSE_node.h index 171a277e8e6..5862918953c 100644 --- a/source/blender/include/BSE_node.h +++ b/source/blender/include/BSE_node.h @@ -72,6 +72,7 @@ void snode_make_group_editable(struct SpaceNode *snode, struct bNode *gnode); void node_hide(struct SpaceNode *snode); void node_read_renderlayers(struct SpaceNode *snode); void clear_scene_in_nodes(struct Scene *sce); +void node_toggle_link(struct SpaceNode *snode); void node_transform_ext(int mode, int unused); void node_shader_default(struct Material *ma); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 5f20939fc23..b5084c41884 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -92,7 +92,8 @@ typedef struct bNodeSocket { #define SOCK_IN_USE 4 /* unavailable is for dynamic sockets */ #define SOCK_UNAVAIL 8 - + /* flag for selection status */ +#define SOCK_SEL 16 # # typedef struct bNodePreview { @@ -167,6 +168,10 @@ typedef struct bNodeTree { ListBase alltypes; /* type definitions */ struct bNodeType *owntype; /* for groups or dynamic trees, no read/write */ + /* selected input/output socket */ + bNodeSocket *selin; + bNodeSocket *selout; + /* callbacks */ void (*timecursor)(int nr); void (*stats_draw)(char *str); diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index b0c55d104f3..cc65b10c8e7 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -1988,7 +1988,8 @@ static void draw_nodespace_back(ScrArea *sa, SpaceNode *snode) } /* nice AA filled circle */ -static void socket_circle_draw(float x, float y, float size, int type, int select) +/* this might have some more generic use */ +static void circle_draw(float x, float y, float size, int type, int col[3]) { /* 16 values of sin function */ static float si[16] = { @@ -2006,28 +2007,7 @@ static void socket_circle_draw(float x, float y, float size, int type, int selec }; int a; - if(select==0) { - if(type==-1) - glColor3ub(0, 0, 0); - else if(type==SOCK_VALUE) - glColor3ub(160, 160, 160); - else if(type==SOCK_VECTOR) - glColor3ub(100, 100, 200); - else if(type==SOCK_RGBA) - glColor3ub(200, 200, 40); - else - glColor3ub(100, 200, 100); - } - else { - if(type==SOCK_VALUE) - glColor3ub(200, 200, 200); - else if(type==SOCK_VECTOR) - glColor3ub(140, 140, 240); - else if(type==SOCK_RGBA) - glColor3ub(240, 240, 100); - else - glColor3ub(140, 240, 140); - } + glColor3ub(col[0], col[1], col[2]); glBegin(GL_POLYGON); for(a=0; a<16; a++) @@ -2045,6 +2025,41 @@ static void socket_circle_draw(float x, float y, float size, int type, int selec glDisable(GL_BLEND); } +static void socket_circle_draw(bNodeSocket *sock, float size) +{ + int col[3]; + + /* choose color based on sock flags */ + if(sock->flag & SELECT) { + if(sock->flag & SOCK_SEL) { + col[0]= 240; col[1]= 200; col[2]= 40;} + else if(sock->type==SOCK_VALUE) { + col[0]= 200; col[1]= 200; col[2]= 200;} + else if(sock->type==SOCK_VECTOR) { + col[0]= 140; col[1]= 140; col[2]= 240;} + else if(sock->type==SOCK_RGBA) { + col[0]= 240; col[1]= 240; col[2]= 100;} + else { + col[0]= 140; col[1]= 240; col[2]= 140;} + } + else if(sock->flag & SOCK_SEL) { + col[0]= 200; col[1]= 160; col[2]= 0;} + else { + if(sock->type==-1) { + col[0]= 0; col[1]= 0; col[2]= 0;} + else if(sock->type==SOCK_VALUE) { + col[0]= 160; col[1]= 160; col[2]= 160;} + else if(sock->type==SOCK_VECTOR) { + col[0]= 100; col[1]= 100; col[2]= 200;} + else if(sock->type==SOCK_RGBA) { + col[0]= 200; col[1]= 200; col[2]= 40;} + else { + col[0]= 100; col[1]= 200; col[2]= 100;} + } + + circle_draw(sock->locx, sock->locy, size, sock->type, col); +} + /* not a callback */ static void node_draw_preview(bNodePreview *preview, rctf *prv) { @@ -2459,7 +2474,7 @@ static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node) /* socket inputs, buttons */ for(sock= node->inputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); if(block && sock->link==NULL) { float *butpoin= sock->ns.vec; @@ -2501,7 +2516,7 @@ static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node) /* socket outputs */ for(sock= node->outputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) { - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); BIF_ThemeColor(TH_TEXT); ofs= 0; @@ -2589,12 +2604,12 @@ void node_draw_hidden(SpaceNode *snode, bNode *node) /* sockets */ for(sock= node->inputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); } for(sock= node->outputs.first; sock; sock= sock->next) { if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); } } @@ -2805,10 +2820,10 @@ static void node_draw_group(ScrArea *sa, SpaceNode *snode, bNode *gnode) /* group sockets */ for(sock= gnode->inputs.first; sock; sock= sock->next) if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); for(sock= gnode->outputs.first; sock; sock= sock->next) if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) - socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT); + socket_circle_draw(sock, NODE_SOCKSIZE); /* and finally the whole tree */ node_draw_nodetree(sa, snode, ngroup); diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c index a14b0ccc389..d035908994c 100644 --- a/source/blender/src/editnode.c +++ b/source/blender/src/editnode.c @@ -830,6 +830,23 @@ static void snode_bg_viewmove(SpaceNode *snode) window_set_cursor(win, oldcursor); } +static void reset_sel_socket(SpaceNode *snode, int in_out) +{ + bNode *node; + bNodeSocket *sock; + + for(node= snode->edittree->nodes.first; node; node= node->next) { + if(in_out & SOCK_IN) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL; + } + if(in_out & SOCK_OUT) { + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL; + } + } +} + /* checks mouse position, and returns found node/socket */ /* type is SOCK_IN and/or SOCK_OUT */ static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out) @@ -1568,6 +1585,33 @@ static void node_insert_convertor(SpaceNode *snode, bNodeLink *link) #endif +static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link) +{ + bNodeLink *tlink; + bNodeSocket *sock; + + if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) { + + for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) { + if(link!=tlink && tlink->tosock==link->tosock) + break; + } + if(tlink) { + /* is there a free input socket with same type? */ + for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) { + if(sock->type==tlink->fromsock->type) + if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit) + break; + } + if(sock) + tlink->tosock= sock; + else { + nodeRemLink(snode->edittree, tlink); + } + } + } +} + /* loop that adds a nodelink, called by function below */ /* in_out = starting socket */ static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out) @@ -1638,35 +1682,12 @@ static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, nodeRemLink(snode->edittree, link); } else { - bNodeLink *tlink; - /* send changed events for original tonode and new */ if(link->tonode) NodeTagChanged(snode->edittree, link->tonode); /* we might need to remove a link */ - if(in_out==SOCK_OUT) { - if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) { - - for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) { - if(link!=tlink && tlink->tosock==link->tosock) - break; - } - if(tlink) { - /* is there a free input socket with same type? */ - for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) { - if(tsock->type==tlink->fromsock->type) - if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) - break; - } - if(tsock) - tlink->tosock= tsock; - else { - nodeRemLink(snode->edittree, tlink); - } - } - } - } + if(in_out==SOCK_OUT) node_remove_extra_links(snode, tsock, link); } ntreeSolveOrder(snode->edittree); @@ -1733,10 +1754,18 @@ static int node_add_link(SpaceNode *snode) void node_delete(SpaceNode *snode) { bNode *node, *next; + bNodeSocket *sock; for(node= snode->edittree->nodes.first; node; node= next) { next= node->next; if(node->flag & SELECT) { + /* set selin and selout NULL if the sockets belong to a node to be deleted */ + for(sock= node->inputs.first; sock; sock= sock->next) + if(snode->edittree->selin == sock) snode->edittree->selin= NULL; + + for(sock= node->outputs.first; sock; sock= sock->next) + if(snode->edittree->selout == sock) snode->edittree->selout= NULL; + /* check id user here, nodeFreeNode is called for free dbase too */ if(node->id) node->id->us--; @@ -1826,6 +1855,36 @@ void node_select_linked(SpaceNode *snode, int out) allqueue(REDRAWNODE, 1); } +void node_toggle_link(SpaceNode *snode) +{ + bNode *fromnode, *tonode; + bNodeLink *remlink, *link; + bNodeSocket *outsock= snode->edittree->selout; + bNodeSocket *insock= snode->edittree->selin; + + if(!insock || !outsock) return; + + remlink= nodeFindLink(snode->edittree, outsock, insock); + + if(remlink) nodeRemLink(snode->edittree, remlink); + else { + if(nodeFindNode(snode->edittree, outsock, &fromnode, NULL) && + nodeFindNode(snode->edittree, insock, &tonode, NULL)) { + link= nodeAddLink(snode->edittree, fromnode, outsock, tonode, insock); + NodeTagChanged(snode->edittree, tonode); + node_remove_extra_links(snode, insock, link); + } + else return; + } + + ntreeSolveOrder(snode->edittree); + snode_verify_groups(snode); + snode_handle_recalc(snode); + + allqueue(REDRAWNODE, 0); + BIF_undo_push("Toggle Link"); +} + static void node_border_link_delete(SpaceNode *snode) { rcti rect; @@ -2091,6 +2150,8 @@ static int node_uiDoBlocks(ScrArea *sa, short event) void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt) { SpaceNode *snode= spacedata; + bNode *actnode; + bNodeSocket *actsock; unsigned short event= evt->event; short val= evt->val, doredraw=0, fromlib= 0; @@ -2118,7 +2179,29 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt) break; case RIGHTMOUSE: - if(!node_mouse_select(snode, event)) + if(find_indicated_socket(snode, &actnode, &actsock, SOCK_IN)) { + if(actsock->flag & SOCK_SEL) { + snode->edittree->selin= NULL; + actsock->flag&= ~SOCK_SEL; + } + else { + snode->edittree->selin= actsock; + reset_sel_socket(snode, SOCK_IN); + actsock->flag|= SOCK_SEL; + } + } + else if(find_indicated_socket(snode, &actnode, &actsock, SOCK_OUT)) { + if(actsock->flag & SOCK_SEL) { + snode->edittree->selout= NULL; + actsock->flag&= ~SOCK_SEL; + } + else { + snode->edittree->selout= actsock; + reset_sel_socket(snode, SOCK_OUT); + actsock->flag|= SOCK_SEL; + } + } + else if(!node_mouse_select(snode, event)) toolbox_n(); break; @@ -2194,6 +2277,9 @@ void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt) case EKEY: snode_handle_recalc(snode); break; + case FKEY: + node_toggle_link(snode); + break; case GKEY: if(fromlib) fromlib= -1; else { diff --git a/source/blender/src/header_node.c b/source/blender/src/header_node.c index ebdd42690f5..7255dcd3286 100644 --- a/source/blender/src/header_node.c +++ b/source/blender/src/header_node.c @@ -513,6 +513,9 @@ static void do_node_nodemenu(void *arg, int event) case 10: /* execute */ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); break; + case 11: /* toggle link */ + node_toggle_link(snode); + break; } if(fromlib==-1) error_libdata(); @@ -536,6 +539,10 @@ static uiBlock *node_nodemenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + + uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Toggle Link|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index 969b9d4657b..244e1ffd7c3 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -1648,6 +1648,8 @@ static TBitem tb_node_node[]= { { 0, "Duplicate|Shift D", TB_SHIFT|'d', NULL}, { 0, "Delete|X", 'x', NULL}, { 0, "SEPR", 0, NULL}, + { 0, "Toggle Link|F", 'f', NULL}, + { 0, "SEPR", 0, NULL}, { 0, "Make Group|Ctrl G", TB_CTRL|'g', NULL}, { 0, "Ungroup|Alt G", TB_ALT|'g', NULL}, { 0, "Edit Group|Tab", TB_TAB, NULL},