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