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