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