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