10449a1133e356721408a461a5fb1b2cdaca1000
[blender-staging.git] / source / blender / editors / interface / interface_layout.c
1 /**
2  * $Id$
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  * Contributor(s): Blender Foundation 2009.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <limits.h>
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_ID.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_screen_types.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "BLI_listbase.h"
39 #include "BLI_string.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_idprop.h"
44 #include "BKE_library.h"
45 #include "BKE_screen.h"
46 #include "BKE_utildefines.h"
47
48 #include "RNA_access.h"
49
50 #include "UI_interface.h"
51 #include "UI_resources.h"
52 #include "UI_view2d.h"
53
54 #include "ED_util.h"
55 #include "ED_types.h"
56 #include "ED_screen.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "interface_intern.h"
62
63 /************************ Structs and Defines *************************/
64
65 #define RNA_NO_INDEX    -1
66 #define RNA_ENUM_VALUE  -2
67
68 #define EM_SEPR_X               6
69 #define EM_SEPR_Y               6
70
71 /* uiLayoutRoot */
72
73 typedef struct uiLayoutRoot {
74         struct uiLayoutRoot *next, *prev;
75
76         int type;
77         int opcontext;
78
79         int emw, emh;
80
81         uiMenuHandleFunc handlefunc;
82         void *argv;
83
84         uiStyle *style;
85         uiBlock *block;
86         uiLayout *layout;
87 } uiLayoutRoot;
88
89 /* Item */
90
91 typedef enum uiItemType {
92         ITEM_BUTTON,
93
94         ITEM_LAYOUT_ROW,
95         ITEM_LAYOUT_COLUMN,
96         ITEM_LAYOUT_COLUMN_FLOW,
97         ITEM_LAYOUT_ROW_FLOW,
98         ITEM_LAYOUT_BOX,
99         ITEM_LAYOUT_ABSOLUTE,
100         ITEM_LAYOUT_SPLIT,
101         ITEM_LAYOUT_OVERLAP,
102
103         ITEM_LAYOUT_ROOT
104 #if 0
105         TEMPLATE_COLUMN_FLOW,
106         TEMPLATE_SPLIT,
107         TEMPLATE_BOX,
108
109         TEMPLATE_HEADER,
110         TEMPLATE_HEADER_ID
111 #endif
112 } uiItemType;
113
114 typedef struct uiItem {
115         void *next, *prev;
116         uiItemType type;
117         int flag;
118 } uiItem;
119
120 typedef struct uiButtonItem {
121         uiItem item;
122         uiBut *but;
123 } uiButtonItem;
124
125 struct uiLayout {
126         uiItem item;
127
128         uiLayoutRoot *root;
129         bContextStore *context;
130         ListBase items;
131
132         int x, y, w, h;
133         float scale[2];
134         short space;
135         char align;
136         char active;
137         char enabled;
138         char redalert;
139         char keepaspect;
140         char alignment;
141 };
142
143 typedef struct uiLayoutItemFlow {
144         uiLayout litem;
145         int number;
146         int totcol;
147 } uiLayoutItemFlow;
148
149 typedef struct uiLayoutItemBx {
150         uiLayout litem;
151         uiBut *roundbox;
152 } uiLayoutItemBx;
153
154 typedef struct uiLayoutItemSplt {
155         uiLayout litem;
156         float percentage;
157 } uiLayoutItemSplt;
158
159 typedef struct uiLayoutItemRoot {
160         uiLayout litem;
161 } uiLayoutItemRoot;
162
163 /************************** Item ***************************/
164
165 static char *ui_item_name_add_colon(char *name, char namestr[UI_MAX_NAME_STR])
166 {
167         int len= strlen(name);
168
169         if(len != 0 && len+1 < UI_MAX_NAME_STR) {
170                 BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
171                 namestr[len]= ':';
172                 namestr[len+1]= '\0';
173                 return namestr;
174         }
175
176         return name;
177 }
178
179 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
180 {
181         /* available == 0 is unlimited */
182         if(available == 0)
183                 return item;
184         
185         if(offset)
186                 *offset= 0;
187         
188         if(all > available) {
189                 /* contents is bigger than available space */
190                 if(last)
191                         return available-pos;
192                 else
193                         return (item*available)/all;
194         }
195         else {
196                 /* contents is smaller or equal to available space */
197                 if(alignment == UI_LAYOUT_ALIGN_EXPAND) {
198                         if(last)
199                                 return available-pos;
200                         else
201                                 return (item*available)/all;
202                 }
203                 else
204                         return item;
205         }
206 }
207
208 /* variable button size in which direction? */
209 #define UI_ITEM_VARY_X  1
210 #define UI_ITEM_VARY_Y  2
211
212 static int ui_layout_vary_direction(uiLayout *layout)
213 {
214         return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND)? UI_ITEM_VARY_X: UI_ITEM_VARY_Y;
215 }
216
217 /* estimated size of text + icon */
218 static int ui_text_icon_width(uiLayout *layout, char *name, int icon, int compact)
219 {
220         int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
221
222         if(icon && !name[0])
223                 return UI_UNIT_X; /* icon only */
224         else if(icon)
225                 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* icon + text */
226         else
227                 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* text only */
228 }
229
230 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
231 {
232         if(item->type == ITEM_BUTTON) {
233                 uiButtonItem *bitem= (uiButtonItem*)item;
234
235                 if(r_w) *r_w= bitem->but->x2 - bitem->but->x1;
236                 if(r_h) *r_h= bitem->but->y2 - bitem->but->y1;
237         }
238         else {
239                 uiLayout *litem= (uiLayout*)item;
240
241                 if(r_w) *r_w= litem->w;
242                 if(r_h) *r_h= litem->h;
243         }
244 }
245
246 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
247 {
248         if(item->type == ITEM_BUTTON) {
249                 uiButtonItem *bitem= (uiButtonItem*)item;
250
251                 if(r_x) *r_x= bitem->but->x1;
252                 if(r_y) *r_y= bitem->but->y1;
253         }
254         else {
255                 if(r_x) *r_x= 0;
256                 if(r_y) *r_y= 0;
257         }
258 }
259
260 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
261 {
262         if(item->type == ITEM_BUTTON) {
263                 uiButtonItem *bitem= (uiButtonItem*)item;
264
265                 bitem->but->x1= x;
266                 bitem->but->y1= y;
267                 bitem->but->x2= x+w;
268                 bitem->but->y2= y+h;
269                 
270                 ui_check_but(bitem->but); /* for strlen */
271         }
272         else {
273                 uiLayout *litem= (uiLayout*)item;
274
275                 litem->x= x;
276                 litem->y= y+h;
277                 litem->w= w;
278                 litem->h= h;
279         }
280 }
281
282 /******************** Special RNA Items *********************/
283
284 static int ui_layout_local_dir(uiLayout *layout)
285 {
286         switch(layout->item.type) {
287                 case ITEM_LAYOUT_ROW:
288                 case ITEM_LAYOUT_ROOT:
289                 case ITEM_LAYOUT_OVERLAP:
290                         return UI_LAYOUT_HORIZONTAL;
291                 case ITEM_LAYOUT_COLUMN:
292                 case ITEM_LAYOUT_COLUMN_FLOW:
293                 case ITEM_LAYOUT_SPLIT:
294                 case ITEM_LAYOUT_ABSOLUTE:
295                 case ITEM_LAYOUT_BOX:
296                 default:
297                         return UI_LAYOUT_VERTICAL;
298         }
299 }
300
301 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
302 {
303         uiLayout *sub;
304
305         if(ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
306                 sub= uiLayoutRow(layout, align);
307         else
308                 sub= uiLayoutColumn(layout, align);
309         
310         sub->space= 0;
311         return sub;
312 }
313
314 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
315 {
316         wmWindow *win= CTX_wm_window(C);
317         uiBut *but= arg_but, *cbut;
318         PointerRNA *ptr= &but->rnapoin;
319         PropertyRNA *prop= but->rnaprop;
320         int i, index= GET_INT_FROM_POINTER(arg_index);
321         int shift= win->eventstate->shift;
322         int len= RNA_property_array_length(ptr, prop);
323
324         if(!shift) {
325                 RNA_property_boolean_set_index(ptr, prop, index, 1);
326
327                 for(i=0; i<len; i++)
328                         if(i != index)
329                                 RNA_property_boolean_set_index(ptr, prop, i, 0);
330
331                 RNA_property_update(C, ptr, prop);
332
333                 for(cbut=but->block->buttons.first; cbut; cbut=cbut->next)
334                         ui_check_but(cbut);
335         }
336 }
337
338 /* create buttons for an item with an RNA array */
339 static void ui_item_array(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int h, int expand, int slider)
340 {
341         uiStyle *style= layout->root->style;
342         uiBut *but;
343         PropertyType type;
344         PropertySubType subtype;
345         uiLayout *sub;
346         int a, b;
347
348         /* retrieve type and subtype */
349         type= RNA_property_type(prop);
350         subtype= RNA_property_subtype(prop);
351
352         sub= ui_item_local_sublayout(layout, layout, 1);
353         uiBlockSetCurLayout(block, sub);
354
355         /* create label */
356         if(strcmp(name, "") != 0)
357                 uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
358
359         /* create buttons */
360         if(type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
361                 /* special check for layer layout */
362                 int butw, buth, unit;
363                 int cols= (len >= 20)? 2: 1;
364                 int colbuts= len/(2*cols);
365
366                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 0));
367
368                 unit= UI_UNIT_X*0.75;
369                 butw= unit;
370                 buth= unit;
371
372                 for(b=0; b<cols; b++) {
373                         uiBlockBeginAlign(block);
374
375                         for(a=0; a<colbuts; a++) {
376                                 but= uiDefAutoButR(block, ptr, prop, a+b*colbuts, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
377                                 if(subtype == PROP_LAYER_MEMBER)
378                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+b*colbuts));
379                         }
380                         for(a=0; a<colbuts; a++) {
381                                 but= uiDefAutoButR(block, ptr, prop, a+len/2+b*colbuts, "", ICON_BLANK1, x + butw*a, y, butw, buth);
382                                 if(subtype == PROP_LAYER_MEMBER)
383                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+len/2+b*colbuts));
384                         }
385                         uiBlockEndAlign(block);
386
387                         x += colbuts*butw + style->buttonspacex;
388                 }
389         }
390         else if(subtype == PROP_MATRIX) {
391                 /* matrix layout */
392                 int row, col;
393
394                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 1));
395
396                 len= ceil(sqrt(len));
397
398                 h /= len;
399                 w /= len;
400
401                 // XXX test
402                 for(a=0; a<len; a++) {
403                         col= a%len;
404                         row= a/len;
405
406                         but= uiDefAutoButR(block, ptr, prop, a, "", 0, x + w*col, y+(row-a-1)*UI_UNIT_Y, w, UI_UNIT_Y);
407                         if(slider && but->type==NUM)
408                                 but->type= NUMSLI;
409                 }
410         }
411         else {
412                 if(ELEM(subtype, PROP_COLOR, PROP_RGB))
413                         uiDefAutoButR(block, ptr, prop, -1, "", 0, 0, 0, w, UI_UNIT_Y);
414
415                 if(!ELEM(subtype, PROP_COLOR, PROP_RGB) || expand) {
416                         /* layout for known array subtypes */
417                         char str[3];
418
419                         for(a=0; a<len; a++) {
420                                 str[0]= RNA_property_array_item_char(prop, a);
421
422                                 if(str[0]) {
423                                         if(type == PROP_BOOLEAN) {
424                                                 str[1]= '\0';
425                                         }
426                                         else {
427                                                 str[1]= ':';
428                                                 str[2]= '\0';
429                                         }
430                                 }
431
432                                 but= uiDefAutoButR(block, ptr, prop, a, str, 0, 0, 0, w, UI_UNIT_Y);
433                                 if(slider && but->type==NUM)
434                                         but->type= NUMSLI;
435                         }
436                 }
437                 else if(ELEM(subtype, PROP_COLOR, PROP_RGB) && len == 4) {
438                         but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, w, UI_UNIT_Y);
439                         if(slider && but->type==NUM)
440                                 but->type= NUMSLI;
441                 }
442         }
443
444         uiBlockSetCurLayout(block, layout);
445 }
446
447 static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, char *uiname, int x, int y, int w, int h, int icon_only)
448 {
449         EnumPropertyItem *item;
450         const char *identifier;
451         char *name;
452         int a, totitem, itemw, icon, value, free;
453
454         identifier= RNA_property_identifier(prop);
455         RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
456
457         uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
458         for(a=0; a<totitem; a++) {
459                 if(!item[a].identifier[0])
460                         continue;
461
462                 name= (!uiname || uiname[0])? (char*)item[a].name: "";
463                 icon= item[a].icon;
464                 value= item[a].value;
465                 itemw= ui_text_icon_width(block->curlayout, name, icon, 0);
466
467                 if(icon && strcmp(name, "") != 0 && !icon_only)
468                         uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
469                 else if(icon)
470                         uiDefIconButR(block, ROW, 0, icon, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
471                 else
472                         uiDefButR(block, ROW, 0, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
473         }
474         uiBlockSetCurLayout(block, layout);
475
476         if(free)
477                 MEM_freeN(item);
478 }
479
480 /* callback for keymap item change button */
481 static void ui_keymap_but_cb(bContext *C, void *but_v, void *key_v)
482 {
483         uiBut *but= but_v;
484         short modifier= *((short*)key_v);
485
486         RNA_boolean_set(&but->rnapoin, "shift", (modifier & KM_SHIFT) != 0);
487         RNA_boolean_set(&but->rnapoin, "ctrl", (modifier & KM_CTRL) != 0);
488         RNA_boolean_set(&but->rnapoin, "alt", (modifier & KM_ALT) != 0);
489         RNA_boolean_set(&but->rnapoin, "oskey", (modifier & KM_OSKEY) != 0);
490 }
491
492 /* create label + button for RNA property */
493 static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag)
494 {
495         uiLayout *sub;
496         uiBut *but=NULL;
497         PropertyType type;
498         PropertySubType subtype;
499         int labelw;
500
501         sub= uiLayoutRow(layout, 0);
502         uiBlockSetCurLayout(block, sub);
503
504         if(strcmp(name, "") != 0) {
505                 /* XXX UI_GetStringWidth is not accurate
506                 labelw= UI_GetStringWidth(name);
507                 CLAMP(labelw, w/4, 3*w/4);*/
508                 labelw= w/3;
509                 uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
510                 w= w-labelw;
511         }
512
513         type= RNA_property_type(prop);
514         subtype= RNA_property_subtype(prop);
515
516         if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
517                 uiBlockSetCurLayout(block, uiLayoutRow(sub, 1));
518                 uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w-UI_UNIT_X, h);
519
520                 /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
521                 but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, "Browse for file or directory.");
522         }
523         else if(subtype == PROP_DIRECTION) {
524                 uiDefButR(block, BUT_NORMAL, 0, name, x, y, 100, 100, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL);
525         }
526         else if(flag & UI_ITEM_R_EVENT) {
527                 uiDefButR(block, KEYEVT, 0, name, x, y, w, h, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL);
528         }
529         else if(flag & UI_ITEM_R_FULL_EVENT) {
530                 if(RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
531                         static short dummy = 0;
532                         char buf[128];
533
534                         WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
535
536                         but= uiDefButR(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, RNA_property_identifier(prop), 0, 0, 0, -1, -1, NULL);
537                         but->func_arg3= &dummy; // XXX abuse
538                         uiButSetFunc(but, ui_keymap_but_cb, but, &dummy);
539                 }
540         }
541         else
542                 but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY))? NULL: "", icon, x, y, w, h);
543
544         uiBlockSetCurLayout(block, layout);
545         return but;
546 }
547
548 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
549 {
550         ARegion *ar= CTX_wm_region(C);
551         uiBlock *block;
552         uiBut *but, *prevbut;
553
554         memset(ptr, 0, sizeof(*ptr));
555         *prop= NULL;
556
557         if(!ar)
558                 return;
559
560         for(block=ar->uiblocks.first; block; block=block->next) {
561                 for(but=block->buttons.first; but; but= but->next) {
562                         prevbut= but->prev;
563
564                         /* find the button before the active one */
565                         if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
566                                 if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
567                                         *ptr= prevbut->rnapoin;
568                                         *prop= prevbut->rnaprop;
569                                         return;
570                                 }
571                         }
572                 }
573         }
574 }
575
576 /********************* Button Items *************************/
577
578 /* disabled item */
579 static void ui_item_disabled(uiLayout *layout, char *name)
580 {
581         uiBlock *block= layout->root->block;
582         uiBut *but;
583         int w;
584
585         uiBlockSetCurLayout(block, layout);
586
587         if(!name)
588                 name= "";
589
590         w= ui_text_icon_width(layout, name, 0, 0);
591
592         but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
593         but->flag |= UI_BUT_DISABLED;
594         but->lock = 1;
595         but->lockstr = "";
596 }
597
598 /* operator items */
599 PointerRNA uiItemFullO(uiLayout *layout, char *name, int icon, char *idname, IDProperty *properties, int context, int flag)
600 {
601         uiBlock *block= layout->root->block;
602         wmOperatorType *ot= WM_operatortype_find(idname, 0);
603         uiBut *but;
604         int w;
605
606         if(!ot) {
607                 ui_item_disabled(layout, idname);
608                 return PointerRNA_NULL;
609         }
610
611         if(!name)
612                 name= ot->name;
613         if(layout->root->type == UI_LAYOUT_MENU && !icon)
614                 icon= ICON_BLANK1;
615
616         /* create button */
617         uiBlockSetCurLayout(block, layout);
618
619         w= ui_text_icon_width(layout, name, icon, 0);
620
621         if(icon && strcmp(name, "") != 0)
622                 but= uiDefIconTextButO(block, BUT, ot->idname, context, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
623         else if(icon)
624                 but= uiDefIconButO(block, BUT, ot->idname, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
625         else
626                 but= uiDefButO(block, BUT, ot->idname, context, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
627
628         /* assign properties */
629         if(properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
630                 PointerRNA *opptr= uiButGetOperatorPtrRNA(but);
631
632                 if(properties) {
633                         opptr->data= properties;
634                 }
635                 else {
636                         IDPropertyTemplate val = {0};
637                         opptr->data= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
638                 }
639
640                 return *opptr;
641         }
642
643         return PointerRNA_NULL;
644 }
645
646 static char *ui_menu_enumpropname(uiLayout *layout, char *opname, char *propname, int retval)
647 {
648         wmOperatorType *ot= WM_operatortype_find(opname, 0);
649         PointerRNA ptr;
650         PropertyRNA *prop;
651
652         if(!ot || !ot->srna)
653                 return "";
654
655         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
656         prop= RNA_struct_find_property(&ptr, propname);
657
658         if(prop) {
659                 EnumPropertyItem *item;
660                 int totitem, free;
661                 const char *name;
662
663                 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, &totitem, &free);
664                 if(RNA_enum_name(item, retval, &name)) {
665                         if(free) MEM_freeN(item);
666                         return (char*)name;
667                 }
668                 
669                 if(free)
670                         MEM_freeN(item);
671         }
672
673         return "";
674 }
675
676 void uiItemEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
677 {
678         PointerRNA ptr;
679
680         WM_operator_properties_create(&ptr, opname);
681         RNA_enum_set(&ptr, propname, value);
682
683         if(!name)
684                 name= ui_menu_enumpropname(layout, opname, propname, value);
685
686         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
687 }
688
689 void uiItemsEnumO(uiLayout *layout, char *opname, char *propname)
690 {
691         wmOperatorType *ot= WM_operatortype_find(opname, 0);
692         PointerRNA ptr;
693         PropertyRNA *prop;
694         uiBut *bt;
695         uiBlock *block= layout->root->block;
696
697         if(!ot || !ot->srna) {
698                 ui_item_disabled(layout, opname);
699                 return;
700         }
701
702         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
703         prop= RNA_struct_find_property(&ptr, propname);
704
705         if(prop && RNA_property_type(prop) == PROP_ENUM) {
706                 EnumPropertyItem *item;
707                 int totitem, i, free;
708                 uiLayout *split= uiLayoutSplit(layout, 0);
709                 uiLayout *column= uiLayoutColumn(split, 0);
710
711                 RNA_property_enum_items(block->evil_C, &ptr, prop, &item, &totitem, &free);
712
713                 for(i=0; i<totitem; i++) {
714                         if(item[i].identifier[0]) {
715                                 uiItemEnumO(column, (char*)item[i].name, item[i].icon, opname, propname, item[i].value);
716                         }
717                         else {
718                                 if(item[i].name) {
719                                         if(i != 0) {
720                                                 column= uiLayoutColumn(split, 0);
721                                                 /* inconsistent, but menus with labels do not look good flipped */
722                                                 block->flag |= UI_BLOCK_NO_FLIP;
723                                         }
724
725                                         uiItemL(column, (char*)item[i].name, 0);
726                                         bt= block->buttons.last;
727                                         bt->flag= UI_TEXT_LEFT;
728                                 }
729                                 else
730                                         uiItemS(column);
731                         }
732                 }
733
734                 if(free)
735                         MEM_freeN(item);
736         }
737 }
738
739 /* for use in cases where we have */
740 void uiItemEnumO_string(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value_str)
741 {
742         PointerRNA ptr;
743         
744         /* for getting the enum */
745         PropertyRNA *prop;
746         EnumPropertyItem *item;
747         int value, free;
748
749         WM_operator_properties_create(&ptr, opname);
750         
751         /* enum lookup */
752         if((prop= RNA_struct_find_property(&ptr, propname))) {
753                 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
754                 if(item==NULL || RNA_enum_value_from_id(item, value_str, &value)==0) {
755                         if(free) MEM_freeN(item);
756                         printf("uiItemEnumO_string: %s.%s, enum %s not found.\n", RNA_struct_identifier(ptr.type), propname, value_str);
757                         return;
758                 }
759
760                 if(free)
761                         MEM_freeN(item);
762         }
763         else {
764                 printf("uiItemEnumO_string: %s.%s not found.\n", RNA_struct_identifier(ptr.type), propname);
765                 return;
766         }
767         
768         RNA_property_enum_set(&ptr, prop, value);
769         
770         /* same as uiItemEnumO */
771         if(!name)
772                 name= ui_menu_enumpropname(layout, opname, propname, value);
773
774         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
775 }
776
777 void uiItemBooleanO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
778 {
779         PointerRNA ptr;
780
781         WM_operator_properties_create(&ptr, opname);
782         RNA_boolean_set(&ptr, propname, value);
783
784         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
785 }
786
787 void uiItemIntO(uiLayout *layout, char *name, int icon, char *opname, char *propname, int value)
788 {
789         PointerRNA ptr;
790
791         WM_operator_properties_create(&ptr, opname);
792         RNA_int_set(&ptr, propname, value);
793
794         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
795 }
796
797 void uiItemFloatO(uiLayout *layout, char *name, int icon, char *opname, char *propname, float value)
798 {
799         PointerRNA ptr;
800
801         WM_operator_properties_create(&ptr, opname);
802         RNA_float_set(&ptr, propname, value);
803
804         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
805 }
806
807 void uiItemStringO(uiLayout *layout, char *name, int icon, char *opname, char *propname, char *value)
808 {
809         PointerRNA ptr;
810
811         WM_operator_properties_create(&ptr, opname);
812         RNA_string_set(&ptr, propname, value);
813
814         uiItemFullO(layout, name, icon, opname, ptr.data, layout->root->opcontext, 0);
815 }
816
817 void uiItemO(uiLayout *layout, char *name, int icon, char *opname)
818 {
819         uiItemFullO(layout, name, icon, opname, NULL, layout->root->opcontext, 0);
820 }
821
822 /* RNA property items */
823
824 static void ui_item_rna_size(uiLayout *layout, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int icon_only, int *r_w, int *r_h)
825 {
826         PropertyType type;
827         PropertySubType subtype;
828         int len, w, h;
829
830         /* arbitrary extended width by type */
831         type= RNA_property_type(prop);
832         subtype= RNA_property_subtype(prop);
833         len= RNA_property_array_length(ptr, prop);
834
835         if(ELEM3(type, PROP_STRING, PROP_POINTER, PROP_ENUM) && !name[0] && !icon_only)
836                 name= "non-empty text";
837         else if(type == PROP_BOOLEAN && !name[0] && !icon_only)
838                 icon= ICON_DOT;
839
840         w= ui_text_icon_width(layout, name, icon, 0);
841         h= UI_UNIT_Y;
842
843         /* increase height for arrays */
844         if(index == RNA_NO_INDEX && len > 0) {
845                 if(!name[0] && icon == 0)
846                         h= 0;
847
848                 if(ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
849                         h += 2*UI_UNIT_Y;
850                 else if(subtype == PROP_MATRIX)
851                         h += ceil(sqrt(len))*UI_UNIT_Y;
852                 else
853                         h += len*UI_UNIT_Y;
854         }
855         else if(ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
856                 if(type == PROP_BOOLEAN && strcmp(name, "") != 0)
857                         w += UI_UNIT_X/5;
858                 else if(type == PROP_ENUM)
859                         w += UI_UNIT_X/4;
860                 else if(type == PROP_FLOAT || type == PROP_INT)
861                         w += UI_UNIT_X*3;
862         }
863
864         *r_w= w;
865         *r_h= h;
866 }
867
868 void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag)
869 {
870         uiBlock *block= layout->root->block;
871         uiBut *but;
872         PropertyType type;
873         char namestr[UI_MAX_NAME_STR];
874         int len, w, h, slider, toggle, expand, icon_only;
875
876         uiBlockSetCurLayout(block, layout);
877
878         /* retrieve info */
879         type= RNA_property_type(prop);
880         len= RNA_property_array_length(ptr, prop);
881
882         /* set name and icon */
883         if(!name)
884                 name= (char*)RNA_property_ui_name(prop);
885         if(!icon)
886                 icon= RNA_property_ui_icon(prop);
887
888         if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
889                 name= ui_item_name_add_colon(name, namestr);
890         else if(type == PROP_BOOLEAN && len)
891                 name= ui_item_name_add_colon(name, namestr);
892         else if(type == PROP_ENUM && index != RNA_ENUM_VALUE)
893                 name= ui_item_name_add_colon(name, namestr);
894
895         if(layout->root->type == UI_LAYOUT_MENU) {
896                 /* whether the property is actually enabled doesn't matter, 
897                  * since the widget code for drawing toggles takes care of the 
898                  * rest (i.e. given the deactivated icon, it finds the active one
899                  * based on the state of the setting)
900                  */
901                 if ( (type == PROP_BOOLEAN) || (type==PROP_ENUM && index==RNA_ENUM_VALUE) )
902                         icon= ICON_CHECKBOX_DEHLT; /* ICON_CHECKBOX_HLT when on... */
903         }
904
905         slider= (flag & UI_ITEM_R_SLIDER);
906         toggle= (flag & UI_ITEM_R_TOGGLE);
907         expand= (flag & UI_ITEM_R_EXPAND);
908         icon_only= (flag & UI_ITEM_R_ICON_ONLY);
909
910         /* get size */
911         ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
912
913         /* array property */
914         if(index == RNA_NO_INDEX && len > 0)
915                 ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider);
916         /* enum item */
917         else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
918                 char *identifier= (char*)RNA_property_identifier(prop);
919
920                 if(icon && strcmp(name, "") != 0 && !icon_only)
921                         uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
922                 else if(icon)
923                         uiDefIconButR(block, ROW, 0, icon, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
924                 else
925                         uiDefButR(block, ROW, 0, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
926         }
927         /* expanded enum */
928         else if(type == PROP_ENUM && expand)
929                 ui_item_enum_row(layout, block, ptr, prop, name, 0, 0, w, h, icon_only);
930         /* property with separate label */
931         else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
932                 but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
933                 ui_but_add_search(but, ptr, prop, NULL, NULL);
934         }
935         /* single button */
936         else {
937                 but= uiDefAutoButR(block, ptr, prop, index, (char*)name, icon, 0, 0, w, h);
938
939                 if(slider && but->type==NUM)
940                         but->type= NUMSLI;
941
942                 if(toggle && but->type==OPTION)
943                         but->type= TOG;
944         }
945 }
946
947 void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int flag)
948 {
949         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
950
951         if(!prop) {
952                 ui_item_disabled(layout, propname);
953                 printf("uiItemR: property not found: %s\n", propname);
954                 return;
955         }
956
957         uiItemFullR(layout, name, icon, ptr, prop, RNA_NO_INDEX, 0, flag);
958 }
959
960 void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value)
961 {
962         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
963
964         if(!prop || RNA_property_type(prop) != PROP_ENUM) {
965                 ui_item_disabled(layout, propname);
966                 printf("uiItemEnumR: enum property not found: %s\n", propname);
967                 return;
968         }
969
970         uiItemFullR(layout, name, icon, ptr, prop, RNA_ENUM_VALUE, value, 0);
971 }
972
973 void uiItemEnumR_string(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, char *value)
974 {
975         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
976         EnumPropertyItem *item;
977         int ivalue, a, free;
978
979         if(!prop || RNA_property_type(prop) != PROP_ENUM) {
980                 ui_item_disabled(layout, propname);
981                 printf("uiItemEnumR: enum property not found: %s\n", propname);
982                 return;
983         }
984
985         RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
986
987         if(!RNA_enum_value_from_id(item, value, &ivalue)) {
988                 if(free) MEM_freeN(item);
989                 ui_item_disabled(layout, propname);
990                 printf("uiItemEnumR: enum property value not found: %s\n", value);
991                 return;
992         }
993
994         for(a=0; item[a].identifier; a++) {
995                 if(item[a].value == ivalue) {
996                         uiItemFullR(layout, (char*)item[a].name, item[a].icon, ptr, prop, RNA_ENUM_VALUE, ivalue, 0);
997                         break;
998                 }
999         }
1000
1001         if(free)
1002                 MEM_freeN(item);
1003 }
1004
1005 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname)
1006 {
1007         PropertyRNA *prop;
1008         uiBlock *block= layout->root->block;
1009         uiBut *bt;
1010
1011         prop= RNA_struct_find_property(ptr, propname);
1012
1013         if(!prop) {
1014                 ui_item_disabled(layout, propname);
1015                 return;
1016         }
1017
1018         if(RNA_property_type(prop) == PROP_ENUM) {
1019                 EnumPropertyItem *item;
1020                 int totitem, i, free;
1021                 uiLayout *split= uiLayoutSplit(layout, 0);
1022                 uiLayout *column= uiLayoutColumn(split, 0);
1023
1024                 RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
1025
1026                 for(i=0; i<totitem; i++) {
1027                         if(item[i].identifier[0]) {
1028                                 uiItemEnumR(column, (char*)item[i].name, 0, ptr, propname, item[i].value);
1029                         }
1030                         else {
1031                                 if(item[i].name) {
1032                                         if(i != 0) {
1033                                                 column= uiLayoutColumn(split, 0);
1034                                                 /* inconsistent, but menus with labels do not look good flipped */
1035                                                 block->flag |= UI_BLOCK_NO_FLIP;
1036                                         }
1037
1038                                         uiItemL(column, (char*)item[i].name, 0);
1039                                         bt= block->buttons.last;
1040                                         bt->flag= UI_TEXT_LEFT;
1041                                 }
1042                                 else
1043                                         uiItemS(column);
1044                         }
1045                 }
1046
1047                 if(free)
1048                         MEM_freeN(item);
1049         }
1050 }
1051
1052 /* Pointer RNA button with search */
1053
1054 static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, uiSearchItems *items)
1055 {
1056         uiBut *but= arg_but;
1057         char *name;
1058         int i, iconid, flag= RNA_property_flag(but->rnaprop);
1059
1060         i = 0;
1061         RNA_PROP_BEGIN(&but->rnasearchpoin, itemptr, but->rnasearchprop) {
1062                 if(flag & PROP_ID_SELF_CHECK)
1063                         if(itemptr.data == but->rnapoin.id.data)
1064                                 continue;
1065
1066                 iconid= 0;
1067                 if(RNA_struct_is_ID(itemptr.type))
1068                         iconid= ui_id_icon_get((bContext*)C, itemptr.data);
1069
1070                 name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
1071
1072                 if(name) {
1073                         if(BLI_strcasestr(name, str)) {
1074                                 if(!uiSearchItemAdd(items, name, SET_INT_IN_POINTER(i), iconid)) {
1075                                         MEM_freeN(name);
1076                                         break;
1077                                 }
1078                         }
1079
1080                         MEM_freeN(name);
1081                 }
1082
1083                 i++;
1084         }
1085         RNA_PROP_END;
1086 }
1087
1088 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
1089 {
1090         StructRNA *srna;
1091
1092         /* look for collection property in Main */
1093         RNA_main_pointer_create(G.main, ptr);
1094
1095         *prop= NULL;
1096
1097         RNA_STRUCT_BEGIN(ptr, iprop) {
1098                 /* if it's a collection and has same pointer type, we've got it */
1099                 if(RNA_property_type(iprop) == PROP_COLLECTION) {
1100                         srna= RNA_property_pointer_type(ptr, iprop);
1101
1102                         if(ptype == srna) {
1103                                 *prop= iprop;
1104                                 break;
1105                         }
1106                 }
1107         }
1108         RNA_STRUCT_END;
1109 }
1110
1111 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
1112 {
1113         StructRNA *ptype;
1114         PointerRNA sptr;
1115
1116         /* for ID's we do automatic lookup */
1117         if(!searchprop) {
1118                 if(RNA_property_type(prop) == PROP_POINTER) {
1119                         ptype= RNA_property_pointer_type(ptr, prop);
1120                         search_id_collection(ptype, &sptr, &searchprop);
1121                         searchptr= &sptr;
1122                 }
1123         }
1124
1125         /* turn button into search button */
1126         if(searchprop) {
1127                 but->type= SEARCH_MENU;
1128                 but->hardmax= MAX2(but->hardmax, 256);
1129                 but->rnasearchpoin= *searchptr;
1130                 but->rnasearchprop= searchprop;
1131                 but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT|UI_BUT_UNDO;
1132
1133                 uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
1134         }
1135 }
1136
1137 void uiItemPointerR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, struct PointerRNA *searchptr, char *searchpropname)
1138 {
1139         PropertyRNA *prop, *searchprop;
1140         PropertyType type;
1141         uiBut *but;
1142         uiBlock *block;
1143         StructRNA *icontype;
1144         int w, h;
1145         
1146         /* validate arguments */
1147         prop= RNA_struct_find_property(ptr, propname);
1148
1149         if(!prop) {
1150                 printf("uiItemPointerR: property not found: %s\n", propname);
1151                 return;
1152         }
1153         
1154         type= RNA_property_type(prop);
1155         if(!ELEM(type, PROP_POINTER, PROP_STRING)) {
1156                 printf("uiItemPointerR: property %s must be a pointer or string.\n", propname);
1157                 return;
1158         }
1159
1160         searchprop= RNA_struct_find_property(searchptr, searchpropname);
1161
1162         if(!searchprop || RNA_property_type(searchprop) != PROP_COLLECTION) {
1163                 printf("uiItemPointerR: search collection property not found: %s\n", searchpropname);
1164                 return;
1165         }
1166
1167         /* get icon & name */
1168         if(!icon) {
1169                 if(type == PROP_POINTER)
1170                         icontype= RNA_property_pointer_type(ptr, prop);
1171                 else
1172                         icontype= RNA_property_pointer_type(searchptr, searchprop);
1173
1174                 icon= RNA_struct_ui_icon(icontype);
1175         }
1176         if(!name)
1177                 name= (char*)RNA_property_ui_name(prop);
1178
1179         /* create button */
1180         block= uiLayoutGetBlock(layout);
1181
1182         ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
1183         but= ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
1184
1185         ui_but_add_search(but, ptr, prop, searchptr, searchprop);
1186 }
1187
1188 /* menu item */
1189 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
1190 {
1191         MenuType *mt= (MenuType*)arg_mt;
1192         Menu menu = {0};
1193
1194         menu.type= mt;
1195         menu.layout= layout;
1196         mt->draw(C, &menu);
1197 }
1198
1199 static void ui_item_menu(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN)
1200 {
1201         uiBlock *block= layout->root->block;
1202         uiBut *but;
1203         int w, h;
1204
1205         uiBlockSetCurLayout(block, layout);
1206
1207         if(layout->root->type == UI_LAYOUT_HEADER)
1208                 uiBlockSetEmboss(block, UI_EMBOSS);
1209
1210         if(!name)
1211                 name= "";
1212         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1213                 icon= ICON_BLANK1;
1214
1215         w= ui_text_icon_width(layout, name, icon, 1);
1216         h= UI_UNIT_Y;
1217
1218         if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
1219                 w -= 10;
1220
1221         if(name[0] && icon)
1222                 but= uiDefIconTextMenuBut(block, func, arg, icon, (char*)name, 0, 0, w, h, "");
1223         else if(icon)
1224                 but= uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, "");
1225         else
1226                 but= uiDefMenuBut(block, func, arg, (char*)name, 0, 0, w, h, "");
1227
1228         if(argN) { /* ugly .. */
1229                 but->poin= (char*)but;
1230                 but->func_argN= argN;
1231         }
1232
1233         if(layout->root->type == UI_LAYOUT_HEADER)
1234                 uiBlockSetEmboss(block, UI_EMBOSS);
1235         else if(layout->root->type == UI_LAYOUT_PANEL)
1236                 but->type= MENU;
1237 }
1238
1239 void uiItemM(uiLayout *layout, bContext *C, char *name, int icon, char *menuname)
1240 {
1241         MenuType *mt;
1242
1243         mt= WM_menutype_find(menuname, FALSE);
1244
1245         if(mt==NULL) {
1246                 printf("uiItemM: not found %s\n", menuname);
1247                 return;
1248         }
1249
1250         if(!name)
1251                 name= mt->label;
1252         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1253                 icon= ICON_BLANK1;
1254
1255         ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL);
1256 }
1257
1258 /* label item */
1259 void uiItemL(uiLayout *layout, char *name, int icon)
1260 {
1261         uiBlock *block= layout->root->block;
1262         uiBut *but;
1263         int w;
1264
1265         uiBlockSetCurLayout(block, layout);
1266
1267         if(!name)
1268                 name= "";
1269         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1270                 icon= ICON_BLANK1;
1271
1272         w= ui_text_icon_width(layout, name, icon, 0);
1273
1274         if(icon && strcmp(name, "") != 0)
1275                 but= uiDefIconTextBut(block, LABEL, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1276         else if(icon)
1277                 but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1278         else
1279                 but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1280 }
1281
1282 /* value item */
1283 void uiItemV(uiLayout *layout, char *name, int icon, int argval)
1284 {
1285         /* label */
1286         uiBlock *block= layout->root->block;
1287         float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
1288         int w;
1289
1290         uiBlockSetCurLayout(block, layout);
1291
1292         if(!name)
1293                 name= "";
1294         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1295                 icon= ICON_BLANK1;
1296
1297         w= ui_text_icon_width(layout, name, icon, 0);
1298
1299         if(icon && strcmp(name, "") != 0)
1300                 uiDefIconTextButF(block, BUTM, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1301         else if(icon)
1302                 uiDefIconButF(block, BUTM, 0, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1303         else
1304                 uiDefButF(block, BUTM, 0, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1305 }
1306
1307 /* separator item */
1308 void uiItemS(uiLayout *layout)
1309 {
1310         uiBlock *block= layout->root->block;
1311
1312         uiBlockSetCurLayout(block, layout);
1313         uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
1314 }
1315
1316 /* level items */
1317 void uiItemMenuF(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg)
1318 {
1319         if(!func)
1320                 return;
1321
1322         ui_item_menu(layout, name, icon, func, arg, NULL);
1323 }
1324
1325 typedef struct MenuItemLevel {
1326         int opcontext;
1327         char *opname;
1328         char *propname;
1329         PointerRNA rnapoin;
1330 } MenuItemLevel;
1331
1332 static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
1333 {
1334         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1335
1336         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
1337         uiItemsEnumO(layout, lvl->opname, lvl->propname);
1338 }
1339
1340 void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname)
1341 {
1342         wmOperatorType *ot= WM_operatortype_find(opname, 0);
1343         MenuItemLevel *lvl;
1344
1345         if(!ot || !ot->srna) {
1346                 ui_item_disabled(layout, opname);
1347                 return;
1348         }
1349
1350         if(!name)
1351                 name= ot->name;
1352         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1353                 icon= ICON_BLANK1;
1354
1355         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1356         lvl->opname= opname;
1357         lvl->propname= propname;
1358         lvl->opcontext= layout->root->opcontext;
1359
1360         ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl);
1361 }
1362
1363 static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg)
1364 {
1365         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1366
1367         uiLayoutSetOperatorContext(layout, lvl->opcontext);
1368         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
1369 }
1370
1371 void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname)
1372 {
1373         MenuItemLevel *lvl;
1374         PropertyRNA *prop;
1375
1376         prop= RNA_struct_find_property(ptr, propname);
1377         if(!prop) {
1378                 ui_item_disabled(layout, propname);
1379                 return;
1380         }
1381
1382         if(!name)
1383                 name= (char*)RNA_property_ui_name(prop);
1384         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1385                 icon= ICON_BLANK1;
1386
1387         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1388         lvl->rnapoin= *ptr;
1389         lvl->propname= propname;
1390         lvl->opcontext= layout->root->opcontext;
1391
1392         ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl);
1393 }
1394
1395 /**************************** Layout Items ***************************/
1396
1397 /* single-row layout */
1398 static void ui_litem_estimate_row(uiLayout *litem)
1399 {
1400         uiItem *item;
1401         int itemw, itemh;
1402
1403         litem->w= 0;
1404         litem->h= 0;
1405
1406         for(item=litem->items.first; item; item=item->next) {
1407                 ui_item_size(item, &itemw, &itemh);
1408
1409                 litem->w += itemw;
1410                 litem->h= MAX2(itemh, litem->h);
1411
1412                 if(item->next)
1413                         litem->w += litem->space;
1414         }
1415 }
1416
1417 static int ui_litem_min_width(int itemw)
1418 {
1419         return MIN2(2*UI_UNIT_X, itemw);
1420 }
1421
1422 static void ui_litem_layout_row(uiLayout *litem)
1423 {
1424         uiItem *item;
1425         int x, y, w, tot, totw, neww, itemw, minw, itemh, offset;
1426         int fixedw, freew, fixedx, freex, flag= 0, lastw= 0;
1427
1428         x= litem->x;
1429         y= litem->y;
1430         w= litem->w;
1431         totw= 0;
1432         tot= 0;
1433
1434         for(item=litem->items.first; item; item=item->next) {
1435                 ui_item_size(item, &itemw, &itemh);
1436                 totw += itemw;
1437                 tot++;
1438         }
1439
1440         if(totw == 0)
1441                 return;
1442         
1443         if(w != 0)
1444                 w -= (tot-1)*litem->space;
1445         fixedw= 0;
1446
1447         /* keep clamping items to fixed minimum size until all are done */
1448         do {
1449                 freew= 0;
1450                 x= 0;
1451                 flag= 0;
1452
1453                 for(item=litem->items.first; item; item=item->next) {
1454                         if(item->flag)
1455                                 continue;
1456
1457                         ui_item_size(item, &itemw, &itemh);
1458                         minw= ui_litem_min_width(itemw);
1459
1460                         if(w - lastw > 0)
1461                                 neww= ui_item_fit(itemw, x, totw, w-lastw, !item->next, litem->alignment, NULL);
1462                         else
1463                                 neww= 0; /* no space left, all will need clamping to minimum size */
1464
1465                         x += neww;
1466
1467                         if((neww < minw || itemw == minw) && w != 0) {
1468                                 /* fixed size */
1469                                 item->flag= 1;
1470                                 fixedw += minw;
1471                                 flag= 1;
1472                                 totw -= itemw;
1473                         }
1474                         else {
1475                                 /* keep free size */
1476                                 item->flag= 0;
1477                                 freew += itemw;
1478                         }
1479                 }
1480
1481                 lastw= fixedw;
1482         } while(flag);
1483
1484         freex= 0;
1485         fixedx= 0;
1486         x= litem->x;
1487
1488         for(item=litem->items.first; item; item=item->next) {
1489                 ui_item_size(item, &itemw, &itemh);
1490                 minw= ui_litem_min_width(itemw);
1491
1492                 if(item->flag) {
1493                         /* fixed minimum size items */
1494                         itemw= ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL);
1495                         fixedx += itemw;
1496                 }
1497                 else {
1498                         /* free size item */
1499                         itemw= ui_item_fit(itemw, freex, freew, w-fixedw, !item->next, litem->alignment, NULL);
1500                         freex += itemw;
1501                 }
1502
1503                 /* align right/center */
1504                 offset= 0;
1505                 if(litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
1506                         if(fixedw == 0 && freew < w-fixedw)
1507                                 offset= (w - fixedw) - freew;
1508                 }
1509                 else if(litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
1510                         if(fixedw == 0 && freew < w-fixedw)
1511                                 offset= ((w - fixedw) - freew)/2;
1512                 }
1513
1514                 /* position item */
1515                 ui_item_position(item, x+offset, y-itemh, itemw, itemh);
1516
1517                 x += itemw;
1518                 if(item->next)
1519                         x += litem->space;
1520         }
1521
1522         litem->w= x - litem->x;
1523         litem->h= litem->y - y;
1524         litem->x= x;
1525         litem->y= y;
1526 }
1527
1528 /* single-column layout */
1529 static void ui_litem_estimate_column(uiLayout *litem)
1530 {
1531         uiItem *item;
1532         int itemw, itemh;
1533
1534         litem->w= 0;
1535         litem->h= 0;
1536
1537         for(item=litem->items.first; item; item=item->next) {
1538                 ui_item_size(item, &itemw, &itemh);
1539
1540                 litem->w= MAX2(litem->w, itemw);
1541                 litem->h += itemh;
1542
1543                 if(item->next)
1544                         litem->h += litem->space;
1545         }
1546 }
1547
1548 static void ui_litem_layout_column(uiLayout *litem)
1549 {
1550         uiItem *item;
1551         int itemh, x, y;
1552
1553         x= litem->x;
1554         y= litem->y;
1555
1556         for(item=litem->items.first; item; item=item->next) {
1557                 ui_item_size(item, NULL, &itemh);
1558
1559                 y -= itemh;
1560                 ui_item_position(item, x, y, litem->w, itemh);
1561
1562                 if(item->next)
1563                         y -= litem->space;
1564         }
1565
1566         litem->h= litem->y - y;
1567         litem->x= x;
1568         litem->y= y;
1569 }
1570
1571 /* root layout */
1572 static void ui_litem_estimate_root(uiLayout *litem)
1573 {
1574         /* nothing to do */
1575 }
1576
1577 static void ui_litem_layout_root(uiLayout *litem)
1578 {
1579         if(litem->root->type == UI_LAYOUT_HEADER)
1580                 ui_litem_layout_row(litem);
1581         else
1582                 ui_litem_layout_column(litem);
1583 }
1584
1585 /* box layout */
1586 static void ui_litem_estimate_box(uiLayout *litem)
1587 {
1588         uiStyle *style= litem->root->style;
1589
1590         ui_litem_estimate_column(litem);
1591         litem->w += 2*style->boxspace;
1592         litem->h += style->boxspace;
1593 }
1594
1595 static void ui_litem_layout_box(uiLayout *litem)
1596 {
1597         uiLayoutItemBx *box= (uiLayoutItemBx*)litem;
1598         uiStyle *style= litem->root->style;
1599         uiBut *but;
1600         int w, h;
1601
1602         w= litem->w;
1603         h= litem->h;
1604
1605         litem->x += style->boxspace;
1606
1607         if(w != 0) litem->w -= 2*style->boxspace;
1608         if(h != 0) litem->h -= 2*style->boxspace;
1609
1610         ui_litem_layout_column(litem);
1611
1612         litem->x -= style->boxspace;
1613         litem->y -= style->boxspace;
1614
1615         if(w != 0) litem->w += 2*style->boxspace;
1616         if(h != 0) litem->h += style->boxspace;
1617
1618         /* roundbox around the sublayout */
1619         but= box->roundbox;
1620         but->x1= litem->x;
1621         but->y1= litem->y;
1622         but->x2= litem->x+litem->w;
1623         but->y2= litem->y+litem->h;
1624 }
1625
1626 /* multi-column layout, automatically flowing to the next */
1627 static void ui_litem_estimate_column_flow(uiLayout *litem)
1628 {
1629         uiStyle *style= litem->root->style;
1630         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1631         uiItem *item;
1632         int col, x, y, emh, emy, miny, itemw, itemh, maxw=0;
1633         int toth, totitem;
1634
1635         /* compute max needed width and total height */
1636         toth= 0;
1637         totitem= 0;
1638         for(item=litem->items.first; item; item=item->next) {
1639                 ui_item_size(item, &itemw, &itemh);
1640                 maxw= MAX2(maxw, itemw);
1641                 toth += itemh;
1642                 totitem++;
1643         }
1644
1645         if(flow->number <= 0) {
1646                 /* auto compute number of columns, not very good */
1647                 if(maxw == 0) {
1648                         flow->totcol= 1;
1649                         return;
1650                 }
1651
1652                 flow->totcol= MAX2(litem->root->emw/maxw, 1);
1653                 flow->totcol= MIN2(flow->totcol, totitem);
1654         }
1655         else
1656                 flow->totcol= flow->number;
1657
1658         /* compute sizes */
1659         x= 0;
1660         y= 0;
1661         emy= 0;
1662         miny= 0;
1663
1664         maxw= 0;
1665         emh= toth/flow->totcol;
1666
1667         /* create column per column */
1668         col= 0;
1669         for(item=litem->items.first; item; item=item->next) {
1670                 ui_item_size(item, &itemw, &itemh);
1671
1672                 y -= itemh + style->buttonspacey;
1673                 miny= MIN2(miny, y);
1674                 emy -= itemh;
1675                 maxw= MAX2(itemw, maxw);
1676
1677                 /* decide to go to next one */
1678                 if(col < flow->totcol-1 && emy <= -emh) {
1679                         x += maxw + litem->space;
1680                         maxw= 0;
1681                         y= 0;
1682                         col++;
1683                 }
1684         }
1685
1686         litem->w= x;
1687         litem->h= litem->y - miny;
1688 }
1689
1690 static void ui_litem_layout_column_flow(uiLayout *litem)
1691 {
1692         uiStyle *style= litem->root->style;
1693         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1694         uiItem *item;
1695         int col, x, y, w, emh, emy, miny, itemw, itemh;
1696         int toth, totitem, offset;
1697
1698         /* compute max needed width and total height */
1699         toth= 0;
1700         totitem= 0;
1701         for(item=litem->items.first; item; item=item->next) {
1702                 ui_item_size(item, &itemw, &itemh);
1703                 toth += itemh;
1704                 totitem++;
1705         }
1706
1707         /* compute sizes */
1708         x= litem->x;
1709         y= litem->y;
1710         emy= 0;
1711         miny= 0;
1712
1713         w= litem->w - (flow->totcol-1)*style->columnspace;
1714         emh= toth/flow->totcol;
1715
1716         /* create column per column */
1717         col= 0;
1718         for(item=litem->items.first; item; item=item->next) {
1719                 ui_item_size(item, NULL, &itemh);
1720                 itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, col == flow->totcol-1, litem->alignment, &offset);
1721         
1722                 y -= itemh;
1723                 emy -= itemh;
1724                 ui_item_position(item, x+offset, y, itemw, itemh);
1725                 y -= style->buttonspacey;
1726                 miny= MIN2(miny, y);
1727
1728                 /* decide to go to next one */
1729                 if(col < flow->totcol-1 && emy <= -emh) {
1730                         x += itemw + style->columnspace;
1731                         y= litem->y;
1732                         col++;
1733                 }
1734         }
1735
1736         litem->h= litem->y - miny;
1737         litem->x= x;
1738         litem->y= miny;
1739 }
1740
1741 /* free layout */
1742 static void ui_litem_estimate_absolute(uiLayout *litem)
1743 {
1744         uiItem *item;
1745         int itemx, itemy, itemw, itemh, minx, miny;
1746
1747         minx= 1e6;
1748         miny= 1e6;
1749         litem->w= 0;
1750         litem->h= 0;
1751
1752         for(item=litem->items.first; item; item=item->next) {
1753                 ui_item_offset(item, &itemx, &itemy);
1754                 ui_item_size(item, &itemw, &itemh);
1755
1756                 minx= MIN2(minx, itemx);
1757                 miny= MIN2(miny, itemy);
1758
1759                 litem->w= MAX2(litem->w, itemx+itemw);
1760                 litem->h= MAX2(litem->h, itemy+itemh);
1761         }
1762
1763         litem->w -= minx;
1764         litem->h -= miny;
1765 }
1766
1767 static void ui_litem_layout_absolute(uiLayout *litem)
1768 {
1769         uiItem *item;
1770         float scalex=1.0f, scaley=1.0f;
1771         int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
1772
1773         minx= 1e6;
1774         miny= 1e6;
1775         totw= 0;
1776         toth= 0;
1777
1778         for(item=litem->items.first; item; item=item->next) {
1779                 ui_item_offset(item, &itemx, &itemy);
1780                 ui_item_size(item, &itemw, &itemh);
1781
1782                 minx= MIN2(minx, itemx);
1783                 miny= MIN2(miny, itemy);
1784
1785                 totw= MAX2(totw, itemx+itemw);
1786                 toth= MAX2(toth, itemy+itemh);
1787         }
1788
1789         totw -= minx;
1790         toth -= miny;
1791
1792         if(litem->w && totw > 0)
1793                 scalex= (float)litem->w/(float)totw;
1794         if(litem->h && toth > 0)
1795                 scaley= (float)litem->h/(float)toth;
1796         
1797         x= litem->x;
1798         y= litem->y - scaley*toth;
1799
1800         for(item=litem->items.first; item; item=item->next) {
1801                 ui_item_offset(item, &itemx, &itemy);
1802                 ui_item_size(item, &itemw, &itemh);
1803
1804                 if(scalex != 1.0f) {
1805                         newx= (itemx - minx)*scalex;
1806                         itemw= (itemx - minx + itemw)*scalex - newx;
1807                         itemx= minx + newx;
1808                 }
1809
1810                 if(scaley != 1.0f) {
1811                         newy= (itemy - miny)*scaley;
1812                         itemh= (itemy - miny + itemh)*scaley - newy;
1813                         itemy= miny + newy;
1814                 }
1815
1816                 ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh);
1817         }
1818
1819         litem->w= scalex*totw;
1820         litem->h= litem->y - y;
1821         litem->x= x + litem->w;
1822         litem->y= y;
1823 }
1824
1825 /* split layout */
1826 static void ui_litem_estimate_split(uiLayout *litem)
1827 {
1828         ui_litem_estimate_row(litem);
1829 }
1830
1831 static void ui_litem_layout_split(uiLayout *litem)
1832 {
1833         uiLayoutItemSplt *split= (uiLayoutItemSplt*)litem;
1834         uiItem *item;
1835         float percentage;
1836         int itemh, x, y, w, tot=0, colw=0;
1837
1838         x= litem->x;
1839         y= litem->y;
1840
1841         for(item=litem->items.first; item; item=item->next)
1842                 tot++;
1843         
1844         if(tot == 0)
1845                 return;
1846         
1847         percentage= (split->percentage == 0.0f)? 1.0f/(float)tot: split->percentage;
1848         
1849         w= (litem->w - (tot-1)*litem->space);
1850         colw= w*percentage;
1851         colw= MAX2(colw, 0);
1852
1853         for(item=litem->items.first; item; item=item->next) {
1854                 ui_item_size(item, NULL, &itemh);
1855
1856                 ui_item_position(item, x, y-itemh, colw, itemh);
1857                 x += colw;
1858
1859                 if(item->next) {
1860                         colw= (w - (int)(w*percentage))/(tot-1);
1861                         colw= MAX2(colw, 0);
1862
1863                         x += litem->space;
1864                 }
1865         }
1866
1867         litem->w= x - litem->x;
1868         litem->h= litem->y - y;
1869         litem->x= x;
1870         litem->y= y;
1871 }
1872
1873 /* overlap layout */
1874 static void ui_litem_estimate_overlap(uiLayout *litem)
1875 {
1876         uiItem *item;
1877         int itemw, itemh;
1878
1879         litem->w= 0;
1880         litem->h= 0;
1881
1882         for(item=litem->items.first; item; item=item->next) {
1883                 ui_item_size(item, &itemw, &itemh);
1884
1885                 litem->w= MAX2(itemw, litem->w);
1886                 litem->h= MAX2(itemh, litem->h);
1887         }
1888 }
1889
1890 static void ui_litem_layout_overlap(uiLayout *litem)
1891 {
1892         uiItem *item;
1893         int itemw, itemh, x, y;
1894
1895         x= litem->x;
1896         y= litem->y;
1897
1898         for(item=litem->items.first; item; item=item->next) {
1899                 ui_item_size(item, &itemw, &itemh);
1900                 ui_item_position(item, x, y-itemh, litem->w, itemh);
1901
1902                 litem->h= MAX2(litem->h, itemh);
1903         }
1904
1905         litem->x= x;
1906         litem->y= y - litem->h;
1907 }
1908
1909 /* layout create functions */
1910 uiLayout *uiLayoutRow(uiLayout *layout, int align)
1911 {
1912         uiLayout *litem;
1913
1914         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
1915         litem->item.type= ITEM_LAYOUT_ROW;
1916         litem->root= layout->root;
1917         litem->align= align;
1918         litem->active= 1;
1919         litem->enabled= 1;
1920         litem->context= layout->context;
1921         litem->space= (align)? 0: layout->root->style->buttonspacex;
1922         BLI_addtail(&layout->items, litem);
1923
1924         uiBlockSetCurLayout(layout->root->block, litem);
1925
1926         return litem;
1927 }
1928
1929 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
1930 {
1931         uiLayout *litem;
1932
1933         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
1934         litem->item.type= ITEM_LAYOUT_COLUMN;
1935         litem->root= layout->root;
1936         litem->align= align;
1937         litem->active= 1;
1938         litem->enabled= 1;
1939         litem->context= layout->context;
1940         litem->space= (litem->align)? 0: layout->root->style->buttonspacey;
1941         BLI_addtail(&layout->items, litem);
1942
1943         uiBlockSetCurLayout(layout->root->block, litem);
1944
1945         return litem;
1946 }
1947
1948 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
1949 {
1950         uiLayoutItemFlow *flow;
1951
1952         flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
1953         flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW;
1954         flow->litem.root= layout->root;
1955         flow->litem.align= align;
1956         flow->litem.active= 1;
1957         flow->litem.enabled= 1;
1958         flow->litem.context= layout->context;
1959         flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace;
1960         flow->number= number;
1961         BLI_addtail(&layout->items, flow);
1962
1963         uiBlockSetCurLayout(layout->root->block, &flow->litem);
1964
1965         return &flow->litem;
1966 }
1967
1968 static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
1969 {
1970         uiLayoutItemBx *box;
1971
1972         box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
1973         box->litem.item.type= ITEM_LAYOUT_BOX;
1974         box->litem.root= layout->root;
1975         box->litem.active= 1;
1976         box->litem.enabled= 1;
1977         box->litem.context= layout->context;
1978         box->litem.space= layout->root->style->columnspace;
1979         BLI_addtail(&layout->items, box);
1980
1981         uiBlockSetCurLayout(layout->root->block, &box->litem);
1982
1983         box->roundbox= uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
1984
1985         return box;
1986 }
1987
1988 uiLayout *uiLayoutBox(uiLayout *layout)
1989 {
1990         return (uiLayout*)ui_layout_box(layout, ROUNDBOX);
1991 }
1992
1993 uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
1994 {
1995     uiLayoutItemBx *box= ui_layout_box(layout, LISTBOX);
1996         uiBut *but= box->roundbox;
1997
1998         but->rnasearchpoin= *ptr;
1999         but->rnasearchprop= prop;
2000         but->rnapoin= *actptr;
2001         but->rnaprop= actprop;
2002
2003         return (uiLayout*)box;
2004 }
2005
2006 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
2007 {
2008         uiLayout *litem;
2009
2010         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
2011         litem->item.type= ITEM_LAYOUT_ABSOLUTE;
2012         litem->root= layout->root;
2013         litem->align= align;
2014         litem->active= 1;
2015         litem->enabled= 1;
2016         litem->context= layout->context;
2017         BLI_addtail(&layout->items, litem);
2018
2019         uiBlockSetCurLayout(layout->root->block, litem);
2020
2021         return litem;
2022 }
2023
2024 uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout)
2025 {
2026         uiBlock *block;
2027
2028         block= uiLayoutGetBlock(layout);
2029         uiLayoutAbsolute(layout, 0);
2030
2031         return block;
2032 }
2033
2034 uiLayout *uiLayoutOverlap(uiLayout *layout)
2035 {
2036         uiLayout *litem;
2037
2038         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
2039         litem->item.type= ITEM_LAYOUT_OVERLAP;
2040         litem->root= layout->root;
2041         litem->active= 1;
2042         litem->enabled= 1;
2043         litem->context= layout->context;
2044         BLI_addtail(&layout->items, litem);
2045
2046         uiBlockSetCurLayout(layout->root->block, litem);
2047
2048         return litem;
2049 }
2050
2051 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage)
2052 {
2053         uiLayoutItemSplt *split;
2054
2055         split= MEM_callocN(sizeof(uiLayoutItemSplt), "uiLayoutItemSplt");
2056         split->litem.item.type= ITEM_LAYOUT_SPLIT;
2057         split->litem.root= layout->root;
2058         split->litem.active= 1;
2059         split->litem.enabled= 1;
2060         split->litem.context= layout->context;
2061         split->litem.space= layout->root->style->columnspace;
2062         split->percentage= percentage;
2063         BLI_addtail(&layout->items, split);
2064
2065         uiBlockSetCurLayout(layout->root->block, &split->litem);
2066
2067         return &split->litem;
2068 }
2069
2070 void uiLayoutSetActive(uiLayout *layout, int active)
2071 {
2072         layout->active= active;
2073 }
2074
2075 void uiLayoutSetEnabled(uiLayout *layout, int enabled)
2076 {
2077         layout->enabled= enabled;
2078 }
2079
2080 void uiLayoutSetRedAlert(uiLayout *layout, int redalert)
2081 {
2082         layout->redalert= redalert;
2083 }
2084
2085 void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect)
2086 {
2087         layout->keepaspect= keepaspect;
2088 }
2089
2090 void uiLayoutSetAlignment(uiLayout *layout, int alignment)
2091 {
2092         layout->alignment= alignment;
2093 }
2094
2095 void uiLayoutSetScaleX(uiLayout *layout, float scale)
2096 {
2097         layout->scale[0]= scale;
2098 }
2099
2100 void uiLayoutSetScaleY(uiLayout *layout, float scale)
2101 {
2102         layout->scale[1]= scale;
2103 }
2104
2105 int uiLayoutGetActive(uiLayout *layout)
2106 {
2107         return layout->active;
2108 }
2109
2110 int uiLayoutGetEnabled(uiLayout *layout)
2111 {
2112         return layout->enabled;
2113 }
2114
2115 int uiLayoutGetRedAlert(uiLayout *layout)
2116 {
2117         return layout->redalert;
2118 }
2119
2120 int uiLayoutGetKeepAspect(uiLayout *layout)
2121 {
2122         return layout->keepaspect;
2123 }
2124
2125 int uiLayoutGetAlignment(uiLayout *layout)
2126 {
2127         return layout->alignment;
2128 }
2129
2130 int uiLayoutGetWidth(uiLayout *layout)
2131 {
2132         return layout->w;
2133 }
2134
2135 float uiLayoutGetScaleX(uiLayout *layout)
2136 {
2137         return layout->scale[0];
2138 }
2139
2140 float uiLayoutGetScaleY(uiLayout *layout)
2141 {
2142         return layout->scale[0];
2143 }
2144
2145 /********************** Layout *******************/
2146
2147 static void ui_item_scale(uiLayout *litem, float scale[2])
2148 {
2149         uiItem *item;
2150         int x, y, w, h;
2151
2152         for(item=litem->items.last; item; item=item->prev) {
2153                 ui_item_size(item, &w, &h);
2154                 ui_item_offset(item, &x, &y);
2155
2156                 if(scale[0] != 0.0f) {
2157                         x *= scale[0];
2158                         w *= scale[0];
2159                 }
2160
2161                 if(scale[1] != 0.0f) {
2162                         y *= scale[1];
2163                         h *= scale[1];
2164                 }
2165
2166                 ui_item_position(item, x, y, w, h);
2167         }
2168 }
2169
2170 static void ui_item_estimate(uiItem *item)
2171 {
2172         uiItem *subitem;
2173
2174         if(item->type != ITEM_BUTTON) {
2175                 uiLayout *litem= (uiLayout*)item;
2176
2177                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2178                         ui_item_estimate(subitem);
2179
2180                 if(litem->items.first == NULL)
2181                         return;
2182
2183                 if(litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
2184                         ui_item_scale(litem, litem->scale);
2185
2186                 switch(litem->item.type) {
2187                         case ITEM_LAYOUT_COLUMN:
2188                                 ui_litem_estimate_column(litem);
2189                                 break;
2190                         case ITEM_LAYOUT_COLUMN_FLOW:
2191                                 ui_litem_estimate_column_flow(litem);
2192                                 break;
2193                         case ITEM_LAYOUT_ROW:
2194                                 ui_litem_estimate_row(litem);
2195                                 break;
2196                         case ITEM_LAYOUT_BOX:
2197                                 ui_litem_estimate_box(litem);
2198                                 break;
2199                         case ITEM_LAYOUT_ROOT:
2200                                 ui_litem_estimate_root(litem);
2201                                 break;
2202                         case ITEM_LAYOUT_ABSOLUTE:
2203                                 ui_litem_estimate_absolute(litem);
2204                                 break;
2205                         case ITEM_LAYOUT_SPLIT:
2206                                 ui_litem_estimate_split(litem);
2207                                 break;
2208                         case ITEM_LAYOUT_OVERLAP:
2209                                 ui_litem_estimate_overlap(litem);
2210                                 break;
2211                         default:
2212                                 break;
2213                 }
2214         }
2215 }
2216
2217 static void ui_item_align(uiLayout *litem, int nr)
2218 {
2219         uiItem *item;
2220         uiButtonItem *bitem;
2221         uiLayoutItemBx *box;
2222
2223         for(item=litem->items.last; item; item=item->prev) {
2224                 if(item->type == ITEM_BUTTON) {
2225                         bitem= (uiButtonItem*)item;
2226                         if(ui_but_can_align(bitem->but))
2227                                 if(!bitem->but->alignnr)
2228                                         bitem->but->alignnr= nr;
2229                 }
2230                 else if(item->type == ITEM_LAYOUT_ABSOLUTE);
2231                 else if(item->type == ITEM_LAYOUT_OVERLAP);
2232                 else if(item->type == ITEM_LAYOUT_BOX) {
2233                         box= (uiLayoutItemBx*)item;
2234                         box->roundbox->alignnr= nr;
2235                         BLI_remlink(&litem->root->block->buttons, box->roundbox);
2236                         BLI_addhead(&litem->root->block->buttons, box->roundbox);
2237                 }
2238                 else
2239                         ui_item_align((uiLayout*)item, nr);
2240         }
2241 }
2242
2243 static void ui_item_flag(uiLayout *litem, int flag)
2244 {
2245         uiItem *item;
2246         uiButtonItem *bitem;
2247
2248         for(item=litem->items.last; item; item=item->prev) {
2249                 if(item->type == ITEM_BUTTON) {
2250                         bitem= (uiButtonItem*)item;
2251                         bitem->but->flag |= flag;
2252                 }
2253                 else
2254                         ui_item_flag((uiLayout*)item, flag);
2255         }
2256 }
2257
2258 static void ui_item_layout(uiItem *item)
2259 {
2260         uiItem *subitem;
2261
2262         if(item->type != ITEM_BUTTON) {
2263                 uiLayout *litem= (uiLayout*)item;
2264
2265                 if(litem->items.first == NULL)
2266                         return;
2267
2268                 if(litem->align)
2269                         ui_item_align(litem, ++litem->root->block->alignnr);
2270                 if(!litem->active)
2271                         ui_item_flag(litem, UI_BUT_INACTIVE);
2272                 if(!litem->enabled)
2273                         ui_item_flag(litem, UI_BUT_DISABLED);
2274
2275                 switch(litem->item.type) {
2276                         case ITEM_LAYOUT_COLUMN:
2277                                 ui_litem_layout_column(litem);
2278                                 break;
2279                         case ITEM_LAYOUT_COLUMN_FLOW:
2280                                 ui_litem_layout_column_flow(litem);
2281                                 break;
2282                         case ITEM_LAYOUT_ROW:
2283                                 ui_litem_layout_row(litem);
2284                                 break;
2285                         case ITEM_LAYOUT_BOX:
2286                                 ui_litem_layout_box(litem);
2287                                 break;
2288                         case ITEM_LAYOUT_ROOT:
2289                                 ui_litem_layout_root(litem);
2290                                 break;
2291                         case ITEM_LAYOUT_ABSOLUTE:
2292                                 ui_litem_layout_absolute(litem);
2293                                 break;
2294                         case ITEM_LAYOUT_SPLIT:
2295                                 ui_litem_layout_split(litem);
2296                                 break;
2297                         case ITEM_LAYOUT_OVERLAP:
2298                                 ui_litem_layout_overlap(litem);
2299                                 break;
2300                         default:
2301                                 break;
2302                 }
2303
2304                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2305                         ui_item_layout(subitem);
2306         }
2307 }
2308
2309 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
2310 {
2311         if(layout->root->handlefunc)
2312                 uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv);
2313
2314         ui_item_estimate(&layout->item);
2315         ui_item_layout(&layout->item);
2316
2317         if(x) *x= layout->x;
2318         if(y) *y= layout->y;
2319 }
2320
2321 static void ui_layout_free(uiLayout *layout)
2322 {
2323         uiItem *item, *next;
2324
2325         for(item=layout->items.first; item; item=next) {
2326                 next= item->next;
2327
2328                 if(item->type == ITEM_BUTTON)
2329                         MEM_freeN(item);
2330                 else
2331                         ui_layout_free((uiLayout*)item);
2332         }
2333
2334         MEM_freeN(layout);
2335 }
2336
2337 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
2338 {
2339         uiLayout *layout;
2340         uiLayoutRoot *root;
2341
2342         root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
2343         root->type= type;
2344         root->style= style;
2345         root->block= block;
2346         root->opcontext= WM_OP_INVOKE_REGION_WIN;
2347
2348         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
2349         layout->item.type= ITEM_LAYOUT_ROOT;
2350
2351         layout->x= x;
2352         layout->y= y;
2353         layout->root= root;
2354         layout->space= style->templatespace;
2355         layout->active= 1;
2356         layout->enabled= 1;
2357         layout->context= NULL;
2358
2359         if(type == UI_LAYOUT_MENU)
2360                 layout->space= 0;
2361
2362         if(dir == UI_LAYOUT_HORIZONTAL) {
2363                 layout->h= size;
2364                 layout->root->emh= em*UI_UNIT_Y;
2365         }
2366         else {
2367                 layout->w= size;
2368                 layout->root->emw= em*UI_UNIT_X;
2369         }
2370
2371         block->curlayout= layout;
2372         root->layout= layout;
2373         BLI_addtail(&block->layouts, root);
2374         
2375         return layout;
2376 }
2377
2378 uiBlock *uiLayoutGetBlock(uiLayout *layout)
2379 {
2380         return layout->root->block;
2381 }
2382
2383 int uiLayoutGetOperatorContext(uiLayout *layout)
2384 {
2385         return layout->root->opcontext;
2386 }
2387
2388
2389 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
2390 {
2391         block->curlayout= layout;
2392 }
2393
2394 void ui_layout_add_but(uiLayout *layout, uiBut *but)
2395 {
2396         uiButtonItem *bitem;
2397         
2398         bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
2399         bitem->item.type= ITEM_BUTTON;
2400         bitem->but= but;
2401         BLI_addtail(&layout->items, bitem);
2402
2403         if(layout->context) {
2404                 but->context= layout->context;
2405                 but->context->used= 1;
2406         }
2407 }
2408
2409 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
2410 {
2411         layout->root->opcontext= opcontext;
2412 }
2413
2414 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
2415 {
2416         layout->root->handlefunc= handlefunc;
2417         layout->root->argv= argv;
2418 }
2419
2420 void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
2421 {
2422         uiLayoutRoot *root;
2423
2424         if(x) *x= 0;
2425         if(y) *y= 0;
2426
2427         block->curlayout= NULL;
2428
2429         for(root=block->layouts.first; root; root=root->next) {
2430                 /* NULL in advance so we don't interfere when adding button */
2431                 ui_layout_end(block, root->layout, x, y);
2432                 ui_layout_free(root->layout);
2433         }
2434
2435         BLI_freelistN(&block->layouts);
2436
2437         /* XXX silly trick, interface_templates.c doesn't get linked
2438          * because it's not used by other files in this module? */
2439         {
2440                 void ui_template_fix_linking();
2441                 ui_template_fix_linking();
2442         }
2443 }
2444
2445 void uiLayoutSetContextPointer(uiLayout *layout, char *name, PointerRNA *ptr)
2446 {
2447         uiBlock *block= layout->root->block;
2448         layout->context= CTX_store_add(&block->contexts, name, ptr);
2449 }
2450