Index: source/blender/editors/space_node/node_edit.c |
=================================================================== |
--- source/blender/editors/space_node/node_edit.c (revision 43995) |
+++ source/blender/editors/space_node/node_edit.c (working copy) |
@@ -39,6 +39,8 @@ |
#include "MEM_guardedalloc.h" |
#include "DNA_ID.h" |
+#include "DNA_action_types.h" |
+#include "DNA_anim_types.h" |
#include "DNA_lamp_types.h" |
#include "DNA_material_types.h" |
#include "DNA_node_types.h" |
@@ -51,6 +53,8 @@ |
#include "BLI_blenlib.h" |
#include "BLI_utildefines.h" |
+#include "BKE_action.h" |
+#include "BKE_animsys.h" |
#include "BKE_context.h" |
#include "BKE_depsgraph.h" |
#include "BKE_global.h" |
@@ -93,13 +97,17 @@ |
#include "GPU_material.h" |
+#include "NOD_common.h" |
+#include "NOD_socket.h" |
#include "node_intern.h" |
+#if 0 /* UNUSED */ |
static EnumPropertyItem socket_in_out_items[] = { |
{ SOCK_IN, "SOCK_IN", 0, "Input", "" }, |
{ SOCK_OUT, "SOCK_OUT", 0, "Output", "" }, |
{ 0, NULL, 0, NULL, NULL }, |
}; |
+#endif |
/* ***************** composite job manager ********************** */ |
@@ -883,252 +891,177 @@ |
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
} |
-/* ***************** Add Group Socket operator ************* */ |
+/* ******************** Ungroup operator ********************** */ |
-static int node_group_socket_add_exec(bContext *C, wmOperator *op) |
+/* returns 1 if its OK */ |
+static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) |
{ |
- SpaceNode *snode = CTX_wm_space_node(C); |
- int in_out= -1; |
- char name[MAX_NAME]= ""; |
- int type= SOCK_FLOAT; |
- bNodeTree *ngroup= snode->edittree; |
- /* bNodeSocket *sock; */ /* UNUSED */ |
+ bNodeLink *link, *linkn; |
+ bNode *node, *nextnode; |
+ bNodeTree *ngroup, *wgroup; |
+ ListBase anim_basepaths = {NULL, NULL}; |
- ED_preview_kill_jobs(C); |
+ ngroup= (bNodeTree *)gnode->id; |
+ if(ngroup==NULL) return 0; |
- if (RNA_struct_property_is_set(op->ptr, "name")) |
- RNA_string_get(op->ptr, "name", name); |
+ /* clear new pointers, set in copytree */ |
+ for(node= ntree->nodes.first; node; node= node->next) |
+ node->new_node= NULL; |
- if (RNA_struct_property_is_set(op->ptr, "type")) |
- type = RNA_enum_get(op->ptr, "type"); |
+ /* wgroup is a temporary copy of the NodeTree we're merging in |
+ * - all of wgroup's nodes are transferred across to their new home |
+ * - ngroup (i.e. the source NodeTree) is left unscathed |
+ */ |
+ wgroup= ntreeCopyTree(ngroup); |
- if (RNA_struct_property_is_set(op->ptr, "in_out")) |
- in_out = RNA_enum_get(op->ptr, "in_out"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- /* using placeholder subtype first */ |
- /* sock = */ /* UNUSED */ node_group_add_socket(ngroup, name, type, in_out); |
- |
- ntreeUpdateTree(ngroup); |
- |
- snode_notify(C, snode); |
- |
- return OPERATOR_FINISHED; |
-} |
- |
-void NODE_OT_group_socket_add(wmOperatorType *ot) |
-{ |
- /* identifiers */ |
- ot->name = "Add Group Socket"; |
- ot->description = "Add node group socket"; |
- ot->idname = "NODE_OT_group_socket_add"; |
- |
- /* api callbacks */ |
- ot->exec = node_group_socket_add_exec; |
- ot->poll = ED_operator_node_active; |
- |
- /* flags */ |
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
- |
- RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); |
- RNA_def_string(ot->srna, "name", "", MAX_NAME, "Name", "Group socket name"); |
- RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket"); |
-} |
- |
-/* ***************** Remove Group Socket operator ************* */ |
- |
-static int node_group_socket_remove_exec(bContext *C, wmOperator *op) |
-{ |
- SpaceNode *snode = CTX_wm_space_node(C); |
- int index= -1; |
- int in_out= -1; |
- bNodeTree *ngroup= snode->edittree; |
- bNodeSocket *sock; |
- |
- ED_preview_kill_jobs(C); |
- |
- if (RNA_struct_property_is_set(op->ptr, "index")) |
- index = RNA_int_get(op->ptr, "index"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- if (RNA_struct_property_is_set(op->ptr, "in_out")) |
- in_out = RNA_enum_get(op->ptr, "in_out"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index); |
- if (sock) { |
- node_group_remove_socket(ngroup, sock, in_out); |
- ntreeUpdateTree(ngroup); |
- |
- snode_notify(C, snode); |
+ /* Restore external links to and from the gnode */ |
+ for(link= ntree->links.first; link; link= link->next) { |
+ if (link->fromnode==gnode) { |
+ bNode *output_node = ntreeFindOutputNode(ngroup, link->fromsock->own_index); |
+ bNodeSocket *output_sock = output_node->inputs.first; |
+ if (output_sock->link) { |
+ /* NB: using the new internal copies here! the link pointer still maps to the old tree */ |
+ link->fromnode = output_sock->link->fromnode->new_node; |
+ link->fromsock = output_sock->link->fromsock->new_sock; |
+ |
+ /* The internal fromnode could also be an input node! (direct input-to-output link) */ |
+ if (link->fromnode->type == NODE_PROXY_INPUT) { |
+ bNodeSocket *insock = node_group_find_input_socket(gnode, link->fromsock->own_index); |
+ if (insock->link) { |
+ link->fromnode = insock->link->fromnode; |
+ link->fromsock = insock->link->fromsock; |
+ } |
+ else { |
+ /* Copy the default input value from the group node socket default to the internal socket, then remove the link. */ |
+ node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, insock->type, insock->default_value); |
+ nodeRemLink(wgroup, link); |
+ } |
+ } |
+ } |
+ else { |
+ /* Copy the default input value from the group socket default to the external socket. |
+ * The link will be removed when the output_node is deleted. |
+ */ |
+ node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, output_sock->type, output_sock->default_value); |
+ } |
+ } |
} |
+ /* Restore links from internal nodes */ |
+ for(link= wgroup->links.first; link; link= link->next) { |
+ if (link->fromnode->type == NODE_PROXY_INPUT) { |
+ bNode *oldnode=NULL; |
+ bNodeSocket *oldsock=NULL; |
+ |
+ /* XXX by copying the ngroup to wgroup the proxy nodes have been assigned new own_index. |
+ * we need to look up the actual own_index from the original nodes. |
+ */ |
+ for (oldnode=ngroup->nodes.first; oldnode; oldnode=oldnode->next) { |
+ if (oldnode->new_node == link->fromnode) { |
+ for (oldsock=oldnode->outputs.first; oldsock; oldsock=oldsock->next) { |
+ if (oldsock->new_sock == link->fromsock) |
+ break; |
+ } |
+ if (oldsock) |
+ break; |
+ } |
+ } |
+ |
+ if (oldsock) { |
+ bNodeSocket *insock = node_group_find_input_socket(gnode, oldsock->own_index); |
+ if (insock->link) { |
+ link->fromnode = insock->link->fromnode; |
+ link->fromsock = insock->link->fromsock; |
+ } |
+ else { |
+ /* Copy the default input value from the group node socket default to the internal socket, then remove the link. */ |
+ node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, insock->type, insock->default_value); |
+ nodeRemLink(wgroup, link); |
+ } |
+ } |
+ } |
+ } |
- return OPERATOR_FINISHED; |
-} |
- |
-void NODE_OT_group_socket_remove(wmOperatorType *ot) |
-{ |
- /* identifiers */ |
- ot->name = "Remove Group Socket"; |
- ot->description = "Remove a node group socket"; |
- ot->idname = "NODE_OT_group_socket_remove"; |
- |
- /* api callbacks */ |
- ot->exec = node_group_socket_remove_exec; |
- ot->poll = ED_operator_node_active; |
- |
- /* flags */ |
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
- |
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); |
- RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); |
-} |
- |
-/* ***************** Move Group Socket Up operator ************* */ |
- |
-static int node_group_socket_move_up_exec(bContext *C, wmOperator *op) |
-{ |
- SpaceNode *snode = CTX_wm_space_node(C); |
- int index= -1; |
- int in_out= -1; |
- bNodeTree *ngroup= snode->edittree; |
- bNodeSocket *sock, *prev; |
- |
- ED_preview_kill_jobs(C); |
- |
- if (RNA_struct_property_is_set(op->ptr, "index")) |
- index = RNA_int_get(op->ptr, "index"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- if (RNA_struct_property_is_set(op->ptr, "in_out")) |
- in_out = RNA_enum_get(op->ptr, "in_out"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- /* swap */ |
- if (in_out==SOCK_IN) { |
- sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index); |
- prev = sock->prev; |
- /* can't move up the first socket */ |
- if (!prev) |
- return OPERATOR_CANCELLED; |
- BLI_remlink(&ngroup->inputs, sock); |
- BLI_insertlinkbefore(&ngroup->inputs, prev, sock); |
+ /* Add the nodes into the ntree */ |
+ for(node= wgroup->nodes.first; node; node= nextnode) { |
+ nextnode= node->next; |
- ngroup->update |= NTREE_UPDATE_GROUP_IN; |
- } |
- else if (in_out==SOCK_OUT) { |
- sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); |
- prev = sock->prev; |
- /* can't move up the first socket */ |
- if (!prev) |
- return OPERATOR_CANCELLED; |
- BLI_remlink(&ngroup->outputs, sock); |
- BLI_insertlinkbefore(&ngroup->outputs, prev, sock); |
+ /* Remove proxy nodes. |
+ * This also removes remaining links to and from proxy nodes. |
+ */ |
+ if (ELEM(node->type, NODE_PROXY_INPUT, NODE_PROXY_OUTPUT)) { |
+ nodeFreeNode(wgroup, node); |
+ continue; |
+ } |
- ngroup->update |= NTREE_UPDATE_GROUP_OUT; |
+ /* keep track of this node's RNA "base" path (the part of the pat identifying the node) |
+ * if the old nodetree has animation data which potentially covers this node |
+ */ |
+ if (wgroup->adt) { |
+ PointerRNA ptr; |
+ char *path; |
+ |
+ RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr); |
+ path = RNA_path_from_ID_to_struct(&ptr); |
+ |
+ if (path) |
+ BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); |
+ } |
+ |
+ /* migrate node */ |
+ BLI_remlink(&wgroup->nodes, node); |
+ BLI_addtail(&ntree->nodes, node); |
+ |
+ node->locx+= gnode->locx; |
+ node->locy+= gnode->locy; |
+ |
+ node->flag |= NODE_SELECT; |
} |
- ntreeUpdateTree(ngroup); |
- snode_notify(C, snode); |
+ /* Add internal links to the ntree */ |
+ for(link= wgroup->links.first; link; link= linkn) { |
+ linkn= link->next; |
+ BLI_remlink(&wgroup->links, link); |
+ BLI_addtail(&ntree->links, link); |
+ } |
- return OPERATOR_FINISHED; |
-} |
- |
-void NODE_OT_group_socket_move_up(wmOperatorType *ot) |
-{ |
- /* identifiers */ |
- ot->name = "Move Group Socket Up"; |
- ot->description = "Move up node group socket"; |
- ot->idname = "NODE_OT_group_socket_move_up"; |
- |
- /* api callbacks */ |
- ot->exec = node_group_socket_move_up_exec; |
- ot->poll = ED_operator_node_active; |
- |
- /* flags */ |
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
- |
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); |
- RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); |
-} |
- |
-/* ***************** Move Group Socket Up operator ************* */ |
- |
-static int node_group_socket_move_down_exec(bContext *C, wmOperator *op) |
-{ |
- SpaceNode *snode = CTX_wm_space_node(C); |
- int index= -1; |
- int in_out= -1; |
- bNodeTree *ngroup= snode->edittree; |
- bNodeSocket *sock, *next; |
- |
- ED_preview_kill_jobs(C); |
- |
- if (RNA_struct_property_is_set(op->ptr, "index")) |
- index = RNA_int_get(op->ptr, "index"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- if (RNA_struct_property_is_set(op->ptr, "in_out")) |
- in_out = RNA_enum_get(op->ptr, "in_out"); |
- else |
- return OPERATOR_CANCELLED; |
- |
- /* swap */ |
- if (in_out==SOCK_IN) { |
- sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index); |
- next = sock->next; |
- /* can't move down the last socket */ |
- if (!next) |
- return OPERATOR_CANCELLED; |
- BLI_remlink(&ngroup->inputs, sock); |
- BLI_insertlinkafter(&ngroup->inputs, next, sock); |
+ /* and copy across the animation, |
+ * note that the animation data's action can be NULL here */ |
+ if (wgroup->adt) { |
+ LinkData *ld, *ldn=NULL; |
+ bAction *waction; |
- ngroup->update |= NTREE_UPDATE_GROUP_IN; |
- } |
- else if (in_out==SOCK_OUT) { |
- sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index); |
- next = sock->next; |
- /* can't move down the last socket */ |
- if (!next) |
- return OPERATOR_CANCELLED; |
- BLI_remlink(&ngroup->outputs, sock); |
- BLI_insertlinkafter(&ngroup->outputs, next, sock); |
+ /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */ |
+ waction = wgroup->adt->action = copy_action(wgroup->adt->action); |
- ngroup->update |= NTREE_UPDATE_GROUP_OUT; |
+ /* now perform the moving */ |
+ BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths); |
+ |
+ /* paths + their wrappers need to be freed */ |
+ for (ld = anim_basepaths.first; ld; ld = ldn) { |
+ ldn = ld->next; |
+ |
+ MEM_freeN(ld->data); |
+ BLI_freelinkN(&anim_basepaths, ld); |
+ } |
+ |
+ /* free temp action too */ |
+ if (waction) { |
+ free_libblock(&G.main->action, waction); |
+ } |
} |
- ntreeUpdateTree(ngroup); |
- snode_notify(C, snode); |
- |
- return OPERATOR_FINISHED; |
-} |
+ /* delete the group instance */ |
+ nodeFreeNode(ntree, gnode); |
-void NODE_OT_group_socket_move_down(wmOperatorType *ot) |
-{ |
- /* identifiers */ |
- ot->name = "Move Group Socket Down"; |
- ot->description = "Move down node group socket"; |
- ot->idname = "NODE_OT_group_socket_move_down"; |
+ /* free the group tree (takes care of user count) */ |
+ free_libblock(&G.main->nodetree, wgroup); |
- /* api callbacks */ |
- ot->exec = node_group_socket_move_down_exec; |
- ot->poll = ED_operator_node_active; |
+ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; |
+ ntreeUpdateTree(ntree); |
- /* flags */ |
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; |
- |
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX); |
- RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output"); |
+ return 1; |
} |
-/* ******************** Ungroup operator ********************** */ |
- |
static int node_group_ungroup_exec(bContext *C, wmOperator *op) |
{ |
SpaceNode *snode = CTX_wm_space_node(C); |
@@ -1832,32 +1765,6 @@ |
} |
} |
- /* check group sockets |
- * NB: using ngroup->outputs as input sockets and vice versa here! |
- */ |
- if(in_out & SOCK_IN) { |
- for(sock= snode->edittree->outputs.first; sock; sock= sock->next) { |
- if(!nodeSocketIsHidden(sock)) { |
- if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { |
- *nodep= NULL; /* NULL node pointer indicates group socket */ |
- *sockp= sock; |
- return 1; |
- } |
- } |
- } |
- } |
- if(in_out & SOCK_OUT) { |
- for(sock= snode->edittree->inputs.first; sock; sock= sock->next) { |
- if(!nodeSocketIsHidden(sock)) { |
- if(BLI_in_rctf(&rect, sock->locx, sock->locy)) { |
- *nodep= NULL; /* NULL node pointer indicates group socket */ |
- *sockp= sock; |
- return 1; |
- } |
- } |
- } |
- } |
- |
return 0; |
} |
@@ -1898,16 +1805,6 @@ |
return redraw; |
} |
-static int outside_group_rect(SpaceNode *snode) |
-{ |
- bNode *gnode= node_tree_get_editgroup(snode->nodetree); |
- if (gnode) { |
- return (snode->mx < gnode->totr.xmin || snode->mx >= gnode->totr.xmax |
- || snode->my < gnode->totr.ymin || snode->my >= gnode->totr.ymax); |
- } |
- return 0; |
-} |
- |
/* ****************** Add *********************** */ |
@@ -2269,6 +2166,7 @@ |
bNodeSocket *tsock= NULL, *sock; |
bNodeLink *link; |
int in_out; |
+ int expose; |
in_out= nldrag->in_out; |
node= nldrag->node; |
@@ -2278,6 +2176,8 @@ |
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], |
&snode->mx, &snode->my); |
+ expose = RNA_boolean_get(op->ptr, "expose"); |
+ |
switch (event->type) { |
case MOUSEMOVE: |
@@ -2351,31 +2251,55 @@ |
/* we might need to remove a link */ |
if(in_out==SOCK_OUT) |
node_remove_extra_links(snode, link->tosock, link); |
+ } |
+ else if (expose) { |
+ /* offsets for initial placing of the node */ |
+ bNode *gnode = node_tree_get_editgroup(snode->nodetree); |
+ float offsetx = (gnode ? gnode->locx : 0.0f); |
+ float offsety = (gnode ? gnode->locy : 0.0f); |
- /* 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 */ |
- if (link->tonode && link->tosock) { |
- link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN); |
- link->fromnode = NULL; |
+ bNode *proxy_node = NULL; |
+ if (link->tosock) { |
+ proxy_node = ntreeExposeInput(snode->edittree, link->tonode, link->tosock, 0); |
+ link->fromnode = proxy_node; |
+ link->fromsock = proxy_node->outputs.first; |
if (link->prev==NULL && link->next==NULL) { |
BLI_addtail(&snode->edittree->links, link); |
} |
snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS; |
+ |
+ { |
+ /* place the node at the mouse pointer */ |
+ float sockx = 42.f + 3*HIDDEN_RAD; /* XXX totally arbitrary initial hidden node size ... */ |
+ float socky = -HIDDEN_RAD; |
+ |
+ /* node loc must be relative to group node */ |
+ proxy_node->locx = snode->mx - offsetx - sockx; |
+ proxy_node->locy = snode->my - offsety - socky; |
+ } |
} |
- else if (link->fromnode && link->fromsock) { |
- link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT); |
- link->tonode = NULL; |
+ else if (link->fromsock) { |
+ proxy_node = ntreeExposeOutput(snode->edittree, link->fromnode, link->fromsock, 0); |
+ link->tonode = proxy_node; |
+ link->tosock = proxy_node->inputs.first; |
if (link->prev==NULL && link->next==NULL) { |
BLI_addtail(&snode->edittree->links, link); |
} |
snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS; |
+ |
+ { |
+ /* place the node at the mouse pointer */ |
+ float sockx = 0; |
+ float socky = -HIDDEN_RAD; |
+ |
+ /* node loc must be relative to group node */ |
+ proxy_node->locx = snode->mx - offsetx - sockx; |
+ proxy_node->locy = snode->my - offsety - socky; |
+ } |
} |
+ else { |
+ nodeRemLink(snode->edittree, link); |
+ } |
} |
else |
nodeRemLink(snode->edittree, link); |
@@ -2514,6 +2438,9 @@ |
/* flags */ |
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; |
+ |
+ /* properties */ |
+ RNA_def_boolean(ot->srna, "expose", 0, "Expose", "Create a proxy node when releasing link in empty area"); |
} |
/* ********************** Make Link operator ***************** */ |
@@ -2913,6 +2840,170 @@ |
/* ****************** Make Group operator ******************* */ |
+static bNode *node_group_make_from_selected(bNodeTree *ntree) |
+{ |
+ bNodeLink *link, *linkn; |
+ bNode *node, *gnode, *nextn; |
+ bNodeTree *ngroup; |
+ ListBase anim_basepaths = {NULL, NULL}; |
+ float min[2], max[2]; |
+ float offsetx, offsety; |
+ int totnode=0; |
+ bNodeTemplate ntemp; |
+ |
+ INIT_MINMAX2(min, max); |
+ |
+ /* is there something to group? also do some clearing */ |
+ for(node= ntree->nodes.first; node; node= node->next) { |
+ if(node->flag & NODE_SELECT) { |
+ /* no groups in groups */ |
+ if(node->type==NODE_GROUP) |
+ return NULL; |
+ DO_MINMAX2( (&node->locx), min, max); |
+ totnode++; |
+ } |
+ node->done= 0; |
+ } |
+ if(totnode==0) return NULL; |
+ |
+ offsetx = 0.5f*(min[0]+max[0]); |
+ offsety = 0.5f*(min[1]+max[1]); |
+ |
+ /* check if all connections are OK, no unselected node has both |
+ inputs and outputs to a selection */ |
+ for(link= ntree->links.first; link; link= link->next) { |
+ if(link->fromnode->flag & NODE_SELECT) |
+ link->tonode->done |= 1; |
+ if(link->tonode->flag & NODE_SELECT) |
+ link->fromnode->done |= 2; |
+ } |
+ |
+ for(node= ntree->nodes.first; node; node= node->next) { |
+ if((node->flag & NODE_SELECT)==0) |
+ if(node->done==3) |
+ break; |
+ } |
+ if(node) |
+ return NULL; |
+ |
+ /* OK! new nodetree */ |
+ ngroup= ntreeAddTree("NodeGroup", ntree->type, NODE_GROUP); |
+ |
+ /* move nodes over */ |
+ for(node= ntree->nodes.first; node; node= nextn) { |
+ nextn= node->next; |
+ if(node->flag & NODE_SELECT) { |
+ /* keep track of this node's RNA "base" path (the part of the pat identifying the node) |
+ * if the old nodetree has animation data which potentially covers this node |
+ */ |
+ if (ntree->adt) { |
+ PointerRNA ptr; |
+ char *path; |
+ |
+ RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); |
+ path = RNA_path_from_ID_to_struct(&ptr); |
+ |
+ if (path) |
+ BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); |
+ } |
+ |
+ /* change node-collection membership */ |
+ BLI_remlink(&ntree->nodes, node); |
+ BLI_addtail(&ngroup->nodes, node); |
+ |
+ node->locx -= offsetx; |
+ node->locy -= offsety; |
+ } |
+ } |
+ |
+ /* move animation data over */ |
+ if (ntree->adt) { |
+ LinkData *ld, *ldn=NULL; |
+ |
+ BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); |
+ |
+ /* paths + their wrappers need to be freed */ |
+ for (ld = anim_basepaths.first; ld; ld = ldn) { |
+ ldn = ld->next; |
+ |
+ MEM_freeN(ld->data); |
+ BLI_freelinkN(&anim_basepaths, ld); |
+ } |
+ } |
+ |
+ /* node groups don't use internal cached data */ |
+ ntreeFreeCache(ngroup); |
+ |
+ /* make group node */ |
+ ntemp.type = NODE_GROUP; |
+ ntemp.ngroup = ngroup; |
+ gnode= nodeAddNode(ntree, &ntemp); |
+ gnode->locx = offsetx; |
+ gnode->locy = offsety; |
+ |
+ /* relink external sockets */ |
+ for(link= ntree->links.first; link; link= linkn) { |
+ linkn= link->next; |
+ |
+ if(link->fromnode->flag & link->tonode->flag & NODE_SELECT) { |
+ BLI_remlink(&ntree->links, link); |
+ BLI_addtail(&ngroup->links, link); |
+ } |
+ else if(link->tonode->flag & NODE_SELECT) { |
+ bNode *input_node = ntreeExposeInput(ngroup, link->tonode, link->tosock, 1); |
+ bNodeSocket *input_sock = input_node->outputs.first; |
+ |
+ { |
+ /* place the interface node next to the original socket */ |
+ float sockx = 42.f + 3*HIDDEN_RAD; /* XXX totally arbitrary initial hidden node size ... */ |
+ float socky = -HIDDEN_RAD; |
+ |
+ /* socket loc is absolute, node loc must be relative to group node */ |
+ input_node->locx = link->tosock->locx - offsetx - sockx - 25; |
+ input_node->locy = link->tosock->locy - offsety - socky; |
+ } |
+ |
+ link->tosock = node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, input_sock); |
+ link->tonode = gnode; |
+ } |
+ else if(link->fromnode->flag & NODE_SELECT) { |
+ /* search for existing group node socket */ |
+ bNode *output_node = ntreeFindOutputNodeByLink(ngroup, link->fromsock); |
+ bNodeSocket *output_sock; |
+ if (output_node) { |
+ output_sock = output_node->inputs.first; |
+ link->fromsock = node_group_find_output_socket(gnode, output_sock->own_index); |
+ } |
+ else { |
+ output_node = ntreeExposeOutput(ngroup, link->fromnode, link->fromsock, 1); |
+ output_sock = output_node->inputs.first; |
+ |
+ { |
+ /* place the interface node next to the original socket */ |
+ float sockx = 0; |
+ float socky = -HIDDEN_RAD; |
+ |
+ /* socket loc is absolute, node loc must be relative to group node */ |
+ output_node->locx = link->fromsock->locx - offsetx - sockx + 25; |
+ output_node->locy = link->fromsock->locy - offsety - socky; |
+ } |
+ |
+ link->fromsock = node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, output_sock); |
+ } |
+ link->fromnode = gnode; |
+ } |
+ } |
+ |
+ /* update of the group tree */ |
+ ngroup->update |= NTREE_UPDATE; |
+ ntreeUpdateTree(ngroup); |
+ /* update of the tree containing the group instance node */ |
+ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; |
+ ntreeUpdateTree(ntree); |
+ |
+ return gnode; |
+} |
+ |
static int node_group_make_exec(bContext *C, wmOperator *op) |
{ |
SpaceNode *snode = CTX_wm_space_node(C); |
@@ -3587,3 +3678,105 @@ |
RNA_def_enum(ot->srna, "type", nodetree_type_items, NTREE_COMPOSIT, "Tree Type", ""); |
RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME-2, "Name", ""); |
} |
+ |
+/********************** Move interface item operators *********************/ |
+ |
+static EnumPropertyItem move_direction_items[] = { |
+ { 1, "UP", 0, "Up", "" }, |
+ { 2, "DOWN", 0, "Down", "" }, |
+ { 0, NULL, 0, NULL, NULL }, |
+}; |
+ |
+static bNodeProxyItem *ntree_get_active_proxy_item(ListBase *lb) |
+{ |
+ bNodeProxyItem *item; |
+ for (item=lb->first; item; item=item->next) |
+ if (item->node->flag & NODE_ACTIVE) |
+ return item; |
+ return NULL; |
+} |
+ |
+static int move_interface_item(ListBase *lb, int direction) |
+{ |
+ bNodeProxyItem *item; |
+ |
+ item = ntree_get_active_proxy_item(lb); |
+ if (!item) |
+ return OPERATOR_CANCELLED; |
+ |
+ switch (direction) { |
+ case 1: { /* up */ |
+ bNodeProxyItem *before = item->prev; |
+ BLI_remlink(lb, item); |
+ if (before) |
+ BLI_insertlinkbefore(lb, before, item); |
+ else |
+ BLI_addhead(lb, item); |
+ break; |
+ } |
+ case 2: { /* down */ |
+ bNodeProxyItem *after = item->next; |
+ BLI_remlink(lb, item); |
+ if (after) |
+ BLI_insertlinkafter(lb, after, item); |
+ else |
+ BLI_addtail(lb, item); |
+ break; |
+ } |
+ } |
+ return OPERATOR_FINISHED; |
+} |
+ |
+static int move_input_item_exec(bContext *C, wmOperator *op) |
+{ |
+ SpaceNode *snode = CTX_wm_space_node(C); |
+ int direction = RNA_enum_get(op->ptr, "direction"); |
+ |
+ int result = move_interface_item(&snode->edittree->proxy_inputs, direction); |
+ ntreeUpdateTree(snode->edittree); |
+ |
+ return result; |
+} |
+ |
+void NODE_OT_move_input_item(wmOperatorType *ot) |
+{ |
+ /* identifiers */ |
+ ot->name= "Move Input Item"; |
+ ot->idname= "NODE_OT_move_input_item"; |
+ |
+ /* api callbacks */ |
+ ot->exec= move_input_item_exec; |
+ ot->poll= ED_operator_node_active; |
+ |
+ /* flags */ |
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; |
+ |
+ RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", ""); |
+} |
+ |
+static int move_output_item_exec(bContext *C, wmOperator *op) |
+{ |
+ SpaceNode *snode = CTX_wm_space_node(C); |
+ int direction = RNA_enum_get(op->ptr, "direction"); |
+ |
+ int result = move_interface_item(&snode->edittree->proxy_outputs, direction); |
+ ntreeUpdateTree(snode->edittree); |
+ |
+ return result; |
+} |
+ |
+void NODE_OT_move_output_item(wmOperatorType *ot) |
+{ |
+ /* identifiers */ |
+ ot->name= "Move Output Item"; |
+ ot->idname= "NODE_OT_move_output_item"; |
+ |
+ /* api callbacks */ |
+ ot->exec= move_output_item_exec; |
+ ot->poll= ED_operator_node_active; |
+ |
+ /* flags */ |
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; |
+ |
+ RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", ""); |
+} |