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