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