correct fsf address
[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
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_action_types.h"
38 #include "DNA_brush_types.h"
39 #include "DNA_color_types.h"
40 #include "DNA_image_types.h"
41 #include "DNA_ipo_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_texture_types.h"
45 #include "DNA_node_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_userdef_types.h"
50
51 #include "BKE_context.h"
52 #include "BKE_colortools.h"
53 #include "BKE_global.h"
54 #include "BKE_image.h"
55 #include "BKE_library.h"
56 #include "BKE_main.h"
57 #include "BKE_node.h"
58 #include "BKE_material.h"
59 #include "BKE_paint.h"
60 #include "BKE_texture.h"
61 #include "BKE_report.h"
62 #include "BKE_scene.h"
63 #include "BKE_utildefines.h"
64
65 #include "BIF_gl.h"
66
67 #include "BLI_math.h"
68 #include "BLI_blenlib.h"
69 #include "BLI_storage_types.h"
70
71 #include "RE_pipeline.h"
72
73 #include "IMB_imbuf_types.h"
74
75 #include "ED_node.h"
76 #include "ED_render.h"
77 #include "ED_screen.h"
78 #include "ED_space_api.h"
79 #include "ED_transform.h"
80 #include "ED_types.h"
81
82 #include "RNA_access.h"
83 #include "RNA_define.h"
84
85 #include "WM_api.h"
86 #include "WM_types.h"
87
88 #include "UI_interface.h"
89 #include "UI_view2d.h"
90  
91 #include "node_intern.h"
92
93 #define SOCK_IN         1
94 #define SOCK_OUT        2
95
96 /* ***************** composite job manager ********************** */
97
98 typedef struct CompoJob {
99         Scene *scene;
100         bNodeTree *ntree;
101         bNodeTree *localtree;
102         short *stop;
103         short *do_update;
104 } CompoJob;
105
106 /* called by compo, only to check job 'stop' value */
107 static int compo_breakjob(void *cjv)
108 {
109         CompoJob *cj= cjv;
110         
111         return *(cj->stop);
112 }
113
114 /* called by compo, wmJob sends notifier */
115 static void compo_redrawjob(void *cjv, char *str)
116 {
117         CompoJob *cj= cjv;
118         
119         *(cj->do_update)= 1;
120 }
121
122 static void compo_freejob(void *cjv)
123 {
124         CompoJob *cj= cjv;
125
126         if(cj->localtree) {
127                 ntreeLocalMerge(cj->localtree, cj->ntree);
128         }
129         MEM_freeN(cj);
130 }
131
132 /* only now we copy the nodetree, so adding many jobs while
133    sliding buttons doesn't frustrate */
134 static void compo_initjob(void *cjv)
135 {
136         CompoJob *cj= cjv;
137
138         cj->localtree= ntreeLocalize(cj->ntree);
139 }
140
141 /* called before redraw notifiers, it moves finished previews over */
142 static void compo_updatejob(void *cjv)
143 {
144         CompoJob *cj= cjv;
145         
146         ntreeLocalSync(cj->localtree, cj->ntree);
147 }
148
149
150 /* only this runs inside thread */
151 static void compo_startjob(void *cjv, short *stop, short *do_update)
152 {
153         CompoJob *cj= cjv;
154         bNodeTree *ntree= cj->localtree;
155
156         if(cj->scene->use_nodes==0)
157                 return;
158         
159         cj->stop= stop;
160         cj->do_update= do_update;
161         
162         ntree->test_break= compo_breakjob;
163         ntree->tbh= cj;
164         ntree->stats_draw= compo_redrawjob;
165         ntree->sdh= 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
174 }
175
176 void snode_composite_job(const bContext *C, ScrArea *sa)
177 {
178         SpaceNode *snode= sa->spacedata.first;
179         wmJob *steve;
180         CompoJob *cj;
181
182         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, WM_JOB_EXCL_RENDER);
183         cj= MEM_callocN(sizeof(CompoJob), "compo job");
184         
185         /* customdata for preview thread */
186         cj->scene= CTX_data_scene(C);
187         cj->ntree= snode->nodetree;
188         
189         /* setup job */
190         WM_jobs_customdata(steve, cj, compo_freejob);
191         WM_jobs_timer(steve, 0.1, NC_SCENE, NC_SCENE|ND_COMPO_RESULT);
192         WM_jobs_callbacks(steve, compo_startjob, compo_initjob, compo_updatejob);
193         
194         WM_jobs_start(CTX_wm_manager(C), steve);
195         
196 }
197
198 /* ***************************************** */
199
200 /* also checks for edited groups */
201 bNode *editnode_get_active(bNodeTree *ntree)
202 {
203         bNode *node;
204         
205         /* check for edited group */
206         for(node= ntree->nodes.first; node; node= node->next)
207                 if(node->flag & NODE_GROUP_EDIT)
208                         break;
209         if(node)
210                 return nodeGetActive((bNodeTree *)node->id);
211         else
212                 return nodeGetActive(ntree);
213 }
214
215 void snode_notify(bContext *C, SpaceNode *snode)
216 {
217         if(snode->treetype==NTREE_SHADER)
218                 WM_event_add_notifier(C, NC_MATERIAL|ND_NODES, snode->id);
219         else if(snode->treetype==NTREE_COMPOSIT)
220                 WM_event_add_notifier(C, NC_SCENE|ND_NODES, snode->id);
221         else if(snode->treetype==NTREE_TEXTURE)
222                 WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id);
223 }
224
225 bNode *node_tree_get_editgroup(bNodeTree *nodetree)
226 {
227         bNode *gnode;
228         
229         /* get the groupnode */
230         for(gnode= nodetree->nodes.first; gnode; gnode= gnode->next)
231                 if(gnode->flag & NODE_GROUP_EDIT)
232                         break;
233         return gnode;
234 }
235
236 /* assumes nothing being done in ntree yet, sets the default in/out node */
237 /* called from shading buttons or header */
238 void ED_node_shader_default(Material *ma)
239 {
240         bNode *in, *out;
241         bNodeSocket *fromsock, *tosock;
242         
243         /* but lets check it anyway */
244         if(ma->nodetree) {
245                 if (G.f & G_DEBUG)
246                         printf("error in shader initialize\n");
247                 return;
248         }
249         
250         ma->nodetree= ntreeAddTree(NTREE_SHADER);
251         
252         out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL, NULL);
253         out->locx= 300.0f; out->locy= 300.0f;
254         
255         in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL, NULL);
256         in->locx= 10.0f; in->locy= 300.0f;
257         nodeSetActive(ma->nodetree, in);
258         
259         /* only a link from color to color */
260         fromsock= in->outputs.first;
261         tosock= out->inputs.first;
262         nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
263         
264         ntreeSolveOrder(ma->nodetree);  /* needed for pointers */
265 }
266
267 /* assumes nothing being done in ntree yet, sets the default in/out node */
268 /* called from shading buttons or header */
269 void ED_node_composit_default(Scene *sce)
270 {
271         bNode *in, *out;
272         bNodeSocket *fromsock, *tosock;
273         
274         /* but lets check it anyway */
275         if(sce->nodetree) {
276                 if (G.f & G_DEBUG)
277                         printf("error in composite initialize\n");
278                 return;
279         }
280         
281         sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
282         
283         out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL, NULL);
284         out->locx= 300.0f; out->locy= 400.0f;
285         out->id= &sce->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         nodeSetActive(sce->nodetree, in);
291         
292         /* links from color to color */
293         fromsock= in->outputs.first;
294         tosock= out->inputs.first;
295         nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
296         
297         ntreeSolveOrder(sce->nodetree); /* needed for pointers */
298         
299         // XXX ntreeCompositForceHidden(sce->nodetree);
300 }
301
302 /* assumes nothing being done in ntree yet, sets the default in/out node */
303 /* called from shading buttons or header */
304 void ED_node_texture_default(Tex *tx)
305 {
306         bNode *in, *out;
307         bNodeSocket *fromsock, *tosock;
308         
309         /* but lets check it anyway */
310         if(tx->nodetree) {
311                 if (G.f & G_DEBUG)
312                         printf("error in texture initialize\n");
313                 return;
314         }
315         
316         tx->nodetree= ntreeAddTree(NTREE_TEXTURE);
317         
318         out= nodeAddNodeType(tx->nodetree, TEX_NODE_OUTPUT, NULL, NULL);
319         out->locx= 300.0f; out->locy= 300.0f;
320         
321         in= nodeAddNodeType(tx->nodetree, TEX_NODE_CHECKER, NULL, NULL);
322         in->locx= 10.0f; in->locy= 300.0f;
323         nodeSetActive(tx->nodetree, in);
324         
325         fromsock= in->outputs.first;
326         tosock= out->inputs.first;
327         nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
328         
329         ntreeSolveOrder(tx->nodetree);  /* needed for pointers */
330 }
331
332 void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype)
333 {
334         bNode *node= NULL;
335         short idtype= GS(id->name);
336
337         if(idtype == ID_MA) {
338                 *ntree= ((Material*)id)->nodetree;
339                 if(treetype) *treetype= NTREE_SHADER;
340         }
341         else if(idtype == ID_SCE) {
342                 *ntree= ((Scene*)id)->nodetree;
343                 if(treetype) *treetype= NTREE_COMPOSIT;
344         }
345         else if(idtype == ID_TE) {
346                 *ntree= ((Tex*)id)->nodetree;
347                 if(treetype) *treetype= NTREE_TEXTURE;
348         }
349
350         /* find editable group */
351         if(edittree) {
352                 if(*ntree)
353                         for(node= (*ntree)->nodes.first; node; node= node->next)
354                                 if(node->flag & NODE_GROUP_EDIT)
355                                         break;
356                 
357                 if(node && node->id)
358                         *edittree= (bNodeTree *)node->id;
359                 else
360                         *edittree= *ntree;
361         }
362 }
363
364 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
365 void snode_set_context(SpaceNode *snode, Scene *scene)
366 {
367         Object *ob= OBACT;
368         
369         snode->nodetree= NULL;
370         snode->edittree= NULL;
371         snode->id= snode->from= NULL;
372         
373         if(snode->treetype==NTREE_SHADER) {
374                 /* need active object, or we allow pinning... */
375                 if(ob) {
376                         Material *ma= give_current_material(ob, ob->actcol);
377                         if(ma) {
378                                 snode->from= &ob->id;
379                                 snode->id= &ma->id;
380                         }
381                 }
382         }
383         else if(snode->treetype==NTREE_COMPOSIT) {
384                 snode->from= NULL;
385                 snode->id= &scene->id;
386                 
387                 /* bit clumsy but reliable way to see if we draw first time */
388                 if(snode->nodetree==NULL)
389                         ntreeCompositForceHidden(scene->nodetree, scene);
390         }
391         else if(snode->treetype==NTREE_TEXTURE) {
392                 Tex *tx= NULL;
393
394                 if(snode->texfrom==SNODE_TEX_OBJECT) {
395                         if(ob) {
396                                 tx= give_current_object_texture(ob);
397
398                                 if(ob->type == OB_LAMP)
399                                         snode->from= (ID*)ob->data;
400                                 else
401                                         snode->from= (ID*)give_current_material(ob, ob->actcol);
402
403                                 /* from is not set fully for material nodes, should be ID + Node then */
404                         }
405                 }
406                 else if(snode->texfrom==SNODE_TEX_WORLD) {
407                         tx= give_current_world_texture(scene->world);
408                         snode->from= (ID *)scene->world;
409                 }
410                 else {
411                         Brush *brush= NULL;
412                         
413                         if(ob && (ob->mode & OB_MODE_SCULPT))
414                                 brush= paint_brush(&scene->toolsettings->sculpt->paint);
415                         else
416                                 brush= paint_brush(&scene->toolsettings->imapaint.paint);
417
418                         snode->from= (ID *)brush;
419                         tx= give_current_brush_texture(brush);
420                 }
421                 
422                 snode->id= &tx->id;
423         }
424
425         if(snode->id)
426                 node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL);
427 }
428
429 void node_set_active(SpaceNode *snode, bNode *node)
430 {
431         nodeSetActive(snode->edittree, node);
432         
433         if(node->type!=NODE_GROUP) {
434                 /* tree specific activate calls */
435                 if(snode->treetype==NTREE_SHADER) {
436                         /* when we select a material, active texture is cleared, for buttons */
437                         if(node->id && GS(node->id->name)==ID_MA)
438                                 nodeClearActiveID(snode->edittree, ID_TE);
439
440                         // XXX
441 #if 0
442                         if(node->id)
443                                 ; // XXX BIF_preview_changed(-1);       /* temp hack to force texture preview to update */
444                         
445                         // allqueue(REDRAWBUTSSHADING, 1);
446                         // allqueue(REDRAWIPO, 0);
447 #endif
448                 }
449                 else if(snode->treetype==NTREE_COMPOSIT) {
450                         Scene *scene= (Scene*)snode->id;
451
452                         /* make active viewer, currently only 1 supported... */
453                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
454                                 bNode *tnode;
455                                 int was_output= (node->flag & NODE_DO_OUTPUT);
456
457                                 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
458                                         if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
459                                                 tnode->flag &= ~NODE_DO_OUTPUT;
460                                 
461                                 node->flag |= NODE_DO_OUTPUT;
462                                 if(was_output==0) {
463                                         bNode *gnode;
464                                         
465                                         NodeTagChanged(snode->edittree, node);
466                                         
467                                         /* if inside group, tag entire group */
468                                         gnode= node_tree_get_editgroup(snode->nodetree);
469                                         if(gnode)
470                                                 NodeTagIDChanged(snode->nodetree, gnode->id);
471                                         
472                                         ED_node_changed_update(snode->id, node);
473                                 }
474                                 
475                                 /* addnode() doesnt link this yet... */
476                                 node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
477                         }
478                         else if(node->type==CMP_NODE_R_LAYERS) {
479                                 if(node->id==NULL || node->id==(ID *)scene) {
480                                         scene->r.actlay= node->custom1;
481                                 }
482                         }
483                 }
484                 else if(snode->treetype==NTREE_TEXTURE) {
485                         // XXX
486 #if 0
487                         if(node->id)
488                                 ; // XXX BIF_preview_changed(-1);
489                         // allqueue(REDRAWBUTSSHADING, 1);
490                         // allqueue(REDRAWIPO, 0);
491 #endif
492                 }
493         }
494 }
495
496 /* when links in groups change, inputs/outputs change, nodes added/deleted... */
497 void node_tree_verify_groups(bNodeTree *nodetree)
498 {
499         bNode *gnode;
500         
501         gnode= node_tree_get_editgroup(nodetree);
502         
503         /* does all materials */
504         if(gnode)
505                 nodeVerifyGroup((bNodeTree *)gnode->id);
506         
507 }
508
509 /* ***************** Edit Group operator ************* */
510
511 void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
512 {
513         bNode *node;
514         
515         /* make sure nothing has group editing on */
516         for(node= snode->nodetree->nodes.first; node; node= node->next)
517                 node->flag &= ~NODE_GROUP_EDIT;
518         
519         if(gnode==NULL) {
520                 /* with NULL argument we do a toggle */
521                 if(snode->edittree==snode->nodetree)
522                         gnode= nodeGetActive(snode->nodetree);
523         }
524         
525         if(gnode && gnode->type==NODE_GROUP && gnode->id) {
526                 if(gnode->id->lib)
527                         ntreeMakeLocal((bNodeTree *)gnode->id);
528
529                 gnode->flag |= NODE_GROUP_EDIT;
530                 snode->edittree= (bNodeTree *)gnode->id;
531                 
532                 /* deselect all other nodes, so we can also do grabbing of entire subtree */
533                 for(node= snode->nodetree->nodes.first; node; node= node->next)
534                         node->flag &= ~SELECT;
535                 gnode->flag |= SELECT;
536                 
537         }
538         else 
539                 snode->edittree= snode->nodetree;
540         
541         ntreeSolveOrder(snode->nodetree);
542 }
543
544 static int node_group_edit_exec(bContext *C, wmOperator *op)
545 {
546         SpaceNode *snode = CTX_wm_space_node(C);
547         bNode *gnode;
548
549         gnode= nodeGetActive(snode->edittree);
550         snode_make_group_editable(snode, gnode);
551
552         WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
553
554         return OPERATOR_FINISHED;
555 }
556
557 static int node_group_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
558 {
559         SpaceNode *snode = CTX_wm_space_node(C);
560         bNode *gnode;
561
562         gnode= nodeGetActive(snode->edittree);
563         if(gnode && gnode->type==NODE_GROUP && gnode->id && gnode->id->lib) {
564                 uiPupMenuOkee(C, op->type->idname, "Make group local?");
565                 return OPERATOR_CANCELLED;
566         }
567
568         return node_group_edit_exec(C, op);
569 }
570
571 void NODE_OT_group_edit(wmOperatorType *ot)
572 {
573         /* identifiers */
574         ot->name = "Edit Group";
575         ot->description = "Edit node group";
576         ot->idname = "NODE_OT_group_edit";
577         
578         /* api callbacks */
579         ot->invoke = node_group_edit_invoke;
580         ot->exec = node_group_edit_exec;
581         ot->poll = ED_operator_node_active;
582         
583         /* flags */
584         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
585 }
586
587 /* ******************** Ungroup operator ********************** */
588
589 static int node_group_ungroup_exec(bContext *C, wmOperator *op)
590 {
591         SpaceNode *snode = CTX_wm_space_node(C);
592         bNode *gnode;
593
594         /* are we inside of a group? */
595         gnode= node_tree_get_editgroup(snode->nodetree);
596         if(gnode)
597                 snode_make_group_editable(snode, NULL);
598         
599         gnode= nodeGetActive(snode->edittree);
600         if(gnode==NULL)
601                 return OPERATOR_CANCELLED;
602         
603         if(gnode->type!=NODE_GROUP) {
604                 BKE_report(op->reports, RPT_ERROR, "Not a group");
605                 return OPERATOR_CANCELLED;
606         }
607         else if(!nodeGroupUnGroup(snode->edittree, gnode)) {
608                 BKE_report(op->reports, RPT_ERROR, "Can't ungroup");
609                 return OPERATOR_CANCELLED;
610         }
611
612         WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
613
614         return OPERATOR_FINISHED;
615 }
616
617 void NODE_OT_group_ungroup(wmOperatorType *ot)
618 {
619         /* identifiers */
620         ot->name = "Ungroup";
621         ot->description = "Ungroup selected nodes";
622         ot->idname = "NODE_OT_group_ungroup";
623         
624         /* api callbacks */
625         ot->exec = node_group_ungroup_exec;
626         ot->poll = ED_operator_node_active;
627         
628         /* flags */
629         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
630 }
631
632 /* ************************** Node generic ************** */
633
634 /* allows to walk the list in order of visibility */
635 bNode *next_node(bNodeTree *ntree)
636 {
637         static bNode *current=NULL, *last= NULL;
638         
639         if(ntree) {
640                 /* set current to the first selected node */
641                 for(current= ntree->nodes.last; current; current= current->prev)
642                         if(current->flag & NODE_SELECT)
643                                 break;
644                 
645                 /* set last to the first unselected node */
646                 for(last= ntree->nodes.last; last; last= last->prev)
647                         if((last->flag & NODE_SELECT)==0)
648                                 break;
649                 
650                 if(current==NULL)
651                         current= last;
652                 
653                 return NULL;
654         }
655         /* no nodes, or we are ready */
656         if(current==NULL)
657                 return NULL;
658         
659         /* now we walk the list backwards, but we always return current */
660         if(current->flag & NODE_SELECT) {
661                 bNode *node= current;
662                 
663                 /* find previous selected */
664                 current= current->prev;
665                 while(current && (current->flag & NODE_SELECT)==0)
666                         current= current->prev;
667                 
668                 /* find first unselected */
669                 if(current==NULL)
670                         current= last;
671                 
672                 return node;
673         }
674         else {
675                 bNode *node= current;
676                 
677                 /* find previous unselected */
678                 current= current->prev;
679                 while(current && (current->flag & NODE_SELECT))
680                         current= current->prev;
681                 
682                 return node;
683         }
684         
685         return NULL;
686 }
687
688 /* is rct in visible part of node? */
689 static bNode *visible_node(SpaceNode *snode, rctf *rct)
690 {
691         bNode *tnode;
692         
693         for(next_node(snode->edittree); (tnode=next_node(NULL));) {
694                 if(BLI_isect_rctf(&tnode->totr, rct, NULL))
695                         break;
696         }
697         return tnode;
698 }
699
700 #if 0
701 static void snode_bg_viewmove(SpaceNode *snode)
702 {
703         ScrArea *sa;
704         Image *ima;
705         ImBuf *ibuf;
706         Window *win;
707         short mval[2], mvalo[2];
708         short rectx, recty, xmin, xmax, ymin, ymax, pad;
709         int oldcursor;
710         
711         ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
712         ibuf= BKE_image_get_ibuf(ima, NULL);
713         
714         sa = snode->area;
715         
716         if(ibuf) {
717                 rectx = ibuf->x;
718                 recty = ibuf->y;
719         } else {
720                 rectx = recty = 1;
721         }
722         
723         pad = 10;
724         xmin = -(sa->winx/2) - rectx/2 + pad;
725         xmax = sa->winx/2 + rectx/2 - pad;
726         ymin = -(sa->winy/2) - recty/2 + pad;
727         ymax = sa->winy/2 + recty/2 - pad;
728         
729         getmouseco_sc(mvalo);
730         
731         /* store the old cursor to temporarily change it */
732         oldcursor=get_cursor();
733         win=winlay_get_active_window();
734         
735         SetBlenderCursor(BC_NSEW_SCROLLCURSOR);
736         
737         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
738                 
739                 getmouseco_sc(mval);
740                 
741                 if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
742                         
743                         snode->xof -= (mvalo[0]-mval[0]);
744                         snode->yof -= (mvalo[1]-mval[1]);
745                         
746                         /* prevent dragging image outside of the window and losing it! */
747                         CLAMP(snode->xof, xmin, xmax);
748                         CLAMP(snode->yof, ymin, ymax);
749                         
750                         mvalo[0]= mval[0];
751                         mvalo[1]= mval[1];
752                         
753                         scrarea_do_windraw(curarea);
754                         screen_swapbuffers();
755                 }
756                 else BIF_wait_for_statechange();
757         }
758         
759         window_set_cursor(win, oldcursor);
760 }
761 #endif
762
763 /* ********************** size widget operator ******************** */
764
765 typedef struct NodeSizeWidget {
766         float mxstart;
767         float oldwidth;
768 } NodeSizeWidget;
769
770 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
771 {
772         SpaceNode *snode= CTX_wm_space_node(C);
773         ARegion *ar= CTX_wm_region(C);
774         bNode *node= editnode_get_active(snode->edittree);
775         NodeSizeWidget *nsw= op->customdata;
776         float mx, my;
777         
778         switch (event->type) {
779                 case MOUSEMOVE:
780                         
781                         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
782                                                                          &mx, &my);
783                         
784                         if (node) {
785                                 if(node->flag & NODE_HIDDEN) {
786                                         node->miniwidth= nsw->oldwidth + mx - nsw->mxstart;
787                                         CLAMP(node->miniwidth, 0.0f, 100.0f);
788                                 }
789                                 else {
790                                         node->width= nsw->oldwidth + mx - nsw->mxstart;
791                                         CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
792                                 }
793                         }
794                                 
795                         ED_region_tag_redraw(ar);
796
797                         break;
798                         
799                 case LEFTMOUSE:
800                 case MIDDLEMOUSE:
801                 case RIGHTMOUSE:
802                         
803                         MEM_freeN(nsw);
804                         op->customdata= NULL;
805                         
806                         return OPERATOR_FINISHED;
807         }
808         
809         return OPERATOR_RUNNING_MODAL;
810 }
811
812 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
813 {
814         SpaceNode *snode= CTX_wm_space_node(C);
815         ARegion *ar= CTX_wm_region(C);
816         bNode *node= editnode_get_active(snode->edittree);
817         
818         if(node) {
819                 rctf totr;
820                 
821                 /* convert mouse coordinates to v2d space */
822                 UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
823                                                                  &snode->mx, &snode->my);
824                 
825                 /* rect we're interested in is just the bottom right corner */
826                 totr= node->totr;
827                 totr.xmin= totr.xmax-10.0f;
828                 totr.ymax= totr.ymin+10.0f;
829                 
830                 if(BLI_in_rctf(&totr, snode->mx, snode->my)) {
831                         NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
832                         
833                         op->customdata= nsw;
834                         nsw->mxstart= snode->mx;
835                         
836                         /* store old */
837                         if(node->flag & NODE_HIDDEN)
838                                 nsw->oldwidth= node->miniwidth;
839                         else
840                                 nsw->oldwidth= node->width;
841                         
842                         /* add modal handler */
843                         WM_event_add_modal_handler(C, op);
844
845                         return OPERATOR_RUNNING_MODAL;
846                 }
847         }
848         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
849 }
850
851 void NODE_OT_resize(wmOperatorType *ot)
852 {
853         /* identifiers */
854         ot->name= "Resize Node";
855         ot->idname= "NODE_OT_resize";
856         
857         /* api callbacks */
858         ot->invoke= node_resize_invoke;
859         ot->modal= node_resize_modal;
860         ot->poll= ED_operator_node_active;
861         
862         /* flags */
863         ot->flag= OPTYPE_BLOCKING;
864 }
865
866 /* ********************** select ******************** */
867
868
869 /* no undo here! */
870 void node_deselectall(SpaceNode *snode)
871 {
872         bNode *node;
873         
874         for(node= snode->edittree->nodes.first; node; node= node->next)
875                 node->flag &= ~SELECT;
876 }
877
878 int node_has_hidden_sockets(bNode *node)
879 {
880         bNodeSocket *sock;
881         
882         for(sock= node->inputs.first; sock; sock= sock->next)
883                 if(sock->flag & SOCK_HIDDEN)
884                         return 1;
885         for(sock= node->outputs.first; sock; sock= sock->next)
886                 if(sock->flag & SOCK_HIDDEN)
887                         return 1;
888         return 0;
889 }
890
891 static void node_link_viewer(SpaceNode *snode, bNode *tonode)
892 {
893         bNode *node;
894
895         /* context check */
896         if(tonode==NULL || tonode->outputs.first==NULL)
897                 return;
898         if( ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
899                 return;
900         
901         /* get viewer */
902         for(node= snode->edittree->nodes.first; node; node= node->next)
903                 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
904                         if(node->flag & NODE_DO_OUTPUT)
905                                 break;
906                 
907         if(node) {
908                 bNodeLink *link;
909                 
910                 /* get link to viewer */
911                 for(link= snode->edittree->links.first; link; link= link->next)
912                         if(link->tonode==node)
913                                 break;
914
915                 if(link) {
916                         link->fromnode= tonode;
917                         link->fromsock= tonode->outputs.first;
918                         NodeTagChanged(snode->edittree, node);
919                 }
920         }
921 }
922
923
924 void node_active_link_viewer(SpaceNode *snode)
925 {
926         bNode *node= editnode_get_active(snode->edittree);
927         if(node)
928                 node_link_viewer(snode, node);
929 }
930
931 /* return 0, nothing done */
932 /*static*/ int node_mouse_groupheader(SpaceNode *snode)
933 {
934         bNode *gnode;
935         float mx=0, my=0;
936 // XXX  short mval[2];
937         
938         gnode= node_tree_get_editgroup(snode->nodetree);
939         if(gnode==NULL) return 0;
940         
941 // XXX  getmouseco_areawin(mval);
942 // XXX  areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
943         
944         /* click in header or outside? */
945         if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
946                 rctf rect= gnode->totr;
947                 
948                 rect.ymax += NODE_DY;
949                 if(BLI_in_rctf(&rect, mx, my)==0)
950                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
951 //              else
952 // XXX                  transform_nodes(snode->nodetree, 'g', "Move group");
953                 
954                 return 1;
955         }
956         return 0;
957 }
958
959 /* checks snode->mouse position, and returns found node/socket */
960 /* type is SOCK_IN and/or SOCK_OUT */
961 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
962 {
963         bNode *node;
964         bNodeSocket *sock;
965         rctf rect;
966         
967         /* check if we click in a socket */
968         for(node= snode->edittree->nodes.first; node; node= node->next) {
969                 
970                 rect.xmin = snode->mx - (NODE_SOCKSIZE+4);
971                 rect.ymin = snode->my - (NODE_SOCKSIZE+4);
972                 rect.xmax = snode->mx + (NODE_SOCKSIZE+4);
973                 rect.ymax = snode->my + (NODE_SOCKSIZE+4);
974                 
975                 if (!(node->flag & NODE_HIDDEN)) {
976                         /* extra padding inside and out - allow dragging on the text areas too */
977                         if (in_out == SOCK_IN) {
978                                 rect.xmax += NODE_SOCKSIZE;
979                                 rect.xmin -= NODE_SOCKSIZE*4;
980                         } else if (in_out == SOCK_OUT) {
981                                 rect.xmax += NODE_SOCKSIZE*4;
982                                 rect.xmin -= NODE_SOCKSIZE;
983                         }
984                 }
985                 
986                 if(in_out & SOCK_IN) {
987                         for(sock= node->inputs.first; sock; sock= sock->next) {
988                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
989                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
990                                                 if(node == visible_node(snode, &rect)) {
991                                                         *nodep= node;
992                                                         *sockp= sock;
993                                                         return 1;
994                                                 }
995                                         }
996                                 }
997                         }
998                 }
999                 if(in_out & SOCK_OUT) {
1000                         for(sock= node->outputs.first; sock; sock= sock->next) {
1001                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1002                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1003                                                 if(node == visible_node(snode, &rect)) {
1004                                                         *nodep= node;
1005                                                         *sockp= sock;
1006                                                         return 1;
1007                                                 }
1008                                         }
1009                                 }
1010                         }
1011                 }
1012         }
1013         return 0;
1014 }
1015
1016 static int node_socket_hilights(SpaceNode *snode, int in_out)
1017 {
1018         bNode *node;
1019         bNodeSocket *sock, *tsock, *socksel= NULL;
1020         short redraw= 0;
1021         
1022         if(snode->edittree==NULL) return 0;
1023         
1024         /* deselect sockets */
1025         for(node= snode->edittree->nodes.first; node; node= node->next) {
1026                 for(sock= node->inputs.first; sock; sock= sock->next) {
1027                         if(sock->flag & SELECT) {
1028                                 sock->flag &= ~SELECT;
1029                                 redraw++;
1030                                 socksel= sock;
1031                         }
1032                 }
1033                 for(sock= node->outputs.first; sock; sock= sock->next) {
1034                         if(sock->flag & SELECT) {
1035                                 sock->flag &= ~SELECT;
1036                                 redraw++;
1037                                 socksel= sock;
1038                         }
1039                 }
1040         }
1041         
1042         // XXX mousepos should be set here!
1043         
1044         if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1045                 tsock->flag |= SELECT;
1046                 if(redraw==1 && tsock==socksel) redraw= 0;
1047                 else redraw= 1;
1048         }
1049         
1050         return redraw;
1051 }
1052
1053 /* ****************** Add *********************** */
1054
1055
1056 typedef struct bNodeListItem {
1057         struct bNodeListItem *next, *prev;
1058         struct bNode *node;     
1059 } bNodeListItem;
1060
1061 int sort_nodes_locx(void *a, void *b)
1062 {
1063         bNodeListItem *nli1 = (bNodeListItem *)a;
1064         bNodeListItem *nli2 = (bNodeListItem *)b;
1065         bNode *node1 = nli1->node;
1066         bNode *node2 = nli2->node;
1067         
1068         if (node1->locx > node2->locx)
1069                 return 1;
1070         else 
1071                 return 0;
1072 }
1073
1074 static int socket_is_available(bNodeTree *ntree, bNodeSocket *sock, int allow_used)
1075 {
1076         if (sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
1077                 return 0;
1078         
1079         if (!allow_used) {
1080                 if (nodeCountSocketLinks(ntree, sock) > 0)
1081                         return 0;
1082         }
1083         return 1;
1084 }
1085
1086 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
1087 {
1088         bNodeSocket *sock;
1089         
1090         /* first try to find a socket with a matching name */
1091         for (sock=node->outputs.first; sock; sock=sock->next) {
1092
1093                 if (!socket_is_available(ntree, sock, allow_multiple))
1094                         continue;
1095
1096                 /* check for same types */
1097                 if (sock->type == sock_target->type) {
1098                         if (strcmp(sock->name, sock_target->name)==0)
1099                                 return sock;
1100                 }
1101         }
1102         
1103         /* otherwise settle for the first available socket of the right type */
1104         for (sock=node->outputs.first; sock; sock=sock->next) {
1105
1106                 if (!socket_is_available(ntree, sock, allow_multiple))
1107                         continue;
1108                 
1109                 /* check for same types */
1110                 if (sock->type == sock_target->type) {
1111                         return sock;
1112                 }
1113         }
1114         
1115         return NULL;
1116 }
1117
1118 /* this is a bit complicated, but designed to prioritise finding 
1119  * sockets of higher types, such as image, first */
1120 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
1121 {
1122         bNodeSocket *sock;
1123         int socktype, maxtype=0;
1124         int a = 0;
1125         
1126         for (sock=node->inputs.first; sock; sock=sock->next) {
1127                 maxtype = MAX2(sock->type, maxtype);
1128         }
1129         
1130         /* find sockets of higher 'types' first (i.e. image) */
1131         for (socktype=maxtype; socktype >= 0; socktype--) {
1132                 for (sock=node->inputs.first; sock; sock=sock->next) {
1133                         
1134                         if (!socket_is_available(ntree, sock, replace)) {
1135                                 a++;
1136                                 continue;
1137                         }
1138                                 
1139                         if (sock->type == socktype) {
1140                                 /* increment to make sure we don't keep finding 
1141                                  * the same socket on every attempt running this function */
1142                                 a++;
1143                                 if (a > num)
1144                                         return sock;
1145                         }
1146                 }
1147         }
1148         
1149         return NULL;
1150 }
1151
1152 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
1153 {
1154         ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
1155         bNodeListItem *nli;
1156         bNode *node;
1157         int i;
1158         
1159         for(node= snode->edittree->nodes.first; node; node= node->next) {
1160                 if(node->flag & NODE_SELECT) {
1161                         nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
1162                         nli->node = node;
1163                         BLI_addtail(nodelist, nli);
1164                 }
1165         }
1166         
1167         /* sort nodes left to right */
1168         BLI_sortlist(nodelist, sort_nodes_locx);
1169         
1170         for (nli=nodelist->first; nli; nli=nli->next) {
1171                 bNode *node_fr, *node_to;
1172                 bNodeSocket *sock_fr, *sock_to;
1173                 
1174                 if (nli->next == NULL) break;
1175                 
1176                 node_fr = nli->node;
1177                 node_to = nli->next->node;
1178                 
1179                 /* check over input sockets first */
1180                 for (i=0; i<BLI_countlist(&node_to->inputs); i++) {
1181                         
1182                         /* find the best guess input socket */
1183                         sock_to = best_socket_input(snode->edittree, node_to, i, replace);
1184                         if (!sock_to) continue;
1185                         
1186                         /* check for an appropriate output socket to connect from */
1187                         sock_fr = best_socket_output(snode->edittree, node_fr, sock_to, allow_multiple);
1188                         if (!sock_fr) continue;
1189                         
1190                         /* then we can connect */
1191                         if (replace)
1192                                 nodeRemSocketLinks(snode->edittree, sock_to);
1193                         nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
1194                         NodeTagChanged(snode->edittree, node_to);
1195                         break;
1196                 }
1197         }
1198         
1199         ntreeSolveOrder(snode->edittree);
1200         
1201         BLI_freelistN(nodelist);
1202         MEM_freeN(nodelist);
1203 }
1204
1205 /* can be called from menus too, but they should do own undopush and redraws */
1206 bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy)
1207 {
1208         bNode *node= NULL, *gnode;
1209         
1210         node_deselectall(snode);
1211         
1212         if(type>=NODE_DYNAMIC_MENU) {
1213                 node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
1214         }
1215         else if(type>=NODE_GROUP_MENU) {
1216                 if(snode->edittree!=snode->nodetree) {
1217                         // XXX error("Can not add a Group in a Group");
1218                         return NULL;
1219                 }
1220                 else {
1221                         bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1222                         if(ngroup)
1223                                 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL);
1224                 }
1225         }
1226         else
1227                 node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
1228         
1229         /* generics */
1230         if(node) {
1231                 node->locx= locx;
1232                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
1233                 node->flag |= SELECT;
1234                 
1235                 gnode= node_tree_get_editgroup(snode->nodetree);
1236                 if(gnode) {
1237                         node->locx -= gnode->locx;
1238                         node->locy -= gnode->locy;
1239                 }
1240
1241                 node_tree_verify_groups(snode->nodetree);
1242                 node_set_active(snode, node);
1243                 
1244                 if(snode->nodetree->type==NTREE_COMPOSIT) {
1245                         if(ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE))
1246                                 node->id = &scene->id;
1247                         
1248                         ntreeCompositForceHidden(snode->edittree, scene);
1249                 }
1250                         
1251                 if(node->id)
1252                         id_us_plus(node->id);
1253                         
1254                 NodeTagChanged(snode->edittree, node);
1255         }
1256         
1257         if(snode->nodetree->type==NTREE_TEXTURE) {
1258                 ntreeTexCheckCyclics(snode->edittree);
1259         }
1260         
1261         return node;
1262 }
1263
1264 /* ****************** Duplicate *********************** */
1265
1266 static int node_duplicate_exec(bContext *C, wmOperator *op)
1267 {
1268         SpaceNode *snode= CTX_wm_space_node(C);
1269         
1270         ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
1271         
1272         ntreeSolveOrder(snode->edittree);
1273         node_tree_verify_groups(snode->nodetree);
1274         snode_notify(C, snode);
1275
1276         return OPERATOR_FINISHED;
1277 }
1278
1279 void NODE_OT_duplicate(wmOperatorType *ot)
1280 {
1281         /* identifiers */
1282         ot->name= "Duplicate Nodes";
1283         ot->description = "Duplicate the nodes";
1284         ot->idname= "NODE_OT_duplicate";
1285         
1286         /* api callbacks */
1287         ot->exec= node_duplicate_exec;
1288         ot->poll= ED_operator_node_active;
1289         
1290         /* flags */
1291         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1292 }
1293
1294 /* *************************** add link op ******************** */
1295
1296 /* temp data to pass on to modal */
1297 typedef struct NodeLinkDrag
1298 {
1299         bNode *node;
1300         bNodeSocket *sock;
1301         bNodeLink *link;
1302         int in_out;
1303 } NodeLinkDrag;
1304
1305 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
1306 {
1307         bNodeLink *tlink;
1308         bNodeSocket *sock;
1309         
1310         if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1311                 
1312                 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1313                         if(link!=tlink && tlink->tosock==link->tosock)
1314                                 break;
1315                 }
1316                 if(tlink) {
1317                         /* is there a free input socket with same type? */
1318                         for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) {
1319                                 if(sock->type==tlink->fromsock->type)
1320                                         if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
1321                                                 break;
1322                         }
1323                         if(sock) {
1324                                 tlink->tosock= sock;
1325                                 sock->flag &= ~SOCK_HIDDEN;
1326                         }
1327                         else {
1328                                 nodeRemLink(snode->edittree, tlink);
1329                         }
1330                 }
1331         }
1332 }
1333
1334 /* loop that adds a nodelink, called by function below  */
1335 /* in_out = starting socket */
1336 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
1337 {
1338         SpaceNode *snode= CTX_wm_space_node(C);
1339         ARegion *ar= CTX_wm_region(C);
1340         NodeLinkDrag *nldrag= op->customdata;
1341         bNode *tnode, *node;
1342         bNodeSocket *tsock= NULL, *sock;
1343         bNodeLink *link;
1344         int in_out;
1345
1346         in_out= nldrag->in_out;
1347         node= nldrag->node;
1348         sock= nldrag->sock;
1349         link= nldrag->link;
1350         
1351         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
1352                                                          &snode->mx, &snode->my);
1353
1354         switch (event->type) {
1355                 case MOUSEMOVE:
1356                         
1357                         if(in_out==SOCK_OUT) {
1358                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1359                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1360                                                 if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
1361                                                         link->tonode= tnode;
1362                                                         link->tosock= tsock;
1363                                                         ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1364                                                 }
1365                                         }
1366                                 }
1367                                 else {
1368                                         link->tonode= NULL;
1369                                         link->tosock= NULL;
1370                                 }
1371                         }
1372                         else {
1373                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1374                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1375                                                 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1376                                                         if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1377                                                                 link->fromnode= tnode;
1378                                                                 link->fromsock= tsock;
1379                                                                 ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1380                                                         }
1381                                                 }
1382                                         }
1383                                 }
1384                                 else {
1385                                         link->fromnode= NULL;
1386                                         link->fromsock= NULL;
1387                                 }
1388                         }
1389                         /* hilight target sockets only */
1390                         node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1391                         ED_region_tag_redraw(ar);
1392                         break;
1393                         
1394                 case LEFTMOUSE:
1395                 case RIGHTMOUSE:
1396                 case MIDDLEMOUSE:
1397         
1398                         /* remove link? */
1399                         if(link->tonode==NULL || link->fromnode==NULL) {
1400                                 nodeRemLink(snode->edittree, link);
1401                         }
1402                         else {
1403                                 /* send changed events for original tonode and new */
1404                                 if(link->tonode) 
1405                                         NodeTagChanged(snode->edittree, link->tonode);
1406                                 
1407                                 /* we might need to remove a link */
1408                                 if(in_out==SOCK_OUT) node_remove_extra_links(snode, link->tosock, link);
1409                         }
1410                         
1411                         ntreeSolveOrder(snode->edittree);
1412                         node_tree_verify_groups(snode->nodetree);
1413                         snode_notify(C, snode);
1414                         
1415                         MEM_freeN(op->customdata);
1416                         op->customdata= NULL;
1417                         
1418                         return OPERATOR_FINISHED;
1419         }
1420         
1421         return OPERATOR_RUNNING_MODAL;
1422 }
1423
1424 /* return 1 when socket clicked */
1425 static int node_link_init(SpaceNode *snode, NodeLinkDrag *nldrag)
1426 {
1427         bNodeLink *link;
1428         
1429         /* output indicated? */
1430         if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_OUT)) {
1431                 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
1432                         return SOCK_OUT;
1433                 else {
1434                         /* find if we break a link */
1435                         for(link= snode->edittree->links.first; link; link= link->next) {
1436                                 if(link->fromsock==nldrag->sock)
1437                                         break;
1438                         }
1439                         if(link) {
1440                                 nldrag->node= link->tonode;
1441                                 nldrag->sock= link->tosock;
1442                                 nodeRemLink(snode->edittree, link);
1443                                 return SOCK_IN;
1444                         }
1445                 }
1446         }
1447         /* or an input? */
1448         else if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_IN)) {
1449                 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
1450                         return SOCK_IN;
1451                 else {
1452                         /* find if we break a link */
1453                         for(link= snode->edittree->links.first; link; link= link->next) {
1454                                 if(link->tosock==nldrag->sock)
1455                                         break;
1456                         }
1457                         if(link) {
1458                                 /* send changed event to original tonode */
1459                                 if(link->tonode) 
1460                                         NodeTagChanged(snode->edittree, link->tonode);
1461                                 
1462                                 nldrag->node= link->fromnode;
1463                                 nldrag->sock= link->fromsock;
1464                                 nodeRemLink(snode->edittree, link);
1465                                 return SOCK_OUT;
1466                         }
1467                 }
1468         }
1469         
1470         return 0;
1471 }
1472
1473 static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
1474 {
1475         SpaceNode *snode= CTX_wm_space_node(C);
1476         ARegion *ar= CTX_wm_region(C);
1477         NodeLinkDrag *nldrag= MEM_callocN(sizeof(NodeLinkDrag), "drag link op customdata");
1478         
1479         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
1480                                                          &snode->mx, &snode->my);
1481
1482         nldrag->in_out= node_link_init(snode, nldrag);
1483                 
1484         if(nldrag->in_out) {
1485                 op->customdata= nldrag;
1486                 
1487                 /* we make a temporal link */
1488                 if(nldrag->in_out==SOCK_OUT)
1489                         nldrag->link= nodeAddLink(snode->edittree, nldrag->node, nldrag->sock, NULL, NULL);
1490                 else
1491                         nldrag->link= nodeAddLink(snode->edittree, NULL, NULL, nldrag->node, nldrag->sock);
1492                 
1493                 /* add modal handler */
1494                 WM_event_add_modal_handler(C, op);
1495                 
1496                 return OPERATOR_RUNNING_MODAL;
1497         }
1498         else {
1499                 MEM_freeN(nldrag);
1500                 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1501         }
1502 }
1503
1504 void NODE_OT_link(wmOperatorType *ot)
1505 {
1506         /* identifiers */
1507         ot->name= "Link Nodes";
1508         ot->idname= "NODE_OT_link";
1509         
1510         /* api callbacks */
1511         ot->invoke= node_link_invoke;
1512         ot->modal= node_link_modal;
1513 //      ot->exec= node_link_exec;
1514         ot->poll= ED_operator_node_active;
1515         
1516         /* flags */
1517         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
1518 }
1519
1520 /* ********************** Make Link operator ***************** */
1521
1522 /* makes a link between selected output and input sockets */
1523 static int node_make_link_exec(bContext *C, wmOperator *op)
1524 {
1525         SpaceNode *snode= CTX_wm_space_node(C);
1526         int replace = RNA_boolean_get(op->ptr, "replace");
1527
1528         snode_autoconnect(snode, 0, replace);
1529
1530         node_tree_verify_groups(snode->nodetree);
1531         snode_notify(C, snode);
1532         
1533         return OPERATOR_FINISHED;
1534 }
1535
1536 void NODE_OT_link_make(wmOperatorType *ot)
1537 {
1538         /* identifiers */
1539         ot->name= "Make Links";
1540         ot->description= "Makes a link between selected output in input sockets";
1541         ot->idname= "NODE_OT_link_make";
1542         
1543         /* callbacks */
1544         ot->exec= node_make_link_exec;
1545         ot->poll= ED_operator_node_active; // XXX we need a special poll which checks that there are selected input/output sockets
1546         
1547         /* flags */
1548         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1549         
1550         RNA_def_boolean(ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
1551 }
1552
1553 /* ********************** Cut Link operator ***************** */
1554
1555 #define LINK_RESOL 12
1556 static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
1557 {
1558         float coord_array[LINK_RESOL+1][2];
1559         int i, b;
1560         
1561         if(node_link_bezier_points(NULL, NULL, link, coord_array, LINK_RESOL)) {
1562
1563                 for(i=0; i<tot-1; i++)
1564                         for(b=0; b<LINK_RESOL-1; b++)
1565                                 if(isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0)
1566                                         return 1;
1567         }
1568         return 0;
1569 }
1570
1571 static int cut_links_exec(bContext *C, wmOperator *op)
1572 {
1573         SpaceNode *snode= CTX_wm_space_node(C);
1574         ARegion *ar= CTX_wm_region(C);
1575         float mcoords[256][2];
1576         int i= 0;
1577         
1578         RNA_BEGIN(op->ptr, itemptr, "path") {
1579                 float loc[2];
1580                 
1581                 RNA_float_get_array(&itemptr, "loc", loc);
1582                 UI_view2d_region_to_view(&ar->v2d, (short)loc[0], (short)loc[1], 
1583                                                                  &mcoords[i][0], &mcoords[i][1]);
1584                 i++;
1585                 if(i>= 256) break;
1586         }
1587         RNA_END;
1588         
1589         if(i>1) {
1590                 bNodeLink *link, *next;
1591                 
1592                 for(link= snode->edittree->links.first; link; link= next) {
1593                         next= link->next;
1594                         
1595                         if(cut_links_intersect(link, mcoords, i)) {
1596                                 NodeTagChanged(snode->edittree, link->tonode);
1597                                 nodeRemLink(snode->edittree, link);
1598                         }
1599                 }
1600                 
1601                 ntreeSolveOrder(snode->edittree);
1602                 node_tree_verify_groups(snode->nodetree);
1603                 snode_notify(C, snode);
1604                 
1605                 return OPERATOR_FINISHED;
1606         }
1607         
1608         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1609 }
1610
1611 void NODE_OT_links_cut(wmOperatorType *ot)
1612 {
1613         PropertyRNA *prop;
1614         
1615         ot->name= "Cut links";
1616         ot->idname= "NODE_OT_links_cut";
1617         
1618         ot->invoke= WM_gesture_lines_invoke;
1619         ot->modal= WM_gesture_lines_modal;
1620         ot->exec= cut_links_exec;
1621         
1622         ot->poll= ED_operator_node_active;
1623         
1624         /* flags */
1625         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1626         
1627         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
1628         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
1629         /* internal */
1630         RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
1631 }
1632
1633 /* ******************************** */
1634 // XXX some code needing updating to operators...
1635
1636 /* goes over all scenes, reads render layerss */
1637 void node_read_renderlayers(SpaceNode *snode)
1638 {
1639         Scene *curscene= NULL; // XXX
1640         Scene *scene;
1641         bNode *node;
1642
1643         /* first tag scenes unread */
1644         for(scene= G.main->scene.first; scene; scene= scene->id.next) 
1645                 scene->id.flag |= LIB_DOIT;
1646
1647         for(node= snode->edittree->nodes.first; node; node= node->next) {
1648                 if(node->type==CMP_NODE_R_LAYERS) {
1649                         ID *id= node->id;
1650                         if(id->flag & LIB_DOIT) {
1651                                 RE_ReadRenderResult(curscene, (Scene *)id);
1652                                 ntreeCompositTagRender((Scene *)id);
1653                                 id->flag &= ~LIB_DOIT;
1654                         }
1655                 }
1656         }
1657         
1658         // XXX                  snode_notify(snode);
1659 }
1660
1661 void node_read_fullsamplelayers(SpaceNode *snode)
1662 {
1663         Scene *curscene= NULL; // XXX
1664         Render *re= RE_NewRender(curscene->id.name, RE_SLOT_VIEW);
1665
1666         WM_cursor_wait(1);
1667
1668         //BIF_init_render_callbacks(re, 1);
1669         RE_MergeFullSample(re, curscene, snode->nodetree);
1670         //BIF_end_render_callbacks();
1671         
1672         // allqueue(REDRAWNODE, 1);
1673         // allqueue(REDRAWIMAGE, 1);
1674         
1675         WM_cursor_wait(0);
1676 }
1677
1678 void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser)
1679 {
1680         bNode *node;
1681         
1682         if(ntree==NULL)
1683                 return;
1684         
1685         /* search for renderresults */
1686         if(image->type==IMA_TYPE_R_RESULT) {
1687                 for(node= ntree->nodes.first; node; node= node->next) {
1688                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
1689                                 /* imageuser comes from ImageWin, so indexes are offset 1 */
1690                                 if(node->custom1==iuser->layer-1)
1691                                         NodeTagChanged(ntree, node);
1692                         }
1693                 }
1694         }
1695         else {
1696                 for(node= ntree->nodes.first; node; node= node->next) {
1697                         if(node->id== &image->id)
1698                                 NodeTagChanged(ntree, node);
1699                 }
1700         }
1701 }
1702
1703 /* ****************** Make Group operator ******************* */
1704
1705 static int node_group_make_exec(bContext *C, wmOperator *op)
1706 {
1707         SpaceNode *snode = CTX_wm_space_node(C);
1708         bNode *gnode;
1709         
1710         if(snode->edittree!=snode->nodetree) {
1711                 BKE_report(op->reports, RPT_ERROR, "Can not add a new Group in a Group");
1712                 return OPERATOR_CANCELLED;
1713         }
1714         
1715         /* for time being... is too complex to handle */
1716         if(snode->treetype==NTREE_COMPOSIT) {
1717                 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
1718                         if(gnode->flag & SELECT)
1719                                 if(gnode->type==CMP_NODE_R_LAYERS)
1720                                         break;
1721                 }
1722                 
1723                 if(gnode) {
1724                         BKE_report(op->reports, RPT_ERROR, "Can not add RenderLayer in a Group");
1725                         return OPERATOR_CANCELLED;
1726                 }
1727         }
1728         
1729         gnode= nodeMakeGroupFromSelected(snode->nodetree);
1730         if(gnode==NULL) {
1731                 BKE_report(op->reports, RPT_ERROR, "Can not make Group");
1732                 return OPERATOR_CANCELLED;
1733         }
1734         else {
1735                 nodeSetActive(snode->nodetree, gnode);
1736                 ntreeSolveOrder(snode->nodetree);
1737         }
1738         
1739         snode_notify(C, snode);
1740         
1741         return OPERATOR_FINISHED;
1742 }
1743
1744 void NODE_OT_group_make(wmOperatorType *ot)
1745 {
1746         /* identifiers */
1747         ot->name = "Group";
1748         ot->description = "Make group from selected nodes";
1749         ot->idname = "NODE_OT_group_make";
1750         
1751         /* api callbacks */
1752         ot->exec = node_group_make_exec;
1753         ot->poll = ED_operator_node_active;
1754         
1755         /* flags */
1756         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1757 }
1758
1759 /* ****************** Hide operator *********************** */
1760
1761 static int node_hide_exec(bContext *C, wmOperator *op)
1762 {
1763         SpaceNode *snode= CTX_wm_space_node(C);
1764         bNode *node;
1765         int nothidden=0, ishidden=0;
1766         
1767         /* sanity checking (poll callback checks this already) */
1768         if((snode == NULL) || (snode->edittree == NULL))
1769                 return OPERATOR_CANCELLED;
1770         
1771         for(node= snode->edittree->nodes.first; node; node= node->next) {
1772                 if(node->flag & SELECT) {
1773                         if(node->flag & NODE_HIDDEN)
1774                                 ishidden++;
1775                         else
1776                                 nothidden++;
1777                 }
1778         }
1779         for(node= snode->edittree->nodes.first; node; node= node->next) {
1780                 if(node->flag & SELECT) {
1781                         if( (ishidden && nothidden) || ishidden==0)
1782                                 node->flag |= NODE_HIDDEN;
1783                         else 
1784                                 node->flag &= ~NODE_HIDDEN;
1785                 }
1786         }
1787         
1788         snode_notify(C, snode);
1789         
1790         return OPERATOR_FINISHED;
1791 }
1792
1793 void NODE_OT_hide(wmOperatorType *ot)
1794 {
1795         /* identifiers */
1796         ot->name= "Hide";
1797         ot->description= "Toggle hiding of the nodes";
1798         ot->idname= "NODE_OT_hide";
1799         
1800         /* callbacks */
1801         ot->exec= node_hide_exec;
1802         ot->poll= ED_operator_node_active;
1803         
1804         /* flags */
1805         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1806 }
1807
1808 /* ****************** Mute operator *********************** */
1809
1810 static int node_mute_exec(bContext *C, wmOperator *op)
1811 {
1812         SpaceNode *snode= CTX_wm_space_node(C);
1813         bNode *node;
1814
1815         /* no disabling inside of groups */
1816         if(node_tree_get_editgroup(snode->nodetree))
1817                 return OPERATOR_CANCELLED;
1818         
1819         for(node= snode->edittree->nodes.first; node; node= node->next) {
1820                 if(node->flag & SELECT) {
1821                         if(node->inputs.first && node->outputs.first) {
1822                                 node->flag ^= NODE_MUTED;
1823                                 NodeTagChanged(snode->edittree, node);
1824                         }
1825                 }
1826         }
1827         
1828         snode_notify(C, snode);
1829         
1830         return OPERATOR_FINISHED;
1831 }
1832
1833 void NODE_OT_mute(wmOperatorType *ot)
1834 {
1835         /* identifiers */
1836         ot->name= "Mute";
1837         ot->description= "Toggle muting of the nodes";
1838         ot->idname= "NODE_OT_mute";
1839         
1840         /* callbacks */
1841         ot->exec= node_mute_exec;
1842         ot->poll= ED_operator_node_active;
1843         
1844         /* flags */
1845         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1846 }
1847
1848 /* ****************** Delete operator ******************* */
1849
1850 static int node_delete_exec(bContext *C, wmOperator *op)
1851 {
1852         SpaceNode *snode= CTX_wm_space_node(C);
1853         bNode *node, *next;
1854         
1855         for(node= snode->edittree->nodes.first; node; node= next) {
1856                 next= node->next;
1857                 if(node->flag & SELECT) {
1858                         /* check id user here, nodeFreeNode is called for free dbase too */
1859                         if(node->id)
1860                                 node->id->us--;
1861                         nodeFreeNode(snode->edittree, node);
1862                 }
1863         }
1864         
1865         node_tree_verify_groups(snode->nodetree);
1866
1867         snode_notify(C, snode);
1868         
1869         return OPERATOR_FINISHED;
1870 }
1871
1872 void NODE_OT_delete(wmOperatorType *ot)
1873 {
1874         /* identifiers */
1875         ot->name= "Delete";
1876         ot->description = "Delete selected nodes";
1877         ot->idname= "NODE_OT_delete";
1878         
1879         /* api callbacks */
1880         ot->exec= node_delete_exec;
1881         ot->poll= ED_operator_node_active;
1882         
1883         /* flags */
1884         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1885 }
1886
1887 /* ****************** Show Cyclic Dependencies Operator  ******************* */
1888
1889 static int node_show_cycles_exec(bContext *C, wmOperator *op)
1890 {
1891         SpaceNode *snode= CTX_wm_space_node(C);
1892         
1893         /* this is just a wrapper around this call... */
1894         ntreeSolveOrder(snode->edittree);
1895         snode_notify(C, snode);
1896         
1897         return OPERATOR_FINISHED;
1898 }
1899
1900 void NODE_OT_show_cyclic_dependencies(wmOperatorType *ot)
1901 {
1902         /* identifiers */
1903         ot->name= "Show Cyclic Dependencies";
1904         ot->description= "Sort the nodes and show the cyclic dependencies between the nodes";
1905         ot->idname= "NODE_OT_show_cyclic_dependencies";
1906         
1907         /* callbacks */
1908         ot->exec= node_show_cycles_exec;
1909         ot->poll= ED_operator_node_active;
1910         
1911         /* flags */
1912         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1913 }
1914
1915