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