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.c1117
1 files changed, 859 insertions, 258 deletions
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 99f2ea99efc..b5633d50997 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -40,9 +40,11 @@
#include "MEM_guardedalloc.h"
+#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -58,11 +60,17 @@
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_material.h"
+#include "BKE_modifier.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_texture.h"
#include "BKE_report.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_storage_types.h"
+
#include "RE_pipeline.h"
#include "IMB_imbuf_types.h"
@@ -74,11 +82,13 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "IMB_imbuf.h"
@@ -88,9 +98,9 @@
#include "node_intern.h"
static EnumPropertyItem socket_in_out_items[] = {
- { SOCK_IN, "IN", 0, "In", "" },
- { SOCK_OUT, "OUT", 0, "Out", "" },
- { 0, NULL, 0, NULL, NULL}
+ { SOCK_IN, "SOCK_IN", 0, "Input", "" },
+ { SOCK_OUT, "SOCK_OUT", 0, "Output", "" },
+ { 0, NULL, 0, NULL, NULL },
};
/* ***************** composite job manager ********************** */
@@ -227,7 +237,7 @@ static bNode *editnode_get_active(bNodeTree *ntree)
/* check for edited group */
for(node= ntree->nodes.first; node; node= node->next)
- if(node->flag & NODE_GROUP_EDIT)
+ if(nodeGroupEditGet(node))
break;
if(node)
return nodeGetActive((bNodeTree *)node->id);
@@ -258,7 +268,7 @@ bNode *node_tree_get_editgroup(bNodeTree *nodetree)
/* get the groupnode */
for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next)
- if(gnode->flag & NODE_GROUP_EDIT)
+ if(nodeGroupEditGet(gnode))
break;
return gnode;
}
@@ -269,6 +279,7 @@ void ED_node_shader_default(Material *ma)
{
bNode *in, *out;
bNodeSocket *fromsock, *tosock;
+ bNodeTemplate ntemp;
/* but lets check it anyway */
if(ma->nodetree) {
@@ -277,12 +288,14 @@ void ED_node_shader_default(Material *ma)
return;
}
- ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, FALSE);
+ ma->nodetree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
- out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL, NULL);
+ ntemp.type = SH_NODE_OUTPUT;
+ out= nodeAddNode(ma->nodetree, &ntemp);
out->locx= 300.0f; out->locy= 300.0f;
- in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL, NULL);
+ ntemp.type = SH_NODE_MATERIAL;
+ in= nodeAddNode(ma->nodetree, &ntemp);
in->locx= 10.0f; in->locy= 300.0f;
nodeSetActive(ma->nodetree, in);
@@ -291,7 +304,7 @@ void ED_node_shader_default(Material *ma)
tosock= out->inputs.first;
nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
- ntreeSolveOrder(ma->nodetree); /* needed for pointers */
+ ntreeUpdateTree(ma->nodetree);
}
/* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -300,6 +313,7 @@ void ED_node_composit_default(Scene *sce)
{
bNode *in, *out;
bNodeSocket *fromsock, *tosock;
+ bNodeTemplate ntemp;
/* but lets check it anyway */
if(sce->nodetree) {
@@ -308,14 +322,16 @@ void ED_node_composit_default(Scene *sce)
return;
}
- sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, FALSE);
+ sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0);
- out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL, NULL);
+ ntemp.type = CMP_NODE_COMPOSITE;
+ out= nodeAddNode(sce->nodetree, &ntemp);
out->locx= 300.0f; out->locy= 400.0f;
out->id= &sce->id;
id_us_plus(out->id);
- in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL, NULL);
+ ntemp.type = CMP_NODE_R_LAYERS;
+ in= nodeAddNode(sce->nodetree, &ntemp);
in->locx= 10.0f; in->locy= 400.0f;
in->id= &sce->id;
id_us_plus(in->id);
@@ -326,7 +342,7 @@ void ED_node_composit_default(Scene *sce)
tosock= out->inputs.first;
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
- ntreeSolveOrder(sce->nodetree); /* needed for pointers */
+ ntreeUpdateTree(sce->nodetree);
// XXX ntreeCompositForceHidden(sce->nodetree);
}
@@ -337,6 +353,7 @@ void ED_node_texture_default(Tex *tx)
{
bNode *in, *out;
bNodeSocket *fromsock, *tosock;
+ bNodeTemplate ntemp;
/* but lets check it anyway */
if(tx->nodetree) {
@@ -345,12 +362,14 @@ void ED_node_texture_default(Tex *tx)
return;
}
- tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, FALSE);
+ tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0);
- out= nodeAddNodeType(tx->nodetree, TEX_NODE_OUTPUT, NULL, NULL);
+ ntemp.type = TEX_NODE_OUTPUT;
+ out= nodeAddNode(tx->nodetree, &ntemp);
out->locx= 300.0f; out->locy= 300.0f;
- in= nodeAddNodeType(tx->nodetree, TEX_NODE_CHECKER, NULL, NULL);
+ ntemp.type = TEX_NODE_CHECKER;
+ in= nodeAddNode(tx->nodetree, &ntemp);
in->locx= 10.0f; in->locy= 300.0f;
nodeSetActive(tx->nodetree, in);
@@ -358,43 +377,53 @@ void ED_node_texture_default(Tex *tx)
tosock= out->inputs.first;
nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
- ntreeSolveOrder(tx->nodetree); /* needed for pointers */
+ ntreeUpdateTree(tx->nodetree);
}
/* id is supposed to contain a node tree */
void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype)
{
- bNode *node= NULL;
- short idtype= GS(id->name);
-
- if(idtype == ID_MA) {
- *ntree= ((Material*)id)->nodetree;
- if(treetype) *treetype= NTREE_SHADER;
- }
- else if(idtype == ID_SCE) {
- *ntree= ((Scene*)id)->nodetree;
- if(treetype) *treetype= NTREE_COMPOSIT;
- }
- else if(idtype == ID_TE) {
- *ntree= ((Tex*)id)->nodetree;
- if(treetype) *treetype= NTREE_TEXTURE;
+ if (id) {
+ bNode *node= NULL;
+ short idtype= GS(id->name);
+
+ if(idtype == ID_NT) {
+ *ntree= (bNodeTree*)id;
+ if(treetype) *treetype= (*ntree)->type;
+ }
+ else if(idtype == ID_MA) {
+ *ntree= ((Material*)id)->nodetree;
+ if(treetype) *treetype= NTREE_SHADER;
+ }
+ else if(idtype == ID_SCE) {
+ *ntree= ((Scene*)id)->nodetree;
+ if(treetype) *treetype= NTREE_COMPOSIT;
+ }
+ else if(idtype == ID_TE) {
+ *ntree= ((Tex*)id)->nodetree;
+ if(treetype) *treetype= NTREE_TEXTURE;
+ }
+ else {
+ if(treetype) *treetype= 0;
+ return;
+ }
+
+ /* find editable group */
+ if(edittree) {
+ if(*ntree)
+ for(node= (*ntree)->nodes.first; node; node= node->next)
+ if(nodeGroupEditGet(node))
+ break;
+
+ if(node && node->id)
+ *edittree= (bNodeTree *)node->id;
+ else
+ *edittree= *ntree;
+ }
}
else {
+ *ntree= NULL;
if(treetype) *treetype= 0;
- return;
- }
-
- /* find editable group */
- if(edittree) {
- if(*ntree)
- for(node= (*ntree)->nodes.first; node; node= node->next)
- if(node->flag & NODE_GROUP_EDIT)
- break;
-
- if(node && node->id)
- *edittree= (bNodeTree *)node->id;
- else
- *edittree= *ntree;
}
}
@@ -403,8 +432,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene)
{
Object *ob= OBACT;
- snode->nodetree= NULL;
- snode->edittree= NULL;
snode->id= snode->from= NULL;
if(snode->treetype==NTREE_SHADER) {
@@ -418,7 +445,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene)
}
}
else if(snode->treetype==NTREE_COMPOSIT) {
- snode->from= NULL;
snode->id= &scene->id;
/* bit clumsy but reliable way to see if we draw first time */
@@ -461,9 +487,14 @@ void snode_set_context(SpaceNode *snode, Scene *scene)
}
}
}
+ else {
+ if (snode->nodetree && snode->nodetree->type == snode->treetype)
+ snode->id = &snode->nodetree->id;
+ else
+ snode->id = NULL;
+ }
- if(snode->id)
- node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
+ node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
}
static void snode_tag_changed(SpaceNode *snode, bNode *node)
@@ -479,79 +510,90 @@ static void snode_tag_changed(SpaceNode *snode, bNode *node)
NodeTagIDChanged(snode->nodetree, gnode->id);
}
-void node_set_active(SpaceNode *snode, bNode *node)
+static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
+{
+ bNode *node;
+
+ if(ntree == lookup)
+ return 1;
+
+ for(node=ntree->nodes.first; node; node=node->next)
+ if(node->type == NODE_GROUP && node->id)
+ if(has_nodetree((bNodeTree*)node->id, lookup))
+ return 1;
+
+ return 0;
+}
+
+void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
{
- nodeSetActive(snode->edittree, node);
+ nodeSetActive(ntree, node);
if(node->type!=NODE_GROUP) {
int was_output= (node->flag & NODE_DO_OUTPUT);
/* tree specific activate calls */
- if(snode->treetype==NTREE_SHADER) {
+ if(ntree->type==NTREE_SHADER) {
/* when we select a material, active texture is cleared, for buttons */
if(node->id && GS(node->id->name)==ID_MA)
- nodeClearActiveID(snode->edittree, ID_TE);
+ nodeClearActiveID(ntree, ID_TE);
if(node->type==SH_NODE_OUTPUT) {
bNode *tnode;
- for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
+ for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
if( tnode->type==SH_NODE_OUTPUT)
tnode->flag &= ~NODE_DO_OUTPUT;
node->flag |= NODE_DO_OUTPUT;
if(was_output==0)
- ED_node_changed_update(snode->id, node);
+ ED_node_generic_update(bmain, ntree, node);
}
- // XXX
-#if 0
- if(node->id)
- ; // XXX BIF_preview_changed(-1); /* temp hack to force texture preview to update */
-
- // allqueue(REDRAWBUTSSHADING, 1);
- // allqueue(REDRAWIPO, 0);
-#endif
+ WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
}
- else if(snode->treetype==NTREE_COMPOSIT) {
- Scene *scene= (Scene*)snode->id;
-
+ else if(ntree->type==NTREE_COMPOSIT) {
/* make active viewer, currently only 1 supported... */
if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
bNode *tnode;
- for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
+ for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
tnode->flag &= ~NODE_DO_OUTPUT;
node->flag |= NODE_DO_OUTPUT;
- if(was_output==0) {
- snode_tag_changed(snode, node);
-
- ED_node_changed_update(snode->id, node);
- }
+ if(was_output==0)
+ ED_node_generic_update(bmain, ntree, node);
/* addnode() doesnt link this yet... */
node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
}
else if(node->type==CMP_NODE_R_LAYERS) {
- if(node->id==NULL || node->id==(ID *)scene) {
- scene->r.actlay= node->custom1;
+ Scene *scene;
+
+ for(scene=bmain->scene.first; scene; scene=scene->id.next) {
+ if(scene->nodetree && scene->use_nodes && has_nodetree(scene->nodetree, ntree)) {
+ if(node->id==NULL || node->id==(ID *)scene) {
+ scene->r.actlay= node->custom1;
+ }
+ }
}
}
else if(node->type==CMP_NODE_COMPOSITE) {
- bNode *tnode;
-
- for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
- if( tnode->type==CMP_NODE_COMPOSITE)
- tnode->flag &= ~NODE_DO_OUTPUT;
-
- node->flag |= NODE_DO_OUTPUT;
- ED_node_changed_update(snode->id, node);
+ if (was_output==0) {
+ bNode *tnode;
+
+ for(tnode= ntree->nodes.first; tnode; tnode= tnode->next)
+ if( tnode->type==CMP_NODE_COMPOSITE)
+ tnode->flag &= ~NODE_DO_OUTPUT;
+
+ node->flag |= NODE_DO_OUTPUT;
+ ED_node_generic_update(bmain, ntree, node);
+ }
}
}
- else if(snode->treetype==NTREE_TEXTURE) {
+ else if(ntree->type==NTREE_TEXTURE) {
// XXX
#if 0
if(node->id)
@@ -563,17 +605,199 @@ void node_set_active(SpaceNode *snode, bNode *node)
}
}
-/* when links in groups change, inputs/outputs change, nodes added/deleted... */
-void node_tree_verify_groups(bNodeTree *nodetree)
+static int compare_nodes(bNode *a, bNode *b)
{
- bNode *gnode;
+ bNode *parent;
+
+ /* if one is an ancestor of the other */
+ /* XXX there might be a better sorting algorithm for stable topological sort, this is O(n^2) worst case */
+ for (parent = a->parent; parent; parent=parent->parent) {
+ if (parent==b)
+ return 1;
+ }
+ for (parent = b->parent; parent; parent=parent->parent) {
+ if (parent==a)
+ return 0;
+ }
+
+ /* if one of the nodes is in the background and the other not */
+ if ((a->flag & NODE_BACKGROUND) && !(b->typeinfo->flag & NODE_BACKGROUND))
+ return 0;
+ else if (!(a->flag & NODE_BACKGROUND) && (b->typeinfo->flag & NODE_BACKGROUND))
+ return 1;
- gnode= node_tree_get_editgroup(nodetree);
+ /* if one has a higher selection state (active > selected > nothing) */
+ if (!(b->flag & NODE_ACTIVE) && (a->flag & NODE_ACTIVE))
+ return 1;
+ else if (!(b->flag & NODE_SELECT) && ((a->flag & NODE_ACTIVE) || (a->flag & NODE_SELECT)))
+ return 1;
- /* does all materials */
- if(gnode)
- nodeGroupVerify((bNodeTree *)gnode->id);
+ return 0;
+}
+/* Sorts nodes by selection: unselected nodes first, then selected,
+ * then the active node at the very end. Relative order is kept intact!
+ */
+void node_sort(bNodeTree *ntree)
+{
+ /* merge sort is the algorithm of choice here */
+ bNode *first_a, *first_b, *node_a, *node_b, *tmp;
+ int totnodes= BLI_countlist(&ntree->nodes);
+ int k, a, b;
+ k = 1;
+ while (k < totnodes) {
+ first_a = first_b = ntree->nodes.first;
+
+ do {
+ /* setup first_b pointer */
+ for (b=0; b < k && first_b; ++b) {
+ first_b = first_b->next;
+ }
+ /* all batches merged? */
+ if (first_b==NULL)
+ break;
+
+ /* merge batches */
+ node_a = first_a;
+ node_b = first_b;
+ a = b = 0;
+ while (a < k && b < k && node_b) {
+ if (compare_nodes(node_a, node_b)==0) {
+ node_a = node_a->next;
+ ++a;
+ }
+ else {
+ tmp = node_b;
+ node_b = node_b->next;
+ ++b;
+ BLI_remlink(&ntree->nodes, tmp);
+ BLI_insertlinkbefore(&ntree->nodes, node_a, tmp);
+ }
+ }
+
+ /* setup first pointers for next batch */
+ first_b = node_b;
+ for (; b < k; ++b) {
+ /* all nodes sorted? */
+ if (first_b==NULL)
+ break;
+ first_b = first_b->next;
+ }
+ first_a = first_b;
+ } while (first_b);
+
+ k = k << 1;
+ }
+}
+
+static int inside_rctf(rctf *bounds, rctf *rect)
+{
+ return (bounds->xmin <= rect->xmin && bounds->xmax >= rect->xmax
+ && bounds->ymin <= rect->ymin && bounds->ymax >= rect->ymax);
+}
+
+static void node_frame_attach_nodes(bNodeTree *UNUSED(ntree), bNode *frame)
+{
+ bNode *node;
+
+ /* only check nodes on top of the frame for attaching */
+ for (node=frame->next; node; node=node->next) {
+ if (node->parent==frame) {
+ /* detach nodes that went outside the frame */
+ if (!inside_rctf(&frame->totr, &node->totr))
+ nodeDetachNode(node);
+ }
+ else if (node->flag & NODE_SELECT && node->parent==NULL) {
+ /* attach selected, still unparented nodes */
+ if (inside_rctf(&frame->totr, &node->totr))
+ nodeAttachNode(node, frame);
+ }
+ }
+}
+
+void ED_node_update_hierarchy(bContext *UNUSED(C), bNodeTree *ntree)
+{
+ bNode *node;
+
+ /* XXX This does not work due to layout functions relying on node->block,
+ * which only exists during actual drawing. Can we rely on valid totr rects?
+ */
+ /* make sure nodes have correct bounding boxes after transform */
+// node_update_nodetree(C, ntree, 0.0f, 0.0f);
+
+ /* all selected nodes are re-parented */
+ for (node=ntree->nodes.last; node; node=node->prev) {
+ if (node->flag & NODE_SELECT && node->parent)
+ nodeDetachNode(node);
+ }
+
+ /* update higher Z-level nodes first */
+ for (node=ntree->nodes.last; node; node=node->prev) {
+ /* XXX callback? */
+ if (node->type==NODE_FRAME)
+ node_frame_attach_nodes(ntree, node);
+ }
+}
+
+/* ***************** generic operator functions for nodes ***************** */
+
+static int edit_node_poll(bContext *C)
+{
+ return ED_operator_node_active(C);
+}
+
+static void edit_node_properties(wmOperatorType *ot)
+{
+ /* XXX could node be a context pointer? */
+ RNA_def_string(ot->srna, "node", "", 32, "Node", "");
+ RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
+ RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", "");
+}
+
+static int edit_node_invoke_properties(bContext *C, wmOperator *op)
+{
+ if (!RNA_property_is_set(op->ptr, "node")) {
+ bNode *node= CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
+ if (!node)
+ return 0;
+ else
+ RNA_string_set(op->ptr, "node", node->name);
+ }
+
+ if (!RNA_property_is_set(op->ptr, "in_out"))
+ RNA_enum_set(op->ptr, "in_out", SOCK_IN);
+
+ if (!RNA_property_is_set(op->ptr, "socket"))
+ RNA_int_set(op->ptr, "socket", 0);
+
+ return 1;
+}
+
+static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ char nodename[32];
+ int sockindex;
+ int in_out;
+
+ RNA_string_get(op->ptr, "node", nodename);
+ node = nodeFindNodebyName(ntree, nodename);
+
+ in_out = RNA_enum_get(op->ptr, "in_out");
+
+ sockindex = RNA_int_get(op->ptr, "socket");
+ switch (in_out) {
+ case SOCK_IN: sock = BLI_findlink(&node->inputs, sockindex); break;
+ case SOCK_OUT: sock = BLI_findlink(&node->outputs, sockindex); break;
+ }
+
+ if (rnode)
+ *rnode = node;
+ if (rsock)
+ *rsock = sock;
+ if (rin_out)
+ *rin_out = in_out;
}
/* ***************** Edit Group operator ************* */
@@ -583,8 +807,8 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
bNode *node;
/* make sure nothing has group editing on */
- for(node= snode->nodetree->nodes.first; node; node= node->next)
- node->flag &= ~NODE_GROUP_EDIT;
+ for(node=snode->nodetree->nodes.first; node; node=node->next)
+ nodeGroupEditClear(node);
if(gnode==NULL) {
/* with NULL argument we do a toggle */
@@ -592,34 +816,30 @@ void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
gnode= nodeGetActive(snode->nodetree);
}
- if(gnode && gnode->type==NODE_GROUP && gnode->id) {
- if(gnode->id->lib)
- ntreeMakeLocal((bNodeTree *)gnode->id);
-
- gnode->flag |= NODE_GROUP_EDIT;
- snode->edittree= (bNodeTree *)gnode->id;
+ if (gnode) {
+ snode->edittree = nodeGroupEditSet(gnode, 1);
/* deselect all other nodes, so we can also do grabbing of entire subtree */
for(node= snode->nodetree->nodes.first; node; node= node->next)
node->flag &= ~SELECT;
gnode->flag |= SELECT;
-
}
else
snode->edittree= snode->nodetree;
-
- ntreeSolveOrder(snode->nodetree);
}
static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
- bNode *gnode;
ED_preview_kill_jobs(C);
- gnode= nodeGetActive(snode->edittree);
- snode_make_group_editable(snode, gnode);
+ if (snode->nodetree==snode->edittree) {
+ bNode *gnode= nodeGetActive(snode->nodetree);
+ snode_make_group_editable(snode, gnode);
+ }
+ else
+ snode_make_group_editable(snode, NULL);
WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
@@ -632,7 +852,8 @@ static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(e
bNode *gnode;
gnode= nodeGetActive(snode->edittree);
- if(gnode && gnode->type==NODE_GROUP && gnode->id && gnode->id->lib) {
+ /* XXX callback? */
+ if(gnode && gnode->id && GS(gnode->id->name)==ID_NT && gnode->id->lib) {
uiPupMenuOkee(C, op->type->idname, "Make group local?");
return OPERATOR_CANCELLED;
}
@@ -663,7 +884,7 @@ static int node_group_socket_add_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
int in_out= -1;
char name[32]= "";
- int type= SOCK_VALUE;
+ int type= SOCK_FLOAT;
bNodeTree *ngroup= snode->edittree;
bNodeSocket *sock;
@@ -680,9 +901,10 @@ static int node_group_socket_add_exec(bContext *C, wmOperator *op)
else
return OPERATOR_CANCELLED;
- sock = nodeGroupAddSocket(ngroup, name, type, in_out);
+ /* using placeholder subtype first */
+ sock = node_group_add_socket(ngroup, name, type, in_out);
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(ngroup);
snode_notify(C, snode);
@@ -705,7 +927,7 @@ void NODE_OT_group_socket_add(wmOperatorType *ot)
RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
RNA_def_string(ot->srna, "name", "", 32, "Name", "Group socket name");
- RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_VALUE, "Type", "Type of the group socket");
+ RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket");
}
/* ***************** Remove Group Socket operator ************* */
@@ -732,8 +954,8 @@ static int node_group_socket_remove_exec(bContext *C, wmOperator *op)
sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index);
if (sock) {
- nodeGroupRemoveSocket(ngroup, sock, in_out);
- node_tree_verify_groups(snode->nodetree);
+ node_group_remove_socket(ngroup, sock, in_out);
+ ntreeUpdateTree(ngroup);
snode_notify(C, snode);
}
@@ -790,6 +1012,8 @@ static int node_group_socket_move_up_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
BLI_remlink(&ngroup->inputs, sock);
BLI_insertlinkbefore(&ngroup->inputs, prev, sock);
+
+ ngroup->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out==SOCK_OUT) {
sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
@@ -799,8 +1023,10 @@ static int node_group_socket_move_up_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
BLI_remlink(&ngroup->outputs, sock);
BLI_insertlinkbefore(&ngroup->outputs, prev, sock);
+
+ ngroup->update |= NTREE_UPDATE_GROUP_OUT;
}
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(ngroup);
snode_notify(C, snode);
@@ -856,6 +1082,8 @@ static int node_group_socket_move_down_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
BLI_remlink(&ngroup->inputs, sock);
BLI_insertlinkafter(&ngroup->inputs, next, sock);
+
+ ngroup->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out==SOCK_OUT) {
sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
@@ -865,8 +1093,10 @@ static int node_group_socket_move_down_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
BLI_remlink(&ngroup->outputs, sock);
BLI_insertlinkafter(&ngroup->outputs, next, sock);
+
+ ngroup->update |= NTREE_UPDATE_GROUP_OUT;
}
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(ngroup);
snode_notify(C, snode);
@@ -913,7 +1143,7 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_WARNING, "Not a group");
return OPERATOR_CANCELLED;
}
- else if(!nodeGroupUnGroup(snode->edittree, gnode)) {
+ else if(!node_group_ungroup(snode->edittree, gnode)) {
BKE_report(op->reports, RPT_WARNING, "Can't ungroup");
return OPERATOR_CANCELLED;
}
@@ -941,70 +1171,16 @@ void NODE_OT_group_ungroup(wmOperatorType *ot)
/* ************************** Node generic ************** */
-/* allows to walk the list in order of visibility */
-bNode *next_node(bNodeTree *ntree)
-{
- static bNode *current=NULL, *last= NULL;
-
- if(ntree) {
- /* set current to the first selected node */
- for(current= ntree->nodes.last; current; current= current->prev)
- if(current->flag & NODE_SELECT)
- break;
-
- /* set last to the first unselected node */
- for(last= ntree->nodes.last; last; last= last->prev)
- if((last->flag & NODE_SELECT)==0)
- break;
-
- if(current==NULL)
- current= last;
-
- return NULL;
- }
- /* no nodes, or we are ready */
- if(current==NULL)
- return NULL;
-
- /* now we walk the list backwards, but we always return current */
- if(current->flag & NODE_SELECT) {
- bNode *node= current;
-
- /* find previous selected */
- current= current->prev;
- while(current && (current->flag & NODE_SELECT)==0)
- current= current->prev;
-
- /* find first unselected */
- if(current==NULL)
- current= last;
-
- return node;
- }
- else {
- bNode *node= current;
-
- /* find previous unselected */
- current= current->prev;
- while(current && (current->flag & NODE_SELECT))
- current= current->prev;
-
- return node;
- }
-
- return NULL;
-}
-
/* is rct in visible part of node? */
static bNode *visible_node(SpaceNode *snode, rctf *rct)
{
- bNode *tnode;
+ bNode *node;
- for(next_node(snode->edittree); (tnode=next_node(NULL));) {
- if(BLI_isect_rctf(&tnode->totr, rct, NULL))
+ for(node=snode->edittree->nodes.last; node; node=node->prev) {
+ if(BLI_isect_rctf(&node->totr, rct, NULL))
break;
}
- return tnode;
+ return node;
}
/* **************************** */
@@ -1108,7 +1284,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)
@@ -1307,8 +1483,9 @@ void NODE_OT_backimage_sample(wmOperatorType *ot)
/* ********************** size widget operator ******************** */
typedef struct NodeSizeWidget {
- float mxstart;
- float oldwidth;
+ float mxstart, mystart;
+ float oldwidth, oldheight;
+ float oldminiwidth;
} NodeSizeWidget;
static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
@@ -1327,13 +1504,16 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
if (node) {
if(node->flag & NODE_HIDDEN) {
- node->miniwidth= nsw->oldwidth + mx - nsw->mxstart;
+ node->miniwidth= nsw->oldminiwidth + mx - nsw->mxstart;
CLAMP(node->miniwidth, 0.0f, 100.0f);
}
else {
node->width= nsw->oldwidth + mx - nsw->mxstart;
- CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
+ CLAMP(node->width, UI_DPI_FAC*node->typeinfo->minwidth, UI_DPI_FAC*node->typeinfo->maxwidth);
}
+ /* height works the other way round ... */
+ node->height= nsw->oldheight - my + nsw->mystart;
+ CLAMP(node->height, node->typeinfo->minheight, node->typeinfo->maxheight);
}
ED_region_tag_redraw(ar);
@@ -1347,6 +1527,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
MEM_freeN(nsw);
op->customdata= NULL;
+ ED_node_update_hierarchy(C, snode->edittree);
+
return OPERATOR_FINISHED;
}
@@ -1360,28 +1542,21 @@ static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
bNode *node= editnode_get_active(snode->edittree);
if(node) {
- rctf totr;
-
/* convert mouse coordinates to v2d space */
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
&snode->mx, &snode->my);
- /* rect we're interested in is just the bottom right corner */
- totr= node->totr;
- totr.xmin= totr.xmax-10.0f;
- totr.ymax= totr.ymin+10.0f;
-
- if(BLI_in_rctf(&totr, snode->mx, snode->my)) {
+ if(node->typeinfo->resize_area_func(node, snode->mx, snode->my)) {
NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
op->customdata= nsw;
nsw->mxstart= snode->mx;
+ nsw->mystart= snode->my;
/* store old */
- if(node->flag & NODE_HIDDEN)
- nsw->oldwidth= node->miniwidth;
- else
- nsw->oldwidth= node->width;
+ nsw->oldwidth= node->width;
+ nsw->oldheight= node->height;
+ nsw->oldminiwidth= node->miniwidth;
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -1580,7 +1755,7 @@ static void node_link_viewer(SpaceNode *snode, bNode *tonode)
link->fromnode= tonode;
link->fromsock= sock;
}
- ntreeSolveOrder(snode->edittree);
+ ntreeUpdateTree(snode->edittree);
snode_tag_changed(snode, node);
}
}
@@ -1625,7 +1800,7 @@ void NODE_OT_link_viewer(wmOperatorType *ot)
/* return 0, nothing done */
-static int node_mouse_groupheader(SpaceNode *snode)
+static int UNUSED_FUNCTION(node_mouse_groupheader)(SpaceNode *snode)
{
bNode *gnode;
float mx=0, my=0;
@@ -1887,6 +2062,7 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
bNodeListItem *nli;
bNode *node;
+ bNodeLink *link;
int i, numlinks=0;
for(node= snode->edittree->nodes.first; node; node= node->next) {
@@ -1923,7 +2099,15 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
/* then we can connect */
if (replace)
nodeRemSocketLinks(snode->edittree, sock_to);
- nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
+
+ link = nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
+ /* validate the new link */
+ ntreeUpdateTree(snode->edittree);
+ if (!(link->flag & NODE_LINK_VALID)) {
+ nodeRemLink(snode->edittree, link);
+ continue;
+ }
+
snode_tag_changed(snode, node_to);
++numlinks;
break;
@@ -1931,8 +2115,7 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
}
if (numlinks > 0) {
- node_tree_verify_groups(snode->nodetree);
- ntreeSolveOrder(snode->edittree);
+ ntreeUpdateTree(snode->edittree);
}
BLI_freelistN(nodelist);
@@ -1940,28 +2123,13 @@ void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
}
/* can be called from menus too, but they should do own undopush and redraws */
-bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy)
+bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate *ntemp, float locx, float locy)
{
bNode *node= NULL, *gnode;
node_deselectall(snode);
- if(type>=NODE_DYNAMIC_MENU) {
- node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
- }
- else if(type>=NODE_GROUP_MENU) {
- if(snode->edittree!=snode->nodetree) {
- // XXX error("Can not add a Group in a Group");
- return NULL;
- }
- else {
- bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
- if(ngroup)
- node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL);
- }
- }
- else
- node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
+ node = nodeAddNode(snode->edittree, ntemp);
/* generics */
if(node) {
@@ -1975,8 +2143,8 @@ bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float
node->locy -= gnode->locy;
}
- node_tree_verify_groups(snode->nodetree);
- node_set_active(snode, node);
+ ntreeUpdateTree(snode->edittree);
+ ED_node_set_active(bmain, snode->edittree, node);
if(snode->nodetree->type==NTREE_COMPOSIT) {
if(ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE))
@@ -2000,23 +2168,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. */
@@ -2027,13 +2193,59 @@ 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;
}
- ntreeSolveOrder(ntree);
+ ntreeUpdateTree(snode->edittree);
- node_tree_verify_groups(snode->nodetree);
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -2053,6 +2265,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 ******************** */
@@ -2071,9 +2285,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;
}
@@ -2120,17 +2334,25 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
if( link->tosock!= tsock && (!tnode || (tnode!=node && link->tonode!=tnode)) ) {
link->tonode= tnode;
link->tosock= tsock;
- if (link->prev==NULL && link->next==NULL)
+ if (link->prev==NULL && link->next==NULL) {
BLI_addtail(&snode->edittree->links, link);
- ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
+ }
+
+ snode->edittree->update |= NTREE_UPDATE_LINKS;
+ ntreeUpdateTree(snode->edittree);
}
}
}
else {
- BLI_remlink(&snode->edittree->links, link);
- link->prev = link->next = NULL;
- link->tonode= NULL;
- link->tosock= NULL;
+ 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;
+ ntreeUpdateTree(snode->edittree);
+ }
}
}
else {
@@ -2140,18 +2362,25 @@ static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
if( link->fromsock!= tsock && (!tnode || (tnode!=node && link->fromnode!=tnode)) ) {
link->fromnode= tnode;
link->fromsock= tsock;
- if (link->prev==NULL && link->next==NULL)
+ if (link->prev==NULL && link->next==NULL) {
BLI_addtail(&snode->edittree->links, link);
- ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
+ }
+
+ snode->edittree->update |= NTREE_UPDATE_LINKS;
+ ntreeUpdateTree(snode->edittree);
}
}
}
}
else {
- BLI_remlink(&snode->edittree->links, link);
- link->prev = link->next = NULL;
- link->fromnode= NULL;
- link->fromsock= NULL;
+ 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);
+ }
}
}
/* hilight target sockets only */
@@ -2169,27 +2398,36 @@ 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 */
if (link->tonode && link->tosock) {
- link->fromsock = nodeGroupExposeSocket(snode->edittree, link->tosock, SOCK_IN);
+ link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN);
link->fromnode = NULL;
- if (link->prev==NULL && link->next==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 = nodeGroupExposeSocket(snode->edittree, link->fromsock, SOCK_OUT);
+ link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT);
link->tonode = NULL;
- if (link->prev==NULL && link->next==NULL)
+ if (link->prev==NULL && link->next==NULL) {
BLI_addtail(&snode->edittree->links, link);
+ }
+ snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS;
}
}
else
nodeRemLink(snode->edittree, link);
- ntreeSolveOrder(snode->edittree);
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -2264,7 +2502,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
ED_preview_kill_jobs(C);
nldrag->in_out= node_link_init(snode, nldrag);
-
+
if(nldrag->in_out) {
op->customdata= nldrag;
@@ -2337,7 +2575,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
snode_autoconnect(snode, 1, replace);
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -2411,8 +2649,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
}
}
- ntreeSolveOrder(snode->edittree);
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -2445,6 +2682,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);
+ ntreeUpdateTree(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...
@@ -2603,14 +2985,14 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(C);
- gnode= nodeMakeGroupFromSelected(snode->nodetree);
+ gnode= node_group_make_from_selected(snode->nodetree);
if(gnode==NULL) {
BKE_report(op->reports, RPT_WARNING, "Can not make Group");
return OPERATOR_CANCELLED;
}
else {
nodeSetActive(snode->nodetree, gnode);
- ntreeSolveOrder(snode->nodetree);
+ ntreeUpdateTree(snode->nodetree);
}
snode_notify(C, snode);
@@ -2756,7 +3138,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(snode->edittree);
snode_notify(C, snode);
@@ -2793,10 +3175,10 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
for(node= snode->edittree->nodes.first; node; node= node->next) {
if(node->flag & SELECT) {
- if(node->inputs.first && node->outputs.first) {
+ /* Be able to mute in-/output nodes as well. - DingTo
+ if(node->inputs.first && node->outputs.first) { */
node->flag ^= NODE_MUTED;
snode_tag_changed(snode, node);
- }
}
}
@@ -2840,7 +3222,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- node_tree_verify_groups(snode->nodetree);
+ ntreeUpdateTree(snode->edittree);
snode_notify(C, snode);
snode_dag_update(C, snode);
@@ -2863,6 +3245,155 @@ void NODE_OT_delete(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
+/* ****************** Delete with reconnect ******************* */
+static int is_connected_to_input_socket(bNode* node, bNodeLink* link) {
+ bNodeSocket *sock;
+ if (link->tonode == node) {
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if (link->tosock == sock) {
+ return sock->type;
+ }
+ }
+ }
+ return -1;
+}
+
+static void node_delete_reconnect(bNodeTree* tree, bNode* node)
+{
+ bNodeLink *link, *next, *first = NULL;
+ bNodeSocket *valsocket= NULL, *colsocket= NULL, *vecsocket= NULL;
+ bNodeSocket *deliveringvalsocket= NULL, *deliveringcolsocket= NULL, *deliveringvecsocket= NULL;
+ bNode *deliveringvalnode= NULL, *deliveringcolnode= NULL, *deliveringvecnode= NULL;
+ bNodeSocket *sock;
+ int type;
+ int numberOfConnectedOutputSockets = 0;
+ int numberOfReconnections = 0;
+ int numberOfConnectedInputSockets = 0;
+
+ /*
+ test the inputs, not really correct when a node has multiple input sockets of the same type
+ the first link evaluated will be used to determine the possible connection.
+ */
+ for(link= tree->links.first; link; link=link->next) {
+ if (link->tonode == node) { numberOfConnectedInputSockets++; }
+ type = is_connected_to_input_socket(node, link);
+ switch (type) {
+ case SOCK_RGBA:
+ if (colsocket == NULL) {
+ colsocket = link->tosock;
+ deliveringcolnode = link->fromnode;
+ deliveringcolsocket = link->fromsock;
+ }
+ break;
+ case SOCK_VECTOR:
+ if (vecsocket == NULL) {
+ vecsocket = link->tosock;
+ deliveringvecnode = link->fromnode;
+ deliveringvecsocket = link->fromsock;
+ }
+ break;
+ case SOCK_FLOAT:
+ if (valsocket == NULL) {
+ valsocket = link->tosock;
+ deliveringvalnode = link->fromnode;
+ deliveringvalsocket = link->fromsock;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // 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;
+ numberOfConnectedOutputSockets ++;
+ if (!first) first = link;
+ switch(sock->type) {
+ case SOCK_FLOAT:
+ if (deliveringvalsocket) {
+ link->fromnode = deliveringvalnode;
+ link->fromsock = deliveringvalsocket;
+ numberOfReconnections++;
+ }
+ break;
+ case SOCK_VECTOR:
+ if (deliveringvecsocket) {
+ link->fromnode = deliveringvecnode;
+ link->fromsock = deliveringvecsocket;
+ numberOfReconnections++;
+ }
+ break;
+ case SOCK_RGBA:
+ if (deliveringcolsocket) {
+ link->fromnode = deliveringcolnode;
+ link->fromsock = deliveringcolsocket;
+ numberOfReconnections++;
+ }
+ break;
+ }
+ }
+ }
+
+ /* when no connections have been made, and if only one delivering input socket type and one output socket we will connect those two */
+ if (numberOfConnectedOutputSockets == 1 && numberOfReconnections == 0 && numberOfConnectedInputSockets == 1) {
+ if (deliveringcolsocket) {
+ first->fromnode = deliveringcolnode;
+ first->fromsock = deliveringcolsocket;
+ } else if (deliveringvecsocket) {
+ first->fromnode = deliveringvecnode;
+ first->fromsock = deliveringvecsocket;
+ } else if (deliveringvalsocket) {
+ first->fromnode = deliveringvalnode;
+ first->fromsock = deliveringvalsocket;
+ }
+ }
+
+ 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);
+ }
+ }
+
+ ntreeUpdateTree(snode->edittree);
+
+ 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))
@@ -2870,7 +3401,7 @@ static int node_show_cycles_exec(bContext *C, wmOperator *UNUSED(op))
SpaceNode *snode= CTX_wm_space_node(C);
/* this is just a wrapper around this call... */
- ntreeSolveOrder(snode->edittree);
+ ntreeUpdateTree(snode->nodetree);
snode_notify(C, snode);
return OPERATOR_FINISHED;
@@ -2895,11 +3426,14 @@ void NODE_OT_show_cyclic_dependencies(wmOperatorType *ot)
static int node_add_file_exec(bContext *C, wmOperator *op)
{
+ Main *bmain= CTX_data_main(C);
Scene *scene= CTX_data_scene(C);
SpaceNode *snode= CTX_wm_space_node(C);
bNode *node;
Image *ima= NULL;
- int ntype=0;
+ bNodeTemplate ntemp;
+
+ ntemp.type = -1;
/* check input variables */
if (RNA_property_is_set(op->ptr, "filepath"))
@@ -2931,11 +3465,14 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
node_deselectall(snode);
if (snode->nodetree->type==NTREE_COMPOSIT)
- ntype = CMP_NODE_IMAGE;
+ ntemp.type = CMP_NODE_IMAGE;
+ if (ntemp.type < 0)
+ return OPERATOR_CANCELLED;
+
ED_preview_kill_jobs(C);
- node = node_add_node(snode, scene, ntype, snode->mx, snode->my);
+ node = node_add_node(snode, bmain, scene, &ntemp, snode->mx, snode->my);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node.");
@@ -2984,3 +3521,67 @@ void NODE_OT_add_file(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign.");
}
+/********************** New node tree operator *********************/
+
+static int new_node_tree_exec(bContext *C, wmOperator *op)
+{
+ SpaceNode *snode;
+ bNodeTree *ntree;
+ PointerRNA ptr, idptr;
+ PropertyRNA *prop;
+ int treetype;
+ char treename[MAX_ID_NAME-2] = "NodeTree";
+
+ /* retrieve state */
+ snode= CTX_wm_space_node(C);
+
+ if (RNA_property_is_set(op->ptr, "type"))
+ treetype = RNA_enum_get(op->ptr, "type");
+ else
+ treetype = snode->treetype;
+
+ if (RNA_property_is_set(op->ptr, "name"))
+ RNA_string_get(op->ptr, "name", treename);
+
+ ntree = ntreeAddTree(treename, treetype, 0);
+ if(!ntree)
+ return OPERATOR_CANCELLED;
+
+ /* hook into UI */
+ uiIDContextProperty(C, &ptr, &prop);
+
+ if(prop) {
+ RNA_id_pointer_create(&ntree->id, &idptr);
+ RNA_property_pointer_set(&ptr, prop, idptr);
+ /* RNA_property_pointer_set increases the user count,
+ * fixed here as the editor is the initial user.
+ */
+ --ntree->id.us;
+ RNA_property_update(C, &ptr, prop);
+ }
+ else if(snode) {
+ Scene *scene= CTX_data_scene(C);
+ snode->nodetree = ntree;
+
+ ED_node_tree_update(snode, scene);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_new_node_tree(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "New node tree";
+ ot->idname= "NODE_OT_new_node_tree";
+
+ /* api callbacks */
+ ot->exec= new_node_tree_exec;
+ ot->poll= ED_operator_node_active;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ 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", "");
+}