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