add vector versions of hsv_to_rgb, rgb_to_hsv & rgb_to_hsv_compat
[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_v(rgb, hsv);
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_v(hsv, col);
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];
2085         float x = 0.0f, y = 0.0f;
2086         float *hsv = ui_block_hsv_get(but->block);
2087         float hsv_n[3];
2088         
2089         copy_v3_v3(hsv_n, hsv);
2090         
2091         ui_get_but_vectorf(but, rgb);
2092         rgb_to_hsv_compat_v(rgb, hsv_n);
2093         
2094         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2095         
2096         switch ((int)but->a1) {
2097                 case UI_GRAD_SV:
2098                         x = hsv_n[2]; y = hsv_n[1]; break;
2099                 case UI_GRAD_HV:
2100                         x = hsv_n[0]; y = hsv_n[2]; break;
2101                 case UI_GRAD_HS:
2102                         x = hsv_n[0]; y = hsv_n[1]; break;
2103                 case UI_GRAD_H:
2104                         x = hsv_n[0]; y = 0.5; break;
2105                 case UI_GRAD_S:
2106                         x = hsv_n[1]; y = 0.5; break;
2107                 case UI_GRAD_V:
2108                         x = hsv_n[2]; y = 0.5; break;
2109         }
2110         
2111         /* cursor */
2112         x = rect->xmin + x * (rect->xmax - rect->xmin);
2113         y = rect->ymin + y * (rect->ymax - rect->ymin);
2114         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2115         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2116         
2117         ui_hsv_cursor(x, y);
2118         
2119         /* outline */
2120         glColor3ub(0,  0,  0);
2121         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2122 }
2123
2124 /* vertical 'value' slider, using new widget code */
2125 static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
2126 {
2127         uiWidgetBase wtb;
2128         float rad = 0.5f * (rect->xmax - rect->xmin);
2129         float x, y;
2130         float rgb[3], hsv[3], v, range;
2131         int color_profile = but->block->color_profile;
2132         
2133         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2134                 color_profile = BLI_PR_NONE;
2135
2136         ui_get_but_vectorf(but, rgb);
2137         rgb_to_hsv_v(rgb, hsv);
2138         v = hsv[2];
2139         
2140         if (color_profile)
2141                 v = linearrgb_to_srgb(v);
2142
2143         /* map v from property range to [0,1] */
2144         range = but->softmax - but->softmin;
2145         v = (v - but->softmin) / range;
2146         
2147         widget_init(&wtb);
2148         
2149         /* fully rounded */
2150         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2151         
2152         /* setup temp colors */
2153         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2154         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2155         wcol_tmp.shadetop = 127;
2156         wcol_tmp.shadedown = -128;
2157         wcol_tmp.shaded = 1;
2158         
2159         widgetbase_draw(&wtb, &wcol_tmp);
2160
2161         /* cursor */
2162         x = rect->xmin + 0.5f * (rect->xmax - rect->xmin);
2163         y = rect->ymin + v * (rect->ymax - rect->ymin);
2164         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2165         
2166         ui_hsv_cursor(x, y);
2167         
2168 }
2169
2170
2171 /* ************ separator, for menus etc ***************** */
2172 static void ui_draw_separator(rcti *rect,  uiWidgetColors *wcol)
2173 {
2174         int y = rect->ymin + (rect->ymax - rect->ymin) / 2 - 1;
2175         unsigned char col[4];
2176         
2177         col[0] = wcol->text[0];
2178         col[1] = wcol->text[1];
2179         col[2] = wcol->text[2];
2180         col[3] = 7;
2181         
2182         glEnable(GL_BLEND);
2183         glColor4ubv(col);
2184         sdrawline(rect->xmin, y, rect->xmax, y);
2185         glDisable(GL_BLEND);
2186 }
2187
2188 /* ************ button callbacks, draw ***************** */
2189
2190 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2191 {
2192         uiWidgetBase wtb;
2193         float rad = 0.5f * (rect->ymax - rect->ymin);
2194         float textofs = rad * 0.75f;
2195
2196         if (state & UI_SELECT)
2197                 SWAP(short, wcol->shadetop, wcol->shadedown);
2198         
2199         widget_init(&wtb);
2200         
2201         /* fully rounded */
2202         round_box_edges(&wtb, roundboxalign, rect, rad);
2203         
2204         /* decoration */
2205         if (!(state & UI_TEXTINPUT)) {
2206                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2207                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2208         }
2209
2210         widgetbase_draw(&wtb, wcol);
2211         
2212         /* text space */
2213         rect->xmin += textofs;
2214         rect->xmax -= textofs;
2215 }
2216
2217 //static int ui_link_bezier_points(rcti *rect, float coord_array[][2], int resol)
2218 int ui_link_bezier_points(rcti *rect, float coord_array[][2], int resol)
2219 {
2220         float dist, vec[4][2];
2221
2222         vec[0][0] = rect->xmin;
2223         vec[0][1] = rect->ymin;
2224         vec[3][0] = rect->xmax;
2225         vec[3][1] = rect->ymax;
2226         
2227         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2228         
2229         vec[1][0] = vec[0][0] + dist;
2230         vec[1][1] = vec[0][1];
2231         
2232         vec[2][0] = vec[3][0] - dist;
2233         vec[2][1] = vec[3][1];
2234         
2235         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2236         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);
2237         
2238         return 1;
2239 }
2240
2241 #define LINK_RESOL  24
2242 void ui_draw_link_bezier(rcti *rect)
2243 {
2244         float coord_array[LINK_RESOL + 1][2];
2245         
2246         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2247                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2248                 // const float dist= 1.0f/(float)LINK_RESOL; // UNUSED
2249
2250                 glEnable(GL_BLEND);
2251                 glEnable(GL_LINE_SMOOTH);
2252
2253                 glEnableClientState(GL_VERTEX_ARRAY);
2254                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2255                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL);
2256                 glDisableClientState(GL_VERTEX_ARRAY);
2257
2258                 glDisable(GL_BLEND);
2259                 glDisable(GL_LINE_SMOOTH);
2260
2261         }
2262 }
2263
2264 /* function in use for buttons and for view2d sliders */
2265 void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int state)
2266 {
2267         uiWidgetBase wtb;
2268         float rad;
2269         int horizontal;
2270         short outline = 0;
2271
2272         widget_init(&wtb);
2273
2274         /* determine horizontal/vertical */
2275         horizontal = (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
2276         
2277         if (horizontal)
2278                 rad = 0.5f * (rect->ymax - rect->ymin);
2279         else
2280                 rad = 0.5f * (rect->xmax - rect->xmin);
2281         
2282         wtb.shadedir = (horizontal) ? 1 : 0;
2283         
2284         /* draw back part, colors swapped and shading inverted */
2285         if (horizontal)
2286                 SWAP(short, wcol->shadetop, wcol->shadedown);
2287         
2288         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2289         widgetbase_draw(&wtb, wcol);
2290         
2291         /* slider */
2292         if (slider->xmax - slider->xmin < 2 || slider->ymax - slider->ymin < 2) ;
2293         else {
2294                 
2295                 SWAP(short, wcol->shadetop, wcol->shadedown);
2296                 
2297                 copy_v4_v4_char(wcol->inner, wcol->item);
2298                 
2299                 if (wcol->shadetop > wcol->shadedown)
2300                         wcol->shadetop += 20;   /* XXX violates themes... */
2301                 else wcol->shadedown += 20;
2302                 
2303                 if (state & UI_SCROLL_PRESSED) {
2304                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2305                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2306                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2307                 }
2308
2309                 /* draw */
2310                 wtb.emboss = 0; /* only emboss once */
2311                 
2312                 /* exception for progress bar */
2313                 if (state & UI_SCROLL_NO_OUTLINE)       
2314                         SWAP(short, outline, wtb.outline);
2315                 
2316                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2317                 
2318                 if (state & UI_SCROLL_ARROWS) {
2319                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2320                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2321                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2322                         wcol->item[3] = 255;
2323                         
2324                         if (horizontal) {
2325                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2326                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2327                         }
2328                         else {
2329                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2330                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2331                         }
2332                 }
2333                 widgetbase_draw(&wtb, wcol);
2334                 
2335                 if (state & UI_SCROLL_NO_OUTLINE)
2336                         SWAP(short, outline, wtb.outline);
2337         }       
2338 }
2339
2340 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2341 {
2342         rcti rect1;
2343         double value;
2344         float fac, size, min;
2345         int horizontal;
2346
2347         /* calculate slider part */
2348         value = ui_get_but_val(but);
2349
2350         size = (but->softmax + but->a1 - but->softmin);
2351         size = MAX2(size, 2);
2352         
2353         /* position */
2354         rect1 = *rect;
2355
2356         /* determine horizontal/vertical */
2357         horizontal = (rect->xmax - rect->xmin > rect->ymax - rect->ymin);
2358         
2359         if (horizontal) {
2360                 fac = (rect->xmax - rect->xmin) / (size);
2361                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2362                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2363
2364                 /* ensure minimium size */
2365                 min = rect->ymax - rect->ymin;
2366
2367                 if (rect1.xmax - rect1.xmin < min) {
2368                         rect1.xmax = rect1.xmin + min;
2369
2370                         if (rect1.xmax > rect->xmax) {
2371                                 rect1.xmax = rect->xmax;
2372                                 rect1.xmin = MAX2(rect1.xmax - min, rect->xmin);
2373                         }
2374                 }
2375         }
2376         else {
2377                 fac = (rect->ymax - rect->ymin) / (size);
2378                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2379                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2380
2381                 /* ensure minimium size */
2382                 min = rect->xmax - rect->xmin;
2383
2384                 if (rect1.ymax - rect1.ymin < min) {
2385                         rect1.ymax = rect1.ymin + min;
2386
2387                         if (rect1.ymax > rect->ymax) {
2388                                 rect1.ymax = rect->ymax;
2389                                 rect1.ymin = MAX2(rect1.ymax - min, rect->ymin);
2390                         }
2391                 }
2392         }
2393
2394         if (state & UI_SELECT)
2395                 state = UI_SCROLL_PRESSED;
2396         else
2397                 state = 0;
2398         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2399 }
2400
2401 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2402 {
2403         rcti rect_prog = *rect, rect_bar = *rect;
2404         float value = but->a1;
2405         float w, min;
2406         
2407         /* make the progress bar a proportion of the original height */
2408         /* hardcoded 4px high for now */
2409         rect_prog.ymax = rect_prog.ymin + 4;
2410         rect_bar.ymax = rect_bar.ymin + 4;
2411         
2412         w = value * (rect_prog.xmax - rect_prog.xmin);
2413         
2414         /* ensure minimium size */
2415         min = rect_prog.ymax - rect_prog.ymin;
2416         w = MAX2(w, min);
2417         
2418         rect_bar.xmax = rect_bar.xmin + w;
2419                 
2420         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2421         
2422         /* raise text a bit */
2423         rect->ymin += 6;
2424         rect->xmin -= 6;
2425 }
2426
2427 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2428 {
2429         
2430         if (but->flag & UI_SELECT) {
2431                 rcti rectlink;
2432                 
2433                 UI_ThemeColor(TH_TEXT_HI);
2434                 
2435                 rectlink.xmin = (rect->xmin + rect->xmax) / 2;
2436                 rectlink.ymin = (rect->ymin + rect->ymax) / 2;
2437                 rectlink.xmax = but->linkto[0];
2438                 rectlink.ymax = but->linkto[1];
2439                 
2440                 ui_draw_link_bezier(&rectlink);
2441         }
2442 }
2443
2444 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2445 {
2446         uiWidgetBase wtb, wtb1;
2447         rcti rect1;
2448         double value;
2449         float offs, toffs, fac;
2450         char outline[3];
2451
2452         widget_init(&wtb);
2453         widget_init(&wtb1);
2454         
2455         /* backdrop first */
2456         
2457         /* fully rounded */
2458         offs = 0.5f * (rect->ymax - rect->ymin);
2459         toffs = offs * 0.75f;
2460         round_box_edges(&wtb, roundboxalign, rect, offs);
2461
2462         wtb.outline = 0;
2463         widgetbase_draw(&wtb, wcol);
2464         
2465         /* draw left/right parts only when not in text editing */
2466         if (!(state & UI_TEXTINPUT)) {
2467                 
2468                 /* slider part */
2469                 copy_v3_v3_char(outline, wcol->outline);
2470                 copy_v3_v3_char(wcol->outline, wcol->item);
2471                 copy_v3_v3_char(wcol->inner, wcol->item);
2472
2473                 if (!(state & UI_SELECT))
2474                         SWAP(short, wcol->shadetop, wcol->shadedown);
2475                 
2476                 rect1 = *rect;
2477                 
2478                 value = ui_get_but_val(but);
2479                 fac = ((float)value - but->softmin) * (rect1.xmax - rect1.xmin - offs) / (but->softmax - but->softmin);
2480                 
2481                 /* left part of slider, always rounded */
2482                 rect1.xmax = rect1.xmin + ceil(offs + 1.0f);
2483                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2484                 wtb1.outline = 0;
2485                 widgetbase_draw(&wtb1, wcol);
2486                 
2487                 /* right part of slider, interpolate roundness */
2488                 rect1.xmax = rect1.xmin + fac + offs;
2489                 rect1.xmin +=  floor(offs - 1.0f);
2490                 if (rect1.xmax + offs > rect->xmax)
2491                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2492                 else 
2493                         offs = 0.0f;
2494                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2495                 
2496                 widgetbase_draw(&wtb1, wcol);
2497                 copy_v3_v3_char(wcol->outline, outline);
2498                 
2499                 if (!(state & UI_SELECT))
2500                         SWAP(short, wcol->shadetop, wcol->shadedown);
2501         }
2502         
2503         /* outline */
2504         wtb.outline = 1;
2505         wtb.inner = 0;
2506         widgetbase_draw(&wtb, wcol);
2507         
2508         /* text space */
2509         rect->xmin += toffs;
2510         rect->xmax -= toffs;
2511 }
2512
2513 /* I think 3 is sufficient border to indicate keyed status */
2514 #define SWATCH_KEYED_BORDER 3
2515
2516 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2517 {
2518         uiWidgetBase wtb;
2519         float col[4];
2520         int color_profile = but->block->color_profile;
2521         
2522         col[3] = 1.0f;
2523
2524         if (but->rnaprop) {
2525                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2526                         color_profile = BLI_PR_NONE;
2527
2528                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2529                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2530                 }
2531         }
2532         
2533         widget_init(&wtb);
2534         
2535         /* half rounded */
2536         round_box_edges(&wtb, roundboxalign, rect, 5.0f);
2537                 
2538         ui_get_but_vectorf(but, col);
2539         
2540         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2541                 // draw based on state - color for keyed etc
2542                 widgetbase_draw(&wtb, wcol);
2543                 
2544                 // inset to draw swatch color
2545                 rect->xmin += SWATCH_KEYED_BORDER;
2546                 rect->xmax -= SWATCH_KEYED_BORDER;
2547                 rect->ymin += SWATCH_KEYED_BORDER;
2548                 rect->ymax -= SWATCH_KEYED_BORDER;
2549                 
2550                 round_box_edges(&wtb, roundboxalign, rect, 5.0f);
2551         }
2552         
2553         if (color_profile)
2554                 linearrgb_to_srgb_v3_v3(col, col);
2555         
2556         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2557
2558         wcol->shaded = 0;
2559         wcol->alpha_check = (wcol->inner[3] < 255);
2560
2561         widgetbase_draw(&wtb, wcol);
2562         
2563 }
2564
2565 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2566 {
2567         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2568                 uiWidgetBase wtb;
2569         
2570                 widget_init(&wtb);
2571                 wtb.outline = 0;
2572                 
2573                 /* rounded */
2574                 round_box_edges(&wtb, UI_CNR_ALL, rect, 10.0f);
2575                 widgetbase_draw(&wtb, wcol);
2576         }       
2577 }
2578
2579
2580 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2581 {
2582         uiWidgetBase wtb;
2583         
2584         if (state & UI_SELECT)
2585                 SWAP(short, wcol->shadetop, wcol->shadedown);
2586         
2587         widget_init(&wtb);
2588         
2589         /* half rounded */
2590         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2591         
2592         widgetbase_draw(&wtb, wcol);
2593
2594 }
2595
2596
2597 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2598 {
2599         uiWidgetBase wtb;
2600         
2601         widget_init(&wtb);
2602         
2603         /* half rounded */
2604         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2605         
2606         /* decoration */
2607         widget_menu_trias(&wtb.tria1, rect);
2608         
2609         widgetbase_draw(&wtb, wcol);
2610         
2611         /* text space */
2612         rect->xmax -= (rect->ymax - rect->ymin);
2613 }
2614
2615 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2616 {
2617         uiWidgetBase wtb;
2618         
2619         widget_init(&wtb);
2620         
2621         /* half rounded */
2622         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2623         
2624         /* decoration */
2625         widgetbase_draw(&wtb, wcol);
2626 }
2627
2628 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2629 {
2630         /* silly node link button hacks */
2631         uiWidgetBase wtb;
2632         uiWidgetColors wcol_backup = *wcol;
2633         
2634         widget_init(&wtb);
2635         
2636         /* half rounded */
2637         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2638
2639         wcol->inner[0] += 15;
2640         wcol->inner[1] += 15;
2641         wcol->inner[2] += 15;
2642         wcol->outline[0] += 15;
2643         wcol->outline[1] += 15;
2644         wcol->outline[2] += 15;
2645         
2646         /* decoration */
2647         widgetbase_draw(&wtb, wcol);
2648         *wcol = wcol_backup;
2649 }
2650
2651 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2652 {
2653         if (state & UI_ACTIVE) {
2654                 uiWidgetBase wtb;
2655                 float rad = 0.5f * (rect->ymax - rect->ymin); // 4.0f
2656                 
2657                 widget_init(&wtb);
2658                 
2659                 /* half rounded */
2660                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2661                 
2662                 widgetbase_draw(&wtb, wcol);
2663         }
2664 }
2665
2666 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2667 {
2668         uiWidgetBase wtb;
2669         
2670         widget_init(&wtb);
2671         
2672         /* not rounded, no outline */
2673         wtb.outline = 0;
2674         round_box_edges(&wtb, 0, rect, 0.0f);
2675         
2676         widgetbase_draw(&wtb, wcol);
2677 }
2678
2679 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2680 {
2681         uiWidgetBase wtb;
2682         
2683         widget_init(&wtb);
2684         
2685         /* rounded, but no outline */
2686         wtb.outline = 0;
2687         round_box_edges(&wtb, UI_CNR_ALL, rect, 4.0f);
2688         
2689         widgetbase_draw(&wtb, wcol);
2690 }
2691
2692 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2693 {
2694         uiWidgetBase wtb;
2695         rcti recttemp = *rect;
2696         int delta;
2697         
2698         widget_init(&wtb);
2699         
2700         /* square */
2701         recttemp.xmax = recttemp.xmin + (recttemp.ymax - recttemp.ymin);
2702         
2703         /* smaller */
2704         delta = 1 + (recttemp.ymax - recttemp.ymin) / 8;
2705         recttemp.xmin += delta;
2706         recttemp.ymin += delta;
2707         recttemp.xmax -= delta;
2708         recttemp.ymax -= delta;
2709         
2710         /* half rounded */
2711         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, 4.0f);
2712         
2713         /* decoration */
2714         if (state & UI_SELECT) {
2715                 widget_check_trias(&wtb.tria1, &recttemp);
2716         }
2717         
2718         widgetbase_draw(&wtb, wcol);
2719         
2720         /* text space */
2721         rect->xmin += (rect->ymax - rect->ymin) * 0.7 + delta;
2722 }
2723
2724
2725 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2726 {
2727         uiWidgetBase wtb;
2728         
2729         widget_init(&wtb);
2730         
2731         /* half rounded */
2732         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2733         
2734         widgetbase_draw(&wtb, wcol);
2735
2736 }
2737
2738 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2739 {
2740         uiWidgetBase wtb;
2741         char old_col[3];
2742         
2743         widget_init(&wtb);
2744         
2745         copy_v3_v3_char(old_col, wcol->inner);
2746         
2747         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2748         if (but->col[3]) {
2749                 wcol->inner[0] = but->col[0];
2750                 wcol->inner[1] = but->col[1];
2751                 wcol->inner[2] = but->col[2];
2752         }
2753         
2754         /* half rounded */
2755         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2756         
2757         widgetbase_draw(&wtb, wcol);
2758         
2759         /* store the box bg as gl clearcolor, to retrieve later when drawing semi-transparent rects
2760          * over the top to indicate disabled buttons */
2761         /* XXX, this doesnt work right since the color applies to buttons outside the box too. */
2762         glClearColor(wcol->inner[0] / 255.0, wcol->inner[1] / 255.0, wcol->inner[2] / 255.0, 1.0);
2763         
2764         copy_v3_v3_char(wcol->inner, old_col);
2765 }
2766
2767 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2768 {
2769         uiWidgetBase wtb;
2770         
2771         widget_init(&wtb);
2772         
2773         /* half rounded */
2774         round_box_edges(&wtb, roundboxalign, rect, 4.0f);
2775                 
2776         widgetbase_draw(&wtb, wcol);
2777
2778 }
2779
2780 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2781 {
2782         uiWidgetBase wtb;
2783         float rad = 5.0f; //0.5f*(rect->ymax - rect->ymin);
2784         
2785         widget_init(&wtb);
2786         
2787         /* half rounded */
2788         round_box_edges(&wtb, roundboxalign, rect, rad);
2789
2790         widgetbase_draw(&wtb, wcol);
2791 }
2792
2793 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2794 {
2795         uiWidgetBase wtb;
2796         unsigned char col[4];
2797         
2798         /* state copy! */
2799         wt->wcol = *(wt->wcol_theme);
2800         
2801         widget_init(&wtb);
2802         
2803         if (but->block->drawextra) {
2804                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2805                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2806                 
2807                 /* make mask to draw over image */
2808                 UI_GetThemeColor3ubv(TH_BACK, col);
2809                 glColor3ubv(col);
2810                 
2811                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, 4.0);
2812                 widgetbase_outline(&wtb);
2813         }
2814         
2815         /* outline */
2816         round_box_edges(&wtb, UI_CNR_ALL, rect, 5.0f);
2817         wtb.outline = 1;
2818         wtb.inner = 0;
2819         widgetbase_draw(&wtb, &wt->wcol);
2820         
2821 }
2822
2823
2824 static void widget_disabled(rcti *rect)
2825 {
2826         float col[4];
2827         
2828         glEnable(GL_BLEND);
2829         
2830         /* can't use theme TH_BACK or TH_PANEL... undefined */
2831         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2832         glColor4f(col[0], col[1], col[2], 0.5f);
2833
2834         /* need -1 and +1 to make it work right for aligned buttons,
2835          * but problem may be somewhere else? */
2836         glRectf(rect->xmin - 1, rect->ymin - 1, rect->xmax, rect->ymax + 1);
2837         
2838         glDisable(GL_BLEND);
2839 }
2840
2841 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2842 {
2843         bTheme *btheme = UI_GetTheme();
2844         static uiWidgetType wt;
2845         
2846         /* defaults */
2847         wt.wcol_theme = &btheme->tui.wcol_regular;
2848         wt.wcol_state = &btheme->tui.wcol_state;
2849         wt.state = widget_state;
2850         wt.draw = widget_but;
2851         wt.custom = NULL;
2852         wt.text = widget_draw_text_icon;
2853         
2854         switch (type) {
2855                 case UI_WTYPE_REGULAR:
2856                         break;
2857
2858                 case UI_WTYPE_LABEL:
2859                         wt.draw = NULL;
2860                         wt.state = widget_state_label;
2861                         break;
2862                         
2863                 case UI_WTYPE_TOGGLE:
2864                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2865                         break;
2866                         
2867                 case UI_WTYPE_OPTION:
2868                         wt.wcol_theme = &btheme->tui.wcol_option;
2869                         wt.draw = widget_optionbut;
2870                         break;
2871                         
2872                 case UI_WTYPE_RADIO:
2873                         wt.wcol_theme = &btheme->tui.wcol_radio;
2874                         wt.draw = widget_radiobut;
2875                         break;
2876
2877                 case UI_WTYPE_NUMBER:
2878                         wt.wcol_theme = &btheme->tui.wcol_num;
2879                         wt.draw = widget_numbut;
2880                         break;
2881                         
2882                 case UI_WTYPE_SLIDER:
2883                         wt.wcol_theme = &btheme->tui.wcol_numslider;
2884                         wt.custom = widget_numslider;
2885                         wt.state = widget_state_numslider;
2886                         break;
2887                         
2888                 case UI_WTYPE_EXEC:
2889                         wt.wcol_theme = &btheme->tui.wcol_tool;
2890                         wt.draw = widget_roundbut;
2891                         break;
2892
2893                 case UI_WTYPE_TOOLTIP:
2894                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
2895                         wt.draw = widget_menu_back;
2896                         break;
2897                         
2898                         
2899                 /* strings */
2900                 case UI_WTYPE_NAME:
2901                         wt.wcol_theme = &btheme->tui.wcol_text;
2902                         wt.draw = widget_textbut;
2903                         break;
2904                         
2905                 case UI_WTYPE_NAME_LINK:
2906                         break;
2907                         
2908                 case UI_WTYPE_POINTER_LINK:
2909                         break;
2910                         
2911                 case UI_WTYPE_FILENAME:
2912                         break;
2913                         
2914                         
2915                 /* start menus */
2916                 case UI_WTYPE_MENU_RADIO:
2917                         wt.wcol_theme = &btheme->tui.wcol_menu;
2918                         wt.draw = widget_menubut;
2919                         break;
2920
2921                 case UI_WTYPE_MENU_ICON_RADIO:
2922                         wt.wcol_theme = &btheme->tui.wcol_menu;
2923                         wt.draw = widget_menuiconbut;
2924                         break;
2925                         
2926                 case UI_WTYPE_MENU_POINTER_LINK:
2927                         wt.wcol_theme = &btheme->tui.wcol_menu;
2928                         wt.draw = widget_menubut;
2929                         break;
2930
2931                 case UI_WTYPE_MENU_NODE_LINK:
2932                         wt.wcol_theme = &btheme->tui.wcol_menu;
2933                         wt.draw = widget_menunodebut;
2934                         break;
2935                         
2936                 case UI_WTYPE_PULLDOWN:
2937                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
2938                         wt.draw = widget_pulldownbut;
2939                         wt.state = widget_state_pulldown;
2940                         break;
2941                         
2942                 /* in menus */
2943                 case UI_WTYPE_MENU_ITEM:
2944                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
2945                         wt.draw = widget_menu_itembut;
2946                         wt.state = widget_state_menu_item;
2947                         break;
2948                         
2949                 case UI_WTYPE_MENU_BACK:
2950                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
2951                         wt.draw = widget_menu_back;
2952                         break;
2953                         
2954                 /* specials */
2955                 case UI_WTYPE_ICON:
2956                         wt.custom = widget_icon_has_anim;
2957                         break;
2958                         
2959                 case UI_WTYPE_SWATCH:
2960                         wt.custom = widget_swatch;
2961                         break;
2962                         
2963                 case UI_WTYPE_BOX:
2964                         wt.custom = widget_box;
2965                         wt.wcol_theme = &btheme->tui.wcol_box;
2966                         break;
2967                         
2968                 case UI_WTYPE_RGB_PICKER:
2969                         break;
2970                         
2971                 case UI_WTYPE_NORMAL:
2972                         break;
2973
2974                 case UI_WTYPE_SCROLL:
2975                         wt.wcol_theme = &btheme->tui.wcol_scroll;
2976                         wt.state = widget_state_nothing;
2977                         wt.custom = widget_scroll;
2978                         break;
2979
2980                 case UI_WTYPE_LISTITEM:
2981                         wt.wcol_theme = &btheme->tui.wcol_list_item;
2982                         wt.draw = widget_list_itembut;
2983                         break;
2984                         
2985                 case UI_WTYPE_PROGRESSBAR:
2986                         wt.wcol_theme = &btheme->tui.wcol_progress;
2987                         wt.custom = widget_progressbar;
2988                         break;
2989         }
2990         
2991         return &wt;
2992 }
2993
2994
2995 static int widget_roundbox_set(uiBut *but, rcti *rect)
2996 {
2997         /* alignment */
2998         if (but->flag & UI_BUT_ALIGN) {
2999                 
3000                 if (but->flag & UI_BUT_ALIGN_TOP)
3001                         rect->ymax += 1;
3002                 if (but->flag & UI_BUT_ALIGN_LEFT)
3003                         rect->xmin -= 1;
3004                 
3005                 switch (but->flag & UI_BUT_ALIGN) {
3006                         case UI_BUT_ALIGN_TOP:
3007                                 return UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
3008                         case UI_BUT_ALIGN_DOWN:
3009                                 return UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
3010                         case UI_BUT_ALIGN_LEFT:
3011                                 return UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
3012                         case UI_BUT_ALIGN_RIGHT:
3013                                 return UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
3014                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
3015                                 return UI_CNR_TOP_LEFT;
3016                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
3017                                 return UI_CNR_TOP_RIGHT;
3018                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
3019                                 return UI_CNR_BOTTOM_LEFT;
3020                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
3021                                 return UI_CNR_BOTTOM_RIGHT;
3022                         default:
3023                                 return 0;
3024                 }
3025         }
3026
3027         return UI_CNR_ALL;
3028 }
3029
3030 /* conversion from old to new buttons, so still messy */
3031 void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
3032 {
3033         bTheme *btheme = UI_GetTheme();
3034         ThemeUI *tui = &btheme->tui;
3035         uiFontStyle *fstyle = &style->widget;
3036         uiWidgetType *wt = NULL;
3037
3038         /* handle menus separately */
3039         if (but->dt == UI_EMBOSSP) {
3040                 switch (but->type) {
3041                         case LABEL:
3042                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
3043                                 break;
3044                         case SEPR:
3045                                 ui_draw_separator(rect, &tui->wcol_menu_item);
3046                                 break;
3047                                 
3048                         default:
3049                                 wt = widget_type(UI_WTYPE_MENU_ITEM);
3050                 }
3051         }
3052         else if (but->dt == UI_EMBOSSN) {
3053                 /* "nothing" */
3054                 wt = widget_type(UI_WTYPE_ICON);
3055         }
3056         else {
3057                 
3058                 switch (but->type) {
3059                         case LABEL:
3060                                 if (but->block->flag & UI_BLOCK_LOOP)
3061                                         widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
3062                                 else {
3063                                         wt = widget_type(UI_WTYPE_LABEL);
3064                                         fstyle = &style->widgetlabel;
3065                                 }
3066                                 break;
3067                                 
3068                         case SEPR:
3069                                 break;
3070                                 
3071                         case BUT:
3072                                 wt = widget_type(UI_WTYPE_EXEC);
3073                                 break;
3074
3075                         case NUM:
3076                                 wt = widget_type(UI_WTYPE_NUMBER);
3077                                 break;
3078                                 
3079                         case NUMSLI:
3080                         case HSVSLI:
3081                                 wt = widget_type(UI_WTYPE_SLIDER);
3082                                 break;
3083                                 
3084                         case ROW:
3085                                 wt = widget_type(UI_WTYPE_RADIO);
3086                                 break;
3087
3088                         case LISTROW:
3089                                 wt = widget_type(UI_WTYPE_LISTITEM);
3090                                 break;
3091                                 
3092                         case TEX:
3093                                 wt = widget_type(UI_WTYPE_NAME);
3094                                 break;
3095                                 
3096                         case SEARCH_MENU:
3097                                 wt = widget_type(UI_WTYPE_NAME);
3098                                 if (but->block->flag & UI_BLOCK_LOOP)
3099                                         wt->wcol_theme = &btheme->tui.wcol_menu_back;
3100                                 break;
3101                                 
3102                         case TOGBUT:
3103                         case TOG:
3104                         case TOGN:
3105                         case TOG3:
3106                                 wt = widget_type(UI_WTYPE_TOGGLE);
3107                                 break;
3108                                 
3109                         case OPTION:
3110                         case OPTIONN:
3111                                 if (!(but->flag & UI_HAS_ICON)) {
3112                                         wt = widget_type(UI_WTYPE_OPTION);
3113                                         but->flag |= UI_TEXT_LEFT;
3114                                 }
3115                                 else
3116                                         wt = widget_type(UI_WTYPE_TOGGLE);
3117                                 
3118                                 /* option buttons have strings outside, on menus use different colors */
3119                                 if (but->block->flag & UI_BLOCK_LOOP)
3120                                         wt->state = widget_state_option_menu;
3121                                 
3122                                 break;
3123                                 
3124                         case MENU:
3125                         case BLOCK:
3126                         case ICONTEXTROW: