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