2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2005 Blender Foundation.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Nathan Letwory
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/space_node/node_edit.c
39 #include "MEM_guardedalloc.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_particle_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_world_types.h"
49 #include "DNA_action_types.h"
50 #include "DNA_anim_types.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_utildefines.h"
56 #include "BKE_action.h"
57 #include "BKE_animsys.h"
58 #include "BKE_context.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_global.h"
61 #include "BKE_image.h"
62 #include "BKE_library.h"
65 #include "BKE_material.h"
66 #include "BKE_modifier.h"
67 #include "BKE_paint.h"
68 #include "BKE_scene.h"
69 #include "BKE_screen.h"
70 #include "BKE_texture.h"
71 #include "BKE_report.h"
73 #include "RE_pipeline.h"
75 #include "IMB_imbuf_types.h"
79 #include "ED_screen.h"
80 #include "ED_space_api.h"
81 #include "ED_render.h"
83 #include "RNA_access.h"
84 #include "RNA_define.h"
85 #include "RNA_enum_types.h"
90 #include "UI_interface.h"
91 #include "UI_resources.h"
92 #include "UI_view2d.h"
94 #include "IMB_imbuf.h"
96 #include "RNA_enum_types.h"
98 #include "GPU_material.h"
100 #include "node_intern.h"
101 #include "NOD_socket.h"
103 static EnumPropertyItem socket_in_out_items[] = {
104 { SOCK_IN, "SOCK_IN", 0, "Input", "" },
105 { SOCK_OUT, "SOCK_OUT", 0, "Output", "" },
106 { 0, NULL, 0, NULL, NULL },
109 /* ***************** composite job manager ********************** */
111 typedef struct CompoJob {
114 bNodeTree *localtree;
120 /* called by compo, only to check job 'stop' value */
121 static int compo_breakjob(void *cjv)
128 /* called by compo, wmJob sends notifier */
129 static void compo_redrawjob(void *cjv, char *UNUSED(str))
133 *(cj->do_update) = TRUE;
136 static void compo_freejob(void *cjv)
141 ntreeLocalMerge(cj->localtree, cj->ntree);
146 /* only now we copy the nodetree, so adding many jobs while
147 * sliding buttons doesn't frustrate */
148 static void compo_initjob(void *cjv)
152 cj->localtree = ntreeLocalize(cj->ntree);
155 /* called before redraw notifiers, it moves finished previews over */
156 static void compo_updatejob(void *cjv)
160 ntreeLocalSync(cj->localtree, cj->ntree);
163 static void compo_progressjob(void *cjv, float progress)
167 *(cj->progress) = progress;
171 /* only this runs inside thread */
172 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
175 bNodeTree *ntree = cj->localtree;
177 if (cj->scene->use_nodes == FALSE)
181 cj->do_update = do_update;
182 cj->progress = progress;
184 ntree->test_break = compo_breakjob;
186 ntree->stats_draw = compo_redrawjob;
188 ntree->progress = compo_progressjob;
191 // XXX BIF_store_spare();
193 ntreeCompositExecTree(ntree, &cj->scene->r, 0, 1); /* 1 is do_previews */
195 ntree->test_break = NULL;
196 ntree->stats_draw = NULL;
197 ntree->progress = NULL;
201 void snode_composite_job(const bContext *C, ScrArea *sa)
203 SpaceNode *snode = sa->spacedata.first;
207 steve = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Compositing", WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS);
208 cj = MEM_callocN(sizeof(CompoJob), "compo job");
210 /* customdata for preview thread */
211 cj->scene = CTX_data_scene(C);
212 cj->ntree = snode->nodetree;
215 WM_jobs_customdata(steve, cj, compo_freejob);
216 WM_jobs_timer(steve, 0.1, NC_SCENE, NC_SCENE | ND_COMPO_RESULT);
217 WM_jobs_callbacks(steve, compo_startjob, compo_initjob, compo_updatejob, NULL);
219 WM_jobs_start(CTX_wm_manager(C), steve);
223 /* ***************************************** */
225 /* operator poll callback */
226 static int composite_node_active(bContext *C)
228 if (ED_operator_node_active(C)) {
229 SpaceNode *snode = CTX_wm_space_node(C);
230 if (snode->treetype == NTREE_COMPOSIT)
236 /* also checks for edited groups */
237 static bNode *editnode_get_active(bNodeTree *ntree)
241 /* check for edited group */
242 for (node = ntree->nodes.first; node; node = node->next)
243 if (nodeGroupEditGet(node))
246 return nodeGetActive((bNodeTree *)node->id);
248 return nodeGetActive(ntree);
251 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
258 for (node = ntree->nodes.first; node; node = node->next)
259 if (node->type == NODE_GROUP && node->id)
260 if (has_nodetree((bNodeTree *)node->id, lookup))
266 static void snode_dag_update_group(void *calldata, ID *owner_id, bNodeTree *ntree)
268 if (has_nodetree(ntree, calldata))
269 DAG_id_tag_update(owner_id, 0);
272 void snode_dag_update(bContext *C, SpaceNode *snode)
274 Main *bmain = CTX_data_main(C);
276 /* for groups, update all ID's using this */
277 if (snode->edittree != snode->nodetree) {
278 bNodeTreeType *tti = ntreeGetType(snode->edittree->type);
279 tti->foreach_nodetree(bmain, snode->edittree, snode_dag_update_group);
282 DAG_id_tag_update(snode->id, 0);
285 void snode_notify(bContext *C, SpaceNode *snode)
287 WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL);
289 if (snode->treetype == NTREE_SHADER)
290 WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id);
291 else if (snode->treetype == NTREE_COMPOSIT)
292 WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id);
293 else if (snode->treetype == NTREE_TEXTURE)
294 WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id);
297 bNode *node_tree_get_editgroup(bNodeTree *nodetree)
301 /* get the groupnode */
302 for (gnode = nodetree->nodes.first; gnode; gnode = gnode->next)
303 if (nodeGroupEditGet(gnode))
308 /* assumes nothing being done in ntree yet, sets the default in/out node */
309 /* called from shading buttons or header */
310 void ED_node_shader_default(Scene *scene, ID *id)
313 bNodeSocket *fromsock, *tosock, *sock;
316 int output_type, shader_type;
317 float color[3], strength = 1.0f;
319 ntree = ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
321 switch (GS(id->name)) {
323 Material *ma = (Material *)id;
324 ma->nodetree = ntree;
326 if (BKE_scene_use_new_shading_nodes(scene)) {
327 output_type = SH_NODE_OUTPUT_MATERIAL;
328 shader_type = SH_NODE_BSDF_DIFFUSE;
331 output_type = SH_NODE_OUTPUT;
332 shader_type = SH_NODE_MATERIAL;
335 copy_v3_v3(color, &ma->r);
340 World *wo = (World *)id;
341 wo->nodetree = ntree;
343 output_type = SH_NODE_OUTPUT_WORLD;
344 shader_type = SH_NODE_BACKGROUND;
346 copy_v3_v3(color, &wo->horr);
351 Lamp *la = (Lamp *)id;
352 la->nodetree = ntree;
354 output_type = SH_NODE_OUTPUT_LAMP;
355 shader_type = SH_NODE_EMISSION;
357 copy_v3_v3(color, &la->r);
358 if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA)
365 printf("ED_node_shader_default called on wrong ID type.\n");
369 ntemp.type = output_type;
370 out = nodeAddNode(ntree, &ntemp);
371 out->locx = 300.0f; out->locy = 300.0f;
373 ntemp.type = shader_type;
374 in = nodeAddNode(ntree, &ntemp);
375 in->locx = 10.0f; in->locy = 300.0f;
376 nodeSetActive(ntree, in);
378 /* only a link from color to color */
379 fromsock = in->outputs.first;
380 tosock = out->inputs.first;
381 nodeAddLink(ntree, in, fromsock, out, tosock);
384 if (BKE_scene_use_new_shading_nodes(scene)) {
385 sock = in->inputs.first;
386 copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, color);
388 if (strength != 0.0f) {
389 sock = in->inputs.last;
390 ((bNodeSocketValueFloat *)sock->default_value)->value = strength;
394 ntreeUpdateTree(ntree);
397 /* assumes nothing being done in ntree yet, sets the default in/out node */
398 /* called from shading buttons or header */
399 void ED_node_composit_default(Scene *sce)
402 bNodeSocket *fromsock, *tosock;
405 /* but lets check it anyway */
407 if (G.debug & G_DEBUG)
408 printf("error in composite initialize\n");
412 sce->nodetree = ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0);
414 sce->nodetree->chunksize = 256;
415 sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
416 sce->nodetree->render_quality = NTREE_QUALITY_HIGH;
418 ntemp.type = CMP_NODE_COMPOSITE;
419 out = nodeAddNode(sce->nodetree, &ntemp);
420 out->locx = 300.0f; out->locy = 400.0f;
424 ntemp.type = CMP_NODE_R_LAYERS;
425 in = nodeAddNode(sce->nodetree, &ntemp);
426 in->locx = 10.0f; in->locy = 400.0f;
429 nodeSetActive(sce->nodetree, in);
431 /* links from color to color */
432 fromsock = in->outputs.first;
433 tosock = out->inputs.first;
434 nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
436 ntreeUpdateTree(sce->nodetree);
438 // XXX ntreeCompositForceHidden(sce->nodetree);
441 /* assumes nothing being done in ntree yet, sets the default in/out node */
442 /* called from shading buttons or header */
443 void ED_node_texture_default(Tex *tx)
446 bNodeSocket *fromsock, *tosock;
449 /* but lets check it anyway */
451 if (G.debug & G_DEBUG)
452 printf("error in texture initialize\n");
456 tx->nodetree = ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0);
458 ntemp.type = TEX_NODE_OUTPUT;
459 out = nodeAddNode(tx->nodetree, &ntemp);
460 out->locx = 300.0f; out->locy = 300.0f;
462 ntemp.type = TEX_NODE_CHECKER;
463 in = nodeAddNode(tx->nodetree, &ntemp);
464 in->locx = 10.0f; in->locy = 300.0f;
465 nodeSetActive(tx->nodetree, in);
467 fromsock = in->outputs.first;
468 tosock = out->inputs.first;
469 nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
471 ntreeUpdateTree(tx->nodetree);
474 /* id is supposed to contain a node tree */
475 void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype)
479 short idtype = GS(id->name);
481 if (idtype == ID_NT) {
482 *ntree = (bNodeTree *)id;
483 if (treetype) *treetype = (*ntree)->type;
485 else if (idtype == ID_MA) {
486 *ntree = ((Material *)id)->nodetree;
487 if (treetype) *treetype = NTREE_SHADER;
489 else if (idtype == ID_LA) {
490 *ntree = ((Lamp *)id)->nodetree;
491 if (treetype) *treetype = NTREE_SHADER;
493 else if (idtype == ID_WO) {
494 *ntree = ((World *)id)->nodetree;
495 if (treetype) *treetype = NTREE_SHADER;
497 else if (idtype == ID_SCE) {
498 *ntree = ((Scene *)id)->nodetree;
499 if (treetype) *treetype = NTREE_COMPOSIT;
501 else if (idtype == ID_TE) {
502 *ntree = ((Tex *)id)->nodetree;
503 if (treetype) *treetype = NTREE_TEXTURE;
506 if (treetype) *treetype = 0;
510 /* find editable group */
513 for (node = (*ntree)->nodes.first; node; node = node->next)
514 if (nodeGroupEditGet(node))
517 if (node && node->id)
518 *edittree = (bNodeTree *)node->id;
526 if (treetype) *treetype = 0;
530 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
531 void snode_set_context(SpaceNode *snode, Scene *scene)
535 snode->id = snode->from = NULL;
537 if (snode->treetype == NTREE_SHADER) {
538 /* need active object, or we allow pinning... */
539 if (snode->shaderfrom == SNODE_SHADER_OBJECT) {
541 if (ob->type == OB_LAMP) {
542 snode->from = &ob->id;
543 snode->id = ob->data;
546 Material *ma = give_current_material(ob, ob->actcol);
548 snode->from = &ob->id;
554 else { /* SNODE_SHADER_WORLD */
557 snode->id = &scene->world->id;
561 else if (snode->treetype == NTREE_COMPOSIT) {
562 snode->id = &scene->id;
564 /* update output sockets based on available layers */
565 ntreeCompositForceHidden(scene->nodetree, scene);
567 else if (snode->treetype == NTREE_TEXTURE) {
570 if (snode->texfrom == SNODE_TEX_OBJECT) {
572 tx = give_current_object_texture(ob);
574 if (ob->type == OB_LAMP)
575 snode->from = (ID *)ob->data;
577 snode->from = (ID *)give_current_material(ob, ob->actcol);
579 /* from is not set fully for material nodes, should be ID + Node then */
583 else if (snode->texfrom == SNODE_TEX_WORLD) {
584 tx = give_current_world_texture(scene->world);
585 snode->from = (ID *)scene->world;
589 struct Brush *brush = NULL;
591 if (ob && (ob->mode & OB_MODE_SCULPT))
592 brush = paint_brush(&scene->toolsettings->sculpt->paint);
594 brush = paint_brush(&scene->toolsettings->imapaint.paint);
597 snode->from = (ID *)brush;
598 tx = give_current_brush_texture(brush);
604 if (snode->nodetree && snode->nodetree->type == snode->treetype)
605 snode->id = &snode->nodetree->id;
610 node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
613 static void snode_update(SpaceNode *snode, bNode *node)
618 nodeUpdate(snode->edittree, node);
620 /* if inside group, tag entire group */
621 gnode = node_tree_get_editgroup(snode->nodetree);
623 nodeUpdateID(snode->nodetree, gnode->id);
626 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
628 int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
630 nodeSetActive(ntree, node);
632 if (node->type != NODE_GROUP) {
633 int was_output = (node->flag & NODE_DO_OUTPUT);
635 /* tree specific activate calls */
636 if (ntree->type == NTREE_SHADER) {
637 /* when we select a material, active texture is cleared, for buttons */
638 if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
639 nodeClearActiveID(ntree, ID_TE);
641 if (node->type == SH_NODE_OUTPUT) {
644 for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
645 if (tnode->type == SH_NODE_OUTPUT)
646 tnode->flag &= ~NODE_DO_OUTPUT;
648 node->flag |= NODE_DO_OUTPUT;
650 ED_node_generic_update(bmain, ntree, node);
653 /* if active texture changed, free glsl materials */
654 if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
657 for (ma = bmain->mat.first; ma; ma = ma->id.next)
658 if (ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
659 GPU_material_free(ma);
661 WM_main_add_notifier(NC_IMAGE, NULL);
664 WM_main_add_notifier(NC_MATERIAL | ND_NODES, node->id);
666 else if (ntree->type == NTREE_COMPOSIT) {
667 /* make active viewer, currently only 1 supported... */
668 if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
672 for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
673 if (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
674 tnode->flag &= ~NODE_DO_OUTPUT;
676 node->flag |= NODE_DO_OUTPUT;
678 ED_node_generic_update(bmain, ntree, node);
680 /* addnode() doesnt link this yet... */
681 node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
683 else if (node->type == CMP_NODE_R_LAYERS) {
686 for (scene = bmain->scene.first; scene; scene = scene->id.next) {
687 if (scene->nodetree && scene->use_nodes && has_nodetree(scene->nodetree, ntree)) {
688 if (node->id == NULL || node->id == (ID *)scene) {
689 scene->r.actlay = node->custom1;
694 else if (node->type == CMP_NODE_COMPOSITE) {
695 if (was_output == 0) {
698 for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
699 if (tnode->type == CMP_NODE_COMPOSITE)
700 tnode->flag &= ~NODE_DO_OUTPUT;
702 node->flag |= NODE_DO_OUTPUT;
703 ED_node_generic_update(bmain, ntree, node);
707 else if (ntree->type == NTREE_TEXTURE) {
711 ; // XXX BIF_preview_changed(-1);
712 // allqueue(REDRAWBUTSSHADING, 1);
713 // allqueue(REDRAWIPO, 0);
719 void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
721 /* XXX This does not work due to layout functions relying on node->block,
722 * which only exists during actual drawing. Can we rely on valid totr rects?
724 /* make sure nodes have correct bounding boxes after transform */
725 /* node_update_nodetree(C, ntree, 0.0f, 0.0f); */
728 /* ***************** generic operator functions for nodes ***************** */
732 static int edit_node_poll(bContext *C)
734 return ED_operator_node_active(C);
737 static void edit_node_properties(wmOperatorType *ot)
739 /* XXX could node be a context pointer? */
740 RNA_def_string(ot->srna, "node", "", MAX_NAME, "Node", "");
741 RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
742 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", "");
745 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
747 if (!RNA_struct_property_is_set(op->ptr, "node")) {
748 bNode *node = CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
752 RNA_string_set(op->ptr, "node", node->name);
755 if (!RNA_struct_property_is_set(op->ptr, "in_out"))
756 RNA_enum_set(op->ptr, "in_out", SOCK_IN);
758 if (!RNA_struct_property_is_set(op->ptr, "socket"))
759 RNA_int_set(op->ptr, "socket", 0);
764 static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
767 bNodeSocket *sock = NULL;
768 char nodename[MAX_NAME];
772 RNA_string_get(op->ptr, "node", nodename);
773 node = nodeFindNodebyName(ntree, nodename);
775 in_out = RNA_enum_get(op->ptr, "in_out");
777 sockindex = RNA_int_get(op->ptr, "socket");
779 case SOCK_IN: sock = BLI_findlink(&node->inputs, sockindex); break;
780 case SOCK_OUT: sock = BLI_findlink(&node->outputs, sockindex); break;
792 /* ***************** Edit Group operator ************* */
794 void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
798 /* make sure nothing has group editing on */
799 for (node = snode->nodetree->nodes.first; node; node = node->next) {
800 nodeGroupEditClear(node);
802 /* while we're here, clear texture active */
803 if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
804 /* this is not 100% sure to be reliable, see comment on the flag */
805 node->flag &= ~NODE_ACTIVE_TEXTURE;
810 /* with NULL argument we do a toggle */
811 if (snode->edittree == snode->nodetree)
812 gnode = nodeGetActive(snode->nodetree);
816 snode->edittree = nodeGroupEditSet(gnode, 1);
818 /* deselect all other nodes, so we can also do grabbing of entire subtree */
819 for (node = snode->nodetree->nodes.first; node; node = node->next) {
822 if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
823 /* this is not 100% sure to be reliable, see comment on the flag */
824 node->flag &= ~NODE_ACTIVE_TEXTURE;
830 snode->edittree = snode->nodetree;
833 static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op))
835 SpaceNode *snode = CTX_wm_space_node(C);
837 ED_preview_kill_jobs(C);
839 if (snode->nodetree == snode->edittree) {
840 bNode *gnode = nodeGetActive(snode->edittree);
841 snode_make_group_editable(snode, gnode);
844 snode_make_group_editable(snode, NULL);
846 WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
848 return OPERATOR_FINISHED;
851 static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
853 SpaceNode *snode = CTX_wm_space_node(C);
857 if (snode->nodetree == snode->edittree) {
858 gnode = nodeGetActive(snode->edittree);
859 if (gnode && gnode->id && GS(gnode->id->name) == ID_NT && gnode->id->lib) {
860 uiPupMenuOkee(C, op->type->idname, "Make group local?");
861 return OPERATOR_CANCELLED;
865 return node_group_edit_exec(C, op);
868 void NODE_OT_group_edit(wmOperatorType *ot)
871 ot->name = "Edit Group";
872 ot->description = "Edit node group";
873 ot->idname = "NODE_OT_group_edit";
876 ot->invoke = node_group_edit_invoke;
877 ot->exec = node_group_edit_exec;
878 ot->poll = ED_operator_node_active;
881 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
884 /* ***************** Add Group Socket operator ************* */
886 static int node_group_socket_add_exec(bContext *C, wmOperator *op)
888 SpaceNode *snode = CTX_wm_space_node(C);
890 char name[MAX_NAME] = "";
891 int type = SOCK_FLOAT;
892 bNodeTree *ngroup = snode->edittree;
893 /* bNodeSocket *sock; */ /* UNUSED */
895 ED_preview_kill_jobs(C);
897 if (RNA_struct_property_is_set(op->ptr, "name"))
898 RNA_string_get(op->ptr, "name", name);
900 if (RNA_struct_property_is_set(op->ptr, "type"))
901 type = RNA_enum_get(op->ptr, "type");
903 if (RNA_struct_property_is_set(op->ptr, "in_out"))
904 in_out = RNA_enum_get(op->ptr, "in_out");
906 return OPERATOR_CANCELLED;
908 /* using placeholder subtype first */
909 /* sock = */ /* UNUSED */ node_group_add_socket(ngroup, name, type, in_out);
911 ntreeUpdateTree(ngroup);
913 snode_notify(C, snode);
915 return OPERATOR_FINISHED;
918 void NODE_OT_group_socket_add(wmOperatorType *ot)
921 ot->name = "Add Group Socket";
922 ot->description = "Add node group socket";
923 ot->idname = "NODE_OT_group_socket_add";
926 ot->exec = node_group_socket_add_exec;
927 ot->poll = ED_operator_node_active;
930 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
932 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
933 RNA_def_string(ot->srna, "name", "", MAX_NAME, "Name", "Group socket name");
934 RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket");
937 /* ***************** Remove Group Socket operator ************* */
939 static int node_group_socket_remove_exec(bContext *C, wmOperator *op)
941 SpaceNode *snode = CTX_wm_space_node(C);
944 bNodeTree *ngroup = snode->edittree;
947 ED_preview_kill_jobs(C);
949 if (RNA_struct_property_is_set(op->ptr, "index"))
950 index = RNA_int_get(op->ptr, "index");
952 return OPERATOR_CANCELLED;
954 if (RNA_struct_property_is_set(op->ptr, "in_out"))
955 in_out = RNA_enum_get(op->ptr, "in_out");
957 return OPERATOR_CANCELLED;
959 sock = (bNodeSocket *)BLI_findlink(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index);
961 node_group_remove_socket(ngroup, sock, in_out);
962 ntreeUpdateTree(ngroup);
964 snode_notify(C, snode);
967 return OPERATOR_FINISHED;
970 void NODE_OT_group_socket_remove(wmOperatorType *ot)
973 ot->name = "Remove Group Socket";
974 ot->description = "Remove a node group socket";
975 ot->idname = "NODE_OT_group_socket_remove";
978 ot->exec = node_group_socket_remove_exec;
979 ot->poll = ED_operator_node_active;
982 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
984 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
985 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
988 /* ***************** Move Group Socket Up operator ************* */
990 static int node_group_socket_move_up_exec(bContext *C, wmOperator *op)
992 SpaceNode *snode = CTX_wm_space_node(C);
995 bNodeTree *ngroup = snode->edittree;
996 bNodeSocket *sock, *prev;
998 ED_preview_kill_jobs(C);
1000 if (RNA_struct_property_is_set(op->ptr, "index"))
1001 index = RNA_int_get(op->ptr, "index");
1003 return OPERATOR_CANCELLED;
1005 if (RNA_struct_property_is_set(op->ptr, "in_out"))
1006 in_out = RNA_enum_get(op->ptr, "in_out");
1008 return OPERATOR_CANCELLED;
1011 if (in_out == SOCK_IN) {
1012 sock = (bNodeSocket *)BLI_findlink(&ngroup->inputs, index);
1014 /* can't move up the first socket */
1016 return OPERATOR_CANCELLED;
1017 BLI_remlink(&ngroup->inputs, sock);
1018 BLI_insertlinkbefore(&ngroup->inputs, prev, sock);
1020 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1022 else if (in_out == SOCK_OUT) {
1023 sock = (bNodeSocket *)BLI_findlink(&ngroup->outputs, index);
1025 /* can't move up the first socket */
1027 return OPERATOR_CANCELLED;
1028 BLI_remlink(&ngroup->outputs, sock);
1029 BLI_insertlinkbefore(&ngroup->outputs, prev, sock);
1031 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1033 ntreeUpdateTree(ngroup);
1035 snode_notify(C, snode);
1037 return OPERATOR_FINISHED;
1040 void NODE_OT_group_socket_move_up(wmOperatorType *ot)
1043 ot->name = "Move Group Socket Up";
1044 ot->description = "Move up node group socket";
1045 ot->idname = "NODE_OT_group_socket_move_up";
1048 ot->exec = node_group_socket_move_up_exec;
1049 ot->poll = ED_operator_node_active;
1052 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1054 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1055 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1058 /* ***************** Move Group Socket Up operator ************* */
1060 static int node_group_socket_move_down_exec(bContext *C, wmOperator *op)
1062 SpaceNode *snode = CTX_wm_space_node(C);
1065 bNodeTree *ngroup = snode->edittree;
1066 bNodeSocket *sock, *next;
1068 ED_preview_kill_jobs(C);
1070 if (RNA_struct_property_is_set(op->ptr, "index"))
1071 index = RNA_int_get(op->ptr, "index");
1073 return OPERATOR_CANCELLED;
1075 if (RNA_struct_property_is_set(op->ptr, "in_out"))
1076 in_out = RNA_enum_get(op->ptr, "in_out");
1078 return OPERATOR_CANCELLED;
1081 if (in_out == SOCK_IN) {
1082 sock = (bNodeSocket *)BLI_findlink(&ngroup->inputs, index);
1084 /* can't move down the last socket */
1086 return OPERATOR_CANCELLED;
1087 BLI_remlink(&ngroup->inputs, sock);
1088 BLI_insertlinkafter(&ngroup->inputs, next, sock);
1090 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1092 else if (in_out == SOCK_OUT) {
1093 sock = (bNodeSocket *)BLI_findlink(&ngroup->outputs, index);
1095 /* can't move down the last socket */
1097 return OPERATOR_CANCELLED;
1098 BLI_remlink(&ngroup->outputs, sock);
1099 BLI_insertlinkafter(&ngroup->outputs, next, sock);
1101 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1103 ntreeUpdateTree(ngroup);
1105 snode_notify(C, snode);
1107 return OPERATOR_FINISHED;
1110 void NODE_OT_group_socket_move_down(wmOperatorType *ot)
1113 ot->name = "Move Group Socket Down";
1114 ot->description = "Move down node group socket";
1115 ot->idname = "NODE_OT_group_socket_move_down";
1118 ot->exec = node_group_socket_move_down_exec;
1119 ot->poll = ED_operator_node_active;
1122 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1124 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1125 RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1128 /* ******************** Ungroup operator ********************** */
1130 /* returns 1 if its OK */
1131 static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
1133 bNodeLink *link, *linkn;
1134 bNode *node, *nextn;
1135 bNodeTree *ngroup, *wgroup;
1136 ListBase anim_basepaths = {NULL, NULL};
1138 ngroup = (bNodeTree *)gnode->id;
1139 if (ngroup == NULL) return 0;
1141 /* clear new pointers, set in copytree */
1142 for (node = ntree->nodes.first; node; node = node->next)
1143 node->new_node = NULL;
1145 /* wgroup is a temporary copy of the NodeTree we're merging in
1146 * - all of wgroup's nodes are transferred across to their new home
1147 * - ngroup (i.e. the source NodeTree) is left unscathed
1149 wgroup = ntreeCopyTree(ngroup);
1151 /* add the nodes into the ntree */
1152 for (node = wgroup->nodes.first; node; node = nextn) {
1155 /* keep track of this node's RNA "base" path (the part of the path identifying the node)
1156 * if the old nodetree has animation data which potentially covers this node
1162 RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr);
1163 path = RNA_path_from_ID_to_struct(&ptr);
1166 BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
1170 BLI_remlink(&wgroup->nodes, node);
1171 BLI_addtail(&ntree->nodes, node);
1173 /* ensure unique node name in the nodee tree */
1174 nodeUniqueName(ntree, node);
1176 node->locx += gnode->locx;
1177 node->locy += gnode->locy;
1179 node->flag |= NODE_SELECT;
1182 /* restore external links to and from the gnode */
1183 for (link = ntree->links.first; link; link = link->next) {
1184 if (link->fromnode == gnode) {
1185 if (link->fromsock->groupsock) {
1186 bNodeSocket *gsock = link->fromsock->groupsock;
1188 if (gsock->link->fromnode) {
1189 /* NB: using the new internal copies here! the groupsock pointer still maps to the old tree */
1190 link->fromnode = (gsock->link->fromnode ? gsock->link->fromnode->new_node : NULL);
1191 link->fromsock = gsock->link->fromsock->new_sock;
1194 /* group output directly maps to group input */
1195 bNodeSocket *insock = node_group_find_input(gnode, gsock->link->fromsock);
1197 link->fromnode = insock->link->fromnode;
1198 link->fromsock = insock->link->fromsock;
1203 /* copy the default input value from the group socket default to the external socket */
1204 node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, gsock->type, gsock->default_value);
1209 /* remove internal output links, these are not used anymore */
1210 for (link = wgroup->links.first; link; link = linkn) {
1213 nodeRemLink(wgroup, link);
1215 /* restore links from internal nodes */
1216 for (link = wgroup->links.first; link; link = linkn) {
1218 /* indicates link to group input */
1219 if (!link->fromnode) {
1220 /* NB: can't use find_group_node_input here,
1221 * because gnode sockets still point to the old tree!
1223 bNodeSocket *insock;
1224 for (insock = gnode->inputs.first; insock; insock = insock->next)
1225 if (insock->groupsock->new_sock == link->fromsock)
1228 link->fromnode = insock->link->fromnode;
1229 link->fromsock = insock->link->fromsock;
1232 /* copy the default input value from the group node socket default to the internal socket */
1233 node_socket_convert_default_value(link->tosock->type, link->tosock->default_value, insock->type, insock->default_value);
1234 nodeRemLink(wgroup, link);
1239 /* add internal links to the ntree */
1240 for (link = wgroup->links.first; link; link = linkn) {
1242 BLI_remlink(&wgroup->links, link);
1243 BLI_addtail(&ntree->links, link);
1246 /* and copy across the animation,
1247 * note that the animation data's action can be NULL here */
1249 LinkData *ld, *ldn = NULL;
1252 /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
1253 waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
1255 /* now perform the moving */
1256 BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths);
1258 /* paths + their wrappers need to be freed */
1259 for (ld = anim_basepaths.first; ld; ld = ldn) {
1262 MEM_freeN(ld->data);
1263 BLI_freelinkN(&anim_basepaths, ld);
1266 /* free temp action too */
1268 BKE_libblock_free(&G.main->action, waction);
1272 /* delete the group instance. this also removes old input links! */
1273 nodeFreeNode(ntree, gnode);
1275 /* free the group tree (takes care of user count) */
1276 BKE_libblock_free(&G.main->nodetree, wgroup);
1278 ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
1283 static int node_group_ungroup_exec(bContext *C, wmOperator *op)
1285 SpaceNode *snode = CTX_wm_space_node(C);
1288 ED_preview_kill_jobs(C);
1290 /* are we inside of a group? */
1291 gnode = node_tree_get_editgroup(snode->nodetree);
1293 snode_make_group_editable(snode, NULL);
1295 gnode = nodeGetActive(snode->edittree);
1297 return OPERATOR_CANCELLED;
1299 if (gnode->type != NODE_GROUP) {
1300 BKE_report(op->reports, RPT_WARNING, "Not a group");
1301 return OPERATOR_CANCELLED;
1303 else if (node_group_ungroup(snode->nodetree, gnode)) {
1304 ntreeUpdateTree(snode->nodetree);
1307 BKE_report(op->reports, RPT_WARNING, "Can't ungroup");
1308 return OPERATOR_CANCELLED;
1311 snode_notify(C, snode);
1312 snode_dag_update(C, snode);
1314 return OPERATOR_FINISHED;
1317 void NODE_OT_group_ungroup(wmOperatorType *ot)
1320 ot->name = "Ungroup";
1321 ot->description = "Ungroup selected nodes";
1322 ot->idname = "NODE_OT_group_ungroup";
1325 ot->exec = node_group_ungroup_exec;
1326 ot->poll = ED_operator_node_active;
1329 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1332 /* ******************** Separate operator ********************** */
1334 /* returns 1 if its OK */
1335 static int node_group_separate_selected(bNodeTree *ntree, bNode *gnode, int make_copy)
1337 bNodeLink *link, *link_next;
1338 bNode *node, *node_next, *newnode;
1340 ListBase anim_basepaths = {NULL, NULL};
1342 ngroup = (bNodeTree *)gnode->id;
1343 if (ngroup == NULL) return 0;
1345 /* deselect all nodes in the target tree */
1346 for (node = ntree->nodes.first; node; node = node->next)
1347 node_deselect(node);
1349 /* clear new pointers, set in nodeCopyNode */
1350 for (node = ngroup->nodes.first; node; node = node->next)
1351 node->new_node = NULL;
1353 /* add selected nodes into the ntree */
1354 for (node = ngroup->nodes.first; node; node = node_next) {
1355 node_next = node->next;
1356 if (!(node->flag & NODE_SELECT))
1361 newnode = nodeCopyNode(ngroup, node);
1364 /* use the existing node */
1368 /* keep track of this node's RNA "base" path (the part of the path identifying the node)
1369 * if the old nodetree has animation data which potentially covers this node
1375 RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &ptr);
1376 path = RNA_path_from_ID_to_struct(&ptr);
1379 BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
1382 /* ensure valid parent pointers, detach if parent stays inside the group */
1383 if (newnode->parent && !(newnode->parent->flag & NODE_SELECT))
1384 nodeDetachNode(newnode);
1387 BLI_remlink(&ngroup->nodes, newnode);
1388 BLI_addtail(&ntree->nodes, newnode);
1390 /* ensure unique node name in the node tree */
1391 nodeUniqueName(ntree, newnode);
1393 newnode->locx += gnode->locx;
1394 newnode->locy += gnode->locy;
1397 /* add internal links to the ntree */
1398 for (link = ngroup->links.first; link; link = link_next) {
1399 int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
1400 int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
1401 link_next = link->next;
1404 /* make a copy of internal links */
1405 if (fromselect && toselect)
1406 nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, link->tonode->new_node, link->tosock->new_sock);
1409 /* move valid links over, delete broken links */
1410 if (fromselect && toselect) {
1411 BLI_remlink(&ngroup->links, link);
1412 BLI_addtail(&ntree->links, link);
1414 else if (fromselect || toselect) {
1415 nodeRemLink(ngroup, link);
1420 /* and copy across the animation,
1421 * note that the animation data's action can be NULL here */
1423 LinkData *ld, *ldn = NULL;
1425 /* now perform the moving */
1426 BKE_animdata_separate_by_basepath(&ngroup->id, &ntree->id, &anim_basepaths);
1428 /* paths + their wrappers need to be freed */
1429 for (ld = anim_basepaths.first; ld; ld = ldn) {
1432 MEM_freeN(ld->data);
1433 BLI_freelinkN(&anim_basepaths, ld);
1437 ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
1439 ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
1444 typedef enum eNodeGroupSeparateType {
1447 } eNodeGroupSeparateType;
1449 /* Operator Property */
1450 EnumPropertyItem node_group_separate_types[] = {
1451 {NODE_GS_COPY, "COPY", 0, "Copy", "Copy to parent node tree, keep group intact"},
1452 {NODE_GS_MOVE, "MOVE", 0, "Move", "Move to parent node tree, remove from group"},
1453 {0, NULL, 0, NULL, NULL}
1456 static int node_group_separate_exec(bContext *C, wmOperator *op)
1458 SpaceNode *snode = CTX_wm_space_node(C);
1460 int type = RNA_enum_get(op->ptr, "type");
1462 ED_preview_kill_jobs(C);
1464 /* are we inside of a group? */
1465 gnode = node_tree_get_editgroup(snode->nodetree);
1467 BKE_report(op->reports, RPT_WARNING, "Not inside node group");
1468 return OPERATOR_CANCELLED;
1473 if (!node_group_separate_selected(snode->nodetree, gnode, 1)) {
1474 BKE_report(op->reports, RPT_WARNING, "Can't separate nodes");
1475 return OPERATOR_CANCELLED;
1479 if (!node_group_separate_selected(snode->nodetree, gnode, 0)) {
1480 BKE_report(op->reports, RPT_WARNING, "Can't separate nodes");
1481 return OPERATOR_CANCELLED;
1486 /* switch to parent tree */
1487 snode_make_group_editable(snode, NULL);
1489 ntreeUpdateTree(snode->nodetree);
1491 snode_notify(C, snode);
1492 snode_dag_update(C, snode);
1494 return OPERATOR_FINISHED;
1497 static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
1499 uiPopupMenu *pup = uiPupMenuBegin(C, "Separate", ICON_NONE);
1500 uiLayout *layout = uiPupMenuLayout(pup);
1502 uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
1503 uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_COPY);
1504 uiItemEnumO(layout, "NODE_OT_group_separate", NULL, 0, "type", NODE_GS_MOVE);
1506 uiPupMenuEnd(C, pup);
1508 return OPERATOR_CANCELLED;
1511 void NODE_OT_group_separate(wmOperatorType *ot)
1514 ot->name = "Separate";
1515 ot->description = "Separate selected nodes from the node group";
1516 ot->idname = "NODE_OT_group_separate";
1519 ot->invoke = node_group_separate_invoke;
1520 ot->exec = node_group_separate_exec;
1521 ot->poll = ED_operator_node_active;
1524 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1526 RNA_def_enum(ot->srna, "type", node_group_separate_types, NODE_GS_COPY, "Type", "");
1529 /* ************************** Node generic ************** */
1531 /* is rct in visible part of node? */
1532 static bNode *visible_node(SpaceNode *snode, rctf *rct)
1536 for (node = snode->edittree->nodes.last; node; node = node->prev) {
1537 if (BLI_rctf_isect(&node->totr, rct, NULL))
1543 /* **************************** */
1545 typedef struct NodeViewMove {
1547 int xmin, ymin, xmax, ymax;
1550 static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
1552 SpaceNode *snode = CTX_wm_space_node(C);
1553 ARegion *ar = CTX_wm_region(C);
1554 NodeViewMove *nvm = op->customdata;
1556 switch (event->type) {
1559 snode->xof -= (nvm->mvalo[0] - event->mval[0]);
1560 snode->yof -= (nvm->mvalo[1] - event->mval[1]);
1561 nvm->mvalo[0] = event->mval[0];
1562 nvm->mvalo[1] = event->mval[1];
1564 /* prevent dragging image outside of the window and losing it! */
1565 CLAMP(snode->xof, nvm->xmin, nvm->xmax);
1566 CLAMP(snode->yof, nvm->ymin, nvm->ymax);
1568 ED_region_tag_redraw(ar);
1577 op->customdata = NULL;
1579 return OPERATOR_FINISHED;
1582 return OPERATOR_RUNNING_MODAL;
1585 static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
1587 SpaceNode *snode = CTX_wm_space_node(C);
1588 ARegion *ar = CTX_wm_region(C);
1592 const float pad = 32.0f; /* better be bigger then scrollbars */
1596 ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1597 ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
1600 BKE_image_release_ibuf(ima, lock);
1601 return OPERATOR_CANCELLED;
1604 nvm = MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
1605 op->customdata = nvm;
1606 nvm->mvalo[0] = event->mval[0];
1607 nvm->mvalo[1] = event->mval[1];
1609 nvm->xmin = -(ar->winx / 2) - (ibuf->x * (0.5f * snode->zoom)) + pad;
1610 nvm->xmax = (ar->winx / 2) + (ibuf->x * (0.5f * snode->zoom)) - pad;
1611 nvm->ymin = -(ar->winy / 2) - (ibuf->y * (0.5f * snode->zoom)) + pad;
1612 nvm->ymax = (ar->winy / 2) + (ibuf->y * (0.5f * snode->zoom)) - pad;
1614 BKE_image_release_ibuf(ima, lock);
1616 /* add modal handler */
1617 WM_event_add_modal_handler(C, op);
1619 return OPERATOR_RUNNING_MODAL;
1622 static int snode_bg_viewmove_cancel(bContext *UNUSED(C), wmOperator *op)
1624 MEM_freeN(op->customdata);
1625 op->customdata = NULL;
1627 return OPERATOR_CANCELLED;
1630 void NODE_OT_backimage_move(wmOperatorType *ot)
1633 ot->name = "Background Image Move";
1634 ot->description = "Move Node backdrop";
1635 ot->idname = "NODE_OT_backimage_move";
1638 ot->invoke = snode_bg_viewmove_invoke;
1639 ot->modal = snode_bg_viewmove_modal;
1640 ot->poll = composite_node_active;
1641 ot->cancel = snode_bg_viewmove_cancel;
1644 ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
1647 static int backimage_zoom(bContext *C, wmOperator *op)
1649 SpaceNode *snode = CTX_wm_space_node(C);
1650 ARegion *ar = CTX_wm_region(C);
1651 float fac = RNA_float_get(op->ptr, "factor");
1654 ED_region_tag_redraw(ar);
1656 return OPERATOR_FINISHED;
1660 void NODE_OT_backimage_zoom(wmOperatorType *ot)
1664 ot->name = "Background Image Zoom";
1665 ot->idname = "NODE_OT_backimage_zoom";
1666 ot->description = "Zoom in/out the background image";
1669 ot->exec = backimage_zoom;
1670 ot->poll = composite_node_active;
1673 ot->flag = OPTYPE_BLOCKING;
1676 RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
1679 /******************** sample backdrop operator ********************/
1681 typedef struct ImageSampleInfo {
1688 unsigned char col[4];
1694 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1696 Scene *scene = CTX_data_scene(C);
1697 ImageSampleInfo *info = arg_info;
1700 ED_image_draw_info(ar, (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT), info->channels,
1701 info->x, info->y, info->col, info->colf,
1702 NULL, NULL /* zbuf - unused for nodes */
1707 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1709 SpaceNode *snode = CTX_wm_space_node(C);
1710 ARegion *ar = CTX_wm_region(C);
1711 ImageSampleInfo *info = op->customdata;
1715 float fx, fy, bufx, bufy;
1717 ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1718 ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
1725 if (info->color_manage)
1726 ibuf->profile = IB_PROFILE_LINEAR_RGB;
1728 ibuf->profile = IB_PROFILE_NONE;
1729 IMB_rect_from_float(ibuf);
1732 /* map the mouse coords to the backdrop image space */
1733 bufx = ibuf->x * snode->zoom;
1734 bufy = ibuf->y * snode->zoom;
1735 fx = (bufx > 0.0f ? ((float)event->mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
1736 fy = (bufy > 0.0f ? ((float)event->mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
1738 if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
1741 int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
1743 CLAMP(x, 0, ibuf->x - 1);
1744 CLAMP(y, 0, ibuf->y - 1);
1749 info->channels = ibuf->channels;
1752 cp = (char *)(ibuf->rect + y * ibuf->x + x);
1754 info->col[0] = cp[0];
1755 info->col[1] = cp[1];
1756 info->col[2] = cp[2];
1757 info->col[3] = cp[3];
1759 info->colf[0] = (float)cp[0] / 255.0f;
1760 info->colf[1] = (float)cp[1] / 255.0f;
1761 info->colf[2] = (float)cp[2] / 255.0f;
1762 info->colf[3] = (float)cp[3] / 255.0f;
1764 if (ibuf->rect_float) {
1765 fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
1767 info->colf[0] = fp[0];
1768 info->colf[1] = fp[1];
1769 info->colf[2] = fp[2];
1770 info->colf[3] = fp[3];
1773 ED_node_sample_set(info->colf);
1777 ED_node_sample_set(NULL);
1780 BKE_image_release_ibuf(ima, lock);
1782 ED_area_tag_redraw(CTX_wm_area(C));
1785 static void sample_exit(bContext *C, wmOperator *op)
1787 ImageSampleInfo *info = op->customdata;
1789 ED_node_sample_set(NULL);
1790 ED_region_draw_cb_exit(info->art, info->draw_handle);
1791 ED_area_tag_redraw(CTX_wm_area(C));
1795 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1797 SpaceNode *snode = CTX_wm_space_node(C);
1798 ARegion *ar = CTX_wm_region(C);
1799 ImageSampleInfo *info;
1801 if (snode->treetype != NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW))
1802 return OPERATOR_CANCELLED;
1804 info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1805 info->art = ar->type;
1806 info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
1807 op->customdata = info;
1809 sample_apply(C, op, event);
1811 WM_event_add_modal_handler(C, op);
1813 return OPERATOR_RUNNING_MODAL;
1816 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1818 switch (event->type) {
1820 case RIGHTMOUSE: // XXX hardcoded
1822 return OPERATOR_CANCELLED;
1824 sample_apply(C, op, event);
1828 return OPERATOR_RUNNING_MODAL;
1831 static int sample_cancel(bContext *C, wmOperator *op)
1834 return OPERATOR_CANCELLED;
1837 void NODE_OT_backimage_sample(wmOperatorType *ot)
1840 ot->name = "Backimage Sample";
1841 ot->idname = "NODE_OT_backimage_sample";
1842 ot->description = "Use mouse to sample background image";
1845 ot->invoke = sample_invoke;
1846 ot->modal = sample_modal;
1847 ot->cancel = sample_cancel;
1848 ot->poll = ED_operator_node_active;
1851 ot->flag = OPTYPE_BLOCKING;
1854 /* ********************** size widget operator ******************** */
1856 typedef struct NodeSizeWidget {
1857 float mxstart, mystart;
1858 float oldlocx, oldlocy;
1859 float oldoffsetx, oldoffsety;
1860 float oldwidth, oldheight;
1865 static void node_resize_init(bContext *C, wmOperator *op, wmEvent *UNUSED(event), bNode *node, int dir)
1867 SpaceNode *snode = CTX_wm_space_node(C);
1869 NodeSizeWidget *nsw = MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
1871 op->customdata = nsw;
1872 nsw->mxstart = snode->mx;
1873 nsw->mystart = snode->my;
1876 nsw->oldlocx = node->locx;
1877 nsw->oldlocy = node->locy;
1878 nsw->oldoffsetx = node->offsetx;
1879 nsw->oldoffsety = node->offsety;
1880 nsw->oldwidth = node->width;
1881 nsw->oldheight = node->height;
1882 nsw->oldminiwidth = node->miniwidth;
1883 nsw->directions = dir;
1885 WM_cursor_modal(CTX_wm_window(C), node_get_resize_cursor(dir));
1886 /* add modal handler */
1887 WM_event_add_modal_handler(C, op);
1890 static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel))
1892 WM_cursor_restore(CTX_wm_window(C));
1894 MEM_freeN(op->customdata);
1895 op->customdata = NULL;
1898 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
1900 SpaceNode *snode = CTX_wm_space_node(C);
1901 ARegion *ar = CTX_wm_region(C);
1902 bNode *node = editnode_get_active(snode->edittree);
1903 NodeSizeWidget *nsw = op->customdata;
1904 float mx, my, dx, dy;
1906 switch (event->type) {
1909 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my);
1910 dx = mx - nsw->mxstart;
1911 dy = my - nsw->mystart;
1914 if (node->flag & NODE_HIDDEN) {
1915 float widthmin = 0.0f;
1916 float widthmax = 100.0f;
1917 if (nsw->directions & NODE_RESIZE_RIGHT) {
1918 node->miniwidth = nsw->oldminiwidth + dx;
1919 CLAMP(node->miniwidth, widthmin, widthmax);
1921 if (nsw->directions & NODE_RESIZE_LEFT) {
1922 float locmax = nsw->oldlocx + nsw->oldminiwidth;
1924 node->locx = nsw->oldlocx + dx;
1925 CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
1926 node->miniwidth = locmax - node->locx;
1930 float widthmin = UI_DPI_FAC * node->typeinfo->minwidth;
1931 float widthmax = UI_DPI_FAC * node->typeinfo->maxwidth;
1932 if (nsw->directions & NODE_RESIZE_RIGHT) {
1933 node->width = nsw->oldwidth + dx;
1934 CLAMP(node->width, widthmin, widthmax);
1936 if (nsw->directions & NODE_RESIZE_LEFT) {
1937 float locmax = nsw->oldlocx + nsw->oldwidth;
1939 node->locx = nsw->oldlocx + dx;
1940 CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
1941 node->width = locmax - node->locx;
1945 /* height works the other way round ... */
1947 float heightmin = UI_DPI_FAC * node->typeinfo->minheight;
1948 float heightmax = UI_DPI_FAC * node->typeinfo->maxheight;
1949 if (nsw->directions & NODE_RESIZE_TOP) {
1950 float locmin = nsw->oldlocy - nsw->oldheight;
1952 node->locy = nsw->oldlocy + dy;
1953 CLAMP(node->locy, locmin + heightmin, locmin + heightmax);
1954 node->height = node->locy - locmin;
1956 if (nsw->directions & NODE_RESIZE_BOTTOM) {
1957 node->height = nsw->oldheight - dy;
1958 CLAMP(node->height, heightmin, heightmax);
1962 /* XXX make callback? */
1963 if (node->type == NODE_FRAME) {
1964 /* keep the offset symmetric around center point */
1965 if (nsw->directions & NODE_RESIZE_LEFT) {
1966 node->locx = nsw->oldlocx + 0.5f * dx;
1967 node->offsetx = nsw->oldoffsetx + 0.5f * dx;
1969 if (nsw->directions & NODE_RESIZE_RIGHT) {
1970 node->locx = nsw->oldlocx + 0.5f * dx;
1971 node->offsetx = nsw->oldoffsetx - 0.5f * dx;
1973 if (nsw->directions & NODE_RESIZE_TOP) {
1974 node->locy = nsw->oldlocy + 0.5f * dy;
1975 node->offsety = nsw->oldoffsety + 0.5f * dy;
1977 if (nsw->directions & NODE_RESIZE_BOTTOM) {
1978 node->locy = nsw->oldlocy + 0.5f * dy;
1979 node->offsety = nsw->oldoffsety - 0.5f * dy;
1984 ED_region_tag_redraw(ar);
1992 node_resize_exit(C, op, 0);
1993 ED_node_post_apply_transform(C, snode->edittree);
1995 return OPERATOR_FINISHED;
1998 return OPERATOR_RUNNING_MODAL;
2001 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
2003 SpaceNode *snode = CTX_wm_space_node(C);
2004 ARegion *ar = CTX_wm_region(C);
2005 bNode *node = editnode_get_active(snode->edittree);
2009 /* convert mouse coordinates to v2d space */
2010 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2011 &snode->mx, &snode->my);
2012 dir = node->typeinfo->resize_area_func(node, snode->mx, snode->my);
2014 node_resize_init(C, op, event, node, dir);
2015 return OPERATOR_RUNNING_MODAL;
2018 return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
2021 static int node_resize_cancel(bContext *C, wmOperator *op)
2023 node_resize_exit(C, op, 1);
2025 return OPERATOR_CANCELLED;
2028 void NODE_OT_resize(wmOperatorType *ot)
2031 ot->name = "Resize Node";
2032 ot->idname = "NODE_OT_resize";
2033 ot->description = "Resize a node";
2036 ot->invoke = node_resize_invoke;
2037 ot->modal = node_resize_modal;
2038 ot->poll = ED_operator_node_active;
2039 ot->cancel = node_resize_cancel;
2042 ot->flag = OPTYPE_BLOCKING;
2046 /* ********************** hidden sockets ******************** */
2048 int node_has_hidden_sockets(bNode *node)
2052 for (sock = node->inputs.first; sock; sock = sock->next)
2053 if (sock->flag & SOCK_HIDDEN)
2055 for (sock = node->outputs.first; sock; sock = sock->next)
2056 if (sock->flag & SOCK_HIDDEN)
2061 void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
2066 for (sock = node->inputs.first; sock; sock = sock->next)
2067 sock->flag &= ~SOCK_HIDDEN;
2068 for (sock = node->outputs.first; sock; sock = sock->next)
2069 sock->flag &= ~SOCK_HIDDEN;
2072 /* hide unused sockets */
2073 for (sock = node->inputs.first; sock; sock = sock->next) {
2074 if (sock->link == NULL)
2075 sock->flag |= SOCK_HIDDEN;
2077 for (sock = node->outputs.first; sock; sock = sock->next) {
2078 if (nodeCountSocketLinks(snode->edittree, sock) == 0)
2079 sock->flag |= SOCK_HIDDEN;
2084 static int node_link_viewer(const bContext *C, bNode *tonode)
2086 SpaceNode *snode = CTX_wm_space_node(C);
2092 if (tonode == NULL || tonode->outputs.first == NULL)
2093 return OPERATOR_CANCELLED;
2094 if (ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
2095 return OPERATOR_CANCELLED;
2098 for (node = snode->edittree->nodes.first; node; node = node->next)
2099 if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
2100 if (node->flag & NODE_DO_OUTPUT)
2102 /* no viewer, we make one active */
2104 for (node = snode->edittree->nodes.first; node; node = node->next) {
2105 if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
2106 node->flag |= NODE_DO_OUTPUT;
2114 /* try to find an already connected socket to cycle to the next */
2117 for (link = snode->edittree->links.first; link; link = link->next)
2118 if (link->tonode == node && link->fromnode == tonode)
2119 if (link->tosock == node->inputs.first)
2122 /* unlink existing connection */
2123 sock = link->fromsock;
2124 nodeRemLink(snode->edittree, link);
2126 /* find a socket after the previously connected socket */
2127 for (sock = sock->next; sock; sock = sock->next)
2128 if (!nodeSocketIsHidden(sock))
2133 /* find a socket starting from the first socket */
2135 for (sock = tonode->outputs.first; sock; sock = sock->next)
2136 if (!nodeSocketIsHidden(sock))
2141 /* add a new viewer if none exists yet */
2143 Main *bmain = CTX_data_main(C);
2144 Scene *scene = CTX_data_scene(C);
2145 bNodeTemplate ntemp;
2147 ntemp.type = CMP_NODE_VIEWER;
2148 /* XXX location is a quick hack, just place it next to the linked socket */
2149 node = node_add_node(snode, bmain, scene, &ntemp, sock->locx + 100, sock->locy);
2151 return OPERATOR_CANCELLED;
2156 /* get link to viewer */
2157 for (link = snode->edittree->links.first; link; link = link->next)
2158 if (link->tonode == node && link->tosock == node->inputs.first)
2163 nodeAddLink(snode->edittree, tonode, sock, node, node->inputs.first);
2166 link->fromnode = tonode;
2167 link->fromsock = sock;
2168 /* make sure the dependency sorting is updated */
2169 snode->edittree->update |= NTREE_UPDATE_LINKS;
2171 ntreeUpdateTree(snode->edittree);
2172 snode_update(snode, node);
2175 return OPERATOR_FINISHED;
2179 static int node_active_link_viewer(bContext *C, wmOperator *UNUSED(op))
2181 SpaceNode *snode = CTX_wm_space_node(C);
2184 node = editnode_get_active(snode->edittree);
2187 return OPERATOR_CANCELLED;
2189 ED_preview_kill_jobs(C);
2191 if (node_link_viewer(C, node) == OPERATOR_CANCELLED)
2192 return OPERATOR_CANCELLED;
2194 snode_notify(C, snode);
2196 return OPERATOR_FINISHED;
2201 void NODE_OT_link_viewer(wmOperatorType *ot)
2204 ot->name = "Link to Viewer Node";
2205 ot->description = "Link to viewer node";
2206 ot->idname = "NODE_OT_link_viewer";
2209 ot->exec = node_active_link_viewer;
2210 ot->poll = composite_node_active;
2213 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2218 /* return 0, nothing done */
2219 static int UNUSED_FUNCTION(node_mouse_groupheader) (SpaceNode * snode)
2222 float mx = 0, my = 0;
2225 gnode = node_tree_get_editgroup(snode->nodetree);
2226 if (gnode == NULL) return 0;
2228 // XXX getmouseco_areawin(mval);
2229 // XXX areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
2231 /* click in header or outside? */
2232 if (BLI_in_rctf(&gnode->totr, mx, my) == 0) {
2233 rctf rect = gnode->totr;
2235 rect.ymax += NODE_DY;
2236 if (BLI_in_rctf(&rect, mx, my) == 0)
2237 snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
2239 // XXX transform_nodes(snode->nodetree, 'g', "Move group");
2246 /* checks snode->mouse position, and returns found node/socket */
2247 /* type is SOCK_IN and/or SOCK_OUT */
2248 int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
2257 /* check if we click in a socket */
2258 for (node = snode->edittree->nodes.first; node; node = node->next) {
2260 rect.xmin = snode->mx - (NODE_SOCKSIZE + 4);
2261 rect.ymin = snode->my - (NODE_SOCKSIZE + 4);
2262 rect.xmax = snode->mx + (NODE_SOCKSIZE + 4);
2263 rect.ymax = snode->my + (NODE_SOCKSIZE + 4);
2265 if (!(node->flag & NODE_HIDDEN)) {
2266 /* extra padding inside and out - allow dragging on the text areas too */
2267 if (in_out == SOCK_IN) {
2268 rect.xmax += NODE_SOCKSIZE;
2269 rect.xmin -= NODE_SOCKSIZE * 4;
2271 else if (in_out == SOCK_OUT) {
2272 rect.xmax += NODE_SOCKSIZE * 4;
2273 rect.xmin -= NODE_SOCKSIZE;
2277 if (in_out & SOCK_IN) {
2278 for (sock = node->inputs.first; sock; sock = sock->next) {
2279 if (!nodeSocketIsHidden(sock)) {
2280 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
2281 if (node == visible_node(snode, &rect)) {
2290 if (in_out & SOCK_OUT) {
2291 for (sock = node->outputs.first; sock; sock = sock->next) {
2292 if (!nodeSocketIsHidden(sock)) {
2293 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
2294 if (node == visible_node(snode, &rect)) {
2305 /* check group sockets
2306 * NB: using ngroup->outputs as input sockets and vice versa here!
2308 if (in_out & SOCK_IN) {
2309 for (sock = snode->edittree->outputs.first; sock; sock = sock->next) {
2310 if (!nodeSocketIsHidden(sock)) {
2311 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
2312 *nodep = NULL; /* NULL node pointer indicates group socket */
2319 if (in_out & SOCK_OUT) {
2320 for (sock = snode->edittree->inputs.first; sock; sock = sock->next) {
2321 if (!nodeSocketIsHidden(sock)) {
2322 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
2323 *nodep = NULL; /* NULL node pointer indicates group socket */
2334 static int outside_group_rect(SpaceNode *snode)
2336 bNode *gnode = node_tree_get_editgroup(snode->nodetree);
2338 return (snode->mx < gnode->totr.xmin ||
2339 snode->mx >= gnode->totr.xmax ||
2340 snode->my < gnode->totr.ymin ||
2341 snode->my >= gnode->totr.ymax);
2346 /* ****************** Add *********************** */
2349 typedef struct bNodeListItem {
2350 struct bNodeListItem *next, *prev;
2354 static int sort_nodes_locx(void *a, void *b)
2356 bNodeListItem *nli1 = (bNodeListItem *)a;
2357 bNodeListItem *nli2 = (bNodeListItem *)b;
2358 bNode *node1 = nli1->node;
2359 bNode *node2 = nli2->node;
2361 if (node1->locx > node2->locx)
2367 static int socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, int allow_used)
2369 if (nodeSocketIsHidden(sock))
2372 if (!allow_used && (sock->flag & SOCK_IN_USE))
2378 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
2382 /* first look for selected output */
2383 for (sock = node->outputs.first; sock; sock = sock->next) {
2384 if (!socket_is_available(ntree, sock, allow_multiple))
2387 if (sock->flag & SELECT)
2391 /* try to find a socket with a matching name */
2392 for (sock = node->outputs.first; sock; sock = sock->next) {
2393 if (!socket_is_available(ntree, sock, allow_multiple))
2396 /* check for same types */
2397 if (sock->type == sock_target->type) {
2398 if (strcmp(sock->name, sock_target->name) == 0)
2403 /* otherwise settle for the first available socket of the right type */
2404 for (sock = node->outputs.first; sock; sock = sock->next) {
2406 if (!socket_is_available(ntree, sock, allow_multiple))
2409 /* check for same types */
2410 if (sock->type == sock_target->type) {
2418 /* this is a bit complicated, but designed to prioritize finding
2419 * sockets of higher types, such as image, first */
2420 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
2423 int socktype, maxtype = 0;
2426 for (sock = node->inputs.first; sock; sock = sock->next) {
2427 maxtype = MAX2(sock->type, maxtype);
2430 /* find sockets of higher 'types' first (i.e. image) */
2431 for (socktype = maxtype; socktype >= 0; socktype--) {
2432 for (sock = node->inputs.first; sock; sock = sock->next) {
2434 if (!socket_is_available(ntree, sock, replace)) {
2439 if (sock->type == socktype) {
2440 /* increment to make sure we don't keep finding
2441 * the same socket on every attempt running this function */
2452 static int snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
2454 bNodeTree *ntree = snode->edittree;
2457 /* then we can connect */
2459 nodeRemSocketLinks(ntree, sock_to);
2461 link = nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
2462 /* validate the new link */
2463 ntreeUpdateTree(ntree);
2464 if (!(link->flag & NODE_LINK_VALID)) {
2465 nodeRemLink(ntree, link);
2469 snode_update(snode, node_to);
2473 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
2475 bNodeTree *ntree = snode->edittree;
2476 ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
2479 int i, numlinks = 0;
2481 for (node = ntree->nodes.first; node; node = node->next) {
2482 if (node->flag & NODE_SELECT) {
2483 nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
2485 BLI_addtail(nodelist, nli);
2489 /* sort nodes left to right */
2490 BLI_sortlist(nodelist, sort_nodes_locx);
2492 for (nli = nodelist->first; nli; nli = nli->next) {
2493 bNode *node_fr, *node_to;
2494 bNodeSocket *sock_fr, *sock_to;
2495 int has_selected_inputs = 0;
2497 if (nli->next == NULL) break;
2499 node_fr = nli->node;
2500 node_to = nli->next->node;
2502 /* if there are selected sockets, connect those */
2503 for (sock_to = node_to->inputs.first; sock_to; sock_to = sock_to->next) {
2504 if (sock_to->flag & SELECT) {
2505 has_selected_inputs = 1;
2507 if (!socket_is_available(ntree, sock_to, replace))
2510 /* check for an appropriate output socket to connect from */
2511 sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
2515 if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace))
2520 if (!has_selected_inputs) {
2521 /* no selected inputs, connect by finding suitable match */
2522 int num_inputs = BLI_countlist(&node_to->inputs);
2524 for (i = 0; i < num_inputs; i++) {
2526 /* find the best guess input socket */
2527 sock_to = best_socket_input(ntree, node_to, i, replace);
2531 /* check for an appropriate output socket to connect from */
2532 sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
2536 if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) {
2545 ntreeUpdateTree(ntree);
2548 BLI_freelistN(nodelist);
2549 MEM_freeN(nodelist);
2552 /* can be called from menus too, but they should do own undopush and redraws */
2553 bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate *ntemp, float locx, float locy)
2555 bNode *node = NULL, *gnode;
2557 node_deselect_all(snode);
2559 node = nodeAddNode(snode->edittree, ntemp);
2565 gnode = node_tree_get_editgroup(snode->nodetree);
2566 // arbitrary y offset of 60 so its visible
2568 nodeFromView(gnode, locx, locy + 60.0f, &node->locx, &node->locy);
2572 node->locy = locy + 60.0f;
2575 ntreeUpdateTree(snode->edittree);
2576 ED_node_set_active(bmain, snode->edittree, node);
2578 if (snode->nodetree->type == NTREE_COMPOSIT) {
2579 if (ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) {
2580 node->id = &scene->id;
2582 else if (ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) {
2583 node->id = (ID *)scene->clip;
2586 ntreeCompositForceHidden(snode->edittree, scene);
2590 id_us_plus(node->id);
2593 if (snode->flag & SNODE_USE_HIDDEN_PREVIEW)
2594 node->flag &= ~NODE_PREVIEW;
2596 snode_update(snode, node);
2599 if (snode->nodetree->type == NTREE_TEXTURE) {
2600 ntreeTexCheckCyclics(snode->edittree);
2606 /* ****************** Duplicate *********************** */
2608 static void node_duplicate_reparent_recursive(bNode *node)
2612 node->flag |= NODE_TEST;
2614 /* find first selected parent */
2615 for (parent = node->parent; parent; parent = parent->parent) {
2616 if (parent->flag & SELECT) {
2617 if (!(parent->flag & NODE_TEST))
2618 node_duplicate_reparent_recursive(parent);
2622 /* reparent node copy to parent copy */
2624 nodeDetachNode(node->new_node);
2625 nodeAttachNode(node->new_node, parent->new_node);
2629 static int node_duplicate_exec(bContext *C, wmOperator *op)
2631 SpaceNode *snode = CTX_wm_space_node(C);
2632 bNodeTree *ntree = snode->edittree;
2633 bNode *node, *newnode, *lastnode;
2634 bNodeLink *link, *newlink, *lastlink;
2635 int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
2637 ED_preview_kill_jobs(C);
2639 lastnode = ntree->nodes.last;
2640 for (node = ntree->nodes.first; node; node = node->next) {
2641 if (node->flag & SELECT) {
2642 newnode = nodeCopyNode(ntree, node);
2645 /* simple id user adjustment, node internal functions don't touch this
2646 * but operators and readfile.c do. */
2647 id_us_plus(newnode->id);
2648 /* to ensure redraws or rerenders happen */
2649 ED_node_changed_update(snode->id, newnode);
2653 /* make sure we don't copy new nodes again! */
2654 if (node == lastnode)
2658 /* copy links between selected nodes
2659 * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
2661 lastlink = ntree->links.last;
2662 for (link = ntree->links.first; link; link = link->next) {
2663 /* This creates new links between copied nodes.
2664 * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)!
2666 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
2667 (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT))))
2669 newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
2670 newlink->flag = link->flag;
2671 newlink->tonode = link->tonode->new_node;
2672 newlink->tosock = link->tosock->new_sock;
2673 if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
2674 newlink->fromnode = link->fromnode->new_node;
2675 newlink->fromsock = link->fromsock->new_sock;
2678 /* input node not copied, this keeps the original input linked */
2679 newlink->fromnode = link->fromnode;
2680 newlink->fromsock = link->fromsock;
2683 BLI_addtail(&ntree->links, newlink);
2686 /* make sure we don't copy new links again! */
2687 if (link == lastlink)
2691 /* clear flags for recursive depth-first iteration */
2692 for (node = ntree->nodes.first; node; node = node->next)
2693 node->flag &= ~NODE_TEST;
2694 /* reparent copied nodes */
2695 for (node = ntree->nodes.first; node; node = node->next) {
2696 if ((node->flag & SELECT) && !(node->flag & NODE_TEST))
2697 node_duplicate_reparent_recursive(node);
2699 /* only has to check old nodes */
2700 if (node == lastnode)
2704 /* deselect old nodes, select the copies instead */
2705 for (node = ntree->nodes.first; node; node = node->next) {
2706 if (node->flag & SELECT) {
2707 /* has been set during copy above */
2708 newnode = node->new_node;
2710 node_deselect(node);
2711 node->flag &= ~NODE_ACTIVE;
2712 node_select(newnode);
2715 /* make sure we don't copy new nodes again! */
2716 if (node == lastnode)
2720 ntreeUpdateTree(snode->edittree);
2722 snode_notify(C, snode);
2723 snode_dag_update(C, snode);
2725 return OPERATOR_FINISHED;
2728 void NODE_OT_duplicate(wmOperatorType *ot)
2731 ot->name = "Duplicate Nodes";
2732 ot->description = "Duplicate selected nodes";
2733 ot->idname = "NODE_OT_duplicate";
2736 ot->exec = node_duplicate_exec;
2737 ot->poll = ED_operator_node_active;
2740 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2742 RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
2745 /* *************************** add link op ******************** */
2747 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
2752 if (tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
2754 for (tlink = snode->edittree->links.first; tlink; tlink = tlink->next) {
2755 if (link != tlink && tlink->tosock == link->tosock)
2759 /* try to move the existing link to the next available socket */
2760 if (tlink->tonode) {
2761 /* is there a free input socket with the target type? */
2762 for (sock = tlink->tonode->inputs.first; sock; sock = sock->next) {
2763 if (sock->type == tlink->tosock->type)
2764 if (nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
2768 tlink->tosock = sock;
2769 sock->flag &= ~SOCK_HIDDEN;
2772 nodeRemLink(snode->edittree, tlink);
2776 nodeRemLink(snode->edittree, tlink);
2778 snode->edittree->update |= NTREE_UPDATE_LINKS;
2783 /* loop that adds a nodelink, called by function below */
2784 /* in_out = starting socket */
2785 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
2787 SpaceNode *snode = CTX_wm_space_node(C);
2788 ARegion *ar = CTX_wm_region(C);
2789 bNodeLinkDrag *nldrag = op->customdata;
2790 bNodeTree *ntree = snode->edittree;
2792 bNodeSocket *tsock = NULL;
2797 in_out = nldrag->in_out;
2799 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2800 &snode->mx, &snode->my);
2802 switch (event->type) {
2805 if (in_out == SOCK_OUT) {
2806 if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
2807 for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
2808 link = linkdata->data;
2810 /* skip if this is already the target socket */
2811 if (link->tosock == tsock)
2813 /* skip if socket is on the same node as the fromsock */
2814 if (tnode && link->fromnode == tnode)
2817 /* attach links to the socket */
2818 link->tonode = tnode;
2819 link->tosock = tsock;
2820 /* add it to the node tree temporarily */
2821 if (BLI_findindex(&ntree->links, link) < 0)
2822 BLI_addtail(&ntree->links, link);
2824 ntree->update |= NTREE_UPDATE_LINKS;
2826 ntreeUpdateTree(ntree);
2829 int do_update = FALSE;
2830 for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
2831 link = linkdata->data;
2833 if (link->tonode || link->tosock) {
2834 BLI_remlink(&ntree->links, link);
2835 link->prev = link->next = NULL;
2836 link->tonode = NULL;
2837 link->tosock = NULL;
2839 ntree->update |= NTREE_UPDATE_LINKS;
2844 ntreeUpdateTree(ntree);
2849 if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
2850 for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
2851 link = linkdata->data;
2853 /* skip if this is already the target socket */
2854 if (link->fromsock == tsock)
2856 /* skip if socket is on the same node as the fromsock */
2857 if (tnode && link->tonode == tnode)
2860 /* attach links to the socket */
2861 link->fromnode = tnode;
2862 link->fromsock = tsock;
2863 /* add it to the node tree temporarily */
2864 if (BLI_findindex(&ntree->links, link) < 0)
2865 BLI_addtail(&ntree->links, link);
2867 ntree->update |= NTREE_UPDATE_LINKS;
2869 ntreeUpdateTree(ntree);
2872 int do_update = FALSE;
2873 for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
2874 link = linkdata->data;
2876 if (link->fromnode || link->fromsock) {
2877 BLI_remlink(&ntree->links, link);
2878 link->prev = link->next = NULL;
2879 link->fromnode = NULL;
2880 link->fromsock = NULL;
2882 ntree->update |= NTREE_UPDATE_LINKS;
2887 ntreeUpdateTree(ntree);
2892 ED_region_tag_redraw(ar);
2898 for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
2899 link = linkdata->data;
2901 if (link->tosock && link->fromsock) {
2902 /* send changed events for original tonode and new */
2904 snode_update(snode, link->tonode);
2906 /* we might need to remove a link */
2907 if (in_out == SOCK_OUT)
2908 node_remove_extra_links(snode, link->tosock, link);
2910 /* when linking to group outputs, update the socket type */
2911 /* XXX this should all be part of a generic update system */
2912 if (!link->tonode) {
2913 if (link->tosock->type != link->fromsock->type)
2914 nodeSocketSetType(link->tosock, link->fromsock->type);
2917 else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) {
2918 /* automatically add new group socket */
2919 if (link->tonode && link->tosock) {
2920 link->fromsock = node_group_expose_socket(ntree, link->tosock, SOCK_IN);
2921 link->fromnode = NULL;
2922 if (BLI_findindex(&ntree->links, link) < 0)
2923 BLI_addtail(&ntree->links, link);
2925 ntree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS;
2927 else if (link->fromnode && link->fromsock) {
2928 link->tosock = node_group_expose_socket(ntree, link->fromsock, SOCK_OUT);
2929 link->tonode = NULL;
2930 if (BLI_findindex(&ntree->links, link) < 0)
2931 BLI_addtail(&ntree->links, link);
2933 ntree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS;
2937 nodeRemLink(ntree, link);
2940 ntreeUpdateTree(ntree);
2941 snode_notify(C, snode);
2942 snode_dag_update(C, snode);
2944 BLI_remlink(&snode->linkdrag, nldrag);
2945 /* links->data pointers are either held by the tree or freed already */
2946 BLI_freelistN(&nldrag->links);
2949 return OPERATOR_FINISHED;
2953 return OPERATOR_RUNNING_MODAL;
2956 /* return 1 when socket clicked */
2957 static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach)
2961 bNodeLink *link, *link_next, *oplink;
2962 bNodeLinkDrag *nldrag = NULL;
2966 /* output indicated? */
2967 if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
2968 nldrag = MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
2970 num_links = nodeCountSocketLinks(snode->edittree, sock);
2971 if (num_links > 0 && (num_links >= sock->limit || detach)) {
2972 /* dragged links are fixed on input side */
2973 nldrag->in_out = SOCK_IN;
2974 /* detach current links and store them in the operator data */
2975 for (link = snode->edittree->links.first; link; link = link_next) {
2976 link_next = link->next;
2977 if (link->fromsock == sock) {