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