Big node groups improvement patch. Node group trees now have their own lists of input...
[blender.git] / source / blender / editors / space_node / node_draw.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  * Contributor(s): Nathan Letwory
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_node_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_screen_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_threads.h"
45 #include "BLI_utildefines.h"
46
47 #include "BKE_context.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_main.h"
50 #include "BKE_node.h"
51
52 #include "BIF_gl.h"
53 #include "BIF_glutil.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 #include "ED_node.h"
59 #include "ED_gpencil.h"
60
61 #include "UI_interface.h"
62 #include "UI_interface_icons.h"
63 #include "UI_resources.h"
64 #include "UI_view2d.h"
65
66 #include "RNA_access.h"
67
68 #include "CMP_node.h"
69 #include "SHD_node.h"
70
71 #include "node_intern.h"
72
73 /* width of socket columns in group display */
74 #define NODE_GROUP_FRAME                120
75
76 // XXX interface.h
77 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
78
79 void ED_node_changed_update(ID *id, bNode *node)
80 {
81         bNodeTree *nodetree, *edittree;
82         int treetype;
83
84         node_tree_from_ID(id, &nodetree, &edittree, &treetype);
85
86         if(treetype==NTREE_SHADER) {
87                 DAG_id_tag_update(id, 0);
88                 WM_main_add_notifier(NC_MATERIAL|ND_SHADING_DRAW, id);
89         }
90         else if(treetype==NTREE_COMPOSIT) {
91                 NodeTagChanged(edittree, node);
92                 /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */
93                         
94                 node= node_tree_get_editgroup(nodetree);
95                 if(node)
96                         NodeTagIDChanged(nodetree, node->id);
97
98                 WM_main_add_notifier(NC_SCENE|ND_NODES, id);
99         }                       
100         else if(treetype==NTREE_TEXTURE) {
101                 DAG_id_tag_update(id, 0);
102                 WM_main_add_notifier(NC_TEXTURE|ND_NODES, id);
103         }
104 }
105
106 static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
107 {
108         bNode *node;
109         
110         if(ntree == lookup)
111                 return 1;
112         
113         for(node=ntree->nodes.first; node; node=node->next)
114                 if(node->type == NODE_GROUP && node->id)
115                         if(has_nodetree((bNodeTree*)node->id, lookup))
116                                 return 1;
117         
118         return 0;
119 }
120
121 void ED_node_generic_update(Main *bmain, bNodeTree *ntree, bNode *node)
122 {
123         Material *ma;
124         Tex *tex;
125         Scene *sce;
126         
127         /* look through all datablocks, to support groups */
128         for(ma=bmain->mat.first; ma; ma=ma->id.next)
129                 if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
130                         ED_node_changed_update(&ma->id, node);
131         
132         for(tex=bmain->tex.first; tex; tex=tex->id.next)
133                 if(tex->nodetree && tex->use_nodes && has_nodetree(tex->nodetree, ntree))
134                         ED_node_changed_update(&tex->id, node);
135         
136         for(sce=bmain->scene.first; sce; sce=sce->id.next)
137                 if(sce->nodetree && sce->use_nodes && has_nodetree(sce->nodetree, ntree))
138                         ED_node_changed_update(&sce->id, node);
139         
140         if(ntree->type == NTREE_TEXTURE)
141                 ntreeTexCheckCyclics(ntree);
142 }
143
144 static void do_node_internal_buttons(bContext *C, void *node_v, int event)
145 {
146         if(event==B_NODE_EXEC) {
147                 SpaceNode *snode= CTX_wm_space_node(C);
148                 if(snode && snode->id)
149                         ED_node_changed_update(snode->id, node_v);
150         }
151 }
152
153
154 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
155 {
156         float dx;
157         float dy;
158         
159         dx= 0.5f*(xmax-xmin);
160         dy= 0.5f*(ymax-ymin);
161         
162         UI_ThemeColorShade(color_id, +30);      
163         fdrawline(xmin, ymin, xmax, ymax);
164         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
165         
166         UI_ThemeColorShade(color_id, -10);
167         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
168         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
169 }
170
171 static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
172 {
173         bNode *node;
174         char str[32];
175         
176         /* add node uiBlocks in reverse order - prevents events going to overlapping nodes */
177         
178         /* process selected nodes first so they're at the start of the uiblocks list */
179         for(node= ntree->nodes.last; node; node= node->prev) {
180                 
181                 if (node->flag & NODE_SELECT) {
182                         /* ui block */
183                         sprintf(str, "node buttons %p", (void *)node);
184                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
185                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
186                 }
187         }
188         
189         /* then the rest */
190         for(node= ntree->nodes.last; node; node= node->prev) {
191                 
192                 if (!(node->flag & (NODE_GROUP_EDIT|NODE_SELECT))) {
193                         /* ui block */
194                         sprintf(str, "node buttons %p", (void *)node);
195                         node->block= uiBeginBlock(C, CTX_wm_region(C), str, UI_EMBOSS);
196                         uiBlockSetHandleFunc(node->block, do_node_internal_buttons, node);
197                 }
198         }
199 }
200
201 /* based on settings in node, sets drawing rect info. each redraw! */
202 static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
203 {
204         uiLayout *layout;
205         PointerRNA ptr;
206         bNodeSocket *nsock;
207         float dy= node->locy;
208         int buty;
209         
210         /* header */
211         dy-= NODE_DY;
212         
213         /* little bit space in top */
214         if(node->outputs.first)
215                 dy-= NODE_DYS/2;
216
217         /* output sockets */
218         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
219                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
220                         nsock->locx= node->locx + node->width;
221                         nsock->locy= dy - NODE_DYS;
222                         dy-= NODE_DY;
223                 }
224         }
225
226         node->prvr.xmin= node->locx + NODE_DYS;
227         node->prvr.xmax= node->locx + node->width- NODE_DYS;
228
229         /* preview rect? */
230         if(node->flag & NODE_PREVIEW) {
231                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
232                 BLI_lock_thread(LOCK_PREVIEW);
233
234                 if(node->preview && node->preview->rect) {
235                         float aspect= 1.0f;
236                         
237                         if(node->preview && node->preview->xsize && node->preview->ysize) 
238                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
239                         
240                         dy-= NODE_DYS/2;
241                         node->prvr.ymax= dy;
242                         
243                         if(aspect <= 1.0f)
244                                 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
245                         else {
246                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
247                                 
248                                 node->prvr.ymin= dy - (node->width-NODE_DY);
249                                 
250                                 node->prvr.xmin+= 0.5f*dx;
251                                 node->prvr.xmax-= 0.5f*dx;
252                         }
253
254                         dy= node->prvr.ymin - NODE_DYS/2;
255
256                         /* make sure that maximums are bigger or equal to minimums */
257                         if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
258                         if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
259                 }
260                 else {
261                         float oldh= node->prvr.ymax - node->prvr.ymin;
262                         if(oldh==0.0f)
263                                 oldh= 0.6f*node->width-NODE_DY;
264                         dy-= NODE_DYS/2;
265                         node->prvr.ymax= dy;
266                         node->prvr.ymin= dy - oldh;
267                         dy= node->prvr.ymin - NODE_DYS/2;
268                 }
269
270                 BLI_unlock_thread(LOCK_PREVIEW);
271         }
272
273         /* buttons rect? */
274         if((node->flag & NODE_OPTIONS) && node->typeinfo->uifunc) {
275                 dy-= NODE_DYS/2;
276
277                 /* set this for uifunc() that don't use layout engine yet */
278                 node->butr.xmin= 0;
279                 node->butr.xmax= node->width - 2*NODE_DYS;
280                 node->butr.ymin= 0;
281                 node->butr.ymax= 0;
282
283                 RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr);
284
285                 layout= uiBlockLayout(node->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
286                         node->locx+NODE_DYS, dy, node->butr.xmax, 20, U.uistyles.first);
287
288                 node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
289                 uiBlockEndAlign(node->block);
290                 uiBlockLayoutResolve(node->block, NULL, &buty);
291
292                 dy= buty - NODE_DYS/2;
293         }
294
295         /* input sockets */
296         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
297                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
298                         nsock->locx= node->locx;
299                         nsock->locy= dy - NODE_DYS;
300                         dy-= NODE_DY;
301                 }
302         }
303         
304         /* little bit space in end */
305         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
306                 dy-= NODE_DYS/2;
307
308         node->totr.xmin= node->locx;
309         node->totr.xmax= node->locx + node->width;
310         node->totr.ymax= node->locy;
311         node->totr.ymin= dy;
312 }
313
314 /* based on settings in node, sets drawing rect info. each redraw! */
315 static void node_update_hidden(bNode *node)
316 {
317         bNodeSocket *nsock;
318         float rad, drad, hiddenrad= HIDDEN_RAD;
319         int totin=0, totout=0, tot;
320         
321         /* calculate minimal radius */
322         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
323                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
324                         totin++;
325         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
326                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
327                         totout++;
328         
329         tot= MAX2(totin, totout);
330         if(tot>4) {
331                 hiddenrad += 5.0f*(float)(tot-4);
332         }
333         
334         node->totr.xmin= node->locx;
335         node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
336         node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
337         node->totr.ymin= node->totr.ymax - 2*hiddenrad;
338         
339         /* output sockets */
340         rad=drad= (float)M_PI/(1.0f + (float)totout);
341         
342         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
343                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
344                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
345                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
346                         rad+= drad;
347                 }
348         }
349         
350         /* input sockets */
351         rad=drad= - (float)M_PI/(1.0f + (float)totin);
352         
353         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
354                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
355                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
356                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
357                         rad+= drad;
358                 }
359         }
360 }
361
362 static int node_get_colorid(bNode *node)
363 {
364         if(node->typeinfo->nclass==NODE_CLASS_INPUT)
365                 return TH_NODE_IN_OUT;
366         if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
367                 if(node->flag & NODE_DO_OUTPUT)
368                         return TH_NODE_IN_OUT;
369                 else
370                         return TH_NODE;
371         }
372         if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
373                 return TH_NODE_CONVERTOR;
374         if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
375                 return TH_NODE_OPERATOR;
376         if(node->typeinfo->nclass==NODE_CLASS_GROUP)
377                 return TH_NODE_GROUP;
378         return TH_NODE;
379 }
380
381 /* based on settings in node, sets drawing rect info. each redraw! */
382 /* note: this assumes only 1 group at a time is drawn (linked data) */
383 /* in node->totr the entire boundbox for the group is stored */
384 static void node_update_group(const bContext *C, bNodeTree *ntree, bNode *gnode)
385 {
386         bNodeTree *ngroup= (bNodeTree *)gnode->id;
387         bNode *node;
388         bNodeSocket *sock, *gsock;
389         rctf *rect= &gnode->totr;
390         int counter;
391         int dy;
392         
393         /* center them, is a bit of abuse of locx and locy though */
394         for(node= ngroup->nodes.first; node; node= node->next) {
395                 node->locx+= gnode->locx;
396                 node->locy+= gnode->locy;
397                 
398                 if(node->flag & NODE_HIDDEN)
399                         node_update_hidden(node);
400                 else
401                         node_update(C, ntree, node);
402                 node->locx-= gnode->locx;
403                 node->locy-= gnode->locy;
404         }
405         counter= 1;
406         for(node= ngroup->nodes.first; node; node= node->next) {
407                 if(counter) {
408                         *rect= node->totr;
409                         counter= 0;
410                 }
411                 else
412                         BLI_union_rctf(rect, &node->totr);
413         }
414         
415         /* add some room for links to group sockets */
416         rect->xmin -= 3*NODE_DY;
417         rect->xmax += 3*NODE_DY;
418         
419         if(counter==1) return;  /* should be prevented? */
420         
421         rect->xmin-= NODE_DY;
422         rect->ymin-= NODE_DY;
423         rect->xmax+= NODE_DY;
424         rect->ymax+= NODE_DY;
425         
426         /* input sockets */
427         dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->inputs)-1);
428         for(gsock=ngroup->inputs.first, sock=gnode->inputs.first; gsock; gsock=gsock->next, sock=sock->next) {
429                 gsock->locx = rect->xmin;
430                 sock->locx = rect->xmin - NODE_GROUP_FRAME;
431                 sock->locy = gsock->locy = dy;
432                 dy -= 2*NODE_DY;
433         }
434         
435         /* output sockets */
436         dy = 0.5f*(rect->ymin+rect->ymax) + NODE_DY*(BLI_countlist(&gnode->outputs)-1);
437         for(gsock=ngroup->outputs.first, sock=gnode->outputs.first; gsock; gsock=gsock->next, sock=sock->next) {
438                 gsock->locx = rect->xmax;
439                 sock->locx = rect->xmax + NODE_GROUP_FRAME;
440                 sock->locy = gsock->locy = dy - NODE_DYS;
441                 dy -= 2*NODE_DY;
442         }
443 }
444
445 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */
446 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
447 {
448         bNodeSocket *valsock= NULL, *colsock= NULL, *vecsock= NULL;
449         bNodeSocket *sock;
450         bNodeLink link= {0};
451         int a;
452         
453         /* connect the first value buffer in with first value out */
454         /* connect the first RGBA buffer in with first RGBA out */
455         
456         /* test the inputs */
457         for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
458                 if(nodeCountSocketLinks(snode->edittree, sock)) {
459                         if(sock->type==SOCK_VALUE && valsock==NULL) valsock= sock;
460                         if(sock->type==SOCK_VECTOR && vecsock==NULL) vecsock= sock;
461                         if(sock->type==SOCK_RGBA && colsock==NULL) colsock= sock;
462                 }
463         }
464         
465         /* outputs, draw lines */
466         glEnable(GL_BLEND);
467         glEnable( GL_LINE_SMOOTH );
468         
469         if(valsock || colsock || vecsock) {
470                 for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
471                         if(nodeCountSocketLinks(snode->edittree, sock)) {
472                                 link.tosock= sock;
473                                 
474                                 if(sock->type==SOCK_VALUE && valsock) {
475                                         link.fromsock= valsock;
476                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
477                                         valsock= NULL;
478                                 }
479                                 if(sock->type==SOCK_VECTOR && vecsock) {
480                                         link.fromsock= vecsock;
481                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
482                                         vecsock= NULL;
483                                 }
484                                 if(sock->type==SOCK_RGBA && colsock) {
485                                         link.fromsock= colsock;
486                                         node_draw_link_bezier(v2d, snode, &link, TH_REDALERT, 0, TH_WIRE, 0, TH_WIRE);
487                                         colsock= NULL;
488                                 }
489                         }
490                 }
491         }
492         glDisable(GL_BLEND);
493         glDisable( GL_LINE_SMOOTH );
494 }
495
496 /* nice AA filled circle */
497 /* this might have some more generic use */
498 static void circle_draw(float x, float y, float size, int col[3])
499 {
500         /* 16 values of sin function */
501         static float si[16] = {
502                 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
503                 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
504                 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
505                 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
506         };
507         /* 16 values of cos function */
508         static float co[16] ={
509                 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
510                 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
511                 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
512                 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
513         };
514         int a;
515         
516         glColor3ub(col[0], col[1], col[2]);
517         
518         glBegin(GL_POLYGON);
519         for(a=0; a<16; a++)
520                 glVertex2f(x+size*si[a], y+size*co[a]);
521         glEnd();
522         
523         glColor4ub(0, 0, 0, 150);
524         glEnable(GL_BLEND);
525         glEnable( GL_LINE_SMOOTH );
526         glBegin(GL_LINE_LOOP);
527         for(a=0; a<16; a++)
528                 glVertex2f(x+size*si[a], y+size*co[a]);
529         glEnd();
530         glDisable( GL_LINE_SMOOTH );
531         glDisable(GL_BLEND);
532 }
533
534 static void socket_circle_draw(bNodeSocket *sock, float size)
535 {
536         int col[3];
537         
538         if(sock->type==-1) {
539                 col[0]= 0; col[1]= 0; col[2]= 0;
540         }
541         else if(sock->type==SOCK_VALUE) {
542                 col[0]= 160; col[1]= 160; col[2]= 160;
543         }
544         else if(sock->type==SOCK_VECTOR) {
545                 col[0]= 100; col[1]= 100; col[2]= 200;
546         }
547         else if(sock->type==SOCK_RGBA) {
548                 col[0]= 200; col[1]= 200; col[2]= 40;
549         }
550         else { 
551                 col[0]= 100; col[1]= 200; col[2]= 100;
552         }
553
554         circle_draw(sock->locx, sock->locy, size, col);
555 }
556
557 static void node_sync_cb(bContext *UNUSED(C), void *snode_v, void *node_v)
558 {
559         SpaceNode *snode= snode_v;
560         
561         if(snode->treetype==NTREE_SHADER) {
562                 nodeShaderSynchronizeID(node_v, 1);
563                 // allqueue(REDRAWBUTSSHADING, 0);
564         }
565 }
566
567 /* **************  Socket callbacks *********** */
568
569 /* not a callback */
570 static void node_draw_preview(bNodePreview *preview, rctf *prv)
571 {
572         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
573         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
574         float tile= (prv->xmax - prv->xmin) / 10.0f;
575         float x, y;
576         
577         /* draw checkerboard backdrop to show alpha */
578         glColor3ub(120, 120, 120);
579         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
580         glColor3ub(160, 160, 160);
581         
582         for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
583                 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
584                         float tilex= tile, tiley= tile;
585
586                         if(x+tile > prv->xmax)
587                                 tilex= prv->xmax-x;
588                         if(y+tile > prv->ymax)
589                                 tiley= prv->ymax-y;
590
591                         glRectf(x, y, x + tilex, y + tiley);
592                 }
593         }
594         for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
595                 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
596                         float tilex= tile, tiley= tile;
597
598                         if(x+tile > prv->xmax)
599                                 tilex= prv->xmax-x;
600                         if(y+tile > prv->ymax)
601                                 tiley= prv->ymax-y;
602
603                         glRectf(x, y, x + tilex, y + tiley);
604                 }
605         }
606         
607         glPixelZoom(xscale, yscale);
608
609         glEnable(GL_BLEND);
610         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    /* premul graphics */
611         
612         glColor4f(1.0, 1.0, 1.0, 1.0);
613         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
614         
615         glDisable(GL_BLEND);
616         glPixelZoom(1.0f, 1.0f);
617
618         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
619         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
620         
621 }
622
623 typedef struct SocketVectorMenuArgs {
624         PointerRNA ptr;
625         int x, y, width;
626         uiButHandleFunc cb;
627         void *arg1, *arg2;
628 } SocketVectorMenuArgs;
629
630 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
631 static uiBlock *socket_vector_menu(bContext *C, ARegion *ar, void *args_v)
632 {
633         SocketVectorMenuArgs *args= (SocketVectorMenuArgs*)args_v;
634         uiBlock *block;
635         uiLayout *layout;
636         
637         block= uiBeginBlock(C, ar, "socket menu", UI_EMBOSS);
638         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
639         
640         layout= uiLayoutColumn(uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, args->x, args->y+2, args->width, 20, U.uistyles.first), 0);
641         
642         uiItemR(layout, &args->ptr, "default_value", UI_ITEM_R_EXPAND, "", ICON_NULL);
643         
644         return block;
645 }
646
647 static void node_draw_socket_button(bNodeTree *ntree, bNodeSocket *sock, const char *name,
648                                                                         uiBlock *block, int x, int y, int width,
649                                                                         uiButHandleFunc cb, void *arg1, void *arg2)
650 {
651         uiBut *bt= NULL;
652         PointerRNA ptr;
653         int labelw;
654         SocketVectorMenuArgs *args;
655         
656         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, sock, &ptr);
657         
658         switch (sock->type) {
659         case SOCK_VALUE:
660                 bt=uiDefButR(block, NUM, B_NODE_EXEC, name,
661                                          x, y+1, width, 17, 
662                                          &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL);
663                 if (cb)
664                         uiButSetFunc(bt, cb, arg1, arg2);
665                 break;
666                 
667         case SOCK_VECTOR:
668                 args= MEM_callocN(sizeof(SocketVectorMenuArgs), "SocketVectorMenuArgs");
669         
670                 args->ptr = ptr;
671                 args->x = x;
672                 args->y = y;
673                 args->width = width;
674                 args->cb = cb;
675                 args->arg1 = arg1;
676                 args->arg2 = arg2;
677                 
678                 uiDefBlockButN(block, socket_vector_menu, args, name, 
679                                            x, y+1, width, 17, 
680                                            "");
681                 break;
682                 
683         case SOCK_RGBA:
684                 labelw= width - 40;
685                 
686                 bt=uiDefButR(block, COL, B_NODE_EXEC, "",
687                                          x, y+2, (labelw>0 ? 40 : width), 15, 
688                                          &ptr, "default_value", 0, sock->ns.min, sock->ns.max, -1, -1, NULL);
689                 if (cb)
690                         uiButSetFunc(bt, cb, arg1, arg2);
691                 
692                 if (name[0]!='\0' && labelw>0)
693                         uiDefBut(block, LABEL, 0, name, 
694                                          x + 40, y+2, labelw, 15, 
695                                          NULL, 0, 0, 0, 0, "");
696                 break;
697         }
698 }
699
700 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *node)
701 {
702         bNodeSocket *sock;
703         rctf *rct= &node->totr;
704         float iconofs;
705         int color_id= node_get_colorid(node);
706         char showname[128]; /* 128 used below */
707         View2D *v2d = &ar->v2d;
708         
709         /* hurmf... another candidate for callback, have to see how this works first */
710         if(node->id && node->block && snode->treetype==NTREE_SHADER)
711                 nodeShaderSynchronizeID(node, 0);
712         
713         /* skip if out of view */
714         if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
715                         node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
716                 
717                 uiEndBlock(C, node->block);
718                 node->block= NULL;
719                 return;
720         }
721         
722         uiSetRoundBox(15-4);
723         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
724         
725         /* header */
726         if(color_id==TH_NODE)
727                 UI_ThemeColorShade(color_id, -20);
728         else
729                 UI_ThemeColor(color_id);
730         
731         if(node->flag & NODE_MUTED)
732            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);
733                 
734         uiSetRoundBox(3);
735         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
736         
737         /* show/hide icons, note this sequence is copied in do_header_node() node_state.c */
738         iconofs= rct->xmax - 7.0f;
739         
740         if(node->typeinfo->flag & NODE_PREVIEW) {
741                 int icon_id;
742                 
743                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
744                         icon_id= ICON_MATERIAL;
745                 else
746                         icon_id= ICON_MATERIAL_DATA;
747                 iconofs-=15.0f;
748                 uiDefIconBut(node->block, LABEL, B_REDR, icon_id, iconofs, rct->ymax-NODE_DY,
749                                          UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
750         }
751         if(node->type == NODE_GROUP) {
752                 
753                 iconofs-=15.0f;
754                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_NODETREE, iconofs, rct->ymax-NODE_DY,
755                                          UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
756         }
757         if(node->typeinfo->flag & NODE_OPTIONS) {
758                 iconofs-=15.0f;
759                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_BUTS, iconofs, rct->ymax-NODE_DY,
760                                          UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
761         }
762         {       /* always hide/reveal unused sockets */ 
763                 int shade;
764
765                 iconofs-=15.0f;
766                 // XXX re-enable
767                 /*if(node_has_hidden_sockets(node))
768                         shade= -40;
769                 else*/
770                         shade= -90;
771                 uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY,
772                                                   UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, "");
773         }
774         
775         /* title */
776         if(node->flag & SELECT) 
777                 UI_ThemeColor(TH_TEXT_HI);
778         else
779                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
780         
781         /* open/close entirely? */
782         UI_DrawTriIcon(rct->xmin+10.0f, rct->ymax-NODE_DY/2.0f, 'v');
783         
784         /* this isn't doing anything for the label, so commenting out
785         if(node->flag & SELECT) 
786                 UI_ThemeColor(TH_TEXT_HI);
787         else
788                 UI_ThemeColor(TH_TEXT); */
789         
790         if (node->typeinfo->labelfunc)
791                 BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname));
792         else
793                 BLI_strncpy(showname, node->typeinfo->name, sizeof(showname));
794
795         //if(node->flag & NODE_MUTED)
796         //      sprintf(showname, "[%s]", showname);
797         
798         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
799                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
800
801         /* body */
802         UI_ThemeColor4(TH_NODE);
803         glEnable(GL_BLEND);
804         uiSetRoundBox(8);
805         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
806         glDisable(GL_BLEND);
807
808         /* scaling indicator */
809         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
810
811         /* outline active and selected emphasis */
812         if( node->flag & (NODE_ACTIVE|SELECT) ) {
813                 glEnable(GL_BLEND);
814                 glEnable( GL_LINE_SMOOTH );
815                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
816                         if( node->flag & NODE_ACTIVE ) 
817                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
818                         else
819                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
820                         uiSetRoundBox(15-4); // round all corners except lower right
821                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
822                         
823                 glDisable( GL_LINE_SMOOTH );
824                 glDisable(GL_BLEND);
825         }
826         
827         /* disable lines */
828         if(node->flag & NODE_MUTED)
829                 node_draw_mute_line(v2d, snode, node);
830
831         
832         /* socket inputs, buttons */
833         for(sock= node->inputs.first; sock; sock= sock->next) {
834                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
835                         socket_circle_draw(sock, NODE_SOCKSIZE);
836                         
837                         if(node->block && sock->link==NULL) {
838                                 node_draw_socket_button(ntree, sock, sock->name, node->block, sock->locx+NODE_DYS, sock->locy-NODE_DYS, node->width-NODE_DY, node_sync_cb, snode, node);
839                         }
840                         else {
841                                 uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+7), (short)(sock->locy-9.0f), 
842                                                  (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
843                         }
844                 }
845         }
846         
847         /* socket outputs */
848         for(sock= node->outputs.first; sock; sock= sock->next) {
849                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
850                         float slen;
851                         int ofs= 0;
852                         
853                         socket_circle_draw(sock, NODE_SOCKSIZE);
854                         
855                         UI_ThemeColor(TH_TEXT);
856                         slen= snode->aspect*UI_GetStringWidth(sock->name);
857                         while(slen > node->width) {
858                                 ofs++;
859                                 slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
860                         }
861                         
862                         uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 
863                                          (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
864                 }
865         }
866         
867         /* preview */
868         if(node->flag & NODE_PREVIEW) {
869                 BLI_lock_thread(LOCK_PREVIEW);
870                 if(node->preview && node->preview->rect && !BLI_rctf_is_empty(&node->prvr))
871                         node_draw_preview(node->preview, &node->prvr);
872                 BLI_unlock_thread(LOCK_PREVIEW);
873         }
874         
875         UI_ThemeClearColor(color_id);
876                 
877         uiEndBlock(C, node->block);
878         uiDrawBlock(C, node->block);
879         node->block= NULL;
880 }
881
882 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
883 {
884         bNodeSocket *sock;
885         rctf *rct= &node->totr;
886         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
887         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
888         int color_id= node_get_colorid(node);
889         char showname[128];     /* 128 is used below */
890         
891         /* shadow */
892         uiSetRoundBox(15);
893         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
894
895         /* body */
896         UI_ThemeColor(color_id);
897         if(node->flag & NODE_MUTED)
898            UI_ThemeColorBlend(color_id, TH_REDALERT, 0.5f);     
899         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
900         
901         /* outline active and selected emphasis */
902         if( node->flag & (NODE_ACTIVE|SELECT) ) {
903                 glEnable(GL_BLEND);
904                 glEnable( GL_LINE_SMOOTH );
905                         /* using different shades of TH_TEXT_HI for the empasis, like triangle */
906                         if( node->flag & NODE_ACTIVE ) 
907                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, 0, -40);
908                         else
909                                 UI_ThemeColorShadeAlpha(TH_TEXT_HI, -20, -120);
910                         uiDrawBox(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
911                 glDisable( GL_LINE_SMOOTH );
912                 glDisable(GL_BLEND);
913         }
914         
915         /* title */
916         if(node->flag & SELECT) 
917                 UI_ThemeColor(TH_TEXT_HI);
918         else
919                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
920         
921         /* open entirely icon */
922         UI_DrawTriIcon(rct->xmin+10.0f, centy, 'h');    
923         
924         /* disable lines */
925         if(node->flag & NODE_MUTED)
926                 node_draw_mute_line(&ar->v2d, snode, node);     
927         
928         if(node->flag & SELECT) 
929                 UI_ThemeColor(TH_TEXT_HI);
930         else
931                 UI_ThemeColor(TH_TEXT);
932         
933         if(node->miniwidth>0.0f) {
934                 if (node->typeinfo->labelfunc)
935                         BLI_strncpy(showname, node->typeinfo->labelfunc(node), sizeof(showname));
936                 else
937                         BLI_strncpy(showname, node->typeinfo->name, sizeof(showname));
938                 
939                 //if(node->flag & NODE_MUTED)
940                 //      sprintf(showname, "[%s]", showname);
941
942                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
943                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
944         }       
945
946         /* scale widget thing */
947         UI_ThemeColorShade(color_id, -10);      
948         dx= 10.0f;
949         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
950         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
951         
952         UI_ThemeColorShade(color_id, +30);
953         dx-= snode->aspect;
954         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
955         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
956         
957         /* sockets */
958         for(sock= node->inputs.first; sock; sock= sock->next) {
959                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
960                         socket_circle_draw(sock, NODE_SOCKSIZE);
961         }
962         
963         for(sock= node->outputs.first; sock; sock= sock->next) {
964                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
965                         socket_circle_draw(sock, NODE_SOCKSIZE);
966         }
967         
968         uiEndBlock(C, node->block);
969         uiDrawBlock(C, node->block);
970         node->block= NULL;
971 }
972
973 static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
974 {
975         bNode *node;
976         bNodeLink *link;
977         int a;
978         
979         if(ntree==NULL) return;         /* groups... */
980         
981         /* node lines */
982         glEnable(GL_BLEND);
983         glEnable(GL_LINE_SMOOTH);
984         for(link= ntree->links.first; link; link= link->next)
985                 node_draw_link(&ar->v2d, snode, link);
986         glDisable(GL_LINE_SMOOTH);
987         glDisable(GL_BLEND);
988         
989         /* not selected first */
990         for(a=0, node= ntree->nodes.first; node; node= node->next, a++) {
991                 node->nr= a;            /* index of node in list, used for exec event code */
992                 if(!(node->flag & SELECT)) {
993                         if(node->flag & NODE_GROUP_EDIT);
994                         else if(node->flag & NODE_HIDDEN)
995                                 node_draw_hidden(C, ar, snode, node);
996                         else
997                                 node_draw_basis(C, ar, snode, ntree, node);
998                 }
999         }
1000         
1001         /* selected */
1002         for(node= ntree->nodes.first; node; node= node->next) {
1003                 if(node->flag & SELECT) {
1004                         if(node->flag & NODE_GROUP_EDIT);
1005                         else if(node->flag & NODE_HIDDEN)
1006                                 node_draw_hidden(C, ar, snode, node);
1007                         else
1008                                 node_draw_basis(C, ar, snode, ntree, node);
1009                 }
1010         }       
1011 }
1012
1013 static void group_verify_cb(bContext *UNUSED(C), void *UNUSED(snode_v), void *ngroup_v)
1014 {
1015         bNodeTree *ngroup= (bNodeTree*)ngroup_v;
1016         
1017         nodeVerifyGroup(ngroup);
1018 }
1019
1020 /* groups are, on creation, centered around 0,0 */
1021 static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
1022 {
1023         bNodeTree *ngroup= (bNodeTree *)gnode->id;
1024         bNodeSocket *sock;
1025         rctf rect= gnode->totr;
1026         int index;
1027         uiLayout *layout;
1028         PointerRNA ptr;
1029         uiBut *bt;
1030         
1031         /* backdrop header */
1032         glEnable(GL_BLEND);
1033         uiSetRoundBox(3);
1034         UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
1035         uiDrawBox(GL_POLYGON, rect.xmin-NODE_GROUP_FRAME, rect.ymax, rect.xmax+NODE_GROUP_FRAME, rect.ymax+26, BASIS_RAD);
1036         
1037         /* backdrop body */
1038         UI_ThemeColorShadeAlpha(TH_BACK, -8, -70);
1039         uiSetRoundBox(0);
1040         uiDrawBox(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
1041
1042         /* input column */
1043         UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
1044         uiSetRoundBox(8);
1045         uiDrawBox(GL_POLYGON, rect.xmin-NODE_GROUP_FRAME, rect.ymin, rect.xmin, rect.ymax, BASIS_RAD);
1046
1047         /* output column */
1048         UI_ThemeColorShadeAlpha(TH_BACK, 10, -50);
1049         uiSetRoundBox(4);
1050         uiDrawBox(GL_POLYGON, rect.xmax, rect.ymin, rect.xmax+NODE_GROUP_FRAME, rect.ymax, BASIS_RAD);
1051
1052         /* input column separator */
1053         glColor4ub(200, 200, 200, 140);
1054         glBegin(GL_LINES);
1055         glVertex2f(rect.xmin, rect.ymin);
1056         glVertex2f(rect.xmin, rect.ymax);
1057         glEnd();
1058
1059         /* output column separator */
1060         glColor4ub(200, 200, 200, 140);
1061         glBegin(GL_LINES);
1062         glVertex2f(rect.xmax, rect.ymin);
1063         glVertex2f(rect.xmax, rect.ymax);
1064         glEnd();
1065
1066         /* group node outline */
1067         uiSetRoundBox(15);
1068         glColor4ub(200, 200, 200, 140);
1069         glEnable( GL_LINE_SMOOTH );
1070         uiDrawBox(GL_LINE_LOOP, rect.xmin-NODE_GROUP_FRAME, rect.ymin, rect.xmax+NODE_GROUP_FRAME, rect.ymax+26, BASIS_RAD);
1071         glDisable( GL_LINE_SMOOTH );
1072         glDisable(GL_BLEND);
1073         
1074         /* backdrop title */
1075         UI_ThemeColor(TH_TEXT_HI);
1076
1077         layout = uiBlockLayout(gnode->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, (short)(rect.xmin+15), (short)(rect.ymax+23),
1078                                                    MIN2((int)(rect.xmax - rect.xmin-18.0f), 140), 20, U.uistyles.first);
1079         RNA_pointer_create(&ntree->id, &RNA_Node, gnode, &ptr);
1080         uiTemplateIDBrowse(layout, (bContext*)C, &ptr, "node_tree", NULL, NULL, NULL);
1081         uiBlockLayoutResolve(gnode->block, NULL, NULL);
1082
1083         /* draw the internal tree nodes and links */
1084         node_draw_nodetree(C, ar, snode, ngroup);
1085
1086         /* group sockets */
1087         for(sock=ngroup->inputs.first, index=0; sock; sock=sock->next, ++index) {
1088                 socket_circle_draw(sock, NODE_SOCKSIZE);
1089                 /* small hack to use socket_circle_draw function with offset */
1090                 sock->locx -= NODE_GROUP_FRAME;
1091                 socket_circle_draw(sock, NODE_SOCKSIZE);
1092                 sock->locx += NODE_GROUP_FRAME;
1093
1094                 bt = uiDefBut(gnode->block, TEX, 0, "", 
1095                                           sock->locx-114, sock->locy+1, 72, NODE_DY,
1096                                           sock->name, 0, 31, 0, 0, "");
1097                 uiButSetFunc(bt, group_verify_cb, snode, ngroup);
1098                 
1099                 node_draw_socket_button(ngroup, sock, "", gnode->block,
1100                                                                 sock->locx-114, sock->locy-NODE_DY, 72,
1101                                                                 NULL, NULL, NULL);
1102
1103                 uiBlockSetDirection(gnode->block, UI_TOP);
1104                 uiBlockBeginAlign(gnode->block);
1105                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP,
1106                                                    sock->locx-40, sock->locy, 16, 16, "");
1107                 if (!sock->prev)
1108                         uiButSetFlag(bt, UI_BUT_DISABLED);
1109                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1110                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
1111                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN,
1112                                                    sock->locx-40, sock->locy-16, 16, 16, "");
1113                 if (!sock->next)
1114                         uiButSetFlag(bt, UI_BUT_DISABLED);
1115                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1116                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
1117                 uiBlockEndAlign(gnode->block);
1118                 uiBlockSetDirection(gnode->block, 0);
1119                 
1120                 uiBlockSetEmboss(gnode->block, UI_EMBOSSN);
1121                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X,
1122                                                    sock->locx-22, sock->locy-8, 16, 16, "");
1123                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1124                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_IN);
1125                 uiBlockSetEmboss(gnode->block, UI_EMBOSS);
1126         }
1127         
1128         for(sock=ngroup->outputs.first, index=0; sock; sock=sock->next, ++index) {
1129                 socket_circle_draw(sock, NODE_SOCKSIZE);
1130                 /* small hack to use socket_circle_draw function with offset */
1131                 sock->locx += NODE_GROUP_FRAME;
1132                 socket_circle_draw(sock, NODE_SOCKSIZE);
1133                 sock->locx -= NODE_GROUP_FRAME;
1134                 
1135                 uiBlockSetEmboss(gnode->block, UI_EMBOSSN);
1136                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_remove", 0, ICON_X,
1137                                                    sock->locx+6, sock->locy-8, 16, 16, "");
1138                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1139                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
1140                 uiBlockSetEmboss(gnode->block, UI_EMBOSS);
1141                 
1142                 uiBlockSetDirection(gnode->block, UI_TOP);
1143                 uiBlockBeginAlign(gnode->block);
1144                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_up", 0, ICON_TRIA_UP,
1145                                                    sock->locx+24, sock->locy, 16, 16, "");
1146                 if (!sock->prev)
1147                         uiButSetFlag(bt, UI_BUT_DISABLED);
1148                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1149                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
1150                 bt = uiDefIconButO(gnode->block, BUT, "NODE_OT_group_socket_move_down", 0, ICON_TRIA_DOWN,
1151                                                    sock->locx+24, sock->locy-16, 16, 16, "");
1152                 if (!sock->next)
1153                         uiButSetFlag(bt, UI_BUT_DISABLED);
1154                 RNA_int_set(uiButGetOperatorPtrRNA(bt), "index", index);
1155                 RNA_enum_set(uiButGetOperatorPtrRNA(bt), "in_out", SOCK_OUT);
1156                 uiBlockEndAlign(gnode->block);
1157                 uiBlockSetDirection(gnode->block, 0);
1158                 
1159                 if (sock->link) {
1160                         bt = uiDefBut(gnode->block, TEX, 0, "", 
1161                                                   sock->locx+42, sock->locy-NODE_DYS+1, 72, NODE_DY,
1162                                                   sock->name, 0, 31, 0, 0, "");
1163                         uiButSetFunc(bt, group_verify_cb, snode, ngroup);
1164                 }
1165                 else {
1166                         bt = uiDefBut(gnode->block, TEX, 0, "", 
1167                                                   sock->locx+42, sock->locy+1, 72, NODE_DY,
1168                                                   sock->name, 0, 31, 0, 0, "");
1169                         uiButSetFunc(bt, group_verify_cb, snode, ngroup);
1170                         
1171                         node_draw_socket_button(ngroup, sock, "", gnode->block, sock->locx+42, sock->locy-NODE_DY, 72, NULL, NULL, NULL);
1172                 }
1173         }
1174         
1175         uiEndBlock(C, gnode->block);
1176         uiDrawBlock(C, gnode->block);
1177         gnode->block= NULL;
1178 }
1179
1180 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1181 {
1182         View2DScrollers *scrollers;
1183         SpaceNode *snode= CTX_wm_space_node(C);
1184         Scene *scene= CTX_data_scene(C);
1185         int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
1186         
1187         UI_ThemeClearColor(TH_BACK);
1188         glClear(GL_COLOR_BUFFER_BIT);
1189
1190         UI_view2d_view_ortho(v2d);
1191         
1192         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1193
1194         /* only set once */
1195         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1196         glEnable(GL_MAP1_VERTEX_3);
1197
1198         /* aspect+font, set each time */
1199         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
1200         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
1201
1202         UI_view2d_constant_grid_draw(v2d);
1203         /* backdrop */
1204         draw_nodespace_back_pix(ar, snode, color_manage);
1205         
1206         /* nodes */
1207         snode_set_context(snode, CTX_data_scene(C));
1208         
1209         if(snode->nodetree) {
1210                 bNode *node;
1211                 
1212                 /* init ui blocks for opened node group trees first 
1213                  * so they're in the correct depth stack order */
1214                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1215                         if(node->flag & NODE_GROUP_EDIT)
1216                                 node_uiblocks_init(C, (bNodeTree *)node->id);
1217                 }
1218
1219                 node_uiblocks_init(C, snode->nodetree);
1220                 
1221                 
1222                 /* for now, we set drawing coordinates on each redraw */
1223                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1224                         if(node->flag & NODE_GROUP_EDIT)
1225                                 node_update_group(C, snode->nodetree, node);
1226                         else if(node->flag & NODE_HIDDEN)
1227                                 node_update_hidden(node);
1228                         else
1229                                 node_update(C, snode->nodetree, node);
1230                 }
1231
1232                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1233                         
1234                 /* active group */
1235                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1236                         if(node->flag & NODE_GROUP_EDIT)
1237                                 node_draw_group(C, ar, snode, snode->nodetree, node);
1238                 }
1239         }
1240         
1241         /* draw grease-pencil ('canvas' strokes) */
1242         if (/*(snode->flag & SNODE_DISPGP) &&*/ (snode->nodetree))
1243                 draw_gpencil_view2d((bContext*)C, 1);
1244         
1245         /* reset view matrix */
1246         UI_view2d_view_restore(C);
1247         
1248         /* draw grease-pencil (screen strokes, and also paintbuffer) */
1249         if (/*(snode->flag & SNODE_DISPGP) && */(snode->nodetree))
1250                 draw_gpencil_view2d((bContext*)C, 0);
1251         
1252         /* scrollers */
1253         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1254         UI_view2d_scrollers_draw(C, v2d, scrollers);
1255         UI_view2d_scrollers_free(scrollers);
1256 }