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