a14b0ccc389e928550c74cc86c186f662b49ed8d
[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 /* checks mouse position, and returns found node/socket */
834 /* type is SOCK_IN and/or SOCK_OUT */
835 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
836 {
837         bNode *node;
838         bNodeSocket *sock;
839         rctf rect;
840         short mval[2];
841         
842         getmouseco_areawin(mval);
843         
844         /* check if we click in a socket */
845         for(node= snode->edittree->nodes.first; node; node= node->next) {
846         
847                 areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
848                 
849                 rect.xmin -= NODE_SOCKSIZE+3;
850                 rect.ymin -= NODE_SOCKSIZE+3;
851                 rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
852                 rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
853                 
854                 if (!(node->flag & NODE_HIDDEN)) {
855                         /* extra padding inside and out - allow dragging on the text areas too */
856                         if (in_out == SOCK_IN) {
857                                 rect.xmax += NODE_SOCKSIZE;
858                                 rect.xmin -= NODE_SOCKSIZE*4;
859                         } else if (in_out == SOCK_OUT) {
860                                 rect.xmax += NODE_SOCKSIZE*4;
861                                 rect.xmin -= NODE_SOCKSIZE;
862                         }
863                 }
864                         
865                 if(in_out & SOCK_IN) {
866                         for(sock= node->inputs.first; sock; sock= sock->next) {
867                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
868                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
869                                                 if(node == visible_node(snode, &rect)) {
870                                                         *nodep= node;
871                                                         *sockp= sock;
872                                                         return 1;
873                                                 }
874                                         }
875                                 }
876                         }
877                 }
878                 if(in_out & SOCK_OUT) {
879                         for(sock= node->outputs.first; sock; sock= sock->next) {
880                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
881                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
882                                                 if(node == visible_node(snode, &rect)) {
883                                                         *nodep= node;
884                                                         *sockp= sock;
885                                                         return 1;
886                                                 }
887                                         }
888                                 }
889                         }
890                 }
891         }
892         return 0;
893 }
894
895 /* ********************* transform ****************** */
896
897 /* releases on event, only intern (for extern see below) */
898 /* we need argument ntree to allow operations on edittree or nodetree */
899 static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
900 {
901         bNode *node;
902         float mxstart, mystart, mx, my, *oldlocs, *ol;
903         int cont=1, tot=0, cancel=0, firsttime=1;
904         short mval[2], mvalo[2];
905         
906         /* count total */
907         for(node= ntree->nodes.first; node; node= node->next)
908                 if(node->flag & SELECT) tot++;
909         
910         if(tot==0) return;
911         
912         /* store oldlocs */
913         ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
914         for(node= ntree->nodes.first; node; node= node->next) {
915                 if(node->flag & SELECT) {
916                         ol[0]= node->locx; ol[1]= node->locy;
917                         ol+= 2;
918                 }
919         }
920         
921         getmouseco_areawin(mvalo);
922         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
923         
924         while(cont) {
925                 
926                 getmouseco_areawin(mval);
927                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
928
929                         firsttime= 0;
930                         
931                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
932                         mvalo[0]= mval[0];
933                         mvalo[1]= mval[1];
934                         
935                         for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
936                                 if(node->flag & SELECT) {
937                                         node->locx= ol[0] + mx-mxstart;
938                                         node->locy= ol[1] + my-mystart;
939                                         ol+= 2;
940                                 }
941                         }
942                         
943                         force_draw(0);
944                 }
945                 else
946                         PIL_sleep_ms(10);
947                 
948                 while (qtest()) {
949                         short val;
950                         unsigned short event= extern_qread(&val);
951                         
952                         switch (event) {
953                                 case LEFTMOUSE:
954                                 case SPACEKEY:
955                                 case RETKEY:
956                                         cont=0;
957                                         break;
958                                 case ESCKEY:
959                                 case RIGHTMOUSE:
960                                         if(val) {
961                                                 cancel=1;
962                                                 cont=0;
963                                         }
964                                         break;
965                                 default:
966                                         if(val) arrows_move_cursor(event);
967                                         break;
968                         }
969                 }
970                 
971         }
972         
973         if(cancel) {
974                 for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
975                         if(node->flag & SELECT) {
976                                 node->locx= ol[0];
977                                 node->locy= ol[1];
978                                 ol+= 2;
979                         }
980                 }
981                 
982         }
983         else
984                 BIF_undo_push(undostr);
985         
986         allqueue(REDRAWNODE, 1);
987         MEM_freeN(oldlocs);
988 }
989
990 /* external call, also for callback */
991 void node_transform_ext(int mode, int unused)
992 {
993         SpaceNode *snode= curarea->spacedata.first;
994         
995         transform_nodes(snode->edittree, 'g', "Move Node");
996 }
997
998
999 /* releases on event, only 1 node */
1000 static void scale_node(SpaceNode *snode, bNode *node)
1001 {
1002         float mxstart, mystart, mx, my, oldwidth;
1003         int cont=1, cancel=0;
1004         short mval[2], mvalo[2];
1005         
1006         /* store old */
1007         if(node->flag & NODE_HIDDEN)
1008                 oldwidth= node->miniwidth;
1009         else
1010                 oldwidth= node->width;
1011                 
1012         getmouseco_areawin(mvalo);
1013         areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
1014         
1015         while(cont) {
1016                 
1017                 getmouseco_areawin(mval);
1018                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
1019                         
1020                         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1021                         mvalo[0]= mval[0];
1022                         mvalo[1]= mval[1];
1023                         
1024                         if(node->flag & NODE_HIDDEN) {
1025                                 node->miniwidth= oldwidth + mx-mxstart;
1026                                 CLAMP(node->miniwidth, 0.0f, 100.0f);
1027                         }
1028                         else {
1029                                 node->width= oldwidth + mx-mxstart;
1030                                 CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
1031                         }
1032                         
1033                         force_draw(0);
1034                 }
1035                 else
1036                         PIL_sleep_ms(10);
1037                 
1038                 while (qtest()) {
1039                         short val;
1040                         unsigned short event= extern_qread(&val);
1041                         
1042                         switch (event) {
1043                                 case LEFTMOUSE:
1044                                 case SPACEKEY:
1045                                 case RETKEY:
1046                                         cont=0;
1047                                         break;
1048                                 case ESCKEY:
1049                                 case RIGHTMOUSE:
1050                                         if(val) {
1051                                                 cancel=1;
1052                                                 cont=0;
1053                                         }
1054                                         break;
1055                         }
1056                 }
1057                 
1058         }
1059         
1060         if(cancel) {
1061                 node->width= oldwidth;
1062         }
1063         else
1064                 BIF_undo_push("Scale Node");
1065         
1066         allqueue(REDRAWNODE, 1);
1067 }
1068
1069
1070
1071 /* ********************** select ******************** */
1072
1073 /* used in buttons to check context, also checks for edited groups */
1074 bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
1075 {
1076         bNode *node;
1077         
1078         /* check for edited group */
1079         for(node= ntree->nodes.first; node; node= node->next)
1080                 if(node->flag & NODE_GROUP_EDIT)
1081                         break;
1082         if(node)
1083                 return nodeGetActiveID((bNodeTree *)node->id, id_code);
1084         else
1085                 return nodeGetActiveID(ntree, id_code);
1086 }
1087
1088 /* used in buttons to check context, also checks for edited groups */
1089 Material *editnode_get_active_material(Material *ma)
1090 {
1091         if(ma && ma->use_nodes && ma->nodetree) {
1092                 bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
1093                 if(node)
1094                         return (Material *)node->id;
1095                 else
1096                         return NULL;
1097         }
1098         return ma;
1099 }
1100
1101 /* used in buttons to check context, also checks for edited groups */
1102 bNode *editnode_get_active(bNodeTree *ntree)
1103 {
1104         bNode *node;
1105         
1106         /* check for edited group */
1107         for(node= ntree->nodes.first; node; node= node->next)
1108                 if(node->flag & NODE_GROUP_EDIT)
1109                         break;
1110         if(node)
1111                 return nodeGetActive((bNodeTree *)node->id);
1112         else
1113                 return nodeGetActive(ntree);
1114 }
1115
1116
1117 /* no undo here! */
1118 void node_deselectall(SpaceNode *snode, int swap)
1119 {
1120         bNode *node;
1121         
1122         if(swap) {
1123                 for(node= snode->edittree->nodes.first; node; node= node->next)
1124                         if(node->flag & SELECT)
1125                                 break;
1126                 if(node==NULL) {
1127                         for(node= snode->edittree->nodes.first; node; node= node->next)
1128                                 node->flag |= SELECT;
1129                         allqueue(REDRAWNODE, 0);
1130                         return;
1131                 }
1132                 /* else pass on to deselect */
1133         }
1134         
1135         for(node= snode->edittree->nodes.first; node; node= node->next)
1136                 node->flag &= ~SELECT;
1137         
1138         allqueue(REDRAWNODE, 0);
1139 }
1140
1141 int node_has_hidden_sockets(bNode *node)
1142 {
1143         bNodeSocket *sock;
1144         
1145         for(sock= node->inputs.first; sock; sock= sock->next)
1146                 if(sock->flag & SOCK_HIDDEN)
1147                         return 1;
1148         for(sock= node->outputs.first; sock; sock= sock->next)
1149                 if(sock->flag & SOCK_HIDDEN)
1150                         return 1;
1151         return 0;
1152 }
1153
1154
1155 static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
1156 {
1157         bNodeSocket *sock;
1158         
1159         /* unhide all */
1160         if( node_has_hidden_sockets(node) ) {
1161                 for(sock= node->inputs.first; sock; sock= sock->next)
1162                         sock->flag &= ~SOCK_HIDDEN;
1163                 for(sock= node->outputs.first; sock; sock= sock->next)
1164                         sock->flag &= ~SOCK_HIDDEN;
1165         }
1166         else {
1167                 bNode *gnode= snode_get_editgroup(snode);
1168                 
1169                 /* hiding inside group should not break links in other group users */
1170                 if(gnode) {
1171                         nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
1172                         for(sock= node->inputs.first; sock; sock= sock->next)
1173                                 if(!(sock->flag & SOCK_IN_USE))
1174                                         if(sock->link==NULL)
1175                                                 sock->flag |= SOCK_HIDDEN;
1176                         for(sock= node->outputs.first; sock; sock= sock->next)
1177                                 if(!(sock->flag & SOCK_IN_USE))
1178                                         if(nodeCountSocketLinks(snode->edittree, sock)==0)
1179                                                 sock->flag |= SOCK_HIDDEN;
1180                 }
1181                 else {
1182                         /* hide unused sockets */
1183                         for(sock= node->inputs.first; sock; sock= sock->next) {
1184                                 if(sock->link==NULL)
1185                                         sock->flag |= SOCK_HIDDEN;
1186                         }
1187                         for(sock= node->outputs.first; sock; sock= sock->next) {
1188                                 if(nodeCountSocketLinks(snode->edittree, sock)==0)
1189                                         sock->flag |= SOCK_HIDDEN;
1190                         }
1191                 }
1192         }
1193
1194         allqueue(REDRAWNODE, 1);
1195         snode_verify_groups(snode);
1196         BIF_undo_push("Hide/Unhide sockets");
1197
1198 }
1199
1200 static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
1201 {
1202         rctf totr= node->totr;
1203         
1204         totr.ymin= totr.ymax-20.0f;
1205         
1206         totr.xmax= totr.xmin+15.0f;
1207         if(BLI_in_rctf(&totr, mx, my)) {
1208                 node->flag |= NODE_HIDDEN;
1209                 allqueue(REDRAWNODE, 0);
1210                 return 1;
1211         }       
1212         
1213         totr.xmax= node->totr.xmax;
1214         totr.xmin= totr.xmax-18.0f;
1215         if(node->typeinfo->flag & NODE_PREVIEW) {
1216                 if(BLI_in_rctf(&totr, mx, my)) {
1217                         node->flag ^= NODE_PREVIEW;
1218                         allqueue(REDRAWNODE, 0);
1219                         return 1;
1220                 }
1221                 totr.xmin-=18.0f;
1222         }
1223         if(node->type == NODE_GROUP) {
1224                 if(BLI_in_rctf(&totr, mx, my)) {
1225                         snode_make_group_editable(snode, node);
1226                         return 1;
1227                 }
1228                 totr.xmin-=18.0f;
1229         }
1230         if(node->typeinfo->flag & NODE_OPTIONS) {
1231                 if(BLI_in_rctf(&totr, mx, my)) {
1232                         node->flag ^= NODE_OPTIONS;
1233                         allqueue(REDRAWNODE, 0);
1234                         return 1;
1235                 }
1236                 totr.xmin-=18.0f;
1237         }
1238         /* hide unused sockets */
1239         if(BLI_in_rctf(&totr, mx, my)) {
1240                 node_hide_unhide_sockets(snode, node);
1241         }
1242         
1243         
1244         totr= node->totr;
1245         totr.xmin= totr.xmax-10.0f;
1246         totr.ymax= totr.ymin+10.0f;
1247         if(BLI_in_rctf(&totr, mx, my)) {
1248                 scale_node(snode, node);
1249                 return 1;
1250         }
1251         return 0;
1252 }
1253
1254 static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
1255 {
1256         rctf totr= node->totr;
1257         
1258         totr.xmax= totr.xmin+15.0f;
1259         if(BLI_in_rctf(&totr, mx, my)) {
1260                 node->flag &= ~NODE_HIDDEN;
1261                 allqueue(REDRAWNODE, 0);
1262                 return 1;
1263         }       
1264         
1265         totr.xmax= node->totr.xmax;
1266         totr.xmin= node->totr.xmax-15.0f;
1267         if(BLI_in_rctf(&totr, mx, my)) {
1268                 scale_node(snode, node);
1269                 return 1;
1270         }
1271         return 0;
1272 }
1273
1274
1275 /* return 0: nothing done */
1276 static int node_mouse_select(SpaceNode *snode, unsigned short event)
1277 {
1278         bNode *node;
1279         float mx, my;
1280         short mval[2];
1281         
1282         getmouseco_areawin(mval);
1283         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1284         
1285         for(next_node(snode->edittree); (node=next_node(NULL));) {
1286                 
1287                 /* first check for the headers or scaling widget */
1288                 if(node->flag & NODE_HIDDEN) {
1289                         if(do_header_hidden_node(snode, node, mx, my))
1290                                 return 1;
1291                 }
1292                 else {
1293                         if(do_header_node(snode, node, mx, my))
1294                                 return 1;
1295                 }
1296                 
1297                 /* node body */
1298                 if(BLI_in_rctf(&node->totr, mx, my))
1299                         break;
1300         }
1301         if(node) {
1302                 if((G.qual & LR_SHIFTKEY)==0)
1303                         node_deselectall(snode, 0);
1304                 
1305                 if(G.qual & LR_SHIFTKEY) {
1306                         if(node->flag & SELECT)
1307                                 node->flag &= ~SELECT;
1308                         else
1309                                 node->flag |= SELECT;
1310                 }
1311                 else 
1312                         node->flag |= SELECT;
1313                 
1314                 node_set_active(snode, node);
1315                 
1316                 /* not so nice (no event), but function below delays redraw otherwise */
1317                 force_draw(0);
1318                 
1319                 std_rmouse_transform(node_transform_ext);       /* does undo push for select */
1320                 
1321                 return 1;
1322         }
1323         return 0;
1324 }
1325
1326 /* return 0, nothing done */
1327 static int node_mouse_groupheader(SpaceNode *snode)
1328 {
1329         bNode *gnode;
1330         float mx, my;
1331         short mval[2];
1332         
1333         gnode= snode_get_editgroup(snode);
1334         if(gnode==NULL) return 0;
1335         
1336         getmouseco_areawin(mval);
1337         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1338         
1339         /* click in header or outside? */
1340         if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1341                 rctf rect= gnode->totr;
1342                 
1343                 rect.ymax += NODE_DY;
1344                 if(BLI_in_rctf(&rect, mx, my)==0)
1345                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1346                 else
1347                         transform_nodes(snode->nodetree, 'g', "Move group");
1348                 
1349                 return 1;
1350         }
1351         return 0;
1352 }
1353
1354 static int node_socket_hilights(SpaceNode *snode, int in_out)
1355 {
1356         bNode *node;
1357         bNodeSocket *sock, *tsock, *socksel= NULL;
1358         float mx, my;
1359         short mval[2], redraw= 0;
1360         
1361         if(snode->edittree==NULL) return 0;
1362         
1363         getmouseco_areawin(mval);
1364         areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1365         
1366         /* deselect socks */
1367         for(node= snode->edittree->nodes.first; node; node= node->next) {
1368                 for(sock= node->inputs.first; sock; sock= sock->next) {
1369                         if(sock->flag & SELECT) {
1370                                 sock->flag &= ~SELECT;
1371                                 redraw++;
1372                                 socksel= sock;
1373                         }
1374                 }
1375                 for(sock= node->outputs.first; sock; sock= sock->next) {
1376                         if(sock->flag & SELECT) {
1377                                 sock->flag &= ~SELECT;
1378                                 redraw++;
1379                                 socksel= sock;
1380                         }
1381                 }
1382         }
1383         
1384         if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1385                 tsock->flag |= SELECT;
1386                 if(redraw==1 && tsock==socksel) redraw= 0;
1387                 else redraw= 1;
1388         }
1389         
1390         return redraw;
1391 }
1392
1393 void node_border_select(SpaceNode *snode)
1394 {
1395         bNode *node;
1396         rcti rect;
1397         rctf rectf;
1398         short val, mval[2];
1399         
1400         if ( (val = get_border(&rect, 3)) ) {
1401                 
1402                 mval[0]= rect.xmin;
1403                 mval[1]= rect.ymin;
1404                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1405                 mval[0]= rect.xmax;
1406                 mval[1]= rect.ymax;
1407                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1408                 
1409                 for(node= snode->edittree->nodes.first; node; node= node->next) {
1410                         if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
1411                                 if(val==LEFTMOUSE)
1412                                         node->flag |= SELECT;
1413                                 else
1414                                         node->flag &= ~SELECT;
1415                         }
1416                 }
1417                 allqueue(REDRAWNODE, 1);
1418                 BIF_undo_push("Border select nodes");
1419         }               
1420 }
1421
1422 /* ****************** Add *********************** */
1423
1424 void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag)
1425 {
1426         bNodeSocket *sock, *sockfrom[8];
1427         bNode *node, *nodefrom[8];
1428         int totsock= 0, socktype=0;
1429
1430         if(node_to==NULL || node_to->inputs.first==NULL)
1431                 return;
1432         
1433         /* no inputs for node allowed (code it) */
1434
1435         /* connect first 1 socket type now */
1436         for(sock= node_to->inputs.first; sock; sock= sock->next)
1437                 if(socktype<sock->type)
1438                         socktype= sock->type;
1439
1440         
1441         /* find potential sockets, max 8 should work */
1442         for(node= snode->edittree->nodes.first; node; node= node->next) {
1443                 if((node->flag & flag) && node!=node_to) {
1444                         for(sock= node->outputs.first; sock; sock= sock->next) {
1445                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1446                                         sockfrom[totsock]= sock;
1447                                         nodefrom[totsock]= node;
1448                                         totsock++;
1449                                         if(totsock>7)
1450                                                 break;
1451                                 }
1452                         }
1453                 }
1454                 if(totsock>7)
1455                         break;
1456         }
1457
1458         /* now just get matching socket types and create links */
1459         for(sock= node_to->inputs.first; sock; sock= sock->next) {
1460                 int a;
1461                 
1462                 for(a=0; a<totsock; a++) {
1463                         if(sockfrom[a]) {
1464                                 if(sock->type==sockfrom[a]->type && sock->type==socktype) {
1465                                         nodeAddLink(snode->edittree, nodefrom[a], sockfrom[a], node_to, sock);
1466                                         sockfrom[a]= NULL;
1467                                         break;
1468                                 }
1469                         }
1470                 }
1471         }
1472         
1473         ntreeSolveOrder(snode->edittree);
1474 }
1475
1476 /* can be called from menus too, but they should do own undopush and redraws */
1477 bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
1478 {
1479         bNode *node= NULL, *gnode;
1480         
1481         node_deselectall(snode, 0);
1482         
1483         if(type>=NODE_GROUP_MENU) {
1484                 if(snode->edittree!=snode->nodetree) {
1485                         error("Can not add a Group in a Group");
1486                         return NULL;
1487                 }
1488                 else {
1489                         bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1490                         if(ngroup)
1491                                 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
1492                 }
1493         }
1494         else
1495                 node= nodeAddNodeType(snode->edittree, type, NULL);
1496         
1497         /* generics */
1498         if(node) {
1499                 node->locx= locx;
1500                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
1501                 node->flag |= SELECT;
1502                 
1503                 gnode= snode_get_editgroup(snode);
1504                 if(gnode) {
1505                         node->locx -= gnode->locx;
1506                         node->locy -= gnode->locy;
1507                 }
1508
1509                 snode_verify_groups(snode);
1510                 node_set_active(snode, node);
1511                 
1512                 if(node->id)
1513                         id_us_plus(node->id);
1514                 
1515                 if(snode->nodetree->type==NTREE_COMPOSIT)
1516                         ntreeCompositForceHidden(snode->edittree);
1517                 
1518                 NodeTagChanged(snode->edittree, node);
1519         }
1520         return node;
1521 }
1522
1523 void node_adduplicate(SpaceNode *snode)
1524 {
1525         
1526         ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
1527         
1528         ntreeSolveOrder(snode->edittree);
1529         snode_verify_groups(snode);
1530         snode_handle_recalc(snode);
1531
1532         transform_nodes(snode->edittree, 'g', "Duplicate");
1533 }
1534
1535 #if 0
1536 static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
1537 {
1538         bNode *newnode= NULL;
1539         
1540         if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
1541                 if(snode->edittree->type==NTREE_SHADER)
1542                         newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
1543                 else if(snode->edittree->type==NTREE_COMPOSIT)
1544                         newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
1545                 else
1546                         newnode= NULL;
1547         }
1548         else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
1549                 if(snode->edittree->type==NTREE_SHADER)
1550                         newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
1551                 else if(snode->edittree->type==NTREE_COMPOSIT)
1552                         newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
1553                 else
1554                         newnode= NULL;
1555         }
1556         
1557         if(newnode) {
1558                 /* dangerous assumption to use first in/out socks, but thats fine for now */
1559                 newnode->flag |= NODE_HIDDEN;
1560                 newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
1561                 newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
1562                 
1563                 nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
1564                 link->tonode= newnode;
1565                 link->tosock= newnode->inputs.first;
1566         }
1567 }
1568
1569 #endif
1570
1571 /* loop that adds a nodelink, called by function below  */
1572 /* in_out = starting socket */
1573 static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
1574 {
1575         bNode *tnode;
1576         bNodeSocket *tsock= NULL;
1577         bNodeLink *link= NULL;
1578         short mval[2], mvalo[2], firsttime=1;   /* firsttime reconnects a link broken by caller */
1579         
1580         /* we make a temporal link */
1581         if(in_out==SOCK_OUT)
1582                 link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
1583         else
1584                 link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
1585         
1586         getmouseco_areawin(mvalo);
1587         while (get_mbut() & L_MOUSE) {
1588                 
1589                 getmouseco_areawin(mval);
1590                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
1591                         firsttime= 0;
1592                         
1593                         mvalo[0]= mval[0];
1594                         mvalo[1]= mval[1];
1595                         
1596                         if(in_out==SOCK_OUT) {
1597                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1598                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1599                                                 if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
1600                                                         link->tonode= tnode;
1601                                                         link->tosock= tsock;
1602                                                         ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1603                                                 }
1604                                         }
1605                                 }
1606                                 else {
1607                                         link->tonode= NULL;
1608                                         link->tosock= NULL;
1609                                 }
1610                         }
1611                         else {
1612                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1613                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1614                                                 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1615                                                         if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1616                                                                 link->fromnode= tnode;
1617                                                                 link->fromsock= tsock;
1618                                                                 ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1619                                                         }
1620                                                 }
1621                                         }
1622                                 }
1623                                 else {
1624                                         link->fromnode= NULL;
1625                                         link->fromsock= NULL;
1626                                 }
1627                         }
1628                         /* hilight target sockets only */
1629                         node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1630                         
1631                         force_draw(0);
1632                 }
1633                 else BIF_wait_for_statechange();                
1634         }
1635         
1636         /* remove link? */
1637         if(link->tonode==NULL || link->fromnode==NULL) {
1638                 nodeRemLink(snode->edittree, link);
1639         }
1640         else {
1641                 bNodeLink *tlink;
1642
1643                 /* send changed events for original tonode and new */
1644                 if(link->tonode) 
1645                         NodeTagChanged(snode->edittree, link->tonode);
1646                 
1647                 /* we might need to remove a link */
1648                 if(in_out==SOCK_OUT) {
1649                         if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1650                                 
1651                                 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1652                                         if(link!=tlink && tlink->tosock==link->tosock)
1653                                                 break;
1654                                 }
1655                                 if(tlink) {
1656                                         /* is there a free input socket with same type? */
1657                                         for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) {
1658                                                 if(tsock->type==tlink->fromsock->type)
1659                                                         if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit)
1660                                                                 break;
1661                                         }
1662                                         if(tsock)
1663                                                 tlink->tosock= tsock;
1664                                         else {
1665                                                 nodeRemLink(snode->edittree, tlink);
1666                                         }
1667                                 }                                       
1668                         }
1669                 }
1670         }
1671         
1672         ntreeSolveOrder(snode->edittree);
1673         snode_verify_groups(snode);
1674         snode_handle_recalc(snode);
1675         
1676         allqueue(REDRAWNODE, 0);
1677         BIF_undo_push("Add link");
1678
1679         return 1;
1680 }
1681
1682 /* return 1 when socket clicked */
1683 static int node_add_link(SpaceNode *snode)
1684 {
1685         bNode *node;
1686         bNodeLink *link;
1687         bNodeSocket *sock;
1688         
1689         /* output indicated? */
1690         if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
1691                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1692                         return node_add_link_drag(snode, node, sock, SOCK_OUT);
1693                 else {
1694                         /* find if we break a link */
1695                         for(link= snode->edittree->links.first; link; link= link->next) {
1696                                 if(link->fromsock==sock)
1697                                         break;
1698                         }
1699                         if(link) {
1700                                 node= link->tonode;
1701                                 sock= link->tosock;
1702                                 nodeRemLink(snode->edittree, link);
1703                                 return node_add_link_drag(snode, node, sock, SOCK_IN);
1704                         }
1705                 }
1706         }
1707         /* or an input? */
1708         else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
1709                 if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
1710                         return node_add_link_drag(snode, node, sock, SOCK_IN);
1711                 else {
1712                         /* find if we break a link */
1713                         for(link= snode->edittree->links.first; link; link= link->next) {
1714                                 if(link->tosock==sock)
1715                                         break;
1716                         }
1717                         if(link) {
1718                                 /* send changed event to original tonode */
1719                                 if(link->tonode) 
1720                                         NodeTagChanged(snode->edittree, link->tonode);
1721                                 
1722                                 node= link->fromnode;
1723                                 sock= link->fromsock;
1724                                 nodeRemLink(snode->edittree, link);
1725                                 return node_add_link_drag(snode, node, sock, SOCK_OUT);
1726                         }
1727                 }
1728         }
1729         
1730         return 0;
1731 }
1732
1733 void node_delete(SpaceNode *snode)
1734 {
1735         bNode *node, *next;
1736         
1737         for(node= snode->edittree->nodes.first; node; node= next) {
1738                 next= node->next;
1739                 if(node->flag & SELECT) {
1740                         /* check id user here, nodeFreeNode is called for free dbase too */
1741                         if(node->id)
1742                                 node->id->us--;
1743                         nodeFreeNode(snode->edittree, node);
1744                 }
1745         }
1746         
1747         snode_verify_groups(snode);
1748         snode_handle_recalc(snode);
1749         BIF_undo_push("Delete nodes");
1750         allqueue(REDRAWNODE, 1);
1751 }
1752
1753 void node_hide(SpaceNode *snode)
1754 {
1755         bNode *node;
1756         int nothidden=0, ishidden=0;
1757         
1758         for(node= snode->edittree->nodes.first; node; node= node->next) {
1759                 if(node->flag & SELECT) {
1760                         if(node->flag & NODE_HIDDEN)
1761                                 ishidden++;
1762                         else
1763                                 nothidden++;
1764                 }
1765         }
1766         for(node= snode->edittree->nodes.first; node; node= node->next) {
1767                 if(node->flag & SELECT) {
1768                         if( (ishidden && nothidden) || ishidden==0)
1769                                 node->flag |= NODE_HIDDEN;
1770                         else 
1771                                 node->flag &= ~NODE_HIDDEN;
1772                 }
1773         }
1774         BIF_undo_push("Hide nodes");
1775         allqueue(REDRAWNODE, 1);
1776 }
1777
1778 void node_insert_key(SpaceNode *snode)
1779 {
1780         bNode *node= editnode_get_active(snode->edittree);
1781
1782         if(node->type==CMP_NODE_TIME) {
1783                 if(node->custom1<node->custom2) {
1784
1785                         CurveMapping *cumap= node->storage;
1786                         float fval, curval;
1787                 
1788                         curval= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
1789                         fval= curvemapping_evaluateF(cumap, 0, curval);
1790                         
1791                         if(fbutton(&fval, 0.0f, 1.0f, 10, 10, "Insert Value")) {
1792                                 curvemap_insert(cumap->cm, curval, fval);
1793
1794                                 BIF_undo_push("Insert key in Time node");
1795                                 allqueue(REDRAWNODE, 1);
1796                         }
1797                 }
1798         }
1799 }
1800
1801 void node_select_linked(SpaceNode *snode, int out)
1802 {
1803         bNodeLink *link;
1804         bNode *node;
1805         
1806         /* NODE_TEST is the free flag */
1807         for(node= snode->edittree->nodes.first; node; node= node->next)
1808                 node->flag &= ~NODE_TEST;
1809
1810         for(link= snode->edittree->links.first; link; link= link->next) {
1811                 if(out) {
1812                         if(link->fromnode->flag & NODE_SELECT)
1813                                 link->tonode->flag |= NODE_TEST;
1814                 }
1815                 else {
1816                         if(link->tonode->flag & NODE_SELECT)
1817                                 link->fromnode->flag |= NODE_TEST;
1818                 }
1819         }
1820         
1821         for(node= snode->edittree->nodes.first; node; node= node->next)
1822                 if(node->flag & NODE_TEST)
1823                         node->flag |= NODE_SELECT;
1824         
1825         BIF_undo_push("Select Linked nodes");
1826         allqueue(REDRAWNODE, 1);
1827 }
1828
1829 static void node_border_link_delete(SpaceNode *snode)
1830 {
1831         rcti rect;
1832         short val, mval[2], mvalo[2];
1833
1834         /* to make this work more friendly, we first wait for a mouse move */
1835         getmouseco_areawin(mvalo);
1836         while (get_mbut() & L_MOUSE) {
1837                 getmouseco_areawin(mval);
1838                 if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
1839                         break;
1840                 else BIF_wait_for_statechange();
1841         }
1842         if((get_mbut() & L_MOUSE)==0)
1843                 return;
1844         
1845         /* now change cursor and draw border */
1846         setcursor_space(SPACE_NODE, CURSOR_VPAINT);
1847         
1848         if ( (val = get_border(&rect, 2)) ) {
1849                 if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
1850                         //#define NODE_MAXPICKBUF       256
1851                         bNodeLink *link, *next;
1852                         GLuint buffer[256];
1853                         rctf rectf;
1854                         int code=0, hits;
1855                         
1856                         mval[0]= rect.xmin;
1857                         mval[1]= rect.ymin;
1858                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
1859                         mval[0]= rect.xmax;
1860                         mval[1]= rect.ymax;
1861                         areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
1862                         
1863                         myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
1864                         
1865                         glSelectBuffer(256, buffer); 
1866                         glRenderMode(GL_SELECT);
1867                         glInitNames();
1868                         glPushName(-1);
1869                         
1870                         /* draw links */
1871                         for(link= snode->edittree->links.first; link; link= link->next) {
1872                                 glLoadName(code++);
1873                                 node_draw_link(snode, link);
1874                         }
1875                         
1876                         hits= glRenderMode(GL_RENDER);
1877                         glPopName();
1878                         if(hits>0) {
1879                                 int a;
1880                                 for(a=0; a<hits; a++) {
1881                                         bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
1882                                         if(link)
1883                                                 link->fromnode= NULL;   /* first tag for delete, otherwise indices are wrong */
1884                                 }
1885                                 for(link= snode->edittree->links.first; link; link= next) {
1886                                         next= link->next;
1887                                         if(link->fromnode==NULL) {
1888                                                 NodeTagChanged(snode->edittree, link->tonode);
1889                                                 nodeRemLink(snode->edittree, link);
1890                                         }
1891                                 }
1892                                 ntreeSolveOrder(snode->edittree);
1893                                 snode_verify_groups(snode);
1894                                 snode_handle_recalc(snode);
1895                         }
1896                         allqueue(REDRAWNODE, 0);
1897                         BIF_undo_push("Erase links");
1898                 }
1899         }
1900         
1901         setcursor_space(SPACE_NODE, CURSOR_STD);
1902 }
1903
1904 /* goes over all scenes, reads render layerss */
1905 void node_read_renderlayers(SpaceNode *snode)
1906 {
1907         Scene *scene;
1908         bNode *node;
1909
1910         /* first tag scenes unread */
1911         for(scene= G.main->scene.first; scene; scene= scene->id.next) 
1912                 scene->id.flag |= LIB_DOIT;
1913
1914         for(node= snode->edittree->nodes.first; node; node= node->next) {
1915                 if(node->type==CMP_NODE_R_LAYERS) {
1916                         ID *id= node->id;
1917                         if(id==NULL) id= (ID *)G.scene;
1918                         if(id->flag & LIB_DOIT) {
1919                                 RE_ReadRenderResult(G.scene, (Scene *)id);
1920                                 ntreeCompositTagRender((Scene *)id);
1921                                 id->flag &= ~LIB_DOIT;
1922                         }
1923                 }
1924         }
1925         
1926         snode_handle_recalc(snode);
1927 }
1928
1929 /* called from header_info, when deleting a scene
1930  * goes over all scenes other than the input, checks if they have
1931  * render layer nodes referencing the to-be-deleted scene, and
1932  * resets them to NULL. */
1933 void clear_scene_in_nodes(Scene *sce)
1934 {
1935         Scene *sce1;
1936         bNode *node;
1937
1938         sce1= G.main->scene.first;
1939         while(sce1) {
1940                 if(sce1!=sce) {
1941                         if (sce1->nodetree) {
1942                                 for(node= sce1->nodetree->nodes.first; node; node= node->next) {
1943                                         if(node->type==CMP_NODE_R_LAYERS) {
1944                                                 Scene *nodesce= (Scene *)node->id;
1945                                                 
1946                                                 if (nodesce==sce) node->id = NULL;
1947                                         }
1948                                 }
1949                         }
1950                 }
1951                 sce1= sce1->id.next;
1952         }
1953 }
1954
1955
1956 /* gets active viewer user */
1957 struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
1958 {
1959         bNode *node;
1960         
1961         if(ntree)
1962                 for(node= ntree->nodes.first; node; node= node->next)
1963                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
1964                                 if(node->flag & NODE_DO_OUTPUT)
1965                                         return node->storage;
1966         return NULL;
1967 }
1968
1969 void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser)
1970 {
1971         bNode *node;
1972         
1973         if(ntree==NULL)
1974                 return;
1975         
1976         /* search for renderresults */
1977         if(image->type==IMA_TYPE_R_RESULT) {
1978                 for(node= ntree->nodes.first; node; node= node->next) {
1979                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
1980                                 /* imageuser comes from ImageWin, so indexes are offset 1 */
1981                                 if(node->custom1==iuser->layer-1)
1982                                         NodeTagChanged(ntree, node);
1983                         }
1984                 }
1985         }
1986         else {
1987                 for(node= ntree->nodes.first; node; node= node->next) {
1988                         if(node->id== &image->id)
1989                                 NodeTagChanged(ntree, node);
1990                 }
1991         }
1992 }
1993
1994 /* ********************** */
1995
1996 void node_make_group(SpaceNode *snode)
1997 {
1998         bNode *gnode;
1999         
2000         if(snode->edittree!=snode->nodetree) {
2001                 error("Can not add a new Group in a Group");
2002                 return;
2003         }
2004         
2005         /* for time being... is too complex to handle */
2006         if(snode->treetype==NTREE_COMPOSIT) {
2007                 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
2008                         if(gnode->flag & SELECT)
2009                                 if(gnode->type==CMP_NODE_R_LAYERS)
2010                                         break;
2011                 }
2012                 if(gnode) {
2013                         error("Can not add RenderLayer in a Group");
2014                         return;
2015                 }
2016         }
2017         
2018         gnode= nodeMakeGroupFromSelected(snode->nodetree);
2019         if(gnode==NULL) {
2020                 error("Can not make Group");
2021         }
2022         else {
2023                 nodeSetActive(snode->nodetree, gnode);
2024                 ntreeSolveOrder(snode->nodetree);
2025                 allqueue(REDRAWNODE, 0);
2026                 BIF_undo_push("Make Node Group");
2027         }
2028 }
2029
2030 /* ******************** main event loop ****************** */
2031
2032 /* special version to prevent overlapping buttons, has a bit of hack... */
2033 /* yes, check for example composit_node_event(), file window use... */
2034 static int node_uiDoBlocks(ScrArea *sa, short event)
2035 {
2036         SpaceNode *snode= sa->spacedata.first;
2037         ListBase *lb= &sa->uiblocks;
2038         ListBase listb= *lb;
2039         bNode *node;
2040         rctf rect;
2041         void *prev, *next;
2042         int retval= UI_NOTHING;
2043         short mval[2];
2044         
2045         getmouseco_areawin(mval);
2046         areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
2047
2048         /* this happens after filesel usage... */
2049         if(lb->first==NULL) {
2050                 return UI_NOTHING;
2051         }
2052         
2053         rect.xmin -= 2.0f;
2054         rect.ymin -= 2.0f;
2055         rect.xmax = rect.xmin + 4.0f;
2056         rect.ymax = rect.ymin + 4.0f;
2057         
2058         for(node= snode->edittree->nodes.first; node; node= node->next) {
2059                 uiBlock *block;
2060                 char str[32];
2061                 
2062                 /* retreive unique block name, see also drawnode.c */
2063                 sprintf(str, "node buttons %p", node);
2064                 block= uiGetBlock(str, sa);
2065                 
2066                 if(block) {
2067                         if(node == visible_node(snode, &rect)) {
2068
2069                                 /* when there's menus, the prev pointer becomes zero! */
2070                                 prev= ((struct Link *)block)->prev;
2071                                 next= ((struct Link *)block)->next;
2072                                 ((struct Link *)block)->prev= NULL;
2073                                 ((struct Link *)block)->next= NULL;
2074                                 
2075                                 lb->first= lb->last= block;
2076                                 retval= uiDoBlocks(lb, event, 1);
2077                                 
2078                                 ((struct Link *)block)->prev= prev;
2079                                 ((struct Link *)block)->next= next;
2080
2081                                 break;
2082                         }
2083                 }
2084         }
2085         
2086         *lb= listb;
2087         
2088         return retval;
2089 }
2090
2091 void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
2092 {
2093         SpaceNode *snode= spacedata;
2094         unsigned short event= evt->event;
2095         short val= evt->val, doredraw=0, fromlib= 0;
2096         
2097         if(sa->win==0) return;
2098         if(snode->nodetree==NULL) return;
2099         
2100         if(val) {
2101
2102                 if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;  
2103
2104                 fromlib= (snode->id && snode->id->lib);
2105                 
2106                 switch(event) {
2107                 case LEFTMOUSE:
2108                         if(fromlib) {
2109                                 if(node_mouse_groupheader(snode)==0)
2110                                         node_mouse_select(snode, event);
2111                         }
2112                         else {
2113                                 if(node_add_link(snode)==0)
2114                                         if(node_mouse_groupheader(snode)==0)
2115                                                 if(node_mouse_select(snode, event)==0)
2116                                                         node_border_link_delete(snode);
2117                         }
2118                         break;
2119                         
2120                 case RIGHTMOUSE: 
2121                         if(!node_mouse_select(snode, event)) 
2122                                 toolbox_n();
2123
2124                         break;
2125                 case MIDDLEMOUSE:
2126                         if (G.qual==LR_SHIFTKEY) {
2127                                 snode_bg_viewmove(snode);
2128                         } else {
2129                                 view2dmove(event);
2130                         }
2131                 case WHEELUPMOUSE:
2132                 case WHEELDOWNMOUSE:
2133                         view2dmove(event);      /* in drawipo.c */
2134                         break;
2135                         
2136                 case MOUSEY:
2137                         doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
2138                         break;
2139                 
2140                 case UI_BUT_EVENT:
2141                         /* future: handlerize this! */
2142                         if(snode->treetype==NTREE_SHADER)
2143                                 shader_node_event(snode, val);
2144                         else if(snode->treetype==NTREE_COMPOSIT)
2145                                 composit_node_event(snode, val);
2146                         break;
2147                         
2148                 case RENDERPREVIEW:
2149                         if(snode->treetype==NTREE_SHADER)
2150                                 shader_node_previewrender(sa, snode);
2151                         break;
2152                         
2153                 case PADPLUSKEY:
2154                         snode_zoom_in(sa);
2155                         doredraw= 1;
2156                         break;
2157                 case PADMINUS:
2158                         snode_zoom_out(sa);
2159                         doredraw= 1;
2160                         break;
2161                 case HOMEKEY:
2162                         snode_home(sa, snode);
2163                         doredraw= 1;
2164                         break;
2165                 case TABKEY:
2166                         if(fromlib) fromlib= -1;
2167                         else snode_make_group_editable(snode, NULL);
2168                         break;
2169                         
2170                 case AKEY:
2171                         if(G.qual==LR_SHIFTKEY) {
2172                                 if(fromlib) fromlib= -1;
2173                                 else toolbox_n_add();
2174                         }
2175                         else if(G.qual==0) {
2176                                 node_deselectall(snode, 1);
2177                                 BIF_undo_push("Deselect all nodes");
2178                         }
2179                         break;
2180                 case BKEY:
2181                         if(G.qual==0)
2182                                 node_border_select(snode);
2183                         break;
2184                 case CKEY:      /* sort again, showing cyclics */
2185                         ntreeSolveOrder(snode->edittree);
2186                         doredraw= 1;
2187                         break;
2188                 case DKEY:
2189                         if(G.qual==LR_SHIFTKEY) {
2190                                 if(fromlib) fromlib= -1;
2191                                 else node_adduplicate(snode);
2192                         }
2193                         break;
2194                 case EKEY:
2195                         snode_handle_recalc(snode);
2196                         break;
2197                 case GKEY:
2198                         if(fromlib) fromlib= -1;
2199                         else {
2200                                 if(G.qual==LR_CTRLKEY) {
2201                                         if(okee("Make Group"))
2202                                                 node_make_group(snode);
2203                                 }
2204                                 else if(G.qual==LR_ALTKEY) {
2205                                         if(okee("Ungroup"))
2206                                                 node_ungroup(snode);
2207                                 }
2208                                 else if(G.qual==LR_SHIFTKEY) {
2209                                         node_addgroup(snode);
2210                                 }
2211                                 else
2212                                         transform_nodes(snode->edittree, 'g', "Move Node");
2213                         }
2214                         break;
2215                 case HKEY:
2216                         node_hide(snode);
2217                         break;
2218                 case IKEY:
2219                         node_insert_key(snode);
2220                         break;
2221                 case LKEY:
2222                         node_select_linked(snode, G.qual==LR_SHIFTKEY);
2223                         break;
2224                 case RKEY:
2225                         if(okee("Read saved Render Layers"))
2226                                 node_read_renderlayers(snode);
2227                         break;
2228                 case DELKEY:
2229                 case XKEY:
2230                         if(fromlib) fromlib= -1;
2231                         else node_delete(snode);
2232                         break;
2233                 }
2234         }
2235
2236         if(fromlib==-1)
2237                 error_libdata();
2238         if(doredraw)
2239                 scrarea_queue_winredraw(sa);
2240         if(doredraw==2)
2241                 scrarea_queue_headredraw(sa);
2242 }
2243
2244