diff options
Diffstat (limited to 'source/blender/editors/space_node/node_edit.c')
-rw-r--r-- | source/blender/editors/space_node/node_edit.c | 333 |
1 files changed, 321 insertions, 12 deletions
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 2d124b7bc23..848b037e1cb 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1179,7 +1179,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot) ot->cancel= snode_bg_viewmove_cancel; /* flags */ - ot->flag= OPTYPE_BLOCKING; + ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; } static int backimage_zoom(bContext *C, wmOperator *op) @@ -2078,23 +2078,21 @@ bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float /* ****************** Duplicate *********************** */ -static int node_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_duplicate_exec(bContext *C, wmOperator *op) { SpaceNode *snode= CTX_wm_space_node(C); bNodeTree *ntree= snode->edittree; - bNode *node, *newnode, *last; + bNode *node, *newnode, *lastnode; + bNodeLink *link, *newlink, *lastlink; + int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); ED_preview_kill_jobs(C); - last = ntree->nodes.last; + lastnode = ntree->nodes.last; for(node= ntree->nodes.first; node; node= node->next) { if(node->flag & SELECT) { newnode = nodeCopyNode(ntree, node); - /* deselect old node, select the copy instead */ - node->flag &= ~(NODE_SELECT|NODE_ACTIVE); - newnode->flag |= NODE_SELECT; - if(newnode->id) { /* simple id user adjustment, node internal functions dont touch this * but operators and readfile.c do. */ @@ -2105,7 +2103,54 @@ static int node_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) } /* make sure we don't copy new nodes again! */ - if (node==last) + if (node==lastnode) + break; + } + + /* copy links between selected nodes + * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! + */ + lastlink = ntree->links.last; + for (link=ntree->links.first; link; link=link->next) { + /* This creates new links between copied nodes. + * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! + */ + if (link->tonode && (link->tonode->flag & NODE_SELECT) + && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { + newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + newlink->flag = link->flag; + newlink->tonode = link->tonode->new_node; + newlink->tosock = link->tosock->new_sock; + if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) { + newlink->fromnode = link->fromnode->new_node; + newlink->fromsock = link->fromsock->new_sock; + } + else { + /* input node not copied, this keeps the original input linked */ + newlink->fromnode = link->fromnode; + newlink->fromsock = link->fromsock; + } + + BLI_addtail(&ntree->links, newlink); + } + + /* make sure we don't copy new links again! */ + if (link==lastlink) + break; + } + + /* deselect old nodes, select the copies instead */ + for(node= ntree->nodes.first; node; node= node->next) { + if(node->flag & SELECT) { + /* has been set during copy above */ + newnode = node->new_node; + + node->flag &= ~(NODE_SELECT|NODE_ACTIVE); + newnode->flag |= NODE_SELECT; + } + + /* make sure we don't copy new nodes again! */ + if (node==lastnode) break; } @@ -2131,6 +2176,8 @@ void NODE_OT_duplicate(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes"); } /* *************************** add link op ******************** */ @@ -2149,9 +2196,9 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeL if(tlink) { /* try to move the existing link to the next available socket */ if (tlink->tonode) { - /* is there a free input socket with same type? */ + /* is there a free input socket with the target type? */ for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) { - if(sock->type==tlink->fromsock->type) + if(sock->type==tlink->tosock->type) if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit) break; } @@ -2247,6 +2294,12 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event) /* 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) { + link->tosock->type = link->fromsock->type; + } } else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) { /* automatically add new group socket */ @@ -2523,6 +2576,151 @@ void NODE_OT_links_cut(wmOperatorType *ot) RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } +/* ********************* automatic node insert on dragging ******************* */ + +/* assumes sockets in list */ +static bNodeSocket *socket_best_match(ListBase *sockets, int type) +{ + bNodeSocket *sock; + + /* first, match type */ + for(sock= sockets->first; sock; sock= sock->next) + if(!(sock->flag & SOCK_HIDDEN)) + if(type == sock->type) + return sock; + + /* then just use first unhidden socket */ + for(sock= sockets->first; sock; sock= sock->next) + if(!(sock->flag & SOCK_HIDDEN)) + return sock; + + /* OK, let's unhide proper one */ + for(sock= sockets->first; sock; sock= sock->next) { + if(type == sock->type) { + sock->flag &= ~SOCK_HIDDEN; + return sock; + } + } + + /* just the first */ + sock= sockets->first; + sock->flag &= ~SOCK_HIDDEN; + + return sockets->first; +} + +/* prevent duplicate testing code below */ +static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select) +{ + SpaceNode *snode= sa?sa->spacedata.first:NULL; + bNode *node; + bNodeLink *link; + + /* no unlucky accidents */ + if(sa==NULL || sa->spacetype!=SPACE_NODE) return NULL; + + *select= NULL; + + for(node= snode->edittree->nodes.first; node; node= node->next) { + if(node->flag & SELECT) { + if(*select) + break; + else + *select= node; + } + } + /* only one selected */ + if(node || *select==NULL) return NULL; + + /* correct node */ + if((*select)->inputs.first==NULL || (*select)->outputs.first==NULL) return NULL; + + /* test node for links */ + for(link= snode->edittree->links.first; link; link=link->next) { + if(link->tonode == *select || link->fromnode == *select) + return NULL; + } + + return snode; +} + +/* assumes link with NODE_LINKFLAG_HILITE set */ +void ED_node_link_insert(ScrArea *sa) +{ + bNode *node, *select; + SpaceNode *snode= ed_node_link_conditions(sa, &select); + bNodeLink *link; + bNodeSocket *sockto; + + if(snode==NULL) return; + + /* get the link */ + for(link= snode->edittree->links.first; link; link=link->next) + if(link->flag & NODE_LINKFLAG_HILITE) + break; + + if(link) { + node= link->tonode; + sockto= link->tosock; + + link->tonode= select; + link->tosock= socket_best_match(&select->inputs, link->fromsock->type); + link->flag &= ~NODE_LINKFLAG_HILITE; + + nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs, sockto->type), node, sockto); + ntreeSolveOrder(snode->edittree); /* needed for pointers */ + snode_tag_changed(snode, select); + ED_node_changed_update(snode->id, select); + } +} + + +/* test == 0, clear all intersect flags */ +void ED_node_link_intersect_test(ScrArea *sa, int test) +{ + bNode *select; + SpaceNode *snode= ed_node_link_conditions(sa, &select); + bNodeLink *link, *selink=NULL; + float mcoords[6][2]; + + if(snode==NULL) return; + + /* clear flags */ + for(link= snode->edittree->links.first; link; link=link->next) + link->flag &= ~NODE_LINKFLAG_HILITE; + + if(test==0) return; + + /* okay, there's 1 node, without links, now intersect */ + mcoords[0][0]= select->totr.xmin; + mcoords[0][1]= select->totr.ymin; + mcoords[1][0]= select->totr.xmax; + mcoords[1][1]= select->totr.ymin; + mcoords[2][0]= select->totr.xmax; + mcoords[2][1]= select->totr.ymax; + mcoords[3][0]= select->totr.xmin; + mcoords[3][1]= select->totr.ymax; + mcoords[4][0]= select->totr.xmin; + mcoords[4][1]= select->totr.ymin; + mcoords[5][0]= select->totr.xmax; + mcoords[5][1]= select->totr.ymax; + + /* we only tag a single link for intersect now */ + /* idea; use header dist when more? */ + for(link= snode->edittree->links.first; link; link=link->next) { + + if(cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */ + if(selink) + break; + selink= link; + } + } + + if(link==NULL && selink) + selink->flag |= NODE_LINKFLAG_HILITE; +} + + /* ******************************** */ // XXX some code needing updating to operators... @@ -2941,6 +3139,118 @@ void NODE_OT_delete(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +/* ****************** Delete with reconnect ******************* */ + +/* note: in cmp_util.c is similar code, for node_compo_pass_on() */ +/* used for disabling node (similar code in node_draw.c for disable line) */ +static void node_delete_reconnect(bNodeTree* tree, bNode* node) +{ + bNodeLink *link, *next; + bNodeSocket *valsocket= NULL, *colsocket= NULL, *vecsocket= NULL; + bNodeSocket *deliveringvalsocket= NULL, *deliveringcolsocket= NULL, *deliveringvecsocket= NULL; + bNode *deliveringvalnode= NULL, *deliveringcolnode= NULL, *deliveringvecnode= NULL; + bNodeSocket *sock; + + /* test the inputs */ + for(sock= node->inputs.first; sock; sock= sock->next) { + int type = sock->type; + if(type==SOCK_VALUE && valsocket==NULL) valsocket = sock; + if(type==SOCK_VECTOR && vecsocket==NULL) vecsocket = sock; + if(type==SOCK_RGBA && colsocket==NULL) colsocket = sock; + } + // we now have the input sockets for the 'data types' + // now find the output sockets (and nodes) in the tree that delivers data to these input sockets + for(link= tree->links.first; link; link=link->next) { + if (valsocket != NULL) { + if (link->tosock == valsocket) { + deliveringvalnode = link->fromnode; + deliveringvalsocket = link->fromsock; + } + } + if (vecsocket != NULL) { + if (link->tosock == vecsocket) { + deliveringvecnode = link->fromnode; + deliveringvecsocket = link->fromsock; + } + } + if (colsocket != NULL) { + if (link->tosock == colsocket) { + deliveringcolnode = link->fromnode; + deliveringcolsocket = link->fromsock; + } + } + } + // we now have the sockets+nodes that fill the inputsockets be aware for group nodes these can be NULL + // now make the links for all outputlinks of the node to be reconnected + for(link= tree->links.first; link; link=next) { + next= link->next; + if (link->fromnode == node) { + sock = link->fromsock; + switch(sock->type) { + case SOCK_VALUE: + if (deliveringvalsocket) { + link->fromnode = deliveringvalnode; + link->fromsock = deliveringvalsocket; + } + break; + case SOCK_VECTOR: + if (deliveringvecsocket) { + link->fromnode = deliveringvecnode; + link->fromsock = deliveringvecsocket; + } + break; + case SOCK_RGBA: + if (deliveringcolsocket) { + link->fromnode = deliveringcolnode; + link->fromsock = deliveringcolsocket; + } + break; + } + } + } + if(node->id) + node->id->us--; + nodeFreeNode(tree, node); + +} + +static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode *snode= CTX_wm_space_node(C); + bNode *node, *next; + + ED_preview_kill_jobs(C); + + for(node= snode->edittree->nodes.first; node; node= next) { + next= node->next; + if(node->flag & SELECT) { + node_delete_reconnect(snode->edittree, node); + } + } + + node_tree_verify_groups(snode->nodetree); + + snode_notify(C, snode); + snode_dag_update(C, snode); + + return OPERATOR_FINISHED; +} + +void NODE_OT_delete_reconnect(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete with reconnect"; + ot->description = "Delete nodes; will reconnect nodes as if deletion was muted"; + ot->idname= "NODE_OT_delete_reconnect"; + + /* api callbacks */ + ot->exec= node_delete_reconnect_exec; + ot->poll= ED_operator_node_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /* ****************** Show Cyclic Dependencies Operator ******************* */ static int node_show_cycles_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3093,4 +3403,3 @@ void NODE_OT_auto_layout(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } - |