ac8750f84e6600c8a7af1c48bea4da316bc1ef8d
[blender-staging.git] / source / blender / editors / interface / interface_widgets.c
1 /**
2 * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  * 
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include <limits.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_ID.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "BLI_arithb.h"
39 #include "BLI_listbase.h"
40 #include "BLI_rect.h"
41
42 #include "BKE_context.h"
43 #include "BKE_curve.h"
44 #include "BKE_global.h"
45 #include "BKE_utildefines.h"
46
47 #include "BIF_gl.h"
48 #include "BIF_glutil.h"
49
50 #include "BLF_api.h"
51
52 #include "UI_interface.h"
53 #include "UI_interface_icons.h"
54 #include "UI_resources.h"
55 #include "UI_view2d.h"
56
57 #include "ED_util.h"
58 #include "ED_types.h"
59
60 #include "interface_intern.h"
61
62 /* ************** widget base functions ************** */
63 /*
64      - in: roundbox codes for corner types and radius
65      - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
66  
67      - draw black box with alpha 0 on exact button boundbox
68      - for ever AA step:
69         - draw the inner part for a round filled box, with color blend codes or texture coords
70         - draw outline in outline color
71         - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
72         - draw extra decorations
73      - draw background color box with alpha 1 on exact button boundbox
74  
75  */
76
77 /* fill this struct with polygon info to draw AA'ed */
78 /* it has outline, back, and two optional tria meshes */
79
80 typedef struct uiWidgetTrias {
81         int tot;
82         
83         float vec[32][2];
84         int (*index)[3];
85         
86 } uiWidgetTrias;
87
88 typedef struct uiWidgetBase {
89         
90         int totvert, halfwayvert;
91         float outer_v[64][2];
92         float inner_v[64][2];
93         float inner_uv[64][2];
94         
95         short inner, outline, emboss; /* set on/off */
96         short shadedir;
97         
98         uiWidgetTrias tria1;
99         uiWidgetTrias tria2;
100         
101 } uiWidgetBase;
102
103 /* uiWidgetType: for time being only for visual appearance,
104    later, a handling callback can be added too 
105 */
106 typedef struct uiWidgetType {
107         
108         /* pointer to theme color definition */
109         uiWidgetColors *wcol_theme;
110         uiWidgetStateColors *wcol_state;
111         
112         /* converted colors for state */
113         uiWidgetColors wcol;
114         
115         void (*state)(struct uiWidgetType *, int state);
116         void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
117         void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
118         void (*text)(uiFontStyle *, uiWidgetColors *, uiBut *, rcti *);
119         
120 } uiWidgetType;
121
122
123 /* *********************** draw data ************************** */
124
125 static float cornervec[9][2]= {{0.0, 0.0}, {0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, 
126 {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0}};
127
128 static float jit[8][2]= {{0.468813 , -0.481430}, {-0.155755 , -0.352820}, 
129 {0.219306 , -0.238501},  {-0.393286 , -0.110949}, {-0.024699 , 0.013908}, 
130 {0.343805 , 0.147431}, {-0.272855 , 0.269918}, {0.095909 , 0.388710}};
131
132 static float num_tria_vert[3][2]= { 
133 {-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}};
134
135 static int num_tria_face[1][3]= {
136 {0, 1, 2}};
137
138 static float scroll_circle_vert[16][2]= {
139 {0.382684, 0.923879}, {0.000001, 1.000000}, {-0.382683, 0.923880}, {-0.707107, 0.707107},
140 {-0.923879, 0.382684}, {-1.000000, 0.000000}, {-0.923880, -0.382684}, {-0.707107, -0.707107},
141 {-0.382683, -0.923880}, {0.000000, -1.000000}, {0.382684, -0.923880}, {0.707107, -0.707107},
142 {0.923880, -0.382684}, {1.000000, -0.000000}, {0.923880, 0.382683}, {0.707107, 0.707107}};
143
144 static int scroll_circle_face[14][3]= {
145 {0, 1, 2}, {2, 0, 3}, {3, 0, 15}, {3, 15, 4}, {4, 15, 14}, {4, 14, 5}, {5, 14, 13}, {5, 13, 6}, 
146 {6, 13, 12}, {6, 12, 7}, {7, 12, 11}, {7, 11, 8}, {8, 11, 10}, {8, 10, 9}};
147
148 static float menu_tria_vert[6][2]= {
149 {-0.41, 0.16}, {0.41, 0.16}, {0, 0.82}, 
150 {0, -0.82}, {-0.41, -0.16}, {0.41, -0.16}};
151
152 static int menu_tria_face[2][3]= {{2, 0, 1}, {3, 5, 4}};
153
154 static float check_tria_vert[6][2]= {
155 {-0.578579, 0.253369},  {-0.392773, 0.412794},  {-0.004241, -0.328551}, 
156 {-0.003001, 0.034320},  {1.055313, 0.864744},   {0.866408, 1.026895}};
157
158 static int check_tria_face[4][3]= {
159 {3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}};
160
161 /* ************************************************* */
162
163 void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
164 {
165         float color[4];
166         int j;
167         
168         glEnable(GL_BLEND);
169         glGetFloatv(GL_CURRENT_COLOR, color);
170         color[3]= 0.125;
171         glColor4fv(color);
172         
173         /* for each AA step */
174         for(j=0; j<8; j++) {
175                 glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
176
177                 glBegin(GL_POLYGON);
178                 glVertex2f(x1, y1);
179                 glVertex2f(x2, y2);
180                 glVertex2f(x3, y3);
181                 glEnd();
182                 
183                 glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
184         }
185
186         glDisable(GL_BLEND);
187         
188 }
189
190 static void widget_init(uiWidgetBase *wtb)
191 {
192         wtb->totvert= wtb->halfwayvert= 0;
193         wtb->tria1.tot= 0;
194         wtb->tria2.tot= 0;
195         
196         wtb->inner= 1;
197         wtb->outline= 1;
198         wtb->emboss= 1;
199         wtb->shadedir= 1;
200 }
201
202 /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
203 /* return tot */
204 static int round_box_shadow_edges(float (*vert)[2], rcti *rect, float rad, int roundboxalign, float step)
205 {
206         float vec[9][2];
207         float minx, miny, maxx, maxy;
208         int a, tot= 0;
209         
210         rad+= step;
211         
212         if(2.0f*rad > rect->ymax-rect->ymin)
213                 rad= 0.5f*(rect->ymax-rect->ymin);
214         
215         minx= rect->xmin-step;
216         miny= rect->ymin-step;
217         maxx= rect->xmax+step;
218         maxy= rect->ymax+step;
219         
220         /* mult */
221         for(a=0; a<9; a++) {
222                 vec[a][0]= rad*cornervec[a][0]; 
223                 vec[a][1]= rad*cornervec[a][1]; 
224         }
225         
226         /* start with left-top, anti clockwise */
227         if(roundboxalign & 1) {
228                 for(a=0; a<9; a++, tot++) {
229                         vert[tot][0]= minx+rad-vec[a][0];
230                         vert[tot][1]= maxy-vec[a][1];
231                 }
232         }
233         else {
234                 for(a=0; a<9; a++, tot++) {
235                         vert[tot][0]= minx;
236                         vert[tot][1]= maxy;
237                 }
238         }
239         
240         if(roundboxalign & 8) {
241                 for(a=0; a<9; a++, tot++) {
242                         vert[tot][0]= minx+vec[a][1];
243                         vert[tot][1]= miny+rad-vec[a][0];
244                 }
245         }
246         else {
247                 for(a=0; a<9; a++, tot++) {
248                         vert[tot][0]= minx;
249                         vert[tot][1]= miny;
250                 }
251         }
252         
253         if(roundboxalign & 4) {
254                 for(a=0; a<9; a++, tot++) {
255                         vert[tot][0]= maxx-rad+vec[a][0];
256                         vert[tot][1]= miny+vec[a][1];
257                 }
258         }
259         else {
260                 for(a=0; a<9; a++, tot++) {
261                         vert[tot][0]= maxx;
262                         vert[tot][1]= miny;
263                 }
264         }
265         
266         if(roundboxalign & 2) {
267                 for(a=0; a<9; a++, tot++) {
268                         vert[tot][0]= maxx-vec[a][1];
269                         vert[tot][1]= maxy-rad+vec[a][0];
270                 }
271         }
272         else {
273                 for(a=0; a<9; a++, tot++) {
274                         vert[tot][0]= maxx;
275                         vert[tot][1]= maxy;
276                 }
277         }
278         return tot;
279 }
280
281 /* this call has 1 extra arg to allow mask outline */
282 static void round_box__edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, float rad, float radi)
283 {
284         float vec[9][2], veci[9][2];
285         float minx= rect->xmin, miny= rect->ymin, maxx= rect->xmax, maxy= rect->ymax;
286         float minxi= minx + 1.0f; /* boundbox inner */
287         float maxxi= maxx - 1.0f;
288         float minyi= miny + 1.0f;
289         float maxyi= maxy - 1.0f;
290         float facxi= 1.0f/(maxxi-minxi); /* for uv */
291         float facyi= 1.0f/(maxyi-minyi);
292         int a, tot= 0, minsize;
293         
294         minsize= MIN2(rect->xmax-rect->xmin, rect->ymax-rect->ymin);
295         
296         if(2.0f*rad > minsize)
297                 rad= 0.5f*minsize;
298
299         if(2.0f*(radi+1.0f) > minsize)
300                 radi= 0.5f*minsize - 1.0f;
301         
302         /* mult */
303         for(a=0; a<9; a++) {
304                 veci[a][0]= radi*cornervec[a][0]; 
305                 veci[a][1]= radi*cornervec[a][1]; 
306                 vec[a][0]= rad*cornervec[a][0]; 
307                 vec[a][1]= rad*cornervec[a][1]; 
308         }
309         
310         /* corner left-bottom */
311         if(roundboxalign & 8) {
312                 
313                 for(a=0; a<9; a++, tot++) {
314                         wt->inner_v[tot][0]= minxi+veci[a][1];
315                         wt->inner_v[tot][1]= minyi+radi-veci[a][0];
316                         
317                         wt->outer_v[tot][0]= minx+vec[a][1];
318                         wt->outer_v[tot][1]= miny+rad-vec[a][0];
319                         
320                         wt->inner_uv[tot][0]= facxi*(wt->inner_v[tot][0] - minxi);
321                         wt->inner_uv[tot][1]= facyi*(wt->inner_v[tot][1] - minyi);
322                 }
323         }
324         else {
325                 wt->inner_v[tot][0]= minxi;
326                 wt->inner_v[tot][1]= minyi;
327                 
328                 wt->outer_v[tot][0]= minx;
329                 wt->outer_v[tot][1]= miny;
330
331                 wt->inner_uv[tot][0]= 0.0f;
332                 wt->inner_uv[tot][1]= 0.0f;
333                 
334                 tot++;
335         }
336         
337         /* corner right-bottom */
338         if(roundboxalign & 4) {
339                 
340                 for(a=0; a<9; a++, tot++) {
341                         wt->inner_v[tot][0]= maxxi-radi+veci[a][0];
342                         wt->inner_v[tot][1]= minyi+veci[a][1];
343                         
344                         wt->outer_v[tot][0]= maxx-rad+vec[a][0];
345                         wt->outer_v[tot][1]= miny+vec[a][1];
346                         
347                         wt->inner_uv[tot][0]= facxi*(wt->inner_v[tot][0] - minxi);
348                         wt->inner_uv[tot][1]= facyi*(wt->inner_v[tot][1] - minyi);
349                 }
350         }
351         else {
352                 wt->inner_v[tot][0]= maxxi;
353                 wt->inner_v[tot][1]= minyi;
354                 
355                 wt->outer_v[tot][0]= maxx;
356                 wt->outer_v[tot][1]= miny;
357
358                 wt->inner_uv[tot][0]= 1.0f;
359                 wt->inner_uv[tot][1]= 0.0f;
360                 
361                 tot++;
362         }
363         
364         wt->halfwayvert= tot;
365         
366         /* corner right-top */
367         if(roundboxalign & 2) {
368                 
369                 for(a=0; a<9; a++, tot++) {
370                         wt->inner_v[tot][0]= maxxi-veci[a][1];
371                         wt->inner_v[tot][1]= maxyi-radi+veci[a][0];
372                         
373                         wt->outer_v[tot][0]= maxx-vec[a][1];
374                         wt->outer_v[tot][1]= maxy-rad+vec[a][0];
375                         
376                         wt->inner_uv[tot][0]= facxi*(wt->inner_v[tot][0] - minxi);
377                         wt->inner_uv[tot][1]= facyi*(wt->inner_v[tot][1] - minyi);
378                 }
379         }
380         else {
381                 wt->inner_v[tot][0]= maxxi;
382                 wt->inner_v[tot][1]= maxyi;
383                 
384                 wt->outer_v[tot][0]= maxx;
385                 wt->outer_v[tot][1]= maxy;
386                 
387                 wt->inner_uv[tot][0]= 1.0f;
388                 wt->inner_uv[tot][1]= 1.0f;
389                 
390                 tot++;
391         }
392         
393         /* corner left-top */
394         if(roundboxalign & 1) {
395                 
396                 for(a=0; a<9; a++, tot++) {
397                         wt->inner_v[tot][0]= minxi+radi-veci[a][0];
398                         wt->inner_v[tot][1]= maxyi-veci[a][1];
399                         
400                         wt->outer_v[tot][0]= minx+rad-vec[a][0];
401                         wt->outer_v[tot][1]= maxy-vec[a][1];
402                         
403                         wt->inner_uv[tot][0]= facxi*(wt->inner_v[tot][0] - minxi);
404                         wt->inner_uv[tot][1]= facyi*(wt->inner_v[tot][1] - minyi);
405                 }
406                 
407         }
408         else {
409                 
410                 wt->inner_v[tot][0]= minxi;
411                 wt->inner_v[tot][1]= maxyi;
412                 
413                 wt->outer_v[tot][0]= minx;
414                 wt->outer_v[tot][1]= maxy;
415                 
416                 wt->inner_uv[tot][0]= 0.0f;
417                 wt->inner_uv[tot][1]= 1.0f;
418                 
419                 tot++;
420         }
421                 
422         wt->totvert= tot;
423 }
424
425 static void round_box_edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, float rad)
426 {
427         round_box__edges(wt, roundboxalign, rect, rad, rad-1.0f);
428 }
429
430
431 /* based on button rect, return scaled array of triangles */
432 static void widget_num_tria(uiWidgetTrias *tria, rcti *rect, float triasize, char where)
433 {
434         float centx, centy, sizex, sizey, minsize;
435         int a, i1=0, i2=1;
436         
437         minsize= MIN2(rect->xmax-rect->xmin, rect->ymax-rect->ymin);
438         
439         /* center position and size */
440         centx= (float)rect->xmin + 0.5f*minsize;
441         centy= (float)rect->ymin + 0.5f*minsize;
442         sizex= sizey= -0.5f*triasize*minsize;
443
444         if(where=='r') {
445                 centx= (float)rect->xmax - 0.5f*minsize;
446                 sizex= -sizex;
447         }       
448         else if(where=='t') {
449                 centy= (float)rect->ymax - 0.5f*minsize;
450                 sizey= -sizey;
451                 i2=0; i1= 1;
452         }       
453         else if(where=='b') {
454                 sizex= -sizex;
455                 i2=0; i1= 1;
456         }       
457         
458         for(a=0; a<3; a++) {
459                 tria->vec[a][0]= sizex*num_tria_vert[a][i1] + centx;
460                 tria->vec[a][1]= sizey*num_tria_vert[a][i2] + centy;
461         }
462         
463         tria->tot= 1;
464         tria->index= num_tria_face;
465 }
466
467 static void widget_scroll_circle(uiWidgetTrias *tria, rcti *rect, float triasize, char where)
468 {
469         float centx, centy, sizex, sizey, minsize;
470         int a, i1=0, i2=1;
471         
472         minsize= MIN2(rect->xmax-rect->xmin, rect->ymax-rect->ymin);
473         
474         /* center position and size */
475         centx= (float)rect->xmin + 0.5f*minsize;
476         centy= (float)rect->ymin + 0.5f*minsize;
477         sizex= sizey= -0.5f*triasize*minsize;
478
479         if(where=='r') {
480                 centx= (float)rect->xmax - 0.5f*minsize;
481                 sizex= -sizex;
482         }       
483         else if(where=='t') {
484                 centy= (float)rect->ymax - 0.5f*minsize;
485                 sizey= -sizey;
486                 i2=0; i1= 1;
487         }       
488         else if(where=='b') {
489                 sizex= -sizex;
490                 i2=0; i1= 1;
491         }       
492         
493         for(a=0; a<16; a++) {
494                 tria->vec[a][0]= sizex*scroll_circle_vert[a][i1] + centx;
495                 tria->vec[a][1]= sizey*scroll_circle_vert[a][i2] + centy;
496         }
497         
498         tria->tot= 14;
499         tria->index= scroll_circle_face;
500 }
501
502 static void widget_trias_draw(uiWidgetTrias *tria)
503 {
504         int a;
505         
506         glBegin(GL_TRIANGLES);
507         for(a=0; a<tria->tot; a++) {
508                 glVertex2fv(tria->vec[ tria->index[a][0] ]);
509                 glVertex2fv(tria->vec[ tria->index[a][1] ]);
510                 glVertex2fv(tria->vec[ tria->index[a][2] ]);
511         }
512         glEnd();
513         
514 }
515
516 static void widget_menu_trias(uiWidgetTrias *tria, rcti *rect)
517 {
518         float centx, centy, size, asp;
519         int a;
520                 
521         /* center position and size */
522         centx= rect->xmax - 0.5f*(rect->ymax-rect->ymin);
523         centy= rect->ymin + 0.5f*(rect->ymax-rect->ymin);
524         size= 0.4f*(rect->ymax-rect->ymin);
525         
526         /* XXX exception */
527         asp= ((float)rect->xmax-rect->xmin)/((float)rect->ymax-rect->ymin);
528         if(asp > 1.2f && asp < 2.6f)
529                 centx= rect->xmax - 0.3f*(rect->ymax-rect->ymin);
530         
531         for(a=0; a<6; a++) {
532                 tria->vec[a][0]= size*menu_tria_vert[a][0] + centx;
533                 tria->vec[a][1]= size*menu_tria_vert[a][1] + centy;
534         }
535
536         tria->tot= 2;
537         tria->index= menu_tria_face;
538 }
539
540 static void widget_check_trias(uiWidgetTrias *tria, rcti *rect)
541 {
542         float centx, centy, size;
543         int a;
544         
545         /* center position and size */
546         centx= rect->xmin + 0.5f*(rect->ymax-rect->ymin);
547         centy= rect->ymin + 0.5f*(rect->ymax-rect->ymin);
548         size= 0.5f*(rect->ymax-rect->ymin);
549         
550         for(a=0; a<6; a++) {
551                 tria->vec[a][0]= size*check_tria_vert[a][0] + centx;
552                 tria->vec[a][1]= size*check_tria_vert[a][1] + centy;
553         }
554         
555         tria->tot= 4;
556         tria->index= check_tria_face;
557 }
558
559
560 /* prepares shade colors */
561 static void shadecolors4(char *coltop, char *coldown, char *color, short shadetop, short shadedown)
562 {
563         
564         coltop[0]= CLAMPIS(color[0]+shadetop, 0, 255);
565         coltop[1]= CLAMPIS(color[1]+shadetop, 0, 255);
566         coltop[2]= CLAMPIS(color[2]+shadetop, 0, 255);
567         coltop[3]= color[3];
568
569         coldown[0]= CLAMPIS(color[0]+shadedown, 0, 255);
570         coldown[1]= CLAMPIS(color[1]+shadedown, 0, 255);
571         coldown[2]= CLAMPIS(color[2]+shadedown, 0, 255);
572         coldown[3]= color[3];   
573 }
574
575 static void round_box_shade_col4(char *col1, char *col2, float fac)
576 {
577         int faci, facm;
578         unsigned char col[4];
579         
580         faci= floor(255.1f*fac);
581         facm= 255-faci;
582         
583         col[0]= (faci*col1[0] + facm*col2[0])>>8;
584         col[1]= (faci*col1[1] + facm*col2[1])>>8;
585         col[2]= (faci*col1[2] + facm*col2[2])>>8;
586         col[3]= (faci*col1[3] + facm*col2[3])>>8;
587         
588         glColor4ubv(col);
589 }
590
591 static void widgetbase_outline(uiWidgetBase *wtb)
592 {
593         int a;
594         
595         /* outline */
596         glBegin(GL_QUAD_STRIP);
597         for(a=0; a<wtb->totvert; a++) {
598                 glVertex2fv(wtb->outer_v[a]);
599                 glVertex2fv(wtb->inner_v[a]);
600         }
601         glVertex2fv(wtb->outer_v[0]);
602         glVertex2fv(wtb->inner_v[0]);
603         glEnd();
604 }
605
606 static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
607 {
608         int j, a;
609         
610         glEnable(GL_BLEND);
611
612         /* backdrop non AA */
613         if(wtb->inner) {
614                 if(wcol->shaded==0) {
615                         
616                         /* filled center, solid */
617                         glColor4ubv((unsigned char*)wcol->inner);
618                         glBegin(GL_POLYGON);
619                         for(a=0; a<wtb->totvert; a++)
620                                 glVertex2fv(wtb->inner_v[a]);
621                         glEnd();
622
623                 }
624                 else {
625                         char col1[4], col2[4];
626                         
627                         shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
628                         
629                         glShadeModel(GL_SMOOTH);
630                         glBegin(GL_POLYGON);
631                         for(a=0; a<wtb->totvert; a++) {
632                                 round_box_shade_col4(col1, col2, wtb->inner_uv[a][wtb->shadedir]);
633                                 glVertex2fv(wtb->inner_v[a]);
634                         }
635                         glEnd();
636                         glShadeModel(GL_FLAT);
637                 }
638         }
639         
640         /* for each AA step */
641         if(wtb->outline) {
642                 for(j=0; j<8; j++) {
643                         glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
644                         
645                         /* outline */
646                         glColor4ub(wcol->outline[0], wcol->outline[1], wcol->outline[2], 32);
647                         glBegin(GL_QUAD_STRIP);
648                         for(a=0; a<wtb->totvert; a++) {
649                                 glVertex2fv(wtb->outer_v[a]);
650                                 glVertex2fv(wtb->inner_v[a]);
651                         }
652                         glVertex2fv(wtb->outer_v[0]);
653                         glVertex2fv(wtb->inner_v[0]);
654                         glEnd();
655                 
656                         /* emboss bottom shadow */
657                         if(wtb->emboss) {
658                                 glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
659                                 glBegin(GL_QUAD_STRIP);
660                                 for(a=0; a<wtb->halfwayvert; a++) {
661                                         glVertex2fv(wtb->outer_v[a]);
662                                         glVertex2f(wtb->outer_v[a][0], wtb->outer_v[a][1]-1.0f);
663                                 }
664                                 glEnd();
665                         }
666                         
667                         glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
668                 }
669         }
670         
671         /* decoration */
672         if(wtb->tria1.tot || wtb->tria2.tot) {
673                 /* for each AA step */
674                 for(j=0; j<8; j++) {
675                         glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
676
677                         if(wtb->tria1.tot) {
678                                 glColor4ub(wcol->item[0], wcol->item[1], wcol->item[2], 32);
679                                 widget_trias_draw(&wtb->tria1);
680                         }
681                         if(wtb->tria2.tot) {
682                                 glColor4ub(wcol->item[0], wcol->item[1], wcol->item[2], 32);
683                                 widget_trias_draw(&wtb->tria2);
684                         }
685                 
686                         glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
687                 }
688         }
689
690         glDisable(GL_BLEND);
691         
692 }
693
694 /* *********************** text/icon ************************************** */
695
696
697 /* icons have been standardized... and this call draws in untransformed coordinates */
698 #define ICON_HEIGHT             16.0f
699
700 static void widget_draw_icon(uiBut *but, BIFIconID icon, int blend, rcti *rect)
701 {
702         int xs=0, ys=0;
703         float aspect, height;
704         
705         /* this icon doesn't need draw... */
706         if(icon==ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU)==0) return;
707         
708         /* we need aspect from block, for menus... these buttons are scaled in uiPositionBlock() */
709         aspect= but->block->aspect;
710         if(aspect != but->aspect) {
711                 /* prevent scaling up icon in pupmenu */
712                 if (aspect < 1.0f) {                    
713                         height= ICON_HEIGHT;
714                         aspect = 1.0f;
715                         
716                 }
717                 else 
718                         height= ICON_HEIGHT/aspect;
719         }
720         else
721                 height= ICON_HEIGHT;
722         
723         /* calculate blend color */
724         if ELEM4(but->type, TOG, ROW, TOGN, LISTROW) {
725                 if(but->flag & UI_SELECT);
726                 else if(but->flag & UI_ACTIVE);
727                 else blend= -60;
728         }
729         
730         glEnable(GL_BLEND);
731         
732         if(icon && icon!=ICON_BLANK1) {
733                 if(but->flag & UI_ICON_LEFT) {
734                         if (but->type==BUT_TOGDUAL) {
735                                 if (but->drawstr[0]) {
736                                         xs= rect->xmin-1;
737                                 } else {
738                                         xs= (rect->xmin+rect->xmax- height)/2;
739                                 }
740                         }
741                         else if (but->block->flag & UI_BLOCK_LOOP) {
742                                 if(but->type==SEARCH_MENU)
743                                         xs= rect->xmin+4;
744                                 else
745                                         xs= rect->xmin+1;
746                         }
747                         else if ((but->type==ICONROW) || (but->type==ICONTEXTROW)) {
748                                 xs= rect->xmin+3;
749                         }
750                         else {
751                                 xs= rect->xmin+4;
752                         }
753                         ys= (rect->ymin+rect->ymax- height)/2;
754                 }
755                 else {
756                         xs= (rect->xmin+rect->xmax- height)/2;
757                         ys= (rect->ymin+rect->ymax- height)/2;
758                 }
759         
760                 UI_icon_draw_aspect_blended(xs, ys, icon, aspect, blend);
761         }
762         
763         if(but->flag & UI_ICON_SUBMENU) {
764                 xs= rect->xmax-17;
765                 ys= (rect->ymin+rect->ymax- height)/2;
766                 
767                 UI_icon_draw_aspect_blended(xs, ys, ICON_RIGHTARROW_THIN, aspect, blend);
768         }
769         
770         glDisable(GL_BLEND);
771 }
772
773 /* sets but->ofs to make sure text is correctly visible */
774 static void ui_text_leftclip(uiFontStyle *fstyle, uiBut *but, rcti *rect)
775 {
776         int border= (but->flag & UI_BUT_ALIGN_RIGHT)? 8: 10;
777         int okwidth= rect->xmax-rect->xmin - border;
778         
779         /* need to set this first */
780         uiStyleFontSet(fstyle);
781
782         but->strwidth= BLF_width(but->drawstr);
783         but->ofs= 0;
784         
785         while(but->strwidth > okwidth ) {
786                 
787                 but->ofs++;
788                 but->strwidth= BLF_width(but->drawstr+but->ofs);
789                 
790                 /* textbut exception */
791                 if(but->editstr && but->pos != -1) {
792                         int pos= but->pos+1;
793                         
794                         if(pos-1 < but->ofs) {
795                                 pos= but->ofs-pos+1;
796                                 but->ofs -= pos;
797                                 if(but->ofs<0) {
798                                         but->ofs= 0;
799                                         pos--;
800                                 }
801                                 but->drawstr[ strlen(but->drawstr)-pos ]= 0;
802                         }
803                 }
804                 
805                 if(but->strwidth < 10) break;
806         }
807 }
808
809 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
810 {
811 //      int transopts;
812         char *cpoin = NULL;
813         
814         uiStyleFontSet(fstyle);
815         
816         if(but->editstr || (but->flag & UI_TEXT_LEFT))
817                 fstyle->align= UI_STYLE_TEXT_LEFT;
818         else
819                 fstyle->align= UI_STYLE_TEXT_CENTER;                    
820                 
821         /* text button selection and cursor */
822         if(but->editstr && but->pos != -1) {
823                 short t=0, pos=0, ch;
824                 short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
825                 
826                 if ((but->selend - but->selsta) > 0) {
827                         /* text button selection */
828                         selsta_tmp = but->selsta;
829                         selend_tmp = but->selend;
830                         
831                         if(but->drawstr[0]!=0) {
832                                 ch= but->drawstr[selsta_tmp];
833                                 but->drawstr[selsta_tmp]= 0;
834                                 
835                                 selsta_draw = BLF_width(but->drawstr+but->ofs);
836                                 
837                                 but->drawstr[selsta_tmp]= ch;
838                                 
839                                 ch= but->drawstr[selend_tmp];
840                                 but->drawstr[selend_tmp]= 0;
841                                 
842                                 selwidth_draw = BLF_width(but->drawstr+but->ofs);
843                                 
844                                 but->drawstr[selend_tmp]= ch;
845
846                                 glColor3ubv((unsigned char*)wcol->item);
847                                 glRects(rect->xmin+selsta_draw, rect->ymin+2, rect->xmin+selwidth_draw, rect->ymax-2);
848                         }
849                 } else {
850                         /* text cursor */
851                         pos= but->pos;
852                         if(pos >= but->ofs) {
853                                 if(but->drawstr[0]!=0) {
854                                         ch= but->drawstr[pos];
855                                         but->drawstr[pos]= 0;
856                                         
857                                         t= BLF_width(but->drawstr+but->ofs);
858                                         
859                                         but->drawstr[pos]= ch;
860                                 }
861
862                                 glColor3ub(255,0,0);
863                                 glRects(rect->xmin+t, rect->ymin+2, rect->xmin+t+2, rect->ymax-2);
864                         }
865                 }
866         }
867         //      ui_rasterpos_safe(x, y, but->aspect);
868 //      if(but->type==IDPOIN) transopts= 0;     // no translation, of course!
869 //      else transopts= ui_translate_buttons();
870         
871         /* cut string in 2 parts - only for menu entries */
872         if((but->block->flag & UI_BLOCK_LOOP)) {
873                 if(ELEM5(but->type, SLI, NUM, TEX, NUMSLI, NUMABS)==0) {
874                         cpoin= strchr(but->drawstr, '|');
875                         if(cpoin) *cpoin= 0;            
876                 }
877         }
878         
879         glColor3ubv((unsigned char*)wcol->text);
880         uiStyleFontDraw(fstyle, rect, but->drawstr+but->ofs);
881
882         /* part text right aligned */
883         if(cpoin) {
884                 fstyle->align= UI_STYLE_TEXT_RIGHT;
885                 rect->xmax-=5;
886                 uiStyleFontDraw(fstyle, rect, cpoin+1);
887                 *cpoin= '|';
888         }
889 }
890
891 /* draws text and icons for buttons */
892 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
893 {
894         
895         if(but==NULL) return;
896         
897         /* cutting off from left part */
898         if ELEM5(but->type, NUM, NUMABS, NUMSLI, SLI, TEX) {    
899                 ui_text_leftclip(fstyle, but, rect);
900         }
901         else but->ofs= 0;
902         
903         /* check for button text label */
904         if (but->type == ICONTEXTROW) {
905                 widget_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0, rect);
906         }
907         else {
908                                 
909                 if(but->type==BUT_TOGDUAL) {
910                         int dualset= 0;
911                         if(but->pointype==SHO)
912                                 dualset= BTST( *(((short *)but->poin)+1), but->bitnr);
913                         else if(but->pointype==INT)
914                                 dualset= BTST( *(((int *)but->poin)+1), but->bitnr);
915                         
916                         widget_draw_icon(but, ICON_DOT, dualset?0:-100, rect);
917                 }
918                 
919                 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
920                 and offset the text label to accomodate it */
921                 
922                 if (but->flag & UI_HAS_ICON) {
923                         widget_draw_icon(but, but->icon+but->iconadd, 0, rect);
924                         
925                         rect->xmin += UI_icon_get_width(but->icon+but->iconadd);
926                         
927                         if(but->editstr || (but->flag & UI_TEXT_LEFT)) 
928                                 rect->xmin += 5;
929                 }
930                 else if((but->flag & UI_TEXT_LEFT)) 
931                         rect->xmin += 5;
932                 
933                 /* always draw text for textbutton cursor */
934                 widget_draw_text(fstyle, wcol, but, rect);
935
936         }
937 }
938
939
940
941 /* *********************** widget types ************************************* */
942
943
944 /*   uiWidgetStateColors
945  char inner_anim[4];
946  char inner_anim_sel[4];
947  char inner_key[4];
948  char inner_key_sel[4];
949  char inner_driven[4];
950  char inner_driven_sel[4];
951  float blend;
952  
953 */
954
955 static struct uiWidgetStateColors wcol_state= {
956         {115, 190, 76, 255},
957         {90, 166, 51, 255},
958         {240, 235, 100, 255},
959         {215, 211, 75, 255},
960         {180, 0, 255, 255},
961         {153, 0, 230, 255},
962         0.5f, 0.0f
963 };
964
965 /*  uiWidgetColors
966  float outline[3];
967  float inner[4];
968  float inner_sel[4];
969  float item[3];
970  float text[3];
971  float text_sel[3];
972
973  short shaded;
974  float shadetop, shadedown;
975 */      
976
977 static struct uiWidgetColors wcol_num= {
978         {25, 25, 25, 255},
979         {180, 180, 180, 255},
980         {153, 153, 153, 255},
981         {90, 90, 90, 255},
982         
983         {0, 0, 0, 255},
984         {255, 255, 255, 255},
985         
986         1,
987         -20, 0
988 };
989
990 static struct uiWidgetColors wcol_numslider= {
991         {25, 25, 25, 255},
992         {180, 180, 180, 255},
993         {153, 153, 153, 255},
994         {128, 128, 128, 255},
995         
996         {0, 0, 0, 255},
997         {255, 255, 255, 255},
998         
999         1,
1000         -20, 0
1001 };
1002
1003 static struct uiWidgetColors wcol_text= {
1004         {25, 25, 25, 255},
1005         {153, 153, 153, 255},
1006         {153, 153, 153, 255},
1007         {90, 90, 90, 255},
1008         
1009         {0, 0, 0, 255},
1010         {255, 255, 255, 255},
1011         
1012         1,
1013         0, 25
1014 };
1015
1016 static struct uiWidgetColors wcol_option= {
1017         {0, 0, 0, 255},
1018         {70, 70, 70, 255},
1019         {70, 70, 70, 255},
1020         {255, 255, 255, 255},
1021         
1022         {0, 0, 0, 255},
1023         {255, 255, 255, 255},
1024         
1025         1,
1026         15, -15
1027 };
1028
1029 /* button that shows popup */
1030 static struct uiWidgetColors wcol_menu= {
1031         {0, 0, 0, 255},
1032         {70, 70, 70, 255},
1033         {70, 70, 70, 255},
1034         {255, 255, 255, 255},
1035         
1036         {255, 255, 255, 255},
1037         {204, 204, 204, 255},
1038         
1039         1,
1040         15, -15
1041 };
1042
1043 /* button that starts pulldown */
1044 static struct uiWidgetColors wcol_pulldown= {
1045         {0, 0, 0, 255},
1046         {63, 63, 63, 255},
1047         {86, 128, 194, 255},
1048         {255, 255, 255, 255},
1049         
1050         {0, 0, 0, 255},
1051         {0, 0, 0, 255},
1052         
1053         0,
1054         25, -20
1055 };
1056
1057 /* button inside menu */
1058 static struct uiWidgetColors wcol_menu_item= {
1059         {0, 0, 0, 255},
1060         {0, 0, 0, 0},
1061         {86, 128, 194, 255},
1062         {255, 255, 255, 255},
1063         
1064         {255, 255, 255, 255},
1065         {0, 0, 0, 255},
1066         
1067         0,
1068         38, 0
1069 };
1070
1071 /* backdrop menu + title text color */
1072 static struct uiWidgetColors wcol_menu_back= {
1073         {0, 0, 0, 255},
1074         {25, 25, 25, 230},
1075         {45, 45, 45, 230},
1076         {100, 100, 100, 255},
1077         
1078         {160, 160, 160, 255},
1079         {255, 255, 255, 255},
1080         
1081         0,
1082         25, -20
1083 };
1084
1085
1086 static struct uiWidgetColors wcol_radio= {
1087         {0, 0, 0, 255},
1088         {70, 70, 70, 255},
1089         {86, 128, 194, 255},
1090         {255, 255, 255, 255},
1091         
1092         {255, 255, 255, 255},
1093         {0, 0, 0, 255},
1094         
1095         1,
1096         15, -15
1097 };
1098
1099 static struct uiWidgetColors wcol_regular= {
1100         {25, 25, 25, 255},
1101         {153, 153, 153, 255},
1102         {100, 100, 100, 255},
1103         {25, 25, 25, 255},
1104         
1105         {0, 0, 0, 255},
1106         {255, 255, 255, 255},
1107         
1108         0,
1109         0, 0
1110 };
1111
1112 static struct uiWidgetColors wcol_tool= {
1113         {25, 25, 25, 255},
1114         {153, 153, 153, 255},
1115         {100, 100, 100, 255},
1116         {25, 25, 25, 255},
1117         
1118         {0, 0, 0, 255},
1119         {255, 255, 255, 255},
1120         
1121         1,
1122         15, -15
1123 };
1124
1125 static struct uiWidgetColors wcol_box= {
1126         {25, 25, 25, 255},
1127         {128, 128, 128, 255},
1128         {100, 100, 100, 255},
1129         {25, 25, 25, 255},
1130         
1131         {0, 0, 0, 255},
1132         {255, 255, 255, 255},
1133         
1134         0,
1135         0, 0
1136 };
1137
1138 static struct uiWidgetColors wcol_toggle= {
1139         {25, 25, 25, 255},
1140         {153, 153, 153, 255},
1141         {100, 100, 100, 255},
1142         {25, 25, 25, 255},
1143         
1144         {0, 0, 0, 255},
1145         {255, 255, 255, 255},
1146         
1147         0,
1148         0, 0
1149 };
1150
1151 static struct uiWidgetColors wcol_scroll= {
1152         {50, 50, 50, 180},
1153         {80, 80, 80, 180},
1154         {100, 100, 100, 180},
1155         {128, 128, 128, 255},
1156         
1157         {0, 0, 0, 255},
1158         {255, 255, 255, 255},
1159         
1160         1,
1161         5, -5
1162 };
1163
1164 static struct uiWidgetColors wcol_list_item= {
1165         {0, 0, 0, 255},
1166         {0, 0, 0, 0},
1167         {86, 128, 194, 255},
1168         {0, 0, 0, 255},
1169         
1170         {0, 0, 0, 255},
1171         {0, 0, 0, 255},
1172         
1173         0,
1174         0, 0
1175 };
1176
1177 /* free wcol struct to play with */
1178 static struct uiWidgetColors wcol_tmp= {
1179         {0, 0, 0, 255},
1180         {128, 128, 128, 255},
1181         {100, 100, 100, 255},
1182         {25, 25, 25, 255},
1183         
1184         {0, 0, 0, 255},
1185         {255, 255, 255, 255},
1186         
1187         0,
1188         0, 0
1189 };
1190
1191
1192 /* called for theme init (new theme) and versions */
1193 void ui_widget_color_init(ThemeUI *tui)
1194 {
1195         tui->wcol_regular= wcol_regular;
1196         tui->wcol_tool= wcol_tool;
1197         tui->wcol_text= wcol_text;
1198         tui->wcol_radio= wcol_radio;
1199         tui->wcol_option= wcol_option;
1200         tui->wcol_toggle= wcol_toggle;
1201         tui->wcol_num= wcol_num;
1202         tui->wcol_numslider= wcol_numslider;
1203         tui->wcol_menu= wcol_menu;
1204         tui->wcol_pulldown= wcol_pulldown;
1205         tui->wcol_menu_back= wcol_menu_back;
1206         tui->wcol_menu_item= wcol_menu_item;
1207         tui->wcol_box= wcol_box;
1208         tui->wcol_scroll= wcol_scroll;
1209         tui->wcol_list_item= wcol_list_item;
1210
1211         tui->wcol_state= wcol_state;
1212 }
1213
1214 /* ************ button callbacks, state ***************** */
1215
1216 static void widget_state_blend(char *cp, char *cpstate, float fac)
1217 {
1218         if(fac != 0.0f) {
1219                 cp[0]= (int)((1.0f-fac)*cp[0] + fac*cpstate[0]);
1220                 cp[1]= (int)((1.0f-fac)*cp[1] + fac*cpstate[1]);
1221                 cp[2]= (int)((1.0f-fac)*cp[2] + fac*cpstate[2]);
1222         }
1223 }
1224
1225 /* copy colors from theme, and set changes in it based on state */
1226 static void widget_state(uiWidgetType *wt, int state)
1227 {
1228         uiWidgetStateColors *wcol_state= wt->wcol_state;
1229
1230         wt->wcol= *(wt->wcol_theme);
1231         
1232         if(state & UI_SELECT) {
1233                 QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel)
1234
1235                 if(state & UI_BUT_ANIMATED_KEY)
1236                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1237                 else if(state & UI_BUT_ANIMATED)
1238                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1239                 else if(state & UI_BUT_DRIVEN)
1240                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1241
1242                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1243                 
1244                 /* only flip shade if it's not "pushed in" already */
1245                 if(wt->wcol.shaded && wt->wcol.shadetop>wt->wcol.shadedown) {
1246                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1247                 }
1248         }
1249         else {
1250                 if(state & UI_BUT_ANIMATED_KEY)
1251                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1252                 else if(state & UI_BUT_ANIMATED)
1253                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1254                 else if(state & UI_BUT_DRIVEN)
1255                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1256
1257                 if(state & UI_ACTIVE) { /* mouse over? */
1258                         wt->wcol.inner[0]= wt->wcol.inner[0]>=240? 255 : wt->wcol.inner[0]+15;
1259                         wt->wcol.inner[1]= wt->wcol.inner[1]>=240? 255 : wt->wcol.inner[1]+15;
1260                         wt->wcol.inner[2]= wt->wcol.inner[2]>=240? 255 : wt->wcol.inner[2]+15;
1261                 }
1262         }
1263 }
1264
1265 /* labels use theme colors for text */
1266 static void widget_state_label(uiWidgetType *wt, int state)
1267 {
1268         /* call this for option button */
1269         widget_state(wt, state);
1270
1271         if(state & UI_SELECT)
1272                 UI_GetThemeColor4ubv(TH_TEXT_HI, wt->wcol.text);
1273         else
1274                 UI_GetThemeColor4ubv(TH_TEXT, wt->wcol.text);
1275         
1276 }
1277
1278 static void widget_state_nothing(uiWidgetType *wt, int state)
1279 {
1280         wt->wcol= *(wt->wcol_theme);
1281 }       
1282
1283 /* special case, button that calls pulldown */
1284 static void widget_state_pulldown(uiWidgetType *wt, int state)
1285 {
1286         wt->wcol= *(wt->wcol_theme);
1287         
1288         QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1289         VECCOPY(wt->wcol.outline, wt->wcol.inner);
1290
1291         if(state & UI_ACTIVE)
1292                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1293 }
1294
1295 /* special case, menu items */
1296 static void widget_state_menu_item(uiWidgetType *wt, int state)
1297 {
1298         wt->wcol= *(wt->wcol_theme);
1299         
1300         if(state & (UI_BUT_DISABLED|UI_BUT_INACTIVE)) {
1301                 wt->wcol.text[0]= 0.5f*(wt->wcol.text[0]+wt->wcol.text_sel[0]);
1302                 wt->wcol.text[1]= 0.5f*(wt->wcol.text[1]+wt->wcol.text_sel[1]);
1303                 wt->wcol.text[2]= 0.5f*(wt->wcol.text[2]+wt->wcol.text_sel[2]);
1304         }
1305         else if(state & UI_ACTIVE) {
1306                 QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1307                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1308                 
1309                 wt->wcol.shaded= 1;
1310         }
1311 }
1312
1313
1314 /* ************ menu backdrop ************************* */
1315
1316 /* outside of rect, rad to left/bottom/right */
1317 static void widget_softshadow(rcti *rect, int roundboxalign, float radin, float radout)
1318 {
1319         uiWidgetBase wtb;
1320         rcti rect1= *rect;
1321         float alpha, alphastep;
1322         int step, tot, a;
1323         
1324         /* prevent tooltips to not show round shadow */
1325         if( 2.0f*radout > 0.2f*(rect1.ymax-rect1.ymin) )
1326                 rect1.ymax -= 0.2f*(rect1.ymax-rect1.ymin);
1327         else
1328                 rect1.ymax -= 2.0f*radout;
1329         
1330         /* inner part */
1331         tot= round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & 12, 0.0f);
1332         
1333         /* inverse linear shadow alpha */
1334         alpha= 0.15;
1335         alphastep= 0.67;
1336         
1337         for(step= 1; step<=radout; step++, alpha*=alphastep) {
1338                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, 15, (float)step);
1339                 
1340                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
1341                 
1342                 glBegin(GL_QUAD_STRIP);
1343                 for(a=0; a<tot; a++) {
1344                         glVertex2fv(wtb.outer_v[a]);
1345                         glVertex2fv(wtb.inner_v[a]);
1346                 }
1347                 glEnd();
1348         }
1349         
1350 }
1351
1352 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1353 {
1354         uiWidgetBase wtb;
1355         int roundboxalign= 15;
1356         
1357         widget_init(&wtb);
1358         
1359         /* menu is 2nd level or deeper */
1360         if (flag & UI_BLOCK_POPUP) {
1361                 //rect->ymin -= 4.0;
1362                 //rect->ymax += 4.0;
1363         }
1364         else if (direction == UI_DOWN) {
1365                 roundboxalign= 12;
1366                 rect->ymin -= 4.0;
1367         } 
1368         else if (direction == UI_TOP) {
1369                 roundboxalign= 3;
1370                 rect->ymax += 4.0;
1371         }
1372         
1373         glEnable(GL_BLEND);
1374         widget_softshadow(rect, roundboxalign, 5.0f, 8.0f);
1375         
1376         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
1377         wtb.emboss= 0;
1378         widgetbase_draw(&wtb, wcol);
1379         
1380         glDisable(GL_BLEND);
1381 }
1382
1383
1384 static void ui_hsv_cursor(float x, float y)
1385 {
1386         
1387         glPushMatrix();
1388         glTranslatef(x, y, 0.0f);
1389         
1390         glColor3f(1.0f, 1.0f, 1.0f);
1391         glutil_draw_filled_arc(0.0f, M_PI*2.0, 3.0f, 8);
1392         
1393         glEnable(GL_BLEND);
1394         glEnable(GL_LINE_SMOOTH );
1395         glColor3f(0.0f, 0.0f, 0.0f);
1396         glutil_draw_lined_arc(0.0f, M_PI*2.0, 3.0f, 12);
1397         glDisable(GL_BLEND);
1398         glDisable(GL_LINE_SMOOTH );
1399         
1400         glPopMatrix();
1401         
1402 }
1403
1404 void ui_hsvcircle_vals_from_pos(float *valrad, float *valdist, rcti *rect, float mx, float my)
1405 {
1406         /* duplication of code... well, simple is better now */
1407         float centx= (float)(rect->xmin + rect->xmax)/2;
1408         float centy= (float)(rect->ymin + rect->ymax)/2;
1409         float radius, dist;
1410         
1411         if( rect->xmax-rect->xmin > rect->ymax-rect->ymin )
1412                 radius= (float)(rect->ymax - rect->ymin)/2; 
1413         else
1414                 radius= (float)(rect->xmax - rect->xmin)/2; 
1415
1416         mx-= centx;
1417         my-= centy;
1418         dist= sqrt( mx*mx + my*my);
1419         if(dist < radius)
1420                 *valdist= dist/radius;
1421         else
1422                 *valdist= 1.0f;
1423         
1424         *valrad= atan2(mx, my)/(2.0f*M_PI) + 0.5f;
1425 }
1426
1427 void ui_draw_but_HSVCIRCLE(uiBut *but, rcti *rect)
1428 {
1429         /* gouraud triangle fan */
1430         float radstep, ang= 0.0f;
1431         float centx, centy, radius;
1432         float hsv[3], col[3], colcent[3];
1433         int a, tot= 32;
1434         
1435         radstep= 2.0f*M_PI/(float)tot;
1436         centx= (float)(rect->xmin + rect->xmax)/2;
1437         centy= (float)(rect->ymin + rect->ymax)/2;
1438         
1439         if( rect->xmax-rect->xmin > rect->ymax-rect->ymin )
1440                 radius= (float)(rect->ymax - rect->ymin)/2; 
1441         else
1442                 radius= (float)(rect->xmax - rect->xmin)/2; 
1443         
1444         /* color */
1445         VECCOPY(hsv, but->hsv);
1446         hsv[0]= hsv[1]= 0.0f;
1447         hsv_to_rgb(hsv[0], hsv[1], hsv[2], colcent, colcent+1, colcent+2);
1448         
1449         glShadeModel(GL_SMOOTH);
1450
1451         glBegin(GL_TRIANGLE_FAN);
1452         glColor3fv(colcent);
1453         glVertex2f( centx, centy);
1454         
1455         for(a=0; a<=tot; a++, ang+=radstep) {
1456                 float si= sin(ang);
1457                 float co= cos(ang);
1458                 
1459                 ui_hsvcircle_vals_from_pos(hsv, hsv+1, rect, centx + co*radius, centy + si*radius);
1460                 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
1461                 glColor3fv(col);
1462                 glVertex2f( centx + co*radius, centy + si*radius);
1463         }
1464         glEnd();
1465         
1466         glShadeModel(GL_FLAT);
1467         
1468         /* fully rounded outline */
1469         glPushMatrix();
1470         glTranslatef(centx, centy, 0.0f);
1471         glEnable(GL_BLEND);
1472         glEnable(GL_LINE_SMOOTH );
1473         glColor3f(0.0f, 0.0f, 0.0f);
1474         glutil_draw_lined_arc(0.0f, M_PI*2.0, radius, tot);
1475         glDisable(GL_BLEND);
1476         glDisable(GL_LINE_SMOOTH );
1477         glPopMatrix();
1478
1479         /* cursor */
1480         ang= 2.0f*M_PI*but->hsv[0] + 0.5f*M_PI;
1481         radius= but->hsv[1]*radius;
1482         ui_hsv_cursor(centx + cos(-ang)*radius, centy + sin(-ang)*radius);
1483         
1484 }
1485
1486 /* ************ custom buttons, old stuff ************** */
1487
1488 /* draws in resolution of 20x4 colors */
1489 static void ui_draw_but_HSVCUBE(uiBut *but, rcti *rect)
1490 {
1491         int a;
1492         float h,s,v;
1493         float dx, dy, sx1, sx2, sy, x=0.0f, y=0.0f;
1494         float col0[4][3];       // left half, rect bottom to top
1495         float col1[4][3];       // right half, rect bottom to top
1496         
1497         h= but->hsv[0];
1498         s= but->hsv[1];
1499         v= but->hsv[2];
1500         
1501         /* draw series of gouraud rects */
1502         glShadeModel(GL_SMOOTH);
1503         
1504         if(but->a1==0) {        // H and V vary
1505                 hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1506                 hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1507                 hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1508                 hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1509                 x= h; y= v;
1510         }
1511         else if(but->a1==1) {   // H and S vary
1512                 hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1513                 hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1514                 hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1515                 hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1516                 x= h; y= s;
1517         }
1518         else if(but->a1==2) {   // S and V vary
1519                 hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1520                 hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
1521                 hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
1522                 hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1523                 x= v; y= s;
1524         }
1525         else if(but->a1==3) {           // only hue slider
1526                 hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1527                 VECCOPY(col1[1], col1[0]);
1528                 VECCOPY(col1[2], col1[0]);
1529                 VECCOPY(col1[3], col1[0]);
1530                 x= h; y= 0.5;
1531         }
1532         
1533         for(dx=0.0; dx<1.0; dx+= 0.05) {
1534                 // previous color
1535                 VECCOPY(col0[0], col1[0]);
1536                 VECCOPY(col0[1], col1[1]);
1537                 VECCOPY(col0[2], col1[2]);
1538                 VECCOPY(col0[3], col1[3]);
1539                 
1540                 // new color
1541                 if(but->a1==0) {        // H and V vary
1542                         hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1543                         hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1544                         hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1545                         hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1546                 }
1547                 else if(but->a1==1) {   // H and S vary
1548                         hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1549                         hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1550                         hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1551                         hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1552                 }
1553                 else if(but->a1==2) {   // S and V vary
1554                         hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
1555                         hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
1556                         hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
1557                         hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
1558                 }
1559                 else if(but->a1==3) {   // only H
1560                         hsv_to_rgb(dx, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1561                         VECCOPY(col1[1], col1[0]);
1562                         VECCOPY(col1[2], col1[0]);
1563                         VECCOPY(col1[3], col1[0]);
1564                 }
1565                 
1566                 // rect
1567                 sx1= rect->xmin + dx*(rect->xmax-rect->xmin);
1568                 sx2= rect->xmin + (dx+0.05)*(rect->xmax-rect->xmin);
1569                 sy= rect->ymin;
1570                 dy= (rect->ymax-rect->ymin)/3.0;
1571                 
1572                 glBegin(GL_QUADS);
1573                 for(a=0; a<3; a++, sy+=dy) {
1574                         glColor3fv(col0[a]);
1575                         glVertex2f(sx1, sy);
1576                         
1577                         glColor3fv(col1[a]);
1578                         glVertex2f(sx2, sy);
1579                         
1580                         glColor3fv(col1[a+1]);
1581                         glVertex2f(sx2, sy+dy);
1582                         
1583                         glColor3fv(col0[a+1]);
1584                         glVertex2f(sx1, sy+dy);
1585                 }
1586                 glEnd();
1587         }
1588         
1589         glShadeModel(GL_FLAT);
1590         
1591         /* cursor */
1592         x= rect->xmin + x*(rect->xmax-rect->xmin);
1593         y= rect->ymin + y*(rect->ymax-rect->ymin);
1594         CLAMP(x, rect->xmin+3.0, rect->xmax-3.0);
1595         CLAMP(y, rect->ymin+3.0, rect->ymax-3.0);
1596         
1597         ui_hsv_cursor(x, y);
1598         
1599         /* outline */
1600         glColor3ub(0,  0,  0);
1601         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
1602 }
1603
1604 /* vertical 'value' slider, using new widget code */
1605 static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
1606 {
1607         uiWidgetBase wtb;
1608         float rad= 0.5f*(rect->xmax - rect->xmin);
1609         float x, y;
1610         
1611         widget_init(&wtb);
1612         
1613         /* fully rounded */
1614         round_box_edges(&wtb, 15, rect, rad);
1615         
1616         /* setup temp colors */
1617         wcol_tmp.outline[0]= wcol_tmp.outline[1]= wcol_tmp.outline[2]= 0;
1618         wcol_tmp.inner[0]= wcol_tmp.inner[1]= wcol_tmp.inner[2]= 128;
1619         wcol_tmp.shadetop= 127;
1620         wcol_tmp.shadedown= -128;
1621         wcol_tmp.shaded= 1;
1622         
1623         widgetbase_draw(&wtb, &wcol_tmp);
1624
1625         /* cursor */
1626         x= rect->xmin + 0.5f*(rect->xmax-rect->xmin);
1627         y= rect->ymin + but->hsv[2]*(rect->ymax-rect->ymin);
1628         CLAMP(y, rect->ymin+3.0, rect->ymax-3.0);
1629         
1630         ui_hsv_cursor(x, y);
1631         
1632 }
1633
1634 /* ************ button callbacks, draw ***************** */
1635
1636 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1637 {
1638         uiWidgetBase wtb;
1639         float rad= 0.5f*(rect->ymax - rect->ymin);
1640         int textoffs;
1641         
1642         widget_init(&wtb);
1643         
1644         /* fully rounded */
1645         round_box_edges(&wtb, roundboxalign, rect, rad);
1646         
1647         /* decoration */
1648         if(!(state & UI_TEXTINPUT)) {
1649                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
1650                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
1651         }       
1652         widgetbase_draw(&wtb, wcol);
1653         
1654         /* text space */
1655         if(!(state & UI_TEXTINPUT)) {
1656                 rect->xmin += (rect->ymax-rect->ymin);
1657                 rect->xmax -= (rect->ymax-rect->ymin);
1658         }
1659         else {
1660                 textoffs= rad;
1661                 rect->xmin += textoffs;
1662                 rect->xmax -= textoffs;
1663         }
1664 }
1665
1666
1667 static int ui_link_bezier_points(rcti *rect, float coord_array[][2], int resol)
1668 {
1669         float dist, vec[4][2];
1670
1671         vec[0][0]= rect->xmin;
1672         vec[0][1]= rect->ymin;
1673         vec[3][0]= rect->xmax;
1674         vec[3][1]= rect->ymax;
1675         
1676         dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
1677         
1678         vec[1][0]= vec[0][0]+dist;
1679         vec[1][1]= vec[0][1];
1680         
1681         vec[2][0]= vec[3][0]-dist;
1682         vec[2][1]= vec[3][1];
1683         
1684         forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float)*2);
1685         forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0]+1, resol, sizeof(float)*2);
1686         
1687         return 1;
1688 }
1689
1690 #define LINK_RESOL      24
1691 void ui_draw_link_bezier(rcti *rect)
1692 {
1693         float coord_array[LINK_RESOL+1][2];
1694         
1695         if(ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
1696                 float dist;
1697                 int i;
1698                 
1699                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
1700                 dist = 1.0f/(float)LINK_RESOL;
1701                 
1702                 glEnable(GL_BLEND);
1703                 glEnable(GL_LINE_SMOOTH);
1704                 
1705                 glBegin(GL_LINE_STRIP);
1706                 for(i=0; i<=LINK_RESOL; i++) {
1707                         glVertex2fv(coord_array[i]);
1708                 }
1709                 glEnd();
1710                 
1711                 glDisable(GL_BLEND);
1712                 glDisable(GL_LINE_SMOOTH);
1713
1714         }
1715 }
1716
1717 /* function in use for buttons and for view2d sliders */
1718 void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int state)
1719 {
1720         uiWidgetBase wtb;
1721         float rad;
1722         int horizontal;
1723
1724         widget_init(&wtb);
1725
1726         /* determine horizontal/vertical */
1727         horizontal= (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
1728         
1729         if(horizontal)
1730                 rad= 0.5f*(rect->ymax - rect->ymin);
1731         else
1732                 rad= 0.5f*(rect->xmax - rect->xmin);
1733         
1734         wtb.shadedir= (horizontal)? 1: 0;
1735         
1736         /* draw back part, colors swapped and shading inverted */
1737         if(horizontal)
1738                 SWAP(short, wcol->shadetop, wcol->shadedown);
1739         
1740         round_box_edges(&wtb, 15, rect, rad); 
1741         widgetbase_draw(&wtb, wcol);
1742         
1743         /* slider */
1744         if(slider->xmax-slider->xmin<2 || slider->ymax-slider->ymin<2);
1745         else {
1746                 
1747                 SWAP(short, wcol->shadetop, wcol->shadedown);
1748                 
1749                 QUATCOPY(wcol->inner, wcol->item);
1750                 
1751                 if(wcol->shadetop>wcol->shadedown)
1752                         wcol->shadetop+= 20;    /* XXX violates themes... */
1753                 else wcol->shadedown+= 20;
1754                 
1755                 if(state & UI_SCROLL_PRESSED) {
1756                         wcol->inner[0]= wcol->inner[0]>=250? 255 : wcol->inner[0]+5;
1757                         wcol->inner[1]= wcol->inner[1]>=250? 255 : wcol->inner[1]+5;
1758                         wcol->inner[2]= wcol->inner[2]>=250? 255 : wcol->inner[2]+5;
1759                 }
1760
1761                 /* draw */
1762                 wtb.emboss= 0; /* only emboss once */
1763                 
1764                 round_box_edges(&wtb, 15, slider, rad); 
1765                 
1766                 if(state & UI_SCROLL_ARROWS) {
1767                         if(wcol->item[0] > 48) wcol->item[0]-= 48;
1768                         if(wcol->item[1] > 48) wcol->item[1]-= 48;
1769                         if(wcol->item[2] > 48) wcol->item[2]-= 48;
1770                         wcol->item[3]= 255;
1771                         
1772                         if(horizontal) {
1773                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
1774                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
1775                         }
1776                         else {
1777                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
1778                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
1779                         }
1780                 }
1781                 widgetbase_draw(&wtb, wcol);
1782         }       
1783 }
1784
1785 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1786 {
1787         rcti rect1;
1788         double value;
1789         float fac, size, min;
1790         int horizontal;
1791
1792         /* calculate slider part */
1793         value= ui_get_but_val(but);
1794
1795         size= (but->softmax + but->a1 - but->softmin);
1796         size= MAX2(size, 2);
1797         
1798         /* position */
1799         rect1= *rect;
1800
1801         /* determine horizontal/vertical */
1802         horizontal= (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
1803         
1804         if(horizontal) {
1805                 fac= (rect->xmax - rect->xmin)/(size);
1806                 rect1.xmin= rect1.xmin + ceil(fac*(value - but->softmin));
1807                 rect1.xmax= rect1.xmin + ceil(fac*(but->a1 - but->softmin));
1808
1809                 /* ensure minimium size */
1810                 min= rect->ymax - rect->ymin;
1811
1812                 if(rect1.xmax - rect1.xmin < min) {
1813                         rect1.xmax= rect1.xmin + min;
1814
1815                         if(rect1.xmax > rect->xmax) {
1816                                 rect1.xmax= rect->xmax;
1817                                 rect1.xmin= MAX2(rect1.xmax - min, rect->xmin);
1818                         }
1819                 }
1820         }
1821         else {
1822                 fac= (rect->ymax - rect->ymin)/(size);
1823                 rect1.ymax= rect1.ymax - ceil(fac*(value - but->softmin));
1824                 rect1.ymin= rect1.ymax - ceil(fac*(but->a1 - but->softmin));
1825
1826                 /* ensure minimium size */
1827                 min= rect->xmax - rect->xmin;
1828
1829                 if(rect1.ymax - rect1.ymin < min) {
1830                         rect1.ymax= rect1.ymin + min;
1831
1832                         if(rect1.ymax > rect->ymax) {
1833                                 rect1.ymax= rect->ymax;
1834                                 rect1.ymin= MAX2(rect1.ymax - min, rect->ymin);
1835                         }
1836                 }
1837         }
1838
1839         if(state & UI_SELECT)
1840                 state= UI_SCROLL_PRESSED;
1841         else
1842                 state= 0;
1843         uiWidgetScrollDraw(wcol, rect, &rect1, state);
1844 }
1845
1846 static void widget_link(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1847 {
1848
1849         if(but->flag & UI_SELECT) {
1850                 rcti rectlink;
1851                 
1852                 UI_ThemeColor(TH_TEXT_HI);
1853                 
1854                 rectlink.xmin= (rect->xmin+rect->xmax)/2;
1855                 rectlink.ymin= (rect->ymin+rect->ymax)/2;
1856                 rectlink.xmax= but->linkto[0];
1857                 rectlink.ymax= but->linkto[1];
1858                 
1859                 ui_draw_link_bezier(&rectlink);
1860         }
1861 }
1862
1863
1864 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1865 {
1866         uiWidgetBase wtb, wtb1;
1867         rcti rect1;
1868         double value;
1869         float offs, fac;
1870         int textoffs;
1871         char outline[3];
1872         
1873         widget_init(&wtb);
1874         widget_init(&wtb1);
1875         
1876         /* backdrop first */
1877         
1878         /* fully rounded */
1879         offs= 0.5f*(rect->ymax - rect->ymin);
1880         textoffs= offs;
1881         round_box_edges(&wtb, roundboxalign, rect, offs);
1882
1883         wtb.outline= 0;
1884         widgetbase_draw(&wtb, wcol);
1885         
1886         /* slider part */
1887         VECCOPY(outline, wcol->outline);
1888         VECCOPY(wcol->outline, wcol->item);
1889         VECCOPY(wcol->inner, wcol->item);
1890         SWAP(short, wcol->shadetop, wcol->shadedown);
1891         
1892         rect1= *rect;
1893         
1894         value= ui_get_but_val(but);
1895         fac= (value-but->softmin)*(rect1.xmax - rect1.xmin - offs)/(but->softmax - but->softmin);
1896         
1897         /* left part of slider, always rounded */
1898         rect1.xmax= rect1.xmin + ceil(offs+1.0f);
1899         round_box_edges(&wtb1, roundboxalign & ~6, &rect1, offs);
1900         wtb1.outline= 0;
1901         widgetbase_draw(&wtb1, wcol);
1902         
1903         /* right part of slider, interpolate roundness */
1904         rect1.xmax= rect1.xmin + fac + offs;
1905         rect1.xmin+=  floor(offs-1.0f);
1906         if(rect1.xmax + offs > rect->xmax)
1907                 offs*= (rect1.xmax + offs - rect->xmax)/offs;
1908         else 
1909                 offs= 0.0f;
1910         round_box_edges(&wtb1, roundboxalign & ~9, &rect1, offs);
1911         
1912         widgetbase_draw(&wtb1, wcol);
1913         VECCOPY(wcol->outline, outline);
1914         SWAP(short, wcol->shadetop, wcol->shadedown);
1915         
1916         /* outline */
1917         wtb.outline= 1;
1918         wtb.inner= 0;
1919         widgetbase_draw(&wtb, wcol);
1920         
1921         /* text space */
1922         rect->xmin += textoffs;
1923         rect->xmax -= textoffs;
1924 }
1925
1926 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1927 {
1928         uiWidgetBase wtb;
1929         float col[4];
1930         
1931         widget_init(&wtb);
1932         
1933         /* half rounded */
1934         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
1935                 
1936         ui_get_but_vectorf(but, col);
1937         wcol->inner[0]= FTOCHAR(col[0]);
1938         wcol->inner[1]= FTOCHAR(col[1]);
1939         wcol->inner[2]= FTOCHAR(col[2]);
1940         
1941         widgetbase_draw(&wtb, wcol);
1942         
1943 }
1944
1945
1946 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1947 {
1948         uiWidgetBase wtb;
1949         
1950         widget_init(&wtb);
1951         
1952         /* half rounded */
1953         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1954         
1955         widgetbase_draw(&wtb, wcol);
1956
1957 }
1958
1959
1960 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1961 {
1962         uiWidgetBase wtb;
1963         
1964         widget_init(&wtb);
1965         
1966         /* half rounded */
1967         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1968         
1969         /* decoration */
1970         widget_menu_trias(&wtb.tria1, rect);
1971         
1972         widgetbase_draw(&wtb, wcol);
1973         
1974         /* text space */
1975         rect->xmax -= (rect->ymax-rect->ymin);
1976         
1977 }
1978
1979 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1980 {
1981         if(state & UI_ACTIVE) {
1982                 uiWidgetBase wtb;
1983                 float rad= 0.5f*(rect->ymax - rect->ymin); // 4.0f
1984                 
1985                 widget_init(&wtb);
1986                 
1987                 /* half rounded */
1988                 round_box_edges(&wtb, 15, rect, rad);
1989                 
1990                 widgetbase_draw(&wtb, wcol);
1991         }
1992 }
1993
1994 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1995 {
1996         uiWidgetBase wtb;
1997         
1998         widget_init(&wtb);
1999         
2000         /* not rounded, no outline */
2001         wtb.outline= 0;
2002         round_box_edges(&wtb, 0, rect, 0.0f);
2003         
2004         widgetbase_draw(&wtb, wcol);
2005 }
2006
2007 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2008 {
2009         uiWidgetBase wtb;
2010         
2011         widget_init(&wtb);
2012         
2013         /* rounded, but no outline */
2014         wtb.outline= 0;
2015         round_box_edges(&wtb, 15, rect, 4.0f);
2016         
2017         widgetbase_draw(&wtb, wcol);
2018 }
2019
2020 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2021 {
2022         uiWidgetBase wtb;
2023         rcti recttemp= *rect;
2024         int delta;
2025         
2026         widget_init(&wtb);
2027         
2028         /* square */
2029         recttemp.xmax= recttemp.xmin + (recttemp.ymax-recttemp.ymin);
2030         
2031         /* smaller */
2032         delta= 1 + (recttemp.ymax-recttemp.ymin)/8;
2033         recttemp.xmin+= delta;
2034         recttemp.ymin+= delta;
2035         recttemp.xmax-= delta;
2036         recttemp.ymax-= delta;
2037         
2038         /* half rounded */
2039         round_box_edges(&wtb, 15, &recttemp, 4.0f);
2040         
2041         /* decoration */
2042         if(state & UI_SELECT) {
2043                 widget_check_trias(&wtb.tria1, &recttemp);
2044         }
2045         
2046         widgetbase_draw(&wtb, wcol);
2047         
2048         /* text space */
2049         rect->xmin += (rect->ymax-rect->ymin)*0.7 + delta;
2050 }
2051
2052
2053 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2054 {
2055         uiWidgetBase wtb;
2056         
2057         widget_init(&wtb);
2058         
2059         /* half rounded */
2060         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2061         
2062         widgetbase_draw(&wtb, wcol);
2063
2064 }
2065
2066 static void widget_but(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2067 {
2068         uiWidgetBase wtb;
2069         
2070         widget_init(&wtb);
2071         
2072         /* half rounded */
2073         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2074                 
2075         widgetbase_draw(&wtb, wcol);
2076
2077 }
2078
2079 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2080 {
2081         uiWidgetBase wtb;
2082         float rad= 5.0f; //0.5f*(rect->ymax - rect->ymin);
2083         
2084         widget_init(&wtb);
2085         
2086         /* half rounded */
2087         round_box_edges(&wtb, roundboxalign, rect, rad);
2088
2089         widgetbase_draw(&wtb, wcol);
2090 }
2091
2092 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2093 {
2094         uiWidgetBase wtb;
2095         char col[4];
2096         
2097         /* state copy! */
2098         wt->wcol= *(wt->wcol_theme);
2099         
2100         widget_init(&wtb);
2101         
2102         if(but->block->drawextra) {
2103                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2104                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2105                 
2106                 /* make mask to draw over image */
2107                 UI_GetThemeColor3ubv(TH_BACK, col);
2108                 glColor3ubv((unsigned char*)col);
2109                 
2110                 round_box__edges(&wtb, 15, rect, 0.0f, 4.0);
2111                 widgetbase_outline(&wtb);
2112         }
2113         
2114         /* outline */
2115         round_box_edges(&wtb, 15, rect, 5.0f);
2116         wtb.outline= 1;
2117         wtb.inner= 0;
2118         widgetbase_draw(&wtb, &wt->wcol);
2119         
2120 }
2121
2122
2123 static void widget_disabled(rcti *rect)
2124 {
2125         float col[4];
2126         
2127         glEnable(GL_BLEND);
2128         
2129         /* can't use theme TH_BACK or TH_PANEL... undefined */
2130         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2131         glColor4f(col[0], col[1], col[2], 0.5f);
2132         /* need -1 and +1 to make it work right for aligned buttons,
2133          * but problem may be somewhere else? */
2134         glRectf(rect->xmin-1, rect->ymin, rect->xmax, rect->ymax+1);
2135
2136         glDisable(GL_BLEND);
2137 }
2138
2139 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2140 {
2141         bTheme *btheme= U.themes.first;
2142         static uiWidgetType wt;
2143         
2144         /* defaults */
2145         wt.wcol_theme= &btheme->tui.wcol_regular;
2146         wt.wcol_state= &btheme->tui.wcol_state;
2147         wt.state= widget_state;
2148         wt.draw= widget_but;
2149         wt.custom= NULL;
2150         wt.text= widget_draw_text_icon;
2151         
2152         switch(type) {
2153                 case UI_WTYPE_REGULAR:
2154                         break;
2155
2156                 case UI_WTYPE_LABEL:
2157                         wt.draw= NULL;
2158                         wt.state= widget_state_label;
2159                         break;
2160                         
2161                 case UI_WTYPE_TOGGLE:
2162                         wt.wcol_theme= &btheme->tui.wcol_toggle;
2163                         break;
2164                         
2165                 case UI_WTYPE_OPTION:
2166                         wt.wcol_theme= &btheme->tui.wcol_option;
2167                         wt.draw= widget_optionbut;
2168                         break;
2169                         
2170                 case UI_WTYPE_RADIO:
2171                         wt.wcol_theme= &btheme->tui.wcol_radio;
2172                         wt.draw= widget_radiobut;
2173                         break;
2174
2175                 case UI_WTYPE_NUMBER:
2176                         wt.wcol_theme= &btheme->tui.wcol_num;
2177                         wt.draw= widget_numbut;
2178                         break;
2179                         
2180                 case UI_WTYPE_SLIDER:
2181                         wt.wcol_theme= &btheme->tui.wcol_numslider;
2182                         wt.custom= widget_numslider;
2183                         break;
2184                         
2185                 case UI_WTYPE_EXEC:
2186                         wt.wcol_theme= &btheme->tui.wcol_tool;
2187                         wt.draw= widget_roundbut;
2188                         break;
2189                         
2190                         
2191                         /* strings */
2192                 case UI_WTYPE_NAME:
2193                         wt.wcol_theme= &btheme->tui.wcol_text;
2194                         wt.draw= widget_textbut;
2195                         break;
2196                         
2197                 case UI_WTYPE_NAME_LINK:
2198                         break;
2199                         
2200                 case UI_WTYPE_POINTER_LINK:
2201                         break;
2202                         
2203                 case UI_WTYPE_FILENAME:
2204                         break;
2205                         
2206                         
2207                         /* start menus */
2208                 case UI_WTYPE_MENU_RADIO:
2209                         wt.wcol_theme= &btheme->tui.wcol_menu;
2210                         wt.draw= widget_menubut;
2211                         break;
2212                         
2213                 case UI_WTYPE_MENU_POINTER_LINK:
2214                         wt.wcol_theme= &btheme->tui.wcol_menu;
2215                         wt.draw= widget_menubut;
2216                         break;
2217                         
2218                         
2219                 case UI_WTYPE_PULLDOWN:
2220                         wt.wcol_theme= &btheme->tui.wcol_pulldown;
2221                         wt.draw= widget_pulldownbut;
2222                         wt.state= widget_state_pulldown;
2223                         break;
2224                         
2225                         /* in menus */
2226                 case UI_WTYPE_MENU_ITEM:
2227                         wt.wcol_theme= &btheme->tui.wcol_menu_item;
2228                         wt.draw= widget_menu_itembut;
2229                         wt.state= widget_state_menu_item;
2230                         break;
2231                         
2232                 case UI_WTYPE_MENU_BACK:
2233                         wt.wcol_theme= &btheme->tui.wcol_menu_back;
2234                         wt.draw= widget_menu_back;
2235                         break;
2236                         
2237                         /* specials */
2238                 case UI_WTYPE_ICON:
2239                         wt.draw= NULL;
2240                         break;
2241                         
2242                 case UI_WTYPE_SWATCH:
2243                         wt.custom= widget_swatch;
2244                         break;
2245                         
2246                 case UI_WTYPE_BOX:
2247                         wt.wcol_theme= &btheme->tui.wcol_box;
2248                         break;
2249                         
2250                 case UI_WTYPE_RGB_PICKER:
2251                         break;
2252                         
2253                 case UI_WTYPE_NORMAL:
2254                         break;
2255
2256                 case UI_WTYPE_SCROLL:
2257                         wt.wcol_theme= &btheme->tui.wcol_scroll;
2258                         wt.state= widget_state_nothing;
2259                         wt.custom= widget_scroll;
2260                         break;
2261
2262                 case UI_WTYPE_LISTITEM:
2263                         wt.wcol_theme= &btheme->tui.wcol_list_item;
2264                         wt.draw= widget_list_itembut;
2265                         break;
2266         }
2267         
2268         return &wt;
2269 }
2270
2271
2272 static int widget_roundbox_set(uiBut *but, rcti *rect)
2273 {
2274         /* alignment */
2275         if(but->flag & UI_BUT_ALIGN) {
2276                 
2277                 if(but->flag & UI_BUT_ALIGN_TOP)
2278                         rect->ymax+= 1;
2279                 if(but->flag & UI_BUT_ALIGN_LEFT)
2280                         rect->xmin-= 1;
2281                 
2282                 switch(but->flag & UI_BUT_ALIGN) {
2283                         case UI_BUT_ALIGN_TOP:
2284                                 return (12);
2285                                 break;
2286                         case UI_BUT_ALIGN_DOWN:
2287                                 return (3);
2288                                 break;
2289                         case UI_BUT_ALIGN_LEFT:
2290                                 return (6);
2291                                 break;
2292                         case UI_BUT_ALIGN_RIGHT:
2293                                 return (9);
2294                                 break;
2295                                 
2296                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
2297                                 return (1);
2298                                 break;
2299                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
2300                                 return (2);
2301                                 break;
2302                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
2303                                 return (8);
2304                                 break;
2305                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
2306                                 return (4);
2307                                 break;
2308                                 
2309                         default:
2310                                 return (0);
2311                                 break;
2312                 }
2313         } 
2314         return 15;
2315 }
2316
2317 /* conversion from old to new buttons, so still messy */
2318 void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
2319 {
2320         bTheme *btheme= U.themes.first;
2321         ThemeUI *tui= &btheme->tui;
2322         uiFontStyle *fstyle= &style->widget;
2323         uiWidgetType *wt= NULL;
2324         
2325         /* handle menus seperately */
2326         if(but->dt==UI_EMBOSSP) {
2327                 switch (but->type) {
2328                         case LABEL:
2329                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
2330                                 break;
2331                         case SEPR:
2332                                 break;
2333                                 
2334                         default:
2335                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
2336                 }
2337         }
2338         else if(but->dt==UI_EMBOSSN) {
2339                 /* "nothing" */
2340                 wt= widget_type(UI_WTYPE_ICON);
2341         }
2342         else {
2343                 
2344                 switch (but->type) {
2345                         case LABEL:
2346                                 if(but->block->flag & UI_BLOCK_LOOP)
2347                                         widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
2348                                 else {
2349                                         wt= widget_type(UI_WTYPE_LABEL);
2350                                         fstyle= &style->widgetlabel;
2351                                 }
2352                                 break;
2353                                 
2354                         case SEPR:
2355                                 break;
2356                                 
2357                         case BUT:
2358                                 wt= widget_type(UI_WTYPE_EXEC);
2359                                 break;
2360
2361                         case NUM:
2362                                 wt= widget_type(UI_WTYPE_NUMBER);
2363                                 break;
2364                                 
2365                         case NUMSLI:
2366                         case HSVSLI:
2367                                 wt= widget_type(UI_WTYPE_SLIDER);
2368                                 break;
2369                                 
2370                         case ROW:
2371                                 wt= widget_type(UI_WTYPE_RADIO);
2372                                 break;
2373
2374                         case LISTROW:
2375                                 wt= widget_type(UI_WTYPE_LISTITEM);
2376                                 break;
2377                                 
2378                         case TEX:
2379                                 wt= widget_type(UI_WTYPE_NAME);
2380                                 break;
2381                                 
2382                         case SEARCH_MENU:
2383                                 wt= widget_type(UI_WTYPE_NAME);
2384                                 if(but->block->flag & UI_BLOCK_LOOP)
2385                                         wt->wcol_theme= &btheme->tui.wcol_menu_back;
2386                                 break;
2387                                 
2388                         case TOGBUT:
2389                         case TOG:
2390                         case TOGN:
2391                         case TOG3:
2392                                 wt= widget_type(UI_WTYPE_TOGGLE);
2393                                 break;
2394                                 
2395                         case OPTION:
2396                         case OPTIONN:
2397                                 if (!(but->flag & UI_HAS_ICON)) {
2398                                         wt= widget_type(UI_WTYPE_OPTION);
2399                                         but->flag |= UI_TEXT_LEFT;
2400                                 }
2401                                 else
2402                                         wt= widget_type(UI_WTYPE_TOGGLE);
2403                                 break;
2404                                 
2405                         case MENU:
2406                         case BLOCK:
2407                         case ICONTEXTROW:
2408                                 wt= widget_type(UI_WTYPE_MENU_RADIO);
2409                                 break;
2410                                 
2411                         case PULLDOWN:
2412                                 wt= widget_type(UI_WTYPE_PULLDOWN);
2413                                 break;
2414                         
2415                         case BUTM:
2416                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
2417                                 break;
2418                                 
2419                         case COL:
2420                                 wt= widget_type(UI_WTYPE_SWATCH);
2421                                 break;
2422                                 
2423                         case ROUNDBOX:
2424                         case LISTBOX:
2425                                 wt= widget_type(UI_WTYPE_BOX);
2426                                 break;
2427                                 
2428                         case LINK:
2429                         case INLINK:
2430                                 wt= widget_type(UI_WTYPE_ICON);
2431                                 wt->custom= widget_link;
2432                                 
2433                                 break;
2434                         
2435                         case BUT_EXTRA:
2436                                 widget_draw_extra_mask(C, but, widget_type(UI_WTYPE_BOX), rect);
2437                                 break;
2438                                 
2439                         case HSVCUBE:
2440                                 if(but->a1==4) // vertical V slider, uses new widget draw now
2441                                         ui_draw_but_HSV_v(but, rect);
2442                                 else  // other HSV pickers...
2443                                         ui_draw_but_HSVCUBE(but, rect);
2444                                 break;
2445                                 
2446                         case HSVCIRCLE:
2447                                 ui_draw_but_HSVCIRCLE(but, rect);
2448                                 break;
2449                                 
2450                         case BUT_COLORBAND:
2451                                 ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
2452                                 break;
2453                                 
2454                         case BUT_NORMAL:
2455                                 ui_draw_but_NORMAL(but, &tui->wcol_regular, rect);
2456                                 break;
2457                                 
2458                         case BUT_CURVE:
2459                                 ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
2460                                 break;
2461
2462                         case SCROLL:
2463                                 wt= widget_type(UI_WTYPE_SCROLL);
2464                                 break;
2465
2466                         default:
2467                                 wt= widget_type(UI_WTYPE_REGULAR);
2468                 }
2469         }
2470         
2471         if(wt) {
2472                 rcti disablerect= *rect; /* rect gets clipped smaller for text */
2473                 int roundboxalign, state;
2474                 
2475                 roundboxalign= widget_roundbox_set(but, rect);
2476
2477                 state= but->flag;
2478                 if(but->editstr) state |= UI_TEXTINPUT;
2479                 
2480                 wt->state(wt, state);
2481                 if(wt->custom)
2482                         wt->custom(but, &wt->wcol, rect, state, roundboxalign);
2483                 else if(wt->draw)
2484                         wt->draw(&wt->wcol, rect, state, roundboxalign);
2485                 wt->text(fstyle, &wt->wcol, but, rect);
2486                 
2487                 if(state & (UI_BUT_DISABLED|UI_BUT_INACTIVE))
2488                         if(but->dt!=UI_EMBOSSP)
2489                                 widget_disabled(&disablerect);
2490         }
2491 }
2492
2493 void ui_draw_menu_back(uiStyle *style, uiBlock *block, rcti *rect)
2494 {
2495         uiWidgetType *wt= widget_type(UI_WTYPE_MENU_BACK);
2496         
2497         wt->state(wt, 0);
2498         if(block)
2499                 wt->draw(&wt->wcol, rect, block->flag, block->direction);
2500         else
2501                 wt->draw(&wt->wcol, rect, 0, 0);
2502         
2503 }
2504
2505 void ui_draw_search_back(uiStyle *style, uiBlock *block, rcti *rect)
2506 {
2507         uiWidgetType *wt= widget_type(UI_WTYPE_BOX);
2508         
2509         glEnable(GL_BLEND);
2510         widget_softshadow(rect, 15, 5.0f, 8.0f);
2511         glDisable(GL_BLEND);
2512
2513         wt->state(wt, 0);
2514         if(block)
2515                 wt->draw(&wt->wcol, rect, block->flag, 15);
2516         else
2517                 wt->draw(&wt->wcol, rect, 0, 15);
2518         
2519 }
2520
2521
2522 /* helper call to draw a menu item without button */
2523 /* state: UI_ACTIVE or 0 */
2524 void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state)
2525 {
2526         uiWidgetType *wt= widget_type(UI_WTYPE_MENU_ITEM);
2527         rcti _rect= *rect;
2528         char *cpoin;
2529         
2530         wt->state(wt, state);
2531         wt->draw(&wt->wcol, rect, 0, 0);
2532         
2533         uiStyleFontSet(fstyle);
2534         fstyle->align= UI_STYLE_TEXT_LEFT;
2535         
2536         /* text location offset */
2537         rect->xmin+=5;
2538         if(iconid) rect->xmin+= ICON_HEIGHT;
2539
2540         /* cut string in 2 parts? */
2541         cpoin= strchr(name, '|');
2542         if(cpoin) {
2543                 *cpoin= 0;
2544                 rect->xmax -= BLF_width(cpoin+1) + 10;
2545         }
2546         
2547         glColor3ubv((unsigned char*)wt->wcol.text);
2548         uiStyleFontDraw(fstyle, rect, name);
2549         
2550         /* part text right aligned */
2551         if(cpoin) {
2552                 fstyle->align= UI_STYLE_TEXT_RIGHT;
2553                 rect->xmax= _rect.xmax - 5;
2554                 uiStyleFontDraw(fstyle, rect, cpoin+1);
2555                 *cpoin= '|';
2556         }
2557         
2558         /* restore rect, was messed with */
2559         *rect= _rect;
2560
2561         if(iconid) {
2562                 int xs= rect->xmin+4;
2563                 int ys= 1 + (rect->ymin+rect->ymax- ICON_HEIGHT)/2;
2564                 glEnable(GL_BLEND);
2565                 UI_icon_draw_aspect_blended(xs, ys, iconid, 1.2f, 0); /* XXX scale weak get from fstyle? */
2566                 glDisable(GL_BLEND);
2567         }
2568 }
2569