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