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