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