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