[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [49495] trunk/blender: Clipboard feature for nodes.

Lukas Toenne lukas.toenne at googlemail.com
Thu Aug 2 11:52:37 CEST 2012


Revision: 49495
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=49495
Author:   lukastoenne
Date:     2012-08-02 09:52:37 +0000 (Thu, 02 Aug 2012)
Log Message:
-----------
Clipboard feature for nodes. With the Copy operator a copy of all selected nodes and links between them is stored in an offscreen list (not in the library). The Paste operator then in turn copies these into the active node tree in the editor.

Currently does not support copying of animation data. This would require copying of individual fcurves etc. between data block, which is not implemented yet.

Also it is currently possible to circumvent some constraints of the nodes, in particular for node groups (e.g. no groups inside groups, render layer not inside groups).

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_node.py
    trunk/blender/source/blender/blenkernel/BKE_node.h
    trunk/blender/source/blender/blenkernel/intern/node.c
    trunk/blender/source/blender/editors/space_node/node_edit.c
    trunk/blender/source/blender/editors/space_node/node_intern.h
    trunk/blender/source/blender/editors/space_node/node_ops.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_node.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_node.py	2012-08-02 08:57:18 UTC (rev 49494)
+++ trunk/blender/release/scripts/startup/bl_ui/space_node.py	2012-08-02 09:52:37 UTC (rev 49495)
@@ -94,6 +94,10 @@
         if toolsettings.snap_node_element != 'INCREMENT':
             row.prop(toolsettings, "snap_target", text="")
 
+        row = layout.row(align=True)
+        row.operator("node.clipboard_copy", text="", icon='COPYDOWN')
+        row.operator("node.clipboard_paste", text="", icon='PASTEDOWN')
+
         layout.template_running_jobs()
 
 

Modified: trunk/blender/source/blender/blenkernel/BKE_node.h
===================================================================
--- trunk/blender/source/blender/blenkernel/BKE_node.h	2012-08-02 08:57:18 UTC (rev 49494)
+++ trunk/blender/source/blender/blenkernel/BKE_node.h	2012-08-02 09:52:37 UTC (rev 49495)
@@ -384,6 +384,13 @@
 int             nodeSocketIsHidden(struct bNodeSocket *sock);
 void            nodeSocketSetType(struct bNodeSocket *sock, int type);
 
+/* Node Clipboard */
+void nodeClipboardClear(void);
+void nodeClipboardAddNode(struct bNode *node);
+void nodeClipboardAddLink(struct bNodeLink *link);
+const struct ListBase *nodeClipboardGetNodes(void);
+const struct ListBase *nodeClipboardGetLinks(void);
+
 /* ************** NODE TYPE ACCESS *************** */
 
 struct bNodeTemplate nodeMakeTemplate(struct bNode *node);

Modified: trunk/blender/source/blender/blenkernel/intern/node.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/node.c	2012-08-02 08:57:18 UTC (rev 49494)
+++ trunk/blender/source/blender/blenkernel/intern/node.c	2012-08-02 09:52:37 UTC (rev 49495)
@@ -347,10 +347,13 @@
 	bNodeSocket *sock, *oldsock;
 
 	*nnode = *node;
-	nodeUniqueName(ntree, nnode);
-	
-	BLI_addtail(&ntree->nodes, nnode);
+	/* can be called for nodes outside a node tree (e.g. clipboard) */
+	if (ntree) {
+		nodeUniqueName(ntree, nnode);
 
+		BLI_addtail(&ntree->nodes, nnode);
+	}
+
 	BLI_duplicatelist(&nnode->inputs, &node->inputs);
 	oldsock = node->inputs.first;
 	for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) {
@@ -390,7 +393,8 @@
 	nnode->new_node = NULL;
 	nnode->preview = NULL;
 	
-	ntree->update |= NTREE_UPDATE_NODES;
+	if (ntree)
+		ntree->update |= NTREE_UPDATE_NODES;
 	
 	return nnode;
 }
@@ -417,7 +421,7 @@
 				from = -1;  /* OK but flip */
 		}
 	}
-	else {
+	else if (ntree) {
 		/* check tree sockets */
 		for (sock = ntree->inputs.first; sock; sock = sock->next)
 			if (sock == fromsock)
@@ -446,7 +450,7 @@
 				to = -1;  /* OK but flip */
 		}
 	}
-	else {
+	else if (ntree) {
 		/* check tree sockets */
 		for (sock = ntree->outputs.first; sock; sock = sock->next)
 			if (sock == tosock)
@@ -464,7 +468,8 @@
 	
 	if (from >= 0 && to >= 0) {
 		link = MEM_callocN(sizeof(bNodeLink), "link");
-		BLI_addtail(&ntree->links, link);
+		if (ntree)
+			BLI_addtail(&ntree->links, link);
 		link->fromnode = fromnode;
 		link->fromsock = fromsock;
 		link->tonode = tonode;
@@ -472,26 +477,32 @@
 	}
 	else if (from <= 0 && to <= 0) {
 		link = MEM_callocN(sizeof(bNodeLink), "link");
-		BLI_addtail(&ntree->links, link);
+		if (ntree)
+			BLI_addtail(&ntree->links, link);
 		link->fromnode = tonode;
 		link->fromsock = tosock;
 		link->tonode = fromnode;
 		link->tosock = fromsock;
 	}
 	
-	ntree->update |= NTREE_UPDATE_LINKS;
+	if (ntree)
+		ntree->update |= NTREE_UPDATE_LINKS;
 	
 	return link;
 }
 
 void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
 {
-	BLI_remlink(&ntree->links, link);
+	/* can be called for links outside a node tree (e.g. clipboard) */
+	if (ntree)
+		BLI_remlink(&ntree->links, link);
+
 	if (link->tosock)
 		link->tosock->link = NULL;
 	MEM_freeN(link);
 	
-	ntree->update |= NTREE_UPDATE_LINKS;
+	if (ntree)
+		ntree->update |= NTREE_UPDATE_LINKS;
 }
 
 void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
@@ -885,20 +896,24 @@
 
 void nodeFreeNode(bNodeTree *ntree, bNode *node)
 {
-	bNodeTreeType *treetype = ntreeGetType(ntree->type);
 	bNodeSocket *sock, *nextsock;
 	
-	/* remove all references to this node */
-	nodeUnlinkNode(ntree, node);
-	node_unlink_attached(ntree, node);
+	/* can be called for nodes outside a node tree (e.g. clipboard) */
+	if (ntree) {
+		bNodeTreeType *treetype = ntreeGetType(ntree->type);
+
+		/* remove all references to this node */
+		nodeUnlinkNode(ntree, node);
+		node_unlink_attached(ntree, node);
+
+		BLI_remlink(&ntree->nodes, node);
+
+		if (treetype->free_node_cache)
+			treetype->free_node_cache(ntree, node);
+	}
 	
-	BLI_remlink(&ntree->nodes, node);
-	
 	/* since it is called while free database, node->id is undefined */
 	
-	if (treetype->free_node_cache)
-		treetype->free_node_cache(ntree, node);
-	
 	if (node->typeinfo && node->typeinfo->freestoragefunc)
 		node->typeinfo->freestoragefunc(node);
 	
@@ -917,7 +932,8 @@
 
 	MEM_freeN(node);
 	
-	ntree->update |= NTREE_UPDATE_NODES;
+	if (ntree)
+		ntree->update |= NTREE_UPDATE_NODES;
 }
 
 /* do not free ntree itself here, BKE_libblock_free calls this function too */
@@ -1388,6 +1404,53 @@
 	node_socket_free_default_value(old_type, old_default_value);
 }
 
+/* ************** Node Clipboard *********** */
+
+typedef struct bNodeClipboard {
+	ListBase nodes;
+	ListBase links;
+} bNodeClipboard;
+
+bNodeClipboard node_clipboard;
+
+void nodeClipboardClear(void)
+{
+	bNode *node, *node_next;
+	bNodeLink *link, *link_next;
+	
+	for (link = node_clipboard.links.first; link; link=link_next) {
+		link_next = link->next;
+		nodeRemLink(NULL, link);
+	}
+	node_clipboard.links.first = node_clipboard.links.last = NULL;
+	
+	for (node = node_clipboard.nodes.first; node; node=node_next) {
+		node_next = node->next;
+		nodeFreeNode(NULL, node);
+	}
+	node_clipboard.nodes.first = node_clipboard.nodes.last = NULL;
+}
+
+void nodeClipboardAddNode(bNode *node)
+{
+	BLI_addtail(&node_clipboard.nodes, node);
+}
+
+void nodeClipboardAddLink(bNodeLink *link)
+{
+	BLI_addtail(&node_clipboard.links, link);
+}
+
+const ListBase *nodeClipboardGetNodes(void)
+{
+	return &node_clipboard.nodes;
+}
+
+const ListBase *nodeClipboardGetLinks(void)
+{
+	return &node_clipboard.links;
+}
+
 /* ************** dependency stuff *********** */
 
 /* node is guaranteed to be not checked before */
@@ -2085,6 +2148,10 @@
 
 void init_nodesystem(void) 
 {
+	/* init clipboard */
+	node_clipboard.nodes.first = node_clipboard.nodes.last = NULL;
+	node_clipboard.links.first = node_clipboard.links.last = NULL;
+	
 	registerCompositNodes(ntreeGetType(NTREE_COMPOSIT));
 	registerShaderNodes(ntreeGetType(NTREE_SHADER));
 	registerTextureNodes(ntreeGetType(NTREE_TEXTURE));

Modified: trunk/blender/source/blender/editors/space_node/node_edit.c
===================================================================
--- trunk/blender/source/blender/editors/space_node/node_edit.c	2012-08-02 08:57:18 UTC (rev 49494)
+++ trunk/blender/source/blender/editors/space_node/node_edit.c	2012-08-02 09:52:37 UTC (rev 49495)
@@ -2215,3 +2215,156 @@
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
+
+/* ****************** Copy to clipboard ******************* */
+
+static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	SpaceNode *snode = CTX_wm_space_node(C);
+	bNodeTree *ntree = snode->edittree;
+	bNode *node, *newnode;
+	bNodeLink *link, *newlink;
+
+	ED_preview_kill_jobs(C);
+
+	/* clear current clipboard */
+	nodeClipboardClear();
+
+	for (node = ntree->nodes.first; node; node = node->next) {
+		if (node->flag & SELECT) {
+			newnode = nodeCopyNode(NULL, node);
+			nodeClipboardAddNode(newnode);
+		}
+	}
+
+	/* copy links between selected nodes
+	 * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
+	 */
+	for (link = ntree->links.first; link; link = link->next) {
+		/* This creates new links between copied nodes. */
+		if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
+		    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;
+			newlink->fromnode = link->fromnode->new_node;
+			newlink->fromsock = link->fromsock->new_sock;
+
+			nodeClipboardAddLink(newlink);
+		}
+	}
+
+	/* reparent copied nodes */
+	for (node = ntree->nodes.first; node; node = node->next) {
+		if ((node->flag & SELECT) && node->parent) {
+			if (node->parent->flag & SELECT)
+				node->parent = node->parent->new_node;
+			else
+				node->parent = NULL;
+		}
+	}
+
+	return OPERATOR_FINISHED;
+}
+
+void NODE_OT_clipboard_copy(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Copy to clipboard";
+	ot->description = "Copies selected nodes to the clipboard";
+	ot->idname = "NODE_OT_clipboard_copy";
+
+	/* api callbacks */
+	ot->exec = node_clipboard_copy_exec;
+	ot->poll = ED_operator_node_active;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ****************** Paste from clipboard ******************* */
+
+static int node_clipboard_paste_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	SpaceNode *snode = CTX_wm_space_node(C);
+	bNodeTree *ntree = snode->edittree;
+	bNode *node;
+	bNodeLink *link;
+	int num_nodes;
+	float centerx, centery;
+
+	ED_preview_kill_jobs(C);
+
+	/* deselect old nodes */
+	node_deselect_all(snode);
+
+	/* calculate "barycenter" for placing on mouse cursor */
+	num_nodes = 0;
+	centerx = centery = 0.0f;
+	for (node = nodeClipboardGetNodes()->first; node; node = node->next) {
+		++num_nodes;
+		centerx += node->locx + 0.5f * node->width;
+		centery += node->locy - 0.5f * node->height;
+	}
+	centerx /= num_nodes;
+	centery /= num_nodes;
+
+	/* copy nodes from clipboard */
+	for (node = nodeClipboardGetNodes()->first; node; node = node->next) {
+		bNode *newnode = nodeCopyNode(ntree, node);
+
+		/* pasted nodes are selected */
+		node_select(newnode);
+
+		/* place nodes around the mouse cursor */
+		newnode->locx += snode->mx - centerx;
+		newnode->locy += snode->my - centery;
+	}
+
+	for (link = nodeClipboardGetLinks()->first; link; link = link->next) {
+		nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock,
+		            link->tonode->new_node, link->tosock->new_sock);
+	}
+
+	/* reparent copied nodes */

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list