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