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:
-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);
}