code cleanup: favor braces when blocks have mixed brace use.
[blender.git] / source / blender / editors / interface / interface.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) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation 2002-2008, full recode.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/interface/interface.c
27  *  \ingroup edinterface
28  */
29
30
31 #include <float.h>
32 #include <limits.h>
33 #include <math.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stddef.h>  /* offsetof() */
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43
44 #include "BLI_math.h"
45 #include "BLI_listbase.h"
46 #include "BLI_string.h"
47 #include "BLI_string_utf8.h"
48 #include "BLI_path_util.h"
49 #include "BLI_rect.h"
50
51 #include "BLI_dynstr.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_context.h"
55 #include "BKE_library.h"
56 #include "BKE_unit.h"
57 #include "BKE_screen.h"
58 #include "BKE_idprop.h"
59
60 #include "BIF_gl.h"
61
62 #include "BLF_api.h"
63 #include "BLF_translation.h"
64
65 #include "UI_interface.h"
66
67 #include "IMB_imbuf.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71 #include "wm_subwindow.h"
72
73 #include "RNA_access.h"
74
75 #include "BPY_extern.h"
76
77 #include "IMB_colormanagement.h"
78
79 #include "interface_intern.h"
80
81 #define PRECISION_FLOAT_MAX 6
82 #define PRECISION_FLOAT_MAX_POW 1000000 /* pow(10, PRECISION_FLOAT_MAX)  */
83
84 /* avoid unneeded calls to ui_get_but_val */
85 #define UI_BUT_VALUE_UNSET DBL_MAX
86 #define UI_GET_BUT_VALUE_INIT(_but, _value) if (_value == DBL_MAX) {  (_value) = ui_get_but_val(_but); } (void)0
87
88 /* 
89  * a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt
90  * 
91  * uiBlahBlah()         external function
92  * ui_blah_blah()       internal function
93  */
94
95 static void ui_free_but(const bContext *C, uiBut *but);
96
97 /* ************* window matrix ************** */
98
99 void ui_block_to_window_fl(const ARegion *ar, uiBlock *block, float *x, float *y)
100 {
101         float gx, gy;
102         int sx, sy, getsizex, getsizey;
103
104         getsizex = BLI_rcti_size_x(&ar->winrct) + 1;
105         getsizey = BLI_rcti_size_y(&ar->winrct) + 1;
106         sx = ar->winrct.xmin;
107         sy = ar->winrct.ymin;
108
109         gx = *x;
110         gy = *y;
111
112         if (block->panel) {
113                 gx += block->panel->ofsx;
114                 gy += block->panel->ofsy;
115         }
116
117         *x = ((float)sx) + ((float)getsizex) * (0.5f + 0.5f * (gx * block->winmat[0][0] + gy * block->winmat[1][0] + block->winmat[3][0]));
118         *y = ((float)sy) + ((float)getsizey) * (0.5f + 0.5f * (gx * block->winmat[0][1] + gy * block->winmat[1][1] + block->winmat[3][1]));
119 }
120
121 void ui_block_to_window(const ARegion *ar, uiBlock *block, int *x, int *y)
122 {
123         float fx, fy;
124
125         fx = *x;
126         fy = *y;
127
128         ui_block_to_window_fl(ar, block, &fx, &fy);
129
130         *x = (int)(fx + 0.5f);
131         *y = (int)(fy + 0.5f);
132 }
133
134 void ui_block_to_window_rct(const ARegion *ar, uiBlock *block, const rctf *graph, rcti *winr)
135 {
136         rctf tmpr;
137
138         tmpr = *graph;
139         ui_block_to_window_fl(ar, block, &tmpr.xmin, &tmpr.ymin);
140         ui_block_to_window_fl(ar, block, &tmpr.xmax, &tmpr.ymax);
141
142         BLI_rcti_rctf_copy(winr, &tmpr);
143 }
144
145 void ui_window_to_block_fl(const ARegion *ar, uiBlock *block, float *x, float *y)   /* for mouse cursor */
146 {
147         float a, b, c, d, e, f, px, py;
148         int sx, sy, getsizex, getsizey;
149
150         getsizex = BLI_rcti_size_x(&ar->winrct) + 1;
151         getsizey = BLI_rcti_size_y(&ar->winrct) + 1;
152         sx = ar->winrct.xmin;
153         sy = ar->winrct.ymin;
154
155         a = 0.5f * ((float)getsizex) * block->winmat[0][0];
156         b = 0.5f * ((float)getsizex) * block->winmat[1][0];
157         c = 0.5f * ((float)getsizex) * (1.0f + block->winmat[3][0]);
158
159         d = 0.5f * ((float)getsizey) * block->winmat[0][1];
160         e = 0.5f * ((float)getsizey) * block->winmat[1][1];
161         f = 0.5f * ((float)getsizey) * (1.0f + block->winmat[3][1]);
162
163         px = *x - sx;
164         py = *y - sy;
165
166         *y =  (a * (py - f) + d * (c - px)) / (a * e - d * b);
167         *x = (px - b * (*y) - c) / a;
168
169         if (block->panel) {
170                 *x -= block->panel->ofsx;
171                 *y -= block->panel->ofsy;
172         }
173 }
174
175 void ui_window_to_block(const ARegion *ar, uiBlock *block, int *x, int *y)
176 {
177         float fx, fy;
178
179         fx = *x;
180         fy = *y;
181
182         ui_window_to_block_fl(ar, block, &fx, &fy);
183
184         *x = (int)(fx + 0.5f);
185         *y = (int)(fy + 0.5f);
186 }
187
188 void ui_window_to_region(const ARegion *ar, int *x, int *y)
189 {
190         *x -= ar->winrct.xmin;
191         *y -= ar->winrct.ymin;
192 }
193
194 /* ******************* block calc ************************* */
195
196 void ui_block_translate(uiBlock *block, int x, int y)
197 {
198         uiBut *but;
199
200         for (but = block->buttons.first; but; but = but->next) {
201                 BLI_rctf_translate(&but->rect, x, y);
202         }
203
204         BLI_rctf_translate(&block->rect, x, y);
205 }
206
207 static void ui_text_bounds_block(uiBlock *block, float offset)
208 {
209         uiStyle *style = UI_GetStyle();
210         uiBut *bt;
211         int i = 0, j, x1addval = offset, nextcol;
212         int lastcol = 0, col = 0;
213         
214         uiStyleFontSet(&style->widget);
215         
216         for (bt = block->buttons.first; bt; bt = bt->next) {
217                 if (bt->type != SEPR) {
218                         j = BLF_width(style->widget.uifont_id, bt->drawstr);
219
220                         if (j > i) i = j;
221                 }
222
223                 if (bt->next && bt->rect.xmin < bt->next->rect.xmin)
224                         lastcol++;
225         }
226
227         /* cope with multi collumns */
228         bt = block->buttons.first;
229         while (bt) {
230                 if (bt->next && bt->rect.xmin < bt->next->rect.xmin) {
231                         nextcol = 1;
232                         col++;
233                 }
234                 else {
235                         nextcol = 0;
236                 }
237                 
238                 bt->rect.xmin = x1addval;
239                 bt->rect.xmax = bt->rect.xmin + i + block->bounds;
240                 
241                 if (col == lastcol) {
242                         bt->rect.xmax = max_ff(bt->rect.xmax, offset + block->minbounds);
243                 }
244
245                 ui_check_but(bt);  /* clips text again */
246                 
247                 if (nextcol)
248                         x1addval += i + block->bounds;
249                 
250                 bt = bt->next;
251         }
252 }
253
254 void ui_bounds_block(uiBlock *block)
255 {
256         uiBut *bt;
257         int xof;
258         
259         if (block->buttons.first == NULL) {
260                 if (block->panel) {
261                         block->rect.xmin = 0.0; block->rect.xmax = block->panel->sizex;
262                         block->rect.ymin = 0.0; block->rect.ymax = block->panel->sizey;
263                 }
264         }
265         else {
266         
267                 BLI_rctf_init_minmax(&block->rect);
268
269                 for (bt = block->buttons.first; bt; bt = bt->next) {
270                         BLI_rctf_union(&block->rect, &bt->rect);
271                 }
272                 
273                 block->rect.xmin -= block->bounds;
274                 block->rect.ymin -= block->bounds;
275                 block->rect.xmax += block->bounds;
276                 block->rect.ymax += block->bounds;
277         }
278
279         block->rect.xmax = block->rect.xmin + max_ff(BLI_rctf_size_x(&block->rect), block->minbounds);
280
281         /* hardcoded exception... but that one is annoying with larger safety */ 
282         bt = block->buttons.first;
283         if (bt && strncmp(bt->str, "ERROR", 5) == 0) xof = 10;
284         else xof = 40;
285
286         block->safety.xmin = block->rect.xmin - xof;
287         block->safety.ymin = block->rect.ymin - xof;
288         block->safety.xmax = block->rect.xmax + xof;
289         block->safety.ymax = block->rect.ymax + xof;
290 }
291
292 static void ui_centered_bounds_block(const bContext *C, uiBlock *block)
293 {
294         wmWindow *window = CTX_wm_window(C);
295         int xmax, ymax;
296         int startx, starty;
297         int width, height;
298         
299         /* note: this is used for the splash where window bounds event has not been
300          * updated by ghost, get the window bounds from ghost directly */
301
302         xmax = WM_window_pixels_x(window);
303         ymax = WM_window_pixels_y(window);
304
305         ui_bounds_block(block);
306         
307         width  = BLI_rctf_size_x(&block->rect);
308         height = BLI_rctf_size_y(&block->rect);
309         
310         startx = (xmax * 0.5f) - (width * 0.5f);
311         starty = (ymax * 0.5f) - (height * 0.5f);
312         
313         ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
314         
315         /* now recompute bounds and safety */
316         ui_bounds_block(block);
317         
318 }
319 static void ui_popup_bounds_block(const bContext *C, uiBlock *block, eBlockBoundsCalc bounds_calc)
320 {
321         wmWindow *window = CTX_wm_window(C);
322         int startx, starty, endx, endy, width, height, oldwidth, oldheight;
323         int oldbounds, xmax, ymax;
324         const int margin = UI_SCREEN_MARGIN;
325
326         oldbounds = block->bounds;
327
328         /* compute mouse position with user defined offset */
329         ui_bounds_block(block);
330         
331         xmax = WM_window_pixels_x(window);
332         ymax = WM_window_pixels_y(window);
333
334         oldwidth  = BLI_rctf_size_x(&block->rect);
335         oldheight = BLI_rctf_size_y(&block->rect);
336
337         /* first we ensure wide enough text bounds */
338         if (bounds_calc == UI_BLOCK_BOUNDS_POPUP_MENU) {
339                 if (block->flag & UI_BLOCK_LOOP) {
340                         block->bounds = 2.5f * UI_UNIT_X;
341                         ui_text_bounds_block(block, block->rect.xmin);
342                 }
343         }
344
345         /* next we recompute bounds */
346         block->bounds = oldbounds;
347         ui_bounds_block(block);
348
349         /* and we adjust the position to fit within window */
350         width  = BLI_rctf_size_x(&block->rect);
351         height = BLI_rctf_size_y(&block->rect);
352
353         /* avoid divide by zero below, caused by calling with no UI, but better not crash */
354         oldwidth = oldwidth > 0 ? oldwidth : MAX2(1, width);
355         oldheight = oldheight > 0 ? oldheight : MAX2(1, height);
356
357         /* offset block based on mouse position, user offset is scaled
358          * along in case we resized the block in ui_text_bounds_block */
359         startx = window->eventstate->x + block->rect.xmin + (block->mx * width) / oldwidth;
360         starty = window->eventstate->y + block->rect.ymin + (block->my * height) / oldheight;
361
362         if (startx < margin)
363                 startx = margin;
364         if (starty < margin)
365                 starty = margin;
366
367         endx = startx + width;
368         endy = starty + height;
369
370         if (endx > xmax) {
371                 endx = xmax - margin;
372                 startx = endx - width;
373         }
374         if (endy > ymax - margin) {
375                 endy = ymax - margin;
376                 starty = endy - height;
377         }
378
379         ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
380
381         /* now recompute bounds and safety */
382         ui_bounds_block(block);
383 }
384
385 /* used for various cases */
386 void uiBoundsBlock(uiBlock *block, int addval)
387 {
388         if (block == NULL)
389                 return;
390         
391         block->bounds = addval;
392         block->bounds_type = UI_BLOCK_BOUNDS;
393 }
394
395 /* used for pulldowns */
396 void uiTextBoundsBlock(uiBlock *block, int addval)
397 {
398         block->bounds = addval;
399         block->bounds_type = UI_BLOCK_BOUNDS_TEXT;
400 }
401
402 /* used for block popups */
403 void uiPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
404 {
405         block->bounds = addval;
406         block->bounds_type = UI_BLOCK_BOUNDS_POPUP_MOUSE;
407         block->mx = mx;
408         block->my = my;
409 }
410
411 /* used for menu popups */
412 void uiMenuPopupBoundsBlock(uiBlock *block, int addval, int mx, int my)
413 {
414         block->bounds = addval;
415         block->bounds_type = UI_BLOCK_BOUNDS_POPUP_MENU;
416         block->mx = mx;
417         block->my = my;
418 }
419
420 /* used for centered popups, i.e. splash */
421 void uiCenteredBoundsBlock(uiBlock *block, int addval)
422 {
423         block->bounds = addval;
424         block->bounds_type = UI_BLOCK_BOUNDS_POPUP_CENTER;
425 }
426
427 void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int maxy)
428 {
429         block->rect.xmin = minx;
430         block->rect.ymin = miny;
431         block->rect.xmax = maxx;
432         block->rect.ymax = maxy;
433         block->bounds_type = UI_BLOCK_BOUNDS_NONE;
434 }
435
436 /* ************** LINK LINE DRAWING  ************* */
437
438 /* link line drawing is not part of buttons or theme.. so we stick with it here */
439
440 static int ui_but_float_precision(uiBut *but, double value)
441 {
442         int prec;
443
444         /* first check if prec is 0 and fallback to a simple default */
445         if ((prec = (int)but->a2) == 0) {
446                 prec = (but->hardmax < 10.001f) ? 3 : 2;
447         }
448
449         /* check on the number of decimal places need to display
450          * the number, this is so 0.00001 is not displayed as 0.00,
451          * _but_, this is only for small values si 10.0001 will not get
452          * the same treatment */
453         if (value != 0.0 && (value = ABS(value)) < 0.1) {
454                 int value_i = (int)((value * PRECISION_FLOAT_MAX_POW) + 0.5);
455                 if (value_i != 0) {
456                         const int prec_span = 3; /* show: 0.01001, 5 would allow 0.0100001 for eg. */
457                         int test_prec;
458                         int prec_min = -1;
459                         int dec_flag = 0;
460                         int i = PRECISION_FLOAT_MAX;
461                         while (i && value_i) {
462                                 if (value_i % 10) {
463                                         dec_flag |= 1 << i;
464                                         prec_min = i;
465                                 }
466                                 value_i /= 10;
467                                 i--;
468                         }
469
470                         /* even though its a small value, if the second last digit is not 0, use it */
471                         test_prec = prec_min;
472
473                         dec_flag = (dec_flag >> (prec_min + 1)) & ((1 << prec_span) - 1);
474
475                         while (dec_flag) {
476                                 test_prec++;
477                                 dec_flag = dec_flag >> 1;
478                         }
479
480                         if (test_prec > prec) {
481                                 prec = test_prec;
482                         }
483                 }
484         }
485
486         CLAMP(prec, 1, PRECISION_FLOAT_MAX);
487
488         return prec;
489 }
490
491 static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines)
492 {
493         rcti rect;
494
495         if (line->from == NULL || line->to == NULL) return;
496         
497         rect.xmin = BLI_rctf_cent_x(&line->from->rect);
498         rect.ymin = BLI_rctf_cent_y(&line->from->rect);
499         rect.xmax = BLI_rctf_cent_x(&line->to->rect);
500         rect.ymax = BLI_rctf_cent_y(&line->to->rect);
501         
502         if (line->flag & UI_SELECT)
503                 glColor3ub(100, 100, 100);
504         else if (highlightActiveLines && ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE)))
505                 UI_ThemeColor(TH_TEXT_HI);
506         else 
507                 glColor3ub(0, 0, 0);
508
509         ui_draw_link_bezier(&rect);
510 }
511
512 static void ui_draw_links(uiBlock *block)
513 {
514         uiBut *but;
515         uiLinkLine *line;
516
517         /* Draw the inactive lines (lines with neither button being hovered over).
518          * As we go, remember if we see any active or selected lines. */
519         int foundselectline = FALSE;
520         int foundactiveline = FALSE;
521         for (but = block->buttons.first; but; but = but->next) {
522                 if (but->type == LINK && but->link) {
523                         for (line = but->link->lines.first; line; line = line->next) {
524                                 if (!(line->from->flag & UI_ACTIVE) && !(line->to->flag & UI_ACTIVE))
525                                         ui_draw_linkline(line, 0);
526                                 else
527                                         foundactiveline = TRUE;
528
529                                 if ((line->from->flag & UI_SELECT) || (line->to->flag & UI_SELECT))
530                                         foundselectline = TRUE;
531                         }
532                 }
533         }
534
535         /* Draw any active lines (lines with either button being hovered over).
536          * Do this last so they appear on top of inactive lines. */
537         if (foundactiveline) {
538                 for (but = block->buttons.first; but; but = but->next) {
539                         if (but->type == LINK && but->link) {
540                                 for (line = but->link->lines.first; line; line = line->next) {
541                                         if ((line->from->flag & UI_ACTIVE) || (line->to->flag & UI_ACTIVE))
542                                                 ui_draw_linkline(line, !foundselectline);
543                                 }
544                         }
545                 }
546         }
547 }
548
549 /* ************** BLOCK ENDING FUNCTION ************* */
550
551 /* NOTE: if but->poin is allocated memory for every defbut, things fail... */
552 static int ui_but_equals_old(uiBut *but, uiBut *oldbut)
553 {
554         /* various properties are being compared here, hopefully sufficient
555          * to catch all cases, but it is simple to add more checks later */
556         if (but->retval != oldbut->retval) return 0;
557         if (but->rnapoin.data != oldbut->rnapoin.data) return 0;
558         if (but->rnaprop != oldbut->rnaprop)
559                 if (but->rnaindex != oldbut->rnaindex) return 0;
560         if (but->func != oldbut->func) return 0;
561         if (but->funcN != oldbut->funcN) return 0;
562         if (oldbut->func_arg1 != oldbut && but->func_arg1 != oldbut->func_arg1) return 0;
563         if (oldbut->func_arg2 != oldbut && but->func_arg2 != oldbut->func_arg2) return 0;
564         if (!but->funcN && ((but->poin != oldbut->poin && (uiBut *)oldbut->poin != oldbut) || but->pointype != oldbut->pointype)) return 0;
565         if (but->optype != oldbut->optype) return 0;
566
567         return 1;
568 }
569
570 /* oldbut is being inserted in new block, so we use the lines from new button, and replace button pointers */
571 static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut)
572 {
573         uiLinkLine *line;
574         uiBut *but;
575         
576         /* if active button is LINK */
577         if (newbut->type == LINK && newbut->link) {
578                 
579                 SWAP(uiLink *, oldbut->link, newbut->link);
580                 
581                 for (line = oldbut->link->lines.first; line; line = line->next) {
582                         if (line->to == newbut)
583                                 line->to = oldbut;
584                         if (line->from == newbut)
585                                 line->from = oldbut;
586                 }
587         }
588         
589         /* check all other button links */
590         for (but = block->buttons.first; but; but = but->next) {
591                 if (but != newbut && but->type == LINK && but->link) {
592                         for (line = but->link->lines.first; line; line = line->next) {
593                                 if (line->to == newbut)
594                                         line->to = oldbut;
595                                 if (line->from == newbut)
596                                         line->from = oldbut;
597                         }
598                 }
599         }
600 }
601
602 static int ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBut **butpp)
603 {
604         uiBlock *oldblock;
605         uiBut *oldbut, *but = *butpp;
606         int found = 0;
607
608         oldblock = block->oldblock;
609         if (!oldblock)
610                 return found;
611
612         for (oldbut = oldblock->buttons.first; oldbut; oldbut = oldbut->next) {
613                 if (ui_but_equals_old(oldbut, but)) {
614                         if (oldbut->active) {
615 #if 0
616 //                              but->flag = oldbut->flag;
617 #else
618                                 /* exception! redalert flag can't be update from old button. 
619                                  * perhaps it should only copy specific flags rather than all. */
620 //                              but->flag = (oldbut->flag & ~UI_BUT_REDALERT) | (but->flag & UI_BUT_REDALERT);
621 #endif
622 //                              but->active = oldbut->active;
623 //                              but->pos = oldbut->pos;
624 //                              but->ofs = oldbut->ofs;
625 //                              but->editstr = oldbut->editstr;
626 //                              but->editval = oldbut->editval;
627 //                              but->editvec = oldbut->editvec;
628 //                              but->editcoba = oldbut->editcoba;
629 //                              but->editcumap = oldbut->editcumap;
630 //                              but->selsta = oldbut->selsta;
631 //                              but->selend = oldbut->selend;
632 //                              but->softmin = oldbut->softmin;
633 //                              but->softmax = oldbut->softmax;
634 //                              but->linkto[0] = oldbut->linkto[0];
635 //                              but->linkto[1] = oldbut->linkto[1];
636                                 found = 1;
637 //                              oldbut->active = NULL;
638                         
639                                 /* move button over from oldblock to new block */
640                                 BLI_remlink(&oldblock->buttons, oldbut);
641                                 BLI_insertlinkafter(&block->buttons, but, oldbut);
642                                 oldbut->block = block;
643                                 *butpp = oldbut;
644                                 
645                                 /* still stuff needs to be copied */
646                                 oldbut->rect = but->rect;
647                                 oldbut->context = but->context; /* set by Layout */
648                                 
649                                 /* typically the same pointers, but not on undo/redo */
650                                 /* XXX some menu buttons store button itself in but->poin. Ugly */
651                                 if (oldbut->poin != (char *)oldbut) {
652                                         SWAP(char *, oldbut->poin, but->poin);
653                                         SWAP(void *, oldbut->func_argN, but->func_argN);
654                                 }
655                                 
656                                 /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
657                                  * when scrolling without moving mouse (see [#28432]) */
658                                 if (ELEM(oldbut->type, ROW, LISTROW))
659                                         oldbut->hardmax = but->hardmax;
660                                 
661                                 ui_but_update_linklines(block, oldbut, but);
662                                 
663                                 BLI_remlink(&block->buttons, but);
664                                 ui_free_but(C, but);
665                                 
666                                 /* note: if layout hasn't been applied yet, it uses old button pointers... */
667                         }
668                         else {
669                                 /* ensures one button can get activated, and in case the buttons
670                                  * draw are the same this gives O(1) lookup for each button */
671                                 BLI_remlink(&oldblock->buttons, oldbut);
672                                 ui_free_but(C, oldbut);
673                         }
674                         
675                         break;
676                 }
677         }
678         
679         return found;
680 }
681
682 /* needed for temporarily rename buttons, such as in outliner or file-select,
683  * they should keep calling uiDefButs to keep them alive */
684 /* returns 0 when button removed */
685 int uiButActiveOnly(const bContext *C, uiBlock *block, uiBut *but)
686 {
687         uiBlock *oldblock;
688         uiBut *oldbut;
689         int activate = FALSE, found = FALSE, isactive = FALSE;
690         
691         oldblock = block->oldblock;
692         if (!oldblock)
693                 activate = TRUE;
694         else {
695                 for (oldbut = oldblock->buttons.first; oldbut; oldbut = oldbut->next) {
696                         if (ui_but_equals_old(oldbut, but)) {
697                                 found = TRUE;
698                                 
699                                 if (oldbut->active)
700                                         isactive = TRUE;
701                                 
702                                 break;
703                         }
704                 }
705         }
706         if ((activate == TRUE) || (found == FALSE)) {
707                 ui_button_activate_do((bContext *)C, CTX_wm_region(C), but);
708         }
709         else if ((found == TRUE) && (isactive == FALSE)) {
710                 BLI_remlink(&block->buttons, but);
711                 ui_free_but(C, but);
712                 return 0;
713         }
714         
715         return 1;
716 }
717
718 /* simulate button click */
719 void uiButExecute(const bContext *C, uiBut *but)
720 {
721         ui_button_execute_do((bContext *)C, CTX_wm_region(C), but);
722 }
723
724 /* use to check if we need to disable undo, but don't make any changes
725  * returns FALSE if undo needs to be disabled. */
726 static int ui_but_is_rna_undo(uiBut *but)
727 {
728         if (but->rnapoin.id.data) {
729                 /* avoid undo push for buttons who's ID are screen or wm level
730                  * we could disable undo for buttons with no ID too but may have
731                  * unforeseen consequences, so best check for ID's we _know_ are not
732                  * handled by undo - campbell */
733                 ID *id = but->rnapoin.id.data;
734                 if (ID_CHECK_UNDO(id) == FALSE) {
735                         return FALSE;
736                 }
737                 else {
738                         return TRUE;
739                 }
740         }
741         else if (but->rnapoin.type && !RNA_struct_undo_check(but->rnapoin.type)) {
742                 return FALSE;
743         }
744
745         return TRUE;
746 }
747
748 /* assigns automatic keybindings to menu items for fast access
749  * (underline key in menu) */
750 static void ui_menu_block_set_keyaccels(uiBlock *block)
751 {
752         uiBut *but;
753
754         unsigned int menu_key_mask = 0;
755         unsigned char menu_key;
756         const char *str_pt;
757         int pass;
758         int tot_missing = 0;
759
760         /* only do it before bounding */
761         if (block->rect.xmin != block->rect.xmax)
762                 return;
763
764         for (pass = 0; pass < 2; pass++) {
765                 /* 2 Passes, on for first letter only, second for any letter if first fails
766                  * fun first pass on all buttons so first word chars always get first priority */
767
768                 for (but = block->buttons.first; but; but = but->next) {
769                         if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
770                                 /* pass */
771                         }
772                         else if (but->menu_key == '\0') {
773                                 if (but->str) {
774                                         for (str_pt = but->str; *str_pt; ) {
775                                                 menu_key = tolower(*str_pt);
776                                                 if ((menu_key >= 'a' && menu_key <= 'z') && !(menu_key_mask & 1 << (menu_key - 'a'))) {
777                                                         menu_key_mask |= 1 << (menu_key - 'a');
778                                                         break;
779                                                 }
780
781                                                 if (pass == 0) {
782                                                         /* Skip to next delimiter on first pass (be picky) */
783                                                         while (isalpha(*str_pt))
784                                                                 str_pt++;
785
786                                                         if (*str_pt)
787                                                                 str_pt++;
788                                                 }
789                                                 else {
790                                                         /* just step over every char second pass and find first usable key */
791                                                         str_pt++;
792                                                 }
793                                         }
794
795                                         if (*str_pt) {
796                                                 but->menu_key = menu_key;
797                                         }
798                                         else {
799                                                 /* run second pass */
800                                                 tot_missing++;
801                                         }
802
803                                         /* if all keys have been used just exit, unlikely */
804                                         if (menu_key_mask == (1 << 26) - 1) {
805                                                 return;
806                                         }
807                                 }
808                         }
809                 }
810
811                 /* check if second pass is needed */
812                 if (!tot_missing) {
813                         break;
814                 }
815         }
816 }
817
818 /* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR'
819  * since this is really long its unlikely to be an issue,
820  * but this could be supported */
821 void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const short do_strip)
822 {
823
824         if (do_strip) {
825                 char *cpoin = strchr(but->str, '|');
826                 if (cpoin) {
827                         *cpoin = '\0';
828                 }
829         }
830
831         /* without this, just allow stripping of the shortcut */
832         if (shortcut_str) {
833                 char *butstr_orig;
834
835                 if (but->str != but->strdata) {
836                         butstr_orig = but->str; /* free after using as source buffer */
837                 }
838                 else {
839                         butstr_orig = BLI_strdup(but->str);
840                 }
841                 BLI_snprintf(but->strdata,
842                              sizeof(but->strdata),
843                              "%s|%s",
844                              butstr_orig, shortcut_str);
845                 MEM_freeN(butstr_orig);
846                 but->str = but->strdata;
847                 ui_check_but(but);
848         }
849 }
850
851 static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
852 {
853         uiBut *but;
854         char buf[128];
855
856         /* for menu's */
857         MenuType *mt;
858         IDProperty *prop_menu = NULL;
859         IDProperty *prop_menu_name = NULL;
860
861         /* only do it before bounding */
862         if (block->rect.xmin != block->rect.xmax)
863                 return;
864
865         for (but = block->buttons.first; but; but = but->next) {
866                 if (but->optype) {
867                         IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
868
869                         if (WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, TRUE,
870                                                          buf, sizeof(buf)))
871                         {
872                                 ui_but_add_shortcut(but, buf, FALSE);
873                         }
874                 }
875                 else if ((mt = uiButGetMenuType(but))) {
876                         /* only allocate menu property once */
877                         if (prop_menu == NULL) {
878                                 /* annoying, create a property */
879                                 IDPropertyTemplate val = {0};
880                                 prop_menu = IDP_New(IDP_GROUP, &val, __func__); /* dummy, name is unimportant  */
881                                 IDP_AddToGroup(prop_menu, (prop_menu_name = IDP_NewString("", "name", sizeof(mt->idname))));
882                         }
883
884                         IDP_AssignString(prop_menu_name, mt->idname, sizeof(mt->idname));
885
886                         if (WM_key_event_operator_string(C, "WM_OT_call_menu", WM_OP_INVOKE_REGION_WIN, prop_menu, FALSE,
887                                                          buf, sizeof(buf)))
888                         {
889                                 ui_but_add_shortcut(but, buf, FALSE);
890                         }
891                 }
892         }
893
894         if (prop_menu) {
895                 IDP_FreeProperty(prop_menu);
896                 MEM_freeN(prop_menu);
897         }
898
899 #undef UI_MENU_KEY_STR_CAT
900
901 }
902
903 void uiEndBlock(const bContext *C, uiBlock *block)
904 {
905         uiBut *but;
906         Scene *scene = CTX_data_scene(C);
907
908         /* inherit flags from 'old' buttons that was drawn here previous, based
909          * on matching buttons, we need this to make button event handling non
910          * blocking, while still allowing buttons to be remade each redraw as it
911          * is expected by blender code */
912         for (but = block->buttons.first; but; but = but->next) {
913                 if (ui_but_update_from_old_block(C, block, &but))
914                         ui_check_but(but);
915                 
916                 /* temp? Proper check for graying out */
917                 if (but->optype) {
918                         wmOperatorType *ot = but->optype;
919
920                         if (but->context)
921                                 CTX_store_set((bContext *)C, but->context);
922
923                         if (ot == NULL || WM_operator_poll_context((bContext *)C, ot, but->opcontext) == 0) {
924                                 but->flag |= UI_BUT_DISABLED;
925                                 but->lock = TRUE;
926                         }
927
928                         if (but->context)
929                                 CTX_store_set((bContext *)C, NULL);
930                 }
931
932                 ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
933         }
934
935         if (block->oldblock) {
936                 block->auto_open = block->oldblock->auto_open;
937                 block->auto_open_last = block->oldblock->auto_open_last;
938                 block->tooltipdisabled = block->oldblock->tooltipdisabled;
939                 copy_v3_v3(ui_block_hsv_get(block),
940                            ui_block_hsv_get(block->oldblock));
941
942                 block->oldblock = NULL;
943         }
944
945         /* handle pending stuff */
946         if (block->layouts.first) {
947                 uiBlockLayoutResolve(block, NULL, NULL);
948         }
949         ui_block_do_align(block);
950         if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) {
951                 ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
952         }
953
954         if (block->flag & UI_BLOCK_LOOP) {
955                 ui_menu_block_set_keymaps(C, block);
956         }
957         
958         /* after keymaps! */
959         switch (block->bounds_type) {
960                 case UI_BLOCK_BOUNDS_NONE:
961                         break;
962                 case UI_BLOCK_BOUNDS:
963                         ui_bounds_block(block);
964                         break;
965                 case UI_BLOCK_BOUNDS_TEXT:
966                         ui_text_bounds_block(block, 0.0f);
967                         break;
968                 case UI_BLOCK_BOUNDS_POPUP_CENTER:
969                         ui_centered_bounds_block(C, block);
970                         break;
971
972                         /* fallback */
973                 case UI_BLOCK_BOUNDS_POPUP_MOUSE:
974                 case UI_BLOCK_BOUNDS_POPUP_MENU:
975                         ui_popup_bounds_block(C, block, block->bounds_type);
976                         break;
977         }
978
979         if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
980                 uiBoundsBlock(block, 0);
981         }
982         if (block->flag & UI_BUT_ALIGN) {
983                 uiBlockEndAlign(block);
984         }
985
986         block->endblock = 1;
987 }
988
989 /* ************** BLOCK DRAWING FUNCTION ************* */
990
991 void ui_fontscale(short *points, float aspect)
992 {
993         if (aspect < 0.9f || aspect > 1.1f) {
994                 float pointsf = *points;
995                 
996                 /* for some reason scaling fonts goes too fast compared to widget size */
997                 /* XXX not true anymore? (ton) */
998                 //aspect = sqrt(aspect);
999                 pointsf /= aspect;
1000                 
1001                 if (aspect > 1.0f)
1002                         *points = ceilf(pointsf);
1003                 else
1004                         *points = floorf(pointsf);
1005         }
1006 }
1007
1008 /* project button or block (but==NULL) to pixels in regionspace */
1009 static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, uiBut *but)
1010 {
1011         rctf rectf = (but) ? but->rect : block->rect;
1012         
1013         ui_block_to_window_fl(ar, block, &rectf.xmin, &rectf.ymin);
1014         ui_block_to_window_fl(ar, block, &rectf.xmax, &rectf.ymax);
1015         
1016         rectf.xmin -= ar->winrct.xmin;
1017         rectf.ymin -= ar->winrct.ymin;
1018         rectf.xmax -= ar->winrct.xmin;
1019         rectf.ymax -= ar->winrct.ymin;
1020
1021         rect->xmin = floorf(rectf.xmin);
1022         rect->ymin = floorf(rectf.ymin);
1023         rect->xmax = floorf(rectf.xmax);
1024         rect->ymax = floorf(rectf.ymax);
1025 }
1026
1027 /* uses local copy of style, to scale things down, and allow widgets to change stuff */
1028 void uiDrawBlock(const bContext *C, uiBlock *block)
1029 {
1030         uiStyle style = *UI_GetStyleDraw();  /* XXX pass on as arg */
1031         ARegion *ar;
1032         uiBut *but;
1033         rcti rect;
1034         int multisample_enabled;
1035         
1036         /* get menu region or area region */
1037         ar = CTX_wm_menu(C);
1038         if (!ar)
1039                 ar = CTX_wm_region(C);
1040
1041         if (!block->endblock)
1042                 uiEndBlock(C, block);
1043
1044         /* disable AA, makes widgets too blurry */
1045         multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
1046         if (multisample_enabled)
1047                 glDisable(GL_MULTISAMPLE_ARB);
1048
1049         /* we set this only once */
1050         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1051         
1052         /* scale fonts */
1053         ui_fontscale(&style.paneltitle.points, block->aspect);
1054         ui_fontscale(&style.grouplabel.points, block->aspect);
1055         ui_fontscale(&style.widgetlabel.points, block->aspect);
1056         ui_fontscale(&style.widget.points, block->aspect);
1057         
1058         /* scale block min/max to rect */
1059         ui_but_to_pixelrect(&rect, ar, block, NULL);
1060         
1061         /* pixel space for AA widgets */
1062         glMatrixMode(GL_PROJECTION);
1063         glPushMatrix();
1064         glMatrixMode(GL_MODELVIEW);
1065         glPushMatrix();
1066         glLoadIdentity();
1067         
1068         wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
1069         
1070         /* back */
1071         if (block->flag & UI_BLOCK_LOOP)
1072                 ui_draw_menu_back(&style, block, &rect);
1073         else if (block->panel)
1074                 ui_draw_aligned_panel(&style, block, &rect);
1075
1076         /* widgets */
1077         for (but = block->buttons.first; but; but = but->next) {
1078                 if (!(but->flag & (UI_HIDDEN | UI_SCROLLED))) {
1079                         ui_but_to_pixelrect(&rect, ar, block, but);
1080                 
1081                         /* XXX: figure out why invalid coordinates happen when closing render window */
1082                         /* and material preview is redrawn in main window (temp fix for bug #23848) */
1083                         if (rect.xmin < rect.xmax && rect.ymin < rect.ymax)
1084                                 ui_draw_but(C, ar, &style, but, &rect);
1085                 }
1086         }
1087         
1088         /* restore matrix */
1089         glMatrixMode(GL_PROJECTION);
1090         glPopMatrix();
1091         glMatrixMode(GL_MODELVIEW);
1092         glPopMatrix();
1093
1094         if (multisample_enabled)
1095                 glEnable(GL_MULTISAMPLE_ARB);
1096         
1097         ui_draw_links(block);
1098 }
1099
1100 /* ************* EVENTS ************* */
1101
1102 int ui_is_but_push_ex(uiBut *but, double *value)
1103 {
1104         int is_push = false;  /* (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOHING) */
1105
1106         if (but->bit) {
1107                 const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
1108                 int lvalue;
1109                 UI_GET_BUT_VALUE_INIT(but, *value);
1110                 lvalue = (int)*value;
1111                 if (UI_BITBUT_TEST(lvalue, (but->bitnr))) {
1112                         is_push = state;
1113                 }
1114                 else {
1115                         is_push = !state;
1116                 }
1117         }
1118         else {
1119                 switch (but->type) {
1120                         case BUT:
1121                         case HOTKEYEVT:
1122                         case KEYEVT:
1123                         case COLOR:
1124                                 is_push = -1;
1125                                 break;
1126                         case TOGBUT:
1127                         case TOG:
1128                         case TOGR:
1129                         case TOG3:
1130                         case BUT_TOGDUAL:
1131                         case ICONTOG:
1132                         case OPTION:
1133                                 UI_GET_BUT_VALUE_INIT(but, *value);
1134                                 if (*value != (double)but->hardmin) is_push = true;
1135                                 break;
1136                         case ICONTOGN:
1137                         case TOGN:
1138                         case OPTIONN:
1139                                 UI_GET_BUT_VALUE_INIT(but, *value);
1140                                 if (*value == 0.0) is_push = true;
1141                                 break;
1142                         case ROW:
1143                         case LISTROW:
1144                                 UI_GET_BUT_VALUE_INIT(but, *value);
1145                                 /* support for rna enum buts */
1146                                 if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
1147                                         if ((int)*value & (int)but->hardmax) is_push = true;
1148                                 }
1149                                 else {
1150                                         if (*value == (double)but->hardmax) is_push = true;
1151                                 }
1152                                 break;
1153                         default:
1154                                 is_push = -1;
1155                                 break;
1156                 }
1157         }
1158
1159         return is_push;
1160 }
1161 int ui_is_but_push(uiBut *but)
1162 {
1163         double value = UI_BUT_VALUE_UNSET;
1164         return ui_is_but_push_ex(but, &value);
1165 }
1166
1167 static void ui_check_but_select(uiBut *but, double *value)
1168 {
1169         switch (ui_is_but_push_ex(but, value)) {
1170                 case true:
1171                         but->flag |= UI_SELECT;
1172                         break;
1173                 case false:
1174                         but->flag &= ~UI_SELECT;
1175                         break;
1176         }
1177 }
1178
1179 static uiBut *ui_find_inlink(uiBlock *block, void *poin)
1180 {
1181         uiBut *but;
1182         
1183         but = block->buttons.first;
1184         while (but) {
1185                 if (but->type == INLINK) {
1186                         if (but->poin == poin) return but;
1187                 }
1188                 but = but->next;
1189         }
1190         return NULL;
1191 }
1192
1193 static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
1194 {
1195         uiLinkLine *line;
1196         
1197         line = MEM_callocN(sizeof(uiLinkLine), "linkline");
1198         BLI_addtail(listb, line);
1199         line->from = but;
1200         line->to = bt;
1201 }
1202
1203 uiBut *uiFindInlink(uiBlock *block, void *poin)
1204 {
1205         return ui_find_inlink(block, poin);
1206 }
1207
1208 void uiComposeLinks(uiBlock *block)
1209 {
1210         uiBut *but, *bt;
1211         uiLink *link;
1212         void ***ppoin;
1213         int a;
1214         
1215         but = block->buttons.first;
1216         while (but) {
1217                 if (but->type == LINK) {
1218                         link = but->link;
1219                         
1220                         /* for all pointers in the array */
1221                         if (link) {
1222                                 if (link->ppoin) {
1223                                         ppoin = link->ppoin;
1224                                         for (a = 0; a < *(link->totlink); a++) {
1225                                                 bt = ui_find_inlink(block, (*ppoin)[a]);
1226                                                 if (bt) {
1227                                                         ui_add_link_line(&link->lines, but, bt);
1228                                                 }
1229                                         }
1230                                 }
1231                                 else if (link->poin) {
1232                                         bt = ui_find_inlink(block, *(link->poin) );
1233                                         if (bt) {
1234                                                 ui_add_link_line(&link->lines, but, bt);
1235                                         }
1236                                 }
1237                         }
1238                 }
1239                 but = but->next;
1240         }
1241 }
1242
1243
1244 /* ************************************************ */
1245
1246 void uiBlockSetButLock(uiBlock *block, int val, const char *lockstr)
1247 {
1248         if (val) {
1249                 block->lock = val ? TRUE : FALSE;
1250                 block->lockstr = lockstr;
1251         }
1252 }
1253
1254 void uiBlockClearButLock(uiBlock *block)
1255 {
1256         block->lock = FALSE;
1257         block->lockstr = NULL;
1258 }
1259
1260 /* *************************************************************** */
1261
1262 void ui_delete_linkline(uiLinkLine *line, uiBut *but)
1263 {
1264         uiLink *link;
1265         int a, b;
1266         
1267         BLI_remlink(&but->link->lines, line);
1268
1269         link = line->from->link;
1270
1271         /* are there more pointers allowed? */
1272         if (link->ppoin) {
1273                 
1274                 if (*(link->totlink) == 1) {
1275                         *(link->totlink) = 0;
1276                         MEM_freeN(*(link->ppoin));
1277                         *(link->ppoin) = NULL;
1278                 }
1279                 else {
1280                         b = 0;
1281                         for (a = 0; a < (*(link->totlink)); a++) {
1282                                 if ((*(link->ppoin))[a] != line->to->poin) {
1283                                         (*(link->ppoin))[b] = (*(link->ppoin))[a];
1284                                         b++;
1285                                 }
1286                         }
1287                         (*(link->totlink))--;
1288                 }
1289         }
1290         else {
1291                 *(link->poin) = NULL;
1292         }
1293
1294         MEM_freeN(line);
1295         //REDRAW
1296 }
1297
1298 /* *********************** data get/set ***********************
1299  * this either works with the pointed to data, or can work with
1300  * an edit override pointer while dragging for example */
1301
1302 /* for buttons pointing to color for example */
1303 void ui_get_but_vectorf(uiBut *but, float vec[3])
1304 {
1305         PropertyRNA *prop;
1306         int a;
1307
1308         if (but->editvec) {
1309                 copy_v3_v3(vec, but->editvec);
1310         }
1311
1312         if (but->rnaprop) {
1313                 prop = but->rnaprop;
1314
1315                 zero_v3(vec);
1316
1317                 if (RNA_property_type(prop) == PROP_FLOAT) {
1318                         int tot = RNA_property_array_length(&but->rnapoin, prop);
1319                         BLI_assert(tot > 0);
1320                         if (tot == 3) {
1321                                 RNA_property_float_get_array(&but->rnapoin, prop, vec);
1322                         }
1323                         else {
1324                                 tot = min_ii(tot, 3);
1325                                 for (a = 0; a < tot; a++) {
1326                                         vec[a] = RNA_property_float_get_index(&but->rnapoin, prop, a);
1327                                 }
1328                         }
1329                 }
1330         }
1331         else if (but->pointype == UI_BUT_POIN_CHAR) {
1332                 char *cp = (char *)but->poin;
1333
1334                 vec[0] = ((float)cp[0]) / 255.0f;
1335                 vec[1] = ((float)cp[1]) / 255.0f;
1336                 vec[2] = ((float)cp[2]) / 255.0f;
1337         }
1338         else if (but->pointype == UI_BUT_POIN_FLOAT) {
1339                 float *fp = (float *)but->poin;
1340                 copy_v3_v3(vec, fp);
1341         }
1342         else {
1343                 if (but->editvec == NULL) {
1344                         fprintf(stderr, "%s: can't get color, should never happen\n", __func__);
1345                         zero_v3(vec);
1346                 }
1347         }
1348
1349         if (but->type == BUT_NORMAL) {
1350                 normalize_v3(vec);
1351         }
1352 }
1353
1354 /* for buttons pointing to color for example */
1355 void ui_set_but_vectorf(uiBut *but, const float vec[3])
1356 {
1357         PropertyRNA *prop;
1358
1359         if (but->editvec) {
1360                 copy_v3_v3(but->editvec, vec);
1361         }
1362
1363         if (but->rnaprop) {
1364                 prop = but->rnaprop;
1365
1366                 if (RNA_property_type(prop) == PROP_FLOAT) {
1367                         int tot;
1368                         int a;
1369
1370                         tot = RNA_property_array_length(&but->rnapoin, prop);
1371                         BLI_assert(tot > 0);
1372                         if (tot == 3) {
1373                                 RNA_property_float_set_array(&but->rnapoin, prop, vec);
1374                         }
1375                         else {
1376                                 tot = min_ii(tot, 3);
1377                                 for (a = 0; a < tot; a++) {
1378                                         RNA_property_float_set_index(&but->rnapoin, prop, a, vec[a]);
1379                                 }
1380                         }
1381                 }
1382         }
1383         else if (but->pointype == UI_BUT_POIN_CHAR) {
1384                 char *cp = (char *)but->poin;
1385                 cp[0] = (char)(0.5f + vec[0] * 255.0f);
1386                 cp[1] = (char)(0.5f + vec[1] * 255.0f);
1387                 cp[2] = (char)(0.5f + vec[2] * 255.0f);
1388         }
1389         else if (but->pointype == UI_BUT_POIN_FLOAT) {
1390                 float *fp = (float *)but->poin;
1391                 copy_v3_v3(fp, vec);
1392         }
1393 }
1394
1395 int ui_is_but_float(uiBut *but)
1396 {
1397         if (but->pointype == UI_BUT_POIN_FLOAT && but->poin)
1398                 return 1;
1399         
1400         if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_FLOAT)
1401                 return 1;
1402         
1403         return 0;
1404 }
1405
1406 int ui_is_but_bool(uiBut *but)
1407 {
1408         if (ELEM5(but->type, TOG, TOGN, TOGR, ICONTOG, ICONTOGN))
1409                 return 1;
1410
1411         if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
1412                 return 1;
1413
1414         return 0;
1415 }
1416
1417
1418 int ui_is_but_unit(uiBut *but)
1419 {
1420         UnitSettings *unit = but->block->unit;
1421         const int unit_type = uiButGetUnitType(but);
1422
1423         if (unit_type == PROP_UNIT_NONE)
1424                 return 0;
1425
1426 #if 1 /* removed so angle buttons get correct snapping */
1427         if (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION)
1428                 return 0;
1429 #endif
1430         
1431         /* for now disable time unit conversion */
1432         if (unit_type == PROP_UNIT_TIME)
1433                 return 0;
1434
1435         if (unit->system == USER_UNIT_NONE) {
1436                 if (unit_type != PROP_UNIT_ROTATION) {
1437                         return 0;
1438                 }
1439         }
1440
1441         return 1;
1442 }
1443
1444 int ui_is_but_rna_valid(uiBut *but)
1445 {
1446         if (but->rnaprop == NULL || RNA_struct_contains_property(&but->rnapoin, but->rnaprop)) {
1447                 return TRUE;
1448         }
1449         else {
1450                 printf("property removed %s: %p\n", but->drawstr, but->rnaprop);
1451                 return FALSE;
1452         }
1453 }
1454
1455 double ui_get_but_val(uiBut *but)
1456 {
1457         PropertyRNA *prop;
1458         double value = 0.0;
1459
1460         if (but->editval) { return *(but->editval); }
1461         if (but->poin == NULL && but->rnapoin.data == NULL) return 0.0;
1462
1463         if (but->rnaprop) {
1464                 prop = but->rnaprop;
1465
1466                 BLI_assert(but->rnaindex != -1);
1467
1468                 switch (RNA_property_type(prop)) {
1469                         case PROP_BOOLEAN:
1470                                 if (RNA_property_array_check(prop))
1471                                         value = RNA_property_boolean_get_index(&but->rnapoin, prop, but->rnaindex);
1472                                 else
1473                                         value = RNA_property_boolean_get(&but->rnapoin, prop);
1474                                 break;
1475                         case PROP_INT:
1476                                 if (RNA_property_array_check(prop))
1477                                         value = RNA_property_int_get_index(&but->rnapoin, prop, but->rnaindex);
1478                                 else
1479                                         value = RNA_property_int_get(&but->rnapoin, prop);
1480                                 break;
1481                         case PROP_FLOAT:
1482                                 if (RNA_property_array_check(prop))
1483                                         value = RNA_property_float_get_index(&but->rnapoin, prop, but->rnaindex);
1484                                 else
1485                                         value = RNA_property_float_get(&but->rnapoin, prop);
1486                                 break;
1487                         case PROP_ENUM:
1488                                 value = RNA_property_enum_get(&but->rnapoin, prop);
1489                                 break;
1490                         default:
1491                                 value = 0.0;
1492                                 break;
1493                 }
1494         }
1495         else if (but->type == HSVSLI) {
1496                 float *fp, hsv[3];
1497                 
1498                 fp = (but->editvec) ? but->editvec : (float *)but->poin;
1499                 rgb_to_hsv_v(fp, hsv);
1500
1501                 switch (but->str[0]) {
1502                         case 'H': value = hsv[0]; break;
1503                         case 'S': value = hsv[1]; break;
1504                         case 'V': value = hsv[2]; break;
1505                 }
1506         }
1507         else if (but->pointype == UI_BUT_POIN_CHAR) {
1508                 value = *(char *)but->poin;
1509         }
1510         else if (but->pointype == UI_BUT_POIN_SHORT) {
1511                 value = *(short *)but->poin;
1512         }
1513         else if (but->pointype == UI_BUT_POIN_INT) {
1514                 value = *(int *)but->poin;
1515         }
1516         else if (but->pointype == UI_BUT_POIN_FLOAT) {
1517                 value = *(float *)but->poin;
1518         }
1519
1520         return value;
1521 }
1522
1523 void ui_set_but_val(uiBut *but, double value)
1524 {
1525         PropertyRNA *prop;
1526
1527         /* value is a hsv value: convert to rgb */
1528         if (but->rnaprop) {
1529                 prop = but->rnaprop;
1530
1531                 if (RNA_property_editable(&but->rnapoin, prop)) {
1532                         switch (RNA_property_type(prop)) {
1533                                 case PROP_BOOLEAN:
1534                                         if (RNA_property_array_length(&but->rnapoin, prop))
1535                                                 RNA_property_boolean_set_index(&but->rnapoin, prop, but->rnaindex, value);
1536                                         else
1537                                                 RNA_property_boolean_set(&but->rnapoin, prop, value);
1538                                         break;
1539                                 case PROP_INT:
1540                                         if (RNA_property_array_length(&but->rnapoin, prop))
1541                                                 RNA_property_int_set_index(&but->rnapoin, prop, but->rnaindex, (int)value);
1542                                         else
1543                                                 RNA_property_int_set(&but->rnapoin, prop, (int)value);
1544                                         break;
1545                                 case PROP_FLOAT:
1546                                         if (RNA_property_array_length(&but->rnapoin, prop))
1547                                                 RNA_property_float_set_index(&but->rnapoin, prop, but->rnaindex, value);
1548                                         else
1549                                                 RNA_property_float_set(&but->rnapoin, prop, value);
1550                                         break;
1551                                 case PROP_ENUM:
1552                                         if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
1553                                                 int ivalue = (int)value;
1554                                                 ivalue ^= RNA_property_enum_get(&but->rnapoin, prop); /* toggle for enum/flag buttons */
1555                                                 RNA_property_enum_set(&but->rnapoin, prop, ivalue);
1556                                         }
1557                                         else {
1558                                                 RNA_property_enum_set(&but->rnapoin, prop, value);
1559                                         }
1560                                         break;
1561                                 default:
1562                                         break;
1563                         }
1564                 }
1565
1566                 /* we can't be sure what RNA set functions actually do,
1567                  * so leave this unset */
1568                 value = UI_BUT_VALUE_UNSET;
1569         }
1570         else if (but->pointype == 0) {
1571                 /* pass */
1572         }
1573         else if (but->type == HSVSLI) {
1574                 float *fp, hsv[3];
1575                 
1576                 fp = (but->editvec) ? but->editvec : (float *)but->poin;
1577                 rgb_to_hsv_v(fp, hsv);
1578                 
1579                 switch (but->str[0]) {
1580                         case 'H': hsv[0] = value; break;
1581                         case 'S': hsv[1] = value; break;
1582                         case 'V': hsv[2] = value; break;
1583                 }
1584                 
1585                 hsv_to_rgb_v(hsv, fp);
1586                 
1587         }
1588         else {
1589                 /* first do rounding */
1590                 if (but->pointype == UI_BUT_POIN_CHAR) {
1591                         value = (char)floor(value + 0.5);
1592                 }
1593                 else if (but->pointype == UI_BUT_POIN_SHORT) {
1594                         /* gcc 3.2.1 seems to have problems
1595                          * casting a double like 32772.0 to
1596                          * a short so we cast to an int, then
1597                          * to a short.
1598                          *
1599                          * Update: even in gcc.4.6 using intermediate int cast gives -32764,
1600                          * where as a direct cast from double to short gives -32768,
1601                          * if this difference isn't important we could remove this hack,
1602                          * since we dont support gcc3 anymore - Campbell */
1603                         int gcckludge;
1604                         gcckludge = (int) floor(value + 0.5);
1605                         value = (short)gcckludge;
1606                 }
1607                 else if (but->pointype == UI_BUT_POIN_INT)
1608                         value = (int)floor(value + 0.5);
1609                 else if (but->pointype == UI_BUT_POIN_FLOAT) {
1610                         float fval = (float)value;
1611                         if (fval >= -0.00001f && fval <= 0.00001f) fval = 0.0f;  /* prevent negative zero */
1612                         value = fval;
1613                 }
1614                 
1615                 /* then set value with possible edit override */
1616                 if (but->editval)
1617                         value = *but->editval = value;
1618                 else if (but->pointype == UI_BUT_POIN_CHAR)
1619                         value = *((char *)but->poin) = (char)value;
1620                 else if (but->pointype == UI_BUT_POIN_SHORT)
1621                         value = *((short *)but->poin) = (short)value;
1622                 else if (but->pointype == UI_BUT_POIN_INT)
1623                         value = *((int *)but->poin) = (int)value;
1624                 else if (but->pointype == UI_BUT_POIN_FLOAT)
1625                         value = *((float *)but->poin) = (float)value;
1626         }
1627
1628         ui_check_but_select(but, &value);
1629 }
1630
1631 int ui_get_but_string_max_length(uiBut *but)
1632 {
1633         if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
1634                 return but->hardmax;
1635         else if (but->type == IDPOIN)
1636                 return MAX_ID_NAME - 2;
1637         else
1638                 return UI_MAX_DRAW_STR;
1639 }
1640
1641 static double ui_get_but_scale_unit(uiBut *but, double value)
1642 {
1643         UnitSettings *unit = but->block->unit;
1644         int unit_type = uiButGetUnitType(but);
1645
1646         if (unit_type == PROP_UNIT_LENGTH) {
1647                 return value * (double)unit->scale_length;
1648         }
1649         else if (unit_type == PROP_UNIT_AREA) {
1650                 return value * pow(unit->scale_length, 2);
1651         }
1652         else if (unit_type == PROP_UNIT_VOLUME) {
1653                 return value * pow(unit->scale_length, 3);
1654         }
1655         else if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
1656                 Scene *scene = CTX_data_scene(but->block->evil_C);
1657                 return FRA2TIME(value);
1658         }
1659         else {
1660                 return value;
1661         }
1662 }
1663
1664 /* str will be overwritten */
1665 void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
1666 {
1667         if (ui_is_but_unit(but)) {
1668                 UnitSettings *unit = but->block->unit;
1669                 int unit_type = uiButGetUnitType(but);
1670                 char *orig_str;
1671                 
1672                 orig_str = MEM_callocN(sizeof(char) * maxlen + 1, "textedit sub str");
1673                 memcpy(orig_str, str, maxlen);
1674                 
1675                 bUnit_ToUnitAltName(str, maxlen, orig_str, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
1676                 
1677                 MEM_freeN(orig_str);
1678         }
1679 }
1680
1681 /**
1682  * \param float_precision  Override the button precision.
1683  */
1684 static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double value, int pad, int float_precision)
1685 {
1686         UnitSettings *unit = but->block->unit;
1687         int do_split = unit->flag & USER_UNIT_OPT_SPLIT;
1688         int unit_type = uiButGetUnitType(but);
1689         int precision;
1690
1691         if (unit->scale_length < 0.0001f) unit->scale_length = 1.0f;  // XXX do_versions
1692
1693         /* Use precision override? */
1694         if (float_precision == -1) {
1695                 /* Sanity checks */
1696                 precision = (int)but->a2;
1697                 if      (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX;
1698                 else if (precision == 0)                  precision = 2;
1699         }
1700         else {
1701                 precision = float_precision;
1702         }
1703
1704         bUnit_AsString(str, len_max, ui_get_but_scale_unit(but, value), precision,
1705                        unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type), do_split, pad);
1706 }
1707
1708 static float ui_get_but_step_unit(uiBut *but, float step_default)
1709 {
1710         int unit_type = RNA_SUBTYPE_UNIT_VALUE(uiButGetUnitType(but));
1711         float step;
1712
1713         step = bUnit_ClosestScalar(ui_get_but_scale_unit(but, step_default), but->block->unit->system, unit_type);
1714
1715         if (step > 0.0f) { /* -1 is an error value */
1716                 return (float)((double)step / ui_get_but_scale_unit(but, 1.0)) * 100.0f;
1717         }
1718         else {
1719                 return step_default;
1720         }
1721 }
1722
1723 /**
1724  * \param float_precision  For number buttons the precission to use or -1 to fallback to the button default.
1725  */
1726 void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
1727 {
1728         if (but->rnaprop && ELEM4(but->type, TEX, IDPOIN, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1729                 PropertyType type;
1730                 const char *buf = NULL;
1731                 int buf_len;
1732
1733                 type = RNA_property_type(but->rnaprop);
1734
1735                 if (type == PROP_STRING) {
1736                         /* RNA string */
1737                         buf = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, str, maxlen, &buf_len);
1738                 }
1739                 else if (type == PROP_ENUM) {
1740                         /* RNA enum */
1741                         int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
1742                         if (RNA_property_enum_name(but->block->evil_C, &but->rnapoin, but->rnaprop, value, &buf)) {
1743                                 BLI_strncpy(str, buf, maxlen);
1744                                 buf = str;
1745                         }
1746                 }
1747                 else if (type == PROP_POINTER) {
1748                         /* RNA pointer */
1749                         PointerRNA ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
1750                         buf = RNA_struct_name_get_alloc(&ptr, str, maxlen, &buf_len);
1751                 }
1752                 else {
1753                         BLI_assert(0);
1754                 }
1755
1756                 if (!buf) {
1757                         str[0] = '\0';
1758                 }
1759                 else if (buf && buf != str) {
1760                         /* string was too long, we have to truncate */
1761                         memcpy(str, buf, MIN2(maxlen, (size_t)buf_len + 1));
1762                         MEM_freeN((void *)buf);
1763                 }
1764         }
1765         else if (but->type == IDPOIN) {
1766                 /* ID pointer */
1767                 if (but->idpoin_idpp) { /* Can be NULL for ID properties by python */
1768                         ID *id = *(but->idpoin_idpp);
1769                         if (id) {
1770                                 BLI_strncpy(str, id->name + 2, maxlen);
1771                                 return;
1772                         }
1773                 }
1774                 str[0] = '\0';
1775                 return;
1776         }
1777         else if (but->type == TEX) {
1778                 /* string */
1779                 BLI_strncpy(str, but->poin, maxlen);
1780                 return;
1781         }
1782         else if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1783                 /* string */
1784                 BLI_strncpy(str, but->poin, maxlen);
1785                 return;
1786         }
1787         else if (ui_but_anim_expression_get(but, str, maxlen)) {
1788                 /* driver expression */
1789         }
1790         else {
1791                 /* number editing */
1792                 double value;
1793
1794                 value = ui_get_but_val(but);
1795
1796                 if (ui_is_but_float(but)) {
1797                         if (ui_is_but_unit(but)) {
1798                                 ui_get_but_string_unit(but, str, maxlen, value, 0, float_precision);
1799                         }
1800                         else {
1801                                 const int prec = (float_precision == -1) ? ui_but_float_precision(but, value) : float_precision;
1802                                 BLI_snprintf(str, maxlen, "%.*f", prec, value);
1803                         }
1804                 }
1805                 else
1806                         BLI_snprintf(str, maxlen, "%d", (int)value);
1807         }
1808 }
1809 void ui_get_but_string(uiBut *but, char *str, const size_t maxlen)
1810 {
1811         ui_get_but_string_ex(but, str, maxlen, -1);
1812 }
1813
1814 #ifdef WITH_PYTHON
1815
1816 static int ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value)
1817 {
1818         char str_unit_convert[256];
1819         const int unit_type = uiButGetUnitType(but);
1820
1821         BLI_strncpy(str_unit_convert, str, sizeof(str_unit_convert));
1822
1823         /* ugly, use the draw string to get the value,
1824          * this could cause problems if it includes some text which resolves to a unit */
1825         bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr,
1826                             ui_get_but_scale_unit(but, 1.0), but->block->unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
1827
1828         return (BPY_button_exec(C, str_unit_convert, value, TRUE) != -1);
1829 }
1830
1831 #endif /* WITH_PYTHON */
1832
1833
1834 int ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double *value)
1835 {
1836         int ok = FALSE;
1837
1838 #ifdef WITH_PYTHON
1839
1840         if (str[0] != '\0') {
1841                 bool is_unit_but = (ui_is_but_float(but) && ui_is_but_unit(but));
1842                 /* only enable verbose if we won't run again with units */
1843                 if (BPY_button_exec(C, str, value, is_unit_but == false) != -1) {
1844                         /* if the value parsed ok without unit conversion this button may still need a unit multiplier */
1845                         if (is_unit_but) {
1846                                 char str_new[128];
1847
1848                                 BLI_snprintf(str_new, sizeof(str_new), "%f", *value);
1849                                 ok = ui_set_but_string_eval_num_unit(C, but, str_new, value);
1850                         }
1851                         else {
1852                                 ok = TRUE; /* parse normal string via py (no unit conversion needed) */
1853                         }
1854                 }
1855                 else if (is_unit_but) {
1856                         /* parse failed, this is a unit but so run replacements and parse again */
1857                         ok = ui_set_but_string_eval_num_unit(C, but, str, value);
1858                 }
1859         }
1860
1861 #else /* WITH_PYTHON */
1862
1863         *value = atof(str);
1864         ok = TRUE;
1865
1866         (void)C;
1867         (void)but;
1868
1869 #endif /* WITH_PYTHON */
1870
1871         return ok;
1872 }
1873
1874
1875 int ui_set_but_string(bContext *C, uiBut *but, const char *str)
1876 {
1877         if (but->rnaprop && ELEM4(but->type, TEX, IDPOIN, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1878                 if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
1879                         PropertyType type;
1880
1881                         type = RNA_property_type(but->rnaprop);
1882
1883                         if (type == PROP_STRING) {
1884                                 /* RNA string */
1885                                 RNA_property_string_set(&but->rnapoin, but->rnaprop, str);
1886                                 return 1;
1887                         }
1888                         else if (type == PROP_POINTER) {
1889                                 /* RNA pointer */
1890                                 PointerRNA ptr, rptr;
1891                                 PropertyRNA *prop;
1892
1893                                 if (str == NULL || str[0] == '\0') {
1894                                         RNA_property_pointer_set(&but->rnapoin, but->rnaprop, PointerRNA_NULL);
1895                                         return 1;
1896                                 }
1897                                 else {
1898                                         ptr = but->rnasearchpoin;
1899                                         prop = but->rnasearchprop;
1900                                         
1901                                         if (prop && RNA_property_collection_lookup_string(&ptr, prop, str, &rptr))
1902                                                 RNA_property_pointer_set(&but->rnapoin, but->rnaprop, rptr);
1903
1904                                         return 1;
1905                                 }
1906
1907                                 return 0;
1908                         }
1909                         else if (type == PROP_ENUM) {
1910                                 int value;
1911                                 if (RNA_property_enum_value(but->block->evil_C, &but->rnapoin, but->rnaprop, str, &value)) {
1912                                         RNA_property_enum_set(&but->rnapoin, but->rnaprop, value);
1913                                         return 1;
1914                                 }
1915                                 return 0;
1916                         }
1917                         else {
1918                                 BLI_assert(0);
1919                         }
1920                 }
1921         }
1922         else if (but->type == IDPOIN) {
1923                 /* ID pointer */
1924                 but->idpoin_func(C, str, but->idpoin_idpp);
1925                 return 1;
1926         }
1927         else if (but->type == TEX) {
1928                 /* string */
1929                 if (ui_is_but_utf8(but)) BLI_strncpy_utf8(but->poin, str, but->hardmax);
1930                 else BLI_strncpy(but->poin, str, but->hardmax);
1931
1932                 return 1;
1933         }
1934         else if (ELEM(but->type, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
1935                 /* string */
1936                 BLI_strncpy(but->poin, str, but->hardmax);
1937                 return 1;
1938         }
1939         else if (ui_but_anim_expression_set(but, str)) {
1940                 /* driver expression */
1941                 return 1;
1942         }
1943         else if (str[0] == '#') {
1944                 /* shortcut to create new driver expression (versus immediate Py-execution) */
1945                 return ui_but_anim_expression_create(but, str + 1);
1946         }
1947         else {
1948                 /* number editing */
1949                 double value;
1950
1951                 if (ui_set_but_string_eval_num(C, but, str, &value) == FALSE) {
1952                         return 0;
1953                 }
1954
1955                 if (!ui_is_but_float(but)) value = (int)floor(value + 0.5);
1956                 if (but->type == NUMABS) value = fabs(value);
1957
1958                 /* not that we use hard limits here */
1959                 if (value < (double)but->hardmin) value = but->hardmin;
1960                 if (value > (double)but->hardmax) value = but->hardmax;
1961
1962                 ui_set_but_val(but, value);
1963                 return 1;
1964         }
1965
1966         return 0;
1967 }
1968
1969 void ui_set_but_default(bContext *C, short all)
1970 {
1971         PointerRNA ptr;
1972
1973         WM_operator_properties_create(&ptr, "UI_OT_reset_default_button");
1974         RNA_boolean_set(&ptr, "all", all);
1975         WM_operator_name_call(C, "UI_OT_reset_default_button", WM_OP_EXEC_DEFAULT, &ptr);
1976         WM_operator_properties_free(&ptr);
1977 }
1978
1979 static double soft_range_round_up(double value, double max)
1980 {
1981         /* round up to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, ..
1982          * checking for 0.0 prevents floating point exceptions */
1983         double newmax = (value != 0.0) ? pow(10.0, ceil(log(value) / M_LN10)) : 0.0;
1984
1985         if (newmax * 0.2 >= max && newmax * 0.2 >= value)
1986                 return newmax * 0.2;
1987         else if (newmax * 0.5 >= max && newmax * 0.5 >= value)
1988                 return newmax * 0.5;
1989         else
1990                 return newmax;
1991 }
1992
1993 static double soft_range_round_down(double value, double max)
1994 {
1995         /* round down to .., 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, ..
1996          * checking for 0.0 prevents floating point exceptions */
1997         double newmax = (value != 0.0) ? pow(10.0, floor(log(value) / M_LN10)) : 0.0;
1998
1999         if (newmax * 5.0 <= max && newmax * 5.0 <= value)
2000                 return newmax * 5.0;
2001         else if (newmax * 2.0 <= max && newmax * 2.0 <= value)
2002                 return newmax * 2.0;
2003         else
2004                 return newmax;
2005 }
2006
2007 /* note: this could be split up into functions which handle arrays and not */
2008 static void ui_set_but_soft_range(uiBut *but)
2009 {
2010         /* ideally we would not limit this but practically, its more then
2011          * enough worst case is very long vectors wont use a smart soft-range
2012          * which isn't so bad. */
2013
2014         if (but->rnaprop) {
2015                 const PropertyType type = RNA_property_type(but->rnaprop);
2016                 double softmin, softmax /*, step, precision*/;
2017                 double value_min;
2018                 double value_max;
2019
2020                 /* clamp button range to something reasonable in case
2021                  * we get -inf/inf from RNA properties */
2022                 if (type == PROP_INT) {
2023                         const bool is_array = RNA_property_array_check(but->rnaprop);
2024                         int imin, imax, istep;
2025
2026                         RNA_property_int_ui_range(&but->rnapoin, but->rnaprop, &imin, &imax, &istep);
2027                         softmin = (imin == INT_MIN) ? -1e4 : imin;
2028                         softmax = (imin == INT_MAX) ? 1e4 : imax;
2029                         /*step = istep;*/ /*UNUSED*/
2030                         /*precision = 1;*/ /*UNUSED*/
2031
2032                         if (is_array) {
2033                                 int value_range[2];
2034                                 RNA_property_int_get_array_range(&but->rnapoin, but->rnaprop, value_range);
2035                                 value_min = (double)value_range[0];
2036                                 value_max = (double)value_range[1];
2037                         }
2038                         else {
2039                                 value_min = value_max = (double)RNA_property_int_get(&but->rnapoin, but->rnaprop);
2040                         }
2041                 }
2042                 else if (type == PROP_FLOAT) {
2043                         const bool is_array = RNA_property_array_check(but->rnaprop);
2044                         float fmin, fmax, fstep, fprecision;
2045
2046                         RNA_property_float_ui_range(&but->rnapoin, but->rnaprop, &fmin, &fmax, &fstep, &fprecision);
2047                         softmin = (fmin == -FLT_MAX) ? (float)-1e4 : fmin;
2048                         softmax = (fmax == FLT_MAX) ? (float)1e4 : fmax;
2049                         /*step = fstep;*/ /*UNUSED*/
2050                         /*precision = fprecision;*/ /*UNUSED*/
2051
2052                         if (is_array) {
2053                                 float value_range[2];
2054                                 RNA_property_float_get_array_range(&but->rnapoin, but->rnaprop, value_range);
2055                                 value_min = (double)value_range[0];
2056                                 value_max = (double)value_range[1];
2057                         }
2058                         else {
2059                                 value_min = value_max = (double)RNA_property_float_get(&but->rnapoin, but->rnaprop);
2060                         }
2061                 }
2062                 else {
2063                         return;
2064                 }
2065
2066                 /* if the value goes out of the soft/max range, adapt the range */
2067                 if (value_min + 1e-10 < softmin) {
2068                         if (value_min < 0.0)
2069                                 softmin = -soft_range_round_up(-value_min, -softmin);
2070                         else
2071                                 softmin = soft_range_round_down(value_min, softmin);
2072
2073                         if (softmin < (double)but->hardmin)
2074                                 softmin = (double)but->hardmin;
2075                 }
2076                 if (value_max - 1e-10 > softmax) {
2077                         if (value_max < 0.0)
2078                                 softmax = -soft_range_round_down(-value_max, -softmax);
2079                         else
2080                                 softmax = soft_range_round_up(value_max, softmax);
2081
2082                         if (softmax > (double)but->hardmax)
2083                                 softmax = but->hardmax;
2084                 }
2085
2086                 but->softmin = softmin;
2087                 but->softmax = softmax;
2088         }
2089 }
2090
2091 /* ******************* Free ********************/
2092
2093 static void ui_free_link(uiLink *link)
2094 {
2095         if (link) {
2096                 BLI_freelistN(&link->lines);
2097                 MEM_freeN(link);
2098         }
2099 }
2100
2101 /* can be called with C==NULL */
2102 static void ui_free_but(const bContext *C, uiBut *but)
2103 {
2104         if (but->opptr) {
2105                 WM_operator_properties_free(but->opptr);
2106                 MEM_freeN(but->opptr);
2107         }
2108
2109         if (but->func_argN) {
2110                 MEM_freeN(but->func_argN);
2111         }
2112
2113         if (but->active) {
2114                 /* XXX solve later, buttons should be free-able without context ideally,
2115                  * however they may have open tooltips or popup windows, which need to
2116                  * be closed using a context pointer */
2117                 if (C) {
2118                         ui_button_active_free(C, but);
2119                 }
2120                 else {
2121                         if (but->active) {
2122                                 MEM_freeN(but->active);
2123                         }
2124                 }
2125         }
2126         if (but->str && but->str != but->strdata) {
2127                 MEM_freeN(but->str);
2128         }
2129         ui_free_link(but->link);
2130
2131         if ((but->type == BUT_IMAGE) && but->poin) {
2132                 IMB_freeImBuf((struct ImBuf *)but->poin);
2133         }
2134
2135         MEM_freeN(but);
2136 }
2137
2138 /* can be called with C==NULL */
2139 void uiFreeBlock(const bContext *C, uiBlock *block)
2140 {
2141         uiBut *but;
2142
2143         while ( (but = block->buttons.first) ) {
2144                 BLI_remlink(&block->buttons, but);
2145                 ui_free_but(C, but);
2146         }
2147
2148         if (block->unit) {
2149                 MEM_freeN(block->unit);
2150         }
2151
2152         if (block->func_argN) {
2153                 MEM_freeN(block->func_argN);
2154         }
2155
2156         CTX_store_free_list(&block->contexts);
2157
2158         BLI_freelistN(&block->saferct);
2159         
2160         MEM_freeN(block);
2161 }
2162
2163 /* can be called with C==NULL */
2164 void uiFreeBlocks(const bContext *C, ListBase *lb)
2165 {
2166         uiBlock *block;
2167         
2168         while ( (block = lb->first) ) {
2169                 BLI_remlink(lb, block);
2170                 uiFreeBlock(C, block);
2171         }
2172 }
2173
2174 void uiFreeInactiveBlocks(const bContext *C, ListBase *lb)
2175 {
2176         uiBlock *block, *nextblock;
2177
2178         for (block = lb->first; block; block = nextblock) {
2179                 nextblock = block->next;
2180         
2181                 if (!block->handle) {
2182                         if (!block->active) {
2183                                 BLI_remlink(lb, block);
2184                                 uiFreeBlock(C, block);
2185                         }
2186                         else
2187                                 block->active = 0;
2188                 }
2189         }
2190 }
2191
2192 void uiBlockSetRegion(uiBlock *block, ARegion *region)
2193 {
2194         ListBase *lb = &region->uiblocks;
2195         uiBlock *oldblock = NULL;
2196
2197         /* each listbase only has one block with this name, free block
2198          * if is already there so it can be rebuilt from scratch */
2199         if (lb) {
2200                 oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name));
2201
2202                 if (oldblock) {
2203                         oldblock->active = 0;
2204                         oldblock->panel = NULL;
2205                 }
2206
2207                 /* at the beginning of the list! for dynamical menus/blocks */
2208                 BLI_addhead(lb, block);
2209         }
2210
2211         block->oldblock = oldblock;
2212 }
2213
2214 uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, short dt)
2215 {
2216         uiBlock *block;
2217         wmWindow *window;
2218         Scene *scn;
2219         int getsizex, getsizey;
2220
2221         window = CTX_wm_window(C);
2222         scn = CTX_data_scene(C);
2223
2224         block = MEM_callocN(sizeof(uiBlock), "uiBlock");
2225         block->active = 1;
2226         block->dt = dt;
2227         block->evil_C = (void *)C;  /* XXX */
2228
2229         if (scn) {
2230                 block->color_profile = TRUE;
2231
2232                 /* store display device name, don't lookup for transformations yet
2233                  * block could be used for non-color displays where looking up for transformation
2234                  * would slow down redraw, so only lookup for actual transform when it's indeed
2235                  * needed
2236                  */
2237                 block->display_device = scn->display_settings.display_device;
2238
2239                 /* copy to avoid crash when scene gets deleted with ui still open */
2240                 block->unit = MEM_mallocN(sizeof(scn->unit), "UI UnitSettings");
2241                 memcpy(block->unit, &scn->unit, sizeof(scn->unit));
2242         }
2243
2244         BLI_strncpy(block->name, name, sizeof(block->name));
2245
2246         if (region)
2247                 uiBlockSetRegion(block, region);
2248
2249         /* window matrix and aspect */
2250         if (region && region->swinid) {
2251                 wm_subwindow_getmatrix(window, region->swinid, block->winmat);
2252                 wm_subwindow_getsize(window, region->swinid, &getsizex, &getsizey);
2253
2254                 block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
2255         }
2256         else {
2257                 /* no subwindow created yet, for menus for example, so we
2258                  * use the main window instead, since buttons are created
2259                  * there anyway */
2260                 wm_subwindow_getmatrix(window, window->screen->mainwin, block->winmat);
2261                 wm_subwindow_getsize(window, window->screen->mainwin, &getsizex, &getsizey);
2262
2263                 block->aspect = 2.0f / fabsf(getsizex * block->winmat[0][0]);
2264                 block->auto_open = TRUE;
2265                 block->flag |= UI_BLOCK_LOOP; /* tag as menu */
2266         }
2267
2268         return block;
2269 }
2270
2271 uiBlock *uiGetBlock(const char *name, ARegion *ar)
2272 {
2273         return BLI_findstring(&ar->uiblocks, name, offsetof(uiBlock, name));
2274 }
2275
2276 void uiBlockSetEmboss(uiBlock *block, char dt)
2277 {
2278         block->dt = dt;
2279 }
2280
2281 void ui_check_but(uiBut *but)
2282 {
2283         /* if something changed in the button */
2284         double value = UI_BUT_VALUE_UNSET;
2285 //      float okwidth; // UNUSED
2286         
2287         ui_check_but_select(but, &value);
2288         
2289         /* only update soft range while not editing */
2290         if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) {
2291                 ui_set_but_soft_range(but);
2292         }
2293
2294         /* test for min and max, icon sliders, etc */
2295         switch (but->type) {
2296                 case NUM:
2297                 case SLI:
2298                 case SCROLL:
2299                 case NUMSLI:
2300                 case HSVSLI:
2301                         UI_GET_BUT_VALUE_INIT(but, value);
2302                         if (value < (double)but->hardmin) ui_set_but_val(but, but->hardmin);
2303                         else if (value > (double)but->hardmax) ui_set_but_val(but, but->hardmax);
2304                         break;
2305                         
2306                 case NUMABS:
2307                 {
2308                         double value_abs;
2309                         UI_GET_BUT_VALUE_INIT(but, value);
2310                         value_abs = fabs(value);
2311                         if (value_abs < (double)but->hardmin) ui_set_but_val(but, but->hardmin);
2312                         else if (value_abs > (double)but->hardmax) ui_set_but_val(but, but->hardmax);
2313                         break;
2314                 }
2315                 case ICONTOG: 
2316                 case ICONTOGN:
2317                         if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
2318                                 if (but->flag & UI_SELECT) but->iconadd = 1;
2319                                 else but->iconadd = 0;
2320                         }
2321                         break;
2322                         
2323                 case ICONROW:
2324                         if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
2325                                 UI_GET_BUT_VALUE_INIT(but, value);
2326                                 but->iconadd = (int)value - (int)(but->hardmin);
2327                         }
2328                         break;
2329                         
2330                 case ICONTEXTROW:
2331                         if (!but->rnaprop || (RNA_property_flag(but->rnaprop) & PROP_ICONS_CONSECUTIVE)) {
2332                                 UI_GET_BUT_VALUE_INIT(but, value);
2333                                 but->iconadd = (int)value - (int)(but->hardmin);
2334                         }
2335                         break;
2336
2337                         /* quiet warnings for unhandled types */
2338                 default:
2339                         break;
2340         }
2341         
2342         
2343         /* safety is 4 to enable small number buttons (like 'users') */
2344         // okwidth = -4 + (BLI_rcti_size_x(&but->rect)); // UNUSED
2345         
2346         /* name: */
2347         switch (but->type) {
2348         
2349                 case MENU:
2350                 case ICONTEXTROW:
2351                 
2352                         if (BLI_rctf_size_x(&but->rect) > 24.0f) {
2353                                 UI_GET_BUT_VALUE_INIT(but, value);
2354                                 ui_set_name_menu(but, (int)value);
2355                         }
2356                         break;
2357         
2358                 case NUM:
2359                 case NUMSLI:
2360                 case HSVSLI:
2361                 case NUMABS:
2362
2363                         UI_GET_BUT_VALUE_INIT(but, value);
2364
2365                         if (ui_is_but_float(but)) {
2366                                 if (value == (double) FLT_MAX) {
2367                                         BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%sinf", but->str);
2368                                 }
2369                                 else if (value == (double) -FLT_MAX) {
2370                                         BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s-inf", but->str);
2371                                 }
2372                                 /* support length type buttons */
2373                                 else if (ui_is_but_unit(but)) {
2374                                         char new_str[sizeof(but->drawstr)];
2375                                         ui_get_but_string_unit(but, new_str, sizeof(new_str), value, TRUE, -1);
2376                                         BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, new_str);
2377                                 }
2378                                 else {
2379                                         const int prec = ui_but_float_precision(but, value);
2380                                         BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%.*f", but->str, prec, value);
2381                                 }
2382                         }
2383                         else {
2384                                 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%d", but->str, (int)value);
2385                         }
2386                         
2387                         if (but->rnaprop) {
2388                                 PropertySubType pstype = RNA_property_subtype(but->rnaprop);
2389                         
2390                                 if (pstype == PROP_PERCENTAGE)
2391                                         strcat(but->drawstr, "%");
2392                         }
2393                         break;
2394
2395                 case LABEL:
2396                         if (ui_is_but_float(but)) {
2397                                 int prec;
2398                                 UI_GET_BUT_VALUE_INIT(but, value);
2399                                 prec = ui_but_float_precision(but, value);
2400                                 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%.*f", but->str, prec, value);
2401                         }
2402                         else {
2403                                 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR);
2404                         }
2405                 
2406                         break;
2407
2408                 case IDPOIN:
2409                 case TEX:
2410                 case SEARCH_MENU:
2411                 case SEARCH_MENU_UNLINK:
2412                         if (!but->editstr) {
2413                                 char str[UI_MAX_DRAW_STR];
2414
2415                                 ui_get_but_string(but, str, UI_MAX_DRAW_STR - strlen(but->str));
2416
2417                                 BLI_snprintf(but->drawstr, sizeof(but->drawstr), "%s%s", but->str, str);
2418                         }
2419                         break;
2420         
2421                 case KEYEVT:
2422                         BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR);
2423                         if (but->flag & UI_SELECT) {
2424                                 strcat(but->drawstr, "Press a key");
2425                         }
2426                         else {
2427                                 UI_GET_BUT_VALUE_INIT(but, value);
2428                                 strcat(but->drawstr, WM_key_event_string((short)value));
2429                         }
2430                         break;
2431                 
2432                 case HOTKEYEVT:
2433                         if (but->flag & UI_SELECT) {
2434                                 but->drawstr[0] = '\0';
2435
2436                                 if (but->modifier_key) {
2437                                         char *str = but->drawstr;
2438
2439                                         if (but->modifier_key & KM_SHIFT)
2440                                                 str = strcat(str, "Shift ");
2441                                         if (but->modifier_key & KM_CTRL)
2442                                                 str = strcat(str, "Ctrl ");
2443                                         if (but->modifier_key & KM_ALT)
2444                                                 str = strcat(str, "Alt ");
2445                                         if (but->modifier_key & KM_OSKEY)
2446                                                 str = strcat(str, "Cmd ");
2447
2448                                         (void)str; /* UNUSED */
2449                                 }
2450                                 else
2451                                         strcat(but->drawstr, "Press a key  ");
2452                         }
2453                         else
2454                                 BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR);
2455
2456                         break;
2457
2458                 case BUT_TOGDUAL:
2459                         /* trying to get the dual-icon to left of text... not very nice */
2460                         if (but->str[0]) {
2461                                 BLI_strncpy(but->drawstr, "  ", UI_MAX_DRAW_STR);
2462                                 BLI_strncpy(but->drawstr + 2, but->str, UI_MAX_DRAW_STR - 2);
2463                         }
2464                         break;
2465                 
2466                 case HSVCUBE:
2467                 case HSVCIRCLE:
2468                         break;
2469                 default:
2470                         BLI_strncpy(but->drawstr, but->str, UI_MAX_DRAW_STR);
2471                 
2472         }
2473
2474         /* if we are doing text editing, this will override the drawstr */
2475         if (but->editstr)
2476                 BLI_strncpy(but->drawstr, but->editstr, UI_MAX_DRAW_STR);
2477         
2478         /* text clipping moved to widget drawing code itself */
2479 }
2480
2481
2482 void uiBlockBeginAlign(uiBlock *block)
2483 {
2484         /* if other align was active, end it */
2485         if (block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
2486
2487         block->flag |= UI_BUT_ALIGN_DOWN;
2488         block->alignnr++;
2489
2490         /* buttons declared after this call will get this align nr */ // XXX flag?
2491 }
2492
2493 static int buts_are_horiz(uiBut *but1, uiBut *but2)
2494 {
2495         float dx, dy;
2496         
2497         dx = fabs(but1->rect.xmax - but2->rect.xmin);
2498         dy = fabs(but1->rect.ymin - but2->rect.ymax);
2499         
2500         if (dx > dy) return 0;
2501         return 1;
2502 }
2503
2504 void uiBlockEndAlign(uiBlock *block)
2505 {
2506         block->flag &= ~UI_BUT_ALIGN;  /* all 4 flags */
2507 }
2508
2509 int ui_but_can_align(uiBut *but)
2510 {
2511         return !ELEM4(but->type, LABEL, OPTION, OPTIONN, SEPR);
2512 }
2513
2514 static void ui_block_do_align_but(uiBut *first, short nr)
2515 {
2516         uiBut *prev, *but = NULL, *next;
2517         int flag = 0, cols = 0, rows = 0;
2518         
2519         /* auto align */
2520
2521         for (but = first; but && but->alignnr == nr; but = but->next) {
2522                 if (but->next && but->next->alignnr == nr) {
2523                         if (buts_are_horiz(but, but->next)) cols++;
2524                         else rows++;
2525                 }
2526         }
2527
2528         /* rows == 0: 1 row, cols == 0: 1 column */
2529         
2530         /* note;  how it uses 'flag' in loop below (either set it, or OR it) is confusing */
2531         for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) {
2532                 next = but->next;
2533                 if (next && next->alignnr != nr)
2534                         next = NULL;
2535
2536                 /* clear old flag */
2537                 but->flag &= ~UI_BUT_ALIGN;
2538                         
2539                 if (flag == 0) {  /* first case */
2540                         if (next) {
2541                                 if (buts_are_horiz(but, next)) {
2542                                         if (rows == 0)
2543                                                 flag = UI_BUT_ALIGN_RIGHT;
2544                                         else 
2545                                                 flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT;
2546                                 }
2547                                 else {
2548                                         flag = UI_BUT_ALIGN_DOWN;
2549                                 }
2550                         }
2551                 }
2552                 else if (next == NULL) {  /* last case */
2553                         if (prev) {
2554                                 if (buts_are_horiz(prev, but)) {
2555                                         if (rows == 0)
2556                                                 flag = UI_BUT_ALIGN_LEFT;
2557                                         else
2558                                                 flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT;
2559                                 }
2560                                 else {
2561                                         flag = UI_BUT_ALIGN_TOP;
2562                                 }
2563                         }
2564                 }
2565                 else if (buts_are_horiz(but, next)) {
2566                         /* check if this is already second row */
2567                         if (prev && buts_are_horiz(prev, but) == 0) {
2568                                 flag &= ~UI_BUT_ALIGN_LEFT;
2569                                 flag |= UI_BUT_ALIGN_TOP;
2570                                 /* exception case: bottom row */
2571                                 if (rows > 0) {
2572                                         uiBut *bt = but;
2573                                         while (bt && bt->alignnr == nr) {
2574                                                 if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) {
2575                                                         break;
2576                                                 }
2577                                                 bt = bt->next;
2578                                         }
2579                                         if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT;
2580                                 }
2581                         }
2582                         else {
2583                                 flag |= UI_BUT_ALIGN_LEFT;
2584                         }
2585                 }
2586                 else {
2587                         if (cols == 0) {
2588                                 flag |= UI_BUT_ALIGN_TOP;
2589                         }
2590                         else {  /* next button switches to new row */
2591                                 
2592                                 if (prev && buts_are_horiz(prev, but))
2593                                         flag |= UI_BUT_ALIGN_LEFT;
2594                                 else {
2595                                         flag &= ~UI_BUT_ALIGN_LEFT;
2596                                         flag |= UI_BUT_ALIGN_TOP;
2597                                 }
2598                                 
2599                                 if ((flag & UI_BUT_ALIGN_TOP) == 0) {  /* stil top row */
2600                                         if (prev) {
2601                                                 if (next && buts_are_horiz(but, next))
2602                                                         flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT;
2603                                                 else {
2604                                                         /* last button in top row */
2605                                                         flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT;
2606                                                 }
2607                                         }
2608                                         else 
2609                                                 flag |= UI_BUT_ALIGN_DOWN;
2610                                 }
2611                                 else 
2612                                         flag |= UI_BUT_ALIGN_TOP;
2613                         }
2614                 }
2615                 
2616                 but->flag |= flag;
2617                 
2618                 /* merge coordinates */
2619                 if (prev) {
2620                         /* simple cases */
2621                         if (rows == 0) {
2622                                 but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
2623                                 prev->rect.xmax = but->rect.xmin;
2624                         }
2625                         else if (cols == 0) {
2626                                 but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
2627                                 prev->rect.ymin = but->rect.ymax;
2628                         }
2629                         else {
2630                                 if (buts_are_horiz(prev, but)) {
2631                                         but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
2632                                         prev->rect.xmax = but->rect.xmin;
2633                                         /* copy height too */
2634                                         but->rect.ymax = prev->rect.ymax;
2635                                 }
2636                                 else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) {
2637                                         /* the previous button is a single one in its row */
2638                                         but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
2639                                         prev->rect.ymin = but->rect.ymax;
2640                                         
2641                                         but->rect.xmin = prev->rect.xmin;
2642                                         if (next && buts_are_horiz(but, next) == 0)
2643                                                 but->rect.xmax = prev->rect.xmax;
2644                                 }
2645                                 else {
2646                                         /* the previous button is not a single one in its row */
2647                                         but->rect.ymax = prev->rect.ymin;
2648                                 }
2649                         }
2650                 }
2651         }
2652 }
2653
2654 void ui_block_do_align(uiBlock *block)
2655 {
2656         uiBut *but;
2657         short nr;
2658
2659         /* align buttons with same align nr */
2660         for (but = block->buttons.first; but; ) {
2661                 if (but->alignnr) {
2662                         nr = but->alignnr;
2663                         ui_block_do_align_but(but, nr);
2664
2665                         /* skip with same number */
2666                         for (; but && but->alignnr == nr; but = but->next) {
2667                                 /* pass */
2668                         }
2669
2670                         if (!but) {
2671                                 break;
2672                         }
2673                 }
2674                 else {
2675                         but = but->next;
2676                 }
2677         }
2678 }
2679
2680 struct ColorManagedDisplay *ui_block_display_get(uiBlock *block)
2681 {
2682         return IMB_colormanagement_display_get_named(block->display_device);
2683 }
2684
2685 void ui_block_to_display_space_v3(uiBlock *block, float pixel[3])
2686 {
2687         struct ColorManagedDisplay *display = ui_block_display_get(block);
2688
2689         IMB_colormanagement_scene_linear_to_display_v3(pixel, display);
2690 }
2691
2692 void ui_block_to_scene_linear_v3(uiBlock *block, float pixel[3])
2693 {
2694         struct ColorManagedDisplay *display = ui_block_display_get(block);
2695
2696         IMB_colormanagement_display_to_scene_linear_v3(pixel, display);
2697 }
2698
2699 /**
2700  * \brief ui_def_but is the function that draws many button types
2701  *
2702  * \param x,y The lower left hand corner of the button (X axis)
2703  * \param width,height The size of the button.
2704  *
2705  * for float buttons:
2706  * - \a a1 Click Step (how much to change the value each click)
2707  * - \a a2 Number of decimal point values to display. 0 defaults to 3 (0.000)
2708  *      1,2,3, and a maximum of 4, all greater values will be clamped to 4.
2709  */
2710 static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
2711                          int x, int y, short width, short height,
2712                          void *poin, float min, float max, float a1, float a2, const char *tip)
2713 {
2714         uiBut *but;
2715         int slen;
2716
2717         BLI_assert(width >= 0);
2718         BLI_assert(height >= 0);
2719         
2720         /* we could do some more error checks here */
2721         if ((type & BUTTYPE) == LABEL) {
2722                 if ((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)))
2723                         printf("blah\n");
2724                 BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == FALSE);
2725         }
2726
2727         if (type & UI_BUT_POIN_TYPES) {  /* a pointer is required */
2728                 if (poin == NULL) {
2729                         BLI_assert(0);
2730                         return NULL;
2731                 }
2732         }
2733
2734         but = MEM_callocN(sizeof(uiBut), "uiBut");
2735
2736         but->type = type & BUTTYPE;
2737         but->pointype = type & UI_BUT_POIN_TYPES;
2738         but->bit = type & UI_BUT_POIN_BIT;
2739         but->bitnr = type & 31;
2740         but->icon = ICON_NONE;
2741         but->iconadd = 0;
2742
2743         but->retval = retval;
2744
2745         slen = strlen(str);
2746         if (slen >= UI_MAX_NAME_STR - 1) {
2747                 but->str = MEM_mallocN(slen + 2, "ui_def_but str"); /* why +2 ? */
2748         }
2749         else {
2750                 but->str = but->strdata;
2751         }
2752         memcpy(but->str, str, slen + 1);
2753
2754         but->rect.xmin = x;
2755         but->rect.ymin = y;
2756         but->rect.xmax = but->rect.xmin + width;
2757         but->rect.ymax = but->rect.ymin + height;
2758
2759         but->poin = poin;
2760         but->hardmin = but->softmin = min;
2761         but->hardmax = but->softmax = max;
2762         but->a1 = a1;
2763         but->a2 = a2;
2764         but->tip = tip;
2765
2766         but->lock = block->lock;
2767         but->lockstr = block->lockstr;
2768         but->dt = block->dt;
2769
2770         but->aspect = 1.0f;  /* XXX block->aspect; */
2771         but->block = block;  /* pointer back, used for frontbuffer status, and picker */
2772
2773         if ((block->flag & UI_BUT_ALIGN) && ui_but_can_align(but))
2774                 but->alignnr = block->alignnr;
2775
2776         but->func = block->func;
2777         but->func_arg1 = block->func_arg1;
2778         but->func_arg2 = block->func_arg2;
2779
2780         but->funcN = block->funcN;
2781         if (block->func_argN)
2782                 but->func_argN = MEM_dupallocN(block->func_argN);
2783         
2784         but->pos = -1;   /* cursor invisible */
2785
2786         if (ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI)) {    /* add a space to name */
2787                 /* slen remains unchanged from previous assignment, ensure this stays true */
2788                 if (slen > 0 && slen < UI_MAX_NAME_STR - 2) {
2789                         if (but->str[slen - 1] != ' ') {
2790                                 but->str[slen] = ' ';
2791                                 but->str[slen + 1] = 0;
2792                         }
2793                 }
2794         }
2795
2796         if ((block->flag & UI_BLOCK_LOOP) ||
2797             ELEM9(but->type, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
2798         {
2799                 but->flag |= (UI_TEXT_LEFT | UI_ICON_LEFT);
2800         }
2801         else if (but->type == BUT_TOGDUAL) {
2802                 but->flag |= UI_ICON_LEFT;
2803         }
2804
2805         but->flag |= (block->flag & UI_BUT_ALIGN);
2806
2807         if (but->lock == TRUE) {
2808                 if (but->lockstr) {
2809                         but->flag |= UI_BUT_DISABLED;
2810                 }
2811         }
2812
2813         /* keep track of UI_interface.h */
2814         if      (ELEM9(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR /* , FTPREVIEW */)) {}
2815         else if (but->type >= SEARCH_MENU) {}
2816         else but->flag |= UI_BUT_UNDO;
2817
2818         BLI_addtail(&block->buttons, but);
2819         
2820         if (block->curlayout)
2821                 ui_layout_add_but(block->curlayout, but);
2822
2823 #ifdef WITH_PYTHON
2824         /* if the 'UI_OT_editsource' is running, extract the source info from the button  */
2825         if (UI_editsource_enable_check()) {
2826                 UI_editsource_active_but_test(but);
2827         }
2828 #endif
2829
2830         return but;
2831 }
2832
2833 static void ui_def_but_rna__disable(uiBut *but)
2834 {
2835         but->flag |= UI_BUT_DISABLED;
2836         but->lock = true;
2837         but->lockstr = "";
2838 }
2839
2840 /**
2841  * ui_def_but_rna_propname and ui_def_but_rna
2842  * both take the same args except for propname vs prop, this is done so we can
2843  * avoid an extra lookup on 'prop' when its already available.
2844  *
2845  * When this kind of change won't disrupt branches, best look into making more
2846  * of our UI functions take prop rather then propname.
2847  */
2848 static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *str,
2849                              int x, int y, short width, short height,
2850                              PointerRNA *ptr, PropertyRNA *prop, int index,
2851                              float min, float max, float a1, float a2,  const char *tip)
2852 {
2853         const PropertyType proptype = RNA_property_type(prop);
2854         uiBut *but;
2855         int freestr = 0, icon = 0;
2856
2857         if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) {
2858                 BLI_assert(index == -1);
2859         }
2860
2861         /* use rna values if parameters are not specified */
2862         if (!str) {
2863                 if (type == MENU && proptype == PROP_ENUM) {
2864                         EnumPropertyItem *item;
2865                         DynStr *dynstr;
2866                         int i, totitem, value, free;
2867
2868                         RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
2869                         value = RNA_property_enum_get(ptr, prop);
2870
2871                         dynstr = BLI_dynstr_new();
2872                         BLI_dynstr_appendf(dynstr, "%s%%t", RNA_property_ui_name(prop));
2873                         for (i = 0; i < totitem; i++) {
2874                                 if (!item[i].identifier[0]) {
2875                                         if (item[i].name)
2876                                                 BLI_dynstr_appendf(dynstr, "|%s%%l", item[i].name);
2877                                         else
2878                                                 BLI_dynstr_append(dynstr, "|%l");
2879                                 }
2880                                 else if (item[i].icon)
2881                                         BLI_dynstr_appendf(dynstr, "|%s %%i%d %%x%d", item[i].name, item[i].icon, item[i].value);
2882                                 else
2883                                         BLI_dynstr_appendf(dynstr, "|%s %%x%d", item[i].name, item[i].value);
2884
2885                                 if (value == item[i].value)
2886                                         icon = item[i].icon;
2887                         }
2888                         str = BLI_dynstr_get_cstring(dynstr);
2889                         BLI_dynstr_free(dynstr);
2890
2891                         if (free) {
2892                                 MEM_freeN(item);
2893                         }
2894
2895                         freestr = 1;
2896                 }
2897                 else if (ELEM(type, ROW, LISTROW) && proptype == PROP_ENUM) {
2898                         EnumPropertyItem *item;
2899                         int i, totitem, free;
2900
2901                         /* get untranslated, then translate the single string we need */
2902                         RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
2903                         for (i = 0; i < totitem; i++) {
2904                                 if (item[i].identifier[0] && item[i].value == (int)max) {
2905                                         str = CTX_IFACE_(RNA_property_translation_context(prop), item[i].name);
2906                                         icon = item[i].icon;
2907                                         break;
2908                                 }
2909                         }
2910
2911                         if (!str) {
2912                                 str = RNA_property_ui_name(prop);
2913                         }
2914                         if (free) {
2915                                 MEM_freeN(item);
2916                         }
2917                 }
2918                 else {
2919                         str = RNA_property_ui_name(prop);
2920                         icon = RNA_property_ui_icon(prop);
2921                 }
2922         }
2923
2924         if (!tip && proptype != PROP_ENUM)
2925                 tip = RNA_property_ui_description(prop);
2926
2927         if (min == max || a1 == -1 || a2 == -1) {
2928                 if (proptype == PROP_INT) {
2929                         int hardmin, hardmax, softmin, softmax, step;
2930
2931                         RNA_property_int_range(ptr, prop, &hardmin, &hardmax);
2932                         RNA_property_int_ui_range(ptr, prop, &softmin, &softmax, &step);
2933
2934                         if (!ELEM(type, ROW, LISTROW) && min == max) {
2935                                 min = hardmin;
2936                                 max = hardmax;
2937                         }
2938                         if (a1 == -1)
2939                                 a1 = step;
2940                         if (a2 == -1)
2941                                 a2 = 0;
2942                 }
2943                 else if (proptype == PROP_FLOAT) {
2944                         float hardmin, hardmax, softmin, softmax, step, precision;
2945
2946                         RNA_property_float_range(ptr, prop, &hardmin, &hardmax);
2947                         RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision);
2948
2949                         if (!ELEM(type, ROW, LISTROW) && min == max) {
2950                                 min = hardmin;
2951                                 max = hardmax;
2952                         }
2953                         if (a1 == -1)
2954                                 a1 = step;
2955                         if (a2 == -1)
2956                                 a2 = precision;
2957                 }
2958                 else if (proptype == PROP_STRING) {
2959                         min = 0;
2960                         max = RNA_property_string_maxlength(prop);
2961                         if (max == 0) /* interface code should ideally support unlimited length */
2962                                 max = UI_MAX_DRAW_STR;
2963                 }
2964         }
2965
2966         /* now create button */
2967         but = ui_def_but(block, type, retval, str, x, y, width, height, NULL, min, max, a1, a2, tip);
2968
2969         but->rnapoin = *ptr;
2970         but->rnaprop = prop;
2971
2972         if (RNA_property_array_length(&but->rnapoin, but->rnaprop))
2973                 but->rnaindex = index;
2974         else
2975                 but->rnaindex = 0;
2976
2977         if (icon) {
2978                 but->icon = (BIFIconID)icon;
2979                 but->flag |= UI_HAS_ICON;
2980                 but->flag |= UI_ICON_LEFT;
2981         }
2982         
2983         if (!RNA_property_editable(&but->rnapoin, prop)) {
2984                 ui_def_but_rna__disable(but);
2985         }
2986
2987         if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == FALSE)) {
2988                 but->flag &= ~UI_BUT_UNDO;
2989         }
2990
2991         /* If this button uses units, calculate the step from this */
2992         if ((proptype == PROP_FLOAT) && ui_is_but_unit(but)) {
2993                 but->a1 = ui_get_but_step_unit(but, but->a1);
2994         }
2995
2996         if (freestr) {
2997                 MEM_freeN((void *)str);
2998         }
2999
3000         return but;
3001 }
3002
3003 static uiBut *ui_def_but_rna_propname(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, PointerRNA *ptr, const char *propname, int index, float min, float max, float a1, float a2,  const char *tip)
3004 {
3005         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
3006         uiBut *but;
3007
3008         if (prop) {
3009                 but = ui_def_but_rna(block, type, retval, str, x, y, width, height, ptr, prop, index, min, max, a1, a2,  tip);
3010         }
3011         else {
3012                 but = ui_def_but(block, type, retval, propname, x, y, width, height, NULL, min, max, a1, a2, tip);
3013
3014                 ui_def_but_rna__disable(but);
3015         }
3016
3017         return but;
3018 }
3019
3020 static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *ot, int opcontext, const char *str, int x, int y, short width, short height, const char *tip)
3021 {
3022         uiBut *but;
3023
3024         if (!str) {
3025                 if (ot && ot->srna)
3026                         str = RNA_struct_ui_name(ot->srna);
3027                 else
3028                         str = "";
3029         }
3030
3031         if ((!tip || tip[0] == '\0') && ot && ot->srna) {
3032                 tip = RNA_struct_ui_description(ot->srna);
3033         }
3034
3035         but = ui_def_but(block, type, -1, str, x, y, width, height, NULL, 0, 0, 0, 0, tip);
3036         but->optype = ot;
3037         but->opcontext = opcontext;
3038         but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_undo(), we never need undo here */
3039
3040         if (!ot) {
3041                 but->flag |= UI_BUT_DISABLED;
3042                 but->lock = TRUE;
3043                 but->lockstr = "";
3044         }
3045
3046         return but;
3047 }
3048
3049 #if 0 /* UNUSED */
3050 static uiBut *UNUSED_FUNCTION(ui_def_but_operator) (uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, const char *tip)
3051 {
3052         wmOperatorType *ot = WM_operatortype_find(opname, 0);
3053         if (str == NULL && ot == NULL) str = opname;
3054         return ui_def_but_operator_ptr(block, type, ot, opcontext, str, x, y, width, height, tip);
3055 }
3056 #endif
3057
3058 static uiBut *ui_def_but_operator_text(uiBlock *block, int type, const char *opname, int opcontext, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
3059 {
3060         uiBut *but;
3061         wmOperatorType *ot;
3062         
3063         ot = WM_operatortype_find(opname, 0);
3064
3065         if (!str) {
3066                 if (ot) str = ot->name;
3067                 else str = opname;
3068         }
3069         
3070         if ((!tip || tip[0] == '\0') && ot && ot->description) {
3071                 tip = ot->description;
3072         }
3073
3074         but = ui_def_but(block, type, -1, str, x, y, width, height, poin, min, max, a1, a2, tip);
3075         but->optype = ot;
3076         but->opcontext = opcontext;
3077         but->flag &= ~UI_BUT_UNDO; /* no need for ui_but_is_undo(), we never ne