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