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