Another one for drag and drop:
[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, NULL);
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 static int backimage_zoom(bContext *C, wmOperator *op)
779 {
780         SpaceNode *snode= CTX_wm_space_node(C);
781         ARegion *ar= CTX_wm_region(C);
782         float fac= RNA_float_get(op->ptr, "factor");
783
784         snode->zoom *= fac;
785         ED_region_tag_redraw(ar);
786
787         return OPERATOR_FINISHED;
788 }
789
790
791 void NODE_OT_backimage_zoom(wmOperatorType *ot)
792 {
793         
794         /* identifiers */
795         ot->name= "Background Image Zoom";
796         ot->idname= "NODE_OT_backimage_zoom";
797         
798         /* api callbacks */
799         ot->exec= backimage_zoom;
800         ot->poll= ED_operator_node_active;
801         
802         /* flags */
803         ot->flag= OPTYPE_BLOCKING;
804
805         /* internal */
806         RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
807 }
808
809
810 /* ********************** size widget operator ******************** */
811
812 typedef struct NodeSizeWidget {
813         float mxstart;
814         float oldwidth;
815 } NodeSizeWidget;
816
817 static int node_resize_modal(bContext *C, wmOperator *op, wmEvent *event)
818 {
819         SpaceNode *snode= CTX_wm_space_node(C);
820         ARegion *ar= CTX_wm_region(C);
821         bNode *node= editnode_get_active(snode->edittree);
822         NodeSizeWidget *nsw= op->customdata;
823         float mx, my;
824         
825         switch (event->type) {
826                 case MOUSEMOVE:
827                         
828                         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
829                                                                          &mx, &my);
830                         
831                         if (node) {
832                                 if(node->flag & NODE_HIDDEN) {
833                                         node->miniwidth= nsw->oldwidth + mx - nsw->mxstart;
834                                         CLAMP(node->miniwidth, 0.0f, 100.0f);
835                                 }
836                                 else {
837                                         node->width= nsw->oldwidth + mx - nsw->mxstart;
838                                         CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
839                                 }
840                         }
841                                 
842                         ED_region_tag_redraw(ar);
843
844                         break;
845                         
846                 case LEFTMOUSE:
847                 case MIDDLEMOUSE:
848                 case RIGHTMOUSE:
849                         
850                         MEM_freeN(nsw);
851                         op->customdata= NULL;
852                         
853                         return OPERATOR_FINISHED;
854         }
855         
856         return OPERATOR_RUNNING_MODAL;
857 }
858
859 static int node_resize_invoke(bContext *C, wmOperator *op, wmEvent *event)
860 {
861         SpaceNode *snode= CTX_wm_space_node(C);
862         ARegion *ar= CTX_wm_region(C);
863         bNode *node= editnode_get_active(snode->edittree);
864         
865         if(node) {
866                 rctf totr;
867                 
868                 /* convert mouse coordinates to v2d space */
869                 UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
870                                                                  &snode->mx, &snode->my);
871                 
872                 /* rect we're interested in is just the bottom right corner */
873                 totr= node->totr;
874                 totr.xmin= totr.xmax-10.0f;
875                 totr.ymax= totr.ymin+10.0f;
876                 
877                 if(BLI_in_rctf(&totr, snode->mx, snode->my)) {
878                         NodeSizeWidget *nsw= MEM_callocN(sizeof(NodeSizeWidget), "size widget op data");
879                         
880                         op->customdata= nsw;
881                         nsw->mxstart= snode->mx;
882                         
883                         /* store old */
884                         if(node->flag & NODE_HIDDEN)
885                                 nsw->oldwidth= node->miniwidth;
886                         else
887                                 nsw->oldwidth= node->width;
888                         
889                         /* add modal handler */
890                         WM_event_add_modal_handler(C, op);
891
892                         return OPERATOR_RUNNING_MODAL;
893                 }
894         }
895         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
896 }
897
898 void NODE_OT_resize(wmOperatorType *ot)
899 {
900         /* identifiers */
901         ot->name= "Resize Node";
902         ot->idname= "NODE_OT_resize";
903         
904         /* api callbacks */
905         ot->invoke= node_resize_invoke;
906         ot->modal= node_resize_modal;
907         ot->poll= ED_operator_node_active;
908         
909         /* flags */
910         ot->flag= OPTYPE_BLOCKING;
911 }
912
913 /* ********************** select ******************** */
914
915
916 /* no undo here! */
917 void node_deselectall(SpaceNode *snode)
918 {
919         bNode *node;
920         
921         for(node= snode->edittree->nodes.first; node; node= node->next)
922                 node->flag &= ~SELECT;
923 }
924
925 int node_has_hidden_sockets(bNode *node)
926 {
927         bNodeSocket *sock;
928         
929         for(sock= node->inputs.first; sock; sock= sock->next)
930                 if(sock->flag & SOCK_HIDDEN)
931                         return 1;
932         for(sock= node->outputs.first; sock; sock= sock->next)
933                 if(sock->flag & SOCK_HIDDEN)
934                         return 1;
935         return 0;
936 }
937
938 static void node_link_viewer(SpaceNode *snode, bNode *tonode)
939 {
940         bNode *node;
941
942         /* context check */
943         if(tonode==NULL || tonode->outputs.first==NULL)
944                 return;
945         if( ELEM(tonode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
946                 return;
947         
948         /* get viewer */
949         for(node= snode->edittree->nodes.first; node; node= node->next)
950                 if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
951                         if(node->flag & NODE_DO_OUTPUT)
952                                 break;
953         /* no viewer, we make one active */
954         if(node==NULL) {
955                 for(node= snode->edittree->nodes.first; node; node= node->next) {
956                         if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
957                                 node->flag |= NODE_DO_OUTPUT;
958                                 break;
959                         }
960                 }
961         }
962                 
963         if(node) {
964                 bNodeLink *link;
965                 
966                 /* get link to viewer */
967                 for(link= snode->edittree->links.first; link; link= link->next)
968                         if(link->tonode==node)
969                                 break;
970                 
971                 if(link==NULL) {
972                         nodeAddLink(snode->edittree, tonode, tonode->outputs.first, node, node->inputs.first);
973                 }
974                 else {
975                         link->fromnode= tonode;
976                         link->fromsock= tonode->outputs.first;
977                 }
978                 ntreeSolveOrder(snode->edittree);
979                 NodeTagChanged(snode->edittree, node);
980         }
981 }
982
983
984 static int node_active_link_viewer(bContext *C, wmOperator *op)
985 {
986         SpaceNode *snode= CTX_wm_space_node(C);
987         bNode *node;
988         
989         
990         node= editnode_get_active(snode->edittree);
991         
992         if(node) {
993                 node_link_viewer(snode, node);
994                 snode_notify(C, snode);
995         }
996         return OPERATOR_FINISHED;
997 }
998
999
1000
1001 void NODE_OT_link_viewer(wmOperatorType *ot)
1002 {
1003         /* identifiers */
1004         ot->name= "Link to Viewer Node";
1005         ot->description = "Link to Viewer Node";
1006         ot->idname= "NODE_OT_link_viewer";
1007         
1008         /* api callbacks */
1009         ot->exec= node_active_link_viewer;
1010         ot->poll= ED_operator_node_active;
1011         
1012         /* flags */
1013         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1014 }
1015
1016
1017
1018 /* return 0, nothing done */
1019 /*static*/ int node_mouse_groupheader(SpaceNode *snode)
1020 {
1021         bNode *gnode;
1022         float mx=0, my=0;
1023 // XXX  short mval[2];
1024         
1025         gnode= node_tree_get_editgroup(snode->nodetree);
1026         if(gnode==NULL) return 0;
1027         
1028 // XXX  getmouseco_areawin(mval);
1029 // XXX  areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
1030         
1031         /* click in header or outside? */
1032         if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
1033                 rctf rect= gnode->totr;
1034                 
1035                 rect.ymax += NODE_DY;
1036                 if(BLI_in_rctf(&rect, mx, my)==0)
1037                         snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
1038 //              else
1039 // XXX                  transform_nodes(snode->nodetree, 'g', "Move group");
1040                 
1041                 return 1;
1042         }
1043         return 0;
1044 }
1045
1046 /* checks snode->mouse position, and returns found node/socket */
1047 /* type is SOCK_IN and/or SOCK_OUT */
1048 static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
1049 {
1050         bNode *node;
1051         bNodeSocket *sock;
1052         rctf rect;
1053         
1054         /* check if we click in a socket */
1055         for(node= snode->edittree->nodes.first; node; node= node->next) {
1056                 
1057                 rect.xmin = snode->mx - (NODE_SOCKSIZE+4);
1058                 rect.ymin = snode->my - (NODE_SOCKSIZE+4);
1059                 rect.xmax = snode->mx + (NODE_SOCKSIZE+4);
1060                 rect.ymax = snode->my + (NODE_SOCKSIZE+4);
1061                 
1062                 if (!(node->flag & NODE_HIDDEN)) {
1063                         /* extra padding inside and out - allow dragging on the text areas too */
1064                         if (in_out == SOCK_IN) {
1065                                 rect.xmax += NODE_SOCKSIZE;
1066                                 rect.xmin -= NODE_SOCKSIZE*4;
1067                         } else if (in_out == SOCK_OUT) {
1068                                 rect.xmax += NODE_SOCKSIZE*4;
1069                                 rect.xmin -= NODE_SOCKSIZE;
1070                         }
1071                 }
1072                 
1073                 if(in_out & SOCK_IN) {
1074                         for(sock= node->inputs.first; sock; sock= sock->next) {
1075                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1076                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1077                                                 if(node == visible_node(snode, &rect)) {
1078                                                         *nodep= node;
1079                                                         *sockp= sock;
1080                                                         return 1;
1081                                                 }
1082                                         }
1083                                 }
1084                         }
1085                 }
1086                 if(in_out & SOCK_OUT) {
1087                         for(sock= node->outputs.first; sock; sock= sock->next) {
1088                                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
1089                                         if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
1090                                                 if(node == visible_node(snode, &rect)) {
1091                                                         *nodep= node;
1092                                                         *sockp= sock;
1093                                                         return 1;
1094                                                 }
1095                                         }
1096                                 }
1097                         }
1098                 }
1099         }
1100         return 0;
1101 }
1102
1103 static int node_socket_hilights(SpaceNode *snode, int in_out)
1104 {
1105         bNode *node;
1106         bNodeSocket *sock, *tsock, *socksel= NULL;
1107         short redraw= 0;
1108         
1109         if(snode->edittree==NULL) return 0;
1110         
1111         /* deselect sockets */
1112         for(node= snode->edittree->nodes.first; node; node= node->next) {
1113                 for(sock= node->inputs.first; sock; sock= sock->next) {
1114                         if(sock->flag & SELECT) {
1115                                 sock->flag &= ~SELECT;
1116                                 redraw++;
1117                                 socksel= sock;
1118                         }
1119                 }
1120                 for(sock= node->outputs.first; sock; sock= sock->next) {
1121                         if(sock->flag & SELECT) {
1122                                 sock->flag &= ~SELECT;
1123                                 redraw++;
1124                                 socksel= sock;
1125                         }
1126                 }
1127         }
1128         
1129         // XXX mousepos should be set here!
1130         
1131         if(find_indicated_socket(snode, &node, &tsock, in_out)) {
1132                 tsock->flag |= SELECT;
1133                 if(redraw==1 && tsock==socksel) redraw= 0;
1134                 else redraw= 1;
1135         }
1136         
1137         return redraw;
1138 }
1139
1140 /* ****************** Add *********************** */
1141
1142
1143 typedef struct bNodeListItem {
1144         struct bNodeListItem *next, *prev;
1145         struct bNode *node;     
1146 } bNodeListItem;
1147
1148 int sort_nodes_locx(void *a, void *b)
1149 {
1150         bNodeListItem *nli1 = (bNodeListItem *)a;
1151         bNodeListItem *nli2 = (bNodeListItem *)b;
1152         bNode *node1 = nli1->node;
1153         bNode *node2 = nli2->node;
1154         
1155         if (node1->locx > node2->locx)
1156                 return 1;
1157         else 
1158                 return 0;
1159 }
1160
1161 static int socket_is_available(bNodeTree *ntree, bNodeSocket *sock, int allow_used)
1162 {
1163         if (sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
1164                 return 0;
1165         
1166         if (!allow_used) {
1167                 if (nodeCountSocketLinks(ntree, sock) > 0)
1168                         return 0;
1169         }
1170         return 1;
1171 }
1172
1173 static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
1174 {
1175         bNodeSocket *sock;
1176         
1177         /* first try to find a socket with a matching name */
1178         for (sock=node->outputs.first; sock; sock=sock->next) {
1179
1180                 if (!socket_is_available(ntree, sock, allow_multiple))
1181                         continue;
1182
1183                 /* check for same types */
1184                 if (sock->type == sock_target->type) {
1185                         if (strcmp(sock->name, sock_target->name)==0)
1186                                 return sock;
1187                 }
1188         }
1189         
1190         /* otherwise settle for the first available socket of the right type */
1191         for (sock=node->outputs.first; sock; sock=sock->next) {
1192
1193                 if (!socket_is_available(ntree, sock, allow_multiple))
1194                         continue;
1195                 
1196                 /* check for same types */
1197                 if (sock->type == sock_target->type) {
1198                         return sock;
1199                 }
1200         }
1201         
1202         return NULL;
1203 }
1204
1205 /* this is a bit complicated, but designed to prioritise finding 
1206  * sockets of higher types, such as image, first */
1207 static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
1208 {
1209         bNodeSocket *sock;
1210         int socktype, maxtype=0;
1211         int a = 0;
1212         
1213         for (sock=node->inputs.first; sock; sock=sock->next) {
1214                 maxtype = MAX2(sock->type, maxtype);
1215         }
1216         
1217         /* find sockets of higher 'types' first (i.e. image) */
1218         for (socktype=maxtype; socktype >= 0; socktype--) {
1219                 for (sock=node->inputs.first; sock; sock=sock->next) {
1220                         
1221                         if (!socket_is_available(ntree, sock, replace)) {
1222                                 a++;
1223                                 continue;
1224                         }
1225                                 
1226                         if (sock->type == socktype) {
1227                                 /* increment to make sure we don't keep finding 
1228                                  * the same socket on every attempt running this function */
1229                                 a++;
1230                                 if (a > num)
1231                                         return sock;
1232                         }
1233                 }
1234         }
1235         
1236         return NULL;
1237 }
1238
1239 void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
1240 {
1241         ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
1242         bNodeListItem *nli;
1243         bNode *node;
1244         int i;
1245         
1246         for(node= snode->edittree->nodes.first; node; node= node->next) {
1247                 if(node->flag & NODE_SELECT) {
1248                         nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
1249                         nli->node = node;
1250                         BLI_addtail(nodelist, nli);
1251                 }
1252         }
1253         
1254         /* sort nodes left to right */
1255         BLI_sortlist(nodelist, sort_nodes_locx);
1256         
1257         for (nli=nodelist->first; nli; nli=nli->next) {
1258                 bNode *node_fr, *node_to;
1259                 bNodeSocket *sock_fr, *sock_to;
1260                 
1261                 if (nli->next == NULL) break;
1262                 
1263                 node_fr = nli->node;
1264                 node_to = nli->next->node;
1265                 
1266                 /* check over input sockets first */
1267                 for (i=0; i<BLI_countlist(&node_to->inputs); i++) {
1268                         
1269                         /* find the best guess input socket */
1270                         sock_to = best_socket_input(snode->edittree, node_to, i, replace);
1271                         if (!sock_to) continue;
1272                         
1273                         /* check for an appropriate output socket to connect from */
1274                         sock_fr = best_socket_output(snode->edittree, node_fr, sock_to, allow_multiple);
1275                         if (!sock_fr) continue;
1276                         
1277                         /* then we can connect */
1278                         if (replace)
1279                                 nodeRemSocketLinks(snode->edittree, sock_to);
1280                         nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
1281                         NodeTagChanged(snode->edittree, node_to);
1282                         break;
1283                 }
1284         }
1285         
1286         ntreeSolveOrder(snode->edittree);
1287         
1288         BLI_freelistN(nodelist);
1289         MEM_freeN(nodelist);
1290 }
1291
1292 /* can be called from menus too, but they should do own undopush and redraws */
1293 bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy)
1294 {
1295         bNode *node= NULL, *gnode;
1296         
1297         node_deselectall(snode);
1298         
1299         if(type>=NODE_DYNAMIC_MENU) {
1300                 node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
1301         }
1302         else if(type>=NODE_GROUP_MENU) {
1303                 if(snode->edittree!=snode->nodetree) {
1304                         // XXX error("Can not add a Group in a Group");
1305                         return NULL;
1306                 }
1307                 else {
1308                         bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
1309                         if(ngroup)
1310                                 node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL);
1311                 }
1312         }
1313         else
1314                 node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
1315         
1316         /* generics */
1317         if(node) {
1318                 node->locx= locx;
1319                 node->locy= locy + 60.0f;               // arbitrary.. so its visible
1320                 node->flag |= SELECT;
1321                 
1322                 gnode= node_tree_get_editgroup(snode->nodetree);
1323                 if(gnode) {
1324                         node->locx -= gnode->locx;
1325                         node->locy -= gnode->locy;
1326                 }
1327
1328                 node_tree_verify_groups(snode->nodetree);
1329                 node_set_active(snode, node);
1330                 
1331                 if(snode->nodetree->type==NTREE_COMPOSIT) {
1332                         if(ELEM4(node->type, CMP_NODE_R_LAYERS, CMP_NODE_COMPOSITE, CMP_NODE_DEFOCUS, CMP_NODE_OUTPUT_FILE))
1333                                 node->id = &scene->id;
1334                         
1335                         ntreeCompositForceHidden(snode->edittree, scene);
1336                 }
1337                         
1338                 if(node->id)
1339                         id_us_plus(node->id);
1340                         
1341                 NodeTagChanged(snode->edittree, node);
1342         }
1343         
1344         if(snode->nodetree->type==NTREE_TEXTURE) {
1345                 ntreeTexCheckCyclics(snode->edittree);
1346         }
1347         
1348         return node;
1349 }
1350
1351 /* ****************** Duplicate *********************** */
1352
1353 static int node_duplicate_exec(bContext *C, wmOperator *op)
1354 {
1355         SpaceNode *snode= CTX_wm_space_node(C);
1356         
1357         ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
1358         
1359         ntreeSolveOrder(snode->edittree);
1360         node_tree_verify_groups(snode->nodetree);
1361         snode_notify(C, snode);
1362
1363         return OPERATOR_FINISHED;
1364 }
1365
1366 void NODE_OT_duplicate(wmOperatorType *ot)
1367 {
1368         /* identifiers */
1369         ot->name= "Duplicate Nodes";
1370         ot->description = "Duplicate the nodes";
1371         ot->idname= "NODE_OT_duplicate";
1372         
1373         /* api callbacks */
1374         ot->exec= node_duplicate_exec;
1375         ot->poll= ED_operator_node_active;
1376         
1377         /* flags */
1378         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1379 }
1380
1381 /* *************************** add link op ******************** */
1382
1383 /* temp data to pass on to modal */
1384 typedef struct NodeLinkDrag
1385 {
1386         bNode *node;
1387         bNodeSocket *sock;
1388         bNodeLink *link;
1389         int in_out;
1390 } NodeLinkDrag;
1391
1392 static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeLink *link)
1393 {
1394         bNodeLink *tlink;
1395         bNodeSocket *sock;
1396         
1397         if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
1398                 
1399                 for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
1400                         if(link!=tlink && tlink->tosock==link->tosock)
1401                                 break;
1402                 }
1403                 if(tlink) {
1404                         /* is there a free input socket with same type? */
1405                         for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) {
1406                                 if(sock->type==tlink->fromsock->type)
1407                                         if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit)
1408                                                 break;
1409                         }
1410                         if(sock) {
1411                                 tlink->tosock= sock;
1412                                 sock->flag &= ~SOCK_HIDDEN;
1413                         }
1414                         else {
1415                                 nodeRemLink(snode->edittree, tlink);
1416                         }
1417                 }
1418         }
1419 }
1420
1421 /* loop that adds a nodelink, called by function below  */
1422 /* in_out = starting socket */
1423 static int node_link_modal(bContext *C, wmOperator *op, wmEvent *event)
1424 {
1425         SpaceNode *snode= CTX_wm_space_node(C);
1426         ARegion *ar= CTX_wm_region(C);
1427         NodeLinkDrag *nldrag= op->customdata;
1428         bNode *tnode, *node;
1429         bNodeSocket *tsock= NULL, *sock;
1430         bNodeLink *link;
1431         int in_out;
1432
1433         in_out= nldrag->in_out;
1434         node= nldrag->node;
1435         sock= nldrag->sock;
1436         link= nldrag->link;
1437         
1438         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
1439                                                          &snode->mx, &snode->my);
1440
1441         switch (event->type) {
1442                 case MOUSEMOVE:
1443                         
1444                         if(in_out==SOCK_OUT) {
1445                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
1446                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1447                                                 if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
1448                                                         link->tonode= tnode;
1449                                                         link->tosock= tsock;
1450                                                         ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1451                                                 }
1452                                         }
1453                                 }
1454                                 else {
1455                                         link->tonode= NULL;
1456                                         link->tosock= NULL;
1457                                 }
1458                         }
1459                         else {
1460                                 if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
1461                                         if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
1462                                                 if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
1463                                                         if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
1464                                                                 link->fromnode= tnode;
1465                                                                 link->fromsock= tsock;
1466                                                                 ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
1467                                                         }
1468                                                 }
1469                                         }
1470                                 }
1471                                 else {
1472                                         link->fromnode= NULL;
1473                                         link->fromsock= NULL;
1474                                 }
1475                         }
1476                         /* hilight target sockets only */
1477                         node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
1478                         ED_region_tag_redraw(ar);
1479                         break;
1480                         
1481                 case LEFTMOUSE:
1482                 case RIGHTMOUSE:
1483                 case MIDDLEMOUSE:
1484         
1485                         /* remove link? */
1486                         if(link->tonode==NULL || link->fromnode==NULL) {
1487                                 nodeRemLink(snode->edittree, link);
1488                         }
1489                         else {
1490                                 /* send changed events for original tonode and new */
1491                                 if(link->tonode) 
1492                                         NodeTagChanged(snode->edittree, link->tonode);
1493                                 
1494                                 /* we might need to remove a link */
1495                                 if(in_out==SOCK_OUT) node_remove_extra_links(snode, link->tosock, link);
1496                         }
1497                         
1498                         ntreeSolveOrder(snode->edittree);
1499                         node_tree_verify_groups(snode->nodetree);
1500                         snode_notify(C, snode);
1501                         
1502                         MEM_freeN(op->customdata);
1503                         op->customdata= NULL;
1504                         
1505                         return OPERATOR_FINISHED;
1506         }
1507         
1508         return OPERATOR_RUNNING_MODAL;
1509 }
1510
1511 /* return 1 when socket clicked */
1512 static int node_link_init(SpaceNode *snode, NodeLinkDrag *nldrag)
1513 {
1514         bNodeLink *link;
1515         
1516         /* output indicated? */
1517         if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_OUT)) {
1518                 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
1519                         return SOCK_OUT;
1520                 else {
1521                         /* find if we break a link */
1522                         for(link= snode->edittree->links.first; link; link= link->next) {
1523                                 if(link->fromsock==nldrag->sock)
1524                                         break;
1525                         }
1526                         if(link) {
1527                                 nldrag->node= link->tonode;
1528                                 nldrag->sock= link->tosock;
1529                                 nodeRemLink(snode->edittree, link);
1530                                 return SOCK_IN;
1531                         }
1532                 }
1533         }
1534         /* or an input? */
1535         else if(find_indicated_socket(snode, &nldrag->node, &nldrag->sock, SOCK_IN)) {
1536                 if(nodeCountSocketLinks(snode->edittree, nldrag->sock) < nldrag->sock->limit)
1537                         return SOCK_IN;
1538                 else {
1539                         /* find if we break a link */
1540                         for(link= snode->edittree->links.first; link; link= link->next) {
1541                                 if(link->tosock==nldrag->sock)
1542                                         break;
1543                         }
1544                         if(link) {
1545                                 /* send changed event to original tonode */
1546                                 if(link->tonode) 
1547                                         NodeTagChanged(snode->edittree, link->tonode);
1548                                 
1549                                 nldrag->node= link->fromnode;
1550                                 nldrag->sock= link->fromsock;
1551                                 nodeRemLink(snode->edittree, link);
1552                                 return SOCK_OUT;
1553                         }
1554                 }
1555         }
1556         
1557         return 0;
1558 }
1559
1560 static int node_link_invoke(bContext *C, wmOperator *op, wmEvent *event)
1561 {
1562         SpaceNode *snode= CTX_wm_space_node(C);
1563         ARegion *ar= CTX_wm_region(C);
1564         NodeLinkDrag *nldrag= MEM_callocN(sizeof(NodeLinkDrag), "drag link op customdata");
1565         
1566         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
1567                                                          &snode->mx, &snode->my);
1568
1569         nldrag->in_out= node_link_init(snode, nldrag);
1570                 
1571         if(nldrag->in_out) {
1572                 op->customdata= nldrag;
1573                 
1574                 /* we make a temporal link */
1575                 if(nldrag->in_out==SOCK_OUT)
1576                         nldrag->link= nodeAddLink(snode->edittree, nldrag->node, nldrag->sock, NULL, NULL);
1577                 else
1578                         nldrag->link= nodeAddLink(snode->edittree, NULL, NULL, nldrag->node, nldrag->sock);
1579                 
1580                 /* add modal handler */
1581                 WM_event_add_modal_handler(C, op);
1582                 
1583                 return OPERATOR_RUNNING_MODAL;
1584         }
1585         else {
1586                 MEM_freeN(nldrag);
1587                 return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1588         }
1589 }
1590
1591 void NODE_OT_link(wmOperatorType *ot)
1592 {
1593         /* identifiers */
1594         ot->name= "Link Nodes";
1595         ot->idname= "NODE_OT_link";
1596         
1597         /* api callbacks */
1598         ot->invoke= node_link_invoke;
1599         ot->modal= node_link_modal;
1600 //      ot->exec= node_link_exec;
1601         ot->poll= ED_operator_node_active;
1602         
1603         /* flags */
1604         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
1605 }
1606
1607 /* ********************** Make Link operator ***************** */
1608
1609 /* makes a link between selected output and input sockets */
1610 static int node_make_link_exec(bContext *C, wmOperator *op)
1611 {
1612         SpaceNode *snode= CTX_wm_space_node(C);
1613         int replace = RNA_boolean_get(op->ptr, "replace");
1614
1615         snode_autoconnect(snode, 0, replace);
1616
1617         node_tree_verify_groups(snode->nodetree);
1618         snode_notify(C, snode);
1619         
1620         return OPERATOR_FINISHED;
1621 }
1622
1623 void NODE_OT_link_make(wmOperatorType *ot)
1624 {
1625         /* identifiers */
1626         ot->name= "Make Links";
1627         ot->description= "Makes a link between selected output in input sockets";
1628         ot->idname= "NODE_OT_link_make";
1629         
1630         /* callbacks */
1631         ot->exec= node_make_link_exec;
1632         ot->poll= ED_operator_node_active; // XXX we need a special poll which checks that there are selected input/output sockets
1633         
1634         /* flags */
1635         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1636         
1637         RNA_def_boolean(ot->srna, "replace", 0, "Replace", "Replace socket connections with the new links");
1638 }
1639
1640 /* ********************** Cut Link operator ***************** */
1641
1642 #define LINK_RESOL 12
1643 static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
1644 {
1645         float coord_array[LINK_RESOL+1][2];
1646         int i, b;
1647         
1648         if(node_link_bezier_points(NULL, NULL, link, coord_array, LINK_RESOL)) {
1649
1650                 for(i=0; i<tot-1; i++)
1651                         for(b=0; b<LINK_RESOL-1; b++)
1652                                 if(isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0)
1653                                         return 1;
1654         }
1655         return 0;
1656 }
1657
1658 static int cut_links_exec(bContext *C, wmOperator *op)
1659 {
1660         SpaceNode *snode= CTX_wm_space_node(C);
1661         ARegion *ar= CTX_wm_region(C);
1662         float mcoords[256][2];
1663         int i= 0;
1664         
1665         RNA_BEGIN(op->ptr, itemptr, "path") {
1666                 float loc[2];
1667                 
1668                 RNA_float_get_array(&itemptr, "loc", loc);
1669                 UI_view2d_region_to_view(&ar->v2d, (short)loc[0], (short)loc[1], 
1670                                                                  &mcoords[i][0], &mcoords[i][1]);
1671                 i++;
1672                 if(i>= 256) break;
1673         }
1674         RNA_END;
1675         
1676         if(i>1) {
1677                 bNodeLink *link, *next;
1678                 
1679                 for(link= snode->edittree->links.first; link; link= next) {
1680                         next= link->next;
1681                         
1682                         if(cut_links_intersect(link, mcoords, i)) {
1683                                 NodeTagChanged(snode->edittree, link->tonode);
1684                                 nodeRemLink(snode->edittree, link);
1685                         }
1686                 }
1687                 
1688                 ntreeSolveOrder(snode->edittree);
1689                 node_tree_verify_groups(snode->nodetree);
1690                 snode_notify(C, snode);
1691                 
1692                 return OPERATOR_FINISHED;
1693         }
1694         
1695         return OPERATOR_CANCELLED|OPERATOR_PASS_THROUGH;
1696 }
1697
1698 void NODE_OT_links_cut(wmOperatorType *ot)
1699 {
1700         PropertyRNA *prop;
1701         
1702         ot->name= "Cut links";
1703         ot->idname= "NODE_OT_links_cut";
1704         
1705         ot->invoke= WM_gesture_lines_invoke;
1706         ot->modal= WM_gesture_lines_modal;
1707         ot->exec= cut_links_exec;
1708         
1709         ot->poll= ED_operator_node_active;
1710         
1711         /* flags */
1712         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1713         
1714         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
1715         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
1716         /* internal */
1717         RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
1718 }
1719
1720 /* ******************************** */
1721 // XXX some code needing updating to operators...
1722
1723 /* goes over all scenes, reads render layers */
1724 static int node_read_renderlayers_exec(bContext *C, wmOperator *op)
1725 {
1726         SpaceNode *snode= CTX_wm_space_node(C);
1727         Scene *curscene= CTX_data_scene(C), *scene;
1728         bNode *node;
1729
1730         /* first tag scenes unread */
1731         for(scene= G.main->scene.first; scene; scene= scene->id.next) 
1732                 scene->id.flag |= LIB_DOIT;
1733
1734         for(node= snode->edittree->nodes.first; node; node= node->next) {
1735                 if(node->type==CMP_NODE_R_LAYERS) {
1736                         ID *id= node->id;
1737                         if(id->flag & LIB_DOIT) {
1738                                 RE_ReadRenderResult(curscene, (Scene *)id);
1739                                 ntreeCompositTagRender((Scene *)id);
1740                                 id->flag &= ~LIB_DOIT;
1741                         }
1742                 }
1743         }
1744         
1745         snode_notify(C, snode);
1746         return OPERATOR_FINISHED;
1747 }
1748
1749 void NODE_OT_read_renderlayers(wmOperatorType *ot)
1750 {
1751         
1752         ot->name= "Read Render Layers";
1753         ot->idname= "NODE_OT_read_renderlayers";
1754         
1755         ot->exec= node_read_renderlayers_exec;
1756         
1757         ot->poll= ED_operator_node_active;
1758         
1759         /* flags */
1760         ot->flag= 0;
1761 }
1762
1763 static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *op)
1764 {
1765         SpaceNode *snode= CTX_wm_space_node(C);
1766         Scene *curscene= CTX_data_scene(C);
1767         Render *re= RE_NewRender(curscene->id.name);
1768
1769 //      WM_cursor_wait(1);
1770
1771         RE_MergeFullSample(re, curscene, snode->nodetree);
1772         snode_notify(C, snode);
1773         
1774 //      WM_cursor_wait(0);
1775         return OPERATOR_FINISHED;
1776 }
1777
1778
1779 void NODE_OT_read_fullsamplelayers(wmOperatorType *ot)
1780 {
1781         
1782         ot->name= "Read Full Sample Layers";
1783         ot->idname= "NODE_OT_read_fullsamplelayers";
1784         
1785         ot->exec= node_read_fullsamplelayers_exec;
1786         
1787         ot->poll= ED_operator_node_active;
1788         
1789         /* flags */
1790         ot->flag= 0;
1791 }
1792
1793
1794 /* ************************* */
1795
1796 void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser)
1797 {
1798         bNode *node;
1799         
1800         if(ntree==NULL)
1801                 return;
1802         
1803         /* search for renderresults */
1804         if(image->type==IMA_TYPE_R_RESULT) {
1805                 for(node= ntree->nodes.first; node; node= node->next) {
1806                         if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
1807                                 /* imageuser comes from ImageWin, so indexes are offset 1 */
1808                                 if(node->custom1==iuser->layer-1)
1809                                         NodeTagChanged(ntree, node);
1810                         }
1811                 }
1812         }
1813         else {
1814                 for(node= ntree->nodes.first; node; node= node->next) {
1815                         if(node->id== &image->id)
1816                                 NodeTagChanged(ntree, node);
1817                 }
1818         }
1819 }
1820
1821 /* ****************** Make Group operator ******************* */
1822
1823 static int node_group_make_exec(bContext *C, wmOperator *op)
1824 {
1825         SpaceNode *snode = CTX_wm_space_node(C);
1826         bNode *gnode;
1827         
1828         if(snode->edittree!=snode->nodetree) {
1829                 BKE_report(op->reports, RPT_ERROR, "Can not add a new Group in a Group");
1830                 return OPERATOR_CANCELLED;
1831         }
1832         
1833         /* for time being... is too complex to handle */
1834         if(snode->treetype==NTREE_COMPOSIT) {
1835                 for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
1836                         if(gnode->flag & SELECT)
1837                                 if(gnode->type==CMP_NODE_R_LAYERS)
1838                                         break;
1839                 }
1840                 
1841                 if(gnode) {
1842                         BKE_report(op->reports, RPT_ERROR, "Can not add RenderLayer in a Group");
1843                         return OPERATOR_CANCELLED;
1844                 }
1845         }
1846         
1847         gnode= nodeMakeGroupFromSelected(snode->nodetree);
1848         if(gnode==NULL) {
1849                 BKE_report(op->reports, RPT_ERROR, "Can not make Group");
1850                 return OPERATOR_CANCELLED;
1851         }
1852         else {
1853                 nodeSetActive(snode->nodetree, gnode);
1854                 ntreeSolveOrder(snode->nodetree);
1855         }
1856         
1857         snode_notify(C, snode);
1858         
1859         return OPERATOR_FINISHED;
1860 }
1861
1862 void NODE_OT_group_make(wmOperatorType *ot)
1863 {
1864         /* identifiers */
1865         ot->name = "Group";
1866         ot->description = "Make group from selected nodes";
1867         ot->idname = "NODE_OT_group_make";
1868         
1869         /* api callbacks */
1870         ot->exec = node_group_make_exec;
1871         ot->poll = ED_operator_node_active;
1872         
1873         /* flags */
1874         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1875 }
1876
1877 /* ****************** Hide operator *********************** */
1878
1879 static int node_hide_exec(bContext *C, wmOperator *op)
1880 {
1881         SpaceNode *snode= CTX_wm_space_node(C);
1882         bNode *node;
1883         int nothidden=0, ishidden=0;
1884         
1885         /* sanity checking (poll callback checks this already) */
1886         if((snode == NULL) || (snode->edittree == NULL))
1887                 return OPERATOR_CANCELLED;
1888         
1889         for(node= snode->edittree->nodes.first; node; node= node->next) {
1890                 if(node->flag & SELECT) {
1891                         if(node->flag & NODE_HIDDEN)
1892                                 ishidden++;
1893                         else
1894                                 nothidden++;
1895                 }
1896         }
1897         for(node= snode->edittree->nodes.first; node; node= node->next) {
1898                 if(node->flag & SELECT) {
1899                         if( (ishidden && nothidden) || ishidden==0)
1900                                 node->flag |= NODE_HIDDEN;
1901                         else 
1902                                 node->flag &= ~NODE_HIDDEN;
1903                 }
1904         }
1905         
1906         snode_notify(C, snode);
1907         
1908         return OPERATOR_FINISHED;
1909 }
1910
1911 void NODE_OT_hide(wmOperatorType *ot)
1912 {
1913         /* identifiers */
1914         ot->name= "Hide";
1915         ot->description= "Toggle hiding of the nodes";
1916         ot->idname= "NODE_OT_hide";
1917         
1918         /* callbacks */
1919         ot->exec= node_hide_exec;
1920         ot->poll= ED_operator_node_active;
1921         
1922         /* flags */
1923         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1924 }
1925
1926 /* ****************** Mute operator *********************** */
1927
1928 static int node_mute_exec(bContext *C, wmOperator *op)
1929 {
1930         SpaceNode *snode= CTX_wm_space_node(C);
1931         bNode *node;
1932
1933         /* no disabling inside of groups */
1934         if(node_tree_get_editgroup(snode->nodetree))
1935                 return OPERATOR_CANCELLED;
1936         
1937         for(node= snode->edittree->nodes.first; node; node= node->next) {
1938                 if(node->flag & SELECT) {
1939                         if(node->inputs.first && node->outputs.first) {
1940                                 node->flag ^= NODE_MUTED;
1941                                 NodeTagChanged(snode->edittree, node);
1942                         }
1943                 }
1944         }
1945         
1946         snode_notify(C, snode);
1947         
1948         return OPERATOR_FINISHED;
1949 }
1950
1951 void NODE_OT_mute(wmOperatorType *ot)
1952 {
1953         /* identifiers */
1954         ot->name= "Mute";
1955         ot->description= "Toggle muting of the nodes";
1956         ot->idname= "NODE_OT_mute";
1957         
1958         /* callbacks */
1959         ot->exec= node_mute_exec;
1960         ot->poll= ED_operator_node_active;
1961         
1962         /* flags */
1963         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1964 }
1965
1966 /* ****************** Delete operator ******************* */
1967
1968 static int node_delete_exec(bContext *C, wmOperator *op)
1969 {
1970         SpaceNode *snode= CTX_wm_space_node(C);
1971         bNode *node, *next;
1972         
1973         for(node= snode->edittree->nodes.first; node; node= next) {
1974                 next= node->next;
1975                 if(node->flag & SELECT) {
1976                         /* check id user here, nodeFreeNode is called for free dbase too */
1977                         if(node->id)
1978                                 node->id->us--;
1979                         nodeFreeNode(snode->edittree, node);
1980                 }
1981         }
1982         
1983         node_tree_verify_groups(snode->nodetree);
1984
1985         snode_notify(C, snode);
1986         
1987         return OPERATOR_FINISHED;
1988 }
1989
1990 void NODE_OT_delete(wmOperatorType *ot)
1991 {
1992         /* identifiers */
1993         ot->name= "Delete";
1994         ot->description = "Delete selected nodes";
1995         ot->idname= "NODE_OT_delete";
1996         
1997         /* api callbacks */
1998         ot->exec= node_delete_exec;
1999         ot->poll= ED_operator_node_active;
2000         
2001         /* flags */
2002         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2003 }
2004
2005 /* ****************** Show Cyclic Dependencies Operator  ******************* */
2006
2007 static int node_show_cycles_exec(bContext *C, wmOperator *op)
2008 {
2009         SpaceNode *snode= CTX_wm_space_node(C);
2010         
2011         /* this is just a wrapper around this call... */
2012         ntreeSolveOrder(snode->edittree);
2013         snode_notify(C, snode);
2014         
2015         return OPERATOR_FINISHED;
2016 }
2017
2018 void NODE_OT_show_cyclic_dependencies(wmOperatorType *ot)
2019 {
2020         /* identifiers */
2021         ot->name= "Show Cyclic Dependencies";
2022         ot->description= "Sort the nodes and show the cyclic dependencies between the nodes";
2023         ot->idname= "NODE_OT_show_cyclic_dependencies";
2024         
2025         /* callbacks */
2026         ot->exec= node_show_cycles_exec;
2027         ot->poll= ED_operator_node_active;
2028         
2029         /* flags */
2030         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2031 }
2032
2033 /* ****************** Add File Node Operator  ******************* */
2034
2035 static int node_add_file_exec(bContext *C, wmOperator *op)
2036 {
2037         Scene *scene= CTX_data_scene(C);
2038         SpaceNode *snode= CTX_wm_space_node(C);
2039         bNode *node;
2040         Image *ima= NULL;
2041         int ntype=0;
2042
2043         /* check input variables */
2044         if (RNA_property_is_set(op->ptr, "path"))
2045         {
2046                 char path[FILE_MAX];
2047                 RNA_string_get(op->ptr, "path", path);
2048                 ima= BKE_add_image_file(path, scene ? scene->r.cfra : 1);
2049         }
2050         else if(RNA_property_is_set(op->ptr, "name"))
2051         {
2052                 char name[32];
2053                 RNA_string_get(op->ptr, "name", name);
2054                 ima= (Image *)find_id("IM", name);
2055         }
2056         
2057         if(!ima) {
2058                 BKE_report(op->reports, RPT_ERROR, "Not an Image.");
2059                 return OPERATOR_CANCELLED;
2060         }
2061         
2062         
2063         node_deselectall(snode);
2064         
2065         if (snode->nodetree->type==NTREE_COMPOSIT)
2066                 ntype = CMP_NODE_IMAGE;
2067         
2068         node = node_add_node(snode, scene, ntype, snode->mx, snode->my);
2069         
2070         if (!node) {
2071                 BKE_report(op->reports, RPT_ERROR, "Could not add an image node.");
2072                 return OPERATOR_CANCELLED;
2073         }
2074         
2075         node->id = (ID *)ima;
2076         
2077         snode_notify(C, snode);
2078         
2079         return OPERATOR_FINISHED;
2080 }
2081
2082 static int node_add_file_invoke(bContext *C, wmOperator *op, wmEvent *event)
2083 {
2084         ARegion *ar= CTX_wm_region(C);
2085         SpaceNode *snode= CTX_wm_space_node(C);
2086         
2087         /* convert mouse coordinates to v2d space */
2088         UI_view2d_region_to_view(&ar->v2d, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin, 
2089                                                          &snode->mx, &snode->my);
2090         
2091         if (RNA_property_is_set(op->ptr, "path") || RNA_property_is_set(op->ptr, "name"))
2092                 return node_add_file_exec(C, op);
2093         else
2094                 return WM_operator_filesel(C, op, event);
2095 }
2096
2097 void NODE_OT_add_file(wmOperatorType *ot)
2098 {
2099         /* identifiers */
2100         ot->name= "Add File Node";
2101         ot->description= "Add a file node to the current node editor";
2102         ot->idname= "NODE_OT_add_file";
2103         
2104         /* callbacks */
2105         ot->exec= node_add_file_exec;
2106         ot->invoke= node_add_file_invoke;
2107         ot->poll= ED_operator_node_active;
2108         
2109         /* flags */
2110         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2111         
2112         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE, FILE_SPECIAL, FILE_OPENFILE);
2113         RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign.");
2114 }
2115