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