4abd6224f0874146bab89356957805bb190219c7
[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[32][2];
84         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 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 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 float num_tria_vert[3][2] = {
144         {-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}
145 };
146
147 static unsigned int num_tria_face[1][3] = {
148         {0, 1, 2}
149 };
150
151 static 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 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 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 unsigned int menu_tria_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
172
173 static 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 unsigned int check_tria_face[4][3] = {
179         {3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
180 };
181
182 GLubyte 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                                                UCHAR_MAX / 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->type == BUT_TOGDUAL) {
895                                 if (but->drawstr[0]) {
896                                         xs = rect->xmin - ofs;
897                                 }
898                                 else {
899                                         xs = (rect->xmin + rect->xmax - height) / 2.0f;
900                                 }
901                         }
902                         else if (but->block->flag & UI_BLOCK_LOOP) {
903                                 if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK))
904                                         xs = rect->xmin + 4.0f * ofs;
905                                 else
906                                         xs = rect->xmin + ofs;
907                         }
908                         else if ((but->type == ICONROW) || (but->type == ICONTEXTROW)) {
909                                 xs = rect->xmin + 3.0f * ofs;
910                         }
911                         else {
912                                 xs = rect->xmin + 4.0f * ofs;
913                         }
914                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
915                 }
916                 else {
917                         xs = (rect->xmin + rect->xmax - height) / 2.0f;
918                         ys = (rect->ymin + rect->ymax - height) / 2.0f;
919                 }
920
921                 /* force positions to integers, for zoom levels near 1. draws icons crisp. */
922                 if (aspect > 0.95f && aspect < 1.05f) {
923                         xs = (int)(xs + 0.1f);
924                         ys = (int)(ys + 0.1f);
925                 }
926                 
927                 /* to indicate draggable */
928                 if (but->dragpoin && (but->flag & UI_ACTIVE)) {
929                         float rgb[3] = {1.25f, 1.25f, 1.25f};
930                         UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
931                 }
932                 else
933                         UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
934         }
935
936         if (ui_but_draw_menu_icon(but)) {
937                 xs = rect->xmax - UI_DPI_ICON_SIZE - aspect;
938                 ys = (rect->ymin + rect->ymax - height) / 2.0f;
939                 
940                 UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
941         }
942         
943         glDisable(GL_BLEND);
944 }
945
946 static void ui_text_clip_give_prev_off(uiBut *but)
947 {
948         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + but->ofs);
949         int bytes = but->drawstr + but->ofs - prev_utf8;
950
951         but->ofs -= bytes;
952 }
953
954 static void ui_text_clip_give_next_off(uiBut *but)
955 {
956         char *next_utf8 = BLI_str_find_next_char_utf8(but->drawstr + but->ofs, NULL);
957         int bytes = next_utf8 - (but->drawstr + but->ofs);
958
959         but->ofs += bytes;
960 }
961
962 /**
963  * Cut off the start of the text to fit into the width of \a rect
964  *
965  * \note Sets but->ofs to make sure text is correctly visible.
966  * \note Clips right in some cases, this function could be cleaned up.
967  */
968 static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
969 {
970         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
971         int okwidth = BLI_rcti_size_x(rect) - border;
972         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
973
974         /* need to set this first */
975         uiStyleFontSet(fstyle);
976         
977         if (fstyle->kerning == 1) /* for BLF_width */
978                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
979
980         but->ofs = 0;
981         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
982
983         while (but->strwidth > okwidth) {
984                 ui_text_clip_give_next_off(but);
985                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
986                 if (but->strwidth < 10) break;
987         }
988
989         if (fstyle->kerning == 1) {
990                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
991         }
992 }
993
994 /**
995  * Cut off the text, taking into account the cursor location (text display while editing).
996  */
997 static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
998 {
999         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
1000         int okwidth = BLI_rcti_size_x(rect) - border;
1001         if (but->flag & UI_HAS_ICON) okwidth -= UI_DPI_ICON_SIZE;
1002
1003         BLI_assert(but->editstr && but->pos >= 0);
1004
1005         /* need to set this first */
1006         uiStyleFontSet(fstyle);
1007
1008         if (fstyle->kerning == 1) /* for BLF_width */
1009                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1010
1011         /* define ofs dynamically */
1012         if (but->ofs > but->pos)
1013                 but->ofs = but->pos;
1014
1015         if (BLF_width(fstyle->uifont_id, but->drawstr) <= okwidth)
1016                 but->ofs = 0;
1017
1018         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1019
1020         while (but->strwidth > okwidth) {
1021                 float width;
1022                 char buf[UI_MAX_DRAW_STR];
1023
1024                 /* copy draw string */
1025                 BLI_strncpy_utf8(buf, but->drawstr, sizeof(buf));
1026                 /* string position of cursor */
1027                 buf[but->pos] = 0;
1028                 width = BLF_width(fstyle->uifont_id, buf + but->ofs);
1029
1030                 /* if cursor is at 20 pixels of right side button we clip left */
1031                 if (width > okwidth - 20) {
1032                         ui_text_clip_give_next_off(but);
1033                 }
1034                 else {
1035                         int len, bytes;
1036                         /* shift string to the left */
1037                         if (width < 20 && but->ofs > 0)
1038                                 ui_text_clip_give_prev_off(but);
1039                         len = strlen(but->drawstr);
1040                         bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len));
1041                         if (bytes < 0)
1042                                 bytes = 1;
1043                         but->drawstr[len - bytes] = 0;
1044                 }
1045
1046                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1047
1048                 if (but->strwidth < 10) break;
1049         }
1050
1051         if (fstyle->kerning == 1) {
1052                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1053         }
1054 }
1055
1056 /**
1057  * Cut off the end of text to fit into the width of \a rect.
1058  *
1059  * \note deals with ': ' especially for number buttons
1060  */
1061 static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
1062 {
1063         int border = (but->flag & UI_BUT_ALIGN_RIGHT) ? 8 : 10;
1064         int okwidth = BLI_rcti_size_x(rect) - border;
1065         char *cpoin = NULL;
1066         int drawstr_len = strlen(but->drawstr);
1067         char *cpend = but->drawstr + drawstr_len;
1068         
1069         /* need to set this first */
1070         uiStyleFontSet(fstyle);
1071         
1072         if (fstyle->kerning == 1) /* for BLF_width */
1073                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1074         
1075         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr);
1076         but->ofs = 0;
1077         
1078
1079         /* First shorten num-buttopns eg,
1080          *   Translucency: 0.000
1081          * becomes
1082          *   Trans: 0.000
1083          */
1084
1085         /* find the space after ':' separator */
1086         cpoin = strrchr(but->drawstr, ':');
1087         
1088         if (cpoin && (cpoin < cpend - 2)) {
1089                 char *cp2 = cpoin;
1090                 
1091                 /* chop off the leading text, starting from the right */
1092                 while (but->strwidth > okwidth && cp2 > but->drawstr) {
1093                         char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, cp2);
1094                         int bytes = cp2 - prev_utf8;
1095
1096                         /* shift the text after and including cp2 back by 1 char, +1 to include null terminator */
1097                         memmove(cp2 - bytes, cp2, drawstr_len + 1);
1098                         cp2 -= bytes;
1099
1100                         drawstr_len -= bytes;
1101                         // BLI_assert(strlen(but->drawstr) == drawstr_len);
1102                         
1103                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1104                         if (but->strwidth < 10) break;
1105                 }
1106         
1107         
1108                 /* after the leading text is gone, chop off the : and following space, with ofs */
1109                 while ((but->strwidth > okwidth) && (but->ofs < 2)) {
1110                         ui_text_clip_give_next_off(but);
1111                         but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1112                         if (but->strwidth < 10) break;
1113                 }
1114                 
1115         }
1116
1117
1118         /* Now just remove trailing chars */
1119         /* once the label's gone, chop off the least significant digits */
1120         while (but->strwidth > okwidth) {
1121                 int bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + drawstr_len));
1122                 if (bytes < 0)
1123                         bytes = 1;
1124
1125                 drawstr_len -= bytes;
1126                 but->drawstr[drawstr_len] = 0;
1127                 // BLI_assert(strlen(but->drawstr) == drawstr_len);
1128                 
1129                 but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1130                 if (but->strwidth < 10) break;
1131         }
1132         
1133         if (fstyle->kerning == 1)
1134                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1135 }
1136
1137
1138 static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1139 {
1140         //int transopts;  // UNUSED
1141         char *cpoin = NULL;
1142         
1143         /* for underline drawing */
1144         float font_xofs, font_yofs;
1145
1146         uiStyleFontSet(fstyle);
1147         
1148         if (but->editstr || (but->flag & UI_TEXT_LEFT))
1149                 fstyle->align = UI_STYLE_TEXT_LEFT;
1150         else
1151                 fstyle->align = UI_STYLE_TEXT_CENTER;
1152         
1153         if (fstyle->kerning == 1) /* for BLF_width */
1154                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1155         
1156         /* text button selection and cursor */
1157         if (but->editstr && but->pos != -1) {
1158                 short t = 0, pos = 0, ch;
1159                 short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
1160
1161                 if ((but->selend - but->selsta) > 0) {
1162                         /* text button selection */
1163                         selsta_tmp = but->selsta;
1164                         selend_tmp = but->selend;
1165                         
1166                         if (but->drawstr[0] != 0) {
1167
1168                                 if (but->selsta >= but->ofs) {
1169                                         ch = but->drawstr[selsta_tmp];
1170                                         but->drawstr[selsta_tmp] = 0;
1171                                         
1172                                         selsta_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1173                                         
1174                                         but->drawstr[selsta_tmp] = ch;
1175                                 }
1176                                 else {
1177                                         selsta_draw = 0;
1178                                 }
1179                                 
1180                                 ch = but->drawstr[selend_tmp];
1181                                 but->drawstr[selend_tmp] = 0;
1182                                 
1183                                 selwidth_draw = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs);
1184                                 
1185                                 but->drawstr[selend_tmp] = ch;
1186
1187                                 glColor3ubv((unsigned char *)wcol->item);
1188                                 glRects(rect->xmin + selsta_draw, rect->ymin + 2, rect->xmin + selwidth_draw, rect->ymax - 2);
1189                         }
1190                 }
1191                 else {
1192                         /* text cursor */
1193                         pos = but->pos;
1194                         if (pos >= but->ofs) {
1195                                 if (but->drawstr[0] != 0) {
1196                                         ch = but->drawstr[pos];
1197                                         but->drawstr[pos] = 0;
1198                                         
1199                                         t = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs) / but->aspect;
1200                                         
1201                                         but->drawstr[pos] = ch;
1202                                 }
1203
1204                                 glColor3f(0.20, 0.6, 0.9);
1205                                 glRects(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
1206                         }
1207                 }
1208         }
1209         
1210         if (fstyle->kerning == 1)
1211                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1212
1213 #if 0
1214         ui_rasterpos_safe(x, y, but->aspect);
1215         if (but->type == IDPOIN) transopts = 0;  /* no translation, of course! */
1216         else transopts = ui_translate_buttons();
1217 #endif
1218
1219         /* cut string in 2 parts - only for menu entries */
1220         if ((but->block->flag & UI_BLOCK_LOOP)) {
1221                 if (ELEM5(but->type, SLI, NUM, TEX, NUMSLI, NUMABS) == 0) {
1222                         cpoin = strchr(but->drawstr, '|');
1223                         if (cpoin) *cpoin = 0;
1224                 }
1225         }
1226         
1227         glColor3ubv((unsigned char *)wcol->text);
1228
1229         uiStyleFontDrawExt(fstyle, rect, but->drawstr + but->ofs, &font_xofs, &font_yofs);
1230
1231         if (but->menu_key != '\0') {
1232                 char fixedbuf[128];
1233                 char *str;
1234
1235                 BLI_strncpy(fixedbuf, but->drawstr + but->ofs, sizeof(fixedbuf));
1236
1237                 str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
1238                 if (str == NULL)
1239                         str = strchr(fixedbuf, but->menu_key);
1240
1241                 if (str) {
1242                         int ul_index = -1;
1243                         float ul_advance;
1244
1245                         ul_index = (int)(str - fixedbuf);
1246
1247                         if (fstyle->kerning == 1) {
1248                                 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1249                         }
1250
1251                         fixedbuf[ul_index] = '\0';
1252                         ul_advance = BLF_width(fstyle->uifont_id, fixedbuf);
1253
1254                         BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
1255                         BLF_draw(fstyle->uifont_id, "_", 2);
1256
1257                         if (fstyle->kerning == 1) {
1258                                 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
1259                         }
1260                 }
1261         }
1262
1263         /* part text right aligned */
1264         if (cpoin) {
1265                 fstyle->align = UI_STYLE_TEXT_RIGHT;
1266                 rect->xmax -= ui_but_draw_menu_icon(but) ? UI_DPI_ICON_SIZE : 5;
1267                 uiStyleFontDraw(fstyle, rect, cpoin + 1);
1268                 *cpoin = '|';
1269         }
1270 }
1271
1272 /* draws text and icons for buttons */
1273 static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect)
1274 {
1275         char password_str[UI_MAX_DRAW_STR];
1276
1277         if (but == NULL)
1278                 return;
1279
1280         ui_button_text_password_hide(password_str, but, FALSE);
1281
1282         /* clip but->drawstr to fit in available space */
1283         if (but->editstr && but->pos >= 0) {
1284                 ui_text_clip_cursor(fstyle, but, rect);
1285         }
1286         else if (ELEM4(but->type, NUM, NUMABS, NUMSLI, SLI)) {
1287                 ui_text_clip_right_label(fstyle, but, rect);
1288         }
1289         else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1290                 ui_text_clip_left(fstyle, but, rect);
1291         }
1292         else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
1293                 ui_text_clip_left(fstyle, but, rect);
1294         }
1295         else but->ofs = 0;
1296
1297         /* check for button text label */
1298         if (but->type == ICONTEXTROW) {
1299                 widget_draw_icon(but, (BIFIconID) (but->icon + but->iconadd), 1.0f, rect);
1300         }
1301         else {
1302
1303                 if (but->type == BUT_TOGDUAL) {
1304                         int dualset = 0;
1305                         if (but->pointype == UI_BUT_POIN_SHORT) {
1306                                 dualset = UI_BITBUT_TEST(*(((short *)but->poin) + 1), but->bitnr);
1307                         }
1308                         else if (but->pointype == UI_BUT_POIN_INT) {
1309                                 dualset = UI_BITBUT_TEST(*(((int *)but->poin) + 1), but->bitnr);
1310                         }
1311
1312                         widget_draw_icon(but, ICON_DOT, dualset ? 1.0f : 0.25f, rect);
1313                 }
1314                 else if (but->type == MENU && (but->flag & UI_BUT_NODE_LINK)) {
1315                         int tmp = rect->xmin;
1316                         rect->xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
1317                         widget_draw_icon(but, ICON_LAYER_USED, 1.0f, rect);
1318                         rect->xmin = tmp;
1319                 }
1320
1321                 /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
1322                  * and offset the text label to accommodate it */
1323
1324                 if (but->flag & UI_HAS_ICON) {
1325                         widget_draw_icon(but, but->icon + but->iconadd, 1.0f, rect);
1326                         
1327                         /* icons default draw 0.8f x height */
1328                         rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect));
1329
1330                         if (but->editstr || (but->flag & UI_TEXT_LEFT)) {
1331                                 rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1332                         }
1333                 }
1334                 else if ((but->flag & UI_TEXT_LEFT)) {
1335                         rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
1336                 }
1337                 
1338                 /* unlink icon for this button type */
1339                 if (but->type == SEARCH_MENU_UNLINK && but->drawstr[0]) {
1340                         rcti temp = *rect;
1341                         
1342                         temp.xmin = temp.xmax - BLI_rcti_size_y(rect);
1343                         widget_draw_icon(but, ICON_X, 1.0f, &temp);
1344                 }
1345
1346                 /* always draw text for textbutton cursor */
1347                 widget_draw_text(fstyle, wcol, but, rect);
1348
1349         }
1350
1351         ui_button_text_password_hide(password_str, but, TRUE);
1352 }
1353
1354
1355
1356 /* *********************** widget types ************************************* */
1357
1358
1359 /* uiWidgetStateColors
1360  *     char inner_anim[4];
1361  *     char inner_anim_sel[4];
1362  *     char inner_key[4];
1363  *     char inner_key_sel[4];
1364  *     char inner_driven[4];
1365  *     char inner_driven_sel[4];
1366  *     float blend;
1367  */
1368
1369 static struct uiWidgetStateColors wcol_state_colors = {
1370         {115, 190, 76, 255},
1371         {90, 166, 51, 255},
1372         {240, 235, 100, 255},
1373         {215, 211, 75, 255},
1374         {180, 0, 255, 255},
1375         {153, 0, 230, 255},
1376         0.5f, 0.0f
1377 };
1378
1379 /* uiWidgetColors
1380  *     float outline[3];
1381  *     float inner[4];
1382  *     float inner_sel[4];
1383  *     float item[3];
1384  *     float text[3];
1385  *     float text_sel[3];
1386  *     
1387  *     short shaded;
1388  *     float shadetop, shadedown;
1389  */
1390
1391 static struct uiWidgetColors wcol_num = {
1392         {25, 25, 25, 255},
1393         {180, 180, 180, 255},
1394         {153, 153, 153, 255},
1395         {90, 90, 90, 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_numslider = {
1405         {25, 25, 25, 255},
1406         {180, 180, 180, 255},
1407         {153, 153, 153, 255},
1408         {128, 128, 128, 255},
1409         
1410         {0, 0, 0, 255},
1411         {255, 255, 255, 255},
1412         
1413         1,
1414         -20, 0
1415 };
1416
1417 static struct uiWidgetColors wcol_text = {
1418         {25, 25, 25, 255},
1419         {153, 153, 153, 255},
1420         {153, 153, 153, 255},
1421         {90, 90, 90, 255},
1422         
1423         {0, 0, 0, 255},
1424         {255, 255, 255, 255},
1425         
1426         1,
1427         0, 25
1428 };
1429
1430 static struct uiWidgetColors wcol_option = {
1431         {0, 0, 0, 255},
1432         {70, 70, 70, 255},
1433         {70, 70, 70, 255},
1434         {255, 255, 255, 255},
1435         
1436         {0, 0, 0, 255},
1437         {255, 255, 255, 255},
1438         
1439         1,
1440         15, -15
1441 };
1442
1443 /* button that shows popup */
1444 static struct uiWidgetColors wcol_menu = {
1445         {0, 0, 0, 255},
1446         {70, 70, 70, 255},
1447         {70, 70, 70, 255},
1448         {255, 255, 255, 255},
1449         
1450         {255, 255, 255, 255},
1451         {204, 204, 204, 255},
1452         
1453         1,
1454         15, -15
1455 };
1456
1457 /* button that starts pulldown */
1458 static struct uiWidgetColors wcol_pulldown = {
1459         {0, 0, 0, 255},
1460         {63, 63, 63, 255},
1461         {86, 128, 194, 255},
1462         {255, 255, 255, 255},
1463         
1464         {0, 0, 0, 255},
1465         {0, 0, 0, 255},
1466         
1467         0,
1468         25, -20
1469 };
1470
1471 /* button inside menu */
1472 static struct uiWidgetColors wcol_menu_item = {
1473         {0, 0, 0, 255},
1474         {0, 0, 0, 0},
1475         {86, 128, 194, 255},
1476         {172, 172, 172, 128},
1477         
1478         {255, 255, 255, 255},
1479         {0, 0, 0, 255},
1480         
1481         1,
1482         38, 0
1483 };
1484
1485 /* backdrop menu + title text color */
1486 static struct uiWidgetColors wcol_menu_back = {
1487         {0, 0, 0, 255},
1488         {25, 25, 25, 230},
1489         {45, 45, 45, 230},
1490         {100, 100, 100, 255},
1491         
1492         {160, 160, 160, 255},
1493         {255, 255, 255, 255},
1494         
1495         0,
1496         25, -20
1497 };
1498
1499 /* tooltip color */
1500 static struct uiWidgetColors wcol_tooltip = {
1501         {0, 0, 0, 255},
1502         {25, 25, 25, 230},
1503         {45, 45, 45, 230},
1504         {100, 100, 100, 255},
1505
1506         {160, 160, 160, 255},
1507         {255, 255, 255, 255},
1508
1509         0,
1510         25, -20
1511 };
1512
1513 static struct uiWidgetColors wcol_radio = {
1514         {0, 0, 0, 255},
1515         {70, 70, 70, 255},
1516         {86, 128, 194, 255},
1517         {255, 255, 255, 255},
1518         
1519         {255, 255, 255, 255},
1520         {0, 0, 0, 255},
1521         
1522         1,
1523         15, -15
1524 };
1525
1526 static struct uiWidgetColors wcol_regular = {
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         0,
1536         0, 0
1537 };
1538
1539 static struct uiWidgetColors wcol_tool = {
1540         {25, 25, 25, 255},
1541         {153, 153, 153, 255},
1542         {100, 100, 100, 255},
1543         {25, 25, 25, 255},
1544         
1545         {0, 0, 0, 255},
1546         {255, 255, 255, 255},
1547         
1548         1,
1549         15, -15
1550 };
1551
1552 static struct uiWidgetColors wcol_box = {
1553         {25, 25, 25, 255},
1554         {128, 128, 128, 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_toggle = {
1566         {25, 25, 25, 255},
1567         {153, 153, 153, 255},
1568         {100, 100, 100, 255},
1569         {25, 25, 25, 255},
1570         
1571         {0, 0, 0, 255},
1572         {255, 255, 255, 255},
1573         
1574         0,
1575         0, 0
1576 };
1577
1578 static struct uiWidgetColors wcol_scroll = {
1579         {50, 50, 50, 180},
1580         {80, 80, 80, 180},
1581         {100, 100, 100, 180},
1582         {128, 128, 128, 255},
1583         
1584         {0, 0, 0, 255},
1585         {255, 255, 255, 255},
1586         
1587         1,
1588         5, -5
1589 };
1590
1591 static struct uiWidgetColors wcol_progress = {
1592         {0, 0, 0, 255},
1593         {190, 190, 190, 255},
1594         {100, 100, 100, 180},
1595         {68, 68, 68, 255},
1596         
1597         {0, 0, 0, 255},
1598         {255, 255, 255, 255},
1599         
1600         0,
1601         0, 0
1602 };
1603
1604 static struct uiWidgetColors wcol_list_item = {
1605         {0, 0, 0, 255},
1606         {0, 0, 0, 0},
1607         {86, 128, 194, 255},
1608         {0, 0, 0, 255},
1609         
1610         {0, 0, 0, 255},
1611         {0, 0, 0, 255},
1612         
1613         0,
1614         0, 0
1615 };
1616
1617 /* free wcol struct to play with */
1618 static struct uiWidgetColors wcol_tmp = {
1619         {0, 0, 0, 255},
1620         {128, 128, 128, 255},
1621         {100, 100, 100, 255},
1622         {25, 25, 25, 255},
1623         
1624         {0, 0, 0, 255},
1625         {255, 255, 255, 255},
1626         
1627         0,
1628         0, 0
1629 };
1630
1631
1632 /* called for theme init (new theme) and versions */
1633 void ui_widget_color_init(ThemeUI *tui)
1634 {
1635         tui->wcol_regular = wcol_regular;
1636         tui->wcol_tool = wcol_tool;
1637         tui->wcol_text = wcol_text;
1638         tui->wcol_radio = wcol_radio;
1639         tui->wcol_option = wcol_option;
1640         tui->wcol_toggle = wcol_toggle;
1641         tui->wcol_num = wcol_num;
1642         tui->wcol_numslider = wcol_numslider;
1643         tui->wcol_menu = wcol_menu;
1644         tui->wcol_pulldown = wcol_pulldown;
1645         tui->wcol_menu_back = wcol_menu_back;
1646         tui->wcol_tooltip = wcol_tooltip;
1647         tui->wcol_menu_item = wcol_menu_item;
1648         tui->wcol_box = wcol_box;
1649         tui->wcol_scroll = wcol_scroll;
1650         tui->wcol_list_item = wcol_list_item;
1651         tui->wcol_progress = wcol_progress;
1652
1653         tui->wcol_state = wcol_state_colors;
1654 }
1655
1656 /* ************ button callbacks, state ***************** */
1657
1658 static void widget_state_blend(char cp[3], const char cpstate[3], const float fac)
1659 {
1660         if (fac != 0.0f) {
1661                 cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
1662                 cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
1663                 cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
1664         }
1665 }
1666
1667 /* copy colors from theme, and set changes in it based on state */
1668 static void widget_state(uiWidgetType *wt, int state)
1669 {
1670         uiWidgetStateColors *wcol_state = wt->wcol_state;
1671
1672         wt->wcol = *(wt->wcol_theme);
1673         
1674         if (state & UI_SELECT) {
1675                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1676
1677                 if (state & UI_BUT_ANIMATED_KEY)
1678                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key_sel, wcol_state->blend);
1679                 else if (state & UI_BUT_ANIMATED)
1680                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
1681                 else if (state & UI_BUT_DRIVEN)
1682                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
1683
1684                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1685                 
1686                 if (state & UI_SELECT)
1687                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1688         }
1689         else {
1690                 if (state & UI_BUT_ANIMATED_KEY)
1691                         widget_state_blend(wt->wcol.inner, wcol_state->inner_key, wcol_state->blend);
1692                 else if (state & UI_BUT_ANIMATED)
1693                         widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
1694                 else if (state & UI_BUT_DRIVEN)
1695                         widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
1696
1697                 if (state & UI_ACTIVE) { /* mouse over? */
1698                         wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
1699                         wt->wcol.inner[1] = wt->wcol.inner[1] >= 240 ? 255 : wt->wcol.inner[1] + 15;
1700                         wt->wcol.inner[2] = wt->wcol.inner[2] >= 240 ? 255 : wt->wcol.inner[2] + 15;
1701                 }
1702         }
1703
1704         if (state & UI_BUT_REDALERT) {
1705                 char red[4] = {255, 0, 0};
1706                 widget_state_blend(wt->wcol.inner, red, 0.4f);
1707         }
1708         if (state & UI_BUT_NODE_ACTIVE) {
1709                 char blue[4] = {86, 128, 194};
1710                 widget_state_blend(wt->wcol.inner, blue, 0.3f);
1711         }
1712 }
1713
1714 /* sliders use special hack which sets 'item' as inner when drawing filling */
1715 static void widget_state_numslider(uiWidgetType *wt, int state)
1716 {
1717         uiWidgetStateColors *wcol_state = wt->wcol_state;
1718         float blend = wcol_state->blend - 0.2f; /* XXX special tweak to make sure that bar will still be visible */
1719
1720         /* call this for option button */
1721         widget_state(wt, state);
1722         
1723         /* now, set the inner-part so that it reflects state settings too */
1724         /* TODO: maybe we should have separate settings for the blending colors used for this case? */
1725         if (state & UI_SELECT) {
1726                 
1727                 if (state & UI_BUT_ANIMATED_KEY)
1728                         widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
1729                 else if (state & UI_BUT_ANIMATED)
1730                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
1731                 else if (state & UI_BUT_DRIVEN)
1732                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
1733                 
1734                 if (state & UI_SELECT)
1735                         SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
1736         }
1737         else {
1738                 if (state & UI_BUT_ANIMATED_KEY)
1739                         widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
1740                 else if (state & UI_BUT_ANIMATED)
1741                         widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
1742                 else if (state & UI_BUT_DRIVEN)
1743                         widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
1744         }
1745 }
1746
1747 /* labels use theme colors for text */
1748 static void widget_state_label(uiWidgetType *wt, int state)
1749 {
1750         /* call this for option button */
1751         widget_state(wt, state);
1752
1753         if (state & UI_SELECT)
1754                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1755         else
1756                 UI_GetThemeColor4ubv(TH_TEXT, (unsigned char *)wt->wcol.text);
1757         
1758 }
1759
1760 /* labels use theme colors for text */
1761 static void widget_state_option_menu(uiWidgetType *wt, int state)
1762 {
1763         
1764         /* call this for option button */
1765         widget_state(wt, state);
1766         
1767         /* if not selected we get theme from menu back */
1768         if (state & UI_SELECT)
1769                 UI_GetThemeColor4ubv(TH_TEXT_HI, (unsigned char *)wt->wcol.text);
1770         else {
1771                 bTheme *btheme = UI_GetTheme(); /* XXX */
1772
1773                 copy_v3_v3_char(wt->wcol.text, btheme->tui.wcol_menu_back.text);
1774         }
1775 }
1776
1777
1778 static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state))
1779 {
1780         wt->wcol = *(wt->wcol_theme);
1781 }       
1782
1783 /* special case, button that calls pulldown */
1784 static void widget_state_pulldown(uiWidgetType *wt, int state)
1785 {
1786         wt->wcol = *(wt->wcol_theme);
1787         
1788         copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1789         copy_v3_v3_char(wt->wcol.outline, wt->wcol.inner);
1790
1791         if (state & UI_ACTIVE)
1792                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1793 }
1794
1795 /* special case, menu items */
1796 static void widget_state_menu_item(uiWidgetType *wt, int state)
1797 {
1798         wt->wcol = *(wt->wcol_theme);
1799         
1800         /* active and disabled (not so common) */
1801         if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
1802                 widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
1803                 /* draw the backdrop at low alpha, helps navigating with keys
1804                  * when disabled items are active */
1805                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1806                 wt->wcol.inner[3] = 64;
1807         }
1808         /* regular disabled */
1809         else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
1810                 widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
1811         }
1812         /* regular active */
1813         else if (state & UI_ACTIVE) {
1814                 copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
1815                 copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
1816         }
1817 }
1818
1819
1820 /* ************ menu backdrop ************************* */
1821
1822 /* outside of rect, rad to left/bottom/right */
1823 static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
1824 {
1825         bTheme *btheme = UI_GetTheme();
1826         uiWidgetBase wtb;
1827         rcti rect1 = *rect;
1828         float alphastep;
1829         int step, totvert;
1830         float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
1831         const float radout = UI_ThemeMenuShadowWidth();
1832         
1833         /* disabled shadow */
1834         if (radout == 0.0f)
1835                 return;
1836         
1837         /* prevent tooltips to not show round shadow */
1838         if (radout > 0.2f * BLI_rcti_size_y(&rect1))
1839                 rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
1840         else
1841                 rect1.ymax -= radout;
1842         
1843         /* inner part */
1844         totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
1845
1846         /* we draw a number of increasing size alpha quad strips */
1847         alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
1848         
1849         glEnableClientState(GL_VERTEX_ARRAY);
1850
1851         for (step = 1; step <= (int)radout; step++) {
1852                 float expfac = sqrt(step / radout);
1853                 
1854                 round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
1855                 
1856                 glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
1857
1858                 widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
1859
1860                 glVertexPointer(2, GL_FLOAT, 0, quad_strip);
1861                 glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
1862         }
1863
1864         glDisableClientState(GL_VERTEX_ARRAY);
1865 }
1866
1867 static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
1868 {
1869         uiWidgetBase wtb;
1870         int roundboxalign = UI_CNR_ALL;
1871         
1872         widget_init(&wtb);
1873         
1874         /* menu is 2nd level or deeper */
1875         if (flag & UI_BLOCK_POPUP) {
1876                 //rect->ymin -= 4.0;
1877                 //rect->ymax += 4.0;
1878         }
1879         else if (direction == UI_DOWN) {
1880                 roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
1881                 rect->ymin -= 0.1f * U.widget_unit;
1882         }
1883         else if (direction == UI_TOP) {
1884                 roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
1885                 rect->ymax += 0.1f * U.widget_unit;
1886         }
1887         
1888         glEnable(GL_BLEND);
1889         widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit);
1890         
1891         round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit);
1892         wtb.emboss = 0;
1893         widgetbase_draw(&wtb, wcol);
1894         
1895         glDisable(GL_BLEND);
1896 }
1897
1898
1899 static void ui_hsv_cursor(float x, float y)
1900 {
1901         
1902         glPushMatrix();
1903         glTranslatef(x, y, 0.0f);
1904         
1905         glColor3f(1.0f, 1.0f, 1.0f);
1906         glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
1907         
1908         glEnable(GL_BLEND);
1909         glEnable(GL_LINE_SMOOTH);
1910         glColor3f(0.0f, 0.0f, 0.0f);
1911         glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12);
1912         glDisable(GL_BLEND);
1913         glDisable(GL_LINE_SMOOTH);
1914         
1915         glPopMatrix();
1916         
1917 }
1918
1919 void ui_hsvcircle_vals_from_pos(float *val_rad, float *val_dist, const rcti *rect,
1920                                 const float mx, const float my)
1921 {
1922         /* duplication of code... well, simple is better now */
1923         const float centx = BLI_rcti_cent_x_fl(rect);
1924         const float centy = BLI_rcti_cent_y_fl(rect);
1925         const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1926         const float m_delta[2] = {mx - centx, my - centy};
1927         const float dist_squared = len_squared_v2(m_delta);
1928
1929         *val_dist = (dist_squared < (radius * radius)) ? sqrtf(dist_squared) / radius : 1.0f;
1930         *val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
1931 }
1932
1933 static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
1934 {
1935         const int tot = 64;
1936         const float radstep = 2.0f * (float)M_PI / (float)tot;
1937
1938         const float centx = BLI_rcti_cent_x_fl(rect);
1939         const float centy = BLI_rcti_cent_y_fl(rect);
1940         float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
1941
1942         /* gouraud triangle fan */
1943         const float *hsv_ptr = ui_block_hsv_get(but->block);
1944         float ang = 0.0f;
1945         float cursor_radius;
1946         float rgb[3], hsvo[3], hsv[3], col[3], colcent[3];
1947         int a;
1948         int color_profile = but->block->color_profile;
1949         
1950         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
1951                 color_profile = FALSE;
1952         
1953         /* color */
1954         ui_get_but_vectorf(but, rgb);
1955
1956         /* since we use compat functions on both 'hsv' and 'hsvo', they need to be initialized */
1957         hsvo[0] = hsv[0] = hsv_ptr[0];
1958         hsvo[1] = hsv[1] = hsv_ptr[1];
1959         hsvo[2] = hsv[2] = hsv_ptr[2];
1960
1961         rgb_to_hsv_compat_v(rgb, hsvo);
1962
1963         if (color_profile)
1964                 ui_block_to_display_space_v3(but->block, rgb);
1965
1966         rgb_to_hsv_compat_v(rgb, hsv);
1967         
1968         /* exception: if 'lock' is set
1969          * lock the value of the color wheel to 1.
1970          * Useful for color correction tools where you're only interested in hue. */
1971         if (but->flag & UI_BUT_COLOR_LOCK)
1972                 hsv[2] = 1.f;
1973         
1974         hsv_to_rgb(0.f, 0.f, hsv[2], colcent, colcent + 1, colcent + 2);
1975         
1976         glShadeModel(GL_SMOOTH);
1977
1978         glBegin(GL_TRIANGLE_FAN);
1979         glColor3fv(colcent);
1980         glVertex2f(centx, centy);
1981         
1982         for (a = 0; a <= tot; a++, ang += radstep) {
1983                 float si = sin(ang);
1984                 float co = cos(ang);
1985                 
1986                 ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
1987                 CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
1988
1989                 hsv_to_rgb_v(hsv, col);
1990                 glColor3fv(col);
1991                 glVertex2f(centx + co * radius, centy + si * radius);
1992         }
1993         glEnd();
1994         
1995         glShadeModel(GL_FLAT);
1996         
1997         /* fully rounded outline */
1998         glPushMatrix();
1999         glTranslatef(centx, centy, 0.0f);
2000         glEnable(GL_BLEND);
2001         glEnable(GL_LINE_SMOOTH);
2002         glColor3ubv((unsigned char *)wcol->outline);
2003         glutil_draw_lined_arc(0.0f, M_PI * 2.0, radius, tot + 1);
2004         glDisable(GL_BLEND);
2005         glDisable(GL_LINE_SMOOTH);
2006         glPopMatrix();
2007
2008         /* cursor */
2009         ang = 2.0f * (float)M_PI * hsvo[0] + 0.5f * (float)M_PI;
2010
2011         if (but->flag & UI_BUT_COLOR_CUBIC)
2012                 cursor_radius = (1.0f - powf(1.0f - hsvo[1], 3.0f));
2013         else
2014                 cursor_radius = hsvo[1];
2015
2016         radius = CLAMPIS(cursor_radius, 0.0f, 1.0f) * radius;
2017         ui_hsv_cursor(centx + cosf(-ang) * radius, centy + sinf(-ang) * radius);
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
2161
2162 static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
2163 {
2164         float rgb[3];
2165         float x = 0.0f, y = 0.0f;
2166         float *hsv = ui_block_hsv_get(but->block);
2167         float hsv_n[3];
2168         int color_profile = but->block->color_profile;
2169         
2170         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2171                 color_profile = FALSE;
2172         
2173         copy_v3_v3(hsv_n, hsv);
2174         
2175         ui_get_but_vectorf(but, rgb);
2176         
2177         if (color_profile && (int)but->a1 != UI_GRAD_SV)
2178                 ui_block_to_display_space_v3(but->block, rgb);
2179         
2180         rgb_to_hsv_compat_v(rgb, hsv_n);
2181         
2182         ui_draw_gradient(rect, hsv_n, but->a1, 1.0f);
2183         
2184         switch ((int)but->a1) {
2185                 case UI_GRAD_SV:
2186                         x = hsv_n[2]; y = hsv_n[1]; break;
2187                 case UI_GRAD_HV:
2188                         x = hsv_n[0]; y = hsv_n[2]; break;
2189                 case UI_GRAD_HS:
2190                         x = hsv_n[0]; y = hsv_n[1]; break;
2191                 case UI_GRAD_H:
2192                         x = hsv_n[0]; y = 0.5; break;
2193                 case UI_GRAD_S:
2194                         x = hsv_n[1]; y = 0.5; break;
2195                 case UI_GRAD_V:
2196                         x = hsv_n[2]; y = 0.5; break;
2197         }
2198         
2199         /* cursor */
2200         x = rect->xmin + x * BLI_rcti_size_x(rect);
2201         y = rect->ymin + y * BLI_rcti_size_y(rect);
2202         CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
2203         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2204         
2205         ui_hsv_cursor(x, y);
2206         
2207         /* outline */
2208         glColor3ub(0,  0,  0);
2209         fdrawbox((rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
2210 }
2211
2212 /* vertical 'value' slider, using new widget code */
2213 static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
2214 {
2215         uiWidgetBase wtb;
2216         const float rad = 0.5f * BLI_rcti_size_x(rect);
2217         float x, y;
2218         float rgb[3], hsv[3], v, range;
2219         int color_profile = but->block->color_profile;
2220         
2221         if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2222                 color_profile = FALSE;
2223
2224         ui_get_but_vectorf(but, rgb);
2225
2226         if (color_profile)
2227                 ui_block_to_display_space_v3(but->block, rgb);
2228
2229         rgb_to_hsv_v(rgb, hsv);
2230         v = hsv[2];
2231         
2232         /* map v from property range to [0,1] */
2233         range = but->softmax - but->softmin;
2234         v = (v - but->softmin) / range;
2235         
2236         widget_init(&wtb);
2237         
2238         /* fully rounded */
2239         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2240         
2241         /* setup temp colors */
2242         wcol_tmp.outline[0] = wcol_tmp.outline[1] = wcol_tmp.outline[2] = 0;
2243         wcol_tmp.inner[0] = wcol_tmp.inner[1] = wcol_tmp.inner[2] = 128;
2244         wcol_tmp.shadetop = 127;
2245         wcol_tmp.shadedown = -128;
2246         wcol_tmp.shaded = 1;
2247         
2248         widgetbase_draw(&wtb, &wcol_tmp);
2249
2250         /* cursor */
2251         x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
2252         y = rect->ymin + v    * BLI_rcti_size_y(rect);
2253         CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
2254         
2255         ui_hsv_cursor(x, y);
2256         
2257 }
2258
2259
2260 /* ************ separator, for menus etc ***************** */
2261 static void ui_draw_separator(const rcti *rect,  uiWidgetColors *wcol)
2262 {
2263         int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2264         unsigned char col[4];
2265         
2266         col[0] = wcol->text[0];
2267         col[1] = wcol->text[1];
2268         col[2] = wcol->text[2];
2269         col[3] = 7;
2270         
2271         glEnable(GL_BLEND);
2272         glColor4ubv(col);
2273         sdrawline(rect->xmin, y, rect->xmax, y);
2274         glDisable(GL_BLEND);
2275 }
2276
2277 /* ************ button callbacks, draw ***************** */
2278
2279 static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2280 {
2281         uiWidgetBase wtb;
2282         const float rad = 0.5f * BLI_rcti_size_y(rect);
2283         float textofs = rad * 0.75f;
2284
2285         if (state & UI_SELECT)
2286                 SWAP(short, wcol->shadetop, wcol->shadedown);
2287         
2288         widget_init(&wtb);
2289         
2290         /* fully rounded */
2291         round_box_edges(&wtb, roundboxalign, rect, rad);
2292         
2293         /* decoration */
2294         if (!(state & UI_TEXTINPUT)) {
2295                 widget_num_tria(&wtb.tria1, rect, 0.6f, 'l');
2296                 widget_num_tria(&wtb.tria2, rect, 0.6f, 'r');
2297         }
2298
2299         widgetbase_draw(&wtb, wcol);
2300         
2301         /* text space */
2302         rect->xmin += textofs;
2303         rect->xmax -= textofs;
2304 }
2305
2306 int ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol)
2307 {
2308         float dist, vec[4][2];
2309
2310         vec[0][0] = rect->xmin;
2311         vec[0][1] = rect->ymin;
2312         vec[3][0] = rect->xmax;
2313         vec[3][1] = rect->ymax;
2314         
2315         dist = 0.5f * ABS(vec[0][0] - vec[3][0]);
2316         
2317         vec[1][0] = vec[0][0] + dist;
2318         vec[1][1] = vec[0][1];
2319         
2320         vec[2][0] = vec[3][0] - dist;
2321         vec[2][1] = vec[3][1];
2322         
2323         BKE_curve_forward_diff_bezier(vec[0][0], vec[1][0], vec[2][0], vec[3][0], coord_array[0], resol, sizeof(float) * 2);
2324         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);
2325         
2326         return 1;
2327 }
2328
2329 #define LINK_RESOL  24
2330 void ui_draw_link_bezier(const rcti *rect)
2331 {
2332         float coord_array[LINK_RESOL + 1][2];
2333         
2334         if (ui_link_bezier_points(rect, coord_array, LINK_RESOL)) {
2335                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
2336                 // const float dist = 1.0f / (float)LINK_RESOL; // UNUSED
2337
2338                 glEnable(GL_BLEND);
2339                 glEnable(GL_LINE_SMOOTH);
2340
2341                 glEnableClientState(GL_VERTEX_ARRAY);
2342                 glVertexPointer(2, GL_FLOAT, 0, coord_array);
2343                 glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1);
2344                 glDisableClientState(GL_VERTEX_ARRAY);
2345
2346                 glDisable(GL_BLEND);
2347                 glDisable(GL_LINE_SMOOTH);
2348
2349         }
2350 }
2351
2352 /* function in use for buttons and for view2d sliders */
2353 void uiWidgetScrollDraw(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
2354 {
2355         uiWidgetBase wtb;
2356         int horizontal;
2357         float rad;
2358         short outline = 0;
2359
2360         widget_init(&wtb);
2361
2362         /* determine horizontal/vertical */
2363         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2364
2365         if (horizontal)
2366                 rad = 0.5f * BLI_rcti_size_y(rect);
2367         else
2368                 rad = 0.5f * BLI_rcti_size_x(rect);
2369         
2370         wtb.shadedir = (horizontal) ? 1 : 0;
2371         
2372         /* draw back part, colors swapped and shading inverted */
2373         if (horizontal)
2374                 SWAP(short, wcol->shadetop, wcol->shadedown);
2375         
2376         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2377         widgetbase_draw(&wtb, wcol);
2378         
2379         /* slider */
2380         if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2381                 /* pass */
2382         }
2383         else {
2384                 SWAP(short, wcol->shadetop, wcol->shadedown);
2385                 
2386                 copy_v4_v4_char(wcol->inner, wcol->item);
2387                 
2388                 if (wcol->shadetop > wcol->shadedown)
2389                         wcol->shadetop += 20;   /* XXX violates themes... */
2390                 else wcol->shadedown += 20;
2391                 
2392                 if (state & UI_SCROLL_PRESSED) {
2393                         wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
2394                         wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
2395                         wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
2396                 }
2397
2398                 /* draw */
2399                 wtb.emboss = 0; /* only emboss once */
2400                 
2401                 /* exception for progress bar */
2402                 if (state & UI_SCROLL_NO_OUTLINE)
2403                         SWAP(short, outline, wtb.outline);
2404                 
2405                 round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
2406                 
2407                 if (state & UI_SCROLL_ARROWS) {
2408                         if (wcol->item[0] > 48) wcol->item[0] -= 48;
2409                         if (wcol->item[1] > 48) wcol->item[1] -= 48;
2410                         if (wcol->item[2] > 48) wcol->item[2] -= 48;
2411                         wcol->item[3] = 255;
2412                         
2413                         if (horizontal) {
2414                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'l');
2415                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 'r');
2416                         }
2417                         else {
2418                                 widget_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
2419                                 widget_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
2420                         }
2421                 }
2422                 widgetbase_draw(&wtb, wcol);
2423                 
2424                 if (state & UI_SCROLL_NO_OUTLINE)
2425                         SWAP(short, outline, wtb.outline);
2426         }
2427 }
2428
2429 static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2430 {
2431         rcti rect1;
2432         double value;
2433         float fac, size, min;
2434         int horizontal;
2435
2436         /* calculate slider part */
2437         value = ui_get_but_val(but);
2438
2439         size = (but->softmax + but->a1 - but->softmin);
2440         size = max_ff(size, 2.0f);
2441         
2442         /* position */
2443         rect1 = *rect;
2444
2445         /* determine horizontal/vertical */
2446         horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
2447         
2448         if (horizontal) {
2449                 fac = BLI_rcti_size_x(rect) / size;
2450                 rect1.xmin = rect1.xmin + ceilf(fac * ((float)value - but->softmin));
2451                 rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2452
2453                 /* ensure minimium size */
2454                 min = BLI_rcti_size_y(rect);
2455
2456                 if (BLI_rcti_size_x(&rect1) < min) {
2457                         rect1.xmax = rect1.xmin + min;
2458
2459                         if (rect1.xmax > rect->xmax) {
2460                                 rect1.xmax = rect->xmax;
2461                                 rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
2462                         }
2463                 }
2464         }
2465         else {
2466                 fac = BLI_rcti_size_y(rect) / size;
2467                 rect1.ymax = rect1.ymax - ceilf(fac * ((float)value - but->softmin));
2468                 rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2469
2470                 /* ensure minimium size */
2471                 min = BLI_rcti_size_x(rect);
2472
2473                 if (BLI_rcti_size_y(&rect1) < min) {
2474                         rect1.ymax = rect1.ymin + min;
2475
2476                         if (rect1.ymax > rect->ymax) {
2477                                 rect1.ymax = rect->ymax;
2478                                 rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
2479                         }
2480                 }
2481         }
2482
2483         if (state & UI_SELECT)
2484                 state = UI_SCROLL_PRESSED;
2485         else
2486                 state = 0;
2487         uiWidgetScrollDraw(wcol, rect, &rect1, state);
2488 }
2489
2490 static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2491 {
2492         rcti rect_prog = *rect, rect_bar = *rect;
2493         float value = but->a1;
2494         float w, min;
2495         
2496         /* make the progress bar a proportion of the original height */
2497         /* hardcoded 4px high for now */
2498         rect_prog.ymax = rect_prog.ymin + 4;
2499         rect_bar.ymax = rect_bar.ymin + 4;
2500         
2501         w = value * BLI_rcti_size_x(&rect_prog);
2502         
2503         /* ensure minimium size */
2504         min = BLI_rcti_size_y(&rect_prog);
2505         w = MAX2(w, min);
2506         
2507         rect_bar.xmax = rect_bar.xmin + w;
2508                 
2509         uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
2510         
2511         /* raise text a bit */
2512         rect->ymin += 6;
2513         rect->xmin -= 6;
2514 }
2515
2516 static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2517 {
2518         
2519         if (but->flag & UI_SELECT) {
2520                 rcti rectlink;
2521                 
2522                 UI_ThemeColor(TH_TEXT_HI);
2523                 
2524                 rectlink.xmin = BLI_rcti_cent_x(rect);
2525                 rectlink.ymin = BLI_rcti_cent_y(rect);
2526                 rectlink.xmax = but->linkto[0];
2527                 rectlink.ymax = but->linkto[1];
2528                 
2529                 ui_draw_link_bezier(&rectlink);
2530         }
2531 }
2532
2533 static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2534 {
2535         uiWidgetBase wtb, wtb1;
2536         rcti rect1;
2537         double value;
2538         float offs, toffs, fac;
2539         char outline[3];
2540
2541         widget_init(&wtb);
2542         widget_init(&wtb1);
2543         
2544         /* backdrop first */
2545         
2546         /* fully rounded */
2547         offs = 0.5f * BLI_rcti_size_y(rect);
2548         toffs = offs * 0.75f;
2549         round_box_edges(&wtb, roundboxalign, rect, offs);
2550
2551         wtb.outline = 0;
2552         widgetbase_draw(&wtb, wcol);
2553         
2554         /* draw left/right parts only when not in text editing */
2555         if (!(state & UI_TEXTINPUT)) {
2556                 
2557                 /* slider part */
2558                 copy_v3_v3_char(outline, wcol->outline);
2559                 copy_v3_v3_char(wcol->outline, wcol->item);
2560                 copy_v3_v3_char(wcol->inner, wcol->item);
2561
2562                 if (!(state & UI_SELECT))
2563                         SWAP(short, wcol->shadetop, wcol->shadedown);
2564                 
2565                 rect1 = *rect;
2566                 
2567                 value = ui_get_but_val(but);
2568                 fac = ((float)value - but->softmin) * (BLI_rcti_size_x(&rect1) - offs) / (but->softmax - but->softmin);
2569                 
2570                 /* left part of slider, always rounded */
2571                 rect1.xmax = rect1.xmin + ceil(offs + U.pixelsize);
2572                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT), &rect1, offs);
2573                 wtb1.outline = 0;
2574                 widgetbase_draw(&wtb1, wcol);
2575                 
2576                 /* right part of slider, interpolate roundness */
2577                 rect1.xmax = rect1.xmin + fac + offs;
2578                 rect1.xmin +=  floor(offs - U.pixelsize);
2579                 
2580                 if (rect1.xmax + offs > rect->xmax)
2581                         offs *= (rect1.xmax + offs - rect->xmax) / offs;
2582                 else 
2583                         offs = 0.0f;
2584                 round_box_edges(&wtb1, roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT), &rect1, offs);
2585                 
2586                 widgetbase_draw(&wtb1, wcol);
2587                 copy_v3_v3_char(wcol->outline, outline);
2588                 
2589                 if (!(state & UI_SELECT))
2590                         SWAP(short, wcol->shadetop, wcol->shadedown);
2591         }
2592         
2593         /* outline */
2594         wtb.outline = 1;
2595         wtb.inner = 0;
2596         widgetbase_draw(&wtb, wcol);
2597         
2598         /* text space */
2599         rect->xmin += toffs;
2600         rect->xmax -= toffs;
2601 }
2602
2603 /* I think 3 is sufficient border to indicate keyed status */
2604 #define SWATCH_KEYED_BORDER 3
2605
2606 static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2607 {
2608         uiWidgetBase wtb;
2609         float rad, col[4];
2610         int color_profile = but->block->color_profile;
2611         
2612         col[3] = 1.0f;
2613
2614         if (but->rnaprop) {
2615                 BLI_assert(but->rnaindex == -1);
2616
2617                 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
2618                         color_profile = FALSE;
2619
2620                 if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
2621                         col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
2622                 }
2623         }
2624         
2625         widget_init(&wtb);
2626         
2627         /* half rounded */
2628         rad = 0.25f * U.widget_unit;
2629         round_box_edges(&wtb, roundboxalign, rect, rad);
2630                 
2631         ui_get_but_vectorf(but, col);
2632
2633         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2634                 /* draw based on state - color for keyed etc */
2635                 widgetbase_draw(&wtb, wcol);
2636
2637                 /* inset to draw swatch color */
2638                 rect->xmin += SWATCH_KEYED_BORDER;
2639                 rect->xmax -= SWATCH_KEYED_BORDER;
2640                 rect->ymin += SWATCH_KEYED_BORDER;
2641                 rect->ymax -= SWATCH_KEYED_BORDER;
2642                 
2643                 round_box_edges(&wtb, roundboxalign, rect, rad);
2644         }
2645         
2646         if (color_profile)
2647                 ui_block_to_display_space_v3(but->block, col);
2648         
2649         rgba_float_to_uchar((unsigned char *)wcol->inner, col);
2650
2651         wcol->shaded = 0;
2652         wcol->alpha_check = (wcol->inner[3] < 255);
2653
2654         widgetbase_draw(&wtb, wcol);
2655         
2656 }
2657
2658 static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2659 {
2660         ui_draw_but_NORMAL(but, wcol, rect);
2661 }
2662
2663 static void widget_icon_has_anim(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2664 {
2665         if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
2666                 uiWidgetBase wtb;
2667                 float rad;
2668                 
2669                 widget_init(&wtb);
2670                 wtb.outline = 0;
2671                 
2672                 /* rounded */
2673                 rad = 0.5f * BLI_rcti_size_y(rect);
2674                 round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2675                 widgetbase_draw(&wtb, wcol);
2676         }
2677 }
2678
2679
2680 static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2681 {
2682         uiWidgetBase wtb;
2683         float rad;
2684         
2685         if (state & UI_SELECT)
2686                 SWAP(short, wcol->shadetop, wcol->shadedown);
2687         
2688         widget_init(&wtb);
2689         
2690         /* half rounded */
2691         rad = 0.2f * U.widget_unit;
2692         round_box_edges(&wtb, roundboxalign, rect, rad);
2693         
2694         widgetbase_draw(&wtb, wcol);
2695
2696 }
2697
2698
2699 static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2700 {
2701         uiWidgetBase wtb;
2702         float rad;
2703         
2704         widget_init(&wtb);
2705         
2706         /* half rounded */
2707         rad = 0.2f * U.widget_unit;
2708         round_box_edges(&wtb, roundboxalign, rect, rad);
2709         
2710         /* decoration */
2711         widget_menu_trias(&wtb.tria1, rect);
2712         
2713         widgetbase_draw(&wtb, wcol);
2714         
2715         /* text space, arrows are about 0.6 height of button */
2716         rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
2717 }
2718
2719 static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2720 {
2721         uiWidgetBase wtb;
2722         float rad;
2723         
2724         widget_init(&wtb);
2725         
2726         /* half rounded */
2727         rad = 0.2f * U.widget_unit;
2728         round_box_edges(&wtb, roundboxalign, rect, rad);
2729         
2730         /* decoration */
2731         widgetbase_draw(&wtb, wcol);
2732 }
2733
2734 static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2735 {
2736         /* silly node link button hacks */
2737         uiWidgetBase wtb;
2738         uiWidgetColors wcol_backup = *wcol;
2739         float rad;
2740         
2741         widget_init(&wtb);
2742         
2743         /* half rounded */
2744         rad = 0.2f * U.widget_unit;
2745         round_box_edges(&wtb, roundboxalign, rect, rad);
2746
2747         wcol->inner[0] += 15;
2748         wcol->inner[1] += 15;
2749         wcol->inner[2] += 15;
2750         wcol->outline[0] += 15;
2751         wcol->outline[1] += 15;
2752         wcol->outline[2] += 15;
2753         
2754         /* decoration */
2755         widgetbase_draw(&wtb, wcol);
2756         *wcol = wcol_backup;
2757 }
2758
2759 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
2760 {
2761         if (state & UI_ACTIVE) {
2762                 uiWidgetBase wtb;
2763                 const float rad = 0.2f * U.widget_unit;
2764
2765                 widget_init(&wtb);
2766
2767                 /* half rounded */
2768                 round_box_edges(&wtb, roundboxalign, rect, rad);
2769                 
2770                 widgetbase_draw(&wtb, wcol);
2771         }
2772 }
2773
2774 static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2775 {
2776         uiWidgetBase wtb;
2777         
2778         widget_init(&wtb);
2779         
2780         /* not rounded, no outline */
2781         wtb.outline = 0;
2782         round_box_edges(&wtb, 0, rect, 0.0f);
2783         
2784         widgetbase_draw(&wtb, wcol);
2785 }
2786
2787 static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
2788 {
2789         uiWidgetBase wtb;
2790         float rad;
2791         
2792         widget_init(&wtb);
2793         
2794         /* rounded, but no outline */
2795         wtb.outline = 0;
2796         rad = 0.2f * U.widget_unit;
2797         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2798         
2799         widgetbase_draw(&wtb, wcol);
2800 }
2801
2802 static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
2803 {
2804         uiWidgetBase wtb;
2805         rcti recttemp = *rect;
2806         float rad;
2807         int delta;
2808         
2809         widget_init(&wtb);
2810         
2811         /* square */
2812         recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
2813         
2814         /* smaller */
2815         delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
2816         recttemp.xmin += delta;
2817         recttemp.ymin += delta;
2818         recttemp.xmax -= delta;
2819         recttemp.ymax -= delta;
2820         
2821         /* half rounded */
2822         rad = 0.2f * U.widget_unit;
2823         round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
2824         
2825         /* decoration */
2826         if (state & UI_SELECT) {
2827                 widget_check_trias(&wtb.tria1, &recttemp);
2828         }
2829         
2830         widgetbase_draw(&wtb, wcol);
2831         
2832         /* text space */
2833         rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta;
2834 }
2835
2836
2837 static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2838 {
2839         uiWidgetBase wtb;
2840         float rad;
2841         
2842         widget_init(&wtb);
2843         
2844         /* half rounded */
2845         rad = 0.2f * U.widget_unit;
2846         round_box_edges(&wtb, roundboxalign, rect, rad);
2847         
2848         widgetbase_draw(&wtb, wcol);
2849
2850 }
2851
2852 static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2853 {
2854         uiWidgetBase wtb;
2855         float rad;
2856         char old_col[3];
2857         
2858         widget_init(&wtb);
2859         
2860         copy_v3_v3_char(old_col, wcol->inner);
2861         
2862         /* abuse but->hsv - if it's non-zero, use this color as the box's background */
2863         if (but->col[3]) {
2864                 wcol->inner[0] = but->col[0];
2865                 wcol->inner[1] = but->col[1];
2866                 wcol->inner[2] = but->col[2];
2867         }
2868         
2869         /* half rounded */
2870         rad = 0.2f * U.widget_unit;
2871         round_box_edges(&wtb, roundboxalign, rect, rad);
2872         
2873         widgetbase_draw(&wtb, wcol);
2874         
2875         /* store the box bg as gl clearcolor, to retrieve later when drawing semi-transparent rects
2876          * over the top to indicate disabled buttons */
2877         /* XXX, this doesnt work right since the color applies to buttons outside the box too. */
2878         glClearColor(wcol->inner[0] / 255.0, wcol->inner[1] / 255.0, wcol->inner[2] / 255.0, 1.0);
2879         
2880         copy_v3_v3_char(wcol->inner, old_col);
2881 }
2882
2883 static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2884 {
2885         uiWidgetBase wtb;
2886         float rad;
2887         
2888         widget_init(&wtb);
2889         
2890         /* half rounded */
2891         rad = 0.2f * U.widget_unit;
2892         round_box_edges(&wtb, roundboxalign, rect, rad);
2893         
2894         widgetbase_draw(&wtb, wcol);
2895
2896 }
2897
2898 static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
2899 {
2900         uiWidgetBase wtb;
2901         const float rad = 0.25f * U.widget_unit;
2902         
2903         widget_init(&wtb);
2904         
2905         /* half rounded */
2906         round_box_edges(&wtb, roundboxalign, rect, rad);
2907
2908         widgetbase_draw(&wtb, wcol);
2909 }
2910
2911 static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
2912 {
2913         uiWidgetBase wtb;
2914         const float rad = 0.25f * U.widget_unit;
2915         unsigned char col[4];
2916         
2917         /* state copy! */
2918         wt->wcol = *(wt->wcol_theme);
2919         
2920         widget_init(&wtb);
2921         
2922         if (but->block->drawextra) {
2923                 /* note: drawextra can change rect +1 or -1, to match round errors of existing previews */
2924                 but->block->drawextra(C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
2925                 
2926                 /* make mask to draw over image */
2927                 UI_GetThemeColor3ubv(TH_BACK, col);
2928                 glColor3ubv(col);
2929                 
2930                 round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
2931                 widgetbase_outline(&wtb);
2932         }
2933         
2934         /* outline */
2935         round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
2936         wtb.outline = 1;
2937         wtb.inner = 0;
2938         widgetbase_draw(&wtb, &wt->wcol);
2939         
2940 }
2941
2942
2943 static void widget_disabled(const rcti *rect)
2944 {
2945         float col[4];
2946         
2947         glEnable(GL_BLEND);
2948         
2949         /* can't use theme TH_BACK or TH_PANEL... undefined */
2950         glGetFloatv(GL_COLOR_CLEAR_VALUE, col);
2951         glColor4f(col[0], col[1], col[2], 0.5f);
2952
2953         /* need -1 and +1 to make it work right for aligned buttons,
2954          * but problem may be somewhere else? */
2955         glRectf(rect->xmin - 1, rect->ymin - 1, rect->xmax, rect->ymax + 1);
2956         
2957         glDisable(GL_BLEND);
2958 }
2959
2960 static uiWidgetType *widget_type(uiWidgetTypeEnum type)
2961 {
2962         bTheme *btheme = UI_GetTheme();
2963         static uiWidgetType wt;
2964         
2965         /* defaults */
2966         wt.wcol_theme = &btheme->tui.wcol_regular;
2967         wt.wcol_state = &btheme->tui.wcol_state;
2968         wt.state = widget_state;
2969         wt.draw = widget_but;
2970         wt.custom = NULL;
2971         wt.text = widget_draw_text_icon;
2972         
2973         switch (type) {
2974                 case UI_WTYPE_REGULAR:
2975                         break;
2976
2977                 case UI_WTYPE_LABEL:
2978                         wt.draw = NULL;
2979                         wt.state = widget_state_label;
2980                         break;
2981                         
2982                 case UI_WTYPE_TOGGLE:
2983                         wt.wcol_theme = &btheme->tui.wcol_toggle;
2984                         break;
2985                         
2986                 case UI_WTYPE_OPTION:
2987                         wt.wcol_theme = &btheme->tui.wcol_option;
2988                         wt.draw = widget_optionbut;
2989                         break;
2990                         
2991                 case UI_WTYPE_RADIO:
2992                         wt.wcol_theme = &btheme->tui.wcol_radio;
2993                         wt.draw = widget_radiobut;
2994                         break;
2995
2996                 case UI_WTYPE_NUMBER:
2997                         wt.wcol_theme = &btheme->tui.wcol_num;
2998                         wt.draw = widget_numbut;
2999                         break;
3000                         
3001                 case UI_WTYPE_SLIDER:
3002                         wt.wcol_theme = &btheme->tui.wcol_numslider;
3003                         wt.custom = widget_numslider;
3004                         wt.state = widget_state_numslider;
3005                         break;
3006                         
3007                 case UI_WTYPE_EXEC:
3008                         wt.wcol_theme = &btheme->tui.wcol_tool;
3009                         wt.draw = widget_roundbut;
3010                         break;
3011
3012                 case UI_WTYPE_TOOLTIP:
3013                         wt.wcol_theme = &btheme->tui.wcol_tooltip;
3014                         wt.draw = widget_menu_back;
3015                         break;
3016                         
3017                         
3018                 /* strings */
3019                 case UI_WTYPE_NAME:
3020                         wt.wcol_theme = &btheme->tui.wcol_text;
3021                         wt.draw = widget_textbut;
3022                         break;
3023                         
3024                 case UI_WTYPE_NAME_LINK:
3025                         break;
3026                         
3027                 case UI_WTYPE_POINTER_LINK:
3028                         break;
3029                         
3030                 case UI_WTYPE_FILENAME:
3031                         break;
3032                         
3033                         
3034                 /* start menus */
3035                 case UI_WTYPE_MENU_RADIO:
3036                         wt.wcol_theme = &btheme->tui.wcol_menu;
3037                         wt.draw = widget_menubut;
3038                         break;
3039
3040                 case UI_WTYPE_MENU_ICON_RADIO:
3041                         wt.wcol_theme = &btheme->tui.wcol_menu;
3042                         wt.draw = widget_menuiconbut;
3043                         break;
3044                         
3045                 case UI_WTYPE_MENU_POINTER_LINK:
3046                         wt.wcol_theme = &btheme->tui.wcol_menu;
3047                         wt.draw = widget_menubut;
3048                         break;
3049
3050                 case UI_WTYPE_MENU_NODE_LINK:
3051                         wt.wcol_theme = &btheme->tui.wcol_menu;
3052                         wt.draw = widget_menunodebut;
3053                         break;
3054                         
3055                 case UI_WTYPE_PULLDOWN:
3056                         wt.wcol_theme = &btheme->tui.wcol_pulldown;
3057                         wt.draw = widget_pulldownbut;
3058                         wt.state = widget_state_pulldown;
3059                         break;
3060                         
3061                 /* in menus */
3062                 case UI_WTYPE_MENU_ITEM:
3063                         wt.wcol_theme = &btheme->tui.wcol_menu_item;
3064                         wt.draw = widget_menu_itembut;
3065                         wt.state = widget_state_menu_item;
3066                         break;
3067                         
3068                 case UI_WTYPE_MENU_BACK:
3069                         wt.wcol_theme = &btheme->tui.wcol_menu_back;
3070                         wt.draw = widget_menu_back;
3071                         break;
3072                         
3073                 /* specials */
3074                 case UI_WTYPE_ICON:
3075                         wt.custom = widget_icon_has_anim;
3076                         break;
3077                         
3078                 case UI_WTYPE_SWATCH:
3079                         wt.custom = widget_swatch;
3080                         break;
3081                         
3082                 case UI_WTYPE_BOX:
3083                         wt.custom = widget_box;
3084                         wt.wcol_theme = &btheme->tui.wcol_box;
3085                         break;
3086                         
3087                 case UI_WTYPE_RGB_PICKER:
3088                         break;
3089                         
3090                 case UI_WTYPE_NORMAL:
3091                         wt.custom = widget_normal;
3092                         break;
3093
3094                 case UI_WTYPE_SCROLL:
3095                         wt.wcol_theme = &btheme->tui.wcol_scroll;
3096                         wt.state = widget_state_nothing;
3097                         wt.custom = widget_scroll;
3098                         break;
3099
3100                 case UI_WTYPE_LISTITEM:
3101                         wt.wcol_theme = &btheme->tui.wcol_list_item;
3102                         wt.draw = widget_list_itembut;
3103                         break;
3104                         
3105                 case UI_WTYPE_PROGRESSBAR:
3106                         wt.wcol_theme = &btheme->tui.wcol_progress;
3107                         wt.custom = widget_progressbar;
3108                         break;
3109         }
3110         
3111         return &wt;
3112 }
3113
3114
3115 static int widget_roundbox_set(uiBut *but, rcti *rect)
3116 {
3117         int roundbox = UI_CNR_ALL;
3118
3119         /* alignment */
3120         if ((but->flag & UI_BUT_ALIGN) && but->type != PULLDOWN) {
3121                 
3122                 /* ui_block_position has this correction too, keep in sync */
3123                 if (but->flag & UI_BUT_ALIGN_TOP)
3124                         rect->ymax += U.pixelsize;
3125                 if (but->flag & UI_BUT_ALIGN_LEFT)
3126                         rect->xmin -= U.pixelsize;
3127                 
3128                 switch (but->flag & UI_BUT_ALIGN) {
3129                         case UI_BUT_ALIGN_TOP:
3130                                 roundbox = UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
3131                                 break;
3132                         case UI_BUT_ALIGN_DOWN:
3133                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
3134                                 break;
3135                         case UI_BUT_ALIGN_LEFT:
3136                                 roundbox = UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
3137                                 break;
3138                         case UI_BUT_ALIGN_RIGHT:
3139                                 roundbox = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
3140                                 break;
3141                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
3142                                 roundbox = UI_CNR_TOP_LEFT;
3143                                 break;
3144                         case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
3145                                 roundbox = UI_CNR_TOP_RIGHT;
3146                                 break;
3147                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
3148                                 roundbox = UI_CNR_BOTTOM_LEFT;
3149                                 break;
3150                         case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
3151                                 roundbox = UI_CNR_BOTTOM_RIGHT;
3152                                 break;
3153                         default: