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, uiBut *but, rcti *rect)
736 {
737 //      int transopts;
738         char *cpoin;
739         
740 //      ui_rasterpos_safe(x, y, but->aspect);
741 //      if(but->type==IDPOIN) transopts= 0;     // no translation, of course!
742 //      else transopts= ui_translate_buttons();
743         
744         /* cut string in 2 parts */
745         cpoin= strchr(but->drawstr, '|');
746         if(cpoin) *cpoin= 0;            
747         
748         if(but->editstr || (but->flag & UI_TEXT_LEFT))
749                 fstyle->align= UI_STYLE_TEXT_LEFT;
750         else
751                 fstyle->align= UI_STYLE_TEXT_CENTER;                    
752         
753         uiStyleFontDraw(fstyle, rect, but->drawstr+but->ofs);
754
755         /* part text right aligned */
756         if(cpoin) {
757                 fstyle->align= UI_STYLE_TEXT_RIGHT;
758                 rect->xmax-=5;
759                 uiStyleFontDraw(fstyle, rect, cpoin+1);
760                 *cpoin= '|';
761         }
762 }
763
764 /* draws text and icons for buttons */
765 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
766 {
767         short t, pos, ch;
768         short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
769         
770         if(but==NULL) return;
771         
772         /* cutting off from left part */
773         if ELEM3(but->type, NUM, NUMABS, TEX) { 
774                 ui_text_leftclip(fstyle, but, rect);
775         }
776         else but->ofs= 0;
777         
778         /* check for button text label */
779         if (but->type == ICONTEXTROW) {
780                 widget_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0, rect);
781         }
782         else {
783                 
784                 /* text button selection and cursor */
785                 if(but->editstr && but->pos != -1) {
786                         
787                         if ((but->selend - but->selsta) > 0) {
788                                 /* text button selection */
789                                 selsta_tmp = but->selsta + strlen(but->str);
790                                 selend_tmp = but->selend + strlen(but->str);
791                                 
792                                 if(but->drawstr[0]!=0) {
793                                         ch= but->drawstr[selsta_tmp];
794                                         but->drawstr[selsta_tmp]= 0;
795                                         
796                                         uiStyleFontSet(fstyle);
797
798                                         selsta_draw = BLF_width(but->drawstr+but->ofs) + 3;
799                                         
800                                         but->drawstr[selsta_tmp]= ch;
801                                         
802                                         
803                                         ch= but->drawstr[selend_tmp];
804                                         but->drawstr[selend_tmp]= 0;
805                                         
806                                         selwidth_draw = BLF_width(but->drawstr+but->ofs) + 3;
807                                         
808                                         but->drawstr[selend_tmp]= ch;
809                                         
810                                         glColor3ubv(wcol->item);
811                                         glRects(rect->xmin+selsta_draw+1, rect->ymin+2, rect->xmin+selwidth_draw+1, rect->ymax-2);
812                                 }
813                         } else {
814                                 /* text cursor */
815                                 pos= but->pos+strlen(but->str);
816                                 if(pos >= but->ofs) {
817                                         if(but->drawstr[0]!=0) {
818                                                 ch= but->drawstr[pos];
819                                                 but->drawstr[pos]= 0;
820                                                 
821                                                 uiStyleFontSet(fstyle);
822
823                                                 t= BLF_width(but->drawstr+but->ofs) + 3;
824                                                 
825                                                 but->drawstr[pos]= ch;
826                                         }
827                                         else t= 3;
828                                         
829                                         glColor3ub(255,0,0);
830                                         glRects(rect->xmin+t, rect->ymin+2, rect->xmin+t+2, rect->ymax-2);
831                                 }
832                         }
833                 }
834                 
835                 if(but->type==BUT_TOGDUAL) {
836                         int dualset= 0;
837                         if(but->pointype==SHO)
838                                 dualset= BTST( *(((short *)but->poin)+1), but->bitnr);
839                         else if(but->pointype==INT)
840                                 dualset= BTST( *(((int *)but->poin)+1), but->bitnr);
841                         
842                         widget_draw_icon(but, ICON_DOT, dualset?0:-100, rect);
843                 }
844                 
845                 if(but->drawstr[0]!=0) {
846                         
847                         /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
848                         and offset the text label to accomodate it */
849                         
850                         if (but->flag & UI_HAS_ICON) {
851                                 widget_draw_icon(but, but->icon, 0, rect);
852                                 
853                                 rect->xmin += UI_icon_get_width(but->icon);
854                                 
855                                 if(but->editstr || (but->flag & UI_TEXT_LEFT)) 
856                                         rect->xmin += 5;
857                         }
858                         else if(but->flag & UI_TEXT_LEFT)
859                                 rect->xmin += 5;
860                         
861                         glColor3ubv(wcol->text);
862                         widget_draw_text(fstyle, but, rect);
863                         
864                 }
865                 /* if there's no text label, then check to see if there's an icon only and draw it */
866                 else if( but->flag & UI_HAS_ICON ) {
867                         widget_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0, rect);
868                 }
869         }
870 }
871
872
873
874 /* *********************** widget types ************************************* */
875
876
877 /*   uiWidgetStateColors
878  char inner_anim[4];
879  char inner_anim_sel[4];
880  char inner_key[4];
881  char inner_key_sel[4];
882  char inner_driven[4];
883  char inner_driven_sel[4];
884  
885 */
886
887 static struct uiWidgetStateColors wcol_state= {
888         {115, 190, 76, 255},
889         {90, 166, 51, 255},
890         {240, 235, 100, 255},
891         {148, 204, 76, 255},
892         {180, 0, 255, 255},
893         {153, 0, 230, 255}
894 };
895
896 /*  uiWidgetColors
897  float outline[3];
898  float inner[4];
899  float inner_sel[4];
900  float item[3];
901  float text[3];
902  float text_sel[3];
903
904  short shaded;
905  float shadetop, shadedown;
906 */      
907
908 static struct uiWidgetColors wcol_num= {
909         {25, 25, 25, 255},
910         {180, 180, 180, 255},
911         {153, 153, 153, 255},
912         {90, 90, 90, 255},
913         
914         {0, 0, 0, 255},
915         {255, 255, 255, 255},
916         
917         1,
918         -20, 0
919 };
920
921 static struct uiWidgetColors wcol_numslider= {
922         {25, 25, 25, 255},
923         {180, 180, 180, 255},
924         {153, 153, 153, 255},
925         {128, 128, 128, 255},
926         
927         {0, 0, 0, 255},
928         {255, 255, 255, 255},
929         
930         1,
931         -20, 0
932 };
933
934 static struct uiWidgetColors wcol_text= {
935         {25, 25, 25, 255},
936         {153, 153, 153, 255},
937         {153, 153, 153, 255},
938         {90, 90, 90, 255},
939         
940         {0, 0, 0, 255},
941         {255, 255, 255, 255},
942         
943         1,
944         0, 25
945 };
946
947 static struct uiWidgetColors wcol_option= {
948         {0, 0, 0, 255},
949         {70, 70, 70, 255},
950         {70, 70, 70, 255},
951         {255, 255, 255, 255},
952         
953         {0, 0, 0, 255},
954         {255, 255, 255, 255},
955         
956         1,
957         25, -20
958 };
959
960 /* button that shows popup */
961 static struct uiWidgetColors wcol_menu= {
962         {0, 0, 0, 255},
963         {70, 70, 70, 255},
964         {70, 70, 70, 255},
965         {255, 255, 255, 255},
966         
967         {255, 255, 255, 255},
968         {204, 204, 204, 255},
969         
970         1,
971         25, -20
972 };
973
974 /* button that starts pulldown */
975 static struct uiWidgetColors wcol_pulldown= {
976         {0, 0, 0, 255},
977         {63, 63, 63, 255},
978         {86, 128, 194, 255},
979         {255, 255, 255, 255},
980         
981         {0, 0, 0, 255},
982         {0, 0, 0, 255},
983         
984         0,
985         25, -20
986 };
987
988 /* button inside menu */
989 static struct uiWidgetColors wcol_menu_item= {
990         {0, 0, 0, 255},
991         {0, 0, 0, 0},
992         {86, 128, 194, 255},
993         {255, 255, 255, 255},
994         
995         {255, 255, 255, 255},
996         {0, 0, 0, 255},
997         
998         0,
999         38, 0
1000 };
1001
1002 /* backdrop menu + title text color */
1003 static struct uiWidgetColors wcol_menu_back= {
1004         {0, 0, 0, 255},
1005         {25, 25, 25, 230},
1006         {46, 124, 217, 204},
1007         {255, 255, 255, 255},
1008         
1009         {255, 255, 255, 255},
1010         {0, 0, 0, 255},
1011         
1012         0,
1013         25, -20
1014 };
1015
1016
1017 static struct uiWidgetColors wcol_radio= {
1018         {0, 0, 0, 255},
1019         {70, 70, 70, 255},
1020         {86, 128, 194, 255},
1021         {255, 255, 255, 255},
1022         
1023         {255, 255, 255, 255},
1024         {0, 0, 0, 255},
1025         
1026         1,
1027         25, -25
1028 };
1029
1030 static struct uiWidgetColors wcol_regular= {
1031         {25, 25, 25, 255},
1032         {153, 153, 153, 255},
1033         {100, 100, 100, 255},
1034         {25, 25, 25, 255},
1035         
1036         {0, 0, 0, 255},
1037         {255, 255, 255, 255},
1038         
1039         0,
1040         0, 0
1041 };
1042
1043 static struct uiWidgetColors wcol_tool= {
1044         {25, 25, 25, 255},
1045         {153, 153, 153, 255},
1046         {100, 100, 100, 255},
1047         {25, 25, 25, 255},
1048         
1049         {0, 0, 0, 255},
1050         {255, 255, 255, 255},
1051         
1052         1,
1053         25, -25
1054 };
1055
1056 /* called for theme init (new theme) and versions */
1057 void ui_widget_color_init(ThemeUI *tui)
1058 {
1059
1060         tui->wcol_regular= wcol_regular;
1061         tui->wcol_tool= wcol_tool;
1062         tui->wcol_radio= wcol_radio;
1063         tui->wcol_text= wcol_text;
1064         tui->wcol_option= wcol_option;
1065         tui->wcol_num= wcol_num;
1066         tui->wcol_numslider= wcol_numslider;
1067         tui->wcol_menu= wcol_menu;
1068         tui->wcol_pulldown= wcol_pulldown;
1069         tui->wcol_menu_back= wcol_menu_back;
1070         tui->wcol_menu_item= wcol_menu_item;
1071         
1072         tui->iconfile[0]= 0;
1073 }
1074
1075 /* ************ button callbacks, state ***************** */
1076
1077 /* copy colors from theme, and set changes in it based on state */
1078 static void widget_state(uiWidgetType *wt, int state)
1079 {
1080         wt->wcol= *(wt->wcol_theme);
1081         
1082         if(state & UI_SELECT) {
1083                 if(state & UI_BUT_ANIMATED_KEY)
1084                         QUATCOPY(wt->wcol.inner, wcol_state.inner_key_sel)
1085                 else if(state & UI_BUT_ANIMATED)
1086                         QUATCOPY(wt->wcol.inner, wcol_state.inner_anim_sel)
1087                 else if(state & UI_BUT_DRIVEN)
1088                         QUATCOPY(wt->wcol.inner, wcol_state.inner_driven_sel)
1089                 else
1090                         QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel)
1091
1092                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1093                 
1094                 /* only flip shade if it's not "pushed in" already */
1095                 if(wt->wcol.shaded && wt->wcol.shadetop>wt->wcol.shadedown) {
1096                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1097                 }
1098         }
1099         else {
1100                 if(state & UI_BUT_ANIMATED_KEY)
1101                         QUATCOPY(wt->wcol.inner, wcol_state.inner_key)
1102                 else if(state & UI_BUT_ANIMATED)
1103                         QUATCOPY(wt->wcol.inner, wcol_state.inner_anim)
1104                 else if(state & UI_BUT_DRIVEN)
1105                         QUATCOPY(wt->wcol.inner, wcol_state.inner_driven)
1106
1107                 if(state & UI_ACTIVE) { /* mouse over? */
1108                         wt->wcol.inner[0]= wt->wcol.inner[0]>=240? 255 : wt->wcol.inner[0]+15;
1109                         wt->wcol.inner[1]= wt->wcol.inner[1]>=240? 255 : wt->wcol.inner[1]+15;
1110                         wt->wcol.inner[2]= wt->wcol.inner[2]>=240? 255 : wt->wcol.inner[2]+15;
1111                 }
1112         }
1113 }
1114
1115 /* labels use theme colors for text */
1116 static void widget_state_label(uiWidgetType *wt, int state)
1117 {
1118         /* call this for option button */
1119         widget_state(wt, state);
1120
1121         if(state & UI_SELECT)
1122                 UI_GetThemeColor4ubv(TH_TEXT_HI, wt->wcol.text);
1123         else
1124                 UI_GetThemeColor4ubv(TH_TEXT, wt->wcol.text);
1125         
1126 }
1127
1128
1129 /* special case, button that calls pulldown */
1130 static void widget_state_pulldown(uiWidgetType *wt, int state)
1131 {
1132         wt->wcol= *(wt->wcol_theme);
1133         
1134         QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1135         VECCOPY(wt->wcol.outline, wt->wcol.inner);
1136
1137         if(state & UI_ACTIVE)
1138                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1139 }
1140
1141 /* special case, menu items */
1142 static void widget_state_menu_item(uiWidgetType *wt, int state)
1143 {
1144         wt->wcol= *(wt->wcol_theme);
1145         
1146         if(state & UI_BUT_DISABLED) {
1147                 wt->wcol.text[0]= 0.5f*(wt->wcol.text[0]+wt->wcol.text_sel[0]);
1148                 wt->wcol.text[1]= 0.5f*(wt->wcol.text[1]+wt->wcol.text_sel[1]);
1149                 wt->wcol.text[2]= 0.5f*(wt->wcol.text[2]+wt->wcol.text_sel[2]);
1150         }
1151         else if(state & UI_ACTIVE) {
1152                 QUATCOPY(wt->wcol.inner, wt->wcol.inner_sel);
1153                 VECCOPY(wt->wcol.text, wt->wcol.text_sel);
1154                 
1155                 wt->wcol.shaded= 1;
1156         }
1157 }
1158
1159
1160 /* ************ menu backdrop ************************* */
1161
1162 /* outside of rect, rad to left/bottom/right */
1163 static void widget_softshadow(rcti *rect, int roundboxalign, float radin, float radout)
1164 {
1165         uiWidgetBase wtb;
1166         rcti rect1= *rect;
1167         float alpha, alphastep;
1168         int step, tot, a;
1169         
1170         /* prevent tooltips to not show round shadow */
1171         if( 2.0f*radout > 0.2f*(rect1.ymax-rect1.ymin) )
1172                 rect1.ymax -= 0.2f*(rect1.ymax-rect1.ymin);
1173         else
1174                 rect1.ymax -= 2.0f*radout;
1175         
1176         /* inner part */
1177         tot= round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & 12, 0.0f);
1178         
1179         /* inverse linear shadow alpha */
1180         alpha= 0.15;
1181         alphastep= 0.67;
1182         
1183         for(step= 1; step<=radout; step++, alpha*=alphastep) {
1184                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, 15, (float)step);
1185                 
1186                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
1187                 
1188                 glBegin(GL_QUAD_STRIP);
1189                 for(a=0; a<tot; a++) {
1190                         glVertex2fv(wtb.outer_v[a]);
1191                         glVertex2fv(wtb.inner_v[a]);
1192                 }
1193                 glEnd();
1194         }
1195         
1196 }
1197
1198 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1199 {
1200         uiWidgetBase wtb;
1201         int roundboxalign= 15;
1202         
1203         widget_init(&wtb);
1204         
1205         /* menu is 2nd level or deeper */
1206         if (flag & UI_BLOCK_POPUP) {
1207                 rect->ymin -= 4.0;
1208                 rect->ymax += 4.0;
1209         }
1210         else if (direction == UI_DOWN) {
1211                 roundboxalign= 12;
1212                 rect->ymin -= 4.0;
1213         } 
1214         else if (direction == UI_TOP) {
1215                 roundboxalign= 3;
1216                 rect->ymax += 4.0;
1217         }
1218         
1219         glEnable(GL_BLEND);
1220         widget_softshadow(rect, roundboxalign, 5.0f, 8.0f);
1221         
1222         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
1223         wtb.emboss= 0;
1224         widgetbase_draw(&wtb, wcol);
1225         
1226         glDisable(GL_BLEND);
1227 }
1228
1229 /* ************ custom buttons, old stuff ************** */
1230
1231 /* draws in resolution of 20x4 colors */
1232 static void ui_draw_but_HSVCUBE(uiBut *but, rcti *rect)
1233 {
1234         int a;
1235         float h,s,v;
1236         float dx, dy, sx1, sx2, sy, x, y;
1237         float col0[4][3];       // left half, rect bottom to top
1238         float col1[4][3];       // right half, rect bottom to top
1239         
1240         h= but->hsv[0];
1241         s= but->hsv[1];
1242         v= but->hsv[2];
1243         
1244         /* draw series of gouraud rects */
1245         glShadeModel(GL_SMOOTH);
1246         
1247         if(but->a1==0) {        // H and V vary
1248                 hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1249                 hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1250                 hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1251                 hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1252                 x= h; y= v;
1253         }
1254         else if(but->a1==1) {   // H and S vary
1255                 hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1256                 hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1257                 hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1258                 hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1259                 x= h; y= s;
1260         }
1261         else if(but->a1==2) {   // S and V vary
1262                 hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1263                 hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
1264                 hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
1265                 hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1266                 x= v; y= s;
1267         }
1268         else {          // only hue slider
1269                 hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1270                 VECCOPY(col1[1], col1[0]);
1271                 VECCOPY(col1[2], col1[0]);
1272                 VECCOPY(col1[3], col1[0]);
1273                 x= h; y= 0.5;
1274         }
1275         
1276         for(dx=0.0; dx<1.0; dx+= 0.05) {
1277                 // previous color
1278                 VECCOPY(col0[0], col1[0]);
1279                 VECCOPY(col0[1], col1[1]);
1280                 VECCOPY(col0[2], col1[2]);
1281                 VECCOPY(col0[3], col1[3]);
1282                 
1283                 // new color
1284                 if(but->a1==0) {        // H and V vary
1285                         hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1286                         hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1287                         hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1288                         hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1289                 }
1290                 else if(but->a1==1) {   // H and S vary
1291                         hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1292                         hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1293                         hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1294                         hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1295                 }
1296                 else if(but->a1==2) {   // S and V vary
1297                         hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
1298                         hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
1299                         hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
1300                         hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
1301                 }
1302                 else {  // only H
1303                         hsv_to_rgb(dx, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1304                         VECCOPY(col1[1], col1[0]);
1305                         VECCOPY(col1[2], col1[0]);
1306                         VECCOPY(col1[3], col1[0]);
1307                 }
1308                 
1309                 // rect
1310                 sx1= rect->xmin + dx*(rect->xmax-rect->xmin);
1311                 sx2= rect->xmin + (dx+0.05)*(rect->xmax-rect->xmin);
1312                 sy= rect->ymin;
1313                 dy= (rect->ymax-rect->ymin)/3.0;
1314                 
1315                 glBegin(GL_QUADS);
1316                 for(a=0; a<3; a++, sy+=dy) {
1317                         glColor3fv(col0[a]);
1318                         glVertex2f(sx1, sy);
1319                         
1320                         glColor3fv(col1[a]);
1321                         glVertex2f(sx2, sy);
1322                         
1323                         glColor3fv(col1[a+1]);
1324                         glVertex2f(sx2, sy+dy);
1325                         
1326                         glColor3fv(col0[a+1]);
1327                         glVertex2f(sx1, sy+dy);
1328                 }
1329                 glEnd();
1330         }
1331         
1332         glShadeModel(GL_FLAT);
1333         
1334         /* cursor */
1335         x= rect->xmin + x*(rect->xmax-rect->xmin);
1336         y= rect->ymin + y*(rect->ymax-rect->ymin);
1337         CLAMP(x, rect->xmin+3.0, rect->xmax-3.0);
1338         CLAMP(y, rect->ymin+3.0, rect->ymax-3.0);
1339         
1340         fdrawXORcirc(x, y, 3.1);
1341         
1342         /* outline */
1343         glColor3ub(0,  0,  0);
1344         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
1345 }
1346
1347
1348 /* ************ button callbacks, draw ***************** */
1349
1350 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1351 {
1352         uiWidgetBase wtb;
1353         
1354         widget_init(&wtb);
1355         
1356         /* fully rounded */
1357         round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1358         
1359         /* decoration */
1360         if(!(state & UI_TEXTINPUT)) {
1361                 widget_num_tria(&wtb.tria1, rect, 0.6f, 0);
1362                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
1363         }       
1364         widgetbase_draw(&wtb, wcol);
1365         
1366         /* text space */
1367         rect->xmin += (rect->ymax-rect->ymin);
1368         rect->xmax -= (rect->ymax-rect->ymin);
1369
1370 }
1371
1372 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1373 {
1374         uiWidgetBase wtb, wtb1;
1375         rcti rect1;
1376         double value;
1377         float offs, fac;
1378         char outline[3];
1379         
1380         widget_init(&wtb);
1381         widget_init(&wtb1);
1382         
1383         /* backdrop first */
1384         
1385         /* fully rounded */
1386         offs= 0.5f*(rect->ymax - rect->ymin);
1387         round_box_edges(&wtb, roundboxalign, rect, offs);
1388
1389         wtb.outline= 0;
1390         widgetbase_draw(&wtb, wcol);
1391         
1392         /* slider part */
1393         rect1= *rect;
1394         
1395         value= ui_get_but_val(but);
1396         fac= (value-but->softmin)*(rect1.xmax - rect1.xmin - 2.0f*offs)/(but->softmax - but->softmin);
1397         
1398         rect1.xmax= rect1.xmin + fac + 2.0f*offs;
1399         round_box_edges(&wtb1, roundboxalign, &rect1, offs);
1400         
1401         VECCOPY(outline, wcol->outline);
1402         VECCOPY(wcol->outline, wcol->item);
1403         VECCOPY(wcol->inner, wcol->item);
1404         SWAP(short, wcol->shadetop, wcol->shadedown);
1405         
1406         widgetbase_draw(&wtb1, wcol);
1407         VECCOPY(wcol->outline, outline);
1408         SWAP(short, wcol->shadetop, wcol->shadedown);
1409         
1410         /* outline */
1411         wtb.outline= 1;
1412         wtb.inner= 0;
1413         widgetbase_draw(&wtb, wcol);
1414         
1415 }
1416
1417 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1418 {
1419         uiWidgetBase wtb;
1420         float col[4];
1421         
1422         widget_init(&wtb);
1423         
1424         /* half rounded */
1425         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1426                 
1427         ui_get_but_vectorf(but, col);
1428         wcol->inner[0]= FTOCHAR(col[0]);
1429         wcol->inner[1]= FTOCHAR(col[1]);
1430         wcol->inner[2]= FTOCHAR(col[2]);
1431         
1432         widgetbase_draw(&wtb, wcol);
1433         
1434 }
1435
1436
1437 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1438 {
1439         uiWidgetBase wtb;
1440         
1441         widget_init(&wtb);
1442         
1443         /* half rounded */
1444         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1445         
1446         widgetbase_draw(&wtb, wcol);
1447
1448 }
1449
1450
1451 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1452 {
1453         uiWidgetBase wtb;
1454         
1455         widget_init(&wtb);
1456         
1457         /* half rounded */
1458         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1459         
1460         /* decoration */
1461         widget_menu_trias(&wtb.tria1, rect);
1462         
1463         widgetbase_draw(&wtb, wcol);
1464         
1465         /* text space */
1466         rect->xmax -= (rect->ymax-rect->ymin);
1467         
1468 }
1469
1470 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1471 {
1472         if(state & UI_ACTIVE) {
1473                 uiWidgetBase wtb;
1474                 
1475                 widget_init(&wtb);
1476                 
1477                 /* fully rounded */
1478                 round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1479                 
1480                 widgetbase_draw(&wtb, wcol);
1481         }
1482 }
1483
1484 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1485 {
1486         uiWidgetBase wtb;
1487         
1488         widget_init(&wtb);
1489         
1490         /* not rounded, no outline */
1491         wtb.outline= 0;
1492         round_box_edges(&wtb, 0, rect, 0.0f);
1493         
1494         widgetbase_draw(&wtb, wcol);
1495 }
1496
1497
1498 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1499 {
1500         uiWidgetBase wtb;
1501         rcti recttemp= *rect;
1502         int delta;
1503         
1504         widget_init(&wtb);
1505         
1506         /* square */
1507         recttemp.xmax= recttemp.xmin + (recttemp.ymax-recttemp.ymin);
1508         
1509         /* smaller */
1510         delta= 1 + (recttemp.ymax-recttemp.ymin)/8;
1511         recttemp.xmin+= delta;
1512         recttemp.ymin+= delta;
1513         recttemp.xmax-= delta;
1514         recttemp.ymax-= delta;
1515         
1516         /* half rounded */
1517         round_box_edges(&wtb, 15, &recttemp, 4.0f);
1518         
1519         /* decoration */
1520         if(state & UI_SELECT) {
1521                 widget_check_trias(&wtb.tria1, &recttemp);
1522         }
1523         
1524         widgetbase_draw(&wtb, wcol);
1525         
1526         /* text space */
1527         rect->xmin += (rect->ymax-rect->ymin)*0.7 + delta;
1528 }
1529
1530
1531 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1532 {
1533         uiWidgetBase wtb;
1534         
1535         widget_init(&wtb);
1536         
1537         /* half rounded */
1538         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1539         
1540         widgetbase_draw(&wtb, wcol);
1541
1542 }
1543
1544 static void widget_but(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1545 {
1546         uiWidgetBase wtb;
1547         
1548         widget_init(&wtb);
1549         
1550         /* half rounded */
1551         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
1552                 
1553         widgetbase_draw(&wtb, wcol);
1554
1555 }
1556
1557 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
1558 {
1559         uiWidgetBase wtb;
1560         
1561         widget_init(&wtb);
1562         
1563         /* fully rounded */
1564         round_box_edges(&wtb, roundboxalign, rect, 0.5f*(rect->ymax - rect->ymin));
1565
1566         widgetbase_draw(&wtb, wcol);
1567 }
1568
1569 static void widget_disabled(rcti *rect)
1570 {
1571         float col[4];
1572         
1573         glEnable(GL_BLEND);
1574         
1575         /* can't use theme TH_BACK or TH_PANEL... undefined */
1576         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
1577         glColor4f(col[0], col[1], col[2], 0.5f);
1578         glRectf(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1579
1580         glDisable(GL_BLEND);
1581 }
1582
1583 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
1584 {
1585         bTheme *btheme= U.themes.first;
1586         static uiWidgetType wt;
1587         
1588         /* defaults */
1589         wt.wcol_theme= &btheme->tui.wcol_regular;
1590         wt.state= widget_state;
1591         wt.draw= widget_but;
1592         wt.custom= NULL;
1593         wt.text= widget_draw_text_icon;
1594         
1595         switch(type) {
1596                 case UI_WTYPE_LABEL:
1597                         wt.draw= NULL;
1598                         wt.state= widget_state_label;
1599                         break;
1600                         
1601                 case UI_WTYPE_TOGGLE:
1602                         break;
1603                         
1604                 case UI_WTYPE_OPTION:
1605                         wt.wcol_theme= &btheme->tui.wcol_option;
1606                         wt.draw= widget_optionbut;
1607                         wt.state= widget_state_label;
1608                         break;
1609                         
1610                 case UI_WTYPE_RADIO:
1611                         wt.wcol_theme= &btheme->tui.wcol_radio;
1612                         wt.draw= widget_radiobut;
1613                         break;
1614                         
1615                 case UI_WTYPE_NUMBER:
1616                         wt.wcol_theme= &btheme->tui.wcol_num;
1617                         wt.draw= widget_numbut;
1618                         break;
1619                         
1620                 case UI_WTYPE_SLIDER:
1621                         wt.wcol_theme= &btheme->tui.wcol_numslider;
1622                         wt.custom= widget_numslider;
1623                         break;
1624                         
1625                 case UI_WTYPE_EXEC:
1626                         wt.wcol_theme= &btheme->tui.wcol_tool;
1627                         wt.draw= widget_roundbut;
1628                         break;
1629                         
1630                         
1631                         /* strings */
1632                 case UI_WTYPE_NAME:
1633                         wt.wcol_theme= &btheme->tui.wcol_text;
1634                         wt.draw= widget_textbut;
1635                         break;
1636                         
1637                 case UI_WTYPE_NAME_LINK:
1638                         break;
1639                         
1640                 case UI_WTYPE_POINTER_LINK:
1641                         break;
1642                         
1643                 case UI_WTYPE_FILENAME:
1644                         break;
1645                         
1646                         
1647                         /* start menus */
1648                 case UI_WTYPE_MENU_RADIO:
1649                         wt.wcol_theme= &btheme->tui.wcol_menu;
1650                         wt.draw= widget_menubut;
1651                         break;
1652                         
1653                 case UI_WTYPE_MENU_POINTER_LINK:
1654                         wt.wcol_theme= &btheme->tui.wcol_menu;
1655                         wt.draw= widget_menubut;
1656                         break;
1657                         
1658                         
1659                 case UI_WTYPE_PULLDOWN:
1660                         wt.wcol_theme= &btheme->tui.wcol_pulldown;
1661                         wt.draw= widget_pulldownbut;
1662                         wt.state= widget_state_pulldown;
1663                         break;
1664                         
1665                         /* in menus */
1666                 case UI_WTYPE_MENU_ITEM:
1667                         wt.wcol_theme= &btheme->tui.wcol_menu_item;
1668                         wt.draw= widget_menu_itembut;
1669                         wt.state= widget_state_menu_item;
1670                         break;
1671                         
1672                 case UI_WTYPE_MENU_BACK:
1673                         wt.wcol_theme= &btheme->tui.wcol_menu_back;
1674                         wt.draw= widget_menu_back;
1675                         break;
1676                         
1677                         /* specials */
1678                 case UI_WTYPE_ICON:
1679                         wt.draw= NULL;
1680                         break;
1681                         
1682                 case UI_WTYPE_SWATCH:
1683                         wt.custom= widget_swatch;
1684                         break;
1685                         
1686                 case UI_WTYPE_RGB_PICKER:
1687                         break;
1688                         
1689                 case UI_WTYPE_NORMAL:
1690                         break;
1691         }
1692         
1693         return &wt;
1694 }
1695
1696
1697 static int widget_roundbox_set(uiBut *but, rcti *rect)
1698 {
1699         /* alignment */
1700         if(but->flag & UI_BUT_ALIGN) {
1701                 
1702                 if(but->flag & UI_BUT_ALIGN_TOP)
1703                         rect->ymax+= 1;
1704                 if(but->flag & UI_BUT_ALIGN_LEFT)
1705                         rect->xmin-= 1;
1706                 
1707                 switch(but->flag & UI_BUT_ALIGN) {
1708                         case UI_BUT_ALIGN_TOP:
1709                                 return (12);
1710                                 break;
1711                         case UI_BUT_ALIGN_DOWN:
1712                                 return (3);
1713                                 break;
1714                         case UI_BUT_ALIGN_LEFT:
1715                                 return (6);
1716                                 break;
1717                         case UI_BUT_ALIGN_RIGHT:
1718                                 return (9);
1719                                 break;
1720                                 
1721                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
1722                                 return (1);
1723                                 break;
1724                         case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
1725                                 return (2);
1726                                 break;
1727                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
1728                                 return (8);
1729                                 break;
1730                         case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
1731                                 return (4);
1732                                 break;
1733                                 
1734                         default:
1735                                 return (0);
1736                                 break;
1737                 }
1738         } 
1739         return 15;
1740 }
1741
1742 /* conversion from old to new buttons, so still messy */
1743 void ui_draw_but(ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
1744 {
1745         bTheme *btheme= U.themes.first;
1746         ThemeUI *tui= &btheme->tui;
1747         uiFontStyle *fstyle= &style->widget;
1748         uiWidgetType *wt= NULL;
1749         
1750         /* handle menus seperately */
1751         if(but->dt==UI_EMBOSSP) {
1752                 switch (but->type) {
1753                         case LABEL:
1754                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
1755                                 break;
1756                         case SEPR:
1757                                 break;
1758                                 
1759                         default:
1760                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
1761                 }
1762         }
1763         else if(but->dt==UI_EMBOSSN) {
1764                 /* "nothing" */
1765                 wt= widget_type(UI_WTYPE_ICON);
1766         }
1767         else {
1768                 
1769                 switch (but->type) {
1770                         case LABEL:
1771                                 if(but->block->flag & UI_BLOCK_LOOP)
1772                                         widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
1773                                 else {
1774                                         wt= widget_type(UI_WTYPE_LABEL);
1775                                         fstyle= &style->widgetlabel;
1776                                 }
1777                                 break;
1778                         case SEPR:
1779                                 break;
1780                         case BUT:
1781                                 wt= widget_type(UI_WTYPE_EXEC);
1782                                 break;
1783                         case NUM:
1784                                 wt= widget_type(UI_WTYPE_NUMBER);
1785                                 break;
1786                         case NUMSLI:
1787                         case HSVSLI:
1788                                 wt= widget_type(UI_WTYPE_SLIDER);
1789                                 break;
1790                         case ROW:
1791                                 wt= widget_type(UI_WTYPE_RADIO);
1792                                 break;
1793                         case TEX:
1794                                 wt= widget_type(UI_WTYPE_NAME);
1795                                 break;
1796                         case TOGBUT:
1797                                 wt= widget_type(UI_WTYPE_TOGGLE);
1798                                 break;
1799                         case TOG:
1800                         case TOGN:
1801                         case TOG3:
1802                                 if (!(but->flag & UI_HAS_ICON)) {
1803                                         wt= widget_type(UI_WTYPE_OPTION);
1804                                         but->flag |= UI_TEXT_LEFT;
1805                                 }
1806                                 else
1807                                         wt= widget_type(UI_WTYPE_TOGGLE);
1808                                 break;
1809                         case MENU:
1810                         case BLOCK:
1811                         case ICONTEXTROW:
1812                                 wt= widget_type(UI_WTYPE_MENU_RADIO);
1813                                 break;
1814                                 
1815                         case PULLDOWN:
1816                         case HMENU:
1817                                 wt= widget_type(UI_WTYPE_PULLDOWN);
1818                                 break;
1819                         
1820                         case BUTM:
1821                                 wt= widget_type(UI_WTYPE_MENU_ITEM);
1822                                 break;
1823                                 
1824                         case COL:
1825                                 wt= widget_type(UI_WTYPE_SWATCH);
1826                                 break;
1827                         
1828                                  // XXX four old button types
1829                         case HSVCUBE:
1830                                 ui_draw_but_HSVCUBE(but, rect);
1831                                 break;
1832                         case BUT_COLORBAND:
1833                                 ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
1834                                 break;
1835                         case BUT_NORMAL:
1836                                 ui_draw_but_NORMAL(but, &tui->wcol_regular, rect);
1837                                 break;
1838                         case BUT_CURVE:
1839                                 ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
1840                                 break;
1841                                 
1842                         default:
1843                                 wt= widget_type(UI_WTYPE_TOGGLE);
1844                 }
1845         }
1846         
1847         if(wt) {
1848                 rcti disablerect= *rect; /* rect gets clipped smaller for text */
1849                 int roundboxalign, state;
1850                 
1851                 roundboxalign= widget_roundbox_set(but, rect);
1852                 state= but->flag;
1853                 if(but->editstr) state |= UI_TEXTINPUT;
1854                 
1855                 wt->state(wt, state);
1856                 if(wt->custom)
1857                         wt->custom(but, &wt->wcol, rect, state, roundboxalign);
1858                 else if(wt->draw)
1859                         wt->draw(&wt->wcol, rect, state, roundboxalign);
1860                 wt->text(fstyle, &wt->wcol, but, rect);
1861                 
1862                 if(state & UI_BUT_DISABLED)
1863                         if(but->dt!=UI_EMBOSSP)
1864                                 widget_disabled(&disablerect);
1865         }
1866 }
1867
1868 void ui_draw_menu_back(uiStyle *style, uiBlock *block, rcti *rect)
1869 {
1870         uiWidgetType *wt= widget_type(UI_WTYPE_MENU_BACK);
1871         
1872         wt->state(wt, 0);
1873         if(block)
1874                 wt->draw(&wt->wcol, rect, block->flag, block->direction);
1875         else
1876                 wt->draw(&wt->wcol, rect, 0, 0);
1877         
1878 }
1879
1880