2.5
[blender.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_global.h"
44 #include "BKE_utildefines.h"
45
46 #include "BIF_gl.h"
47 #include "BIF_glutil.h"
48
49 #include "BLF_api.h"
50
51 #include "UI_interface.h"
52 #include "UI_interface_icons.h"
53 #include "UI_resources.h"
54 #include "UI_view2d.h"
55
56 #include "ED_util.h"
57 #include "ED_types.h"
58
59 #include "interface_intern.h"
60
61 /* ************** widget base functions ************** */
62 /*
63      - in: roundbox codes for corner types and radius
64      - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
65  
66      - draw black box with alpha 0 on exact button boundbox
67      - for ever AA step:
68         - draw the inner part for a round filled box, with color blend codes or texture coords
69         - draw outline in outline color
70         - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
71         - draw extra decorations
72      - draw background color box with alpha 1 on exact button boundbox
73  
74  */
75
76 /* fill this struct with polygon info to draw AA'ed */
77 /* it has outline, back, and two optional tria meshes */
78
79 typedef struct uiWidgetTrias {
80         int tot;
81         
82         float vec[32][2];
83         int (*index)[3];
84         
85 } uiWidgetTrias;
86
87 typedef struct uiWidgetStateColors {
88         char inner_anim[4];
89         char inner_anim_sel[4];
90         char inner_key[4];
91         char inner_key_sel[4];
92         char inner_driven[4];
93         char inner_driven_sel[4];
94 } uiWidgetStateColors;
95
96 typedef struct uiWidgetBase {
97         
98         int totvert, halfwayvert;
99         float outer_v[64][2];
100         float inner_v[64][2];
101         float inner_uv[64][2];
102         
103         short inner, outline, emboss; /* set on/off */
104         
105         uiWidgetTrias tria1;
106         uiWidgetTrias tria2;
107         
108 } uiWidgetBase;
109
110 /* uiWidgetType: for time being only for visual appearance,
111    later, a handling callback can be added too 
112 */
113 typedef struct uiWidgetType {
114         
115         /* pointer to theme color definition */
116         uiWidgetColors *wcol_theme;
117         
118         /* converted colors for state */
119         uiWidgetColors wcol;
120         
121         void (*state)(struct uiWidgetType *, int state);
122         void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
123         void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
124         void (*text)(uiFontStyle *, uiWidgetColors *, uiBut *, rcti *);
125         
126 } uiWidgetType;
127
128
129 /* *********************** draw data ************************** */
130
131 static float cornervec[9][2]= {{0.0, 0.0}, {0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, 
132 {0.707, 0.293}, {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0}};
133
134 static float jit[8][2]= {{0.468813 , -0.481430}, {-0.155755 , -0.352820}, 
135 {0.219306 , -0.238501},  {-0.393286 , -0.110949}, {-0.024699 , 0.013908}, 
136 {0.343805 , 0.147431}, {-0.272855 , 0.269918}, {0.095909 , 0.388710}};
137
138 static float num_tria_vert[19][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 {-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.729843, -0.008353}};
144
145 static int num_tria_face[19][3]= {
146 {13, 14, 18}, {17, 5, 6}, {12, 13, 18}, {17, 6, 7}, {15, 18, 14}, {16, 4, 5}, {16, 5, 17}, {18, 11, 12}, 
147 {18, 17, 10}, {18, 10, 11}, {17, 9, 10}, {15, 0, 18}, {18, 0, 16}, {3, 4, 16}, {8, 9, 17}, {8, 17, 7}, 
148 {2, 3, 16}, {1, 2, 16}, {16, 0, 1}};
149
150 static float menu_tria_vert[6][2]= {
151 {-0.41, 0.16}, {0.41, 0.16}, {0, 0.82}, 
152 {0, -0.82}, {-0.41, -0.16}, {0.41, -0.16}};
153
154 static int menu_tria_face[2][3]= {{2, 0, 1}, {3, 5, 4}};
155
156 static float check_tria_vert[6][2]= {
157 {-0.578579, 0.253369},  {-0.392773, 0.412794},  {-0.004241, -0.328551}, 
158 {-0.003001, 0.034320},  {1.055313, 0.864744},   {0.866408, 1.026895}};
159
160 static int check_tria_face[4][3]= {
161 {3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}};
162
163 /* ************************************************* */
164
165 void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
166 {
167         float color[4];
168         int j;
169         
170         glEnable(GL_BLEND);
171         glGetFloatv(GL_CURRENT_COLOR, color);
172         color[3]= 0.125;
173         glColor4fv(color);
174         
175         /* for each AA step */
176         for(j=0; j<8; j++) {
177                 glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
178
179                 glBegin(GL_POLYGON);
180                 glVertex2f(x1, y1);
181                 glVertex2f(x2, y2);
182                 glVertex2f(x3, y3);
183                 glEnd();
184                 
185                 glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
186         }
187
188         glDisable(GL_BLEND);
189         
190 }
191
192 static void widget_init(uiWidgetBase *wtb)
193 {
194         wtb->totvert= wtb->halfwayvert= 0;
195         wtb->tria1.tot= 0;
196         wtb->tria2.tot= 0;
197         
198         wtb->inner= 1;
199         wtb->outline= 1;
200         wtb->emboss= 1;
201 }
202
203 /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
204 /* return tot */
205 static int round_box_shadow_edges(float (*vert)[2], rcti *rect, float rad, int roundboxalign, float step)
206 {
207         float vec[9][2];
208         float minx, miny, maxx, maxy;
209         int a, tot= 0;
210         
211         rad+= step;
212         
213         if(2.0f*rad > rect->ymax-rect->ymin)
214                 rad= 0.5f*(rect->ymax-rect->ymin);
215         
216         minx= rect->xmin-step;
217         miny= rect->ymin-step;
218         maxx= rect->xmax+step;
219         maxy= rect->ymax+step;
220         
221         /* mult */
222         for(a=0; a<9; a++) {
223                 vec[a][0]= rad*cornervec[a][0]; 
224                 vec[a][1]= rad*cornervec[a][1]; 
225         }
226         
227         /* start with left-top, anti clockwise */
228         if(roundboxalign & 1) {
229                 for(a=0; a<9; a++, tot++) {
230                         vert[tot][0]= minx+rad-vec[a][0];
231                         vert[tot][1]= maxy-vec[a][1];
232                 }
233         }
234         else {
235                 for(a=0; a<9; a++, tot++) {
236                         vert[tot][0]= minx;
237                         vert[tot][1]= maxy;
238                 }
239         }
240         
241         if(roundboxalign & 8) {
242                 for(a=0; a<9; a++, tot++) {
243                         vert[tot][0]= minx+vec[a][1];
244                         vert[tot][1]= miny+rad-vec[a][0];
245                 }
246         }
247         else {
248                 for(a=0; a<9; a++, tot++) {
249                         vert[tot][0]= minx;
250                         vert[tot][1]= miny;
251                 }
252         }
253         
254         if(roundboxalign & 4) {
255                 for(a=0; a<9; a++, tot++) {
256                         vert[tot][0]= maxx-rad+vec[a][0];
257                         vert[tot][1]= miny+vec[a][1];
258                 }
259         }
260         else {
261                 for(a=0; a<9; a++, tot++) {
262                         vert[tot][0]= maxx;
263                         vert[tot][1]= miny;
264                 }
265         }
266         
267         if(roundboxalign & 2) {
268                 for(a=0; a<9; a++, tot++) {
269                         vert[tot][0]= maxx-vec[a][1];
270                         vert[tot][1]= maxy-rad+vec[a][0];
271                 }
272         }
273         else {
274                 for(a=0; a<9; a++, tot++) {
275                         vert[tot][0]= maxx;
276                         vert[tot][1]= maxy;
277                 }
278         }
279         return tot;
280 }
281
282
283
284 static void round_box_edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, float rad)
285 {
286         float vec[9][2], veci[9][2];
287         float minx= rect->xmin, miny= rect->ymin, maxx= rect->xmax, maxy= rect->ymax;
288         float radi;                               /* rad inner */
289         float minxi= minx + 1.0f; /* boundbox inner */
290         float maxxi= maxx - 1.0f;
291         float minyi= miny + 1.0f;
292         float maxyi= maxy - 1.0f;
293         float facxi= 1.0f/(maxxi-minxi); /* for uv */
294         float facyi= 1.0f/(maxyi-minyi);
295         int a, tot= 0;
296         
297         if(2.0f*rad > rect->ymax-rect->ymin)
298                 rad= 0.5f*(rect->ymax-rect->ymin);
299
300         radi= rad - 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 /* based on button rect, return scaled array of triangles */
426 static void widget_num_tria(uiWidgetTrias *tria, rcti *rect, float triasize, char where)
427 {
428         float centx, centy, size;
429         int a;
430         
431         /* center position and size */
432         centx= (float)rect->xmin + 0.5f*(rect->ymax-rect->ymin);
433         centy= (float)rect->ymin + 0.5f*(rect->ymax-rect->ymin);
434         size= -0.5f*triasize*(rect->ymax-rect->ymin);
435
436         if(where=='r') {
437                 centx= (float)rect->xmax - 0.5f*(rect->ymax-rect->ymin);
438                 size= -size;
439         }       
440         
441         for(a=0; a<19; a++) {
442                 tria->vec[a][0]= size*num_tria_vert[a][0] + centx;
443                 tria->vec[a][1]= size*num_tria_vert[a][1] + centy;
444         }
445         
446         tria->tot= 19;
447         tria->index= num_tria_face;
448 }
449
450 static void widget_trias_draw(uiWidgetTrias *tria)
451 {
452         int a;
453         
454         glBegin(GL_TRIANGLES);
455         for(a=0; a<tria->tot; a++) {
456                 glVertex2fv(tria->vec[ tria->index[a][0] ]);
457                 glVertex2fv(tria->vec[ tria->index[a][1] ]);
458                 glVertex2fv(tria->vec[ tria->index[a][2] ]);
459         }
460         glEnd();
461         
462 }
463
464 static void widget_menu_trias(uiWidgetTrias *tria, rcti *rect)
465 {
466         float centx, centy, size, asp;
467         int a;
468                 
469         /* center position and size */
470         centx= rect->xmax - 0.5f*(rect->ymax-rect->ymin);
471         centy= rect->ymin + 0.5f*(rect->ymax-rect->ymin);
472         size= 0.4f*(rect->ymax-rect->ymin);
473         
474         /* XXX exception */
475         asp= ((float)rect->xmax-rect->xmin)/((float)rect->ymax-rect->ymin);
476         if(asp > 1.2f && asp < 2.6f)
477                 centx= rect->xmax - 0.3f*(rect->ymax-rect->ymin);
478         
479         for(a=0; a<6; a++) {
480                 tria->vec[a][0]= size*menu_tria_vert[a][0] + centx;
481                 tria->vec[a][1]= size*menu_tria_vert[a][1] + centy;
482         }
483
484         tria->tot= 2;
485         tria->index= menu_tria_face;
486 }
487
488 static void widget_check_trias(uiWidgetTrias *tria, rcti *rect)
489 {
490         float centx, centy, size;
491         int a;
492         
493         /* center position and size */
494         centx= rect->xmin + 0.5f*(rect->ymax-rect->ymin);
495         centy= rect->ymin + 0.5f*(rect->ymax-rect->ymin);
496         size= 0.5f*(rect->ymax-rect->ymin);
497         
498         for(a=0; a<6; a++) {
499                 tria->vec[a][0]= size*check_tria_vert[a][0] + centx;
500                 tria->vec[a][1]= size*check_tria_vert[a][1] + centy;
501         }
502         
503         tria->tot= 4;
504         tria->index= check_tria_face;
505 }
506
507
508 /* prepares shade colors */
509 static void shadecolors4(char *coltop, char *coldown, char *color, short shadetop, short shadedown)
510 {
511         
512         coltop[0]= CLAMPIS(color[0]+shadetop, 0, 255);
513         coltop[1]= CLAMPIS(color[1]+shadetop, 0, 255);
514         coltop[2]= CLAMPIS(color[2]+shadetop, 0, 255);
515         coltop[3]= color[3];
516
517         coldown[0]= CLAMPIS(color[0]+shadedown, 0, 255);
518         coldown[1]= CLAMPIS(color[1]+shadedown, 0, 255);
519         coldown[2]= CLAMPIS(color[2]+shadedown, 0, 255);
520         coldown[3]= color[3];
521 }
522
523 static void round_box_shade_col4(char *col1, char *col2, float fac)
524 {
525         int faci, facm;
526         char col[4];
527         
528         faci= floor(255.1f*fac);
529         facm= 255-faci;
530         
531         col[0]= (faci*col1[0] + facm*col2[0])>>8;
532         col[1]= (faci*col1[1] + facm*col2[1])>>8;
533         col[2]= (faci*col1[2] + facm*col2[2])>>8;
534         col[3]= (faci*col1[3] + facm*col2[3])>>8;
535         
536         glColor4ubv(col);
537 }
538
539 static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
540 {
541         int j, a;
542         
543         glEnable(GL_BLEND);
544
545         /* backdrop non AA */
546         if(wtb->inner) {
547                 if(wcol->shaded==0) {
548                         /* filled center, solid */
549                         glColor4ubv(wcol->inner);
550                         glBegin(GL_POLYGON);
551                         for(a=0; a<wtb->totvert; a++)
552                                 glVertex2fv(wtb->inner_v[a]);
553                         glEnd();
554                 }
555                 else {
556                         char col1[4], col2[4];
557                         
558                         shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
559                         
560                         glShadeModel(GL_SMOOTH);
561                         glBegin(GL_POLYGON);
562                         for(a=0; a<wtb->totvert; a++) {
563                                 round_box_shade_col4(col1, col2, wtb->inner_uv[a][1]);
564                                 glVertex2fv(wtb->inner_v[a]);
565                         }
566                         glEnd();
567                         glShadeModel(GL_FLAT);
568                 }
569         }
570         
571         /* for each AA step */
572         if(wtb->outline) {
573                 for(j=0; j<8; j++) {
574                         glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
575                         
576                         /* outline */
577                         glColor4ub(wcol->outline[0], wcol->outline[1], wcol->outline[2], 32);
578                         glBegin(GL_QUAD_STRIP);
579                         for(a=0; a<wtb->totvert; a++) {
580                                 glVertex2fv(wtb->outer_v[a]);
581                                 glVertex2fv(wtb->inner_v[a]);
582                         }
583                         glVertex2fv(wtb->outer_v[0]);
584                         glVertex2fv(wtb->inner_v[0]);
585                         glEnd();
586                 
587                         /* emboss bottom shadow */
588                         if(wtb->emboss) {
589                                 glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
590                                 glBegin(GL_QUAD_STRIP);
591                                 for(a=0; a<wtb->halfwayvert; a++) {
592                                         glVertex2fv(wtb->outer_v[a]);
593                                         glVertex2f(wtb->outer_v[a][0], wtb->outer_v[a][1]-1.0f);
594                                 }
595                                 glEnd();
596                         }
597                         
598                         glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
599                 }
600         }
601         
602         /* decoration */
603         if(wtb->tria1.tot || wtb->tria2.tot) {
604                 /* for each AA step */
605                 for(j=0; j<8; j++) {
606                         glTranslatef(1.0*jit[j][0], 1.0*jit[j][1], 0.0f);
607
608                         if(wtb->tria1.tot) {
609                                 glColor4ub(wcol->item[0], wcol->item[1], wcol->item[2], 32);
610                                 widget_trias_draw(&wtb->tria1);
611                         }
612                         if(wtb->tria2.tot) {
613                                 glColor4ub(wcol->item[0], wcol->item[1], wcol->item[2], 32);
614                                 widget_trias_draw(&wtb->tria2);
615                         }
616                 
617                         glTranslatef(-1.0*jit[j][0], -1.0*jit[j][1], 0.0f);
618                 }
619         }
620
621         glDisable(GL_BLEND);
622         
623 }
624
625 /* *********************** text/icon ************************************** */
626
627
628 /* icons have been standardized... and this call draws in untransformed coordinates */
629 #define ICON_HEIGHT             16.0f
630
631 static void widget_draw_icon(uiBut *but, BIFIconID icon, int blend, rcti *rect)
632 {
633         float xs=0, ys=0, aspect, height;
634         
635         /* this icon doesn't need draw... */
636         if(icon==ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU)==0) return;
637         
638         /* we need aspect from block, for menus... these buttons are scaled in uiPositionBlock() */
639         aspect= but->block->aspect;
640         if(aspect != but->aspect) {
641                 /* prevent scaling up icon in pupmenu */
642                 if (aspect < 1.0f) {                    
643                         height= ICON_HEIGHT;
644                         aspect = 1.0f;
645                         
646                 }
647                 else 
648                         height= ICON_HEIGHT/aspect;
649         }
650         else
651                 height= ICON_HEIGHT;
652         
653         /* calculate blend color */
654         if ELEM3(but->type, TOG, ROW, TOGN) {
655                 if(but->flag & UI_SELECT);
656                 else if(but->flag & UI_ACTIVE);
657                 else blend= -60;
658         }
659         
660         glEnable(GL_BLEND);
661         
662         if(icon && icon!=ICON_BLANK1) {
663                 if(but->flag & UI_ICON_LEFT) {
664                         if (but->type==BUT_TOGDUAL) {
665                                 if (but->drawstr[0]) {
666                                         xs= rect->xmin-1.0;
667                                 } else {
668                                         xs= (rect->xmin+rect->xmax- height)/2.0;
669                                 }
670                         }
671                         else if (but->block->flag & UI_BLOCK_LOOP) {
672                                 xs= rect->xmin+1.0;
673                         }
674                         else if ((but->type==ICONROW) || (but->type==ICONTEXTROW)) {
675                                 xs= rect->xmin+3.0;
676                         }
677                         else {
678                                 xs= rect->xmin+4.0;
679                         }
680                         ys= (rect->ymin+rect->ymax- height)/2.0;
681                 }
682                 else {
683                         xs= (rect->xmin+rect->xmax- height)/2.0;
684                         ys= (rect->ymin+rect->ymax- height)/2.0;
685                 }
686         
687                 UI_icon_draw_aspect_blended(xs, ys, icon, aspect, blend);
688         }
689         
690         if(but->flag & UI_ICON_SUBMENU) {
691                 xs= rect->xmax-17.0;
692                 ys= (rect->ymin+rect->ymax- height)/2.0;
693                 
694                 UI_icon_draw_aspect_blended(xs, ys, ICON_RIGHTARROW_THIN, aspect, blend);
695         }
696         
697         glDisable(GL_BLEND);
698 }
699
700 /* sets but->ofs to make sure text is correctly visible */
701 static void ui_text_leftclip(uiFontStyle *fstyle, uiBut *but, rcti *rect)
702 {
703         int okwidth= rect->xmax-rect->xmin;
704         
705         /* need to set this first */
706         uiStyleFontSet(fstyle);
707
708         but->strwidth= BLF_width(but->drawstr);
709         but->ofs= 0;
710         
711         while(but->strwidth > okwidth ) {
712                 
713                 but->ofs++;
714                 but->strwidth= BLF_width(but->drawstr+but->ofs);
715                 
716                 /* textbut exception */
717                 if(but->editstr && but->pos != -1) {
718                         int pos= but->pos+strlen(but->str);
719                         
720                         if(pos-1 < but->ofs) {
721                                 pos= but->ofs-pos+1;
722                                 but->ofs -= pos;
723                                 if(but->ofs<0) {
724                                         but->ofs= 0;
725                                         pos--;
726                                 }
727                                 but->drawstr[ strlen(but->drawstr)-pos ]= 0;
728                         }
729                 }
730                 
731                 if(but->strwidth < 10) break;
732         }
733 }
734
735 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
736 {
737 //      int transopts;
738         char *cpoin = NULL;
739         
740         uiStyleFontSet(fstyle);
741         
742         if(but->editstr || (but->flag & UI_TEXT_LEFT))
743                 fstyle->align= UI_STYLE_TEXT_LEFT;
744         else
745                 fstyle->align= UI_STYLE_TEXT_CENTER;                    
746                 
747         /* text button selection and cursor */
748         if(but->editstr && but->pos != -1) {
749                 short t, pos, ch;
750                 short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
751                 
752                 if ((but->selend - but->selsta) > 0) {
753                         /* XXX weak, why is this? (ton) */
754                         t= but->str[0]?1:-2;
755                         
756                         /* text button selection */
757                         selsta_tmp = but->selsta + strlen(but->str);
758                         selend_tmp = but->selend + strlen(but->str);
759                         
760                         if(but->drawstr[0]!=0) {
761                                 ch= but->drawstr[selsta_tmp];
762                                 but->drawstr[selsta_tmp]= 0;
763                                 
764                                 selsta_draw = BLF_width(but->drawstr+but->ofs) + t;
765                                 
766                                 but->drawstr[selsta_tmp]= ch;
767                                 
768                                 ch= but->drawstr[selend_tmp];
769                                 but->drawstr[selend_tmp]= 0;
770                                 
771                                 selwidth_draw = BLF_width(but->drawstr+but->ofs) + t;
772                                 
773                                 but->drawstr[selend_tmp]= ch;
774                                 
775                                 glColor3ubv(wcol->item);
776                                 glRects(rect->xmin+selsta_draw+1, rect->ymin+2, rect->xmin+selwidth_draw+1, rect->ymax-2);
777                         }
778                 } else {
779                         /* text cursor */
780                         pos= but->pos+strlen(but->str);
781                         if(pos >= but->ofs) {
782                                 if(but->drawstr[0]!=0) {
783                                         ch= but->drawstr[pos];
784                                         but->drawstr[pos]= 0;
785                                         
786                                         t= BLF_width(but->drawstr+but->ofs) + 1;
787                                         
788                                         but->drawstr[pos]= ch;
789                                 }
790                                 else t= 1;
791                                 
792                                 glColor3ub(255,0,0);
793                                 glRects(rect->xmin+t, rect->ymin+2, rect->xmin+t+2, rect->ymax-2);
794                         }
795                 }
796         }
797         //      ui_rasterpos_safe(x, y, but->aspect);
798 //      if(but->type==IDPOIN) transopts= 0;     // no translation, of course!
799 //      else transopts= ui_translate_buttons();
800         
801         /* cut string in 2 parts - only for menu entries */
802         if(ELEM5(but->type, SLI, NUM, TEX, NUMSLI, NUMABS)==0) {
803                 cpoin= strchr(but->drawstr, '|');
804                 if(cpoin) *cpoin= 0;            
805         }
806         
807         glColor3ubv(wcol->text);
808         uiStyleFontDraw(fstyle, rect, but->drawstr+but->ofs);
809
810         /* part text right aligned */
811         if(cpoin) {
812                 fstyle->align= UI_STYLE_TEXT_RIGHT;
813                 rect->xmax-=5;
814                 uiStyleFontDraw(fstyle, rect, cpoin+1);
815                 *cpoin= '|';
816         }
817 }
818
819 /* draws text and icons for buttons */
820 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
821 {
822         
823         if(but==NULL) return;
824         
825         /* cutting off from left part */
826         if ELEM3(but->type, NUM, NUMABS, TEX) { 
827                 ui_text_leftclip(fstyle, but, rect);
828         }
829         else but->ofs= 0;
830         
831         /* check for button text label */
832         if (but->type == ICONTEXTROW) {
833                 widget_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0, rect);
834         }
835         else {
836                                 
837                 if(but->type==BUT_TOGDUAL) {
838                         int dualset= 0;
839                         if(but->pointype==SHO)
840                                 dualset= BTST( *(((short *)but->poin)+1), but->bitnr);
841                         else if(but->pointype==INT)
842                                 dualset= BTST( *(((int *)but->poin)+1), but->bitnr);
843                         
844                         widget_draw_icon(but, ICON_DOT, dualset?0:-100, rect);
845                 }
846                 
847                 if(but->drawstr[0]!=0) {
848                         
849                         /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
850                         and offset the text label to accomodate it */
851                         
852                         if (but->flag & UI_HAS_ICON) {
853                                 widget_draw_icon(but, but->icon, 0, rect);
854                                 
855                                 rect->xmin += UI_icon_get_width(but->icon);
856                                 
857                                 if(but->editstr || (but->flag & UI_TEXT_LEFT)) 
858                                         rect->xmin += 5;
859                         }
860                         else if(but->flag & UI_TEXT_LEFT)
861                                 rect->xmin += 5;
862                         
863                         widget_draw_text(fstyle, wcol, but, rect);
864                         
865                 }
866                 /* if there's no text label, then check to see if there's an icon only and draw it */
867                 else if( but->flag & UI_HAS_ICON ) {
868                         widget_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0, rect);
869                 }
870         }
871 }
872
873
874
875 /* *********************** widget types ************************************* */
876
877
878 /*   uiWidgetStateColors
879  char inner_anim[4];
880  char inner_anim_sel[4];
881  char inner_key[4];
882  char inner_key_sel[4];
883  char inner_driven[4];
884  char inner_driven_sel[4];
885  
886 */
887
888 static struct uiWidgetStateColors wcol_state= {
889         {115, 190, 76, 255},
890         {90, 166, 51, 255},
891         {240, 235, 100, 255},
892         {148, 204, 76, 255},
893         {180, 0, 255, 255},
894         {153, 0, 230, 255}
895 };
896
897 /*  uiWidgetColors
898  float outline[3];
899  float inner[4];
900  float inner_sel[4];
901  float item[3];
902  float text[3];
903  float text_sel[3];
904
905  short shaded;
906  float shadetop, shadedown;
907 */      
908
909 static struct uiWidgetColors wcol_num= {
910         {25, 25, 25, 255},
911         {180, 180, 180, 255},
912         {153, 153, 153, 255},
913         {90, 90, 90, 255},
914         
915         {0, 0, 0, 255},
916         {255, 255, 255, 255},
917         
918         1,
919         -20, 0
920 };
921
922 static struct uiWidgetColors wcol_numslider= {
923         {25, 25, 25, 255},
924         {180, 180, 180, 255},
925         {153, 153, 153, 255},
926         {128, 128, 128, 255},
927         
928         {0, 0, 0, 255},
929         {255, 255, 255, 255},
930         
931         1,
932         -20, 0
933 };
934
935 static struct uiWidgetColors wcol_text= {
936         {25, 25, 25, 255},
937         {153, 153, 153, 255},
938         {153, 153, 153, 255},
939         {90, 90, 90, 255},
940         
941         {0, 0, 0, 255},
942         {255, 255, 255, 255},
943         
944         1,
945         0, 25
946 };
947
948 static struct uiWidgetColors wcol_option= {
949         {0, 0, 0, 255},
950         {70, 70, 70, 255},
951         {70, 70, 70, 255},
952         {255, 255, 255, 255},
953         
954         {0, 0, 0, 255},
955         {255, 255, 255, 255},
956         
957         1,
958         15, -15
959 };
960
961 /* button that shows popup */
962 static struct uiWidgetColors wcol_menu= {
963         {0, 0, 0, 255},
964         {70, 70, 70, 255},
965         {70, 70, 70, 255},
966         {255, 255, 255, 255},
967         
968         {255, 255, 255, 255},
969         {204, 204, 204, 255},
970         
971         1,
972         15, -15
973 };
974
975 /* button that starts pulldown */
976 static struct uiWidgetColors wcol_pulldown= {
977         {0, 0, 0, 255},
978         {63, 63, 63, 255},
979         {86, 128, 194, 255},
980         {255, 255, 255, 255},
981         
982         {0, 0, 0, 255},
983         {0, 0, 0, 255},
984         
985         0,
986         25, -20
987 };
988
989 /* button inside menu */
990 static struct uiWidgetColors wcol_menu_item= {
991         {0, 0, 0, 255},
992         {0, 0, 0, 0},
993         {86, 128, 194, 255},
994         {255, 255, 255, 255},
995         
996         {255, 255, 255, 255},
997         {0, 0, 0, 255},
998         
999         0,
1000         38, 0
1001 };
1002
1003 /* backdrop menu + title text color */
1004 static struct uiWidgetColors wcol_menu_back= {
1005         {0, 0, 0, 255},
1006         {25, 25, 25, 230},
1007         {46, 124, 217, 204},
1008         {255, 255, 255, 255},
1009         
1010         {255, 255, 255, 255},
1011         {0, 0, 0, 255},
1012         
1013         0,
1014         25, -20
1015 };
1016
1017
1018 static struct uiWidgetColors wcol_radio= {
1019         {0, 0, 0, 255},
1020         {70, 70, 70, 255},
1021         {86, 128, 194, 255},
1022         {255, 255, 255, 255},
1023         
1024         {255, 255, 255, 255},
1025         {0, 0, 0, 255},
1026         
1027         1,
1028         15, -15
1029 };
1030
1031 static struct uiWidgetColors wcol_regular= {
1032         {25, 25, 25, 255},
1033         {153, 153, 153, 255},
1034         {100, 100, 100, 255},
1035         {25, 25, 25, 255},
1036         
1037         {0, 0, 0, 255},
1038         {255, 255, 255, 255},
1039         
1040         0,
1041         0, 0
1042 };
1043
1044 static struct uiWidgetColors wcol_tool= {
1045         {25, 25, 25, 255},
1046         {153, 153, 153, 255},
1047         {100, 100, 100, 255},
1048         {25, 25, 25, 255},
1049         
1050         {0, 0, 0, 255},
1051         {255, 255, 255, 255},
1052         
1053         1,
1054         25, -25
1055 };
1056
1057 /* called for theme init (new theme) and versions */
1058 void ui_widget_color_init(ThemeUI *tui)
1059 {
1060
1061         tui->wcol_regular= wcol_regular;
1062         tui->wcol_tool= wcol_tool;
1063         tui->wcol_radio= wcol_radio;
1064         tui->wcol_text= wcol_text;
1065         tui->wcol_option= wcol_option;
1066         tui->wcol_num= wcol_num;
1067         tui->wcol_numslider= wcol_numslider;
1068         tui->wcol_menu= wcol_menu;
1069         tui->wcol_pulldown= wcol_pulldown;
1070         tui->wcol_menu_back= wcol_menu_back;
1071         tui->wcol_menu_item= wcol_menu_item;
1072         
1073         tui->iconfile[0]= 0;
1074 }
1075
1076 /* ************ button callbacks, state ***************** */
1077
1078 /* copy colors from theme, and set changes in it based on state */
1079 static void widget_state(uiWidgetType *wt, int state)
1080 {
1081         wt->wcol= *(wt->wcol_theme);
1082         
1083         if(state & UI_SELECT) {
1084                 if(state & UI_BUT_ANIMATED_KEY)
1085                         QUATCOPY(wt->wcol.inner, wcol_state.inner_key_sel)
1086                 else if(state & UI_BUT_ANIMATED)
1087                         QUATCOPY(wt->wcol.inner, wcol_state.inner_anim_sel)
1088                 else if(state & UI_BUT_DRIVEN)
1089                         QUATCOPY(wt->wcol.inner, wcol_state.inner_driven_sel)
1090                 else
1091                         QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel)
1092
1093                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1094                 
1095                 /* only flip shade if it's not "pushed in" already */
1096                 if(wt->wcol.shaded && wt->wcol.shadetop>wt->wcol.shadedown) {
1097                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1098                 }
1099         }
1100         else {
1101                 if(state & UI_BUT_ANIMATED_KEY)
1102                         QUATCOPY(wt->wcol.inner, wcol_state.inner_key)
1103                 else if(state & UI_BUT_ANIMATED)
1104                         QUATCOPY(wt->wcol.inner, wcol_state.inner_anim)
1105                 else if(state & UI_BUT_DRIVEN)
1106                         QUATCOPY(wt->wcol.inner, wcol_state.inner_driven)
1107
1108                 if(state & UI_ACTIVE) { /* mouse over? */
1109                         wt->wcol.inner[0]= wt->wcol.inner[0]>=240? 255 : wt->wcol.inner[0]+15;
1110                         wt->wcol.inner[1]= wt->wcol.inner[1]>=240? 255 : wt->wcol.inner[1]+15;
1111                         wt->wcol.inner[2]= wt->wcol.inner[2]>=240? 255 : wt->wcol.inner[2]+15;
1112                 }
1113         }
1114 }
1115
1116 /* labels use theme colors for text */
1117 static void widget_state_label(uiWidgetType *wt, int state)
1118 {
1119         /* call this for option button */
1120         widget_state(wt, state);
1121
1122         if(state & UI_SELECT)
1123                 UI_GetThemeColor4ubv(TH_TEXT_HI, wt->wcol.text);
1124         else
1125                 UI_GetThemeColor4ubv(TH_TEXT, wt->wcol.text);
1126         
1127 }
1128
1129
1130 /* special case, button that calls pulldown */
1131 static void widget_state_pulldown(uiWidgetType *wt, int state)
1132 {
1133         wt->wcol= *(wt->wcol_theme);
1134         
1135         QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1136         VECCOPY(wt->wcol.outline, wt->wcol.inner);
1137
1138         if(state & UI_ACTIVE)
1139                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1140 }
1141
1142 /* special case, menu items */
1143 static void widget_state_menu_item(uiWidgetType *wt, int state)
1144 {
1145         wt->wcol= *(wt->wcol_theme);
1146         
1147         if(state & UI_BUT_DISABLED) {
1148                 wt->wcol.text[0]= 0.5f*(wt->wcol.text[0]+wt->wcol.text_sel[0]);
1149                 wt->wcol.text[1]= 0.5f*(wt->wcol.text[1]+wt->wcol.text_sel[1]);
1150                 wt->wcol.text[2]= 0.5f*(wt->wcol.text[2]+wt->wcol.text_sel[2]);
1151         }
1152         else if(state & UI_ACTIVE) {
1153                 QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1154                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1155                 
1156                 wt->wcol.shaded= 1;
1157         }
1158 }
1159
1160
1161 /* ************ menu backdrop ************************* */
1162
1163 /* outside of rect, rad to left/bottom/right */
1164 static void widget_softshadow(rcti *rect, int roundboxalign, float radin, float radout)
1165 {
1166         uiWidgetBase wtb;
1167         rcti rect1= *rect;
1168         float alpha, alphastep;
1169         int step, tot, a;
1170         
1171         /* prevent tooltips to not show round shadow */
1172         if( 2.0f*radout > 0.2f*(rect1.ymax-rect1.ymin) )
1173                 rect1.ymax -= 0.2f*(rect1.ymax-rect1.ymin);
1174         else
1175                 rect1.ymax -= 2.0f*radout;
1176         
1177         /* inner part */
1178         tot= round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & 12, 0.0f);
1179         
1180         /* inverse linear shadow alpha */
1181         alpha= 0.15;
1182         alphastep= 0.67;
1183         
1184         for(step= 1; step<=radout; step++, alpha*=alphastep) {
1185                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, 15, (float)step);
1186                 
1187                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
1188                 
1189                 glBegin(GL_QUAD_STRIP);
1190                 for(a=0; a<tot; a++) {
1191                         glVertex2fv(wtb.outer_v[a]);
1192                         glVertex2fv(wtb.inner_v[a]);
1193                 }
1194                 glEnd();
1195         }
1196         
1197 }
1198
1199 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1200 {
1201         uiWidgetBase wtb;
1202         int roundboxalign= 15;
1203         
1204         widget_init(&wtb);
1205         
1206         /* menu is 2nd level or deeper */
1207         if (flag & UI_BLOCK_POPUP) {
1208                 rect->ymin -= 4.0;
1209                 rect->ymax += 4.0;
1210         }
1211         else if (direction == UI_DOWN) {
1212                 roundboxalign= 12;
1213                 rect->ymin -= 4.0;
1214         } 
1215         else if (direction == UI_TOP) {
1216                 roundboxalign= 3;
1217                 rect->ymax += 4.0;
1218         }
1219         
1220         glEnable(GL_BLEND);
1221         widget_softshadow(rect, roundboxalign, 5.0f, 8.0f);
1222         
1223         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
1224         wtb.emboss= 0;
1225         widgetbase_draw(&wtb, wcol);
1226         
1227         glDisable(GL_BLEND);
1228 }
1229
1230 /* ************ custom buttons, old stuff ************** */
1231
1232 /* draws in resolution of 20x4 colors */
1233 static void ui_draw_but_HSVCUBE(uiBut *but, rcti *rect)
1234 {
1235         int a;
1236         float h,s,v;
1237         float dx, dy, sx1, sx2, sy, x, y;
1238         float col0[4][3];       // left half, rect bottom to top
1239         float col1[4][3];       // right half, rect bottom to top
1240         
1241         h= but->hsv[0];
1242         s= but->hsv[1];
1243         v= but->hsv[2];
1244         
1245         /* draw series of gouraud rects */
1246         glShadeModel(GL_SMOOTH);
1247         
1248         if(but->a1==0) {        // H and V vary
1249                 hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1250                 hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1251                 hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1252                 hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1253                 x= h; y= v;
1254         }
1255         else if(but->a1==1) {   // H and S vary
1256                 hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1257                 hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1258                 hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1259                 hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1260                 x= h; y= s;
1261         }
1262         else if(but->a1==2) {   // S and V vary
1263                 hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1264                 hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
1265                 hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
1266                 hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1267                 x= v; y= s;
1268         }
1269         else {          // only hue slider
1270                 hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1271                 VECCOPY(col1[1], col1[0]);
1272                 VECCOPY(col1[2], col1[0]);
1273                 VECCOPY(col1[3], col1[0]);
1274                 x= h; y= 0.5;
1275         }
1276         
1277         for(dx=0.0; dx<1.0; dx+= 0.05) {
1278                 // previous color
1279                 VECCOPY(col0[0], col1[0]);
1280                 VECCOPY(col0[1], col1[1]);
1281                 VECCOPY(col0[2], col1[2]);
1282                 VECCOPY(col0[3], col1[3]);
1283                 
1284                 // new color
1285                 if(but->a1==0) {        // H and V vary
1286                         hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1287                         hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1288                         hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1289                         hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1290                 }
1291                 else if(but->a1==1) {   // H and S vary
1292                         hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1293                         hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1294                         hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1295                         hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1296                 }
1297                 else if(but->a1==2) {   // S and V vary
1298                         hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
1299                         hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
1300                         hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
1301                         hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
1302                 }
1303                 else {  // only H
1304                         hsv_to_rgb(dx, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1305                         VECCOPY(col1[1], col1[0]);
1306                         VECCOPY(col1[2], col1[0]);
1307                         VECCOPY(col1[3], col1[0]);
1308                 }
1309                 
1310                 // rect
1311                 sx1= rect->xmin + dx*(rect->xmax-rect->xmin);
1312                 sx2= rect->xmin + (dx+0.05)*(rect->xmax-rect->xmin);
1313                 sy= rect->ymin;
1314                 dy= (rect->ymax-rect->ymin)/3.0;
1315                 
1316                 glBegin(GL_QUADS);
1317                 for(a=0; a<3; a++, sy+=dy) {
1318                         glColor3fv(col0[a]);
1319                         glVertex2f(sx1, sy);
1320                         
1321                         glColor3fv(col1[a]);
1322                         glVertex2f(sx2, sy);
1323                         
1324                         glColor3fv(col1[a+1]);
1325                         glVertex2f(sx2, sy+dy);
1326                         
1327                         glColor3fv(col0[a+1]);
1328                         glVertex2f(sx1, sy+dy);
1329                 }
1330                 glEnd();
1331         }
1332         
1333         glShadeModel(GL_FLAT);
1334         
1335         /* cursor */
1336         x= rect->xmin + x*(rect->xmax-rect->xmin);
1337         y= rect->ymin + y*(rect->ymax-rect->ymin);
1338         CLAMP(x, rect->xmin+3.0, rect->xmax-3.0);
1339         CLAMP(y, rect->ymin+3.0, rect->ymax-3.0);
1340         
1341         fdrawXORcirc(x, y, 3.1);
1342         
1343         /* outline */
1344         glColor3ub(0,  0,  0);
1345         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
1346 }
1347
1348
1349 /* ************ button callbacks, draw ***************** */
1350
1351 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1352 {
1353         uiWidgetBase wtb;
1354         
1355         widget_init(&wtb);
1356         
1357         /* fully rounded */
1358         round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1359         
1360         /* decoration */
1361         if(!(state & UI_TEXTINPUT)) {
1362                 widget_num_tria(&wtb.tria1, rect, 0.6f, 0);
1363                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
1364         }       
1365         widgetbase_draw(&wtb, wcol);
1366         
1367         /* text space */
1368         rect->xmin += (rect->ymax-rect->ymin);
1369         rect->xmax -= (rect->ymax-rect->ymin);
1370
1371 }
1372
1373 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1374 {
1375         uiWidgetBase wtb, wtb1;
1376         rcti rect1;
1377         double value;
1378         float offs, fac;
1379         char outline[3];
1380         
1381         widget_init(&wtb);
1382         widget_init(&wtb1);
1383         
1384         /* backdrop first */
1385         
1386         /* fully rounded */
1387         offs= 0.5f*(rect->ymax - rect->ymin);
1388         round_box_edges(&wtb, roundboxalign, rect, offs);
1389
1390         wtb.outline= 0;
1391         widgetbase_draw(&wtb, wcol);
1392         
1393         /* slider part */
1394         VECCOPY(outline, wcol->outline);
1395         VECCOPY(wcol->outline, wcol->item);
1396         VECCOPY(wcol->inner, wcol->item);
1397         SWAP(short, wcol->shadetop, wcol->shadedown);
1398         
1399         rect1= *rect;
1400         
1401         value= ui_get_but_val(but);
1402         fac= (value-but->softmin)*(rect1.xmax - rect1.xmin - offs)/(but->softmax - but->softmin);
1403         
1404         /* left part of slider, always rounded */
1405         rect1.xmax= rect1.xmin + ceil(offs+1.0f);
1406         round_box_edges(&wtb1, roundboxalign & ~6, &rect1, offs);
1407         wtb1.outline= 0;
1408         widgetbase_draw(&wtb1, wcol);
1409         
1410         /* right part of slider, interpolate roundness */
1411         rect1.xmax= rect1.xmin + fac + offs;
1412         rect1.xmin+=  floor(offs-1.0f);
1413         if(rect1.xmax + offs > rect->xmax)
1414                 offs*= (rect1.xmax + offs - rect->xmax)/offs;
1415         else 
1416                 offs= 0.0f;
1417         round_box_edges(&wtb1, roundboxalign & ~9, &rect1, offs);
1418         
1419         widgetbase_draw(&wtb1, wcol);
1420         VECCOPY(wcol->outline, outline);
1421         SWAP(short, wcol->shadetop, wcol->shadedown);
1422         
1423         /* outline */
1424         wtb.outline= 1;
1425         wtb.inner= 0;
1426         widgetbase_draw(&wtb, wcol);
1427         
1428         /* text space */
1429         rect->xmin += (rect->ymax-rect->ymin);
1430         rect->xmax -= (rect->ymax-rect->ymin);
1431         
1432 }
1433
1434 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1435 {
1436         uiWidgetBase wtb;
1437         float col[4];
1438         
1439         widget_init(&wtb);
1440         
1441         /* half rounded */
1442         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1443                 
1444         ui_get_but_vectorf(but, col);
1445         wcol->inner[0]= FTOCHAR(col[0]);
1446         wcol->inner[1]= FTOCHAR(col[1]);
1447         wcol->inner[2]= FTOCHAR(col[2]);
1448         
1449         widgetbase_draw(&wtb, wcol);
1450         
1451 }
1452
1453
1454 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1455 {
1456         uiWidgetBase wtb;
1457         
1458         widget_init(&wtb);
1459         
1460         /* half rounded */
1461         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1462         
1463         widgetbase_draw(&wtb, wcol);
1464
1465 }
1466
1467
1468 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1469 {
1470         uiWidgetBase wtb;
1471         
1472         widget_init(&wtb);
1473         
1474         /* half rounded */
1475         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1476         
1477         /* decoration */
1478         widget_menu_trias(&wtb.tria1, rect);
1479         
1480         widgetbase_draw(&wtb, wcol);
1481         
1482         /* text space */
1483         rect->xmax -= (rect->ymax-rect->ymin);
1484         
1485 }
1486
1487 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1488 {
1489         if(state & UI_ACTIVE) {
1490                 uiWidgetBase wtb;
1491                 
1492                 widget_init(&wtb);
1493                 
1494                 /* fully rounded */
1495                 round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1496                 
1497                 widgetbase_draw(&wtb, wcol);
1498         }
1499 }
1500
1501 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1502 {
1503         uiWidgetBase wtb;
1504         
1505         widget_init(&wtb);
1506         
1507         /* not rounded, no outline */
1508         wtb.outline= 0;
1509         round_box_edges(&wtb, 0, rect, 0.0f);
1510         
1511         widgetbase_draw(&wtb, wcol);
1512 }
1513
1514
1515 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1516 {
1517         uiWidgetBase wtb;
1518         rcti recttemp= *rect;
1519         int delta;
1520         
1521         widget_init(&wtb);
1522         
1523         /* square */
1524         recttemp.xmax= recttemp.xmin + (recttemp.ymax-recttemp.ymin);
1525         
1526         /* smaller */
1527         delta= 1 + (recttemp.ymax-recttemp.ymin)/8;
1528         recttemp.xmin+= delta;
1529         recttemp.ymin+= delta;
1530         recttemp.xmax-= delta;
1531         recttemp.ymax-= delta;
1532         
1533         /* half rounded */
1534         round_box_edges(&wtb, 15, &recttemp, 4.0f);
1535         
1536         /* decoration */
1537         if(state & UI_SELECT) {
1538                 widget_check_trias(&wtb.tria1, &recttemp);
1539         }
1540         
1541         widgetbase_draw(&wtb, wcol);
1542         
1543         /* text space */
1544         rect->xmin += (rect->ymax-rect->ymin)*0.7 + delta;
1545 }
1546
1547
1548 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1549 {
1550         uiWidgetBase wtb;
1551         
1552         widget_init(&wtb);
1553         
1554         /* half rounded */
1555         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1556         
1557         widgetbase_draw(&wtb, wcol);
1558
1559 }
1560
1561 static void widget_but(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1562 {
1563         uiWidgetBase wtb;
1564         
1565         widget_init(&wtb);
1566         
1567         /* half rounded */
1568         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1569                 
1570         widgetbase_draw(&wtb, wcol);
1571
1572 }
1573
1574 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1575 {
1576         uiWidgetBase wtb;
1577         
1578         widget_init(&wtb);
1579         
1580         /* fully rounded */
1581         round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1582
1583         widgetbase_draw(&wtb, wcol);
1584 }
1585
1586 static void widget_disabled(rcti *rect)
1587 {
1588         float col[4];
1589         
1590         glEnable(GL_BLEND);
1591         
1592         /* can't use theme TH_BACK or TH_PANEL... undefined */
1593         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
1594         glColor4f(col[0], col[1], col[2], 0.5f);
1595         glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1596
1597         glDisable(GL_BLEND);
1598 }
1599
1600 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
1601 {
1602         bTheme *btheme= U.themes.first;
1603         static uiWidgetType wt;
1604         
1605         /* defaults */
1606         wt.wcol_theme= &btheme->tui.wcol_regular;
1607         wt.state= widget_state;
1608         wt.draw= widget_but;
1609         wt.custom= NULL;
1610         wt.text= widget_draw_text_icon;
1611         
1612         switch(type) {
1613                 case UI_WTYPE_LABEL:
1614                         wt.draw= NULL;
1615                         wt.state= widget_state_label;
1616                         break;
1617                         
1618                 case UI_WTYPE_TOGGLE:
1619                         break;
1620                         
1621                 case UI_WTYPE_OPTION:
1622                         wt.wcol_theme= &btheme->tui.wcol_option;
1623                         wt.draw= widget_optionbut;
1624                         wt.state= widget_state_label;
1625                         break;
1626                         
1627                 case UI_WTYPE_RADIO:
1628                         wt.wcol_theme= &btheme->tui.wcol_radio;
1629                         wt.draw= widget_radiobut;
1630                         break;
1631                         
1632                 case UI_WTYPE_NUMBER:
1633                         wt.wcol_theme= &btheme->tui.wcol_num;
1634                         wt.draw= widget_numbut;
1635                         break;
1636                         
1637                 case UI_WTYPE_SLIDER:
1638                         wt.wcol_theme= &btheme->tui.wcol_numslider;
1639                         wt.custom= widget_numslider;
1640                         break;
1641                         
1642                 case UI_WTYPE_EXEC:
1643                         wt.wcol_theme= &btheme->tui.wcol_tool;
1644                         wt.draw= widget_roundbut;
1645                         break;
1646                         
1647                         
1648                         /* strings */
1649                 case UI_WTYPE_NAME:
1650                         wt.wcol_theme= &btheme->tui.wcol_text;
1651                         wt.draw= widget_textbut;
1652                         break;
1653                         
1654                 case UI_WTYPE_NAME_LINK:
1655                         break;
1656                         
1657                 case UI_WTYPE_POINTER_LINK:
1658                         break;
1659                         
1660                 case UI_WTYPE_FILENAME:
1661                         break;
1662                         
1663                         
1664                         /* start menus */
1665                 case UI_WTYPE_MENU_RADIO:
1666                         wt.wcol_theme= &btheme->tui.wcol_menu;
1667                         wt.draw= widget_menubut;
1668                         break;
1669                         
1670                 case UI_WTYPE_MENU_POINTER_LINK:
1671                         wt.wcol_theme= &btheme->tui.wcol_menu;
1672                         wt.draw= widget_menubut;
1673                         break;
1674                         
1675                         
1676                 case UI_WTYPE_PULLDOWN:
1677                         wt.wcol_theme= &btheme->tui.wcol_pulldown;
1678                         wt.draw= widget_pulldownbut;
1679                         wt.state= widget_state_pulldown;
1680                         break;
1681                         
1682                         /* in menus */
1683                 case UI_WTYPE_MENU_ITEM:
1684                         wt.wcol_theme= &btheme->tui.wcol_menu_item;
1685                         wt.draw= widget_menu_itembut;
1686                         wt.state= widget_state_menu_item;
1687                         break;
1688                         
1689                 case UI_WTYPE_MENU_BACK:
1690                         wt.wcol_theme= &btheme->tui.wcol_menu_back;
1691                         wt.draw= widget_menu_back;
1692                         break;
1693                         
1694                         /* specials */
1695                 case UI_WTYPE_ICON:
1696                         wt.draw= NULL;
1697                         break;
1698                         
1699                 case UI_WTYPE_SWATCH:
1700                         wt.custom= widget_swatch;
1701                         break;
1702                         
1703                 case UI_WTYPE_RGB_PICKER:
1704                         break;
1705                         
1706                 case UI_WTYPE_NORMAL:
1707                         break;
1708         }
1709         
1710         return &wt;
1711 }
1712
1713
1714 static int widget_roundbox_set(uiBut *but, rcti *rect)
1715 {
1716         /* alignment */
1717         if(but->flag & UI_BUT_ALIGN) {
1718                 
1719                 if(but->flag & UI_BUT_ALIGN_TOP)
1720                         rect->ymax+= 1;
1721                 if(but->flag & UI_BUT_ALIGN_LEFT)
1722                         rect->xmin-= 1;
1723                 
1724                 switch(but->flag & UI_BUT_ALIGN) {
1725                         case UI_BUT_ALIGN_TOP:
1726                                 return (12);
1727                                 break;
1728                         case UI_BUT_ALIGN_DOWN:
1729                                 return (3);
1730                                 break;
1731                         case UI_BUT_ALIGN_LEFT:
1732                                 return (6);
1733                                 break;
1734                         case UI_BUT_ALIGN_RIGHT:
1735                                 return (9);
1736                                 break;
1737                                 
1738                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
1739                                 return (1);
1740                                 break;
1741                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
1742                                 return (2);
1743                                 break;
1744                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
1745                                 return (8);
1746                                 break;
1747                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
1748                                 return (4);
1749                                 break;
1750                                 
1751                         default:
1752                                 return (0);
1753                                 break;
1754                 }
1755         } 
1756         return 15;
1757 }
1758
1759 /* conversion from old to new buttons, so still messy */
1760 void ui_draw_but(ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
1761 {
1762         bTheme *btheme= U.themes.first;
1763         ThemeUI *tui= &btheme->tui;
1764         uiFontStyle *fstyle= &style->widget;
1765         uiWidgetType *wt= NULL;
1766         
1767         /* handle menus seperately */
1768         if(but->dt==UI_EMBOSSP) {
1769                 switch (but->type) {
1770                         case LABEL:
1771                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
1772                                 break;
1773                         case SEPR:
1774                                 break;
1775                                 
1776                         default:
1777                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
1778                 }
1779         }
1780         else if(but->dt==UI_EMBOSSN) {
1781                 /* "nothing" */
1782                 wt= widget_type(UI_WTYPE_ICON);
1783         }
1784         else {
1785                 
1786                 switch (but->type) {
1787                         case LABEL:
1788                                 if(but->block->flag & UI_BLOCK_LOOP)
1789                                         widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
1790                                 else {
1791                                         wt= widget_type(UI_WTYPE_LABEL);
1792                                         fstyle= &style->widgetlabel;
1793                                 }
1794                                 break;
1795                         case SEPR:
1796                                 break;
1797                         case BUT:
1798                                 wt= widget_type(UI_WTYPE_EXEC);
1799                                 break;
1800                         case NUM:
1801                                 wt= widget_type(UI_WTYPE_NUMBER);
1802                                 break;
1803                         case NUMSLI:
1804                         case HSVSLI:
1805                                 wt= widget_type(UI_WTYPE_SLIDER);
1806                                 break;
1807                         case ROW:
1808                                 wt= widget_type(UI_WTYPE_RADIO);
1809                                 break;
1810                         case TEX:
1811                                 wt= widget_type(UI_WTYPE_NAME);
1812                                 break;
1813                         case TOGBUT:
1814                                 wt= widget_type(UI_WTYPE_TOGGLE);
1815                                 break;
1816                         case TOG:
1817                         case TOGN:
1818                         case TOG3:
1819                                 if (!(but->flag & UI_HAS_ICON)) {
1820                                         wt= widget_type(UI_WTYPE_OPTION);
1821                                         but->flag |= UI_TEXT_LEFT;
1822                                 }
1823                                 else
1824                                         wt= widget_type(UI_WTYPE_TOGGLE);
1825                                 break;
1826                         case MENU:
1827                         case BLOCK:
1828                         case ICONTEXTROW:
1829                                 wt= widget_type(UI_WTYPE_MENU_RADIO);
1830                                 break;
1831                                 
1832                         case PULLDOWN:
1833                                 wt= widget_type(UI_WTYPE_PULLDOWN);
1834                                 break;
1835                         
1836                         case BUTM:
1837                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
1838                                 break;
1839                                 
1840                         case COL:
1841                                 wt= widget_type(UI_WTYPE_SWATCH);
1842                                 break;
1843                         
1844                                  // XXX four old button types
1845                         case HSVCUBE:
1846                                 ui_draw_but_HSVCUBE(but, rect);
1847                                 break;
1848                         case BUT_COLORBAND:
1849                                 ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
1850                                 break;
1851                         case BUT_NORMAL:
1852                                 ui_draw_but_NORMAL(but, &tui->wcol_regular, rect);
1853                                 break;
1854                         case BUT_CURVE:
1855                                 ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
1856                                 break;
1857                                 
1858                         default:
1859                                 wt= widget_type(UI_WTYPE_TOGGLE);
1860                 }
1861         }
1862         
1863         if(wt) {
1864                 rcti disablerect= *rect; /* rect gets clipped smaller for text */
1865                 int roundboxalign, state;
1866                 
1867                 roundboxalign= widget_roundbox_set(but, rect);
1868                 state= but->flag;
1869                 if(but->editstr) state |= UI_TEXTINPUT;
1870                 
1871                 wt->state(wt, state);
1872                 if(wt->custom)
1873                         wt->custom(but, &wt->wcol, rect, state, roundboxalign);
1874                 else if(wt->draw)
1875                         wt->draw(&wt->wcol, rect, state, roundboxalign);
1876                 wt->text(fstyle, &wt->wcol, but, rect);
1877                 
1878                 if(state & UI_BUT_DISABLED)
1879                         if(but->dt!=UI_EMBOSSP)
1880                                 widget_disabled(&disablerect);
1881         }
1882 }
1883
1884 void ui_draw_menu_back(uiStyle *style, uiBlock *block, rcti *rect)
1885 {
1886         uiWidgetType *wt= widget_type(UI_WTYPE_MENU_BACK);
1887         
1888         wt->state(wt, 0);
1889         if(block)
1890                 wt->draw(&wt->wcol, rect, block->flag, block->direction);
1891         else
1892                 wt->draw(&wt->wcol, rect, 0, 0);
1893         
1894 }
1895
1896