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