Bug fix (own collection)
[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->inner_v[a][0];
650                 quad_strip[a * 2 + 1][1] = wtb->inner_v[a][1];
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 (but->type == SEARCH_MENU)
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 (ELEM(but->type, TEX, SEARCH_MENU)) {
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 += 0.4f * U.widget_unit;
1329                 }
1330                 else if ((but->flag & UI_TEXT_LEFT))
1331                         rect->xmin += 0.4f * U.widget_unit;
1332
1333                 /* always draw text for textbutton cursor */
1334                 widget_draw_text(fstyle, wcol, but, rect);
1335
1336         }
1337
1338         ui_button_text_password_hide(password_str, but, TRUE);
1339 }
1340
1341
1342
1343 /* *********************** widget types ************************************* */
1344
1345
1346 /* uiWidgetStateColors
1347  *     char inner_anim[4];
1348  *     char inner_anim_sel[4];
1349  *     char inner_key[4];
1350  *     char inner_key_sel[4];
1351  *     char inner_driven[4];
1352  *     char inner_driven_sel[4];
1353  *     float blend;
1354  */
1355
1356 static struct uiWidgetStateColors wcol_state_colors = {
1357         {115, 190, 76, 255},
1358         {90, 166, 51, 255},
1359         {240, 235, 100, 255},
1360         {215, 211, 75, 255},
1361         {180, 0, 255, 255},
1362         {153, 0, 230, 255},
1363         0.5f, 0.0f
1364 };
1365
1366 /* uiWidgetColors
1367  *     float outline[3];
1368  *     float inner[4];
1369  *     float inner_sel[4];
1370  *     float item[3];
1371  *     float text[3];
1372  *     float text_sel[3];
1373  *     
1374  *     short shaded;
1375  *     float shadetop, shadedown;
1376  */
1377
1378 static struct uiWidgetColors wcol_num = {
1379         {25, 25, 25, 255},
1380         {180, 180, 180, 255},
1381         {153, 153, 153, 255},
1382         {90, 90, 90, 255},
1383         
1384         {0, 0, 0, 255},
1385         {255, 255, 255, 255},
1386         
1387         1,
1388         -20, 0
1389 };
1390
1391 static struct uiWidgetColors wcol_numslider = {
1392         {25, 25, 25, 255},
1393         {180, 180, 180, 255},
1394         {153, 153, 153, 255},
1395         {128, 128, 128, 255},
1396         
1397         {0, 0, 0, 255},
1398         {255, 255, 255, 255},
1399         
1400         1,
1401         -20, 0
1402 };
1403
1404 static struct uiWidgetColors wcol_text = {
1405         {25, 25, 25, 255},
1406         {153, 153, 153, 255},
1407         {153, 153, 153, 255},
1408         {90, 90, 90, 255},
1409         
1410         {0, 0, 0, 255},
1411         {255, 255, 255, 255},
1412         
1413         1,
1414         0, 25
1415 };
1416
1417 static struct uiWidgetColors wcol_option = {
1418         {0, 0, 0, 255},
1419         {70, 70, 70, 255},
1420         {70, 70, 70, 255},
1421         {255, 255, 255, 255},
1422         
1423         {0, 0, 0, 255},
1424         {255, 255, 255, 255},
1425         
1426         1,
1427         15, -15
1428 };
1429
1430 /* button that shows popup */
1431 static struct uiWidgetColors wcol_menu = {
1432         {0, 0, 0, 255},
1433         {70, 70, 70, 255},
1434         {70, 70, 70, 255},
1435         {255, 255, 255, 255},
1436         
1437         {255, 255, 255, 255},
1438         {204, 204, 204, 255},
1439         
1440         1,
1441         15, -15
1442 };
1443
1444 /* button that starts pulldown */
1445 static struct uiWidgetColors wcol_pulldown = {
1446         {0, 0, 0, 255},
1447         {63, 63, 63, 255},
1448         {86, 128, 194, 255},
1449         {255, 255, 255, 255},
1450         
1451         {0, 0, 0, 255},
1452         {0, 0, 0, 255},
1453         
1454         0,
1455         25, -20
1456 };
1457
1458 /* button inside menu */
1459 static struct uiWidgetColors wcol_menu_item = {
1460         {0, 0, 0, 255},
1461         {0, 0, 0, 0},
1462         {86, 128, 194, 255},
1463         {172, 172, 172, 128},
1464         
1465         {255, 255, 255, 255},
1466         {0, 0, 0, 255},
1467         
1468         1,
1469         38, 0
1470 };
1471
1472 /* backdrop menu + title text color */
1473 static struct uiWidgetColors wcol_menu_back = {
1474         {0, 0, 0, 255},
1475         {25, 25, 25, 230},
1476         {45, 45, 45, 230},
1477         {100, 100, 100, 255},
1478         
1479         {160, 160, 160, 255},
1480         {255, 255, 255, 255},
1481         
1482         0,
1483         25, -20
1484 };
1485
1486 /* tooltip color */
1487 static struct uiWidgetColors wcol_tooltip = {
1488         {0, 0, 0, 255},
1489         {25, 25, 25, 230},
1490         {45, 45, 45, 230},
1491         {100, 100, 100, 255},
1492
1493         {160, 160, 160, 255},
1494         {255, 255, 255, 255},
1495
1496         0,
1497         25, -20
1498 };
1499
1500 static struct uiWidgetColors wcol_radio = {
1501         {0, 0, 0, 255},
1502         {70, 70, 70, 255},
1503         {86, 128, 194, 255},
1504         {255, 255, 255, 255},
1505         
1506         {255, 255, 255, 255},
1507         {0, 0, 0, 255},
1508         
1509         1,
1510         15, -15
1511 };
1512
1513 static struct uiWidgetColors wcol_regular = {
1514         {25, 25, 25, 255},
1515         {153, 153, 153, 255},
1516         {100, 100, 100, 255},
1517         {25, 25, 25, 255},
1518         
1519         {0, 0, 0, 255},
1520         {255, 255, 255, 255},
1521         
1522         0,
1523         0, 0
1524 };
1525
1526 static struct uiWidgetColors wcol_tool = {
1527         {25, 25, 25, 255},
1528         {153, 153, 153, 255},
1529         {100, 100, 100, 255},
1530         {25, 25, 25, 255},
1531         
1532         {0, 0, 0, 255},
1533         {255, 255, 255, 255},
1534         
1535         1,
1536         15, -15
1537 };
1538
1539 static struct uiWidgetColors wcol_box = {
1540         {25, 25, 25, 255},
1541         {128, 128, 128, 255},
1542         {100, 100, 100, 255},
1543         {25, 25, 25, 255},
1544         
1545         {0, 0, 0, 255},
1546         {255, 255, 255, 255},
1547         
1548         0,
1549         0, 0
1550 };
1551
1552 static struct uiWidgetColors wcol_toggle = {
1553         {25, 25, 25, 255},
1554         {153, 153, 153, 255},
1555         {100, 100, 100, 255},
1556         {25, 25, 25, 255},
1557         
1558         {0, 0, 0, 255},
1559         {255, 255, 255, 255},
1560         
1561         0,
1562         0, 0
1563 };
1564
1565 static struct uiWidgetColors wcol_scroll = {
1566         {50, 50, 50, 180},
1567         {80, 80, 80, 180},
1568         {100, 100, 100, 180},
1569         {128, 128, 128, 255},
1570         
1571         {0, 0, 0, 255},
1572         {255, 255, 255, 255},
1573         
1574         1,
1575         5, -5
1576 };
1577
1578 static struct uiWidgetColors wcol_progress = {
1579         {0, 0, 0, 255},
1580         {190, 190, 190, 255},
1581         {100, 100, 100, 180},
1582         {68, 68, 68, 255},
1583         
1584         {0, 0, 0, 255},
1585         {255, 255, 255, 255},
1586         
1587         0,
1588         0, 0
1589 };
1590
1591 static struct uiWidgetColors wcol_list_item = {
1592         {0, 0, 0, 255},
1593         {0, 0, 0, 0},
1594         {86, 128, 194, 255},
1595         {0, 0, 0, 255},
1596         
1597         {0, 0, 0, 255},
1598         {0, 0, 0, 255},
1599         
1600         0,
1601         0, 0
1602 };
1603
1604 /* free wcol struct to play with */
1605 static struct uiWidgetColors wcol_tmp = {
1606         {0, 0, 0, 255},
1607         {128, 128, 128, 255},
1608         {100, 100, 100, 255},
1609         {25, 25, 25, 255},
1610         
1611         {0, 0, 0, 255},
1612         {255, 255, 255, 255},
1613         
1614         0,
1615         0, 0
1616 };
1617
1618
1619 /* called for theme init (new theme) and versions */
1620 void ui_widget_color_init(ThemeUI *tui)
1621 {
1622         tui->wcol_regular = wcol_regular;
1623         tui->wcol_tool = wcol_tool;
1624         tui->wcol_text = wcol_text;
1625         tui->wcol_radio = wcol_radio;
1626         tui->wcol_option = wcol_option;
1627         tui->wcol_toggle = wcol_toggle;
1628         tui->wcol_num = wcol_num;
1629         tui->wcol_numslider = wcol_numslider;
1630         tui->wcol_menu = wcol_menu;
1631         tui->wcol_pulldown = wcol_pulldown;
1632         tui->wcol_menu_back = wcol_menu_back;
1633         tui->wcol_tooltip = wcol_tooltip;
1634         tui->wcol_menu_item = wcol_menu_item;
1635         tui->wcol_box = wcol_box;
1636         tui->wcol_scroll = wcol_scroll;
1637         tui->wcol_list_item = wcol_list_item;
1638         tui->wcol_progress = wcol_progress;
1639
1640         tui->wcol_state = wcol_state_colors;
1641 }
1642
1643 /* ************ button callbacks, state ***************** */
1644
1645 static void widget_state_blend(char cp[3], const char cpstate[3], const float fac)
1646 {
1647         if (fac != 0.0f) {
1648                 cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
1649                 cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
1650                 cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
1651         }
1652 }
1653
1654 /* copy colors from theme, and set changes in it based on state */
1655 static void widget_state(uiWidgetType *wt, int state)
1656 {
1657         uiWidgetStateColors *wcol_state = wt->wcol_state;
1658
1659         wt->wcol = *(wt->wcol_theme);
1660         
1661         if (state & UI_SELECT) {
1662                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1663
1664                 if (state & UI_BUT_ANIMATED_KEY)
1665                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1666                 else if (state & UI_BUT_ANIMATED)
1667                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1668                 else if (state & UI_BUT_DRIVEN)
1669                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1670
1671                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1672                 
1673                 if (state & UI_SELECT)
1674                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1675         }
1676         else {
1677                 if (state & UI_BUT_ANIMATED_KEY)
1678                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1679                 else if (state & UI_BUT_ANIMATED)
1680                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1681                 else if (state & UI_BUT_DRIVEN)
1682                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1683
1684                 if (state & UI_ACTIVE) { /* mouse over? */
1685                         wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
1686                         wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
1687                         wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
1688                 }
1689         }
1690
1691         if (state & UI_BUT_REDALERT) {
1692                 char red[4] = {255, 0, 0};
1693                 widget_state_blend(wt->wcol.inner, red, 0.4f);
1694         }
1695         if (state & UI_BUT_NODE_ACTIVE) {
1696                 char blue[4] = {86, 128, 194};
1697                 widget_state_blend(wt->wcol.inner, blue, 0.3f);
1698         }
1699 }
1700
1701 /* sliders use special hack which sets 'item' as inner when drawing filling */
1702 static void widget_state_numslider(uiWidgetType *wt, int state)
1703 {
1704         uiWidgetStateColors *wcol_state = wt->wcol_state;
1705         float blend = wcol_state->blend - 0.2f; /* XXX special tweak to make sure that bar will still be visible */
1706
1707         /* call this for option button */
1708         widget_state(wt, state);
1709         
1710         /* now, set the inner-part so that it reflects state settings too */
1711         /* TODO: maybe we should have separate settings for the blending colors used for this case? */
1712         if (state & UI_SELECT) {
1713                 
1714                 if (state & UI_BUT_ANIMATED_KEY)
1715                         widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
1716                 else if (state & UI_BUT_ANIMATED)
1717                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
1718                 else if (state & UI_BUT_DRIVEN)
1719                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
1720                 
1721                 if (state & UI_SELECT)
1722                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1723         }
1724         else {
1725                 if (state & UI_BUT_ANIMATED_KEY)
1726                         widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
1727                 else if (state & UI_BUT_ANIMATED)
1728                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
1729                 else if (state & UI_BUT_DRIVEN)
1730                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
1731         }
1732 }
1733
1734 /* labels use theme colors for text */
1735 static void widget_state_label(uiWidgetType *wt, int state)
1736 {
1737         /* call this for option button */
1738         widget_state(wt, state);
1739
1740         if (state & UI_SELECT)
1741                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1742         else
1743                 UI_GetThemeColor4ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
1744         
1745 }
1746
1747 /* labels use theme colors for text */
1748 static void widget_state_option_menu(uiWidgetType *wt, int state)
1749 {
1750         
1751         /* call this for option button */
1752         widget_state(wt, state);
1753         
1754         /* if not selected we get theme from menu back */
1755         if (state & UI_SELECT)
1756                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1757         else {
1758                 bTheme *btheme = UI_GetTheme(); /* XXX */
1759
1760                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text);
1761         }
1762 }
1763
1764
1765 static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
1766 {
1767         wt->wcol = *(wt->wcol_theme);
1768 }       
1769
1770 /* special case, button that calls pulldown */
1771 static void widget_state_pulldown(uiWidgetType *wt, int state)
1772 {
1773         wt->wcol = *(wt->wcol_theme);
1774         
1775         copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1776         copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
1777
1778         if (state & UI_ACTIVE)
1779                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1780 }
1781
1782 /* special case, menu items */
1783 static void widget_state_menu_item(uiWidgetType *wt, int state)
1784 {
1785         wt->wcol = *(wt->wcol_theme);
1786         
1787         if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1788                 wt->wcol.text[0] = 0.5f * (wt->wcol.text[0] + wt->wcol.text_sel[0]);
1789                 wt->wcol.text[1] = 0.5f * (wt->wcol.text[1] + wt->wcol.text_sel[1]);
1790                 wt->wcol.text[2] = 0.5f * (wt->wcol.text[2] + wt->wcol.text_sel[2]);
1791         }
1792         else if (state & UI_ACTIVE) {
1793                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1794                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1795         }
1796 }
1797
1798
1799 /* ************ menu backdrop ************************* */
1800
1801 /* outside of rect, rad to left/bottom/right */
1802 static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
1803 {
1804         bTheme *btheme = UI_GetTheme();
1805         uiWidgetBase wtb;
1806         rcti rect1 = *rect;
1807         float alphastep;
1808         int step, totvert;
1809         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
1810         const float radout = UI_ThemeMenuShadowWidth();
1811         
1812         /* disabled shadow */
1813         if (radout == 0.0f)
1814                 return;
1815         
1816         /* prevent tooltips to not show round shadow */
1817         if (radout > 0.2f * BLI_rcti_size_y(&rect1))
1818                 rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
1819         else
1820                 rect1.ymax -= radout;
1821         
1822         /* inner part */
1823         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1824
1825         /* we draw a number of increasing size alpha quad strips */
1826         alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
1827         
1828         glEnableClientState(GL_VERTEX_ARRAY);
1829
1830         for (step = 1; step <= (int)radout; step++) {
1831                 float expfac = sqrt(step / radout);
1832                 
1833                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1834                 
1835                 glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
1836
1837                 widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
1838
1839                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1840                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2 + 2);
1841         }
1842
1843         glDisableClientState(GL_VERTEX_ARRAY);
1844 }
1845
1846 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1847 {
1848         uiWidgetBase wtb;
1849         int roundboxalign = UI_CNR_ALL;
1850         
1851         widget_init(&wtb);
1852         
1853         /* menu is 2nd level or deeper */
1854         if (flag & UI_BLOCK_POPUP) {
1855                 //rect->ymin -= 4.0;
1856                 //rect->ymax += 4.0;
1857         }
1858         else if (direction == UI_DOWN) {
1859                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1860                 rect->ymin -= 0.1f * U.widget_unit;
1861         }
1862         else if (direction == UI_TOP) {
1863                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1864                 rect->ymax += 0.1f * U.widget_unit;
1865         }
1866         
1867         glEnable(GL_BLEND);
1868         widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
1869         
1870         round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
1871         wtb.emboss = 0;
1872         widgetbase_draw(&wtb, wcol);
1873         
1874         glDisable(GL_BLEND);
1875 }
1876
1877
1878 static void ui_hsv_cursor(float x, float y)
1879 {
1880         
1881         glPushMatrix();
1882         glTranslatef(x, y, 0.0f);
1883         
1884         glColor3f(1.0f, 1.0f, 1.0f);
1885         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f, 8);
1886         
1887         glEnable(GL_BLEND);
1888         glEnable(GL_LINE_SMOOTH);
1889         glColor3f(0.0f, 0.0f, 0.0f);
1890         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f, 12);
1891         glDisable(GL_BLEND);
1892         glDisable(GL_LINE_SMOOTH);
1893         
1894         glPopMatrix();
1895         
1896 }
1897
1898 void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
1899                                 const float mx, const float my)
1900 {
1901         /* duplication of code... well, simple is better now */
1902         const float centx = BLI_rcti_cent_x_fl(rect);
1903         const float centy = BLI_rcti_cent_y_fl(rect);
1904         const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1905         const float m_delta[2] = {mx - centx, my - centy};
1906         const float dist_squared = len_squared_v2(m_delta);
1907
1908         *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f;
1909         *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
1910 }
1911
1912 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
1913 {
1914         const int tot = 32;
1915         const float radstep = 2.0f * (float)M_PI / (float)tot;
1916
1917         const float centx = BLI_rcti_cent_x_fl(rect);
1918         const float centy = BLI_rcti_cent_y_fl(rect);
1919         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1920
1921         /* gouraud triangle fan */
1922         const float *hsv_ptr = ui_block_hsv_get(but->block);
1923         float ang = 0.0f;
1924         float cursor_radius;
1925         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1926         int a;
1927         int color_profile = but->block->color_profile;
1928         
1929         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1930                 color_profile = FALSE;
1931         
1932         /* color */
1933         ui_get_but_vectorf(but, rgb);
1934
1935         /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
1936         hsvo[0] = hsv[0] = hsv_ptr[0];
1937         hsvo[1] = hsv[1] = hsv_ptr[1];
1938         hsvo[2] = hsv[2] = hsv_ptr[2];
1939
1940         rgb_to_hsv_compat_v(rgb, hsvo);
1941
1942         if (color_profile)
1943                 ui_block_to_display_space_v3(but->block, rgb);
1944
1945         rgb_to_hsv_compat_v(rgb, hsv);
1946         
1947         /* exception: if 'lock' is set
1948          * lock the value of the color wheel to 1.
1949          * Useful for color correction tools where you're only interested in hue. */
1950         if (but->flag & UI_BUT_COLOR_LOCK)
1951                 hsv[2] = 1.f;
1952         
1953         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1954         
1955         glShadeModel(GL_SMOOTH);
1956
1957         glBegin(GL_TRIANGLE_FAN);
1958         glColor3fv(colcent);
1959         glVertex2f(centx, centy);
1960         
1961         for (a = 0; a <= tot; a++, ang += radstep) {
1962                 float si = sin(ang);
1963                 float co = cos(ang);
1964                 
1965                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1966                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1967
1968                 hsv_to_rgb_v(hsv, col);
1969                 glColor3fv(col);
1970                 glVertex2f(centx + co * radius, centy + si * radius);
1971         }
1972         glEnd();
1973         
1974         glShadeModel(GL_FLAT);
1975         
1976         /* fully rounded outline */
1977         glPushMatrix();
1978         glTranslatef(centx, centy, 0.0f);
1979         glEnable(GL_BLEND);
1980         glEnable(GL_LINE_SMOOTH);
1981         glColor3ubv((unsigned char *)wcol->outline);
1982         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
1983         glDisable(GL_BLEND);
1984         glDisable(GL_LINE_SMOOTH);
1985         glPopMatrix();
1986
1987         /* cursor */
1988         ang = 2.0f * (float)M_PI * hsvo[0] + 0.5f * (float)M_PI;
1989
1990         if (but->flag & UI_BUT_COLOR_CUBIC)
1991                 cursor_radius = (1.0f - powf(1.0f - hsvo[1], 3.0f));
1992         else
1993                 cursor_radius = hsvo[1];
1994
1995         radius = CLAMPIS(cursor_radius, 0.0f, 1.0f) * radius;
1996         ui_hsv_cursor(centx + cosf(-ang) * radius, centy + sinf(-ang) * radius);
1997 }
1998
1999 /* ************ custom buttons, old stuff ************** */
2000
2001 /* draws in resolution of 20x4 colors */
2002 void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
2003 {
2004         const float color_step = (type == UI_GRAD_H) ? 0.02f : 0.05f;
2005         int a;
2006         float h = hsv[0], s = hsv[1], v = hsv[2];
2007         float dx, dy, sx1, sx2, sy;
2008         float col0[4][3];   /* left half, rect bottom to top */
2009         float col1[4][3];   /* right half, rect bottom to top */
2010
2011         /* draw series of gouraud rects */
2012         glShadeModel(GL_SMOOTH);
2013         
2014         switch (type) {
2015                 case UI_GRAD_SV:
2016                         hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2017                         hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
2018                         hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
2019                         hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2020                         break;
2021                 case UI_GRAD_HV:
2022                         hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2023                         hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2024                         hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2025                         hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2026                         break;
2027                 case UI_GRAD_HS:
2028                         hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2029                         hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2030                         hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2031                         hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2032                         break;
2033                 case UI_GRAD_H:
2034                         hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2035                         copy_v3_v3(col1[1], col1[0]);
2036                         copy_v3_v3(col1[2], col1[0]);
2037                         copy_v3_v3(col1[3], col1[0]);
2038                         break;
2039                 case UI_GRAD_S:
2040                         hsv_to_rgb(1.0, 0.0, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2041                         copy_v3_v3(col1[0], col1[1]);
2042                         copy_v3_v3(col1[2], col1[1]);
2043                         copy_v3_v3(col1[3], col1[1]);
2044                         break;
2045                 case UI_GRAD_V:
2046                         hsv_to_rgb(1.0, 1.0, 0.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2047                         copy_v3_v3(col1[0], col1[2]);
2048                         copy_v3_v3(col1[1], col1[2]);
2049                         copy_v3_v3(col1[3], col1[2]);
2050                         break;
2051                 default:
2052                         assert(!"invalid 'type' argument");
2053                         hsv_to_rgb(1.0, 1.0, 1.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2054                         copy_v3_v3(col1[0], col1[2]);
2055                         copy_v3_v3(col1[1], col1[2]);
2056                         copy_v3_v3(col1[3], col1[2]);
2057         }
2058         
2059         /* old below */
2060         
2061         for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */
2062                 /* previous color */
2063                 copy_v3_v3(col0[0], col1[0]);
2064                 copy_v3_v3(col0[1], col1[1]);
2065                 copy_v3_v3(col0[2], col1[2]);
2066                 copy_v3_v3(col0[3], col1[3]);
2067                 
2068                 /* new color */
2069                 switch (type) {
2070                         case UI_GRAD_SV:
2071                                 hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
2072                                 hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
2073                                 hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
2074                                 hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
2075                                 break;
2076                         case UI_GRAD_HV:
2077                                 hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2078                                 hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2079                                 hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2080                                 hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2081                                 break;
2082                         case UI_GRAD_HS:
2083                                 hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2084                                 hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2085                                 hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2086                                 hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2087                                 break;
2088                         case UI_GRAD_H:
2089                         {
2090                                 /* annoying but without this the color shifts - could be solved some other way
2091                                  * - campbell */
2092                                 hsv_to_rgb(dx + color_step, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2093                                 copy_v3_v3(col1[1], col1[0]);
2094                                 copy_v3_v3(col1[2], col1[0]);
2095                                 copy_v3_v3(col1[3], col1[0]);
2096                                 break;
2097                         }
2098                         case UI_GRAD_S:
2099                                 hsv_to_rgb(h, dx, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2100                                 copy_v3_v3(col1[0], col1[1]);
2101                                 copy_v3_v3(col1[2], col1[1]);
2102                                 copy_v3_v3(col1[3], col1[1]);
2103                                 break;
2104                         case UI_GRAD_V:
2105                                 hsv_to_rgb(h, 1.0, dx,   &col1[2][0], &col1[2][1], &col1[2][2]);
2106                                 copy_v3_v3(col1[0], col1[2]);
2107                                 copy_v3_v3(col1[1], col1[2]);
2108                                 copy_v3_v3(col1[3], col1[2]);
2109                                 break;
2110                 }
2111                 
2112                 /* rect */
2113                 sx1 = rect->xmin +  dx               * BLI_rcti_size_x(rect);
2114                 sx2 = rect->xmin + (dx + color_step) * BLI_rcti_size_x(rect);
2115                 sy = rect->ymin;
2116                 dy = (float)BLI_rcti_size_y(rect) / 3.0f;
2117                 
2118                 glBegin(GL_QUADS);
2119                 for (a = 0; a < 3; a++, sy += dy) {
2120                         glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
2121                         glVertex2f(sx1, sy);
2122                         
2123                         glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
2124                         glVertex2f(sx2, sy);
2125
2126                         glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
2127                         glVertex2f(sx2, sy + dy);
2128                         
2129                         glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
2130                         glVertex2f(sx1, sy + dy);
2131                 }
2132                 glEnd();
2133         }
2134         
2135         glShadeModel(GL_FLAT);
2136         
2137 }
2138
2139
2140
2141 static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
2142 {
2143         float rgb[3];
2144         float x = 0.0f, y = 0.0f;
2145         float *hsv = ui_block_hsv_get(but->block);
2146         float hsv_n[3];
2147         int color_profile = but->block->color_profile;
2148         
2149         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2150                 color_profile = FALSE;
2151         
2152         copy_v3_v3(hsv_n, hsv);
2153         
2154         ui_get_but_vectorf(but, rgb);
2155         
2156         if (color_profile && (int)but->a1 != UI_GRAD_SV)
2157                 ui_block_to_display_space_v3(but->block, rgb);
2158         
2159         rgb_to_hsv_compat_v(rgb, hsv_n);
2160         
2161         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2162         
2163         switch ((int)but->a1) {
2164                 case UI_GRAD_SV:
2165                         x = hsv_n[2]; y = hsv_n[1]; break;
2166                 case UI_GRAD_HV:
2167                         x = hsv_n[0]; y = hsv_n[2]; break;
2168                 case UI_GRAD_HS:
2169                         x = hsv_n[0]; y = hsv_n[1]; break;
2170                 case UI_GRAD_H:
2171                         x = hsv_n[0]; y = 0.5; break;
2172                 case UI_GRAD_S:
2173                         x = hsv_n[1]; y = 0.5; break;
2174                 case UI_GRAD_V:
2175                         x = hsv_n[2]; y = 0.5; break;
2176         }
2177         
2178         /* cursor */
2179         x = rect->xmin + x * BLI_rcti_size_x(rect);
2180         y = rect->ymin + y * BLI_rcti_size_y(rect);
2181         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2182         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2183         
2184         ui_hsv_cursor(x, y);
2185         
2186         /* outline */
2187         glColor3ub(0,  0,  0);
2188         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2189 }
2190
2191 /* vertical 'value' slider, using new widget code */
2192 static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
2193 {
2194         uiWidgetBase wtb;
2195         const float rad = 0.5f * BLI_rcti_size_x(rect);
2196         float x, y;
2197         float rgb[3], hsv[3], v, range;
2198         int color_profile = but->block->color_profile;
2199         
2200         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2201                 color_profile = FALSE;
2202
2203         ui_get_but_vectorf(but, rgb);
2204
2205         if (color_profile)
2206                 ui_block_to_display_space_v3(but->block, rgb);
2207
2208         rgb_to_hsv_v(rgb, hsv);
2209         v = hsv[2];
2210         
2211         /* map v from property range to [0,1] */
2212         range = but->softmax - but->softmin;
2213         v = (v - but->softmin) / range;
2214         
2215         widget_init(&wtb);
2216         
2217         /* fully rounded */
2218         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2219         
2220         /* setup temp colors */
2221         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2222         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2223         wcol_tmp.shadetop = 127;
2224         wcol_tmp.shadedown = -128;
2225         wcol_tmp.shaded = 1;
2226         
2227         widgetbase_draw(&wtb, &wcol_tmp);
2228
2229         /* cursor */
2230         x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
2231         y = rect->ymin + v    * BLI_rcti_size_y(rect);
2232         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2233         
2234         ui_hsv_cursor(x, y);
2235         
2236 }
2237
2238
2239 /* ************ separator, for menus etc ***************** */
2240 static void ui_draw_separator(const rcti *rect,  uiWidgetColors *wcol)
2241 {
2242         int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2243         unsigned char col[4];
2244         
2245         col[0] = wcol->text[0];
2246         col[1] = wcol->text[1];
2247         col[2] = wcol->text[2];
2248         col[3] = 7;
2249         
2250         glEnable(GL_BLEND);
2251         glColor4ubv(col);
2252         sdrawline(rect->xmin, y, rect->xmax, y);
2253         glDisable(GL_BLEND);
2254 }
2255
2256 /* ************ button callbacks, draw ***************** */
2257
2258 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2259 {
2260         uiWidgetBase wtb;
2261         const float rad = 0.5f * BLI_rcti_size_y(rect);
2262         float textofs = rad * 0.75f;
2263
2264         if (state & UI_SELECT)
2265                 SWAP(short, wcol->shadetop, wcol->shadedown);
2266         
2267         widget_init(&wtb);
2268         
2269         /* fully rounded */
2270         round_box_edges(&wtb, roundboxalign, rect, rad);
2271         
2272         /* decoration */
2273         if (!(state & UI_TEXTINPUT)) {
2274                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2275                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2276         }
2277
2278         widgetbase_draw(&wtb, wcol);
2279         
2280         /* text space */
2281         rect->xmin += textofs;
2282         rect->xmax -= textofs;
2283 }
2284
2285 int ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
2286 {
2287         float dist, vec[4][2];
2288
2289         vec[0][0] = rect->xmin;
2290         vec[0][1] = rect->ymin;
2291         vec[3][0] = rect->xmax;
2292         vec[3][1] = rect->ymax;
2293         
2294         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2295         
2296         vec[1][0] = vec[0][0] + dist;
2297         vec[1][1] = vec[0][1];
2298         
2299         vec[2][0] = vec[3][0] - dist;
2300         vec[2][1] = vec[3][1];
2301         
2302         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2303         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);
2304         
2305         return 1;
2306 }
2307
2308 #define LINK_RESOL  24
2309 void ui_draw_link_bezier(const rcti *rect)
2310 {
2311         float coord_array[LINK_RESOL + 1][2];
2312         
2313         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2314                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2315                 // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
2316
2317                 glEnable(GL_BLEND);
2318                 glEnable(GL_LINE_SMOOTH);
2319
2320                 glEnableClientState(GL_VERTEX_ARRAY);
2321                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2322                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL);
2323                 glDisableClientState(GL_VERTEX_ARRAY);
2324
2325                 glDisable(GL_BLEND);
2326                 glDisable(GL_LINE_SMOOTH);
2327
2328         }
2329 }
2330
2331 /* function in use for buttons and for view2d sliders */
2332 void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
2333 {
2334         uiWidgetBase wtb;
2335         int horizontal;
2336         float rad;
2337         short outline = 0;
2338
2339         widget_init(&wtb);
2340
2341         /* determine horizontal/vertical */
2342         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2343
2344         if (horizontal)
2345                 rad = 0.5f * BLI_rcti_size_y(rect);
2346         else
2347                 rad = 0.5f * BLI_rcti_size_x(rect);
2348         
2349         wtb.shadedir = (horizontal) ? 1 : 0;
2350         
2351         /* draw back part, colors swapped and shading inverted */
2352         if (horizontal)
2353                 SWAP(short, wcol->shadetop, wcol->shadedown);
2354         
2355         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2356         widgetbase_draw(&wtb, wcol);
2357         
2358         /* slider */
2359         if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2360                 /* pass */
2361         }
2362         else {
2363                 SWAP(short, wcol->shadetop, wcol->shadedown);
2364                 
2365                 copy_v4_v4_char(wcol->inner, wcol->item);
2366                 
2367                 if (wcol->shadetop > wcol->shadedown)
2368                         wcol->shadetop += 20;   /* XXX violates themes... */
2369                 else wcol->shadedown += 20;
2370                 
2371                 if (state & UI_SCROLL_PRESSED) {
2372                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2373                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2374                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2375                 }
2376
2377                 /* draw */
2378                 wtb.emboss = 0; /* only emboss once */
2379                 
2380                 /* exception for progress bar */
2381                 if (state & UI_SCROLL_NO_OUTLINE)
2382                         SWAP(short, outline, wtb.outline);
2383                 
2384                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2385                 
2386                 if (state & UI_SCROLL_ARROWS) {
2387                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2388                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2389                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2390                         wcol->item[3] = 255;
2391                         
2392                         if (horizontal) {
2393                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2394                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2395                         }
2396                         else {
2397                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2398                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2399                         }
2400                 }
2401                 widgetbase_draw(&wtb, wcol);
2402                 
2403                 if (state & UI_SCROLL_NO_OUTLINE)
2404                         SWAP(short, outline, wtb.outline);
2405         }
2406 }
2407
2408 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2409 {
2410         rcti rect1;
2411         double value;
2412         float fac, size, min;
2413         int horizontal;
2414
2415         /* calculate slider part */
2416         value = ui_get_but_val(but);
2417
2418         size = (but->softmax + but->a1 - but->softmin);
2419         size = max_ff(size, 2.0f);
2420         
2421         /* position */
2422         rect1 = *rect;
2423
2424         /* determine horizontal/vertical */
2425         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2426         
2427         if (horizontal) {
2428                 fac = BLI_rcti_size_x(rect) / size;
2429                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2430                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2431
2432                 /* ensure minimium size */
2433                 min = BLI_rcti_size_y(rect);
2434
2435                 if (BLI_rcti_size_x(&rect1) < min) {
2436                         rect1.xmax = rect1.xmin + min;
2437
2438                         if (rect1.xmax > rect->xmax) {
2439                                 rect1.xmax = rect->xmax;
2440                                 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
2441                         }
2442                 }
2443         }
2444         else {
2445                 fac = BLI_rcti_size_y(rect) / size;
2446                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2447                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2448
2449                 /* ensure minimium size */
2450                 min = BLI_rcti_size_x(rect);
2451
2452                 if (BLI_rcti_size_y(&rect1) < min) {
2453                         rect1.ymax = rect1.ymin + min;
2454
2455                         if (rect1.ymax > rect->ymax) {
2456                                 rect1.ymax = rect->ymax;
2457                                 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
2458                         }
2459                 }
2460         }
2461
2462         if (state & UI_SELECT)
2463                 state = UI_SCROLL_PRESSED;
2464         else
2465                 state = 0;
2466         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2467 }
2468
2469 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2470 {
2471         rcti rect_prog = *rect, rect_bar = *rect;
2472         float value = but->a1;
2473         float w, min;
2474         
2475         /* make the progress bar a proportion of the original height */
2476         /* hardcoded 4px high for now */
2477         rect_prog.ymax = rect_prog.ymin + 4;
2478         rect_bar.ymax = rect_bar.ymin + 4;
2479         
2480         w = value * BLI_rcti_size_x(&rect_prog);
2481         
2482         /* ensure minimium size */
2483         min = BLI_rcti_size_y(&rect_prog);
2484         w = MAX2(w, min);
2485         
2486         rect_bar.xmax = rect_bar.xmin + w;
2487                 
2488         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2489         
2490         /* raise text a bit */
2491         rect->ymin += 6;
2492         rect->xmin -= 6;
2493 }
2494
2495 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2496 {
2497         
2498         if (but->flag & UI_SELECT) {
2499                 rcti rectlink;
2500                 
2501                 UI_ThemeColor(TH_TEXT_HI);
2502                 
2503                 rectlink.xmin = BLI_rcti_cent_x(rect);
2504                 rectlink.ymin = BLI_rcti_cent_y(rect);
2505                 rectlink.xmax = but->linkto[0];
2506                 rectlink.ymax = but->linkto[1];
2507                 
2508                 ui_draw_link_bezier(&rectlink);
2509         }
2510 }
2511
2512 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2513 {
2514         uiWidgetBase wtb, wtb1;
2515         rcti rect1;
2516         double value;
2517         float offs, toffs, fac;
2518         char outline[3];
2519
2520         widget_init(&wtb);
2521         widget_init(&wtb1);
2522         
2523         /* backdrop first */
2524         
2525         /* fully rounded */
2526         offs = 0.5f * BLI_rcti_size_y(rect);
2527         toffs = offs * 0.75f;
2528         round_box_edges(&wtb, roundboxalign, rect, offs);
2529
2530         wtb.outline = 0;
2531         widgetbase_draw(&wtb, wcol);
2532         
2533         /* draw left/right parts only when not in text editing */
2534         if (!(state & UI_TEXTINPUT)) {
2535                 
2536                 /* slider part */
2537                 copy_v3_v3_char(outline, wcol->outline);
2538                 copy_v3_v3_char(wcol->outline, wcol->item);
2539                 copy_v3_v3_char(wcol->inner, wcol->item);
2540
2541                 if (!(state & UI_SELECT))
2542                         SWAP(short, wcol->shadetop, wcol->shadedown);
2543                 
2544                 rect1 = *rect;
2545                 
2546                 value = ui_get_but_val(but);
2547                 fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
2548                 
2549                 /* left part of slider, always rounded */
2550                 rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
2551                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2552                 wtb1.outline = 0;
2553                 widgetbase_draw(&wtb1, wcol);
2554                 
2555                 /* right part of slider, interpolate roundness */
2556                 rect1.xmax = rect1.xmin + fac + offs;
2557                 rect1.xmin +=  floor(offs - U.pixelsize);
2558                 
2559                 if (rect1.xmax + offs > rect->xmax)
2560                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2561                 else 
2562                         offs = 0.0f;
2563                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2564                 
2565                 widgetbase_draw(&wtb1, wcol);
2566                 copy_v3_v3_char(wcol->outline, outline);
2567                 
2568                 if (!(state & UI_SELECT))
2569                         SWAP(short, wcol->shadetop, wcol->shadedown);
2570         }
2571         
2572         /* outline */
2573         wtb.outline = 1;
2574         wtb.inner = 0;
2575         widgetbase_draw(&wtb, wcol);
2576         
2577         /* text space */
2578         rect->xmin += toffs;
2579         rect->xmax -= toffs;
2580 }
2581
2582 /* I think 3 is sufficient border to indicate keyed status */
2583 #define SWATCH_KEYED_BORDER 3
2584
2585 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2586 {
2587         uiWidgetBase wtb;
2588         float rad, col[4];
2589         int color_profile = but->block->color_profile;
2590         
2591         col[3] = 1.0f;
2592
2593         if (but->rnaprop) {
2594                 BLI_assert(but->rnaindex == -1);
2595
2596                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2597                         color_profile = FALSE;
2598
2599                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2600                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2601                 }
2602         }
2603         
2604         widget_init(&wtb);
2605         
2606         /* half rounded */
2607         rad = 0.25f * U.widget_unit;
2608         round_box_edges(&wtb, roundboxalign, rect, rad);
2609                 
2610         ui_get_but_vectorf(but, col);
2611
2612         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2613                 /* draw based on state - color for keyed etc */
2614                 widgetbase_draw(&wtb, wcol);
2615
2616                 /* inset to draw swatch color */
2617                 rect->xmin += SWATCH_KEYED_BORDER;
2618                 rect->xmax -= SWATCH_KEYED_BORDER;
2619                 rect->ymin += SWATCH_KEYED_BORDER;
2620                 rect->ymax -= SWATCH_KEYED_BORDER;
2621                 
2622                 round_box_edges(&wtb, roundboxalign, rect, rad);
2623         }
2624         
2625         if (color_profile)
2626                 ui_block_to_display_space_v3(but->block, col);
2627         
2628         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2629
2630         wcol->shaded = 0;
2631         wcol->alpha_check = (wcol->inner[3] < 255);
2632
2633         widgetbase_draw(&wtb, wcol);
2634         
2635 }
2636
2637 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2638 {
2639         ui_draw_but_NORMAL(but, wcol, rect);
2640 }
2641
2642 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2643 {
2644         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2645                 uiWidgetBase wtb;
2646                 float rad;
2647                 
2648                 widget_init(&wtb);
2649                 wtb.outline = 0;
2650                 
2651                 /* rounded */
2652                 rad = 0.5f * BLI_rcti_size_y(rect);
2653                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2654                 widgetbase_draw(&wtb, wcol);
2655         }
2656 }
2657
2658
2659 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2660 {
2661         uiWidgetBase wtb;
2662         float rad;
2663         
2664         if (state & UI_SELECT)
2665                 SWAP(short, wcol->shadetop, wcol->shadedown);
2666         
2667         widget_init(&wtb);
2668         
2669         /* half rounded */
2670         rad = 0.2f * U.widget_unit;
2671         round_box_edges(&wtb, roundboxalign, rect, rad);
2672         
2673         widgetbase_draw(&wtb, wcol);
2674
2675 }
2676
2677
2678 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2679 {
2680         uiWidgetBase wtb;
2681         float rad;
2682         
2683         widget_init(&wtb);
2684         
2685         /* half rounded */
2686         rad = 0.2f * U.widget_unit;
2687         round_box_edges(&wtb, roundboxalign, rect, rad);
2688         
2689         /* decoration */
2690         widget_menu_trias(&wtb.tria1, rect);
2691         
2692         widgetbase_draw(&wtb, wcol);
2693         
2694         /* text space, arrows are about 0.6 height of button */
2695         rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
2696 }
2697
2698 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2699 {
2700         uiWidgetBase wtb;
2701         float rad;
2702         
2703         widget_init(&wtb);
2704         
2705         /* half rounded */
2706         rad = 0.2f * U.widget_unit;
2707         round_box_edges(&wtb, roundboxalign, rect, rad);
2708         
2709         /* decoration */
2710         widgetbase_draw(&wtb, wcol);
2711 }
2712
2713 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2714 {
2715         /* silly node link button hacks */
2716         uiWidgetBase wtb;
2717         uiWidgetColors wcol_backup = *wcol;
2718         float rad;
2719         
2720         widget_init(&wtb);
2721         
2722         /* half rounded */
2723         rad = 0.2f * U.widget_unit;
2724         round_box_edges(&wtb, roundboxalign, rect, rad);
2725
2726         wcol->inner[0] += 15;
2727         wcol->inner[1] += 15;
2728         wcol->inner[2] += 15;
2729         wcol->outline[0] += 15;
2730         wcol->outline[1] += 15;
2731         wcol->outline[2] += 15;
2732         
2733         /* decoration */
2734         widgetbase_draw(&wtb, wcol);
2735         *wcol = wcol_backup;
2736 }
2737
2738 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2739 {
2740         if (state & UI_ACTIVE) {
2741                 uiWidgetBase wtb;
2742                 const float rad = 0.2f * U.widget_unit;
2743
2744                 widget_init(&wtb);
2745
2746                 /* half rounded */
2747                 round_box_edges(&wtb, roundboxalign, rect, rad);
2748                 
2749                 widgetbase_draw(&wtb, wcol);
2750         }
2751 }
2752
2753 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2754 {
2755         uiWidgetBase wtb;
2756         
2757         widget_init(&wtb);
2758         
2759         /* not rounded, no outline */
2760         wtb.outline = 0;
2761         round_box_edges(&wtb, 0, rect, 0.0f);
2762         
2763         widgetbase_draw(&wtb, wcol);
2764 }
2765
2766 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2767 {
2768         uiWidgetBase wtb;
2769         float rad;
2770         
2771         widget_init(&wtb);
2772         
2773         /* rounded, but no outline */
2774         wtb.outline = 0;
2775         rad = 0.2f * U.widget_unit;
2776         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2777         
2778         widgetbase_draw(&wtb, wcol);
2779 }
2780
2781 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2782 {
2783         uiWidgetBase wtb;
2784         rcti recttemp = *rect;
2785         float rad;
2786         int delta;
2787         
2788         widget_init(&wtb);
2789         
2790         /* square */
2791         recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
2792         
2793         /* smaller */
2794         delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
2795         recttemp.xmin += delta;
2796         recttemp.ymin += delta;
2797         recttemp.xmax -= delta;
2798         recttemp.ymax -= delta;
2799         
2800         /* half rounded */
2801         rad = 0.2f * U.widget_unit;
2802         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
2803         
2804         /* decoration */
2805         if (state & UI_SELECT) {
2806                 widget_check_trias(&wtb.tria1, &recttemp);
2807         }
2808         
2809         widgetbase_draw(&wtb, wcol);
2810         
2811         /* text space */
2812         rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta;
2813 }
2814
2815
2816 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2817 {
2818         uiWidgetBase wtb;
2819         float rad;
2820         
2821         widget_init(&wtb);
2822         
2823         /* half rounded */
2824         rad = 0.2f * U.widget_unit;
2825         round_box_edges(&wtb, roundboxalign, rect, rad);
2826         
2827         widgetbase_draw(&wtb, wcol);
2828
2829 }
2830
2831 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2832 {
2833         uiWidgetBase wtb;
2834         float rad;
2835         char old_col[3];
2836         
2837         widget_init(&wtb);
2838         
2839         copy_v3_v3_char(old_col, wcol->inner);
2840         
2841         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2842         if (but->col[3]) {
2843                 wcol->inner[0] = but->col[0];
2844                 wcol->inner[1] = but->col[1];
2845                 wcol->inner[2] = but->col[2];
2846         }
2847         
2848         /* half rounded */
2849         rad = 0.2f * U.widget_unit;
2850         round_box_edges(&wtb, roundboxalign, rect, rad);
2851         
2852         widgetbase_draw(&wtb, wcol);
2853         
2854         /* store the box bg as gl clearcolor, to retrieve later when drawing semi-transparent rects
2855          * over the top to indicate disabled buttons */
2856         /* XXX, this doesnt work right since the color applies to buttons outside the box too. */
2857         glClearColor(wcol->inner[0] / 255.0, wcol->inner[1] / 255.0, wcol->inner[2] / 255.0, 1.0);
2858         
2859         copy_v3_v3_char(wcol->inner, old_col);
2860 }
2861
2862 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2863 {
2864         uiWidgetBase wtb;
2865         float rad;
2866         
2867         widget_init(&wtb);
2868         
2869         /* half rounded */
2870         rad = 0.2f * U.widget_unit;
2871         round_box_edges(&wtb, roundboxalign, rect, rad);
2872         
2873         widgetbase_draw(&wtb, wcol);
2874
2875 }
2876
2877 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2878 {
2879         uiWidgetBase wtb;
2880         const float rad = 0.25f * U.widget_unit;
2881         
2882         widget_init(&wtb);
2883         
2884         /* half rounded */
2885         round_box_edges(&wtb, roundboxalign, rect, rad);
2886
2887         widgetbase_draw(&wtb, wcol);
2888 }
2889
2890 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2891 {
2892         uiWidgetBase wtb;
2893         const float rad = 0.25f * U.widget_unit;
2894         unsigned char col[4];
2895         
2896         /* state copy! */
2897         wt->wcol = *(wt->wcol_theme);
2898         
2899         widget_init(&wtb);
2900         
2901         if (but->block->drawextra) {
2902                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2903                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2904                 
2905                 /* make mask to draw over image */
2906                 UI_GetThemeColor3ubv(TH_BACK, col);
2907                 glColor3ubv(col);
2908                 
2909                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
2910                 widgetbase_outline(&wtb);
2911         }
2912         
2913         /* outline */
2914         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2915         wtb.outline = 1;
2916         wtb.inner = 0;
2917         widgetbase_draw(&wtb, &wt->wcol);
2918         
2919 }
2920
2921
2922 static void widget_disabled(const rcti *rect)
2923 {
2924         float col[4];
2925         
2926         glEnable(GL_BLEND);
2927         
2928         /* can't use theme TH_BACK or TH_PANEL... undefined */
2929         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2930         glColor4f(col[0], col[1], col[2], 0.5f);
2931
2932         /* need -1 and +1 to make it work right for aligned buttons,
2933          * but problem may be somewhere else? */
2934         glRectf(rect->xmin - 1, rect->ymin - 1, rect->xmax, rect->ymax + 1);
2935         
2936         glDisable(GL_BLEND);
2937 }
2938
2939 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2940 {
2941         bTheme *btheme = UI_GetTheme();
2942         static uiWidgetType wt;
2943         
2944         /* defaults */
2945         wt.wcol_theme = &btheme->tui.wcol_regular;
2946         wt.wcol_state = &btheme->tui.wcol_state;
2947         wt.state = widget_state;
2948         wt.draw = widget_but;
2949         wt.custom = NULL;
2950         wt.text = widget_draw_text_icon;
2951         
2952         switch (type) {
2953                 case UI_WTYPE_REGULAR:
2954                         break;
2955
2956                 case UI_WTYPE_LABEL:
2957                         wt.draw = NULL;
2958                         wt.state = widget_state_label;
2959                         break;
2960                         
2961                 case UI_WTYPE_TOGGLE:
2962                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2963                         break;
2964                         
2965                 case UI_WTYPE_OPTION:
2966                         wt.wcol_theme = &btheme->tui.wcol_option;
2967                         wt.draw = widget_optionbut;
2968                         break;
2969                         
2970                 case UI_WTYPE_RADIO:
2971                         wt.wcol_theme = &btheme->tui.wcol_radio;
2972                         wt.draw = widget_radiobut;
2973                         break;
2974
2975                 case UI_WTYPE_NUMBER:
2976                         wt.wcol_theme = &btheme->tui.wcol_num;
2977                         wt.draw = widget_numbut;
2978                         break;
2979                         
2980                 case UI_WTYPE_SLIDER:
2981                         wt.wcol_theme = &btheme->tui.wcol_numslider;
2982                         wt.custom = widget_numslider;
2983                         wt.state = widget_state_numslider;
2984                         break;
2985                         
2986                 case UI_WTYPE_EXEC:
2987                         wt.wcol_theme = &btheme->tui.wcol_tool;
2988                         wt.draw = widget_roundbut;
2989                         break;
2990
2991                 case UI_WTYPE_TOOLTIP:
2992                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
2993                         wt.draw = widget_menu_back;
2994                         break;
2995                         
2996                         
2997                 /* strings */
2998                 case UI_WTYPE_NAME:
2999                         wt.wcol_theme = &btheme->tui.wcol_text;
3000                         wt.draw = widget_textbut;
3001                         break;
3002                         
3003                 case UI_WTYPE_NAME_LINK:
3004                         break;
3005                         
3006                 case UI_WTYPE_POINTER_LINK:
3007                         break;
3008                         
3009                 case UI_WTYPE_FILENAME:
3010                         break;
3011                         
3012                         
3013                 /* start menus */
3014                 case UI_WTYPE_MENU_RADIO:
3015                         wt.wcol_theme = &btheme->tui.wcol_menu;
3016                         wt.draw = widget_menubut;
3017                         break;
3018
3019                 case UI_WTYPE_MENU_ICON_RADIO:
3020                         wt.wcol_theme = &btheme->tui.wcol_menu;
3021                         wt.draw = widget_menuiconbut;
3022                         break;
3023                         
3024                 case UI_WTYPE_MENU_POINTER_LINK:
3025                         wt.wcol_theme = &btheme->tui.wcol_menu;
3026                         wt.draw = widget_menubut;
3027                         break;
3028
3029                 case UI_WTYPE_MENU_NODE_LINK:
3030                         wt.wcol_theme = &btheme->tui.wcol_menu;
3031                         wt.draw = widget_menunodebut;
3032                         break;
3033                         
3034                 case UI_WTYPE_PULLDOWN:
3035                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
3036                         wt.draw = widget_pulldownbut;
3037                         wt.state = widget_state_pulldown;
3038                         break;
3039                         
3040                 /* in menus */
3041                 case UI_WTYPE_MENU_ITEM:
3042                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
3043                         wt.draw = widget_menu_itembut;
3044                         wt.state = widget_state_menu_item;
3045                         break;
3046                         
3047                 case UI_WTYPE_MENU_BACK:
3048                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
3049                         wt.draw = widget_menu_back;
3050                         break;
3051                         
3052                 /* specials */
3053                 case UI_WTYPE_ICON:
3054                         wt.custom = widget_icon_has_anim;
3055                         break;
3056                         
3057                 case UI_WTYPE_SWATCH:
3058                         wt.custom = widget_swatch;
3059                         break;
3060                         
3061                 case UI_WTYPE_BOX:
3062                         wt.custom = widget_box;
3063                         wt.wcol_theme = &btheme->tui.wcol_box;
3064                         break;
3065                         
3066                 case UI_WTYPE_RGB_PICKER:
3067                         break;
3068                         
3069                 case UI_WTYPE_NORMAL:
3070                         wt.custom = widget_normal;
3071                         break;
3072
3073                 case UI_WTYPE_SCROLL:
3074                         wt.wcol_theme = &btheme->tui.wcol_scroll;
3075                         wt.state = widget_state_nothing;
3076                         wt.custom = widget_scroll;
3077                         break;
3078
3079                 case UI_WTYPE_LISTITEM:
3080                         wt.wcol_theme = &btheme->tui.wcol_list_item;
3081                         wt.draw = widget_list_itembut;
3082                         break;
3083                         
3084                 case UI_WTYPE_PROGRESSBAR:
3085                         wt.wcol_theme = &btheme->tui.wcol_progress;
3086                         wt.custom = widget_progressbar;
3087                         break;
3088         }
3089         
3090         return &wt;
3091 }
3092
3093
3094 static int widget_roundbox_set(uiBut *but, rcti *rect)
3095 {
3096         int roundbox = UI_CNR_ALL;
3097
3098         /* alignment */
3099         if ((but->flag & UI_BUT_ALIGN) && but->type != PULLDOWN) {
3100                 
3101                 /* ui_block_position has this correction too, keep in sync */
3102                 if (but->flag & UI_BUT_ALIGN_TOP)
3103                         rect->ymax += U.pixelsize;
3104                 if (but->flag & UI_BUT_ALIGN_LEFT)
3105                         rect->xmin -= U.pixelsize;
3106                 
3107                 switch (but->flag & UI_BUT_ALIGN) {
3108                         case UI_BUT_ALIGN_TOP:
3109                                 roundbox = UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
3110                                 break;
3111                         case UI_BUT_ALIGN_DOWN:
3112                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
3113                                 break;
3114                         case UI_BUT_ALIGN_LEFT:
3115                                 roundbox = UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
3116                                 break;
3117                         case UI_BUT_ALIGN_RIGHT:
3118                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
3119                                 break;
3120                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
3121                                 roundbox = UI_CNR_TOP_LEFT;
3122                                 break;
3123                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
3124                                 roundbox = UI_CNR_TOP_RIGHT;
3125                                 break;
3126                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
3127                                 roundbox = UI_CNR_BOTTOM_LEFT;
3128                                 break;
3129                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
3130                                 roundbox = UI_CNR_BOTTOM_RIGHT;
3131                                 break;
3132                         default:
3133                                 roundbox = 0;
3134                                 break;
3135                 }
3136         }
3137
3138         /* align with open menu */
3139         if (but->active) {
3140                 int direction = ui_button_open_menu_direction(but);
3141
3142                 if      (direction == UI_TOP)   roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
3143                 else if (direction == UI_DOWN)  roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
3144                 else if (direction == UI_LEFT)  roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
3145                 else if (direction == UI_RIGHT) roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
3146         }
3147
3148         return roundbox;
3149 }
3150
3151 /* conversion from old to new buttons, so still messy */
3152 void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rcti *rect)
3153 {
3154         bTheme *btheme = UI_GetTheme();
3155         ThemeUI *tui = &btheme->tui;
3156         uiFontStyle *fstyle = &style->widget;
3157         uiWidgetType *wt = NULL;
3158
3159         /* handle menus separately */
3160         if (but->dt == UI_EMBOSSP) {
3161                 switch (but->type) {
3162  &