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