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