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