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