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