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