A number of improvements for the file output node(s).
[blender.git] / source / blender / editors / space_node / drawnode.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): David Millan Escriva, Juho Vepsäläinen, Bob Holcomb, Thomas Dinges
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_node/drawnode.c
29  *  \ingroup spnode
30  */
31
32
33 #include <math.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_node_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_space_types.h"
46 #include "DNA_screen_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_curve.h"
50 #include "BKE_global.h"
51 #include "BKE_image.h"
52 #include "BKE_library.h"
53 #include "BKE_main.h"
54 #include "BKE_node.h"
55
56 #include "NOD_composite.h"
57 #include "NOD_shader.h"
58
59 #include "BIF_gl.h"
60 #include "BIF_glutil.h"
61
62 #include "BLF_api.h"
63
64 #include "MEM_guardedalloc.h"
65
66
67 #include "RNA_access.h"
68
69 #include "ED_node.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76
77 #include "IMB_imbuf.h"
78 #include "IMB_imbuf_types.h"
79
80 #include "node_intern.h"
81
82
83 // XXX interface.h
84 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
85
86 /* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */
87
88 static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v)
89 {
90         SpaceNode *snode= snode_v;
91         
92         if(snode->treetype==NTREE_SHADER) {
93                 nodeShaderSynchronizeID(node_v, 1);
94                 // allqueue(REDRAWBUTSSHADING, 0);
95         }
96 }
97
98 static void node_socket_button_label(const bContext *UNUSED(C), uiBlock *block,
99                                                           bNodeTree *UNUSED(ntree), bNode *UNUSED(node), bNodeSocket *sock,
100                                                           const char *UNUSED(name), int x, int y, int width)
101 {
102         uiDefBut(block, LABEL, 0, sock->name, x, y, width, NODE_DY, NULL, 0, 0, 0, 0, "");
103 }
104
105 /* draw function for file output node sockets.
106  * XXX a bit ugly use atm, called from datatype button functions,
107  * since all node types and callbacks only use data type without struct_type.
108  */
109 static void node_socket_button_output_file(const bContext *C, uiBlock *block,
110                                            bNodeTree *ntree, bNode *node, bNodeSocket *sock,
111                                            const char *UNUSED(name), int x, int y, int width)
112 {
113         uiLayout *layout, *row;
114         PointerRNA nodeptr, sockptr, imfptr;
115         int imtype;
116         int rx, ry;
117         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
118         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &sockptr);
119         
120         layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y+NODE_DY, width, 20, UI_GetStyle());
121         row = uiLayoutRow(layout, 0);           
122         
123         uiItemL(row, sock->name, 0);
124         
125         imfptr = RNA_pointer_get(&nodeptr, "format");
126         imtype = RNA_enum_get(&imfptr, "file_format");
127         /* in multilayer format all socket format details are ignored */
128         if (imtype != R_IMF_IMTYPE_MULTILAYER) {
129                 PropertyRNA *imtype_prop;
130                 const char *imtype_name;
131                 
132                 if (!RNA_boolean_get(&sockptr, "use_node_format"))
133                         imfptr = RNA_pointer_get(&sockptr, "format");
134                 
135                 imtype_prop = RNA_struct_find_property(&imfptr, "file_format");
136                 RNA_property_enum_name((bContext*)C, &imfptr, imtype_prop, RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name);
137                 uiBlockSetEmboss(block, UI_EMBOSSP);
138                 uiItemL(row, imtype_name, 0);
139                 uiBlockSetEmboss(block, UI_EMBOSSN);
140         }
141         
142         uiBlockLayoutResolve(block, &rx, &ry);
143 }
144
145 static void node_socket_button_default(const bContext *C, uiBlock *block,
146                                                                 bNodeTree *ntree, bNode *node, bNodeSocket *sock,
147                                                                 const char *name, int x, int y, int width)
148 {
149         switch (sock->struct_type) {
150         case SOCK_STRUCT_NONE: {
151                 if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
152                         node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
153                 else {
154                         PointerRNA ptr;
155                         uiBut *bt;
156                         
157                         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
158                         
159                         bt = uiDefButR(block, NUM, B_NODE_EXEC, name,
160                                                    x, y+1, width, NODE_DY-2, 
161                                                    &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
162                         if (node)
163                                 uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
164                 }
165                 break;
166         }
167         case SOCK_STRUCT_OUTPUT_FILE:
168                 node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width);
169                 break;
170         }
171 }
172
173 typedef struct SocketComponentMenuArgs {
174         PointerRNA ptr;
175         int x, y, width;
176         uiButHandleFunc cb;
177         void *arg1, *arg2;
178 } SocketComponentMenuArgs;
179 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
180 static uiBlock *socket_component_menu(bContext *C, ARegion *ar, void *args_v)
181 {
182         SocketComponentMenuArgs *args= (SocketComponentMenuArgs*)args_v;
183         uiBlock *block;
184         uiLayout *layout;
185         
186         block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
187         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
188         
189         layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, NODE_DY, UI_GetStyle()), 0);
190         
191         uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NONE);
192         
193         return block;
194 }
195 static void node_socket_button_components(const bContext *C, uiBlock *block,
196                                                                    bNodeTree *ntree, bNode *node, bNodeSocket *sock,
197                                                                    const char *name, int x, int y, int width)
198 {
199         switch (sock->struct_type) {
200         case SOCK_STRUCT_NONE: {
201                 if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
202                         node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
203                 else {
204                         PointerRNA ptr;
205                         SocketComponentMenuArgs *args;
206                         
207                         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
208                         
209                         args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs");
210                         
211                         args->ptr = ptr;
212                         args->x = x;
213                         args->y = y;
214                         args->width = width;
215                         args->cb = node_sync_cb;
216                         args->arg1 = CTX_wm_space_node(C);
217                         args->arg2 = node;
218                         
219                         uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, "");
220                 }
221                 break;
222         }
223         case SOCK_STRUCT_OUTPUT_FILE:
224                 node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width);
225                 break;
226         }
227 }
228
229 static void node_socket_button_color(const bContext *C, uiBlock *block,
230                                                           bNodeTree *ntree, bNode *node, bNodeSocket *sock,
231                                                           const char *name, int x, int y, int width)
232 {
233         /* XXX would be nicer to have draw function based on sock->struct_type as well,
234          * but currently socket types are completely identified by data type only.
235          */
236         
237         switch (sock->struct_type) {
238         case SOCK_STRUCT_NONE: {
239                 if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
240                         node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
241                 else {
242                         PointerRNA ptr;
243                         uiBut *bt;
244                         int labelw= width - 40;
245                         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
246                         
247                         bt=uiDefButR(block, COL, B_NODE_EXEC, "",
248                                                  x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, 
249                                                  &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
250                         if (node)
251                                 uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
252                         
253                         if (name[0]!='\0' && labelw>0)
254                                 uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, "");
255                 }
256                 break;
257         }
258         case SOCK_STRUCT_OUTPUT_FILE:
259                 node_socket_button_output_file(C, block, ntree, node, sock, name, x, y, width);
260                 break;
261         }
262 }
263
264 /* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */
265
266 #if 0 /* UNUSED */
267 static void node_draw_socket_new(bNodeSocket *sock, float size)
268 {
269         float x=sock->locx, y=sock->locy;
270         
271         /* 16 values of sin function */
272         static float si[16] = {
273                 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
274                 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
275                 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
276                 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
277         };
278         /* 16 values of cos function */
279         static float co[16] ={
280                 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
281                 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
282                 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
283                 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
284         };
285         int a;
286         
287         glColor3ub(180, 180, 180);
288         
289         glBegin(GL_POLYGON);
290         for(a=0; a<16; a++)
291                 glVertex2f(x+size*si[a], y+size*co[a]);
292         glEnd();
293         
294         glColor4ub(0, 0, 0, 150);
295         glEnable(GL_BLEND);
296         glEnable( GL_LINE_SMOOTH );
297         glBegin(GL_LINE_LOOP);
298         for(a=0; a<16; a++)
299                 glVertex2f(x+size*si[a], y+size*co[a]);
300         glEnd();
301         glDisable( GL_LINE_SMOOTH );
302         glDisable(GL_BLEND);
303 }
304 #endif
305
306 /* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
307
308 static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
309 {
310         PointerRNA sockptr;
311         PropertyRNA *prop;
312         
313         /* first socket stores value */
314         prop = RNA_struct_find_property(ptr, "outputs");
315         RNA_property_collection_lookup_int(ptr, prop, 0, &sockptr);
316         
317         uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
318 }
319
320 static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
321 {
322         uiLayout *col;
323         PointerRNA sockptr;
324         PropertyRNA *prop;
325         
326         /* first socket stores value */
327         prop = RNA_struct_find_property(ptr, "outputs");
328         RNA_property_collection_lookup_int(ptr, prop, 0, &sockptr);
329         
330         col = uiLayoutColumn(layout, 0);
331         uiTemplateColorWheel(col, &sockptr, "default_value", 1, 0, 0, 0);
332         uiItemR(col, &sockptr, "default_value", 0, "", ICON_NONE);
333 }
334
335 static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
336 {       
337         uiLayout *row;
338
339         bNodeTree *ntree= (bNodeTree*)ptr->id.data;
340
341         row= uiLayoutRow(layout, 1);
342         uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
343         if(ntree->type == NTREE_COMPOSIT)
344                 uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA);
345 }
346
347 static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
348 {
349         uiLayout *row;
350 #if 0
351         /* XXX no context access here .. */
352         bNode *node= ptr->data;
353         CurveMapping *cumap= node->storage;
354         
355         if(cumap) {
356                 cumap->flag |= CUMA_DRAW_CFRA;
357                 if(node->custom1<node->custom2)
358                         cumap->sample[0]= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
359         }
360 #endif
361
362         uiTemplateCurveMapping(layout, ptr, "curve", 's', 0, 0);
363
364         row= uiLayoutRow(layout, 1);
365         uiItemR(row, ptr, "frame_start", 0, "Sta", ICON_NONE);
366         uiItemR(row, ptr, "frame_end", 0, "End", ICON_NONE);
367 }
368
369 static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
370 {
371         uiTemplateColorRamp(layout, ptr, "color_ramp", 0);
372 }
373
374 static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
375 {
376         uiTemplateCurveMapping(layout, ptr, "mapping", 'v', 0, 0);
377 }
378
379 static float *_sample_col= NULL;        // bad bad, 2.5 will do better?
380 #if 0
381 static void node_curvemap_sample(float *col)
382 {
383         _sample_col= col;
384 }
385 #endif
386
387 static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
388 {
389         bNode *node= ptr->data;
390         CurveMapping *cumap= node->storage;
391
392         if(_sample_col) {
393                 cumap->flag |= CUMA_DRAW_SAMPLE;
394                 copy_v3_v3(cumap->sample, _sample_col);
395         }
396         else 
397                 cumap->flag &= ~CUMA_DRAW_SAMPLE;
398
399         uiTemplateCurveMapping(layout, ptr, "mapping", 'c', 0, 0);
400 }
401
402 static void node_normal_cb(bContext *C, void *ntree_v, void *node_v)
403 {
404         Main *bmain = CTX_data_main(C);
405
406         ED_node_generic_update(bmain, ntree_v, node_v);
407         WM_event_add_notifier(C, NC_NODE|NA_EDITED, ntree_v);
408 }
409
410 static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
411 {
412         uiBlock *block= uiLayoutAbsoluteBlock(layout);
413         bNodeTree *ntree= ptr->id.data;
414         bNode *node= ptr->data;
415         rctf *butr= &node->butr;
416         bNodeSocket *sock= node->outputs.first;         /* first socket stores normal */
417         float *nor= ((bNodeSocketValueVector*)sock->default_value)->value;
418         uiBut *bt;
419         
420         bt= uiDefButF(block, BUT_NORMAL, B_NODE_EXEC, "", 
421                       (short)butr->xmin, (short)butr->xmin,
422                       butr->xmax-butr->xmin, butr->xmax-butr->xmin,
423                       nor, 0.0f, 1.0f, 0, 0, "");
424         uiButSetFunc(bt, node_normal_cb, ntree, node);
425 }
426 #if 0 // not used in 2.5x yet
427 static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v)
428 {
429         Main *bmain= CTX_data_main(C);
430         bNodeTree *ntree= ntree_v;
431         bNode *node= node_v;
432         Tex *tex;
433         
434         if(node->menunr<1) return;
435         
436         if(node->id) {
437                 node->id->us--;
438                 node->id= NULL;
439         }
440         tex= BLI_findlink(&bmain->tex, node->menunr-1);
441
442         node->id= &tex->id;
443         id_us_plus(node->id);
444         BLI_strncpy(node->name, node->id->name+2, sizeof(node->name));
445         
446         nodeSetActive(ntree, node);
447         
448         if( ntree->type == NTREE_TEXTURE )
449                 ntreeTexCheckCyclics( ntree );
450         
451         // allqueue(REDRAWBUTSSHADING, 0);
452         // allqueue(REDRAWNODE, 0);
453         NodeTagChanged(ntree, node); 
454         
455         node->menunr= 0;
456 }
457 #endif
458 static void node_dynamic_update_cb(bContext *C, void *UNUSED(ntree_v), void *node_v)
459 {
460         Main *bmain= CTX_data_main(C);
461         Material *ma;
462         bNode *node= (bNode *)node_v;
463         ID *id= node->id;
464         int error= 0;
465
466         if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) error= 1;
467
468         /* Users only have to press the "update" button in one pynode
469          * and we also update all others sharing the same script */
470         for (ma= bmain->mat.first; ma; ma= ma->id.next) {
471                 if (ma->nodetree) {
472                         bNode *nd;
473                         for (nd= ma->nodetree->nodes.first; nd; nd= nd->next) {
474                                 if ((nd->type == NODE_DYNAMIC) && (nd->id == id)) {
475                                         nd->custom1= 0;
476                                         nd->custom1= BSET(nd->custom1, NODE_DYNAMIC_REPARSE);
477                                         nd->menunr= 0;
478                                         if (error)
479                                                 nd->custom1= BSET(nd->custom1, NODE_DYNAMIC_ERROR);
480                                 }
481                         }
482                 }
483         }
484
485         // allqueue(REDRAWBUTSSHADING, 0);
486         // allqueue(REDRAWNODE, 0);
487         // XXX BIF_preview_changed(ID_MA);
488 }
489
490 static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
491 {
492         bNode *node= ptr->data;
493
494         short multi = (
495                 node->id &&
496                 ((Tex*)node->id)->use_nodes &&
497                 (node->type != CMP_NODE_TEXTURE) &&
498                 (node->type != TEX_NODE_TEXTURE)
499         );
500         
501         uiItemR(layout, ptr, "texture", 0, "", ICON_NONE);
502         
503         if(multi) {
504                 /* Number Drawing not optimal here, better have a list*/
505                 uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE);
506         }
507 }
508
509 static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
510
511         uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
512 }
513
514 static int node_resize_area_default(bNode *node, int x, int y)
515 {
516         if (node->flag & NODE_HIDDEN) {
517                 rctf totr= node->totr;
518                 /* right part of node */
519                 totr.xmin= node->totr.xmax-20.0f;
520                 return BLI_in_rctf(&totr, x, y);
521         }
522         else {
523                 /* rect we're interested in is just the bottom right corner */
524                 rctf totr= node->totr;
525                 /* bottom right corner */
526                 totr.xmin= totr.xmax-10.0f;
527                 totr.ymax= totr.ymin+10.0f;
528                 return BLI_in_rctf(&totr, x, y);
529         }
530 }
531
532 /* ****************** BUTTON CALLBACKS FOR COMMON NODES ***************** */
533
534 /* width of socket columns in group display */
535 #define NODE_GROUP_FRAME                120
536
537 /* based on settings in node, sets drawing rect info. each redraw! */
538 /* note: this assumes only 1 group at a time is drawn (linked data) */
539 /* in node->totr the entire boundbox for the group is stored */
540 static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode)
541 {
542         if (!(gnode->flag & NODE_GROUP_EDIT)) {
543                 node_update_default(C, ntree, gnode);
544         }
545         else {
546                 bNodeTree *ngroup= (bNodeTree *)gnode->id;
547                 bNode *node;
548                 bNodeSocket *sock, *gsock;
549                 float locx, locy;
550                 rctf *rect= &gnode->totr;
551                 float node_group_frame= U.dpi*NODE_GROUP_FRAME/72;
552                 float group_header= 26*U.dpi/72;
553                 int counter;
554                 int dy;
555                 
556                 /* get "global" coords */
557                 nodeSpaceCoords(gnode, &locx, &locy);
558                 
559                 /* center them, is a bit of abuse of locx and locy though */
560                 node_update_nodetree(C, ngroup, locx, locy);
561                 
562                 rect->xmin = rect->xmax = locx;
563                 rect->ymin = rect->ymax = locy;
564                 
565                 counter= 1;
566                 for(node= ngroup->nodes.first; node; node= node->next) {
567                         if(counter) {
568                                 *rect= node->totr;
569                                 counter= 0;
570                         }
571                         else
572                                 BLI_union_rctf(rect, &node->totr);
573                 }
574                 
575                 /* add some room for links to group sockets */
576                 rect->xmin -= 4*NODE_DY;
577                 rect->xmax += 4*NODE_DY;
578                 rect->ymin-= NODE_DY;
579                 rect->ymax+= NODE_DY;
580                 
581                 /* input sockets */
582                 dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->inputs)-1);
583                 gsock=ngroup->inputs.first;
584                 sock=gnode->inputs.first;
585                 while (gsock || sock) {
586                         while (sock && !sock->groupsock) {
587                                 sock->locx = rect->xmin - node_group_frame;
588                                 sock->locy = dy;
589
590                                 /* prevent long socket lists from growing out of the group box */
591                                 if (dy-3*NODE_DYS < rect->ymin)
592                                         rect->ymin = dy-3*NODE_DYS;
593                                 if (dy+3*NODE_DYS > rect->ymax)
594                                         rect->ymax = dy+3*NODE_DYS;
595                                 dy -= 2*NODE_DY;
596                                 
597                                 sock = sock->next;
598                         }
599                         while (gsock && (!sock || sock->groupsock!=gsock)) {
600                                 gsock->locx = rect->xmin;
601                                 gsock->locy = dy;
602                                 
603                                 /* prevent long socket lists from growing out of the group box */
604                                 if (dy-3*NODE_DYS < rect->ymin)
605                                         rect->ymin = dy-3*NODE_DYS;
606                                 if (dy+3*NODE_DYS > rect->ymax)
607                                         rect->ymax = dy+3*NODE_DYS;
608                                 dy -= 2*NODE_DY;
609                                 
610                                 gsock = gsock->next;
611                         }
612                         while (sock && gsock && sock->groupsock==gsock) {
613                                 gsock->locx = rect->xmin;
614                                 sock->locx = rect->xmin - node_group_frame;
615                                 sock->locy = gsock->locy = dy;
616                                 
617                                 /* prevent long socket lists from growing out of the group box */
618                                 if (dy-3*NODE_DYS < rect->ymin)
619                                         rect->ymin = dy-3*NODE_DYS;
620                                 if (dy+3*NODE_DYS > rect->ymax)
621                                         rect->ymax = dy+3*NODE_DYS;
622                                 dy -= 2*NODE_DY;
623                                 
624                                 sock = sock->next;
625                                 gsock = gsock->next;
626                         }
627                 }
628                 
629                 /* output sockets */
630                 dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->outputs)-1);
631                 gsock=ngroup->outputs.first;
632                 sock=gnode->outputs.first;
633                 while (gsock || sock) {
634                         while (sock && !sock->groupsock) {
635                                 sock->locx = rect->xmax + node_group_frame;
636                                 sock->locy = dy - NODE_DYS;
637                                 
638                                 /* prevent long socket lists from growing out of the group box */
639                                 if (dy-3*NODE_DYS < rect->ymin)
640                                         rect->ymin = dy-3*NODE_DYS;
641                                 if (dy+3*NODE_DYS > rect->ymax)
642                                         rect->ymax = dy+3*NODE_DYS;
643                                 dy -= 2*NODE_DY;
644                                 
645                                 sock = sock->next;
646                         }
647                         while (gsock && (!sock || sock->groupsock!=gsock)) {
648                                 gsock->locx = rect->xmax;
649                                 gsock->locy = dy - NODE_DYS;
650                                 
651                                 /* prevent long socket lists from growing out of the group box */
652                                 if (dy-3*NODE_DYS < rect->ymin)
653                                         rect->ymin = dy-3*NODE_DYS;
654                                 if (dy+3*NODE_DYS > rect->ymax)
655                                         rect->ymax = dy+3*NODE_DYS;
656                                 dy -= 2*NODE_DY;
657                                 
658                                 gsock = gsock->next;
659                         }
660                         while (sock && gsock && sock->groupsock==gsock) {
661                                 gsock->locx = rect->xmax;
662                                 sock->locx = rect->xmax + node_group_frame;
663                                 sock->locy = gsock->locy = dy - NODE_DYS;
664                                 
665                                 /* prevent long socket lists from growing out of the group box */
666                                 if (dy-3*NODE_DYS < rect->ymin)
667                                         rect->ymin = dy-3*NODE_DYS;
668                                 if (dy+3*NODE_DYS > rect->ymax)
669                                         rect->ymax = dy+3*NODE_DYS;
670                                 dy -= 2*NODE_DY;
671                                 
672                                 sock = sock->next;
673                                 gsock = gsock->next;
674                         }
675                 }
676                 
677                 /* Set the block bounds to clip mouse events from underlying nodes.
678                  * Add margin for header and input/output columns.
679                  */
680                 uiExplicitBoundsBlock(gnode->block,
681                                                           rect->xmin - node_group_frame,
682                                                           rect->ymin,
683                                                           rect->xmax + node_group_frame,
684                                                           rect->ymax + group_header);
685         }
686 }
687
688 static void update_group_input_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v)
689 {
690         bNodeTree *ngroup= (bNodeTree*)ngroup_v;
691         
692         ngroup->update |= NTREE_UPDATE_GROUP_IN;
693         ntreeUpdateTree(ngroup);
694 }
695
696 static void update_group_output_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v)
697 {
698         bNodeTree *ngroup= (bNodeTree*)ngroup_v;
699         
700         ngroup->update |= NTREE_UPDATE_GROUP_OUT;
701         ntreeUpdateTree(ngroup);
702 }
703
704 static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *sock, int in_out, float xoffset, float yoffset)
705 {
706         bNodeTree *ngroup= (bNodeTree*)gnode->id;
707         uiBut *bt;
708         
709         if (sock->flag & SOCK_DYNAMIC) {
710                 bt = uiDefBut(gnode->block, TEX, 0, "", 
711                                           sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY,
712                                           sock->name, 0, sizeof(sock->name), 0, 0, "");
713                 if (in_out==SOCK_IN)
714                         uiButSetFunc(bt, update_group_input_cb, snode, ngroup);
715                 else
716                         uiButSetFunc(bt, update_group_output_cb, snode, ngroup);
717         }
718         else {
719                 uiDefBut(gnode->block, LABEL, 0, sock->name,
720                          sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY,
721                          NULL, 0, sizeof(sock->name), 0, 0, "");
722         }
723 }
724
725 static void draw_group_socket(const bContext *C, SpaceNode *snode, bNodeTree *ntree, bNode *gnode, bNodeSocket *sock, bNodeSocket *gsock, int index, int in_out)
726 {
727         bNodeTree *ngroup= (bNodeTree*)gnode->id;
728         bNodeSocketType *stype= ntreeGetSocketType(gsock ? gsock->type : sock->type);
729         uiBut *bt;
730         float offset;
731         int draw_value;
732         float node_group_frame= U.dpi*NODE_GROUP_FRAME/72;
733         float socket_size= NODE_SOCKSIZE*U.dpi/72;
734         float arrowbutw= 0.8f*UI_UNIT_X;
735         /* layout stuff for buttons on group left frame */
736         float colw= 0.6f*node_group_frame;
737         float col1= 6 - node_group_frame;
738         float col2= col1 + colw+6;
739         float col3= - arrowbutw - 6;
740         /* layout stuff for buttons on group right frame */
741         float cor1= 6;
742         float cor2= cor1 + arrowbutw + 6;
743         float cor3= cor2 + arrowbutw + 6;
744         
745         /* node and group socket circles */
746         if (sock)
747                 node_socket_circle_draw(ntree, sock, socket_size);
748         if (gsock)
749                 node_socket_circle_draw(ngroup, gsock, socket_size);
750         
751         /* socket name */
752         offset = (in_out==SOCK_IN ? col1 : cor3);
753         if (!gsock)
754                 offset += (in_out==SOCK_IN ? node_group_frame : -node_group_frame);
755         
756         /* draw both name and value button if:
757          * 1) input: not internal
758          * 2) output: (node type uses const outputs) and (group output is unlinked)
759          */
760         draw_value = 0;
761         switch (in_out) {
762         case SOCK_IN:
763                 draw_value = !(gsock && (gsock->flag & SOCK_INTERNAL));
764                 break;
765         case SOCK_OUT:
766                 if (gnode->typeinfo->flag & NODE_CONST_OUTPUT)
767                         draw_value = !(gsock && gsock->link);
768                 break;
769         }
770         if (draw_value) {
771                 /* both name and value buttons */
772                 if (gsock) {
773                         draw_group_socket_name(snode, gnode, gsock, in_out, offset, 0);
774                         if (stype->buttonfunc)
775                                 stype->buttonfunc(C, gnode->block, ngroup, NULL, gsock, "", gsock->locx+offset, gsock->locy-NODE_DY, colw);
776                 }
777                 else {
778                         draw_group_socket_name(snode, gnode, sock, in_out, offset, 0);
779                         if (stype->buttonfunc)
780                                 stype->buttonfunc(C, gnode->block, ngroup, NULL, sock, "", sock->locx+offset, sock->locy-NODE_DY, colw);
781                 }
782         }
783         else {
784                 /* only name, no value button */
785                 if (gsock)
786                         draw_group_socket_name(snode, gnode, gsock, in_out, offset, -NODE_DYS);
787                 else
788                         draw_group_socket_name(snode, gnode, sock, in_out, offset, -NODE_DYS);
789         }
790         
791         if (gsock && (gsock->flag & SOCK_DYNAMIC)) {
792                 /* up/down buttons */
793                 offset = (in_out==SOCK_IN ? col2 : cor2);
794                 uiBlockSetDirection(gnode->block, UI_TOP);
795                 uiBlockBeginAlign(gnode->block);
796                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP,
797                                                    gsock->locx+offset, gsock->locy, arrowbutw, arrowbutw, "");
798                 if (!gsock->prev || !(gsock->prev->flag & SOCK_DYNAMIC))
799                         uiButSetFlag(bt, UI_BUT_DISABLED);
800                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
801                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out);
802                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN,
803                                                    gsock->locx+offset, gsock->locy-arrowbutw, arrowbutw, arrowbutw, "");
804                 if (!gsock->next || !(gsock->next->flag & SOCK_DYNAMIC))
805                         uiButSetFlag(bt, UI_BUT_DISABLED);
806                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
807                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out);
808                 uiBlockEndAlign(gnode->block);
809                 uiBlockSetDirection(gnode->block, 0);
810                 
811                 /* remove button */
812                 offset = (in_out==SOCK_IN ? col3 : cor1);
813                 uiBlockSetEmboss(gnode->block, UI_EMBOSSN);
814                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X,
815                                                    gsock->locx+offset, gsock->locy-0.5f*arrowbutw, arrowbutw, arrowbutw, "");
816                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
817                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", in_out);
818                 uiBlockSetEmboss(gnode->block, UI_EMBOSS);
819         }
820 }
821
822 /* groups are, on creation, centered around 0,0 */
823 static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
824 {
825         if (!(gnode->flag & NODE_GROUP_EDIT)) {
826                 node_draw_default(C, ar, snode, ntree, gnode);
827         }
828         else {
829                 bNodeTree *ngroup= (bNodeTree *)gnode->id;
830                 bNodeSocket *sock, *gsock;
831                 uiLayout *layout;
832                 PointerRNA ptr;
833                 rctf rect= gnode->totr;
834                 float node_group_frame= U.dpi*NODE_GROUP_FRAME/72;
835                 float group_header= 26*U.dpi/72;
836                 
837                 int index;
838                 
839                 /* backdrop header */
840                 glEnable(GL_BLEND);
841                 uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
842                 UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
843                 uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymax, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD);
844                 
845                 /* backdrop body */
846                 UI_ThemeColorShadeAlpha(TH_BACK, -8, -70);
847                 uiSetRoundBox(UI_CNR_NONE);
848                 uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
849         
850                 /* input column */
851                 UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
852                 uiSetRoundBox(UI_CNR_BOTTOM_LEFT);
853                 uiDrawBox(GL_POLYGON, rect.xmin-node_group_frame, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD);
854         
855                 /* output column */
856                 UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
857                 uiSetRoundBox(UI_CNR_BOTTOM_RIGHT);
858                 uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax+node_group_frame, rect.ymax, BASIS_RAD);
859         
860                 /* input column separator */
861                 glColor4ub(200, 200, 200, 140);
862                 glBegin(GL_LINES);
863                 glVertex2f(rect.xmin, rect.ymin);
864                 glVertex2f(rect.xmin, rect.ymax);
865                 glEnd();
866         
867                 /* output column separator */
868                 glColor4ub(200, 200, 200, 140);
869                 glBegin(GL_LINES);
870                 glVertex2f(rect.xmax, rect.ymin);
871                 glVertex2f(rect.xmax, rect.ymax);
872                 glEnd();
873         
874                 /* group node outline */
875                 uiSetRoundBox(UI_CNR_ALL);
876                 glColor4ub(200, 200, 200, 140);
877                 glEnable( GL_LINE_SMOOTH );
878                 uiDrawBox(GL_LINE_LOOP, rect.xmin-node_group_frame, rect.ymin, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD);
879                 glDisable( GL_LINE_SMOOTH );
880                 glDisable(GL_BLEND);
881                 
882                 /* backdrop title */
883                 UI_ThemeColor(TH_TEXT_HI);
884         
885                 layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+group_header),
886                                                            MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, UI_GetStyle());
887                 RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr);
888                 uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL);
889                 uiBlockLayoutResolve(gnode->block, NULL, NULL);
890         
891                 /* draw the internal tree nodes and links */
892                 node_draw_nodetree(C, ar, snode, ngroup);
893         
894                 /* group sockets */
895                 gsock=ngroup->inputs.first;
896                 sock=gnode->inputs.first;
897                 index = 0;
898                 while (gsock || sock) {
899                         while (sock && !sock->groupsock) {
900                                 draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_IN);
901                                 sock = sock->next;
902                         }
903                         while (gsock && (!sock || sock->groupsock!=gsock)) {
904                                 draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_IN);
905                                 gsock = gsock->next;
906                                 ++index;
907                         }
908                         while (sock && gsock && sock->groupsock==gsock) {
909                                 draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_IN);
910                                 sock = sock->next;
911                                 gsock = gsock->next;
912                                 ++index;
913                         }
914                 }
915                 gsock=ngroup->outputs.first;
916                 sock=gnode->outputs.first;
917                 index = 0;
918                 while (gsock || sock) {
919                         while (sock && !sock->groupsock) {
920                                 draw_group_socket(C, snode, ntree, gnode, sock, NULL, index, SOCK_OUT);
921                                 sock = sock->next;
922                         }
923                         while (gsock && (!sock || sock->groupsock!=gsock)) {
924                                 draw_group_socket(C, snode, ntree, gnode, NULL, gsock, index, SOCK_OUT);
925                                 gsock = gsock->next;
926                                 ++index;
927                         }
928                         while (sock && gsock && sock->groupsock==gsock) {
929                                 draw_group_socket(C, snode, ntree, gnode, sock, gsock, index, SOCK_OUT);
930                                 sock = sock->next;
931                                 gsock = gsock->next;
932                                 ++index;
933                         }
934                 }
935                 
936                 uiEndBlock(C, gnode->block);
937                 uiDrawBlock(C, gnode->block);
938                 gnode->block= NULL;
939         }
940 }
941
942 void node_uifunc_group(uiLayout *layout, bContext *C, PointerRNA *ptr)
943 {
944         uiTemplateIDBrowse(layout, C, ptr, "node_tree", NULL, NULL, NULL);
945 }
946
947 static void node_common_buts_whileloop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
948 {
949         uiItemR(layout, ptr, "max_iterations", 0, NULL, 0);
950 }
951
952 static void node_update_frame(const bContext *UNUSED(C), bNodeTree *UNUSED(ntree), bNode *node)
953 {
954         float locx, locy;
955
956         /* get "global" coords */
957         nodeSpaceCoords(node, &locx, &locy);
958
959         node->prvr.xmin= locx + NODE_DYS;
960         node->prvr.xmax= locx + node->width- NODE_DYS;
961
962         node->totr.xmin= locx;
963         node->totr.xmax= locx + node->width;
964         node->totr.ymax= locy;
965         node->totr.ymin= locy - node->height;
966 }
967
968 static void node_common_set_butfunc(bNodeType *ntype)
969 {
970         switch(ntype->type) {
971                 case NODE_GROUP:
972                         ntype->uifunc= node_uifunc_group;
973                         ntype->drawfunc= node_draw_group;
974                         ntype->drawupdatefunc= node_update_group;
975                         break;
976                 case NODE_FORLOOP:
977 //                      ntype->uifunc= node_common_buts_group;
978                         ntype->drawfunc= node_draw_group;
979                         ntype->drawupdatefunc= node_update_group;
980                         break;
981                 case NODE_WHILELOOP:
982                         ntype->uifunc= node_common_buts_whileloop;
983                         ntype->drawfunc= node_draw_group;
984                         ntype->drawupdatefunc= node_update_group;
985                         break;
986                 case NODE_FRAME:
987                         ntype->drawupdatefunc= node_update_frame;
988                         break;
989         }
990 }
991
992 /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
993
994 static void node_browse_text_cb(bContext *C, void *ntree_v, void *node_v)
995 {
996         Main *bmain= CTX_data_main(C);
997         bNodeTree *ntree= ntree_v;
998         bNode *node= node_v;
999         /* ID *oldid; */ /* UNUSED */
1000         
1001         if(node->menunr<1) return;
1002         
1003         if(node->id) {
1004                 node->id->us--;
1005         }
1006         /* oldid= node->id; */ /* UNUSED */
1007         node->id= BLI_findlink(&bmain->text, node->menunr-1);
1008         id_us_plus(node->id);
1009         BLI_strncpy(node->name, node->id->name+2, sizeof(node->name));
1010
1011         node->custom1= BSET(node->custom1, NODE_DYNAMIC_NEW);
1012         
1013         nodeSetActive(ntree, node);
1014
1015         // allqueue(REDRAWBUTSSHADING, 0);
1016         // allqueue(REDRAWNODE, 0);
1017
1018         node->menunr= 0;
1019 }
1020
1021 static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr)
1022 {
1023         bNode *node= ptr->data;
1024         uiLayout *col;
1025         
1026         uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL);
1027         
1028         if(!node->id) return;
1029         
1030         col= uiLayoutColumn(layout, 0);
1031         uiItemR(col, ptr, "use_diffuse", 0, NULL, ICON_NONE);
1032         uiItemR(col, ptr, "use_specular", 0, NULL, ICON_NONE);
1033         uiItemR(col, ptr, "invert_normal", 0, NULL, ICON_NONE);
1034 }
1035
1036 static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1037 {
1038         uiLayout *row;
1039         
1040         uiItemL(layout, "Location:", ICON_NONE);
1041         row= uiLayoutRow(layout, 1);
1042         uiItemR(row, ptr, "location", 0, "", ICON_NONE);
1043         
1044         uiItemL(layout, "Rotation:", ICON_NONE);
1045         row= uiLayoutRow(layout, 1);
1046         uiItemR(row, ptr, "rotation", 0, "", ICON_NONE);
1047         
1048         uiItemL(layout, "Scale:", ICON_NONE);
1049         row= uiLayoutRow(layout, 1);
1050         uiItemR(row, ptr, "scale", 0, "", ICON_NONE);
1051         
1052         row= uiLayoutRow(layout, 1);
1053         uiItemR(row, ptr, "use_min", 0, "Min", ICON_NONE);
1054         uiItemR(row, ptr, "min", 0, "", ICON_NONE);
1055         
1056         row= uiLayoutRow(layout, 1);
1057         uiItemR(row, ptr, "use_max", 0, "Max", ICON_NONE);
1058         uiItemR(row, ptr, "max", 0, "", ICON_NONE);
1059 }
1060
1061 static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1062
1063         uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
1064 }
1065
1066 static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA *ptr)
1067 {
1068         PointerRNA obptr= CTX_data_pointer_get(C, "active_object");
1069         uiLayout *col;
1070
1071         col= uiLayoutColumn(layout, 0);
1072
1073         if(obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
1074                 PointerRNA dataptr= RNA_pointer_get(&obptr, "data");
1075
1076                 uiItemPointerR(col, ptr, "uv_layer", &dataptr, "uv_textures", "", ICON_NONE);
1077                 uiItemPointerR(col, ptr, "color_layer", &dataptr, "vertex_colors", "", ICON_NONE);
1078         }
1079         else {
1080                 uiItemR(col, ptr, "uv_layer", 0, "UV", ICON_NONE);
1081                 uiItemR(col, ptr, "color_layer", 0, "VCol", ICON_NONE);
1082         }
1083 }
1084
1085 static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1086 {
1087         uiItemR(layout, ptr, "attribute_name", 0, "Name", ICON_NONE);
1088 }
1089
1090 static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
1091 {
1092         uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
1093         uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
1094 }
1095
1096 static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1097 {
1098         uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
1099         uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE);
1100 }
1101
1102 static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1103 {
1104         uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE);
1105 }
1106
1107 static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1108 {
1109         uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
1110 }
1111
1112 static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1113 {
1114         uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
1115 }
1116
1117 static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1118 {
1119         uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
1120 }
1121
1122 static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1123 {
1124         uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
1125 }
1126
1127 static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1128 {
1129         uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
1130 }
1131
1132 static void node_shader_buts_dynamic(uiLayout *layout, bContext *C, PointerRNA *ptr)
1133
1134         Main *bmain= CTX_data_main(C);
1135         uiBlock *block= uiLayoutAbsoluteBlock(layout);
1136         bNode *node= ptr->data;
1137         bNodeTree *ntree= ptr->id.data;
1138         rctf *butr= &node->butr;
1139         uiBut *bt;
1140         // XXX SpaceNode *snode= curarea->spacedata.first;
1141         short dy= (short)butr->ymin;
1142         int xoff=0;
1143
1144         /* B_NODE_EXEC is handled in butspace.c do_node_buts */
1145         if(!node->id) {
1146                         const char *strp;
1147                         IDnames_to_pupstring(&strp, NULL, "", &(bmain->text), NULL, NULL);
1148                         node->menunr= 0;
1149                         bt= uiDefButS(block, MENU, B_NODE_EXEC/*+node->nr*/, strp, 
1150                                                         butr->xmin, dy, 19, 19, 
1151                                                         &node->menunr, 0, 0, 0, 0, "Browses existing choices");
1152                         uiButSetFunc(bt, node_browse_text_cb, ntree, node);
1153                         xoff=19;
1154                         if(strp) MEM_freeN((void *)strp);
1155         }
1156         else {
1157                 bt = uiDefBut(block, BUT, B_NOP, "Update",
1158                                 butr->xmin+xoff, butr->ymin+20, 50, 19,
1159                                 &node->menunr, 0.0, 19.0, 0, 0, "Refresh this node (and all others that use the same script)");
1160                 uiButSetFunc(bt, node_dynamic_update_cb, ntree, node);
1161
1162                 if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
1163                         // UI_ThemeColor(TH_REDALERT);
1164                         // XXX ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect);
1165                         // XXX snode_drawstring(snode, "Error! Check console...", butr->xmax - butr->xmin);
1166                         ;
1167                 }
1168         }
1169 }
1170
1171 /* only once called */
1172 static void node_shader_set_butfunc(bNodeType *ntype)
1173 {
1174         ntype->uifuncbut = NULL;
1175         switch(ntype->type) {
1176                 /* case NODE_GROUP:      note, typeinfo for group is generated... see "XXX ugly hack" */
1177
1178                 case SH_NODE_MATERIAL:
1179                 case SH_NODE_MATERIAL_EXT:
1180                         ntype->uifunc= node_shader_buts_material;
1181                         break;
1182                 case SH_NODE_TEXTURE:
1183                         ntype->uifunc= node_buts_texture;
1184                         break;
1185                 case SH_NODE_NORMAL:
1186                         ntype->uifunc= node_buts_normal;
1187                         break;
1188                 case SH_NODE_CURVE_VEC:
1189                         ntype->uifunc= node_buts_curvevec;
1190                         break;
1191                 case SH_NODE_CURVE_RGB:
1192                         ntype->uifunc= node_buts_curvecol;
1193                         break;
1194                 case SH_NODE_MAPPING:
1195                         ntype->uifunc= node_shader_buts_mapping;
1196                         break;
1197                 case SH_NODE_VALUE:
1198                         ntype->uifunc= node_buts_value;
1199                         break;
1200                 case SH_NODE_RGB:
1201                         ntype->uifunc= node_buts_rgb;
1202                         break;
1203                 case SH_NODE_MIX_RGB:
1204                         ntype->uifunc= node_buts_mix_rgb;
1205                         break;
1206                 case SH_NODE_VALTORGB:
1207                         ntype->uifunc= node_buts_colorramp;
1208                         break;
1209                 case SH_NODE_MATH: 
1210                         ntype->uifunc= node_buts_math;
1211                         break; 
1212                 case SH_NODE_VECT_MATH: 
1213                         ntype->uifunc= node_shader_buts_vect_math;
1214                         break; 
1215                 case SH_NODE_GEOMETRY:
1216                         ntype->uifunc= node_shader_buts_geometry;
1217                         break;
1218                 case SH_NODE_ATTRIBUTE:
1219                         ntype->uifunc= node_shader_buts_attribute;
1220                         break;
1221                 case SH_NODE_TEX_SKY:
1222                         ntype->uifunc= node_shader_buts_tex_sky;
1223                         break;
1224                 case SH_NODE_TEX_IMAGE:
1225                         ntype->uifunc= node_shader_buts_tex_image;
1226                         break;
1227                 case SH_NODE_TEX_ENVIRONMENT:
1228                         ntype->uifunc= node_shader_buts_tex_image;
1229                         break;
1230                 case SH_NODE_TEX_GRADIENT:
1231                         ntype->uifunc= node_shader_buts_tex_gradient;
1232                         break;
1233                 case SH_NODE_TEX_MAGIC:
1234                         ntype->uifunc= node_shader_buts_tex_magic;
1235                         break;
1236                 case SH_NODE_TEX_WAVE:
1237                         ntype->uifunc= node_shader_buts_tex_wave;
1238                         break;
1239                 case SH_NODE_TEX_MUSGRAVE:
1240                         ntype->uifunc= node_shader_buts_tex_musgrave;
1241                         break;
1242                 case SH_NODE_TEX_VORONOI:
1243                         ntype->uifunc= node_shader_buts_tex_voronoi;
1244                         break;
1245                 case SH_NODE_BSDF_GLOSSY:
1246                 case SH_NODE_BSDF_GLASS:
1247                         ntype->uifunc= node_shader_buts_glossy;
1248                         break;
1249                 case NODE_DYNAMIC:
1250                         ntype->uifunc= node_shader_buts_dynamic;
1251                         break;
1252         }
1253                 if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
1254 }
1255
1256 /* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
1257
1258 static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
1259 {
1260         uiLayout *col;
1261         bNode *node= ptr->data;
1262         PointerRNA imaptr;
1263         PropertyRNA *prop;
1264         int source;
1265         
1266         uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
1267         
1268         if(!node->id) return;
1269         
1270         prop = RNA_struct_find_property(ptr, "image");
1271         if (!prop || RNA_property_type(prop) != PROP_POINTER) return;
1272         imaptr= RNA_property_pointer_get(ptr, prop);
1273         
1274         col= uiLayoutColumn(layout, 0);
1275         
1276         uiItemR(col, &imaptr, "source", 0, NULL, ICON_NONE);
1277         
1278         source= RNA_enum_get(&imaptr, "source");
1279
1280         if(source == IMA_SRC_SEQUENCE) {
1281                 /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
1282                 Scene *scene= CTX_data_scene(C);
1283                 ImageUser *iuser= node->storage;
1284                 char numstr[32];
1285                 const int framenr= BKE_image_user_get_frame(iuser, CFRA, 0);
1286                 BLI_snprintf(numstr, sizeof(numstr), "Frame: %d", framenr);
1287                 uiItemL(layout, numstr, ICON_NONE);
1288         }
1289
1290         if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
1291                 col= uiLayoutColumn(layout, 1);
1292                 uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE);
1293                 uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE);
1294                 uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE);
1295                 uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE);
1296                 uiItemR(col, ptr, "use_auto_refresh", UI_ITEM_R_ICON_ONLY, NULL, ICON_NONE);
1297         }
1298
1299         col= uiLayoutColumn(layout, 0);
1300         
1301         if (RNA_enum_get(&imaptr, "type")== IMA_TYPE_MULTILAYER)
1302                 uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
1303 }
1304
1305 static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
1306 {
1307         bNode *node= ptr->data;
1308         uiLayout *col, *row;
1309         PointerRNA op_ptr;
1310         PointerRNA scn_ptr;
1311         PropertyRNA *prop;
1312         const char *layer_name;
1313         char scene_name[MAX_ID_NAME-2];
1314         wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1);
1315
1316         BLI_assert(ot != 0);
1317
1318         uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
1319         
1320         if(!node->id) return;
1321
1322         col= uiLayoutColumn(layout, 0);
1323         row = uiLayoutRow(col, 0);
1324         uiItemR(row, ptr, "layer", 0, "", ICON_NONE);
1325         
1326         prop = RNA_struct_find_property(ptr, "layer");
1327         if (!(RNA_property_enum_identifier(C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name)))
1328                 return;
1329         
1330         scn_ptr = RNA_pointer_get(ptr, "scene");
1331         RNA_string_get(&scn_ptr, "name", scene_name);
1332         
1333         WM_operator_properties_create_ptr(&op_ptr, ot);
1334         RNA_string_set(&op_ptr, "layer", layer_name);
1335         RNA_string_set(&op_ptr, "scene", scene_name);
1336         uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
1337
1338 }
1339
1340
1341 static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1342 {
1343         uiLayout *col, *row;
1344         
1345         col= uiLayoutColumn(layout, 0);
1346         
1347         uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE);
1348         if (RNA_enum_get(ptr, "filter_type")!= R_FILTER_FAST_GAUSS) {
1349                 uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE);
1350                 uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
1351         }
1352         
1353         uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE);
1354         
1355         if (RNA_boolean_get(ptr, "use_relative")) {
1356                 uiItemL(col, "Aspect Correction", 0);
1357                 row= uiLayoutRow(layout, 1);
1358                 uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, 0);
1359                 
1360                 col= uiLayoutColumn(layout, 1);
1361                 uiItemR(col, ptr, "factor_x", 0, "X", ICON_NONE);
1362                 uiItemR(col, ptr, "factor_y", 0, "Y", ICON_NONE);
1363         }
1364         else {
1365                 col= uiLayoutColumn(layout, 1);
1366                 uiItemR(col, ptr, "size_x", 0, "X", ICON_NONE);
1367                 uiItemR(col, ptr, "size_y", 0, "Y", ICON_NONE);
1368         }
1369 }
1370
1371 static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1372 {
1373         uiLayout *col;
1374         
1375         uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
1376         uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE);
1377         
1378         col= uiLayoutColumn(layout, 1);
1379         uiItemL(col, "Center:", ICON_NONE);
1380         uiItemR(col, ptr, "center_x", 0, "X", ICON_NONE);
1381         uiItemR(col, ptr, "center_y", 0, "Y", ICON_NONE);
1382         
1383         uiItemS(layout);
1384         
1385         col= uiLayoutColumn(layout, 1);
1386         uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
1387         uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
1388         
1389         uiItemS(layout);
1390         
1391         uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE);
1392         uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE);
1393 }
1394
1395 static void node_composit_buts_bilateralblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1396 {       
1397         uiLayout *col;
1398         
1399         col= uiLayoutColumn(layout, 1);
1400         uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE);
1401         uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE);
1402         uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE);
1403 }
1404
1405 static void node_composit_buts_defocus(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1406 {
1407         uiLayout *sub, *col;
1408         
1409         col= uiLayoutColumn(layout, 0);
1410         uiItemL(col, "Bokeh Type:", ICON_NONE);
1411         uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE);
1412         uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
1413
1414         uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
1415
1416         col = uiLayoutColumn(layout, 0);
1417         uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer")==1);
1418         uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE);
1419
1420         uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
1421         uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
1422
1423         col = uiLayoutColumn(layout, 0);
1424         uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
1425         sub = uiLayoutColumn(col, 0);
1426         uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_preview"));
1427         uiItemR(sub, ptr, "samples", 0, NULL, ICON_NONE);
1428         
1429         col = uiLayoutColumn(layout, 0);
1430         uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
1431         sub = uiLayoutColumn(col, 0);
1432         uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer")==0);
1433         uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE);
1434 }
1435
1436 /* qdn: glare node */
1437 static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1438 {       
1439         uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE);
1440         uiItemR(layout, ptr, "quality", 0, "", ICON_NONE);
1441
1442         if (RNA_enum_get(ptr, "glare_type")!= 1) {
1443                 uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
1444         
1445                 if (RNA_enum_get(ptr, "glare_type")!= 0) 
1446                         uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1447         }
1448         
1449         uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE);
1450         uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
1451
1452         if (RNA_enum_get(ptr, "glare_type")== 2) {
1453                 uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE);
1454                 uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE);
1455         }
1456         if (RNA_enum_get(ptr, "glare_type")== 0 || RNA_enum_get(ptr, "glare_type")== 2) {
1457                 uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1458                 
1459                 if (RNA_enum_get(ptr, "glare_type")== 0) 
1460                         uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE);
1461         }
1462         if (RNA_enum_get(ptr, "glare_type")== 1) {
1463                 uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE);
1464         }
1465 }
1466
1467 static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1468 {       
1469         uiLayout *col;
1470
1471         col = uiLayoutColumn(layout, 0);
1472         uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE);
1473         if (RNA_enum_get(ptr, "tonemap_type")== 0) {
1474                 uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1475                 uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
1476                 uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE);
1477         }
1478         else {
1479                 uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE);
1480                 uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1481                 uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1482                 uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1483         }
1484 }
1485
1486 static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1487 {
1488         uiLayout *col;
1489
1490         col= uiLayoutColumn(layout, 0);
1491         uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE);
1492
1493         col = uiLayoutColumn(col, 0);
1494         uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector")==0);
1495         uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE);
1496         uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE);
1497 }
1498
1499 static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1500 {
1501         uiLayout *col;
1502         
1503         col= uiLayoutColumn(layout, 0);
1504         uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE);
1505         uiItemR(col, ptr, "factor", 0, "Blur", ICON_NONE);
1506         
1507         col= uiLayoutColumn(layout, 1);
1508         uiItemL(col, "Speed:", ICON_NONE);
1509         uiItemR(col, ptr, "speed_min", 0, "Min", ICON_NONE);
1510         uiItemR(col, ptr, "speed_max", 0, "Max", ICON_NONE);
1511
1512         uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE);
1513 }
1514
1515 static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1516 {
1517         uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
1518 }
1519
1520 static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1521 {
1522         uiItemR(layout, ptr, "axis", 0, "", ICON_NONE);
1523 }
1524
1525 static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1526 {
1527         uiLayout *col;
1528
1529         uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE);
1530         uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE);
1531
1532         col= uiLayoutColumn(layout, 1);
1533         if (RNA_boolean_get(ptr, "relative")){
1534                 uiItemR(col, ptr, "rel_min_x", 0, "Left", ICON_NONE);
1535                 uiItemR(col, ptr, "rel_max_x", 0, "Right", ICON_NONE);
1536                 uiItemR(col, ptr, "rel_min_y", 0, "Up", ICON_NONE);
1537                 uiItemR(col, ptr, "rel_max_y", 0, "Down", ICON_NONE);
1538         } else {
1539                 uiItemR(col, ptr, "min_x", 0, "Left", ICON_NONE);
1540                 uiItemR(col, ptr, "max_x", 0, "Right", ICON_NONE);
1541                 uiItemR(col, ptr, "min_y", 0, "Up", ICON_NONE);
1542                 uiItemR(col, ptr, "max_y", 0, "Down", ICON_NONE);
1543         }
1544 }
1545
1546 static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1547 {
1548         uiLayout *row, *col;
1549         
1550         col= uiLayoutColumn(layout, 0);
1551         row= uiLayoutRow(col, 0);
1552         uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1553         uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
1554 }
1555
1556 static void node_composit_buts_double_edge_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1557 {
1558         uiLayout *col;
1559
1560         col= uiLayoutColumn(layout, 0);
1561
1562         uiItemL(col, "Inner Edge:", ICON_NONE);
1563         uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
1564         uiItemL(col, "Buffer Edge:", ICON_NONE);
1565         uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
1566 }
1567
1568 static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1569 {
1570         uiLayout *sub, *col;
1571         
1572         col = uiLayoutColumn(layout, 1);
1573         uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
1574         uiItemR(col, ptr, "size", 0, NULL, ICON_NONE);
1575         
1576         col = uiLayoutColumn(layout, 1);
1577         uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE);
1578         sub = uiLayoutColumn(col, 0);
1579         uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
1580         uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
1581         
1582         col = uiLayoutColumn(layout, 1);
1583         uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE);
1584         sub = uiLayoutColumn(col, 0);
1585         uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
1586         uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
1587 }
1588
1589 static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1590 {       
1591         uiLayout *col;
1592         
1593         col = uiLayoutColumn(layout, 1);
1594         uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE);
1595         uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE);
1596 }
1597
1598 static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1599 {       
1600         uiLayout *col;
1601         
1602         col = uiLayoutColumn(layout, 1);
1603         uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE);
1604 }
1605
1606
1607 static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1608 {
1609         uiLayout *col;
1610         
1611         col = uiLayoutColumn(layout, 0);
1612         uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1613         uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1614         uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1615 }
1616
1617 static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1618 {
1619         uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
1620 }
1621
1622 static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1623 {
1624         uiLayout *col;
1625         
1626         col = uiLayoutColumn(layout, 1);
1627         uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1628         uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1629 }
1630
1631 static void node_composit_buts_distance_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1632 {
1633         uiLayout *col;
1634         
1635         col = uiLayoutColumn(layout, 1);
1636         uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1637         uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1638 }
1639
1640 static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1641 {
1642         uiLayout *row, *col;
1643         
1644         uiItemL(layout, "Despill Channel:", ICON_NONE);
1645         row = uiLayoutRow(layout,0);
1646         uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1647
1648         col= uiLayoutColumn(layout, 0);
1649         uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
1650
1651         if(RNA_enum_get(ptr, "limit_method")==0) {
1652                 uiItemL(col, "Limiting Channel:", ICON_NONE);
1653                 row=uiLayoutRow(col,0);
1654                 uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1655         }
1656
1657         uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1658         uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE);
1659         if (RNA_boolean_get(ptr, "use_unspill")== 1) {
1660                 uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1661                 uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1662                 uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1663         }
1664 }
1665
1666 static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1667 {
1668         uiLayout *col;
1669         
1670         col= uiLayoutColumn(layout, 0);
1671         uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE);
1672         uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
1673         
1674         col= uiLayoutColumn(layout, 1);
1675         /*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);  Removed for now */
1676         uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1677         /*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE);  Removed for now*/
1678 }
1679
1680 static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1681 {
1682         uiLayout *col;
1683         
1684         col= uiLayoutColumn(layout, 1);
1685         uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1686         uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1687         uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1688 }
1689
1690 static void node_composit_buts_channel_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1691 {       
1692         uiLayout *col, *row;
1693
1694         uiItemL(layout, "Color Space:", ICON_NONE);
1695         row= uiLayoutRow(layout, 0);
1696         uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1697
1698         col=uiLayoutColumn(layout, 0);
1699         uiItemL(col, "Key Channel:", ICON_NONE);
1700         row= uiLayoutRow(col, 0);
1701         uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1702
1703         col = uiLayoutColumn(layout, 0);
1704
1705         uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
1706         if(RNA_enum_get(ptr, "limit_method")==0) {
1707                 uiItemL(col, "Limiting Channel:", ICON_NONE);
1708                 row=uiLayoutRow(col,0);
1709                 uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1710         }
1711
1712         uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1713         uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1714 }
1715
1716 static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1717 {
1718         uiLayout *col;
1719         
1720         col= uiLayoutColumn(layout, 1);
1721         uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1722         uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
1723 }
1724
1725 static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1726 {
1727         uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE);
1728 }
1729
1730 static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1731 {
1732         uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
1733         uiItemR(layout, ptr, "use_smooth_mask", 0, NULL, ICON_NONE);
1734 }
1735
1736 static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1737 {
1738         PointerRNA imfptr = RNA_pointer_get(ptr, "format");
1739         int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
1740         
1741         if (multilayer)
1742                 uiItemL(layout, "Path:", 0);
1743         else
1744                 uiItemL(layout, "Base Path:", 0);
1745         uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE);
1746 }
1747 static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C, PointerRNA *ptr)
1748 {
1749         PointerRNA imfptr = RNA_pointer_get(ptr, "format");
1750         PointerRNA active_input_ptr = RNA_pointer_get(ptr, "active_input");
1751         int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
1752         
1753         node_composit_buts_file_output(layout, C, ptr);
1754         uiTemplateImageSettings(layout, &imfptr);
1755         
1756         uiItemS(layout);
1757         
1758         uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
1759         
1760         uiTemplateList(layout, C, ptr, "inputs", ptr, "active_input_index", NULL, 0, 0, 0);
1761         
1762         if (active_input_ptr.data) {
1763                 uiLayout *row, *col;
1764                 
1765                 col = uiLayoutColumn(layout, 1);
1766                 if (multilayer)
1767                         uiItemL(col, "Layer Name:", 0);
1768                 else
1769                         uiItemL(col, "File Path:", 0);
1770                 row = uiLayoutRow(col, 0);
1771                 uiItemR(row, &active_input_ptr, "name", 0, "", 0);
1772                 uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY);
1773                 
1774                 /* in multilayer format all socket format details are ignored */
1775                 if (!multilayer) {
1776                         imfptr = RNA_pointer_get(&active_input_ptr, "format");
1777                         
1778                         col = uiLayoutColumn(layout, 1);
1779                         uiItemL(col, "Format:", 0);
1780                         uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, 0);
1781                         
1782                         col= uiLayoutColumn(layout, 0);
1783                         uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format")==0);
1784                         uiTemplateImageSettings(col, &imfptr);
1785                 }
1786         }
1787 }
1788
1789 static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1790 {
1791         uiItemR(layout, ptr, "space", 0, "", ICON_NONE);
1792 }
1793
1794 static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1795 {
1796         uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
1797 }
1798
1799 static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1800 {
1801         uiLayout *col;
1802         
1803         col= uiLayoutColumn(layout, 0);
1804         uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE);
1805         uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE);
1806 }
1807
1808 static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1809 {
1810         uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
1811 }
1812
1813 static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1814 {
1815         uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
1816 }
1817
1818 static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1819 {
1820         uiLayout *split, *col, *row;
1821         
1822         uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
1823         
1824         if (RNA_enum_get(ptr, "correction_method")== 0) {
1825         
1826                 split = uiLayoutSplit(layout, 0, 0);
1827                 col = uiLayoutColumn(split, 0);
1828                 uiTemplateColorWheel(col, ptr, "lift", 1, 1, 0, 1);
1829                 row = uiLayoutRow(col, 0);
1830                 uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE);
1831                 
1832                 col = uiLayoutColumn(split, 0);
1833                 uiTemplateColorWheel(col, ptr, "gamma", 1, 1, 1, 1);
1834                 row = uiLayoutRow(col, 0);
1835                 uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE);
1836                 
1837                 col = uiLayoutColumn(split, 0);
1838                 uiTemplateColorWheel(col, ptr, "gain", 1, 1, 1, 1);
1839                 row = uiLayoutRow(col, 0);
1840                 uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE);
1841
1842         } else {
1843                 
1844                 split = uiLayoutSplit(layout, 0, 0);
1845                 col = uiLayoutColumn(split, 0);
1846                 uiTemplateColorWheel(col, ptr, "offset", 1, 1, 0, 1);
1847                 row = uiLayoutRow(col, 0);
1848                 uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE);
1849                 
1850                 col = uiLayoutColumn(split, 0);
1851                 uiTemplateColorWheel(col, ptr, "power", 1, 1, 0, 1);
1852                 row = uiLayoutRow(col, 0);
1853                 uiItemR(row, ptr, "power", 0, NULL, ICON_NONE);
1854                 
1855                 col = uiLayoutColumn(split, 0);
1856                 uiTemplateColorWheel(col, ptr, "slope", 1, 1, 0, 1);
1857                 row = uiLayoutRow(col, 0);
1858                 uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE);
1859         }
1860
1861 }
1862 static void node_composit_buts_colorbalance_but(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1863 {
1864         uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
1865
1866         if (RNA_enum_get(ptr, "correction_method")== 0) {
1867
1868         uiTemplateColorWheel(layout, ptr, "lift", 1, 1, 0, 1);
1869                 uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE);
1870
1871                 uiTemplateColorWheel(layout, ptr, "gamma", 1, 1, 1, 1);
1872                 uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE);
1873
1874                 uiTemplateColorWheel(layout, ptr, "gain", 1, 1, 1, 1);
1875                 uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE);
1876         } else {
1877                 uiTemplateColorWheel(layout, ptr, "offset", 1, 1, 0, 1);
1878                 uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
1879
1880                 uiTemplateColorWheel(layout, ptr, "power", 1, 1, 0, 1);
1881                 uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE);
1882
1883                 uiTemplateColorWheel(layout, ptr, "slope", 1, 1, 0, 1);
1884                 uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE);
1885         }
1886 }
1887
1888
1889 static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1890 {
1891         uiTemplateCurveMapping(layout, ptr, "mapping", 'h', 0, 0);
1892 }
1893
1894 static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1895
1896         uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
1897 }
1898
1899 static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
1900 {
1901         uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
1902 }
1903
1904 static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr)
1905 {
1906         bNode *node= ptr->data;
1907
1908         uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
1909
1910         if(!node->id)
1911                 return;
1912
1913         uiItemR(layout, ptr, "filter_type", 0, "", 0);
1914 }
1915
1916 static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
1917 {
1918         uiItemR(layout, ptr, "filter_type", 0, "", 0);
1919 }
1920
1921 static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
1922 {
1923         bNode *node= ptr->data;
1924
1925         uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
1926
1927         if(!node->id)
1928                 return;
1929
1930         uiItemR(layout, ptr, "distortion_type", 0, "", 0);
1931 }
1932
1933 /* only once called */
1934 static void node_composit_set_butfunc(bNodeType *ntype)
1935 {
1936         ntype->uifuncbut = NULL;
1937         switch(ntype->type) {
1938                 /* case NODE_GROUP:      note, typeinfo for group is generated... see "XXX ugly hack" */
1939
1940                 case CMP_NODE_IMAGE:
1941                         ntype->uifunc= node_composit_buts_image;
1942                         break;
1943                 case CMP_NODE_R_LAYERS:
1944                         ntype->uifunc= node_composit_buts_renderlayers;
1945                         break;
1946                 case CMP_NODE_NORMAL:
1947                         ntype->uifunc= node_buts_normal;
1948                         break;
1949                 case CMP_NODE_CURVE_VEC:
1950                         ntype->uifunc= node_buts_curvevec;
1951                         break;
1952                 case CMP_NODE_CURVE_RGB:
1953                         ntype->uifunc= node_buts_curvecol;
1954                         break;
1955                 case CMP_NODE_VALUE:
1956                         ntype->uifunc= node_buts_value;
1957                         break;
1958                 case CMP_NODE_RGB:
1959                         ntype->uifunc= node_buts_rgb;
1960                         break;
1961                 case CMP_NODE_FLIP:
1962                         ntype->uifunc= node_composit_buts_flip;
1963                         break;
1964                 case CMP_NODE_SPLITVIEWER:
1965                         ntype->uifunc= node_composit_buts_splitviewer;
1966                         break;
1967                 case CMP_NODE_MIX_RGB:
1968                         ntype->uifunc= node_buts_mix_rgb;
1969                         break;
1970                 case CMP_NODE_VALTORGB:
1971                         ntype->uifunc= node_buts_colorramp;
1972                         break;
1973                 case CMP_NODE_CROP:
1974                         ntype->uifunc= node_composit_buts_crop;
1975                         break;
1976                 case CMP_NODE_BLUR:
1977                         ntype->uifunc= node_composit_buts_blur;
1978                         break;
1979                 case CMP_NODE_DBLUR:
1980                         ntype->uifunc= node_composit_buts_dblur;
1981                         break;
1982                 case CMP_NODE_BILATERALBLUR:
1983                         ntype->uifunc= node_composit_buts_bilateralblur;
1984                         break;
1985                 case CMP_NODE_DEFOCUS:
1986                         ntype->uifunc = node_composit_buts_defocus;
1987                         break;
1988                 case CMP_NODE_GLARE:
1989                         ntype->uifunc = node_composit_buts_glare;
1990                         break;
1991                 case CMP_NODE_TONEMAP:
1992                         ntype->uifunc = node_composit_buts_tonemap;
1993                         break;
1994                 case CMP_NODE_LENSDIST:
1995                         ntype->uifunc = node_composit_buts_lensdist;
1996                         break;
1997                 case CMP_NODE_VECBLUR:
1998                         ntype->uifunc= node_composit_buts_vecblur;
1999                         break;
2000                 case CMP_NODE_FILTER:
2001                         ntype->uifunc= node_composit_buts_filter;
2002                         break;
2003                 case CMP_NODE_MAP_VALUE:
2004                         ntype->uifunc= node_composit_buts_map_value;
2005                         break;
2006                 case CMP_NODE_TIME:
2007                         ntype->uifunc= node_buts_time;
2008                         break;
2009                 case CMP_NODE_ALPHAOVER:
2010                         ntype->uifunc= node_composit_buts_alphaover;
2011                         break;
2012                 case CMP_NODE_HUE_SAT:
2013                         ntype->uifunc= node_composit_buts_hue_sat;
2014                         break;
2015                 case CMP_NODE_TEXTURE:
2016                         ntype->uifunc= node_buts_texture;
2017                         break;
2018                 case CMP_NODE_DILATEERODE:
2019                         ntype->uifunc= node_composit_buts_dilateerode;
2020                         break;
2021                 case CMP_NODE_OUTPUT_FILE:
2022                         ntype->uifunc= node_composit_buts_file_output;
2023                         ntype->uifuncbut= node_composit_buts_file_output_details;
2024                         break;
2025                 case CMP_NODE_DIFF_MATTE:
2026                         ntype->uifunc=node_composit_buts_diff_matte;
2027                         break;
2028                 case CMP_NODE_DIST_MATTE:
2029                         ntype->uifunc=node_composit_buts_distance_matte;
2030                         break;
2031                 case CMP_NODE_COLOR_SPILL:
2032                         ntype->uifunc=node_composit_buts_color_spill;
2033                         break;
2034                 case CMP_NODE_CHROMA_MATTE:
2035                         ntype->uifunc=node_composit_buts_chroma_matte;
2036                         break;
2037                 case CMP_NODE_COLOR_MATTE:
2038                         ntype->uifunc=node_composit_buts_color_matte;
2039                         break;
2040                 case CMP_NODE_SCALE:
2041                         ntype->uifunc= node_composit_buts_scale;
2042                         break;
2043                 case CMP_NODE_ROTATE:
2044                         ntype->uifunc=node_composit_buts_rotate;
2045                         break;
2046                 case CMP_NODE_CHANNEL_MATTE:
2047                         ntype->uifunc= node_composit_buts_channel_matte;
2048                         break;
2049                 case CMP_NODE_LUMA_MATTE:
2050                         ntype->uifunc= node_composit_buts_luma_matte;
2051                         break;
2052                 case CMP_NODE_MAP_UV:
2053                         ntype->uifunc= node_composit_buts_map_uv;
2054                         break;
2055                 case CMP_NODE_ID_MASK:
2056                         ntype->uifunc= node_composit_buts_id_mask;
2057                         break;
2058                 case CMP_NODE_DOUBLEEDGEMASK:
2059                         ntype->uifunc= node_composit_buts_double_edge_mask;
2060                         break;
2061                 case CMP_NODE_MATH:
2062                         ntype->uifunc= node_buts_math;
2063                         break;
2064                 case CMP_NODE_INVERT:
2065                         ntype->uifunc= node_composit_buts_invert;
2066                         break;
2067                 case CMP_NODE_PREMULKEY:
2068                         ntype->uifunc= node_composit_buts_premulkey;
2069                         break;
2070                 case CMP_NODE_VIEW_LEVELS:
2071                         ntype->uifunc=node_composit_buts_view_levels;
2072                         break;
2073                 case CMP_NODE_COLORBALANCE:
2074                         ntype->uifunc=node_composit_buts_colorbalance;
2075                         ntype->uifuncbut=node_composit_buts_colorbalance_but;
2076                         break;
2077                 case CMP_NODE_HUECORRECT:
2078                         ntype->uifunc=node_composit_buts_huecorrect;
2079                         break;
2080                 case CMP_NODE_ZCOMBINE:
2081                         ntype->uifunc=node_composit_buts_zcombine;
2082                         break;
2083                 case CMP_NODE_COMBYCCA:
2084                 case CMP_NODE_SEPYCCA:
2085                         ntype->uifunc=node_composit_buts_ycc;
2086                         break;
2087                 case CMP_NODE_MOVIECLIP:
2088                         ntype->uifunc= node_composit_buts_movieclip;
2089                         break;
2090                 case CMP_NODE_STABILIZE2D:
2091                         ntype->uifunc= node_composit_buts_stabilize2d;
2092                         break;
2093                 case CMP_NODE_TRANSFORM:
2094                         ntype->uifunc= node_composit_buts_transform;
2095                         break;
2096                 case CMP_NODE_MOVIEDISTORTION:
2097                         ntype->uifunc= node_composit_buts_moviedistortion;
2098                         break;
2099                 default:
2100                         ntype->uifunc= NULL;
2101         }
2102         if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
2103
2104 }
2105
2106 /* ****************** BUTTON CALLBACKS FOR TEXTURE NODES ***************** */
2107
2108 static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
2109 {
2110         uiLayout *col;
2111         
2112         col= uiLayoutColumn(layout, 1);
2113         uiItemR(col, ptr, "offset", 0, "Offset", ICON_NONE);
2114         uiItemR(col, ptr, "offset_frequency", 0, "Frequency", ICON_NONE);
2115         
2116         col= uiLayoutColumn(layout, 1);
2117         uiItemR(col, ptr, "squash", 0, "Squash", ICON_NONE);
2118         uiItemR(col, ptr, "squash_frequency", 0, "Frequency", ICON_NONE);
2119 }
2120
2121 static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
2122 {
2123         PointerRNA tex_ptr;
2124         bNode *node= ptr->data;
2125         ID *id= ptr->id.data;
2126         Tex *tex = (Tex *)node->storage;
2127         uiLayout *col, *row;
2128         
2129         RNA_pointer_create(id, &RNA_Texture, tex, &tex_ptr);
2130
2131         col= uiLayoutColumn(layout, 0);
2132
2133         switch( tex->type ) {
2134                 case TEX_BLEND:
2135                         uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE);
2136                         row= uiLayoutRow(col, 0);
2137                         uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2138                         break;
2139
2140                 case TEX_MARBLE:
2141                         row= uiLayoutRow(col, 0);
2142                         uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2143                         row= uiLayoutRow(col, 0);
2144                         uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2145                         row= uiLayoutRow(col, 0);
2146                         uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2147                         row= uiLayoutRow(col, 0);
2148                         uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2149                         break;
2150
2151                 case TEX_MAGIC:
2152                         uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE);
2153                         break;
2154
2155                 case TEX_STUCCI:
2156                         row= uiLayoutRow(col, 0);
2157                         uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2158                         row= uiLayoutRow(col, 0);
2159                         uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2160                         uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2161                         break;
2162
2163                 case TEX_WOOD:
2164                         uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2165                         uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE);
2166                         row= uiLayoutRow(col, 0);
2167                         uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2168                         row= uiLayoutRow(col, 0);
2169                         uiLayoutSetActive(row, !(RNA_enum_get(&tex_ptr, "wood_type")==TEX_BAND || RNA_enum_get(&tex_ptr, "wood_type")==TEX_RING)); 
2170                         uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2171                         break;
2172                         
2173                 case TEX_CLOUDS:
2174                         uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2175                         row= uiLayoutRow(col, 0);
2176                         uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2177                         row= uiLayoutRow(col, 0);
2178                         uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
2179                         uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, "Depth", ICON_NONE);
2180                         break;
2181                         
2182                 case TEX_DISTNOISE:
2183                         uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2184                         uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE);
2185                         break;
2186
2187                 case TEX_MUSGRAVE:
2188                         uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE);
2189                         uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
2190                         break;
2191                 case TEX_VORONOI:
2192                         uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE);
2193                         if(tex->vn_distm == TEX_MINKOVSKY) {
2194                                 uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE);
2195                         }
2196                         uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE);
2197                         break;
2198         }
2199 }
2200
2201 static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
2202 {
2203         uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
2204 }
2205
2206 static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
2207 {
2208         uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE);
2209 }
2210
2211 /* only once called */
2212 static void node_texture_set_butfunc(bNodeType *ntype)
2213 {
2214         ntype->uifuncbut = NULL;
2215         if( ntype->type >= TEX_NODE_PROC && ntype->type < TEX_NODE_PROC_MAX ) {
2216                 ntype->uifunc = node_texture_buts_proc;
2217         }
2218         else switch(ntype->type) {
2219                 
2220                 case TEX_NODE_MATH:
2221                         ntype->uifunc = node_buts_math;
2222                         break;
2223                 
2224                 case TEX_NODE_MIX_RGB:
2225                         ntype->uifunc = node_buts_mix_rgb;
2226                         break;
2227                         
2228                 case TEX_NODE_VALTORGB:
2229                         ntype->uifunc = node_buts_colorramp;
2230                         break;
2231                         
2232                 case TEX_NODE_CURVE_RGB:
2233                         ntype->uifunc= node_buts_curvecol;
2234                         break;
2235                         
2236                 case TEX_NODE_CURVE_TIME:
2237                         ntype->uifunc = node_buts_time;
2238                         break;
2239                         
2240                 case TEX_NODE_TEXTURE:
2241                         ntype->uifunc = node_buts_texture;
2242                         break;
2243                         
2244                 case TEX_NODE_BRICKS:
2245                         ntype->uifunc = node_texture_buts_bricks;
2246                         break;
2247                         
2248                 case TEX_NODE_IMAGE:
2249                         ntype->uifunc = node_texture_buts_image;
2250                         break;
2251                         
2252                 case TEX_NODE_OUTPUT:
2253                         ntype->uifunc = node_texture_buts_output;
2254                         break;
2255         }
2256         if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
2257 }
2258
2259 /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */
2260
2261 void ED_init_node_butfuncs(void)
2262 {
2263         bNodeTreeType *treetype;
2264         bNodeType *ntype;
2265         bNodeSocketType *stype;
2266         int i;
2267         
2268         /* node type ui functions */
2269         for (i=0; i < NUM_NTREE_TYPES; ++i) {
2270                 treetype = ntreeGetType(i);
2271                 if (treetype) {
2272                         for (ntype= treetype->node_types.first; ntype; ntype= ntype->next) {
2273                                 /* default ui functions */
2274                                 ntype->drawfunc = node_draw_default;
2275                                 ntype->drawupdatefunc = node_update_default;
2276                                 ntype->uifunc = NULL;
2277                                 ntype->uifuncbut = NULL;
2278                                 ntype->resize_area_func = node_resize_area_default;
2279                                 
2280                                 node_common_set_butfunc(ntype);
2281                                 
2282                                 switch (i) {
2283                                 case NTREE_COMPOSIT:
2284                                         node_composit_set_butfunc(ntype);
2285                                         break;
2286                                 case NTREE_SHADER:
2287                                         node_shader_set_butfunc(ntype);
2288                                         break;
2289                                 case NTREE_TEXTURE:
2290                                         node_texture_set_butfunc(ntype);
2291                                         break;
2292                                 }
2293                         }
2294                 }
2295         }
2296         
2297         /* socket type ui functions */
2298         for (i=0; i < NUM_SOCKET_TYPES; ++i) {
2299                 stype = ntreeGetSocketType(i);
2300                 if (stype) {
2301                         switch(stype->type) {
2302                         case SOCK_FLOAT:
2303                         case SOCK_INT:
2304                         case SOCK_BOOLEAN:
2305                                 stype->buttonfunc = node_socket_button_default;
2306                                 break;
2307                         case SOCK_VECTOR:
2308                                 stype->buttonfunc = node_socket_button_components;
2309                                 break;
2310                         case SOCK_RGBA:
2311                                 stype->buttonfunc = node_socket_button_color;
2312                                 break;
2313                         case SOCK_SHADER:
2314                                 stype->buttonfunc = node_socket_button_label;
2315                                 break;
2316                         default:
2317                                 stype->buttonfunc = NULL;
2318                         }
2319                 }
2320         }
2321 }
2322
2323 /* ************** Generic drawing ************** */
2324
2325 void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
2326 {
2327         
2328         if((snode->flag & SNODE_BACKDRAW) && snode->treetype==NTREE_COMPOSIT) {
2329                 Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
2330                 void *lock;
2331                 ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
2332                 if(ibuf) {
2333                         float x, y; 
2334                         
2335                         glMatrixMode(GL_PROJECTION);
2336                         glPushMatrix();
2337                         glMatrixMode(GL_MODELVIEW);
2338                         glPushMatrix();
2339
2340                         /* keep this, saves us from a version patch */
2341                         if(snode->zoom==0.0f) snode->zoom= 1.0f;
2342                         
2343                         /* somehow the offset has to be calculated inverse */
2344                         
2345                         glaDefine2DArea(&ar->winrct);
2346                         /* ortho at pixel level curarea */
2347                         wmOrtho2(-0.375, ar->winx-0.375, -0.375, ar->winy-0.375);
2348                         
2349                         x = (ar->winx-snode->zoom*ibuf->x)/2 + snode->xof;
2350                         y = (ar->winy-snode->zoom*ibuf->y)/2 + snode->yof;
2351                         
2352                         if(!ibuf->rect) {
2353                                 if(color_manage)
2354                                         ibuf->profile = IB_PROFILE_LINEAR_RGB;
2355                                 else
2356                                         ibuf->profile = IB_PROFILE_NONE;
2357                                 IMB_rect_from_float(ibuf);
2358                         }
2359
2360                         if(ibuf->rect) {
2361                                 if (snode->flag & SNODE_SHOW_ALPHA) {
2362                                         glPixelZoom(snode->zoom, snode->zoom);
2363                                         /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
2364                                         if(ENDIAN_ORDER == B_ENDIAN)
2365                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
2366                                         
2367                                         glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT, ibuf->rect);
2368                                         
2369                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
2370                                         glPixelZoom(1.0f, 1.0f);
2371                                 } else if (snode->flag & SNODE_USE_ALPHA) {
2372                                         glEnable(GL_BLEND);
2373                                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2374                                         glPixelZoom(snode->zoom, snode->zoom);
2375                                         
2376                                         glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
2377                                         
2378                                         glPixelZoom(1.0f, 1.0f);
2379                                         glDisable(GL_BLEND);
2380                                 } else {
2381                                         glPixelZoom(snode->zoom, snode->zoom);
2382                                         
2383                                         glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
2384                                         
2385                                         glPixelZoom(1.0f, 1.0f);
2386                                 }
2387                         }
2388                         
2389                         glMatrixMode(GL_PROJECTION);
2390                         glPopMatrix();
2391                         glMatrixMode(GL_MODELVIEW);
2392                         glPopMatrix();
2393                 }
2394
2395                 BKE_image_release_ibuf(ima, lock);
2396         }
2397 }
2398
2399 #if 0
2400 /* note: needs to be userpref or opengl profile option */
2401 static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
2402 {
2403
2404         draw_nodespace_grid(snode);
2405         
2406         if(snode->flag & SNODE_BACKDRAW) {
2407                 Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
2408                 ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
2409                 if(ibuf) {
2410                         int x, y;
2411                         float zoom = 1.0;
2412
2413                         glMatrixMode(GL_PROJECTION);
2414                         glPushMatrix();
2415                         glMatrixMode(GL_MODELVIEW);
2416                         glPushMatrix();
2417                         
2418                         glaDefine2DArea(&sa->winrct);
2419
2420                         if(ibuf->x > sa->winx || ibuf->y > sa->winy) {
2421                                 float zoomx, zoomy;
2422                                 zoomx= (float)sa->winx/ibuf->x;
2423                                 zoomy= (float)sa->winy/ibuf->y;
2424                                 zoom = MIN2(zoomx, zoomy);
2425                         }
2426                         
2427                         x = (sa->winx-zoom*ibuf->x)/2 + snode->xof;
2428                         y = (sa->winy-zoom*ibuf->y)/2 + snode->yof;
2429
2430                         glPixelZoom(zoom, zoom);
2431
2432                         glColor4f(1.0, 1.0, 1.0, 1.0);
2433                         if(ibuf->rect)
2434                                 glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
2435                         else if(ibuf->channels==4)
2436                                 glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float);
2437
2438                         glPixelZoom(1.0, 1.0);
2439
2440                         glMatrixMode(GL_PROJECTION);
2441                         glPopMatrix();
2442                         glMatrixMode(GL_MODELVIEW);
2443                         glPopMatrix();
2444                 }
2445         }
2446 }
2447 #endif
2448
2449 /* if v2d not NULL, it clips and returns 0 if not visible */
2450 int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
2451 {
2452         float dist, vec[4][2];
2453         
2454         /* in v0 and v3 we put begin/end points */
2455         if(link->fromsock) {
2456                 vec[0][0]= link->fromsock->locx;
2457                 vec[0][1]= link->fromsock->locy;
2458         }
2459         else {
2460                 if(snode==NULL) return 0;
2461                 vec[0][0]= snode->mx;
2462                 vec[0][1]= snode->my;
2463         }
2464         if(link->tosock) {
2465                 vec[3][0]= link->tosock->locx;
2466                 vec[3][1]= link->tosock->locy;
2467         }
2468         else {
2469                 if(snode==NULL) return 0;
2470                 vec[3][0]= snode->mx;
2471                 vec[3][1]= snode->my;
2472         }
2473
2474         dist= UI_GetThemeValue(TH_NODE_CURVING)*0.10f*ABS(vec[0][0] - vec[3][0]);
2475         
2476         /* check direction later, for top sockets */
2477         vec[1][0]= vec[0][0]+dist;
2478         vec[1][1]= vec[0][1];
2479         
2480         vec[2][0]= vec[3][0]-dist;
2481         vec[2][1]= vec[3][1];
2482         
2483         if(v2d && MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax); /* clipped */      
2484         else if (v2d && MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin); /* clipped */
2485         else {
2486                 
2487                 /* always do all three, to prevent data hanging around */
2488                 forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float)*2);
2489                 forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0]+1, resol, sizeof(float)*2);
2490                 
2491                 return 1;
2492         }
2493         return 0;
2494 }
2495
2496 #define LINK_RESOL      24
2497 void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 )
2498 {
2499         float coord_array[LINK_RESOL+1][2];
2500         
2501         if(node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) {
2502                 float dist, spline_step = 0.0f;
2503                 int i;
2504                 
2505                 /* store current linewidth */
2506                 float linew;
2507                 glGetFloatv(GL_LINE_WIDTH, &linew);
2508                 
2509                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2510                 dist = 1.0f/(float)LINK_RESOL;
2511                 
2512                 glEnable(GL_LINE_SMOOTH);
2513                 
2514                 if(do_triple) {
2515                         UI_ThemeColorShadeAlpha(th_col3, -80, -120);
2516                         glLineWidth(4.0f);
2517                         
2518                         glBegin(GL_LINE_STRIP);
2519                         for(i=0; i<=LINK_RESOL; i++) {
2520                                 glVertex2fv(coord_array[i]);
2521                         }
2522                         glEnd();
2523                 }
2524                 
2525                 /* XXX using GL_LINES for shaded node lines is a workaround
2526                  * for Intel hardware, this breaks with GL_LINE_STRIP and
2527                  * changing color in begin/end blocks.
2528                  */
2529                 glLineWidth(1.5f);
2530                 if(do_shaded) {
2531                         glBegin(GL_LINES);
2532                         for(i=0; i<LINK_RESOL; i++) {
2533                                 UI_ThemeColorBlend(th_col1, th_col2, spline_step);
2534                                 glVertex2fv(coord_array[i]);
2535                                 
2536                                 UI_ThemeColorBlend(th_col1, th_col2, spline_step+dist);
2537                                 glVertex2fv(coord_array[i+1]);
2538                                 
2539                                 spline_step += dist;
2540                         }
2541                         glEnd();
2542                 }
2543                 else {
2544                         UI_ThemeColor(th_col1);
2545                         glBegin(GL_LINE_STRIP);
2546                         for(i=0; i<=LINK_RESOL; i++) {
2547                                 glVertex2fv(coord_array[i]);
2548                         }
2549                         glEnd();
2550                 }
2551                 
2552                 glDisable(GL_LINE_SMOOTH);
2553                 
2554                 /* restore previuos linewidth */
2555                 glLineWidth(linew);
2556         }
2557 }
2558
2559 static void node_link_straight_points(View2D *UNUSED(v2d), SpaceNode *snode, bNodeLink *link, float coord_array[][2])
2560 {
2561         if(link->fromsock) {
2562                 coord_array[0][0]= link->fromsock->locx;
2563                 coord_array[0][1]= link->fromsock->locy;
2564         }
2565         else {
2566                 if(snode==NULL) return;
2567                 coord_array[0][0]= snode->mx;
2568                 coord_array[0][1]= snode->my;
2569         }
2570         if(link->tosock) {
2571                 coord_array[1][0]= link->tosock->locx;
2572                 coord_array[1][1]= link->tosock->locy;
2573         }
2574         else {
2575                 if(snode==NULL) return;
2576                 coord_array[1][0]= snode->mx;
2577                 coord_array[1][1]= snode->my;
2578         }
2579 }
2580
2581 void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 )
2582 {
2583         float coord_array[2][2];
2584         float linew;
2585         int i;
2586         
2587         node_link_straight_points(v2d, snode, link, coord_array);
2588         
2589         /* store current linewidth */
2590         glGetFloatv(GL_LINE_WIDTH, &linew);
2591         
2592         glEnable(GL_LINE_SMOOTH);
2593         
2594         if(do_triple) {
2595                 UI_ThemeColorShadeAlpha(th_col3, -80, -120);
2596                 glLineWidth(4.0f);
2597                 
2598                 glBegin(GL_LINES);
2599                 glVertex2fv(coord_array[0]);
2600                 glVertex2fv(coord_array[1]);
2601                 glEnd();
2602         }
2603         
2604         UI_ThemeColor(th_col1);
2605         glLineWidth(1.5f);
2606         
2607         /* XXX using GL_LINES for shaded node lines is a workaround
2608          * for Intel hardware, this breaks with GL_LINE_STRIP and
2609          * changing color in begin/end blocks.
2610          */
2611         if(do_shaded) {
2612                 glBegin(GL_LINES);
2613                 for (i=0; i < LINK_RESOL-1; ++i) {
2614                         float t= (float)i/(float)(LINK_RESOL-1);
2615                         UI_ThemeColorBlend(th_col1, th_col2, t);
2616                         glVertex2f((1.0f-t)*coord_array[0][0]+t*coord_array[1][0], (1.0f-t)*coord_array[0][1]+t*coord_array[1][1]);
2617                         
2618                         t= (float)(i+1)/(float)(LINK_RESOL-1);
2619                         UI_ThemeColorBlend(th_col1, th_col2, t);
2620                         glVertex2f((1.0f-t)*coord_array[0][0]+t*coord_array[1][0], (1.0f-t)*coord_array[0][1]+t*coord_array[1][1]);
2621                 }
2622                 glEnd();
2623         }
2624         else {
2625                 glBegin(GL_LINE_STRIP);
2626                 for (i=0; i < LINK_RESOL; ++i) {
2627                         float t= (float)i/(float)(LINK_RESOL-1);
2628                         glVertex2f((1.0f-t)*coord_array[0][0]+t*coord_array[1][0], (1.0f-t)*coord_array[0][1]+t*coord_array[1][1]);
2629                 }
2630                 glEnd();
2631         }
2632         
2633         glDisable(GL_LINE_SMOOTH);
2634         
2635         /* restore previuos linewidth */
2636         glLineWidth(linew);
2637 }
2638
2639 /* note; this is used for fake links in groups too */
2640 void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
2641 {
2642         int do_shaded= 0, th_col1= TH_HEADER, th_col2= TH_HEADER;
2643         int do_triple= 0, th_col3= TH_WIRE;
2644         
2645         if(link->fromsock==NULL && link->tosock==NULL)
2646                 return;
2647         
2648         /* new connection */
2649         if(!link->fromsock || !link->tosock) {
2650                 th_col1 = TH_ACTIVE;
2651                 do_triple = 1;
2652         }
2653         else {
2654                 /* going to give issues once... */
2655                 if(link->tosock->flag & SOCK_UNAVAIL)
2656                         return;
2657                 if(link->fromsock->flag & SOCK_UNAVAIL)
2658                         return;
2659                 
2660                 /* a bit ugly... but thats how we detect the internal group links */
2661                 if(!link->fromnode || !link->tonode) {
2662                         UI_ThemeColorBlend(TH_BACK, TH_WIRE, 0.5f);
2663                         do_shaded= 0;
2664                 }
2665                 else {
2666                         /* check cyclic */
2667                         if((link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) && (link->flag & NODE_LINK_VALID)) {
2668                                 /* special indicated link, on drop-node */
2669                                 if(link->flag & NODE_LINKFLAG_HILITE) {
2670                                         th_col1= th_col2= TH_ACTIVE;
2671                                 }
2672                                 else {
2673                                         /* regular link */
2674                                         if(link->fromnode->flag & SELECT)
2675                                                 th_col1= TH_EDGE_SELECT;
2676                                         if(link->tonode->flag & SELECT)
2677                                                 th_col2= TH_EDGE_SELECT;
2678                                 }
2679                                 do_shaded= 1;
2680                                 do_triple= 1;
2681                         }                               
2682                         else {
2683                                 th_col1 = TH_REDALERT;
2684                         }
2685                 }
2686         }
2687         
2688         node_draw_link_bezier(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
2689 //      node_draw_link_straight(v2d, snode, link, th_col1, do_shaded, th_col2, do_triple, th_col3);
2690 }