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