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