This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/space_node/node_group.c

1079 lines
31 KiB
C
Raw Normal View History

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup spnode
*/
#include <stdlib.h>
#include "MEM_guardedalloc.h"
#include "DNA_node_types.h"
#include "DNA_anim_types.h"
#include "BLI_listbase.h"
2017-07-19 14:32:31 +10:00
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLT_translation.h"
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_render.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
#include "UI_resources.h"
#include "node_intern.h" /* own include */
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
#include "NOD_common.h"
2018-07-02 11:47:00 +02:00
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;
}
2018-07-02 11:47:00 +02:00
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;
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
}
static const char *group_ntree_idname(bContext *C)
{
SpaceNode *snode = CTX_wm_space_node(C);
return snode->tree_idname;
}
static const char *group_node_idname(bContext *C)
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
{
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 "";
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
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;
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
/* ***************** Edit Group operator ************* */
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
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");
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
gnode = node_group_get_active(C, node_idname);
if (gnode && !exit) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
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);
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";
/* api callbacks */
ot->exec = node_group_edit_exec;
ot->poll = node_group_operator_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "exit", false, "Exit", "");
}
/* ******************** Ungroup operator ********************** */
/* returns 1 if its OK */
2018-06-09 15:16:44 +02:00
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;
}
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;
}
void NODE_OT_group_ungroup(wmOperatorType *ot)
{
/* 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;
/* 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)
{
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,
} 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},
};
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;
}
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);
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);
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";
/* 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;
RNA_def_enum(ot->srna, "type", node_group_separate_types, NODE_GS_COPY, "Type", "");
}
/* ****************** Make Group operator ******************* */
2013-03-18 18:25:05 +00:00
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));
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
}
static bool node_group_make_test_selected(bNodeTree *ntree,
bNode *gnode,
const char *ntree_idname,
struct ReportList *reports)
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
{
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;
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
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;
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
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_update(ntree, gnode);
node_group_input_update(ngroup, input_node);
/* 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_update(ntree, gnode);
node_group_output_update(ngroup, output_node);
/* 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_update(ngroup, input_node);
/* 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_update(ngroup, output_node);
/* 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)
{
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;
}
/* new nodetree */
ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
/* 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]);
node_group_make_insert_selected(C, ntree, gnode);
/* update of the tree containing the group instance node */
ntree->update |= NTREE_UPDATE_NODES;
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);
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;
}
gnode = node_group_make_from_selected(C, ntree, node_idname, ntree_idname);
if (gnode) {
ngroup = (bNodeTree *)gnode->id;
nodeSetActive(ntree, gnode);
if (ngroup) {
ED_node_tree_push(snode, ngroup, gnode);
ntreeUpdateTree(bmain, ngroup);
}
}
ntreeUpdateTree(bmain, ntree);
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);
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";
/* api callbacks */
ot->exec = node_group_make_exec;
ot->poll = node_group_operator_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
}
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
/* ****************** 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);
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
gnode = node_group_get_active(C, node_idname);
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;
}
node_group_make_insert_selected(C, ntree, gnode);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
ntreeUpdateTree(bmain, ngroup);
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
snode_dag_update(C, snode);
return OPERATOR_FINISHED;
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
}
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";
/* api callbacks */
ot->exec = node_group_insert_exec;
ot->poll = node_group_operator_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}