3e6564b696ff47503160a3da44b6fe0e1a68e67b
[blender.git] / source / blender / editors / space_node / node_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Nathan Letwory
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_node/node_edit.c
29  *  \ingroup spnode
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_lamp_types.h"
35 #include "DNA_material_types.h"
36 #include "DNA_node_types.h"
37 #include "DNA_text_types.h"
38 #include "DNA_world_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_blenlib.h"
42
43 #include "BKE_context.h"
44 #include "BKE_depsgraph.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_library.h"
48 #include "BKE_main.h"
49 #include "BKE_node.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52
53 #include "RE_engine.h"
54 #include "RE_pipeline.h"
55
56
57 #include "ED_node.h"  /* own include */
58 #include "ED_screen.h"
59 #include "ED_render.h"
60
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63 #include "RNA_enum_types.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "UI_view2d.h"
69
70 #include "GPU_material.h"
71
72 #include "IMB_imbuf_types.h"
73
74 #include "node_intern.h"  /* own include */
75 #include "NOD_composite.h"
76 #include "NOD_shader.h"
77 #include "NOD_texture.h"
78
79
80 #define USE_ESC_COMPO
81
82 /* ***************** composite job manager ********************** */
83
84 enum {
85         COM_RECALC_COMPOSITE = 1,
86         COM_RECALC_VIEWER    = 2
87 };
88
89 typedef struct CompoJob {
90         Main *bmain;
91         Scene *scene;
92         bNodeTree *ntree;
93         bNodeTree *localtree;
94         const short *stop;
95         short *do_update;
96         float *progress;
97         int recalc_flags;
98 } CompoJob;
99
100 static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
101 {
102         bNode *node;
103
104         for (node = nodetree->nodes.first; node; node = node->next) {
105                 if (node->type == CMP_NODE_COMPOSITE) {
106                         if (recalc_flags & COM_RECALC_COMPOSITE)
107                                 node->flag |= NODE_DO_OUTPUT_RECALC;
108                 }
109                 else if (node->type == CMP_NODE_VIEWER || node->type == CMP_NODE_SPLITVIEWER) {
110                         if (recalc_flags & COM_RECALC_VIEWER)
111                                 node->flag |= NODE_DO_OUTPUT_RECALC;
112                 }
113                 else if (node->type == NODE_GROUP) {
114                         if (node->id)
115                                 compo_tag_output_nodes((bNodeTree *)node->id, recalc_flags);
116                 }
117         }
118 }
119
120 static int compo_get_recalc_flags(const bContext *C)
121 {
122         wmWindowManager *wm = CTX_wm_manager(C);
123         wmWindow *win;
124         int recalc_flags = 0;
125
126         for (win = wm->windows.first; win; win = win->next) {
127                 bScreen *sc = win->screen;
128                 ScrArea *sa;
129
130                 for (sa = sc->areabase.first; sa; sa = sa->next) {
131                         if (sa->spacetype == SPACE_IMAGE) {
132                                 SpaceImage *sima = sa->spacedata.first;
133                                 if (sima->image) {
134                                         if (sima->image->type == IMA_TYPE_R_RESULT)
135                                                 recalc_flags |= COM_RECALC_COMPOSITE;
136                                         else if (sima->image->type == IMA_TYPE_COMPOSITE)
137                                                 recalc_flags |= COM_RECALC_VIEWER;
138                                 }
139                         }
140                         else if (sa->spacetype == SPACE_NODE) {
141                                 SpaceNode *snode = sa->spacedata.first;
142                                 if (snode->flag & SNODE_BACKDRAW)
143                                         recalc_flags |= COM_RECALC_VIEWER;
144                         }
145                 }
146         }
147
148         return recalc_flags;
149 }
150
151 /* called by compo, only to check job 'stop' value */
152 static int compo_breakjob(void *cjv)
153 {
154         CompoJob *cj = cjv;
155
156         /* without G.is_break 'ESC' wont quit - which annoys users */
157         return (*(cj->stop)
158 #ifdef USE_ESC_COMPO
159                 ||
160                 G.is_break
161 #endif
162                 );
163 }
164
165 /* called by compo, wmJob sends notifier */
166 static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
167 {
168         CompoJob *cj = cjv;
169
170         *(cj->do_update) = true;
171 }
172
173 /* called by compo, wmJob sends notifier */
174 static void compo_redrawjob(void *cjv)
175 {
176         CompoJob *cj = cjv;
177
178         *(cj->do_update) = true;
179 }
180
181 static void compo_freejob(void *cjv)
182 {
183         CompoJob *cj = cjv;
184
185         if (cj->localtree) {
186                 ntreeLocalMerge(cj->bmain, cj->localtree, cj->ntree);
187         }
188         MEM_freeN(cj);
189 }
190
191 /* only now we copy the nodetree, so adding many jobs while
192  * sliding buttons doesn't frustrate */
193 static void compo_initjob(void *cjv)
194 {
195         CompoJob *cj = cjv;
196
197         cj->localtree = ntreeLocalize(cj->ntree);
198
199         if (cj->recalc_flags)
200                 compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
201 }
202
203 /* called before redraw notifiers, it moves finished previews over */
204 static void compo_updatejob(void *UNUSED(cjv))
205 {
206         WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
207 }
208
209 static void compo_progressjob(void *cjv, float progress)
210 {
211         CompoJob *cj = cjv;
212
213         *(cj->progress) = progress;
214 }
215
216 /* only this runs inside thread */
217 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
218 {
219         CompoJob *cj = cjv;
220         bNodeTree *ntree = cj->localtree;
221         Scene *scene = cj->scene;
222         SceneRenderView *srv;
223
224         if (scene->use_nodes == false)
225                 return;
226
227         cj->stop = stop;
228         cj->do_update = do_update;
229         cj->progress = progress;
230
231         ntree->test_break = compo_breakjob;
232         ntree->tbh = cj;
233         ntree->stats_draw = compo_statsdrawjob;
234         ntree->sdh = cj;
235         ntree->progress = compo_progressjob;
236         ntree->prh = cj;
237         ntree->update_draw = compo_redrawjob;
238         ntree->udh = cj;
239
240         // XXX BIF_store_spare();
241         /* 1 is do_previews */
242
243         if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
244                 ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, "");
245         }
246         else {
247                 for (srv = scene->r.views.first; srv; srv = srv->next) {
248                         if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
249                         ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
250                 }
251         }
252
253         ntree->test_break = NULL;
254         ntree->stats_draw = NULL;
255         ntree->progress = NULL;
256
257 }
258
259 /**
260  * \param scene_owner: is the owner of the job,
261  * we don't use it for anything else currently so could also be a void pointer,
262  * but for now keep it an 'Scene' for consistency.
263  *
264  * \note only call from spaces `refresh` callbacks, not direct! - use with care.
265  */
266 void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner)
267 {
268         wmJob *wm_job;
269         CompoJob *cj;
270         Main *bmain = CTX_data_main(C);
271         Scene *scene = CTX_data_scene(C);
272
273         /* to fix bug: [#32272] */
274         if (G.is_rendering) {
275                 return;
276         }
277
278 #ifdef USE_ESC_COMPO
279         G.is_break = false;
280 #endif
281
282         BKE_image_backup_render(scene, BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false);
283
284         wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene_owner, "Compositing",
285                              WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE);
286         cj = MEM_callocN(sizeof(CompoJob), "compo job");
287
288         /* customdata for preview thread */
289         cj->bmain = bmain;
290         cj->scene = scene;
291         cj->ntree = nodetree;
292         cj->recalc_flags = compo_get_recalc_flags(C);
293
294         /* setup job */
295         WM_jobs_customdata_set(wm_job, cj, compo_freejob);
296         WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
297         WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, NULL);
298
299         WM_jobs_start(CTX_wm_manager(C), wm_job);
300 }
301
302 /* ***************************************** */
303
304 /* operator poll callback */
305 bool composite_node_active(bContext *C)
306 {
307         if (ED_operator_node_active(C)) {
308                 SpaceNode *snode = CTX_wm_space_node(C);
309                 if (ED_node_is_compositor(snode))
310                         return 1;
311         }
312         return 0;
313 }
314
315 /* operator poll callback */
316 bool composite_node_editable(bContext *C)
317 {
318         if (ED_operator_node_editable(C)) {
319                 SpaceNode *snode = CTX_wm_space_node(C);
320                 if (ED_node_is_compositor(snode))
321                         return 1;
322         }
323         return 0;
324 }
325
326 void snode_dag_update(bContext *C, SpaceNode *snode)
327 {
328         Main *bmain = CTX_data_main(C);
329
330         /* for groups, update all ID's using this */
331         if (snode->edittree != snode->nodetree) {
332                 FOREACH_NODETREE_BEGIN(bmain, tntree, id) {
333                         if (ntreeHasTree(tntree, snode->edittree))
334                                 DAG_id_tag_update(id, 0);
335                 } FOREACH_NODETREE_END;
336         }
337
338         DAG_id_tag_update(snode->id, 0);
339 }
340
341 void snode_notify(bContext *C, SpaceNode *snode)
342 {
343         ID *id = snode->id;
344
345         WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL);
346
347         if (ED_node_is_shader(snode)) {
348                 if (GS(id->name) == ID_MA)
349                         WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
350                 else if (GS(id->name) == ID_LA)
351                         WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
352                 else if (GS(id->name) == ID_WO)
353                         WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
354         }
355         else if (ED_node_is_compositor(snode))
356                 WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
357         else if (ED_node_is_texture(snode))
358                 WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
359 }
360
361 void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
362 {
363         if (typeinfo)
364                 BLI_strncpy(snode->tree_idname, typeinfo->idname, sizeof(snode->tree_idname));
365         else
366                 snode->tree_idname[0] = '\0';
367 }
368
369 bool ED_node_is_compositor(struct SpaceNode *snode)
370 {
371         return STREQ(snode->tree_idname, ntreeType_Composite->idname);
372 }
373
374 bool ED_node_is_shader(struct SpaceNode *snode)
375 {
376         return STREQ(snode->tree_idname, ntreeType_Shader->idname);
377 }
378
379 bool ED_node_is_texture(struct SpaceNode *snode)
380 {
381         return STREQ(snode->tree_idname, ntreeType_Texture->idname);
382 }
383
384 /* assumes nothing being done in ntree yet, sets the default in/out node */
385 /* called from shading buttons or header */
386 void ED_node_shader_default(const bContext *C, ID *id)
387 {
388         Scene *scene = CTX_data_scene(C);
389         bNode *in, *out;
390         bNodeSocket *fromsock, *tosock, *sock;
391         bNodeTree *ntree;
392         int output_type, shader_type;
393         float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }, strength = 1.0f;
394
395         ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
396
397         switch (GS(id->name)) {
398                 case ID_MA:
399                 {
400                         Material *ma = (Material *)id;
401                         ma->nodetree = ntree;
402
403                         if (BKE_scene_use_new_shading_nodes(scene)) {
404                                 output_type = SH_NODE_OUTPUT_MATERIAL;
405                                 shader_type = SH_NODE_BSDF_DIFFUSE;
406                         }
407                         else {
408                                 output_type = SH_NODE_OUTPUT;
409                                 shader_type = SH_NODE_MATERIAL;
410                         }
411
412                         copy_v3_v3(color, &ma->r);
413                         strength = 0.0f;
414                         break;
415                 }
416                 case ID_WO:
417                 {
418                         World *wo = (World *)id;
419                         wo->nodetree = ntree;
420
421                         output_type = SH_NODE_OUTPUT_WORLD;
422                         shader_type = SH_NODE_BACKGROUND;
423
424                         copy_v3_v3(color, &wo->horr);
425                         strength = 1.0f;
426                         break;
427                 }
428                 case ID_LA:
429                 {
430                         Lamp *la = (Lamp *)id;
431                         la->nodetree = ntree;
432
433                         output_type = SH_NODE_OUTPUT_LAMP;
434                         shader_type = SH_NODE_EMISSION;
435
436                         copy_v3_v3(color, &la->r);
437                         if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA)
438                                 strength = 100.0f;
439                         else
440                                 strength = 1.0f;
441                         break;
442                 }
443                 default:
444                         printf("ED_node_shader_default called on wrong ID type.\n");
445                         return;
446         }
447
448         out = nodeAddStaticNode(C, ntree, output_type);
449         out->locx = 300.0f; out->locy = 300.0f;
450
451         in = nodeAddStaticNode(C, ntree, shader_type);
452         in->locx = 10.0f; in->locy = 300.0f;
453         nodeSetActive(ntree, in);
454
455         /* only a link from color to color */
456         fromsock = in->outputs.first;
457         tosock = out->inputs.first;
458         nodeAddLink(ntree, in, fromsock, out, tosock);
459
460         /* default values */
461         if (BKE_scene_use_new_shading_nodes(scene)) {
462                 PointerRNA sockptr;
463                 sock = in->inputs.first;
464                 RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
465
466                 RNA_float_set_array(&sockptr, "default_value", color);
467
468                 if (strength != 0.0f) {
469                         sock = in->inputs.last;
470                         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &sockptr);
471                         RNA_float_set(&sockptr, "default_value", strength);
472                 }
473         }
474
475         ntreeUpdateTree(CTX_data_main(C), ntree);
476 }
477
478 /* assumes nothing being done in ntree yet, sets the default in/out node */
479 /* called from shading buttons or header */
480 void ED_node_composit_default(const bContext *C, struct Scene *sce)
481 {
482         bNode *in, *out;
483         bNodeSocket *fromsock, *tosock;
484
485         /* but lets check it anyway */
486         if (sce->nodetree) {
487                 if (G.debug & G_DEBUG)
488                         printf("error in composite initialize\n");
489                 return;
490         }
491
492         sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname);
493
494         sce->nodetree->chunksize = 256;
495         sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
496         sce->nodetree->render_quality = NTREE_QUALITY_HIGH;
497
498         out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE);
499         out->locx = 300.0f; out->locy = 400.0f;
500
501         in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS);
502         in->locx = 10.0f; in->locy = 400.0f;
503         nodeSetActive(sce->nodetree, in);
504
505         /* links from color to color */
506         fromsock = in->outputs.first;
507         tosock = out->inputs.first;
508         nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
509
510         ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
511 }
512
513 /* assumes nothing being done in ntree yet, sets the default in/out node */
514 /* called from shading buttons or header */
515 void ED_node_texture_default(const bContext *C, Tex *tx)
516 {
517         bNode *in, *out;
518         bNodeSocket *fromsock, *tosock;
519
520         /* but lets check it anyway */
521         if (tx->nodetree) {
522                 if (G.debug & G_DEBUG)
523                         printf("error in texture initialize\n");
524                 return;
525         }
526
527         tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname);
528
529         out = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_OUTPUT);
530         out->locx = 300.0f; out->locy = 300.0f;
531
532         in = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_CHECKER);
533         in->locx = 10.0f; in->locy = 300.0f;
534         nodeSetActive(tx->nodetree, in);
535
536         fromsock = in->outputs.first;
537         tosock = out->inputs.first;
538         nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
539
540         ntreeUpdateTree(CTX_data_main(C), tx->nodetree);
541 }
542
543 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
544 void snode_set_context(const bContext *C)
545 {
546         SpaceNode *snode = CTX_wm_space_node(C);
547         bNodeTreeType *treetype = ntreeTypeFind(snode->tree_idname);
548         bNodeTree *ntree = snode->nodetree;
549         ID *id = snode->id, *from = snode->from;
550
551         /* we use this to signal warnings, when node shaders are drawn in wrong render engine */
552         if (BKE_scene_use_new_shading_nodes(CTX_data_scene(C)))
553                 snode->flag |= SNODE_NEW_SHADERS;
554         else
555                 snode->flag &= ~SNODE_NEW_SHADERS;
556
557         /* check the tree type */
558         if (!treetype ||
559             (treetype->poll && !treetype->poll(C, treetype)))
560         {
561                 /* invalid tree type, skip
562                  * NB: not resetting the node path here, invalid bNodeTreeType
563                  * may still be registered at a later point.
564                  */
565                 return;
566         }
567
568         if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
569                 /* current tree does not match selected type, clear tree path */
570                 ntree = NULL;
571                 id = NULL;
572                 from = NULL;
573         }
574
575         if (!(snode->flag & SNODE_PIN) || ntree == NULL) {
576                 if (treetype->get_from_context) {
577                         /* reset and update from context */
578                         ntree = NULL;
579                         id = NULL;
580                         from = NULL;
581
582                         treetype->get_from_context(C, treetype, &ntree, &id, &from);
583                 }
584         }
585
586         if (snode->nodetree != ntree || snode->id != id || snode->from != from ||
587             (snode->treepath.last == NULL && ntree))
588         {
589                 ED_node_tree_start(snode, ntree, id, from);
590         }
591 }
592
593 void snode_update(SpaceNode *snode, bNode *node)
594 {
595         bNodeTreePath *path;
596
597         /* XXX this only updates nodes in the current node space tree path.
598          * The function supposedly should update any potential group node linking to changed tree,
599          * this really requires a working depsgraph ...
600          */
601
602         /* update all edited group nodes */
603         path = snode->treepath.last;
604         if (path) {
605                 bNodeTree *ngroup = path->nodetree;
606                 for (path = path->prev; path; path = path->prev) {
607                         nodeUpdateID(path->nodetree, (ID *)ngroup);
608                         ngroup = path->nodetree;
609                 }
610         }
611
612         if (node)
613                 nodeUpdate(snode->edittree, node);
614 }
615
616 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
617 {
618         const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
619
620         nodeSetActive(ntree, node);
621
622         if (node->type != NODE_GROUP) {
623                 const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
624                 bool do_update = false;
625
626                 /* generic node group output: set node as active output */
627                 if (node->type == NODE_GROUP_OUTPUT) {
628                         bNode *tnode;
629                         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
630                                 if (tnode->type == NODE_GROUP_OUTPUT)
631                                         tnode->flag &= ~NODE_DO_OUTPUT;
632
633                         node->flag |= NODE_DO_OUTPUT;
634                         if (!was_output)
635                                 do_update = 1;
636                 }
637
638                 /* tree specific activate calls */
639                 if (ntree->type == NTREE_SHADER) {
640                         /* when we select a material, active texture is cleared, for buttons */
641                         if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
642                                 nodeClearActiveID(ntree, ID_TE);
643
644                         if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
645                                  SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE))
646                         {
647                                 bNode *tnode;
648
649                                 for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
650                                         if (tnode->type == node->type)
651                                                 tnode->flag &= ~NODE_DO_OUTPUT;
652
653                                 node->flag |= NODE_DO_OUTPUT;
654                                 if (was_output == 0)
655                                         ED_node_tag_update_nodetree(bmain, ntree, node);
656                         }
657                         else if (do_update)
658                                 ED_node_tag_update_nodetree(bmain, ntree, node);
659
660                         /* if active texture changed, free glsl materials */
661                         if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
662                                 Material *ma;
663                                 World *wo;
664
665                                 for (ma = bmain->mat.first; ma; ma = ma->id.next)
666                                         if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree))
667                                                 GPU_material_free(&ma->gpumaterial);
668
669                                 for (wo = bmain->world.first; wo; wo = wo->id.next)
670                                         if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree))
671                                                 GPU_material_free(&wo->gpumaterial);
672
673                                 WM_main_add_notifier(NC_IMAGE, NULL);
674                         }
675
676                         WM_main_add_notifier(NC_MATERIAL | ND_NODES, node->id);
677                 }
678                 else if (ntree->type == NTREE_COMPOSIT) {
679                         /* make active viewer, currently only 1 supported... */
680                         if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
681                                 bNode *tnode;
682
683
684                                 for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
685                                         if (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
686                                                 tnode->flag &= ~NODE_DO_OUTPUT;
687
688                                 node->flag |= NODE_DO_OUTPUT;
689                                 if (was_output == 0)
690                                         ED_node_tag_update_nodetree(bmain, ntree, node);
691
692                                 /* addnode() doesnt link this yet... */
693                                 node->id = (ID *)BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
694                         }
695                         else if (node->type == CMP_NODE_R_LAYERS) {
696                                 Scene *scene;
697
698                                 for (scene = bmain->scene.first; scene; scene = scene->id.next) {
699                                         if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
700                                                 if (node->id == NULL || node->id == (ID *)scene) {
701                                                         int num_layers = BLI_listbase_count(&scene->r.layers);
702                                                         scene->r.actlay = node->custom1;
703                                                         /* Clamp the value, because it might have come from a different
704                                                          * scene which could have more render layers than new one.
705                                                          */
706                                                         scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
707                                                 }
708                                         }
709                                 }
710                         }
711                         else if (node->type == CMP_NODE_COMPOSITE) {
712                                 if (was_output == 0) {
713                                         bNode *tnode;
714
715                                         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
716                                                 if (tnode->type == CMP_NODE_COMPOSITE)
717                                                         tnode->flag &= ~NODE_DO_OUTPUT;
718
719                                         node->flag |= NODE_DO_OUTPUT;
720                                         ED_node_tag_update_nodetree(bmain, ntree, node);
721                                 }
722                         }
723                         else if (do_update)
724                                 ED_node_tag_update_nodetree(bmain, ntree, node);
725                 }
726                 else if (ntree->type == NTREE_TEXTURE) {
727                         // XXX
728 #if 0
729                         if (node->id)
730                                 ;  // XXX BIF_preview_changed(-1);
731                         // allqueue(REDRAWBUTSSHADING, 1);
732                         // allqueue(REDRAWIPO, 0);
733 #endif
734                 }
735         }
736 }
737
738 void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
739 {
740         /* XXX This does not work due to layout functions relying on node->block,
741          * which only exists during actual drawing. Can we rely on valid totr rects?
742          */
743         /* make sure nodes have correct bounding boxes after transform */
744         /* node_update_nodetree(C, ntree, 0.0f, 0.0f); */
745 }
746
747 /* ***************** generic operator functions for nodes ***************** */
748
749 #if 0 /* UNUSED */
750
751 static bool edit_node_poll(bContext *C)
752 {
753         return ED_operator_node_active(C);
754 }
755
756 static void edit_node_properties(wmOperatorType *ot)
757 {
758         /* XXX could node be a context pointer? */
759         RNA_def_string(ot->srna, "node", NULL, MAX_NAME, "Node", "");
760         RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
761         RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Side", "");
762 }
763
764 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
765 {
766         if (!RNA_struct_property_is_set(op->ptr, "node")) {
767                 bNode *node = CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
768                 if (!node)
769                         return 0;
770                 else
771                         RNA_string_set(op->ptr, "node", node->name);
772         }
773
774         if (!RNA_struct_property_is_set(op->ptr, "in_out"))
775                 RNA_enum_set(op->ptr, "in_out", SOCK_IN);
776
777         if (!RNA_struct_property_is_set(op->ptr, "socket"))
778                 RNA_int_set(op->ptr, "socket", 0);
779
780         return 1;
781 }
782
783 static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
784 {
785         bNode *node;
786         bNodeSocket *sock = NULL;
787         char nodename[MAX_NAME];
788         int sockindex;
789         int in_out;
790
791         RNA_string_get(op->ptr, "node", nodename);
792         node = nodeFindNodebyName(ntree, nodename);
793
794         in_out = RNA_enum_get(op->ptr, "in_out");
795
796         sockindex = RNA_int_get(op->ptr, "socket");
797         switch (in_out) {
798                 case SOCK_IN:   sock = BLI_findlink(&node->inputs, sockindex);  break;
799                 case SOCK_OUT:  sock = BLI_findlink(&node->outputs, sockindex); break;
800         }
801
802         if (rnode)
803                 *rnode = node;
804         if (rsock)
805                 *rsock = sock;
806         if (rin_out)
807                 *rin_out = in_out;
808 }
809 #endif
810
811 /* ************************** Node generic ************** */
812
813 /* is rct in visible part of node? */
814 static bNode *visible_node(SpaceNode *snode, const rctf *rct)
815 {
816         bNode *node;
817
818         for (node = snode->edittree->nodes.last; node; node = node->prev) {
819                 if (BLI_rctf_isect(&node->totr, rct, NULL))
820                         break;
821         }
822         return node;
823 }
824
825 /* ********************** size widget operator ******************** */
826
827 typedef struct NodeSizeWidget {
828         float mxstart, mystart;
829         float oldlocx, oldlocy;
830         float oldoffsetx, oldoffsety;
831         float oldwidth, oldheight;
832         float oldminiwidth;
833         int directions;
834 } NodeSizeWidget;
835
836 static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event), bNode *node, int dir)
837 {
838         SpaceNode *snode = CTX_wm_space_node(C);
839
840         NodeSizeWidget *nsw = MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
841
842         op->customdata = nsw;
843         nsw->mxstart = snode->cursor[0];
844         nsw->mystart = snode->cursor[1];
845
846         /* store old */
847         nsw->oldlocx = node->locx;
848         nsw->oldlocy = node->locy;
849         nsw->oldoffsetx = node->offsetx;
850         nsw->oldoffsety = node->offsety;
851         nsw->oldwidth = node->width;
852         nsw->oldheight = node->height;
853         nsw->oldminiwidth = node->miniwidth;
854         nsw->directions = dir;
855
856         WM_cursor_modal_set(CTX_wm_window(C), node_get_resize_cursor(dir));
857         /* add modal handler */
858         WM_event_add_modal_handler(C, op);
859 }
860
861 static void node_resize_exit(bContext *C, wmOperator *op, bool UNUSED(cancel))
862 {
863         WM_cursor_modal_restore(CTX_wm_window(C));
864
865         MEM_freeN(op->customdata);
866         op->customdata = NULL;
867 }
868
869 static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
870 {
871         SpaceNode *snode = CTX_wm_space_node(C);
872         ARegion *ar = CTX_wm_region(C);
873         bNode *node = nodeGetActive(snode->edittree);
874         NodeSizeWidget *nsw = op->customdata;
875         float mx, my, dx, dy;
876
877         switch (event->type) {
878                 case MOUSEMOVE:
879
880                         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &mx, &my);
881                         dx = (mx - nsw->mxstart) / UI_DPI_FAC;
882                         dy = (my - nsw->mystart) / UI_DPI_FAC;
883
884                         if (node) {
885                                 /* width can use node->width or node->miniwidth (hidden nodes) */
886                                 float *pwidth;
887                                 float oldwidth, widthmin, widthmax;
888                                 /* ignore hidden flag for frame nodes */
889                                 bool use_hidden = (node->type != NODE_FRAME);
890                                 if (use_hidden && node->flag & NODE_HIDDEN) {
891                                         pwidth = &node->miniwidth;
892                                         oldwidth = nsw->oldminiwidth;
893                                         widthmin = 0.0f;
894                                 }
895                                 else {
896                                         pwidth = &node->width;
897                                         oldwidth = nsw->oldwidth;
898                                         widthmin = node->typeinfo->minwidth;
899                                 }
900                                 widthmax = node->typeinfo->maxwidth;
901
902                                 {
903                                         if (nsw->directions & NODE_RESIZE_RIGHT) {
904                                                 *pwidth = oldwidth + dx;
905                                                 CLAMP(*pwidth, widthmin, widthmax);
906                                         }
907                                         if (nsw->directions & NODE_RESIZE_LEFT) {
908                                                 float locmax = nsw->oldlocx + oldwidth;
909
910                                                 node->locx = nsw->oldlocx + dx;
911                                                 CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
912                                                 *pwidth = locmax - node->locx;
913                                         }
914                                 }
915
916                                 /* height works the other way round ... */
917                                 {
918                                         float heightmin = UI_DPI_FAC * node->typeinfo->minheight;
919                                         float heightmax = UI_DPI_FAC * node->typeinfo->maxheight;
920                                         if (nsw->directions & NODE_RESIZE_TOP) {
921                                                 float locmin = nsw->oldlocy - nsw->oldheight;
922
923                                                 node->locy = nsw->oldlocy + dy;
924                                                 CLAMP(node->locy, locmin + heightmin, locmin + heightmax);
925                                                 node->height = node->locy - locmin;
926                                         }
927                                         if (nsw->directions & NODE_RESIZE_BOTTOM) {
928                                                 node->height = nsw->oldheight - dy;
929                                                 CLAMP(node->height, heightmin, heightmax);
930                                         }
931                                 }
932
933                                 /* XXX make callback? */
934                                 if (node->type == NODE_FRAME) {
935                                         /* keep the offset symmetric around center point */
936                                         if (nsw->directions & NODE_RESIZE_LEFT) {
937                                                 node->locx = nsw->oldlocx + 0.5f * dx;
938                                                 node->offsetx = nsw->oldoffsetx + 0.5f * dx;
939                                         }
940                                         if (nsw->directions & NODE_RESIZE_RIGHT) {
941                                                 node->locx = nsw->oldlocx + 0.5f * dx;
942                                                 node->offsetx = nsw->oldoffsetx - 0.5f * dx;
943                                         }
944                                         if (nsw->directions & NODE_RESIZE_TOP) {
945                                                 node->locy = nsw->oldlocy + 0.5f * dy;
946                                                 node->offsety = nsw->oldoffsety + 0.5f * dy;
947                                         }
948                                         if (nsw->directions & NODE_RESIZE_BOTTOM) {
949                                                 node->locy = nsw->oldlocy + 0.5f * dy;
950                                                 node->offsety = nsw->oldoffsety - 0.5f * dy;
951                                         }
952                                 }
953                         }
954
955                         ED_region_tag_redraw(ar);
956
957                         break;
958
959                 case LEFTMOUSE:
960                 case MIDDLEMOUSE:
961                 case RIGHTMOUSE:
962                         if (event->val == KM_RELEASE) {
963                                 node_resize_exit(C, op, false);
964                                 ED_node_post_apply_transform(C, snode->edittree);
965
966                                 return OPERATOR_FINISHED;
967                         }
968                         break;
969         }
970
971         return OPERATOR_RUNNING_MODAL;
972 }
973
974 static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
975 {
976         SpaceNode *snode = CTX_wm_space_node(C);
977         ARegion *ar = CTX_wm_region(C);
978         bNode *node = nodeGetActive(snode->edittree);
979         int dir;
980
981         if (node) {
982                 /* convert mouse coordinates to v2d space */
983                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
984                                          &snode->cursor[0], &snode->cursor[1]);
985                 dir = node->typeinfo->resize_area_func(node, snode->cursor[0], snode->cursor[1]);
986                 if (dir != 0) {
987                         node_resize_init(C, op, event, node, dir);
988                         return OPERATOR_RUNNING_MODAL;
989                 }
990         }
991         return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
992 }
993
994 static void node_resize_cancel(bContext *C, wmOperator *op)
995 {
996         node_resize_exit(C, op, true);
997 }
998
999 void NODE_OT_resize(wmOperatorType *ot)
1000 {
1001         /* identifiers */
1002         ot->name = "Resize Node";
1003         ot->idname = "NODE_OT_resize";
1004         ot->description = "Resize a node";
1005
1006         /* api callbacks */
1007         ot->invoke = node_resize_invoke;
1008         ot->modal = node_resize_modal;
1009         ot->poll = ED_operator_node_active;
1010         ot->cancel = node_resize_cancel;
1011
1012         /* flags */
1013         ot->flag = OPTYPE_BLOCKING;
1014 }
1015
1016
1017 /* ********************** hidden sockets ******************** */
1018
1019 int node_has_hidden_sockets(bNode *node)
1020 {
1021         bNodeSocket *sock;
1022
1023         for (sock = node->inputs.first; sock; sock = sock->next)
1024                 if (sock->flag & SOCK_HIDDEN)
1025                         return 1;
1026         for (sock = node->outputs.first; sock; sock = sock->next)
1027                 if (sock->flag & SOCK_HIDDEN)
1028                         return 1;
1029         return 0;
1030 }
1031
1032 void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
1033 {
1034         bNodeSocket *sock;
1035
1036         if (set == 0) {
1037                 for (sock = node->inputs.first; sock; sock = sock->next)
1038                         sock->flag &= ~SOCK_HIDDEN;
1039                 for (sock = node->outputs.first; sock; sock = sock->next)
1040                         sock->flag &= ~SOCK_HIDDEN;
1041         }
1042         else {
1043                 /* hide unused sockets */
1044                 for (sock = node->inputs.first; sock; sock = sock->next) {
1045                         if (sock->link == NULL)
1046                                 sock->flag |= SOCK_HIDDEN;
1047                 }
1048                 for (sock = node->outputs.first; sock; sock = sock->next) {
1049                         if (nodeCountSocketLinks(snode->edittree, sock) == 0)
1050                                 sock->flag |= SOCK_HIDDEN;
1051                 }
1052         }
1053 }
1054
1055
1056 /* checks snode->mouse position, and returns found node/socket */
1057 /* type is SOCK_IN and/or SOCK_OUT */
1058 int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out)
1059 {
1060         bNode *node;
1061         bNodeSocket *sock;
1062         rctf rect;
1063
1064         *nodep = NULL;
1065         *sockp = NULL;
1066
1067         /* check if we click in a socket */
1068         for (node = snode->edittree->nodes.first; node; node = node->next) {
1069
1070                 BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4);
1071
1072                 if (!(node->flag & NODE_HIDDEN)) {
1073                         /* extra padding inside and out - allow dragging on the text areas too */
1074                         if (in_out == SOCK_IN) {
1075                                 rect.xmax += NODE_SOCKSIZE;
1076                                 rect.xmin -= NODE_SOCKSIZE * 4;
1077                         }
1078                         else if (in_out == SOCK_OUT) {
1079                                 rect.xmax += NODE_SOCKSIZE * 4;
1080                                 rect.xmin -= NODE_SOCKSIZE;
1081                         }
1082                 }
1083
1084                 if (in_out & SOCK_IN) {
1085                         for (sock = node->inputs.first; sock; sock = sock->next) {
1086                                 if (!nodeSocketIsHidden(sock)) {
1087                                         if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
1088                                                 if (node == visible_node(snode, &rect)) {
1089                                                         *nodep = node;
1090                                                         *sockp = sock;
1091                                                         return 1;
1092                                                 }
1093                                         }
1094                                 }
1095                         }
1096                 }
1097                 if (in_out & SOCK_OUT) {
1098                         for (sock = node->outputs.first; sock; sock = sock->next) {
1099                                 if (!nodeSocketIsHidden(sock)) {
1100                                         if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) {
1101                                                 if (node == visible_node(snode, &rect)) {
1102                                                         *nodep = node;
1103                                                         *sockp = sock;
1104                                                         return 1;
1105                                                 }
1106                                         }
1107                                 }
1108                         }
1109                 }
1110         }
1111
1112         return 0;
1113 }
1114
1115 /* ****************** Duplicate *********************** */
1116
1117 static void node_duplicate_reparent_recursive(bNode *node)
1118 {
1119         bNode *parent;
1120
1121         node->flag |= NODE_TEST;
1122
1123         /* find first selected parent */
1124         for (parent = node->parent; parent; parent = parent->parent) {
1125                 if (parent->flag & SELECT) {
1126                         if (!(parent->flag & NODE_TEST))
1127                                 node_duplicate_reparent_recursive(parent);
1128                         break;
1129                 }
1130         }
1131         /* reparent node copy to parent copy */
1132         if (parent) {
1133                 nodeDetachNode(node->new_node);
1134                 nodeAttachNode(node->new_node, parent->new_node);
1135         }
1136 }
1137
1138 static int node_duplicate_exec(bContext *C, wmOperator *op)
1139 {
1140         Main *bmain = CTX_data_main(C);
1141         SpaceNode *snode = CTX_wm_space_node(C);
1142         bNodeTree *ntree = snode->edittree;
1143         bNode *node, *newnode, *lastnode;
1144         bNodeLink *link, *newlink, *lastlink;
1145         const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
1146         bool do_tag_update = false;
1147
1148         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1149
1150         lastnode = ntree->nodes.last;
1151         for (node = ntree->nodes.first; node; node = node->next) {
1152                 if (node->flag & SELECT) {
1153                         newnode = nodeCopyNode(ntree, node);
1154
1155                         if (newnode->id) {
1156                                 /* simple id user adjustment, node internal functions don't touch this
1157                                  * but operators and readfile.c do. */
1158                                 id_us_plus(newnode->id);
1159                                 /* to ensure redraws or rerenders happen */
1160                                 ED_node_tag_update_id(snode->id);
1161                         }
1162                 }
1163
1164                 /* make sure we don't copy new nodes again! */
1165                 if (node == lastnode)
1166                         break;
1167         }
1168
1169         /* copy links between selected nodes
1170          * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
1171          */
1172         lastlink = ntree->links.last;
1173         for (link = ntree->links.first; link; link = link->next) {
1174                 /* This creates new links between copied nodes.
1175                  * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)!
1176                  */
1177                 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
1178                     (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT))))
1179                 {
1180                         newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
1181                         newlink->flag = link->flag;
1182                         newlink->tonode = link->tonode->new_node;
1183                         newlink->tosock = link->tosock->new_sock;
1184                         if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
1185                                 newlink->fromnode = link->fromnode->new_node;
1186                                 newlink->fromsock = link->fromsock->new_sock;
1187                         }
1188                         else {
1189                                 /* input node not copied, this keeps the original input linked */
1190                                 newlink->fromnode = link->fromnode;
1191                                 newlink->fromsock = link->fromsock;
1192                         }
1193
1194                         BLI_addtail(&ntree->links, newlink);
1195                 }
1196
1197                 /* make sure we don't copy new links again! */
1198                 if (link == lastlink)
1199                         break;
1200         }
1201
1202         /* clear flags for recursive depth-first iteration */
1203         for (node = ntree->nodes.first; node; node = node->next)
1204                 node->flag &= ~NODE_TEST;
1205         /* reparent copied nodes */
1206         for (node = ntree->nodes.first; node; node = node->next) {
1207                 if ((node->flag & SELECT) && !(node->flag & NODE_TEST))
1208                         node_duplicate_reparent_recursive(node);
1209
1210                 /* only has to check old nodes */
1211                 if (node == lastnode)
1212                         break;
1213         }
1214
1215         /* deselect old nodes, select the copies instead */
1216         for (node = ntree->nodes.first; node; node = node->next) {
1217                 if (node->flag & SELECT) {
1218                         /* has been set during copy above */
1219                         newnode = node->new_node;
1220
1221                         nodeSetSelected(node, false);
1222                         node->flag &= ~NODE_ACTIVE;
1223                         nodeSetSelected(newnode, true);
1224
1225                         do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
1226                 }
1227
1228                 /* make sure we don't copy new nodes again! */
1229                 if (node == lastnode)
1230                         break;
1231         }
1232
1233         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1234
1235         snode_notify(C, snode);
1236         if (do_tag_update) {
1237                 snode_dag_update(C, snode);
1238         }
1239
1240         return OPERATOR_FINISHED;
1241 }
1242
1243 void NODE_OT_duplicate(wmOperatorType *ot)
1244 {
1245         /* identifiers */
1246         ot->name = "Duplicate Nodes";
1247         ot->description = "Duplicate selected nodes";
1248         ot->idname = "NODE_OT_duplicate";
1249
1250         /* api callbacks */
1251         ot->exec = node_duplicate_exec;
1252         ot->poll = ED_operator_node_editable;
1253
1254         /* flags */
1255         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1256
1257         RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
1258 }
1259
1260 bool ED_node_select_check(ListBase *lb)
1261
1262
1263 {
1264         bNode *node;
1265
1266         for (node = lb->first; node; node = node->next) {
1267                 if (node->flag & NODE_SELECT) {
1268                         return true;
1269                 }
1270         }
1271
1272         return false;
1273 }
1274
1275 /* ******************************** */
1276 // XXX some code needing updating to operators...
1277
1278
1279 /* goes over all scenes, reads render layers */
1280 static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
1281 {
1282         Main *bmain = CTX_data_main(C);
1283         SpaceNode *snode = CTX_wm_space_node(C);
1284         Scene *curscene = CTX_data_scene(C), *scene;
1285         bNode *node;
1286
1287         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1288
1289         /* first tag scenes unread */
1290         for (scene = bmain->scene.first; scene; scene = scene->id.next)
1291                 scene->id.tag |= LIB_TAG_DOIT;
1292
1293         for (node = snode->edittree->nodes.first; node; node = node->next) {
1294                 if (node->type == CMP_NODE_R_LAYERS) {
1295                         ID *id = node->id;
1296                         if (id->tag & LIB_TAG_DOIT) {
1297                                 RE_ReadRenderResult(curscene, (Scene *)id);
1298                                 ntreeCompositTagRender((Scene *)id);
1299                                 id->tag &= ~LIB_TAG_DOIT;
1300                         }
1301                 }
1302         }
1303
1304         snode_notify(C, snode);
1305         snode_dag_update(C, snode);
1306
1307         return OPERATOR_FINISHED;
1308 }
1309
1310 void NODE_OT_read_renderlayers(wmOperatorType *ot)
1311 {
1312
1313         ot->name = "Read Render Layers";
1314         ot->idname = "NODE_OT_read_renderlayers";
1315         ot->description = "Read all render layers of all used scenes";
1316
1317         ot->exec = node_read_renderlayers_exec;
1318
1319         ot->poll = composite_node_active;
1320
1321         /* flags */
1322         ot->flag = 0;
1323 }
1324
1325 static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
1326 {
1327         Main *bmain = CTX_data_main(C);
1328         SpaceNode *snode = CTX_wm_space_node(C);
1329         Scene *curscene = CTX_data_scene(C);
1330         Render *re = RE_NewSceneRender(curscene);
1331
1332         WM_cursor_wait(1);
1333         RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
1334         WM_cursor_wait(0);
1335
1336         /* note we are careful to send the right notifier, as otherwise the
1337          * compositor would reexecute and overwrite the full sample result */
1338         WM_event_add_notifier(C, NC_SCENE | ND_COMPO_RESULT, NULL);
1339
1340         return OPERATOR_FINISHED;
1341 }
1342
1343
1344 void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
1345 {
1346
1347         ot->name = "Read Full Sample Layers";
1348         ot->idname = "NODE_OT_read_fullsamplelayers";
1349         ot->description = "Read all render layers of current scene, in full sample";
1350
1351         ot->exec = node_read_fullsamplelayers_exec;
1352
1353         ot->poll = composite_node_active;
1354
1355         /* flags */
1356         ot->flag = 0;
1357 }
1358
1359 int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
1360 {
1361         Scene *sce = CTX_data_scene(C);
1362         bNode *node;
1363
1364         for (node = sce->nodetree->nodes.first; node; node = node->next) {
1365                 if (node->id == (ID *)sce && node->need_exec) {
1366                         break;
1367                 }
1368         }
1369         if (node) {
1370                 SceneRenderLayer *srl = BLI_findlink(&sce->r.layers, node->custom1);
1371
1372                 if (srl) {
1373                         PointerRNA op_ptr;
1374
1375                         WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
1376                         RNA_string_set(&op_ptr, "layer", srl->name);
1377                         RNA_string_set(&op_ptr, "scene", sce->id.name + 2);
1378
1379                         /* to keep keypositions */
1380                         sce->r.scemode |= R_NO_FRAME_UPDATE;
1381
1382                         WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr);
1383
1384                         WM_operator_properties_free(&op_ptr);
1385
1386                         return OPERATOR_FINISHED;
1387                 }
1388         }
1389         return OPERATOR_CANCELLED;
1390 }
1391
1392 void NODE_OT_render_changed(wmOperatorType *ot)
1393 {
1394         ot->name = "Render Changed Layer";
1395         ot->idname = "NODE_OT_render_changed";
1396         ot->description = "Render current scene, when input node's layer has been changed";
1397
1398         ot->exec = node_render_changed_exec;
1399
1400         ot->poll = composite_node_active;
1401
1402         /* flags */
1403         ot->flag = 0;
1404 }
1405
1406
1407 /* ****************** Hide operator *********************** */
1408
1409 static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
1410 {
1411         bNode *node;
1412         int tot_eq = 0, tot_neq = 0;
1413
1414         /* Toggles the flag on all selected nodes.
1415          * If the flag is set on all nodes it is unset.
1416          * If the flag is not set on all nodes, it is set.
1417          */
1418         for (node = snode->edittree->nodes.first; node; node = node->next) {
1419                 if (node->flag & SELECT) {
1420
1421                         if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0)
1422                                 continue;
1423                         if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1424                                 continue;
1425
1426                         if (node->flag & toggle_flag)
1427                                 tot_eq++;
1428                         else
1429                                 tot_neq++;
1430                 }
1431         }
1432         for (node = snode->edittree->nodes.first; node; node = node->next) {
1433                 if (node->flag & SELECT) {
1434
1435                         if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0)
1436                                 continue;
1437                         if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
1438                                 continue;
1439
1440                         if ((tot_eq && tot_neq) || tot_eq == 0)
1441                                 node->flag |= toggle_flag;
1442                         else
1443                                 node->flag &= ~toggle_flag;
1444                 }
1445         }
1446 }
1447
1448 static int node_hide_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1449 {
1450         SpaceNode *snode = CTX_wm_space_node(C);
1451
1452         /* sanity checking (poll callback checks this already) */
1453         if ((snode == NULL) || (snode->edittree == NULL))
1454                 return OPERATOR_CANCELLED;
1455
1456         node_flag_toggle_exec(snode, NODE_HIDDEN);
1457
1458         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1459
1460         return OPERATOR_FINISHED;
1461 }
1462
1463 void NODE_OT_hide_toggle(wmOperatorType *ot)
1464 {
1465         /* identifiers */
1466         ot->name = "Hide";
1467         ot->description = "Toggle hiding of selected nodes";
1468         ot->idname = "NODE_OT_hide_toggle";
1469
1470         /* callbacks */
1471         ot->exec = node_hide_toggle_exec;
1472         ot->poll = ED_operator_node_active;
1473
1474         /* flags */
1475         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1476 }
1477
1478 static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1479 {
1480         SpaceNode *snode = CTX_wm_space_node(C);
1481
1482         /* sanity checking (poll callback checks this already) */
1483         if ((snode == NULL) || (snode->edittree == NULL))
1484                 return OPERATOR_CANCELLED;
1485
1486         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1487
1488         node_flag_toggle_exec(snode, NODE_PREVIEW);
1489
1490         snode_notify(C, snode);
1491
1492         return OPERATOR_FINISHED;
1493 }
1494
1495 void NODE_OT_preview_toggle(wmOperatorType *ot)
1496 {
1497         /* identifiers */
1498         ot->name = "Toggle Node Preview";
1499         ot->description = "Toggle preview display for selected nodes";
1500         ot->idname = "NODE_OT_preview_toggle";
1501
1502         /* callbacks */
1503         ot->exec = node_preview_toggle_exec;
1504         ot->poll = ED_operator_node_active;
1505
1506         /* flags */
1507         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1508 }
1509
1510 static int node_options_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1511 {
1512         SpaceNode *snode = CTX_wm_space_node(C);
1513
1514         /* sanity checking (poll callback checks this already) */
1515         if ((snode == NULL) || (snode->edittree == NULL))
1516                 return OPERATOR_CANCELLED;
1517
1518         node_flag_toggle_exec(snode, NODE_OPTIONS);
1519
1520         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1521
1522         return OPERATOR_FINISHED;
1523 }
1524
1525 void NODE_OT_options_toggle(wmOperatorType *ot)
1526 {
1527         /* identifiers */
1528         ot->name = "Toggle Node Options";
1529         ot->description = "Toggle option buttons display for selected nodes";
1530         ot->idname = "NODE_OT_options_toggle";
1531
1532         /* callbacks */
1533         ot->exec = node_options_toggle_exec;
1534         ot->poll = ED_operator_node_active;
1535
1536         /* flags */
1537         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1538 }
1539
1540 static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1541 {
1542         SpaceNode *snode = CTX_wm_space_node(C);
1543         bNode *node;
1544         int hidden;
1545
1546         /* sanity checking (poll callback checks this already) */
1547         if ((snode == NULL) || (snode->edittree == NULL))
1548                 return OPERATOR_CANCELLED;
1549
1550         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1551
1552         /* Toggle for all selected nodes */
1553         hidden = 0;
1554         for (node = snode->edittree->nodes.first; node; node = node->next) {
1555                 if (node->flag & SELECT) {
1556                         if (node_has_hidden_sockets(node)) {
1557                                 hidden = 1;
1558                                 break;
1559                         }
1560                 }
1561         }
1562
1563         for (node = snode->edittree->nodes.first; node; node = node->next) {
1564                 if (node->flag & SELECT) {
1565                         node_set_hidden_sockets(snode, node, !hidden);
1566                 }
1567         }
1568
1569         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1570
1571         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1572
1573         return OPERATOR_FINISHED;
1574 }
1575
1576 void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
1577 {
1578         /* identifiers */
1579         ot->name = "Toggle Hidden Node Sockets";
1580         ot->description = "Toggle unused node socket display";
1581         ot->idname = "NODE_OT_hide_socket_toggle";
1582
1583         /* callbacks */
1584         ot->exec = node_socket_toggle_exec;
1585         ot->poll = ED_operator_node_active;
1586
1587         /* flags */
1588         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1589 }
1590
1591 /* ****************** Mute operator *********************** */
1592
1593 static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
1594 {
1595         Main *bmain = CTX_data_main(C);
1596         SpaceNode *snode = CTX_wm_space_node(C);
1597         bNode *node;
1598         bool do_tag_update = false;
1599
1600         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1601
1602         for (node = snode->edittree->nodes.first; node; node = node->next) {
1603                 /* Only allow muting of nodes having a mute func! */
1604                 if ((node->flag & SELECT) && node->typeinfo->update_internal_links) {
1605                         node->flag ^= NODE_MUTED;
1606                         snode_update(snode, node);
1607                         do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
1608                 }
1609         }
1610
1611         snode_notify(C, snode);
1612         if (do_tag_update) {
1613                 snode_dag_update(C, snode);
1614         }
1615
1616         return OPERATOR_FINISHED;
1617 }
1618
1619 void NODE_OT_mute_toggle(wmOperatorType *ot)
1620 {
1621         /* identifiers */
1622         ot->name = "Toggle Node Mute";
1623         ot->description = "Toggle muting of the nodes";
1624         ot->idname = "NODE_OT_mute_toggle";
1625
1626         /* callbacks */
1627         ot->exec = node_mute_exec;
1628         ot->poll = ED_operator_node_editable;
1629
1630         /* flags */
1631         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1632 }
1633
1634 /* ****************** Delete operator ******************* */
1635
1636 static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
1637 {
1638         Main *bmain = CTX_data_main(C);
1639         SpaceNode *snode = CTX_wm_space_node(C);
1640         bNode *node, *next;
1641         bool do_tag_update = false;
1642
1643         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
1644
1645         for (node = snode->edittree->nodes.first; node; node = next) {
1646                 next = node->next;
1647                 if (node->flag & SELECT) {
1648                         /* check id user here, nodeFreeNode is called for free dbase too */
1649                         do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node));
1650                         if (node->id)
1651                                 id_us_min(node->id);
1652                         nodeFreeNode(snode->edittree, node);
1653                 }
1654         }
1655
1656         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1657
1658         snode_notify(C, snode);
1659         if (do_tag_update) {
1660                 snode_dag_update(C, snode);
1661         }
1662
1663         return OPERATOR_FINISHED;
1664 }
1665
1666 void NODE_OT_delete(wmOperatorType *ot)
1667 {
1668         /* identifiers */
1669         ot->name = "Delete";
1670         ot->description = "Delete selected nodes";
1671         ot->idname = "NODE_OT_delete";
1672
1673         /* api callbacks */
1674         ot->exec = node_delete_exec;
1675         ot->poll = ED_operator_node_editable;
1676
1677         /* flags */
1678         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1679 }
1680
1681 /* ****************** Switch View ******************* */
1682
1683 static bool node_switch_view_poll(bContext *C)
1684 {
1685         SpaceNode *snode = CTX_wm_space_node(C);
1686
1687         if (snode && snode->edittree)
1688                 return true;
1689
1690         return false;
1691 }
1692
1693 static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
1694 {
1695         SpaceNode *snode = CTX_wm_space_node(C);
1696         bNode *node, *next;
1697
1698         for (node = snode->edittree->nodes.first; node; node = next) {
1699                 next = node->next;
1700                 if (node->flag & SELECT) {
1701                         /* call the update function from the Switch View node */
1702                         node->update = NODE_UPDATE_OPERATOR;
1703                 }
1704         }
1705
1706         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1707
1708         snode_notify(C, snode);
1709         snode_dag_update(C, snode);
1710
1711         return OPERATOR_FINISHED;
1712 }
1713
1714 void NODE_OT_switch_view_update(wmOperatorType *ot)
1715 {
1716         /* identifiers */
1717         ot->name = "Update Views";
1718         ot->description = "Update views of selected node";
1719         ot->idname = "NODE_OT_switch_view_update";
1720
1721         /* api callbacks */
1722         ot->exec = node_switch_view_exec;
1723         ot->poll = node_switch_view_poll;
1724
1725         /* flags */
1726         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1727 }
1728
1729 /* ****************** Delete with reconnect ******************* */
1730 static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
1731 {
1732         SpaceNode *snode = CTX_wm_space_node(C);
1733         bNode *node, *next;
1734
1735         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1736
1737         for (node = snode->edittree->nodes.first; node; node = next) {
1738                 next = node->next;
1739                 if (node->flag & SELECT) {
1740                         nodeInternalRelink(snode->edittree, node);
1741
1742                         /* check id user here, nodeFreeNode is called for free dbase too */
1743                         if (node->id)
1744                                 id_us_min(node->id);
1745                         nodeFreeNode(snode->edittree, node);
1746                 }
1747         }
1748
1749         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
1750
1751         snode_notify(C, snode);
1752         snode_dag_update(C, snode);
1753
1754         return OPERATOR_FINISHED;
1755 }
1756
1757 void NODE_OT_delete_reconnect(wmOperatorType *ot)
1758 {
1759         /* identifiers */
1760         ot->name = "Delete with Reconnect";
1761         ot->description = "Delete nodes; will reconnect nodes as if deletion was muted";
1762         ot->idname = "NODE_OT_delete_reconnect";
1763
1764         /* api callbacks */
1765         ot->exec = node_delete_reconnect_exec;
1766         ot->poll = ED_operator_node_editable;
1767
1768         /* flags */
1769         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1770 }
1771
1772
1773 /* ****************** File Output Add Socket  ******************* */
1774
1775 static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
1776 {
1777         Scene *scene = CTX_data_scene(C);
1778         SpaceNode *snode = CTX_wm_space_node(C);
1779         PointerRNA ptr = CTX_data_pointer_get(C, "node");
1780         bNodeTree *ntree = NULL;
1781         bNode *node = NULL;
1782         char file_path[MAX_NAME];
1783
1784         if (ptr.data) {
1785                 node = ptr.data;
1786                 ntree = ptr.id.data;
1787         }
1788         else if (snode && snode->edittree) {
1789                 ntree = snode->edittree;
1790                 node = nodeGetActive(snode->edittree);
1791         }
1792
1793         if (!node || node->type != CMP_NODE_OUTPUT_FILE)
1794                 return OPERATOR_CANCELLED;
1795
1796         RNA_string_get(op->ptr, "file_path", file_path);
1797         ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
1798
1799         snode_notify(C, snode);
1800
1801         return OPERATOR_FINISHED;
1802 }
1803
1804 void NODE_OT_output_file_add_socket(wmOperatorType *ot)
1805 {
1806         /* identifiers */
1807         ot->name = "Add File Node Socket";
1808         ot->description = "Add a new input to a file output node";
1809         ot->idname = "NODE_OT_output_file_add_socket";
1810
1811         /* callbacks */
1812         ot->exec = node_output_file_add_socket_exec;
1813         ot->poll = composite_node_editable;
1814
1815         /* flags */
1816         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1817
1818         RNA_def_string(ot->srna, "file_path", "Image", MAX_NAME, "File Path", "Sub-path of the output file");
1819 }
1820
1821 /* ****************** Multi File Output Remove Socket  ******************* */
1822
1823 static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *UNUSED(op))
1824 {
1825         SpaceNode *snode = CTX_wm_space_node(C);
1826         PointerRNA ptr = CTX_data_pointer_get(C, "node");
1827         bNodeTree *ntree = NULL;
1828         bNode *node = NULL;
1829
1830         if (ptr.data) {
1831                 node = ptr.data;
1832                 ntree = ptr.id.data;
1833         }
1834         else if (snode && snode->edittree) {
1835                 ntree = snode->edittree;
1836                 node = nodeGetActive(snode->edittree);
1837         }
1838
1839         if (!node || node->type != CMP_NODE_OUTPUT_FILE)
1840                 return OPERATOR_CANCELLED;
1841
1842         if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node))
1843                 return OPERATOR_CANCELLED;
1844
1845         snode_notify(C, snode);
1846
1847         return OPERATOR_FINISHED;
1848 }
1849
1850 void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot)
1851 {
1852         /* identifiers */
1853         ot->name = "Remove File Node Socket";
1854         ot->description = "Remove active input from a file output node";
1855         ot->idname = "NODE_OT_output_file_remove_active_socket";
1856
1857         /* callbacks */
1858         ot->exec = node_output_file_remove_active_socket_exec;
1859         ot->poll = composite_node_editable;
1860
1861         /* flags */
1862         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1863 }
1864
1865 /* ****************** Multi File Output Move Socket  ******************* */
1866
1867 static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
1868 {
1869         SpaceNode *snode = CTX_wm_space_node(C);
1870         PointerRNA ptr = CTX_data_pointer_get(C, "node");
1871         bNode *node = NULL;
1872         NodeImageMultiFile *nimf;
1873         bNodeSocket *sock;
1874         int direction;
1875
1876         if (ptr.data)
1877                 node = ptr.data;
1878         else if (snode && snode->edittree)
1879                 node = nodeGetActive(snode->edittree);
1880
1881         if (!node || node->type != CMP_NODE_OUTPUT_FILE)
1882                 return OPERATOR_CANCELLED;
1883
1884         nimf = node->storage;
1885
1886         sock = BLI_findlink(&node->inputs, nimf->active_input);
1887         if (!sock)
1888                 return OPERATOR_CANCELLED;
1889
1890         direction = RNA_enum_get(op->ptr, "direction");
1891
1892         if (direction == 1) {
1893                 bNodeSocket *before = sock->prev;
1894                 if (!before)
1895                         return OPERATOR_CANCELLED;
1896                 BLI_remlink(&node->inputs, sock);
1897                 BLI_insertlinkbefore(&node->inputs, before, sock);
1898                 nimf->active_input--;
1899         }
1900         else {
1901                 bNodeSocket *after = sock->next;
1902                 if (!after)
1903                         return OPERATOR_CANCELLED;
1904                 BLI_remlink(&node->inputs, sock);
1905                 BLI_insertlinkafter(&node->inputs, after, sock);
1906                 nimf->active_input++;
1907         }
1908
1909         snode_notify(C, snode);
1910
1911         return OPERATOR_FINISHED;
1912 }
1913
1914 void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
1915 {
1916         static const EnumPropertyItem direction_items[] = {
1917                 {1, "UP", 0, "Up", ""},
1918                 {2, "DOWN", 0, "Down", ""},
1919                 { 0, NULL, 0, NULL, NULL }
1920         };
1921
1922         /* identifiers */
1923         ot->name = "Move File Node Socket";
1924         ot->description = "Move the active input of a file output node up or down the list";
1925         ot->idname = "NODE_OT_output_file_move_active_socket";
1926
1927         /* callbacks */
1928         ot->exec = node_output_file_move_active_socket_exec;
1929         ot->poll = composite_node_editable;
1930
1931         /* flags */
1932         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1933
1934         RNA_def_enum(ot->srna, "direction", direction_items, 2, "Direction", "");
1935 }
1936
1937 /* ****************** Copy Node Color ******************* */
1938
1939 static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
1940 {
1941         SpaceNode *snode = CTX_wm_space_node(C);
1942         bNodeTree *ntree = snode->edittree;
1943         bNode *node, *tnode;
1944
1945         if (!ntree)
1946                 return OPERATOR_CANCELLED;
1947         node = nodeGetActive(ntree);
1948         if (!node)
1949                 return OPERATOR_CANCELLED;
1950
1951         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
1952                 if (tnode->flag & NODE_SELECT && tnode != node) {
1953                         if (node->flag & NODE_CUSTOM_COLOR) {
1954                                 tnode->flag |= NODE_CUSTOM_COLOR;
1955                                 copy_v3_v3(tnode->color, node->color);
1956                         }
1957                         else
1958                                 tnode->flag &= ~NODE_CUSTOM_COLOR;
1959                 }
1960         }
1961
1962         ED_node_sort(ntree);
1963         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
1964
1965         return OPERATOR_FINISHED;
1966 }
1967
1968 void NODE_OT_node_copy_color(wmOperatorType *ot)
1969 {
1970         /* identifiers */
1971         ot->name = "Copy Color";
1972         ot->description = "Copy color to all selected nodes";
1973         ot->idname = "NODE_OT_node_copy_color";
1974
1975         /* api callbacks */
1976         ot->exec = node_copy_color_exec;
1977         ot->poll = ED_operator_node_editable;
1978
1979         /* flags */
1980         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1981 }
1982
1983 /* ****************** Copy to clipboard ******************* */
1984
1985 static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
1986 {
1987         SpaceNode *snode = CTX_wm_space_node(C);
1988         bNodeTree *ntree = snode->edittree;
1989         bNode *node;
1990         bNodeLink *link, *newlink;
1991
1992         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
1993
1994         /* clear current clipboard */
1995         BKE_node_clipboard_clear();
1996         BKE_node_clipboard_init(ntree);
1997
1998         for (node = ntree->nodes.first; node; node = node->next) {
1999                 if (node->flag & SELECT) {
2000                         bNode *new_node;
2001                         new_node = nodeCopyNode(NULL, node);
2002                         BKE_node_clipboard_add_node(new_node);
2003                 }
2004         }
2005
2006         for (node = ntree->nodes.first; node; node = node->next) {
2007                 if (node->flag & SELECT) {
2008                         bNode *new_node = node->new_node;
2009
2010                         /* ensure valid pointers */
2011                         if (new_node->parent) {
2012                                 /* parent pointer must be redirected to new node or detached if parent is
2013                                  * not copied */
2014                                 if (new_node->parent->flag & NODE_SELECT) {
2015                                         new_node->parent = new_node->parent->new_node;
2016                                 }
2017                                 else {
2018                                         nodeDetachNode(new_node);
2019                                 }
2020                         }
2021                 }
2022         }
2023
2024         /* copy links between selected nodes
2025          * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
2026          */
2027         for (link = ntree->links.first; link; link = link->next) {
2028                 /* This creates new links between copied nodes. */
2029                 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
2030                     link->fromnode && (link->fromnode->flag & NODE_SELECT))
2031                 {
2032                         newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
2033                         newlink->flag = link->flag;
2034                         newlink->tonode = link->tonode->new_node;
2035                         newlink->tosock = link->tosock->new_sock;
2036                         newlink->fromnode = link->fromnode->new_node;
2037                         newlink->fromsock = link->fromsock->new_sock;
2038
2039                         BKE_node_clipboard_add_link(newlink);
2040                 }
2041         }
2042
2043         return OPERATOR_FINISHED;
2044 }
2045
2046 void NODE_OT_clipboard_copy(wmOperatorType *ot)
2047 {
2048         /* identifiers */
2049         ot->name = "Copy to Clipboard";
2050         ot->description = "Copies selected nodes to the clipboard";
2051         ot->idname = "NODE_OT_clipboard_copy";
2052
2053         /* api callbacks */
2054         ot->exec = node_clipboard_copy_exec;
2055         ot->poll = ED_operator_node_active;
2056
2057         /* flags */
2058         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2059 }
2060
2061 /* ****************** Paste from clipboard ******************* */
2062
2063 static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
2064 {
2065         SpaceNode *snode = CTX_wm_space_node(C);
2066         bNodeTree *ntree = snode->edittree;
2067         const ListBase *clipboard_nodes_lb;
2068         const ListBase *clipboard_links_lb;
2069         bNode *node;
2070         bNodeLink *link;
2071         int num_nodes;
2072         float center[2];
2073         bool is_clipboard_valid, all_nodes_valid;
2074
2075         /* validate pointers in the clipboard */
2076         is_clipboard_valid = BKE_node_clipboard_validate();
2077         clipboard_nodes_lb = BKE_node_clipboard_get_nodes();
2078         clipboard_links_lb = BKE_node_clipboard_get_links();
2079
2080         if (BLI_listbase_is_empty(clipboard_nodes_lb)) {
2081                 BKE_report(op->reports, RPT_ERROR, "Clipboard is empty");
2082                 return OPERATOR_CANCELLED;
2083         }
2084
2085         if (BKE_node_clipboard_get_type() != ntree->type) {
2086                 BKE_report(op->reports, RPT_ERROR, "Clipboard nodes are an incompatible type");
2087                 return OPERATOR_CANCELLED;
2088         }
2089
2090         /* only warn */
2091         if (is_clipboard_valid == false) {
2092                 BKE_report(op->reports, RPT_WARNING, "Some nodes references could not be restored, will be left empty");
2093         }
2094
2095         /* make sure all clipboard nodes would be valid in the target tree */
2096         all_nodes_valid = true;
2097         for (node = clipboard_nodes_lb->first; node; node = node->next) {
2098                 if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) {
2099                         all_nodes_valid = false;
2100                         BKE_reportf(op->reports, RPT_ERROR, "Cannot add node %s into node tree %s", node->name, ntree->id.name + 2);
2101                 }
2102         }
2103         if (!all_nodes_valid)
2104                 return OPERATOR_CANCELLED;
2105
2106         ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
2107
2108         /* deselect old nodes */
2109         node_deselect_all(snode);
2110
2111         /* calculate "barycenter" for placing on mouse cursor */
2112         zero_v2(center);
2113         for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) {
2114                 center[0] += BLI_rctf_cent_x(&node->totr);
2115                 center[1] += BLI_rctf_cent_y(&node->totr);
2116         }
2117         mul_v2_fl(center, 1.0 / num_nodes);
2118
2119         /* copy nodes from clipboard */
2120         for (node = clipboard_nodes_lb->first; node; node = node->next) {
2121                 bNode *new_node = nodeCopyNode(ntree, node);
2122
2123                 /* needed since nodeCopyNode() doesn't increase ID's */
2124                 id_us_plus(node->id);
2125
2126                 /* pasted nodes are selected */
2127                 nodeSetSelected(new_node, true);
2128         }
2129
2130         /* reparent copied nodes */
2131         for (node = clipboard_nodes_lb->first; node; node = node->next) {
2132                 bNode *new_node = node->new_node;
2133                 if (new_node->parent)
2134                         new_node->parent = new_node->parent->new_node;
2135         }
2136
2137         for (link = clipboard_links_lb->first; link; link = link->next) {
2138                 nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock,
2139                             link->tonode->new_node, link->tosock->new_sock);
2140         }
2141
2142         ntreeUpdateTree(CTX_data_main(C), snode->edittree);
2143
2144         snode_notify(C, snode);
2145         snode_dag_update(C, snode);
2146
2147         return OPERATOR_FINISHED;
2148 }
2149
2150 void NODE_OT_clipboard_paste(wmOperatorType *ot)
2151 {
2152         /* identifiers */
2153         ot->name = "Paste from Clipboard";
2154         ot->description = "Pastes nodes from the clipboard to the active node tree";
2155         ot->idname = "NODE_OT_clipboard_paste";
2156
2157         /* api callbacks */
2158         ot->exec = node_clipboard_paste_exec;
2159         ot->poll = ED_operator_node_editable;
2160
2161         /* flags */
2162         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2163 }
2164
2165 /********************** Add interface socket operator *********************/
2166
2167 static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb)
2168 {
2169         bNodeSocket *sock;
2170         for (sock = lb->first; sock; sock = sock->next)
2171                 if (sock->flag & SELECT)
2172                         return sock;
2173         return NULL;
2174 }
2175
2176 static int ntree_socket_add_exec(bContext *C, wmOperator *op)
2177 {
2178         SpaceNode *snode = CTX_wm_space_node(C);
2179         bNodeTree *ntree = snode->edittree;
2180         int in_out = RNA_enum_get(op->ptr, "in_out");
2181         PointerRNA ntree_ptr;
2182         bNodeSocket *sock, *tsock, *active_sock;
2183         const char *default_name;
2184
2185         RNA_id_pointer_create((ID *)ntree, &ntree_ptr);
2186
2187         if (in_out == SOCK_IN) {
2188                 active_sock = ntree_get_active_interface_socket(&ntree->inputs);
2189                 default_name = "Input";
2190         }
2191         else {
2192                 active_sock = ntree_get_active_interface_socket(&ntree->outputs);
2193                 default_name = "Output";
2194         }
2195
2196         if (active_sock) {
2197                 /* insert a copy of the active socket right after it */
2198                 sock = ntreeInsertSocketInterface(ntree, in_out, active_sock->idname, active_sock->next, active_sock->name);
2199                 /* XXX this only works for actual sockets, not interface templates! */
2200                 /*nodeSocketCopyValue(sock, &ntree_ptr, active_sock, &ntree_ptr);*/
2201         }
2202         else {
2203                 /* XXX TODO define default socket type for a tree! */
2204                 sock = ntreeAddSocketInterface(ntree, in_out, "NodeSocketFloat", default_name);
2205         }
2206
2207         /* deactivate sockets (has to check both lists) */
2208         for (tsock = ntree->inputs.first; tsock; tsock = tsock->next)
2209                 tsock->flag &= ~SELECT;
2210         for (tsock = ntree->outputs.first; tsock; tsock = tsock->next)
2211                 tsock->flag &= ~SELECT;
2212         /* make the new socket active */
2213         sock->flag |= SELECT;
2214
2215         ntreeUpdateTree(CTX_data_main(C), ntree);
2216
2217         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2218
2219         return OPERATOR_FINISHED;
2220 }
2221
2222 void NODE_OT_tree_socket_add(wmOperatorType *ot)
2223 {
2224         /* identifiers */
2225         ot->name = "Add Node Tree Interface Socket";
2226         ot->description = "Add an input or output socket to the current node tree";
2227         ot->idname = "NODE_OT_tree_socket_add";
2228
2229         /* api callbacks */
2230         ot->exec = ntree_socket_add_exec;
2231         ot->poll = ED_operator_node_editable;
2232
2233         /* flags */
2234         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2235
2236         RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
2237 }
2238
2239 /********************** Remove interface socket operator *********************/
2240
2241 static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op))
2242 {
2243         SpaceNode *snode = CTX_wm_space_node(C);
2244         bNodeTree *ntree = snode->edittree;
2245         bNodeSocket *iosock, *active_sock;
2246
2247         iosock = ntree_get_active_interface_socket(&ntree->inputs);
2248         if (!iosock)
2249                 iosock = ntree_get_active_interface_socket(&ntree->outputs);
2250         if (!iosock)
2251                 return OPERATOR_CANCELLED;
2252
2253         /* preferably next socket becomes active, otherwise try previous socket */
2254         active_sock = (iosock->next ? iosock->next : iosock->prev);
2255         ntreeRemoveSocketInterface(ntree, iosock);
2256
2257         /* set active socket */
2258         if (active_sock)
2259                 active_sock->flag |= SELECT;
2260
2261         ntreeUpdateTree(CTX_data_main(C), ntree);
2262
2263         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2264
2265         return OPERATOR_FINISHED;
2266 }
2267
2268 void NODE_OT_tree_socket_remove(wmOperatorType *ot)
2269 {
2270         /* identifiers */
2271         ot->name = "Remove Node Tree Interface Socket";
2272         ot->description = "Remove an input or output socket to the current node tree";
2273         ot->idname = "NODE_OT_tree_socket_remove";
2274
2275         /* api callbacks */
2276         ot->exec = ntree_socket_remove_exec;
2277         ot->poll = ED_operator_node_editable;
2278
2279         /* flags */
2280         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2281 }
2282
2283 /********************** Move interface socket operator *********************/
2284
2285 static const EnumPropertyItem move_direction_items[] = {
2286         { 1, "UP", 0, "Up", "" },
2287         { 2, "DOWN", 0, "Down", "" },
2288         { 0, NULL, 0, NULL, NULL },
2289 };
2290
2291 static int ntree_socket_move_exec(bContext *C, wmOperator *op)
2292 {
2293         SpaceNode *snode = CTX_wm_space_node(C);
2294         bNodeTree *ntree = snode->edittree;
2295         int direction = RNA_enum_get(op->ptr, "direction");
2296         bNodeSocket *iosock;
2297         ListBase *lb;
2298
2299         lb = &ntree->inputs;
2300         iosock = ntree_get_active_interface_socket(lb);
2301         if (!iosock) {
2302                 lb = &ntree->outputs;
2303                 iosock = ntree_get_active_interface_socket(lb);
2304         }
2305         if (!iosock)
2306                 return OPERATOR_CANCELLED;
2307
2308         switch (direction) {
2309                 case 1:
2310                 {       /* up */
2311                         bNodeSocket *before = iosock->prev;
2312                         BLI_remlink(lb, iosock);
2313                         if (before)
2314                                 BLI_insertlinkbefore(lb, before, iosock);
2315                         else
2316                                 BLI_addhead(lb, iosock);
2317                         break;
2318                 }
2319                 case 2:
2320                 {       /* down */
2321                         bNodeSocket *after = iosock->next;
2322                         BLI_remlink(lb, iosock);
2323                         if (after)
2324                                 BLI_insertlinkafter(lb, after, iosock);
2325                         else
2326                                 BLI_addtail(lb, iosock);
2327                         break;
2328                 }
2329         }
2330
2331         ntreeUpdateTree(CTX_data_main(C), ntree);
2332
2333         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2334
2335         return OPERATOR_FINISHED;
2336 }
2337
2338 void NODE_OT_tree_socket_move(wmOperatorType *ot)
2339 {
2340         /* identifiers */
2341         ot->name = "Move Node Tree Socket";
2342         ot->description = "Move a socket up or down in the current node tree's sockets stack";
2343         ot->idname = "NODE_OT_tree_socket_move";
2344
2345         /* api callbacks */
2346         ot->exec = ntree_socket_move_exec;
2347         ot->poll = ED_operator_node_editable;
2348
2349         /* flags */
2350         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2351
2352         RNA_def_enum(ot->srna, "direction", move_direction_items, 1, "Direction", "");
2353 }
2354
2355 /* ********************** Shader Script Update ******************/
2356
2357 static bool node_shader_script_update_poll(bContext *C)
2358 {
2359         Scene *scene = CTX_data_scene(C);
2360         RenderEngineType *type = RE_engines_find(scene->r.engine);
2361         SpaceNode *snode = CTX_wm_space_node(C);
2362         bNode *node;
2363         Text *text;
2364
2365         /* test if we have a render engine that supports shaders scripts */
2366         if (!(type && type->update_script_node))
2367                 return 0;
2368
2369         /* see if we have a shader script node in context */
2370         node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
2371
2372         if (!node && snode && snode->edittree)
2373                 node = nodeGetActive(snode->edittree);
2374
2375         if (node && node->type == SH_NODE_SCRIPT) {
2376                 NodeShaderScript *nss = node->storage;
2377
2378                 if (node->id || nss->filepath[0]) {
2379                         return ED_operator_node_editable(C);
2380                 }
2381         }
2382
2383         /* see if we have a text datablock in context */
2384         text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2385         if (text)
2386                 return 1;
2387
2388         /* we don't check if text datablock is actually in use, too slow for poll */
2389
2390         return 0;
2391 }
2392
2393 /* recursively check for script nodes in groups using this text and update */
2394 static bool node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text)
2395 {
2396         bool found = false;
2397         bNode *node;
2398
2399         ntree->done = true;
2400
2401         /* update each script that is using this text datablock */
2402         for (node = ntree->nodes.first; node; node = node->next) {
2403                 if (node->type == NODE_GROUP) {
2404                         bNodeTree *ngroup = (bNodeTree *)node->id;
2405                         if (ngroup && !ngroup->done)
2406                                 found |= node_shader_script_update_text_recursive(engine, type, ngroup, text);
2407                 }
2408                 else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) {
2409                         type->update_script_node(engine, ntree, node);
2410                         found = true;
2411                 }
2412         }
2413
2414         return found;
2415 }
2416
2417 static int node_shader_script_update_exec(bContext *C, wmOperator *op)
2418 {
2419         Main *bmain = CTX_data_main(C);
2420         Scene *scene = CTX_data_scene(C);
2421         SpaceNode *snode = CTX_wm_space_node(C);
2422         PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
2423         bNodeTree *ntree_base = NULL;
2424         bNode *node = NULL;
2425         RenderEngine *engine;
2426         RenderEngineType *type;
2427         bool found = false;
2428
2429         /* setup render engine */
2430         type = RE_engines_find(scene->r.engine);
2431         engine = RE_engine_create(type);
2432         engine->reports = op->reports;
2433
2434         /* get node */
2435         if (nodeptr.data) {
2436                 ntree_base = nodeptr.id.data;
2437                 node = nodeptr.data;
2438         }
2439         else if (snode && snode->edittree) {
2440                 ntree_base = snode->edittree;
2441                 node = nodeGetActive(snode->edittree);
2442         }
2443
2444         if (node) {
2445                 /* update single node */
2446                 type->update_script_node(engine, ntree_base, node);
2447
2448                 found = true;
2449         }
2450         else {
2451                 /* update all nodes using text datablock */
2452                 Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data;
2453
2454                 if (text) {
2455                         /* clear flags for recursion check */
2456                         FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
2457                                 if (ntree->type == NTREE_SHADER)
2458                                         ntree->done = false;
2459                         } FOREACH_NODETREE_END;
2460
2461                         FOREACH_NODETREE_BEGIN(bmain, ntree, id) {
2462                                 if (ntree->type == NTREE_SHADER) {
2463                                         if (!ntree->done)
2464                                                 found |= node_shader_script_update_text_recursive(engine, type, ntree, text);
2465                                 }
2466                         } FOREACH_NODETREE_END;
2467
2468                         if (!found)
2469                                 BKE_report(op->reports, RPT_INFO, "Text not used by any node, no update done");
2470                 }
2471         }
2472
2473         RE_engine_free(engine);
2474
2475         return (found) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
2476 }
2477
2478 void NODE_OT_shader_script_update(wmOperatorType *ot)
2479 {
2480         /* identifiers */
2481         ot->name = "Script Node Update";
2482         ot->description = "Update shader script node with new sockets and options from the script";
2483         ot->idname = "NODE_OT_shader_script_update";
2484
2485         /* api callbacks */
2486         ot->exec = node_shader_script_update_exec;
2487         ot->poll = node_shader_script_update_poll;
2488
2489         /* flags */
2490         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2491 }
2492
2493 /* ********************** Viewer border ******************/
2494
2495 static void viewer_border_corner_to_backdrop(SpaceNode *snode, ARegion *ar, int x, int y,
2496                                              int backdrop_width, int backdrop_height,
2497                                              float *fx, float *fy)
2498 {
2499         float bufx, bufy;
2500
2501         bufx = backdrop_width * snode->zoom;
2502         bufy = backdrop_height * snode->zoom;
2503
2504         *fx = (bufx > 0.0f ? ((float) x - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
2505         *fy = (bufy > 0.0f ? ((float) y - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
2506 }
2507
2508 static int viewer_border_exec(bContext *C, wmOperator *op)
2509 {
2510         Main *bmain = CTX_data_main(C);
2511         Image *ima;
2512         void *lock;
2513         ImBuf *ibuf;
2514
2515         ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
2516
2517         ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
2518         ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
2519
2520         if (ibuf) {
2521                 ARegion *ar = CTX_wm_region(C);
2522                 SpaceNode *snode = CTX_wm_space_node(C);
2523                 bNodeTree *btree = snode->nodetree;
2524                 rcti rect;
2525                 rctf rectf;
2526
2527                 /* get border from operator */
2528                 WM_operator_properties_border_to_rcti(op, &rect);
2529
2530                 /* convert border to unified space within backdrop image */
2531                 viewer_border_corner_to_backdrop(snode, ar, rect.xmin, rect.ymin, ibuf->x, ibuf->y,
2532                                                  &rectf.xmin, &rectf.ymin);
2533
2534                 viewer_border_corner_to_backdrop(snode, ar, rect.xmax, rect.ymax, ibuf->x, ibuf->y,
2535                                                  &rectf.xmax, &rectf.ymax);
2536
2537                 /* clamp coordinates */
2538                 rectf.xmin = max_ff(rectf.xmin, 0.0f);
2539                 rectf.ymin = max_ff(rectf.ymin, 0.0f);
2540                 rectf.xmax = min_ff(rectf.xmax, 1.0f);
2541                 rectf.ymax = min_ff(rectf.ymax, 1.0f);
2542
2543                 if (rectf.xmin < rectf.xmax && rectf.ymin < rectf.ymax) {
2544                         btree->viewer_border = rectf;
2545
2546                         if (rectf.xmin == 0.0f && rectf.ymin == 0.0f &&
2547                             rectf.xmax == 1.0f && rectf.ymax == 1.0f)
2548                         {
2549                                 btree->flag &= ~NTREE_VIEWER_BORDER;
2550                         }
2551                         else {
2552                                 btree->flag |= NTREE_VIEWER_BORDER;
2553                         }
2554
2555                         snode_notify(C, snode);
2556                         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2557                 }
2558                 else {
2559                         btree->flag &= ~NTREE_VIEWER_BORDER;
2560                 }
2561         }
2562
2563         BKE_image_release_ibuf(ima, ibuf, lock);
2564
2565         return OPERATOR_FINISHED;
2566 }
2567
2568 void NODE_OT_viewer_border(wmOperatorType *ot)
2569 {
2570         /* identifiers */
2571         ot->name = "Viewer Border";
2572         ot->description = "Set the boundaries for viewer operations";
2573         ot->idname = "NODE_OT_viewer_border";
2574
2575         /* api callbacks */
2576         ot->invoke = WM_gesture_border_invoke;
2577         ot->exec = viewer_border_exec;
2578         ot->modal = WM_gesture_border_modal;
2579         ot->cancel = WM_gesture_border_cancel;
2580         ot->poll = composite_node_active;
2581
2582         /* flags */
2583         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2584
2585         /* properties */
2586         WM_operator_properties_gesture_border_select(ot);
2587 }
2588
2589 static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
2590 {
2591         SpaceNode *snode = CTX_wm_space_node(C);
2592         bNodeTree *btree = snode->nodetree;
2593
2594         btree->flag &= ~NTREE_VIEWER_BORDER;
2595         snode_notify(C, snode);
2596         WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
2597
2598         return OPERATOR_FINISHED;
2599 }
2600
2601 void NODE_OT_clear_viewer_border(wmOperatorType *ot)
2602 {
2603         /* identifiers */
2604         ot->name = "Clear Viewer Border";
2605         ot->description = "Clear the boundaries for viewer operations";
2606         ot->idname = "NODE_OT_clear_viewer_border";
2607
2608         /* api callbacks */
2609         ot->exec = clear_viewer_border_exec;
2610         ot->poll = composite_node_active;
2611
2612         /* flags */
2613         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2614 }
2615
2616 /* ****************** Cryptomatte Add Socket  ******************* */
2617
2618 static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
2619 {
2620         SpaceNode *snode = CTX_wm_space_node(C);
2621         PointerRNA ptr = CTX_data_pointer_get(C, "node");
2622         bNodeTree *ntree = NULL;
2623         bNode *node = NULL;
2624
2625         if (ptr.data) {
2626                 node = ptr.data;
2627                 ntree = ptr.id.data;
2628         }
2629         else if (snode && snode->edittree) {
2630                 ntree = snode->edittree;
2631                 node = nodeGetActive(snode->edittree);
2632         }
2633
2634         if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
2635                 return OPERATOR_CANCELLED;
2636         }
2637
2638         ntreeCompositCryptomatteAddSocket(ntree, node);
2639
2640         snode_notify(C, snode);
2641
2642         return OPERATOR_FINISHED;
2643 }
2644
2645 void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
2646 {
2647         /* identifiers */
2648         ot->name = "Add Cryptomatte Socket";
2649         ot->description = "Add a new input layer to a Cryptomatte node";
2650         ot->idname = "NODE_OT_cryptomatte_layer_add";
2651
2652         /* callbacks */
2653         ot->exec = node_cryptomatte_add_socket_exec;
2654         ot->poll = composite_node_editable;
2655
2656         /* flags */
2657         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2658 }
2659
2660 /* ****************** Cryptomatte Remove Socket  ******************* */
2661
2662 static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(op))
2663 {
2664         SpaceNode *snode = CTX_wm_space_node(C);
2665         PointerRNA ptr = CTX_data_pointer_get(C, "node");
2666         bNodeTree *ntree = NULL;
2667         bNode *node = NULL;
2668
2669         if (ptr.data) {
2670                 node = ptr.data;
2671                 ntree = ptr.id.data;
2672         }
2673         else if (snode && snode->edittree) {
2674                 ntree = snode->edittree;
2675                 node = nodeGetActive(snode->edittree);
2676         }
2677
2678         if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
2679                 return OPERATOR_CANCELLED;
2680         }
2681
2682         if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
2683                 return OPERATOR_CANCELLED;
2684         }
2685
2686         snode_notify(C, snode);
2687
2688         return OPERATOR_FINISHED;
2689 }
2690
2691 void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
2692 {
2693         /* identifiers */
2694         ot->name = "Remove Cryptomatte Socket";
2695         ot->description = "Remove layer from a Crytpomatte node";
2696         ot->idname = "NODE_OT_cryptomatte_layer_remove";
2697
2698         /* callbacks */
2699         ot->exec = node_cryptomatte_remove_socket_exec;
2700         ot->poll = composite_node_editable;
2701
2702         /* flags */
2703         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2704 }