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