2.5 - node editor
[blender-staging.git] / source / blender / editors / space_node / node_draw.c
1 /**
2  * $Id: drawnode.c 17439 2008-11-13 09:57:11Z kakbarnf $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 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 "DNA_ID.h"
34 #include "DNA_node_types.h"
35 #include "DNA_image_types.h"
36 #include "DNA_material_types.h"
37 #include "DNA_mesh_types.h"
38 #include "DNA_action_types.h"
39 #include "DNA_color_types.h"
40 #include "DNA_customdata_types.h"
41 #include "DNA_gpencil_types.h"
42 #include "DNA_ipo_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_space_types.h"
46 #include "DNA_screen_types.h"
47 #include "DNA_texture_types.h"
48 #include "DNA_text_types.h"
49 #include "DNA_userdef_types.h"
50
51 #include "BLI_blenlib.h"
52 #include "BLI_arithb.h"
53 #include "MEM_guardedalloc.h"
54
55 #include "BKE_context.h"
56 #include "BKE_global.h"
57 #include "BKE_image.h"
58 #include "BKE_library.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_node.h"
62 #include "BKE_object.h"
63 #include "BKE_texture.h"
64 #include "BKE_text.h"
65 #include "BKE_utildefines.h"
66
67 /* #include "BDR_gpencil.h" XXX */
68
69 #include "BIF_gl.h"
70 #include "BIF_glutil.h"
71 #include "BMF_Api.h"
72
73 #include "WM_api.h"
74
75 #include "ED_screen.h"
76 #include "ED_util.h"
77 #include "ED_types.h"
78
79 #include "UI_text.h"
80 #include "UI_interface.h"
81 #include "UI_interface_icons.h"
82 #include "UI_resources.h"
83 #include "UI_view2d.h"
84
85 #include "CMP_node.h"
86 #include "SHD_node.h"
87
88 #include "node_intern.h"
89
90 // XXX from BSE_node.h
91 #define HIDDEN_RAD              15.0f
92 #define BASIS_RAD               8.0f
93 #define NODE_DYS                10
94 #define NODE_DY                 20
95 #define NODE_SOCKSIZE   5
96
97 // XXX interface.h
98 extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
99 extern void ui_rasterpos_safe(float x, float y, float aspect);
100 extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
101 void ui_draw_tria_icon(float x, float y, float aspect, char dir) {}
102
103 // XXX butspace.h
104 #define B_NODE_EXEC                     3610
105
106 static void snode_drawstring(void *curfont, SpaceNode *snode, char *str, int okwidth)
107 {
108 #if 0 // XXX
109         char drawstr[NODE_MAXSTR];
110         int width;
111         
112         if(str[0]==0 || okwidth<4) return;
113         
114         BLI_strncpy(drawstr, str, NODE_MAXSTR);
115         width= snode->aspect*UI_GetStringWidth(curfont, drawstr, 0);
116
117         if(width > okwidth) {
118                 int len= strlen(drawstr)-1;
119                 
120                 while(width > okwidth && len>=0) {
121                         drawstr[len]= 0;
122                         
123                         width= snode->aspect*UI_GetStringWidth(curfont, drawstr, 0);
124                         len--;
125                 }
126                 if(len==0) return;
127         }
128         UI_DrawString(curfont, drawstr, 0);
129 #endif
130 }
131
132 static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
133 {
134         float dx;
135         float dy;
136         
137         dx= 0.5f*(xmax-xmin);
138         dy= 0.5f*(ymax-ymin);
139         
140         UI_ThemeColorShade(color_id, +30);      
141         fdrawline(xmin, ymin, xmax, ymax);
142         fdrawline(xmin+dx, ymin, xmax, ymax-dy);
143         
144         UI_ThemeColorShade(color_id, -10);
145         fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
146         fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
147 }
148
149 /* based on settings in node, sets drawing rect info. each redraw! */
150 static void node_update(bNode *node)
151 {
152         bNodeSocket *nsock;
153         float dy= node->locy;
154         
155         /* header */
156         dy-= NODE_DY;
157         
158         /* little bit space in top */
159         if(node->outputs.first)
160                 dy-= NODE_DYS/2;
161         
162         /* output sockets */
163         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
164                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
165                         nsock->locx= node->locx + node->width;
166                         nsock->locy= dy - NODE_DYS;
167                         dy-= NODE_DY;
168                 }
169         }
170         
171         node->prvr.xmin= node->butr.xmin= node->locx + NODE_DYS;
172         node->prvr.xmax= node->butr.xmax= node->locx + node->width- NODE_DYS;
173         
174         /* preview rect? */
175         if(node->flag & NODE_PREVIEW) {
176                 /* only recalculate size when there's a preview actually, otherwise we use stored result */
177                 if(node->preview && node->preview->rect) {
178                         float aspect= 1.0f;
179                         
180                         if(node->preview && node->preview->xsize && node->preview->ysize) 
181                                 aspect= (float)node->preview->ysize/(float)node->preview->xsize;
182                         
183                         dy-= NODE_DYS/2;
184                         node->prvr.ymax= dy;
185                         
186                         if(aspect <= 1.0f)
187                                 node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
188                         else {
189                                 float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect;    /* width correction of image */
190                                 
191                                 node->prvr.ymin= dy - (node->width-NODE_DY);
192                                 
193                                 node->prvr.xmin+= 0.5f*dx;
194                                 node->prvr.xmax-= 0.5f*dx;
195                         }
196
197                         dy= node->prvr.ymin - NODE_DYS/2;
198
199                         /* make sure that maximums are bigger or equal to minimums */
200                         if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
201                         if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
202                 }
203                 else {
204                         float oldh= node->prvr.ymax - node->prvr.ymin;
205                         if(oldh==0.0f)
206                                 oldh= 0.6f*node->width-NODE_DY;
207                         dy-= NODE_DYS/2;
208                         node->prvr.ymax= dy;
209                         node->prvr.ymin= dy - oldh;
210                         dy= node->prvr.ymin - NODE_DYS/2;
211                 }
212         }
213
214         /* XXX ugly hack, typeinfo for group is generated */
215         if(node->type == NODE_GROUP)
216                 ; // XXX node->typeinfo->butfunc= node_buts_group;
217         
218         /* buttons rect? */
219         if((node->flag & NODE_OPTIONS) && node->typeinfo->butfunc) {
220                 dy-= NODE_DYS/2;
221                 node->butr.ymax= dy;
222                 node->butr.ymin= dy - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL);
223                 dy= node->butr.ymin - NODE_DYS/2;
224         }
225         
226         /* input sockets */
227         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
228                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
229                         nsock->locx= node->locx;
230                         nsock->locy= dy - NODE_DYS;
231                         dy-= NODE_DY;
232                 }
233         }
234         
235         /* little bit space in end */
236         if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
237                 dy-= NODE_DYS/2;
238         
239         node->totr.xmin= node->locx;
240         node->totr.xmax= node->locx + node->width;
241         node->totr.ymax= node->locy;
242         node->totr.ymin= dy;
243 }
244
245 /* based on settings in node, sets drawing rect info. each redraw! */
246 static void node_update_hidden(bNode *node)
247 {
248         bNodeSocket *nsock;
249         float rad, drad, hiddenrad= HIDDEN_RAD;
250         int totin=0, totout=0, tot;
251         
252         /* calculate minimal radius */
253         for(nsock= node->inputs.first; nsock; nsock= nsock->next)
254                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
255                         totin++;
256         for(nsock= node->outputs.first; nsock; nsock= nsock->next)
257                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
258                         totout++;
259         
260         tot= MAX2(totin, totout);
261         if(tot>4) {
262                 hiddenrad += 5.0f*(float)(tot-4);
263         }
264         
265         node->totr.xmin= node->locx;
266         node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
267         node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
268         node->totr.ymin= node->totr.ymax - 2*hiddenrad;
269         
270         /* output sockets */
271         rad=drad= (float)M_PI/(1.0f + (float)totout);
272         
273         for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
274                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
275                         nsock->locx= node->totr.xmax - hiddenrad + (float)sin(rad)*hiddenrad;
276                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
277                         rad+= drad;
278                 }
279         }
280         
281         /* input sockets */
282         rad=drad= - (float)M_PI/(1.0f + (float)totin);
283         
284         for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
285                 if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
286                         nsock->locx= node->totr.xmin + hiddenrad + (float)sin(rad)*hiddenrad;
287                         nsock->locy= node->totr.ymin + hiddenrad + (float)cos(rad)*hiddenrad;
288                         rad+= drad;
289                 }
290         }
291 }
292
293 static int node_get_colorid(bNode *node)
294 {
295         if(node->typeinfo->nclass==NODE_CLASS_INPUT)
296                 return TH_NODE_IN_OUT;
297         if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
298                 if(node->flag & NODE_DO_OUTPUT)
299                         return TH_NODE_IN_OUT;
300                 else
301                         return TH_NODE;
302         }
303         if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
304                 return TH_NODE_CONVERTOR;
305         if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
306                 return TH_NODE_OPERATOR;
307         if(node->typeinfo->nclass==NODE_CLASS_GROUP)
308                 return TH_NODE_GROUP;
309         return TH_NODE;
310 }
311
312 /* based on settings in node, sets drawing rect info. each redraw! */
313 /* note: this assumes only 1 group at a time is drawn (linked data) */
314 /* in node->totr the entire boundbox for the group is stored */
315 static void node_update_group(bNode *gnode)
316 {
317         bNodeTree *ngroup= (bNodeTree *)gnode->id;
318         bNode *node;
319         bNodeSocket *nsock;
320         rctf *rect= &gnode->totr;
321         int counter;
322         
323         /* center them, is a bit of abuse of locx and locy though */
324         for(node= ngroup->nodes.first; node; node= node->next) {
325                 node->locx+= gnode->locx;
326                 node->locy+= gnode->locy;
327                 if(node->flag & NODE_HIDDEN)
328                         node_update_hidden(node);
329                 else
330                         node_update(node);
331                 node->locx-= gnode->locx;
332                 node->locy-= gnode->locy;
333         }
334         counter= 1;
335         for(node= ngroup->nodes.first; node; node= node->next) {
336                 if(counter) {
337                         *rect= node->totr;
338                         counter= 0;
339                 }
340                 else
341                         BLI_union_rctf(rect, &node->totr);
342         }
343         if(counter==1) return;  /* should be prevented? */
344         
345         rect->xmin-= NODE_DY;
346         rect->ymin-= NODE_DY;
347         rect->xmax+= NODE_DY;
348         rect->ymax+= NODE_DY;
349         
350         /* output sockets */
351         for(nsock= gnode->outputs.first; nsock; nsock= nsock->next) {
352                 nsock->locx= rect->xmax;
353                 nsock->locy= nsock->tosock->locy;
354         }
355         
356         /* input sockets */
357         for(nsock= gnode->inputs.first; nsock; nsock= nsock->next) {
358                 nsock->locx= rect->xmin;
359                 nsock->locy= nsock->tosock->locy;
360         }
361 }
362
363 /* note: in cmp_util.c is similar code, for node_compo_pass_on() */
364 static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
365 {
366         bNodeSocket *valsock= NULL, *colsock= NULL, *vecsock= NULL;
367         bNodeSocket *sock;
368         float vec[4][3];
369         int a;
370         
371         vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
372         
373         /* connect the first value buffer in with first value out */
374         /* connect the first RGBA buffer in with first RGBA out */
375         
376         /* test the inputs */
377         for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
378                 if(nodeCountSocketLinks(snode->edittree, sock)) {
379                         if(sock->type==SOCK_VALUE && valsock==NULL) valsock= sock;
380                         if(sock->type==SOCK_VECTOR && vecsock==NULL) vecsock= sock;
381                         if(sock->type==SOCK_RGBA && colsock==NULL) colsock= sock;
382                 }
383         }
384         
385         /* outputs, draw lines */
386         UI_ThemeColor(TH_REDALERT);
387         glEnable(GL_BLEND);
388         glEnable( GL_LINE_SMOOTH );
389         
390         if(valsock || colsock || vecsock) {
391                 for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
392                         if(nodeCountSocketLinks(snode->edittree, sock)) {
393                                 vec[3][0]= sock->locx;
394                                 vec[3][1]= sock->locy;
395                                 
396                                 if(sock->type==SOCK_VALUE && valsock) {
397                                         vec[0][0]= valsock->locx;
398                                         vec[0][1]= valsock->locy;
399                                         node_draw_link_bezier(v2d, vec, TH_WIRE, TH_WIRE, 0);
400                                         valsock= NULL;
401                                 }
402                                 if(sock->type==SOCK_VECTOR && vecsock) {
403                                         vec[0][0]= vecsock->locx;
404                                         vec[0][1]= vecsock->locy;
405                                         node_draw_link_bezier(v2d, vec, TH_WIRE, TH_WIRE, 0);
406                                         vecsock= NULL;
407                                 }
408                                 if(sock->type==SOCK_RGBA && colsock) {
409                                         vec[0][0]= colsock->locx;
410                                         vec[0][1]= colsock->locy;
411                                         node_draw_link_bezier(v2d, vec, TH_WIRE, TH_WIRE, 0);
412                                         colsock= NULL;
413                                 }
414                         }
415                 }
416         }
417         glDisable(GL_BLEND);
418         glDisable( GL_LINE_SMOOTH );
419 }
420
421 /* nice AA filled circle */
422 /* this might have some more generic use */
423 static void circle_draw(float x, float y, float size, int type, int col[3])
424 {
425         /* 16 values of sin function */
426         static float si[16] = {
427                 0.00000000f, 0.39435585f,0.72479278f,0.93775213f,
428                 0.99871650f,0.89780453f,0.65137248f,0.29936312f,
429                 -0.10116832f,-0.48530196f,-0.79077573f,-0.96807711f,
430                 -0.98846832f,-0.84864425f,-0.57126821f,-0.20129852f
431         };
432         /* 16 values of cos function */
433         static float co[16] ={
434                 1.00000000f,0.91895781f,0.68896691f,0.34730525f,
435                 -0.05064916f,-0.44039415f,-0.75875812f,-0.95413925f,
436                 -0.99486932f,-0.87434661f,-0.61210598f,-0.25065253f,
437                 0.15142777f,0.52896401f,0.82076344f,0.97952994f,
438         };
439         int a;
440         
441         glColor3ub(col[0], col[1], col[2]);
442         
443         glBegin(GL_POLYGON);
444         for(a=0; a<16; a++)
445                 glVertex2f(x+size*si[a], y+size*co[a]);
446         glEnd();
447         
448         glColor4ub(0, 0, 0, 150);
449         glEnable(GL_BLEND);
450         glEnable( GL_LINE_SMOOTH );
451         glBegin(GL_LINE_LOOP);
452         for(a=0; a<16; a++)
453                 glVertex2f(x+size*si[a], y+size*co[a]);
454         glEnd();
455         glDisable( GL_LINE_SMOOTH );
456         glDisable(GL_BLEND);
457 }
458
459 static void socket_circle_draw(bNodeSocket *sock, float size)
460 {
461         int col[3];
462         
463         /* choose color based on sock flags */
464         if(sock->flag & SELECT) {
465                 if(sock->flag & SOCK_SEL) {
466                         col[0]= 240; col[1]= 200; col[2]= 40;}
467                 else if(sock->type==SOCK_VALUE) {
468                         col[0]= 200; col[1]= 200; col[2]= 200;}
469                 else if(sock->type==SOCK_VECTOR) {
470                         col[0]= 140; col[1]= 140; col[2]= 240;}
471                 else if(sock->type==SOCK_RGBA) {
472                         col[0]= 240; col[1]= 240; col[2]= 100;}
473                 else {
474                         col[0]= 140; col[1]= 240; col[2]= 140;}
475         }
476         else if(sock->flag & SOCK_SEL) {
477                 col[0]= 200; col[1]= 160; col[2]= 0;}
478         else {
479                 if(sock->type==-1) {
480                         col[0]= 0; col[1]= 0; col[2]= 0;}
481                 else if(sock->type==SOCK_VALUE) {
482                         col[0]= 160; col[1]= 160; col[2]= 160;}
483                 else if(sock->type==SOCK_VECTOR) {
484                         col[0]= 100; col[1]= 100; col[2]= 200;}
485                 else if(sock->type==SOCK_RGBA) {
486                         col[0]= 200; col[1]= 200; col[2]= 40;}
487                 else { 
488                         col[0]= 100; col[1]= 200; col[2]= 100;}
489         }
490         
491         circle_draw(sock->locx, sock->locy, size, sock->type, col);
492 }
493
494 static void node_sync_cb(bContext *C, void *snode_v, void *node_v)
495 {
496         SpaceNode *snode= snode_v;
497         
498         if(snode->treetype==NTREE_SHADER) {
499                 nodeShaderSynchronizeID(node_v, 1);
500                 // allqueue(REDRAWBUTSSHADING, 0);
501         }
502 }
503
504 /* **************  Socket callbacks *********** */
505
506 static void socket_vector_menu_cb(bContext *C, void *node_v, void *ntree_v)
507 {
508         if(node_v && ntree_v) {
509                 NodeTagChanged(ntree_v, node_v); 
510                 // addqueue(curarea->win, UI_BUT_EVENT, B_NODE_EXEC+((bNode *)node_v)->nr); XXX
511         }
512 }
513
514 /* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
515 static uiBlock *socket_vector_menu(bContext *C, uiMenuBlockHandle *handle, void *socket_v)
516 {
517 #if 0 //XXX
518         SpaceNode *snode= curarea->spacedata.first;
519         bNode *node;
520         bNodeSocket *sock= socket_v;
521         bNodeStack *ns= &sock->ns;
522         uiBlock *block;
523         uiBut *bt;
524         
525         /* a bit ugly... retrieve the node the socket comes from */
526         for(node= snode->nodetree->nodes.first; node; node= node->next) {
527                 bNodeSocket *sockt;
528                 for(sockt= node->inputs.first; sockt; sockt= sockt->next)
529                         if(sockt==sock)
530                                 break;
531                 if(sockt)
532                         break;
533         }
534         
535         block= uiNewBlock(&curarea->uiblocks, "socket menu", UI_EMBOSS, UI_HELV, curarea->win);
536
537         /* use this for a fake extra empy space around the buttons */
538         uiDefBut(block, LABEL, 0, "",                   -4, -4, 188, 68, NULL, 0, 0, 0, 0, "");
539         
540         uiBlockBeginAlign(block);
541         bt= uiDefButF(block, NUMSLI, 0, "X ",    0,40,180,20, ns->vec, ns->min, ns->max, 10, 0, "");
542         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
543         bt= uiDefButF(block, NUMSLI, 0, "Y ",    0,20,180,20, ns->vec+1, ns->min, ns->max, 10, 0, "");
544         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
545         bt= uiDefButF(block, NUMSLI, 0, "Z ",    0,0,180,20, ns->vec+2, ns->min, ns->max, 10, 0, "");
546         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
547         
548         uiBlockSetDirection(block, UI_TOP);
549         
550         // allqueue(REDRAWNODE, 0);
551         
552         return block;
553 #endif
554 return NULL;
555 }
556
557 /* not a callback */
558 static void node_draw_preview(bNodePreview *preview, rctf *prv)
559 {
560         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
561         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
562         float tile= (prv->xmax - prv->xmin) / 10.0f;
563         float x, y;
564         
565         /* draw checkerboard backdrop to show alpha */
566         glColor3ub(120, 120, 120);
567         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
568         glColor3ub(160, 160, 160);
569         
570         for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
571                 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
572                         float tilex= tile, tiley= tile;
573
574                         if(x+tile > prv->xmax)
575                                 tilex= prv->xmax-x;
576                         if(y+tile > prv->ymax)
577                                 tiley= prv->ymax-y;
578
579                         glRectf(x, y, x + tilex, y + tiley);
580                 }
581         }
582         for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
583                 for(x=prv->xmin+tile; 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         
595 #ifdef __APPLE__
596         if(is_a_really_crappy_nvidia_card()) {
597                 float zoomx= curarea->winx/(float)(G.v2d->cur.xmax-G.v2d->cur.xmin);
598                 float zoomy= curarea->winy/(float)(G.v2d->cur.ymax-G.v2d->cur.ymin);
599                 glPixelZoom(zoomx*xscale, zoomy*yscale);
600         }
601         else
602 #endif
603                 glPixelZoom(xscale, yscale);
604
605         glEnable(GL_BLEND);
606         glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );  /* premul graphics */
607         
608         glColor4f(1.0, 1.0, 1.0, 1.0);
609         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect);
610         
611         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
612         glDisable(GL_BLEND);
613         glPixelZoom(1.0f, 1.0f);
614
615         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
616         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
617         
618 }
619
620 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
621 {
622         bNodeSocket *sock;
623         uiBlock *block= NULL;
624         uiBut *bt;
625         rctf *rct= &node->totr;
626         float /*slen,*/ iconofs;
627         int /*ofs,*/ color_id= node_get_colorid(node);
628         char showname[128]; /* 128 used below */
629         View2D *v2d = &ar->v2d;
630         
631         uiSetRoundBox(15-4);
632         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
633         
634         /* header */
635         if(color_id==TH_NODE)
636                 UI_ThemeColorShade(color_id, -20);
637         else
638                 UI_ThemeColor(color_id);
639                 
640         uiSetRoundBox(3);
641         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
642         
643         /* show/hide icons, note this sequence is copied in editnode.c */
644         iconofs= rct->xmax;
645         
646         if(node->typeinfo->flag & NODE_PREVIEW) {
647                 int icon_id;
648                 
649                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
650                         icon_id= ICON_MATERIAL;
651                 else
652                         icon_id= ICON_MATERIAL_DEHLT;
653                 iconofs-= 18.0f;
654                 glEnable(GL_BLEND);
655                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, icon_id, snode->aspect, -60);
656                 glDisable(GL_BLEND);
657         }
658         if(node->type == NODE_GROUP) {
659                 
660                 iconofs-= 18.0f;
661                 glEnable(GL_BLEND);
662                 if(node->id->lib) {
663                         glPixelTransferf(GL_GREEN_SCALE, 0.7f);
664                         glPixelTransferf(GL_BLUE_SCALE, 0.3f);
665                         UI_icon_draw_aspect(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect);
666                         glPixelTransferf(GL_GREEN_SCALE, 1.0f);
667                         glPixelTransferf(GL_BLUE_SCALE, 1.0f);
668                 }
669                 else {
670                         UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect, -60);
671                 }
672                 glDisable(GL_BLEND);
673         }
674         if(node->typeinfo->flag & NODE_OPTIONS) {
675                 iconofs-= 18.0f;
676                 glEnable(GL_BLEND);
677                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_BUTS, snode->aspect, -60);
678                 glDisable(GL_BLEND);
679         }
680         {       /* always hide/reveil unused sockets */ 
681                 int shade;
682
683                 iconofs-= 18.0f;
684                 // XXX re-enable
685                 /*if(node_has_hidden_sockets(node))
686                         shade= -40;
687                 else*/
688                         shade= -90;
689                 glEnable(GL_BLEND);
690                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_PLUS, snode->aspect, shade);
691                 glDisable(GL_BLEND);
692         }
693         
694         /* title */
695         if(node->flag & SELECT) 
696                 UI_ThemeColor(TH_TEXT_HI);
697         else
698                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
699         
700         /* open/close entirely? */
701         ui_draw_tria_icon(rct->xmin+8.0f, rct->ymax-NODE_DY+4.0f, snode->aspect, 'v');
702         
703         if(node->flag & SELECT) 
704                 UI_ThemeColor(TH_TEXT_HI);
705         else
706                 UI_ThemeColor(TH_TEXT);
707         
708         // ui_rasterpos_safe(rct->xmin+19.0f, rct->ymax-NODE_DY+5.0f, snode->aspect);
709         
710         if(node->flag & NODE_MUTED)
711                 sprintf(showname, "[%s]", node->name);
712         else if(node->username[0])
713                 sprintf(showname, "(%s) %s", node->username, node->name);
714         else
715                 BLI_strncpy(showname, node->name, 128);
716         
717         block= uiBeginBlock(C, ar, "snode_drawstring_hack", UI_EMBOSSN, UI_HELV);
718         // snode_drawstring(block->curfont, snode, showname, (int)(iconofs - rct->xmin-18.0f));
719         bt= uiDefBut(block, LABEL, 0, showname, (int)rct->xmin+19, (int)rct->ymax-NODE_DY+5, 100, 20, NULL, 0, 0, 0, 0, "");
720         uiEndBlock(C, block);
721         block= NULL;
722
723         /* body */
724         UI_ThemeColor4(TH_NODE);
725         glEnable(GL_BLEND);
726         uiSetRoundBox(8);
727         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
728         glDisable(GL_BLEND);
729
730         /* scaling indicator */
731         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
732
733         /* outline active emphasis */
734         if(node->flag & NODE_ACTIVE) {
735                 glEnable(GL_BLEND);
736                 glColor4ub(200, 200, 200, 140);
737                 uiSetRoundBox(15-4);
738                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
739                 glDisable(GL_BLEND);
740         }
741         
742         /* disable lines */
743         if(node->flag & NODE_MUTED)
744                 node_draw_mute_line(v2d, snode, node);
745
746         /* we make buttons for input sockets, if... */
747         if(node->flag & NODE_OPTIONS) {
748                 if(node->inputs.first || node->typeinfo->butfunc) {
749                         char str[32];
750                         
751                         /* make unique block name, also used for handling blocks in editnode.c */
752                         sprintf(str, "node buttons %p", node);
753                         
754                         //block= uiNewBlock(&sa->uiblocks, str, UI_EMBOSS, UI_HELV, sa->win);
755                         block= uiBeginBlock(C, ar, str, UI_EMBOSS, UI_HELV);
756                         uiBlockSetFlag(block, UI_BLOCK_NO_HILITE);
757                         // XXX if(snode->id)
758                         // XXX  uiSetButLock(snode->id->lib!=NULL, ERROR_LIBDATA_MESSAGE);
759                 }
760         }
761         
762         /* hurmf... another candidate for callback, have to see how this works first */
763         if(node->id && block && snode->treetype==NTREE_SHADER)
764                 nodeShaderSynchronizeID(node, 0);
765         
766         /* socket inputs, buttons */
767         for(sock= node->inputs.first; sock; sock= sock->next) {
768                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
769                         socket_circle_draw(sock, NODE_SOCKSIZE);
770                         
771                         if(block && sock->link==NULL) {
772                                 float *butpoin= sock->ns.vec;
773                                 
774                                 if(sock->type==SOCK_VALUE) {
775                                         bt= uiDefButF(block, NUM, B_NODE_EXEC+node->nr, sock->name, 
776                                                   (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17, 
777                                                   butpoin, sock->ns.min, sock->ns.max, 10, 2, "");
778                                         uiButSetFunc(bt, node_sync_cb, snode, node);
779                                 }
780                                 else if(sock->type==SOCK_VECTOR) {
781                                         uiDefBlockBut(block, socket_vector_menu, sock, sock->name, 
782                                                   (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17, 
783                                                   "");
784                                 }
785                                 else if(block && sock->type==SOCK_RGBA) {
786                                         short labelw= (short)node->width-NODE_DY-40, width;
787                                         
788                                         if(labelw>0) width= 40; else width= (short)node->width-NODE_DY;
789                                         
790                                         bt= uiDefButF(block, COL, B_NODE_EXEC+node->nr, "", 
791                                                 (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15, 
792                                                    butpoin, 0, 0, 0, 0, "");
793                                         uiButSetFunc(bt, node_sync_cb, snode, node);
794                                         
795                                         if(labelw>0) uiDefBut(block, LABEL, 0, sock->name, 
796                                                                                    (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15, 
797                                                                                    NULL, 0, 0, 0, 0, "");
798                                 }
799                         }
800                         else {
801                                 /* XXX fix
802                                 UI_ThemeColor(TH_TEXT);
803                                 ui_rasterpos_safe(sock->locx+8.0f, sock->locy-5.0f, snode->aspect);
804                                 UI_DrawString(snode->curfont, sock->name, 0);
805                                 */
806                         }
807                 }
808         }
809         
810         /* socket outputs */
811         for(sock= node->outputs.first; sock; sock= sock->next) {
812                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
813                         socket_circle_draw(sock, NODE_SOCKSIZE);
814                         
815                         /* XXX fix
816                         UI_ThemeColor(TH_TEXT);
817                         ofs= 0;
818                         slen= snode->aspect*UI_GetStringWidth(snode->curfont, sock->name, 0);
819                         while(slen > node->width) {
820                                 ofs++;
821                                 slen= snode->aspect*UI_GetStringWidth(snode->curfont, sock->name+ofs, 0);
822                         }
823                         ui_rasterpos_safe(sock->locx-8.0f-slen, sock->locy-5.0f, snode->aspect);
824                         UI_DrawString(snode->curfont, sock->name+ofs, 0);
825                         */
826                 }
827         }
828         
829         /* preview */
830         if(node->flag & NODE_PREVIEW)
831                 if(node->preview && node->preview->rect)
832                         node_draw_preview(node->preview, &node->prvr);
833                 
834         /* buttons */
835         if(node->flag & NODE_OPTIONS) {
836                 if(block) {
837                         if(node->typeinfo->butfunc) {
838                                 node->typeinfo->butfunc(block, snode->nodetree, node, &node->butr);
839                         }
840                         uiDrawBlock(block);
841                 }
842         }
843         
844         if(block)
845                 uiEndBlock(C, block);
846 }
847
848 static void node_draw_hidden(View2D *v2d, SpaceNode *snode, bNode *node)
849 {
850 //      uiBlock *block; // XXX HACK
851         bNodeSocket *sock;
852         rctf *rct= &node->totr;
853         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
854         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
855         int color_id= node_get_colorid(node);
856         char showname[128];     /* 128 is used below */
857         
858         /* shadow */
859         uiSetRoundBox(15);
860         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
861
862         /* body */
863         UI_ThemeColor(color_id);        
864         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
865         
866         /* outline active emphasis */
867         if(node->flag & NODE_ACTIVE) {
868                 glEnable(GL_BLEND);
869                 glColor4ub(200, 200, 200, 140);
870                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
871                 glDisable(GL_BLEND);
872         }
873         
874         /* title */
875         if(node->flag & SELECT) 
876                 UI_ThemeColor(TH_TEXT_HI);
877         else
878                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
879         
880         /* open entirely icon */
881         ui_draw_tria_icon(rct->xmin+9.0f, centy-6.0f, snode->aspect, 'h');      
882         
883         /* disable lines */
884         if(node->flag & NODE_MUTED)
885                 node_draw_mute_line(v2d, snode, node);  
886         
887         if(node->flag & SELECT) 
888                 UI_ThemeColor(TH_TEXT_HI);
889         else
890                 UI_ThemeColor(TH_TEXT);
891         
892         if(node->miniwidth>0.0f) {
893                 ui_rasterpos_safe(rct->xmin+21.0f, centy-4.0f, snode->aspect);
894
895                 if(node->flag & NODE_MUTED)
896                         sprintf(showname, "[%s]", node->name);
897                 else if(node->username[0])
898                         sprintf(showname, "(%s)%s", node->username, node->name);
899                 else
900                         BLI_strncpy(showname, node->name, 128);
901
902                 /* XXX 
903                 block= uiBeginBlock(C, ar, "snode_drawstring_hack", UI_EMBOSSN, UI_HELV);
904                 // snode_drawstring(block->curfont, snode, showname, (int)(iconofs - rct->xmin-18.0f));
905                 bt= uiDefBut(block, LABEL, 0, showname, rct->xmin+21, centy-4, 100, 20, NULL, 0, 0, 0, 0, "");
906                 uiEndBlock(C, block);
907                 */
908                 
909         }       
910
911         /* scale widget thing */
912         UI_ThemeColorShade(color_id, -10);      
913         dx= 10.0f;
914         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
915         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
916         
917         UI_ThemeColorShade(color_id, +30);
918         dx-= snode->aspect;
919         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
920         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
921         
922         /* sockets */
923         for(sock= node->inputs.first; sock; sock= sock->next) {
924                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
925                         socket_circle_draw(sock, NODE_SOCKSIZE);
926         }
927         
928         for(sock= node->outputs.first; sock; sock= sock->next) {
929                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
930                         socket_circle_draw(sock, NODE_SOCKSIZE);
931         }
932 }
933
934 static void node_draw_nodetree(const bContext *C, ARegion *ar, SpaceNode *snode, bNodeTree *ntree)
935 {
936         bNode *node;
937         bNodeLink *link;
938         int a;
939         
940         if(ntree==NULL) return;         /* groups... */
941         
942         /* node lines */
943         glEnable(GL_BLEND);
944         glEnable(GL_LINE_SMOOTH);
945         for(link= ntree->links.first; link; link= link->next)
946                 node_draw_link(&ar->v2d, snode, link);
947         glDisable(GL_LINE_SMOOTH);
948         glDisable(GL_BLEND);
949         
950         /* not selected first */
951         for(a=0, node= ntree->nodes.first; node; node= node->next, a++) {
952                 node->nr= a;            /* index of node in list, used for exec event code */
953                 if(!(node->flag & SELECT)) {
954                         if(node->flag & NODE_GROUP_EDIT);
955                         else if(node->flag & NODE_HIDDEN)
956                                 node_draw_hidden(&ar->v2d, snode, node);
957                         else
958                                 node_draw_basis(C, ar, snode, node);
959                 }
960         }
961         
962         /* selected */
963         for(node= ntree->nodes.first; node; node= node->next) {
964                 if(node->flag & SELECT) {
965                         if(node->flag & NODE_GROUP_EDIT);
966                         else if(node->flag & NODE_HIDDEN)
967                                 node_draw_hidden(&ar->v2d, snode, node);
968                         else
969                                 node_draw_basis(C, ar, snode, node);
970                 }
971         }       
972 }
973
974 /* fake links from groupnode to internal nodes */
975 static void node_draw_group_links(View2D *v2d, SpaceNode *snode, bNode *gnode)
976 {
977         bNodeLink fakelink;
978         bNodeSocket *sock;
979         
980         glEnable(GL_BLEND);
981         glEnable(GL_LINE_SMOOTH);
982         
983         fakelink.tonode= fakelink.fromnode= gnode;
984         
985         for(sock= gnode->inputs.first; sock; sock= sock->next) {
986                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
987                         if(sock->tosock) {
988                                 fakelink.fromsock= sock;
989                                 fakelink.tosock= sock->tosock;
990                                 node_draw_link(v2d, snode, &fakelink);
991                         }
992                 }
993         }
994         
995         for(sock= gnode->outputs.first; sock; sock= sock->next) {
996                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
997                         if(sock->tosock) {
998                                 fakelink.tosock= sock;
999                                 fakelink.fromsock= sock->tosock;
1000                                 node_draw_link(v2d, snode, &fakelink);
1001                         }
1002                 }
1003         }
1004         
1005         glDisable(GL_BLEND);
1006         glDisable(GL_LINE_SMOOTH);
1007 }
1008
1009 /* groups are, on creation, centered around 0,0 */
1010 static void node_draw_group(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *gnode)
1011 {
1012         bNodeTree *ngroup= (bNodeTree *)gnode->id;
1013         bNodeSocket *sock;
1014         rctf rect= gnode->totr;
1015         char showname[128];
1016         
1017         /* backdrop header */
1018         glEnable(GL_BLEND);
1019         uiSetRoundBox(3);
1020         UI_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
1021         gl_round_box(GL_POLYGON, rect.xmin, rect.ymax, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1022         
1023         /* backdrop body */
1024         UI_ThemeColorShadeAlpha(TH_BACK, -8, -70);
1025         uiSetRoundBox(12);
1026         gl_round_box(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
1027         
1028         /* selection outline */
1029         uiSetRoundBox(15);
1030         glColor4ub(200, 200, 200, 140);
1031         glEnable( GL_LINE_SMOOTH );
1032         gl_round_box(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
1033         glDisable( GL_LINE_SMOOTH );
1034         glDisable(GL_BLEND);
1035         
1036         /* backdrop title */
1037         UI_ThemeColor(TH_TEXT_HI);
1038         ui_rasterpos_safe(rect.xmin+8.0f, rect.ymax+5.0f, snode->aspect);
1039
1040         if(gnode->username[0]) {
1041                 strcpy(showname,"(");
1042                 strcat(showname, gnode->username);
1043                 strcat(showname,") ");
1044                 strcat(showname, ngroup->id.name+2);
1045         }
1046         else
1047                 strcpy(showname, ngroup->id.name+2);
1048
1049         UI_DrawString(snode->curfont, showname, 0);
1050         
1051         /* links from groupsockets to the internal nodes */
1052         node_draw_group_links(&ar->v2d, snode, gnode);
1053         
1054         /* group sockets */
1055         for(sock= gnode->inputs.first; sock; sock= sock->next)
1056                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1057                         socket_circle_draw(sock, NODE_SOCKSIZE);
1058         for(sock= gnode->outputs.first; sock; sock= sock->next)
1059                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1060                         socket_circle_draw(sock, NODE_SOCKSIZE);
1061
1062         /* and finally the whole tree */
1063         node_draw_nodetree(C, ar, snode, ngroup);
1064 }
1065
1066 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1067 {
1068         float col[3];
1069         View2DScrollers *scrollers;
1070         SpaceNode *snode= (SpaceNode*)CTX_wm_space_data(C);
1071         
1072         UI_GetThemeColor3fv(TH_BACK, col);
1073         glClearColor(col[0], col[1], col[2], 0.0);
1074         glClear(GL_COLOR_BUFFER_BIT);
1075
1076         UI_view2d_view_ortho(C, v2d);
1077         
1078         //bwin_clear_viewmat(sa->win);  /* clear buttons view */
1079         //glLoadIdentity();
1080         
1081         /* always free, blocks here have no unique identifier (1 block per node) */
1082         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1083
1084         /* only set once */
1085         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1086         glEnable(GL_MAP1_VERTEX_3);
1087
1088         /* aspect+font, set each time */
1089         //snode->aspect= (snode->v2d.cur.xmax - snode->v2d.cur.xmin)/((float)sa->winx);
1090         //snode->curfont= uiSetCurFont_ext(snode->aspect);
1091
1092         UI_view2d_constant_grid_draw(C, v2d);
1093         /* backdrop */
1094         // draw_nodespace_back_pix(sa, snode);
1095         
1096         /* nodes */
1097         snode_set_context(snode, CTX_data_scene(C));
1098         
1099         if(snode->nodetree) {
1100                 bNode *node;
1101                 
1102                 /* for now, we set drawing coordinates on each redraw */
1103                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1104                         if(node->flag & NODE_GROUP_EDIT)
1105                                 node_update_group(node);
1106                         else if(node->flag & NODE_HIDDEN)
1107                                 node_update_hidden(node);
1108                         else
1109                                 node_update(node);
1110                 }
1111
1112                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1113                         
1114                 /* active group */
1115                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1116                         if(node->flag & NODE_GROUP_EDIT)
1117                                 node_draw_group(C, ar, snode, node);
1118                 }
1119         }
1120         
1121         /* draw grease-pencil ('canvas' strokes) */
1122         /*if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
1123                 draw_gpencil_2dview(sa, 1);*/
1124         
1125         /* restore viewport (not needed yet) */
1126         /*mywinset(sa->win);*/
1127
1128         /* ortho at pixel level curarea */
1129         /*myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);*/
1130         
1131         /* draw grease-pencil (screen strokes) */
1132         /*if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
1133                 draw_gpencil_2dview(sa, 0);*/
1134
1135         //draw_area_emboss(sa);
1136         
1137         /* it is important to end a view in a transform compatible with buttons */
1138         /*bwin_scalematrix(sa->win, snode->blockscale, snode->blockscale, snode->blockscale);
1139         nodes_blockhandlers(sa);*/
1140         
1141         //curarea->win_swap= WIN_BACK_OK;
1142         
1143         /* in the end, this is a delayed previewrender test, to allow buttons to be first */
1144         /*if(snode->flag & SNODE_DO_PREVIEW) {
1145                 addafterqueue(sa->win, RENDERPREVIEW, 1);
1146                 snode->flag &= ~SNODE_DO_PREVIEW;
1147         }*/
1148         
1149         
1150         
1151         /* reset view matrix */
1152         UI_view2d_view_restore(C);
1153         
1154         /* scrollers */
1155         scrollers= UI_view2d_scrollers_calc(C, v2d, 10/*unit*/, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1156         UI_view2d_scrollers_draw(C, v2d, scrollers);
1157         UI_view2d_scrollers_free(scrollers);
1158 }