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