Fix part of #19309: editing node vector input in a popup did
[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         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN);
571
572         /* use this for a fake extra empy space around the buttons */
573         uiDefBut(block, LABEL, 0, "",                   -4, -4, 188, 68, NULL, 0, 0, 0, 0, "");
574         
575         uiBlockBeginAlign(block);
576         bt= uiDefButF(block, NUMSLI, 0, "X ",    0,40,180,20, ns->vec, ns->min, ns->max, 10, 0, "");
577         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
578         bt= uiDefButF(block, NUMSLI, 0, "Y ",    0,20,180,20, ns->vec+1, ns->min, ns->max, 10, 0, "");
579         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
580         bt= uiDefButF(block, NUMSLI, 0, "Z ",    0,0,180,20, ns->vec+2, ns->min, ns->max, 10, 0, "");
581         uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
582         
583         uiBlockSetDirection(block, UI_TOP);
584         uiEndBlock(C, block);
585         
586         ED_area_tag_redraw(sa);
587         
588         return block;
589 }
590
591 /* not a callback */
592 static void node_draw_preview(bNodePreview *preview, rctf *prv)
593 {
594         float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
595         float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
596         float tile= (prv->xmax - prv->xmin) / 10.0f;
597         float x, y;
598         
599         /* draw checkerboard backdrop to show alpha */
600         glColor3ub(120, 120, 120);
601         glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
602         glColor3ub(160, 160, 160);
603         
604         for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
605                 for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
606                         float tilex= tile, tiley= tile;
607
608                         if(x+tile > prv->xmax)
609                                 tilex= prv->xmax-x;
610                         if(y+tile > prv->ymax)
611                                 tiley= prv->ymax-y;
612
613                         glRectf(x, y, x + tilex, y + tiley);
614                 }
615         }
616         for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
617                 for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
618                         float tilex= tile, tiley= tile;
619
620                         if(x+tile > prv->xmax)
621                                 tilex= prv->xmax-x;
622                         if(y+tile > prv->ymax)
623                                 tiley= prv->ymax-y;
624
625                         glRectf(x, y, x + tilex, y + tiley);
626                 }
627         }
628         
629 #ifdef __APPLE__
630 //      if(is_a_really_crappy_nvidia_card()) {  XXX
631 //              float zoomx= curarea->winx/(float)(G.v2d->cur.xmax-G.v2d->cur.xmin);
632 //              float zoomy= curarea->winy/(float)(G.v2d->cur.ymax-G.v2d->cur.ymin);
633 //              glPixelZoom(zoomx*xscale, zoomy*yscale);
634 //      }
635 //      else
636 #endif
637                 glPixelZoom(xscale, yscale);
638
639         glEnable(GL_BLEND);
640         glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );  /* premul graphics */
641         
642         glColor4f(1.0, 1.0, 1.0, 1.0);
643         glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect);
644         
645         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
646         glDisable(GL_BLEND);
647         glPixelZoom(1.0f, 1.0f);
648
649         UI_ThemeColorShadeAlpha(TH_BACK, -15, +100);
650         fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
651         
652 }
653
654 static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
655 {
656         bNodeSocket *sock;
657         uiBut *bt;
658         rctf *rct= &node->totr;
659         float /*slen,*/ iconofs;
660         int /*ofs,*/ color_id= node_get_colorid(node);
661         char showname[128]; /* 128 used below */
662         View2D *v2d = &ar->v2d;
663         
664         uiSetRoundBox(15-4);
665         ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
666         
667         /* header */
668         if(color_id==TH_NODE)
669                 UI_ThemeColorShade(color_id, -20);
670         else
671                 UI_ThemeColor(color_id);
672                 
673         uiSetRoundBox(3);
674         uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
675         
676         /* show/hide icons, note this sequence is copied in editnode.c */
677         iconofs= rct->xmax;
678         
679         if(node->typeinfo->flag & NODE_PREVIEW) {
680                 int icon_id;
681                 
682                 if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
683                         icon_id= ICON_MATERIAL;
684                 else
685                         icon_id= ICON_MATERIAL_DATA;
686                 iconofs-= 18.0f;
687                 glEnable(GL_BLEND);
688                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, icon_id, snode->aspect, -60);
689                 glDisable(GL_BLEND);
690         }
691         if(node->type == NODE_GROUP) {
692                 
693                 iconofs-= 18.0f;
694                 glEnable(GL_BLEND);
695                 if(node->id->lib) {
696                         glPixelTransferf(GL_GREEN_SCALE, 0.7f);
697                         glPixelTransferf(GL_BLUE_SCALE, 0.3f);
698                         UI_icon_draw_aspect(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect);
699                         glPixelTransferf(GL_GREEN_SCALE, 1.0f);
700                         glPixelTransferf(GL_BLUE_SCALE, 1.0f);
701                 }
702                 else {
703                         UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect, -60);
704                 }
705                 glDisable(GL_BLEND);
706         }
707         if(node->typeinfo->flag & NODE_OPTIONS) {
708                 iconofs-= 18.0f;
709                 glEnable(GL_BLEND);
710                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_BUTS, snode->aspect, -60);
711                 glDisable(GL_BLEND);
712         }
713         {       /* always hide/reveal unused sockets */ 
714                 int shade;
715
716                 iconofs-= 18.0f;
717                 // XXX re-enable
718                 /*if(node_has_hidden_sockets(node))
719                         shade= -40;
720                 else*/
721                         shade= -90;
722                 glEnable(GL_BLEND);
723                 UI_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_PLUS, snode->aspect, shade);
724                 glDisable(GL_BLEND);
725         }
726         
727         /* title */
728         if(node->flag & SELECT) 
729                 UI_ThemeColor(TH_TEXT_HI);
730         else
731                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
732         
733         /* open/close entirely? */
734         ui_draw_tria_icon(rct->xmin+8.0f, rct->ymax-NODE_DY+4.0f, snode->aspect, 'v');
735         
736         if(node->flag & SELECT) 
737                 UI_ThemeColor(TH_TEXT_HI);
738         else
739                 UI_ThemeColor(TH_TEXT);
740         
741         if(node->flag & NODE_MUTED)
742                 sprintf(showname, "[%s]", node->name);
743         else if(node->username[0])
744                 sprintf(showname, "(%s) %s", node->username, node->name);
745         else
746                 BLI_strncpy(showname, node->name, 128);
747         
748         uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(rct->ymax-NODE_DY), 
749                          (int)(iconofs - rct->xmin-18.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
750
751         /* body */
752         UI_ThemeColor4(TH_NODE);
753         glEnable(GL_BLEND);
754         uiSetRoundBox(8);
755         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
756         glDisable(GL_BLEND);
757
758         /* scaling indicator */
759         node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
760
761         /* outline active emphasis */
762         if(node->flag & NODE_ACTIVE) {
763                 glEnable(GL_BLEND);
764                 glColor4ub(200, 200, 200, 140);
765                 uiSetRoundBox(15-4);
766                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
767                 glDisable(GL_BLEND);
768         }
769         
770         /* disable lines */
771         if(node->flag & NODE_MUTED)
772                 node_draw_mute_line(v2d, snode, node);
773
774         
775         /* hurmf... another candidate for callback, have to see how this works first */
776         if(node->id && node->block && snode->treetype==NTREE_SHADER)
777                 nodeShaderSynchronizeID(node, 0);
778         
779         /* socket inputs, buttons */
780         for(sock= node->inputs.first; sock; sock= sock->next) {
781                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
782                         socket_circle_draw(sock, NODE_SOCKSIZE);
783                         
784                         if(node->block && sock->link==NULL) {
785                                 float *butpoin= sock->ns.vec;
786                                 
787                                 if(sock->type==SOCK_VALUE) {
788                                         bt= uiDefButF(node->block, NUM, B_NODE_EXEC, sock->name, 
789                                                   (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17, 
790                                                   butpoin, sock->ns.min, sock->ns.max, 10, 2, "");
791                                         uiButSetFunc(bt, node_sync_cb, snode, node);
792                                 }
793                                 else if(sock->type==SOCK_VECTOR) {
794                                         uiDefBlockBut(node->block, socket_vector_menu, sock, sock->name, 
795                                                   (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17, 
796                                                   "");
797                                 }
798                                 else if(node->block && sock->type==SOCK_RGBA) {
799                                         short labelw= (short)node->width-NODE_DY-40, width;
800                                         
801                                         if(labelw>0) width= 40; else width= (short)node->width-NODE_DY;
802                                         
803                                         bt= uiDefButF(node->block, COL, B_NODE_EXEC, "", 
804                                                 (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15, 
805                                                    butpoin, 0, 0, 0, 0, "");
806                                         uiButSetFunc(bt, node_sync_cb, snode, node);
807                                         
808                                         if(labelw>0) uiDefBut(node->block, LABEL, 0, sock->name, 
809                                                                                    (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15, 
810                                                                                    NULL, 0, 0, 0, 0, "");
811                                 }
812                         }
813                         else {
814                                 
815                                 uiDefBut(node->block, LABEL, 0, sock->name, (short)(sock->locx+3.0f), (short)(sock->locy-9.0f), 
816                                                  (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
817                         }
818                 }
819         }
820         
821         /* socket outputs */
822         for(sock= node->outputs.first; sock; sock= sock->next) {
823                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
824                         float slen;
825                         int ofs= 0;
826                         
827                         socket_circle_draw(sock, NODE_SOCKSIZE);
828                         
829                         UI_ThemeColor(TH_TEXT);
830                         slen= snode->aspect*UI_GetStringWidth(sock->name);
831                         while(slen > node->width) {
832                                 ofs++;
833                                 slen= snode->aspect*UI_GetStringWidth(sock->name+ofs);
834                         }
835                         
836                         uiDefBut(node->block, LABEL, 0, sock->name+ofs, (short)(sock->locx-15.0f-slen), (short)(sock->locy-9.0f), 
837                                          (short)(node->width-NODE_DY), NODE_DY,  NULL, 0, 0, 0, 0, "");
838                 }
839         }
840         
841         /* preview */
842         if(node->flag & NODE_PREVIEW)
843                 if(node->preview && node->preview->rect)
844                         node_draw_preview(node->preview, &node->prvr);
845                 
846         uiEndBlock(C, node->block);
847         uiDrawBlock(C, node->block);
848         node->block= NULL;
849 }
850
851 static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, bNode *node)
852 {
853         bNodeSocket *sock;
854         rctf *rct= &node->totr;
855         float dx, centy= 0.5f*(rct->ymax+rct->ymin);
856         float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
857         int color_id= node_get_colorid(node);
858         char showname[128];     /* 128 is used below */
859         
860         /* shadow */
861         uiSetRoundBox(15);
862         ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
863
864         /* body */
865         UI_ThemeColor(color_id);        
866         uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
867         
868         /* outline active emphasis */
869         if(node->flag & NODE_ACTIVE) {
870                 glEnable(GL_BLEND);
871                 glColor4ub(200, 200, 200, 140);
872                 gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
873                 glDisable(GL_BLEND);
874         }
875         
876         /* title */
877         if(node->flag & SELECT) 
878                 UI_ThemeColor(TH_TEXT_HI);
879         else
880                 UI_ThemeColorBlendShade(TH_TEXT, color_id, 0.4f, 10);
881         
882         /* open entirely icon */
883         ui_draw_tria_icon(rct->xmin+9.0f, centy-6.0f, snode->aspect, 'h');      
884         
885         /* disable lines */
886         if(node->flag & NODE_MUTED)
887                 node_draw_mute_line(&ar->v2d, snode, node);     
888         
889         if(node->flag & SELECT) 
890                 UI_ThemeColor(TH_TEXT_HI);
891         else
892                 UI_ThemeColor(TH_TEXT);
893         
894         if(node->miniwidth>0.0f) {
895
896                 if(node->flag & NODE_MUTED)
897                         sprintf(showname, "[%s]", node->name);
898                 else if(node->username[0])
899                         sprintf(showname, "(%s)%s", node->username, node->name);
900                 else
901                         BLI_strncpy(showname, node->name, 128);
902
903                 uiDefBut(node->block, LABEL, 0, showname, (short)(rct->xmin+15), (short)(centy-10), 
904                                  (int)(rct->xmax - rct->xmin-18.0f -12.0f), NODE_DY,  NULL, 0, 0, 0, 0, "");
905         }       
906
907         /* scale widget thing */
908         UI_ThemeColorShade(color_id, -10);      
909         dx= 10.0f;
910         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
911         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
912         
913         UI_ThemeColorShade(color_id, +30);
914         dx-= snode->aspect;
915         fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
916         fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
917         
918         /* sockets */
919         for(sock= node->inputs.first; sock; sock= sock->next) {
920                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
921                         socket_circle_draw(sock, NODE_SOCKSIZE);
922         }
923         
924         for(sock= node->outputs.first; sock; sock= sock->next) {
925                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
926                         socket_circle_draw(sock, NODE_SOCKSIZE);
927         }
928         
929         uiEndBlock(C, node->block);
930         uiDrawBlock(C, node->block);
931         node->block= NULL;
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(C, ar, 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(C, ar, 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
1039         if(gnode->username[0]) {
1040                 strcpy(showname,"(");
1041                 strcat(showname, gnode->username);
1042                 strcat(showname,") ");
1043                 strcat(showname, ngroup->id.name+2);
1044         }
1045         else
1046                 strcpy(showname, ngroup->id.name+2);
1047
1048         UI_DrawString(rect.xmin+8.0f, rect.ymax+5.0f, showname);
1049         
1050         /* links from groupsockets to the internal nodes */
1051         node_draw_group_links(&ar->v2d, snode, gnode);
1052         
1053         /* group sockets */
1054         for(sock= gnode->inputs.first; sock; sock= sock->next)
1055                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1056                         socket_circle_draw(sock, NODE_SOCKSIZE);
1057         for(sock= gnode->outputs.first; sock; sock= sock->next)
1058                 if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
1059                         socket_circle_draw(sock, NODE_SOCKSIZE);
1060
1061         /* and finally the whole tree */
1062         node_draw_nodetree(C, ar, snode, ngroup);
1063 }
1064
1065 void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d)
1066 {
1067         float col[3];
1068         View2DScrollers *scrollers;
1069         SpaceNode *snode= CTX_wm_space_node(C);
1070         
1071         UI_GetThemeColor3fv(TH_BACK, col);
1072         glClearColor(col[0], col[1], col[2], 0);
1073         glClear(GL_COLOR_BUFFER_BIT);
1074
1075         UI_view2d_view_ortho(C, v2d);
1076         
1077         //uiFreeBlocksWin(&sa->uiblocks, sa->win);
1078
1079         /* only set once */
1080         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1081         glEnable(GL_MAP1_VERTEX_3);
1082
1083         /* aspect+font, set each time */
1084         snode->aspect= (v2d->cur.xmax - v2d->cur.xmin)/((float)ar->winx);
1085         // XXX snode->curfont= uiSetCurFont_ext(snode->aspect);
1086
1087         UI_view2d_constant_grid_draw(C, v2d);
1088         /* backdrop */
1089         draw_nodespace_back_pix(ar, snode);
1090         
1091         /* nodes */
1092         snode_set_context(snode, CTX_data_scene(C));
1093         
1094         if(snode->nodetree) {
1095                 bNode *node;
1096                 
1097                 /* for now, we set drawing coordinates on each redraw */
1098                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1099                         if(node->flag & NODE_GROUP_EDIT)
1100                                 node_update_group(C, snode->nodetree, node);
1101                         else if(node->flag & NODE_HIDDEN)
1102                                 node_update_hidden(C, node);
1103                         else
1104                                 node_update(C, snode->nodetree, node);
1105                 }
1106
1107                 node_draw_nodetree(C, ar, snode, snode->nodetree);
1108                         
1109                 /* active group */
1110                 for(node= snode->nodetree->nodes.first; node; node= node->next) {
1111                         if(node->flag & NODE_GROUP_EDIT)
1112                                 node_draw_group(C, ar, snode, node);
1113                 }
1114         }
1115         
1116         /* draw grease-pencil ('canvas' strokes) */
1117         /*if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
1118                 draw_gpencil_2dview(sa, 1);*/
1119         
1120         /* restore viewport (not needed yet) */
1121         /*mywinset(sa->win);*/
1122
1123         /* ortho at pixel level curarea */
1124         /*myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);*/
1125         
1126         /* draw grease-pencil (screen strokes) */
1127         /*if ((snode->flag & SNODE_DISPGP) && (snode->nodetree))
1128                 draw_gpencil_2dview(sa, 0);*/
1129
1130         //draw_area_emboss(sa);
1131         
1132         /* it is important to end a view in a transform compatible with buttons */
1133         /*bwin_scalematrix(sa->win, snode->blockscale, snode->blockscale, snode->blockscale);
1134         nodes_blockhandlers(sa);*/
1135         
1136         //curarea->win_swap= WIN_BACK_OK;
1137         
1138         /* in the end, this is a delayed previewrender test, to allow buttons to be first */
1139         /*if(snode->flag & SNODE_DO_PREVIEW) {
1140                 addafterqueue(sa->win, RENDERPREVIEW, 1);
1141                 snode->flag &= ~SNODE_DO_PREVIEW;
1142         }*/
1143         
1144         
1145         
1146         /* reset view matrix */
1147         UI_view2d_view_restore(C);
1148         
1149         /* scrollers */
1150         scrollers= UI_view2d_scrollers_calc(C, v2d, 10, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1151         UI_view2d_scrollers_draw(C, v2d, scrollers);
1152         UI_view2d_scrollers_free(scrollers);
1153 }