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