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