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