Use use_render argument rather than G.is_rendering to detect
[blender-staging.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[16][2];
84         const 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 const 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 const 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 const float num_tria_vert[3][2] = {
144         {-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}
145 };
146
147 static const unsigned int num_tria_face[1][3] = {
148         {0, 1, 2}
149 };
150
151 static const 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 const 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 const 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 const unsigned int menu_tria_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
172
173 static const 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 const unsigned int check_tria_face[4][3] = {
179         {3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
180 };
181
182 GLubyte const 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, bool use_alpha)
222 {
223         float color[4];
224         int j;
225         
226         glEnable(GL_BLEND);
227         glGetFloatv(GL_CURRENT_COLOR, color);
228         if (use_alpha) {
229                 color[3] = 0.5f;
230         }
231         color[3] *= 0.125f;
232         glColor4fv(color);
233         
234         for (j = 0; j < WIDGET_AA_JITTER; j++) {
235                 glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
236                 uiDrawBox(mode, minx, miny, maxx, maxy, rad);
237                 glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
238         }
239
240         glDisable(GL_BLEND);
241 }
242
243 static void widget_init(uiWidgetBase *wtb)
244 {
245         wtb->totvert = wtb->halfwayvert = 0;
246         wtb->tria1.tot = 0;
247         wtb->tria2.tot = 0;
248
249         wtb->inner = 1;
250         wtb->outline = 1;
251         wtb->emboss = 1;
252         wtb->shadedir = 1;
253 }
254
255 /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
256 /* return tot */
257 static int round_box_shadow_edges(float (*vert)[2], const rcti *rect, float rad, int roundboxalign, float step)
258 {
259         float vec[WIDGET_CURVE_RESOLU][2];
260         float minx, miny, maxx, maxy;
261         int a, tot = 0;
262         
263         rad += step;
264         
265         if (2.0f * rad > BLI_rcti_size_y(rect))
266                 rad = 0.5f * BLI_rcti_size_y(rect);
267
268         minx = rect->xmin - step;
269         miny = rect->ymin - step;
270         maxx = rect->xmax + step;
271         maxy = rect->ymax + step;
272         
273         /* mult */
274         for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
275                 vec[a][0] = rad * cornervec[a][0];
276                 vec[a][1] = rad * cornervec[a][1];
277         }
278         
279         /* start with left-top, anti clockwise */
280         if (roundboxalign & UI_CNR_TOP_LEFT) {
281                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
282                         vert[tot][0] = minx + rad - vec[a][0];
283                         vert[tot][1] = maxy - vec[a][1];
284                 }
285         }
286         else {
287                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
288                         vert[tot][0] = minx;
289                         vert[tot][1] = maxy;
290                 }
291         }
292         
293         if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
294                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
295                         vert[tot][0] = minx + vec[a][1];
296                         vert[tot][1] = miny + rad - vec[a][0];
297                 }
298         }
299         else {
300                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
301                         vert[tot][0] = minx;
302                         vert[tot][1] = miny;
303                 }
304         }
305         
306         if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
307                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
308                         vert[tot][0] = maxx - rad + vec[a][0];
309                         vert[tot][1] = miny + vec[a][1];
310                 }
311         }
312         else {
313                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
314                         vert[tot][0] = maxx;
315                         vert[tot][1] = miny;
316                 }
317         }
318         
319         if (roundboxalign & UI_CNR_TOP_RIGHT) {
320                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
321                         vert[tot][0] = maxx - vec[a][1];
322                         vert[tot][1] = maxy - rad + vec[a][0];
323                 }
324         }
325         else {
326                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
327                         vert[tot][0] = maxx;
328                         vert[tot][1] = maxy;
329                 }
330         }
331         return tot;
332 }
333
334 /* this call has 1 extra arg to allow mask outline */
335 static void round_box__edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
336 {
337         float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
338         float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
339         float minxi = minx + U.pixelsize; /* boundbox inner */
340         float maxxi = maxx - U.pixelsize;
341         float minyi = miny + U.pixelsize;
342         float maxyi = maxy - U.pixelsize;
343         float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f; /* for uv, can divide by zero */
344         float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
345         int a, tot = 0, minsize;
346         const int hnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT)) == (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT) ||
347                           (roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) ? 1 : 2;
348         const int vnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) ||
349                           (roundboxalign & (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) == (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) ? 1 : 2;
350
351         minsize = min_ii(BLI_rcti_size_x(rect) * hnum,
352                          BLI_rcti_size_y(rect) * vnum);
353         
354         if (2.0f * rad > minsize)
355                 rad = 0.5f * minsize;
356
357         if (2.0f * (radi + 1.0f) > minsize)
358                 radi = 0.5f * minsize - U.pixelsize;
359         
360         /* mult */
361         for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
362                 veci[a][0] = radi * cornervec[a][0];
363                 veci[a][1] = radi * cornervec[a][1];
364                 vec[a][0] = rad * cornervec[a][0];
365                 vec[a][1] = rad * cornervec[a][1];
366         }
367         
368         /* corner left-bottom */
369         if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
370                 
371                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
372                         wt->inner_v[tot][0] = minxi + veci[a][1];
373                         wt->inner_v[tot][1] = minyi + radi - veci[a][0];
374                         
375                         wt->outer_v[tot][0] = minx + vec[a][1];
376                         wt->outer_v[tot][1] = miny + rad - vec[a][0];
377                         
378                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
379                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
380                 }
381         }
382         else {
383                 wt->inner_v[tot][0] = minxi;
384                 wt->inner_v[tot][1] = minyi;
385                 
386                 wt->outer_v[tot][0] = minx;
387                 wt->outer_v[tot][1] = miny;
388
389                 wt->inner_uv[tot][0] = 0.0f;
390                 wt->inner_uv[tot][1] = 0.0f;
391                 
392                 tot++;
393         }
394         
395         /* corner right-bottom */
396         if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
397                 
398                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
399                         wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
400                         wt->inner_v[tot][1] = minyi + veci[a][1];
401                         
402                         wt->outer_v[tot][0] = maxx - rad + vec[a][0];
403                         wt->outer_v[tot][1] = miny + vec[a][1];
404                         
405                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
406                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
407                 }
408         }
409         else {
410                 wt->inner_v[tot][0] = maxxi;
411                 wt->inner_v[tot][1] = minyi;
412                 
413                 wt->outer_v[tot][0] = maxx;
414                 wt->outer_v[tot][1] = miny;
415
416                 wt->inner_uv[tot][0] = 1.0f;
417                 wt->inner_uv[tot][1] = 0.0f;
418                 
419                 tot++;
420         }
421         
422         wt->halfwayvert = tot;
423         
424         /* corner right-top */
425         if (roundboxalign & UI_CNR_TOP_RIGHT) {
426                 
427                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
428                         wt->inner_v[tot][0] = maxxi - veci[a][1];
429                         wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
430                         
431                         wt->outer_v[tot][0] = maxx - vec[a][1];
432                         wt->outer_v[tot][1] = maxy - rad + vec[a][0];
433                         
434                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
435                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
436                 }
437         }
438         else {
439                 wt->inner_v[tot][0] = maxxi;
440                 wt->inner_v[tot][1] = maxyi;
441                 
442                 wt->outer_v[tot][0] = maxx;
443                 wt->outer_v[tot][1] = maxy;
444                 
445                 wt->inner_uv[tot][0] = 1.0f;
446                 wt->inner_uv[tot][1] = 1.0f;
447                 
448                 tot++;
449         }
450         
451         /* corner left-top */
452         if (roundboxalign & UI_CNR_TOP_LEFT) {
453                 
454                 for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
455                         wt->inner_v[tot][0] = minxi + radi - veci[a][0];
456                         wt->inner_v[tot][1] = maxyi - veci[a][1];
457                         
458                         wt->outer_v[tot][0] = minx + rad - vec[a][0];
459                         wt->outer_v[tot][1] = maxy - vec[a][1];
460                         
461                         wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
462                         wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
463                 }
464                 
465         }
466         else {
467                 
468                 wt->inner_v[tot][0] = minxi;
469                 wt->inner_v[tot][1] = maxyi;
470                 
471                 wt->outer_v[tot][0] = minx;
472                 wt->outer_v[tot][1] = maxy;
473                 
474                 wt->inner_uv[tot][0] = 0.0f;
475                 wt->inner_uv[tot][1] = 1.0f;
476                 
477                 tot++;
478         }
479
480         BLI_assert(tot <= WIDGET_SIZE_MAX);
481
482         wt->totvert = tot;
483 }
484
485 static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad)
486 {
487         round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
488 }
489
490
491 /* based on button rect, return scaled array of triangles */
492 static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
493 {
494         float centx, centy, sizex, sizey, minsize;
495         int a, i1 = 0, i2 = 1;
496         
497         minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
498         
499         /* center position and size */
500         centx = (float)rect->xmin + 0.5f * minsize;
501         centy = (float)rect->ymin + 0.5f * minsize;
502         sizex = sizey = -0.5f * triasize * minsize;
503
504         if (where == 'r') {
505                 centx = (float)rect->xmax - 0.5f * minsize;
506                 sizex = -sizex;
507         }
508         else if (where == 't') {
509                 centy = (float)rect->ymax - 0.5f * minsize;
510                 sizey = -sizey;
511                 i2 = 0; i1 = 1;
512         }
513         else if (where == 'b') {
514                 sizex = -sizex;
515                 i2 = 0; i1 = 1;
516         }
517         
518         for (a = 0; a < 3; a++) {
519                 tria->vec[a][0] = sizex * num_tria_vert[a][i1] + centx;
520                 tria->vec[a][1] = sizey * num_tria_vert[a][i2] + centy;
521         }
522         
523         tria->tot = 1;
524         tria->index = num_tria_face;
525 }
526
527 static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
528 {
529         float centx, centy, sizex, sizey, minsize;
530         int a, i1 = 0, i2 = 1;
531         
532         minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
533         
534         /* center position and size */
535         centx = (float)rect->xmin + 0.5f * minsize;
536         centy = (float)rect->ymin + 0.5f * minsize;
537         sizex = sizey = -0.5f * triasize * minsize;
538
539         if (where == 'r') {
540                 centx = (float)rect->xmax - 0.5f * minsize;
541                 sizex = -sizex;
542         }
543         else if (where == 't') {
544                 centy = (float)rect->ymax - 0.5f * minsize;
545                 sizey = -sizey;
546                 i2 = 0; i1 = 1;
547         }
548         else if (where == 'b') {
549                 sizex = -sizex;
550                 i2 = 0; i1 = 1;
551         }
552         
553         for (a = 0; a < 16; a++) {
554                 tria->vec[a][0] = sizex * scroll_circle_vert[a][i1] + centx;
555                 tria->vec[a][1] = sizey * scroll_circle_vert[a][i2] + centy;
556         }
557         
558         tria->tot = 14;
559         tria->index = scroll_circle_face;
560 }
561
562 static void widget_trias_draw(uiWidgetTrias *tria)
563 {
564         glEnableClientState(GL_VERTEX_ARRAY);
565         glVertexPointer(2, GL_FLOAT, 0, tria->vec);
566         glDrawElements(GL_TRIANGLES, tria->tot * 3, GL_UNSIGNED_INT, tria->index);
567         glDisableClientState(GL_VERTEX_ARRAY);
568 }
569
570 static void widget_menu_trias(uiWidgetTrias *tria, const rcti *rect)
571 {
572         float centx, centy, size;
573         int a;
574                 
575         /* center position and size */
576         centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
577         centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
578         size = 0.4f * (float)BLI_rcti_size_y(rect);
579         
580         for (a = 0; a < 6; a++) {
581                 tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
582                 tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
583         }
584
585         tria->tot = 2;
586         tria->index = menu_tria_face;
587 }
588
589 static void widget_check_trias(uiWidgetTrias *tria, const rcti *rect)
590 {
591         float centx, centy, size;
592         int a;
593         
594         /* center position and size */
595         centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
596         centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
597         size = 0.5f * BLI_rcti_size_y(rect);
598         
599         for (a = 0; a < 6; a++) {
600                 tria->vec[a][0] = size * check_tria_vert[a][0] + centx;
601                 tria->vec[a][1] = size * check_tria_vert[a][1] + centy;
602         }
603         
604         tria->tot = 4;
605         tria->index = check_tria_face;
606 }
607
608
609 /* prepares shade colors */
610 static void shadecolors4(char coltop[4], char *coldown, const char *color, short shadetop, short shadedown)
611 {
612         
613         coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
614         coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
615         coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
616         coltop[3] = color[3];
617
618         coldown[0] = CLAMPIS(color[0] + shadedown, 0, 255);
619         coldown[1] = CLAMPIS(color[1] + shadedown, 0, 255);
620         coldown[2] = CLAMPIS(color[2] + shadedown, 0, 255);
621         coldown[3] = color[3];
622 }
623
624 static void round_box_shade_col4_r(unsigned char col_r[4], const char col1[4], const char col2[4], const float fac)
625 {
626         const int faci = FTOCHAR(fac);
627         const int facm = 255 - faci;
628
629         col_r[0] = (faci * col1[0] + facm * col2[0]) >> 8;
630         col_r[1] = (faci * col1[1] + facm * col2[1]) >> 8;
631         col_r[2] = (faci * col1[2] + facm * col2[2]) >> 8;
632         col_r[3] = (faci * col1[3] + facm * col2[3]) >> 8;
633 }
634
635 static void widget_verts_to_quad_strip(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2])
636 {
637         int a;
638         for (a = 0; a < totvert; a++) {
639                 copy_v2_v2(quad_strip[a * 2], wtb->outer_v[a]);
640                 copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[a]);
641         }
642         copy_v2_v2(quad_strip[a * 2], wtb->outer_v[0]);
643         copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[0]);
644 }
645
646 static void widget_verts_to_quad_strip_open(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2][2])
647 {
648         int a;
649         for (a = 0; a < totvert; a++) {
650                 quad_strip[a * 2][0] = wtb->outer_v[a][0];
651                 quad_strip[a * 2][1] = wtb->outer_v[a][1];
652                 quad_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
653                 quad_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
654         }
655 }
656
657 static void widgetbase_outline(uiWidgetBase *wtb)
658 {
659         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
660         widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
661
662         glEnableClientState(GL_VERTEX_ARRAY);
663         glVertexPointer(2, GL_FLOAT, 0, quad_strip);
664         glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
665         glDisableClientState(GL_VERTEX_ARRAY);
666 }
667
668 static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
669 {
670         int j, a;
671         
672         glEnable(GL_BLEND);
673
674         /* backdrop non AA */
675         if (wtb->inner) {
676                 if (wcol->shaded == 0) {
677                         if (wcol->alpha_check) {
678                                 float inner_v_half[WIDGET_SIZE_MAX][2];
679                                 float x_mid = 0.0f; /* used for dumb clamping of values */
680
681                                 /* dark checkers */
682                                 glColor4ub(UI_TRANSP_DARK, UI_TRANSP_DARK, UI_TRANSP_DARK, 255);
683                                 glEnableClientState(GL_VERTEX_ARRAY);
684                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
685                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
686                                 glDisableClientState(GL_VERTEX_ARRAY);
687
688                                 /* light checkers */
689                                 glEnable(GL_POLYGON_STIPPLE);
690                                 glColor4ub(UI_TRANSP_LIGHT, UI_TRANSP_LIGHT, UI_TRANSP_LIGHT, 255);
691                                 glPolygonStipple(checker_stipple_sml);
692
693                                 glEnableClientState(GL_VERTEX_ARRAY);
694                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
695                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
696                                 glDisableClientState(GL_VERTEX_ARRAY);
697
698                                 glDisable(GL_POLYGON_STIPPLE);
699
700                                 /* alpha fill */
701                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
702
703                                 glColor4ubv((unsigned char *)wcol->inner);
704                                 glEnableClientState(GL_VERTEX_ARRAY);
705
706                                 for (a = 0; a < wtb->totvert; a++) {
707                                         x_mid += wtb->inner_v[a][0];
708                                 }
709                                 x_mid /= wtb->totvert;
710
711                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
712                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
713                                 glDisableClientState(GL_VERTEX_ARRAY);
714
715                                 /* 1/2 solid color */
716                                 glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255);
717
718                                 for (a = 0; a < wtb->totvert; a++) {
719                                         inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid);
720                                         inner_v_half[a][1] = wtb->inner_v[a][1];
721                                 }
722
723                                 glEnableClientState(GL_VERTEX_ARRAY);
724                                 glVertexPointer(2, GL_FLOAT, 0, inner_v_half);
725                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
726                                 glDisableClientState(GL_VERTEX_ARRAY);
727                         }
728                         else {
729                                 /* simple fill */
730                                 glColor4ubv((unsigned char *)wcol->inner);
731
732                                 glEnableClientState(GL_VERTEX_ARRAY);
733                                 glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
734                                 glDrawArrays(GL_POLYGON, 0, wtb->totvert);
735                                 glDisableClientState(GL_VERTEX_ARRAY);
736                         }
737                 }
738                 else {
739                         char col1[4], col2[4];
740                         unsigned char col_array[WIDGET_SIZE_MAX * 4];
741                         unsigned char *col_pt = col_array;
742                         
743                         shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
744                         
745                         glShadeModel(GL_SMOOTH);
746                         for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
747                                 round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->shadedir]);
748                         }
749
750                         glEnableClientState(GL_VERTEX_ARRAY);
751                         glEnableClientState(GL_COLOR_ARRAY);
752                         glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
753                         glColorPointer(4, GL_UNSIGNED_BYTE, 0, col_array);
754                         glDrawArrays(GL_POLYGON, 0, wtb->totvert);
755                         glDisableClientState(GL_VERTEX_ARRAY);
756                         glDisableClientState(GL_COLOR_ARRAY);
757
758                         glShadeModel(GL_FLAT);
759                 }
760         }
761         
762         /* for each AA step */
763         if (wtb->outline) {
764                 float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
765                 float quad_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
766
767                 const unsigned char tcol[4] = {wcol->outline[0],
768                                                wcol->outline[1],
769                                                wcol->outline[2],
770                                                wcol->outline[3] / WIDGET_AA_JITTER};
771
772                 widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
773
774                 if (wtb->emboss) {
775                         widget_verts_to_quad_strip_open(wtb, wtb->halfwayvert, quad_strip_emboss);
776                 }
777
778                 glEnableClientState(GL_VERTEX_ARRAY);
779
780                 for (j = 0; j < WIDGET_AA_JITTER; j++) {
781                         glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
782                         
783                         /* outline */
784                         glColor4ubv(tcol);
785
786                         glVertexPointer(2, GL_FLOAT, 0, quad_strip);
787                         glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
788                 
789                         /* emboss bottom shadow */
790                         if (wtb->emboss) {
791                                 glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
792
793                                 glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss);
794                                 glDrawArrays(GL_QUAD_STRIP, 0, wtb->halfwayvert * 2);
795                         }
796                         
797                         glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
798                 }
799
800                 glDisableClientState(GL_VERTEX_ARRAY);
801         }
802         
803         /* decoration */
804         if (wtb->tria1.tot || wtb->tria2.tot) {
805                 const unsigned char tcol[4] = {wcol->item[0],
806                                                wcol->item[1],
807                                                wcol->item[2],
808                                                (unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
809                 /* for each AA step */
810                 for (j = 0; j < WIDGET_AA_JITTER; j++) {
811                         glTranslatef(1.0f * jit[j][0], 1.0f * jit[j][1], 0.0f);
812
813                         if (wtb->tria1.tot) {
814                                 glColor4ubv(tcol);
815                                 widget_trias_draw(&wtb->tria1);
816                         }
817                         if (wtb->tria2.tot) {
818                                 glColor4ubv(tcol);
819                                 widget_trias_draw(&wtb->tria2);
820                         }
821                 
822                         glTranslatef(-1.0f * jit[j][0], -1.0f * jit[j][1], 0.0f);
823                 }
824         }
825
826         glDisable(GL_BLEND);
827         
828 }
829
830 /* *********************** text/icon ************************************** */
831
832 #define PREVIEW_PAD 4
833
834 static void widget_draw_preview(BIFIconID icon, float UNUSED(alpha), const rcti *rect)
835 {
836         int w, h, size;
837
838         if (icon == ICON_NONE)
839                 return;
840
841         w = BLI_rcti_size_x(rect);
842         h = BLI_rcti_size_y(rect);
843         size = MIN2(w, h);
844         size -= PREVIEW_PAD * 2;  /* padding */
845
846         if (size > 0) {
847                 int x = rect->xmin + w / 2 - size / 2;
848                 int y = rect->ymin + h / 2 - size / 2;
849
850                 UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, size);
851         }
852 }
853
854
855 static int ui_but_draw_menu_icon(uiBut *but)
856 {
857         return (but->flag & UI_ICON_SUBMENU) && (but->dt == UI_EMBOSSP);
858 }
859
860 /* icons have been standardized... and this call draws in untransformed coordinates */
861
862 static void widget_draw_icon(uiBut *but, BIFIconID icon, float alpha, const rcti *rect)
863 {
864         float xs = 0.0f, ys = 0.0f;
865         float aspect, height;
866         
867         if (but->flag & UI_ICON_PREVIEW) {
868                 widget_draw_preview(icon, alpha, rect);
869                 return;
870         }
871         
872         /* this icon doesn't need draw... */
873         if (icon == ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU) == 0) return;
874         
875         aspect = but->block->aspect / UI_DPI_FAC;
876         height = ICON_DEFAULT_HEIGHT / aspect;
877
878         /* calculate blend color */
879         if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
880                 if (but->flag & UI_SELECT) {}
881                 else if (but->flag & UI_ACTIVE) {}
882                 else alpha = 0.5f;
883         }
884         
885         /* extra feature allows more alpha blending */
886         if (but->type == LABEL && but->a1 == 1.0f) alpha *= but->a2;
887         
888         glEnable(GL_BLEND);
889         
890         if (icon && icon != ICON_BLANK1) {
891                 float ofs = 1.0f / aspect;
892                 
893                 if (but->flag & UI_ICON_LEFT) {
894                         if (but->block->flag & UI_BLOCK_LOOP) {
895                                 if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK))
896                                         xs = rect->xmin + 4.0f * ofs;
897                                 else
898                                         xs = rect->xmin + ofs;
899                         }
900                         else {
901                                 xs = rect->xmin + 4.0f * ofs;
902                         }
903                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
904                 }
905                 else {
906                         xs = (rect->xmin + rect->xmax - height) / 2.0f;
907                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
908                 }
909
910                 /* force positions to integers, for zoom levels near 1. draws icons crisp. */
911                 if (aspect > 0.95f && aspect < 1.05f) {
912                         xs = (int)(xs + 0.1f);
913                         ys = (int)(ys + 0.1f);
914                 }
915                 
916                 /* to indicate draggable */
917                 if (but->dragpoin && (but->flag & UI_ACTIVE)) {
918                         float rgb[3] = {1.25f, 1.25f, 1.25f};
919                         UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
920                 }
921                 else
922                         UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
923         }
924
925         if (ui_but_draw_menu_icon(but)) {
926                 xs = rect->xmax - UI_DPI_ICON_SIZE - aspect;
927                 ys = (rect->ymin + rect->ymax - height) / 2.0f;
928                 
929                 UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
930         }
931         
932         glDisable(GL_BLEND);
933 }
934
935 static void ui_text_clip_give_prev_off(uiBut *but)
936 {
937         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + but->ofs);
938         int bytes = but->drawstr + but->ofs - prev_utf8;
939
940         but->ofs -= bytes;
941 }
942
943 static void ui_text_clip_give_next_off(uiBut *but)
944 {
945         char *next_utf8 = BLI_str_find_next_char_utf8(but->drawstr + but->ofs, NULL);
946         int bytes = next_utf8 - (but->drawstr + but->ofs);
947
948         but->ofs += bytes;
949 }
950
951 /**
952  * Cut off the start of the text to fit into the width of \a rect
953  *
954  * \note Sets but->ofs to make sure text is correctly visible.
955  * \note Clips right in some cases, this function could be cleaned up.
956  */
957 static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
958 {
959         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
960         int okwidth = BLI_rcti_size_x(rect) - border;
961
962         if (but->flag & UI_HAS_ICON)
963                 okwidth -= UI_DPI_ICON_SIZE;
964         if (but->type == SEARCH_MENU_UNLINK && !but->editstr)
965                 okwidth -= BLI_rcti_size_y(rect);
966
967         okwidth = max_ii(okwidth, 0);
968
969         /* need to set this first */
970         uiStyleFontSet(fstyle);
971         
972         if (fstyle->kerning == 1) /* for BLF_width */
973                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
974
975         but->ofs = 0;
976         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
977
978         while (but->strwidth > okwidth) {
979                 ui_text_clip_give_next_off(but);
980                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
981                 if (but->strwidth < 10) break;
982         }
983
984         if (fstyle->kerning == 1) {
985                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
986         }
987 }
988
989 /**
990  * Cut off the text, taking into account the cursor location (text display while editing).
991  */
992 static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
993 {
994         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
995         int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
996         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
997
998         BLI_assert(but->editstr && but->pos >= 0);
999
1000         /* need to set this first */
1001         uiStyleFontSet(fstyle);
1002
1003         if (fstyle->kerning == 1) /* for BLF_width */
1004                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1005
1006         /* define ofs dynamically */
1007         if (but->ofs > but->pos)
1008                 but->ofs = but->pos;
1009
1010         if (BLF_width(fstyle->uifont_id, but->drawstr) <= okwidth)
1011                 but->ofs = 0;
1012
1013         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1014
1015         while (but->strwidth > okwidth) {
1016                 float width;
1017                 char buf[UI_MAX_DRAW_STR];
1018
1019                 /* copy draw string */
1020                 BLI_strncpy_utf8(buf, but->drawstr, sizeof(buf));
1021                 /* string position of cursor */
1022                 buf[but->pos] = 0;
1023                 width = BLF_width(fstyle->uifont_id, buf + but->ofs);
1024
1025                 /* if cursor is at 20 pixels of right side button we clip left */
1026                 if (width > okwidth - 20) {
1027                         ui_text_clip_give_next_off(but);
1028                 }
1029                 else {
1030                         int len, bytes;
1031                         /* shift string to the left */
1032                         if (width < 20 && but->ofs > 0)
1033                                 ui_text_clip_give_prev_off(but);
1034                         len = strlen(but->drawstr);
1035                         bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len));
1036                         if (bytes < 0)
1037                                 bytes = 1;
1038                         but->drawstr[len - bytes] = 0;
1039                 }
1040
1041                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1042
1043                 if (but->strwidth < 10) break;
1044         }
1045
1046         if (fstyle->kerning == 1) {
1047                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1048         }
1049 }
1050
1051 /**
1052  * Cut off the end of text to fit into the width of \a rect.
1053  *
1054  * \note deals with ': ' especially for number buttons
1055  */
1056 static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1057 {
1058         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
1059         int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
1060         char *cpoin = NULL;
1061         int drawstr_len = strlen(but->drawstr);
1062         char *cpend = but->drawstr + drawstr_len;
1063         
1064         /* need to set this first */
1065         uiStyleFontSet(fstyle);
1066         
1067         if (fstyle->kerning == 1) /* for BLF_width */
1068                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1069         
1070         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
1071         but->ofs = 0;
1072         
1073
1074         /* First shorten num-buttopns eg,
1075          *   Translucency: 0.000
1076          * becomes
1077          *   Trans: 0.000
1078          */
1079
1080         /* find the space after ':' separator */
1081         cpoin = strrchr(but->drawstr, ':');
1082         
1083         if (cpoin && (cpoin < cpend - 2)) {
1084                 char *cp2 = cpoin;
1085                 
1086                 /* chop off the leading text, starting from the right */
1087                 while (but->strwidth > okwidth && cp2 > but->drawstr) {
1088                         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, cp2);
1089                         int bytes = cp2 - prev_utf8;
1090
1091                         /* shift the text after and including cp2 back by 1 char, +1 to include null terminator */
1092                         memmove(cp2 - bytes, cp2, drawstr_len + 1);
1093                         cp2 -= bytes;
1094
1095                         drawstr_len -= bytes;
1096                         // BLI_assert(strlen(but->drawstr) == drawstr_len);
1097                         
1098                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1099                         if (but->strwidth < 10) break;
1100                 }
1101         
1102         
1103                 /* after the leading text is gone, chop off the : and following space, with ofs */
1104                 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1105                         ui_text_clip_give_next_off(but);
1106                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1107                         if (but->strwidth < 10) break;
1108                 }
1109                 
1110         }
1111
1112
1113         /* Now just remove trailing chars */
1114         /* once the label's gone, chop off the least significant digits */
1115         while (but->strwidth > okwidth) {
1116                 int bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + drawstr_len));
1117                 if (bytes < 0)
1118                         bytes = 1;
1119
1120                 drawstr_len -= bytes;
1121                 but->drawstr[drawstr_len] = 0;
1122                 // BLI_assert(strlen(but->drawstr) == drawstr_len);
1123                 
1124                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1125                 if (but->strwidth < 10) break;
1126         }
1127         
1128         if (fstyle->kerning == 1)
1129                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1130 }
1131
1132
1133 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1134 {
1135         //int transopts;  // UNUSED
1136         char *cpoin = NULL;
1137         
1138         /* for underline drawing */
1139         float font_xofs, font_yofs;
1140
1141         uiStyleFontSet(fstyle);
1142         
1143         if (but->editstr || (but->flag & UI_TEXT_LEFT))
1144                 fstyle->align = UI_STYLE_TEXT_LEFT;
1145         else if (but->flag & UI_TEXT_RIGHT)
1146                 fstyle->align = UI_STYLE_TEXT_RIGHT;
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                                 glColor4ubv((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         transopts = ui_translate_buttons();
1213 #endif
1214
1215         /* cut string in 2 parts - only for menu entries */
1216         if ((but->block->flag & UI_BLOCK_LOOP)) {
1217                 if (ELEM3(but->type, NUM, TEX, NUMSLI) == 0) {
1218                         cpoin = strchr(but->drawstr, '|');
1219                         if (cpoin) *cpoin = 0;
1220                 }
1221         }
1222         
1223         glColor4ubv((unsigned char *)wcol->text);
1224
1225         uiStyleFontDrawExt(fstyle, rect, but->drawstr + but->ofs, &font_xofs, &font_yofs);
1226
1227         if (but->menu_key != '\0') {
1228                 char fixedbuf[128];
1229                 char *str;
1230
1231                 BLI_strncpy(fixedbuf, but->drawstr + but->ofs, sizeof(fixedbuf));
1232
1233                 str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
1234                 if (str == NULL)
1235                         str = strchr(fixedbuf, but->menu_key);
1236
1237                 if (str) {
1238                         int ul_index = -1;
1239                         float ul_advance;
1240
1241                         ul_index = (int)(str - fixedbuf);
1242
1243                         if (fstyle->kerning == 1) {
1244                                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1245                         }
1246
1247                         fixedbuf[ul_index] = '\0';
1248                         ul_advance = BLF_width(fstyle->uifont_id, fixedbuf);
1249
1250                         BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
1251                         BLF_draw(fstyle->uifont_id, "_", 2);
1252
1253                         if (fstyle->kerning == 1) {
1254                                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1255                         }
1256                 }
1257         }
1258
1259         /* part text right aligned */
1260         if (cpoin) {
1261                 fstyle->align = UI_STYLE_TEXT_RIGHT;
1262                 rect->xmax -= ui_but_draw_menu_icon(but) ? UI_DPI_ICON_SIZE : 0.25f * U.widget_unit;
1263                 uiStyleFontDraw(fstyle, rect, cpoin + 1);
1264                 *cpoin = '|';
1265         }
1266 }
1267
1268 /* draws text and icons for buttons */
1269 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1270 {
1271         float alpha = (float)wcol->text[3] / 255.0f;
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 (ELEM(but->type, NUM, NUMSLI)) {
1284                 ui_text_clip_right_label(fstyle, but, rect);
1285         }
1286         else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1287                 ui_text_clip_left(fstyle, but, rect);
1288         }
1289         else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
1290                 ui_text_clip_left(fstyle, but, rect);
1291         }
1292         else {
1293                 but->ofs = 0;
1294         }
1295
1296         /* check for button text label */
1297         if (but->type == MENU && (but->flag & UI_BUT_NODE_LINK)) {
1298                 int tmp = rect->xmin;
1299                 rect->xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
1300                 widget_draw_icon(but, ICON_LAYER_USED, alpha, rect);
1301                 rect->xmin = tmp;
1302         }
1303
1304         /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
1305          * and offset the text label to accommodate it */
1306
1307         if (but->flag & UI_HAS_ICON) {
1308                 widget_draw_icon(but, but->icon + but->iconadd, alpha, rect);
1309                 
1310                 /* icons default draw 0.8f x height */
1311                 rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect));
1312
1313                 if (but->editstr || (but->flag & UI_TEXT_LEFT)) {
1314                         rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1315                 }
1316                 else if ((but->flag & UI_TEXT_RIGHT)) {
1317                         rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1318                 }
1319         }
1320         else if ((but->flag & UI_TEXT_LEFT)) {
1321                 rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1322         }
1323         else if ((but->flag & UI_TEXT_RIGHT)) {
1324                 rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1325         }
1326         
1327         /* unlink icon for this button type */
1328         if (but->type == SEARCH_MENU_UNLINK && !but->editstr && but->drawstr[0]) {
1329                 rcti temp = *rect;
1330
1331                 temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
1332                 widget_draw_icon(but, ICON_X, alpha, &temp);
1333         }
1334
1335         /* always draw text for textbutton cursor */
1336         widget_draw_text(fstyle, wcol, but, rect);
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  *     char outline[3];
1368  *     char inner[4];
1369  *     char inner_sel[4];
1370  *     char item[3];
1371  *     char text[3];
1372  *     char 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_GetThemeColor3ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1742         else
1743                 UI_GetThemeColor3ubv(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         /* active and disabled (not so common) */
1788         if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
1789                 widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
1790                 /* draw the backdrop at low alpha, helps navigating with keys
1791                  * when disabled items are active */
1792                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1793                 wt->wcol.inner[3] = 64;
1794         }
1795         /* regular disabled */
1796         else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1797                 widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
1798         }
1799         /* regular active */
1800         else if (state & UI_ACTIVE) {
1801                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1802                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1803         }
1804 }
1805
1806
1807 /* ************ menu backdrop ************************* */
1808
1809 /* outside of rect, rad to left/bottom/right */
1810 static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
1811 {
1812         bTheme *btheme = UI_GetTheme();
1813         uiWidgetBase wtb;
1814         rcti rect1 = *rect;
1815         float alphastep;
1816         int step, totvert;
1817         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
1818         const float radout = UI_ThemeMenuShadowWidth();
1819         
1820         /* disabled shadow */
1821         if (radout == 0.0f)
1822                 return;
1823         
1824         /* prevent tooltips to not show round shadow */
1825         if (radout > 0.2f * BLI_rcti_size_y(&rect1))
1826                 rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
1827         else
1828                 rect1.ymax -= radout;
1829         
1830         /* inner part */
1831         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1832
1833         /* we draw a number of increasing size alpha quad strips */
1834         alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
1835         
1836         glEnableClientState(GL_VERTEX_ARRAY);
1837
1838         for (step = 1; step <= (int)radout; step++) {
1839                 float expfac = sqrt(step / radout);
1840                 
1841                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1842                 
1843                 glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
1844
1845                 widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
1846
1847                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1848                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
1849         }
1850
1851         glDisableClientState(GL_VERTEX_ARRAY);
1852 }
1853
1854 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1855 {
1856         uiWidgetBase wtb;
1857         int roundboxalign = UI_CNR_ALL;
1858         
1859         widget_init(&wtb);
1860         
1861         /* menu is 2nd level or deeper */
1862         if (flag & UI_BLOCK_POPUP) {
1863                 //rect->ymin -= 4.0;
1864                 //rect->ymax += 4.0;
1865         }
1866         else if (direction == UI_DOWN) {
1867                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1868                 rect->ymin -= 0.1f * U.widget_unit;
1869         }
1870         else if (direction == UI_TOP) {
1871                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1872                 rect->ymax += 0.1f * U.widget_unit;
1873         }
1874         
1875         glEnable(GL_BLEND);
1876         widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
1877         
1878         round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
1879         wtb.emboss = 0;
1880         widgetbase_draw(&wtb, wcol);
1881         
1882         glDisable(GL_BLEND);
1883 }
1884
1885
1886 static void ui_hsv_cursor(float x, float y)
1887 {
1888         
1889         glPushMatrix();
1890         glTranslatef(x, y, 0.0f);
1891         
1892         glColor3f(1.0f, 1.0f, 1.0f);
1893         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
1894         
1895         glEnable(GL_BLEND);
1896         glEnable(GL_LINE_SMOOTH);
1897         glColor3f(0.0f, 0.0f, 0.0f);
1898         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12);
1899         glDisable(GL_BLEND);
1900         glDisable(GL_LINE_SMOOTH);
1901         
1902         glPopMatrix();
1903         
1904 }
1905
1906 void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
1907                                 const float mx, const float my)
1908 {
1909         /* duplication of code... well, simple is better now */
1910         const float centx = BLI_rcti_cent_x_fl(rect);
1911         const float centy = BLI_rcti_cent_y_fl(rect);
1912         const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1913         const float m_delta[2] = {mx - centx, my - centy};
1914         const float dist_squared = len_squared_v2(m_delta);
1915
1916         *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f;
1917         *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
1918 }
1919
1920 /* cursor in hsv circle, in float units -1 to 1, to map on radius */
1921 void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos)
1922 {
1923         /* duplication of code... well, simple is better now */
1924         const float centx = BLI_rcti_cent_x_fl(rect);
1925         const float centy = BLI_rcti_cent_y_fl(rect);
1926         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1927         float ang, radius_t;
1928         
1929         ang = 2.0f * (float)M_PI * hsv[0] + 0.5f * (float)M_PI;
1930         
1931         if (but->flag & UI_BUT_COLOR_CUBIC)
1932                 radius_t = (1.0f - powf(1.0f - hsv[1], 3.0f));
1933         else
1934                 radius_t = hsv[1];
1935         
1936         radius = CLAMPIS(radius_t, 0.0f, 1.0f) * radius;
1937         *xpos = centx + cosf(-ang) * radius;
1938         *ypos = centy + sinf(-ang) * radius;
1939 }
1940
1941 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
1942 {
1943         const int tot = 64;
1944         const float radstep = 2.0f * (float)M_PI / (float)tot;
1945         const float centx = BLI_rcti_cent_x_fl(rect);
1946         const float centy = BLI_rcti_cent_y_fl(rect);
1947         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1948
1949         /* gouraud triangle fan */
1950         const float *hsv_ptr = ui_block_hsv_get(but->block);
1951         float xpos, ypos, ang = 0.0f;
1952         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1953         int a;
1954         int color_profile = but->block->color_profile;
1955         
1956         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1957                 color_profile = FALSE;
1958         
1959         /* color */
1960         ui_get_but_vectorf(but, rgb);
1961
1962         /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
1963         hsvo[0] = hsv[0] = hsv_ptr[0];
1964         hsvo[1] = hsv[1] = hsv_ptr[1];
1965         hsvo[2] = hsv[2] = hsv_ptr[2];
1966
1967         rgb_to_hsv_compat_v(rgb, hsvo);
1968
1969         if (color_profile)
1970                 ui_block_to_display_space_v3(but->block, rgb);
1971
1972         rgb_to_hsv_compat_v(rgb, hsv);
1973         
1974         /* exception: if 'lock' is set
1975          * lock the value of the color wheel to 1.
1976          * Useful for color correction tools where you're only interested in hue. */
1977         if (but->flag & UI_BUT_COLOR_LOCK)
1978                 hsv[2] = 1.f;
1979         
1980         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1981         
1982         glShadeModel(GL_SMOOTH);
1983
1984         glBegin(GL_TRIANGLE_FAN);
1985         glColor3fv(colcent);
1986         glVertex2f(centx, centy);
1987         
1988         for (a = 0; a <= tot; a++, ang += radstep) {
1989                 float si = sin(ang);
1990                 float co = cos(ang);
1991                 
1992                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1993                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1994
1995                 hsv_to_rgb_v(hsv, col);
1996                 glColor3fv(col);
1997                 glVertex2f(centx + co * radius, centy + si * radius);
1998         }
1999         glEnd();
2000         
2001         glShadeModel(GL_FLAT);
2002         
2003         /* fully rounded outline */
2004         glPushMatrix();
2005         glTranslatef(centx, centy, 0.0f);
2006         glEnable(GL_BLEND);
2007         glEnable(GL_LINE_SMOOTH);
2008         glColor3ubv((unsigned char *)wcol->outline);
2009         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
2010         glDisable(GL_BLEND);
2011         glDisable(GL_LINE_SMOOTH);
2012         glPopMatrix();
2013
2014         /* cursor */
2015         ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos);
2016
2017         ui_hsv_cursor(xpos, ypos);
2018 }
2019
2020 /* ************ custom buttons, old stuff ************** */
2021
2022 /* draws in resolution of 20x4 colors */
2023 void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
2024 {
2025         const float color_step = (type == UI_GRAD_H) ? 0.02f : 0.05f;
2026         int a;
2027         float h = hsv[0], s = hsv[1], v = hsv[2];
2028         float dx, dy, sx1, sx2, sy;
2029         float col0[4][3];   /* left half, rect bottom to top */
2030         float col1[4][3];   /* right half, rect bottom to top */
2031
2032         /* draw series of gouraud rects */
2033         glShadeModel(GL_SMOOTH);
2034         
2035         switch (type) {
2036                 case UI_GRAD_SV:
2037                         hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2038                         hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
2039                         hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
2040                         hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2041                         break;
2042                 case UI_GRAD_HV:
2043                         hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2044                         hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2045                         hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2046                         hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2047                         break;
2048                 case UI_GRAD_HS:
2049                         hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2050                         hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2051                         hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2052                         hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2053                         break;
2054                 case UI_GRAD_H:
2055                         hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2056                         copy_v3_v3(col1[1], col1[0]);
2057                         copy_v3_v3(col1[2], col1[0]);
2058                         copy_v3_v3(col1[3], col1[0]);
2059                         break;
2060                 case UI_GRAD_S:
2061                         hsv_to_rgb(1.0, 0.0, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2062                         copy_v3_v3(col1[0], col1[1]);
2063                         copy_v3_v3(col1[2], col1[1]);
2064                         copy_v3_v3(col1[3], col1[1]);
2065                         break;
2066                 case UI_GRAD_V:
2067                         hsv_to_rgb(1.0, 1.0, 0.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2068                         copy_v3_v3(col1[0], col1[2]);
2069                         copy_v3_v3(col1[1], col1[2]);
2070                         copy_v3_v3(col1[3], col1[2]);
2071                         break;
2072                 default:
2073                         assert(!"invalid 'type' argument");
2074                         hsv_to_rgb(1.0, 1.0, 1.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2075                         copy_v3_v3(col1[0], col1[2]);
2076                         copy_v3_v3(col1[1], col1[2]);
2077                         copy_v3_v3(col1[3], col1[2]);
2078         }
2079         
2080         /* old below */
2081         
2082         for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */
2083                 /* previous color */
2084                 copy_v3_v3(col0[0], col1[0]);
2085                 copy_v3_v3(col0[1], col1[1]);
2086                 copy_v3_v3(col0[2], col1[2]);
2087                 copy_v3_v3(col0[3], col1[3]);
2088                 
2089                 /* new color */
2090                 switch (type) {
2091                         case UI_GRAD_SV:
2092                                 hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
2093                                 hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
2094                                 hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
2095                                 hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
2096                                 break;
2097                         case UI_GRAD_HV:
2098                                 hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2099                                 hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2100                                 hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2101                                 hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2102                                 break;
2103                         case UI_GRAD_HS:
2104                                 hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2105                                 hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2106                                 hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2107                                 hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2108                                 break;
2109                         case UI_GRAD_H:
2110                         {
2111                                 /* annoying but without this the color shifts - could be solved some other way
2112                                  * - campbell */
2113                                 hsv_to_rgb(dx + color_step, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2114                                 copy_v3_v3(col1[1], col1[0]);
2115                                 copy_v3_v3(col1[2], col1[0]);
2116                                 copy_v3_v3(col1[3], col1[0]);
2117                                 break;
2118                         }
2119                         case UI_GRAD_S:
2120                                 hsv_to_rgb(h, dx, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2121                                 copy_v3_v3(col1[0], col1[1]);
2122                                 copy_v3_v3(col1[2], col1[1]);
2123                                 copy_v3_v3(col1[3], col1[1]);
2124                                 break;
2125                         case UI_GRAD_V:
2126                                 hsv_to_rgb(h, 1.0, dx,   &col1[2][0], &col1[2][1], &col1[2][2]);
2127                                 copy_v3_v3(col1[0], col1[2]);
2128                                 copy_v3_v3(col1[1], col1[2]);
2129                                 copy_v3_v3(col1[3], col1[2]);
2130                                 break;
2131                 }
2132                 
2133                 /* rect */
2134                 sx1 = rect->xmin +  dx               * BLI_rcti_size_x(rect);
2135                 sx2 = rect->xmin + (dx + color_step) * BLI_rcti_size_x(rect);
2136                 sy = rect->ymin;
2137                 dy = (float)BLI_rcti_size_y(rect) / 3.0f;
2138                 
2139                 glBegin(GL_QUADS);
2140                 for (a = 0; a < 3; a++, sy += dy) {
2141                         glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
2142                         glVertex2f(sx1, sy);
2143                         
2144                         glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
2145                         glVertex2f(sx2, sy);
2146
2147                         glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
2148                         glVertex2f(sx2, sy + dy);
2149                         
2150                         glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
2151                         glVertex2f(sx1, sy + dy);
2152                 }
2153                 glEnd();
2154         }
2155         
2156         glShadeModel(GL_FLAT);
2157         
2158 }
2159
2160 void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp)
2161 {
2162         float x, y;
2163         
2164         switch ((int)but->a1) {
2165                 case UI_GRAD_SV:
2166                         x = hsv[2]; y = hsv[1]; break;
2167                 case UI_GRAD_HV:
2168                         x = hsv[0]; y = hsv[2]; break;
2169                 case UI_GRAD_HS:
2170                         x = hsv[0]; y = hsv[1]; break;
2171                 case UI_GRAD_H:
2172                         x = hsv[0]; y = 0.5; break;
2173                 case UI_GRAD_S:
2174                         x = hsv[1]; y = 0.5; break;
2175                 case UI_GRAD_V:
2176                         x = hsv[2]; y = 0.5; break;
2177                 case UI_GRAD_V_ALT:
2178                         x = 0.5f;
2179                         /* exception only for value strip - use the range set in but->min/max */
2180                         y = (hsv[2] - but->softmin ) / (but->softmax - but->softmin);
2181                         break;
2182         }
2183         
2184         /* cursor */
2185         *xp = rect->xmin + x * BLI_rcti_size_x(rect);
2186         *yp = rect->ymin + y * BLI_rcti_size_y(rect);
2187
2188 }
2189
2190 static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
2191 {
2192         float rgb[3];
2193         float x = 0.0f, y = 0.0f;
2194         float *hsv = ui_block_hsv_get(but->block);
2195         float hsv_n[3];
2196         int color_profile = but->block->color_profile;
2197         
2198         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2199                 color_profile = FALSE;
2200         
2201         copy_v3_v3(hsv_n, hsv);
2202         
2203         ui_get_but_vectorf(but, rgb);
2204         
2205         if (color_profile && (int)but->a1 != UI_GRAD_SV)
2206                 ui_block_to_display_space_v3(but->block, rgb);
2207         
2208         rgb_to_hsv_compat_v(rgb, hsv_n);
2209         
2210         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2211
2212         ui_hsvcube_pos_from_vals(but, rect, hsv_n, &x, &y);
2213         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2214         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2215         
2216         ui_hsv_cursor(x, y);
2217         
2218         /* outline */
2219         glColor3ub(0,  0,  0);
2220         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2221 }
2222
2223 /* vertical 'value' slider, using new widget code */
2224 static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
2225 {
2226         uiWidgetBase wtb;
2227         const float rad = 0.5f * BLI_rcti_size_x(rect);
2228         float x, y;
2229         float rgb[3], hsv[3], v, range;
2230         int color_profile = but->block->color_profile;
2231         
2232         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2233                 color_profile = FALSE;
2234
2235         ui_get_but_vectorf(but, rgb);
2236
2237         if (color_profile)
2238                 ui_block_to_display_space_v3(but->block, rgb);
2239
2240         rgb_to_hsv_v(rgb, hsv);
2241         v = hsv[2];
2242         
2243         /* map v from property range to [0,1] */
2244         range = but->softmax - but->softmin;
2245         v = (v - but->softmin) / range;
2246         
2247         widget_init(&wtb);
2248         
2249         /* fully rounded */
2250         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2251         
2252         /* setup temp colors */
2253         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2254         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2255         wcol_tmp.shadetop = 127;
2256         wcol_tmp.shadedown = -128;
2257         wcol_tmp.shaded = 1;
2258         
2259         widgetbase_draw(&wtb, &wcol_tmp);
2260
2261         /* cursor */
2262         x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
2263         y = rect->ymin + v    * BLI_rcti_size_y(rect);
2264         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2265         
2266         ui_hsv_cursor(x, y);
2267         
2268 }
2269
2270
2271 /* ************ separator, for menus etc ***************** */
2272 static void ui_draw_separator(const rcti *rect,  uiWidgetColors *wcol)
2273 {
2274         int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2275         unsigned char col[4];
2276         
2277         col[0] = wcol->text[0];
2278         col[1] = wcol->text[1];
2279         col[2] = wcol->text[2];
2280         col[3] = 7;
2281         
2282         glEnable(GL_BLEND);
2283         glColor4ubv(col);
2284         sdrawline(rect->xmin, y, rect->xmax, y);
2285         glDisable(GL_BLEND);
2286 }
2287
2288 /* ************ button callbacks, draw ***************** */
2289
2290 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2291 {
2292         uiWidgetBase wtb;
2293         const float rad = 0.5f * BLI_rcti_size_y(rect);
2294         float textofs = rad * 0.75f;
2295
2296         if (state & UI_SELECT)
2297                 SWAP(short, wcol->shadetop, wcol->shadedown);
2298         
2299         widget_init(&wtb);
2300         
2301         /* fully rounded */
2302         round_box_edges(&wtb, roundboxalign, rect, rad);
2303         
2304         /* decoration */
2305         if (!(state & UI_TEXTINPUT)) {
2306                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2307                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2308         }
2309
2310         widgetbase_draw(&wtb, wcol);
2311         
2312         /* text space */
2313         rect->xmin += textofs;
2314         rect->xmax -= textofs;
2315 }
2316
2317 int ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
2318 {
2319         float dist, vec[4][2];
2320
2321         vec[0][0] = rect->xmin;
2322         vec[0][1] = rect->ymin;
2323         vec[3][0] = rect->xmax;
2324         vec[3][1] = rect->ymax;
2325         
2326         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2327         
2328         vec[1][0] = vec[0][0] + dist;
2329         vec[1][1] = vec[0][1];
2330         
2331         vec[2][0] = vec[3][0] - dist;
2332         vec[2][1] = vec[3][1];
2333         
2334         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2335         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);
2336         
2337         return 1;
2338 }
2339
2340 #define LINK_RESOL  24
2341 void ui_draw_link_bezier(const rcti *rect)
2342 {
2343         float coord_array[LINK_RESOL + 1][2];
2344         
2345         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2346                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2347                 // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
2348
2349                 glEnable(GL_BLEND);
2350                 glEnable(GL_LINE_SMOOTH);
2351
2352                 glEnableClientState(GL_VERTEX_ARRAY);
2353                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2354                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1);
2355                 glDisableClientState(GL_VERTEX_ARRAY);
2356
2357                 glDisable(GL_BLEND);
2358                 glDisable(GL_LINE_SMOOTH);
2359
2360         }
2361 }
2362
2363 /* function in use for buttons and for view2d sliders */
2364 void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
2365 {
2366         uiWidgetBase wtb;
2367         int horizontal;
2368         float rad;
2369         short outline = 0;
2370
2371         widget_init(&wtb);
2372
2373         /* determine horizontal/vertical */
2374         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2375
2376         if (horizontal)
2377                 rad = 0.5f * BLI_rcti_size_y(rect);
2378         else
2379                 rad = 0.5f * BLI_rcti_size_x(rect);
2380         
2381         wtb.shadedir = (horizontal) ? 1 : 0;
2382         
2383         /* draw back part, colors swapped and shading inverted */
2384         if (horizontal)
2385                 SWAP(short, wcol->shadetop, wcol->shadedown);
2386         
2387         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2388         widgetbase_draw(&wtb, wcol);
2389         
2390         /* slider */
2391         if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2392                 /* pass */
2393         }
2394         else {
2395                 SWAP(short, wcol->shadetop, wcol->shadedown);
2396                 
2397                 copy_v4_v4_char(wcol->inner, wcol->item);
2398                 
2399                 if (wcol->shadetop > wcol->shadedown)
2400                         wcol->shadetop += 20;   /* XXX violates themes... */
2401                 else wcol->shadedown += 20;
2402                 
2403                 if (state & UI_SCROLL_PRESSED) {
2404                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2405                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2406                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2407                 }
2408
2409                 /* draw */
2410                 wtb.emboss = 0; /* only emboss once */
2411                 
2412                 /* exception for progress bar */
2413                 if (state & UI_SCROLL_NO_OUTLINE)
2414                         SWAP(short, outline, wtb.outline);
2415                 
2416                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2417                 
2418                 if (state & UI_SCROLL_ARROWS) {
2419                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2420                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2421                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2422                         wcol->item[3] = 255;
2423                         
2424                         if (horizontal) {
2425                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2426                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2427                         }
2428                         else {
2429                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2430                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2431                         }
2432                 }
2433                 widgetbase_draw(&wtb, wcol);
2434                 
2435                 if (state & UI_SCROLL_NO_OUTLINE)
2436                         SWAP(short, outline, wtb.outline);
2437         }
2438 }
2439
2440 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2441 {
2442         rcti rect1;
2443         double value;
2444         float fac, size, min;
2445         int horizontal;
2446
2447         /* calculate slider part */
2448         value = ui_get_but_val(but);
2449
2450         size = (but->softmax + but->a1 - but->softmin);
2451         size = max_ff(size, 2.0f);
2452         
2453         /* position */
2454         rect1 = *rect;
2455
2456         /* determine horizontal/vertical */
2457         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2458         
2459         if (horizontal) {
2460                 fac = BLI_rcti_size_x(rect) / size;
2461                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2462                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2463
2464                 /* ensure minimium size */
2465                 min = BLI_rcti_size_y(rect);
2466
2467                 if (BLI_rcti_size_x(&rect1) < min) {
2468                         rect1.xmax = rect1.xmin + min;
2469
2470                         if (rect1.xmax > rect->xmax) {
2471                                 rect1.xmax = rect->xmax;
2472                                 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
2473                         }
2474                 }
2475         }
2476         else {
2477                 fac = BLI_rcti_size_y(rect) / size;
2478                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2479                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2480
2481                 /* ensure minimium size */
2482                 min = BLI_rcti_size_x(rect);
2483
2484                 if (BLI_rcti_size_y(&rect1) < min) {
2485                         rect1.ymax = rect1.ymin + min;
2486
2487                         if (rect1.ymax > rect->ymax) {
2488                                 rect1.ymax = rect->ymax;
2489                                 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
2490                         }
2491                 }
2492         }
2493
2494         if (state & UI_SELECT)
2495                 state = UI_SCROLL_PRESSED;
2496         else
2497                 state = 0;
2498         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2499 }
2500
2501 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2502 {
2503         rcti rect_prog = *rect, rect_bar = *rect;
2504         float value = but->a1;
2505         float w, min;
2506         
2507         /* make the progress bar a proportion of the original height */
2508         /* hardcoded 4px high for now */
2509         rect_prog.ymax = rect_prog.ymin + 4 * UI_DPI_FAC;
2510         rect_bar.ymax = rect_bar.ymin + 4 * UI_DPI_FAC;
2511         
2512         w = value * BLI_rcti_size_x(&rect_prog);
2513         
2514         /* ensure minimium size */
2515         min = BLI_rcti_size_y(&rect_prog);
2516         w = MAX2(w, min);
2517         
2518         rect_bar.xmax = rect_bar.xmin + w;
2519                 
2520         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2521         
2522         /* raise text a bit */
2523         rect->ymin += 6 * UI_DPI_FAC;
2524         rect->xmin -= 6 * UI_DPI_FAC;
2525 }
2526
2527 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2528 {
2529         
2530         if (but->flag & UI_SELECT) {
2531                 rcti rectlink;
2532                 
2533                 UI_ThemeColor(TH_TEXT_HI);
2534                 
2535                 rectlink.xmin = BLI_rcti_cent_x(rect);
2536                 rectlink.ymin = BLI_rcti_cent_y(rect);
2537                 rectlink.xmax = but->linkto[0];
2538                 rectlink.ymax = but->linkto[1];
2539                 
2540                 ui_draw_link_bezier(&rectlink);
2541         }
2542 }
2543
2544 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2545 {
2546         uiWidgetBase wtb, wtb1;
2547         rcti rect1;
2548         double value;
2549         float offs, toffs, fac;
2550         char outline[3];
2551
2552         widget_init(&wtb);
2553         widget_init(&wtb1);
2554         
2555         /* backdrop first */
2556         
2557         /* fully rounded */
2558         offs = 0.5f * BLI_rcti_size_y(rect);
2559         toffs = offs * 0.75f;
2560         round_box_edges(&wtb, roundboxalign, rect, offs);
2561
2562         wtb.outline = 0;
2563         widgetbase_draw(&wtb, wcol);
2564         
2565         /* draw left/right parts only when not in text editing */
2566         if (!(state & UI_TEXTINPUT)) {
2567                 
2568                 /* slider part */
2569                 copy_v3_v3_char(outline, wcol->outline);
2570                 copy_v3_v3_char(wcol->outline, wcol->item);
2571                 copy_v3_v3_char(wcol->inner, wcol->item);
2572
2573                 if (!(state & UI_SELECT))
2574                         SWAP(short, wcol->shadetop, wcol->shadedown);
2575                 
2576                 rect1 = *rect;
2577                 
2578                 value = ui_get_but_val(but);
2579                 fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
2580                 
2581                 /* left part of slider, always rounded */
2582                 rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
2583                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2584                 wtb1.outline = 0;
2585                 widgetbase_draw(&wtb1, wcol);
2586                 
2587                 /* right part of slider, interpolate roundness */
2588                 rect1.xmax = rect1.xmin + fac + offs;
2589                 rect1.xmin +=  floor(offs - U.pixelsize);
2590                 
2591                 if (rect1.xmax + offs > rect->xmax)
2592                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2593                 else 
2594                         offs = 0.0f;
2595                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2596                 
2597                 widgetbase_draw(&wtb1, wcol);
2598                 copy_v3_v3_char(wcol->outline, outline);
2599                 
2600                 if (!(state & UI_SELECT))
2601                         SWAP(short, wcol->shadetop, wcol->shadedown);
2602         }
2603         
2604         /* outline */
2605         wtb.outline = 1;
2606         wtb.inner = 0;
2607         widgetbase_draw(&wtb, wcol);
2608         
2609         /* text space */
2610         rect->xmin += toffs;
2611         rect->xmax -= toffs;
2612 }
2613
2614 /* I think 3 is sufficient border to indicate keyed status */
2615 #define SWATCH_KEYED_BORDER 3
2616
2617 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2618 {
2619         uiWidgetBase wtb;
2620         float rad, col[4];
2621         int color_profile = but->block->color_profile;
2622         
2623         col[3] = 1.0f;
2624
2625         if (but->rnaprop) {
2626                 BLI_assert(but->rnaindex == -1);
2627
2628                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2629                         color_profile = FALSE;
2630
2631                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2632                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2633                 }
2634         }
2635         
2636         widget_init(&wtb);
2637         
2638         /* half rounded */
2639         rad = 0.25f * U.widget_unit;
2640         round_box_edges(&wtb, roundboxalign, rect, rad);
2641                 
2642         ui_get_but_vectorf(but, col);
2643
2644         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2645                 /* draw based on state - color for keyed etc */
2646                 widgetbase_draw(&wtb, wcol);
2647
2648                 /* inset to draw swatch color */
2649                 rect->xmin += SWATCH_KEYED_BORDER;
2650                 rect->xmax -= SWATCH_KEYED_BORDER;
2651                 rect->ymin += SWATCH_KEYED_BORDER;
2652                 rect->ymax -= SWATCH_KEYED_BORDER;
2653                 
2654                 round_box_edges(&wtb, roundboxalign, rect, rad);
2655         }
2656         
2657         if (color_profile)
2658                 ui_block_to_display_space_v3(but->block, col);
2659         
2660         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2661
2662         wcol->shaded = 0;
2663         wcol->alpha_check = (wcol->inner[3] < 255);
2664
2665         widgetbase_draw(&wtb, wcol);
2666         
2667 }
2668
2669 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2670 {
2671         ui_draw_but_NORMAL(but, wcol, rect);
2672 }
2673
2674 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2675 {
2676         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2677                 uiWidgetBase wtb;
2678                 float rad;
2679                 
2680                 widget_init(&wtb);
2681                 wtb.outline = 0;
2682                 
2683                 /* rounded */
2684                 rad = 0.5f * BLI_rcti_size_y(rect);
2685                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2686                 widgetbase_draw(&wtb, wcol);
2687         }
2688 }
2689
2690
2691 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2692 {
2693         uiWidgetBase wtb;
2694         float rad;
2695         
2696         if (state & UI_SELECT)
2697                 SWAP(short, wcol->shadetop, wcol->shadedown);
2698         
2699         widget_init(&wtb);
2700         
2701         /* half rounded */
2702         rad = 0.2f * U.widget_unit;
2703         round_box_edges(&wtb, roundboxalign, rect, rad);
2704         
2705         widgetbase_draw(&wtb, wcol);
2706
2707 }
2708
2709
2710 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2711 {
2712         uiWidgetBase wtb;
2713         float rad;
2714         
2715         widget_init(&wtb);
2716         
2717         /* half rounded */
2718         rad = 0.2f * U.widget_unit;
2719         round_box_edges(&wtb, roundboxalign, rect, rad);
2720         
2721         /* decoration */
2722         widget_menu_trias(&wtb.tria1, rect);
2723         
2724         widgetbase_draw(&wtb, wcol);
2725         
2726         /* text space, arrows are about 0.6 height of button */
2727         rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
2728 }
2729
2730 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2731 {
2732         uiWidgetBase wtb;
2733         float rad;
2734         
2735         widget_init(&wtb);
2736         
2737         /* half rounded */
2738         rad = 0.2f * U.widget_unit;
2739         round_box_edges(&wtb, roundboxalign, rect, rad);
2740         
2741         /* decoration */
2742         widgetbase_draw(&wtb, wcol);
2743 }
2744
2745 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2746 {
2747         /* silly node link button hacks */
2748         uiWidgetBase wtb;
2749         uiWidgetColors wcol_backup = *wcol;
2750         float rad;
2751         
2752         widget_init(&wtb);
2753         
2754         /* half rounded */
2755         rad = 0.2f * U.widget_unit;
2756         round_box_edges(&wtb, roundboxalign, rect, rad);
2757
2758         wcol->inner[0] += 15;
2759         wcol->inner[1] += 15;
2760         wcol->inner[2] += 15;
2761         wcol->outline[0] += 15;
2762         wcol->outline[1] += 15;
2763         wcol->outline[2] += 15;
2764         
2765         /* decoration */
2766         widgetbase_draw(&wtb, wcol);
2767         *wcol = wcol_backup;
2768 }
2769
2770 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2771 {
2772         if (state & UI_ACTIVE) {
2773                 uiWidgetBase wtb;
2774                 const float rad = 0.2f * U.widget_unit;
2775
2776                 widget_init(&wtb);
2777
2778                 /* half rounded */
2779                 round_box_edges(&wtb, roundboxalign, rect, rad);
2780                 
2781                 widgetbase_draw(&wtb, wcol);
2782         }
2783 }
2784
2785 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2786 {
2787         uiWidgetBase wtb;
2788         
2789         widget_init(&wtb);
2790         
2791         /* not rounded, no outline */
2792         wtb.outline = 0;
2793         round_box_edges(&wtb, 0, rect, 0.0f);
2794         
2795         widgetbase_draw(&wtb, wcol);
2796 }
2797
2798 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2799 {
2800         uiWidgetBase wtb;
2801         float rad;
2802         
2803         widget_init(&wtb);
2804         
2805         /* rounded, but no outline */
2806         wtb.outline = 0;
2807         rad = 0.2f * U.widget_unit;
2808         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2809         
2810         widgetbase_draw(&wtb, wcol);
2811 }
2812
2813 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2814 {
2815         uiWidgetBase wtb;
2816         rcti recttemp = *rect;
2817         float rad;
2818         int delta;
2819         
2820         widget_init(&wtb);
2821         
2822         /* square */
2823         recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
2824         
2825         /* smaller */
2826         delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
2827         recttemp.xmin += delta;
2828         recttemp.ymin += delta;
2829         recttemp.xmax -= delta;
2830         recttemp.ymax -= delta;
2831         
2832         /* half rounded */
2833         rad = 0.2f * U.widget_unit;
2834         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
2835         
2836         /* decoration */
2837         if (state & UI_SELECT) {
2838                 widget_check_trias(&wtb.tria1, &recttemp);
2839         }
2840         
2841         widgetbase_draw(&wtb, wcol);
2842         
2843         /* text space */
2844         rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta;
2845 }
2846
2847
2848 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2849 {
2850         uiWidgetBase wtb;
2851         float rad;
2852         
2853         widget_init(&wtb);
2854         
2855         /* half rounded */
2856         rad = 0.2f * U.widget_unit;
2857         round_box_edges(&wtb, roundboxalign, rect, rad);
2858         
2859         widgetbase_draw(&wtb, wcol);
2860
2861 }
2862
2863 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2864 {
2865         uiWidgetBase wtb;
2866         float rad;
2867         char old_col[3];
2868         
2869         widget_init(&wtb);
2870         
2871         copy_v3_v3_char(old_col, wcol->inner);
2872         
2873         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2874         if (but->col[3]) {
2875                 wcol->inner[0] = but->col[0];
2876                 wcol->inner[1] = but->col[1];
2877                 wcol->inner[2] = but->col[2];
2878         }
2879         
2880         /* half rounded */
2881         rad = 0.2f * U.widget_unit;
2882         round_box_edges(&wtb, roundboxalign, rect, rad);
2883         
2884         widgetbase_draw(&wtb, wcol);
2885                 
2886         copy_v3_v3_char(wcol->inner, old_col);
2887 }
2888
2889 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2890 {
2891         uiWidgetBase wtb;
2892         float rad;
2893         
2894         widget_init(&wtb);
2895         
2896         /* half rounded */
2897         rad = 0.2f * U.widget_unit;
2898         round_box_edges(&wtb, roundboxalign, rect, rad);
2899         
2900         widgetbase_draw(&wtb, wcol);
2901
2902 }
2903
2904 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2905 {
2906         uiWidgetBase wtb;
2907         const float rad = 0.25f * U.widget_unit;
2908         
2909         widget_init(&wtb);
2910         
2911         /* half rounded */
2912         round_box_edges(&wtb, roundboxalign, rect, rad);
2913
2914         widgetbase_draw(&wtb, wcol);
2915 }
2916
2917 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2918 {
2919         uiWidgetBase wtb;
2920         const float rad = 0.25f * U.widget_unit;
2921         unsigned char col[4];
2922         
2923         /* state copy! */
2924         wt->wcol = *(wt->wcol_theme);
2925         
2926         widget_init(&wtb);
2927         
2928         if (but->block->drawextra) {
2929                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2930                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2931                 
2932                 /* make mask to draw over image */
2933                 UI_GetThemeColor3ubv(TH_BACK, col);
2934                 glColor3ubv(col);
2935                 
2936                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
2937                 widgetbase_outline(&wtb);
2938         }
2939         
2940         /* outline */
2941         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2942         wtb.outline = 1;
2943         wtb.inner = 0;
2944         widgetbase_draw(&wtb, &wt->wcol);
2945         
2946 }
2947
2948 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2949 {
2950         bTheme *btheme = UI_GetTheme();
2951         static uiWidgetType wt;
2952         
2953         /* defaults */
2954         wt.wcol_theme = &btheme->tui.wcol_regular;
2955         wt.wcol_state = &btheme->tui.wcol_state;
2956         wt.state = widget_state;
2957         wt.draw = widget_but;
2958         wt.custom = NULL;
2959         wt.text = widget_draw_text_icon;
2960         
2961         switch (type) {
2962                 case UI_WTYPE_REGULAR:
2963                         break;
2964
2965                 case UI_WTYPE_LABEL:
2966                         wt.draw = NULL;
2967                         wt.state = widget_state_label;
2968                         break;
2969                         
2970                 case UI_WTYPE_TOGGLE:
2971                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2972                         break;
2973                         
2974                 case UI_WTYPE_OPTION:
2975                         wt.wcol_theme = &btheme->tui.wcol_option;
2976                         wt.draw = widget_optionbut;
2977                         break;
2978                         
2979                 case UI_WTYPE_RADIO:
2980                         wt.wcol_theme = &btheme->tui.wcol_radio;
2981                         wt.draw = widget_radiobut;
2982                         break;
2983
2984                 case UI_WTYPE_NUMBER:
2985                         wt.wcol_theme = &btheme->tui.wcol_num;
2986                         wt.draw = widget_numbut;
2987                         break;
2988                         
2989                 case UI_WTYPE_SLIDER:
2990                         wt.wcol_theme = &btheme->tui.wcol_numslider;
2991                         wt.custom = widget_numslider;
2992                         wt.state = widget_state_numslider;
2993                         break;
2994                         
2995                 case UI_WTYPE_EXEC:
2996                         wt.wcol_theme = &btheme->tui.wcol_tool;
2997                         wt.draw = widget_roundbut;
2998                         break;
2999
3000                 case UI_WTYPE_TOOLTIP:
3001                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
3002                         wt.draw = widget_menu_back;
3003                         break;
3004                         
3005                         
3006                 /* strings */
3007                 case UI_WTYPE_NAME:
3008                         wt.wcol_theme = &btheme->tui.wcol_text;
3009                         wt.draw = widget_textbut;
3010                         break;
3011                         
3012                 case UI_WTYPE_NAME_LINK:
3013                         break;
3014                         
3015                 case UI_WTYPE_POINTER_LINK:
3016                         break;
3017                         
3018                 case UI_WTYPE_FILENAME:
3019                         break;
3020                         
3021                         
3022                 /* start menus */
3023                 case UI_WTYPE_MENU_RADIO:
3024                         wt.wcol_theme = &btheme->tui.wcol_menu;
3025                         wt.draw = widget_menubut;
3026                         break;
3027
3028                 case UI_WTYPE_MENU_ICON_RADIO:
3029                         wt.wcol_theme = &btheme->tui.wcol_menu;
3030                         wt.draw = widget_menuiconbut;
3031                         break;
3032                         
3033                 case UI_WTYPE_MENU_POINTER_LINK:
3034                         wt.wcol_theme = &btheme->tui.wcol_menu;
3035                         wt.draw = widget_menubut;
3036                         break;
3037
3038                 case UI_WTYPE_MENU_NODE_LINK:
3039                         wt.wcol_theme = &btheme->tui.wcol_menu;
3040                         wt.draw = widget_menunodebut;
3041                         break;
3042                         
3043                 case UI_WTYPE_PULLDOWN:
3044                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
3045                         wt.draw = widget_pulldownbut;
3046                         wt.state = widget_state_pulldown;
3047                         break;
3048                         
3049                 /* in menus */
3050                 case UI_WTYPE_MENU_ITEM:
3051                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
3052                         wt.draw = widget_menu_itembut;
3053                         wt.state = widget_state_menu_item;
3054                         break;
3055                         
3056                 case UI_WTYPE_MENU_BACK:
3057                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
3058                         wt.draw = widget_menu_back;
3059                         break;
3060                         
3061                 /* specials */
3062                 case UI_WTYPE_ICON:
3063                         wt.custom = widget_icon_has_anim;
3064                         break;
3065                         
3066                 case UI_WTYPE_SWATCH:
3067                         wt.custom = widget_swatch;
3068                         break;
3069                         
3070                 case UI_WTYPE_BOX:
3071                         wt.custom = widget_box;
3072                         wt.wcol_theme = &btheme->tui.wcol_box;
3073                         break;
3074                         
3075                 case UI_WTYPE_RGB_PICKER:
3076                         break;
3077                         
3078                 case UI_WTYPE_NORMAL:
3079                         wt.custom = widget_normal;
3080                         break;
3081
3082                 case UI_WTYPE_SCROLL:
3083                         wt.wcol_theme = &btheme->tui.wcol_scroll;
3084                         wt.state = widget_state_nothing;
3085                         wt.custom = widget_scroll;
3086                         break;
3087
3088                 case UI_WTYPE_LISTITEM:
3089                         wt.wcol_theme = &btheme->tui.wcol_list_item;
3090                         wt.draw = widget_list_itembut;
3091                         break;
3092                         
3093                 case UI_WTYPE_PROGRESSBAR:
3094                         wt.wcol_theme = &btheme->tui.wcol_progress;
3095                         wt.custom = widget_progressbar;
3096                         break;
3097         }
3098