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