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:
authorLukas Toenne <lukas.toenne@googlemail.com>2012-08-02 13:52:37 +0400
committerLukas Toenne <lukas.toenne@googlemail.com>2012-08-02 13:52:37 +0400
commit9d2173518cd7da7d18bb032c8537c8952abc2b78 (patch)
tree5fd02e1b8013ed6a37915cacfabb960dd9f66877
parent0a782a4550904cdec15efbf5bf81c8be144896ee (diff)
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).
-rw-r--r--release/scripts/startup/bl_ui/space_node.py4
-rw-r--r--source/blender/blenkernel/BKE_node.h7
-rw-r--r--source/blender/blenkernel/intern/node.c109
-rw-r--r--source/blender/editors/space_node/node_edit.c153
-rw-r--r--source/blender/editors/space_node/node_intern.h4
-rw-r--r--source/blender/editors/space_node/node_ops.c6
6 files changed, 262 insertions, 21 deletions
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index e66d8f70c81..adcf5a9e9df 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -94,6 +94,10 @@ class NODE_HT_header(Header):
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()
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 93b5e748987..00bdbbf4537 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -384,6 +384,13 @@ void nodeFreePreview(struct bNode *node);
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);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 592bc10424f..565e2de79f8 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -347,9 +347,12 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
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;
@@ -390,7 +393,8 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
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 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock,
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 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock,
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 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock,
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 @@ bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock,
}
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 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
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);
-
- BLI_remlink(&ntree->nodes, 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);
+ }
/* 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 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
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 @@ void nodeSocketSetType(bNodeSocket *sock, int type)
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 @@ static void free_typeinfos(ListBase *list)
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));
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 4b554185933..fa8fa13a645 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -2215,3 +2215,156 @@ void NODE_OT_node_copy_color(wmOperatorType *ot)
/* 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 */
+ for (node = nodeClipboardGetNodes()->first; node; node = node->next) {
+ if (node->new_node->parent)
+ node->new_node->parent = node->new_node->parent->new_node;
+ }
+
+ ntreeUpdateTree(snode->edittree);
+
+ snode_notify(C, snode);
+ snode_dag_update(C, snode);
+
+ return OPERATOR_FINISHED;
+}
+
+static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceNode *snode = CTX_wm_space_node(C);
+
+ /* convert mouse coordinates to v2d space */
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->mx, &snode->my);
+
+ return node_clipboard_paste_exec(C, op);
+}
+
+void NODE_OT_clipboard_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Paste from clipboard";
+ ot->description = "Pastes nodes from the clipboard to the active node tree";
+ ot->idname = "NODE_OT_clipboard_paste";
+
+ /* api callbacks */
+ ot->exec = node_clipboard_paste_exec;
+ ot->invoke = node_clipboard_paste_invoke;
+ ot->poll = ED_operator_node_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 5c6a91195a6..7077229fae1 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -200,6 +200,10 @@ void NODE_OT_output_file_add_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot);
void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot);
+/* Note: clipboard_cut is a simple macro of copy + delete */
+void NODE_OT_clipboard_copy(struct wmOperatorType *ot);
+void NODE_OT_clipboard_paste(struct wmOperatorType *ot);
+
extern const char *node_context_dir[];
// XXXXXX
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 0ce72848c56..2efeebbfc75 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -113,6 +113,9 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_join);
WM_operatortype_append(NODE_OT_attach);
WM_operatortype_append(NODE_OT_detach);
+
+ WM_operatortype_append(NODE_OT_clipboard_copy);
+ WM_operatortype_append(NODE_OT_clipboard_paste);
}
void ED_operatormacros_node(void)
@@ -281,5 +284,8 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "NODE_OT_render_changed", ZKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_clipboard_copy", CKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_CTRL, 0);
+
transform_keymap_for_space(keyconf, keymap, SPACE_NODE);
}