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