UI List: ctrl click on names in list can be used for renaming.
[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         if ((state & UI_BUT_LIST_ITEM) && !(state & UI_TEXTINPUT)) {
1660                 /* Override default widget's colors. */
1661                 bTheme *btheme = UI_GetTheme();
1662                 wt->wcol_theme = &btheme->tui.wcol_list_item;
1663         }
1664
1665         wt->wcol = *(wt->wcol_theme);
1666
1667         if (state & UI_SELECT) {
1668                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1669
1670                 if (state & UI_BUT_ANIMATED_KEY)
1671                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1672                 else if (state & UI_BUT_ANIMATED)
1673                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1674                 else if (state & UI_BUT_DRIVEN)
1675                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1676
1677                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1678                 
1679                 if (state & UI_SELECT)
1680                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1681         }
1682         else {
1683                 if (state & UI_BUT_ANIMATED_KEY)
1684                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1685                 else if (state & UI_BUT_ANIMATED)
1686                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1687                 else if (state & UI_BUT_DRIVEN)
1688                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1689
1690                 if (state & UI_ACTIVE) { /* mouse over? */
1691                         wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
1692                         wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
1693                         wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
1694                 }
1695         }
1696
1697         if (state & UI_BUT_REDALERT) {
1698                 char red[4] = {255, 0, 0};
1699                 widget_state_blend(wt->wcol.inner, red, 0.4f);
1700         }
1701         if (state & UI_BUT_NODE_ACTIVE) {
1702                 char blue[4] = {86, 128, 194};
1703                 widget_state_blend(wt->wcol.inner, blue, 0.3f);
1704         }
1705 }
1706
1707 /* sliders use special hack which sets 'item' as inner when drawing filling */
1708 static void widget_state_numslider(uiWidgetType *wt, int state)
1709 {
1710         uiWidgetStateColors *wcol_state = wt->wcol_state;
1711         float blend = wcol_state->blend - 0.2f; /* XXX special tweak to make sure that bar will still be visible */
1712
1713         /* call this for option button */
1714         widget_state(wt, state);
1715         
1716         /* now, set the inner-part so that it reflects state settings too */
1717         /* TODO: maybe we should have separate settings for the blending colors used for this case? */
1718         if (state & UI_SELECT) {
1719                 
1720                 if (state & UI_BUT_ANIMATED_KEY)
1721                         widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
1722                 else if (state & UI_BUT_ANIMATED)
1723                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
1724                 else if (state & UI_BUT_DRIVEN)
1725                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
1726                 
1727                 if (state & UI_SELECT)
1728                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1729         }
1730         else {
1731                 if (state & UI_BUT_ANIMATED_KEY)
1732                         widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
1733                 else if (state & UI_BUT_ANIMATED)
1734                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
1735                 else if (state & UI_BUT_DRIVEN)
1736                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
1737         }
1738 }
1739
1740 /* labels use theme colors for text */
1741 static void widget_state_option_menu(uiWidgetType *wt, int state)
1742 {
1743         bTheme *btheme = UI_GetTheme(); /* XXX */
1744         
1745         /* call this for option button */
1746         widget_state(wt, state);
1747         
1748         /* if not selected we get theme from menu back */
1749         if (state & UI_SELECT)
1750                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text_sel);
1751         else
1752                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text);
1753 }
1754
1755
1756 static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
1757 {
1758         wt->wcol = *(wt->wcol_theme);
1759 }       
1760
1761 /* special case, button that calls pulldown */
1762 static void widget_state_pulldown(uiWidgetType *wt, int state)
1763 {
1764         wt->wcol = *(wt->wcol_theme);
1765         
1766         copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1767         copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
1768
1769         if (state & UI_ACTIVE)
1770                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1771 }
1772
1773 /* special case, menu items */
1774 static void widget_state_menu_item(uiWidgetType *wt, int state)
1775 {
1776         wt->wcol = *(wt->wcol_theme);
1777         
1778         /* active and disabled (not so common) */
1779         if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
1780                 widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
1781                 /* draw the backdrop at low alpha, helps navigating with keys
1782                  * when disabled items are active */
1783                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1784                 wt->wcol.inner[3] = 64;
1785         }
1786         /* regular disabled */
1787         else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1788                 widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
1789         }
1790         /* regular active */
1791         else if (state & UI_ACTIVE) {
1792                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1793                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1794         }
1795 }
1796
1797
1798 /* ************ menu backdrop ************************* */
1799
1800 /* outside of rect, rad to left/bottom/right */
1801 static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
1802 {
1803         bTheme *btheme = UI_GetTheme();
1804         uiWidgetBase wtb;
1805         rcti rect1 = *rect;
1806         float alphastep;
1807         int step, totvert;
1808         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
1809         const float radout = UI_ThemeMenuShadowWidth();
1810         
1811         /* disabled shadow */
1812         if (radout == 0.0f)
1813                 return;
1814         
1815         /* prevent tooltips to not show round shadow */
1816         if (radout > 0.2f * BLI_rcti_size_y(&rect1))
1817                 rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
1818         else
1819                 rect1.ymax -= radout;
1820         
1821         /* inner part */
1822         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1823
1824         /* we draw a number of increasing size alpha quad strips */
1825         alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
1826         
1827         glEnableClientState(GL_VERTEX_ARRAY);
1828
1829         for (step = 1; step <= (int)radout; step++) {
1830                 float expfac = sqrt(step / radout);
1831                 
1832                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1833                 
1834                 glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
1835
1836                 widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
1837
1838                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1839                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
1840         }
1841
1842         glDisableClientState(GL_VERTEX_ARRAY);
1843 }
1844
1845 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1846 {
1847         uiWidgetBase wtb;
1848         int roundboxalign = UI_CNR_ALL;
1849         
1850         widget_init(&wtb);
1851         
1852         /* menu is 2nd level or deeper */
1853         if (flag & UI_BLOCK_POPUP) {
1854                 //rect->ymin -= 4.0;
1855                 //rect->ymax += 4.0;
1856         }
1857         else if (direction == UI_DOWN) {
1858                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1859                 rect->ymin -= 0.1f * U.widget_unit;
1860         }
1861         else if (direction == UI_TOP) {
1862                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1863                 rect->ymax += 0.1f * U.widget_unit;
1864         }
1865         
1866         glEnable(GL_BLEND);
1867         widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
1868         
1869         round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
1870         wtb.emboss = 0;
1871         widgetbase_draw(&wtb, wcol);
1872         
1873         glDisable(GL_BLEND);
1874 }
1875
1876
1877 static void ui_hsv_cursor(float x, float y)
1878 {
1879         
1880         glPushMatrix();
1881         glTranslatef(x, y, 0.0f);
1882         
1883         glColor3f(1.0f, 1.0f, 1.0f);
1884         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
1885         
1886         glEnable(GL_BLEND);
1887         glEnable(GL_LINE_SMOOTH);
1888         glColor3f(0.0f, 0.0f, 0.0f);
1889         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12);
1890         glDisable(GL_BLEND);
1891         glDisable(GL_LINE_SMOOTH);
1892         
1893         glPopMatrix();
1894         
1895 }
1896
1897 void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
1898                                 const float mx, const float my)
1899 {
1900         /* duplication of code... well, simple is better now */
1901         const float centx = BLI_rcti_cent_x_fl(rect);
1902         const float centy = BLI_rcti_cent_y_fl(rect);
1903         const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1904         const float m_delta[2] = {mx - centx, my - centy};
1905         const float dist_squared = len_squared_v2(m_delta);
1906
1907         *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f;
1908         *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
1909 }
1910
1911 /* cursor in hsv circle, in float units -1 to 1, to map on radius */
1912 void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *xpos, float *ypos)
1913 {
1914         /* duplication of code... well, simple is better now */
1915         const float centx = BLI_rcti_cent_x_fl(rect);
1916         const float centy = BLI_rcti_cent_y_fl(rect);
1917         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1918         float ang, radius_t;
1919         
1920         ang = 2.0f * (float)M_PI * hsv[0] + 0.5f * (float)M_PI;
1921         
1922         if (but->flag & UI_BUT_COLOR_CUBIC)
1923                 radius_t = (1.0f - powf(1.0f - hsv[1], 3.0f));
1924         else
1925                 radius_t = hsv[1];
1926         
1927         radius = CLAMPIS(radius_t, 0.0f, 1.0f) * radius;
1928         *xpos = centx + cosf(-ang) * radius;
1929         *ypos = centy + sinf(-ang) * radius;
1930 }
1931
1932 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
1933 {
1934         const int tot = 64;
1935         const float radstep = 2.0f * (float)M_PI / (float)tot;
1936         const float centx = BLI_rcti_cent_x_fl(rect);
1937         const float centy = BLI_rcti_cent_y_fl(rect);
1938         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1939
1940         /* gouraud triangle fan */
1941         const float *hsv_ptr = ui_block_hsv_get(but->block);
1942         float xpos, ypos, ang = 0.0f;
1943         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1944         int a;
1945         int color_profile = but->block->color_profile;
1946         
1947         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1948                 color_profile = FALSE;
1949         
1950         /* color */
1951         ui_get_but_vectorf(but, rgb);
1952
1953         /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
1954         hsvo[0] = hsv[0] = hsv_ptr[0];
1955         hsvo[1] = hsv[1] = hsv_ptr[1];
1956         hsvo[2] = hsv[2] = hsv_ptr[2];
1957
1958         rgb_to_hsv_compat_v(rgb, hsvo);
1959
1960         if (color_profile)
1961                 ui_block_to_display_space_v3(but->block, rgb);
1962
1963         rgb_to_hsv_compat_v(rgb, hsv);
1964         
1965         /* exception: if 'lock' is set
1966          * lock the value of the color wheel to 1.
1967          * Useful for color correction tools where you're only interested in hue. */
1968         if (but->flag & UI_BUT_COLOR_LOCK)
1969                 hsv[2] = 1.f;
1970         
1971         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1972         
1973         glShadeModel(GL_SMOOTH);
1974
1975         glBegin(GL_TRIANGLE_FAN);
1976         glColor3fv(colcent);
1977         glVertex2f(centx, centy);
1978         
1979         for (a = 0; a <= tot; a++, ang += radstep) {
1980                 float si = sin(ang);
1981                 float co = cos(ang);
1982                 
1983                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1984                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1985
1986                 hsv_to_rgb_v(hsv, col);
1987                 glColor3fv(col);
1988                 glVertex2f(centx + co * radius, centy + si * radius);
1989         }
1990         glEnd();
1991         
1992         glShadeModel(GL_FLAT);
1993         
1994         /* fully rounded outline */
1995         glPushMatrix();
1996         glTranslatef(centx, centy, 0.0f);
1997         glEnable(GL_BLEND);
1998         glEnable(GL_LINE_SMOOTH);
1999         glColor3ubv((unsigned char *)wcol->outline);
2000         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
2001         glDisable(GL_BLEND);
2002         glDisable(GL_LINE_SMOOTH);
2003         glPopMatrix();
2004
2005         /* cursor */
2006         ui_hsvcircle_pos_from_vals(but, rect, hsvo, &xpos, &ypos);
2007
2008         ui_hsv_cursor(xpos, ypos);
2009 }
2010
2011 /* ************ custom buttons, old stuff ************** */
2012
2013 /* draws in resolution of 48x4 colors */
2014 void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, const float alpha)
2015 {
2016         /* allows for 4 steps (red->yellow) */
2017         const float color_step = (1.0 / 48.0);
2018         int a;
2019         float h = hsv[0], s = hsv[1], v = hsv[2];
2020         float dx, dy, sx1, sx2, sy;
2021         float col0[4][3];   /* left half, rect bottom to top */
2022         float col1[4][3];   /* right half, rect bottom to top */
2023
2024         /* draw series of gouraud rects */
2025         glShadeModel(GL_SMOOTH);
2026         
2027         switch (type) {
2028                 case UI_GRAD_SV:
2029                         hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2030                         hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
2031                         hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
2032                         hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2033                         break;
2034                 case UI_GRAD_HV:
2035                         hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2036                         hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2037                         hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2038                         hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2039                         break;
2040                 case UI_GRAD_HS:
2041                         hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2042                         hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2043                         hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2044                         hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2045                         break;
2046                 case UI_GRAD_H:
2047                         hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2048                         copy_v3_v3(col1[1], col1[0]);
2049                         copy_v3_v3(col1[2], col1[0]);
2050                         copy_v3_v3(col1[3], col1[0]);
2051                         break;
2052                 case UI_GRAD_S:
2053                         hsv_to_rgb(1.0, 0.0, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2054                         copy_v3_v3(col1[0], col1[1]);
2055                         copy_v3_v3(col1[2], col1[1]);
2056                         copy_v3_v3(col1[3], col1[1]);
2057                         break;
2058                 case UI_GRAD_V:
2059                         hsv_to_rgb(1.0, 1.0, 0.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2060                         copy_v3_v3(col1[0], col1[2]);
2061                         copy_v3_v3(col1[1], col1[2]);
2062                         copy_v3_v3(col1[3], col1[2]);
2063                         break;
2064                 default:
2065                         assert(!"invalid 'type' argument");
2066                         hsv_to_rgb(1.0, 1.0, 1.0,   &col1[2][0], &col1[2][1], &col1[2][2]);
2067                         copy_v3_v3(col1[0], col1[2]);
2068                         copy_v3_v3(col1[1], col1[2]);
2069                         copy_v3_v3(col1[3], col1[2]);
2070                         break;
2071         }
2072         
2073         /* old below */
2074         
2075         for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */
2076                 const float dx_next = dx + color_step;
2077
2078                 /* previous color */
2079                 copy_v3_v3(col0[0], col1[0]);
2080                 copy_v3_v3(col0[1], col1[1]);
2081                 copy_v3_v3(col0[2], col1[2]);
2082                 copy_v3_v3(col0[3], col1[3]);
2083                 
2084                 /* new color */
2085                 switch (type) {
2086                         case UI_GRAD_SV:
2087                                 hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
2088                                 hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
2089                                 hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
2090                                 hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
2091                                 break;
2092                         case UI_GRAD_HV:
2093                                 hsv_to_rgb(dx_next, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2094                                 hsv_to_rgb(dx_next, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
2095                                 hsv_to_rgb(dx_next, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
2096                                 hsv_to_rgb(dx_next, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
2097                                 break;
2098                         case UI_GRAD_HS:
2099                                 hsv_to_rgb(dx_next, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
2100                                 hsv_to_rgb(dx_next, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
2101                                 hsv_to_rgb(dx_next, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
2102                                 hsv_to_rgb(dx_next, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
2103                                 break;
2104                         case UI_GRAD_H:
2105                         {
2106                                 /* annoying but without this the color shifts - could be solved some other way
2107                                  * - campbell */
2108                                 hsv_to_rgb(dx_next, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
2109                                 copy_v3_v3(col1[1], col1[0]);
2110                                 copy_v3_v3(col1[2], col1[0]);
2111                                 copy_v3_v3(col1[3], col1[0]);
2112                                 break;
2113                         }
2114                         case UI_GRAD_S:
2115                                 hsv_to_rgb(h, dx, 1.0,   &col1[1][0], &col1[1][1], &col1[1][2]);
2116                                 copy_v3_v3(col1[0], col1[1]);
2117                                 copy_v3_v3(col1[2], col1[1]);
2118                                 copy_v3_v3(col1[3], col1[1]);
2119                                 break;
2120                         case UI_GRAD_V:
2121                                 hsv_to_rgb(h, 1.0, dx,   &col1[2][0], &col1[2][1], &col1[2][2]);
2122                                 copy_v3_v3(col1[0], col1[2]);
2123                                 copy_v3_v3(col1[1], col1[2]);
2124                                 copy_v3_v3(col1[3], col1[2]);
2125                                 break;
2126                 }
2127                 
2128                 /* rect */
2129                 sx1 = rect->xmin + dx      * BLI_rcti_size_x(rect);
2130                 sx2 = rect->xmin + dx_next * BLI_rcti_size_x(rect);
2131                 sy = rect->ymin;
2132                 dy = (float)BLI_rcti_size_y(rect) / 3.0f;
2133                 
2134                 glBegin(GL_QUADS);
2135                 for (a = 0; a < 3; a++, sy += dy) {
2136                         glColor4f(col0[a][0], col0[a][1], col0[a][2], alpha);
2137                         glVertex2f(sx1, sy);
2138                         
2139                         glColor4f(col1[a][0], col1[a][1], col1[a][2], alpha);
2140                         glVertex2f(sx2, sy);
2141
2142                         glColor4f(col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
2143                         glVertex2f(sx2, sy + dy);
2144                         
2145                         glColor4f(col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
2146                         glVertex2f(sx1, sy + dy);
2147                 }
2148                 glEnd();
2149         }
2150         
2151         glShadeModel(GL_FLAT);
2152         
2153 }
2154
2155 bool ui_hsvcube_use_display_colorspace(uiBut *but)
2156 {
2157         bool color_profile = but->block->color_profile;
2158
2159         if (but->rnaprop) {
2160                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2161                         color_profile = FALSE;
2162         }
2163
2164         /* SV+H gradient does not use display colorspace */
2165         return color_profile && !ELEM((int)but->a1, UI_GRAD_SV, UI_GRAD_H);
2166 }
2167
2168 void ui_hsvcube_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float *xp, float *yp)
2169 {
2170         float x, y;
2171         
2172         switch ((int)but->a1) {
2173                 case UI_GRAD_SV:
2174                         x = hsv[2]; y = hsv[1]; break;
2175                 case UI_GRAD_HV:
2176                         x = hsv[0]; y = hsv[2]; break;
2177                 case UI_GRAD_HS:
2178                         x = hsv[0]; y = hsv[1]; break;
2179                 case UI_GRAD_H:
2180                         x = hsv[0]; y = 0.5; break;
2181                 case UI_GRAD_S:
2182                         x = hsv[1]; y = 0.5; break;
2183                 case UI_GRAD_V:
2184                         x = hsv[2]; y = 0.5; break;
2185                 case UI_GRAD_V_ALT:
2186                         x = 0.5f;
2187                         /* exception only for value strip - use the range set in but->min/max */
2188                         y = (hsv[2] - but->softmin ) / (but->softmax - but->softmin);
2189                         break;
2190         }
2191         
2192         /* cursor */
2193         *xp = rect->xmin + x * BLI_rcti_size_x(rect);
2194         *yp = rect->ymin + y * BLI_rcti_size_y(rect);
2195
2196 }
2197
2198 static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
2199 {
2200         float rgb[3];
2201         float x = 0.0f, y = 0.0f;
2202         float *hsv = ui_block_hsv_get(but->block);
2203         float hsv_n[3];
2204         bool use_display_colorspace = ui_hsvcube_use_display_colorspace(but);
2205         
2206         copy_v3_v3(hsv_n, hsv);
2207         
2208         ui_get_but_vectorf(but, rgb);
2209         
2210         if (use_display_colorspace)
2211                 ui_block_to_display_space_v3(but->block, rgb);
2212         
2213         rgb_to_hsv_compat_v(rgb, hsv_n);
2214         
2215         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2216
2217         ui_hsvcube_pos_from_vals(but, rect, hsv_n, &x, &y);
2218         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2219         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2220         
2221         ui_hsv_cursor(x, y);
2222         
2223         /* outline */
2224         glColor3ub(0,  0,  0);
2225         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2226 }
2227
2228 /* vertical 'value' slider, using new widget code */
2229 static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
2230 {
2231         uiWidgetBase wtb;
2232         const float rad = 0.5f * BLI_rcti_size_x(rect);
2233         float x, y;
2234         float rgb[3], hsv[3], v, range;
2235         int color_profile = but->block->color_profile;
2236         
2237         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2238                 color_profile = FALSE;
2239
2240         ui_get_but_vectorf(but, rgb);
2241
2242         if (color_profile)
2243                 ui_block_to_display_space_v3(but->block, rgb);
2244
2245         rgb_to_hsv_v(rgb, hsv);
2246         v = hsv[2];
2247         
2248         /* map v from property range to [0,1] */
2249         range = but->softmax - but->softmin;
2250         v = (v - but->softmin) / range;
2251         
2252         widget_init(&wtb);
2253         
2254         /* fully rounded */
2255         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2256         
2257         /* setup temp colors */
2258         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2259         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2260         wcol_tmp.shadetop = 127;
2261         wcol_tmp.shadedown = -128;
2262         wcol_tmp.shaded = 1;
2263         
2264         widgetbase_draw(&wtb, &wcol_tmp);
2265
2266         /* cursor */
2267         x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
2268         y = rect->ymin + v    * BLI_rcti_size_y(rect);
2269         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2270         
2271         ui_hsv_cursor(x, y);
2272         
2273 }
2274
2275
2276 /* ************ separator, for menus etc ***************** */
2277 static void ui_draw_separator(const rcti *rect,  uiWidgetColors *wcol)
2278 {
2279         int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2280         unsigned char col[4];
2281         
2282         col[0] = wcol->text[0];
2283         col[1] = wcol->text[1];
2284         col[2] = wcol->text[2];
2285         col[3] = 7;
2286         
2287         glEnable(GL_BLEND);
2288         glColor4ubv(col);
2289         sdrawline(rect->xmin, y, rect->xmax, y);
2290         glDisable(GL_BLEND);
2291 }
2292
2293 /* ************ button callbacks, draw ***************** */
2294 static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
2295 {
2296         uiWidgetBase wtb;
2297         const float rad = 0.5f * BLI_rcti_size_y(rect);
2298         float textofs = rad * 0.75f;
2299
2300         if (state & UI_SELECT)
2301                 SWAP(short, wcol->shadetop, wcol->shadedown);
2302         
2303         widget_init(&wtb);
2304         
2305         if (!emboss) {
2306                 round_box_edges(&wtb, roundboxalign, rect, rad);
2307         }
2308
2309         /* decoration */
2310         if (!(state & UI_TEXTINPUT)) {
2311                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2312                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2313         }
2314
2315         widgetbase_draw(&wtb, wcol);
2316         
2317         /* text space */
2318         rect->xmin += textofs;
2319         rect->xmax -= textofs;
2320 }
2321
2322 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2323 {
2324         widget_numbut_draw(wcol, rect, state, roundboxalign, false);
2325 }
2326
2327 /*
2328  * Draw number buttons still with triangles when field is not embossed
2329 */
2330 static void widget_numbut_embossn(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2331 {
2332         widget_numbut_draw(wcol, rect, state, roundboxalign, true);
2333 }
2334
2335 int ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
2336 {
2337         float dist, vec[4][2];
2338
2339         vec[0][0] = rect->xmin;
2340         vec[0][1] = rect->ymin;
2341         vec[3][0] = rect->xmax;
2342         vec[3][1] = rect->ymax;
2343         
2344         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2345         
2346         vec[1][0] = vec[0][0] + dist;
2347         vec[1][1] = vec[0][1];
2348         
2349         vec[2][0] = vec[3][0] - dist;
2350         vec[2][1] = vec[3][1];
2351         
2352         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2353         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);
2354         
2355         return 1;
2356 }
2357
2358 #define LINK_RESOL  24
2359 void ui_draw_link_bezier(const rcti *rect)
2360 {
2361         float coord_array[LINK_RESOL + 1][2];
2362         
2363         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2364                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2365                 // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
2366
2367                 glEnable(GL_BLEND);
2368                 glEnable(GL_LINE_SMOOTH);
2369
2370                 glEnableClientState(GL_VERTEX_ARRAY);
2371                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2372                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1);
2373                 glDisableClientState(GL_VERTEX_ARRAY);
2374
2375                 glDisable(GL_BLEND);
2376                 glDisable(GL_LINE_SMOOTH);
2377
2378         }
2379 }
2380
2381 /* function in use for buttons and for view2d sliders */
2382 void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
2383 {
2384         uiWidgetBase wtb;
2385         int horizontal;
2386         float rad;
2387         bool outline = false;
2388
2389         widget_init(&wtb);
2390
2391         /* determine horizontal/vertical */
2392         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2393
2394         if (horizontal)
2395                 rad = 0.5f * BLI_rcti_size_y(rect);
2396         else
2397                 rad = 0.5f * BLI_rcti_size_x(rect);
2398         
2399         wtb.shadedir = (horizontal) ? 1 : 0;
2400         
2401         /* draw back part, colors swapped and shading inverted */
2402         if (horizontal)
2403                 SWAP(short, wcol->shadetop, wcol->shadedown);
2404         
2405         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2406         widgetbase_draw(&wtb, wcol);
2407         
2408         /* slider */
2409         if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2410                 /* pass */
2411         }
2412         else {
2413                 SWAP(short, wcol->shadetop, wcol->shadedown);
2414                 
2415                 copy_v4_v4_char(wcol->inner, wcol->item);
2416                 
2417                 if (wcol->shadetop > wcol->shadedown)
2418                         wcol->shadetop += 20;   /* XXX violates themes... */
2419                 else wcol->shadedown += 20;
2420                 
2421                 if (state & UI_SCROLL_PRESSED) {
2422                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2423                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2424                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2425                 }
2426
2427                 /* draw */
2428                 wtb.emboss = 0; /* only emboss once */
2429                 
2430                 /* exception for progress bar */
2431                 if (state & UI_SCROLL_NO_OUTLINE) {
2432                         SWAP(bool, outline, wtb.outline);
2433                 }
2434                 
2435                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2436                 
2437                 if (state & UI_SCROLL_ARROWS) {
2438                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2439                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2440                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2441                         wcol->item[3] = 255;
2442                         
2443                         if (horizontal) {
2444                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2445                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2446                         }
2447                         else {
2448                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2449                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2450                         }
2451                 }
2452                 widgetbase_draw(&wtb, wcol);
2453                 
2454                 if (state & UI_SCROLL_NO_OUTLINE) {
2455                         SWAP(bool, outline, wtb.outline);
2456                 }
2457         }
2458 }
2459
2460 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2461 {
2462         rcti rect1;
2463         double value;
2464         float fac, size, min;
2465         int horizontal;
2466
2467         /* calculate slider part */
2468         value = ui_get_but_val(but);
2469
2470         size = (but->softmax + but->a1 - but->softmin);
2471         size = max_ff(size, 2.0f);
2472         
2473         /* position */
2474         rect1 = *rect;
2475
2476         /* determine horizontal/vertical */
2477         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2478         
2479         if (horizontal) {
2480                 fac = BLI_rcti_size_x(rect) / size;
2481                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2482                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2483
2484                 /* ensure minimium size */
2485                 min = BLI_rcti_size_y(rect);
2486
2487                 if (BLI_rcti_size_x(&rect1) < min) {
2488                         rect1.xmax = rect1.xmin + min;
2489
2490                         if (rect1.xmax > rect->xmax) {
2491                                 rect1.xmax = rect->xmax;
2492                                 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
2493                         }
2494                 }
2495         }
2496         else {
2497                 fac = BLI_rcti_size_y(rect) / size;
2498                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2499                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2500
2501                 /* ensure minimium size */
2502                 min = BLI_rcti_size_x(rect);
2503
2504                 if (BLI_rcti_size_y(&rect1) < min) {
2505                         rect1.ymax = rect1.ymin + min;
2506
2507                         if (rect1.ymax > rect->ymax) {
2508                                 rect1.ymax = rect->ymax;
2509                                 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
2510                         }
2511                 }
2512         }
2513
2514         if (state & UI_SELECT)
2515                 state = UI_SCROLL_PRESSED;
2516         else
2517                 state = 0;
2518         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2519 }
2520
2521 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2522 {
2523         rcti rect_prog = *rect, rect_bar = *rect;
2524         float value = but->a1;
2525         float w, min;
2526         
2527         /* make the progress bar a proportion of the original height */
2528         /* hardcoded 4px high for now */
2529         rect_prog.ymax = rect_prog.ymin + 4 * UI_DPI_FAC;
2530         rect_bar.ymax = rect_bar.ymin + 4 * UI_DPI_FAC;
2531         
2532         w = value * BLI_rcti_size_x(&rect_prog);
2533         
2534         /* ensure minimium size */
2535         min = BLI_rcti_size_y(&rect_prog);
2536         w = MAX2(w, min);
2537         
2538         rect_bar.xmax = rect_bar.xmin + w;
2539                 
2540         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2541         
2542         /* raise text a bit */
2543         rect->ymin += 6 * UI_DPI_FAC;
2544         rect->xmin -= 6 * UI_DPI_FAC;
2545 }
2546
2547 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2548 {
2549         
2550         if (but->flag & UI_SELECT) {
2551                 rcti rectlink;
2552                 
2553                 UI_ThemeColor(TH_TEXT_HI);
2554                 
2555                 rectlink.xmin = BLI_rcti_cent_x(rect);
2556                 rectlink.ymin = BLI_rcti_cent_y(rect);
2557                 rectlink.xmax = but->linkto[0];
2558                 rectlink.ymax = but->linkto[1];
2559                 
2560                 ui_draw_link_bezier(&rectlink);
2561         }
2562 }
2563
2564 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2565 {
2566         uiWidgetBase wtb, wtb1;
2567         rcti rect1;
2568         double value;
2569         float offs, toffs, fac;
2570         char outline[3];
2571
2572         widget_init(&wtb);
2573         widget_init(&wtb1);
2574         
2575         /* backdrop first */
2576         
2577         /* fully rounded */
2578         offs = 0.5f * BLI_rcti_size_y(rect);
2579         toffs = offs * 0.75f;
2580         round_box_edges(&wtb, roundboxalign, rect, offs);
2581
2582         wtb.outline = 0;
2583         widgetbase_draw(&wtb, wcol);
2584         
2585         /* draw left/right parts only when not in text editing */
2586         if (!(state & UI_TEXTINPUT)) {
2587                 
2588                 /* slider part */
2589                 copy_v3_v3_char(outline, wcol->outline);
2590                 copy_v3_v3_char(wcol->outline, wcol->item);
2591                 copy_v3_v3_char(wcol->inner, wcol->item);
2592
2593                 if (!(state & UI_SELECT))
2594                         SWAP(short, wcol->shadetop, wcol->shadedown);
2595                 
2596                 rect1 = *rect;
2597                 
2598                 value = ui_get_but_val(but);
2599                 fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
2600                 
2601                 /* left part of slider, always rounded */
2602                 rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
2603                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2604                 wtb1.outline = 0;
2605                 widgetbase_draw(&wtb1, wcol);
2606                 
2607                 /* right part of slider, interpolate roundness */
2608                 rect1.xmax = rect1.xmin + fac + offs;
2609                 rect1.xmin +=  floor(offs - U.pixelsize);
2610                 
2611                 if (rect1.xmax + offs > rect->xmax)
2612                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2613                 else 
2614                         offs = 0.0f;
2615                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2616                 
2617                 widgetbase_draw(&wtb1, wcol);
2618                 copy_v3_v3_char(wcol->outline, outline);
2619                 
2620                 if (!(state & UI_SELECT))
2621                         SWAP(short, wcol->shadetop, wcol->shadedown);
2622         }
2623         
2624         /* outline */
2625         wtb.outline = 1;
2626         wtb.inner = 0;
2627         widgetbase_draw(&wtb, wcol);
2628         
2629         /* text space */
2630         rect->xmin += toffs;
2631         rect->xmax -= toffs;
2632 }
2633
2634 /* I think 3 is sufficient border to indicate keyed status */
2635 #define SWATCH_KEYED_BORDER 3
2636
2637 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2638 {
2639         uiWidgetBase wtb;
2640         float rad, col[4];
2641         int color_profile = but->block->color_profile;
2642         
2643         col[3] = 1.0f;
2644
2645         if (but->rnaprop) {
2646                 BLI_assert(but->rnaindex == -1);
2647
2648                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2649                         color_profile = FALSE;
2650
2651                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2652                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2653                 }
2654         }
2655         
2656         widget_init(&wtb);
2657         
2658         /* half rounded */
2659         rad = 0.25f * U.widget_unit;
2660         round_box_edges(&wtb, roundboxalign, rect, rad);
2661                 
2662         ui_get_but_vectorf(but, col);
2663
2664         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2665                 /* draw based on state - color for keyed etc */
2666                 widgetbase_draw(&wtb, wcol);
2667
2668                 /* inset to draw swatch color */
2669                 rect->xmin += SWATCH_KEYED_BORDER;
2670                 rect->xmax -= SWATCH_KEYED_BORDER;
2671                 rect->ymin += SWATCH_KEYED_BORDER;
2672                 rect->ymax -= SWATCH_KEYED_BORDER;
2673                 
2674                 round_box_edges(&wtb, roundboxalign, rect, rad);
2675         }
2676         
2677         if (color_profile)
2678                 ui_block_to_display_space_v3(but->block, col);
2679         
2680         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2681
2682         wcol->shaded = 0;
2683         wcol->alpha_check = (wcol->inner[3] < 255);
2684
2685         widgetbase_draw(&wtb, wcol);
2686         
2687 }
2688
2689 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2690 {
2691         ui_draw_but_NORMAL(but, wcol, rect);
2692 }
2693
2694 static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2695 {
2696         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2697                 uiWidgetBase wtb;
2698                 float rad;
2699                 
2700                 widget_init(&wtb);
2701                 wtb.outline = 0;
2702                 
2703                 /* rounded */
2704                 rad = 0.5f * BLI_rcti_size_y(rect);
2705                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2706                 widgetbase_draw(&wtb, wcol);
2707         }
2708         else if (but->type == NUM) {
2709                 /* Draw number buttons still with left/right 
2710                  * triangles when field is not embossed */
2711                 widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
2712         }
2713 }
2714
2715
2716 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2717 {
2718         uiWidgetBase wtb;
2719         float rad;
2720         
2721         if (state & UI_SELECT)
2722                 SWAP(short, wcol->shadetop, wcol->shadedown);
2723         
2724         widget_init(&wtb);
2725         
2726         /* half rounded */
2727         rad = 0.2f * U.widget_unit;
2728         round_box_edges(&wtb, roundboxalign, rect, rad);
2729         
2730         widgetbase_draw(&wtb, wcol);
2731
2732 }
2733
2734
2735 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2736 {
2737         uiWidgetBase wtb;
2738         float rad;
2739         
2740         widget_init(&wtb);
2741         
2742         /* half rounded */
2743         rad = 0.2f * U.widget_unit;
2744         round_box_edges(&wtb, roundboxalign, rect, rad);
2745         
2746         /* decoration */
2747         widget_menu_trias(&wtb.tria1, rect);
2748         
2749         widgetbase_draw(&wtb, wcol);
2750         
2751         /* text space, arrows are about 0.6 height of button */
2752         rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
2753 }
2754
2755 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2756 {
2757         uiWidgetBase wtb;
2758         float rad;
2759         
2760         widget_init(&wtb);
2761         
2762         /* half rounded */
2763         rad = 0.2f * U.widget_unit;
2764         round_box_edges(&wtb, roundboxalign, rect, rad);
2765         
2766         /* decoration */
2767         widgetbase_draw(&wtb, wcol);
2768 }
2769
2770 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2771 {
2772         /* silly node link button hacks */
2773         uiWidgetBase wtb;
2774         uiWidgetColors wcol_backup = *wcol;
2775         float rad;
2776         
2777         widget_init(&wtb);
2778         
2779         /* half rounded */
2780         rad = 0.2f * U.widget_unit;
2781         round_box_edges(&wtb, roundboxalign, rect, rad);
2782
2783         wcol->inner[0] += 15;
2784         wcol->inner[1] += 15;
2785         wcol->inner[2] += 15;
2786         wcol->outline[0] += 15;
2787         wcol->outline[1] += 15;
2788         wcol->outline[2] += 15;
2789         
2790         /* decoration */
2791         widgetbase_draw(&wtb, wcol);
2792         *wcol = wcol_backup;
2793 }
2794
2795 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2796 {
2797         if (state & UI_ACTIVE) {
2798                 uiWidgetBase wtb;
2799                 const float rad = 0.2f * U.widget_unit;
2800
2801                 widget_init(&wtb);
2802
2803                 /* half rounded */
2804                 round_box_edges(&wtb, roundboxalign, rect, rad);
2805                 
2806                 widgetbase_draw(&wtb, wcol);
2807         }
2808 }
2809
2810 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2811 {
2812         uiWidgetBase wtb;
2813         
2814         widget_init(&wtb);
2815         
2816         /* not rounded, no outline */
2817         wtb.outline = 0;
2818         round_box_edges(&wtb, 0, rect, 0.0f);
2819         
2820         widgetbase_draw(&wtb, wcol);
2821 }
2822
2823 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2824 {
2825         uiWidgetBase wtb;
2826         float rad;
2827         
2828         widget_init(&wtb);
2829         
2830         /* rounded, but no outline */
2831         wtb.outline = 0;
2832         rad = 0.2f * U.widget_unit;
2833         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2834         
2835         widgetbase_draw(&wtb, wcol);
2836 }
2837
2838 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2839 {
2840         uiWidgetBase wtb;
2841         rcti recttemp = *rect;
2842         float rad;
2843         int delta;
2844         
2845         widget_init(&wtb);
2846         
2847         /* square */
2848         recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
2849         
2850         /* smaller */
2851         delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
2852         recttemp.xmin += delta;
2853         recttemp.ymin += delta;
2854         recttemp.xmax -= delta;
2855         recttemp.ymax -= delta;
2856         
2857         /* half rounded */
2858         rad = 0.2f * U.widget_unit;
2859         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
2860         
2861         /* decoration */
2862         if (state & UI_SELECT) {
2863                 widget_check_trias(&wtb.tria1, &recttemp);
2864         }
2865         
2866         widgetbase_draw(&wtb, wcol);
2867         
2868         /* text space */
2869         rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta;
2870 }
2871
2872 /* labels use Editor theme colors for text */
2873 static void widget_state_label(uiWidgetType *wt, int state)
2874 {
2875         if (state & UI_BUT_LIST_ITEM) {
2876                 /* Override default label theme's colors. */
2877                 bTheme *btheme = UI_GetTheme();
2878                 wt->wcol_theme = &btheme->tui.wcol_list_item;
2879                 /* call this for option button */
2880                 widget_state(wt, state);
2881         }
2882         else {
2883                 /* call this for option button */
2884                 widget_state(wt, state);
2885                 if (state & UI_SELECT)
2886                         UI_GetThemeColor3ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
2887                 else
2888                         UI_GetThemeColor3ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
2889         }
2890 }
2891
2892 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2893 {
2894         uiWidgetBase wtb;
2895         float rad;
2896         
2897         widget_init(&wtb);
2898         
2899         /* half rounded */
2900         rad = 0.2f * U.widget_unit;
2901         round_box_edges(&wtb, roundboxalign, rect, rad);
2902         
2903         widgetbase_draw(&wtb, wcol);
2904
2905 }
2906
2907 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2908 {
2909         uiWidgetBase wtb;
2910         float rad;
2911         char old_col[3];
2912         
2913         widget_init(&wtb);
2914         
2915         copy_v3_v3_char(old_col, wcol->inner);
2916         
2917         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2918         if (but->col[3]) {
2919                 wcol->inner[0] = but->col[0];
2920                 wcol->inner[1] = but->col[1];
2921                 wcol->inner[2] = but->col[2];
2922         }
2923         
2924         /* half rounded */
2925         rad = 0.2f * U.widget_unit;
2926         round_box_edges(&wtb, roundboxalign, rect, rad);
2927         
2928         widgetbase_draw(&wtb, wcol);
2929                 
2930         copy_v3_v3_char(wcol->inner, old_col);
2931 }
2932
2933 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2934 {
2935         uiWidgetBase wtb;
2936         float rad;
2937         
2938         widget_init(&wtb);
2939         
2940         /* half rounded */
2941         rad = 0.2f * U.widget_unit;
2942         round_box_edges(&wtb, roundboxalign, rect, rad);
2943         
2944         widgetbase_draw(&wtb, wcol);
2945
2946 }
2947
2948 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2949 {
2950         uiWidgetBase wtb;
2951         const float rad = 0.25f * U.widget_unit;
2952         
2953         widget_init(&wtb);
2954         
2955         /* half rounded */
2956         round_box_edges(&wtb, roundboxalign, rect, rad);
2957
2958         widgetbase_draw(&wtb, wcol);
2959 }
2960
2961 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2962 {
2963         uiWidgetBase wtb;
2964         const float rad = 0.25f * U.widget_unit;
2965         unsigned char col[4];
2966         
2967         /* state copy! */
2968         wt->wcol = *(wt->wcol_theme);
2969         
2970         widget_init(&wtb);
2971         
2972         if (but->block->drawextra) {
2973                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2974                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2975                 
2976                 /* make mask to draw over image */
2977                 UI_GetThemeColor3ubv(TH_BACK, col);
2978                 glColor3ubv(col);
2979                 
2980                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
2981                 widgetbase_outline(&wtb);
2982         }
2983         
2984         /* outline */
2985         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2986         wtb.outline = 1;
2987         wtb.inner = 0;
2988         widgetbase_draw(&wtb, &wt->wcol);
2989         
2990 }
2991
2992 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2993 {
2994         bTheme *btheme = UI_GetTheme();
2995         static uiWidgetType wt;
2996         
2997         /* defaults */
2998         wt.wcol_theme = &btheme->tui.wcol_regular;
2999         wt.wcol_state = &btheme->tui.wcol_state;
3000         wt.state = widget_state;
3001         wt.draw = widget_but;
3002         wt.custom = NULL;
3003         wt.text = widget_draw_text_icon;
3004         
3005         switch (type) {
3006                 case UI_WTYPE_REGULAR:
3007                         break;
3008
3009                 case UI_WTYPE_LABEL:
3010                         wt.draw = NULL;
3011                         wt.state = widget_state_label;
3012                         break;
3013                         
3014                 case UI_WTYPE_TOGGLE:
3015                         wt.wcol_theme = &btheme->tui.wcol_toggle;
3016                         break;
3017                         
3018                 case UI_WTYPE_OPTION:
3019                         wt.wcol_theme = &btheme->tui.wcol_option;
3020                         wt.draw = widget_optionbut;
3021                         break;
3022                         
3023                 case UI_WTYPE_RADIO:
3024                         wt.wcol_theme = &btheme->tui.wcol_radio;
3025                         wt.draw = widget_radiobut;
3026                         break;
3027
3028                 case UI_WTYPE_NUMBER:
3029                         wt.wcol_theme = &btheme->tui.wcol_num;
3030                         wt.draw = widget_numbut;
3031                         break;
3032                         
3033                 case UI_WTYPE_SLIDER:
3034                         wt.wcol_theme = &btheme->tui.wcol_numslider;
3035                         wt.custom = widget_numslider;
3036                         wt.state = widget_state_numslider;
3037                         break;
3038                         
3039                 case UI_WTYPE_EXEC:
3040                         wt.wcol_theme = &btheme->tui.wcol_tool;
3041                         wt.draw = widget_roundbut;
3042                         break;
3043
3044                 case UI_WTYPE_TOOLTIP:
3045                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
3046                         wt.draw = widget_menu_back;
3047                         break;
3048                         
3049                         
3050                 /* strings */
3051                 case UI_WTYPE_NAME:
3052                         wt.wcol_theme = &btheme->tui.wcol_text;
3053                         wt.draw = widget_textbut;
3054                         break;
3055                         
3056                 case UI_WTYPE_NAME_LINK:
3057                         break;
3058                         
3059                 case UI_WTYPE_POINTER_LINK:
3060                         break;
3061                         
3062                 case UI_WTYPE_FILENAME:
3063                         break;
3064                         
3065                         
3066                 /* start menus */
3067                 case UI_WTYPE_MENU_RADIO:
3068                         wt.wcol_theme = &btheme->tui.wcol_menu;
3069                         wt.draw = widget_menubut;
3070                         break;
3071
3072                 case UI_WTYPE_MENU_ICON_RADIO:
3073                         wt.wcol_theme = &btheme->tui.wcol_menu;
3074                         wt.draw = widget_menuiconbut;
3075                         break;
3076                         
3077                 case UI_WTYPE_MENU_POINTER_LINK:
3078                         wt.wcol_theme = &btheme->tui.wcol_menu;
3079                         wt.draw = widget_menubut;
3080                         break;
3081
3082                 case UI_WTYPE_MENU_NODE_LINK:
3083                         wt.wcol_theme = &btheme->tui.wcol_menu;
3084                         wt.draw = widget_menunodebut;
3085                         break;
3086                         
3087                 case UI_WTYPE_PULLDOWN:
3088                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
3089                         wt.draw = widget_pulldownbut;
3090                         wt.state = widget_state_pulldown;
3091                         break;
3092                         
3093                 /* in menus */
3094                 case UI_WTYPE_MENU_ITEM:
3095                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
3096                         wt.draw = widget_menu_itembut;
3097                         wt.state = widget_state_menu_item;
3098                         break;
3099                         
3100                 case UI_WTYPE_MENU_BACK:
3101                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
3102                         wt.draw = widget_menu_back;
3103                         break;
3104