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