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