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