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