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