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