diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/space_node/node_group.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/space_node/node_group.c')
-rw-r--r-- | source/blender/editors/space_node/node_group.c | 1720 |
1 files changed, 867 insertions, 853 deletions
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index e38d29454dc..3c65c4854b8 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -43,7 +43,7 @@ #include "DEG_depsgraph_build.h" -#include "ED_node.h" /* own include */ +#include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_render.h" @@ -55,127 +55,123 @@ #include "UI_resources.h" -#include "node_intern.h" /* own include */ +#include "node_intern.h" /* own include */ #include "NOD_common.h" static bool node_group_operator_active(bContext *C) { - if (ED_operator_node_active(C)) { - SpaceNode *snode = CTX_wm_space_node(C); - - /* Group operators only defined for standard node tree types. - * Disabled otherwise to allow pynodes define their own operators - * with same keymap. - */ - if (STREQ(snode->tree_idname, "ShaderNodeTree") || - STREQ(snode->tree_idname, "CompositorNodeTree") || - STREQ(snode->tree_idname, "TextureNodeTree")) - { - return true; - } - } - return false; + if (ED_operator_node_active(C)) { + SpaceNode *snode = CTX_wm_space_node(C); + + /* Group operators only defined for standard node tree types. + * Disabled otherwise to allow pynodes define their own operators + * with same keymap. + */ + if (STREQ(snode->tree_idname, "ShaderNodeTree") || + STREQ(snode->tree_idname, "CompositorNodeTree") || + STREQ(snode->tree_idname, "TextureNodeTree")) { + return true; + } + } + return false; } static bool node_group_operator_editable(bContext *C) { - if (ED_operator_node_editable(C)) { - SpaceNode *snode = CTX_wm_space_node(C); - - /* Group operators only defined for standard node tree types. - * Disabled otherwise to allow pynodes define their own operators - * with same keymap. - */ - if (ED_node_is_shader(snode) || - ED_node_is_compositor(snode) || - ED_node_is_texture(snode)) - { - return true; - } - } - return false; + if (ED_operator_node_editable(C)) { + SpaceNode *snode = CTX_wm_space_node(C); + + /* Group operators only defined for standard node tree types. + * Disabled otherwise to allow pynodes define their own operators + * with same keymap. + */ + if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode)) { + return true; + } + } + return false; } static const char *group_ntree_idname(bContext *C) { - SpaceNode *snode = CTX_wm_space_node(C); - return snode->tree_idname; + SpaceNode *snode = CTX_wm_space_node(C); + return snode->tree_idname; } static const char *group_node_idname(bContext *C) { - SpaceNode *snode = CTX_wm_space_node(C); - - if (ED_node_is_shader(snode)) { - return "ShaderNodeGroup"; - } - else if (ED_node_is_compositor(snode)) { - return "CompositorNodeGroup"; - } - else if (ED_node_is_texture(snode)) { - return "TextureNodeGroup"; - } - - return ""; + SpaceNode *snode = CTX_wm_space_node(C); + + if (ED_node_is_shader(snode)) { + return "ShaderNodeGroup"; + } + else if (ED_node_is_compositor(snode)) { + return "CompositorNodeGroup"; + } + else if (ED_node_is_texture(snode)) { + return "TextureNodeGroup"; + } + + return ""; } static bNode *node_group_get_active(bContext *C, const char *node_idname) { - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node = nodeGetActive(snode->edittree); - - if (node && STREQ(node->idname, node_idname)) { - return node; - } - else { - return NULL; - } + SpaceNode *snode = CTX_wm_space_node(C); + bNode *node = nodeGetActive(snode->edittree); + + if (node && STREQ(node->idname, node_idname)) { + return node; + } + else { + return NULL; + } } /* ***************** Edit Group operator ************* */ static int node_group_edit_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - const char *node_idname = group_node_idname(C); - bNode *gnode; - const bool exit = RNA_boolean_get(op->ptr, "exit"); + SpaceNode *snode = CTX_wm_space_node(C); + const char *node_idname = group_node_idname(C); + bNode *gnode; + const bool exit = RNA_boolean_get(op->ptr, "exit"); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - gnode = node_group_get_active(C, node_idname); + gnode = node_group_get_active(C, node_idname); - if (gnode && !exit) { - bNodeTree *ngroup = (bNodeTree *)gnode->id; + if (gnode && !exit) { + bNodeTree *ngroup = (bNodeTree *)gnode->id; - if (ngroup) { - ED_node_tree_push(snode, ngroup, gnode); - } - } - else { - ED_node_tree_pop(snode); - } + if (ngroup) { + ED_node_tree_push(snode, ngroup, gnode); + } + } + else { + ED_node_tree_pop(snode); + } - WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void NODE_OT_group_edit(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Edit Group"; - ot->description = "Edit node group"; - ot->idname = "NODE_OT_group_edit"; + /* identifiers */ + ot->name = "Edit Group"; + ot->description = "Edit node group"; + ot->idname = "NODE_OT_group_edit"; - /* api callbacks */ - ot->exec = node_group_edit_exec; - ot->poll = node_group_operator_active; + /* api callbacks */ + ot->exec = node_group_edit_exec; + ot->poll = node_group_operator_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_boolean(ot->srna, "exit", false, "Exit", ""); + RNA_def_boolean(ot->srna, "exit", false, "Exit", ""); } /* ******************** Ungroup operator ********************** */ @@ -183,882 +179,900 @@ void NODE_OT_group_edit(wmOperatorType *ot) /* returns 1 if its OK */ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) { - bNodeLink *link, *linkn, *tlink; - bNode *node, *nextnode; - bNodeTree *ngroup, *wgroup; - ListBase anim_basepaths = {NULL, NULL}; - LinkNode *nodes_delayed_free = NULL; - - ngroup = (bNodeTree *)gnode->id; - - /* clear new pointers, set in copytree */ - for (node = ntree->nodes.first; node; node = node->next) { - node->new_node = NULL; - } - - /* 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 - * - temp copy. don't change ID usercount - */ - wgroup = ntreeCopyTree_ex(ngroup, bmain, false); - - /* Add the nodes into the ntree */ - for (node = wgroup->nodes.first; node; node = nextnode) { - nextnode = node->next; - - /* Remove interface nodes. - * This also removes remaining links to and from interface nodes. - */ - if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { - /* We must delay removal since sockets will reference this node. see: T52092 */ - BLI_linklist_prepend(&nodes_delayed_free, node); - } - - /* keep track of this node's RNA "base" path (the part of the path 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); - - /* ensure unique node name in the node tree */ - nodeUniqueName(ntree, node); - - if (!node->parent) { - node->locx += gnode->locx; - node->locy += gnode->locy; - } - - node->flag |= NODE_SELECT; - } - - /* 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); - } - - /* 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; - - /* firstly, wgroup needs to temporary dummy action - * that can be destroyed, as it shares copies */ - waction = wgroup->adt->action = BKE_action_copy(bmain, wgroup->adt->action); - - /* now perform the moving */ - BKE_animdata_separate_by_basepath(bmain, &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) { - BKE_id_free(bmain, waction); - wgroup->adt->action = NULL; - } - } - - /* free the group tree (takes care of user count) */ - BKE_id_free(bmain, wgroup); - - /* restore external links to and from the gnode */ - /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node), - * then transferred to ntree (new_node pointers remain valid). - */ - - /* input links */ - for (link = ngroup->links.first; link; link = link->next) { - if (link->fromnode->type == NODE_GROUP_INPUT) { - const char *identifier = link->fromsock->identifier; - int num_external_links = 0; - - /* find external links to this input */ - for (tlink = ntree->links.first; tlink; tlink = tlink->next) { - if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode->new_node, link->tosock->new_sock); - ++num_external_links; - } - } - - /* if group output is not externally linked, - * convert the constant input value to ensure somewhat consistent behavior */ - if (num_external_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); - BLI_assert(sock);*/ - - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, - * ntree, sock, gnode);*/ - } - } - } - - /* output links */ - for (link = ntree->links.first; link; link = link->next) { - if (link->fromnode == gnode) { - const char *identifier = link->fromsock->identifier; - int num_internal_links = 0; - - /* find internal links to this output */ - for (tlink = ngroup->links.first; tlink; tlink = tlink->next) { - /* only use active output node */ - if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { - if (STREQ(tlink->tosock->identifier, identifier)) { - nodeAddLink(ntree, tlink->fromnode->new_node, tlink->fromsock->new_sock, link->tonode, link->tosock); - ++num_internal_links; - } - } - } - - /* if group output is not internally linked, - * convert the constant output value to ensure somewhat consistent behavior */ - if (num_internal_links == 0) { - /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); - BLI_assert(sock);*/ - - /* XXX TODO - * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ - } - } - } - - while (nodes_delayed_free) { - node = BLI_linklist_pop(&nodes_delayed_free); - nodeRemoveNode(bmain, ntree, node, false); - } - - /* delete the group instance */ - nodeRemoveNode(bmain, ntree, gnode, false); - - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - - return 1; + bNodeLink *link, *linkn, *tlink; + bNode *node, *nextnode; + bNodeTree *ngroup, *wgroup; + ListBase anim_basepaths = {NULL, NULL}; + LinkNode *nodes_delayed_free = NULL; + + ngroup = (bNodeTree *)gnode->id; + + /* clear new pointers, set in copytree */ + for (node = ntree->nodes.first; node; node = node->next) { + node->new_node = NULL; + } + + /* 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 + * - temp copy. don't change ID usercount + */ + wgroup = ntreeCopyTree_ex(ngroup, bmain, false); + + /* Add the nodes into the ntree */ + for (node = wgroup->nodes.first; node; node = nextnode) { + nextnode = node->next; + + /* Remove interface nodes. + * This also removes remaining links to and from interface nodes. + */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + /* We must delay removal since sockets will reference this node. see: T52092 */ + BLI_linklist_prepend(&nodes_delayed_free, node); + } + + /* keep track of this node's RNA "base" path (the part of the path 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); + + /* ensure unique node name in the node tree */ + nodeUniqueName(ntree, node); + + if (!node->parent) { + node->locx += gnode->locx; + node->locy += gnode->locy; + } + + node->flag |= NODE_SELECT; + } + + /* 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); + } + + /* 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; + + /* firstly, wgroup needs to temporary dummy action + * that can be destroyed, as it shares copies */ + waction = wgroup->adt->action = BKE_action_copy(bmain, wgroup->adt->action); + + /* now perform the moving */ + BKE_animdata_separate_by_basepath(bmain, &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) { + BKE_id_free(bmain, waction); + wgroup->adt->action = NULL; + } + } + + /* free the group tree (takes care of user count) */ + BKE_id_free(bmain, wgroup); + + /* restore external links to and from the gnode */ + /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node), + * then transferred to ntree (new_node pointers remain valid). + */ + + /* input links */ + for (link = ngroup->links.first; link; link = link->next) { + if (link->fromnode->type == NODE_GROUP_INPUT) { + const char *identifier = link->fromsock->identifier; + int num_external_links = 0; + + /* find external links to this input */ + for (tlink = ntree->links.first; tlink; tlink = tlink->next) { + if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, + tlink->fromnode, + tlink->fromsock, + link->tonode->new_node, + link->tosock->new_sock); + ++num_external_links; + } + } + + /* if group output is not externally linked, + * convert the constant input value to ensure somewhat consistent behavior */ + if (num_external_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier); + BLI_assert(sock);*/ + + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, + * ntree, sock, gnode);*/ + } + } + } + + /* output links */ + for (link = ntree->links.first; link; link = link->next) { + if (link->fromnode == gnode) { + const char *identifier = link->fromsock->identifier; + int num_internal_links = 0; + + /* find internal links to this output */ + for (tlink = ngroup->links.first; tlink; tlink = tlink->next) { + /* only use active output node */ + if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) { + if (STREQ(tlink->tosock->identifier, identifier)) { + nodeAddLink(ntree, + tlink->fromnode->new_node, + tlink->fromsock->new_sock, + link->tonode, + link->tosock); + ++num_internal_links; + } + } + } + + /* if group output is not internally linked, + * convert the constant output value to ensure somewhat consistent behavior */ + if (num_internal_links == 0) { + /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier); + BLI_assert(sock);*/ + + /* XXX TODO + * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */ + } + } + } + + while (nodes_delayed_free) { + node = BLI_linklist_pop(&nodes_delayed_free); + nodeRemoveNode(bmain, ntree, node, false); + } + + /* delete the group instance */ + nodeRemoveNode(bmain, ntree, gnode, false); + + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + + return 1; } - static int node_group_ungroup_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceNode *snode = CTX_wm_space_node(C); - const char *node_idname = group_node_idname(C); - bNode *gnode; - - ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - - gnode = node_group_get_active(C, node_idname); - if (!gnode) { - return OPERATOR_CANCELLED; - } - - if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) { - ntreeUpdateTree(bmain, snode->nodetree); - } - else { - BKE_report(op->reports, RPT_WARNING, "Cannot ungroup"); - return OPERATOR_CANCELLED; - } - - snode_notify(C, snode); - snode_dag_update(C, snode); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + const char *node_idname = group_node_idname(C); + bNode *gnode; + + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); + + gnode = node_group_get_active(C, node_idname); + if (!gnode) { + return OPERATOR_CANCELLED; + } + + if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) { + ntreeUpdateTree(bmain, snode->nodetree); + } + else { + BKE_report(op->reports, RPT_WARNING, "Cannot ungroup"); + return OPERATOR_CANCELLED; + } + + snode_notify(C, snode); + snode_dag_update(C, snode); + + return OPERATOR_FINISHED; } void NODE_OT_group_ungroup(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Ungroup"; - ot->description = "Ungroup selected nodes"; - ot->idname = "NODE_OT_group_ungroup"; + /* identifiers */ + ot->name = "Ungroup"; + ot->description = "Ungroup selected nodes"; + ot->idname = "NODE_OT_group_ungroup"; - /* api callbacks */ - ot->exec = node_group_ungroup_exec; - ot->poll = node_group_operator_editable; + /* api callbacks */ + ot->exec = node_group_ungroup_exec; + ot->poll = node_group_operator_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************** Separate operator ********************** */ /* returns 1 if its OK */ static int node_group_separate_selected( - Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy) + Main *bmain, bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy) { - bNodeLink *link, *link_next; - bNode *node, *node_next, *newnode; - ListBase anim_basepaths = {NULL, NULL}; - - /* deselect all nodes in the target tree */ - for (node = ntree->nodes.first; node; node = node->next) { - nodeSetSelected(node, false); - } - - /* clear new pointers, set in BKE_node_copy_ex(). */ - for (node = ngroup->nodes.first; node; node = node->next) { - node->new_node = NULL; - } - - /* add selected nodes into the ntree */ - for (node = ngroup->nodes.first; node; node = node_next) { - node_next = node->next; - if (!(node->flag & NODE_SELECT)) { - continue; - } - - /* ignore interface nodes */ - if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { - nodeSetSelected(node, false); - continue; - } - - if (make_copy) { - /* make a copy */ - newnode = BKE_node_copy_ex(ngroup, node, LIB_ID_COPY_DEFAULT); - } - else { - /* use the existing node */ - newnode = node; - } - - /* keep track of this node's RNA "base" path (the part of the path identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ - if (ngroup->adt) { - PointerRNA ptr; - char *path; - - RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr); - path = RNA_path_from_ID_to_struct(&ptr); - - if (path) { - BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); - } - } - - /* ensure valid parent pointers, detach if parent stays inside the group */ - if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) { - nodeDetachNode(newnode); - } - - /* migrate node */ - BLI_remlink(&ngroup->nodes, newnode); - BLI_addtail(&ntree->nodes, newnode); - - /* ensure unique node name in the node tree */ - nodeUniqueName(ntree, newnode); - - if (!newnode->parent) { - newnode->locx += offx; - newnode->locy += offy; - } - } - - /* add internal links to the ntree */ - for (link = ngroup->links.first; link; link = link_next) { - const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT)); - const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT)); - link_next = link->next; - - if (make_copy) { - /* make a copy of internal links */ - if (fromselect && toselect) { - nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, link->tonode->new_node, link->tosock->new_sock); - } - } - else { - /* move valid links over, delete broken links */ - if (fromselect && toselect) { - BLI_remlink(&ngroup->links, link); - BLI_addtail(&ntree->links, link); - } - else if (fromselect || toselect) { - nodeRemLink(ngroup, link); - } - } - } - - /* and copy across the animation, - * note that the animation data's action can be NULL here */ - if (ngroup->adt) { - LinkData *ld, *ldn = NULL; - - /* now perform the moving */ - BKE_animdata_separate_by_basepath(bmain, &ngroup->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); - } - } - - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - if (!make_copy) { - ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - } - - return 1; + bNodeLink *link, *link_next; + bNode *node, *node_next, *newnode; + ListBase anim_basepaths = {NULL, NULL}; + + /* deselect all nodes in the target tree */ + for (node = ntree->nodes.first; node; node = node->next) { + nodeSetSelected(node, false); + } + + /* clear new pointers, set in BKE_node_copy_ex(). */ + for (node = ngroup->nodes.first; node; node = node->next) { + node->new_node = NULL; + } + + /* add selected nodes into the ntree */ + for (node = ngroup->nodes.first; node; node = node_next) { + node_next = node->next; + if (!(node->flag & NODE_SELECT)) { + continue; + } + + /* ignore interface nodes */ + if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + nodeSetSelected(node, false); + continue; + } + + if (make_copy) { + /* make a copy */ + newnode = BKE_node_copy_ex(ngroup, node, LIB_ID_COPY_DEFAULT); + } + else { + /* use the existing node */ + newnode = node; + } + + /* keep track of this node's RNA "base" path (the part of the path identifying the node) + * if the old nodetree has animation data which potentially covers this node + */ + if (ngroup->adt) { + PointerRNA ptr; + char *path; + + RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr); + path = RNA_path_from_ID_to_struct(&ptr); + + if (path) { + BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); + } + } + + /* ensure valid parent pointers, detach if parent stays inside the group */ + if (newnode->parent && !(newnode->parent->flag & NODE_SELECT)) { + nodeDetachNode(newnode); + } + + /* migrate node */ + BLI_remlink(&ngroup->nodes, newnode); + BLI_addtail(&ntree->nodes, newnode); + + /* ensure unique node name in the node tree */ + nodeUniqueName(ntree, newnode); + + if (!newnode->parent) { + newnode->locx += offx; + newnode->locy += offy; + } + } + + /* add internal links to the ntree */ + for (link = ngroup->links.first; link; link = link_next) { + const bool fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT)); + const bool toselect = (link->tonode && (link->tonode->flag & NODE_SELECT)); + link_next = link->next; + + if (make_copy) { + /* make a copy of internal links */ + if (fromselect && toselect) { + nodeAddLink(ntree, + link->fromnode->new_node, + link->fromsock->new_sock, + link->tonode->new_node, + link->tosock->new_sock); + } + } + else { + /* move valid links over, delete broken links */ + if (fromselect && toselect) { + BLI_remlink(&ngroup->links, link); + BLI_addtail(&ntree->links, link); + } + else if (fromselect || toselect) { + nodeRemLink(ngroup, link); + } + } + } + + /* and copy across the animation, + * note that the animation data's action can be NULL here */ + if (ngroup->adt) { + LinkData *ld, *ldn = NULL; + + /* now perform the moving */ + BKE_animdata_separate_by_basepath(bmain, &ngroup->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); + } + } + + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + if (!make_copy) { + ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + } + + return 1; } typedef enum eNodeGroupSeparateType { - NODE_GS_COPY, - NODE_GS_MOVE, + NODE_GS_COPY, + NODE_GS_MOVE, } eNodeGroupSeparateType; /* Operator Property */ static const EnumPropertyItem node_group_separate_types[] = { - {NODE_GS_COPY, "COPY", 0, "Copy", "Copy to parent node tree, keep group intact"}, - {NODE_GS_MOVE, "MOVE", 0, "Move", "Move to parent node tree, remove from group"}, - {0, NULL, 0, NULL, NULL}, + {NODE_GS_COPY, "COPY", 0, "Copy", "Copy to parent node tree, keep group intact"}, + {NODE_GS_MOVE, "MOVE", 0, "Move", "Move to parent node tree, remove from group"}, + {0, NULL, 0, NULL, NULL}, }; static int node_group_separate_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ngroup, *nparent; - int type = RNA_enum_get(op->ptr, "type"); - float offx, offy; - - ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - - /* are we inside of a group? */ - ngroup = snode->edittree; - nparent = ED_node_tree_get(snode, 1); - if (!nparent) { - BKE_report(op->reports, RPT_WARNING, "Not inside node group"); - return OPERATOR_CANCELLED; - } - /* get node tree offset */ - snode_group_offset(snode, &offx, &offy); - - switch (type) { - case NODE_GS_COPY: - if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) { - BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); - return OPERATOR_CANCELLED; - } - break; - case NODE_GS_MOVE: - if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) { - BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); - return OPERATOR_CANCELLED; - } - break; - } - - /* switch to parent tree */ - ED_node_tree_pop(snode); - - ntreeUpdateTree(CTX_data_main(C), snode->nodetree); - - snode_notify(C, snode); - snode_dag_update(C, snode); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ngroup, *nparent; + int type = RNA_enum_get(op->ptr, "type"); + float offx, offy; + + ED_preview_kill_jobs(CTX_wm_manager(C), bmain); + + /* are we inside of a group? */ + ngroup = snode->edittree; + nparent = ED_node_tree_get(snode, 1); + if (!nparent) { + BKE_report(op->reports, RPT_WARNING, "Not inside node group"); + return OPERATOR_CANCELLED; + } + /* get node tree offset */ + snode_group_offset(snode, &offx, &offy); + + switch (type) { + case NODE_GS_COPY: + if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, true)) { + BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); + return OPERATOR_CANCELLED; + } + break; + case NODE_GS_MOVE: + if (!node_group_separate_selected(bmain, nparent, ngroup, offx, offy, false)) { + BKE_report(op->reports, RPT_WARNING, "Cannot separate nodes"); + return OPERATOR_CANCELLED; + } + break; + } + + /* switch to parent tree */ + ED_node_tree_pop(snode); + + ntreeUpdateTree(CTX_data_main(C), snode->nodetree); + + snode_notify(C, snode); + snode_dag_update(C, snode); + + return OPERATOR_FINISHED; } -static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +static int node_group_separate_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) { - uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); - uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); - uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY); - uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE); + uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT); + uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY); + uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE); - UI_popup_menu_end(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_INTERFACE; + return OPERATOR_INTERFACE; } void NODE_OT_group_separate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Separate"; - ot->description = "Separate selected nodes from the node group"; - ot->idname = "NODE_OT_group_separate"; + /* identifiers */ + ot->name = "Separate"; + ot->description = "Separate selected nodes from the node group"; + ot->idname = "NODE_OT_group_separate"; - /* api callbacks */ - ot->invoke = node_group_separate_invoke; - ot->exec = node_group_separate_exec; - ot->poll = node_group_operator_editable; + /* api callbacks */ + ot->invoke = node_group_separate_invoke; + ot->exec = node_group_separate_exec; + ot->poll = node_group_operator_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_enum(ot->srna, "type", node_group_separate_types, NODE_GS_COPY, "Type", ""); + RNA_def_enum(ot->srna, "type", node_group_separate_types, NODE_GS_COPY, "Type", ""); } /* ****************** Make Group operator ******************* */ static bool node_group_make_use_node(bNode *node, bNode *gnode) { - return (node != gnode && - !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) && - (node->flag & NODE_SELECT)); + return (node != gnode && !ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) && + (node->flag & NODE_SELECT)); } -static bool node_group_make_test_selected(bNodeTree *ntree, bNode *gnode, const char *ntree_idname, struct ReportList *reports) +static bool node_group_make_test_selected(bNodeTree *ntree, + bNode *gnode, + const char *ntree_idname, + struct ReportList *reports) { - bNodeTree *ngroup; - bNode *node; - bNodeLink *link; - int ok = true; - - /* make a local pseudo node tree to pass to the node poll functions */ - ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname); - - /* check poll functions for selected nodes */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node_group_make_use_node(node, gnode)) { - if (node->typeinfo->poll_instance && !node->typeinfo->poll_instance(node, ngroup)) { - BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name); - ok = false; - break; - } - } - - node->done = 0; - } - - /* free local pseudo node tree again */ - ntreeFreeTree(ngroup); - MEM_freeN(ngroup); - if (!ok) { - return false; - } - - /* 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 (node_group_make_use_node(link->fromnode, gnode)) { - link->tonode->done |= 1; - } - if (node_group_make_use_node(link->tonode, gnode)) { - link->fromnode->done |= 2; - } - } - for (node = ntree->nodes.first; node; node = node->next) { - if (!(node->flag & NODE_SELECT) && - node != gnode && - node->done == 3) - { - return false; - } - } - return true; + bNodeTree *ngroup; + bNode *node; + bNodeLink *link; + int ok = true; + + /* make a local pseudo node tree to pass to the node poll functions */ + ngroup = ntreeAddTree(NULL, "Pseudo Node Group", ntree_idname); + + /* check poll functions for selected nodes */ + for (node = ntree->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode)) { + if (node->typeinfo->poll_instance && !node->typeinfo->poll_instance(node, ngroup)) { + BKE_reportf(reports, RPT_WARNING, "Can not add node '%s' in a group", node->name); + ok = false; + break; + } + } + + node->done = 0; + } + + /* free local pseudo node tree again */ + ntreeFreeTree(ngroup); + MEM_freeN(ngroup); + if (!ok) { + return false; + } + + /* 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 (node_group_make_use_node(link->fromnode, gnode)) { + link->tonode->done |= 1; + } + if (node_group_make_use_node(link->tonode, gnode)) { + link->fromnode->done |= 2; + } + } + for (node = ntree->nodes.first; node; node = node->next) { + if (!(node->flag & NODE_SELECT) && node != gnode && node->done == 3) { + return false; + } + } + return true; } static int node_get_selected_minmax(bNodeTree *ntree, bNode *gnode, float *min, float *max) { - bNode *node; - float loc[2]; - int totselect = 0; - - INIT_MINMAX2(min, max); - for (node = ntree->nodes.first; node; node = node->next) { - if (node_group_make_use_node(node, gnode)) { - nodeToView(node, 0.0f, 0.0f, &loc[0], &loc[1]); - minmax_v2v2_v2(min, max, loc); - ++totselect; - } - } - - /* sane min/max if no selected nodes */ - if (totselect == 0) { - min[0] = min[1] = max[0] = max[1] = 0.0f; - } - - return totselect; + bNode *node; + float loc[2]; + int totselect = 0; + + INIT_MINMAX2(min, max); + for (node = ntree->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode)) { + nodeToView(node, 0.0f, 0.0f, &loc[0], &loc[1]); + minmax_v2v2_v2(min, max, loc); + ++totselect; + } + } + + /* sane min/max if no selected nodes */ + if (totselect == 0) { + min[0] = min[1] = max[0] = max[1] = 0.0f; + } + + return totselect; } static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode) { - Main *bmain = CTX_data_main(C); - bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNodeLink *link, *linkn; - bNode *node, *nextn; - bNodeSocket *sock; - ListBase anim_basepaths = {NULL, NULL}; - float min[2], max[2], center[2]; - int totselect; - bool expose_all = false; - bNode *input_node, *output_node; - - /* XXX rough guess, not nice but we don't have access to UI constants here ... */ - static const float offsetx = 200; - static const float offsety = 0.0f; - - /* deselect all nodes in the target tree */ - for (node = ngroup->nodes.first; node; node = node->next) { - nodeSetSelected(node, false); - } - - totselect = node_get_selected_minmax(ntree, gnode, min, max); - add_v2_v2v2(center, min, max); - mul_v2_fl(center, 0.5f); - - /* auto-add interface for "solo" nodes */ - if (totselect == 1) { - expose_all = true; - } - - /* move nodes over */ - for (node = ntree->nodes.first; node; node = nextn) { - nextn = node->next; - if (node_group_make_use_node(node, gnode)) { - /* 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)); - } - } - - /* ensure valid parent pointers, detach if parent stays outside the group */ - if (node->parent && !(node->parent->flag & NODE_SELECT)) { - nodeDetachNode(node); - } - - /* change node-collection membership */ - BLI_remlink(&ntree->nodes, node); - BLI_addtail(&ngroup->nodes, node); - - /* ensure unique node name in the ngroup */ - nodeUniqueName(ngroup, node); - } - } - - /* move animation data over */ - if (ntree->adt) { - LinkData *ld, *ldn = NULL; - - BKE_animdata_separate_by_basepath(bmain, &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); - - /* create input node */ - input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT); - input_node->locx = min[0] - center[0] - offsetx; - input_node->locy = -offsety; - - /* create output node */ - output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT); - output_node->locx = max[0] - center[0] + offsetx; - output_node->locy = -offsety; - - /* relink external sockets */ - for (link = ntree->links.first; link; link = linkn) { - int fromselect = node_group_make_use_node(link->fromnode, gnode); - int toselect = node_group_make_use_node(link->tonode, gnode); - - linkn = link->next; - - if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) { - /* remove all links to/from the gnode. - * this can remove link information, but there's no general way to preserve it. - */ - nodeRemLink(ntree, link); - } - else if (fromselect && toselect) { - BLI_remlink(&ntree->links, link); - BLI_addtail(&ngroup->links, link); - } - else if (toselect) { - bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->tonode, link->tosock); - bNodeSocket *input_sock; - - /* update the group node and interface node sockets, - * so the new interface socket can be linked. - */ - node_group_verify(ntree, gnode, (ID *)ngroup); - node_group_input_verify(ngroup, input_node, (ID *)ngroup); - - /* create new internal link */ - input_sock = node_group_input_find_socket(input_node, iosock->identifier); - nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock); - - /* redirect external link */ - link->tonode = gnode; - link->tosock = node_group_find_input_socket(gnode, iosock->identifier); - } - else if (fromselect) { - /* First check whether the source of this link is already connected to an output. - * If yes, reuse that output instead of duplicating it. */ - bool connected = false; - bNodeLink *olink; - for (olink = ngroup->links.first; olink; olink = olink->next) { - if (olink->fromsock == link->fromsock && olink->tonode == output_node) { - bNodeSocket *output_sock = node_group_find_output_socket(gnode, olink->tosock->identifier); - link->fromnode = gnode; - link->fromsock = output_sock; - connected = true; - } - } - - if (!connected) { - bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock); - bNodeSocket *output_sock; - - /* update the group node and interface node sockets, - * so the new interface socket can be linked. - */ - node_group_verify(ntree, gnode, (ID *)ngroup); - node_group_output_verify(ngroup, output_node, (ID *)ngroup); - - /* create new internal link */ - output_sock = node_group_output_find_socket(output_node, iosock->identifier); - nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock); - - /* redirect external link */ - link->fromnode = gnode; - link->fromsock = node_group_find_output_socket(gnode, iosock->identifier); - } - } - } - - /* move nodes in the group to the center */ - for (node = ngroup->nodes.first; node; node = node->next) { - if (node_group_make_use_node(node, gnode) && !node->parent) { - node->locx -= center[0]; - node->locy -= center[1]; - } - } - - /* expose all unlinked sockets too */ - if (expose_all) { - for (node = ngroup->nodes.first; node; node = node->next) { - if (node_group_make_use_node(node, gnode)) { - for (sock = node->inputs.first; sock; sock = sock->next) { - bNodeSocket *iosock, *input_sock; - bool skip = false; - for (link = ngroup->links.first; link; link = link->next) { - if (link->tosock == sock) { - skip = true; - break; - } - } - if (skip) { - continue; - } - - iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); - - node_group_input_verify(ngroup, input_node, (ID *)ngroup); - - /* create new internal link */ - input_sock = node_group_input_find_socket(input_node, iosock->identifier); - nodeAddLink(ngroup, input_node, input_sock, node, sock); - } - - for (sock = node->outputs.first; sock; sock = sock->next) { - bNodeSocket *iosock, *output_sock; - bool skip = false; - for (link = ngroup->links.first; link; link = link->next) { - if (link->fromsock == sock) { - skip = true; - } - } - if (skip) { - continue; - } - - iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); - - node_group_output_verify(ngroup, output_node, (ID *)ngroup); - - /* create new internal link */ - output_sock = node_group_output_find_socket(output_node, iosock->identifier); - nodeAddLink(ngroup, node, sock, output_node, output_sock); - } - } - } - } - - /* update of the group tree */ - ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; - /* update of the tree containing the group instance node */ - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + Main *bmain = CTX_data_main(C); + bNodeTree *ngroup = (bNodeTree *)gnode->id; + bNodeLink *link, *linkn; + bNode *node, *nextn; + bNodeSocket *sock; + ListBase anim_basepaths = {NULL, NULL}; + float min[2], max[2], center[2]; + int totselect; + bool expose_all = false; + bNode *input_node, *output_node; + + /* XXX rough guess, not nice but we don't have access to UI constants here ... */ + static const float offsetx = 200; + static const float offsety = 0.0f; + + /* deselect all nodes in the target tree */ + for (node = ngroup->nodes.first; node; node = node->next) { + nodeSetSelected(node, false); + } + + totselect = node_get_selected_minmax(ntree, gnode, min, max); + add_v2_v2v2(center, min, max); + mul_v2_fl(center, 0.5f); + + /* auto-add interface for "solo" nodes */ + if (totselect == 1) { + expose_all = true; + } + + /* move nodes over */ + for (node = ntree->nodes.first; node; node = nextn) { + nextn = node->next; + if (node_group_make_use_node(node, gnode)) { + /* 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)); + } + } + + /* ensure valid parent pointers, detach if parent stays outside the group */ + if (node->parent && !(node->parent->flag & NODE_SELECT)) { + nodeDetachNode(node); + } + + /* change node-collection membership */ + BLI_remlink(&ntree->nodes, node); + BLI_addtail(&ngroup->nodes, node); + + /* ensure unique node name in the ngroup */ + nodeUniqueName(ngroup, node); + } + } + + /* move animation data over */ + if (ntree->adt) { + LinkData *ld, *ldn = NULL; + + BKE_animdata_separate_by_basepath(bmain, &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); + + /* create input node */ + input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT); + input_node->locx = min[0] - center[0] - offsetx; + input_node->locy = -offsety; + + /* create output node */ + output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT); + output_node->locx = max[0] - center[0] + offsetx; + output_node->locy = -offsety; + + /* relink external sockets */ + for (link = ntree->links.first; link; link = linkn) { + int fromselect = node_group_make_use_node(link->fromnode, gnode); + int toselect = node_group_make_use_node(link->tonode, gnode); + + linkn = link->next; + + if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) { + /* remove all links to/from the gnode. + * this can remove link information, but there's no general way to preserve it. + */ + nodeRemLink(ntree, link); + } + else if (fromselect && toselect) { + BLI_remlink(&ntree->links, link); + BLI_addtail(&ngroup->links, link); + } + else if (toselect) { + bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->tonode, link->tosock); + bNodeSocket *input_sock; + + /* update the group node and interface node sockets, + * so the new interface socket can be linked. + */ + node_group_verify(ntree, gnode, (ID *)ngroup); + node_group_input_verify(ngroup, input_node, (ID *)ngroup); + + /* create new internal link */ + input_sock = node_group_input_find_socket(input_node, iosock->identifier); + nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock); + + /* redirect external link */ + link->tonode = gnode; + link->tosock = node_group_find_input_socket(gnode, iosock->identifier); + } + else if (fromselect) { + /* First check whether the source of this link is already connected to an output. + * If yes, reuse that output instead of duplicating it. */ + bool connected = false; + bNodeLink *olink; + for (olink = ngroup->links.first; olink; olink = olink->next) { + if (olink->fromsock == link->fromsock && olink->tonode == output_node) { + bNodeSocket *output_sock = node_group_find_output_socket(gnode, + olink->tosock->identifier); + link->fromnode = gnode; + link->fromsock = output_sock; + connected = true; + } + } + + if (!connected) { + bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket( + ngroup, link->fromnode, link->fromsock); + bNodeSocket *output_sock; + + /* update the group node and interface node sockets, + * so the new interface socket can be linked. + */ + node_group_verify(ntree, gnode, (ID *)ngroup); + node_group_output_verify(ngroup, output_node, (ID *)ngroup); + + /* create new internal link */ + output_sock = node_group_output_find_socket(output_node, iosock->identifier); + nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock); + + /* redirect external link */ + link->fromnode = gnode; + link->fromsock = node_group_find_output_socket(gnode, iosock->identifier); + } + } + } + + /* move nodes in the group to the center */ + for (node = ngroup->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode) && !node->parent) { + node->locx -= center[0]; + node->locy -= center[1]; + } + } + + /* expose all unlinked sockets too */ + if (expose_all) { + for (node = ngroup->nodes.first; node; node = node->next) { + if (node_group_make_use_node(node, gnode)) { + for (sock = node->inputs.first; sock; sock = sock->next) { + bNodeSocket *iosock, *input_sock; + bool skip = false; + for (link = ngroup->links.first; link; link = link->next) { + if (link->tosock == sock) { + skip = true; + break; + } + } + if (skip) { + continue; + } + + iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); + + node_group_input_verify(ngroup, input_node, (ID *)ngroup); + + /* create new internal link */ + input_sock = node_group_input_find_socket(input_node, iosock->identifier); + nodeAddLink(ngroup, input_node, input_sock, node, sock); + } + + for (sock = node->outputs.first; sock; sock = sock->next) { + bNodeSocket *iosock, *output_sock; + bool skip = false; + for (link = ngroup->links.first; link; link = link->next) { + if (link->fromsock == sock) { + skip = true; + } + } + if (skip) { + continue; + } + + iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); + + node_group_output_verify(ngroup, output_node, (ID *)ngroup); + + /* create new internal link */ + output_sock = node_group_output_find_socket(output_node, iosock->identifier); + nodeAddLink(ngroup, node, sock, output_node, output_sock); + } + } + } + } + + /* update of the group tree */ + ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; + /* update of the tree containing the group instance node */ + ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; } -static bNode *node_group_make_from_selected(const bContext *C, bNodeTree *ntree, const char *ntype, const char *ntreetype) +static bNode *node_group_make_from_selected(const bContext *C, + bNodeTree *ntree, + const char *ntype, + const char *ntreetype) { - Main *bmain = CTX_data_main(C); - bNode *gnode; - bNodeTree *ngroup; - float min[2], max[2]; - int totselect; + Main *bmain = CTX_data_main(C); + bNode *gnode; + bNodeTree *ngroup; + float min[2], max[2]; + int totselect; - totselect = node_get_selected_minmax(ntree, NULL, min, max); - /* don't make empty group */ - if (totselect == 0) { - return NULL; - } + totselect = node_get_selected_minmax(ntree, NULL, min, max); + /* don't make empty group */ + if (totselect == 0) { + return NULL; + } - /* new nodetree */ - ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype); + /* new nodetree */ + ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype); - /* make group node */ - gnode = nodeAddNode(C, ntree, ntype); - gnode->id = (ID *)ngroup; + /* make group node */ + gnode = nodeAddNode(C, ntree, ntype); + gnode->id = (ID *)ngroup; - gnode->locx = 0.5f * (min[0] + max[0]); - gnode->locy = 0.5f * (min[1] + max[1]); + gnode->locx = 0.5f * (min[0] + max[0]); + gnode->locy = 0.5f * (min[1] + max[1]); - node_group_make_insert_selected(C, ntree, gnode); + node_group_make_insert_selected(C, ntree, gnode); - /* update of the tree containing the group instance node */ - ntree->update |= NTREE_UPDATE_NODES; + /* update of the tree containing the group instance node */ + ntree->update |= NTREE_UPDATE_NODES; - return gnode; + return gnode; } static int node_group_make_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - const char *ntree_idname = group_ntree_idname(C); - const char *node_idname = group_node_idname(C); - bNodeTree *ngroup; - bNode *gnode; - Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + const char *ntree_idname = group_ntree_idname(C); + const char *node_idname = group_node_idname(C); + bNodeTree *ngroup; + bNode *gnode; + Main *bmain = CTX_data_main(C); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports)) { - return OPERATOR_CANCELLED; - } + if (!node_group_make_test_selected(ntree, NULL, ntree_idname, op->reports)) { + return OPERATOR_CANCELLED; + } - gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname); + gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname); - if (gnode) { - ngroup = (bNodeTree *)gnode->id; + if (gnode) { + ngroup = (bNodeTree *)gnode->id; - nodeSetActive(ntree, gnode); - if (ngroup) { - ED_node_tree_push(snode, ngroup, gnode); - ntreeUpdateTree(bmain, ngroup); - } - } + nodeSetActive(ntree, gnode); + if (ngroup) { + ED_node_tree_push(snode, ngroup, gnode); + ntreeUpdateTree(bmain, ngroup); + } + } - ntreeUpdateTree(bmain, ntree); + ntreeUpdateTree(bmain, ntree); - snode_notify(C, snode); - snode_dag_update(C, snode); + snode_notify(C, snode); + snode_dag_update(C, snode); - /* We broke relations in node tree, need to rebuild them in the grahes. */ - DEG_relations_tag_update(bmain); + /* We broke relations in node tree, need to rebuild them in the grahes. */ + DEG_relations_tag_update(bmain); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void NODE_OT_group_make(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Make Group"; - ot->description = "Make group from selected nodes"; - ot->idname = "NODE_OT_group_make"; + /* identifiers */ + ot->name = "Make Group"; + ot->description = "Make group from selected nodes"; + ot->idname = "NODE_OT_group_make"; - /* api callbacks */ - ot->exec = node_group_make_exec; - ot->poll = node_group_operator_editable; + /* api callbacks */ + ot->exec = node_group_make_exec; + ot->poll = node_group_operator_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ****************** Group Insert operator ******************* */ static int node_group_insert_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - bNodeTree *ngroup; - const char *node_idname = group_node_idname(C); - bNode *gnode; - Main *bmain = CTX_data_main(C); + SpaceNode *snode = CTX_wm_space_node(C); + bNodeTree *ntree = snode->edittree; + bNodeTree *ngroup; + const char *node_idname = group_node_idname(C); + bNode *gnode; + Main *bmain = CTX_data_main(C); - ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - gnode = node_group_get_active(C, node_idname); + gnode = node_group_get_active(C, node_idname); - if (!gnode || !gnode->id) { - return OPERATOR_CANCELLED; - } + if (!gnode || !gnode->id) { + return OPERATOR_CANCELLED; + } - ngroup = (bNodeTree *)gnode->id; - if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) { - return OPERATOR_CANCELLED; - } + ngroup = (bNodeTree *)gnode->id; + if (!node_group_make_test_selected(ntree, gnode, ngroup->idname, op->reports)) { + return OPERATOR_CANCELLED; + } - node_group_make_insert_selected(C, ntree, gnode); + node_group_make_insert_selected(C, ntree, gnode); - nodeSetActive(ntree, gnode); - ED_node_tree_push(snode, ngroup, gnode); - ntreeUpdateTree(bmain, ngroup); + nodeSetActive(ntree, gnode); + ED_node_tree_push(snode, ngroup, gnode); + ntreeUpdateTree(bmain, ngroup); - ntreeUpdateTree(bmain, ntree); + ntreeUpdateTree(bmain, ntree); - snode_notify(C, snode); - snode_dag_update(C, snode); + snode_notify(C, snode); + snode_dag_update(C, snode); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void NODE_OT_group_insert(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Group Insert"; - ot->description = "Insert selected nodes into a node group"; - ot->idname = "NODE_OT_group_insert"; + /* identifiers */ + ot->name = "Group Insert"; + ot->description = "Insert selected nodes into a node group"; + ot->idname = "NODE_OT_group_insert"; - /* api callbacks */ - ot->exec = node_group_insert_exec; - ot->poll = node_group_operator_editable; + /* api callbacks */ + ot->exec = node_group_insert_exec; + ot->poll = node_group_operator_editable; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } |