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