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