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