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