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