Icons now draw good again!
[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], const 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, const 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 + U.pixelsize; /* boundbox inner */
337         float maxxi = maxx - U.pixelsize;
338         float minyi = miny + U.pixelsize;
339         float maxyi = maxy - U.pixelsize;
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 = min_ii(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 - U.pixelsize;
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, const rcti *rect, float rad)
483 {
484         round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
485 }
486
487
488 /* based on button rect, return scaled array of triangles */
489 static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
490 {
491         float centx, centy, sizex, sizey, minsize;
492         int a, i1 = 0, i2 = 1;
493         
494         minsize = min_ii(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, const rcti *rect, float triasize, char where)
525 {
526         float centx, centy, sizex, sizey, minsize;
527         int a, i1 = 0, i2 = 1;
528         
529         minsize = min_ii(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, const 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 * (float)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.4f * (float)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, const 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->inner_v[a][0];
655                 quad_strip[a * 2 + 1][1] = wtb->inner_v[a][1];
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), const 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, const rcti *rect)
865 {
866         float xs = 0.0f, ys = 0.0f;
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         aspect = but->block->aspect / UI_DPI_FAC;
878         height = ICON_DEFAULT_HEIGHT / aspect;
879         
880         /* calculate blend color */
881         if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
882                 if (but->flag & UI_SELECT) {}
883                 else if (but->flag & UI_ACTIVE) {}
884                 else alpha = 0.5f;
885         }
886         
887         /* extra feature allows more alpha blending */
888         if (but->type == LABEL && but->a1 == 1.0f) alpha *= but->a2;
889         
890         glEnable(GL_BLEND);
891         
892         if (icon && icon != ICON_BLANK1) {
893                 float ofs = 1.0f / aspect;
894                 
895                 if (but->flag & UI_ICON_LEFT) {
896                         if (but->type == BUT_TOGDUAL) {
897                                 if (but->drawstr[0]) {
898                                         xs = rect->xmin - ofs;
899                                 }
900                                 else {
901                                         xs = (rect->xmin + rect->xmax - height) / 2.0f;
902                                 }
903                         }
904                         else if (but->block->flag & UI_BLOCK_LOOP) {
905                                 if (but->type == SEARCH_MENU)
906                                         xs = rect->xmin + 4.0f * ofs;
907                                 else
908                                         xs = rect->xmin + ofs;
909                         }
910                         else if ((but->type == ICONROW) || (but->type == ICONTEXTROW)) {
911                                 xs = rect->xmin + 3.0f * ofs;
912                         }
913                         else {
914                                 xs = rect->xmin + 4.0f * ofs;
915                         }
916                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
917                 }
918                 else {
919                         xs = (rect->xmin + rect->xmax - height) / 2.0f;
920                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
921                 }
922
923                 /* to indicate draggable */
924                 if (but->dragpoin && (but->flag & UI_ACTIVE)) {
925                         float rgb[3] = {1.25f, 1.25f, 1.25f};
926                         UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
927                 }
928                 else
929                         UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
930         }
931
932         if (ui_but_draw_menu_icon(but)) {
933                 xs = rect->xmax - UI_DPI_ICON_SIZE - aspect;
934                 ys = (rect->ymin + rect->ymax - height) / 2.0f;
935                 
936                 UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
937         }
938         
939         glDisable(GL_BLEND);
940 }
941
942 static void ui_text_clip_give_prev_off(uiBut *but)
943 {
944         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + but->ofs);
945         int bytes = but->drawstr + but->ofs - prev_utf8;
946
947         but->ofs -= bytes;
948 }
949
950 static void ui_text_clip_give_next_off(uiBut *but)
951 {
952         char *next_utf8 = BLI_str_find_next_char_utf8(but->drawstr + but->ofs, NULL);
953         int bytes = next_utf8 - (but->drawstr + but->ofs);
954
955         but->ofs += bytes;
956 }
957
958 /**
959  * Cut off the start of the text to fit into the width of \a rect
960  *
961  * \note Sets but->ofs to make sure text is correctly visible.
962  * \note Clips right in some cases, this function could be cleaned up.
963  */
964 static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
965 {
966         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
967         int okwidth = BLI_rcti_size_x(rect) - border;
968         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
969
970         /* need to set this first */
971         uiStyleFontSet(fstyle);
972         
973         if (fstyle->kerning == 1) /* for BLF_width */
974                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
975
976         but->ofs = 0;
977         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
978
979         while (but->strwidth > okwidth) {
980                 ui_text_clip_give_next_off(but);
981                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
982                 if (but->strwidth < 10) break;
983         }
984
985         if (fstyle->kerning == 1) {
986                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
987         }
988 }
989
990 /**
991  * Cut off the text, taking into account the cursor location (text display while editing).
992  */
993 static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
994 {
995         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
996         int okwidth = BLI_rcti_size_x(rect) - border;
997         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
998
999         BLI_assert(but->editstr && but->pos >= 0);
1000
1001         /* need to set this first */
1002         uiStyleFontSet(fstyle);
1003
1004         if (fstyle->kerning == 1) /* for BLF_width */
1005                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1006
1007         /* define ofs dynamically */
1008         if (but->ofs > but->pos)
1009                 but->ofs = but->pos;
1010
1011         if (BLF_width(fstyle->uifont_id, but->drawstr) <= okwidth)
1012                 but->ofs = 0;
1013
1014         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1015
1016         while (but->strwidth > okwidth) {
1017                 float width;
1018                 char buf[UI_MAX_DRAW_STR];
1019
1020                 /* copy draw string */
1021                 BLI_strncpy_utf8(buf, but->drawstr, sizeof(buf));
1022                 /* string position of cursor */
1023                 buf[but->pos] = 0;
1024                 width = BLF_width(fstyle->uifont_id, buf + but->ofs);
1025
1026                 /* if cursor is at 20 pixels of right side button we clip left */
1027                 if (width > okwidth - 20) {
1028                         ui_text_clip_give_next_off(but);
1029                 }
1030                 else {
1031                         int len, bytes;
1032                         /* shift string to the left */
1033                         if (width < 20 && but->ofs > 0)
1034                                 ui_text_clip_give_prev_off(but);
1035                         len = strlen(but->drawstr);
1036                         bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len));
1037                         if (bytes < 0)
1038                                 bytes = 1;
1039                         but->drawstr[len - bytes] = 0;
1040                 }
1041
1042                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1043
1044                 if (but->strwidth < 10) break;
1045         }
1046
1047         if (fstyle->kerning == 1) {
1048                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1049         }
1050 }
1051
1052 /**
1053  * Cut off the end of text to fit into the width of \a rect.
1054  *
1055  * \note deals with ': ' especially for number buttons
1056  */
1057 static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1058 {
1059         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
1060         int okwidth = BLI_rcti_size_x(rect) - border;
1061         char *cpoin = NULL;
1062         int drawstr_len = strlen(but->drawstr);
1063         char *cpend = but->drawstr + drawstr_len;
1064         
1065         /* need to set this first */
1066         uiStyleFontSet(fstyle);
1067         
1068         if (fstyle->kerning == 1) /* for BLF_width */
1069                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1070         
1071         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
1072         but->ofs = 0;
1073         
1074
1075         /* First shorten num-buttopns eg,
1076          *   Translucency: 0.000
1077          * becomes
1078          *   Trans: 0.000
1079          */
1080
1081         /* find the space after ':' separator */
1082         cpoin = strrchr(but->drawstr, ':');
1083         
1084         if (cpoin && (cpoin < cpend - 2)) {
1085                 char *cp2 = cpoin;
1086                 
1087                 /* chop off the leading text, starting from the right */
1088                 while (but->strwidth > okwidth && cp2 > but->drawstr) {
1089                         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, cp2);
1090                         int bytes = cp2 - prev_utf8;
1091
1092                         /* shift the text after and including cp2 back by 1 char, +1 to include null terminator */
1093                         memmove(cp2 - bytes, cp2, drawstr_len + 1);
1094                         cp2 -= bytes;
1095
1096                         drawstr_len -= bytes;
1097                         // BLI_assert(strlen(but->drawstr) == drawstr_len);
1098                         
1099                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1100                         if (but->strwidth < 10) break;
1101                 }
1102         
1103         
1104                 /* after the leading text is gone, chop off the : and following space, with ofs */
1105                 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1106                         ui_text_clip_give_next_off(but);
1107                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1108                         if (but->strwidth < 10) break;
1109                 }
1110                 
1111         }
1112
1113
1114         /* Now just remove trailing chars */
1115         /* once the label's gone, chop off the least significant digits */
1116         while (but->strwidth > okwidth) {
1117                 int bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + drawstr_len));
1118                 if (bytes < 0)
1119                         bytes = 1;
1120
1121                 drawstr_len -= bytes;
1122                 but->drawstr[drawstr_len] = 0;
1123                 // BLI_assert(strlen(but->drawstr) == drawstr_len);
1124                 
1125                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1126                 if (but->strwidth < 10) break;
1127         }
1128         
1129         if (fstyle->kerning == 1)
1130                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1131 }
1132
1133
1134 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1135 {
1136         //int transopts;  // UNUSED
1137         char *cpoin = NULL;
1138         
1139         /* for underline drawing */
1140         float font_xofs, font_yofs;
1141
1142         uiStyleFontSet(fstyle);
1143         
1144         if (but->editstr || (but->flag & UI_TEXT_LEFT))
1145                 fstyle->align = UI_STYLE_TEXT_LEFT;
1146         else
1147                 fstyle->align = UI_STYLE_TEXT_CENTER;
1148         
1149         if (fstyle->kerning == 1) /* for BLF_width */
1150                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1151         
1152         /* text button selection and cursor */
1153         if (but->editstr && but->pos != -1) {
1154                 short t = 0, pos = 0, ch;
1155                 short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
1156
1157                 if ((but->selend - but->selsta) > 0) {
1158                         /* text button selection */
1159                         selsta_tmp = but->selsta;
1160                         selend_tmp = but->selend;
1161                         
1162                         if (but->drawstr[0] != 0) {
1163
1164                                 if (but->selsta >= but->ofs) {
1165                                         ch = but->drawstr[selsta_tmp];
1166                                         but->drawstr[selsta_tmp] = 0;
1167                                         
1168                                         selsta_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1169                                         
1170                                         but->drawstr[selsta_tmp] = ch;
1171                                 }
1172                                 else {
1173                                         selsta_draw = 0;
1174                                 }
1175                                 
1176                                 ch = but->drawstr[selend_tmp];
1177                                 but->drawstr[selend_tmp] = 0;
1178                                 
1179                                 selwidth_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1180                                 
1181                                 but->drawstr[selend_tmp] = ch;
1182
1183                                 glColor3ubv((unsigned char *)wcol->item);
1184                                 glRects(rect->xmin + selsta_draw, rect->ymin + 2, rect->xmin + selwidth_draw, rect->ymax - 2);
1185                         }
1186                 }
1187                 else {
1188                         /* text cursor */
1189                         pos = but->pos;
1190                         if (pos >= but->ofs) {
1191                                 if (but->drawstr[0] != 0) {
1192                                         ch = but->drawstr[pos];
1193                                         but->drawstr[pos] = 0;
1194                                         
1195                                         t = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs) / but->aspect;
1196                                         
1197                                         but->drawstr[pos] = ch;
1198                                 }
1199
1200                                 glColor3f(0.20, 0.6, 0.9);
1201                                 glRects(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
1202                         }
1203                 }
1204         }
1205         
1206         if (fstyle->kerning == 1)
1207                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1208
1209 #if 0
1210         ui_rasterpos_safe(x, y, but->aspect);
1211         if (but->type == IDPOIN) transopts = 0;  /* no translation, of course! */
1212         else transopts = ui_translate_buttons();
1213 #endif
1214
1215         /* cut string in 2 parts - only for menu entries */
1216         if ((but->block->flag & UI_BLOCK_LOOP)) {
1217                 if (ELEM5(but->type, SLI, NUM, TEX, NUMSLI, NUMABS) == 0) {
1218                         cpoin = strchr(but->drawstr, '|');
1219                         if (cpoin) *cpoin = 0;
1220                 }
1221         }
1222         
1223         glColor3ubv((unsigned char *)wcol->text);
1224
1225         uiStyleFontDrawExt(fstyle, rect, but->drawstr + but->ofs, &font_xofs, &font_yofs);
1226
1227         if (but->menu_key != '\0') {
1228                 char fixedbuf[128];
1229                 char *str;
1230
1231                 BLI_strncpy(fixedbuf, but->drawstr + but->ofs, sizeof(fixedbuf));
1232
1233                 str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
1234                 if (str == NULL)
1235                         str = strchr(fixedbuf, but->menu_key);
1236
1237                 if (str) {
1238                         int ul_index = -1;
1239                         float ul_advance;
1240
1241                         ul_index = (int)(str - fixedbuf);
1242
1243                         if (fstyle->kerning == 1) {
1244                                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1245                         }
1246
1247                         fixedbuf[ul_index] = '\0';
1248                         ul_advance = BLF_width(fstyle->uifont_id, fixedbuf);
1249
1250                         BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
1251                         BLF_draw(fstyle->uifont_id, "_", 2);
1252
1253                         if (fstyle->kerning == 1) {
1254                                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1255                         }
1256                 }
1257         }
1258
1259         /* part text right aligned */
1260         if (cpoin) {
1261                 fstyle->align = UI_STYLE_TEXT_RIGHT;
1262                 rect->xmax -= ui_but_draw_menu_icon(but) ? UI_DPI_ICON_SIZE : 5;
1263                 uiStyleFontDraw(fstyle, rect, cpoin + 1);
1264                 *cpoin = '|';
1265         }
1266 }
1267
1268 /* draws text and icons for buttons */
1269 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1270 {
1271         char password_str[UI_MAX_DRAW_STR];
1272
1273         if (but == NULL)
1274                 return;
1275
1276         ui_button_text_password_hide(password_str, but, FALSE);
1277
1278         /* clip but->drawstr to fit in available space */
1279         if (but->editstr && but->pos >= 0) {
1280                 ui_text_clip_cursor(fstyle, but, rect);
1281         }
1282         else if (ELEM4(but->type, NUM, NUMABS, NUMSLI, SLI)) {
1283                 ui_text_clip_right_label(fstyle, but, rect);
1284         }
1285         else if (ELEM(but->type, TEX, SEARCH_MENU)) {
1286                 ui_text_clip_left(fstyle, but, rect);
1287         }
1288         else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
1289                 ui_text_clip_left(fstyle, but, rect);
1290         }
1291         else but->ofs = 0;
1292
1293         /* check for button text label */
1294         if (but->type == ICONTEXTROW) {
1295                 widget_draw_icon(but, (BIFIconID) (but->icon + but->iconadd), 1.0f, rect);
1296         }
1297         else {
1298
1299                 if (but->type == BUT_TOGDUAL) {
1300                         int dualset = 0;
1301                         if (but->pointype == UI_BUT_POIN_SHORT) {
1302                                 dualset = UI_BITBUT_TEST(*(((short *)but->poin) + 1), but->bitnr);
1303                         }
1304                         else if (but->pointype == UI_BUT_POIN_INT) {
1305                                 dualset = UI_BITBUT_TEST(*(((int *)but->poin) + 1), but->bitnr);
1306                         }
1307
1308                         widget_draw_icon(but, ICON_DOT, dualset ? 1.0f : 0.25f, rect);
1309                 }
1310                 else if (but->type == MENU && (but->flag & UI_BUT_NODE_LINK)) {
1311                         int tmp = rect->xmin;
1312                         rect->xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
1313                         widget_draw_icon(but, ICON_LAYER_USED, 1.0f, rect);
1314                         rect->xmin = tmp;
1315                 }
1316
1317                 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
1318                  * and offset the text label to accommodate it */
1319
1320                 if (but->flag & UI_HAS_ICON) {
1321                         widget_draw_icon(but, but->icon + but->iconadd, 1.0f, rect);
1322                         
1323                         /* icons default draw 0.8f x height */
1324                         rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect));
1325
1326                         if (but->editstr || (but->flag & UI_TEXT_LEFT))
1327                                 rect->xmin += 0.4f * U.widget_unit;
1328                 }
1329                 else if ((but->flag & UI_TEXT_LEFT))
1330                         rect->xmin += 0.4f * U.widget_unit;
1331
1332                 /* always draw text for textbutton cursor */
1333                 widget_draw_text(fstyle, wcol, but, rect);
1334
1335         }
1336
1337         ui_button_text_password_hide(password_str, but, TRUE);
1338 }
1339
1340
1341
1342 /* *********************** widget types ************************************* */
1343
1344
1345 /* uiWidgetStateColors
1346  *     char inner_anim[4];
1347  *     char inner_anim_sel[4];
1348  *     char inner_key[4];
1349  *     char inner_key_sel[4];
1350  *     char inner_driven[4];
1351  *     char inner_driven_sel[4];
1352  *     float blend;
1353  */
1354
1355 static struct uiWidgetStateColors wcol_state_colors = {
1356         {115, 190, 76, 255},
1357         {90, 166, 51, 255},
1358         {240, 235, 100, 255},
1359         {215, 211, 75, 255},
1360         {180, 0, 255, 255},
1361         {153, 0, 230, 255},
1362         0.5f, 0.0f
1363 };
1364
1365 /* uiWidgetColors
1366  *     float outline[3];
1367  *     float inner[4];
1368  *     float inner_sel[4];
1369  *     float item[3];
1370  *     float text[3];
1371  *     float text_sel[3];
1372  *     
1373  *     short shaded;
1374  *     float shadetop, shadedown;
1375  */
1376
1377 static struct uiWidgetColors wcol_num = {
1378         {25, 25, 25, 255},
1379         {180, 180, 180, 255},
1380         {153, 153, 153, 255},
1381         {90, 90, 90, 255},
1382         
1383         {0, 0, 0, 255},
1384         {255, 255, 255, 255},
1385         
1386         1,
1387         -20, 0
1388 };
1389
1390 static struct uiWidgetColors wcol_numslider = {
1391         {25, 25, 25, 255},
1392         {180, 180, 180, 255},
1393         {153, 153, 153, 255},
1394         {128, 128, 128, 255},
1395         
1396         {0, 0, 0, 255},
1397         {255, 255, 255, 255},
1398         
1399         1,
1400         -20, 0
1401 };
1402
1403 static struct uiWidgetColors wcol_text = {
1404         {25, 25, 25, 255},
1405         {153, 153, 153, 255},
1406         {153, 153, 153, 255},
1407         {90, 90, 90, 255},
1408         
1409         {0, 0, 0, 255},
1410         {255, 255, 255, 255},
1411         
1412         1,
1413         0, 25
1414 };
1415
1416 static struct uiWidgetColors wcol_option = {
1417         {0, 0, 0, 255},
1418         {70, 70, 70, 255},
1419         {70, 70, 70, 255},
1420         {255, 255, 255, 255},
1421         
1422         {0, 0, 0, 255},
1423         {255, 255, 255, 255},
1424         
1425         1,
1426         15, -15
1427 };
1428
1429 /* button that shows popup */
1430 static struct uiWidgetColors wcol_menu = {
1431         {0, 0, 0, 255},
1432         {70, 70, 70, 255},
1433         {70, 70, 70, 255},
1434         {255, 255, 255, 255},
1435         
1436         {255, 255, 255, 255},
1437         {204, 204, 204, 255},
1438         
1439         1,
1440         15, -15
1441 };
1442
1443 /* button that starts pulldown */
1444 static struct uiWidgetColors wcol_pulldown = {
1445         {0, 0, 0, 255},
1446         {63, 63, 63, 255},
1447         {86, 128, 194, 255},
1448         {255, 255, 255, 255},
1449         
1450         {0, 0, 0, 255},
1451         {0, 0, 0, 255},
1452         
1453         0,
1454         25, -20
1455 };
1456
1457 /* button inside menu */
1458 static struct uiWidgetColors wcol_menu_item = {
1459         {0, 0, 0, 255},
1460         {0, 0, 0, 0},
1461         {86, 128, 194, 255},
1462         {172, 172, 172, 128},
1463         
1464         {255, 255, 255, 255},
1465         {0, 0, 0, 255},
1466         
1467         1,
1468         38, 0
1469 };
1470
1471 /* backdrop menu + title text color */
1472 static struct uiWidgetColors wcol_menu_back = {
1473         {0, 0, 0, 255},
1474         {25, 25, 25, 230},
1475         {45, 45, 45, 230},
1476         {100, 100, 100, 255},
1477         
1478         {160, 160, 160, 255},
1479         {255, 255, 255, 255},
1480         
1481         0,
1482         25, -20
1483 };
1484
1485 /* tooltip color */
1486 static struct uiWidgetColors wcol_tooltip = {
1487         {0, 0, 0, 255},
1488         {25, 25, 25, 230},
1489         {45, 45, 45, 230},
1490         {100, 100, 100, 255},
1491
1492         {160, 160, 160, 255},
1493         {255, 255, 255, 255},
1494
1495         0,
1496         25, -20
1497 };
1498
1499 static struct uiWidgetColors wcol_radio = {
1500         {0, 0, 0, 255},
1501         {70, 70, 70, 255},
1502         {86, 128, 194, 255},
1503         {255, 255, 255, 255},
1504         
1505         {255, 255, 255, 255},
1506         {0, 0, 0, 255},
1507         
1508         1,
1509         15, -15
1510 };
1511
1512 static struct uiWidgetColors wcol_regular = {
1513         {25, 25, 25, 255},
1514         {153, 153, 153, 255},
1515         {100, 100, 100, 255},
1516         {25, 25, 25, 255},
1517         
1518         {0, 0, 0, 255},
1519         {255, 255, 255, 255},
1520         
1521         0,
1522         0, 0
1523 };
1524
1525 static struct uiWidgetColors wcol_tool = {
1526         {25, 25, 25, 255},
1527         {153, 153, 153, 255},
1528         {100, 100, 100, 255},
1529         {25, 25, 25, 255},
1530         
1531         {0, 0, 0, 255},
1532         {255, 255, 255, 255},
1533         
1534         1,
1535         15, -15
1536 };
1537
1538 static struct uiWidgetColors wcol_box = {
1539         {25, 25, 25, 255},
1540         {128, 128, 128, 255},
1541         {100, 100, 100, 255},
1542         {25, 25, 25, 255},
1543         
1544         {0, 0, 0, 255},
1545         {255, 255, 255, 255},
1546         
1547         0,
1548         0, 0
1549 };
1550
1551 static struct uiWidgetColors wcol_toggle = {
1552         {25, 25, 25, 255},
1553         {153, 153, 153, 255},
1554         {100, 100, 100, 255},
1555         {25, 25, 25, 255},
1556         
1557         {0, 0, 0, 255},
1558         {255, 255, 255, 255},
1559         
1560         0,
1561         0, 0
1562 };
1563
1564 static struct uiWidgetColors wcol_scroll = {
1565         {50, 50, 50, 180},
1566         {80, 80, 80, 180},
1567         {100, 100, 100, 180},
1568         {128, 128, 128, 255},
1569         
1570         {0, 0, 0, 255},
1571         {255, 255, 255, 255},
1572         
1573         1,
1574         5, -5
1575 };
1576
1577 static struct uiWidgetColors wcol_progress = {
1578         {0, 0, 0, 255},
1579         {190, 190, 190, 255},
1580         {100, 100, 100, 180},
1581         {68, 68, 68, 255},
1582         
1583         {0, 0, 0, 255},
1584         {255, 255, 255, 255},
1585         
1586         0,
1587         0, 0
1588 };
1589
1590 static struct uiWidgetColors wcol_list_item = {
1591         {0, 0, 0, 255},
1592         {0, 0, 0, 0},
1593         {86, 128, 194, 255},
1594         {0, 0, 0, 255},
1595         
1596         {0, 0, 0, 255},
1597         {0, 0, 0, 255},
1598         
1599         0,
1600         0, 0
1601 };
1602
1603 /* free wcol struct to play with */
1604 static struct uiWidgetColors wcol_tmp = {
1605         {0, 0, 0, 255},
1606         {128, 128, 128, 255},
1607         {100, 100, 100, 255},
1608         {25, 25, 25, 255},
1609         
1610         {0, 0, 0, 255},
1611         {255, 255, 255, 255},
1612         
1613         0,
1614         0, 0
1615 };
1616
1617
1618 /* called for theme init (new theme) and versions */
1619 void ui_widget_color_init(ThemeUI *tui)
1620 {
1621         tui->wcol_regular = wcol_regular;
1622         tui->wcol_tool = wcol_tool;
1623         tui->wcol_text = wcol_text;
1624         tui->wcol_radio = wcol_radio;
1625         tui->wcol_option = wcol_option;
1626         tui->wcol_toggle = wcol_toggle;
1627         tui->wcol_num = wcol_num;
1628         tui->wcol_numslider = wcol_numslider;
1629         tui->wcol_menu = wcol_menu;
1630         tui->wcol_pulldown = wcol_pulldown;
1631         tui->wcol_menu_back = wcol_menu_back;
1632         tui->wcol_tooltip = wcol_tooltip;
1633         tui->wcol_menu_item = wcol_menu_item;
1634         tui->wcol_box = wcol_box;
1635         tui->wcol_scroll = wcol_scroll;
1636         tui->wcol_list_item = wcol_list_item;
1637         tui->wcol_progress = wcol_progress;
1638
1639         tui->wcol_state = wcol_state_colors;
1640 }
1641
1642 /* ************ button callbacks, state ***************** */
1643
1644 static void widget_state_blend(char cp[3], const char cpstate[3], const float fac)
1645 {
1646         if (fac != 0.0f) {
1647                 cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
1648                 cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
1649                 cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
1650         }
1651 }
1652
1653 /* copy colors from theme, and set changes in it based on state */
1654 static void widget_state(uiWidgetType *wt, int state)
1655 {
1656         uiWidgetStateColors *wcol_state = wt->wcol_state;
1657
1658         wt->wcol = *(wt->wcol_theme);
1659         
1660         if (state & UI_SELECT) {
1661                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1662
1663                 if (state & UI_BUT_ANIMATED_KEY)
1664                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1665                 else if (state & UI_BUT_ANIMATED)
1666                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1667                 else if (state & UI_BUT_DRIVEN)
1668                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1669
1670                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1671                 
1672                 if (state & UI_SELECT)
1673                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1674         }
1675         else {
1676                 if (state & UI_BUT_ANIMATED_KEY)
1677                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1678                 else if (state & UI_BUT_ANIMATED)
1679                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1680                 else if (state & UI_BUT_DRIVEN)
1681                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1682
1683                 if (state & UI_ACTIVE) { /* mouse over? */
1684                         wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
1685                         wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
1686                         wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
1687                 }
1688         }
1689
1690         if (state & UI_BUT_REDALERT) {
1691                 char red[4] = {255, 0, 0};
1692                 widget_state_blend(wt->wcol.inner, red, 0.4f);
1693         }
1694         if (state & UI_BUT_NODE_ACTIVE) {
1695                 char blue[4] = {86, 128, 194};
1696                 widget_state_blend(wt->wcol.inner, blue, 0.3f);
1697         }
1698 }
1699
1700 /* sliders use special hack which sets 'item' as inner when drawing filling */
1701 static void widget_state_numslider(uiWidgetType *wt, int state)
1702 {
1703         uiWidgetStateColors *wcol_state = wt->wcol_state;
1704         float blend = wcol_state->blend - 0.2f; /* XXX special tweak to make sure that bar will still be visible */
1705
1706         /* call this for option button */
1707         widget_state(wt, state);
1708         
1709         /* now, set the inner-part so that it reflects state settings too */
1710         /* TODO: maybe we should have separate settings for the blending colors used for this case? */
1711         if (state & UI_SELECT) {
1712                 
1713                 if (state & UI_BUT_ANIMATED_KEY)
1714                         widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
1715                 else if (state & UI_BUT_ANIMATED)
1716                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
1717                 else if (state & UI_BUT_DRIVEN)
1718                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
1719                 
1720                 if (state & UI_SELECT)
1721                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1722         }
1723         else {
1724                 if (state & UI_BUT_ANIMATED_KEY)
1725                         widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
1726                 else if (state & UI_BUT_ANIMATED)
1727                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
1728                 else if (state & UI_BUT_DRIVEN)
1729                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
1730         }
1731 }
1732
1733 /* labels use theme colors for text */
1734 static void widget_state_label(uiWidgetType *wt, int state)
1735 {
1736         /* call this for option button */
1737         widget_state(wt, state);
1738
1739         if (state & UI_SELECT)
1740                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1741         else
1742                 UI_GetThemeColor4ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
1743         
1744 }
1745
1746 /* labels use theme colors for text */
1747 static void widget_state_option_menu(uiWidgetType *wt, int state)
1748 {
1749         
1750         /* call this for option button */
1751         widget_state(wt, state);
1752         
1753         /* if not selected we get theme from menu back */
1754         if (state & UI_SELECT)
1755                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1756         else {
1757                 bTheme *btheme = UI_GetTheme(); /* XXX */
1758
1759                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text);
1760         }
1761 }
1762
1763
1764 static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
1765 {
1766         wt->wcol = *(wt->wcol_theme);
1767 }       
1768
1769 /* special case, button that calls pulldown */
1770 static void widget_state_pulldown(uiWidgetType *wt, int state)
1771 {
1772         wt->wcol = *(wt->wcol_theme);
1773         
1774         copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1775         copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
1776
1777         if (state & UI_ACTIVE)
1778                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1779 }
1780
1781 /* special case, menu items */
1782 static void widget_state_menu_item(uiWidgetType *wt, int state)
1783 {
1784         wt->wcol = *(wt->wcol_theme);
1785         
1786         if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1787                 wt->wcol.text[0] = 0.5f * (wt->wcol.text[0] + wt->wcol.text_sel[0]);
1788                 wt->wcol.text[1] = 0.5f * (wt->wcol.text[1] + wt->wcol.text_sel[1]);
1789                 wt->wcol.text[2] = 0.5f * (wt->wcol.text[2] + wt->wcol.text_sel[2]);
1790         }
1791         else if (state & UI_ACTIVE) {
1792                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1793                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1794         }
1795 }
1796
1797
1798 /* ************ menu backdrop ************************* */
1799
1800 /* outside of rect, rad to left/bottom/right */
1801 static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin, const float radout)
1802 {
1803         uiWidgetBase wtb;
1804         rcti rect1 = *rect;
1805         float alpha, alphastep;
1806         int step, totvert;
1807         float quad_strip[WIDGET_SIZE_MAX * 2][2];
1808         
1809         /* prevent tooltips to not show round shadow */
1810         if (radout > 0.2f * BLI_rcti_size_y(&rect1))
1811                 rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
1812         else
1813                 rect1.ymax -= radout;
1814         
1815         /* inner part */
1816         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1817
1818         /* inverse linear shadow alpha */
1819         alpha = 0.15f;
1820         if (U.pixelsize > 1.0f)
1821                 alphastep = 0.78f;
1822         else
1823                 alphastep = 0.67f;
1824         
1825         glEnableClientState(GL_VERTEX_ARRAY);
1826
1827         for (step = 1; step <= radout; step++, alpha *= alphastep) {
1828                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1829                 
1830                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
1831
1832                 widget_verts_to_quad_strip_open(&wtb, totvert, quad_strip);
1833
1834                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1835                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2);
1836         }
1837
1838         glDisableClientState(GL_VERTEX_ARRAY);
1839 }
1840
1841 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1842 {
1843         uiWidgetBase wtb;
1844         int roundboxalign = UI_CNR_ALL;
1845         
1846         widget_init(&wtb);
1847         
1848         /* menu is 2nd level or deeper */
1849         if (flag & UI_BLOCK_POPUP) {
1850                 //rect->ymin -= 4.0;
1851                 //rect->ymax += 4.0;
1852         }
1853         else if (direction == UI_DOWN) {
1854                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1855                 rect->ymin -= 0.1f * U.widget_unit;
1856         }
1857         else if (direction == UI_TOP) {
1858                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1859                 rect->ymax += 0.1f * U.widget_unit;
1860         }
1861         
1862         glEnable(GL_BLEND);
1863         widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit, 0.4f * U.widget_unit);
1864         
1865         round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
1866         wtb.emboss = 0;
1867         widgetbase_draw(&wtb, wcol);
1868         
1869         glDisable(GL_BLEND);
1870 }
1871
1872
1873 static void ui_hsv_cursor(float x, float y)
1874 {
1875         
1876         glPushMatrix();
1877         glTranslatef(x, y, 0.0f);
1878         
1879         glColor3f(1.0f, 1.0f, 1.0f);
1880         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f, 8);
1881         
1882         glEnable(GL_BLEND);
1883         glEnable(GL_LINE_SMOOTH);
1884         glColor3f(0.0f, 0.0f, 0.0f);
1885         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f, 12);
1886         glDisable(GL_BLEND);
1887         glDisable(GL_LINE_SMOOTH);
1888         
1889         glPopMatrix();
1890         
1891 }
1892
1893 void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
1894                                 const float mx, const float my)
1895 {
1896         /* duplication of code... well, simple is better now */
1897         const float centx = BLI_rcti_cent_x_fl(rect);
1898         const float centy = BLI_rcti_cent_y_fl(rect);
1899         const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1900         const float m_delta[2] = {mx - centx, my - centy};
1901         const float dist_squared = len_squared_v2(m_delta);
1902
1903         *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f;
1904         *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
1905 }
1906
1907 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
1908 {
1909         const int tot = 32;
1910         const float radstep = 2.0f * (float)M_PI / (float)tot;
1911
1912         const float centx = BLI_rcti_cent_x_fl(rect);
1913         const float centy = BLI_rcti_cent_y_fl(rect);
1914         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1915
1916         /* gouraud triangle fan */
1917         const float *hsv_ptr = ui_block_hsv_get(but->block);
1918         float ang = 0.0f;
1919         float cursor_radius;
1920         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1921         int a;
1922         int color_profile = but->block->color_profile;
1923         
1924         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1925                 color_profile = FALSE;
1926         
1927         /* color */
1928         ui_get_but_vectorf(but, rgb);
1929
1930         /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
1931         hsvo[0] = hsv[0] = hsv_ptr[0];
1932         hsvo[1] = hsv[1] = hsv_ptr[1];
1933         hsvo[2] = hsv[2] = hsv_ptr[2];
1934
1935         rgb_to_hsv_compat_v(rgb, hsvo);
1936
1937         if (color_profile)
1938                 ui_block_to_display_space_v3(but->block, rgb);
1939
1940         rgb_to_hsv_compat_v(rgb, hsv);
1941         
1942         /* exception: if 'lock' is set
1943          * lock the value of the color wheel to 1.
1944          * Useful for color correction tools where you're only interested in hue. */
1945         if (but->flag & UI_BUT_COLOR_LOCK)
1946                 hsv[2] = 1.f;
1947         
1948         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1949         
1950         glShadeModel(GL_SMOOTH);
1951
1952         glBegin(GL_TRIANGLE_FAN);
1953         glColor3fv(colcent);
1954         glVertex2f(centx, centy);
1955         
1956         for (a = 0; a <= tot; a++, ang += radstep) {
1957                 float si = sin(ang);
1958                 float co = cos(ang);
1959                 
1960                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1961                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1962
1963                 hsv_to_rgb_v(hsv, col);
1964                 glColor3fv(col);
1965                 glVertex2f(centx + co * radius, centy + si * radius);
1966         }
1967         glEnd();
1968         
1969         glShadeModel(GL_FLAT);
1970         
1971         /* fully rounded outline */
1972         glPushMatrix();
1973         glTranslatef(centx, centy, 0.0f);
1974         glEnable(GL_BLEND);
1975         glEnable(GL_LINE_SMOOTH);
1976         glColor3ubv((unsigned char *)wcol->outline);
1977         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
1978         glDisable(GL_BLEND);
1979         glDisable(GL_LINE_SMOOTH);
1980         glPopMatrix();
1981
1982         /* cursor */
1983         ang = 2.0f * (float)M_PI * hsvo[0] + 0.5f * (float)M_PI;
1984
1985         if (but->flag & UI_BUT_COLOR_CUBIC)
1986                 cursor_radius = (1.0f - powf(1.0f - hsvo[1], 3.0f));
1987         else
1988                 cursor_radius = hsvo[1];
1989
1990         radius = CLAMPIS(cursor_radius, 0.0f, 1.0f) * radius;
1991         ui_hsv_cursor(centx + cosf(-ang) * radius, centy + sinf(-ang) * radius);
1992 }
1993
1994 /* ************ custom buttons, old stuff ************** */
1995
1996 /* draws in resolution of 20x4 colors */
1997 void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
1998 {
1999         const float color_step = (type == UI_GRAD_H) ? 0.02f : 0.05f;
2000         int a;
2001         float h = hsv[0], s = hsv[1], v = hsv[2];
2002         float dx, dy, sx1, sx2, sy;
2003         float col0[4][3];   /* left half, rect bottom to top */
2004         float col1[4][3];   /* right half, rect bottom to top */
2005
2006         /* draw series of gouraud rects */
2007         glShadeModel(GL_SMOOTH);
2008         
2009         switch (type) {
2010                 case UI_GRAD_SV:
2011                         hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2012                         hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
2013                         hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
2014                         hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2015                         break;
2016                 case UI_GRAD_HV:
2017                         hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2018                         hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2019                         hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2020                         hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2021                         break;
2022                 case UI_GRAD_HS:
2023                         hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2024                         hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2025                         hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2026                         hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2027                         break;
2028                 case UI_GRAD_H:
2029                         hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2030                         copy_v3_v3(col1[1], col1[0]);
2031                         copy_v3_v3(col1[2], col1[0]);
2032                         copy_v3_v3(col1[3], col1[0]);
2033                         break;
2034                 case UI_GRAD_S:
2035                         hsv_to_rgb(1.0, 0.0, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2036                         copy_v3_v3(col1[0], col1[1]);
2037                         copy_v3_v3(col1[2], col1[1]);
2038                         copy_v3_v3(col1[3], col1[1]);
2039                         break;
2040                 case UI_GRAD_V:
2041                         hsv_to_rgb(1.0, 1.0, 0.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2042                         copy_v3_v3(col1[0], col1[2]);
2043                         copy_v3_v3(col1[1], col1[2]);
2044                         copy_v3_v3(col1[3], col1[2]);
2045                         break;
2046                 default:
2047                         assert(!"invalid 'type' argument");
2048                         hsv_to_rgb(1.0, 1.0, 1.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2049                         copy_v3_v3(col1[0], col1[2]);
2050                         copy_v3_v3(col1[1], col1[2]);
2051                         copy_v3_v3(col1[3], col1[2]);
2052         }
2053         
2054         /* old below */
2055         
2056         for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */
2057                 /* previous color */
2058                 copy_v3_v3(col0[0], col1[0]);
2059                 copy_v3_v3(col0[1], col1[1]);
2060                 copy_v3_v3(col0[2], col1[2]);
2061                 copy_v3_v3(col0[3], col1[3]);
2062                 
2063                 /* new color */
2064                 switch (type) {
2065                         case UI_GRAD_SV:
2066                                 hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
2067                                 hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
2068                                 hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
2069                                 hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
2070                                 break;
2071                         case UI_GRAD_HV:
2072                                 hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2073                                 hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2074                                 hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2075                                 hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2076                                 break;
2077                         case UI_GRAD_HS:
2078                                 hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2079                                 hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2080                                 hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2081                                 hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2082                                 break;
2083                         case UI_GRAD_H:
2084                         {
2085                                 /* annoying but without this the color shifts - could be solved some other way
2086                                  * - campbell */
2087                                 hsv_to_rgb(dx + color_step, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2088                                 copy_v3_v3(col1[1], col1[0]);
2089                                 copy_v3_v3(col1[2], col1[0]);
2090                                 copy_v3_v3(col1[3], col1[0]);
2091                                 break;
2092                         }
2093                         case UI_GRAD_S:
2094                                 hsv_to_rgb(h, dx, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2095                                 copy_v3_v3(col1[0], col1[1]);
2096                                 copy_v3_v3(col1[2], col1[1]);
2097                                 copy_v3_v3(col1[3], col1[1]);
2098                                 break;
2099                         case UI_GRAD_V:
2100                                 hsv_to_rgb(h, 1.0, dx,   &col1[2][0], &col1[2][1], &col1[2][2]);
2101                                 copy_v3_v3(col1[0], col1[2]);
2102                                 copy_v3_v3(col1[1], col1[2]);
2103                                 copy_v3_v3(col1[3], col1[2]);
2104                                 break;
2105                 }
2106                 
2107                 /* rect */
2108                 sx1 = rect->xmin +  dx               * BLI_rcti_size_x(rect);
2109                 sx2 = rect->xmin + (dx + color_step) * BLI_rcti_size_x(rect);
2110                 sy = rect->ymin;
2111                 dy = (float)BLI_rcti_size_y(rect) / 3.0f;
2112                 
2113                 glBegin(GL_QUADS);
2114                 for (a = 0; a < 3; a++, sy += dy) {
2115                         glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
2116                         glVertex2f(sx1, sy);
2117                         
2118                         glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
2119                         glVertex2f(sx2, sy);
2120
2121                         glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
2122                         glVertex2f(sx2, sy + dy);
2123                         
2124                         glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
2125                         glVertex2f(sx1, sy + dy);
2126                 }
2127                 glEnd();
2128         }
2129         
2130         glShadeModel(GL_FLAT);
2131         
2132 }
2133
2134
2135
2136 static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
2137 {
2138         float rgb[3];
2139         float x = 0.0f, y = 0.0f;
2140         float *hsv = ui_block_hsv_get(but->block);
2141         float hsv_n[3];
2142         int color_profile = but->block->color_profile;
2143         
2144         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2145                 color_profile = FALSE;
2146         
2147         copy_v3_v3(hsv_n, hsv);
2148         
2149         ui_get_but_vectorf(but, rgb);
2150         
2151         if (color_profile && (int)but->a1 != UI_GRAD_SV)
2152                 ui_block_to_display_space_v3(but->block, rgb);
2153         
2154         rgb_to_hsv_compat_v(rgb, hsv_n);
2155         
2156         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2157         
2158         switch ((int)but->a1) {
2159                 case UI_GRAD_SV:
2160                         x = hsv_n[2]; y = hsv_n[1]; break;
2161                 case UI_GRAD_HV:
2162                         x = hsv_n[0]; y = hsv_n[2]; break;
2163                 case UI_GRAD_HS:
2164                         x = hsv_n[0]; y = hsv_n[1]; break;
2165                 case UI_GRAD_H:
2166                         x = hsv_n[0]; y = 0.5; break;
2167                 case UI_GRAD_S:
2168                         x = hsv_n[1]; y = 0.5; break;
2169                 case UI_GRAD_V:
2170                         x = hsv_n[2]; y = 0.5; break;
2171         }
2172         
2173         /* cursor */
2174         x = rect->xmin + x * BLI_rcti_size_x(rect);
2175         y = rect->ymin + y * BLI_rcti_size_y(rect);
2176         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2177         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2178         
2179         ui_hsv_cursor(x, y);
2180         
2181         /* outline */
2182         glColor3ub(0,  0,  0);
2183         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2184 }
2185
2186 /* vertical 'value' slider, using new widget code */
2187 static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
2188 {
2189         uiWidgetBase wtb;
2190         const float rad = 0.5f * BLI_rcti_size_x(rect);
2191         float x, y;
2192         float rgb[3], hsv[3], v, range;
2193         int color_profile = but->block->color_profile;
2194         
2195         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2196                 color_profile = FALSE;
2197
2198         ui_get_but_vectorf(but, rgb);
2199
2200         if (color_profile)
2201                 ui_block_to_display_space_v3(but->block, rgb);
2202
2203         rgb_to_hsv_v(rgb, hsv);
2204         v = hsv[2];
2205         
2206         /* map v from property range to [0,1] */
2207         range = but->softmax - but->softmin;
2208         v = (v - but->softmin) / range;
2209         
2210         widget_init(&wtb);
2211         
2212         /* fully rounded */
2213         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2214         
2215         /* setup temp colors */
2216         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2217         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2218         wcol_tmp.shadetop = 127;
2219         wcol_tmp.shadedown = -128;
2220         wcol_tmp.shaded = 1;
2221         
2222         widgetbase_draw(&wtb, &wcol_tmp);
2223
2224         /* cursor */
2225         x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
2226         y = rect->ymin + v    * BLI_rcti_size_y(rect);
2227         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2228         
2229         ui_hsv_cursor(x, y);
2230         
2231 }
2232
2233
2234 /* ************ separator, for menus etc ***************** */
2235 static void ui_draw_separator(const rcti *rect,  uiWidgetColors *wcol)
2236 {
2237         int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2238         unsigned char col[4];
2239         
2240         col[0] = wcol->text[0];
2241         col[1] = wcol->text[1];
2242         col[2] = wcol->text[2];
2243         col[3] = 7;
2244         
2245         glEnable(GL_BLEND);
2246         glColor4ubv(col);
2247         sdrawline(rect->xmin, y, rect->xmax, y);
2248         glDisable(GL_BLEND);
2249 }
2250
2251 /* ************ button callbacks, draw ***************** */
2252
2253 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2254 {
2255         uiWidgetBase wtb;
2256         const float rad = 0.5f * BLI_rcti_size_y(rect);
2257         float textofs = rad * 0.75f;
2258
2259         if (state & UI_SELECT)
2260                 SWAP(short, wcol->shadetop, wcol->shadedown);
2261         
2262         widget_init(&wtb);
2263         
2264         /* fully rounded */
2265         round_box_edges(&wtb, roundboxalign, rect, rad);
2266         
2267         /* decoration */
2268         if (!(state & UI_TEXTINPUT)) {
2269                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2270                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2271         }
2272
2273         widgetbase_draw(&wtb, wcol);
2274         
2275         /* text space */
2276         rect->xmin += textofs;
2277         rect->xmax -= textofs;
2278 }
2279
2280 int ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
2281 {
2282         float dist, vec[4][2];
2283
2284         vec[0][0] = rect->xmin;
2285         vec[0][1] = rect->ymin;
2286         vec[3][0] = rect->xmax;
2287         vec[3][1] = rect->ymax;
2288         
2289         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2290         
2291         vec[1][0] = vec[0][0] + dist;
2292         vec[1][1] = vec[0][1];
2293         
2294         vec[2][0] = vec[3][0] - dist;
2295         vec[2][1] = vec[3][1];
2296         
2297         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2298         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);
2299         
2300         return 1;
2301 }
2302
2303 #define LINK_RESOL  24
2304 void ui_draw_link_bezier(const rcti *rect)
2305 {
2306         float coord_array[LINK_RESOL + 1][2];
2307         
2308         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2309                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2310                 // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
2311
2312                 glEnable(GL_BLEND);
2313                 glEnable(GL_LINE_SMOOTH);
2314
2315                 glEnableClientState(GL_VERTEX_ARRAY);
2316                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2317                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL);
2318                 glDisableClientState(GL_VERTEX_ARRAY);
2319
2320                 glDisable(GL_BLEND);
2321                 glDisable(GL_LINE_SMOOTH);
2322
2323         }
2324 }
2325
2326 /* function in use for buttons and for view2d sliders */
2327 void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
2328 {
2329         uiWidgetBase wtb;
2330         int horizontal;
2331         float rad;
2332         short outline = 0;
2333
2334         widget_init(&wtb);
2335
2336         /* determine horizontal/vertical */
2337         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2338
2339         if (horizontal)
2340                 rad = 0.5f * BLI_rcti_size_y(rect);
2341         else
2342                 rad = 0.5f * BLI_rcti_size_x(rect);
2343         
2344         wtb.shadedir = (horizontal) ? 1 : 0;
2345         
2346         /* draw back part, colors swapped and shading inverted */
2347         if (horizontal)
2348                 SWAP(short, wcol->shadetop, wcol->shadedown);
2349         
2350         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2351         widgetbase_draw(&wtb, wcol);
2352         
2353         /* slider */
2354         if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2355                 /* pass */
2356         }
2357         else {
2358                 SWAP(short, wcol->shadetop, wcol->shadedown);
2359                 
2360                 copy_v4_v4_char(wcol->inner, wcol->item);
2361                 
2362                 if (wcol->shadetop > wcol->shadedown)
2363                         wcol->shadetop += 20;   /* XXX violates themes... */
2364                 else wcol->shadedown += 20;
2365                 
2366                 if (state & UI_SCROLL_PRESSED) {
2367                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2368                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2369                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2370                 }
2371
2372                 /* draw */
2373                 wtb.emboss = 0; /* only emboss once */
2374                 
2375                 /* exception for progress bar */
2376                 if (state & UI_SCROLL_NO_OUTLINE)
2377                         SWAP(short, outline, wtb.outline);
2378                 
2379                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2380                 
2381                 if (state & UI_SCROLL_ARROWS) {
2382                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2383                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2384                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2385                         wcol->item[3] = 255;
2386                         
2387                         if (horizontal) {
2388                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2389                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2390                         }
2391                         else {
2392                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2393                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2394                         }
2395                 }
2396                 widgetbase_draw(&wtb, wcol);
2397                 
2398                 if (state & UI_SCROLL_NO_OUTLINE)
2399                         SWAP(short, outline, wtb.outline);
2400         }
2401 }
2402
2403 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2404 {
2405         rcti rect1;
2406         double value;
2407         float fac, size, min;
2408         int horizontal;
2409
2410         /* calculate slider part */
2411         value = ui_get_but_val(but);
2412
2413         size = (but->softmax + but->a1 - but->softmin);
2414         size = max_ff(size, 2.0f);
2415         
2416         /* position */
2417         rect1 = *rect;
2418
2419         /* determine horizontal/vertical */
2420         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2421         
2422         if (horizontal) {
2423                 fac = BLI_rcti_size_x(rect) / size;
2424                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2425                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2426
2427                 /* ensure minimium size */
2428                 min = BLI_rcti_size_y(rect);
2429
2430                 if (BLI_rcti_size_x(&rect1) < min) {
2431                         rect1.xmax = rect1.xmin + min;
2432
2433                         if (rect1.xmax > rect->xmax) {
2434                                 rect1.xmax = rect->xmax;
2435                                 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
2436                         }
2437                 }
2438         }
2439         else {
2440                 fac = BLI_rcti_size_y(rect) / size;
2441                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2442                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2443
2444                 /* ensure minimium size */
2445                 min = BLI_rcti_size_x(rect);
2446
2447                 if (BLI_rcti_size_y(&rect1) < min) {
2448                         rect1.ymax = rect1.ymin + min;
2449
2450                         if (rect1.ymax > rect->ymax) {
2451                                 rect1.ymax = rect->ymax;
2452                                 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
2453                         }
2454                 }
2455         }
2456
2457         if (state & UI_SELECT)
2458                 state = UI_SCROLL_PRESSED;
2459         else
2460                 state = 0;
2461         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2462 }
2463
2464 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2465 {
2466         rcti rect_prog = *rect, rect_bar = *rect;
2467         float value = but->a1;
2468         float w, min;
2469         
2470         /* make the progress bar a proportion of the original height */
2471         /* hardcoded 4px high for now */
2472         rect_prog.ymax = rect_prog.ymin + 4;
2473         rect_bar.ymax = rect_bar.ymin + 4;
2474         
2475         w = value * BLI_rcti_size_x(&rect_prog);
2476         
2477         /* ensure minimium size */
2478         min = BLI_rcti_size_y(&rect_prog);
2479         w = MAX2(w, min);
2480         
2481         rect_bar.xmax = rect_bar.xmin + w;
2482                 
2483         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2484         
2485         /* raise text a bit */
2486         rect->ymin += 6;
2487         rect->xmin -= 6;
2488 }
2489
2490 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2491 {
2492         
2493         if (but->flag & UI_SELECT) {
2494                 rcti rectlink;
2495                 
2496                 UI_ThemeColor(TH_TEXT_HI);
2497                 
2498                 rectlink.xmin = BLI_rcti_cent_x(rect);
2499                 rectlink.ymin = BLI_rcti_cent_y(rect);
2500                 rectlink.xmax = but->linkto[0];
2501                 rectlink.ymax = but->linkto[1];
2502                 
2503                 ui_draw_link_bezier(&rectlink);
2504         }
2505 }
2506
2507 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2508 {
2509         uiWidgetBase wtb, wtb1;
2510         rcti rect1;
2511         double value;
2512         float offs, toffs, fac;
2513         char outline[3];
2514
2515         widget_init(&wtb);
2516         widget_init(&wtb1);
2517         
2518         /* backdrop first */
2519         
2520         /* fully rounded */
2521         offs = 0.5f * BLI_rcti_size_y(rect);
2522         toffs = offs * 0.75f;
2523         round_box_edges(&wtb, roundboxalign, rect, offs);
2524
2525         wtb.outline = 0;
2526         widgetbase_draw(&wtb, wcol);
2527         
2528         /* draw left/right parts only when not in text editing */
2529         if (!(state & UI_TEXTINPUT)) {
2530                 
2531                 /* slider part */
2532                 copy_v3_v3_char(outline, wcol->outline);
2533                 copy_v3_v3_char(wcol->outline, wcol->item);
2534                 copy_v3_v3_char(wcol->inner, wcol->item);
2535
2536                 if (!(state & UI_SELECT))
2537                         SWAP(short, wcol->shadetop, wcol->shadedown);
2538                 
2539                 rect1 = *rect;
2540                 
2541                 value = ui_get_but_val(but);
2542                 fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
2543                 
2544                 /* left part of slider, always rounded */
2545                 rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
2546                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2547                 wtb1.outline = 0;
2548                 widgetbase_draw(&wtb1, wcol);
2549                 
2550                 /* right part of slider, interpolate roundness */
2551                 rect1.xmax = rect1.xmin + fac + offs;
2552                 rect1.xmin +=  floor(offs - U.pixelsize);
2553                 
2554                 if (rect1.xmax + offs > rect->xmax)
2555                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2556                 else 
2557                         offs = 0.0f;
2558                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2559                 
2560                 widgetbase_draw(&wtb1, wcol);
2561                 copy_v3_v3_char(wcol->outline, outline);
2562                 
2563                 if (!(state & UI_SELECT))
2564                         SWAP(short, wcol->shadetop, wcol->shadedown);
2565         }
2566         
2567         /* outline */
2568         wtb.outline = 1;
2569         wtb.inner = 0;
2570         widgetbase_draw(&wtb, wcol);
2571         
2572         /* text space */
2573         rect->xmin += toffs;
2574         rect->xmax -= toffs;
2575 }
2576
2577 /* I think 3 is sufficient border to indicate keyed status */
2578 #define SWATCH_KEYED_BORDER 3
2579
2580 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2581 {
2582         uiWidgetBase wtb;
2583         float rad, col[4];
2584         int color_profile = but->block->color_profile;
2585         
2586         col[3] = 1.0f;
2587
2588         if (but->rnaprop) {
2589                 BLI_assert(but->rnaindex == -1);
2590
2591                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2592                         color_profile = FALSE;
2593
2594                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2595                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2596                 }
2597         }
2598         
2599         widget_init(&wtb);
2600         
2601         /* half rounded */
2602         rad = 0.25f * U.widget_unit;
2603         round_box_edges(&wtb, roundboxalign, rect, rad);
2604                 
2605         ui_get_but_vectorf(but, col);
2606
2607         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2608                 /* draw based on state - color for keyed etc */
2609                 widgetbase_draw(&wtb, wcol);
2610
2611                 /* inset to draw swatch color */
2612                 rect->xmin += SWATCH_KEYED_BORDER;
2613                 rect->xmax -= SWATCH_KEYED_BORDER;
2614                 rect->ymin += SWATCH_KEYED_BORDER;
2615                 rect->ymax -= SWATCH_KEYED_BORDER;
2616                 
2617                 round_box_edges(&wtb, roundboxalign, rect, rad);
2618         }
2619         
2620         if (color_profile)
2621                 ui_block_to_display_space_v3(but->block, col);
2622         
2623         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2624
2625         wcol->shaded = 0;
2626         wcol->alpha_check = (wcol->inner[3] < 255);
2627
2628         widgetbase_draw(&wtb, wcol);
2629         
2630 }
2631
2632 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2633 {
2634         ui_draw_but_NORMAL(but, wcol, rect);
2635 }
2636
2637 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2638 {
2639         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2640                 uiWidgetBase wtb;
2641                 float rad;
2642                 
2643                 widget_init(&wtb);
2644                 wtb.outline = 0;
2645                 
2646                 /* rounded */
2647                 rad = 0.5f * BLI_rcti_size_y(rect);
2648                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2649                 widgetbase_draw(&wtb, wcol);
2650         }
2651 }
2652
2653
2654 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2655 {
2656         uiWidgetBase wtb;
2657         float rad;
2658         
2659         if (state & UI_SELECT)
2660                 SWAP(short, wcol->shadetop, wcol->shadedown);
2661         
2662         widget_init(&wtb);
2663         
2664         /* half rounded */
2665         rad = 0.2f * U.widget_unit;
2666         round_box_edges(&wtb, roundboxalign, rect, rad);
2667         
2668         widgetbase_draw(&wtb, wcol);
2669
2670 }
2671
2672
2673 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2674 {
2675         uiWidgetBase wtb;
2676         float rad;
2677         
2678         widget_init(&wtb);
2679         
2680         /* half rounded */
2681         rad = 0.2f * U.widget_unit;
2682         round_box_edges(&wtb, roundboxalign, rect, rad);
2683         
2684         /* decoration */
2685         widget_menu_trias(&wtb.tria1, rect);
2686         
2687         widgetbase_draw(&wtb, wcol);
2688         
2689         /* text space, arrows are about 0.6 height of button */
2690         rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
2691 }
2692
2693 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2694 {
2695         uiWidgetBase wtb;
2696         float rad;
2697         
2698         widget_init(&wtb);
2699         
2700         /* half rounded */
2701         rad = 0.2f * U.widget_unit;
2702         round_box_edges(&wtb, roundboxalign, rect, rad);
2703         
2704         /* decoration */
2705         widgetbase_draw(&wtb, wcol);
2706 }
2707
2708 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2709 {
2710         /* silly node link button hacks */
2711         uiWidgetBase wtb;
2712         uiWidgetColors wcol_backup = *wcol;
2713         float rad;
2714         
2715         widget_init(&wtb);
2716         
2717         /* half rounded */
2718         rad = 0.2f * U.widget_unit;
2719         round_box_edges(&wtb, roundboxalign, rect, rad);
2720
2721         wcol->inner[0] += 15;
2722         wcol->inner[1] += 15;
2723         wcol->inner[2] += 15;
2724         wcol->outline[0] += 15;
2725         wcol->outline[1] += 15;
2726         wcol->outline[2] += 15;
2727         
2728         /* decoration */
2729         widgetbase_draw(&wtb, wcol);
2730         *wcol = wcol_backup;
2731 }
2732
2733 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2734 {
2735         if (state & UI_ACTIVE) {
2736                 uiWidgetBase wtb;
2737                 const float rad = 0.2f * U.widget_unit;
2738
2739                 widget_init(&wtb);
2740
2741                 /* half rounded */
2742                 round_box_edges(&wtb, roundboxalign, rect, rad);
2743                 
2744                 widgetbase_draw(&wtb, wcol);
2745         }
2746 }
2747
2748 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2749 {
2750         uiWidgetBase wtb;
2751         
2752         widget_init(&wtb);
2753         
2754         /* not rounded, no outline */
2755         wtb.outline = 0;
2756         round_box_edges(&wtb, 0, rect, 0.0f);
2757         
2758         widgetbase_draw(&wtb, wcol);
2759 }
2760
2761 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2762 {
2763         uiWidgetBase wtb;
2764         float rad;
2765         
2766         widget_init(&wtb);
2767         
2768         /* rounded, but no outline */
2769         wtb.outline = 0;
2770         rad = 0.2f * U.widget_unit;
2771         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2772         
2773         widgetbase_draw(&wtb, wcol);
2774 }
2775
2776 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2777 {
2778         uiWidgetBase wtb;
2779         rcti recttemp = *rect;
2780         float rad;
2781         int delta;
2782         
2783         widget_init(&wtb);
2784         
2785         /* square */
2786         recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
2787         
2788         /* smaller */
2789         delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
2790         recttemp.xmin += delta;
2791         recttemp.ymin += delta;
2792         recttemp.xmax -= delta;
2793         recttemp.ymax -= delta;
2794         
2795         /* half rounded */
2796         rad = 0.2f * U.widget_unit;
2797         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
2798         
2799         /* decoration */
2800         if (state & UI_SELECT) {
2801                 widget_check_trias(&wtb.tria1, &recttemp);
2802         }
2803         
2804         widgetbase_draw(&wtb, wcol);
2805         
2806         /* text space */
2807         rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta;
2808 }
2809
2810
2811 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2812 {
2813         uiWidgetBase wtb;
2814         float rad;
2815         
2816         widget_init(&wtb);
2817         
2818         /* half rounded */
2819         rad = 0.2f * U.widget_unit;
2820         round_box_edges(&wtb, roundboxalign, rect, rad);
2821         
2822         widgetbase_draw(&wtb, wcol);
2823
2824 }
2825
2826 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2827 {
2828         uiWidgetBase wtb;
2829         float rad;
2830         char old_col[3];
2831         
2832         widget_init(&wtb);
2833         
2834         copy_v3_v3_char(old_col, wcol->inner);
2835         
2836         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2837         if (but->col[3]) {
2838                 wcol->inner[0] = but->col[0];
2839                 wcol->inner[1] = but->col[1];
2840                 wcol->inner[2] = but->col[2];
2841         }
2842         
2843         /* half rounded */
2844         rad = 0.2f * U.widget_unit;
2845         round_box_edges(&wtb, roundboxalign, rect, rad);
2846         
2847         widgetbase_draw(&wtb, wcol);
2848         
2849         /* store the box bg as gl clearcolor, to retrieve later when drawing semi-transparent rects
2850          * over the top to indicate disabled buttons */
2851         /* XXX, this doesnt work right since the color applies to buttons outside the box too. */
2852         glClearColor(wcol->inner[0] / 255.0, wcol->inner[1] / 255.0, wcol->inner[2] / 255.0, 1.0);
2853         
2854         copy_v3_v3_char(wcol->inner, old_col);
2855 }
2856
2857 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2858 {
2859         uiWidgetBase wtb;
2860         float rad;
2861         
2862         widget_init(&wtb);
2863         
2864         /* half rounded */
2865         rad = 0.2f * U.widget_unit;
2866         round_box_edges(&wtb, roundboxalign, rect, rad);
2867         
2868         widgetbase_draw(&wtb, wcol);
2869
2870 }
2871
2872 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2873 {
2874         uiWidgetBase wtb;
2875         const float rad = 0.25f * U.widget_unit;
2876         
2877         widget_init(&wtb);
2878         
2879         /* half rounded */
2880         round_box_edges(&wtb, roundboxalign, rect, rad);
2881
2882         widgetbase_draw(&wtb, wcol);
2883 }
2884
2885 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2886 {
2887         uiWidgetBase wtb;
2888         const float rad = 0.25f * U.widget_unit;
2889         unsigned char col[4];
2890         
2891         /* state copy! */
2892         wt->wcol = *(wt->wcol_theme);
2893         
2894         widget_init(&wtb);
2895         
2896         if (but->block->drawextra) {
2897                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2898                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2899                 
2900                 /* make mask to draw over image */
2901                 UI_GetThemeColor3ubv(TH_BACK, col);
2902                 glColor3ubv(col);
2903                 
2904                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
2905                 widgetbase_outline(&wtb);
2906         }
2907         
2908         /* outline */
2909         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2910         wtb.outline = 1;
2911         wtb.inner = 0;
2912         widgetbase_draw(&wtb, &wt->wcol);
2913         
2914 }
2915
2916
2917 static void widget_disabled(const rcti *rect)
2918 {
2919         float col[4];
2920         
2921         glEnable(GL_BLEND);
2922         
2923         /* can't use theme TH_BACK or TH_PANEL... undefined */
2924         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2925         glColor4f(col[0], col[1], col[2], 0.5f);
2926
2927         /* need -1 and +1 to make it work right for aligned buttons,
2928          * but problem may be somewhere else? */
2929         glRectf(rect->xmin - 1, rect->ymin - 1, rect->xmax, rect->ymax + 1);
2930         
2931         glDisable(GL_BLEND);
2932 }
2933
2934 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2935 {
2936         bTheme *btheme = UI_GetTheme();
2937         static uiWidgetType wt;
2938         
2939         /* defaults */
2940         wt.wcol_theme = &btheme->tui.wcol_regular;
2941         wt.wcol_state = &btheme->tui.wcol_state;
2942         wt.state = widget_state;
2943         wt.draw = widget_but;
2944         wt.custom = NULL;
2945         wt.text = widget_draw_text_icon;
2946         
2947         switch (type) {
2948                 case UI_WTYPE_REGULAR:
2949                         break;
2950
2951                 case UI_WTYPE_LABEL:
2952                         wt.draw = NULL;
2953                         wt.state = widget_state_label;
2954                         break;
2955                         
2956                 case UI_WTYPE_TOGGLE:
2957                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2958                         break;
2959                         
2960                 case UI_WTYPE_OPTION:
2961                         wt.wcol_theme = &btheme->tui.wcol_option;
2962                         wt.draw = widget_optionbut;
2963                         break;
2964                         
2965                 case UI_WTYPE_RADIO:
2966                         wt.wcol_theme = &btheme->tui.wcol_radio;
2967                         wt.draw = widget_radiobut;
2968                         break;
2969
2970                 case UI_WTYPE_NUMBER:
2971                         wt.wcol_theme = &btheme->tui.wcol_num;
2972                         wt.draw = widget_numbut;
2973                         break;
2974                         
2975                 case UI_WTYPE_SLIDER:
2976                         wt.wcol_theme = &btheme->tui.wcol_numslider;
2977                         wt.custom = widget_numslider;
2978                         wt.state = widget_state_numslider;
2979                         break;
2980                         
2981                 case UI_WTYPE_EXEC:
2982                         wt.wcol_theme = &btheme->tui.wcol_tool;
2983                         wt.draw = widget_roundbut;
2984                         break;
2985
2986                 case UI_WTYPE_TOOLTIP:
2987                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
2988                         wt.draw = widget_menu_back;
2989                         break;
2990                         
2991                         
2992                 /* strings */
2993                 case UI_WTYPE_NAME:
2994                         wt.wcol_theme = &btheme->tui.wcol_text;
2995                         wt.draw = widget_textbut;
2996                         break;
2997                         
2998                 case UI_WTYPE_NAME_LINK:
2999                         break;
3000                         
3001                 case UI_WTYPE_POINTER_LINK:
3002                         break;
3003                         
3004                 case UI_WTYPE_FILENAME:
3005                         break;
3006                         
3007                         
3008                 /* start menus */
3009                 case UI_WTYPE_MENU_RADIO:
3010                         wt.wcol_theme = &btheme->tui.wcol_menu;
3011                         wt.draw = widget_menubut;
3012                         break;
3013
3014                 case UI_WTYPE_MENU_ICON_RADIO:
3015                         wt.wcol_theme = &btheme->tui.wcol_menu;
3016                         wt.draw = widget_menuiconbut;
3017                         break;
3018                         
3019                 case UI_WTYPE_MENU_POINTER_LINK:
3020                         wt.wcol_theme = &btheme->tui.wcol_menu;
3021                         wt.draw = widget_menubut;
3022                         break;
3023
3024                 case UI_WTYPE_MENU_NODE_LINK:
3025                         wt.wcol_theme = &btheme->tui.wcol_menu;
3026                         wt.draw = widget_menunodebut;
3027                         break;
3028                         
3029                 case UI_WTYPE_PULLDOWN:
3030                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
3031                         wt.draw = widget_pulldownbut;
3032                         wt.state = widget_state_pulldown;
3033                         break;
3034                         
3035                 /* in menus */
3036                 case UI_WTYPE_MENU_ITEM:
3037                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
3038                         wt.draw = widget_menu_itembut;
3039                         wt.state = widget_state_menu_item;
3040                         break;
3041                         
3042                 case UI_WTYPE_MENU_BACK:
3043                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
3044                         wt.draw = widget_menu_back;
3045                         break;
3046                         
3047                 /* specials */
3048                 case UI_WTYPE_ICON:
3049                         wt.custom = widget_icon_has_anim;
3050                         break;
3051                         
3052                 case UI_WTYPE_SWATCH:
3053                         wt.custom = widget_swatch;
3054                         break;
3055                         
3056                 case UI_WTYPE_BOX:
3057                         wt.custom = widget_box;
3058                         wt.wcol_theme = &btheme->tui.wcol_box;
3059                         break;
3060                         
3061                 case UI_WTYPE_RGB_PICKER:
3062                         break;
3063                         
3064                 case UI_WTYPE_NORMAL:
3065                         wt.custom = widget_normal;
3066                         break;
3067
3068                 case UI_WTYPE_SCROLL:
3069                         wt.wcol_theme = &btheme->tui.wcol_scroll;
3070                         wt.state = widget_state_nothing;
3071                         wt.custom = widget_scroll;
3072                         break;
3073
3074                 case UI_WTYPE_LISTITEM:
3075                         wt.wcol_theme = &btheme->tui.wcol_list_item;
3076                         wt.draw = widget_list_itembut;
3077                         break;
3078                         
3079                 case UI_WTYPE_PROGRESSBAR:
3080                         wt.wcol_theme = &btheme->tui.wcol_progress;
3081                         wt.custom = widget_progressbar;
3082                         break;
3083         }
3084         
3085         return &wt;
3086 }
3087
3088
3089 static int widget_roundbox_set(uiBut *but, rcti *rect)
3090 {
3091         int roundbox = UI_CNR_ALL;
3092
3093         /* alignment */
3094         if ((but->flag & UI_BUT_ALIGN) && but->type != PULLDOWN) {
3095                 
3096                 /* ui_block_position has this correction too, keep in sync */
3097                 if (but->flag & UI_BUT_ALIGN_TOP)
3098                         rect->ymax += U.pixelsize;
3099                 if (but->flag & UI_BUT_ALIGN_LEFT)
3100                         rect->xmin -= U.pixelsize;
3101                 
3102                 switch (but->flag & UI_BUT_ALIGN) {
3103                         case UI_BUT_ALIGN_TOP:
3104                                 roundbox = UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
3105                                 break;
3106                         case UI_BUT_ALIGN_DOWN:
3107                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
3108                                 break;
3109                         case UI_BUT_ALIGN_LEFT:
3110                                 roundbox = UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
3111                                 break;
3112                         case UI_BUT_ALIGN_RIGHT:
3113                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
3114                                 break;
3115                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
3116                                 roundbox = UI_CNR_TOP_LEFT;
3117                                 break;
3118                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
3119                                 roundbox = UI_CNR_TOP_RIGHT;
3120                                 break;
3121                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
3122                                 roundbox = UI_CNR_BOTTOM_LEFT;
3123                                 break;
3124                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
3125                                 roundbox = UI_CNR_BOTTOM_RIGHT;
3126                                 break;
3127                         default:
3128                                 roundbox = 0;
3129                                 break;
3130                 }
3131         }
3132
3133         /* align with open menu */
3134         if (but->active) {
3135                 int direction = ui_button_open_menu_direction(but);
3136
3137                 if      (direction == UI_TOP)   roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
3138                 else if (direction == UI_DOWN)  roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
3139                 else if (direction == UI_LEFT)  roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
3140                 else if (direction == UI_RIGHT) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3141         }
3142
3143         return roundbox;
3144 }
3145
3146 /* conversion from old to new buttons, so still messy */
3147 void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
3148 {
3149         bTheme *btheme = UI_GetTheme();
3150         ThemeUI *tui = &btheme->tui;
3151         uiFontStyle *fstyle = &style->widget;
3152         uiWidgetType *wt = NULL;
3153
3154         /* handle menus separately */
3155         if (but->dt == UI_EMBOSSP) {
3156                 switch (but->type) {
3157                         case LABEL:
3158                                 widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
3159                                 break;
3160                         case SEPR:
3161                                &nb