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