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