~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to source/blender/src/editnode.c

  • Committer: Bazaar Package Importer
  • Author(s): Lukas Fittl
  • Date: 2006-09-20 01:57:27 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060920015727-gmoqlxwstx9wwqs3
Tags: 2.42a-1ubuntu1
* Merge from Debian unstable (Closes: Malone #55903). Remaining changes:
  - debian/genpot: Add python scripts from Lee June <blender@eyou.com> to
    generate a reasonable PO template from the sources. Since gettext is used
    in a highly nonstandard way, xgettext does not work for this job.
  - debian/rules: Call the scripts, generate po/blender.pot, and clean it up
    in the clean target.
  - Add a proper header to the generated PO template.
* debian/control: Build depend on libavformat-dev >= 3:0.cvs20060823-3.1,
  otherwise this package will FTBFS

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * $Id:
 
3
 *
 
4
 * ***** BEGIN GPL LICENSE BLOCK *****
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; either version 2
 
9
 * of the License, or (at your option) any later version. 
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software Foundation,
 
18
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
19
 *
 
20
 * The Original Code is Copyright (C) 2005 Blender Foundation.
 
21
 * All rights reserved.
 
22
 *
 
23
 * The Original Code is: all of this file.
 
24
 *
 
25
 * Contributor(s): none yet.
 
26
 *
 
27
 * ***** END GPL LICENSE BLOCK *****
 
28
 */
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <math.h>
 
33
#include <string.h>
 
34
 
 
35
#include "MEM_guardedalloc.h"
 
36
 
 
37
#include "DNA_action_types.h"
 
38
#include "DNA_image_types.h"
 
39
#include "DNA_ipo_types.h"
 
40
#include "DNA_object_types.h"
 
41
#include "DNA_material_types.h"
 
42
#include "DNA_node_types.h"
 
43
#include "DNA_space_types.h"
 
44
#include "DNA_screen_types.h"
 
45
#include "DNA_scene_types.h"
 
46
#include "DNA_userdef_types.h"
 
47
 
 
48
#include "BKE_global.h"
 
49
#include "BKE_image.h"
 
50
#include "BKE_library.h"
 
51
#include "BKE_main.h"
 
52
#include "BKE_node.h"
 
53
#include "BKE_material.h"
 
54
#include "BKE_scene.h"
 
55
#include "BKE_utildefines.h"
 
56
 
 
57
#include "BIF_editview.h"
 
58
#include "BIF_gl.h"
 
59
#include "BIF_graphics.h"
 
60
#include "BIF_interface.h"
 
61
#include "BIF_mywindow.h"
 
62
#include "BIF_previewrender.h"
 
63
#include "BIF_resources.h"
 
64
#include "BIF_renderwin.h"
 
65
#include "BIF_space.h"
 
66
#include "BIF_screen.h"
 
67
#include "BIF_toolbox.h"
 
68
 
 
69
#include "BSE_drawipo.h"
 
70
#include "BSE_edit.h"
 
71
#include "BSE_filesel.h"
 
72
#include "BSE_headerbuttons.h"
 
73
#include "BSE_node.h"
 
74
 
 
75
#include "BLI_blenlib.h"
 
76
#include "BLI_arithb.h"
 
77
 
 
78
#include "BDR_editobject.h"
 
79
 
 
80
#include "RE_pipeline.h"
 
81
 
 
82
#include "blendef.h"
 
83
#include "butspace.h"
 
84
#include "PIL_time.h"
 
85
#include "mydevice.h"
 
86
 
 
87
 
 
88
/* currently called from BIF_preview_changed */
 
89
void snode_tag_dirty(SpaceNode *snode)
 
90
{
 
91
        bNode *node;
 
92
        
 
93
        if(snode->treetype==NTREE_SHADER) {
 
94
                if(snode->nodetree) {
 
95
                        for(node= snode->nodetree->nodes.first; node; node= node->next) {
 
96
                                if(node->type==SH_NODE_OUTPUT)
 
97
                                        node->lasty= 0;
 
98
                        }
 
99
                        snode->flag |= SNODE_DO_PREVIEW;        /* this adds an afterqueue on a redraw, to allow button previews to work first */
 
100
                }
 
101
        }
 
102
        allqueue(REDRAWNODE, 1);
 
103
}
 
104
 
 
105
static void shader_node_previewrender(ScrArea *sa, SpaceNode *snode)
 
106
{
 
107
        bNode *node;
 
108
        
 
109
        if(snode->id==NULL) return;
 
110
        if( ((Material *)snode->id )->use_nodes==0 ) return;
 
111
 
 
112
        for(node= snode->nodetree->nodes.first; node; node= node->next) {
 
113
                if(node->type==SH_NODE_OUTPUT) {
 
114
                        if(node->flag & NODE_DO_OUTPUT) {
 
115
                                if(node->lasty<PREVIEW_RENDERSIZE-2) {
 
116
                                        RenderInfo ri;  
 
117
//                                      int test= node->lasty;
 
118
                                        
 
119
                                        ri.curtile = 0;
 
120
                                        ri.tottile = 0;
 
121
                                        ri.rect = NULL;
 
122
                                        ri.pr_rectx = PREVIEW_RENDERSIZE;
 
123
                                        ri.pr_recty = PREVIEW_RENDERSIZE;
 
124
                                        
 
125
                                        BIF_previewrender(snode->id, &ri, NULL, PR_DO_RENDER);  /* sends redraw event */
 
126
                                        if(ri.rect) MEM_freeN(ri.rect);
 
127
                                        
 
128
                                        /* when not finished... */
 
129
                                        if(ri.curtile<ri.tottile)
 
130
                                                addafterqueue(sa->win, RENDERPREVIEW, 1);
 
131
//                                      if(test!=node->lasty)
 
132
//                                              printf("node rendered to %d\n", node->lasty);
 
133
 
 
134
                                        break;
 
135
                                }
 
136
                        }
 
137
                }
 
138
        }
 
139
}
 
140
 
 
141
 
 
142
static void snode_handle_recalc(SpaceNode *snode)
 
143
{
 
144
        if(snode->treetype==NTREE_SHADER) {
 
145
                BIF_preview_changed(ID_MA);      /* signals buttons windows and node editors */
 
146
        }
 
147
        else if(snode->treetype==NTREE_COMPOSIT) {
 
148
                if(G.scene->use_nodes) {
 
149
                        snode->nodetree->timecursor= set_timecursor;
 
150
                        G.afbreek= 0;
 
151
                        snode->nodetree->test_break= blender_test_break;
 
152
 
 
153
                        ntreeCompositExecTree(snode->nodetree, &G.scene->r, 1); /* 1 is do_previews */
 
154
                        
 
155
                        snode->nodetree->timecursor= NULL;
 
156
                        snode->nodetree->test_break= NULL;
 
157
                        waitcursor(0);
 
158
                        
 
159
                        allqueue(REDRAWNODE, 1);
 
160
                        allqueue(REDRAWIMAGE, 1);
 
161
                        if(G.scene->r.scemode & R_DOCOMP) {
 
162
                                BIF_redraw_render_rect();       /* seems to screwup display? */
 
163
                                mywinset(curarea->win);
 
164
                        }
 
165
                }
 
166
        }
 
167
}
 
168
 
 
169
static void shader_node_event(SpaceNode *snode, short event)
 
170
{
 
171
        switch(event) {
 
172
                case B_REDR:
 
173
                        allqueue(REDRAWNODE, 1);
 
174
                        break;
 
175
                default:
 
176
                        /* B_NODE_EXEC */
 
177
                        snode_handle_recalc(snode);
 
178
                        break;
 
179
                        
 
180
        }
 
181
}
 
182
 
 
183
static void load_node_image(char *str)  /* called from fileselect */
 
184
{
 
185
        SpaceNode *snode= curarea->spacedata.first;
 
186
        bNode *node= nodeGetActive(snode->edittree);
 
187
        Image *ima= NULL;
 
188
        
 
189
        ima= add_image(str);
 
190
        if(ima) {
 
191
                if(node->id)
 
192
                        node->id->us--;
 
193
                
 
194
                node->id= &ima->id;
 
195
                ima->id.us++;
 
196
 
 
197
                free_image_buffers(ima);        /* force read again */
 
198
                ima->ok= 1;
 
199
                
 
200
                NodeTagChanged(snode->edittree, node);
 
201
                snode_handle_recalc(snode);
 
202
                allqueue(REDRAWNODE, 0); 
 
203
        }
 
204
}
 
205
 
 
206
static bNode *snode_get_editgroup(SpaceNode *snode)
 
207
{
 
208
        bNode *gnode;
 
209
        
 
210
        /* get the groupnode */
 
211
        for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next)
 
212
                if(gnode->flag & NODE_GROUP_EDIT)
 
213
                        break;
 
214
        return gnode;
 
215
}
 
216
 
 
217
/* node has to be of type 'render layers' */
 
218
/* is a bit clumsy copying renderdata here... scene nodes use render size of current render */
 
219
static void composite_node_render(SpaceNode *snode, bNode *node)
 
220
{
 
221
        RenderData rd;
 
222
        Scene *scene= NULL;
 
223
        int scemode, actlay;
 
224
        
 
225
        /* the button press won't show up otherwise, button hilites disabled */
 
226
        force_draw(0);
 
227
        
 
228
        if(node->id && node->id!=(ID *)G.scene) {
 
229
                scene= G.scene;
 
230
                set_scene_bg((Scene *)node->id);
 
231
                rd= G.scene->r;
 
232
                G.scene->r.xsch= scene->r.xsch;
 
233
                G.scene->r.ysch= scene->r.ysch;
 
234
                G.scene->r.size= scene->r.size;
 
235
                G.scene->r.mode &= ~(R_BORDER|R_DOCOMP);
 
236
                G.scene->r.mode |= scene->r.mode & R_BORDER;
 
237
                G.scene->r.border= scene->r.border;
 
238
        }
 
239
        
 
240
        scemode= G.scene->r.scemode;
 
241
        actlay= G.scene->r.actlay;
 
242
        
 
243
        G.scene->r.scemode |= R_SINGLE_LAYER;
 
244
        G.scene->r.actlay= node->custom1;
 
245
        
 
246
        BIF_do_render(0);
 
247
        
 
248
        G.scene->r.scemode= scemode;
 
249
        G.scene->r.actlay= actlay;
 
250
 
 
251
        node->custom2= 0;
 
252
        
 
253
        if(scene) {
 
254
                G.scene->r= rd;
 
255
                set_scene_bg(scene);
 
256
        }
 
257
}
 
258
 
 
259
static void composit_node_event(SpaceNode *snode, short event)
 
260
{
 
261
        
 
262
        switch(event) {
 
263
                case B_REDR:
 
264
                        allqueue(REDRAWNODE, 1);
 
265
                        break;
 
266
                case B_NODE_LOADIMAGE:
 
267
                {
 
268
                        bNode *node= nodeGetActive(snode->edittree);
 
269
                        char name[FILE_MAXDIR+FILE_MAXFILE];
 
270
                        
 
271
                        if(node->id)
 
272
                                strcpy(name, ((Image *)node->id)->name);
 
273
                        else strcpy(name, U.textudir);
 
274
                        
 
275
                        activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
 
276
                        break;
 
277
                }
 
278
                case B_NODE_TREE_EXEC:
 
279
                        snode_handle_recalc(snode);
 
280
                        break;          
 
281
                default:
 
282
                        /* B_NODE_EXEC */
 
283
                {
 
284
                        bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
 
285
                        if(node) {
 
286
                                NodeTagChanged(snode->edittree, node);
 
287
                                NodeTagIDChanged(snode->nodetree, node->id);    /* Scene-layer nodes, texture nodes, image nodes, all can be used many times */
 
288
                                
 
289
                                /* not the best implementation of the world... but we need it to work now :) */
 
290
                                if(node->type==CMP_NODE_R_LAYERS && node->custom2) {
 
291
                                        composite_node_render(snode, node);
 
292
                                        /* new event, a render can go fullscreen and open new window */
 
293
                                        addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
 
294
                                }
 
295
                                else {
 
296
                                        node= snode_get_editgroup(snode);
 
297
                                        if(node)
 
298
                                                NodeTagIDChanged(snode->nodetree, node->id);
 
299
                                        
 
300
                                        snode_handle_recalc(snode);
 
301
                                }
 
302
                        }
 
303
                }                       
 
304
        }
 
305
}
 
306
 
 
307
 
 
308
/* assumes nothing being done in ntree yet, sets the default in/out node */
 
309
/* called from shading buttons or header */
 
310
void node_shader_default(Material *ma)
 
311
{
 
312
        bNode *in, *out;
 
313
        bNodeSocket *fromsock, *tosock;
 
314
        
 
315
        /* but lets check it anyway */
 
316
        if(ma->nodetree) {
 
317
                printf("error in shader initialize\n");
 
318
                return;
 
319
        }
 
320
        
 
321
        ma->nodetree= ntreeAddTree(NTREE_SHADER);
 
322
        
 
323
        out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
 
324
        out->locx= 300.0f; out->locy= 300.0f;
 
325
        
 
326
        in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
 
327
        in->locx= 10.0f; in->locy= 300.0f;
 
328
        nodeSetActive(ma->nodetree, in);
 
329
        
 
330
        /* only a link from color to color */
 
331
        fromsock= in->outputs.first;
 
332
        tosock= out->inputs.first;
 
333
        nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
 
334
        
 
335
        ntreeSolveOrder(ma->nodetree);  /* needed for pointers */
 
336
}
 
337
 
 
338
/* assumes nothing being done in ntree yet, sets the default in/out node */
 
339
/* called from shading buttons or header */
 
340
void node_composit_default(Scene *sce)
 
341
{
 
342
        bNode *in, *out;
 
343
        bNodeSocket *fromsock, *tosock;
 
344
        
 
345
        /* but lets check it anyway */
 
346
        if(sce->nodetree) {
 
347
                printf("error in composit initialize\n");
 
348
                return;
 
349
        }
 
350
        
 
351
        sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
 
352
        
 
353
        out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
 
354
        out->locx= 300.0f; out->locy= 400.0f;
 
355
        
 
356
        in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL);
 
357
        in->locx= 10.0f; in->locy= 400.0f;
 
358
        nodeSetActive(sce->nodetree, in);
 
359
        
 
360
        /* links from color to color */
 
361
        fromsock= in->outputs.first;
 
362
        tosock= out->inputs.first;
 
363
        nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
 
364
        
 
365
        ntreeSolveOrder(sce->nodetree); /* needed for pointers */
 
366
}
 
367
 
 
368
/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
 
369
void snode_set_context(SpaceNode *snode)
 
370
{
 
371
        Object *ob= OBACT;
 
372
        bNode *node= NULL;
 
373
        
 
374
        snode->nodetree= NULL;
 
375
        snode->id= snode->from= NULL;
 
376
        
 
377
        if(snode->treetype==NTREE_SHADER) {
 
378
                /* need active object, or we allow pinning... */
 
379
                if(ob) {
 
380
                        Material *ma= give_current_material(ob, ob->actcol);
 
381
                        if(ma) {
 
382
                                snode->from= material_from(ob, ob->actcol);
 
383
                                snode->id= &ma->id;
 
384
                                snode->nodetree= ma->nodetree;
 
385
                        }
 
386
                }
 
387
        }
 
388
        else if(snode->treetype==NTREE_COMPOSIT) {
 
389
                snode->from= NULL;
 
390
                snode->id= &G.scene->id;
 
391
                snode->nodetree= G.scene->nodetree;
 
392
        }
 
393
        
 
394
        /* find editable group */
 
395
        if(snode->nodetree)
 
396
                for(node= snode->nodetree->nodes.first; node; node= node->next)
 
397
                        if(node->flag & NODE_GROUP_EDIT)
 
398
                                break;
 
399
        
 
400
        if(node && node->id)
 
401
                snode->edittree= (bNodeTree *)node->id;
 
402
        else
 
403
                snode->edittree= snode->nodetree;
 
404
}
 
405
 
 
406
static void node_set_active(SpaceNode *snode, bNode *node)
 
407
{
 
408
        
 
409
        nodeSetActive(snode->edittree, node);
 
410
        
 
411
        if(node->type!=NODE_GROUP) {
 
412
                
 
413
                /* tree specific activate calls */
 
414
                if(snode->treetype==NTREE_SHADER) {
 
415
                        
 
416
                        /* when we select a material, active texture is cleared, for buttons */
 
417
                        if(node->id && GS(node->id->name)==ID_MA)
 
418
                                nodeClearActiveID(snode->edittree, ID_TE);
 
419
                        if(node->id)
 
420
                                BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
 
421
                        
 
422
                        allqueue(REDRAWBUTSSHADING, 1);
 
423
                        allqueue(REDRAWIPO, 0);
 
424
                }
 
425
                else if(snode->treetype==NTREE_COMPOSIT) {
 
426
                        /* make active viewer, currently only 1 supported... */
 
427
                        if(node->type==CMP_NODE_VIEWER) {
 
428
                                bNode *tnode;
 
429
                                int was_output= node->flag & NODE_DO_OUTPUT;
 
430
 
 
431
                                for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
 
432
                                        if(tnode->type==CMP_NODE_VIEWER)
 
433
                                                tnode->flag &= ~NODE_DO_OUTPUT;
 
434
                                
 
435
                                node->flag |= NODE_DO_OUTPUT;
 
436
                                if(was_output==0) {
 
437
                                        bNode *gnode;
 
438
                                        
 
439
                                        NodeTagChanged(snode->edittree, node);
 
440
                                        
 
441
                                        /* if inside group, tag entire group */
 
442
                                        gnode= snode_get_editgroup(snode);
 
443
                                        if(gnode)
 
444
                                                NodeTagIDChanged(snode->nodetree, gnode->id);
 
445
                                        
 
446
                                        snode_handle_recalc(snode);
 
447
                                }
 
448
                                
 
449
                                /* add node doesnt link this yet... */
 
450
                                if(node->id==NULL) {
 
451
                                        node->id= find_id("IM", "Viewer Node");
 
452
                                        if(node->id==NULL) {
 
453
                                                Image *ima= alloc_libblock(&G.main->image, ID_IM, "Viewer Node");
 
454
                                                strcpy(ima->name, "Viewer Node");
 
455
                                                ima->ok= 1;
 
456
                                                ima->xrep= ima->yrep= 1;
 
457
                                                node->id= &ima->id;
 
458
                                        }
 
459
                                        else 
 
460
                                                node->id->us++;
 
461
                                }
 
462
                        }
 
463
                }
 
464
        }
 
465
}
 
466
 
 
467
void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
 
468
{
 
469
        bNode *node;
 
470
        
 
471
        /* make sure nothing has group editing on */
 
472
        for(node= snode->nodetree->nodes.first; node; node= node->next)
 
473
                node->flag &= ~NODE_GROUP_EDIT;
 
474
        
 
475
        if(gnode==NULL) {
 
476
                /* with NULL argument we do a toggle */
 
477
                if(snode->edittree==snode->nodetree)
 
478
                        gnode= nodeGetActive(snode->nodetree);
 
479
        }
 
480
        
 
481
        if(gnode && gnode->type==NODE_GROUP && gnode->id) {
 
482
                if(gnode->id->lib) {
 
483
                        if(okee("Make Group Local"))
 
484
                                ntreeMakeLocal((bNodeTree *)gnode->id);
 
485
                        else
 
486
                                return;
 
487
                }
 
488
                gnode->flag |= NODE_GROUP_EDIT;
 
489
                snode->edittree= (bNodeTree *)gnode->id;
 
490
                
 
491
                /* deselect all other nodes, so we can also do grabbing of entire subtree */
 
492
                for(node= snode->nodetree->nodes.first; node; node= node->next)
 
493
                        node->flag &= ~SELECT;
 
494
                gnode->flag |= SELECT;
 
495
                
 
496
        }
 
497
        else 
 
498
                snode->edittree= snode->nodetree;
 
499
        
 
500
        ntreeSolveOrder(snode->nodetree);
 
501
        
 
502
        /* finally send out events for new active node */
 
503
        if(snode->treetype==NTREE_SHADER) {
 
504
                allqueue(REDRAWBUTSSHADING, 0);
 
505
                
 
506
                BIF_preview_changed(-1);        /* temp hack to force texture preview to update */
 
507
        }
 
508
        
 
509
        allqueue(REDRAWNODE, 0);
 
510
}
 
511
 
 
512
void node_ungroup(SpaceNode *snode)
 
513
{
 
514
        bNode *gnode;
 
515
 
 
516
        /* are we inside of a group? */
 
517
        gnode= snode_get_editgroup(snode);
 
518
        if(gnode)
 
519
                snode_make_group_editable(snode, NULL);
 
520
        
 
521
        gnode= nodeGetActive(snode->edittree);
 
522
        if(gnode==NULL) return;
 
523
        
 
524
        if(gnode->type!=NODE_GROUP)
 
525
                error("Not a group");
 
526
        else {
 
527
                if(nodeGroupUnGroup(snode->edittree, gnode)) {
 
528
                        
 
529
                        ntreeSolveOrder(snode->edittree);
 
530
                        BIF_undo_push("Deselect all nodes");
 
531
                        allqueue(REDRAWNODE, 0);
 
532
                }
 
533
                else
 
534
                        error("Can't ungroup");
 
535
        }
 
536
}
 
537
 
 
538
/* when links in groups change, inputs/outputs change, nodes added/deleted... */
 
539
static void snode_verify_groups(SpaceNode *snode)
 
540
{
 
541
        bNode *gnode;
 
542
        
 
543
        gnode= snode_get_editgroup(snode);
 
544
        
 
545
        /* does all materials */
 
546
        if(gnode)
 
547
                nodeVerifyGroup((bNodeTree *)gnode->id);
 
548
        
 
549
}
 
550
 
 
551
static void node_addgroup(SpaceNode *snode)
 
552
{
 
553
        bNodeTree *ngroup;
 
554
        int tot= 0, offs, val;
 
555
        char *strp;
 
556
        
 
557
        if(snode->edittree!=snode->nodetree) {
 
558
                error("Can not add a Group in a Group");
 
559
                return;
 
560
        }
 
561
        
 
562
        /* construct menu with choices */
 
563
        for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
 
564
                if(ngroup->type==snode->treetype)
 
565
                        tot++;
 
566
        }
 
567
        if(tot==0) {
 
568
                error("No groups available in database");
 
569
                return;
 
570
        }
 
571
        strp= MEM_mallocN(32*tot+32, "menu");
 
572
        strcpy(strp, "Add Group %t");
 
573
        offs= strlen(strp);
 
574
        
 
575
        for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
 
576
                if(ngroup->type==snode->treetype)
 
577
                        offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
 
578
        }       
 
579
        
 
580
        val= pupmenu(strp);
 
581
        if(val>=0) {
 
582
                ngroup= BLI_findlink(&G.main->nodetree, val);
 
583
                if(ngroup) {
 
584
                        bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
 
585
                        
 
586
                        /* generics */
 
587
                        if(node) {
 
588
                                float locx, locy;
 
589
                                short mval[2];
 
590
 
 
591
                                node_deselectall(snode, 0);
 
592
                                
 
593
                                getmouseco_areawin(mval);
 
594
                                areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
 
595
                                
 
596
                                node->locx= locx;
 
597
                                node->locy= locy + 60.0f;               // arbitrary.. so its visible
 
598
                                node->flag |= SELECT;
 
599
                                
 
600
                                id_us_plus(node->id);
 
601
                                
 
602
                                node_set_active(snode, node);
 
603
                                BIF_undo_push("Add Node");
 
604
                        }
 
605
                }                       
 
606
        }
 
607
        MEM_freeN(strp);
 
608
}
 
609
 
 
610
 
 
611
/* ************************** Node generic ************** */
 
612
 
 
613
/* allows to walk the list in order of visibility */
 
614
static bNode *next_node(bNodeTree *ntree)
 
615
{
 
616
        static bNode *current=NULL, *last= NULL;
 
617
        
 
618
        if(ntree) {
 
619
                /* set current to the first selected node */
 
620
                for(current= ntree->nodes.last; current; current= current->prev)
 
621
                        if(current->flag & NODE_SELECT)
 
622
                                break;
 
623
                
 
624
                /* set last to the first unselected node */
 
625
                for(last= ntree->nodes.last; last; last= last->prev)
 
626
                        if((last->flag & NODE_SELECT)==0)
 
627
                                break;
 
628
                
 
629
                if(current==NULL)
 
630
                        current= last;
 
631
                
 
632
                return NULL;
 
633
        }
 
634
        /* no nodes, or we are ready */
 
635
        if(current==NULL)
 
636
                return NULL;
 
637
        
 
638
        /* now we walk the list backwards, but we always return current */
 
639
        if(current->flag & NODE_SELECT) {
 
640
                bNode *node= current;
 
641
                
 
642
                /* find previous selected */
 
643
                current= current->prev;
 
644
                while(current && (current->flag & NODE_SELECT)==0)
 
645
                        current= current->prev;
 
646
                
 
647
                /* find first unselected */
 
648
                if(current==NULL)
 
649
                        current= last;
 
650
                
 
651
                return node;
 
652
        }
 
653
        else {
 
654
                bNode *node= current;
 
655
                
 
656
                /* find previous unselected */
 
657
                current= current->prev;
 
658
                while(current && (current->flag & NODE_SELECT))
 
659
                        current= current->prev;
 
660
                
 
661
                return node;
 
662
        }
 
663
        
 
664
        return NULL;
 
665
}
 
666
 
 
667
/* is rct in visible part of node? */
 
668
static bNode *visible_node(SpaceNode *snode, rctf *rct)
 
669
{
 
670
        bNode *tnode;
 
671
        
 
672
        for(next_node(snode->edittree); (tnode=next_node(NULL));) {
 
673
                if(BLI_isect_rctf(&tnode->totr, rct, NULL))
 
674
                        break;
 
675
        }
 
676
        return tnode;
 
677
}
 
678
 
 
679
void snode_home(ScrArea *sa, SpaceNode *snode)
 
680
{
 
681
        bNode *node;
 
682
        int first= 1;
 
683
        
 
684
        snode->v2d.cur.xmin= snode->v2d.cur.ymin= 0.0f;
 
685
        snode->v2d.cur.xmax= sa->winx;
 
686
        snode->v2d.cur.xmax= sa->winy;
 
687
        
 
688
        if(snode->edittree) {
 
689
                for(node= snode->edittree->nodes.first; node; node= node->next) {
 
690
                        if(first) {
 
691
                                first= 0;
 
692
                                snode->v2d.cur= node->totr;
 
693
                        }
 
694
                        else {
 
695
                                BLI_union_rctf(&snode->v2d.cur, &node->totr);
 
696
                        }
 
697
                }
 
698
        }
 
699
        snode->v2d.tot= snode->v2d.cur;
 
700
        test_view2d(G.v2d, sa->winx, sa->winy);
 
701
        
 
702
}
 
703
 
 
704
void snode_zoom_out(ScrArea *sa)
 
705
{
 
706
        float dx;
 
707
        
 
708
        dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
 
709
        G.v2d->cur.xmin-= dx;
 
710
        G.v2d->cur.xmax+= dx;
 
711
        dx= (float)(0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin));
 
712
        G.v2d->cur.ymin-= dx;
 
713
        G.v2d->cur.ymax+= dx;
 
714
        test_view2d(G.v2d, sa->winx, sa->winy);
 
715
}
 
716
 
 
717
void snode_zoom_in(ScrArea *sa)
 
718
{
 
719
        float dx;
 
720
        
 
721
        dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
 
722
        G.v2d->cur.xmin+= dx;
 
723
        G.v2d->cur.xmax-= dx;
 
724
        dx= (float)(0.1154*(G.v2d->cur.ymax-G.v2d->cur.ymin));
 
725
        G.v2d->cur.ymin+= dx;
 
726
        G.v2d->cur.ymax-= dx;
 
727
        test_view2d(G.v2d, sa->winx, sa->winy);
 
728
}
 
729
 
 
730
/* checks mouse position, and returns found node/socket */
 
731
/* type is SOCK_IN and/or SOCK_OUT */
 
732
static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
 
733
{
 
734
        bNode *node;
 
735
        bNodeSocket *sock;
 
736
        rctf rect;
 
737
        short mval[2];
 
738
        
 
739
        getmouseco_areawin(mval);
 
740
        areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
 
741
        
 
742
        rect.xmin -= NODE_SOCKSIZE+3;
 
743
        rect.ymin -= NODE_SOCKSIZE+3;
 
744
        rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
 
745
        rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
 
746
        
 
747
        /* check if we click in a socket */
 
748
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
749
                if(in_out & SOCK_IN) {
 
750
                        for(sock= node->inputs.first; sock; sock= sock->next) {
 
751
                                if(!(sock->flag & SOCK_HIDDEN)) {
 
752
                                        if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
 
753
                                                if(node == visible_node(snode, &rect)) {
 
754
                                                        *nodep= node;
 
755
                                                        *sockp= sock;
 
756
                                                        return 1;
 
757
                                                }
 
758
                                        }
 
759
                                }
 
760
                        }
 
761
                }
 
762
                if(in_out & SOCK_OUT) {
 
763
                        for(sock= node->outputs.first; sock; sock= sock->next) {
 
764
                                if(!(sock->flag & SOCK_HIDDEN)) {
 
765
                                        if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
 
766
                                                if(node == visible_node(snode, &rect)) {
 
767
                                                        *nodep= node;
 
768
                                                        *sockp= sock;
 
769
                                                        return 1;
 
770
                                                }
 
771
                                        }
 
772
                                }
 
773
                        }
 
774
                }
 
775
        }
 
776
        return 0;
 
777
}
 
778
 
 
779
/* ********************* transform ****************** */
 
780
 
 
781
/* releases on event, only intern (for extern see below) */
 
782
/* we need argument ntree to allow operations on edittree or nodetree */
 
783
static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
 
784
{
 
785
        bNode *node;
 
786
        float mxstart, mystart, mx, my, *oldlocs, *ol;
 
787
        int cont=1, tot=0, cancel=0, firsttime=1;
 
788
        short mval[2], mvalo[2];
 
789
        
 
790
        /* count total */
 
791
        for(node= ntree->nodes.first; node; node= node->next)
 
792
                if(node->flag & SELECT) tot++;
 
793
        
 
794
        if(tot==0) return;
 
795
        
 
796
        /* store oldlocs */
 
797
        ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
 
798
        for(node= ntree->nodes.first; node; node= node->next) {
 
799
                if(node->flag & SELECT) {
 
800
                        ol[0]= node->locx; ol[1]= node->locy;
 
801
                        ol+= 2;
 
802
                }
 
803
        }
 
804
        
 
805
        getmouseco_areawin(mvalo);
 
806
        areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
 
807
        
 
808
        while(cont) {
 
809
                
 
810
                getmouseco_areawin(mval);
 
811
                if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
 
812
 
 
813
                        firsttime= 0;
 
814
                        
 
815
                        areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
 
816
                        mvalo[0]= mval[0];
 
817
                        mvalo[1]= mval[1];
 
818
                        
 
819
                        for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
 
820
                                if(node->flag & SELECT) {
 
821
                                        node->locx= ol[0] + mx-mxstart;
 
822
                                        node->locy= ol[1] + my-mystart;
 
823
                                        ol+= 2;
 
824
                                }
 
825
                        }
 
826
                        
 
827
                        force_draw(0);
 
828
                }
 
829
                else
 
830
                        PIL_sleep_ms(10);
 
831
                
 
832
                while (qtest()) {
 
833
                        short val;
 
834
                        unsigned short event= extern_qread(&val);
 
835
                        
 
836
                        switch (event) {
 
837
                                case LEFTMOUSE:
 
838
                                case SPACEKEY:
 
839
                                case RETKEY:
 
840
                                        cont=0;
 
841
                                        break;
 
842
                                case ESCKEY:
 
843
                                case RIGHTMOUSE:
 
844
                                        if(val) {
 
845
                                                cancel=1;
 
846
                                                cont=0;
 
847
                                        }
 
848
                                        break;
 
849
                                default:
 
850
                                        if(val) arrows_move_cursor(event);
 
851
                                        break;
 
852
                        }
 
853
                }
 
854
                
 
855
        }
 
856
        
 
857
        if(cancel) {
 
858
                for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
 
859
                        if(node->flag & SELECT) {
 
860
                                node->locx= ol[0];
 
861
                                node->locy= ol[1];
 
862
                                ol+= 2;
 
863
                        }
 
864
                }
 
865
                
 
866
        }
 
867
        else
 
868
                BIF_undo_push(undostr);
 
869
        
 
870
        allqueue(REDRAWNODE, 1);
 
871
        MEM_freeN(oldlocs);
 
872
}
 
873
 
 
874
/* external call, also for callback */
 
875
void node_transform_ext(int mode, int unused)
 
876
{
 
877
        SpaceNode *snode= curarea->spacedata.first;
 
878
        
 
879
        transform_nodes(snode->edittree, 'g', "Move Node");
 
880
}
 
881
 
 
882
 
 
883
/* releases on event, only 1 node */
 
884
static void scale_node(SpaceNode *snode, bNode *node)
 
885
{
 
886
        float mxstart, mystart, mx, my, oldwidth;
 
887
        int cont=1, cancel=0;
 
888
        short mval[2], mvalo[2];
 
889
        
 
890
        /* store old */
 
891
        if(node->flag & NODE_HIDDEN)
 
892
                oldwidth= node->miniwidth;
 
893
        else
 
894
                oldwidth= node->width;
 
895
                
 
896
        getmouseco_areawin(mvalo);
 
897
        areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
 
898
        
 
899
        while(cont) {
 
900
                
 
901
                getmouseco_areawin(mval);
 
902
                if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
 
903
                        
 
904
                        areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
 
905
                        mvalo[0]= mval[0];
 
906
                        mvalo[1]= mval[1];
 
907
                        
 
908
                        if(node->flag & NODE_HIDDEN) {
 
909
                                node->miniwidth= oldwidth + mx-mxstart;
 
910
                                CLAMP(node->miniwidth, 0.0f, 100.0f);
 
911
                        }
 
912
                        else {
 
913
                                node->width= oldwidth + mx-mxstart;
 
914
                                CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
 
915
                        }
 
916
                        
 
917
                        force_draw(0);
 
918
                }
 
919
                else
 
920
                        PIL_sleep_ms(10);
 
921
                
 
922
                while (qtest()) {
 
923
                        short val;
 
924
                        unsigned short event= extern_qread(&val);
 
925
                        
 
926
                        switch (event) {
 
927
                                case LEFTMOUSE:
 
928
                                case SPACEKEY:
 
929
                                case RETKEY:
 
930
                                        cont=0;
 
931
                                        break;
 
932
                                case ESCKEY:
 
933
                                case RIGHTMOUSE:
 
934
                                        if(val) {
 
935
                                                cancel=1;
 
936
                                                cont=0;
 
937
                                        }
 
938
                                        break;
 
939
                        }
 
940
                }
 
941
                
 
942
        }
 
943
        
 
944
        if(cancel) {
 
945
                node->width= oldwidth;
 
946
        }
 
947
        else
 
948
                BIF_undo_push("Scale Node");
 
949
        
 
950
        allqueue(REDRAWNODE, 1);
 
951
}
 
952
 
 
953
 
 
954
 
 
955
/* ********************** select ******************** */
 
956
 
 
957
/* used in buttons to check context, also checks for edited groups */
 
958
bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
 
959
{
 
960
        bNode *node;
 
961
        
 
962
        /* check for edited group */
 
963
        for(node= ntree->nodes.first; node; node= node->next)
 
964
                if(node->flag & NODE_GROUP_EDIT)
 
965
                        break;
 
966
        if(node)
 
967
                return nodeGetActiveID((bNodeTree *)node->id, id_code);
 
968
        else
 
969
                return nodeGetActiveID(ntree, id_code);
 
970
}
 
971
 
 
972
/* used in buttons to check context, also checks for edited groups */
 
973
Material *editnode_get_active_material(Material *ma)
 
974
{
 
975
        if(ma && ma->use_nodes && ma->nodetree) {
 
976
                bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
 
977
                if(node)
 
978
                        return (Material *)node->id;
 
979
                else
 
980
                        return NULL;
 
981
        }
 
982
        return ma;
 
983
}
 
984
 
 
985
/* used in buttons to check context, also checks for edited groups */
 
986
bNode *editnode_get_active(bNodeTree *ntree)
 
987
{
 
988
        bNode *node;
 
989
        
 
990
        /* check for edited group */
 
991
        for(node= ntree->nodes.first; node; node= node->next)
 
992
                if(node->flag & NODE_GROUP_EDIT)
 
993
                        break;
 
994
        if(node)
 
995
                return nodeGetActive((bNodeTree *)node->id);
 
996
        else
 
997
                return nodeGetActive(ntree);
 
998
}
 
999
 
 
1000
 
 
1001
/* no undo here! */
 
1002
void node_deselectall(SpaceNode *snode, int swap)
 
1003
{
 
1004
        bNode *node;
 
1005
        
 
1006
        if(swap) {
 
1007
                for(node= snode->edittree->nodes.first; node; node= node->next)
 
1008
                        if(node->flag & SELECT)
 
1009
                                break;
 
1010
                if(node==NULL) {
 
1011
                        for(node= snode->edittree->nodes.first; node; node= node->next)
 
1012
                                node->flag |= SELECT;
 
1013
                        allqueue(REDRAWNODE, 0);
 
1014
                        return;
 
1015
                }
 
1016
                /* else pass on to deselect */
 
1017
        }
 
1018
        
 
1019
        for(node= snode->edittree->nodes.first; node; node= node->next)
 
1020
                node->flag &= ~SELECT;
 
1021
        
 
1022
        allqueue(REDRAWNODE, 0);
 
1023
}
 
1024
 
 
1025
int node_has_hidden_sockets(bNode *node)
 
1026
{
 
1027
        bNodeSocket *sock;
 
1028
        
 
1029
        for(sock= node->inputs.first; sock; sock= sock->next)
 
1030
                if(sock->flag & SOCK_HIDDEN)
 
1031
                        return 1;
 
1032
        for(sock= node->outputs.first; sock; sock= sock->next)
 
1033
                if(sock->flag & SOCK_HIDDEN)
 
1034
                        return 1;
 
1035
        return 0;
 
1036
}
 
1037
 
 
1038
 
 
1039
static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
 
1040
{
 
1041
        bNodeSocket *sock;
 
1042
        
 
1043
        /* unhide all */
 
1044
        if( node_has_hidden_sockets(node) ) {
 
1045
                for(sock= node->inputs.first; sock; sock= sock->next)
 
1046
                        sock->flag &= ~SOCK_HIDDEN;
 
1047
                for(sock= node->outputs.first; sock; sock= sock->next)
 
1048
                        sock->flag &= ~SOCK_HIDDEN;
 
1049
        }
 
1050
        else {
 
1051
                bNode *gnode= snode_get_editgroup(snode);
 
1052
                
 
1053
                /* hiding inside group should not break links in other group users */
 
1054
                if(gnode) {
 
1055
                        nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
 
1056
                        for(sock= node->inputs.first; sock; sock= sock->next)
 
1057
                                if(!(sock->flag & SOCK_IN_USE))
 
1058
                                        if(sock->link==NULL)
 
1059
                                                sock->flag |= SOCK_HIDDEN;
 
1060
                        for(sock= node->outputs.first; sock; sock= sock->next)
 
1061
                                if(!(sock->flag & SOCK_IN_USE))
 
1062
                                        if(nodeCountSocketLinks(snode->edittree, sock)==0)
 
1063
                                                sock->flag |= SOCK_HIDDEN;
 
1064
                }
 
1065
                else {
 
1066
                        /* hide unused sockets */
 
1067
                        for(sock= node->inputs.first; sock; sock= sock->next) {
 
1068
                                if(sock->link==NULL)
 
1069
                                        sock->flag |= SOCK_HIDDEN;
 
1070
                        }
 
1071
                        for(sock= node->outputs.first; sock; sock= sock->next) {
 
1072
                                if(nodeCountSocketLinks(snode->edittree, sock)==0)
 
1073
                                        sock->flag |= SOCK_HIDDEN;
 
1074
                        }
 
1075
                }
 
1076
        }
 
1077
 
 
1078
        allqueue(REDRAWNODE, 1);
 
1079
        snode_verify_groups(snode);
 
1080
        BIF_undo_push("Hide/Unhide sockets");
 
1081
 
 
1082
}
 
1083
 
 
1084
static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
 
1085
{
 
1086
        rctf totr= node->totr;
 
1087
        
 
1088
        totr.ymin= totr.ymax-20.0f;
 
1089
        
 
1090
        totr.xmax= totr.xmin+15.0f;
 
1091
        if(BLI_in_rctf(&totr, mx, my)) {
 
1092
                node->flag |= NODE_HIDDEN;
 
1093
                allqueue(REDRAWNODE, 0);
 
1094
                return 1;
 
1095
        }       
 
1096
        
 
1097
        totr.xmax= node->totr.xmax;
 
1098
        totr.xmin= totr.xmax-18.0f;
 
1099
        if(node->typeinfo->flag & NODE_PREVIEW) {
 
1100
                if(BLI_in_rctf(&totr, mx, my)) {
 
1101
                        node->flag ^= NODE_PREVIEW;
 
1102
                        allqueue(REDRAWNODE, 0);
 
1103
                        return 1;
 
1104
                }
 
1105
                totr.xmin-=18.0f;
 
1106
        }
 
1107
        if(node->type == NODE_GROUP) {
 
1108
                if(BLI_in_rctf(&totr, mx, my)) {
 
1109
                        snode_make_group_editable(snode, node);
 
1110
                        return 1;
 
1111
                }
 
1112
                totr.xmin-=18.0f;
 
1113
        }
 
1114
        if(node->typeinfo->flag & NODE_OPTIONS) {
 
1115
                if(BLI_in_rctf(&totr, mx, my)) {
 
1116
                        node->flag ^= NODE_OPTIONS;
 
1117
                        allqueue(REDRAWNODE, 0);
 
1118
                        return 1;
 
1119
                }
 
1120
                totr.xmin-=18.0f;
 
1121
        }
 
1122
        /* hide unused sockets */
 
1123
        if(BLI_in_rctf(&totr, mx, my)) {
 
1124
                node_hide_unhide_sockets(snode, node);
 
1125
        }
 
1126
        
 
1127
        
 
1128
        totr= node->totr;
 
1129
        totr.xmin= totr.xmax-10.0f;
 
1130
        totr.ymax= totr.ymin+10.0f;
 
1131
        if(BLI_in_rctf(&totr, mx, my)) {
 
1132
                scale_node(snode, node);
 
1133
                return 1;
 
1134
        }
 
1135
        return 0;
 
1136
}
 
1137
 
 
1138
static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
 
1139
{
 
1140
        rctf totr= node->totr;
 
1141
        
 
1142
        totr.xmax= totr.xmin+15.0f;
 
1143
        if(BLI_in_rctf(&totr, mx, my)) {
 
1144
                node->flag &= ~NODE_HIDDEN;
 
1145
                allqueue(REDRAWNODE, 0);
 
1146
                return 1;
 
1147
        }       
 
1148
        
 
1149
        totr.xmax= node->totr.xmax;
 
1150
        totr.xmin= node->totr.xmax-15.0f;
 
1151
        if(BLI_in_rctf(&totr, mx, my)) {
 
1152
                scale_node(snode, node);
 
1153
                return 1;
 
1154
        }
 
1155
        return 0;
 
1156
}
 
1157
 
 
1158
 
 
1159
/* return 0: nothing done */
 
1160
static int node_mouse_select(SpaceNode *snode, unsigned short event)
 
1161
{
 
1162
        bNode *node;
 
1163
        float mx, my;
 
1164
        short mval[2];
 
1165
        
 
1166
        getmouseco_areawin(mval);
 
1167
        areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
 
1168
        
 
1169
        for(next_node(snode->edittree); (node=next_node(NULL));) {
 
1170
                
 
1171
                /* first check for the headers or scaling widget */
 
1172
                if(node->flag & NODE_HIDDEN) {
 
1173
                        if(do_header_hidden_node(snode, node, mx, my))
 
1174
                                return 1;
 
1175
                }
 
1176
                else {
 
1177
                        if(do_header_node(snode, node, mx, my))
 
1178
                                return 1;
 
1179
                }
 
1180
                
 
1181
                /* node body */
 
1182
                if(BLI_in_rctf(&node->totr, mx, my))
 
1183
                        break;
 
1184
        }
 
1185
        if(node) {
 
1186
                if((G.qual & LR_SHIFTKEY)==0)
 
1187
                        node_deselectall(snode, 0);
 
1188
                
 
1189
                if(G.qual & LR_SHIFTKEY) {
 
1190
                        if(node->flag & SELECT)
 
1191
                                node->flag &= ~SELECT;
 
1192
                        else
 
1193
                                node->flag |= SELECT;
 
1194
                }
 
1195
                else 
 
1196
                        node->flag |= SELECT;
 
1197
                
 
1198
                node_set_active(snode, node);
 
1199
                
 
1200
                /* not so nice (no event), but function below delays redraw otherwise */
 
1201
                force_draw(0);
 
1202
                
 
1203
                std_rmouse_transform(node_transform_ext);       /* does undo push for select */
 
1204
                
 
1205
                return 1;
 
1206
        }
 
1207
        return 0;
 
1208
}
 
1209
 
 
1210
/* return 0, nothing done */
 
1211
static int node_mouse_groupheader(SpaceNode *snode)
 
1212
{
 
1213
        bNode *gnode;
 
1214
        float mx, my;
 
1215
        short mval[2];
 
1216
        
 
1217
        gnode= snode_get_editgroup(snode);
 
1218
        if(gnode==NULL) return 0;
 
1219
        
 
1220
        getmouseco_areawin(mval);
 
1221
        areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
 
1222
        
 
1223
        /* click in header or outside? */
 
1224
        if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
 
1225
                rctf rect= gnode->totr;
 
1226
                
 
1227
                rect.ymax += NODE_DY;
 
1228
                if(BLI_in_rctf(&rect, mx, my)==0)
 
1229
                        snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
 
1230
                else
 
1231
                        transform_nodes(snode->nodetree, 'g', "Move group");
 
1232
                
 
1233
                return 1;
 
1234
        }
 
1235
        return 0;
 
1236
}
 
1237
 
 
1238
static int node_socket_hilights(SpaceNode *snode, int in_out)
 
1239
{
 
1240
        bNode *node;
 
1241
        bNodeSocket *sock, *tsock, *socksel= NULL;
 
1242
        float mx, my;
 
1243
        short mval[2], redraw= 0;
 
1244
        
 
1245
        if(snode->edittree==NULL) return 0;
 
1246
        
 
1247
        getmouseco_areawin(mval);
 
1248
        areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
 
1249
        
 
1250
        /* deselect socks */
 
1251
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1252
                for(sock= node->inputs.first; sock; sock= sock->next) {
 
1253
                        if(sock->flag & SELECT) {
 
1254
                                sock->flag &= ~SELECT;
 
1255
                                redraw++;
 
1256
                                socksel= sock;
 
1257
                        }
 
1258
                }
 
1259
                for(sock= node->outputs.first; sock; sock= sock->next) {
 
1260
                        if(sock->flag & SELECT) {
 
1261
                                sock->flag &= ~SELECT;
 
1262
                                redraw++;
 
1263
                                socksel= sock;
 
1264
                        }
 
1265
                }
 
1266
        }
 
1267
        
 
1268
        if(find_indicated_socket(snode, &node, &tsock, in_out)) {
 
1269
                tsock->flag |= SELECT;
 
1270
                if(redraw==1 && tsock==socksel) redraw= 0;
 
1271
                else redraw= 1;
 
1272
        }
 
1273
        
 
1274
        return redraw;
 
1275
}
 
1276
 
 
1277
void node_border_select(SpaceNode *snode)
 
1278
{
 
1279
        bNode *node;
 
1280
        rcti rect;
 
1281
        rctf rectf;
 
1282
        short val, mval[2];
 
1283
        
 
1284
        if ( (val = get_border(&rect, 3)) ) {
 
1285
                
 
1286
                mval[0]= rect.xmin;
 
1287
                mval[1]= rect.ymin;
 
1288
                areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
 
1289
                mval[0]= rect.xmax;
 
1290
                mval[1]= rect.ymax;
 
1291
                areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
 
1292
                
 
1293
                for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1294
                        if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
 
1295
                                if(val==LEFTMOUSE)
 
1296
                                        node->flag |= SELECT;
 
1297
                                else
 
1298
                                        node->flag &= ~SELECT;
 
1299
                        }
 
1300
                }
 
1301
                allqueue(REDRAWNODE, 1);
 
1302
                BIF_undo_push("Border select nodes");
 
1303
        }               
 
1304
}
 
1305
 
 
1306
/* ****************** Add *********************** */
 
1307
 
 
1308
/* can be called from menus too, but they should do own undopush and redraws */
 
1309
bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
 
1310
{
 
1311
        bNode *node= NULL, *gnode;
 
1312
        
 
1313
        node_deselectall(snode, 0);
 
1314
        
 
1315
        if(type>=NODE_GROUP_MENU) {
 
1316
                if(snode->edittree!=snode->nodetree) {
 
1317
                        error("Can not add a Group in a Group");
 
1318
                        return NULL;
 
1319
                }
 
1320
                else {
 
1321
                        bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
 
1322
                        if(ngroup)
 
1323
                                node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
 
1324
                }
 
1325
        }
 
1326
        else
 
1327
                node= nodeAddNodeType(snode->edittree, type, NULL);
 
1328
        
 
1329
        /* generics */
 
1330
        if(node) {
 
1331
                node->locx= locx;
 
1332
                node->locy= locy + 60.0f;               // arbitrary.. so its visible
 
1333
                node->flag |= SELECT;
 
1334
                
 
1335
                gnode= snode_get_editgroup(snode);
 
1336
                if(gnode) {
 
1337
                        node->locx -= gnode->locx;
 
1338
                        node->locy -= gnode->locy;
 
1339
                }
 
1340
 
 
1341
                snode_verify_groups(snode);
 
1342
                node_set_active(snode, node);
 
1343
                
 
1344
                if(node->id)
 
1345
                        id_us_plus(node->id);
 
1346
        }
 
1347
        return node;
 
1348
}
 
1349
 
 
1350
void node_adduplicate(SpaceNode *snode)
 
1351
{
 
1352
        
 
1353
        ntreeCopyTree(snode->edittree, 1);      /* 1 == internally selected nodes */
 
1354
        
 
1355
        ntreeSolveOrder(snode->edittree);
 
1356
        snode_verify_groups(snode);
 
1357
        snode_handle_recalc(snode);
 
1358
 
 
1359
        transform_nodes(snode->edittree, 'g', "Duplicate");
 
1360
}
 
1361
 
 
1362
static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
 
1363
{
 
1364
        bNode *newnode= NULL;
 
1365
        
 
1366
        if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
 
1367
                if(snode->edittree->type==NTREE_SHADER)
 
1368
                        newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
 
1369
                else if(snode->edittree->type==NTREE_COMPOSIT)
 
1370
                        newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
 
1371
                else
 
1372
                        newnode= NULL;
 
1373
        }
 
1374
        else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
 
1375
                if(snode->edittree->type==NTREE_SHADER)
 
1376
                        newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
 
1377
                else if(snode->edittree->type==NTREE_COMPOSIT)
 
1378
                        newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
 
1379
                else
 
1380
                        newnode= NULL;
 
1381
        }
 
1382
        
 
1383
        if(newnode) {
 
1384
                /* dangerous assumption to use first in/out socks, but thats fine for now */
 
1385
                newnode->flag |= NODE_HIDDEN;
 
1386
                newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
 
1387
                newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
 
1388
                
 
1389
                nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
 
1390
                link->tonode= newnode;
 
1391
                link->tosock= newnode->inputs.first;
 
1392
        }
 
1393
}
 
1394
 
 
1395
 
 
1396
/* loop that adds a nodelink, called by function below  */
 
1397
/* in_out = starting socket */
 
1398
static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
 
1399
{
 
1400
        bNode *tnode;
 
1401
        bNodeSocket *tsock;
 
1402
        bNodeLink *link= NULL;
 
1403
        short mval[2], mvalo[2], firsttime=1;   /* firsttime reconnects a link broken by caller */
 
1404
        
 
1405
        /* we make a temporal link */
 
1406
        if(in_out==SOCK_OUT)
 
1407
                link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
 
1408
        else
 
1409
                link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
 
1410
        
 
1411
        getmouseco_areawin(mvalo);
 
1412
        while (get_mbut() & L_MOUSE) {
 
1413
                
 
1414
                getmouseco_areawin(mval);
 
1415
                if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
 
1416
                        firsttime= 0;
 
1417
                        
 
1418
                        mvalo[0]= mval[0];
 
1419
                        mvalo[1]= mval[1];
 
1420
                        
 
1421
                        if(in_out==SOCK_OUT) {
 
1422
                                if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
 
1423
                                        if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
 
1424
                                                if(tnode!=node  && link->tonode!=tnode && link->tosock!= tsock) {
 
1425
                                                        link->tonode= tnode;
 
1426
                                                        link->tosock= tsock;
 
1427
                                                        ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
 
1428
                                                }
 
1429
                                        }
 
1430
                                }
 
1431
                                else {
 
1432
                                        link->tonode= NULL;
 
1433
                                        link->tosock= NULL;
 
1434
                                }
 
1435
                        }
 
1436
                        else {
 
1437
                                if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
 
1438
                                        if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
 
1439
                                                if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
 
1440
                                                        if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
 
1441
                                                                link->fromnode= tnode;
 
1442
                                                                link->fromsock= tsock;
 
1443
                                                                ntreeSolveOrder(snode->edittree);       /* for interactive red line warning */
 
1444
                                                        }
 
1445
                                                }
 
1446
                                        }
 
1447
                                }
 
1448
                                else {
 
1449
                                        link->fromnode= NULL;
 
1450
                                        link->fromsock= NULL;
 
1451
                                }
 
1452
                        }
 
1453
                        /* hilight target sockets only */
 
1454
                        node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
 
1455
                        
 
1456
                        force_draw(0);
 
1457
                }
 
1458
                else BIF_wait_for_statechange();                
 
1459
        }
 
1460
        
 
1461
        /* remove link? */
 
1462
        if(link->tonode==NULL || link->fromnode==NULL) {
 
1463
                nodeRemLink(snode->edittree, link);
 
1464
        }
 
1465
        else {
 
1466
                bNodeLink *tlink;
 
1467
 
 
1468
                /* send changed events for original tonode and new */
 
1469
                if(link->tonode) 
 
1470
                        NodeTagChanged(snode->edittree, link->tonode);
 
1471
                
 
1472
                /* we might need to remove a link */
 
1473
                if(in_out==SOCK_OUT) {
 
1474
                        if(nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
 
1475
                                
 
1476
                                for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
 
1477
                                        if(link!=tlink && tlink->tosock==link->tosock)
 
1478
                                                break;
 
1479
                                }
 
1480
                                if(tlink) {
 
1481
                                        /* is there a free input socket with same type? */
 
1482
                                        for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) {
 
1483
                                                if(tsock->type==tlink->fromsock->type)
 
1484
                                                        if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit)
 
1485
                                                                break;
 
1486
                                        }
 
1487
                                        if(tsock)
 
1488
                                                tlink->tosock= tsock;
 
1489
                                        else {
 
1490
                                                nodeRemLink(snode->edittree, tlink);
 
1491
                                        }
 
1492
                                }                                       
 
1493
                        }
 
1494
                }
 
1495
                
 
1496
                /* and last trick: insert a convertor when types dont match */
 
1497
                if(snode->treetype==NTREE_SHADER) {
 
1498
                        if(link->tosock->type!=link->fromsock->type) {
 
1499
                                node_insert_convertor(snode, link);
 
1500
                                /* so nice do it twice! well, the sort-order can only handle 1 added link at a time */
 
1501
                                ntreeSolveOrder(snode->edittree);
 
1502
                        }
 
1503
                }
 
1504
        }
 
1505
        
 
1506
        ntreeSolveOrder(snode->edittree);
 
1507
        snode_verify_groups(snode);
 
1508
        snode_handle_recalc(snode);
 
1509
        
 
1510
        allqueue(REDRAWNODE, 0);
 
1511
        BIF_undo_push("Add link");
 
1512
 
 
1513
        return 1;
 
1514
}
 
1515
 
 
1516
/* return 1 when socket clicked */
 
1517
static int node_add_link(SpaceNode *snode)
 
1518
{
 
1519
        bNode *node;
 
1520
        bNodeLink *link;
 
1521
        bNodeSocket *sock;
 
1522
        
 
1523
        /* output indicated? */
 
1524
        if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
 
1525
                if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
 
1526
                        return node_add_link_drag(snode, node, sock, SOCK_OUT);
 
1527
                else {
 
1528
                        /* find if we break a link */
 
1529
                        for(link= snode->edittree->links.first; link; link= link->next) {
 
1530
                                if(link->fromsock==sock)
 
1531
                                        break;
 
1532
                        }
 
1533
                        if(link) {
 
1534
                                node= link->tonode;
 
1535
                                sock= link->tosock;
 
1536
                                nodeRemLink(snode->edittree, link);
 
1537
                                return node_add_link_drag(snode, node, sock, SOCK_IN);
 
1538
                        }
 
1539
                }
 
1540
        }
 
1541
        /* or an input? */
 
1542
        else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
 
1543
                if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
 
1544
                        return node_add_link_drag(snode, node, sock, SOCK_IN);
 
1545
                else {
 
1546
                        /* find if we break a link */
 
1547
                        for(link= snode->edittree->links.first; link; link= link->next) {
 
1548
                                if(link->tosock==sock)
 
1549
                                        break;
 
1550
                        }
 
1551
                        if(link) {
 
1552
                                /* send changed event to original tonode */
 
1553
                                if(link->tonode) 
 
1554
                                        NodeTagChanged(snode->edittree, link->tonode);
 
1555
                                
 
1556
                                node= link->fromnode;
 
1557
                                sock= link->fromsock;
 
1558
                                nodeRemLink(snode->edittree, link);
 
1559
                                return node_add_link_drag(snode, node, sock, SOCK_OUT);
 
1560
                        }
 
1561
                }
 
1562
        }
 
1563
        
 
1564
        return 0;
 
1565
}
 
1566
 
 
1567
void node_delete(SpaceNode *snode)
 
1568
{
 
1569
        bNode *node, *next;
 
1570
        
 
1571
        for(node= snode->edittree->nodes.first; node; node= next) {
 
1572
                next= node->next;
 
1573
                if(node->flag & SELECT)
 
1574
                        nodeFreeNode(snode->edittree, node);
 
1575
        }
 
1576
        
 
1577
        snode_verify_groups(snode);
 
1578
        snode_handle_recalc(snode);
 
1579
        BIF_undo_push("Delete nodes");
 
1580
        allqueue(REDRAWNODE, 1);
 
1581
}
 
1582
 
 
1583
void node_hide(SpaceNode *snode)
 
1584
{
 
1585
        bNode *node;
 
1586
        int nothidden=0, ishidden=0;
 
1587
        
 
1588
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1589
                if(node->flag & SELECT) {
 
1590
                        if(node->flag & NODE_HIDDEN)
 
1591
                                ishidden++;
 
1592
                        else
 
1593
                                nothidden++;
 
1594
                }
 
1595
        }
 
1596
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1597
                if(node->flag & SELECT) {
 
1598
                        if( (ishidden && nothidden) || ishidden==0)
 
1599
                                node->flag |= NODE_HIDDEN;
 
1600
                        else 
 
1601
                                node->flag &= ~NODE_HIDDEN;
 
1602
                }
 
1603
        }
 
1604
        BIF_undo_push("Hide nodes");
 
1605
        allqueue(REDRAWNODE, 1);
 
1606
}
 
1607
                        
 
1608
 
 
1609
static void node_border_link_delete(SpaceNode *snode)
 
1610
{
 
1611
        rcti rect;
 
1612
        short val, mval[2], mvalo[2];
 
1613
 
 
1614
        /* to make this work more friendly, we first wait for a mouse move */
 
1615
        getmouseco_areawin(mvalo);
 
1616
        while (get_mbut() & L_MOUSE) {
 
1617
                getmouseco_areawin(mval);
 
1618
                if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
 
1619
                        break;
 
1620
                else BIF_wait_for_statechange();
 
1621
        }
 
1622
        if((get_mbut() & L_MOUSE)==0)
 
1623
                return;
 
1624
        
 
1625
        /* now change cursor and draw border */
 
1626
        setcursor_space(SPACE_NODE, CURSOR_VPAINT);
 
1627
        
 
1628
        if ( (val = get_border(&rect, 2)) ) {
 
1629
                if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
 
1630
                        //#define NODE_MAXPICKBUF       256
 
1631
                        bNodeLink *link, *next;
 
1632
                        GLuint buffer[256];
 
1633
                        rctf rectf;
 
1634
                        int code=0, hits;
 
1635
                        
 
1636
                        mval[0]= rect.xmin;
 
1637
                        mval[1]= rect.ymin;
 
1638
                        areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
 
1639
                        mval[0]= rect.xmax;
 
1640
                        mval[1]= rect.ymax;
 
1641
                        areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
 
1642
                        
 
1643
                        myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
 
1644
                        
 
1645
                        glSelectBuffer(256, buffer); 
 
1646
                        glRenderMode(GL_SELECT);
 
1647
                        glInitNames();
 
1648
                        glPushName(-1);
 
1649
                        
 
1650
                        /* draw links */
 
1651
                        for(link= snode->edittree->links.first; link; link= link->next) {
 
1652
                                glLoadName(code++);
 
1653
                                node_draw_link(snode, link);
 
1654
                        }
 
1655
                        
 
1656
                        hits= glRenderMode(GL_RENDER);
 
1657
                        glPopName();
 
1658
                        if(hits>0) {
 
1659
                                int a;
 
1660
                                for(a=0; a<hits; a++) {
 
1661
                                        bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
 
1662
                                        if(link)
 
1663
                                                link->fromnode= NULL;   /* first tag for delete, otherwise indices are wrong */
 
1664
                                }
 
1665
                                for(link= snode->edittree->links.first; link; link= next) {
 
1666
                                        next= link->next;
 
1667
                                        if(link->fromnode==NULL) {
 
1668
                                                NodeTagChanged(snode->edittree, link->tonode);
 
1669
                                                nodeRemLink(snode->edittree, link);
 
1670
                                        }
 
1671
                                }
 
1672
                                ntreeSolveOrder(snode->edittree);
 
1673
                                snode_verify_groups(snode);
 
1674
                                snode_handle_recalc(snode);
 
1675
                        }
 
1676
                        allqueue(REDRAWNODE, 0);
 
1677
                        BIF_undo_push("Erase links");
 
1678
                }
 
1679
        }
 
1680
        
 
1681
        setcursor_space(SPACE_NODE, CURSOR_STD);
 
1682
}
 
1683
 
 
1684
/* goes over all scenes, reads render layerss */
 
1685
void node_read_renderlayers(SpaceNode *snode)
 
1686
{
 
1687
        Scene *scene;
 
1688
        bNode *node;
 
1689
 
 
1690
        /* first tag scenes unread */
 
1691
        for(scene= G.main->scene.first; scene; scene= scene->id.next) 
 
1692
                scene->id.flag |= LIB_DOIT;
 
1693
 
 
1694
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1695
                if(node->type==CMP_NODE_R_LAYERS) {
 
1696
                        ID *id= node->id;
 
1697
                        if(id==NULL) id= (ID *)G.scene;
 
1698
                        if(id->flag & LIB_DOIT) {
 
1699
                                RE_ReadRenderResult(G.scene, (Scene *)id);
 
1700
                                id->flag &= ~LIB_DOIT;
 
1701
                        }
 
1702
                }
 
1703
        }
 
1704
        
 
1705
        ntreeCompositTagRender(snode->edittree);
 
1706
        snode_handle_recalc(snode);
 
1707
}
 
1708
 
 
1709
 
 
1710
/* ********************** */
 
1711
 
 
1712
void node_make_group(SpaceNode *snode)
 
1713
{
 
1714
        bNode *gnode;
 
1715
        
 
1716
        if(snode->edittree!=snode->nodetree) {
 
1717
                error("Can not add a new Group in a Group");
 
1718
                return;
 
1719
        }
 
1720
        
 
1721
        /* for time being... is too complex to handle */
 
1722
        if(snode->treetype==NTREE_COMPOSIT) {
 
1723
                for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
 
1724
                        if(gnode->flag & SELECT)
 
1725
                                if(gnode->type==CMP_NODE_R_LAYERS)
 
1726
                                        break;
 
1727
                }
 
1728
                if(gnode) {
 
1729
                        error("Can not add RenderLayer in a Group");
 
1730
                        return;
 
1731
                }
 
1732
        }
 
1733
        
 
1734
        gnode= nodeMakeGroupFromSelected(snode->nodetree);
 
1735
        if(gnode==NULL) {
 
1736
                error("Can not make Group");
 
1737
        }
 
1738
        else {
 
1739
                nodeSetActive(snode->nodetree, gnode);
 
1740
                ntreeSolveOrder(snode->nodetree);
 
1741
                allqueue(REDRAWNODE, 0);
 
1742
                BIF_undo_push("Make Node Group");
 
1743
        }
 
1744
}
 
1745
 
 
1746
/* ******************** main event loop ****************** */
 
1747
 
 
1748
/* special version to prevent overlapping buttons, has a bit of hack... */
 
1749
/* yes, check for example composit_node_event(), file window use... */
 
1750
static int node_uiDoBlocks(ScrArea *sa, short event)
 
1751
{
 
1752
        SpaceNode *snode= sa->spacedata.first;
 
1753
        ListBase *lb= &sa->uiblocks;
 
1754
        ListBase listb= *lb;
 
1755
        bNode *node;
 
1756
        rctf rect;
 
1757
        void *prev, *next;
 
1758
        int retval= UI_NOTHING;
 
1759
        short mval[2];
 
1760
        
 
1761
        getmouseco_areawin(mval);
 
1762
        areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
 
1763
 
 
1764
        /* this happens after filesel usage... */
 
1765
        if(lb->first==NULL) {
 
1766
                return UI_NOTHING;
 
1767
        }
 
1768
        
 
1769
        rect.xmin -= 2.0f;
 
1770
        rect.ymin -= 2.0f;
 
1771
        rect.xmax = rect.xmin + 4.0f;
 
1772
        rect.ymax = rect.ymin + 4.0f;
 
1773
        
 
1774
        for(node= snode->edittree->nodes.first; node; node= node->next) {
 
1775
                uiBlock *block;
 
1776
                char str[32];
 
1777
                
 
1778
                /* retreive unique block name, see also drawnode.c */
 
1779
                sprintf(str, "node buttons %p", node);
 
1780
                block= uiGetBlock(str, sa);
 
1781
                
 
1782
                if(block) {
 
1783
                        if(node == visible_node(snode, &rect)) {
 
1784
 
 
1785
                                /* when there's menus, the prev pointer becomes zero! */
 
1786
                                prev= ((struct Link *)block)->prev;
 
1787
                                next= ((struct Link *)block)->next;
 
1788
                                ((struct Link *)block)->prev= NULL;
 
1789
                                ((struct Link *)block)->next= NULL;
 
1790
                                
 
1791
                                lb->first= lb->last= block;
 
1792
                                retval= uiDoBlocks(lb, event);
 
1793
                                
 
1794
                                ((struct Link *)block)->prev= prev;
 
1795
                                ((struct Link *)block)->next= next;
 
1796
 
 
1797
                                break;
 
1798
                        }
 
1799
                }
 
1800
        }
 
1801
        
 
1802
        *lb= listb;
 
1803
        
 
1804
        return retval;
 
1805
}
 
1806
 
 
1807
void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
 
1808
{
 
1809
        SpaceNode *snode= spacedata;
 
1810
        unsigned short event= evt->event;
 
1811
        short val= evt->val, doredraw=0, fromlib= 0;
 
1812
        
 
1813
        if(sa->win==0) return;
 
1814
        if(snode->nodetree==NULL) return;
 
1815
        
 
1816
        if(val) {
 
1817
 
 
1818
                if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;  
 
1819
 
 
1820
                fromlib= (snode->id && snode->id->lib);
 
1821
                
 
1822
                switch(event) {
 
1823
                case LEFTMOUSE:
 
1824
                        if(fromlib) {
 
1825
                                if(node_mouse_groupheader(snode)==0)
 
1826
                                        node_mouse_select(snode, event);
 
1827
                        }
 
1828
                        else {
 
1829
                                if(node_add_link(snode)==0)
 
1830
                                        if(node_mouse_groupheader(snode)==0)
 
1831
                                                if(node_mouse_select(snode, event)==0)
 
1832
                                                        node_border_link_delete(snode);
 
1833
                        }
 
1834
                        break;
 
1835
                        
 
1836
                case RIGHTMOUSE: 
 
1837
                        node_mouse_select(snode, event);
 
1838
 
 
1839
                        break;
 
1840
                case MIDDLEMOUSE:
 
1841
                case WHEELUPMOUSE:
 
1842
                case WHEELDOWNMOUSE:
 
1843
                        view2dmove(event);      /* in drawipo.c */
 
1844
                        break;
 
1845
                        
 
1846
                case MOUSEY:
 
1847
                        doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
 
1848
                        break;
 
1849
                
 
1850
                case UI_BUT_EVENT:
 
1851
                        /* future: handlerize this! */
 
1852
                        if(snode->treetype==NTREE_SHADER)
 
1853
                                shader_node_event(snode, val);
 
1854
                        else if(snode->treetype==NTREE_COMPOSIT)
 
1855
                                composit_node_event(snode, val);
 
1856
                        break;
 
1857
                        
 
1858
                case RENDERPREVIEW:
 
1859
                        if(snode->treetype==NTREE_SHADER)
 
1860
                                shader_node_previewrender(sa, snode);
 
1861
                        break;
 
1862
                        
 
1863
                case PADPLUSKEY:
 
1864
                        snode_zoom_in(sa);
 
1865
                        doredraw= 1;
 
1866
                        break;
 
1867
                case PADMINUS:
 
1868
                        snode_zoom_out(sa);
 
1869
                        doredraw= 1;
 
1870
                        break;
 
1871
                case HOMEKEY:
 
1872
                        snode_home(sa, snode);
 
1873
                        doredraw= 1;
 
1874
                        break;
 
1875
                case TABKEY:
 
1876
                        if(fromlib) fromlib= -1;
 
1877
                        else snode_make_group_editable(snode, NULL);
 
1878
                        break;
 
1879
                        
 
1880
                case AKEY:
 
1881
                        if(G.qual==LR_SHIFTKEY) {
 
1882
                                if(fromlib) fromlib= -1;
 
1883
                                else toolbox_n_add();
 
1884
                        }
 
1885
                        else if(G.qual==0) {
 
1886
                                node_deselectall(snode, 1);
 
1887
                                BIF_undo_push("Deselect all nodes");
 
1888
                        }
 
1889
                        break;
 
1890
                case BKEY:
 
1891
                        if(G.qual==0)
 
1892
                                node_border_select(snode);
 
1893
                        break;
 
1894
                case CKEY:      /* sort again, showing cyclics */
 
1895
                        ntreeSolveOrder(snode->edittree);
 
1896
                        doredraw= 1;
 
1897
                        break;
 
1898
                case DKEY:
 
1899
                        if(G.qual==LR_SHIFTKEY) {
 
1900
                                if(fromlib) fromlib= -1;
 
1901
                                else node_adduplicate(snode);
 
1902
                        }
 
1903
                        break;
 
1904
                case GKEY:
 
1905
                        if(fromlib) fromlib= -1;
 
1906
                        else {
 
1907
                                if(G.qual==LR_CTRLKEY) {
 
1908
                                        if(okee("Make Group"))
 
1909
                                                node_make_group(snode);
 
1910
                                }
 
1911
                                else if(G.qual==LR_ALTKEY) {
 
1912
                                        if(okee("Ungroup"))
 
1913
                                                node_ungroup(snode);
 
1914
                                }
 
1915
                                else if(G.qual==LR_SHIFTKEY) {
 
1916
                                        node_addgroup(snode);
 
1917
                                }
 
1918
                                else
 
1919
                                        transform_nodes(snode->edittree, 'g', "Move Node");
 
1920
                        }
 
1921
                        break;
 
1922
                case HKEY:
 
1923
                        node_hide(snode);
 
1924
                        break;
 
1925
                case RKEY:
 
1926
                        if(okee("Read saved Render Layers"))
 
1927
                                node_read_renderlayers(snode);
 
1928
                        break;
 
1929
                case DELKEY:
 
1930
                case XKEY:
 
1931
                        if(fromlib) fromlib= -1;
 
1932
                        else node_delete(snode);
 
1933
                        break;
 
1934
                }
 
1935
        }
 
1936
 
 
1937
        if(fromlib==-1)
 
1938
                error("Cannot edit Library Data");
 
1939
        if(doredraw)
 
1940
                scrarea_queue_winredraw(sa);
 
1941
        if(doredraw==2)
 
1942
                scrarea_queue_headredraw(sa);
 
1943
}
 
1944
 
 
1945