Toggle links tool for Node Editor
[blender.git] / source / blender / src / editnode.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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): none yet.
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_color_types.h"
39 #include "DNA_image_types.h"
40 #include "DNA_ipo_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_node_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_userdef_types.h"
48
49 #include "BKE_colortools.h"
50 #include "BKE_global.h"
51 #include "BKE_image.h"
52 #include "BKE_library.h"
53 #include "BKE_main.h"
54 #include "BKE_node.h"
55 #include "BKE_material.h"
56 #include "BKE_scene.h"
57 #include "BKE_utildefines.h"
58
59 #include "BIF_cursors.h"
60 #include "BIF_editview.h"
61 #include "BIF_gl.h"
62 #include "BIF_graphics.h"
63 #include "BIF_imasel.h"
64 #include "BIF_interface.h"
65 #include "BIF_mywindow.h"
66 #include "BIF_previewrender.h"
67 #include "BIF_resources.h"
68 #include "BIF_renderwin.h"
69 #include "BIF_space.h"
70 #include "BIF_screen.h"
71 #include "BIF_toolbox.h"
72
73 #include "BSE_drawipo.h"
74 #include "BSE_edit.h"
75 #include "BSE_filesel.h"
76 #include "BSE_headerbuttons.h"
77 #include "BSE_node.h"
78
79 #include "BLI_blenlib.h"
80 #include "BLI_arithb.h"
81
82 #include "BDR_editobject.h"
83
84 #include "RE_pipeline.h"
85 #include "IMB_imbuf_types.h"
86
87 #include "blendef.h"
88 #include "butspace.h"
89 #include "PIL_time.h"
90 #include "mydevice.h"
91 #include "winlay.h"
92
93
94 /* currently called from BIF_preview_changed */
95 void snode_tag_dirty(SpaceNode *snode)
96 {
97         bNode *node;
98         
99         if(snode->treetype==NTREE_SHADER) {
100                 if(snode->nodetree) {
101                         for(node= snode->nodetree->nodes.first; node; node= node->next) {
102                                 if(node->type==SH_NODE_OUTPUT)
103                                         node->lasty= 0;
104                         }
105                         snode->flag |= SNODE_DO_PREVIEW;        /* this adds an afterqueue on a redraw, to allow button previews to work first */
106                 }
107         }
108         allqueue(REDRAWNODE, 1);
109 }
110
111 static void shader_node_previewrender(ScrArea *sa, SpaceNode *snode)
112 {
113         bNode *node;
114         
115         if(snode->id==NULL) return;
116         if( ((Material *)snode->id )->use_nodes==0 ) return;
117
118         for(node= snode->nodetree->nodes.first; node; node= node->next) {
119                 if(node->type==SH_NODE_OUTPUT) {
120                         if(node->flag & NODE_DO_OUTPUT) {
121                                 if(node->lasty<PREVIEW_RENDERSIZE-2) {
122                                         RenderInfo ri;  
123 //                                      int test= node->lasty;
124                                         
125                                         ri.curtile = 0;
126                                         ri.tottile = 0;
127                                         ri.rect = NULL;
128                                         ri.pr_rectx = PREVIEW_RENDERSIZE;
129                                         ri.pr_recty = PREVIEW_RENDERSIZE;
130                                         
131                                         BIF_previewrender(snode->id, &ri, NULL, PR_DO_RENDER);  /* sends redraw event */
132                                         if(ri.rect) MEM_freeN(ri.rect);
133                                         
134                                         /* when not finished... */
135                                         if(ri.curtile<ri.tottile)
136                                                 addafterqueue(sa->win, RENDERPREVIEW, 1);
137 //                                      if(test!=node->lasty)
138 //                                              printf("node rendered to %d\n", node->lasty);
139
140                                         break;
141                                 }
142                         }
143                 }
144         }
145 }
146
147
148 static void snode_handle_recalc(SpaceNode *snode)
149 {
150         if(snode->treetype==NTREE_SHADER) {
151                 BIF_preview_changed(ID_MA);      /* signals buttons windows and node editors */
152         }
153         else if(snode->treetype==NTREE_COMPOSIT) {
154                 if(G.scene->use_nodes) {
155                         snode->nodetree->timecursor= set_timecursor;
156                         G.afbreek= 0;
157                         snode->nodetree->test_break= blender_test_break;
158                         
159                         BIF_store_spare();
160                         
161                         ntreeCompositExecTree(snode->nodetree, &G.scene->r, 1); /* 1 is do_previews */
162                         
163                         snode->nodetree->timecursor= NULL;
164                         snode->nodetree->test_break= NULL;
165                         waitcursor(0);
166                         
167                         allqueue(REDRAWNODE, 1);
168                         allqueue(REDRAWIMAGE, 1);
169                         if(G.scene->r.scemode & R_DOCOMP) {
170                                 BIF_redraw_render_rect();       /* seems to screwup display? */
171                                 mywinset(curarea->win);
172                         }
173                 }
174         }
175 }
176
177 static void shader_node_event(SpaceNode *snode, short event)
178 {
179         switch(event) {
180                 case B_REDR:
181                         allqueue(REDRAWNODE, 1);
182                         break;
183                 default:
184                         /* B_NODE_EXEC */
185                         snode_handle_recalc(snode);
186                         break;
187                         
188         }
189 }
190
191 static void load_node_image(char *str)  /* called from fileselect */
192 {
193         SpaceNode *snode= curarea->spacedata.first;
194         bNode *node= nodeGetActive(snode->edittree);
195         Image *ima= NULL;
196         
197         ima= BKE_add_image_file(str);
198         if(ima) {
199                 if(node->id)
200                         node->id->us--;
201                 
202                 node->id= &ima->id;
203                 id_us_plus(node->id);
204
205                 BLI_strncpy(node->name, node->id->name+2, 21);
206                                    
207                 BKE_image_signal(ima, node->storage, IMA_SIGNAL_RELOAD);
208                 
209                 NodeTagChanged(snode->edittree, node);
210                 snode_handle_recalc(snode);
211                 allqueue(REDRAWNODE, 0); 
212         }
213 }
214
215 static bNode *snode_get_editgroup(SpaceNode *snode)
216 {
217         bNode *gnode;
218         
219         /* get the groupnode */
220         for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next)
221                 if(gnode->flag & NODE_GROUP_EDIT)
222                         break;
223         return gnode;
224 }
225
226 /* node has to be of type 'render layers' */
227 /* is a bit clumsy copying renderdata here... scene nodes use render size of current render */
228 static void composite_node_render(SpaceNode *snode, bNode *node)
229 {
230         RenderData rd;
231         Scene *scene= NULL;
232         int scemode, actlay;
233         
234         /* the button press won't show up otherwise, button hilites disabled */
235         force_draw(0);
236         
237         if(node->id && node->id!=(ID *)G.scene) {
238                 scene= G.scene;
239                 set_scene_bg((Scene *)node->id);
240                 rd= G.scene->r;
241                 G.scene->r.xsch= scene->r.xsch;
242                 G.scene->r.ysch= scene->r.ysch;
243                 G.scene->r.size= scene->r.size;
244                 G.scene->r.mode &= ~(R_BORDER|R_DOCOMP);
245                 G.scene->r.mode |= scene->r.mode & R_BORDER;
246                 G.scene->r.border= scene->r.border;
247         }
248         
249         scemode= G.scene->r.scemode;
250         actlay= G.scene->r.actlay;
251         
252         G.scene->r.scemode |= R_SINGLE_LAYER;
253         G.scene->r.actlay= node->custom1;
254         
255         BIF_do_render(0);
256         
257         G.scene->r.scemode= scemode;
258         G.scene->r.actlay= actlay;
259
260         node->custom2= 0;
261         
262         if(scene) {
263                 G.scene->r= rd;
264                 set_scene_bg(scene);
265         }
266 }
267
268 static void composit_node_event(SpaceNode *snode, short event)
269 {
270         
271         switch(event) {
272                 case B_REDR:
273                         allqueue(REDRAWNODE, 1);
274                         break;
275                 case B_NODE_LOADIMAGE:
276                 {
277                         bNode *node= nodeGetActive(snode->edittree);
278                         char name[FILE_MAXDIR+FILE_MAXFILE];
279                         
280                         if(node->id)
281                                 strcpy(name, ((Image *)node->id)->name);
282                         else strcpy(name, U.textudir);
283                         if (G.qual & LR_CTRLKEY) {
284                                 activate_imageselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
285                         } else {
286                                 activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
287                         }
288                         break;
289                 }
290                 case B_NODE_TREE_EXEC:
291                         snode_handle_recalc(snode);
292                         break;          
293                 default:
294                         /* B_NODE_EXEC */
295                 {
296                         bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
297                         if(node) {
298                                 NodeTagChanged(snode->edittree, node);
299                                 NodeTagIDChanged(snode->nodetree, node->id);    /* Scene-layer nodes, texture nodes, image nodes, all can be used many times */
300                                 
301                                 /* not the best implementation of the world... but we need it to work now :) */
302                                 if(node->type==CMP_NODE_R_LAYERS && node->custom2) {
303                                         composite_node_render(snode, node);
304                                         /* new event, a render can go fullscreen and open new window */
305                                         addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
306                                 }
307                                 else {
308                                         node= snode_get_editgroup(snode);
309                                         if(node)
310                                                 NodeTagIDChanged(snode->nodetree, node->id);
311                                         
312                                         snode_handle_recalc(snode);
313                                 }
314                         }
315                 }                       
316         }
317 }
318
319
320 /* assumes nothing being done in ntree yet, sets the default in/out node */
321 /* called from shading buttons or header */
322 void node_shader_default(Material *ma)
323 {
324         bNode *in, *out;
325         bNodeSocket *fromsock, *tosock;
326         
327         /* but lets check it anyway */
328         if(ma->nodetree) {
329                 printf("error in shader initialize\n");
330                 return;
331         }
332         
333         ma->nodetree= ntreeAddTree(NTREE_SHADER);
334         
335         out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
336         out->locx= 300.0f; out->locy= 300.0f;
337         
338         in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
339         in->locx= 10.0f; in->locy= 300.0f;
340         nodeSetActive(ma->nodetree, in);
341         
342         /* only a link from color to color */
343         fromsock= in->outputs.first;
344         tosock= out->inputs.first;
345         nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
346         
347         ntreeSolveOrder(ma->nodetree);  /* needed for pointers */
348 }
349
350 /* assumes nothing being done in ntree yet, sets the default in/out node */
351 /* called from shading buttons or header */
352 void node_composit_default(Scene *sce)
353 {
354         bNode *in, *out;
355         bNodeSocket *fromsock, *tosock;
356         
357         /* but lets check it anyway */
358         if(sce->nodetree) {
359                 printf("error in composit initialize\n");
360                 return;
361         }
362         
363         sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
364         
365         out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
366         out->locx= 300.0f; out->locy= 400.0f;
367         
368         in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL);
369         in->locx= 10.0f; in->locy= 400.0f;
370         nodeSetActive(sce->nodetree, in);
371         
372         /* links from color to color */
373         fromsock= in->outputs.first;
374         tosock= out->inputs.first;
375         nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
376         
377         ntreeSolveOrder(sce->nodetree); /* needed for pointers */
378         
379         ntreeCompositForceHidden(sce->nodetree);
380 }
381
382 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
383 void snode_set_context(SpaceNode *snode)
384 {
385         Object *ob= OBACT;
386         bNode *node= NULL;
387         
388         snode->nodetree= NULL;
389         snode->id= snode->from= NULL;
390         
391         if(snode->treetype==NTREE_SHADER) {
392                 /* need active object, or we allow pinning... */
393                 if(ob) {
394                         Material *ma= give_current_material(ob, ob->actcol);
395                         if(ma) {
396                                 snode->from= material_from(ob, ob->actcol);
397                                 snode->id= &ma->id;
398                                 snode->nodetree= ma->nodetree;
399                         }
400                 }
401         }
402         else if(snode->treetype==NTREE_COMPOSIT) {
403                 snode->from= NULL;
404                 snode->id= &G.scene->id;
405                 
406                 /* bit clumsy but reliable way to see if we draw first time */
407                 if(snode->nodetree==NULL)
408                         ntreeCompositForceHidden(G.scene->nodetree);
409                 
410                 snode->nodetree= G.scene->nodetree;
411         }
412         
413         /* find editable group */
414         if(snode->nodetree)
415                 for(node= snode->nodetree->nodes.first; node; node= node->next)
416                         if(node->flag & NODE_GROUP_EDIT)
417                                 break;
418         
419         if(node && node->id)
420                 snode->edittree= (bNodeTree *)node->id;
421         else
422                 snode->edittree= snode->nodetree;
423 }
424
425 /* on activate image viewer, check if we show it */
426 static void node_active_image(Image *ima)
427 {
428         ScrArea *sa;
429         SpaceImage *sima= NULL;
430         
431         /* find an imagewindow showing render result */
432         for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
433                 if(sa->spacetype==SPACE_IMAGE) {
434                         sima= sa->spacedata.first;
435                         if(sima->image && sima->image->source!=IMA_SRC_VIEWER)
436                                 break;
437                 }
438         }
439         if(sa && sima) {
440                 sima->image= ima;
441                 scrarea_queue_winredraw(sa);
442                 scrarea_queue_headredraw(sa);
443         }
444 }
445
446
447 static void node_set_active(SpaceNode *snode, bNode *node)
448 {
449         
450         nodeSetActive(snode->edittree, node);
451         
452         if(node->type!=NODE_GROUP) {
453                 
454                 /* tree specific activate calls */
455                 if(snode->treetype==NTREE_SHADER) {
456                         
457                         /* when we select a material, active texture is cleared, for buttons */
458                         if(node->id && GS(node->id->name)==ID_MA)
459                                 nodeClearActiveID(snode->edittree, ID_TE);
460                         if(node->id)
461                                 BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
462                         
463                         allqueue(REDRAWBUTSSHADING, 1);
464                         allqueue(REDRAWIPO, 0);
465                 }
466                 else if(snode->treetype==NTREE_COMPOSIT) {
467                         /* make active viewer, currently only 1 supported... */
468                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
469                                 bNode *tnode;
470                                 int was_output= node->flag & NODE_DO_OUTPUT;
471
472                                 for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
473                                         if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
474                                                 tnode->flag &= ~NODE_DO_OUTPUT;
475                                 
476                                 node->flag |= NODE_DO_OUTPUT;
477                                 if(was_output==0) {
478                                         bNode *gnode;
479                                         
480                                         NodeTagChanged(snode->edittree, node);
481                                         
482                                         /* if inside group, tag entire group */
483                                         gnode= snode_get_editgroup(snode);
484                                         if(gnode)
485                                                 NodeTagIDChanged(snode->nodetree, gnode->id);
486                                         
487                                         snode_handle_recalc(snode);
488                                 }
489                                 
490                                 /* addnode() doesnt link this yet... */
491                                 node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
492                         }
493                         else if(node->type==CMP_NODE_IMAGE) {
494                                 if(node->id)
495                                         node_active_image((Image *)node->id);
496                         }
497                         else if(node->type==CMP_NODE_R_LAYERS) {
498                                 if(node->id==NULL || node->id==(ID *)G.scene) {
499                                         G.scene->r.actlay= node->custom1;
500                                         allqueue(REDRAWBUTSSCENE, 0);
501                                 }
502                         }
503                 }
504         }
505 }
506
507 void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
508 {
509         bNode *node;
510         
511         /* make sure nothing has group editing on */
512         for(node= snode->nodetree->nodes.first; node; node= node->next)
513                 node->flag &= ~NODE_GROUP_EDIT;
514         
515         if(gnode==NULL) {
516                 /* with NULL argument we do a toggle */
517                 if(snode->edittree==snode->nodetree)
518                         gnode= nodeGetActive(snode->nodetree);
519         }
520         
521         if(gnode && gnode->type==NODE_GROUP && gnode->id) {
522                 if(gnode->id->lib) {
523                         if(okee("Make Group Local"))
524                                 ntreeMakeLocal((bNodeTree *)gnode->id);
525                         else
526                                 return;
527                 }
528                 gnode->flag |= NODE_GROUP_EDIT;
529                 snode->edittree= (bNodeTree *)gnode->id;
530                 
531                 /* deselect all other nodes, so we can also do grabbing of entire subtree */
532                 for(node= snode->nodetree->nodes.first; node; node= node->next)
533                         node->flag &= ~SELECT;
534                 gnode->flag |= SELECT;
535                 
536         }
537         else 
538                 snode->edittree= snode->nodetree;
539         
540         ntreeSolveOrder(snode->nodetree);
541         
542         /* finally send out events for new active node */
543         if(snode->treetype==NTREE_SHADER) {
544                 allqueue(REDRAWBUTSSHADING, 0);
545                 
546                 BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
547         }
548         
549         allqueue(REDRAWNODE, 0);
550 }
551
552 void node_ungroup(SpaceNode *snode)
553 {
554         bNode *gnode;
555
556         /* are we inside of a group? */
557         gnode= snode_get_editgroup(snode);
558         if(gnode)
559                 snode_make_group_editable(snode, NULL);
560         
561         gnode= nodeGetActive(snode->edittree);
562         if(gnode==NULL) return;
563         
564         if(gnode->type!=NODE_GROUP)
565                 error("Not a group");
566         else {
567                 if(nodeGroupUnGroup(snode->edittree, gnode)) {
568                         
569                         BIF_undo_push("Deselect all nodes");
570                         allqueue(REDRAWNODE, 0);
571                 }
572                 else
573                         error("Can't ungroup");
574         }
575 }
576
577 /* when links in groups change, inputs/outputs change, nodes added/deleted... */
578 static void snode_verify_groups(SpaceNode *snode)
579 {
580         bNode *gnode;
581         
582         gnode= snode_get_editgroup(snode);
583         
584         /* does all materials */
585         if(gnode)
586                 nodeVerifyGroup((bNodeTree *)gnode->id);
587         
588 }
589
590 static void node_addgroup(SpaceNode *snode)
591 {
592         bNodeTree *ngroup;
593         int tot= 0, offs, val;
594         char *strp;
595         
596         if(snode->edittree!=snode->nodetree) {
597                 error("Can not add a Group in a Group");
598                 return;
599         }
600         
601         /* construct menu with choices */
602         for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
603                 if(ngroup->type==snode->treetype)
604                         tot++;
605         }
606         if(tot==0) {
607                 error("No groups available in database");
608                 return;
609         }
610         strp= MEM_mallocN(32*tot+32, "menu");
611         strcpy(strp, "Add Group %t");
612         offs= strlen(strp);
613         
614         for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
615                 if(ngroup->type==snode->treetype)
616                         offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
617         }       
618         
619         val= pupmenu(strp);
620         if(val>=0) {
621                 ngroup= BLI_findlink(&G.main->nodetree, val);
622                 if(ngroup) {
623                         bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
624                         
625                         /* generics */
626                         if(node) {
627                                 float locx, locy;
628                                 short mval[2];
629
630                                 node_deselectall(snode, 0);
631                                 
632                                 getmouseco_areawin(mval);
633                                 areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
634                                 
635                                 node->locx= locx;
636                                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
637                                 node->flag |= SELECT;
638                                 
639                                 id_us_plus(node->id);
640                                 
641                                 node_set_active(snode, node);
642                                 BIF_undo_push("Add Node");
643                         }
644                 }                       
645         }
646         MEM_freeN(strp);
647 }
648
649
650 /* ************************** Node generic ************** */
651
652 /* allows to walk the list in order of visibility */
653 static bNode *next_node(bNodeTree *ntree)
654 {
655         static bNode *current=NULL, *last= NULL;
656         
657         if(ntree) {
658                 /* set current to the first selected node */
659                 for(current= ntree->nodes.last; current; current= current->prev)
660                         if(current->flag & NODE_SELECT)
661                                 break;
662                 
663                 /* set last to the first unselected node */
664                 for(last= ntree->nodes.last; last; last= last->prev)
665                         if((last->flag & NODE_SELECT)==0)
666                                 break;
667                 
668                 if(current==NULL)
669                         current= last;
670                 
671                 return NULL;
672         }
673         /* no nodes, or we are ready */
674         if(current==NULL)
675                 return NULL;
676         
677         /* now we walk the list backwards, but we always return current */
678         if(current->flag & NODE_SELECT) {
679                 bNode *node= current;
680                 
681                 /* find previous selected */
682                 current= current->prev;
683                 while(current && (current->flag & NODE_SELECT)==0)
684                         current= current->prev;
685                 
686                 /* find first unselected */
687                 if(current==NULL)
688                         current= last;
689                 
690                 return node;
691         }
692         else {
693                 bNode *node= current;
694                 
695                 /* find previous unselected */
696                 current= current->prev;
697                 while(current && (current->flag & NODE_SELECT))
698                         current= current->prev;
699                 
700                 return node;
701         }
702         
703         return NULL;
704 }
705
706 /* is rct in visible part of node? */
707 static bNode *visible_node(SpaceNode *snode, rctf *rct)
708 {
709         bNode *tnode;
710         
711         for(next_node(snode->edittree); (tnode=next_node(NULL));) {
712                 if(BLI_isect_rctf(&tnode->totr, rct, NULL))
713                         break;
714         }
715         return tnode;
716 }
717
718 void snode_home(ScrArea *sa, SpaceNode *snode)
719 {
720         bNode *node;
721         int first= 1;
722         
723         snode->v2d.cur.xmin= snode->v2d.cur.ymin= 0.0f;
724         snode->v2d.cur.xmax= sa->winx;
725         snode->v2d.cur.xmax= sa->winy;
726         
727         if(snode->edittree) {
728                 for(node= snode->edittree->nodes.first; node; node= node->next) {
729                         if(first) {
730                                 first= 0;
731                                 snode->v2d.cur= node->totr;
732                         }
733                         else {
734                                 BLI_union_rctf(&snode->v2d.cur, &node->totr);
735                         }
736                 }
737         }
738         snode->v2d.tot= snode->v2d.cur;
739         
740         snode->xof = snode->yof = 0.0;
741         
742         test_view2d(G.v2d, sa->winx, sa->winy);
743         
744 }
745
746 void snode_zoom_out(ScrArea *sa)
747 {
748         float dx;
749         
750         dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
751         G.v2d->cur.xmin-= dx;
752         G.v2d->cur.xmax+= dx;
753         dx= (float)(0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin));
754         G.v2d->cur.ymin-= dx;
755         G.v2d->cur.ymax+= dx;
756         test_view2d(G.v2d, sa->winx, sa->winy);
757 }
758
759 void snode_zoom_in(ScrArea *sa)
760 {
761         float dx;
762         
763         dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
764         G.v2d->cur.xmin+= dx;
765         G.v2d->cur.xmax-= dx;
766         dx= (float)(0.1154*(G.v2d->cur.ymax-G.v2d->cur.ymin));
767         G.v2d->cur.ymin+= dx;
768         G.v2d->cur.ymax-= dx;
769         test_view2d(G.v2d, sa->winx, sa->winy);
770 }
771
772 static void snode_bg_viewmove(SpaceNode *snode)
773 {
774         ScrArea *sa;
775         Image *ima;
776         ImBuf *ibuf;
777         Window *win;
778         short mval[2], mvalo[2];
779         short rectx, recty, xmin, xmax, ymin, ymax, pad;
780         int oldcursor;
781         
782         ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
783         ibuf= BKE_image_get_ibuf(ima, NULL);
784         
785         sa = snode->area;
786         
787         if(ibuf) {
788                 rectx = ibuf->x;
789                 recty = ibuf->y;
790         } else {
791                 rectx = recty = 1;
792         }
793         
794         pad = 10;
795         xmin = -(sa->winx/2) - rectx/2 + pad;
796         xmax = sa->winx/2 + rectx/2 - pad;
797         ymin = -(sa->winy/2) - recty/2 + pad;
798         ymax = sa->winy/2 + recty/2 - pad;
799         
800         getmouseco_sc(mvalo);
801         
802         /* store the old cursor to temporarily change it */
803         oldcursor=get_cursor();
804         win=winlay_get_active_window();
805         
806         SetBlenderCursor(BC_NSEW_SCROLLCURSOR);
807         
808         while(get_mbut()&(L_MOUSE|M_MOUSE)) {
809                 
810                 getmouseco_sc(mval);
811                 
812                 if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
813                         
814                         snode->xof -= (mvalo[0]-mval[0]);
815                         snode->yof -= (mvalo[1]-mval[1]);
816                         
817                         /* prevent dragging image outside of the window and losing it! */
818                         CLAMP(snode->xof, xmin, xmax);
819                         CLAMP(snode->yof, ymin, ymax);
820                         
821                         mvalo[0]= mval[0];
822                         mvalo[1]= mval[1];
823                         
824                         scrarea_do_windraw(curarea);
825                         screen_swapbuffers();
826                 }
827                 else BIF_wait_for_statechange();
828         }
829         
830         window_set_cursor(win, oldcursor);
831 }
832
833 static void reset_sel_socket(SpaceNode *snode, int in_out)
834 {
835         bNode *node;
836         bNodeSocket *sock;
837         
838         for(node= snode->edittree->nodes.first; node; node= node->next) {
839                 if(in_out & SOCK_IN) {
840                         for(sock= node->inputs.first; sock; sock= sock->next)
841                                 if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
842                 }
843                 if(in_out & SOCK_OUT) {
844                         for(sock= node->outputs.first; sock; sock= sock->next)
845                                 if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
846                 }
847         }
848 }
849
850 /* checks mouse position, and returns found node/socket */
851 /* type is SOCK_IN and/or SOCK_OUT */
852 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
853 {
854         bNode *node;
855         bNodeSocket *sock;
856         rctf rect;
857         short mval[2];
858         
859         getmouseco_areawin(mval);
860         
861         /* check if we click in a socket */
862         for(node= snode->edittree->nodes.first; node; node= node->next) {
863         
864                 areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
865                 
866                 rect.xmin -= NODE_SOCKSIZE+3;
867                 rect.ymin -= NODE_SOCKSIZE+3;
868                 rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
869                 rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
870                 
871                 if (!(node->flag & NODE_HIDDEN)) {
872                         /* extra padding inside and out - allow dragging on the text areas too */
873                         if (in_out == SOCK_IN) {
874                                 rect.xmax += NODE_SOCKSIZE;
875                                 rect.xmin -= NODE_SOCKSIZE*4;
876                         } else if (in_out == SOCK_OUT) {
877                                 rect.xmax += NODE_SOCKSIZE*4;
878                                 rect.xmin -= NODE_SOCKSIZE;
879                         }
880                 }
881                         
882                 if(in_out & SOCK_IN) {
883                         for(sock= node->inputs.first; sock; sock= sock->next) {
884                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
885                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
886                                                 if(node == visible_node(snode, &rect)) {
887                                                         *nodep= node;
888                                                         *sockp= sock;
889                                                         return 1;
890                                                 }
891                                         }
892                                 }
893                         }
894                 }
895                 if(in_out & SOCK_OUT) {
896                         for(sock= node->outputs.first; sock; sock= sock->next) {
897                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
898                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
899                                                 if(node == visible_node(snode, &rect)) {
900                                                         *nodep= node;
901                                                         *sockp= sock;
902                                                         return 1;
903                                                 }
904                                         }
905                                 }
906                         }
907                 }
908         }
909         return 0;
910 }
911
912 /* ********************* transform ****************** */
913
914 /* releases on event, only intern (for extern see below) */
915 /* we need argument ntree to allow operations on edittree or nodetree */
916 static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
917 {
918         bNode *node;
919         float mxstart, mystart, mx, my, *oldlocs, *ol;
920         int cont=1, tot=0, cancel=0, firsttime=1;
921         short mval[2], mvalo[2];
922         
923         /* count total */
924         for(node= ntree->nodes.first; node; node= node->next)
925                 if(node->flag & SELECT) tot++;
926         
927         if(tot==0) return;
928         
929         /* store oldlocs */
930         ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
931         for(node= ntree->nodes.first; node; node= node->next) {
932                 if(node->flag & SELECT) {
933                         ol[0]= node->locx; ol[1]= node->locy;
934                         ol+= 2;
935                 }
936         }
937         
938         getmouseco_areawin(mvalo);
939         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
940         
941         while(cont) {
942                 
943                 getmouseco_areawin(mval);
944                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
945
946                         firsttime= 0;
947                         
948                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
949                         mvalo[0]= mval[0];
950                         mvalo[1]= mval[1];
951                         
952                         for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
953                                 if(node->flag & SELECT) {
954                                         node->locx= ol[0] + mx-mxstart;
955                                         node->locy= ol[1] + my-mystart;
956                                         ol+= 2;
957                                 }
958                         }
959                         
960                         force_draw(0);
961                 }
962                 else
963                         PIL_sleep_ms(10);
964                 
965                 while (qtest()) {
966                         short val;
967                         unsigned short event= extern_qread(&val);
968                         
969                         switch (event) {
970                                 case LEFTMOUSE:
971                                 case SPACEKEY:
972                                 case RETKEY:
973                                         cont=0;
974                                         break;
975                                 case ESCKEY:
976                                 case RIGHTMOUSE:
977                                         if(val) {
978                                                 cancel=1;
979                                                 cont=0;
980                                         }
981                                         break;
982                                 default:
983                                         if(val) arrows_move_cursor(event);
984                                         break;
985                         }
986                 }
987                 
988         }
989         
990         if(cancel) {
991                 for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
992                         if(node->flag & SELECT) {
993                                 node->locx= ol[0];
994                                 node->locy= ol[1];
995                                 ol+= 2;
996                         }
997                 }
998                 
999         }
1000         else
1001                 BIF_undo_push(undostr);
1002         
1003         allqueue(REDRAWNODE, 1);
1004         MEM_freeN(oldlocs);
1005 }
1006
1007 /* external call, also for callback */
1008 void node_transform_ext(int mode, int unused)
1009 {
1010         SpaceNode *snode= curarea->spacedata.first;
1011         
1012         transform_nodes(snode->edittree, 'g', "Move Node");
1013 }
1014
1015
1016 /* releases on event, only 1 node */
1017 static void scale_node(SpaceNode *snode, bNode *node)
1018 {
1019         float mxstart, mystart, mx, my, oldwidth;
1020         int cont=1, cancel=0;
1021         short mval[2], mvalo[2];
1022         
1023         /* store old */
1024         if(node->flag & NODE_HIDDEN)
1025                 oldwidth= node->miniwidth;
1026         else
1027                 oldwidth= node->width;
1028                 
1029         getmouseco_areawin(mvalo);
1030         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
1031         
1032         while(cont) {
1033                 
1034                 getmouseco_areawin(mval);
1035                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
1036                         
1037                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1038                         mvalo[0]= mval[0];
1039                         mvalo[1]= mval[1];
1040                         
1041                         if(node->flag & NODE_HIDDEN) {
1042                                 node->miniwidth= oldwidth + mx-mxstart;
1043                                 CLAMP(node->miniwidth, 0.0f, 100.0f);
1044                         }
1045                         else {
1046                                 node->width= oldwidth + mx-mxstart;
1047                                 CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
1048                         }
1049                         
1050                         force_draw(0);
1051                 }
1052                 else
1053                         PIL_sleep_ms(10);
1054                 
1055                 while (qtest()) {
1056                         short val;
1057                         unsigned short event= extern_qread(&val);
1058                         
1059                         switch (event) {
1060                                 case LEFTMOUSE:
1061                                 case SPACEKEY:
1062                                 case RETKEY:
1063                                         cont=0;
1064                                         break;
1065                                 case ESCKEY:
1066                                 case RIGHTMOUSE:
1067                                         if(val) {
1068                                                 cancel=1;
1069                                                 cont=0;
1070                                         }
1071                                         break;
1072                         }
1073                 }
1074                 
1075         }
1076         
1077         if(cancel) {
1078                 node->width= oldwidth;
1079         }
1080         else
1081                 BIF_undo_push("Scale Node");
1082         
1083         allqueue(REDRAWNODE, 1);
1084 }
1085
1086
1087
1088 /* ********************** select ******************** */
1089
1090 /* used in buttons to check context, also checks for edited groups */
1091 bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
1092 {
1093         bNode *node;
1094         
1095         /* check for edited group */
1096         for(node= ntree->nodes.first; node; node= node->next)
1097                 if(node->flag & NODE_GROUP_EDIT)
1098                         break;
1099         if(node)
1100                 return nodeGetActiveID((bNodeTree *)node->id, id_code);
1101         else
1102                 return nodeGetActiveID(ntree, id_code);
1103 }
1104
1105 /* used in buttons to check context, also checks for edited groups */
1106 Material *editnode_get_active_material(Material *ma)
1107 {
1108         if(ma && ma->use_nodes && ma->nodetree) {
1109                 bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
1110                 if(node)
1111                         return (Material *)node->id;
1112                 else
1113                         return NULL;
1114         }
1115         return ma;
1116 }
1117
1118 /* used in buttons to check context, also checks for edited groups */
1119 bNode *editnode_get_active(bNodeTree *ntree)
1120 {
1121         bNode *node;
1122         
1123         /* check for edited group */
1124         for(node= ntree->nodes.first; node; node= node->next)
1125                 if(node->flag & NODE_GROUP_EDIT)
1126                         break;
1127         if(node)
1128                 return nodeGetActive((bNodeTree *)node->id);
1129         else
1130                 return nodeGetActive(ntree);
1131 }
1132
1133
1134 /* no undo here! */
1135 void node_deselectall(SpaceNode *snode, int swap)
1136 {
1137         bNode *node;
1138         
1139         if(swap) {
1140                 for(node= snode->edittree->nodes.first; node; node= node->next)
1141                         if(node->flag & SELECT)
1142                                 break;
1143                 if(node==NULL) {
1144                         for(node= snode->edittree->nodes.first; node; node= node->next)
1145                                 node->flag |= SELECT;
1146                         allqueue(REDRAWNODE, 0);
1147                         return;
1148                 }
1149                 /* else pass on to deselect */
1150         }
1151         
1152         for(node= snode->edittree->nodes.first; node; node= node->next)
1153                 node->flag &= ~SELECT;
1154         
1155         allqueue(REDRAWNODE, 0);
1156 }
1157
1158 int node_has_hidden_sockets(bNode *node)
1159 {
1160         bNodeSocket *sock;
1161         
1162         for(sock= node->inputs.first; sock; sock= sock->next)
1163                 if(sock->flag & SOCK_HIDDEN)
1164                         return 1;
1165         for(sock= node->outputs.first; sock; sock= sock->next)
1166                 if(sock->flag & SOCK_HIDDEN)
1167                         return 1;
1168         return 0;
1169 }
1170
1171
1172 static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
1173 {
1174         bNodeSocket *sock;
1175         
1176         /* unhide all */
1177         if( node_has_hidden_sockets(node) ) {
1178                 for(sock= node->inputs.first; sock; sock= sock->next)
1179                         sock->flag &= ~SOCK_HIDDEN;
1180                 for(sock= node->outputs.first; sock; sock= sock->next)
1181                         sock->flag &= ~SOCK_HIDDEN;
1182         }
1183         else {
1184                 bNode *gnode= snode_get_editgroup(snode);
1185                 
1186                 /* hiding inside group should not break links in other group users */
1187                 if(gnode) {
1188                         nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
1189                         for(sock= node->inputs.first; sock; sock= sock->next)
1190                                 if(!(sock->flag & SOCK_IN_USE))
1191                                         if(sock->link==NULL)
1192                                                 sock->flag |= SOCK_HIDDEN;
1193                         for(sock= node->outputs.first; sock; sock= sock->next)
1194                                 if(!(sock->flag & SOCK_IN_USE))
1195                                         if(nodeCountSocketLinks(snode->edittree, sock)==0)
1196                                                 sock->flag |= SOCK_HIDDEN;
1197                 }
1198                 else {
1199                         /* hide unused sockets */
1200                         for(sock= node->inputs.first; sock; sock= sock->next) {
1201                                 if(sock->link==NULL)
1202                                         sock->flag |= SOCK_HIDDEN;
1203                         }
1204                         for(sock= node->outputs.first; sock; sock= sock->next) {
1205                                 if(nodeCountSocketLinks(snode->edittree, sock)==0)
1206                                         sock->flag |= SOCK_HIDDEN;
1207                         }
1208                 }
1209         }
1210
1211         allqueue(REDRAWNODE, 1);
1212         snode_verify_groups(snode);
1213         BIF_undo_push("Hide/Unhide sockets");
1214
1215 }
1216
1217 static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
1218 {
1219         rctf totr= node->totr;
1220         
1221         totr.ymin= totr.ymax-20.0f;
1222         
1223         totr.xmax= totr.xmin+15.0f;
1224         if(BLI_in_rctf(&totr, mx, my)) {
1225                 node->flag |= NODE_HIDDEN;
1226                 allqueue(REDRAWNODE, 0);
1227                 return 1;
1228         }       
1229         
1230         totr.xmax= node->totr.xmax;
1231         totr.xmin= totr.xmax-18.0f;
1232         if(node->typeinfo->flag & NODE_PREVIEW) {
1233                 if(BLI_in_rctf(&totr, mx, my)) {
1234                         node->flag ^= NODE_PREVIEW;
1235                         allqueue(REDRAWNODE, 0);
1236                         return 1;
1237                 }
1238                 totr.xmin-=18.0f;
1239         }
1240         if(node->type == NODE_GROUP) {
1241                 if(BLI_in_rctf(&totr, mx, my)) {
1242                         snode_make_group_editable(snode, node);
1243                         return 1;
1244                 }
1245                 totr.xmin-=18.0f;
1246         }
1247         if(node->typeinfo->flag & NODE_OPTIONS) {
1248                 if(BLI_in_rctf(&totr, mx, my)) {
1249                         node->flag ^= NODE_OPTIONS;
1250                         allqueue(REDRAWNODE, 0);
1251                         return 1;
1252                 }
1253                 totr.xmin-=18.0f;
1254         }
1255         /* hide unused sockets */
1256         if(BLI_in_rctf(&totr, mx, my)) {
1257                 node_hide_unhide_sockets(snode, node);
1258         }
1259         
1260         
1261         totr= node->totr;
1262         totr.xmin= totr.xmax-10.0f;
1263         totr.ymax= totr.ymin+10.0f;
1264         if(BLI_in_rctf(&totr, mx, my)) {
1265                 scale_node(snode, node);
1266                 return 1;
1267         }
1268         return 0;
1269 }
1270
1271 static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
1272 {
1273         rctf totr= node->totr;
1274         
1275         totr.xmax= totr.xmin+15.0f;
1276         if(BLI_in_rctf(&totr, mx, my)) {
1277                 node->flag &= ~NODE_HIDDEN;
1278                 allqueue(REDRAWNODE, 0);
1279                 return 1;
1280         }       
1281         
1282         totr.xmax= node->totr.xmax;
1283         totr.xmin= node->totr.xmax-15.0f;
1284         if(BLI_in_rctf(&totr, mx, my)) {
1285                 scale_node(snode, node);
1286                 return 1;
1287         }
1288         return 0;
1289 }
1290
1291
1292 /* return 0: nothing done */
1293 static int node_mouse_select(SpaceNode *snode, unsigned short event)
1294 {
1295         bNode *node;
1296         float mx, my;
1297         short mval[2];
1298         
1299         getmouseco_areawin(mval);
1300         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1301         
1302         for(next_node(snode->edittree); (node=next_node(NULL));) {
1303                 
1304                 /* first check for the headers or scaling widget */
1305                 if(node->flag & NODE_HIDDEN) {
1306                         if(do_header_hidden_node(snode, node, mx, my))
1307                                 return 1;
1308                 }
1309                 else {
1310                         if(do_header_node(snode, node, mx, my))
1311                                 return 1;
1312                 }
1313                 
1314                 /* node body */
1315                 if(BLI_in_rctf(&node->totr, mx, my))
1316                         break;
1317         }
1318         if(node) {
1319                 if((G.qual & LR_SHIFTKEY)==0)
1320                         node_deselectall(snode, 0);
1321                 
1322                 if(G.qual & LR_SHIFTKEY) {
1323                         if(node->flag & SELECT)
1324                                 node->flag &= ~SELECT;
1325                         else
1326                                 node->flag |= SELECT;
1327                 }
1328                 else 
1329                         node->flag |= SELECT;
1330                 
1331                 node_set_active(snode, node);
1332                 
1333                 /* not so nice (no event), but function below delays redraw otherwise */
1334                 force_draw(0);
1335                 
1336                 std_rmouse_transform(node_transform_ext);       /* does undo push for select */
1337                 
1338                 return 1;
1339         }
1340         return 0;
1341 }
1342
1343 /* return 0, nothing done */
1344 static int node_mouse_groupheader(SpaceNode *snode)
1345 {
1346         bNode *gnode;
1347         float mx, my;
1348         short mval[2];
1349         
1350         gnode= snode_get_editgroup(snode);
1351         if(gnode==NULL) return 0;
1352         
1353         getmouseco_areawin(mval);
1354         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1355         
1356         /* click in header or outside? */
1357         if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1358                 rctf rect= gnode->totr;
1359                 
1360                 rect.ymax += NODE_DY;
1361                 if(BLI_in_rctf(&rect, mx, my)==0)
1362                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1363                 else
1364                         transform_nodes(snode->nodetree, 'g', "Move group");
1365                 
1366                 return 1;
1367         }
1368         return 0;
1369 }
1370
1371 static int node_socket_hilights(SpaceNode *snode, int in_out)
1372 {
1373         bNode *node;
1374         bNodeSocket *sock, *tsock, *socksel= NULL;
1375         float mx, my;
1376         short mval[2], redraw= 0;
1377         
1378         if(snode->edittree==NULL) return 0;
1379         
1380         getmouseco_areawin(mval);
1381         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1382         
1383         /* deselect socks */
1384         for(node= snode->edittree->nodes.first; node; node= node->next) {
1385                 for(sock= node->inputs.first; sock; sock= sock->next) {
1386                         if(sock->flag & SELECT) {
1387                                 sock->flag &= ~SELECT;
1388                                 redraw++;
1389                                 socksel= sock;
1390                         }
1391                 }
1392                 for(sock= node->outputs.first; sock; sock= sock->next) {
1393                         if(sock->flag & SELECT) {
1394                                 sock->flag &= ~SELECT;
1395                                 redraw++;
1396                                 socksel= sock;
1397                         }
1398                 }
1399         }
1400         
1401         if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1402                 tsock->flag |= SELECT;
1403                 if(redraw==1 && tsock==socksel) redraw= 0;
1404                 else redraw= 1;
1405         }
1406         
1407         return redraw;
1408 }
1409
1410 void node_border_select(SpaceNode *snode)
1411 {
1412         bNode *node;
1413         rcti rect;
1414         rctf rectf;
1415         short val, mval[2];
1416         
1417         if ( (val = get_border(&rect, 3)) ) {
1418                 
1419                 mval[0]= rect.xmin;
1420                 mval[1]= rect.ymin;
1421                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1422                 mval[0]= rect.xmax;
1423                 mval[1]= rect.ymax;
1424                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1425                 
1426                 for(node= snode->edittree->nodes.first; node; node= node->next) {
1427                         if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
1428                                 if(val==LEFTMOUSE)
1429                                         node->flag |= SELECT;
1430                                 else
1431                                         node->flag &= ~SELECT;
1432                         }
1433                 }
1434                 allqueue(REDRAWNODE, 1);
1435                 BIF_undo_push("Border select nodes");
1436         }               
1437 }
1438
1439 /* ****************** Add *********************** */
1440
1441 void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag)
1442 {
1443         bNodeSocket *sock, *sockfrom[8];
1444         bNode *node, *nodefrom[8];
1445         int totsock= 0, socktype=0;
1446
1447         if(node_to==NULL || node_to->inputs.first==NULL)
1448                 return;
1449         
1450         /* no inputs for node allowed (code it) */
1451
1452         /* connect first 1 socket type now */
1453         for(sock= node_to->inputs.first; sock; sock= sock->next)
1454                 if(socktype<sock->type)
1455                         socktype= sock->type;
1456
1457         
1458         /* find potential sockets, max 8 should work */
1459         for(node= snode->edittree->nodes.first; node; node= node->next) {
1460                 if((node->flag & flag) && node!=node_to) {
1461                         for(sock= node->outputs.first; sock; sock= sock->next) {
1462                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1463                                         sockfrom[totsock]= sock;
1464                                         nodefrom[totsock]= node;
1465                                         totsock++;
1466                                         if(totsock>7)
1467                                                 break;
1468                                 }
1469                         }
1470                 }
1471                 if(totsock>7)
1472                         break;
1473         }
1474
1475         /* now just get matching socket types and create links */
1476         for(sock= node_to->inputs.first; sock; sock= sock->next) {
1477                 int a;
1478                 
1479                 for(a=0; a<totsock; a++) {
1480                         if(sockfrom[a]) {
1481                                 if(sock->type==sockfrom[a]->type && sock->type==socktype) {
1482                                         nodeAddLink(snode->edittree, nodefrom[a], sockfrom[a], node_to, sock);
1483                                         sockfrom[a]= NULL;
1484                                         break;
1485                                 }
1486                         }
1487                 }
1488         }
1489         
1490         ntreeSolveOrder(snode->edittree);
1491 }
1492
1493 /* can be called from menus too, but they should do own undopush and redraws */
1494 bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
1495 {
1496         bNode *node= NULL, *gnode;
1497         
1498         node_deselectall(snode, 0);
1499         
1500         if(type>=NODE_GROUP_MENU) {
1501                 if(snode->edittree!=snode->nodetree) {
1502                         error("Can not add a Group in a Group");
1503                         return NULL;
1504                 }
1505                 else {
1506                         bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1507                         if(ngroup)
1508                                 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
1509                 }
1510         }
1511         else
1512                 node= nodeAddNodeType(snode->edittree, type, NULL);
1513         
1514         /* generics */
1515         if(node) {
1516                 node->locx= locx;
1517                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
1518                 node->flag |= SELECT;
1519                 
1520                 gnode= snode_get_editgroup(snode);
1521                 if(gnode) {
1522                         node->locx -= gnode->locx;
1523                         node->locy -= gnode->locy;
1524                 }
1525
1526                 snode_verify_groups(snode);
1527                 node_set_active(snode, node);
1528                 
1529                 if(node->id)
1530                         id_us_plus(node->id);
1531                 
1532                 if(snode->nodetree->type==NTREE_COMPOSIT)
1533                         ntreeCompositForceHidden(snode->edittree);
1534                 
1535                 NodeTagChanged(snode->edittree, node);
1536         }
1537         return node;
1538 }
1539
1540 void node_adduplicate(SpaceNode *snode)
1541 {
1542         
1543         ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
1544         
1545         ntreeSolveOrder(snode->edittree);
1546         snode_verify_groups(snode);
1547         snode_handle_recalc(snode);
1548
1549         transform_nodes(snode->edittree, 'g', "Duplicate");
1550 }
1551
1552 #if 0
1553 static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
1554 {
1555         bNode *newnode= NULL;
1556         
1557         if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
1558                 if(snode->edittree->type==NTREE_SHADER)
1559                         newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
1560                 else if(snode->edittree->type==NTREE_COMPOSIT)
1561                         newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
1562                 else
1563                         newnode= NULL;
1564         }
1565         else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
1566                 if(snode->edittree->type==NTREE_SHADER)
1567                         newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
1568                 else if(snode->edittree->type==NTREE_COMPOSIT)
1569                         newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
1570                 else
1571                         newnode= NULL;
1572         }
1573         
1574         if(newnode) {
1575                 /* dangerous assumption to use first in/out socks, but thats fine for now */
1576                 newnode->flag |= NODE_HIDDEN;
1577                 newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
1578                 newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
1579                 
1580                 nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
1581                 link->tonode= newnode;
1582                 link->tosock= newnode->inputs.first;
1583         }
1584 }
1585
1586 #endif
1587
1588 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
1589 {
1590         bNodeLink *tlink;
1591         bNodeSocket *sock;
1592         
1593         if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1594                 
1595                 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1596                         if(link!=tlink && tlink->tosock==link->tosock)
1597                                 break;
1598                 }
1599                 if(tlink) {
1600                         /* is there a free input socket with same type? */
1601                         for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) {
1602                                 if(sock->type==tlink->fromsock->type)
1603                                         if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
1604                                                 break;
1605                         }
1606                         if(sock)
1607                                 tlink->tosock= sock;
1608                         else {
1609                                 nodeRemLink(snode->edittree, tlink);
1610                         }
1611                 }
1612         }
1613 }
1614
1615 /* loop that adds a nodelink, called by function below  */
1616 /* in_out = starting socket */
1617 static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
1618 {
1619         bNode *tnode;
1620         bNodeSocket *tsock= NULL;
1621         bNodeLink *link= NULL;
1622         short mval[2], mvalo[2], firsttime=1;   /* firsttime reconnects a link broken by caller */
1623         
1624         /* we make a temporal link */
1625         if(in_out==SOCK_OUT)
1626                 link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
1627         else
1628                 link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
1629         
1630         getmouseco_areawin(mvalo);
1631         while (get_mbut() & L_MOUSE) {
1632                 
1633                 getmouseco_areawin(mval);
1634                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1635                         firsttime= 0;
1636                         
1637                         mvalo[0]= mval[0];
1638                         mvalo[1]= mval[1];
1639                         
1640                         if(in_out==SOCK_OUT) {
1641                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1642                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1643                                                 if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
1644                                                         link->tonode= tnode;
1645                                                         link->tosock= tsock;
1646                                                         ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1647                                                 }
1648                                         }
1649                                 }
1650                                 else {
1651                                         link->tonode= NULL;
1652                                         link->tosock= NULL;
1653                                 }
1654                         }
1655                         else {
1656                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1657                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1658                                                 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1659                                                         if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1660                                                                 link->fromnode= tnode;
1661                                                                 link->fromsock= tsock;
1662                                                                 ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1663                                                         }
1664                                                 }
1665                                         }
1666                                 }
1667                                 else {
1668                                         link->fromnode= NULL;
1669                                         link->fromsock= NULL;
1670                                 }
1671                         }
1672                         /* hilight target sockets only */
1673                         node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1674                         
1675                         force_draw(0);
1676                 }
1677                 else BIF_wait_for_statechange();                
1678         }
1679         
1680         /* remove link? */
1681         if(link->tonode==NULL || link->fromnode==NULL) {
1682                 nodeRemLink(snode->edittree, link);
1683         }
1684         else {
1685                 /* send changed events for original tonode and new */
1686                 if(link->tonode) 
1687                         NodeTagChanged(snode->edittree, link->tonode);
1688                 
1689                 /* we might need to remove a link */
1690                 if(in_out==SOCK_OUT) node_remove_extra_links(snode, tsock, link);
1691         }
1692         
1693         ntreeSolveOrder(snode->edittree);
1694         snode_verify_groups(snode);
1695         snode_handle_recalc(snode);
1696         
1697         allqueue(REDRAWNODE, 0);
1698         BIF_undo_push("Add link");
1699
1700         return 1;
1701 }
1702
1703 /* return 1 when socket clicked */
1704 static int node_add_link(SpaceNode *snode)
1705 {
1706         bNode *node;
1707         bNodeLink *link;
1708         bNodeSocket *sock;
1709         
1710         /* output indicated? */
1711         if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
1712                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1713                         return node_add_link_drag(snode, node, sock, SOCK_OUT);
1714                 else {
1715                         /* find if we break a link */
1716                         for(link= snode->edittree->links.first; link; link= link->next) {
1717                                 if(link->fromsock==sock)
1718                                         break;
1719                         }
1720                         if(link) {
1721                                 node= link->tonode;
1722                                 sock= link->tosock;
1723                                 nodeRemLink(snode->edittree, link);
1724                                 return node_add_link_drag(snode, node, sock, SOCK_IN);
1725                         }
1726                 }
1727         }
1728         /* or an input? */
1729         else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
1730                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1731                         return node_add_link_drag(snode, node, sock, SOCK_IN);
1732                 else {
1733                         /* find if we break a link */
1734                         for(link= snode->edittree->links.first; link; link= link->next) {
1735                                 if(link->tosock==sock)
1736                                         break;
1737                         }
1738                         if(link) {
1739                                 /* send changed event to original tonode */
1740                                 if(link->tonode) 
1741                                         NodeTagChanged(snode->edittree, link->tonode);
1742                                 
1743                                 node= link->fromnode;
1744                                 sock= link->fromsock;
1745                                 nodeRemLink(snode->edittree, link);
1746                                 return node_add_link_drag(snode, node, sock, SOCK_OUT);
1747                         }
1748                 }
1749         }
1750         
1751         return 0;
1752 }
1753
1754 void node_delete(SpaceNode *snode)
1755 {
1756         bNode *node, *next;
1757         bNodeSocket *sock;
1758         
1759         for(node= snode->edittree->nodes.first; node; node= next) {
1760                 next= node->next;
1761                 if(node->flag & SELECT) {
1762                         /* set selin and selout NULL if the sockets belong to a node to be deleted */
1763                         for(sock= node->inputs.first; sock; sock= sock->next)
1764                                 if(snode->edittree->selin == sock) snode->edittree->selin= NULL;
1765
1766                         for(sock= node->outputs.first; sock; sock= sock->next)
1767                                 if(snode->edittree->selout == sock) snode->edittree->selout= NULL;
1768
1769                         /* check id user here, nodeFreeNode is called for free dbase too */
1770                         if(node->id)
1771                                 node->id->us--;
1772                         nodeFreeNode(snode->edittree, node);
1773                 }
1774         }
1775         
1776         snode_verify_groups(snode);
1777         snode_handle_recalc(snode);
1778         BIF_undo_push("Delete nodes");
1779         allqueue(REDRAWNODE, 1);
1780 }
1781
1782 void node_hide(SpaceNode *snode)
1783 {
1784         bNode *node;
1785         int nothidden=0, ishidden=0;
1786         
1787         for(node= snode->edittree->nodes.first; node; node= node->next) {
1788                 if(node->flag & SELECT) {
1789                         if(node->flag & NODE_HIDDEN)
1790                                 ishidden++;
1791                         else
1792                                 nothidden++;
1793                 }
1794         }
1795         for(node= snode->edittree->nodes.first; node; node= node->next) {
1796                 if(node->flag & SELECT) {
1797                         if( (ishidden && nothidden) || ishidden==0)
1798                                 node->flag |= NODE_HIDDEN;
1799                         else 
1800                                 node->flag &= ~NODE_HIDDEN;
1801                 }
1802         }
1803         BIF_undo_push("Hide nodes");
1804         allqueue(REDRAWNODE, 1);
1805 }
1806
1807 void node_insert_key(SpaceNode *snode)
1808 {
1809         bNode *node= editnode_get_active(snode->edittree);
1810
1811         if(node->type==CMP_NODE_TIME) {
1812                 if(node->custom1<node->custom2) {
1813
1814                         CurveMapping *cumap= node->storage;
1815                         float fval, curval;
1816                 
1817                         curval= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
1818                         fval= curvemapping_evaluateF(cumap, 0, curval);
1819                         
1820                         if(fbutton(&fval, 0.0f, 1.0f, 10, 10, "Insert Value")) {
1821                                 curvemap_insert(cumap->cm, curval, fval);
1822
1823                                 BIF_undo_push("Insert key in Time node");
1824                                 allqueue(REDRAWNODE, 1);
1825                         }
1826                 }
1827         }
1828 }
1829
1830 void node_select_linked(SpaceNode *snode, int out)
1831 {
1832         bNodeLink *link;
1833         bNode *node;
1834         
1835         /* NODE_TEST is the free flag */
1836         for(node= snode->edittree->nodes.first; node; node= node->next)
1837                 node->flag &= ~NODE_TEST;
1838
1839         for(link= snode->edittree->links.first; link; link= link->next) {
1840                 if(out) {
1841                         if(link->fromnode->flag & NODE_SELECT)
1842                                 link->tonode->flag |= NODE_TEST;
1843                 }
1844                 else {
1845                         if(link->tonode->flag & NODE_SELECT)
1846                                 link->fromnode->flag |= NODE_TEST;
1847                 }
1848         }
1849         
1850         for(node= snode->edittree->nodes.first; node; node= node->next)
1851                 if(node->flag & NODE_TEST)
1852                         node->flag |= NODE_SELECT;
1853         
1854         BIF_undo_push("Select Linked nodes");
1855         allqueue(REDRAWNODE, 1);
1856 }
1857
1858 void node_toggle_link(SpaceNode *snode)
1859 {
1860         bNode *fromnode, *tonode;
1861         bNodeLink *remlink, *link;
1862         bNodeSocket *outsock= snode->edittree->selout;
1863         bNodeSocket *insock= snode->edittree->selin;
1864
1865         if(!insock || !outsock) return;
1866
1867         remlink= nodeFindLink(snode->edittree, outsock, insock);
1868         
1869         if(remlink) nodeRemLink(snode->edittree, remlink);
1870         else {
1871                 if(nodeFindNode(snode->edittree, outsock, &fromnode, NULL) &&
1872                    nodeFindNode(snode->edittree, insock, &tonode, NULL)) {
1873                         link= nodeAddLink(snode->edittree, fromnode, outsock, tonode, insock);
1874                         NodeTagChanged(snode->edittree, tonode);
1875                         node_remove_extra_links(snode, insock, link);
1876                 }
1877                 else return;
1878         }
1879
1880         ntreeSolveOrder(snode->edittree);
1881         snode_verify_groups(snode);
1882         snode_handle_recalc(snode);
1883
1884         allqueue(REDRAWNODE, 0);
1885         BIF_undo_push("Toggle Link");
1886 }
1887
1888 static void node_border_link_delete(SpaceNode *snode)
1889 {
1890         rcti rect;
1891         short val, mval[2], mvalo[2];
1892
1893         /* to make this work more friendly, we first wait for a mouse move */
1894         getmouseco_areawin(mvalo);
1895         while (get_mbut() & L_MOUSE) {
1896                 getmouseco_areawin(mval);
1897                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
1898                         break;
1899                 else BIF_wait_for_statechange();
1900         }
1901         if((get_mbut() & L_MOUSE)==0)
1902                 return;
1903         
1904         /* now change cursor and draw border */
1905         setcursor_space(SPACE_NODE, CURSOR_VPAINT);
1906         
1907         if ( (val = get_border(&rect, 2)) ) {
1908                 if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
1909                         //#define NODE_MAXPICKBUF       256
1910                         bNodeLink *link, *next;
1911                         GLuint buffer[256];
1912                         rctf rectf;
1913                         int code=0, hits;
1914                         
1915                         mval[0]= rect.xmin;
1916                         mval[1]= rect.ymin;
1917                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
1918                         mval[0]= rect.xmax;
1919                         mval[1]= rect.ymax;
1920                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
1921                         
1922                         myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
1923                         
1924                         glSelectBuffer(256, buffer); 
1925                         glRenderMode(GL_SELECT);
1926                         glInitNames();
1927                         glPushName(-1);
1928                         
1929                         /* draw links */
1930                         for(link= snode->edittree->links.first; link; link= link->next) {
1931                                 glLoadName(code++);
1932                                 node_draw_link(snode, link);
1933                         }
1934                         
1935                         hits= glRenderMode(GL_RENDER);
1936                         glPopName();
1937                         if(hits>0) {
1938                                 int a;
1939                                 for(a=0; a<hits; a++) {
1940                                         bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
1941                                         if(link)
1942                                                 link->fromnode= NULL;   /* first tag for delete, otherwise indices are wrong */
1943                                 }
1944                                 for(link= snode->edittree->links.first; link; link= next) {
1945                                         next= link->next;
1946                                         if(link->fromnode==NULL) {
1947                                                 NodeTagChanged(snode->edittree, link->tonode);
1948                                                 nodeRemLink(snode->edittree, link);
1949                                         }
1950                                 }
1951                                 ntreeSolveOrder(snode->edittree);
1952                                 snode_verify_groups(snode);
1953                                 snode_handle_recalc(snode);
1954                         }
1955                         allqueue(REDRAWNODE, 0);
1956                         BIF_undo_push("Erase links");
1957                 }
1958         }
1959         
1960         setcursor_space(SPACE_NODE, CURSOR_STD);
1961 }
1962
1963 /* goes over all scenes, reads render layerss */
1964 void node_read_renderlayers(SpaceNode *snode)
1965 {
1966         Scene *scene;
1967         bNode *node;
1968
1969         /* first tag scenes unread */
1970         for(scene= G.main->scene.first; scene; scene= scene->id.next) 
1971                 scene->id.flag |= LIB_DOIT;
1972
1973         for(node= snode->edittree->nodes.first; node; node= node->next) {
1974                 if(node->type==CMP_NODE_R_LAYERS) {
1975                         ID *id= node->id;
1976                         if(id==NULL) id= (ID *)G.scene;
1977                         if(id->flag & LIB_DOIT) {
1978                                 RE_ReadRenderResult(G.scene, (Scene *)id);
1979                                 ntreeCompositTagRender((Scene *)id);
1980                                 id->flag &= ~LIB_DOIT;
1981                         }
1982                 }
1983         }
1984         
1985         snode_handle_recalc(snode);
1986 }
1987
1988 /* called from header_info, when deleting a scene
1989  * goes over all scenes other than the input, checks if they have
1990  * render layer nodes referencing the to-be-deleted scene, and
1991  * resets them to NULL. */
1992 void clear_scene_in_nodes(Scene *sce)
1993 {
1994         Scene *sce1;
1995         bNode *node;
1996
1997         sce1= G.main->scene.first;
1998         while(sce1) {
1999                 if(sce1!=sce) {
2000                         if (sce1->nodetree) {
2001                                 for(node= sce1->nodetree->nodes.first; node; node= node->next) {
2002                                         if(node->type==CMP_NODE_R_LAYERS) {
2003                                                 Scene *nodesce= (Scene *)node->id;
2004                                                 
2005                                                 if (nodesce==sce) node->id = NULL;
2006                                         }
2007                                 }
2008                         }
2009                 }
2010                 sce1= sce1->id.next;
2011         }
2012 }
2013
2014
2015 /* gets active viewer user */
2016 struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
2017 {
2018         bNode *node;
2019         
2020         if(ntree)
2021                 for(node= ntree->nodes.first; node; node= node->next)
2022                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
2023                                 if(node->flag & NODE_DO_OUTPUT)
2024                                         return node->storage;
2025         return NULL;
2026 }
2027
2028 void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser)
2029 {
2030         bNode *node;
2031         
2032         if(ntree==NULL)
2033                 return;
2034         
2035         /* search for renderresults */
2036         if(image->type==IMA_TYPE_R_RESULT) {
2037                 for(node= ntree->nodes.first; node; node= node->next) {
2038                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
2039                                 /* imageuser comes from ImageWin, so indexes are offset 1 */
2040                                 if(node->custom1==iuser->layer-1)
2041                                         NodeTagChanged(ntree, node);
2042                         }
2043                 }
2044         }
2045         else {
2046                 for(node= ntree->nodes.first; node; node= node->next) {
2047                         if(node->id== &image->id)
2048                                 NodeTagChanged(ntree, node);
2049                 }
2050         }
2051 }
2052
2053 /* ********************** */
2054
2055 void node_make_group(SpaceNode *snode)
2056 {
2057         bNode *gnode;
2058         
2059         if(snode->edittree!=snode->nodetree) {
2060                 error("Can not add a new Group in a Group");
2061                 return;
2062         }
2063         
2064         /* for time being... is too complex to handle */
2065         if(snode->treetype==NTREE_COMPOSIT) {
2066                 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
2067                         if(gnode->flag & SELECT)
2068                                 if(gnode->type==CMP_NODE_R_LAYERS)
2069                                         break;
2070                 }
2071                 if(gnode) {
2072                         error("Can not add RenderLayer in a Group");
2073                         return;
2074                 }
2075         }
2076         
2077         gnode= nodeMakeGroupFromSelected(snode->nodetree);
2078         if(gnode==NULL) {
2079                 error("Can not make Group");
2080         }
2081         else {
2082                 nodeSetActive(snode->nodetree, gnode);
2083                 ntreeSolveOrder(snode->nodetree);
2084                 allqueue(REDRAWNODE, 0);
2085                 BIF_undo_push("Make Node Group");
2086         }
2087 }
2088
2089 /* ******************** main event loop ****************** */
2090
2091 /* special version to prevent overlapping buttons, has a bit of hack... */
2092 /* yes, check for example composit_node_event(), file window use... */
2093 static int node_uiDoBlocks(ScrArea *sa, short event)
2094 {
2095         SpaceNode *snode= sa->spacedata.first;
2096         ListBase *lb= &sa->uiblocks;
2097         ListBase listb= *lb;
2098         bNode *node;
2099         rctf rect;
2100         void *prev, *next;
2101         int retval= UI_NOTHING;
2102         short mval[2];
2103         
2104         getmouseco_areawin(mval);
2105         areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
2106
2107         /* this happens after filesel usage... */
2108         if(lb->first==NULL) {
2109                 return UI_NOTHING;
2110         }
2111         
2112         rect.xmin -= 2.0f;
2113         rect.ymin -= 2.0f;
2114         rect.xmax = rect.xmin + 4.0f;
2115         rect.ymax = rect.ymin + 4.0f;
2116         
2117         for(node= snode->edittree->nodes.first; node; node= node->next) {
2118                 uiBlock *block;
2119                 char str[32];
2120                 
2121                 /* retreive unique block name, see also drawnode.c */
2122                 sprintf(str, "node buttons %p", node);
2123                 block= uiGetBlock(str, sa);
2124                 
2125                 if(block) {
2126                         if(node == visible_node(snode, &rect)) {
2127
2128                                 /* when there's menus, the prev pointer becomes zero! */
2129                                 prev= ((struct Link *)block)->prev;
2130                                 next= ((struct Link *)block)->next;
2131                                 ((struct Link *)block)->prev= NULL;
2132                                 ((struct Link *)block)->next= NULL;
2133                                 
2134                                 lb->first= lb->last= block;
2135                                 retval= uiDoBlocks(lb, event, 1);
2136                                 
2137                                 ((struct Link *)block)->prev= prev;
2138                                 ((struct Link *)block)->next= next;
2139
2140                                 break;
2141                         }
2142                 }
2143         }
2144         
2145         *lb= listb;
2146         
2147         return retval;
2148 }
2149
2150 void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
2151 {
2152         SpaceNode *snode= spacedata;
2153         bNode *actnode;
2154         bNodeSocket *actsock;
2155         unsigned short event= evt->event;
2156         short val= evt->val, doredraw=0, fromlib= 0;
2157         
2158         if(sa->win==0) return;
2159         if(snode->nodetree==NULL) return;
2160         
2161         if(val) {
2162
2163                 if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;  
2164
2165                 fromlib= (snode->id && snode->id->lib);
2166                 
2167                 switch(event) {
2168                 case LEFTMOUSE:
2169                         if(fromlib) {
2170                                 if(node_mouse_groupheader(snode)==0)
2171                                         node_mouse_select(snode, event);
2172                         }
2173                         else {
2174                                 if(node_add_link(snode)==0)
2175                                         if(node_mouse_groupheader(snode)==0)
2176                                                 if(node_mouse_select(snode, event)==0)
2177                                                         node_border_link_delete(snode);
2178                         }
2179                         break;
2180                         
2181                 case RIGHTMOUSE: 
2182                         if(find_indicated_socket(snode, &actnode, &actsock, SOCK_IN)) {
2183                                 if(actsock->flag & SOCK_SEL) {
2184                                         snode->edittree->selin= NULL;
2185                                         actsock->flag&= ~SOCK_SEL;
2186                                 }
2187                                 else {
2188                                         snode->edittree->selin= actsock;
2189                                         reset_sel_socket(snode, SOCK_IN);
2190                                         actsock->flag|= SOCK_SEL;
2191                                 }
2192                         }
2193                         else if(find_indicated_socket(snode, &actnode, &actsock, SOCK_OUT)) {
2194                                 if(actsock->flag & SOCK_SEL) {
2195                                         snode->edittree->selout= NULL;
2196                                         actsock->flag&= ~SOCK_SEL;
2197                                 }
2198                                 else {
2199                                         snode->edittree->selout= actsock;
2200                                         reset_sel_socket(snode, SOCK_OUT);
2201                                         actsock->flag|= SOCK_SEL;
2202                                 }
2203                         }
2204                         else if(!node_mouse_select(snode, event)) 
2205                                 toolbox_n();
2206
2207                         break;
2208                 case MIDDLEMOUSE:
2209                         if (G.qual==LR_SHIFTKEY) {
2210                                 snode_bg_viewmove(snode);
2211                         } else {
2212                                 view2dmove(event);
2213                         }
2214                 case WHEELUPMOUSE:
2215                 case WHEELDOWNMOUSE:
2216                         view2dmove(event);      /* in drawipo.c */
2217                         break;
2218                         
2219                 case MOUSEY:
2220                         doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
2221                         break;
2222                 
2223                 case UI_BUT_EVENT:
2224                         /* future: handlerize this! */
2225                         if(snode->treetype==NTREE_SHADER)
2226                                 shader_node_event(snode, val);
2227                         else if(snode->treetype==NTREE_COMPOSIT)
2228                                 composit_node_event(snode, val);
2229                         break;
2230                         
2231                 case RENDERPREVIEW:
2232                         if(snode->treetype==NTREE_SHADER)
2233                                 shader_node_previewrender(sa, snode);
2234                         break;
2235                         
2236                 case PADPLUSKEY:
2237                         snode_zoom_in(sa);
2238                         doredraw= 1;
2239                         break;
2240                 case PADMINUS:
2241                         snode_zoom_out(sa);
2242                         doredraw= 1;
2243                         break;
2244                 case HOMEKEY:
2245                         snode_home(sa, snode);
2246                         doredraw= 1;
2247                         break;
2248                 case TABKEY:
2249                         if(fromlib) fromlib= -1;
2250                         else snode_make_group_editable(snode, NULL);
2251                         break;
2252                         
2253                 case AKEY:
2254                         if(G.qual==LR_SHIFTKEY) {
2255                                 if(fromlib) fromlib= -1;
2256                                 else toolbox_n_add();
2257                         }
2258                         else if(G.qual==0) {
2259                                 node_deselectall(snode, 1);
2260                                 BIF_undo_push("Deselect all nodes");
2261                         }
2262                         break;
2263                 case BKEY:
2264                         if(G.qual==0)
2265                                 node_border_select(snode);
2266                         break;
2267                 case CKEY:      /* sort again, showing cyclics */
2268                         ntreeSolveOrder(snode->edittree);
2269                         doredraw= 1;
2270                         break;
2271                 case DKEY:
2272                         if(G.qual==LR_SHIFTKEY) {
2273                                 if(fromlib) fromlib= -1;
2274                                 else node_adduplicate(snode);
2275                         }
2276                         break;
2277                 case EKEY:
2278                         snode_handle_recalc(snode);
2279                         break;
2280                 case FKEY:
2281                         node_toggle_link(snode);
2282                         break;
2283                 case GKEY:
2284                         if(fromlib) fromlib= -1;
2285                         else {
2286                                 if(G.qual==LR_CTRLKEY) {
2287                                         if(okee("Make Group"))
2288                                                 node_make_group(snode);
2289                                 }
2290                                 else if(G.qual==LR_ALTKEY) {
2291                                         if(okee("Ungroup"))
2292                                                 node_ungroup(snode);
2293                                 }
2294                                 else if(G.qual==LR_SHIFTKEY) {
2295                                         node_addgroup(snode);
2296                                 }
2297                                 else
2298                                         transform_nodes(snode->edittree, 'g', "Move Node");
2299                         }
2300                         break;
2301                 case HKEY:
2302                         node_hide(snode);
2303                         break;
2304                 case IKEY:
2305                         node_insert_key(snode);
2306                         break;
2307                 case LKEY:
2308                         node_select_linked(snode, G.qual==LR_SHIFTKEY);
2309                         break;
2310                 case RKEY:
2311                         if(okee("Read saved Render Layers"))
2312                                 node_read_renderlayers(snode);
2313                         break;
2314                 case DELKEY:
2315                 case XKEY:
2316                         if(fromlib) fromlib= -1;
2317                         else node_delete(snode);
2318                         break;
2319                 }
2320         }
2321
2322         if(fromlib==-1)
2323                 error_libdata();
2324         if(doredraw)
2325                 scrarea_queue_winredraw(sa);
2326         if(doredraw==2)
2327                 scrarea_queue_headredraw(sa);
2328 }
2329
2330