svn merge ^/trunk/blender -r46632:46684
[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
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <math.h>
36 #include <string.h>
37 #include <errno.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_ID.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_particle_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_world_types.h"
49
50 #include "BLI_math.h"
51 #include "BLI_blenlib.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_context.h"
55 #include "BKE_depsgraph.h"
56 #include "BKE_global.h"
57 #include "BKE_image.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_node.h"
61 #include "BKE_material.h"
62 #include "BKE_modifier.h"
63 #include "BKE_paint.h"
64 #include "BKE_scene.h"
65 #include "BKE_screen.h"
66 #include "BKE_texture.h"
67 #include "BKE_report.h"
68
69 #include "RE_pipeline.h"
70
71 #include "IMB_imbuf_types.h"
72
73 #include "ED_node.h"
74 #include "ED_image.h"
75 #include "ED_screen.h"
76 #include "ED_space_api.h"
77 #include "ED_render.h"
78
79 #include "RNA_access.h"
80 #include "RNA_define.h"
81 #include "RNA_enum_types.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "UI_interface.h"
87 #include "UI_resources.h"
88 #include "UI_view2d.h"
89
90 #include "IMB_imbuf.h"
91
92 #include "RNA_enum_types.h"
93
94 #include "GPU_material.h"
95
96 #include "node_intern.h"
97
98 static EnumPropertyItem socket_in_out_items[] = {
99         { SOCK_IN, "SOCK_IN", 0, "Input", "" },
100         { SOCK_OUT, "SOCK_OUT", 0, "Output", "" },
101         { 0, NULL, 0, NULL, NULL },
102 };
103
104 /* ***************** composite job manager ********************** */
105
106 typedef struct CompoJob {
107         Scene *scene;
108         bNodeTree *ntree;
109         bNodeTree *localtree;
110         short *stop;
111         short *do_update;
112         float *progress;
113 } CompoJob;
114
115 /* called by compo, only to check job 'stop' value */
116 static int compo_breakjob(void *cjv)
117 {
118         CompoJob *cj= cjv;
119         
120         return *(cj->stop);
121 }
122
123 /* called by compo, wmJob sends notifier */
124 static void compo_redrawjob(void *cjv, char *UNUSED(str))
125 {
126         CompoJob *cj= cjv;
127         
128         *(cj->do_update)= 1;
129 }
130
131 static void compo_freejob(void *cjv)
132 {
133         CompoJob *cj= cjv;
134
135         if (cj->localtree) {
136                 ntreeLocalMerge(cj->localtree, cj->ntree);
137         }
138         MEM_freeN(cj);
139 }
140
141 /* only now we copy the nodetree, so adding many jobs while
142  * sliding buttons doesn't frustrate */
143 static void compo_initjob(void *cjv)
144 {
145         CompoJob *cj= cjv;
146
147         cj->localtree= ntreeLocalize(cj->ntree);
148 }
149
150 /* called before redraw notifiers, it moves finished previews over */
151 static void compo_updatejob(void *cjv)
152 {
153         CompoJob *cj= cjv;
154         
155         ntreeLocalSync(cj->localtree, cj->ntree);
156 }
157
158 static void compo_progressjob(void *cjv, float progress)
159 {
160         CompoJob *cj= cjv;
161         
162         *(cj->progress) = progress;
163 }
164
165
166 /* only this runs inside thread */
167 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
168 {
169         CompoJob *cj= cjv;
170         bNodeTree *ntree= cj->localtree;
171
172         if (cj->scene->use_nodes==0)
173                 return;
174         
175         cj->stop= stop;
176         cj->do_update= do_update;
177         cj->progress= progress;
178         
179         ntree->test_break= compo_breakjob;
180         ntree->tbh= cj;
181         ntree->stats_draw= compo_redrawjob;
182         ntree->sdh= cj;
183         ntree->progress= compo_progressjob;
184         ntree->prh= cj;
185         
186         // XXX BIF_store_spare();
187         
188         ntreeCompositExecTree(ntree, &cj->scene->r, 1); /* 1 is do_previews */
189         
190         ntree->test_break= NULL;
191         ntree->stats_draw= NULL;
192         ntree->progress= NULL;
193
194 }
195
196 void snode_composite_job(const bContext *C, ScrArea *sa)
197 {
198         SpaceNode *snode= sa->spacedata.first;
199         wmJob *steve;
200         CompoJob *cj;
201
202         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Compositing", WM_JOB_EXCL_RENDER|WM_JOB_PROGRESS);
203         cj= MEM_callocN(sizeof(CompoJob), "compo job");
204         
205         /* customdata for preview thread */
206         cj->scene= CTX_data_scene(C);
207         cj->ntree= snode->nodetree;
208         
209         /* setup job */
210         WM_jobs_customdata(steve, cj, compo_freejob);
211         WM_jobs_timer(steve, 0.1, NC_SCENE, NC_SCENE|ND_COMPO_RESULT);
212         WM_jobs_callbacks(steve, compo_startjob, compo_initjob, compo_updatejob, NULL);
213         
214         WM_jobs_start(CTX_wm_manager(C), steve);
215         
216 }
217
218 /* ***************************************** */
219
220 /* operator poll callback */
221 static int composite_node_active(bContext *C)
222 {
223         if ( ED_operator_node_active(C)) {
224                 SpaceNode *snode= CTX_wm_space_node(C);
225                 if (snode->treetype==NTREE_COMPOSIT)
226                         return 1;
227         }
228         return 0;
229 }
230
231 /* also checks for edited groups */
232 static bNode *editnode_get_active(bNodeTree *ntree)
233 {
234         bNode *node;
235         
236         /* check for edited group */
237         for (node= ntree->nodes.first; node; node= node->next)
238                 if (nodeGroupEditGet(node))
239                         break;
240         if (node)
241                 return nodeGetActive((bNodeTree *)node->id);
242         else
243                 return nodeGetActive(ntree);
244 }
245
246 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
247 {
248         bNode *node;
249         
250         if (ntree == lookup)
251                 return 1;
252         
253         for (node=ntree->nodes.first; node; node=node->next)
254                 if (node->type == NODE_GROUP && node->id)
255                         if (has_nodetree((bNodeTree*)node->id, lookup))
256                                 return 1;
257         
258         return 0;
259 }
260
261 static void snode_dag_update_group(void *calldata, ID *owner_id, bNodeTree *ntree)
262 {
263         if (has_nodetree(ntree, calldata))
264                 DAG_id_tag_update(owner_id, 0);
265 }
266
267 void snode_dag_update(bContext *C, SpaceNode *snode)
268 {
269         Main *bmain = CTX_data_main(C);
270
271         /* for groups, update all ID's using this */
272         if (snode->edittree!=snode->nodetree) {
273                 bNodeTreeType *tti= ntreeGetType(snode->edittree->type);
274                 tti->foreach_nodetree(bmain, snode->edittree, snode_dag_update_group);
275         }
276
277         DAG_id_tag_update(snode->id, 0);
278 }
279
280 void snode_notify(bContext *C, SpaceNode *snode)
281 {
282         WM_event_add_notifier(C, NC_NODE|NA_EDITED, NULL);
283
284         if (snode->treetype==NTREE_SHADER)
285                 WM_event_add_notifier(C, NC_MATERIAL|ND_NODES, snode->id);
286         else if (snode->treetype==NTREE_COMPOSIT)
287                 WM_event_add_notifier(C, NC_SCENE|ND_NODES, snode->id);
288         else if (snode->treetype==NTREE_TEXTURE)
289                 WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id);
290 }
291
292 bNode *node_tree_get_editgroup(bNodeTree *nodetree)
293 {
294         bNode *gnode;
295         
296         /* get the groupnode */
297         for (gnode= nodetree->nodes.first; gnode; gnode= gnode->next)
298                 if (nodeGroupEditGet(gnode))
299                         break;
300         return gnode;
301 }
302
303 /* assumes nothing being done in ntree yet, sets the default in/out node */
304 /* called from shading buttons or header */
305 void ED_node_shader_default(Scene *scene, ID *id)
306 {
307         bNode *in, *out;
308         bNodeSocket *fromsock, *tosock, *sock;
309         bNodeTree *ntree;
310         bNodeTemplate ntemp;
311         int output_type, shader_type;
312         float color[3], strength = 1.0f;
313         
314         ntree= ntreeAddTree("Shader Nodetree", NTREE_SHADER, 0);
315
316         switch (GS(id->name)) {
317                 case ID_MA: {
318                         Material *ma= (Material*)id;
319                         ma->nodetree = ntree;
320
321                         if (BKE_scene_use_new_shading_nodes(scene)) {
322                                 output_type = SH_NODE_OUTPUT_MATERIAL;
323                                 shader_type = SH_NODE_BSDF_DIFFUSE;
324                         }
325                         else {
326                                 output_type = SH_NODE_OUTPUT;
327                                 shader_type = SH_NODE_MATERIAL;
328                         }
329
330                         copy_v3_v3(color, &ma->r);
331                         strength= 0.0f;
332                         break;
333                 }
334                 case ID_WO: {
335                         World *wo= (World*)id;
336                         wo->nodetree = ntree;
337
338                         output_type = SH_NODE_OUTPUT_WORLD;
339                         shader_type = SH_NODE_BACKGROUND;
340
341                         copy_v3_v3(color, &wo->horr);
342                         strength= 1.0f;
343                         break;
344                 }
345                 case ID_LA: {
346                         Lamp *la= (Lamp*)id;
347                         la->nodetree = ntree;
348
349                         output_type = SH_NODE_OUTPUT_LAMP;
350                         shader_type = SH_NODE_EMISSION;
351
352                         copy_v3_v3(color, &la->r);
353                         if (la->type == LA_LOCAL || la->type == LA_SPOT || la->type == LA_AREA)
354                                 strength= 100.0f;
355                         else
356                                 strength= 1.0f;
357                         break;
358                 }
359                 default:
360                         printf("ED_node_shader_default called on wrong ID type.\n");
361                         return;
362         }
363         
364         ntemp.type = output_type;
365         out= nodeAddNode(ntree, &ntemp);
366         out->locx= 300.0f; out->locy= 300.0f;
367         
368         ntemp.type = shader_type;
369         in= nodeAddNode(ntree, &ntemp);
370         in->locx= 10.0f; in->locy= 300.0f;
371         nodeSetActive(ntree, in);
372         
373         /* only a link from color to color */
374         fromsock= in->outputs.first;
375         tosock= out->inputs.first;
376         nodeAddLink(ntree, in, fromsock, out, tosock);
377
378         /* default values */
379         if (BKE_scene_use_new_shading_nodes(scene)) {
380                 sock= in->inputs.first;
381                 copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, color);
382
383                 if (strength != 0.0f) {
384                         sock= in->inputs.last;
385                         ((bNodeSocketValueFloat*)sock->default_value)->value= strength;
386                 }
387         }
388         
389         ntreeUpdateTree(ntree);
390 }
391
392 /* assumes nothing being done in ntree yet, sets the default in/out node */
393 /* called from shading buttons or header */
394 void ED_node_composit_default(Scene *sce)
395 {
396         bNode *in, *out;
397         bNodeSocket *fromsock, *tosock;
398         bNodeTemplate ntemp;
399         
400         /* but lets check it anyway */
401         if (sce->nodetree) {
402                 if (G.debug & G_DEBUG)
403                         printf("error in composite initialize\n");
404                 return;
405         }
406         
407         sce->nodetree= ntreeAddTree("Compositing Nodetree", NTREE_COMPOSIT, 0);
408         
409         ntemp.type = CMP_NODE_COMPOSITE;
410         out= nodeAddNode(sce->nodetree, &ntemp);
411         out->locx= 300.0f; out->locy= 400.0f;
412         out->id= &sce->id;
413         id_us_plus(out->id);
414         
415         ntemp.type = CMP_NODE_R_LAYERS;
416         in= nodeAddNode(sce->nodetree, &ntemp);
417         in->locx= 10.0f; in->locy= 400.0f;
418         in->id= &sce->id;
419         id_us_plus(in->id);
420         nodeSetActive(sce->nodetree, in);
421         
422         /* links from color to color */
423         fromsock= in->outputs.first;
424         tosock= out->inputs.first;
425         nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
426         
427         ntreeUpdateTree(sce->nodetree);
428         
429         // XXX ntreeCompositForceHidden(sce->nodetree);
430 }
431
432 /* assumes nothing being done in ntree yet, sets the default in/out node */
433 /* called from shading buttons or header */
434 void ED_node_texture_default(Tex *tx)
435 {
436         bNode *in, *out;
437         bNodeSocket *fromsock, *tosock;
438         bNodeTemplate ntemp;
439         
440         /* but lets check it anyway */
441         if (tx->nodetree) {
442                 if (G.debug & G_DEBUG)
443                         printf("error in texture initialize\n");
444                 return;
445         }
446         
447         tx->nodetree= ntreeAddTree("Texture Nodetree", NTREE_TEXTURE, 0);
448         
449         ntemp.type = TEX_NODE_OUTPUT;
450         out= nodeAddNode(tx->nodetree, &ntemp);
451         out->locx= 300.0f; out->locy= 300.0f;
452         
453         ntemp.type = TEX_NODE_CHECKER;
454         in= nodeAddNode(tx->nodetree, &ntemp);
455         in->locx= 10.0f; in->locy= 300.0f;
456         nodeSetActive(tx->nodetree, in);
457         
458         fromsock= in->outputs.first;
459         tosock= out->inputs.first;
460         nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
461         
462         ntreeUpdateTree(tx->nodetree);
463 }
464
465 /* id is supposed to contain a node tree */
466 void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype)
467 {
468         if (id) {
469                 bNode *node= NULL;
470                 short idtype= GS(id->name);
471         
472                 if (idtype == ID_NT) {
473                         *ntree= (bNodeTree*)id;
474                         if (treetype) *treetype= (*ntree)->type;
475                 }
476                 else if (idtype == ID_MA) {
477                         *ntree= ((Material*)id)->nodetree;
478                         if (treetype) *treetype= NTREE_SHADER;
479                 }
480                 else if (idtype == ID_LA) {
481                         *ntree= ((Lamp*)id)->nodetree;
482                         if (treetype) *treetype= NTREE_SHADER;
483                 }
484                 else if (idtype == ID_WO) {
485                         *ntree= ((World*)id)->nodetree;
486                         if (treetype) *treetype= NTREE_SHADER;
487                 }
488                 else if (idtype == ID_SCE) {
489                         *ntree= ((Scene*)id)->nodetree;
490                         if (treetype) *treetype= NTREE_COMPOSIT;
491                 }
492                 else if (idtype == ID_TE) {
493                         *ntree= ((Tex*)id)->nodetree;
494                         if (treetype) *treetype= NTREE_TEXTURE;
495                 }
496                 else {
497                         if (treetype) *treetype= 0;
498                         return;
499                 }
500         
501                 /* find editable group */
502                 if (edittree) {
503                         if (*ntree)
504                                 for (node= (*ntree)->nodes.first; node; node= node->next)
505                                         if (nodeGroupEditGet(node))
506                                                 break;
507                         
508                         if (node && node->id)
509                                 *edittree= (bNodeTree *)node->id;
510                         else
511                                 *edittree= *ntree;
512                 }
513         }
514         else {
515                 *ntree= NULL;
516                 *edittree= NULL;
517                 if (treetype) *treetype= 0;
518         }
519 }
520
521 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
522 void snode_set_context(SpaceNode *snode, Scene *scene)
523 {
524         Object *ob= OBACT;
525         
526         snode->id= snode->from= NULL;
527         
528         if (snode->treetype==NTREE_SHADER) {
529                 /* need active object, or we allow pinning... */
530                 if (snode->shaderfrom == SNODE_SHADER_OBJECT) {
531                         if (ob) {
532                                 if (ob->type == OB_LAMP) {
533                                         snode->from= &ob->id;
534                                         snode->id= ob->data;
535                                 }
536                                 else {
537                                         Material *ma= give_current_material(ob, ob->actcol);
538                                         if (ma) {
539                                                 snode->from= &ob->id;
540                                                 snode->id= &ma->id;
541                                         }
542                                 }
543                         }
544                 }
545                 else { /* SNODE_SHADER_WORLD */
546                         if (scene->world) {
547                                 snode->from= NULL;
548                                 snode->id= &scene->world->id;
549                         }
550                 }
551         }
552         else if (snode->treetype==NTREE_COMPOSIT) {
553                 snode->id= &scene->id;
554                 
555                 /* update output sockets based on available layers */
556                 ntreeCompositForceHidden(scene->nodetree, scene);
557         }
558         else if (snode->treetype==NTREE_TEXTURE) {
559                 Tex *tx= NULL;
560
561                 if (snode->texfrom==SNODE_TEX_OBJECT) {
562                         if (ob) {
563                                 tx= give_current_object_texture(ob);
564
565                                 if (ob->type == OB_LAMP)
566                                         snode->from= (ID*)ob->data;
567                                 else
568                                         snode->from= (ID*)give_current_material(ob, ob->actcol);
569
570                                 /* from is not set fully for material nodes, should be ID + Node then */
571                                 snode->id= &tx->id;
572                         }
573                 }
574                 else if (snode->texfrom==SNODE_TEX_WORLD) {
575                         tx= give_current_world_texture(scene->world);
576                         snode->from= (ID *)scene->world;
577                         snode->id= &tx->id;
578                 }
579                 else {
580                         struct Brush *brush= NULL;
581                         
582                         if (ob && (ob->mode & OB_MODE_SCULPT))
583                                 brush= paint_brush(&scene->toolsettings->sculpt->paint);
584                         else
585                                 brush= paint_brush(&scene->toolsettings->imapaint.paint);
586
587                         if (brush) {
588                                 snode->from= (ID *)brush;
589                                 tx= give_current_brush_texture(brush);
590                                 snode->id= &tx->id;
591                         }
592                 }
593         }
594         else {
595                 if (snode->nodetree && snode->nodetree->type == snode->treetype)
596                         snode->id = &snode->nodetree->id;
597                 else
598                         snode->id = NULL;
599         }
600
601         node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
602 }
603
604 static void snode_update(SpaceNode *snode, bNode *node)
605 {
606         bNode *gnode;
607         
608         if (node)
609                 nodeUpdate(snode->edittree, node);
610         
611         /* if inside group, tag entire group */
612         gnode= node_tree_get_editgroup(snode->nodetree);
613         if (gnode)
614                 nodeUpdateID(snode->nodetree, gnode->id);
615 }
616
617 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
618 {
619         int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
620
621         nodeSetActive(ntree, node);
622         
623         if (node->type!=NODE_GROUP) {
624                 int was_output= (node->flag & NODE_DO_OUTPUT);
625                 
626                 /* tree specific activate calls */
627                 if (ntree->type==NTREE_SHADER) {
628                         /* when we select a material, active texture is cleared, for buttons */
629                         if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
630                                 nodeClearActiveID(ntree, ID_TE);
631                         
632                         if (node->type==SH_NODE_OUTPUT) {
633                                 bNode *tnode;
634                                 
635                                 for (tnode= ntree->nodes.first; tnode; tnode= tnode->next)
636                                         if ( tnode->type==SH_NODE_OUTPUT)
637                                                 tnode->flag &= ~NODE_DO_OUTPUT;
638                                 
639                                 node->flag |= NODE_DO_OUTPUT;
640                                 if (was_output==0)
641                                         ED_node_generic_update(bmain, ntree, node);
642                         }
643
644                         /* if active texture changed, free glsl materials */
645                         if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
646                                 Material *ma;
647
648                                 for (ma=bmain->mat.first; ma; ma=ma->id.next)
649                                         if (ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
650                                                 GPU_material_free(ma);
651
652                                 WM_main_add_notifier(NC_IMAGE, NULL);
653                         }
654
655                         WM_main_add_notifier(NC_MATERIAL|ND_NODES, node->id);
656                 }
657                 else if (ntree->type==NTREE_COMPOSIT) {
658                         /* make active viewer, currently only 1 supported... */
659                         if ( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
660                                 bNode *tnode;
661                                 
662
663                                 for (tnode= ntree->nodes.first; tnode; tnode= tnode->next)
664                                         if ( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
665                                                 tnode->flag &= ~NODE_DO_OUTPUT;
666                                 
667                                 node->flag |= NODE_DO_OUTPUT;
668                                 if (was_output==0)
669                                         ED_node_generic_update(bmain, ntree, node);
670                                 
671                                 /* addnode() doesnt link this yet... */
672                                 node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
673                         }
674                         else if (node->type==CMP_NODE_R_LAYERS) {
675                                 Scene *scene;
676
677                                 for (scene=bmain->scene.first; scene; scene=scene->id.next) {
678                                         if (scene->nodetree && scene->use_nodes && has_nodetree(scene->nodetree, ntree)) {
679                                                 if (node->id==NULL || node->id==(ID *)scene) {
680                                                         scene->r.actlay= node->custom1;
681                                                 }
682                                         }
683                                 }
684                         }
685                         else if (node->type==CMP_NODE_COMPOSITE) {
686                                 if (was_output==0) {
687                                         bNode *tnode;
688                                         
689                                         for (tnode= ntree->nodes.first; tnode; tnode= tnode->next)
690                                                 if ( tnode->type==CMP_NODE_COMPOSITE)
691                                                         tnode->flag &= ~NODE_DO_OUTPUT;
692                                         
693                                         node->flag |= NODE_DO_OUTPUT;
694                                         ED_node_generic_update(bmain, ntree, node);
695                                 }
696                         }
697                 }
698                 else if (ntree->type==NTREE_TEXTURE) {
699                         // XXX
700 #if 0
701                         if (node->id)
702                                 ; // XXX BIF_preview_changed(-1);
703                         // allqueue(REDRAWBUTSSHADING, 1);
704                         // allqueue(REDRAWIPO, 0);
705 #endif
706                 }
707         }
708 }
709
710 static int inside_rctf(rctf *bounds, rctf *rect)
711 {
712         return (bounds->xmin <= rect->xmin &&
713                 bounds->xmax >= rect->xmax &&
714                 bounds->ymin <= rect->ymin &&
715                 bounds->ymax >= rect->ymax);
716 }
717
718 static void node_frame_attach_nodes(bNodeTree *UNUSED(ntree), bNode *frame)
719 {
720         bNode *node;
721         
722         /* only check nodes on top of the frame for attaching */
723         for (node=frame->next; node; node=node->next) {
724                 if (node->parent==frame) {
725                         /* detach nodes that went outside the frame */
726                         if (!inside_rctf(&frame->totr, &node->totr))
727                                 nodeDetachNode(node);
728                 }
729                 else if (node->flag & NODE_SELECT && node->parent==NULL) {
730                         /* attach selected, still unparented nodes */
731                         if (inside_rctf(&frame->totr, &node->totr))
732                                 nodeAttachNode(node, frame);
733                 }
734         }
735 }
736
737 void ED_node_update_hierarchy(bContext *UNUSED(C), bNodeTree *ntree)
738 {
739         bNode *node;
740         
741         /* XXX This does not work due to layout functions relying on node->block,
742          * which only exists during actual drawing. Can we rely on valid totr rects?
743          */
744         /* make sure nodes have correct bounding boxes after transform */
745 //      node_update_nodetree(C, ntree, 0.0f, 0.0f);
746         
747         /* all selected nodes are re-parented */
748         for (node=ntree->nodes.last; node; node=node->prev) {
749                 if (node->flag & NODE_SELECT && node->parent)
750                         nodeDetachNode(node);
751         }
752         
753         /* update higher Z-level nodes first */
754         for (node=ntree->nodes.last; node; node=node->prev) {
755                 /* XXX callback? */
756                 if (node->type==NODE_FRAME)
757                         node_frame_attach_nodes(ntree, node);
758         }
759 }
760
761 /* ***************** generic operator functions for nodes ***************** */
762
763 #if 0 /* UNUSED */
764
765 static int edit_node_poll(bContext *C)
766 {
767         return ED_operator_node_active(C);
768 }
769
770 static void edit_node_properties(wmOperatorType *ot)
771 {
772         /* XXX could node be a context pointer? */
773         RNA_def_string(ot->srna, "node", "", MAX_NAME, "Node", "");
774         RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
775         RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Side", "");
776 }
777
778 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
779 {
780         if (!RNA_struct_property_is_set(op->ptr, "node")) {
781                 bNode *node= CTX_data_pointer_get_type(C, "node", &RNA_Node).data;
782                 if (!node)
783                         return 0;
784                 else
785                         RNA_string_set(op->ptr, "node", node->name);
786         }
787         
788         if (!RNA_struct_property_is_set(op->ptr, "in_out"))
789                 RNA_enum_set(op->ptr, "in_out", SOCK_IN);
790         
791         if (!RNA_struct_property_is_set(op->ptr, "socket"))
792                 RNA_int_set(op->ptr, "socket", 0);
793         
794         return 1;
795 }
796
797 static void edit_node_properties_get(wmOperator *op, bNodeTree *ntree, bNode **rnode, bNodeSocket **rsock, int *rin_out)
798 {
799         bNode *node;
800         bNodeSocket *sock=NULL;
801         char nodename[MAX_NAME];
802         int sockindex;
803         int in_out;
804         
805         RNA_string_get(op->ptr, "node", nodename);
806         node = nodeFindNodebyName(ntree, nodename);
807         
808         in_out = RNA_enum_get(op->ptr, "in_out");
809         
810         sockindex = RNA_int_get(op->ptr, "socket");
811         switch (in_out) {
812         case SOCK_IN:   sock = BLI_findlink(&node->inputs, sockindex);  break;
813         case SOCK_OUT:  sock = BLI_findlink(&node->outputs, sockindex); break;
814         }
815         
816         if (rnode)
817                 *rnode = node;
818         if (rsock)
819                 *rsock = sock;
820         if (rin_out)
821                 *rin_out = in_out;
822 }
823 #endif
824
825 /* ***************** Edit Group operator ************* */
826
827 void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
828 {
829         bNode *node;
830         
831         /* make sure nothing has group editing on */
832         for (node=snode->nodetree->nodes.first; node; node=node->next)
833                 nodeGroupEditClear(node);
834         
835         if (gnode==NULL) {
836                 /* with NULL argument we do a toggle */
837                 if (snode->edittree==snode->nodetree)
838                         gnode= nodeGetActive(snode->nodetree);
839         }
840         
841         if (gnode) {
842                 snode->edittree = nodeGroupEditSet(gnode, 1);
843                 
844                 /* deselect all other nodes, so we can also do grabbing of entire subtree */
845                 for (node= snode->nodetree->nodes.first; node; node= node->next)
846                         node_deselect(node);
847                 node_select(gnode);
848         }
849         else 
850                 snode->edittree= snode->nodetree;
851 }
852
853 static int node_group_edit_exec(bContext *C, wmOperator *UNUSED(op))
854 {
855         SpaceNode *snode = CTX_wm_space_node(C);
856
857         ED_preview_kill_jobs(C);
858
859         if (snode->nodetree==snode->edittree) {
860                 bNode *gnode = nodeGetActive(snode->edittree);
861                 snode_make_group_editable(snode, gnode);
862         }
863         else
864                 snode_make_group_editable(snode, NULL);
865
866         WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
867
868         return OPERATOR_FINISHED;
869 }
870
871 static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
872 {
873         SpaceNode *snode = CTX_wm_space_node(C);
874         bNode *gnode;
875         
876         /* XXX callback? */
877         if (snode->nodetree==snode->edittree) {
878                 gnode = nodeGetActive(snode->edittree);
879                 if (gnode && gnode->id && GS(gnode->id->name)==ID_NT && gnode->id->lib) {
880                         uiPupMenuOkee(C, op->type->idname, "Make group local?");
881                         return OPERATOR_CANCELLED;
882                 }
883         }
884
885         return node_group_edit_exec(C, op);
886 }
887
888 void NODE_OT_group_edit(wmOperatorType *ot)
889 {
890         /* identifiers */
891         ot->name = "Edit Group";
892         ot->description = "Edit node group";
893         ot->idname = "NODE_OT_group_edit";
894         
895         /* api callbacks */
896         ot->invoke = node_group_edit_invoke;
897         ot->exec = node_group_edit_exec;
898         ot->poll = ED_operator_node_active;
899         
900         /* flags */
901         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
902 }
903
904 /* ***************** Add Group Socket operator ************* */
905
906 static int node_group_socket_add_exec(bContext *C, wmOperator *op)
907 {
908         SpaceNode *snode = CTX_wm_space_node(C);
909         int in_out= -1;
910         char name[MAX_NAME]= "";
911         int type= SOCK_FLOAT;
912         bNodeTree *ngroup= snode->edittree;
913         /* bNodeSocket *sock; */ /* UNUSED */
914         
915         ED_preview_kill_jobs(C);
916         
917         if (RNA_struct_property_is_set(op->ptr, "name"))
918                 RNA_string_get(op->ptr, "name", name);
919         
920         if (RNA_struct_property_is_set(op->ptr, "type"))
921                 type = RNA_enum_get(op->ptr, "type");
922         
923         if (RNA_struct_property_is_set(op->ptr, "in_out"))
924                 in_out = RNA_enum_get(op->ptr, "in_out");
925         else
926                 return OPERATOR_CANCELLED;
927         
928         /* using placeholder subtype first */
929         /* sock = */ /* UNUSED */ node_group_add_socket(ngroup, name, type, in_out);
930         
931         ntreeUpdateTree(ngroup);
932         
933         snode_notify(C, snode);
934         
935         return OPERATOR_FINISHED;
936 }
937
938 void NODE_OT_group_socket_add(wmOperatorType *ot)
939 {
940         /* identifiers */
941         ot->name = "Add Group Socket";
942         ot->description = "Add node group socket";
943         ot->idname = "NODE_OT_group_socket_add";
944         
945         /* api callbacks */
946         ot->exec = node_group_socket_add_exec;
947         ot->poll = ED_operator_node_active;
948         
949         /* flags */
950         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
951         
952         RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
953         RNA_def_string(ot->srna, "name", "", MAX_NAME, "Name", "Group socket name");
954         RNA_def_enum(ot->srna, "type", node_socket_type_items, SOCK_FLOAT, "Type", "Type of the group socket");
955 }
956
957 /* ***************** Remove Group Socket operator ************* */
958
959 static int node_group_socket_remove_exec(bContext *C, wmOperator *op)
960 {
961         SpaceNode *snode = CTX_wm_space_node(C);
962         int index= -1;
963         int in_out= -1;
964         bNodeTree *ngroup= snode->edittree;
965         bNodeSocket *sock;
966         
967         ED_preview_kill_jobs(C);
968         
969         if (RNA_struct_property_is_set(op->ptr, "index"))
970                 index = RNA_int_get(op->ptr, "index");
971         else
972                 return OPERATOR_CANCELLED;
973         
974         if (RNA_struct_property_is_set(op->ptr, "in_out"))
975                 in_out = RNA_enum_get(op->ptr, "in_out");
976         else
977                 return OPERATOR_CANCELLED;
978         
979         sock = (bNodeSocket*)BLI_findlink(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, index);
980         if (sock) {
981                 node_group_remove_socket(ngroup, sock, in_out);
982                 ntreeUpdateTree(ngroup);
983                 
984                 snode_notify(C, snode);
985         }
986         
987         return OPERATOR_FINISHED;
988 }
989
990 void NODE_OT_group_socket_remove(wmOperatorType *ot)
991 {
992         /* identifiers */
993         ot->name = "Remove Group Socket";
994         ot->description = "Remove a node group socket";
995         ot->idname = "NODE_OT_group_socket_remove";
996         
997         /* api callbacks */
998         ot->exec = node_group_socket_remove_exec;
999         ot->poll = ED_operator_node_active;
1000         
1001         /* flags */
1002         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1003         
1004         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1005         RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1006 }
1007
1008 /* ***************** Move Group Socket Up operator ************* */
1009
1010 static int node_group_socket_move_up_exec(bContext *C, wmOperator *op)
1011 {
1012         SpaceNode *snode = CTX_wm_space_node(C);
1013         int index= -1;
1014         int in_out= -1;
1015         bNodeTree *ngroup= snode->edittree;
1016         bNodeSocket *sock, *prev;
1017         
1018         ED_preview_kill_jobs(C);
1019         
1020         if (RNA_struct_property_is_set(op->ptr, "index"))
1021                 index = RNA_int_get(op->ptr, "index");
1022         else
1023                 return OPERATOR_CANCELLED;
1024         
1025         if (RNA_struct_property_is_set(op->ptr, "in_out"))
1026                 in_out = RNA_enum_get(op->ptr, "in_out");
1027         else
1028                 return OPERATOR_CANCELLED;
1029         
1030         /* swap */
1031         if (in_out==SOCK_IN) {
1032                 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index);
1033                 prev = sock->prev;
1034                 /* can't move up the first socket */
1035                 if (!prev)
1036                         return OPERATOR_CANCELLED;
1037                 BLI_remlink(&ngroup->inputs, sock);
1038                 BLI_insertlinkbefore(&ngroup->inputs, prev, sock);
1039                 
1040                 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1041         }
1042         else if (in_out==SOCK_OUT) {
1043                 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
1044                 prev = sock->prev;
1045                 /* can't move up the first socket */
1046                 if (!prev)
1047                         return OPERATOR_CANCELLED;
1048                 BLI_remlink(&ngroup->outputs, sock);
1049                 BLI_insertlinkbefore(&ngroup->outputs, prev, sock);
1050                 
1051                 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1052         }
1053         ntreeUpdateTree(ngroup);
1054         
1055         snode_notify(C, snode);
1056         
1057         return OPERATOR_FINISHED;
1058 }
1059
1060 void NODE_OT_group_socket_move_up(wmOperatorType *ot)
1061 {
1062         /* identifiers */
1063         ot->name = "Move Group Socket Up";
1064         ot->description = "Move up node group socket";
1065         ot->idname = "NODE_OT_group_socket_move_up";
1066         
1067         /* api callbacks */
1068         ot->exec = node_group_socket_move_up_exec;
1069         ot->poll = ED_operator_node_active;
1070         
1071         /* flags */
1072         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1073         
1074         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1075         RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1076 }
1077
1078 /* ***************** Move Group Socket Up operator ************* */
1079
1080 static int node_group_socket_move_down_exec(bContext *C, wmOperator *op)
1081 {
1082         SpaceNode *snode = CTX_wm_space_node(C);
1083         int index= -1;
1084         int in_out= -1;
1085         bNodeTree *ngroup= snode->edittree;
1086         bNodeSocket *sock, *next;
1087         
1088         ED_preview_kill_jobs(C);
1089         
1090         if (RNA_struct_property_is_set(op->ptr, "index"))
1091                 index = RNA_int_get(op->ptr, "index");
1092         else
1093                 return OPERATOR_CANCELLED;
1094         
1095         if (RNA_struct_property_is_set(op->ptr, "in_out"))
1096                 in_out = RNA_enum_get(op->ptr, "in_out");
1097         else
1098                 return OPERATOR_CANCELLED;
1099         
1100         /* swap */
1101         if (in_out==SOCK_IN) {
1102                 sock = (bNodeSocket*)BLI_findlink(&ngroup->inputs, index);
1103                 next = sock->next;
1104                 /* can't move down the last socket */
1105                 if (!next)
1106                         return OPERATOR_CANCELLED;
1107                 BLI_remlink(&ngroup->inputs, sock);
1108                 BLI_insertlinkafter(&ngroup->inputs, next, sock);
1109                 
1110                 ngroup->update |= NTREE_UPDATE_GROUP_IN;
1111         }
1112         else if (in_out==SOCK_OUT) {
1113                 sock = (bNodeSocket*)BLI_findlink(&ngroup->outputs, index);
1114                 next = sock->next;
1115                 /* can't move down the last socket */
1116                 if (!next)
1117                         return OPERATOR_CANCELLED;
1118                 BLI_remlink(&ngroup->outputs, sock);
1119                 BLI_insertlinkafter(&ngroup->outputs, next, sock);
1120                 
1121                 ngroup->update |= NTREE_UPDATE_GROUP_OUT;
1122         }
1123         ntreeUpdateTree(ngroup);
1124         
1125         snode_notify(C, snode);
1126         
1127         return OPERATOR_FINISHED;
1128 }
1129
1130 void NODE_OT_group_socket_move_down(wmOperatorType *ot)
1131 {
1132         /* identifiers */
1133         ot->name = "Move Group Socket Down";
1134         ot->description = "Move down node group socket";
1135         ot->idname = "NODE_OT_group_socket_move_down";
1136         
1137         /* api callbacks */
1138         ot->exec = node_group_socket_move_down_exec;
1139         ot->poll = ED_operator_node_active;
1140         
1141         /* flags */
1142         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1143         
1144         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, INT_MAX);
1145         RNA_def_enum(ot->srna, "in_out", socket_in_out_items, SOCK_IN, "Socket Type", "Input or Output");
1146 }
1147
1148 /* ******************** Ungroup operator ********************** */
1149
1150 static int node_group_ungroup_exec(bContext *C, wmOperator *op)
1151 {
1152         SpaceNode *snode = CTX_wm_space_node(C);
1153         bNode *gnode;
1154
1155         ED_preview_kill_jobs(C);
1156
1157         /* are we inside of a group? */
1158         gnode= node_tree_get_editgroup(snode->nodetree);
1159         if (gnode)
1160                 snode_make_group_editable(snode, NULL);
1161         
1162         gnode= nodeGetActive(snode->edittree);
1163         if (gnode==NULL)
1164                 return OPERATOR_CANCELLED;
1165         
1166         if (gnode->type!=NODE_GROUP) {
1167                 BKE_report(op->reports, RPT_WARNING, "Not a group");
1168                 return OPERATOR_CANCELLED;
1169         }
1170         else if (!node_group_ungroup(snode->edittree, gnode)) {
1171                 BKE_report(op->reports, RPT_WARNING, "Can't ungroup");
1172                 return OPERATOR_CANCELLED;
1173         }
1174
1175         snode_notify(C, snode);
1176         snode_dag_update(C, snode);
1177
1178         return OPERATOR_FINISHED;
1179 }
1180
1181 void NODE_OT_group_ungroup(wmOperatorType *ot)
1182 {
1183         /* identifiers */
1184         ot->name = "Ungroup";
1185         ot->description = "Ungroup selected nodes";
1186         ot->idname = "NODE_OT_group_ungroup";
1187         
1188         /* api callbacks */
1189         ot->exec = node_group_ungroup_exec;
1190         ot->poll = ED_operator_node_active;
1191         
1192         /* flags */
1193         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1194 }
1195
1196 /* ************************** Node generic ************** */
1197
1198 /* is rct in visible part of node? */
1199 static bNode *visible_node(SpaceNode *snode, rctf *rct)
1200 {
1201         bNode *node;
1202         
1203         for (node=snode->edittree->nodes.last; node; node=node->prev) {
1204                 if (BLI_isect_rctf(&node->totr, rct, NULL))
1205                         break;
1206         }
1207         return node;
1208 }
1209
1210 /* **************************** */
1211
1212 typedef struct NodeViewMove {
1213         int mvalo[2];
1214         int xmin, ymin, xmax, ymax;
1215 } NodeViewMove;
1216
1217 static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
1218 {
1219         SpaceNode *snode= CTX_wm_space_node(C);
1220         ARegion *ar= CTX_wm_region(C);
1221         NodeViewMove *nvm= op->customdata;
1222
1223         switch (event->type) {
1224                 case MOUSEMOVE:
1225                         
1226                         snode->xof -= (nvm->mvalo[0]-event->mval[0]);
1227                         snode->yof -= (nvm->mvalo[1]-event->mval[1]);
1228                         nvm->mvalo[0]= event->mval[0];
1229                         nvm->mvalo[1]= event->mval[1];
1230                         
1231                         /* prevent dragging image outside of the window and losing it! */
1232                         CLAMP(snode->xof, nvm->xmin, nvm->xmax);
1233                         CLAMP(snode->yof, nvm->ymin, nvm->ymax);
1234                         
1235                         ED_region_tag_redraw(ar);
1236                         
1237                         break;
1238                         
1239                 case LEFTMOUSE:
1240                 case MIDDLEMOUSE:
1241                 case RIGHTMOUSE:
1242                         
1243                         MEM_freeN(nvm);
1244                         op->customdata= NULL;
1245
1246                         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE, NULL);
1247                         
1248                         return OPERATOR_FINISHED;
1249         }
1250         
1251         return OPERATOR_RUNNING_MODAL;
1252 }
1253
1254 static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
1255 {
1256         ARegion *ar= CTX_wm_region(C);
1257         NodeViewMove *nvm;
1258         Image *ima;
1259         ImBuf *ibuf;
1260         int pad= 10;
1261         void *lock;
1262         
1263         ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1264         ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
1265         
1266         if (ibuf == NULL) {
1267                 BKE_image_release_ibuf(ima, lock);
1268                 return OPERATOR_CANCELLED;
1269         }
1270
1271         nvm= MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
1272         op->customdata= nvm;
1273         nvm->mvalo[0]= event->mval[0];
1274         nvm->mvalo[1]= event->mval[1];
1275
1276         nvm->xmin = -(ar->winx/2) - ibuf->x/2 + pad;
1277         nvm->xmax = ar->winx/2 + ibuf->x/2 - pad;
1278         nvm->ymin = -(ar->winy/2) - ibuf->y/2 + pad;
1279         nvm->ymax = ar->winy/2 + ibuf->y/2 - pad;
1280
1281         BKE_image_release_ibuf(ima, lock);
1282         
1283         /* add modal handler */
1284         WM_event_add_modal_handler(C, op);
1285         
1286         return OPERATOR_RUNNING_MODAL;
1287 }
1288
1289 static int snode_bg_viewmove_cancel(bContext *UNUSED(C), wmOperator *op)
1290 {
1291         MEM_freeN(op->customdata);
1292         op->customdata= NULL;
1293
1294         return OPERATOR_CANCELLED;
1295 }
1296
1297 void NODE_OT_backimage_move(wmOperatorType *ot)
1298 {
1299         /* identifiers */
1300         ot->name = "Background Image Move";
1301         ot->description = "Move Node backdrop";
1302         ot->idname = "NODE_OT_backimage_move";
1303         
1304         /* api callbacks */
1305         ot->invoke = snode_bg_viewmove_invoke;
1306         ot->modal = snode_bg_viewmove_modal;
1307         ot->poll = composite_node_active;
1308         ot->cancel = snode_bg_viewmove_cancel;
1309         
1310         /* flags */
1311         ot->flag = OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1312 }
1313
1314 static int backimage_zoom(bContext *C, wmOperator *op)
1315 {
1316         SpaceNode *snode= CTX_wm_space_node(C);
1317         ARegion *ar= CTX_wm_region(C);
1318         float fac= RNA_float_get(op->ptr, "factor");
1319
1320         snode->zoom *= fac;
1321         ED_region_tag_redraw(ar);
1322
1323         return OPERATOR_FINISHED;
1324 }
1325
1326
1327 void NODE_OT_backimage_zoom(wmOperatorType *ot)
1328 {
1329         
1330         /* identifiers */
1331         ot->name = "Background Image Zoom";
1332         ot->idname = "NODE_OT_backimage_zoom";
1333         ot->description = "Zoom in/out the brackground image";
1334         
1335         /* api callbacks */
1336         ot->exec = backimage_zoom;
1337         ot->poll = composite_node_active;
1338         
1339         /* flags */
1340         ot->flag = OPTYPE_BLOCKING;
1341
1342         /* internal */
1343         RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
1344 }
1345
1346 /******************** sample backdrop operator ********************/
1347
1348 typedef struct ImageSampleInfo {
1349         ARegionType *art;
1350         void *draw_handle;
1351         int x, y;
1352         int channels;
1353         int color_manage;
1354
1355         unsigned char col[4];
1356         float colf[4];
1357
1358         int draw;
1359 } ImageSampleInfo;
1360
1361 static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
1362 {
1363         Scene *scene = CTX_data_scene(C);
1364         ImageSampleInfo *info= arg_info;
1365
1366         ED_image_draw_info(ar, (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT), info->channels,
1367                            info->x, info->y, info->col, info->colf,
1368                            NULL, NULL /* zbuf - unused for nodes */
1369                            );
1370 }
1371
1372 static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
1373 {
1374         SpaceNode *snode= CTX_wm_space_node(C);
1375         ARegion *ar= CTX_wm_region(C);
1376         ImageSampleInfo *info= op->customdata;
1377         void *lock;
1378         Image *ima;
1379         ImBuf *ibuf;
1380         float fx, fy, bufx, bufy;
1381         
1382         ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
1383         ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
1384         if (!ibuf)
1385                 return;
1386         
1387         if (!ibuf->rect) {
1388                 if (info->color_manage)
1389                         ibuf->profile = IB_PROFILE_LINEAR_RGB;
1390                 else
1391                         ibuf->profile = IB_PROFILE_NONE;
1392                 IMB_rect_from_float(ibuf);
1393         }
1394
1395         /* map the mouse coords to the backdrop image space */
1396         bufx = ibuf->x * snode->zoom;
1397         bufy = ibuf->y * snode->zoom;
1398         fx = (bufx > 0.0f ? ((float)event->mval[0] - 0.5f*ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
1399         fy = (bufy > 0.0f ? ((float)event->mval[1] - 0.5f*ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
1400
1401         if (fx>=0.0f && fy>=0.0f && fx<1.0f && fy<1.0f) {
1402                 float *fp;
1403                 char *cp;
1404                 int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
1405
1406                 CLAMP(x, 0, ibuf->x-1);
1407                 CLAMP(y, 0, ibuf->y-1);
1408
1409                 info->x= x;
1410                 info->y= y;
1411                 info->draw= 1;
1412                 info->channels= ibuf->channels;
1413
1414                 if (ibuf->rect) {
1415                         cp= (char *)(ibuf->rect + y*ibuf->x + x);
1416
1417                         info->col[0]= cp[0];
1418                         info->col[1]= cp[1];
1419                         info->col[2]= cp[2];
1420                         info->col[3]= cp[3];
1421
1422                         info->colf[0]= (float)cp[0]/255.0f;
1423                         info->colf[1]= (float)cp[1]/255.0f;
1424                         info->colf[2]= (float)cp[2]/255.0f;
1425                         info->colf[3]= (float)cp[3]/255.0f;
1426                 }
1427                 if (ibuf->rect_float) {
1428                         fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
1429
1430                         info->colf[0]= fp[0];
1431                         info->colf[1]= fp[1];
1432                         info->colf[2]= fp[2];
1433                         info->colf[3]= fp[3];
1434                 }
1435         }
1436         else
1437                 info->draw= 0;
1438
1439         BKE_image_release_ibuf(ima, lock);
1440         
1441         ED_area_tag_redraw(CTX_wm_area(C));
1442 }
1443
1444 static void sample_exit(bContext *C, wmOperator *op)
1445 {
1446         ImageSampleInfo *info= op->customdata;
1447
1448         ED_region_draw_cb_exit(info->art, info->draw_handle);
1449         ED_area_tag_redraw(CTX_wm_area(C));
1450         MEM_freeN(info);
1451 }
1452
1453 static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
1454 {
1455         SpaceNode *snode= CTX_wm_space_node(C);
1456         ARegion *ar= CTX_wm_region(C);
1457         ImageSampleInfo *info;
1458
1459         if (snode->treetype!=NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW))
1460                 return OPERATOR_CANCELLED;
1461         
1462         info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
1463         info->art= ar->type;
1464         info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
1465         op->customdata= info;
1466
1467         sample_apply(C, op, event);
1468
1469         WM_event_add_modal_handler(C, op);
1470
1471         return OPERATOR_RUNNING_MODAL;
1472 }
1473
1474 static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
1475 {
1476         switch (event->type) {
1477                 case LEFTMOUSE:
1478                 case RIGHTMOUSE: // XXX hardcoded
1479                         sample_exit(C, op);
1480                         return OPERATOR_CANCELLED;
1481                 case MOUSEMOVE:
1482                         sample_apply(C, op, event);
1483                         break;
1484         }
1485
1486         return OPERATOR_RUNNING_MODAL;
1487 }
1488
1489 static int sample_cancel(bContext *C, wmOperator *op)
1490 {
1491         sample_exit(C, op);
1492         return OPERATOR_CANCELLED;
1493 }
1494
1495 void NODE_OT_backimage_sample(wmOperatorType *ot)
1496 {
1497         /* identifiers */
1498         ot->name = "Backimage Sample";
1499         ot->idname = "NODE_OT_backimage_sample";
1500         ot->description = "Use mouse to sample background image";
1501         
1502         /* api callbacks */
1503         ot->invoke = sample_invoke;
1504         ot->modal = sample_modal;
1505         ot->cancel = sample_cancel;
1506         ot->poll = ED_operator_node_active;
1507
1508         /* flags */
1509         ot->flag = OPTYPE_BLOCKING;
1510 }
1511
1512 /* ********************** size widget operator ******************** */
1513
1514 typedef struct NodeSizeWidget {
1515         float mxstart, mystart;
1516         float oldwidth, oldheight;
1517         float oldminiwidth;
1518 } NodeSizeWidget;
1519
1520 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
1521 {
1522         SpaceNode *snode= CTX_wm_space_node(C);
1523         ARegion *ar= CTX_wm_region(C);
1524         bNode *node= editnode_get_active(snode->edittree);
1525         NodeSizeWidget *nsw= op->customdata;
1526         float mx, my;
1527         
1528         switch (event->type) {
1529                 case MOUSEMOVE:
1530                         
1531                         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
1532                                                                          &mx, &my);
1533                         
1534                         if (node) {
1535                                 if (node->flag & NODE_HIDDEN) {
1536                                         node->miniwidth= nsw->oldminiwidth + mx - nsw->mxstart;
1537                                         CLAMP(node->miniwidth, 0.0f, 100.0f);
1538                                 }
1539                                 else {
1540                                         node->width= nsw->oldwidth + mx - nsw->mxstart;
1541                                         CLAMP(node->width, UI_DPI_FAC*node->typeinfo->minwidth, UI_DPI_FAC*node->typeinfo->maxwidth);
1542                                 }
1543                                 /* height works the other way round ... */
1544                                 node->height= nsw->oldheight - my + nsw->mystart;
1545                                 CLAMP(node->height, node->typeinfo->minheight, node->typeinfo->maxheight);
1546                         }
1547                                 
1548                         ED_region_tag_redraw(ar);
1549
1550                         break;
1551                         
1552                 case LEFTMOUSE:
1553                 case MIDDLEMOUSE:
1554                 case RIGHTMOUSE:
1555                         
1556                         MEM_freeN(nsw);
1557                         op->customdata= NULL;
1558                         
1559                         ED_node_update_hierarchy(C, snode->edittree);
1560                         
1561                         return OPERATOR_FINISHED;
1562         }
1563         
1564         return OPERATOR_RUNNING_MODAL;
1565 }
1566
1567 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
1568 {
1569         SpaceNode *snode= CTX_wm_space_node(C);
1570         ARegion *ar= CTX_wm_region(C);
1571         bNode *node= editnode_get_active(snode->edittree);
1572         
1573         if (node) {
1574                 /* convert mouse coordinates to v2d space */
1575                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
1576                                                                  &snode->mx, &snode->my);
1577                 
1578                 if (node->typeinfo->resize_area_func(node, snode->mx, snode->my)) {
1579                         NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
1580                         
1581                         op->customdata= nsw;
1582                         nsw->mxstart= snode->mx;
1583                         nsw->mystart= snode->my;
1584                         
1585                         /* store old */
1586                         nsw->oldwidth= node->width;
1587                         nsw->oldheight= node->height;
1588                         nsw->oldminiwidth= node->miniwidth;
1589                         
1590                         /* add modal handler */
1591                         WM_event_add_modal_handler(C, op);
1592
1593                         return OPERATOR_RUNNING_MODAL;
1594                 }
1595         }
1596         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1597 }
1598
1599 static int node_resize_cancel(bContext *UNUSED(C), wmOperator *op)
1600 {
1601         MEM_freeN(op->customdata);
1602         op->customdata= NULL;
1603
1604         return OPERATOR_CANCELLED;
1605 }
1606
1607 void NODE_OT_resize(wmOperatorType *ot)
1608 {
1609         /* identifiers */
1610         ot->name = "Resize Node";
1611         ot->idname = "NODE_OT_resize";
1612         ot->description = "Resize a node";
1613         
1614         /* api callbacks */
1615         ot->invoke = node_resize_invoke;
1616         ot->modal = node_resize_modal;
1617         ot->poll = ED_operator_node_active;
1618         ot->cancel = node_resize_cancel;
1619         
1620         /* flags */
1621         ot->flag = OPTYPE_BLOCKING;
1622 }
1623
1624
1625 /* ********************** hidden sockets ******************** */
1626
1627 int node_has_hidden_sockets(bNode *node)
1628 {
1629         bNodeSocket *sock;
1630         
1631         for (sock= node->inputs.first; sock; sock= sock->next)
1632                 if (sock->flag & SOCK_HIDDEN)
1633                         return 1;
1634         for (sock= node->outputs.first; sock; sock= sock->next)
1635                 if (sock->flag & SOCK_HIDDEN)
1636                         return 1;
1637         return 0;
1638 }
1639
1640 void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
1641 {       
1642         bNodeSocket *sock;
1643
1644         if (set==0) {
1645                 for (sock= node->inputs.first; sock; sock= sock->next)
1646                         sock->flag &= ~SOCK_HIDDEN;
1647                 for (sock= node->outputs.first; sock; sock= sock->next)
1648                         sock->flag &= ~SOCK_HIDDEN;
1649         }
1650         else {
1651                 /* hide unused sockets */
1652                 for (sock= node->inputs.first; sock; sock= sock->next) {
1653                         if (sock->link==NULL)
1654                                 sock->flag |= SOCK_HIDDEN;
1655                 }
1656                 for (sock= node->outputs.first; sock; sock= sock->next) {
1657                         if (nodeCountSocketLinks(snode->edittree, sock)==0)
1658                                 sock->flag |= SOCK_HIDDEN;
1659                 }
1660         }
1661 }
1662
1663 static int node_link_viewer(const bContext *C, bNode *tonode)
1664 {
1665         SpaceNode *snode = CTX_wm_space_node(C);
1666         bNode *node;
1667         bNodeLink *link;
1668         bNodeSocket *sock;
1669
1670         /* context check */
1671         if (tonode==NULL || tonode->outputs.first==NULL)
1672                 return OPERATOR_CANCELLED;
1673         if ( ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
1674                 return OPERATOR_CANCELLED;
1675         
1676         /* get viewer */
1677         for (node= snode->edittree->nodes.first; node; node= node->next)
1678                 if ( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
1679                         if (node->flag & NODE_DO_OUTPUT)
1680                                 break;
1681         /* no viewer, we make one active */
1682         if (node==NULL) {
1683                 for (node= snode->edittree->nodes.first; node; node= node->next) {
1684                         if ( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
1685                                 node->flag |= NODE_DO_OUTPUT;
1686                                 break;
1687                         }
1688                 }
1689         }
1690         
1691         sock = NULL;
1692         
1693         /* try to find an already connected socket to cycle to the next */
1694         if (node) {
1695                 link = NULL;
1696                 for (link= snode->edittree->links.first; link; link= link->next)
1697                         if (link->tonode==node && link->fromnode==tonode)
1698                                 if (link->tosock==node->inputs.first)
1699                                         break;
1700                 if (link) {
1701                         /* unlink existing connection */
1702                         sock= link->fromsock;
1703                         nodeRemLink(snode->edittree, link);
1704                         
1705                         /* find a socket after the previously connected socket */
1706                         for (sock=sock->next; sock; sock= sock->next)
1707                                 if (!nodeSocketIsHidden(sock))
1708                                         break;
1709                 }
1710         }
1711         
1712         /* find a socket starting from the first socket */
1713         if (!sock) {
1714                 for (sock= tonode->outputs.first; sock; sock= sock->next)
1715                         if (!nodeSocketIsHidden(sock))
1716                                 break;
1717         }
1718         
1719         if (sock) {
1720                 /* add a new viewer if none exists yet */
1721                 if (!node) {
1722                         Main *bmain = CTX_data_main(C);
1723                         Scene *scene = CTX_data_scene(C);
1724                         bNodeTemplate ntemp;
1725                         
1726                         ntemp.type = CMP_NODE_VIEWER;
1727                         /* XXX location is a quick hack, just place it next to the linked socket */
1728                         node = node_add_node(snode, bmain, scene, &ntemp, sock->locx + 100, sock->locy);
1729                         if (!node)
1730                                 return OPERATOR_CANCELLED;
1731                         
1732                         link = NULL;
1733                 }
1734                 else {
1735                         /* get link to viewer */
1736                         for (link= snode->edittree->links.first; link; link= link->next)
1737                                 if (link->tonode==node && link->tosock==node->inputs.first)
1738                                         break;
1739                 }
1740                 
1741                 if (link==NULL) {
1742                         nodeAddLink(snode->edittree, tonode, sock, node, node->inputs.first);
1743                 }
1744                 else {
1745                         link->fromnode= tonode;
1746                         link->fromsock= sock;
1747                 }
1748                 ntreeUpdateTree(snode->edittree);
1749                 snode_update(snode, node);
1750         }
1751         
1752         return OPERATOR_FINISHED;
1753 }
1754
1755
1756 static int node_active_link_viewer(bContext *C, wmOperator *UNUSED(op))
1757 {
1758         SpaceNode *snode= CTX_wm_space_node(C);
1759         bNode *node;
1760         
1761         node= editnode_get_active(snode->edittree);
1762         
1763         if (!node)
1764                 return OPERATOR_CANCELLED;
1765
1766         ED_preview_kill_jobs(C);
1767
1768         if (node_link_viewer(C, node) == OPERATOR_CANCELLED)
1769                 return OPERATOR_CANCELLED;
1770
1771         snode_notify(C, snode);
1772
1773         return OPERATOR_FINISHED;
1774 }
1775
1776
1777
1778 void NODE_OT_link_viewer(wmOperatorType *ot)
1779 {
1780         /* identifiers */
1781         ot->name = "Link to Viewer Node";
1782         ot->description = "Link to viewer node";
1783         ot->idname = "NODE_OT_link_viewer";
1784         
1785         /* api callbacks */
1786         ot->exec = node_active_link_viewer;
1787         ot->poll = composite_node_active;
1788         
1789         /* flags */
1790         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1791 }
1792
1793
1794
1795 /* return 0, nothing done */
1796 static int UNUSED_FUNCTION(node_mouse_groupheader)(SpaceNode *snode)
1797 {
1798         bNode *gnode;
1799         float mx=0, my=0;
1800 // XXX  int mval[2];
1801         
1802         gnode= node_tree_get_editgroup(snode->nodetree);
1803         if (gnode==NULL) return 0;
1804         
1805 // XXX  getmouseco_areawin(mval);
1806 // XXX  areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1807         
1808         /* click in header or outside? */
1809         if (BLI_in_rctf(&gnode->totr, mx, my)==0) {
1810                 rctf rect= gnode->totr;
1811                 
1812                 rect.ymax += NODE_DY;
1813                 if (BLI_in_rctf(&rect, mx, my)==0)
1814                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1815 //              else
1816 // XXX                  transform_nodes(snode->nodetree, 'g', "Move group");
1817                 
1818                 return 1;
1819         }
1820         return 0;
1821 }
1822
1823 /* checks snode->mouse position, and returns found node/socket */
1824 /* type is SOCK_IN and/or SOCK_OUT */
1825 int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
1826 {
1827         bNode *node;
1828         bNodeSocket *sock;
1829         rctf rect;
1830         
1831         *nodep= NULL;
1832         *sockp= NULL;
1833         
1834         /* check if we click in a socket */
1835         for (node= snode->edittree->nodes.first; node; node= node->next) {
1836                 
1837                 rect.xmin = snode->mx - (NODE_SOCKSIZE+4);
1838                 rect.ymin = snode->my - (NODE_SOCKSIZE+4);
1839                 rect.xmax = snode->mx + (NODE_SOCKSIZE+4);
1840                 rect.ymax = snode->my + (NODE_SOCKSIZE+4);
1841                 
1842                 if (!(node->flag & NODE_HIDDEN)) {
1843                         /* extra padding inside and out - allow dragging on the text areas too */
1844                         if (in_out == SOCK_IN) {
1845                                 rect.xmax += NODE_SOCKSIZE;
1846                                 rect.xmin -= NODE_SOCKSIZE*4;
1847                         }
1848                         else if (in_out == SOCK_OUT) {
1849                                 rect.xmax += NODE_SOCKSIZE*4;
1850                                 rect.xmin -= NODE_SOCKSIZE;
1851                         }
1852                 }
1853                 
1854                 if (in_out & SOCK_IN) {
1855                         for (sock= node->inputs.first; sock; sock= sock->next) {
1856                                 if (!nodeSocketIsHidden(sock)) {
1857                                         if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1858                                                 if (node == visible_node(snode, &rect)) {
1859                                                         *nodep= node;
1860                                                         *sockp= sock;
1861                                                         return 1;
1862                                                 }
1863                                         }
1864                                 }
1865                         }
1866                 }
1867                 if (in_out & SOCK_OUT) {
1868                         for (sock= node->outputs.first; sock; sock= sock->next) {
1869                                 if (!nodeSocketIsHidden(sock)) {
1870                                         if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1871                                                 if (node == visible_node(snode, &rect)) {
1872                                                         *nodep= node;
1873                                                         *sockp= sock;
1874                                                         return 1;
1875                                                 }
1876                                         }
1877                                 }
1878                         }
1879                 }
1880         }
1881         
1882         /* check group sockets
1883          * NB: using ngroup->outputs as input sockets and vice versa here!
1884          */
1885         if (in_out & SOCK_IN) {
1886                 for (sock= snode->edittree->outputs.first; sock; sock= sock->next) {
1887                         if (!nodeSocketIsHidden(sock)) {
1888                                 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1889                                         *nodep= NULL;   /* NULL node pointer indicates group socket */
1890                                         *sockp= sock;
1891                                         return 1;
1892                                 }
1893                         }
1894                 }
1895         }
1896         if (in_out & SOCK_OUT) {
1897                 for (sock= snode->edittree->inputs.first; sock; sock= sock->next) {
1898                         if (!nodeSocketIsHidden(sock)) {
1899                                 if (BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1900                                         *nodep= NULL;   /* NULL node pointer indicates group socket */
1901                                         *sockp= sock;
1902                                         return 1;
1903                                 }
1904                         }
1905                 }
1906         }
1907         
1908         return 0;
1909 }
1910
1911 static int outside_group_rect(SpaceNode *snode)
1912 {
1913         bNode *gnode= node_tree_get_editgroup(snode->nodetree);
1914         if (gnode) {
1915                 return (snode->mx <  gnode->totr.xmin ||
1916                         snode->mx >= gnode->totr.xmax ||
1917                         snode->my <  gnode->totr.ymin ||
1918                         snode->my >= gnode->totr.ymax);
1919         }
1920         return 0;
1921 }
1922
1923 /* ****************** Add *********************** */
1924
1925
1926 typedef struct bNodeListItem {
1927         struct bNodeListItem *next, *prev;
1928         struct bNode *node;     
1929 } bNodeListItem;
1930
1931 static int sort_nodes_locx(void *a, void *b)
1932 {
1933         bNodeListItem *nli1 = (bNodeListItem *)a;
1934         bNodeListItem *nli2 = (bNodeListItem *)b;
1935         bNode *node1 = nli1->node;
1936         bNode *node2 = nli2->node;
1937         
1938         if (node1->locx > node2->locx)
1939                 return 1;
1940         else 
1941                 return 0;
1942 }
1943
1944 static int socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, int allow_used)
1945 {
1946         if (nodeSocketIsHidden(sock))
1947                 return 0;
1948         
1949         if (!allow_used && (sock->flag & SOCK_IN_USE))
1950                 return 0;
1951         
1952         return 1;
1953 }
1954
1955 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
1956 {
1957         bNodeSocket *sock;
1958         
1959         /* first look for selected output */
1960         for (sock=node->outputs.first; sock; sock=sock->next) {
1961                 if (!socket_is_available(ntree, sock, allow_multiple))
1962                         continue;
1963                 
1964                 if (sock->flag & SELECT)
1965                         return sock;
1966         }
1967         
1968         /* try to find a socket with a matching name */
1969         for (sock=node->outputs.first; sock; sock=sock->next) {
1970                 if (!socket_is_available(ntree, sock, allow_multiple))
1971                         continue;
1972
1973                 /* check for same types */
1974                 if (sock->type == sock_target->type) {
1975                         if (strcmp(sock->name, sock_target->name)==0)
1976                                 return sock;
1977                 }
1978         }
1979         
1980         /* otherwise settle for the first available socket of the right type */
1981         for (sock=node->outputs.first; sock; sock=sock->next) {
1982
1983                 if (!socket_is_available(ntree, sock, allow_multiple))
1984                         continue;
1985                 
1986                 /* check for same types */
1987                 if (sock->type == sock_target->type) {
1988                         return sock;
1989                 }
1990         }
1991         
1992         return NULL;
1993 }
1994
1995 /* this is a bit complicated, but designed to prioritize finding
1996  * sockets of higher types, such as image, first */
1997 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
1998 {
1999         bNodeSocket *sock;
2000         int socktype, maxtype=0;
2001         int a = 0;
2002         
2003         for (sock=node->inputs.first; sock; sock=sock->next) {
2004                 maxtype = MAX2(sock->type, maxtype);
2005         }
2006         
2007         /* find sockets of higher 'types' first (i.e. image) */
2008         for (socktype=maxtype; socktype >= 0; socktype--) {
2009                 for (sock=node->inputs.first; sock; sock=sock->next) {
2010                         
2011                         if (!socket_is_available(ntree, sock, replace)) {
2012                                 a++;
2013                                 continue;
2014                         }
2015                                 
2016                         if (sock->type == socktype) {
2017                                 /* increment to make sure we don't keep finding 
2018                                  * the same socket on every attempt running this function */
2019                                 a++;
2020                                 if (a > num)
2021                                         return sock;
2022                         }
2023                 }
2024         }
2025         
2026         return NULL;
2027 }
2028
2029 static int snode_autoconnect_input(SpaceNode *snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to, int replace)
2030 {
2031         bNodeTree *ntree = snode->edittree;
2032         bNodeLink *link;
2033         
2034         /* then we can connect */
2035         if (replace)
2036                 nodeRemSocketLinks(ntree, sock_to);
2037         
2038         link = nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
2039         /* validate the new link */
2040         ntreeUpdateTree(ntree);
2041         if (!(link->flag & NODE_LINK_VALID)) {
2042                 nodeRemLink(ntree, link);
2043                 return 0;
2044         }
2045         
2046         snode_update(snode, node_to);
2047         return 1;
2048 }
2049
2050 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
2051 {
2052         bNodeTree *ntree = snode->edittree;
2053         ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
2054         bNodeListItem *nli;
2055         bNode *node;
2056         int i, numlinks=0;
2057         
2058         for (node= ntree->nodes.first; node; node= node->next) {
2059                 if (node->flag & NODE_SELECT) {
2060                         nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
2061                         nli->node = node;
2062                         BLI_addtail(nodelist, nli);
2063                 }
2064         }
2065         
2066         /* sort nodes left to right */
2067         BLI_sortlist(nodelist, sort_nodes_locx);
2068         
2069         for (nli=nodelist->first; nli; nli=nli->next) {
2070                 bNode *node_fr, *node_to;
2071                 bNodeSocket *sock_fr, *sock_to;
2072                 int has_selected_inputs = 0;
2073                 
2074                 if (nli->next == NULL) break;
2075                 
2076                 node_fr = nli->node;
2077                 node_to = nli->next->node;
2078                 
2079                 /* if there are selected sockets, connect those */
2080                 for (sock_to = node_to->inputs.first; sock_to; sock_to=sock_to->next) {
2081                         if (sock_to->flag & SELECT) {
2082                                 has_selected_inputs = 1;
2083                                 
2084                                 if (!socket_is_available(ntree, sock_to, replace))
2085                                         continue;
2086                                 
2087                                 /* check for an appropriate output socket to connect from */
2088                                 sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
2089                                 if (!sock_fr)
2090                                         continue;
2091         
2092                                 if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace))
2093                                         ++numlinks;
2094                         }
2095                 }
2096                 
2097                 if (!has_selected_inputs) {
2098                         /* no selected inputs, connect by finding suitable match */
2099                         int num_inputs = BLI_countlist(&node_to->inputs);
2100                         
2101                         for (i=0; i<num_inputs; i++) {
2102                                 
2103                                 /* find the best guess input socket */
2104                                 sock_to = best_socket_input(ntree, node_to, i, replace);
2105                                 if (!sock_to)
2106                                         continue;
2107                                 
2108                                 /* check for an appropriate output socket to connect from */
2109                                 sock_fr = best_socket_output(ntree, node_fr, sock_to, allow_multiple);
2110                                 if (!sock_fr)
2111                                         continue;
2112         
2113                                 if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) {
2114                                         ++numlinks;
2115                                         break;
2116                                 }
2117                         }
2118                 }
2119         }
2120         
2121         if (numlinks > 0) {
2122                 ntreeUpdateTree(ntree);
2123         }
2124         
2125         BLI_freelistN(nodelist);
2126         MEM_freeN(nodelist);
2127 }
2128
2129 /* can be called from menus too, but they should do own undopush and redraws */
2130 bNode *node_add_node(SpaceNode *snode, Main *bmain, Scene *scene, bNodeTemplate *ntemp, float locx, float locy)
2131 {
2132         bNode *node= NULL, *gnode;
2133         
2134         node_deselect_all(snode);
2135         
2136         node = nodeAddNode(snode->edittree, ntemp);
2137         
2138         /* generics */
2139         if (node) {
2140                 node->locx= locx;
2141                 node->locy= locy + 60.0f;               // arbitrary.. so its visible, (0,0) is top of node
2142                 node_select(node);
2143                 
2144                 gnode= node_tree_get_editgroup(snode->nodetree);
2145                 if (gnode) {
2146                         node->locx -= gnode->locx;
2147                         node->locy -= gnode->locy;
2148                 }
2149
2150                 ntreeUpdateTree(snode->edittree);
2151                 ED_node_set_active(bmain, snode->edittree, node);
2152                 
2153                 if (snode->nodetree->type==NTREE_COMPOSIT) {
2154                         if (ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE)) {
2155                                 node->id = &scene->id;
2156                         }
2157                         else if (ELEM3(node->type, CMP_NODE_MOVIECLIP, CMP_NODE_MOVIEDISTORTION, CMP_NODE_STABILIZE2D)) {
2158                                 node->id = (ID *)scene->clip;
2159                         }
2160                         
2161                         ntreeCompositForceHidden(snode->edittree, scene);
2162                 }
2163                         
2164                 if (node->id)
2165                         id_us_plus(node->id);
2166                         
2167                 snode_update(snode, node);
2168         }
2169         
2170         if (snode->nodetree->type==NTREE_TEXTURE) {
2171                 ntreeTexCheckCyclics(snode->edittree);
2172         }
2173         
2174         return node;
2175 }
2176
2177 /* ****************** Duplicate *********************** */
2178
2179 static int node_duplicate_exec(bContext *C, wmOperator *op)
2180 {
2181         SpaceNode *snode= CTX_wm_space_node(C);
2182         bNodeTree *ntree= snode->edittree;
2183         bNode *node, *newnode, *lastnode;
2184         bNodeLink *link, *newlink, *lastlink;
2185         int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
2186         
2187         ED_preview_kill_jobs(C);
2188         
2189         lastnode = ntree->nodes.last;
2190         for (node= ntree->nodes.first; node; node= node->next) {
2191                 if (node->flag & SELECT) {
2192                         newnode = nodeCopyNode(ntree, node);
2193                         
2194                         if (newnode->id) {
2195                                 /* simple id user adjustment, node internal functions don't touch this
2196                                  * but operators and readfile.c do. */
2197                                 id_us_plus(newnode->id);
2198                                 /* to ensure redraws or rerenders happen */
2199                                 ED_node_changed_update(snode->id, newnode);
2200                         }
2201                 }
2202                 
2203                 /* make sure we don't copy new nodes again! */
2204                 if (node==lastnode)
2205                         break;
2206         }
2207         
2208         /* copy links between selected nodes
2209          * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy!
2210          */
2211         lastlink = ntree->links.last;
2212         for (link=ntree->links.first; link; link=link->next) {
2213                 /* This creates new links between copied nodes.
2214                  * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)!
2215                  */
2216                 if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
2217                     (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT))))
2218                 {
2219                         newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink");
2220                         newlink->flag = link->flag;
2221                         newlink->tonode = link->tonode->new_node;
2222                         newlink->tosock = link->tosock->new_sock;
2223                         if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
2224                                 newlink->fromnode = link->fromnode->new_node;
2225                                 newlink->fromsock = link->fromsock->new_sock;
2226                         }
2227                         else {
2228                                 /* input node not copied, this keeps the original input linked */
2229                                 newlink->fromnode = link->fromnode;
2230                                 newlink->fromsock = link->fromsock;
2231                         }
2232                         
2233                         BLI_addtail(&ntree->links, newlink);
2234                 }
2235                 
2236                 /* make sure we don't copy new links again! */
2237                 if (link==lastlink)
2238                         break;
2239         }
2240         
2241         /* deselect old nodes, select the copies instead */
2242         for (node= ntree->nodes.first; node; node= node->next) {
2243                 if (node->flag & SELECT) {
2244                         /* has been set during copy above */
2245                         newnode = node->new_node;
2246                         
2247                         node_deselect(node);
2248                         node->flag &= ~NODE_ACTIVE;
2249                         node_select(newnode);
2250                 }
2251                 
2252                 /* make sure we don't copy new nodes again! */
2253                 if (node==lastnode)
2254                         break;
2255         }
2256         
2257         ntreeUpdateTree(snode->edittree);
2258         
2259         snode_notify(C, snode);
2260         snode_dag_update(C, snode);
2261
2262         return OPERATOR_FINISHED;
2263 }
2264
2265 void NODE_OT_duplicate(wmOperatorType *ot)
2266 {
2267         /* identifiers */
2268         ot->name = "Duplicate Nodes";
2269         ot->description = "Duplicate selected nodes";
2270         ot->idname = "NODE_OT_duplicate";
2271         
2272         /* api callbacks */
2273         ot->exec = node_duplicate_exec;
2274         ot->poll = ED_operator_node_active;
2275         
2276         /* flags */
2277         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2278         
2279         RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
2280 }
2281
2282 /* *************************** add link op ******************** */
2283
2284 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
2285 {
2286         bNodeLink *tlink;
2287         bNodeSocket *sock;
2288         
2289         if (tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
2290                 
2291                 for (tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
2292                         if (link!=tlink && tlink->tosock==link->tosock)
2293                                 break;
2294                 }
2295                 if (tlink) {
2296                         /* try to move the existing link to the next available socket */
2297                         if (tlink->tonode) {
2298                                 /* is there a free input socket with the target type? */
2299                                 for (sock= tlink->tonode->inputs.first; sock; sock= sock->next) {
2300                                         if (sock->type==tlink->tosock->type)
2301                                                 if (nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
2302                                                         break;
2303                                 }
2304                                 if (sock) {
2305                                         tlink->tosock= sock;
2306                                         sock->flag &= ~SOCK_HIDDEN;
2307                                 }
2308                                 else {
2309                                         nodeRemLink(snode->edittree, tlink);
2310                                 }
2311                         }
2312                         else
2313                                 nodeRemLink(snode->edittree, tlink);
2314                         
2315                         snode->edittree->update |= NTREE_UPDATE_LINKS;
2316                 }
2317         }
2318 }
2319
2320 /* loop that adds a nodelink, called by function below  */
2321 /* in_out = starting socket */
2322 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
2323 {
2324         SpaceNode *snode= CTX_wm_space_node(C);
2325         ARegion *ar= CTX_wm_region(C);
2326         bNodeLinkDrag *nldrag= op->customdata;
2327         bNode *tnode;
2328         bNodeSocket *tsock= NULL;
2329         bNodeLink *link;
2330         LinkData *linkdata;
2331         int in_out;
2332
2333         in_out = nldrag->in_out;
2334         
2335         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2336                                                          &snode->mx, &snode->my);
2337
2338         switch (event->type) {
2339                 case MOUSEMOVE:
2340                         
2341                         if (in_out==SOCK_OUT) {
2342                                 if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
2343                                         for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) {
2344                                                 link = linkdata->data;
2345                                                 
2346                                                 /* skip if this is already the target socket */
2347                                                 if (link->tosock == tsock)
2348                                                         continue;
2349                                                 /* skip if socket is on the same node as the fromsock */
2350                                                 if (tnode && link->fromnode == tnode)
2351                                                         continue;
2352                                                 
2353                                                 /* attach links to the socket */
2354                                                 link->tonode = tnode;
2355                                                 link->tosock = tsock;
2356                                                 /* add it to the node tree temporarily */
2357                                                 if (link->prev==NULL && link->next==NULL)
2358                                                         BLI_addtail(&snode->edittree->links, link);
2359                                                 
2360                                                 snode->edittree->update |= NTREE_UPDATE_LINKS;
2361                                         }
2362                                         ntreeUpdateTree(snode->edittree);
2363                                 }
2364                                 else {
2365                                         int do_update = 0;
2366                                         for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) {
2367                                                 link = linkdata->data;
2368                                                 
2369                                                 if (link->tonode || link->tosock) {
2370                                                         BLI_remlink(&snode->edittree->links, link);
2371                                                         link->prev = link->next = NULL;
2372                                                         link->tonode= NULL;
2373                                                         link->tosock= NULL;
2374                                                         
2375                                                         snode->edittree->update |= NTREE_UPDATE_LINKS;
2376                                                         do_update = 1;
2377                                                 }
2378                                         }
2379                                         if (do_update)
2380                                                 ntreeUpdateTree(snode->edittree);
2381                                 }
2382                         }
2383                         else {
2384                                 if (node_find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
2385                                         for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) {
2386                                                 link = linkdata->data;
2387                                                 
2388                                                 /* skip if this is already the target socket */
2389                                                 if (link->fromsock == tsock)
2390                                                         continue;
2391                                                 /* skip if socket is on the same node as the fromsock */
2392                                                 if (tnode && link->tonode == tnode)
2393                                                         continue;
2394                                                 
2395                                                 /* attach links to the socket */
2396                                                 link->fromnode = tnode;
2397                                                 link->fromsock = tsock;
2398                                                 /* add it to the node tree temporarily */
2399                                                 if (link->prev==NULL && link->next==NULL)
2400                                                         BLI_addtail(&snode->edittree->links, link);
2401                                                 
2402                                                 snode->edittree->update |= NTREE_UPDATE_LINKS;
2403                                         }
2404                                         ntreeUpdateTree(snode->edittree);
2405                                 }
2406                                 else {
2407                                         int do_update = 0;
2408                                         for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) {
2409                                                 link = linkdata->data;
2410                                                 
2411                                                 if (link->fromnode || link->fromsock) {
2412                                                         BLI_remlink(&snode->edittree->links, link);
2413                                                         link->prev = link->next = NULL;
2414                                                         link->fromnode= NULL;
2415                                                         link->fromsock= NULL;
2416                                                         
2417                                                         snode->edittree->update |= NTREE_UPDATE_LINKS;
2418                                                         do_update = 1;
2419                                                 }
2420                                         }
2421                                         if (do_update)
2422                                                 ntreeUpdateTree(snode->edittree);
2423                                 }
2424                         }
2425                         
2426                         ED_region_tag_redraw(ar);
2427                         break;
2428                         
2429                 case LEFTMOUSE:
2430                 case RIGHTMOUSE:
2431                 case MIDDLEMOUSE: {
2432                         for (linkdata=nldrag->links.first; linkdata; linkdata=linkdata->next) {
2433                                 link = linkdata->data;
2434                                 
2435                                 if (link->tosock && link->fromsock) {
2436                                         /* send changed events for original tonode and new */
2437                                         if (link->tonode)
2438                                                 snode_update(snode, link->tonode);
2439                                         
2440                                         /* we might need to remove a link */
2441                                         if (in_out==SOCK_OUT)
2442                                                 node_remove_extra_links(snode, link->tosock, link);
2443                                         
2444                                         /* when linking to group outputs, update the socket type */
2445                                         /* XXX this should all be part of a generic update system */
2446                                         if (!link->tonode) {
2447                                                 if(link->tosock->type != link->fromsock->type)
2448                                                         nodeSocketSetType(link->tosock, link->fromsock->type);
2449                                         }
2450                                 }
2451                                 else if (outside_group_rect(snode) && (link->tonode || link->fromnode)) {
2452                                         /* automatically add new group socket */
2453                                         if (link->tonode && link->tosock) {
2454                                                 link->fromsock = node_group_expose_socket(snode->edittree, link->tosock, SOCK_IN);
2455                                                 link->fromnode = NULL;
2456                                                 if (link->prev==NULL && link->next==NULL)
2457                                                         BLI_addtail(&snode->edittree->links, link);
2458                                                 
2459                                                 snode->edittree->update |= NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_LINKS;
2460                                         }
2461                                         else if (link->fromnode && link->fromsock) {
2462                                                 link->tosock = node_group_expose_socket(snode->edittree, link->fromsock, SOCK_OUT);
2463                                                 link->tonode = NULL;
2464                                                 if (link->prev==NULL && link->next==NULL)
2465                                                         BLI_addtail(&snode->edittree->links, link);
2466                                                 
2467                                                 snode->edittree->update |= NTREE_UPDATE_GROUP_OUT | NTREE_UPDATE_LINKS;
2468                                         }
2469                                 }
2470                                 else
2471                                         nodeRemLink(snode->edittree, link);
2472                         }
2473                         
2474                         ntreeUpdateTree(snode->edittree);
2475                         snode_notify(C, snode);
2476                         snode_dag_update(C, snode);
2477                         
2478                         BLI_remlink(&snode->linkdrag, nldrag);
2479                         /* links->data pointers are either held by the tree or freed already */
2480                         BLI_freelistN(&nldrag->links);
2481                         MEM_freeN(nldrag);
2482                         
2483                         return OPERATOR_FINISHED;
2484                 }
2485         }
2486         
2487         return OPERATOR_RUNNING_MODAL;
2488 }
2489
2490 /* return 1 when socket clicked */
2491 static bNodeLinkDrag *node_link_init(SpaceNode *snode, int detach)
2492 {
2493         bNode *node;
2494         bNodeSocket *sock;
2495         bNodeLink *link, *link_next, *oplink;
2496         bNodeLinkDrag *nldrag = NULL;
2497         LinkData *linkdata;
2498         int num_links;
2499         
2500         /* output indicated? */
2501         if (node_find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
2502                 nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
2503                 
2504                 num_links = nodeCountSocketLinks(snode->edittree, sock);
2505                 if (num_links > 0 && (num_links >= sock->limit || detach)) {
2506                         /* dragged links are fixed on input side */
2507                         nldrag->in_out = SOCK_IN;
2508                         /* detach current links and store them in the operator data */
2509                         for (link= snode->edittree->links.first; link; link= link_next) {
2510                                 link_next = link->next;
2511                                 if (link->fromsock==sock) {
2512                                         linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
2513                                         linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
2514                                         *oplink = *link;
2515                                         BLI_addtail(&nldrag->links, linkdata);
2516                                         nodeRemLink(snode->edittree, link);
2517                                 }
2518                         }
2519                 }
2520                 else {
2521                         /* dragged links are fixed on output side */
2522                         nldrag->in_out = SOCK_OUT;
2523                         /* create a new link */
2524                         linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
2525                         linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
2526                         oplink->fromnode = node;
2527                         oplink->fromsock = sock;
2528                         BLI_addtail(&nldrag->links, linkdata);
2529                 }
2530         }
2531         /* or an input? */
2532         else if (node_find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
2533                 nldrag= MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata");
2534                 
2535                 num_links = nodeCountSocketLinks(snode->edittree, sock);
2536                 if (num_links > 0 && (num_links >= sock->limit || detach)) {
2537                         /* dragged links are fixed on output side */
2538                         nldrag->in_out = SOCK_OUT;
2539                         /* detach current links and store them in the operator data */
2540                         for (link= snode->edittree->links.first; link; link= link_next) {
2541                                 link_next = link->next;
2542                                 if (link->tosock==sock) {
2543                                         linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
2544                                         linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
2545                                         *oplink = *link;
2546                                         BLI_addtail(&nldrag->links, linkdata);
2547                                         nodeRemLink(snode->edittree, link);
2548                                         
2549                                         /* send changed event to original link->tonode */
2550                                         if (node)
2551                                                 snode_update(snode, node);
2552                                 }
2553                         }
2554                 }
2555                 else {
2556                         /* dragged links are fixed on input side */
2557                         nldrag->in_out = SOCK_IN;
2558                         /* create a new link */
2559                         linkdata = MEM_callocN(sizeof(LinkData), "drag link op link data");
2560                         linkdata->data = oplink = MEM_callocN(sizeof(bNodeLink), "drag link op link");
2561                         oplink->tonode = node;
2562                         oplink->tosock = sock;
2563                         BLI_addtail(&nldrag->links, linkdata);
2564                 }
2565         }
2566         
2567         return nldrag;
2568 }
2569
2570 static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
2571 {
2572         SpaceNode *snode= CTX_wm_space_node(C);
2573         ARegion *ar= CTX_wm_region(C);
2574         bNodeLinkDrag *nldrag;
2575         int detach = RNA_boolean_get(op->ptr, "detach");
2576         
2577         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1],
2578                                                          &snode->mx, &snode->my);
2579
2580         ED_preview_kill_jobs(C);
2581
2582         nldrag = node_link_init(snode, detach);
2583         
2584         if (nldrag) {
2585                 op->customdata= nldrag;
2586                 BLI_addtail(&snode->linkdrag, nldrag);
2587                 
2588                 /* add modal handler */
2589                 WM_event_add_modal_handler(C, op);
2590                 
2591                 return OPERATOR_RUNNING_MODAL;
2592         }
2593         else
2594                 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
2595 }
2596
2597 static int node_link_cancel(bContext *C, wmOperator *op)
2598 {
2599         SpaceNode *snode= CTX_wm_space_node(C);
2600         bNodeLinkDrag *nldrag= op->customdata;
2601         
2602         BLI_remlink(&snode->linkdrag, nldrag);
2603         
2604         BLI_freelistN(&nldrag->links);
2605         MEM_freeN(nldrag);
2606         
2607         return OPERATOR_CANCELLED;
2608 }
2609
2610 void NODE_OT_link(wmOperatorType *ot)
2611 {
2612         /* identifiers */
2613         ot->name = "Link Nodes";
2614         ot->idname = "NODE_OT_link";
2615         ot->description = "Use the mouse to create a link between two nodes";
2616         
2617         /* api callbacks */
2618         ot->invoke = node_link_invoke;
2619         ot->modal = node_link_modal;
2620 //      ot->exec = node_link_exec;
2621         ot->poll = ED_operator_node_active;
2622         ot->cancel = node_link_cancel;
2623         
2624         /* flags */
2625         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2626         
2627         RNA_def_boolean(ot->srna, "detach", FALSE, "Detach", "Detach and redirect existing links");
2628 }
2629
2630 /* ********************** Make Link operator ***************** */
2631
2632 /* makes a link between selected output and input sockets */
2633 static int node_make_link_exec(bContext *C, wmOperator *op)
2634 {
2635         SpaceNode *snode= CTX_wm_space_node(C);
2636         int replace = RNA_boolean_get(op->ptr, "replace");
2637
2638         ED_preview_kill_jobs(C);
2639
2640         snode_autoconnect(snode, 1, replace);
2641
2642         /* deselect sockets after linking */
2643         node_deselect_all_input_sockets(snode, 0);
2644         node_deselect_all_output_sockets(snode, 0);
2645
2646         ntreeUpdateTree(snode->edittree);
2647         snode_notify(C, snode);
2648         snode_dag_update(C, snode);
2649         
2650         return OPERATOR_FINISHED;
2651 }
2652
2653 void NODE_OT_link_make(wmOperatorType *ot)
2654 {
2655         /* identifiers */
2656         ot->name = "Make Links";
2657         ot->description = "Makes a link between selected output in input sockets";
2658         ot->idname = "NODE_OT_link_make";
2659         
2660         /* callbacks */
2661         ot->exec = node_make_link_exec;
2662         ot->poll = ED_operator_node_active; // XXX we need a special poll which checks that there are selected input/output sockets
2663         
2664         /* flags */
2665         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2666         
2667         RNA_def_boolean(ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
2668 }
2669
2670 /* ********************** Cut Link operator ***************** */
2671
2672 #define LINK_RESOL 12
2673 static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
2674 {
2675         float coord_array[LINK_RESOL+1][2];
2676         int i, b;
2677         
2678         if (node_link_bezier_points(NULL, NULL, link, coord_array, LINK_RESOL)) {
2679
2680                 for (i=0; i<tot-1; i++)
2681                         for (b=0; b<LINK_RESOL; b++)
2682                                 if (isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0)
2683                                         return 1;
2684         }
2685         return 0;
2686 }
2687
2688 static int cut_links_exec(bContext *C, wmOperator *op)
2689 {
2690         SpaceNode *snode= CTX_wm_space_node(C);
2691         ARegion *ar= CTX_wm_region(C);
2692         float mcoords[256][2];
2693         int i= 0;
2694         
2695         RNA_BEGIN (op->ptr, itemptr, "path")
2696         {
2697                 float loc[2];
2698                 
2699                 RNA_float_get_array(&itemptr, "loc", loc);
2700                 UI_view2d_region_to_view(&ar->v2d, (int)loc[0], (int)loc[1],
2701                                                                  &mcoords[i][0], &mcoords[i][1]);
2702                 i++;
2703                 if (i>= 256) break;
2704         }
2705         RNA_END;
2706         
2707         if (i>1) {
2708                 bNodeLink *link, *next;
2709
2710                 ED_preview_kill_jobs(C);
2711                 
2712                 for (link= snode->edittree->links.first; link; link= next) {
2713                         next= link->next;
2714                         
2715                         if (cut_links_intersect(link, mcoords, i)) {
2716                                 snode_update(snode, link->tonode);
2717                                 nodeRemLink(snode->edittree, link);
2718                         }
2719                 }
2720                 
2721                 ntreeUpdateTree(snode->edittree);
2722                 snode_notify(C, snode);
2723                 snode_dag_update(C, snode);
2724                 
2725                 return OPERATOR_FINISHED;
2726         }
2727         
2728         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
2729 }
2730
2731 void NODE_OT_links_cut(wmOperatorType *ot)
2732 {
2733         PropertyRNA *prop;
2734         
2735         ot->name = "Cut links";
2736         ot->idname = "NODE_OT_links_cut";
2737         ot->description = "Use the mouse to cut (remove) some links";
2738         
2739         ot->invoke = WM_gesture_lines_invoke;
2740         ot->modal = WM_gesture_lines_modal;
2741         ot->exec = cut_links_exec;
2742         ot->cancel = WM_gesture_lines_cancel;
2743         
2744         ot->poll = ED_operator_node_active;
2745         
2746         /* flags */
2747         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2748         
2749         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
2750         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
2751         /* internal */
2752         RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
2753 }
2754
2755 /* ********************** Detach links operator ***************** */
2756
2757 static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
2758 {
2759         SpaceNode *snode= CTX_wm_space_node(C);
2760         bNodeTree *ntree= snode->edittree;
2761         bNode *node;
2762         
2763         ED_preview_kill_jobs(C);
2764         
2765         for (node= ntree->nodes.first; node; node= node->next) {
2766                 if (node->flag & SELECT) {
2767                         nodeInternalRelink(ntree, node);
2768                 }
2769         }
2770         
2771         ntreeUpdateTree(ntree);
2772         
2773         snode_notify(C, snode);
2774         snode_dag_update(C, snode);
2775
2776         return OPERATOR_FINISHED;
2777 }
2778
2779 void NODE_OT_links_detach(wmOperatorType *ot)
2780 {
2781         ot->name = "Detach Links";
2782         ot->idname = "NODE_OT_links_detach";
2783         ot->description = "Remove all links to selected nodes, and try to connect neighbor nodes together";
2784         
2785         ot->exec = detach_links_exec;
2786         ot->poll = ED_operator_node_active;
2787         
2788         /* flags */
2789         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2790 }
2791
2792 /* *********************  automatic node insert on dragging ******************* */
2793
2794 /* assumes sockets in list */
2795 static bNodeSocket *socket_best_match(ListBase *sockets)
2796 {
2797         bNodeSocket *sock;
2798         int type, maxtype=0;
2799         
2800         /* find type range */
2801         for (sock=sockets->first; sock; sock=sock->next)
2802                 maxtype = MAX2(sock->type, maxtype);
2803         
2804         /* try all types, starting from 'highest' (i.e. colors, vectors, values) */
2805         for (type=maxtype; type >= 0; --type) {
2806                 for (sock= sockets->first; sock; sock= sock->next) {
2807                         if (!nodeSocketIsHidden(sock) && type==sock->type) {
2808                                 return sock;
2809                         }
2810                 }
2811         }
2812         
2813         /* no visible sockets, unhide first of highest type */
2814         for (type=maxtype; type >= 0; --type) {
2815                 for (sock= sockets->first; sock; sock= sock->next) {
2816                         if (type==sock->type) {
2817                                 sock->flag &= ~SOCK_HIDDEN;
2818                                 return sock;
2819                         }
2820                 }
2821         }
2822         
2823         return NULL;
2824 }
2825
2826 /* prevent duplicate testing code below */
2827 static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select)
2828 {
2829         SpaceNode *snode= sa?sa->spacedata.first:NULL;
2830         bNode *node;
2831         bNodeLink *link;
2832         
2833         /* no unlucky accidents */
2834         if (sa==NULL || sa->spacetype!=SPACE_NODE) return NULL;
2835         
2836         *select= NULL;
2837         
2838         for (node= snode->edittree->nodes.first; node; node= node->next) {
2839                 if (node->flag & SELECT) {
2840                         if (*select)
2841                                 break;
2842                         else
2843                                 *select= node;
2844                 }
2845         }
2846         /* only one selected */
2847         if (node || *select==NULL) return NULL;
2848         
2849         /* correct node */
2850         if ((*select)->inputs.first==NULL || (*select)->outputs.first==NULL) return NULL;
2851         
2852         /* test node for links */
2853         for (link= snode->edittree->links.first; link; link=link->next) {
2854                 if (link->tonode == *select || link->fromnode == *select)
2855                         return NULL;
2856         }
2857         
2858         return snode;
2859 }
2860
2861 /* assumes link with NODE_LINKFLAG_HILITE set */
2862 void ED_node_link_insert(ScrArea *sa)
2863 {
2864         bNode *node, *select;
2865         SpaceNode *snode= ed_node_link_conditions(sa, &select);
2866         bNodeLink *link;
2867         bNodeSocket *sockto;
2868         
2869         if (snode==NULL) return;
2870         
2871         /* get the link */
2872         for (link= snode->edittree->links.first; link; link=link->next)
2873                 if (link->flag & NODE_LINKFLAG_HILITE)
2874                         break;
2875         
2876         if (link) {
2877                 node= link->tonode;
2878                 sockto= link->tosock;
2879                 
2880                 link->tonode= select;
2881                 link->tosock= socket_best_match(&select->inputs);
2882                 link->flag &= ~NODE_LINKFLAG_HILITE;
2883                 
2884                 nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs), node, sockto);
2885                 ntreeUpdateTree(snode->edittree);       /* needed for pointers */
2886                 snode_update(snode, select);
2887                 ED_node_changed_update(snode->id, select);
2888         }
2889 }
2890
2891
2892 /* test == 0, clear all intersect flags */
2893 void ED_node_link_intersect_test(ScrArea *sa, int test)
2894 {
2895         bNode *select;
2896         SpaceNode *snode= ed_node_link_conditions(sa, &select);
2897         bNodeLink *link, *selink=NULL;
2898         float mcoords[6][2];
2899         
2900         if (snode==NULL) return;
2901         
2902         /* clear flags */
2903         for (link= snode->edittree->links.first; link; link=link->next)
2904                 link->flag &= ~NODE_LINKFLAG_HILITE;
2905         
2906         if (test==0) return;
2907         
2908         /* okay, there's 1 node, without links, now intersect */
2909         mcoords[0][0]= select->totr.xmin;
2910         mcoords[0][1]= select->totr.ymin;
2911         mcoords[1][0]= select->totr.xmax;
2912         mcoords[1][1]= select->totr.ymin;
2913         mcoords[2][0]= select->totr.xmax;
2914         mcoords[2][1]= select->totr.ymax;
2915         mcoords[3][0]= select->totr.xmin;
2916         mcoords[3][1]= select->totr.ymax;
2917         mcoords[4][0]= select->totr.xmin;
2918         mcoords[4][1]= select->totr.ymin;
2919         mcoords[5][0]= select->totr.xmax;
2920         mcoords[5][1]= select->totr.ymax;
2921         
2922         /* we only tag a single link for intersect now */
2923         /* idea; use header dist when more? */
2924         for (link= snode->edittree->links.first; link; link=link->next) {
2925                 
2926                 if (cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */
2927                         if (selink)
2928                                 break;
2929                         selink= link;
2930                 }
2931         }
2932                 
2933         if (link==NULL && selink)
2934                 selink->flag |= NODE_LINKFLAG_HILITE;
2935 }
2936
2937
2938 /* ******************************** */
2939 // XXX some code needing updating to operators...
2940
2941
2942 /* goes over all scenes, reads render layers */
2943 static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
2944 {
2945         Main *bmain= CTX_data_main(C);
2946         SpaceNode *snode= CTX_wm_space_node(C);
2947         Scene *curscene= CTX_data_scene(C), *scene;
2948         bNode *node;
2949
2950         ED_preview_kill_jobs(C);
2951
2952         /* first tag scenes unread */
2953         for (scene= bmain->scene.first; scene; scene= scene->id.next)
2954                 scene->id.flag |= LIB_DOIT;
2955
2956         for (node= snode->edittree->nodes.first; node; node= node->next) {
2957                 if (node->type==CMP_NODE_R_LAYERS) {
2958                         ID *id= node->id;
2959                         if (id->flag & LIB_DOIT) {
2960                                 RE_ReadRenderResult(curscene, (Scene *)id);
2961                                 ntreeCompositTagRender((Scene *)id);
2962                                 id->flag &= ~LIB_DOIT;
2963                         }
2964                 }
2965         }
2966         
2967         snode_notify(C, snode);
2968         snode_dag_update(C, snode);
2969
2970         return OPERATOR_FINISHED;
2971 }
2972
2973 void NODE_OT_read_renderlayers(wmOperatorType *ot)
2974 {
2975         
2976         ot->name = "Read Render Layers";
2977         ot->idname = "NODE_OT_read_renderlayers";
2978         ot->description = "Read all render layers of all used scenes";
2979         
2980         ot->exec = node_read_renderlayers_exec;
2981         
2982         ot->poll = composite_node_active;
2983         
2984         /* flags */
2985         ot->flag = 0;
2986 }
2987
2988 static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op))
2989 {
2990         Main *bmain= CTX_data_main(C);
2991         SpaceNode *snode= CTX_wm_space_node(C);
2992         Scene *curscene= CTX_data_scene(C);
2993         Render *re= RE_NewRender(curscene->id.name);
2994
2995         WM_cursor_wait(1);
2996         RE_MergeFullSample(re, bmain, curscene, snode->nodetree);
2997         WM_cursor_wait(0);
2998
2999         /* note we are careful to send the right notifier, as otherwise the
3000          * compositor would reexecute and overwrite the full sample result */
3001         WM_event_add_notifier(C, NC_SCENE|ND_COMPO_RESULT, NULL);
3002
3003         return OPERATOR_FINISHED;
3004 }
3005
3006
3007 void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
3008 {
3009         
3010         ot->name = "Read Full Sample Layers";
3011         ot->idname = "NODE_OT_read_fullsamplelayers";
3012         ot->description = "Read all render layers of current scene, in full sample";
3013         
3014         ot->exec = node_read_fullsamplelayers_exec;
3015         
3016         ot->poll = composite_node_active;
3017         
3018         /* flags */
3019         ot->flag = 0;
3020 }
3021
3022 int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
3023 {
3024         Scene *sce= CTX_data_scene(C);
3025         bNode *node;
3026         
3027         for (node= sce->nodetree->nodes.first; node; node= node->next) {
3028                 if (node->id==(ID *)sce && node->need_exec) {
3029                         break;
3030                 }
3031         }
3032         if (node) {
3033                 SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
3034                 
3035                 if (srl) {
3036                         PointerRNA op_ptr;
3037                         
3038                         WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
3039                         RNA_string_set(&op_ptr, "layer", srl->name);
3040                         RNA_string_set(&op_ptr, "scene", sce->id.name+2);
3041                         
3042                         /* to keep keypositions */
3043                         sce->r.scemode |= R_NO_FRAME_UPDATE;
3044                         
3045                         WM_operator_name_call(C, "RENDER_OT_render", WM_OP_INVOKE_DEFAULT, &op_ptr);
3046
3047                         WM_operator_properties_free(&op_ptr);
3048                         
3049                         return OPERATOR_FINISHED;
3050                 }
3051                    
3052         }
3053         return OPERATOR_CANCELLED;
3054 }
3055
3056 void NODE_OT_render_changed(wmOperatorType *ot)
3057 {
3058         
3059         ot->name = "Render Changed Layer";
3060         ot->idname = "NODE_OT_render_changed";
3061         ot->description = "Render current scene, when input node's layer has been changed";
3062         
3063         ot->exec = node_render_changed_exec;
3064         
3065         ot->poll = composite_node_active;
3066         
3067         /* flags */
3068         ot->flag = 0;
3069 }
3070
3071
3072 /* ****************** Make Group operator ******************* */
3073
3074 static int node_group_make_exec(bContext *C, wmOperator *op)
3075 {
3076         SpaceNode *snode = CTX_wm_space_node(C);
3077         bNode *gnode;
3078         
3079         if (snode->edittree!=snode->nodetree) {
3080                 BKE_report(op->reports, RPT_WARNING, "Can not add a new Group in a Group");
3081                 return OPERATOR_CANCELLED;
3082         }
3083         
3084         /* for time being... is too complex to handle */
3085         if (snode->treetype==NTREE_COMPOSIT) {
3086                 for (gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
3087                         if (gnode->flag & SELECT)
3088                                 if (gnode->type==CMP_NODE_R_LAYERS)
3089                                         break;
3090                 }
3091                 
3092                 if (gnode) {
3093                         BKE_report(op->reports, RPT_WARNING, "Can not add RenderLayer in a Group");
3094                         return OPERATOR_CANCELLED;
3095                 }
3096         }
3097
3098         ED_preview_kill_jobs(C);
3099         
3100         gnode= node_group_make_from_selected(snode->nodetree);
3101         if (gnode==NULL) {
3102                 BKE_report(op->reports, RPT_WARNING, "Can not make Group");
3103                 return OPERATOR_CANCELLED;
3104         }
3105         else {
3106                 nodeSetActive(snode->nodetree, gnode);
3107                 ntreeUpdateTree(snode->nodetree);
3108         }
3109         
3110         snode_notify(C, snode);
3111         snode_dag_update(C, snode);
3112         
3113         return OPERATOR_FINISHED;
3114 }
3115
3116 void NODE_OT_group_make(wmOperatorType *ot)
3117 {
3118         /* identifiers */
3119         ot->name = "Group";
3120         ot->description = "Make group from selected nodes";
3121         ot->idname = "NODE_OT_group_make";
3122         
3123         /* api callbacks */
3124         ot->exec = node_group_make_exec;
3125         ot->poll = ED_operator_node_active;
3126         
3127         /* flags */
3128         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
3129 }
3130
3131 /* ****************** Hide operator *********************** */
3132
3133 static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
3134 {