svn merge ^/trunk/blender -r46930:HEAD
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/interface/interface_widgets.c
27  *  \ingroup edinterface
28  */
29
30
31 #include <limits.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35
36
37 #include "DNA_screen_types.h"
38 #include "DNA_userdef_types.h"
39
40 #include "BLI_math.h"
41 #include "BLI_listbase.h"
42 #include "BLI_rect.h"
43 #include "BLI_string.h"
44 #include "BLI_string_utf8.h"
45 #include "BLI_utildefines.h"
46
47 #include "BKE_context.h"
48 #include "BKE_curve.h"
49 #include "BKE_utildefines.h"
50
51 #include "RNA_access.h"
52
53 #include "BIF_gl.h"
54 #include "BIF_glutil.h"
55
56 #include "BLF_api.h"
57
58 #include "UI_interface.h"
59 #include "UI_interface_icons.h"
60
61
62 #include "interface_intern.h"
63
64 /* ************** widget base functions ************** */
65 /*
66  * - in: roundbox codes for corner types and radius
67  * - return: array of [size][2][x,y] points, the edges of the roundbox, + UV coords
68  *
69  * - draw black box with alpha 0 on exact button boundbox
70  * - for ever AA step:
71  *    - draw the inner part for a round filled box, with color blend codes or texture coords
72  *    - draw outline in outline color
73  *    - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
74  *    - draw extra decorations
75  * - draw background color box with alpha 1 on exact button boundbox
76  */
77
78 /* fill this struct with polygon info to draw AA'ed */
79 /* it has outline, back, and two optional tria meshes */
80
81 typedef struct uiWidgetTrias {
82         unsigned int tot;
83         
84         float vec[32][2];
85         unsigned int (*index)[3];
86         
87 } uiWidgetTrias;
88
89 /* max as used by round_box__edges */
90 #define WIDGET_CURVE_RESOLU 9
91 #define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
92
93 typedef struct uiWidgetBase {
94         
95         int totvert, halfwayvert;
96         float outer_v[WIDGET_SIZE_MAX][2];
97         float inner_v[WIDGET_SIZE_MAX][2];
98         float inner_uv[WIDGET_SIZE_MAX][2];
99         
100         short inner, outline, emboss; /* set on/off */
101         short shadedir;
102         
103         uiWidgetTrias tria1;
104         uiWidgetTrias tria2;
105         
106 } uiWidgetBase;
107
108 /* uiWidgetType: for time being only for visual appearance,
109  * later, a handling callback can be added too 
110  */
111 typedef struct uiWidgetType {
112         
113         /* pointer to theme color definition */
114         uiWidgetColors *wcol_theme;
115         uiWidgetStateColors *wcol_state;
116         
117         /* converted colors for state */
118         uiWidgetColors wcol;
119         
120         void (*state)(struct uiWidgetType *, int state);
121         void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
122         void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
123         void (*text)(uiFontStyle *, uiWidgetColors *, uiBut *, rcti *);
124         
125 } uiWidgetType;
126
127
128 /* *********************** draw data ************************** */
129
130 static float cornervec[WIDGET_CURVE_RESOLU][2] = {
131         {0.0, 0.0}, {0.195, 0.02}, {0.383, 0.067},
132         {0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45},
133         {0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0}
134 };
135
136 #define WIDGET_AA_JITTER 8
137 static float jit[WIDGET_AA_JITTER][2] = {
138         { 0.468813, -0.481430}, {-0.155755, -0.352820},
139         { 0.219306, -0.238501}, {-0.393286, -0.110949},
140         {-0.024699,  0.013908}, { 0.343805,  0.147431},
141         {-0.272855,  0.269918}, { 0.095909,  0.388710}
142 };
143
144 static float num_tria_vert[3][2] = {
145         {-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}
146 };
147
148 static unsigned int num_tria_face[1][3] = {
149         {0, 1, 2}
150 };
151
152 static float scroll_circle_vert[16][2] = {
153         {0.382684, 0.923879}, {0.000001, 1.000000}, {-0.382683, 0.923880}, {-0.707107, 0.707107},
154         {-0.923879, 0.382684}, {-1.000000, 0.000000}, {-0.923880, -0.382684}, {-0.707107, -0.707107},
155         {-0.382683, -0.923880}, {0.000000, -1.000000}, {0.382684, -0.923880}, {0.707107, -0.707107},
156         {0.923880, -0.382684}, {1.000000, -0.000000}, {0.923880, 0.382683}, {0.707107, 0.707107}
157 };
158
159 static unsigned int scroll_circle_face[14][3] = {
160         {0, 1, 2}, {2, 0, 3}, {3, 0, 15}, {3, 15, 4}, {4, 15, 14}, {4, 14, 5}, {5, 14, 13}, {5, 13, 6},
161         {6, 13, 12}, {6, 12, 7}, {7, 12, 11}, {7, 11, 8}, {8, 11, 10}, {8, 10, 9}
162 };
163
164
165 static float menu_tria_vert[6][2]= {
166 {-0.33, 0.16}, {0.33, 0.16}, {0, 0.82}, 
167 {0, -0.82}, {-0.33, -0.16}, {0.33, -0.16}};
168
169
170
171 static unsigned int menu_tria_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
172
173 static float check_tria_vert[6][2] = {
174         {-0.578579, 0.253369},  {-0.392773, 0.412794},  {-0.004241, -0.328551},
175         {-0.003001, 0.034320},  {1.055313, 0.864744},   {0.866408, 1.026895}
176 };
177
178 static unsigned int check_tria_face[4][3] = {
179         {3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
180 };
181
182 GLubyte checker_stipple_sml[32 * 32 / 8] =
183 {
184         255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
185         255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
186         0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
187         0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
188         255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
189         255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
190         0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
191         0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
192 };
193
194 /* ************************************************* */
195
196 void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
197 {
198         float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
199         float color[4];
200         int j;
201         
202         glEnable(GL_BLEND);
203         glGetFloatv(GL_CURRENT_COLOR, color);
204         color[3] *= 0.125f;
205         glColor4fv(color);
206
207         glEnableClientState(GL_VERTEX_ARRAY);
208         glVertexPointer(2, GL_FLOAT, 0, tri_arr);
209
210         /* for each AA step */
211         for (j = 0; j < WIDGET_AA_JITTER; j++) {
212                 glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
213                 glDrawArrays(GL_TRIANGLES, 0, 3);
214                 glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
215         }
216
217         glDisableClientState(GL_VERTEX_ARRAY);
218         glDisable(GL_BLEND);
219 }
220
221 void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad)
222 {
223         float color[4];
224         int j;
225         
226         glEnable(GL_BLEND);
227         glGetFloatv(GL_CURRENT_COLOR, color);
228         color[3] *= 0.125f;
229         glColor4fv(color);
230         
231         for (j = 0; j < WIDGET_AA_JITTER; j++) {
232                 glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
233                 uiDrawBox(mode, minx, miny, maxx, maxy, rad);
234                 glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
235         }
236
237         glDisable(GL_BLEND);
238 }
239
240 static void widget_init(uiWidgetBase *wtb)
241 {
242         wtb->totvert = wtb->halfwayvert = 0;
243         wtb->tria1.tot = 0;
244         wtb->tria2.tot = 0;
245
246         wtb->inner = 1;
247         wtb->outline = 1;
248         wtb->emboss = 1;
249         wtb->shadedir = 1;
250 }
251
252 /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
253 /* return tot */
254 static int round_box_shadow_edges(float (*vert)[2], rcti *rect, float rad, int roundboxalign, float step)
255 {
256         float vec[WIDGET_CURVE_RESOLU][2];
257         float minx, miny, maxx, maxy;
258         int a, tot = 0;
259         
260         rad += step;
261         
262         if (2.0f * rad > rect->ymax - rect->ymin)
263                 rad = 0.5f * (rect->ymax - rect->ymin);
264         
265         minx = rect->xmin - step;
266         miny = rect->ymin - step;
267         maxx = rect->xmax + step;
268         maxy = rect->ymax + step;
269         
270         /* mult */
271         for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
272                 vec[a][0] = rad * cornervec[a][0];
273                 vec[a][1] = rad * cornervec[a][1];
274         }
275         
276         /* start with left-top, anti clockwise */
277         if (roundboxalign & UI_CNR_TOP_LEFT) {
278                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
279                         vert[tot][0] = minx + rad - vec[a][0];
280                         vert[tot][1] = maxy - vec[a][1];
281                 }
282         }
283         else {
284                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
285                         vert[tot][0] = minx;
286                         vert[tot][1] = maxy;
287                 }
288         }
289         
290         if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
291                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
292                         vert[tot][0] = minx + vec[a][1];
293                         vert[tot][1] = miny + rad - vec[a][0];
294                 }
295         }
296         else {
297                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
298                         vert[tot][0] = minx;
299                         vert[tot][1] = miny;
300                 }
301         }
302         
303         if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
304                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
305                         vert[tot][0] = maxx - rad + vec[a][0];
306                         vert[tot][1] = miny + vec[a][1];
307                 }
308         }
309         else {
310                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
311                         vert[tot][0] = maxx;
312                         vert[tot][1] = miny;
313                 }
314         }
315         
316         if (roundboxalign & UI_CNR_TOP_RIGHT) {
317                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
318                         vert[tot][0] = maxx - vec[a][1];
319                         vert[tot][1] = maxy - rad + vec[a][0];
320                 }
321         }
322         else {
323                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
324                         vert[tot][0] = maxx;
325                         vert[tot][1] = maxy;
326                 }
327         }
328         return tot;
329 }
330
331 /* this call has 1 extra arg to allow mask outline */
332 static void round_box__edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, float rad, float radi)
333 {
334         float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
335         float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
336         float minxi = minx + 1.0f; /* boundbox inner */
337         float maxxi = maxx - 1.0f;
338         float minyi = miny + 1.0f;
339         float maxyi = maxy - 1.0f;
340         float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f; /* for uv, can divide by zero */
341         float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
342         int a, tot = 0, minsize;
343         const int hnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT)) == (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT) ||
344                           (roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) ? 1 : 2;
345         const int vnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) ||
346                           (roundboxalign & (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) == (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) ? 1 : 2;
347
348         minsize = MIN2((rect->xmax - rect->xmin) * hnum, (rect->ymax - rect->ymin) * vnum);
349         
350         if (2.0f * rad > minsize)
351                 rad = 0.5f * minsize;
352
353         if (2.0f * (radi + 1.0f) > minsize)
354                 radi = 0.5f * minsize - 1.0f;
355         
356         /* mult */
357         for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
358                 veci[a][0] = radi * cornervec[a][0];
359                 veci[a][1] = radi * cornervec[a][1];
360                 vec[a][0] = rad * cornervec[a][0];
361                 vec[a][1] = rad * cornervec[a][1];
362         }
363         
364         /* corner left-bottom */
365         if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
366                 
367                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
368                         wt->inner_v[tot][0] = minxi + veci[a][1];
369                         wt->inner_v[tot][1] = minyi + radi - veci[a][0];
370                         
371                         wt->outer_v[tot][0] = minx + vec[a][1];
372                         wt->outer_v[tot][1] = miny + rad - vec[a][0];
373                         
374                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
375                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
376                 }
377         }
378         else {
379                 wt->inner_v[tot][0] = minxi;
380                 wt->inner_v[tot][1] = minyi;
381                 
382                 wt->outer_v[tot][0] = minx;
383                 wt->outer_v[tot][1] = miny;
384
385                 wt->inner_uv[tot][0] = 0.0f;
386                 wt->inner_uv[tot][1] = 0.0f;
387                 
388                 tot++;
389         }
390         
391         /* corner right-bottom */
392         if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
393                 
394                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
395                         wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
396                         wt->inner_v[tot][1] = minyi + veci[a][1];
397                         
398                         wt->outer_v[tot][0] = maxx - rad + vec[a][0];
399                         wt->outer_v[tot][1] = miny + vec[a][1];
400                         
401                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
402                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
403                 }
404         }
405         else {
406                 wt->inner_v[tot][0] = maxxi;
407                 wt->inner_v[tot][1] = minyi;
408                 
409                 wt->outer_v[tot][0] = maxx;
410                 wt->outer_v[tot][1] = miny;
411
412                 wt->inner_uv[tot][0] = 1.0f;
413                 wt->inner_uv[tot][1] = 0.0f;
414                 
415                 tot++;
416         }
417         
418         wt->halfwayvert = tot;
419         
420         /* corner right-top */
421         if (roundboxalign & UI_CNR_TOP_RIGHT) {
422                 
423                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
424                         wt->inner_v[tot][0] = maxxi - veci[a][1];
425                         wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
426                         
427                         wt->outer_v[tot][0] = maxx - vec[a][1];
428                         wt->outer_v[tot][1] = maxy - rad + vec[a][0];
429                         
430                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
431                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
432                 }
433         }
434         else {
435                 wt->inner_v[tot][0] = maxxi;
436                 wt->inner_v[tot][1] = maxyi;
437                 
438                 wt->outer_v[tot][0] = maxx;
439                 wt->outer_v[tot][1] = maxy;
440                 
441                 wt->inner_uv[tot][0] = 1.0f;
442                 wt->inner_uv[tot][1] = 1.0f;
443                 
444                 tot++;
445         }
446         
447         /* corner left-top */
448         if (roundboxalign & UI_CNR_TOP_LEFT) {
449                 
450                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
451                         wt->inner_v[tot][0] = minxi + radi - veci[a][0];
452                         wt->inner_v[tot][1] = maxyi - veci[a][1];
453                         
454                         wt->outer_v[tot][0] = minx + rad - vec[a][0];
455                         wt->outer_v[tot][1] = maxy - vec[a][1];
456                         
457                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
458                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
459                 }
460                 
461         }
462         else {
463                 
464                 wt->inner_v[tot][0] = minxi;
465                 wt->inner_v[tot][1] = maxyi;
466                 
467                 wt->outer_v[tot][0] = minx;
468                 wt->outer_v[tot][1] = maxy;
469                 
470                 wt->inner_uv[tot][0] = 0.0f;
471                 wt->inner_uv[tot][1] = 1.0f;
472                 
473                 tot++;
474         }
475
476         BLI_assert(tot <= WIDGET_SIZE_MAX);
477
478         wt->totvert = tot;
479 }
480
481 static void round_box_edges(uiWidgetBase *wt, int roundboxalign, rcti *rect, float rad)
482 {
483         round_box__edges(wt, roundboxalign, rect, rad, rad - 1.0f);
484 }
485
486
487 /* based on button rect, return scaled array of triangles */
488 static void widget_num_tria(uiWidgetTrias *tria, rcti *rect, float triasize, char where)
489 {
490         float centx, centy, sizex, sizey, minsize;
491         int a, i1 = 0, i2 = 1;
492         
493         minsize = MIN2(rect->xmax - rect->xmin, rect->ymax - rect->ymin);
494         
495         /* center position and size */
496         centx = (float)rect->xmin + 0.5f * minsize;
497         centy = (float)rect->ymin + 0.5f * minsize;
498         sizex = sizey = -0.5f * triasize * minsize;
499
500         if (where == 'r') {
501                 centx = (float)rect->xmax - 0.5f * minsize;
502                 sizex = -sizex;
503         }       
504         else if (where == 't') {
505                 centy = (float)rect->ymax - 0.5f * minsize;
506                 sizey = -sizey;
507                 i2 = 0; i1 = 1;
508         }       
509         else if (where == 'b') {
510                 sizex = -sizex;
511                 i2 = 0; i1 = 1;
512         }       
513         
514         for (a = 0; a < 3; a++) {
515                 tria->vec[a][0] = sizex * num_tria_vert[a][i1] + centx;
516                 tria->vec[a][1] = sizey * num_tria_vert[a][i2] + centy;
517         }
518         
519         tria->tot = 1;
520         tria->index = num_tria_face;
521 }
522
523 static void widget_scroll_circle(uiWidgetTrias *tria, rcti *rect, float triasize, char where)
524 {
525         float centx, centy, sizex, sizey, minsize;
526         int a, i1 = 0, i2 = 1;
527         
528         minsize = MIN2(rect->xmax - rect->xmin, rect->ymax - rect->ymin);
529         
530         /* center position and size */
531         centx = (float)rect->xmin + 0.5f * minsize;
532         centy = (float)rect->ymin + 0.5f * minsize;
533         sizex = sizey = -0.5f * triasize * minsize;
534
535         if (where == 'r') {
536                 centx = (float)rect->xmax - 0.5f * minsize;
537                 sizex = -sizex;
538         }       
539         else if (where == 't') {
540                 centy = (float)rect->ymax - 0.5f * minsize;
541                 sizey = -sizey;
542                 i2 = 0; i1 = 1;
543         }       
544         else if (where == 'b') {
545                 sizex = -sizex;
546                 i2 = 0; i1 = 1;
547         }       
548         
549         for (a = 0; a < 16; a++) {
550                 tria->vec[a][0] = sizex * scroll_circle_vert[a][i1] + centx;
551                 tria->vec[a][1] = sizey * scroll_circle_vert[a][i2] + centy;
552         }
553         
554         tria->tot = 14;
555         tria->index = scroll_circle_face;
556 }
557
558 static void widget_trias_draw(uiWidgetTrias *tria)
559 {
560         glEnableClientState(GL_VERTEX_ARRAY);
561         glVertexPointer(2, GL_FLOAT, 0, tria->vec);
562         glDrawElements(GL_TRIANGLES, tria->tot * 3, GL_UNSIGNED_INT, tria->index);
563         glDisableClientState(GL_VERTEX_ARRAY);
564 }
565
566 static void widget_menu_trias(uiWidgetTrias *tria, rcti *rect)
567 {
568         float centx, centy, size, asp;
569         int a;
570                 
571         /* center position and size */
572         centx = rect->xmax - 0.5f * (rect->ymax - rect->ymin);
573         centy = rect->ymin + 0.5f * (rect->ymax - rect->ymin);
574         size = 0.4f * (rect->ymax - rect->ymin);
575         
576         /* XXX exception */
577         asp = ((float)rect->xmax - rect->xmin) / ((float)rect->ymax - rect->ymin);
578         if (asp > 1.2f && asp < 2.6f)
579                 centx = rect->xmax - 0.3f * (rect->ymax - rect->ymin);
580         
581         for (a = 0; a < 6; a++) {
582                 tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
583                 tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
584         }
585
586         tria->tot = 2;
587         tria->index = menu_tria_face;
588 }
589
590 static void widget_check_trias(uiWidgetTrias *tria, rcti *rect)
591 {
592         float centx, centy, size;
593         int a;
594         
595         /* center position and size */
596         centx = rect->xmin + 0.5f * (rect->ymax - rect->ymin);
597         centy = rect->ymin + 0.5f * (rect->ymax - rect->ymin);
598         size = 0.5f * (rect->ymax - rect->ymin);
599         
600         for (a = 0; a < 6; a++) {
601                 tria->vec[a][0] = size * check_tria_vert[a][0] + centx;
602                 tria->vec[a][1] = size * check_tria_vert[a][1] + centy;
603         }
604         
605         tria->tot = 4;
606         tria->index = check_tria_face;
607 }
608
609
610 /* prepares shade colors */
611 static void shadecolors4(char coltop[4], char *coldown, const char *color, short shadetop, short shadedown)
612 {
613         
614         coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
615         coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
616         coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
617         coltop[3] = color[3];
618
619         coldown[0] = CLAMPIS(color[0] + shadedown, 0, 255);
620         coldown[1] = CLAMPIS(color[1] + shadedown, 0, 255);
621         coldown[2] = CLAMPIS(color[2] + shadedown, 0, 255);
622         coldown[3] = color[3];
623 }
624
625 static void round_box_shade_col4_r(unsigned char col_r[4], const char col1[4], const char col2[4], const float fac)
626 {
627         const int faci = FTOCHAR(fac);
628         const int facm = 255 - faci;
629
630         col_r[0] = (faci * col1[0] + facm * col2[0]) >> 8;
631         col_r[1] = (faci * col1[1] + facm * col2[1]) >> 8;
632         col_r[2] = (faci * col1[2] + facm * col2[2]) >> 8;
633         col_r[3] = (faci * col1[3] + facm * col2[3]) >> 8;
634 }
635
636 static void widget_verts_to_quad_strip(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2])
637 {
638         int a;
639         for (a = 0; a < totvert; a++) {
640                 copy_v2_v2(quad_strip[a * 2], wtb->outer_v[a]);
641                 copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[a]);
642         }
643         copy_v2_v2(quad_strip[a * 2], wtb->outer_v[0]);
644         copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[0]);
645 }
646
647 static void widget_verts_to_quad_strip_open(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2][2])
648 {
649         int a;
650         for (a = 0; a < totvert; a++) {
651                 quad_strip[a * 2][0] = wtb->outer_v[a][0];
652                 quad_strip[a * 2][1] = wtb->outer_v[a][1];
653                 quad_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
654                 quad_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
655         }
656 }
657
658 static void widgetbase_outline(uiWidgetBase *wtb)
659 {
660         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
661         widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
662
663         glEnableClientState(GL_VERTEX_ARRAY);
664         glVertexPointer(2, GL_FLOAT, 0, quad_strip);
665         glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
666         glDisableClientState(GL_VERTEX_ARRAY);
667 }
668
669 static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
670 {
671         int j, a;
672         
673         glEnable(GL_BLEND);
674
675         /* backdrop non AA */
676         if (wtb->inner) {
677                 if (wcol->shaded == 0) {
678                         if (wcol->alpha_check) {
679                                 float inner_v_half[WIDGET_SIZE_MAX][2];
680                                 float x_mid = 0.0f; /* used for dumb clamping of values */
681
682                                 /* dark checkers */
683                                 glColor4ub(UI_TRANSP_DARK, UI_TRANSP_DARK, UI_TRANSP_DARK, 255);
684                                 glEnableClientState(GL_VERTEX_ARRAY);
685                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
686                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
687                                 glDisableClientState(GL_VERTEX_ARRAY);
688
689                                 /* light checkers */
690                                 glEnable(GL_POLYGON_STIPPLE);
691                                 glColor4ub(UI_TRANSP_LIGHT, UI_TRANSP_LIGHT, UI_TRANSP_LIGHT, 255);
692                                 glPolygonStipple(checker_stipple_sml);
693
694                                 glEnableClientState(GL_VERTEX_ARRAY);
695                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
696                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
697                                 glDisableClientState(GL_VERTEX_ARRAY);
698
699                                 glDisable(GL_POLYGON_STIPPLE);
700
701                                 /* alpha fill */
702                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
703
704                                 glColor4ubv((unsigned char *)wcol->inner);
705                                 glEnableClientState(GL_VERTEX_ARRAY);
706
707                                 for (a = 0; a < wtb->totvert; a++) {
708                                         x_mid += wtb->inner_v[a][0];
709                                 }
710                                 x_mid /= wtb->totvert;
711
712                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
713                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
714                                 glDisableClientState(GL_VERTEX_ARRAY);
715
716                                 /* 1/2 solid color */
717                                 glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255);
718
719                                 for (a = 0; a < wtb->totvert; a++) {
720                                         inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid);
721                                         inner_v_half[a][1] = wtb->inner_v[a][1];
722                                 }
723
724                                 glEnableClientState(GL_VERTEX_ARRAY);
725                                 glVertexPointer(2, GL_FLOAT, 0, inner_v_half);
726                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
727                                 glDisableClientState(GL_VERTEX_ARRAY);
728                         }
729                         else {
730                                 /* simple fill */
731                                 glColor4ubv((unsigned char *)wcol->inner);
732
733                                 glEnableClientState(GL_VERTEX_ARRAY);
734                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
735                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
736                                 glDisableClientState(GL_VERTEX_ARRAY);
737                         }
738                 }
739                 else {
740                         char col1[4], col2[4];
741                         unsigned char col_array[WIDGET_SIZE_MAX * 4];
742                         unsigned char *col_pt = col_array;
743                         
744                         shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
745                         
746                         glShadeModel(GL_SMOOTH);
747                         for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
748                                 round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]);
749                         }
750
751                         glEnableClientState(GL_VERTEX_ARRAY);
752                         glEnableClientState(GL_COLOR_ARRAY);
753                         glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
754                         glColorPointer(4, GL_UNSIGNED_BYTE, 0, col_array);
755                         glDrawArrays(GL_POLYGON, 0, wtb->totvert);
756                         glDisableClientState(GL_VERTEX_ARRAY);
757                         glDisableClientState(GL_COLOR_ARRAY);
758
759                         glShadeModel(GL_FLAT);
760                 }
761         }
762         
763         /* for each AA step */
764         if (wtb->outline) {
765                 float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
766                 float quad_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
767
768                 const unsigned char tcol[4] = {wcol->outline[0],
769                                                wcol->outline[1],
770                                                wcol->outline[2],
771                                                UCHAR_MAX / WIDGET_AA_JITTER};
772
773                 widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
774
775                 if (wtb->emboss) {
776                         widget_verts_to_quad_strip_open(wtb, wtb->halfwayvert, quad_strip_emboss);
777                 }
778
779                 glEnableClientState(GL_VERTEX_ARRAY);
780
781                 for (j = 0; j < WIDGET_AA_JITTER; j++) {
782                         glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
783                         
784                         /* outline */
785                         glColor4ubv(tcol);
786
787                         glVertexPointer(2, GL_FLOAT, 0, quad_strip);
788                         glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
789                 
790                         /* emboss bottom shadow */
791                         if (wtb->emboss) {
792                                 glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
793
794                                 glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss);
795                                 glDrawArrays(GL_QUAD_STRIP, 0, wtb->halfwayvert * 2);
796                         }
797                         
798                         glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
799                 }
800
801                 glDisableClientState(GL_VERTEX_ARRAY);
802         }
803         
804         /* decoration */
805         if (wtb->tria1.tot || wtb->tria2.tot) {
806                 const unsigned char tcol[4] = {wcol->item[0],
807                                                wcol->item[1],
808                                                wcol->item[2],
809                                                (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
810                 /* for each AA step */
811                 for (j = 0; j < WIDGET_AA_JITTER; j++) {
812                         glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
813
814                         if (wtb->tria1.tot) {
815                                 glColor4ubv(tcol);
816                                 widget_trias_draw(&wtb->tria1);
817                         }
818                         if (wtb->tria2.tot) {
819                                 glColor4ubv(tcol);
820                                 widget_trias_draw(&wtb->tria2);
821                         }
822                 
823                         glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
824                 }
825         }
826
827         glDisable(GL_BLEND);
828         
829 }
830
831 /* *********************** text/icon ************************************** */
832
833 #define PREVIEW_PAD 4
834
835 static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), rcti *rect)
836 {
837         int w, h, size;
838
839         if (icon == ICON_NONE)
840                 return;
841
842         w = rect->xmax - rect->xmin;
843         h = rect->ymax - rect->ymin;
844         size = MIN2(w, h);
845         size -= PREVIEW_PAD * 2;  /* padding */
846
847         if (size > 0) {
848                 int x = rect->xmin + w / 2 - size / 2;
849                 int y = rect->ymin + h / 2 - size / 2;
850
851                 UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, size);
852         }
853 }
854
855
856 static int ui_but_draw_menu_icon(uiBut *but)
857 {
858         return (but->flag & UI_ICON_SUBMENU) && (but->dt == UI_EMBOSSP);
859 }
860
861 /* icons have been standardized... and this call draws in untransformed coordinates */
862
863 static void widget_draw_icon(uiBut *but, BIFIconID icon, float alpha, rcti *rect)
864 {
865         int xs = 0, ys = 0;
866         float aspect, height;
867         
868         if (but->flag & UI_ICON_PREVIEW) {
869                 widget_draw_preview(icon, alpha, rect);
870                 return;
871         }
872         
873         /* this icon doesn't need draw... */
874         if (icon == ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU) == 0) return;
875         
876         /* we need aspect from block, for menus... these buttons are scaled in uiPositionBlock() */
877         aspect = but->block->aspect;
878         if (aspect != but->aspect) {
879                 /* prevent scaling up icon in pupmenu */
880                 if (aspect < 1.0f) {                    
881                         height = UI_DPI_ICON_SIZE;
882                         aspect = 1.0f;
883                         
884                 }
885                 else 
886                         height = UI_DPI_ICON_SIZE / aspect;
887         }
888         else
889                 height = UI_DPI_ICON_SIZE;
890         
891         /* calculate blend color */
892         if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
893                 if (but->flag & UI_SELECT) ;
894                 else if (but->flag & UI_ACTIVE) ;
895                 else alpha = 0.5f;
896         }
897         
898         /* extra feature allows more alpha blending */
899         if (but->type == LABEL && but->a1 == 1.0f) alpha *= but->a2;
900         
901         glEnable(GL_BLEND);
902         
903         if (icon && icon != ICON_BLANK1) {
904                 if (but->flag & UI_ICON_LEFT) {
905                         if (but->type == BUT_TOGDUAL) {
906                                 if (but->drawstr[0]) {
907                                         xs = rect->xmin - 1;
908                                 }
909                                 else {
910                                         xs = (rect->xmin + rect->xmax - height) / 2;
911                                 }
912                         }
913                         else if (but->block->flag & UI_BLOCK_LOOP) {
914                                 if (but->type == SEARCH_MENU)
915                                         xs = rect->xmin + 4;
916                                 else
917                                         xs = rect->xmin + 1;
918                         }
919                         else if ((but->type == ICONROW) || (but->type == ICONTEXTROW)) {
920                                 xs = rect->xmin + 3;
921                         }
922                         else {
923                                 xs = rect->xmin + 4;
924                         }
925                         ys = (rect->ymin + rect->ymax - height) / 2;
926                 }
927                 else {
928                         xs = (rect->xmin + rect->xmax - height) / 2;
929                         ys = (rect->ymin + rect->ymax - height) / 2;
930                 }
931                 
932                 /* to indicate draggable */
933                 if (but->dragpoin && (but->flag & UI_ACTIVE)) {
934                         float rgb[3] = {1.25f, 1.25f, 1.25f};
935                         UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
936                 }
937                 else
938                         UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
939         }
940
941         if (ui_but_draw_menu_icon(but)) {
942                 xs = rect->xmax - UI_DPI_ICON_SIZE - 1;
943                 ys = (rect->ymin + rect->ymax - height) / 2;
944                 
945                 UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
946         }
947         
948         glDisable(GL_BLEND);
949 }
950
951 static void ui_text_clip_give_prev_off(uiBut *but)
952 {
953         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + but->ofs);
954         int bytes = but->drawstr + but->ofs - prev_utf8;
955
956         but->ofs -= bytes;
957 }
958
959 static void ui_text_clip_give_next_off(uiBut *but)
960 {
961         char *next_utf8 = BLI_str_find_next_char_utf8(but->drawstr + but->ofs, NULL);
962         int bytes = next_utf8 - (but->drawstr + but->ofs);
963
964         but->ofs += bytes;
965 }
966
967 /* sets but->ofs to make sure text is correctly visible */
968 static void ui_text_leftclip(uiFontStyle *fstyle, uiBut *but, rcti *rect)
969 {
970         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
971         int okwidth = rect->xmax - rect->xmin - border;
972         
973         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
974         
975         /* need to set this first */
976         uiStyleFontSet(fstyle);
977         
978         if (fstyle->kerning == 1) /* for BLF_width */
979                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
980
981         /* if text editing we define ofs dynamically */
982         if (but->editstr && but->pos >= 0) {
983                 if (but->ofs > but->pos)
984                         but->ofs = but->pos;
985
986                 if (BLF_width(fstyle->uifont_id, but->drawstr) <= okwidth)
987                         but->ofs = 0;
988         }
989         else but->ofs = 0;
990         
991         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
992         
993         while (but->strwidth > okwidth) {
994                 
995                 /* textbut exception, clip right when... */
996                 if (but->editstr && but->pos >= 0) {
997                         float width;
998                         char buf[UI_MAX_DRAW_STR];
999                         
1000                         /* copy draw string */
1001                         BLI_strncpy_utf8(buf, but->drawstr, sizeof(buf));
1002                         /* string position of cursor */
1003                         buf[but->pos] = 0;
1004                         width = BLF_width(fstyle->uifont_id, buf + but->ofs);
1005                         
1006                         /* if cursor is at 20 pixels of right side button we clip left */
1007                         if (width > okwidth - 20)
1008                                 ui_text_clip_give_next_off(but);
1009                         else {
1010                                 int len, bytes;
1011                                 /* shift string to the left */
1012                                 if (width < 20 && but->ofs > 0)
1013                                         ui_text_clip_give_prev_off(but);
1014                                 len = strlen(but->drawstr);
1015                                 bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len));
1016                                 but->drawstr[len - bytes] = 0;
1017                         }
1018                 }
1019                 else
1020                         ui_text_clip_give_next_off(but);
1021
1022                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1023                 
1024                 if (but->strwidth < 10) break;
1025         }
1026         
1027         if (fstyle->kerning == 1)
1028                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1029 }
1030
1031 static void ui_text_label_rightclip(uiFontStyle *fstyle, uiBut *but, rcti *rect)
1032 {
1033         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
1034         int okwidth = rect->xmax - rect->xmin - border;
1035         char *cpoin = NULL;
1036         char *cpend = but->drawstr + strlen(but->drawstr);
1037         
1038         /* need to set this first */
1039         uiStyleFontSet(fstyle);
1040         
1041         if (fstyle->kerning == 1) /* for BLF_width */
1042                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1043         
1044         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
1045         but->ofs = 0;
1046         
1047         /* find the space after ':' separator */
1048         cpoin = strrchr(but->drawstr, ':');
1049         
1050         if (cpoin && (cpoin < cpend - 2)) {
1051                 char *cp2 = cpoin;
1052                 
1053                 /* chop off the leading text, starting from the right */
1054                 while (but->strwidth > okwidth && cp2 > but->drawstr) {
1055                         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, cp2);
1056                         int bytes = cp2 - prev_utf8;
1057
1058                         /* shift the text after and including cp2 back by 1 char, +1 to include null terminator */
1059                         memmove(cp2 - bytes, cp2, strlen(cp2) + 1);
1060                         cp2 -= bytes;
1061                         
1062                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1063                         if (but->strwidth < 10) break;
1064                 }
1065         
1066         
1067                 /* after the leading text is gone, chop off the : and following space, with ofs */
1068                 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1069                         ui_text_clip_give_next_off(but);
1070                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1071                         if (but->strwidth < 10) break;
1072                 }
1073                 
1074         }
1075
1076         /* once the label's gone, chop off the least significant digits */
1077         while (but->strwidth > okwidth) {
1078                 int len = strlen(but->drawstr);
1079                 int bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len));
1080                 if (bytes < 0)
1081                         bytes = 1;
1082
1083                 but->drawstr[len - bytes] = 0;
1084                 
1085                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1086                 if (but->strwidth < 10) break;
1087         }
1088         
1089         if (fstyle->kerning == 1)
1090                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1091 }
1092
1093
1094 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1095 {
1096 //      int transopts;
1097         char *cpoin = NULL;
1098         
1099         /* for underline drawing */
1100         float font_xofs, font_yofs;
1101
1102         uiStyleFontSet(fstyle);
1103         
1104         if (but->editstr || (but->flag & UI_TEXT_LEFT))
1105                 fstyle->align = UI_STYLE_TEXT_LEFT;
1106         else
1107                 fstyle->align = UI_STYLE_TEXT_CENTER;
1108         
1109         if (fstyle->kerning == 1) /* for BLF_width */
1110                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1111         
1112         /* text button selection and cursor */
1113         if (but->editstr && but->pos != -1) {
1114                 short t = 0, pos = 0, ch;
1115                 short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
1116
1117                 if ((but->selend - but->selsta) > 0) {
1118                         /* text button selection */
1119                         selsta_tmp = but->selsta;
1120                         selend_tmp = but->selend;
1121                         
1122                         if (but->drawstr[0] != 0) {
1123
1124                                 if (but->selsta >= but->ofs) {
1125                                         ch = but->drawstr[selsta_tmp];
1126                                         but->drawstr[selsta_tmp] = 0;
1127                                         
1128                                         selsta_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1129                                         
1130                                         but->drawstr[selsta_tmp] = ch;
1131                                 }
1132                                 else {
1133                                         selsta_draw = 0;
1134                                 }
1135                                 
1136                                 ch = but->drawstr[selend_tmp];
1137                                 but->drawstr[selend_tmp] = 0;
1138                                 
1139                                 selwidth_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1140                                 
1141                                 but->drawstr[selend_tmp] = ch;
1142
1143                                 glColor3ubv((unsigned char *)wcol->item);
1144                                 glRects(rect->xmin + selsta_draw, rect->ymin + 2, rect->xmin + selwidth_draw, rect->ymax - 2);
1145                         }
1146                 }
1147                 else {
1148                         /* text cursor */
1149                         pos = but->pos;
1150                         if (pos >= but->ofs) {
1151                                 if (but->drawstr[0] != 0) {
1152                                         ch = but->drawstr[pos];
1153                                         but->drawstr[pos] = 0;
1154                                         
1155                                         t = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs) / but->aspect;
1156                                         
1157                                         but->drawstr[pos] = ch;
1158                                 }
1159
1160                                 glColor3f(0.20, 0.6, 0.9);
1161                                 glRects(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
1162                         }
1163                 }
1164         }
1165         
1166         if (fstyle->kerning == 1)
1167                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1168
1169 #if 0
1170         ui_rasterpos_safe(x, y, but->aspect);
1171         if (but->type == IDPOIN) transopts = 0; // no translation, of course!
1172         else transopts = ui_translate_buttons();
1173 #endif
1174
1175         /* cut string in 2 parts - only for menu entries */
1176         if ((but->block->flag & UI_BLOCK_LOOP)) {
1177                 if (ELEM5(but->type, SLI, NUM, TEX, NUMSLI, NUMABS) == 0) {
1178                         cpoin = strchr(but->drawstr, '|');
1179                         if (cpoin) *cpoin = 0;
1180                 }
1181         }
1182         
1183         glColor3ubv((unsigned char *)wcol->text);
1184
1185         uiStyleFontDrawExt(fstyle, rect, but->drawstr + but->ofs, &font_xofs, &font_yofs);
1186
1187         if (but->menu_key != '\0') {
1188                 char fixedbuf[128];
1189                 char *str;
1190
1191                 BLI_strncpy(fixedbuf, but->drawstr + but->ofs, sizeof(fixedbuf));
1192
1193                 str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
1194                 if (str == NULL)
1195                         str = strchr(fixedbuf, but->menu_key);
1196
1197                 if (str) {
1198                         int ul_index = -1;
1199                         float ul_advance;
1200
1201                         ul_index = (int)(str - fixedbuf);
1202
1203                         if (fstyle->kerning == 1) {
1204                                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1205                         }
1206
1207                         fixedbuf[ul_index] = '\0';
1208                         ul_advance = BLF_width(fstyle->uifont_id, fixedbuf);
1209
1210                         BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
1211                         BLF_draw(fstyle->uifont_id, "_", 2);
1212
1213                         if (fstyle->kerning == 1) {
1214                                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1215                         }
1216                 }
1217         }
1218
1219         /* part text right aligned */
1220         if (cpoin) {
1221                 fstyle->align = UI_STYLE_TEXT_RIGHT;
1222                 rect->xmax -= ui_but_draw_menu_icon(but) ? UI_DPI_ICON_SIZE : 5;
1223                 uiStyleFontDraw(fstyle, rect, cpoin + 1);
1224                 *cpoin = '|';
1225         }
1226 }
1227
1228 /* draws text and icons for buttons */
1229 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1230 {
1231         
1232         if (but == NULL) return;
1233
1234         /* clip but->drawstr to fit in available space */
1235         if (but->editstr && but->pos >= 0) {
1236                 ui_text_leftclip(fstyle, but, rect);
1237         }
1238         else if (ELEM4(but->type, NUM, NUMABS, NUMSLI, SLI)) {
1239                 ui_text_label_rightclip(fstyle, but, rect);
1240         }
1241         else if (ELEM(but->type, TEX, SEARCH_MENU)) {
1242                 ui_text_leftclip(fstyle, but, rect);
1243         }
1244         else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
1245                 ui_text_leftclip(fstyle, but, rect);
1246         }
1247         else but->ofs = 0;
1248         
1249         /* check for button text label */
1250         if (but->type == ICONTEXTROW) {
1251                 widget_draw_icon(but, (BIFIconID) (but->icon + but->iconadd), 1.0f, rect);
1252         }
1253         else {
1254                                 
1255                 if (but->type == BUT_TOGDUAL) {
1256                         int dualset = 0;
1257                         if (but->pointype == SHO)
1258                                 dualset = BTST(*(((short *)but->poin) + 1), but->bitnr);
1259                         else if (but->pointype == INT)
1260                                 dualset = BTST(*(((int *)but->poin) + 1), but->bitnr);
1261                         
1262                         widget_draw_icon(but, ICON_DOT, dualset ? 1.0f : 0.25f, rect);
1263                 }
1264                 else if (but->type == MENU && (but->flag & UI_BUT_NODE_LINK)) {
1265                         int tmp = rect->xmin;
1266                         rect->xmin = rect->xmax - (rect->ymax - rect->ymin) - 1;
1267                         widget_draw_icon(but, ICON_LAYER_USED, 1.0f, rect);
1268                         rect->xmin = tmp;
1269                 }
1270                 
1271                 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
1272                  * and offset the text label to accommodate it */
1273                 
1274                 if (but->flag & UI_HAS_ICON) {
1275                         widget_draw_icon(but, but->icon + but->iconadd, 1.0f, rect);
1276                         
1277                         rect->xmin += (int)((float)UI_icon_get_width(but->icon + but->iconadd) * UI_DPI_ICON_FAC);
1278                         
1279                         if (but->editstr || (but->flag & UI_TEXT_LEFT)) 
1280                                 rect->xmin += 5;
1281                 }
1282                 else if ((but->flag & UI_TEXT_LEFT)) 
1283                         rect->xmin += 5;
1284                 
1285                 /* always draw text for textbutton cursor */
1286                 widget_draw_text(fstyle, wcol, but, rect);
1287
1288         }
1289 }
1290
1291
1292
1293 /* *********************** widget types ************************************* */
1294
1295
1296 /* uiWidgetStateColors
1297  *     char inner_anim[4];
1298  *     char inner_anim_sel[4];
1299  *     char inner_key[4];
1300  *     char inner_key_sel[4];
1301  *     char inner_driven[4];
1302  *     char inner_driven_sel[4];
1303  *     float blend;
1304  */
1305
1306 static struct uiWidgetStateColors wcol_state_colors = {
1307         {115, 190, 76, 255},
1308         {90, 166, 51, 255},
1309         {240, 235, 100, 255},
1310         {215, 211, 75, 255},
1311         {180, 0, 255, 255},
1312         {153, 0, 230, 255},
1313         0.5f, 0.0f
1314 };
1315
1316 /* uiWidgetColors
1317  *     float outline[3];
1318  *     float inner[4];
1319  *     float inner_sel[4];
1320  *     float item[3];
1321  *     float text[3];
1322  *     float text_sel[3];
1323  *     
1324  *     short shaded;
1325  *     float shadetop, shadedown;
1326  */
1327
1328 static struct uiWidgetColors wcol_num = {
1329         {25, 25, 25, 255},
1330         {180, 180, 180, 255},
1331         {153, 153, 153, 255},
1332         {90, 90, 90, 255},
1333         
1334         {0, 0, 0, 255},
1335         {255, 255, 255, 255},
1336         
1337         1,
1338         -20, 0
1339 };
1340
1341 static struct uiWidgetColors wcol_numslider = {
1342         {25, 25, 25, 255},
1343         {180, 180, 180, 255},
1344         {153, 153, 153, 255},
1345         {128, 128, 128, 255},
1346         
1347         {0, 0, 0, 255},
1348         {255, 255, 255, 255},
1349         
1350         1,
1351         -20, 0
1352 };
1353
1354 static struct uiWidgetColors wcol_text = {
1355         {25, 25, 25, 255},
1356         {153, 153, 153, 255},
1357         {153, 153, 153, 255},
1358         {90, 90, 90, 255},
1359         
1360         {0, 0, 0, 255},
1361         {255, 255, 255, 255},
1362         
1363         1,
1364         0, 25
1365 };
1366
1367 static struct uiWidgetColors wcol_option = {
1368         {0, 0, 0, 255},
1369         {70, 70, 70, 255},
1370         {70, 70, 70, 255},
1371         {255, 255, 255, 255},
1372         
1373         {0, 0, 0, 255},
1374         {255, 255, 255, 255},
1375         
1376         1,
1377         15, -15
1378 };
1379
1380 /* button that shows popup */
1381 static struct uiWidgetColors wcol_menu = {
1382         {0, 0, 0, 255},
1383         {70, 70, 70, 255},
1384         {70, 70, 70, 255},
1385         {255, 255, 255, 255},
1386         
1387         {255, 255, 255, 255},
1388         {204, 204, 204, 255},
1389         
1390         1,
1391         15, -15
1392 };
1393
1394 /* button that starts pulldown */
1395 static struct uiWidgetColors wcol_pulldown = {
1396         {0, 0, 0, 255},
1397         {63, 63, 63, 255},
1398         {86, 128, 194, 255},
1399         {255, 255, 255, 255},
1400         
1401         {0, 0, 0, 255},
1402         {0, 0, 0, 255},
1403         
1404         0,
1405         25, -20
1406 };
1407
1408 /* button inside menu */
1409 static struct uiWidgetColors wcol_menu_item = {
1410         {0, 0, 0, 255},
1411         {0, 0, 0, 0},
1412         {86, 128, 194, 255},
1413         {172, 172, 172, 128},
1414         
1415         {255, 255, 255, 255},
1416         {0, 0, 0, 255},
1417         
1418         1,
1419         38, 0
1420 };
1421
1422 /* backdrop menu + title text color */
1423 static struct uiWidgetColors wcol_menu_back = {
1424         {0, 0, 0, 255},
1425         {25, 25, 25, 230},
1426         {45, 45, 45, 230},
1427         {100, 100, 100, 255},
1428         
1429         {160, 160, 160, 255},
1430         {255, 255, 255, 255},
1431         
1432         0,
1433         25, -20
1434 };
1435
1436 /* tooltip colour */
1437 static struct uiWidgetColors wcol_tooltip = {
1438         {0, 0, 0, 255},
1439         {25, 25, 25, 230},
1440         {45, 45, 45, 230},
1441         {100, 100, 100, 255},
1442
1443         {160, 160, 160, 255},
1444         {255, 255, 255, 255},
1445
1446         0,
1447         25, -20
1448 };
1449
1450 static struct uiWidgetColors wcol_radio = {
1451         {0, 0, 0, 255},
1452         {70, 70, 70, 255},
1453         {86, 128, 194, 255},
1454         {255, 255, 255, 255},
1455         
1456         {255, 255, 255, 255},
1457         {0, 0, 0, 255},
1458         
1459         1,
1460         15, -15
1461 };
1462
1463 static struct uiWidgetColors wcol_regular = {
1464         {25, 25, 25, 255},
1465         {153, 153, 153, 255},
1466         {100, 100, 100, 255},
1467         {25, 25, 25, 255},
1468         
1469         {0, 0, 0, 255},
1470         {255, 255, 255, 255},
1471         
1472         0,
1473         0, 0
1474 };
1475
1476 static struct uiWidgetColors wcol_tool = {
1477         {25, 25, 25, 255},
1478         {153, 153, 153, 255},
1479         {100, 100, 100, 255},
1480         {25, 25, 25, 255},
1481         
1482         {0, 0, 0, 255},
1483         {255, 255, 255, 255},
1484         
1485         1,
1486         15, -15
1487 };
1488
1489 static struct uiWidgetColors wcol_box = {
1490         {25, 25, 25, 255},
1491         {128, 128, 128, 255},
1492         {100, 100, 100, 255},
1493         {25, 25, 25, 255},
1494         
1495         {0, 0, 0, 255},
1496         {255, 255, 255, 255},
1497         
1498         0,
1499         0, 0
1500 };
1501
1502 static struct uiWidgetColors wcol_toggle = {
1503         {25, 25, 25, 255},
1504         {153, 153, 153, 255},
1505         {100, 100, 100, 255},
1506         {25, 25, 25, 255},
1507         
1508         {0, 0, 0, 255},
1509         {255, 255, 255, 255},
1510         
1511         0,
1512         0, 0
1513 };
1514
1515 static struct uiWidgetColors wcol_scroll = {
1516         {50, 50, 50, 180},
1517         {80, 80, 80, 180},
1518         {100, 100, 100, 180},
1519         {128, 128, 128, 255},
1520         
1521         {0, 0, 0, 255},
1522         {255, 255, 255, 255},
1523         
1524         1,
1525         5, -5
1526 };
1527
1528 static struct uiWidgetColors wcol_progress = {
1529         {0, 0, 0, 255},
1530         {190, 190, 190, 255},
1531         {100, 100, 100, 180},
1532         {68, 68, 68, 255},
1533         
1534         {0, 0, 0, 255},
1535         {255, 255, 255, 255},
1536         
1537         0,
1538         0, 0
1539 };
1540
1541 static struct uiWidgetColors wcol_list_item = {
1542         {0, 0, 0, 255},
1543         {0, 0, 0, 0},
1544         {86, 128, 194, 255},
1545         {0, 0, 0, 255},
1546         
1547         {0, 0, 0, 255},
1548         {0, 0, 0, 255},
1549         
1550         0,
1551         0, 0
1552 };
1553
1554 /* free wcol struct to play with */
1555 static struct uiWidgetColors wcol_tmp = {
1556         {0, 0, 0, 255},
1557         {128, 128, 128, 255},
1558         {100, 100, 100, 255},
1559         {25, 25, 25, 255},
1560         
1561         {0, 0, 0, 255},
1562         {255, 255, 255, 255},
1563         
1564         0,
1565         0, 0
1566 };
1567
1568
1569 /* called for theme init (new theme) and versions */
1570 void ui_widget_color_init(ThemeUI *tui)
1571 {
1572         tui->wcol_regular = wcol_regular;
1573         tui->wcol_tool = wcol_tool;
1574         tui->wcol_text = wcol_text;
1575         tui->wcol_radio = wcol_radio;
1576         tui->wcol_option = wcol_option;
1577         tui->wcol_toggle = wcol_toggle;
1578         tui->wcol_num = wcol_num;
1579         tui->wcol_numslider = wcol_numslider;
1580         tui->wcol_menu = wcol_menu;
1581         tui->wcol_pulldown = wcol_pulldown;
1582         tui->wcol_menu_back = wcol_menu_back;
1583         tui->wcol_tooltip = wcol_tooltip;
1584         tui->wcol_menu_item = wcol_menu_item;
1585         tui->wcol_box = wcol_box;
1586         tui->wcol_scroll = wcol_scroll;
1587         tui->wcol_list_item = wcol_list_item;
1588         tui->wcol_progress = wcol_progress;
1589
1590         tui->wcol_state = wcol_state_colors;
1591 }
1592
1593 /* ************ button callbacks, state ***************** */
1594
1595 static void widget_state_blend(char cp[3], const char cpstate[3], const float fac)
1596 {
1597         if (fac != 0.0f) {
1598                 cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
1599                 cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
1600                 cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
1601         }
1602 }
1603
1604 /* copy colors from theme, and set changes in it based on state */
1605 static void widget_state(uiWidgetType *wt, int state)
1606 {
1607         uiWidgetStateColors *wcol_state = wt->wcol_state;
1608
1609         wt->wcol = *(wt->wcol_theme);
1610         
1611         if (state & UI_SELECT) {
1612                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1613
1614                 if (state & UI_BUT_ANIMATED_KEY)
1615                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1616                 else if (state & UI_BUT_ANIMATED)
1617                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1618                 else if (state & UI_BUT_DRIVEN)
1619                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1620
1621                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1622                 
1623                 if (state & UI_SELECT)
1624                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1625         }
1626         else {
1627                 if (state & UI_BUT_ANIMATED_KEY)
1628                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1629                 else if (state & UI_BUT_ANIMATED)
1630                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1631                 else if (state & UI_BUT_DRIVEN)
1632                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1633
1634                 if (state & UI_ACTIVE) { /* mouse over? */
1635                         wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
1636                         wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
1637                         wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
1638                 }
1639         }
1640
1641         if (state & UI_BUT_REDALERT) {
1642                 char red[4] = {255, 0, 0};
1643                 widget_state_blend(wt->wcol.inner, red, 0.4f);
1644         }
1645         if (state & UI_BUT_NODE_ACTIVE) {
1646                 char blue[4] = {86, 128, 194};
1647                 widget_state_blend(wt->wcol.inner, blue, 0.3f);
1648         }
1649 }
1650
1651 /* sliders use special hack which sets 'item' as inner when drawing filling */
1652 static void widget_state_numslider(uiWidgetType *wt, int state)
1653 {
1654         uiWidgetStateColors *wcol_state = wt->wcol_state;
1655         float blend = wcol_state->blend - 0.2f; // XXX special tweak to make sure that bar will still be visible
1656
1657         /* call this for option button */
1658         widget_state(wt, state);
1659         
1660         /* now, set the inner-part so that it reflects state settings too */
1661         // TODO: maybe we should have separate settings for the blending colors used for this case?
1662         if (state & UI_SELECT) {
1663                 
1664                 if (state & UI_BUT_ANIMATED_KEY)
1665                         widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
1666                 else if (state & UI_BUT_ANIMATED)
1667                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
1668                 else if (state & UI_BUT_DRIVEN)
1669                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
1670                 
1671                 if (state & UI_SELECT)
1672                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1673         }
1674         else {
1675                 if (state & UI_BUT_ANIMATED_KEY)
1676                         widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
1677                 else if (state & UI_BUT_ANIMATED)
1678                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
1679                 else if (state & UI_BUT_DRIVEN)
1680                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
1681         }
1682 }
1683
1684 /* labels use theme colors for text */
1685 static void widget_state_label(uiWidgetType *wt, int state)
1686 {
1687         /* call this for option button */
1688         widget_state(wt, state);
1689
1690         if (state & UI_SELECT)
1691                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1692         else
1693                 UI_GetThemeColor4ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
1694         
1695 }
1696
1697 /* labels use theme colors for text */
1698 static void widget_state_option_menu(uiWidgetType *wt, int state)
1699 {
1700         
1701         /* call this for option button */
1702         widget_state(wt, state);
1703         
1704         /* if not selected we get theme from menu back */
1705         if (state & UI_SELECT)
1706                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1707         else {
1708                 bTheme *btheme = UI_GetTheme(); /* XXX */
1709
1710                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text);
1711         }
1712 }
1713
1714
1715 static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
1716 {
1717         wt->wcol = *(wt->wcol_theme);
1718 }       
1719
1720 /* special case, button that calls pulldown */
1721 static void widget_state_pulldown(uiWidgetType *wt, int state)
1722 {
1723         wt->wcol = *(wt->wcol_theme);
1724         
1725         copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1726         copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
1727
1728         if (state & UI_ACTIVE)
1729                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1730 }
1731
1732 /* special case, menu items */
1733 static void widget_state_menu_item(uiWidgetType *wt, int state)
1734 {
1735         wt->wcol = *(wt->wcol_theme);
1736         
1737         if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1738                 wt->wcol.text[0] = 0.5f * (wt->wcol.text[0] + wt->wcol.text_sel[0]);
1739                 wt->wcol.text[1] = 0.5f * (wt->wcol.text[1] + wt->wcol.text_sel[1]);
1740                 wt->wcol.text[2] = 0.5f * (wt->wcol.text[2] + wt->wcol.text_sel[2]);
1741         }
1742         else if (state & UI_ACTIVE) {
1743                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1744                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1745         }
1746 }
1747
1748
1749 /* ************ menu backdrop ************************* */
1750
1751 /* outside of rect, rad to left/bottom/right */
1752 static void widget_softshadow(rcti *rect, int roundboxalign, float radin, float radout)
1753 {
1754         uiWidgetBase wtb;
1755         rcti rect1 = *rect;
1756         float alpha, alphastep;
1757         int step, totvert;
1758         float quad_strip[WIDGET_SIZE_MAX * 2][2];
1759         
1760         /* prevent tooltips to not show round shadow */
1761         if (2.0f * radout > 0.2f * (rect1.ymax - rect1.ymin) )
1762                 rect1.ymax -= 0.2f * (rect1.ymax - rect1.ymin);
1763         else
1764                 rect1.ymax -= 2.0f * radout;
1765         
1766         /* inner part */
1767         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1768
1769         /* inverse linear shadow alpha */
1770         alpha = 0.15;
1771         alphastep = 0.67;
1772         
1773         glEnableClientState(GL_VERTEX_ARRAY);
1774
1775         for (step = 1; step <= radout; step++, alpha *= alphastep) {
1776                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1777                 
1778                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
1779
1780                 widget_verts_to_quad_strip_open(&wtb, totvert, quad_strip);
1781
1782                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1783                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2);
1784         }
1785
1786         glDisableClientState(GL_VERTEX_ARRAY);
1787 }
1788
1789 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1790 {
1791         uiWidgetBase wtb;
1792         int roundboxalign = UI_CNR_ALL;
1793         
1794         widget_init(&wtb);
1795         
1796         /* menu is 2nd level or deeper */
1797         if (flag & UI_BLOCK_POPUP) {
1798                 //rect->ymin -= 4.0;
1799                 //rect->ymax += 4.0;
1800         }
1801         else if (direction == UI_DOWN) {
1802                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1803                 rect->ymin -= 4.0;
1804         } 
1805         else if (direction == UI_TOP) {
1806                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1807                 rect->ymax += 4.0;
1808         }
1809         
1810         glEnable(GL_BLEND);
1811         widget_softshadow(rect, roundboxalign, 5.0f, 8.0f);
1812         
1813         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
1814         wtb.emboss = 0;
1815         widgetbase_draw(&wtb, wcol);
1816         
1817         glDisable(GL_BLEND);
1818 }
1819
1820
1821 static void ui_hsv_cursor(float x, float y)
1822 {
1823         
1824         glPushMatrix();
1825         glTranslatef(x, y, 0.0f);
1826         
1827         glColor3f(1.0f, 1.0f, 1.0f);
1828         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f, 8);
1829         
1830         glEnable(GL_BLEND);
1831         glEnable(GL_LINE_SMOOTH);
1832         glColor3f(0.0f, 0.0f, 0.0f);
1833         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f, 12);
1834         glDisable(GL_BLEND);
1835         glDisable(GL_LINE_SMOOTH);
1836         
1837         glPopMatrix();
1838         
1839 }
1840
1841 void ui_hsvcircle_vals_from_pos(float *valrad, float *valdist, rcti *rect, float mx, float my)
1842 {
1843         /* duplication of code... well, simple is better now */
1844         float centx = (float)(rect->xmin + rect->xmax) / 2;
1845         float centy = (float)(rect->ymin + rect->ymax) / 2;
1846         float radius, dist;
1847         
1848         if (rect->xmax - rect->xmin > rect->ymax - rect->ymin)
1849                 radius = (float)(rect->ymax - rect->ymin) / 2;
1850         else
1851                 radius = (float)(rect->xmax - rect->xmin) / 2;
1852
1853         mx -= centx;
1854         my -= centy;
1855         dist = sqrt(mx * mx + my * my);
1856         if (dist < radius)
1857                 *valdist = dist / radius;
1858         else
1859                 *valdist = 1.0f;
1860         
1861         *valrad = atan2f(mx, my) / (2.0f * (float)M_PI) + 0.5f;
1862 }
1863
1864 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, rcti *rect)
1865 {
1866         /* gouraud triangle fan */
1867         float radstep, ang = 0.0f;
1868         float centx, centy, radius, cursor_radius;
1869         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1870         int a, tot = 32;
1871         int color_profile = but->block->color_profile;
1872         
1873         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1874                 color_profile = BLI_PR_NONE;
1875         
1876         radstep = 2.0f * (float)M_PI / (float)tot;
1877         centx = (float)(rect->xmin + rect->xmax) / 2;
1878         centy = (float)(rect->ymin + rect->ymax) / 2;
1879         
1880         if (rect->xmax - rect->xmin > rect->ymax - rect->ymin)
1881                 radius = (float)(rect->ymax - rect->ymin) / 2;
1882         else
1883                 radius = (float)(rect->xmax - rect->xmin) / 2;
1884         
1885         /* color */
1886         ui_get_but_vectorf(but, rgb);
1887         copy_v3_v3(hsv, ui_block_hsv_get(but->block));
1888         rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv + 1, hsv + 2);
1889         copy_v3_v3(hsvo, hsv);
1890         
1891         /* exception: if 'lock' is set
1892          * lock the value of the color wheel to 1.
1893          * Useful for color correction tools where you're only interested in hue. */
1894         if (but->flag & UI_BUT_COLOR_LOCK)
1895                 hsv[2] = 1.f;
1896         else if (color_profile)
1897                 hsv[2] = linearrgb_to_srgb(hsv[2]);
1898         
1899         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1900         
1901         glShadeModel(GL_SMOOTH);
1902
1903         glBegin(GL_TRIANGLE_FAN);
1904         glColor3fv(colcent);
1905         glVertex2f(centx, centy);
1906         
1907         for (a = 0; a <= tot; a++, ang += radstep) {
1908                 float si = sin(ang);
1909                 float co = cos(ang);
1910                 
1911                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1912                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1913
1914                 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col + 1, col + 2);
1915                 glColor3fv(col);
1916                 glVertex2f(centx + co * radius, centy + si * radius);
1917         }
1918         glEnd();
1919         
1920         glShadeModel(GL_FLAT);
1921         
1922         /* fully rounded outline */
1923         glPushMatrix();
1924         glTranslatef(centx, centy, 0.0f);
1925         glEnable(GL_BLEND);
1926         glEnable(GL_LINE_SMOOTH);
1927         glColor3ubv((unsigned char *)wcol->outline);
1928         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
1929         glDisable(GL_BLEND);
1930         glDisable(GL_LINE_SMOOTH);
1931         glPopMatrix();
1932
1933         /* cursor */
1934         ang = 2.0f * (float)M_PI * hsvo[0] + 0.5f * (float)M_PI;
1935
1936         if (but->flag & UI_BUT_COLOR_CUBIC)
1937                 cursor_radius = (1.0f - powf(1.0f - hsvo[1], 3.0f));
1938         else
1939                 cursor_radius = hsvo[1];
1940
1941         radius = CLAMPIS(cursor_radius, 0.0f, 1.0f) * radius;
1942         ui_hsv_cursor(centx + cosf(-ang) * radius, centy + sinf(-ang) * radius);
1943 }
1944
1945 /* ************ custom buttons, old stuff ************** */
1946
1947 /* draws in resolution of 20x4 colors */
1948 void ui_draw_gradient(rcti *rect, const float hsv[3], int type, float alpha)
1949 {
1950         int a;
1951         float h = hsv[0], s = hsv[1], v = hsv[2];
1952         float dx, dy, sx1, sx2, sy;
1953         float col0[4][3];   // left half, rect bottom to top
1954         float col1[4][3];   // right half, rect bottom to top
1955
1956         /* draw series of gouraud rects */
1957         glShadeModel(GL_SMOOTH);
1958         
1959         switch (type) {
1960                 case UI_GRAD_SV:
1961                         hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1962                         hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
1963                         hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
1964                         hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1965                         break;
1966                 case UI_GRAD_HV:
1967                         hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1968                         hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
1969                         hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
1970                         hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
1971                         break;
1972                 case UI_GRAD_HS:
1973                         hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
1974                         hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
1975                         hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
1976                         hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
1977                         break;
1978                 case UI_GRAD_H:
1979                         hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
1980                         copy_v3_v3(col1[1], col1[0]);
1981                         copy_v3_v3(col1[2], col1[0]);
1982                         copy_v3_v3(col1[3], col1[0]);
1983                         break;
1984                 case UI_GRAD_S:
1985                         hsv_to_rgb(1.0, 0.0, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
1986                         copy_v3_v3(col1[0], col1[1]);
1987                         copy_v3_v3(col1[2], col1[1]);
1988                         copy_v3_v3(col1[3], col1[1]);
1989                         break;
1990                 case UI_GRAD_V:
1991                         hsv_to_rgb(1.0, 1.0, 0.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
1992                         copy_v3_v3(col1[0], col1[2]);
1993                         copy_v3_v3(col1[1], col1[2]);
1994                         copy_v3_v3(col1[3], col1[2]);
1995                         break;
1996                 default:
1997                         assert(!"invalid 'type' argument");
1998                         hsv_to_rgb(1.0, 1.0, 1.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
1999                         copy_v3_v3(col1[0], col1[2]);
2000                         copy_v3_v3(col1[1], col1[2]);
2001                         copy_v3_v3(col1[3], col1[2]);
2002         }
2003         
2004         /* old below */
2005         
2006         for (dx = 0.0f; dx < 1.0f; dx += 0.05f) {
2007                 // previous color
2008                 copy_v3_v3(col0[0], col1[0]);
2009                 copy_v3_v3(col0[1], col1[1]);
2010                 copy_v3_v3(col0[2], col1[2]);
2011                 copy_v3_v3(col0[3], col1[3]);
2012                 
2013                 // new color
2014                 switch (type) {
2015                         case UI_GRAD_SV:
2016                                 hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
2017                                 hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
2018                                 hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
2019                                 hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
2020                                 break;
2021                         case UI_GRAD_HV:
2022                                 hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2023                                 hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2024                                 hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2025                                 hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2026                                 break;
2027                         case UI_GRAD_HS:
2028                                 hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2029                                 hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2030                                 hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2031                                 hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2032                                 break;
2033                         case UI_GRAD_H:
2034                                 hsv_to_rgb(dx, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2035                                 copy_v3_v3(col1[1], col1[0]);
2036                                 copy_v3_v3(col1[2], col1[0]);
2037                                 copy_v3_v3(col1[3], col1[0]);
2038                                 break;
2039                         case UI_GRAD_S:
2040                                 hsv_to_rgb(h, dx, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2041                                 copy_v3_v3(col1[0], col1[1]);
2042                                 copy_v3_v3(col1[2], col1[1]);
2043                                 copy_v3_v3(col1[3], col1[1]);
2044                                 break;
2045                         case UI_GRAD_V:
2046                                 hsv_to_rgb(h, 1.0, dx,   &col1[2][0], &col1[2][1], &col1[2][2]);
2047                                 copy_v3_v3(col1[0], col1[2]);
2048                                 copy_v3_v3(col1[1], col1[2]);
2049                                 copy_v3_v3(col1[3], col1[2]);
2050                                 break;
2051                 }
2052                 
2053                 // rect
2054                 sx1 = rect->xmin + dx * (rect->xmax - rect->xmin);
2055                 sx2 = rect->xmin + (dx + 0.05f) * (rect->xmax - rect->xmin);
2056                 sy = rect->ymin;
2057                 dy = (rect->ymax - rect->ymin) / 3.0;
2058                 
2059                 glBegin(GL_QUADS);
2060                 for (a = 0; a < 3; a++, sy += dy) {
2061                         glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
2062                         glVertex2f(sx1, sy);
2063                         
2064                         glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
2065                         glVertex2f(sx2, sy);
2066
2067                         glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
2068                         glVertex2f(sx2, sy + dy);
2069                         
2070                         glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
2071                         glVertex2f(sx1, sy + dy);
2072                 }
2073                 glEnd();
2074         }
2075         
2076         glShadeModel(GL_FLAT);
2077         
2078 }
2079
2080
2081
2082 static void ui_draw_but_HSVCUBE(uiBut *but, rcti *rect)
2083 {
2084         float rgb[3], h, s, v;
2085         float x = 0.0f, y = 0.0f;
2086         float *hsv = ui_block_hsv_get(but->block);
2087         float hsvn[3];
2088         
2089         h = hsv[0];
2090         s = hsv[1];
2091         v = hsv[2];
2092         
2093         ui_get_but_vectorf(but, rgb);
2094         rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &h, &s, &v);
2095
2096         hsvn[0] = h;
2097         hsvn[1] = s;
2098         hsvn[2] = v;
2099         
2100         ui_draw_gradient(rect, hsvn, but->a1, 1.f);
2101         
2102         switch ((int)but->a1) {
2103                 case UI_GRAD_SV:
2104                         x = v; y = s; break;
2105                 case UI_GRAD_HV:
2106                         x = h; y = v; break;
2107                 case UI_GRAD_HS:
2108                         x = h; y = s; break;
2109                 case UI_GRAD_H:
2110                         x = h; y = 0.5; break;
2111                 case UI_GRAD_S:
2112                         x = s; y = 0.5; break;
2113                 case UI_GRAD_V:
2114                         x = v; y = 0.5; break;
2115         }
2116         
2117         /* cursor */
2118         x = rect->xmin + x * (rect->xmax - rect->xmin);
2119         y = rect->ymin + y * (rect->ymax - rect->ymin);
2120         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2121         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2122         
2123         ui_hsv_cursor(x, y);
2124         
2125         /* outline */
2126         glColor3ub(0,  0,  0);
2127         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2128 }
2129
2130 /* vertical 'value' slider, using new widget code */
2131 static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
2132 {
2133         uiWidgetBase wtb;
2134         float rad = 0.5f * (rect->xmax - rect->xmin);
2135         float x, y;
2136         float rgb[3], hsv[3], v, range;
2137         int color_profile = but->block->color_profile;
2138         
2139         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2140                 color_profile = BLI_PR_NONE;
2141
2142         ui_get_but_vectorf(but, rgb);
2143         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv + 1, hsv + 2);
2144         v = hsv[2];
2145         
2146         if (color_profile)
2147                 v = linearrgb_to_srgb(v);
2148
2149         /* map v from property range to [0,1] */
2150         range = but->softmax - but->softmin;
2151         v = (v - but->softmin) / range;
2152         
2153         widget_init(&wtb);
2154         
2155         /* fully rounded */
2156         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2157         
2158         /* setup temp colors */
2159         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2160         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2161         wcol_tmp.shadetop = 127;
2162         wcol_tmp.shadedown = -128;
2163         wcol_tmp.shaded = 1;
2164         
2165         widgetbase_draw(&wtb, &wcol_tmp);
2166
2167         /* cursor */
2168         x = rect->xmin + 0.5f * (rect->xmax - rect->xmin);
2169         y = rect->ymin + v * (rect->ymax - rect->ymin);
2170         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2171         
2172         ui_hsv_cursor(x, y);
2173         
2174 }
2175
2176
2177 /* ************ separator, for menus etc ***************** */
2178 static void ui_draw_separator(rcti *rect,  uiWidgetColors *wcol)
2179 {
2180         int y = rect->ymin + (rect->ymax - rect->ymin) / 2 - 1;
2181         unsigned char col[4];
2182         
2183         col[0] = wcol->text[0];
2184         col[1] = wcol->text[1];
2185         col[2] = wcol->text[2];
2186         col[3] = 7;
2187         
2188         glEnable(GL_BLEND);
2189         glColor4ubv(col);
2190         sdrawline(rect->xmin, y, rect->xmax, y);
2191         glDisable(GL_BLEND);
2192 }
2193
2194 /* ************ button callbacks, draw ***************** */
2195
2196 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2197 {
2198         uiWidgetBase wtb;
2199         float rad = 0.5f * (rect->ymax - rect->ymin);
2200         float textofs = rad * 0.75f;
2201
2202         if (state & UI_SELECT)
2203                 SWAP(short, wcol->shadetop, wcol->shadedown);
2204         
2205         widget_init(&wtb);
2206         
2207         /* fully rounded */
2208         round_box_edges(&wtb, roundboxalign, rect, rad);
2209         
2210         /* decoration */
2211         if (!(state & UI_TEXTINPUT)) {
2212                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2213                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2214         }
2215
2216         widgetbase_draw(&wtb, wcol);
2217         
2218         /* text space */
2219         rect->xmin += textofs;
2220         rect->xmax -= textofs;
2221 }
2222
2223 //static int ui_link_bezier_points(rcti *rect, float coord_array[][2], int resol)
2224 int ui_link_bezier_points(rcti *rect, float coord_array[][2], int resol)
2225 {
2226         float dist, vec[4][2];
2227
2228         vec[0][0] = rect->xmin;
2229         vec[0][1] = rect->ymin;
2230         vec[3][0] = rect->xmax;
2231         vec[3][1] = rect->ymax;
2232         
2233         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2234         
2235         vec[1][0] = vec[0][0] + dist;
2236         vec[1][1] = vec[0][1];
2237         
2238         vec[2][0] = vec[3][0] - dist;
2239         vec[2][1] = vec[3][1];
2240         
2241         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2242         BKE_curve_forward_diff_bezier(vec[0][1], vec[1][1], vec[2][1], vec[3][1], coord_array[0] + 1, resol, sizeof(float) * 2);
2243         
2244         return 1;
2245 }
2246
2247 #define LINK_RESOL  24
2248 void ui_draw_link_bezier(rcti *rect)
2249 {
2250         float coord_array[LINK_RESOL + 1][2];
2251         
2252         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2253                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2254                 // const float dist= 1.0f/(float)LINK_RESOL; // UNUSED
2255
2256                 glEnable(GL_BLEND);
2257                 glEnable(GL_LINE_SMOOTH);
2258
2259                 glEnableClientState(GL_VERTEX_ARRAY);
2260                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2261                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL);
2262                 glDisableClientState(GL_VERTEX_ARRAY);
2263
2264                 glDisable(GL_BLEND);
2265                 glDisable(GL_LINE_SMOOTH);
2266
2267         }
2268 }
2269
2270 /* function in use for buttons and for view2d sliders */
2271 void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int state)
2272 {
2273         uiWidgetBase wtb;
2274         float rad;
2275         int horizontal;
2276         short outline = 0;
2277
2278         widget_init(&wtb);
2279
2280         /* determine horizontal/vertical */
2281         horizontal = (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
2282         
2283         if (horizontal)
2284                 rad = 0.5f * (rect->ymax - rect->ymin);
2285         else
2286                 rad = 0.5f * (rect->xmax - rect->xmin);
2287         
2288         wtb.shadedir = (horizontal) ? 1 : 0;
2289         
2290         /* draw back part, colors swapped and shading inverted */
2291         if (horizontal)
2292                 SWAP(short, wcol->shadetop, wcol->shadedown);
2293         
2294         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2295         widgetbase_draw(&wtb, wcol);
2296         
2297         /* slider */
2298         if (slider->xmax - slider->xmin < 2 || slider->ymax - slider->ymin < 2) ;
2299         else {
2300                 
2301                 SWAP(short, wcol->shadetop, wcol->shadedown);
2302                 
2303                 copy_v4_v4_char(wcol->inner, wcol->item);
2304                 
2305                 if (wcol->shadetop > wcol->shadedown)
2306                         wcol->shadetop += 20;   /* XXX violates themes... */
2307                 else wcol->shadedown += 20;
2308                 
2309                 if (state & UI_SCROLL_PRESSED) {
2310                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2311                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2312                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2313                 }
2314
2315                 /* draw */
2316                 wtb.emboss = 0; /* only emboss once */
2317                 
2318                 /* exception for progress bar */
2319                 if (state & UI_SCROLL_NO_OUTLINE)       
2320                         SWAP(short, outline, wtb.outline);
2321                 
2322                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2323                 
2324                 if (state & UI_SCROLL_ARROWS) {
2325                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2326                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2327                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2328                         wcol->item[3] = 255;
2329                         
2330                         if (horizontal) {
2331                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2332                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2333                         }
2334                         else {
2335                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2336                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2337                         }
2338                 }
2339                 widgetbase_draw(&wtb, wcol);
2340                 
2341                 if (state & UI_SCROLL_NO_OUTLINE)
2342                         SWAP(short, outline, wtb.outline);
2343         }       
2344 }
2345
2346 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2347 {
2348         rcti rect1;
2349         double value;
2350         float fac, size, min;
2351         int horizontal;
2352
2353         /* calculate slider part */
2354         value = ui_get_but_val(but);
2355
2356         size = (but->softmax + but->a1 - but->softmin);
2357         size = MAX2(size, 2);
2358         
2359         /* position */
2360         rect1 = *rect;
2361
2362         /* determine horizontal/vertical */
2363         horizontal = (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
2364         
2365         if (horizontal) {
2366                 fac = (rect->xmax - rect->xmin) / (size);
2367                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2368                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2369
2370                 /* ensure minimium size */
2371                 min = rect->ymax - rect->ymin;
2372
2373                 if (rect1.xmax - rect1.xmin < min) {
2374                         rect1.xmax = rect1.xmin + min;
2375
2376                         if (rect1.xmax > rect->xmax) {
2377                                 rect1.xmax = rect->xmax;
2378                                 rect1.xmin = MAX2(rect1.xmax - min, rect->xmin);
2379                         }
2380                 }
2381         }
2382         else {
2383                 fac = (rect->ymax - rect->ymin) / (size);
2384                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2385                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2386
2387                 /* ensure minimium size */
2388                 min = rect->xmax - rect->xmin;
2389
2390                 if (rect1.ymax - rect1.ymin < min) {
2391                         rect1.ymax = rect1.ymin + min;
2392
2393                         if (rect1.ymax > rect->ymax) {
2394                                 rect1.ymax = rect->ymax;
2395                                 rect1.ymin = MAX2(rect1.ymax - min, rect->ymin);
2396                         }
2397                 }
2398         }
2399
2400         if (state & UI_SELECT)
2401                 state = UI_SCROLL_PRESSED;
2402         else
2403                 state = 0;
2404         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2405 }
2406
2407 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2408 {
2409         rcti rect_prog = *rect, rect_bar = *rect;
2410         float value = but->a1;
2411         float w, min;
2412         
2413         /* make the progress bar a proportion of the original height */
2414         /* hardcoded 4px high for now */
2415         rect_prog.ymax = rect_prog.ymin + 4;
2416         rect_bar.ymax = rect_bar.ymin + 4;
2417         
2418         w = value * (rect_prog.xmax - rect_prog.xmin);
2419         
2420         /* ensure minimium size */
2421         min = rect_prog.ymax - rect_prog.ymin;
2422         w = MAX2(w, min);
2423         
2424         rect_bar.xmax = rect_bar.xmin + w;
2425                 
2426         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2427         
2428         /* raise text a bit */
2429         rect->ymin += 6;
2430         rect->xmin -= 6;
2431 }
2432
2433 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2434 {
2435         
2436         if (but->flag & UI_SELECT) {
2437                 rcti rectlink;
2438                 
2439                 UI_ThemeColor(TH_TEXT_HI);
2440                 
2441                 rectlink.xmin = (rect->xmin + rect->xmax) / 2;
2442                 rectlink.ymin = (rect->ymin + rect->ymax) / 2;
2443                 rectlink.xmax = but->linkto[0];
2444                 rectlink.ymax = but->linkto[1];
2445                 
2446                 ui_draw_link_bezier(&rectlink);
2447         }
2448 }
2449
2450 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2451 {
2452         uiWidgetBase wtb, wtb1;
2453         rcti rect1;
2454         double value;
2455         float offs, toffs, fac;
2456         char outline[3];
2457
2458         widget_init(&wtb);
2459         widget_init(&wtb1);
2460         
2461         /* backdrop first */
2462         
2463         /* fully rounded */
2464         offs = 0.5f * (rect->ymax - rect->ymin);
2465         toffs = offs * 0.75f;
2466         round_box_edges(&wtb, roundboxalign, rect, offs);
2467
2468         wtb.outline = 0;
2469         widgetbase_draw(&wtb, wcol);
2470         
2471         /* draw left/right parts only when not in text editing */
2472         if (!(state & UI_TEXTINPUT)) {
2473                 
2474                 /* slider part */
2475                 copy_v3_v3_char(outline, wcol->outline);
2476                 copy_v3_v3_char(wcol->outline, wcol->item);
2477                 copy_v3_v3_char(wcol->inner, wcol->item);
2478
2479                 if (!(state & UI_SELECT))
2480                         SWAP(short, wcol->shadetop, wcol->shadedown);
2481                 
2482                 rect1 = *rect;
2483                 
2484                 value = ui_get_but_val(but);
2485                 fac = ((float)value - but->softmin) * (rect1.xmax - rect1.xmin - offs) / (but->softmax - but->softmin);
2486                 
2487                 /* left part of slider, always rounded */
2488                 rect1.xmax = rect1.xmin + ceil(offs + 1.0f);
2489                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2490                 wtb1.outline = 0;
2491                 widgetbase_draw(&wtb1, wcol);
2492                 
2493                 /* right part of slider, interpolate roundness */
2494                 rect1.xmax = rect1.xmin + fac + offs;
2495                 rect1.xmin +=  floor(offs - 1.0f);
2496                 if (rect1.xmax + offs > rect->xmax)
2497                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2498                 else 
2499                         offs = 0.0f;
2500                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2501                 
2502                 widgetbase_draw(&wtb1, wcol);
2503                 copy_v3_v3_char(wcol->outline, outline);
2504                 
2505                 if (!(state & UI_SELECT))
2506                         SWAP(short, wcol->shadetop, wcol->shadedown);
2507         }
2508         
2509         /* outline */
2510         wtb.outline = 1;
2511         wtb.inner = 0;
2512         widgetbase_draw(&wtb, wcol);
2513         
2514         /* text space */
2515         rect->xmin += toffs;
2516         rect->xmax -= toffs;
2517 }
2518
2519 /* I think 3 is sufficient border to indicate keyed status */
2520 #define SWATCH_KEYED_BORDER 3
2521
2522 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2523 {
2524         uiWidgetBase wtb;
2525         float col[4];
2526         int color_profile = but->block->color_profile;
2527         
2528         col[3] = 1.0f;
2529
2530         if (but->rnaprop) {
2531                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2532                         color_profile = BLI_PR_NONE;
2533
2534                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2535                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2536                 }
2537         }
2538         
2539         widget_init(&wtb);
2540         
2541         /* half rounded */
2542         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
2543                 
2544         ui_get_but_vectorf(but, col);
2545         
2546         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2547                 // draw based on state - color for keyed etc
2548                 widgetbase_draw(&wtb, wcol);
2549                 
2550                 // inset to draw swatch color
2551                 rect->xmin += SWATCH_KEYED_BORDER;
2552                 rect->xmax -= SWATCH_KEYED_BORDER;
2553                 rect->ymin += SWATCH_KEYED_BORDER;
2554                 rect->ymax -= SWATCH_KEYED_BORDER;
2555                 
2556                 round_box_edges(&wtb, roundboxalign, rect, 5.0f);
2557         }
2558         
2559         if (color_profile)
2560                 linearrgb_to_srgb_v3_v3(col, col);
2561         
2562         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2563
2564         wcol->shaded = 0;
2565         wcol->alpha_check = (wcol->inner[3] < 255);
2566
2567         widgetbase_draw(&wtb, wcol);
2568         
2569 }
2570
2571 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2572 {
2573         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2574                 uiWidgetBase wtb;
2575         
2576                 widget_init(&wtb);
2577                 wtb.outline = 0;
2578                 
2579                 /* rounded */
2580                 round_box_edges(&wtb, UI_CNR_ALL, rect, 10.0f);
2581                 widgetbase_draw(&wtb, wcol);
2582         }       
2583 }
2584
2585
2586 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2587 {
2588         uiWidgetBase wtb;
2589         
2590         if (state & UI_SELECT)
2591                 SWAP(short, wcol->shadetop, wcol->shadedown);
2592         
2593         widget_init(&wtb);
2594         
2595         /* half rounded */
2596         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2597         
2598         widgetbase_draw(&wtb, wcol);
2599
2600 }
2601
2602
2603 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2604 {
2605         uiWidgetBase wtb;
2606         
2607         widget_init(&wtb);
2608         
2609         /* half rounded */
2610         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2611         
2612         /* decoration */
2613         widget_menu_trias(&wtb.tria1, rect);
2614         
2615         widgetbase_draw(&wtb, wcol);
2616         
2617         /* text space */
2618         rect->xmax -= (rect->ymax - rect->ymin);
2619 }
2620
2621 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2622 {
2623         uiWidgetBase wtb;
2624         
2625         widget_init(&wtb);
2626         
2627         /* half rounded */
2628         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2629         
2630         /* decoration */
2631         widgetbase_draw(&wtb, wcol);
2632 }
2633
2634 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2635 {
2636         /* silly node link button hacks */
2637         uiWidgetBase wtb;
2638         uiWidgetColors wcol_backup = *wcol;
2639         
2640         widget_init(&wtb);
2641         
2642         /* half rounded */
2643         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2644
2645         wcol->inner[0] += 15;
2646         wcol->inner[1] += 15;
2647         wcol->inner[2] += 15;
2648         wcol->outline[0] += 15;
2649         wcol->outline[1] += 15;
2650         wcol->outline[2] += 15;
2651         
2652         /* decoration */
2653         widgetbase_draw(&wtb, wcol);
2654         *wcol = wcol_backup;
2655 }
2656
2657 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2658 {
2659         if (state & UI_ACTIVE) {
2660                 uiWidgetBase wtb;
2661                 float rad = 0.5f * (rect->ymax - rect->ymin); // 4.0f
2662                 
2663                 widget_init(&wtb);
2664                 
2665                 /* half rounded */
2666                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2667                 
2668                 widgetbase_draw(&wtb, wcol);
2669         }
2670 }
2671
2672 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2673 {
2674         uiWidgetBase wtb;
2675         
2676         widget_init(&wtb);
2677         
2678         /* not rounded, no outline */
2679         wtb.outline = 0;
2680         round_box_edges(&wtb, 0, rect, 0.0f);
2681         
2682         widgetbase_draw(&wtb, wcol);
2683 }
2684
2685 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2686 {
2687         uiWidgetBase wtb;
2688         
2689         widget_init(&wtb);
2690         
2691         /* rounded, but no outline */
2692         wtb.outline = 0;
2693         round_box_edges(&wtb, UI_CNR_ALL, rect, 4.0f);
2694         
2695         widgetbase_draw(&wtb, wcol);
2696 }
2697
2698 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2699 {
2700         uiWidgetBase wtb;
2701         rcti recttemp = *rect;
2702         int delta;
2703         
2704         widget_init(&wtb);
2705         
2706         /* square */
2707         recttemp.xmax = recttemp.xmin + (recttemp.ymax - recttemp.ymin);
2708         
2709         /* smaller */
2710         delta = 1 + (recttemp.ymax - recttemp.ymin) / 8;
2711         recttemp.xmin += delta;
2712         recttemp.ymin += delta;
2713         recttemp.xmax -= delta;
2714         recttemp.ymax -= delta;
2715         
2716         /* half rounded */
2717         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, 4.0f);
2718         
2719         /* decoration */
2720         if (state & UI_SELECT) {
2721                 widget_check_trias(&wtb.tria1, &recttemp);
2722         }
2723         
2724         widgetbase_draw(&wtb, wcol);
2725         
2726         /* text space */
2727         rect->xmin += (rect->ymax - rect->ymin) * 0.7 + delta;
2728 }
2729
2730
2731 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2732 {
2733         uiWidgetBase wtb;
2734         
2735         widget_init(&wtb);
2736         
2737         /* half rounded */
2738         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2739         
2740         widgetbase_draw(&wtb, wcol);
2741
2742 }
2743
2744 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2745 {
2746         uiWidgetBase wtb;
2747         char old_col[3];
2748         
2749         widget_init(&wtb);
2750         
2751         copy_v3_v3_char(old_col, wcol->inner);
2752         
2753         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2754         if (but->col[3]) {
2755                 wcol->inner[0] = but->col[0];
2756                 wcol->inner[1] = but->col[1];
2757                 wcol->inner[2] = but->col[2];
2758         }
2759         
2760         /* half rounded */
2761         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2762         
2763         widgetbase_draw(&wtb, wcol);
2764         
2765         /* store the box bg as gl clearcolor, to retrieve later when drawing semi-transparent rects
2766          * over the top to indicate disabled buttons */
2767         /* XXX, this doesnt work right since the color applies to buttons outside the box too. */
2768         glClearColor(wcol->inner[0] / 255.0, wcol->inner[1] / 255.0, wcol->inner[2] / 255.0, 1.0);
2769         
2770         copy_v3_v3_char(wcol->inner, old_col);
2771 }
2772
2773 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2774 {
2775         uiWidgetBase wtb;
2776         
2777         widget_init(&wtb);
2778         
2779         /* half rounded */
2780         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2781                 
2782         widgetbase_draw(&wtb, wcol);
2783
2784 }
2785
2786 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2787 {
2788         uiWidgetBase wtb;
2789         float rad = 5.0f; //0.5f*(rect->ymax - rect->ymin);
2790         
2791         widget_init(&wtb);
2792         
2793         /* half rounded */
2794         round_box_edges(&wtb, roundboxalign, rect, rad);
2795
2796         widgetbase_draw(&wtb, wcol);
2797 }
2798
2799 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2800 {
2801         uiWidgetBase wtb;
2802         unsigned char col[4];
2803         
2804         /* state copy! */
2805         wt->wcol = *(wt->wcol_theme);
2806         
2807         widget_init(&wtb);
2808         
2809         if (but->block->drawextra) {
2810                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2811                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2812                 
2813                 /* make mask to draw over image */
2814                 UI_GetThemeColor3ubv(TH_BACK, col);
2815                 glColor3ubv(col);
2816                 
2817                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, 4.0);
2818                 widgetbase_outline(&wtb);
2819         }
2820         
2821         /* outline */
2822         round_box_edges(&wtb, UI_CNR_ALL, rect, 5.0f);
2823         wtb.outline = 1;
2824         wtb.inner = 0;
2825         widgetbase_draw(&wtb, &wt->wcol);
2826         
2827 }
2828
2829
2830 static void widget_disabled(rcti *rect)
2831 {
2832         float col[4];
2833         
2834         glEnable(GL_BLEND);
2835         
2836         /* can't use theme TH_BACK or TH_PANEL... undefined */
2837         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2838         glColor4f(col[0], col[1], col[2], 0.5f);
2839
2840         /* need -1 and +1 to make it work right for aligned buttons,
2841          * but problem may be somewhere else? */
2842         glRectf(rect->xmin - 1, rect->ymin - 1, rect->xmax, rect->ymax + 1);
2843         
2844         glDisable(GL_BLEND);
2845 }
2846
2847 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2848 {
2849         bTheme *btheme = UI_GetTheme();
2850         static uiWidgetType wt;
2851         
2852         /* defaults */
2853         wt.wcol_theme = &btheme->tui.wcol_regular;
2854         wt.wcol_state = &btheme->tui.wcol_state;
2855         wt.state = widget_state;
2856         wt.draw = widget_but;
2857         wt.custom = NULL;
2858         wt.text = widget_draw_text_icon;
2859         
2860         switch (type) {
2861                 case UI_WTYPE_REGULAR:
2862                         break;
2863
2864                 case UI_WTYPE_LABEL:
2865                         wt.draw = NULL;
2866                         wt.state = widget_state_label;
2867                         break;
2868                         
2869                 case UI_WTYPE_TOGGLE:
2870                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2871                         break;
2872                         
2873                 case UI_WTYPE_OPTION:
2874                         wt.wcol_theme = &btheme->tui.wcol_option;
2875                         wt.draw = widget_optionbut;
2876                         break;
2877                         
2878                 case UI_WTYPE_RADIO:
2879                         wt.wcol_theme = &btheme->tui.wcol_radio;
2880                         wt.draw = widget_radiobut;
2881                         break;
2882
2883                 case UI_WTYPE_NUMBER:
2884                         wt.wcol_theme = &btheme->tui.wcol_num;
2885                         wt.draw = widget_numbut;
2886                         break;
2887                         
2888                 case UI_WTYPE_SLIDER:
2889                         wt.wcol_theme = &btheme->tui.wcol_numslider;
2890                         wt.custom = widget_numslider;
2891                         wt.state = widget_state_numslider;
2892                         break;
2893                         
2894                 case UI_WTYPE_EXEC:
2895                         wt.wcol_theme = &btheme->tui.wcol_tool;
2896                         wt.draw = widget_roundbut;
2897                         break;
2898
2899                 case UI_WTYPE_TOOLTIP:
2900                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
2901                         wt.draw = widget_menu_back;
2902                         break;
2903                         
2904                         
2905                 /* strings */
2906                 case UI_WTYPE_NAME:
2907                         wt.wcol_theme = &btheme->tui.wcol_text;
2908                         wt.draw = widget_textbut;
2909                         break;
2910                         
2911                 case UI_WTYPE_NAME_LINK:
2912                         break;
2913                         
2914                 case UI_WTYPE_POINTER_LINK:
2915                         break;
2916                         
2917                 case UI_WTYPE_FILENAME:
2918                         break;
2919                         
2920                         
2921                 /* start menus */
2922                 case UI_WTYPE_MENU_RADIO:
2923                         wt.wcol_theme = &btheme->tui.wcol_menu;
2924                         wt.draw = widget_menubut;
2925                         break;
2926
2927                 case UI_WTYPE_MENU_ICON_RADIO:
2928                         wt.wcol_theme = &btheme->tui.wcol_menu;
2929                         wt.draw = widget_menuiconbut;
2930                         break;
2931                         
2932                 case UI_WTYPE_MENU_POINTER_LINK:
2933                         wt.wcol_theme = &btheme->tui.wcol_menu;
2934                         wt.draw = widget_menubut;
2935                         break;
2936
2937                 case UI_WTYPE_MENU_NODE_LINK:
2938                         wt.wcol_theme = &btheme->tui.wcol_menu;
2939                         wt.draw = widget_menunodebut;
2940                         break;
2941                         
2942                 case UI_WTYPE_PULLDOWN:
2943                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
2944                         wt.draw = widget_pulldownbut;
2945                         wt.state = widget_state_pulldown;
2946                         break;
2947                         
2948                 /* in menus */
2949                 case UI_WTYPE_MENU_ITEM:
2950                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
2951                         wt.draw = widget_menu_itembut;
2952                         wt.state = widget_state_menu_item;
2953                         break;
2954                         
2955                 case UI_WTYPE_MENU_BACK:
2956                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
2957                         wt.draw = widget_menu_back;
2958                         break;
2959                         
2960                 /* specials */
2961                 case UI_WTYPE_ICON:
2962                         wt.custom = widget_icon_has_anim;
2963                         break;
2964                         
2965                 case UI_WTYPE_SWATCH:
2966                         wt.custom = widget_swatch;
2967                         break;
2968                         
2969                 case UI_WTYPE_BOX:
2970                         wt.custom = widget_box;
2971                         wt.wcol_theme = &btheme->tui.wcol_box;
2972                         break;
2973                         
2974                 case UI_WTYPE_RGB_PICKER:
2975                         break;
2976                         
2977                 case UI_WTYPE_NORMAL:
2978                         break;
2979
2980                 case UI_WTYPE_SCROLL:
2981                         wt.wcol_theme = &btheme->tui.wcol_scroll;
2982                         wt.state = widget_state_nothing;
2983                         wt.custom = widget_scroll;
2984                         break;
2985
2986                 case UI_WTYPE_LISTITEM:
2987                         wt.wcol_theme = &btheme->tui.wcol_list_item;
2988                         wt.draw = widget_list_itembut;
2989                         break;
2990                         
2991                 case UI_WTYPE_PROGRESSBAR:
2992                         wt.wcol_theme = &btheme->tui.wcol_progress;
2993                         wt.custom = widget_progressbar;
2994                         break;
2995         }
2996         
2997         return &wt;
2998 }
2999
3000
3001 static int widget_roundbox_set(uiBut *but, rcti *rect)
3002 {
3003         /* alignment */
3004         if (but->flag & UI_BUT_ALIGN) {
3005                 
3006                 if (but->flag & UI_BUT_ALIGN_TOP)
3007                         rect->ymax += 1;
3008                 if (but->flag & UI_BUT_ALIGN_LEFT)
3009                         rect->xmin -= 1;
3010                 
3011                 switch (but->flag & UI_BUT_ALIGN) {
3012                         case UI_BUT_ALIGN_TOP:
3013                                 return UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
3014                         case UI_BUT_ALIGN_DOWN:
3015                                 return UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
3016                         case UI_BUT_ALIGN_LEFT:
3017                                 return UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
3018                         case UI_BUT_ALIGN_RIGHT:
3019                                 return UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
3020                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
3021                                 return UI_CNR_TOP_LEFT;
3022                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
3023                                 return UI_CNR_TOP_RIGHT;
3024                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
3025                                 return UI_CNR_BOTTOM_LEFT;
3026                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
3027                                 return UI_CNR_BOTTOM_RIGHT;
3028                         default:
3029                                 return 0;
3030                 }
3031         }
3032
3033         return UI_CNR_ALL;
3034 }
3035
3036 /* conversion from old to new buttons, so still messy */
3037 void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
3038 {
3039         bTheme *btheme = UI_GetTheme();
3040         ThemeUI *tui = &btheme->tui;
3041         uiFontStyle *fstyle = &style->widget;
3042         uiWidgetType *wt = NULL;
3043
3044         /* handle menus separately */
3045         if (but->dt == UI_EMBOSSP) {
3046                 switch (but->type) {
3047                         case LABEL:
3048                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
3049                                 break;
3050                         case SEPR:
3051                                 ui_draw_separator(rect, &tui->wcol_menu_item);
3052                                 break;
3053                                 
3054                         default:
3055                                 wt = widget_type(UI_WTYPE_MENU_ITEM);
3056                 }
3057         }
3058         else if (but->dt == UI_EMBOSSN) {
3059                 /* "nothing" */
3060                 wt = widget_type(UI_WTYPE_ICON);
3061         }
3062         else {
3063                 
3064                 switch (but->type) {
3065                         case LABEL:
3066                                 if (but->block->flag & UI_BLOCK_LOOP)
3067                                         widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
3068                                 else {
3069                                         wt = widget_type(UI_WTYPE_LABEL);
3070                                         fstyle = &style->widgetlabel;
3071                                 }
3072                                 break;
3073                                 
3074                         case SEPR:
3075                                 break;
3076                                 
3077                         case BUT:
3078                                 wt = widget_type(UI_WTYPE_EXEC);
3079                                 break;
3080
3081                         case NUM:
3082                                 wt = widget_type(UI_WTYPE_NUMBER);
3083                                 break;
3084                                 
3085                         case NUMSLI:
3086                         case HSVSLI:
3087                                 wt = widget_type(UI_WTYPE_SLIDER);
3088                                 break;
3089                                 
3090                         case ROW:
3091                                 wt = widget_type(UI_WTYPE_RADIO);
3092                                 break;
3093
3094                         case LISTROW:
3095                                 wt = widget_type(UI_WTYPE_LISTITEM);
3096                                 break;
3097                                 
3098                         case TEX:
3099                                 wt = widget_type(UI_WTYPE_NAME);
3100                                 break;
3101                                 
3102                         case SEARCH_MENU:
3103                                 wt = widget_type(UI_WTYPE_NAME);
3104                                 if (but->block->flag & UI_BLOCK_LOOP)
3105                                         wt->wcol_theme = &btheme->tui.wcol_menu_back;
3106                                 break;
3107                                 
3108                         case TOGBUT:
3109                         case TOG:
3110                         case TOGN:
3111                         case TOG3:
3112                                 wt = widget_type(UI_WTYPE_TOGGLE);
3113                                 break;
3114                                 
3115                         case OPTION:
3116                         case OPTIONN:
3117                                 if (!(but->flag & UI_HAS_ICON)) {
3118                                         wt = widget_type(UI_WTYPE_OPTION);
3119                                         but->flag |= UI_TEXT_LEFT;
3120                                 }
3121                                 else
3122                                         wt = widget_type(UI_WTYPE_TOGGLE);
3123                                 
3124                                 /* option buttons have strings outside, on menus use different colors */
3125                                 if (but->block->flag & UI_BLOCK_LOOP)
3126                                         wt->state = widget_state_option_menu;
3127