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:
Diffstat (limited to 'source/blender/editors/space_node/node_edit.c')
-rw-r--r--source/blender/editors/space_node/node_edit.c333
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;
}
-