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