Merging r46725 through r46963 from trunk into soc-2011-tomato
[blender.git] / source / blender / editors / space_node / drawnode.c
index 4e9ac08..fcc92ff 100644 (file)
@@ -53,6 +53,8 @@
 #include "BKE_main.h"
 #include "BKE_node.h"
 
+#include "BLF_api.h"
+
 #include "NOD_composite.h"
 #include "NOD_shader.h"
 
@@ -79,7 +81,6 @@
 
 #include "node_intern.h"
 
-
 // XXX interface.h
 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
 
@@ -89,7 +90,7 @@ static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v)
 {
        SpaceNode *snode= snode_v;
        
-       if(snode->treetype==NTREE_SHADER) {
+       if (snode->treetype==NTREE_SHADER) {
                nodeShaderSynchronizeID(node_v, 1);
                // allqueue(REDRAWBUTSSHADING, 0);
        }
@@ -102,21 +103,24 @@ static void node_socket_button_label(const bContext *UNUSED(C), uiBlock *block,
        uiDefBut(block, LABEL, 0, sock->name, x, y, width, NODE_DY, NULL, 0, 0, 0, 0, "");
 }
 
-
 static void node_socket_button_default(const bContext *C, uiBlock *block,
                                                                bNodeTree *ntree, bNode *node, bNodeSocket *sock,
                                                                const char *name, int x, int y, int width)
 {
-       PointerRNA ptr;
-       uiBut *bt;
-       
-       RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
-       
-       bt = uiDefButR(block, NUM, B_NODE_EXEC, name,
-                                  x, y+1, width, NODE_DY-2, 
-                                  &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
-       if (node)
-               uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
+       if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
+               node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
+       else {
+               PointerRNA ptr;
+               uiBut *bt;
+               
+               RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
+               
+               bt = uiDefButR(block, NUM, B_NODE_EXEC, name,
+                                          x, y+1, width, NODE_DY-2, 
+                                          &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
+               if (node)
+                       uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
+       }
 }
 
 typedef struct SocketComponentMenuArgs {
@@ -132,7 +136,7 @@ static uiBlock *socket_component_menu(bContext *C, ARegion *ar, void *args_v)
        uiBlock *block;
        uiLayout *layout;
        
-       block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS);
+       block= uiBeginBlock(C, ar, __func__, UI_EMBOSS);
        uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
        
        layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, NODE_DY, UI_GetStyle()), 0);
@@ -145,42 +149,78 @@ static void node_socket_button_components(const bContext *C, uiBlock *block,
                                                                   bNodeTree *ntree, bNode *node, bNodeSocket *sock,
                                                                   const char *name, int x, int y, int width)
 {
-       PointerRNA ptr;
-       SocketComponentMenuArgs *args;
-       
-       RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
-       
-       args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs");
-       
-       args->ptr = ptr;
-       args->x = x;
-       args->y = y;
-       args->width = width;
-       args->cb = node_sync_cb;
-       args->arg1 = CTX_wm_space_node(C);
-       args->arg2 = node;
-       
-       uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, "");
+       if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
+               node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
+       else {
+               PointerRNA ptr;
+               SocketComponentMenuArgs *args;
+               
+               RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
+               
+               args= MEM_callocN(sizeof(SocketComponentMenuArgs), "SocketComponentMenuArgs");
+               
+               args->ptr = ptr;
+               args->x = x;
+               args->y = y;
+               args->width = width;
+               args->cb = node_sync_cb;
+               args->arg1 = CTX_wm_space_node(C);
+               args->arg2 = node;
+               
+               uiDefBlockButN(block, socket_component_menu, args, name, x, y+1, width, NODE_DY-2, "");
+       }
 }
 
 static void node_socket_button_color(const bContext *C, uiBlock *block,
                                                          bNodeTree *ntree, bNode *node, bNodeSocket *sock,
                                                          const char *name, int x, int y, int width)
 {
-       PointerRNA ptr;
-       uiBut *bt;
-       int labelw= width - 40;
-       
-       RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
-       
-       bt=uiDefButR(block, COL, B_NODE_EXEC, "",
-                                x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, 
-                                &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
-       if (node)
-               uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
-       
-       if (name[0]!='\0' && labelw>0)
-               uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, "");
+       if (sock->link || (sock->flag & SOCK_HIDE_VALUE))
+               node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
+       else {
+               PointerRNA ptr;
+               uiBut *bt;
+               int labelw= width - 40;
+               RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
+               
+               bt=uiDefButR(block, COL, B_NODE_EXEC, "",
+                                        x, y+2, (labelw>0 ? 40 : width), NODE_DY-2, 
+                                        &ptr, "default_value", 0, 0, 0, -1, -1, NULL);
+               if (node)
+                       uiButSetFunc(bt, node_sync_cb, CTX_wm_space_node(C), node);
+               
+               if (name[0]!='\0' && labelw>0)
+                       uiDefBut(block, LABEL, 0, name, x + 40, y+2, labelw, NODE_DY-2, NULL, 0, 0, 0, 0, "");
+       }
+}
+
+/* standard draw function, display the default input value */
+static void node_draw_input_default(const bContext *C, uiBlock *block,
+                                     bNodeTree *ntree, bNode *node, bNodeSocket *sock,
+                                     const char *name, int x, int y, int width)
+{
+       bNodeSocketType *stype = ntreeGetSocketType(sock->type);
+       if (stype->buttonfunc)
+               stype->buttonfunc(C, block, ntree, node, sock, name, x, y, width);
+       else
+               node_socket_button_label(C, block, ntree, node, sock, name, x, y, width);
+}
+
+static void node_draw_output_default(const bContext *C, uiBlock *block,
+                                     bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock,
+                                     const char *name, int UNUSED(x), int UNUSED(y), int UNUSED(width))
+{
+       SpaceNode *snode = CTX_wm_space_node(C);
+       float slen;
+       int ofs = 0;
+       UI_ThemeColor(TH_TEXT);
+       slen= snode->aspect*UI_GetStringWidth(name);
+       while (slen > node->width) {
+               ofs++;
+               slen= snode->aspect*UI_GetStringWidth(name+ofs);
+       }
+       uiDefBut(block, LABEL, 0, name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 
+             (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
 }
 
 /* ****************** BASE DRAW FUNCTIONS FOR NEW OPERATOR NODES ***************** */
@@ -192,7 +232,7 @@ static void node_draw_socket_new(bNodeSocket *sock, float size)
        
        /* 16 values of sin function */
        static float si[16] = {
-               0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
+               0.00000000f, 0.39435585f, 0.72479278f,0.93775213f,
                0.99871650f,0.89780453f,0.65137248f,0.29936312f,
                -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
                -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
@@ -209,18 +249,18 @@ static void node_draw_socket_new(bNodeSocket *sock, float size)
        glColor3ub(180, 180, 180);
        
        glBegin(GL_POLYGON);
-       for(a=0; a<16; a++)
+       for (a=0; a<16; a++)
                glVertex2f(x+size*si[a], y+size*co[a]);
        glEnd();
        
        glColor4ub(0, 0, 0, 150);
        glEnable(GL_BLEND);
-       glEnable( GL_LINE_SMOOTH );
+       glEnable(GL_LINE_SMOOTH);
        glBegin(GL_LINE_LOOP);
-       for(a=0; a<16; a++)
+       for (a=0; a<16; a++)
                glVertex2f(x+size*si[a], y+size*co[a]);
        glEnd();
-       glDisable( GL_LINE_SMOOTH );
+       glDisable(GL_LINE_SMOOTH);
        glDisable(GL_BLEND);
 }
 #endif
@@ -262,7 +302,7 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
 
        row= uiLayoutRow(layout, 1);
        uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
-       if(ntree->type == NTREE_COMPOSIT)
+       if (ntree->type == NTREE_COMPOSIT)
                uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA);
 }
 
@@ -274,9 +314,9 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
        bNode *node= ptr->data;
        CurveMapping *cumap= node->storage;
        
-       if(cumap) {
+       if (cumap) {
                cumap->flag |= CUMA_DRAW_CFRA;
-               if(node->custom1<node->custom2)
+               if (node->custom1<node->custom2)
                        cumap->sample[0]= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
        }
 #endif
@@ -311,7 +351,7 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA
        bNode *node= ptr->data;
        CurveMapping *cumap= node->storage;
 
-       if(_sample_col) {
+       if (_sample_col) {
                cumap->flag |= CUMA_DRAW_SAMPLE;
                copy_v3_v3(cumap->sample, _sample_col);
        }
@@ -353,9 +393,9 @@ static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v)
        bNode *node= node_v;
        Tex *tex;
        
-       if(node->menunr<1) return;
+       if (node->menunr<1) return;
        
-       if(node->id) {
+       if (node->id) {
                node->id->us--;
                node->id= NULL;
        }
@@ -367,8 +407,8 @@ static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v)
        
        nodeSetActive(ntree, node);
        
-       if( ntree->type == NTREE_TEXTURE )
-               ntreeTexCheckCyclics( ntree );
+       if ( ntree->type == NTREE_TEXTURE )
+               ntreeTexCheckCyclics(ntree);
        
        // allqueue(REDRAWBUTSSHADING, 0);
        // allqueue(REDRAWNODE, 0);
@@ -422,7 +462,7 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
        
        uiItemR(layout, ptr, "texture", 0, "", ICON_NONE);
        
-       if(multi) {
+       if (multi) {
                /* Number Drawing not optimal here, better have a list*/
                uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE);
        }
@@ -438,16 +478,22 @@ static int node_resize_area_default(bNode *node, int x, int y)
        if (node->flag & NODE_HIDDEN) {
                rctf totr= node->totr;
                /* right part of node */
-               totr.xmin= node->totr.xmax-20.0f;
-               return BLI_in_rctf(&totr, x, y);
+               totr.xmin = node->totr.xmax-20.0f;
+               if (BLI_in_rctf(&totr, x, y))
+                       return NODE_RESIZE_RIGHT;
+               else
+                       return 0;
        }
        else {
-               /* rect we're interested in is just the bottom right corner */
+               const float size = 10.0f;
                rctf totr= node->totr;
-               /* bottom right corner */
-               totr.xmin= totr.xmax-10.0f;
-               totr.ymax= totr.ymin+10.0f;
-               return BLI_in_rctf(&totr, x, y);
+               int dir = 0;
+               
+               if (x >= totr.xmax-size && x < totr.xmax && y >= totr.ymin && y < totr.ymax)
+                       dir |= NODE_RESIZE_RIGHT;
+               if (x >= totr.xmin && x < totr.xmin+size && y >= totr.ymin && y < totr.ymax)
+                       dir |= NODE_RESIZE_LEFT;
+               return dir;
        }
 }
 
@@ -476,7 +522,7 @@ static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode)
                int dy;
                
                /* get "global" coords */
-               nodeSpaceCoords(gnode, &locx, &locy);
+               nodeToView(gnode, 0.0f, 0.0f, &locx, &locy);
                
                /* center them, is a bit of abuse of locx and locy though */
                node_update_nodetree(C, ngroup, locx, locy);
@@ -485,8 +531,8 @@ static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode)
                rect->ymin = rect->ymax = locy;
                
                counter= 1;
-               for(node= ngroup->nodes.first; node; node= node->next) {
-                       if(counter) {
+               for (node= ngroup->nodes.first; node; node= node->next) {
+                       if (counter) {
                                *rect= node->totr;
                                counter= 0;
                        }
@@ -631,7 +677,7 @@ static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *
        if (sock->flag & SOCK_DYNAMIC) {
                bt = uiDefBut(gnode->block, TEX, 0, "", 
                                          sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY,
-                                         sock->name, 0, 31, 0, 0, "");
+                                         sock->name, 0, sizeof(sock->name), 0, 0, "");
                if (in_out==SOCK_IN)
                        uiButSetFunc(bt, update_group_input_cb, snode, ngroup);
                else
@@ -640,7 +686,7 @@ static void draw_group_socket_name(SpaceNode *snode, bNode *gnode, bNodeSocket *
        else {
                uiDefBut(gnode->block, LABEL, 0, sock->name,
                         sock->locx+xoffset, sock->locy+1+yoffset, 72, NODE_DY,
-                        NULL, 0, 31, 0, 0, "");
+                        NULL, 0, sizeof(sock->name), 0, 0, "");
        }
 }
 
@@ -796,16 +842,16 @@ static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bN
                /* group node outline */
                uiSetRoundBox(UI_CNR_ALL);
                glColor4ub(200, 200, 200, 140);
-               glEnable( GL_LINE_SMOOTH );
+               glEnable(GL_LINE_SMOOTH);
                uiDrawBox(GL_LINE_LOOP, rect.xmin-node_group_frame, rect.ymin, rect.xmax+node_group_frame, rect.ymax+group_header, BASIS_RAD);
-               glDisable( GL_LINE_SMOOTH );
+               glDisable(GL_LINE_SMOOTH);
                glDisable(GL_BLEND);
                
                /* backdrop title */
                UI_ThemeColor(TH_TEXT_HI);
        
                layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+group_header),
-                                                          MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, UI_GetStyle());
+                                      MIN2((int)(rect.xmax - rect.xmin-18.0f), node_group_frame+20), group_header, UI_GetStyle());
                RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr);
                uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL);
                uiBlockLayoutResolve(gnode->block, NULL, NULL);
@@ -871,25 +917,171 @@ static void node_common_buts_whileloop(uiLayout *layout, bContext *UNUSED(C), Po
        uiItemR(layout, ptr, "max_iterations", 0, NULL, 0);
 }
 
-static void node_update_frame(const bContext *UNUSED(C), bNodeTree *UNUSED(ntree), bNode *node)
+/* XXX Does a bounding box update by iterating over all children.
+ * Not ideal to do this in every draw call, but doing as transform callback doesn't work,
+ * since the child node totr rects are not updated properly at that point.
+ */
+static void node_update_frame(const bContext *UNUSED(C), bNodeTree *ntree, bNode *node)
+{
+       const float margin = 30.0f;
+       NodeFrame *data = (NodeFrame *)node->storage;
+       int bbinit;
+       bNode *tnode;
+       rctf rect, noderect;
+       float xmax, ymax;
+       
+       /* init rect from current frame size */
+       nodeToView(node, node->offsetx, node->offsety, &rect.xmin, &rect.ymax);
+       nodeToView(node, node->offsetx+node->width, node->offsety-node->height, &rect.xmax, &rect.ymin);
+       
+       /* frame can be resized manually only if shrinking is disabled or no children are attached */
+       data->flag |= NODE_FRAME_RESIZEABLE;
+       /* for shrinking bbox, initialize the rect from first child node */
+       bbinit = (data->flag & NODE_FRAME_SHRINK);
+       /* fit bounding box to all children */
+       for (tnode=ntree->nodes.first; tnode; tnode=tnode->next) {
+               if (tnode->parent!=node)
+                       continue;
+               
+               /* add margin to node rect */
+               noderect = tnode->totr;
+               noderect.xmin -= margin;
+               noderect.xmax += margin;
+               noderect.ymin -= margin;
+               noderect.ymax += margin;
+               
+               /* first child initializes frame */
+               if (bbinit) {
+                       bbinit = 0;
+                       rect = noderect;
+                       data->flag &= ~NODE_FRAME_RESIZEABLE;
+               }
+               else
+                       BLI_union_rctf(&rect, &noderect);
+       }
+       
+       /* now adjust the frame size from view-space bounding box */
+       nodeFromView(node, rect.xmin, rect.ymax, &node->offsetx, &node->offsety);
+       nodeFromView(node, rect.xmax, rect.ymin, &xmax, &ymax);
+       node->width = xmax - node->offsetx;
+       node->height = -ymax + node->offsety;
+       
+       node->totr = rect;
+}
+
+static void node_draw_frame_label(bNode *node)
 {
-       float locx, locy;
+       /* XXX font id is crap design */
+       const int fontid = blf_mono_font;
+       NodeFrame *data = (NodeFrame *)node->storage;
+       rctf *rct= &node->totr;
+       int color_id= node_get_colorid(node);
+       char label[128];
+       /* XXX a bit hacky, should use separate align values for x and y */
+       float width, ascender;
+       float x, y;
+       
+       BLI_strncpy(label, nodeLabel(node), sizeof(label));
+       BLF_size(fontid, data->label_size, U.dpi);
+       
+       /* title color */
+       UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.8f, 10);
 
-       /* get "global" coords */
-       nodeSpaceCoords(node, &locx, &locy);
+       width = BLF_width(fontid, label);
+       ascender = BLF_ascender(fontid);
+       
+       x = 0.5f*(rct->xmin + rct->xmax) - 0.5f*width;
+       y = rct->ymax - NODE_DYS - ascender;
+       
+       BLF_position(fontid, x, y, 0);
+       BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+}
 
-       node->prvr.xmin= locx + NODE_DYS;
-       node->prvr.xmax= locx + node->width- NODE_DYS;
+static void node_draw_frame(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *UNUSED(ntree), bNode *node)
+{
+       rctf *rct= &node->totr;
+       int color_id= node_get_colorid(node);
+       
+       /* skip if out of view */
+       if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
+                       node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
+               
+               uiEndBlock(C, node->block);
+               node->block= NULL;
+               return;
+       }
+       
+       /* shadow */
+       node_draw_shadow(snode, node, BASIS_RAD);
+       
+       /* body */
+       if (node->flag & NODE_CUSTOM_COLOR)
+               glColor3fv(node->color);
+       else
+               UI_ThemeColor4(TH_NODE);
+       glEnable(GL_BLEND);
+       uiSetRoundBox(UI_CNR_ALL);
+       uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
+       glDisable(GL_BLEND);
 
-       node->totr.xmin= locx;
-       node->totr.xmax= locx + node->width;
-       node->totr.ymax= locy;
-       node->totr.ymin= locy - node->height;
+       /* outline active and selected emphasis */
+       if ( node->flag & (NODE_ACTIVE|SELECT) ) {
+               glEnable(GL_BLEND);
+               glEnable( GL_LINE_SMOOTH );
+               
+               if (node->flag & NODE_ACTIVE)
+                       UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -40);
+               else
+                       UI_ThemeColorShadeAlpha(TH_SELECT, 0, -40);
+               uiSetRoundBox(UI_CNR_ALL);
+               uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
+               
+               glDisable( GL_LINE_SMOOTH );
+               glDisable(GL_BLEND);
+       }
+       
+       /* label */
+       node_draw_frame_label(node);
+       
+       UI_ThemeClearColor(color_id);
+               
+       uiEndBlock(C, node->block);
+       uiDrawBlock(C, node->block);
+       node->block= NULL;
+}
+
+static int node_resize_area_frame(bNode *node, int x, int y)
+{
+       const float size = 10.0f;
+       NodeFrame *data = (NodeFrame *)node->storage;
+       rctf totr= node->totr;
+       int dir = 0;
+       
+       /* shrinking frame size is determined by child nodes */
+       if (!(data->flag & NODE_FRAME_RESIZEABLE))
+               return 0;
+       
+       if (x >= totr.xmax-size && x < totr.xmax && y >= totr.ymin && y < totr.ymax)
+               dir |= NODE_RESIZE_RIGHT;
+       if (x >= totr.xmin && x < totr.xmin+size && y >= totr.ymin && y < totr.ymax)
+               dir |= NODE_RESIZE_LEFT;
+       if (x >= totr.xmin && x < totr.xmax && y >= totr.ymax-size && y < totr.ymax)
+               dir |= NODE_RESIZE_TOP;
+       if (x >= totr.xmin && x < totr.xmax && y >= totr.ymin && y < totr.ymin+size)
+               dir |= NODE_RESIZE_BOTTOM;
+       
+       return dir;
+}
+
+static void node_buts_frame_details(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "label_size", 0, "Label Size", ICON_NONE);
+       uiItemR(layout, ptr, "shrink", 0, "Shrink", ICON_NONE);
 }
 
 static void node_common_set_butfunc(bNodeType *ntype)
 {
-       switch(ntype->type) {
+       switch (ntype->type) {
                case NODE_GROUP:
                        ntype->uifunc= node_uifunc_group;
                        ntype->drawfunc= node_draw_group;
@@ -906,7 +1098,10 @@ static void node_common_set_butfunc(bNodeType *ntype)
                        ntype->drawupdatefunc= node_update_group;
                        break;
                case NODE_FRAME:
+                       ntype->drawfunc= node_draw_frame;
                        ntype->drawupdatefunc= node_update_frame;
+                       ntype->uifuncbut= node_buts_frame_details;
+                       ntype->resize_area_func= node_resize_area_frame;
                        break;
        }
 }
@@ -920,9 +1115,9 @@ static void node_browse_text_cb(bContext *C, void *ntree_v, void *node_v)
        bNode *node= node_v;
        /* ID *oldid; */ /* UNUSED */
        
-       if(node->menunr<1) return;
+       if (node->menunr<1) return;
        
-       if(node->id) {
+       if (node->id) {
                node->id->us--;
        }
        /* oldid= node->id; */ /* UNUSED */
@@ -947,7 +1142,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA
        
        uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL);
        
-       if(!node->id) return;
+       if (!node->id) return;
        
        col= uiLayoutColumn(layout, 0);
        uiItemR(col, ptr, "use_diffuse", 0, NULL, ICON_NONE);
@@ -961,7 +1156,7 @@ static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), Poin
        
        uiItemL(layout, "Location:", ICON_NONE);
        row= uiLayoutRow(layout, 1);
-       uiItemR(row, ptr, "location", 0, "", ICON_NONE);
+       uiItemR(row, ptr, "translation", 0, "", ICON_NONE);
        
        uiItemL(layout, "Rotation:", ICON_NONE);
        row= uiLayoutRow(layout, 1);
@@ -992,7 +1187,7 @@ static void node_shader_buts_geometry(uiLayout *layout, bContext *C, PointerRNA
 
        col= uiLayoutColumn(layout, 0);
 
-       if(obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+       if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
                PointerRNA dataptr= RNA_pointer_get(&obptr, "data");
 
                uiItemPointerR(col, ptr, "uv_layer", &dataptr, "uv_textures", "", ICON_NONE);
@@ -1015,6 +1210,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
        uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
 }
 
+
+static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+       uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+       uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
+       uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+}
+
 static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
@@ -1064,7 +1267,7 @@ static void node_shader_buts_dynamic(uiLayout *layout, bContext *C, PointerRNA *
        int xoff=0;
 
        /* B_NODE_EXEC is handled in butspace.c do_node_buts */
-       if(!node->id) {
+       if (!node->id) {
                        const char *strp;
                        IDnames_to_pupstring(&strp, NULL, "", &(bmain->text), NULL, NULL);
                        node->menunr= 0;
@@ -1073,7 +1276,7 @@ static void node_shader_buts_dynamic(uiLayout *layout, bContext *C, PointerRNA *
                                                        &node->menunr, 0, 0, 0, 0, "Browses existing choices");
                        uiButSetFunc(bt, node_browse_text_cb, ntree, node);
                        xoff=19;
-                       if(strp) MEM_freeN((void *)strp);
+                       if (strp) MEM_freeN((void *)strp);
        }
        else {
                bt = uiDefBut(block, BUT, B_NOP, "Update",
@@ -1093,8 +1296,7 @@ static void node_shader_buts_dynamic(uiLayout *layout, bContext *C, PointerRNA *
 /* only once called */
 static void node_shader_set_butfunc(bNodeType *ntype)
 {
-       ntype->uifuncbut = NULL;
-       switch(ntype->type) {
+       switch (ntype->type) {
                /* case NODE_GROUP:      note, typeinfo for group is generated... see "XXX ugly hack" */
 
                case SH_NODE_MATERIAL:
@@ -1147,7 +1349,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                        ntype->uifunc= node_shader_buts_tex_image;
                        break;
                case SH_NODE_TEX_ENVIRONMENT:
-                       ntype->uifunc= node_shader_buts_tex_image;
+                       ntype->uifunc= node_shader_buts_tex_environment;
                        break;
                case SH_NODE_TEX_GRADIENT:
                        ntype->uifunc= node_shader_buts_tex_gradient;
@@ -1172,7 +1374,6 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                        ntype->uifunc= node_shader_buts_dynamic;
                        break;
        }
-               if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
 }
 
 /* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
@@ -1187,7 +1388,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
        
        uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
        
-       if(!node->id) return;
+       if (!node->id) return;
        
        prop = RNA_struct_find_property(ptr, "image");
        if (!prop || RNA_property_type(prop) != PROP_POINTER) return;
@@ -1199,14 +1400,14 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
        
        source= RNA_enum_get(&imaptr, "source");
 
-       if(source == IMA_SRC_SEQUENCE) {
+       if (source == IMA_SRC_SEQUENCE) {
                /* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
                Scene *scene= CTX_data_scene(C);
                ImageUser *iuser= node->storage;
-               char tstr[32];
-               const int framenr= BKE_image_user_get_frame(iuser, CFRA, 0);
-               BLI_snprintf(tstr, sizeof(tstr), "Frame: %d", framenr);
-               uiItemL(layout, tstr, ICON_NONE);
+               char numstr[32];
+               const int framenr= BKE_image_user_frame_get(iuser, CFRA, 0);
+               BLI_snprintf(numstr, sizeof(numstr), "Frame: %d", framenr);
+               uiItemL(layout, numstr, ICON_NONE);
        }
 
        if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
@@ -1219,7 +1420,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
        }
 
        col= uiLayoutColumn(layout, 0);
-       
+
        if (RNA_enum_get(&imaptr, "type")== IMA_TYPE_MULTILAYER)
                uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
 }
@@ -1233,10 +1434,13 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
        PropertyRNA *prop;
        const char *layer_name;
        char scene_name[MAX_ID_NAME-2];
-       
+       wmOperatorType *ot = WM_operatortype_find("RENDER_OT_render", 1);
+
+       BLI_assert(ot != 0);
+
        uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
        
-       if(!node->id) return;
+       if (!node->id) return;
 
        col= uiLayoutColumn(layout, 0);
        row = uiLayoutRow(col, 0);
@@ -1249,10 +1453,10 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
        scn_ptr = RNA_pointer_get(ptr, "scene");
        RNA_string_get(&scn_ptr, "name", scene_name);
        
-       WM_operator_properties_create(&op_ptr, "RENDER_OT_render");
+       WM_operator_properties_create_ptr(&op_ptr, ot);
        RNA_string_set(&op_ptr, "layer", layer_name);
        RNA_string_set(&op_ptr, "scene", scene_name);
-       uiItemFullO(row, "RENDER_OT_render", "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
+       uiItemFullO_ptr(row, ot, "", ICON_RENDER_STILL, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
 
 }
 
@@ -1333,7 +1537,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *UNUSED(C), Po
        uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
 
        col = uiLayoutColumn(layout, 0);
-       uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer")==1);
+       uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == TRUE);
        uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE);
 
        uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
@@ -1348,7 +1552,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *UNUSED(C), Po
        col = uiLayoutColumn(layout, 0);
        uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
        sub = uiLayoutColumn(col, 0);
-       uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer")==0);
+       uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == FALSE);
        uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE);
 }
 
@@ -1410,7 +1614,7 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P
        uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE);
 
        col = uiLayoutColumn(col, 0);
-       uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector")==0);
+       uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == FALSE);
        uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE);
        uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE);
 }
@@ -1449,12 +1653,13 @@ static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), Point
        uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE);
 
        col= uiLayoutColumn(layout, 1);
-       if (RNA_boolean_get(ptr, "relative")){
+       if (RNA_boolean_get(ptr, "relative")) {
                uiItemR(col, ptr, "rel_min_x", 0, "Left", ICON_NONE);
                uiItemR(col, ptr, "rel_max_x", 0, "Right", ICON_NONE);
                uiItemR(col, ptr, "rel_min_y", 0, "Up", ICON_NONE);
                uiItemR(col, ptr, "rel_max_y", 0, "Down", ICON_NONE);
-       } else {
+       }
+       else {
                uiItemR(col, ptr, "min_x", 0, "Left", ICON_NONE);
                uiItemR(col, ptr, "max_x", 0, "Right", ICON_NONE);
                uiItemR(col, ptr, "min_y", 0, "Up", ICON_NONE);
@@ -1472,23 +1677,35 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C)
        uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
 }
 
+static void node_composit_buts_double_edge_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiLayout *col;
+
+       col= uiLayoutColumn(layout, 0);
+
+       uiItemL(col, "Inner Edge:", ICON_NONE);
+       uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
+       uiItemL(col, "Buffer Edge:", ICON_NONE);
+       uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
+}
+
 static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiLayout *sub, *col;
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
        uiItemR(col, ptr, "size", 0, NULL, ICON_NONE);
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE);
-       sub =uiLayoutColumn(col, 0);
+       sub = uiLayoutColumn(col, 0);
        uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
        uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE);
-       sub =uiLayoutColumn(col, 0);
+       sub = uiLayoutColumn(col, 0);
        uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
        uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
 }
@@ -1497,7 +1714,7 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C),
 {      
        uiLayout *col;
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE);
        uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE);
 }
@@ -1506,7 +1723,7 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
 {      
        uiLayout *col;
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE);
 }
 
@@ -1515,7 +1732,7 @@ static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), Po
 {
        uiLayout *col;
        
-       col =uiLayoutColumn(layout, 0);
+       col = uiLayoutColumn(layout, 0);
        uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
        uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
        uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
@@ -1523,23 +1740,32 @@ static void node_composit_buts_hue_sat(uiLayout *layout, bContext *UNUSED(C), Po
 
 static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
+       uiItemR(layout, ptr, "type", 0, NULL, ICON_NONE);
        uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+       if (RNA_enum_get(ptr, "type") == CMP_NODE_DILATEERODE_DISTANCE) {
+               uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE);
+       }
 }
 
 static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
        uiLayout *col;
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
        uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
        uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
 }
 
 static void node_composit_buts_distance_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
-       uiLayout *col;
+       uiLayout *col, *row;
        
-       col =uiLayoutColumn(layout, 1);
+       col = uiLayoutColumn(layout, 1);
+   
+       uiItemL(layout, "Color Space:", ICON_NONE);
+       row= uiLayoutRow(layout, 0);
+       uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
        uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
        uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
 }
@@ -1549,21 +1775,21 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C)
        uiLayout *row, *col;
        
        uiItemL(layout, "Despill Channel:", ICON_NONE);
-       row =uiLayoutRow(layout,0);
+       row = uiLayoutRow(layout, 0);
        uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
 
        col= uiLayoutColumn(layout, 0);
        uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
 
-       if(RNA_enum_get(ptr, "limit_method")==0) {
+       if (RNA_enum_get(ptr, "limit_method")==0) {
                uiItemL(col, "Limiting Channel:", ICON_NONE);
-               row=uiLayoutRow(col,0);
+               row=uiLayoutRow(col, 0);
                uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
        }
 
        uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
        uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE);
-       if (RNA_boolean_get(ptr, "use_unspill")== 1) {
+       if (RNA_boolean_get(ptr, "use_unspill") == TRUE) {
                uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
                uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
                uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
@@ -1607,12 +1833,12 @@ static void node_composit_buts_channel_matte(uiLayout *layout, bContext *UNUSED(
        row= uiLayoutRow(col, 0);
        uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
 
-       col =uiLayoutColumn(layout, 0);
+       col = uiLayoutColumn(layout, 0);
 
        uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
-       if(RNA_enum_get(ptr, "limit_method")==0) {
+       if (RNA_enum_get(ptr, "limit_method")==0) {
                uiItemL(col, "Limiting Channel:", ICON_NONE);
-               row=uiLayoutRow(col,0);
+               row=uiLayoutRow(col, 0);
                uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
        }
 
@@ -1640,22 +1866,124 @@ static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), Po
        uiItemR(layout, ptr, "use_smooth_mask", 0, NULL, ICON_NONE);
 }
 
+/* draw function for file output node sockets, displays only sub-path and format, no value button */
+static void node_draw_input_file_output(const bContext *C, uiBlock *block,
+                                         bNodeTree *ntree, bNode *node, bNodeSocket *sock,
+                                         const char *UNUSED(name), int x, int y, int width)
+{
+       uiLayout *layout, *row;
+       PointerRNA nodeptr, inputptr, imfptr;
+       int imtype;
+       int rx, ry;
+       RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+       
+       layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, x, y+NODE_DY, width, 20, UI_GetStyle());
+       row = uiLayoutRow(layout, 0);
+       
+       imfptr = RNA_pointer_get(&nodeptr, "format");
+       imtype = RNA_enum_get(&imfptr, "file_format");
+       if (imtype == R_IMF_IMTYPE_MULTILAYER) {
+               NodeImageMultiFileSocket *input = sock->storage;
+               RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotLayer, input, &inputptr);
+               
+               uiItemL(row, input->layer, 0);
+       }
+       else {
+               NodeImageMultiFileSocket *input = sock->storage;
+               PropertyRNA *imtype_prop;
+               const char *imtype_name;
+               RNA_pointer_create(&ntree->id, &RNA_NodeOutputFileSlotFile, input, &inputptr);
+               
+               uiItemL(row, input->path, 0);
+               
+               if (!RNA_boolean_get(&inputptr, "use_node_format"))
+                       imfptr = RNA_pointer_get(&inputptr, "format");
+               
+               imtype_prop = RNA_struct_find_property(&imfptr, "file_format");
+               RNA_property_enum_name((bContext*)C, &imfptr, imtype_prop, RNA_property_enum_get(&imfptr, imtype_prop), &imtype_name);
+               uiBlockSetEmboss(block, UI_EMBOSSP);
+               uiItemL(row, imtype_name, 0);
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+       }
+       
+       uiBlockLayoutResolve(block, &rx, &ry);
+}
 static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
-       bNode *node= ptr->data;
-       NodeImageFile *nif= node->storage;
-       PointerRNA imfptr;
-
+       PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+       int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
+       
+       if (multilayer)
+               uiItemL(layout, "Path:", 0);
+       else
+               uiItemL(layout, "Base Path:", 0);
+       uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE);
+}
+static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+       PointerRNA imfptr = RNA_pointer_get(ptr, "format");
+       PointerRNA active_input_ptr, op_ptr;
        uiLayout *row;
-
-       uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE);
-
-       RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &nif->im_format, &imfptr);
+       int active_index;
+       int multilayer = (RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER);
+       
+       node_composit_buts_file_output(layout, C, ptr);
        uiTemplateImageSettings(layout, &imfptr);
-
-       row= uiLayoutRow(layout, 1);
-       uiItemR(row, ptr, "frame_start", 0, "Start", ICON_NONE);
-       uiItemR(row, ptr, "frame_end", 0, "End", ICON_NONE);
+       
+       uiItemS(layout);
+       
+       uiItemO(layout, "Add Input", ICON_ZOOMIN, "NODE_OT_output_file_add_socket");
+       
+       active_index = RNA_int_get(ptr, "active_input_index");
+       /* using different collection properties if multilayer format is enabled */
+       if (multilayer) {
+               uiTemplateList(layout, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+               RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
+       }
+       else {
+               uiTemplateList(layout, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+               RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
+       }
+       /* XXX collection lookup does not return the ID part of the pointer, setting this manually here */
+       active_input_ptr.id.data = ptr->id.data;
+       
+       row = uiLayoutRow(layout, 1);
+       op_ptr = uiItemFullO(row, "NODE_OT_output_file_move_active_socket", "", ICON_TRIA_UP, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+       RNA_enum_set(&op_ptr, "direction", 1);
+       op_ptr = uiItemFullO(row, "NODE_OT_output_file_move_active_socket", "", ICON_TRIA_DOWN, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+       RNA_enum_set(&op_ptr, "direction", 2);
+       
+       if (active_input_ptr.data) {
+               if (multilayer) {
+                       uiLayout *row, *col;
+                       col = uiLayoutColumn(layout, 1);
+                       
+                       uiItemL(col, "Layer:", 0);
+                       row = uiLayoutRow(col, 0);
+                       uiItemR(row, &active_input_ptr, "name", 0, "", 0);
+                       uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY);
+               }
+               else {
+                       uiLayout *row, *col;
+                       col = uiLayoutColumn(layout, 1);
+                       
+                       uiItemL(col, "File Path:", 0);
+                       row = uiLayoutRow(col, 0);
+                       uiItemR(row, &active_input_ptr, "path", 0, "", 0);
+                       uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", ICON_X, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_R_ICON_ONLY);
+                       
+                       /* format details for individual files */
+                       imfptr = RNA_pointer_get(&active_input_ptr, "format");
+                       
+                       col = uiLayoutColumn(layout, 1);
+                       uiItemL(col, "Format:", 0);
+                       uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, 0);
+                       
+                       col= uiLayoutColumn(layout, 0);
+                       uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == FALSE);
+                       uiTemplateImageSettings(col, &imfptr);
+               }
+       }
 }
 
 static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1711,7 +2039,8 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
                row = uiLayoutRow(col, 0);
                uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE);
 
-       } else {
+       }
+       else {
                
                split = uiLayoutSplit(layout, 0, 0);
                col = uiLayoutColumn(split, 0);
@@ -1745,7 +2074,8 @@ static void node_composit_buts_colorbalance_but(uiLayout *layout, bContext *UNUS
 
                uiTemplateColorWheel(layout, ptr, "gain", 1, 1, 1, 1);
                uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE);
-       } else {
+       }
+       else {
                uiTemplateColorWheel(layout, ptr, "offset", 1, 1, 0, 1);
                uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
 
@@ -1779,7 +2109,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
 
        uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
 
-       if(!node->id)
+       if (!node->id)
                return;
 
        uiItemR(layout, ptr, "filter_type", 0, "", 0);
@@ -1796,17 +2126,277 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
 
        uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
 
-       if(!node->id)
+       if (!node->id)
                return;
 
        uiItemR(layout, ptr, "distortion_type", 0, "", 0);
 }
 
+static void node_composit_buts_colorcorrection(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiLayout *row;
+       
+       row = uiLayoutRow(layout, 0);
+       uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemL(row, "", 0);
+       uiItemL(row, "Saturation", 0);
+       uiItemL(row, "Contrast", 0);
+       uiItemL(row, "Gamma", 0);
+       uiItemL(row, "Gain", 0);
+       uiItemL(row, "Lift", 0);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemL(row, "Master", 0);
+       uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemL(row, "Highlights", 0);
+       uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemL(row, "Midtones", 0);
+       uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemL(row, "Shadows", 0);
+       uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
+       uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
+static void node_composit_buts_colorcorrection_but(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) {
+       uiLayout *row;
+       
+       row = uiLayoutRow(layout, 0);
+       uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+       row = layout;
+       uiItemL(row, "Saturation", 0);
+       uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       uiItemL(row, "Contrast", 0);
+       uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       uiItemL(row, "Gamma", 0);
+       uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       uiItemL(row, "Gain", 0);
+       uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       
+       uiItemL(row, "Lift", 0);
+       uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       row = uiLayoutRow(layout, 0);
+       uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE);
+}
+
+static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
+}
+
+static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiLayout *row;
+       
+       row= uiLayoutRow(layout, 1);
+       uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+       
+       row= uiLayoutRow(layout, 1);
+       uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+}
+
+static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
+void node_composit_backdrop_viewer(SpaceNode* snode, ImBuf* backdrop, bNode* node, int x, int y)
+{
+//     node_composit_backdrop_canvas(snode, backdrop, node, x, y);
+       if (node->custom1 == 0) { /// @todo: why did we need this one?
+               const float backdropWidth = backdrop->x;
+               const float backdropHeight = backdrop->y;
+               const float cx  = x+snode->zoom*backdropWidth*node->custom3;
+               const float cy = y+snode->zoom*backdropHeight*node->custom4;
+
+               glColor3f(1.0, 1.0, 1.0);
+
+               glBegin(GL_LINES);
+               glVertex2f(cx-25, cy-25);
+               glVertex2f(cx+25, cy+25);
+               glVertex2f(cx+25, cy-25);
+               glVertex2f(cx-25, cy+25);
+               glEnd();
+       }
+}
+
+void node_composit_backdrop_boxmask(SpaceNode* snode, ImBuf* backdrop, bNode* node, int x, int y)
+{
+       NodeBoxMask *boxmask = node->storage;
+       const float backdropWidth = backdrop->x;
+       const float backdropHeight = backdrop->y;
+       const float aspect = backdropWidth/backdropHeight;
+       const float rad = DEG2RADF(-boxmask->rotation);
+       const float cosine = cosf(rad);
+       const float sine = sinf(rad);
+       const float halveBoxWidth = backdropWidth * (boxmask->width / 2.0f);
+       const float halveBoxHeight = backdropHeight * (boxmask->height / 2.0f) * aspect;
+
+       float cx, cy, x1, x2, x3, x4;
+       float y1, y2, y3, y4;
+
+
+       /* keep this, saves us from a version patch */
+       if (snode->zoom == 0.0f) snode->zoom = 1.0f;
+
+       glColor3f(1.0, 1.0, 1.0);
+
+       cx  = x+snode->zoom*backdropWidth*boxmask->x;
+       cy = y+snode->zoom*backdropHeight*boxmask->y;
+
+       x1 = cx - (cosine*halveBoxWidth+sine*halveBoxHeight)*snode->zoom;
+       x2 = cx - (cosine*-halveBoxWidth+sine*halveBoxHeight)*snode->zoom;
+       x3 = cx - (cosine*-halveBoxWidth+sine*-halveBoxHeight)*snode->zoom;
+       x4 = cx - (cosine*halveBoxWidth+sine*-halveBoxHeight)*snode->zoom;
+       y1 = cy - (-sine*halveBoxWidth + cosine*halveBoxHeight)*snode->zoom;
+       y2 = cy - (-sine*-halveBoxWidth + cosine*halveBoxHeight)*snode->zoom;
+       y3 = cy - (-sine*-halveBoxWidth + cosine*-halveBoxHeight)*snode->zoom;
+       y4 = cy - (-sine*halveBoxWidth + cosine*-halveBoxHeight)*snode->zoom;
+
+       glBegin(GL_LINE_LOOP);
+       glVertex2f(x1, y1);
+       glVertex2f(x2, y2);
+       glVertex2f(x3, y3);
+       glVertex2f(x4, y4);
+       glEnd();
+}
+
+void node_composit_backdrop_ellipsemask(SpaceNode* snode, ImBuf* backdrop, bNode* node, int x, int y)
+{
+       NodeEllipseMask * ellipsemask = node->storage;
+       const float backdropWidth = backdrop->x;
+       const float backdropHeight = backdrop->y;
+       const float aspect = backdropWidth / backdropHeight;
+       const float rad = DEG2RADF(-ellipsemask->rotation);
+       const float cosine = cosf(rad);
+       const float sine = sinf(rad);
+       const float halveBoxWidth = backdropWidth * (ellipsemask->width / 2.0f);
+       const float halveBoxHeight = backdropHeight * (ellipsemask->height / 2.0f) * aspect;
+
+       float cx, cy, x1, x2, x3, x4;
+       float y1, y2, y3, y4;
+
+
+       /* keep this, saves us from a version patch */
+       if (snode->zoom == 0.0f) snode->zoom = 1.0f;
+
+       glColor3f(1.0, 1.0, 1.0);
+
+       cx  = x+snode->zoom*backdropWidth*ellipsemask->x;
+       cy = y+snode->zoom*backdropHeight*ellipsemask->y;
+
+       x1 = cx - (cosine*halveBoxWidth+sine*halveBoxHeight)*snode->zoom;
+       x2 = cx - (cosine*-halveBoxWidth+sine*halveBoxHeight)*snode->zoom;
+       x3 = cx - (cosine*-halveBoxWidth+sine*-halveBoxHeight)*snode->zoom;
+       x4 = cx - (cosine*halveBoxWidth+sine*-halveBoxHeight)*snode->zoom;
+       y1 = cy - (-sine*halveBoxWidth + cosine*halveBoxHeight)*snode->zoom;
+       y2 = cy - (-sine*-halveBoxWidth + cosine*halveBoxHeight)*snode->zoom;
+       y3 = cy - (-sine*-halveBoxWidth + cosine*-halveBoxHeight)*snode->zoom;
+       y4 = cy - (-sine*halveBoxWidth + cosine*-halveBoxHeight)*snode->zoom;
+
+       glBegin(GL_LINE_LOOP);
+
+       glVertex2f(x1, y1);
+       glVertex2f(x2, y2);
+       glVertex2f(x3, y3);
+       glVertex2f(x4, y4);
+       glEnd();
+}
+
+static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiLayout *row;
+       row= uiLayoutRow(layout, 1);
+       uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
+       uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+       row= uiLayoutRow(layout, 1);
+       uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+       uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
+       uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
+       uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+}
+
+static void node_composit_buts_viewer_but(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+       uiLayout *col;
+       
+       uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE);
+       if (RNA_enum_get(ptr, "tile_order")==0) {
+               col= uiLayoutColumn(layout, 1);
+               uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE);
+               uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE);
+       }
+}
+
+static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+       uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL);
+}
+
 /* only once called */
 static void node_composit_set_butfunc(bNodeType *ntype)
 {
-       ntype->uifuncbut = NULL;
-       switch(ntype->type) {
+       switch (ntype->type) {
                /* case NODE_GROUP:      note, typeinfo for group is generated... see "XXX ugly hack" */
 
                case CMP_NODE_IMAGE:
@@ -1892,6 +2482,8 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                        break;
                case CMP_NODE_OUTPUT_FILE:
                        ntype->uifunc= node_composit_buts_file_output;
+                       ntype->uifuncbut= node_composit_buts_file_output_details;
+                       ntype->drawinputfunc = node_draw_input_file_output;
                        break;
                case CMP_NODE_DIFF_MATTE:
                        ntype->uifunc=node_composit_buts_diff_matte;
@@ -1926,6 +2518,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_ID_MASK:
                        ntype->uifunc= node_composit_buts_id_mask;
                        break;
+               case CMP_NODE_DOUBLEEDGEMASK:
+                       ntype->uifunc= node_composit_buts_double_edge_mask;
+                       break;
                case CMP_NODE_MATH:
                        ntype->uifunc= node_buts_math;
                        break;
@@ -1964,11 +2559,36 @@ static void node_composit_set_butfunc(bNodeType *ntype)
                case CMP_NODE_MOVIEDISTORTION:
                        ntype->uifunc= node_composit_buts_moviedistortion;
                        break;
+               case CMP_NODE_COLORCORRECTION:
+                       ntype->uifunc=node_composit_buts_colorcorrection;
+                       ntype->uifuncbut=node_composit_buts_colorcorrection_but;
+                       break;
+               case CMP_NODE_SWITCH:
+                       ntype->uifunc= node_composit_buts_switch;
+                       break;
+               case CMP_NODE_MASK_BOX:
+                       ntype->uifunc= node_composit_buts_boxmask;
+                       ntype->uibackdropfunc = node_composit_backdrop_boxmask;
+                       break;
+               case CMP_NODE_MASK_ELLIPSE:
+                       ntype->uifunc= node_composit_buts_ellipsemask;
+                       ntype->uibackdropfunc = node_composit_backdrop_ellipsemask;
+                       break;
+               case CMP_NODE_BOKEHIMAGE:
+                       ntype->uifunc= node_composit_buts_bokehimage;
+                       break;
+               case CMP_NODE_VIEWER:
+                       ntype->uifunc = NULL;
+                       ntype->uifuncbut= node_composit_buts_viewer_but;
+                       ntype->uibackdropfunc = node_composit_backdrop_viewer;
+                       break;
+               case CMP_NODE_MASK:
+                       ntype->uifunc= node_composit_buts_mask;
+                       break;
+
                default:
                        ntype->uifunc= NULL;
        }
-       if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
-
 }
 
 /* ****************** BUTTON CALLBACKS FOR TEXTURE NODES ***************** */
@@ -1998,7 +2618,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
 
        col= uiLayoutColumn(layout, 0);
 
-       switch( tex->type ) {
+       switch ( tex->type ) {
                case TEX_BLEND:
                        uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE);
                        row= uiLayoutRow(col, 0);
@@ -2058,7 +2678,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
                        break;
                case TEX_VORONOI:
                        uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE);
-                       if(tex->vn_distm == TEX_MINKOVSKY) {
+                       if (tex->vn_distm == TEX_MINKOVSKY) {
                                uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE);
                        }
                        uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE);
@@ -2079,49 +2699,49 @@ static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), Poin
 /* only once called */
 static void node_texture_set_butfunc(bNodeType *ntype)
 {
-       ntype->uifuncbut = NULL;
-       if( ntype->type >= TEX_NODE_PROC && ntype->type < TEX_NODE_PROC_MAX ) {
+       if ( ntype->type >= TEX_NODE_PROC && ntype->type < TEX_NODE_PROC_MAX ) {
                ntype->uifunc = node_texture_buts_proc;
        }
-       else switch(ntype->type) {
-               
+       else {
+               switch (ntype->type) {
+
                case TEX_NODE_MATH:
                        ntype->uifunc = node_buts_math;
                        break;
-               
+
                case TEX_NODE_MIX_RGB:
                        ntype->uifunc = node_buts_mix_rgb;
                        break;
-                       
+
                case TEX_NODE_VALTORGB:
                        ntype->uifunc = node_buts_colorramp;
                        break;
-                       
+
                case TEX_NODE_CURVE_RGB:
                        ntype->uifunc= node_buts_curvecol;
                        break;
-                       
+
                case TEX_NODE_CURVE_TIME:
                        ntype->uifunc = node_buts_time;
                        break;
-                       
+
                case TEX_NODE_TEXTURE:
                        ntype->uifunc = node_buts_texture;
                        break;
-                       
+
                case TEX_NODE_BRICKS:
                        ntype->uifunc = node_texture_buts_bricks;
                        break;
-                       
+
                case TEX_NODE_IMAGE:
                        ntype->uifunc = node_texture_buts_image;
                        break;
-                       
+
                case TEX_NODE_OUTPUT:
                        ntype->uifunc = node_texture_buts_output;
                        break;
+               }
        }
-       if (ntype->uifuncbut == NULL) ntype->uifuncbut = ntype->uifunc;
 }
 
 /* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */
@@ -2143,6 +2763,8 @@ void ED_init_node_butfuncs(void)
                                ntype->drawupdatefunc = node_update_default;
                                ntype->uifunc = NULL;
                                ntype->uifuncbut = NULL;
+                               ntype->drawinputfunc = node_draw_input_default;
+                               ntype->drawoutputfunc = node_draw_output_default;
                                ntype->resize_area_func = node_resize_area_default;
                                
                                node_common_set_butfunc(ntype);
@@ -2166,7 +2788,7 @@ void ED_init_node_butfuncs(void)
        for (i=0; i < NUM_SOCKET_TYPES; ++i) {
                stype = ntreeGetSocketType(i);
                if (stype) {
-                       switch(stype->type) {
+                       switch (stype->type) {
                        case SOCK_FLOAT:
                        case SOCK_INT:
                        case SOCK_BOOLEAN:
@@ -2193,11 +2815,11 @@ void ED_init_node_butfuncs(void)
 void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
 {
        
-       if((snode->flag & SNODE_BACKDRAW) && snode->treetype==NTREE_COMPOSIT) {
+       if ((snode->flag & SNODE_BACKDRAW) && snode->treetype==NTREE_COMPOSIT) {
                Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
                void *lock;
                ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
-               if(ibuf) {
+               if (ibuf) {
                        float x, y; 
                        
                        glMatrixMode(GL_PROJECTION);
@@ -2206,7 +2828,7 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
                        glPushMatrix();
 
                        /* keep this, saves us from a version patch */
-                       if(snode->zoom==0.0f) snode->zoom= 1.0f;
+                       if (snode->zoom==0.0f) snode->zoom= 1.0f;
                        
                        /* somehow the offset has to be calculated inverse */
                        
@@ -2217,26 +2839,27 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
                        x = (ar->winx-snode->zoom*ibuf->x)/2 + snode->xof;
                        y = (ar->winy-snode->zoom*ibuf->y)/2 + snode->yof;
                        
-                       if(!ibuf->rect) {
-                               if(color_manage)
+                       if (!ibuf->rect) {
+                               if (color_manage)
                                        ibuf->profile = IB_PROFILE_LINEAR_RGB;
                                else
                                        ibuf->profile = IB_PROFILE_NONE;
                                IMB_rect_from_float(ibuf);
                        }
 
-                       if(ibuf->rect) {
+                       if (ibuf->rect) {
                                if (snode->flag & SNODE_SHOW_ALPHA) {
                                        glPixelZoom(snode->zoom, snode->zoom);
                                        /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
-                                       if(ENDIAN_ORDER == B_ENDIAN)
+                                       if (ENDIAN_ORDER == B_ENDIAN)
                                                glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
                                        
                                        glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT, ibuf->rect);
                                        
                                        glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
                                        glPixelZoom(1.0f, 1.0f);
-                               } else if (snode->flag & SNODE_USE_ALPHA) {
+                               }
+                               else if (snode->flag & SNODE_USE_ALPHA) {
                                        glEnable(GL_BLEND);
                                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                        glPixelZoom(snode->zoom, snode->zoom);
@@ -2245,7 +2868,8 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
                                        
                                        glPixelZoom(1.0f, 1.0f);
                                        glDisable(GL_BLEND);
-                               } else {
+                               }
+                               else {
                                        glPixelZoom(snode->zoom, snode->zoom);
                                        
                                        glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
@@ -2253,6 +2877,19 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
                                        glPixelZoom(1.0f, 1.0f);
                                }
                        }
+
+                       /// @note draw selected info on backdrop
+                       if (snode->edittree) {
+                               bNode *node = snode->edittree->nodes.first;
+                               while (node) {
+                                       if (node->flag & NODE_SELECT) {
+                                               if (node->typeinfo->uibackdropfunc) {
+                                                       node->typeinfo->uibackdropfunc(snode, ibuf, node, x, y);
+                                               }
+                                       }
+                                       node = node->next;
+                               }
+                       }
                        
                        glMatrixMode(GL_PROJECTION);
                        glPopMatrix();
@@ -2264,211 +2901,6 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
        }
 }
 
-void draw_nodespace_color_info(ARegion *ar, int color_manage, int channels, int x, int y, const char cp[4], const float fp[4])
-{
-       char str[256];
-       float dx= 6;
-       /* text colors */
-       /* XXX colored text not allowed in Blender UI */
-       #if 0
-       unsigned char red[3] = {255, 50, 50};
-       unsigned char green[3] = {0, 255, 0};
-       unsigned char blue[3] = {100, 100, 255};
-       #else
-       unsigned char red[3] = {255, 255, 255};
-       unsigned char green[3] = {255, 255, 255};
-       unsigned char blue[3] = {255, 255, 255};
-       #endif
-       float hue=0, sat=0, val=0, lum=0, u=0, v=0;
-       float col[4], finalcol[4];
-
-       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-       glEnable(GL_BLEND);
-
-       /* noisy, high contrast make impossible to read if lower alpha is used. */
-       glColor4ub(0, 0, 0, 190);
-       glRecti(0.0, 0.0, ar->winrct.xmax - ar->winrct.xmin + 1, 20);
-       glDisable(GL_BLEND);
-
-       BLF_size(blf_mono_font, 11, 72);
-
-       glColor3ub(255, 255, 255);
-       sprintf(str, "X:%-4d  Y:%-4d |", x, y);
-       // UI_DrawString(6, 6, str); // works ok but fixed width is nicer.
-       BLF_position(blf_mono_font, dx, 6, 0);
-       BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-       dx += BLF_width(blf_mono_font, str);
-
-       #if 0   /* XXX no Z value in compo backdrop atm */
-       if(zp) {
-               glColor3ub(255, 255, 255);
-               sprintf(str, " Z:%-.4f |", 0.5f+0.5f*(((float)*zp)/(float)0x7fffffff));
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-       }
-       if(zpf) {
-               glColor3ub(255, 255, 255);
-               sprintf(str, " Z:%-.3f |", *zpf);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-       }
-       #endif
-
-       if(channels >= 3) {
-               glColor3ubv(red);
-               if (fp)
-                       sprintf(str, "  R:%-.4f", fp[0]);
-               else if (cp)
-                       sprintf(str, "  R:%-3d", cp[0]);
-               else
-                       sprintf(str, "  R:-");
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-               
-               glColor3ubv(green);
-               if (fp)
-                       sprintf(str, "  G:%-.4f", fp[1]);
-               else if (cp)
-                       sprintf(str, "  G:%-3d", cp[1]);
-               else
-                       sprintf(str, "  G:-");
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-               
-               glColor3ubv(blue);
-               if (fp)
-                       sprintf(str, "  B:%-.4f", fp[2]);
-               else if (cp)
-                       sprintf(str, "  B:%-3d", cp[2]);
-               else
-                       sprintf(str, "  B:-");
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-               
-               if(channels == 4) {
-                       glColor3ub(255, 255, 255);
-                       if (fp)
-                               sprintf(str, "  A:%-.4f", fp[3]);
-                       else if (cp)
-                               sprintf(str, "  A:%-3d", cp[3]);
-                       else
-                               sprintf(str, "- ");
-                       BLF_position(blf_mono_font, dx, 6, 0);
-                       BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-                       dx += BLF_width(blf_mono_font, str);
-               }
-       }
-       
-       /* color rectangle */
-       if (channels==1) {
-               if (fp)
-                       col[0] = col[1] = col[2] = fp[0];
-               else if (cp)
-                       col[0] = col[1] = col[2] = (float)cp[0]/255.0f;
-               else
-                       col[0] = col[1] = col[2] = 0.0f;
-       }
-       else if (channels==3) {
-               if (fp)
-                       copy_v3_v3(col, fp);
-               else if (cp) {
-                       col[0] = (float)cp[0]/255.0f;
-                       col[1] = (float)cp[1]/255.0f;
-                       col[2] = (float)cp[2]/255.0f;
-               }
-               else
-                       zero_v3(col);
-       }
-       else if (channels==4) {
-               if (fp)
-                       copy_v4_v4(col, fp);
-               else if (cp) {
-                       col[0] = (float)cp[0]/255.0f;
-                       col[1] = (float)cp[1]/255.0f;
-                       col[2] = (float)cp[2]/255.0f;
-                       col[3] = (float)cp[3]/255.0f;
-               }
-               else
-                       zero_v4(col);
-       }
-       if (color_manage) {
-               linearrgb_to_srgb_v3_v3(finalcol, col);
-               finalcol[3] = col[3];
-       }
-       else {
-               copy_v4_v4(finalcol, col);
-       }
-       glDisable(GL_BLEND);
-       glColor3fv(finalcol);
-       dx += 5;
-       glBegin(GL_QUADS);
-       glVertex2f(dx, 3);
-       glVertex2f(dx, 17);
-       glVertex2f(dx+30, 17);
-       glVertex2f(dx+30, 3);
-       glEnd();
-       dx += 35;
-
-       glColor3ub(255, 255, 255);
-       if(channels == 1) {
-               if (fp) {
-                       rgb_to_hsv(fp[0], fp[0], fp[0], &hue, &sat, &val);
-                       rgb_to_yuv(fp[0], fp[0], fp[0], &lum, &u, &v);
-               }
-               else if (cp) {
-                       rgb_to_hsv((float)cp[0]/255.0f, (float)cp[0]/255.0f, (float)cp[0]/255.0f, &hue, &sat, &val);
-                       rgb_to_yuv((float)cp[0]/255.0f, (float)cp[0]/255.0f, (float)cp[0]/255.0f, &lum, &u, &v);
-               }
-               
-               sprintf(str, "V:%-.4f", val);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-
-               sprintf(str, "   L:%-.4f", lum);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-       }
-       else if(channels >= 3) {
-               if (fp) {
-                       rgb_to_hsv(fp[0], fp[1], fp[2], &hue, &sat, &val);
-                       rgb_to_yuv(fp[0], fp[1], fp[2], &lum, &u, &v);
-               }
-               else if (cp) {
-                       rgb_to_hsv((float)cp[0]/255.0f, (float)cp[1]/255.0f, (float)cp[2]/255.0f, &hue, &sat, &val);
-                       rgb_to_yuv((float)cp[0]/255.0f, (float)cp[1]/255.0f, (float)cp[2]/255.0f, &lum, &u, &v);
-               }
-
-               sprintf(str, "H:%-.4f", hue);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-
-               sprintf(str, "  S:%-.4f", sat);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-
-               sprintf(str, "  V:%-.4f", val);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-
-               sprintf(str, "   L:%-.4f", lum);
-               BLF_position(blf_mono_font, dx, 6, 0);
-               BLF_draw_ascii(blf_mono_font, str, sizeof(str));
-               dx += BLF_width(blf_mono_font, str);
-       }
-
-       (void)dx;
-}
-
 #if 0
 /* note: needs to be userpref or opengl profile option */
 static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
@@ -2476,10 +2908,10 @@ static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
 
        draw_nodespace_grid(snode);
        
-       if(snode->flag & SNODE_BACKDRAW) {
+       if (snode->flag & SNODE_BACKDRAW) {
                Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
                ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
-               if(ibuf) {
+               if (ibuf) {
                        int x, y;
                        float zoom = 1.0;
 
@@ -2490,7 +2922,7 @@ static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
                        
                        glaDefine2DArea(&sa->winrct);
 
-                       if(ibuf->x > sa->winx || ibuf->y > sa->winy) {
+                       if (ibuf->x > sa->winx || ibuf->y > sa->winy) {
                                float zoomx, zoomy;
                                zoomx= (float)sa->winx/ibuf->x;
                                zoomy= (float)sa->winy/ibuf->y;
@@ -2503,9 +2935,9 @@ static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
                        glPixelZoom(zoom, zoom);
 
                        glColor4f(1.0, 1.0, 1.0, 1.0);
-                       if(ibuf->rect)
+                       if (ibuf->rect)
                                glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
-                       else if(ibuf->channels==4)
+                       else if (ibuf->channels==4)
                                glaDrawPixelsTex(x, y, ibuf->x, ibuf->y, GL_FLOAT, ibuf->rect_float);
 
                        glPixelZoom(1.0, 1.0);
@@ -2525,21 +2957,21 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa
        float dist, vec[4][2];
        
        /* in v0 and v3 we put begin/end points */
-       if(link->fromsock) {
+       if (link->fromsock) {
                vec[0][0]= link->fromsock->locx;
                vec[0][1]= link->fromsock->locy;
        }
        else {
-               if(snode==NULL) return 0;
+               if (snode==NULL) return 0;
                vec[0][0]= snode->mx;
                vec[0][1]= snode->my;
        }
-       if(link->tosock) {
+       if (link->tosock) {
                vec[3][0]= link->tosock->locx;
                vec[3][1]= link->tosock->locy;
        }
        else {
-               if(snode==NULL) return 0;
+               if (snode==NULL) return 0;
                vec[3][0]= snode->mx;
                vec[3][1]= snode->my;
        }
@@ -2553,13 +2985,13 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa
        vec[2][0]= vec[3][0]-dist;
        vec[2][1]= vec[3][1];
        
-       if(v2d && MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax); /* clipped */      
+       if (v2d && MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > v2d->cur.xmax); /* clipped */
        else if (v2d && MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < v2d->cur.xmin); /* clipped */
        else {
                
                /* always do all three, to prevent data hanging around */
-               forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float)*2);
-               forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0]+1, resol, sizeof(float)*2);
+               BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float)*2);
+               BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0]+1, resol, sizeof(float)*2);
                
                return 1;
        }
@@ -2571,7 +3003,7 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int t
 {
        float coord_array[LINK_RESOL+1][2];
        
-       if(node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) {
+       if (node_link_bezier_points(v2d, snode, link, coord_array, LINK_RESOL)) {
                float dist, spline_step = 0.0f;
                int i;
                
@@ -2584,29 +3016,43 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int t
                
                glEnable(GL_LINE_SMOOTH);
                
-               if(do_triple) {
+               if (do_triple) {
                        UI_ThemeColorShadeAlpha(th_col3, -80, -120);
                        glLineWidth(4.0f);
                        
                        glBegin(GL_LINE_STRIP);
-                       for(i=0; i<=LINK_RESOL; i++) {
+                       for (i=0; i<=LINK_RESOL; i++) {
                                glVertex2fv(coord_array[i]);
                        }
                        glEnd();
                }
                
-               UI_ThemeColor(th_col1);
+               /* XXX using GL_LINES for shaded node lines is a workaround
+                * for Intel hardware, this breaks with GL_LINE_STRIP and
+                * changing color in begin/end blocks.
+                */
                glLineWidth(1.5f);
-               
-               glBegin(GL_LINE_STRIP);
-               for(i=0; i<=LINK_RESOL; i++) {
-                       if(do_shaded) {
+               if (do_shaded) {
+                       glBegin(GL_LINES);
+                       for (i=0; i<LINK_RESOL; i++) {
                                UI_ThemeColorBlend(th_col1, th_col2, spline_step);
+                               glVertex2fv(coord_array[i]);
+                               
+                               UI_ThemeColorBlend(th_col1, th_col2, spline_step+dist);
+                               glVertex2fv(coord_array[i+1]);
+                               
                                spline_step += dist;
                        }
-                       glVertex2fv(coord_array[i]);
+                       glEnd();
+               }
+               else {
+                       UI_ThemeColor(th_col1);
+                       glBegin(GL_LINE_STRIP);
+                       for (i=0; i<=LINK_RESOL; i++) {
+                               glVertex2fv(coord_array[i]);
+                       }
+                       glEnd();
                }
-               glEnd();
                
                glDisable(GL_LINE_SMOOTH);
                
@@ -2617,21 +3063,21 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int t
 
 static void node_link_straight_points(View2D *UNUSED(v2d), SpaceNode *snode, bNodeLink *link, float coord_array[][2])
 {
-       if(link->fromsock) {
+       if (link->fromsock) {
                coord_array[0][0]= link->fromsock->locx;
                coord_array[0][1]= link->fromsock->locy;
        }
        else {
-               if(snode==NULL) return;
+               if (snode==NULL) return;
                coord_array[0][0]= snode->mx;
                coord_array[0][1]= snode->my;
        }
-       if(link->tosock) {
+       if (link->tosock) {
                coord_array[1][0]= link->tosock->locx;
                coord_array[1][1]= link->tosock->locy;
        }
        else {
-               if(snode==NULL) return;
+               if (snode==NULL) return;
                coord_array[1][0]= snode->mx;
                coord_array[1][1]= snode->my;
        }
@@ -2650,7 +3096,7 @@ void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int
        
        glEnable(GL_LINE_SMOOTH);
        
-       if(do_triple) {
+       if (do_triple) {
                UI_ThemeColorShadeAlpha(th_col3, -80, -120);
                glLineWidth(4.0f);
                
@@ -2663,14 +3109,31 @@ void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int
        UI_ThemeColor(th_col1);
        glLineWidth(1.5f);
        
-       glBegin(GL_LINE_STRIP);
-       for (i=0; i < LINK_RESOL; ++i) {
-               float t= (float)i/(float)(LINK_RESOL-1);
-               if(do_shaded)
+       /* XXX using GL_LINES for shaded node lines is a workaround
+        * for Intel hardware, this breaks with GL_LINE_STRIP and
+        * changing color in begin/end blocks.
+        */
+       if (do_shaded) {
+               glBegin(GL_LINES);
+               for (i=0; i < LINK_RESOL-1; ++i) {
+                       float t= (float)i/(float)(LINK_RESOL-1);
                        UI_ThemeColorBlend(th_col1, th_col2, t);
-               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]);
+                       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]);
+                       
+                       t= (float)(i+1)/(float)(LINK_RESOL-1);
+                       UI_ThemeColorBlend(th_col1, th_col2, t);
+                       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]);
+               }
+               glEnd();
+       }
+       else {
+               glBegin(GL_LINE_STRIP);
+               for (i=0; i < LINK_RESOL; ++i) {
+                       float t= (float)i/(float)(LINK_RESOL-1);
+                       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]);
+               }
+               glEnd();
        }
-       glEnd();
        
        glDisable(GL_LINE_SMOOTH);
        
@@ -2681,45 +3144,45 @@ void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int
 /* note; this is used for fake links in groups too */
 void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
 {
-       int do_shaded= 0, th_col1= TH_HEADER, th_col2= TH_HEADER;
-       int do_triple= 0, th_col3= TH_WIRE;
+       int do_shaded= FALSE, th_col1= TH_HEADER, th_col2= TH_HEADER;
+       int do_triple= FALSE, th_col3= TH_WIRE;
        
-       if(link->fromsock==NULL && link->tosock==NULL)
+       if (link->fromsock==NULL && link->tosock==NULL)
                return;
        
        /* new connection */
-       if(!link->fromsock || !link->tosock) {
+       if (!link->fromsock || !link->tosock) {
                th_col1 = TH_ACTIVE;
-               do_triple = 1;
+               do_triple = TRUE;
        }
        else {
                /* going to give issues once... */
-               if(link->tosock->flag & SOCK_UNAVAIL)
+               if (link->tosock->flag & SOCK_UNAVAIL)
                        return;
-               if(link->fromsock->flag & SOCK_UNAVAIL)
+               if (link->fromsock->flag & SOCK_UNAVAIL)
                        return;
                
                /* a bit ugly... but thats how we detect the internal group links */
-               if(!link->fromnode || !link->tonode) {
+               if (!link->fromnode || !link->tonode) {
                        UI_ThemeColorBlend(TH_BACK, TH_WIRE, 0.5f);
-                       do_shaded= 0;
+                       do_shaded = FALSE;
                }
                else {
                        /* check cyclic */
-                       if((link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) && (link->flag & NODE_LINK_VALID)) {
+                       if ((link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) && (link->flag & NODE_LINK_VALID)) {
                                /* special indicated link, on drop-node */
-                               if(link->flag & NODE_LINKFLAG_HILITE) {
+                               if (link->flag & NODE_LINKFLAG_HILITE) {
                                        th_col1= th_col2= TH_ACTIVE;
                                }
                                else {
                                        /* regular link */
-                                       if(link->fromnode->flag & SELECT)
+                                       if (link->fromnode->flag & SELECT)
                                                th_col1= TH_EDGE_SELECT;
-                                       if(link->tonode->flag & SELECT)
+                                       if (link->tonode->flag & SELECT)
                                                th_col2= TH_EDGE_SELECT;
                                }
-                               do_shaded= 1;
-                               do_triple= 1;
+                               do_shaded = TRUE;
+                               do_triple = TRUE;
                        }                               
                        else {
                                th_col1 = TH_REDALERT;