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