NLA SoC: Merge from 2.5 20215:20439 (HEAD)
[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)
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 }
739
740 void uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int expand, int slider)
741 {
742         PropertyRNA *prop;
743
744         if(!ptr->data || !propname)
745                 return;
746
747         prop= RNA_struct_find_property(ptr, propname);
748
749         if(!prop) {
750                 ui_item_disabled(layout, propname);
751                 printf("uiItemR: property not found: %s\n", propname);
752                 return;
753         }
754
755         uiItemFullR(layout, name, icon, ptr, prop, RNA_NO_INDEX, 0, expand, slider);
756 }
757
758 void uiItemEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname, int value)
759 {
760         PropertyRNA *prop;
761
762         if(!ptr->data || !propname)
763                 return;
764
765         prop= RNA_struct_find_property(ptr, propname);
766
767         if(!prop) {
768                 ui_item_disabled(layout, propname);
769                 printf("uiItemEnumR: property not found: %s\n", propname);
770                 return;
771         }
772
773         uiItemFullR(layout, name, icon, ptr, prop, RNA_ENUM_VALUE, value, 0, 0);
774 }
775
776 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, char *propname)
777 {
778         PropertyRNA *prop;
779
780         prop= RNA_struct_find_property(ptr, propname);
781
782         if(!prop) {
783                 ui_item_disabled(layout, propname);
784                 return;
785         }
786
787         if(RNA_property_type(prop) == PROP_ENUM) {
788                 const EnumPropertyItem *item;
789                 int totitem, i;
790
791                 RNA_property_enum_items(ptr, prop, &item, &totitem);
792
793                 for(i=0; i<totitem; i++)
794                         uiItemEnumR(layout, (char*)item[i].name, 0, ptr, propname, item[i].value);
795         }
796 }
797
798 /* menu item */
799 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
800 {
801         MenuType *mt= (MenuType*)arg_mt;
802         Menu menu = {0};
803
804         menu.type= mt;
805         menu.layout= layout;
806         mt->draw(C, &menu);
807 }
808
809 static void ui_item_menu(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN)
810 {
811         uiBlock *block= layout->root->block;
812         uiBut *but;
813         int w, h;
814
815         uiBlockSetCurLayout(block, layout);
816
817         if(layout->root->type == UI_LAYOUT_HEADER)
818                 uiBlockSetEmboss(block, UI_EMBOSSP);
819
820         if(!name)
821                 name= "";
822         if(layout->root->type == UI_LAYOUT_MENU && !icon)
823                 icon= ICON_BLANK1;
824
825         w= ui_text_icon_width(layout, name, icon);
826         h= UI_UNIT_Y;
827
828         if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
829                 w -= 3;
830
831         if(icon)
832                 but= uiDefIconTextMenuBut(block, func, arg, icon, (char*)name, 0, 0, w, h, "");
833         else
834                 but= uiDefMenuBut(block, func, arg, (char*)name, 0, 0, w, h, "");
835
836         if(argN) { /* ugly .. */
837                 but->poin= (char*)but;
838                 but->func_argN= argN;
839         }
840
841         if(layout->root->type == UI_LAYOUT_HEADER)
842                 uiBlockSetEmboss(block, UI_EMBOSS);
843         else if(layout->root->type == UI_LAYOUT_PANEL)
844                 but->type= MENU;
845 }
846
847 void uiItemM(uiLayout *layout, bContext *C, char *name, int icon, char *menuname)
848 {
849         ARegion *ar= CTX_wm_region(C);
850         MenuType *mt;
851
852         if(!menuname)
853                 return;
854
855         for(mt=ar->type->menutypes.first; mt; mt=mt->next) {
856                 if(strcmp(menuname, mt->idname) == 0) {
857                         if(!name)
858                                 name= mt->label;
859                         if(layout->root->type == UI_LAYOUT_MENU && !icon)
860                                 icon= ICON_BLANK1;
861                         ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL);
862                         break;
863                 }
864         }
865 }
866
867 /* label item */
868 void uiItemL(uiLayout *layout, char *name, int icon)
869 {
870         uiBlock *block= layout->root->block;
871         uiBut *but;
872         int w;
873
874         uiBlockSetCurLayout(block, layout);
875
876         if(!name)
877                 name= "";
878         if(layout->root->type == UI_LAYOUT_MENU && !icon)
879                 icon= ICON_BLANK1;
880
881         w= ui_text_icon_width(layout, name, icon);
882
883         if(icon && strcmp(name, "") != 0)
884                 but= uiDefIconTextBut(block, LABEL, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
885         else if(icon)
886                 but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
887         else
888                 but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
889 }
890
891 /* value item */
892 void uiItemV(uiLayout *layout, char *name, int icon, int argval)
893 {
894         /* label */
895         uiBlock *block= layout->root->block;
896         float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
897         int w;
898
899         uiBlockSetCurLayout(block, layout);
900
901         if(!name)
902                 name= "";
903         if(layout->root->type == UI_LAYOUT_MENU && !icon)
904                 icon= ICON_BLANK1;
905
906         w= ui_text_icon_width(layout, name, icon);
907
908         if(icon && strcmp(name, "") != 0)
909                 uiDefIconTextButF(block, BUTM, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
910         else if(icon)
911                 uiDefIconButF(block, BUTM, 0, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
912         else
913                 uiDefButF(block, BUTM, 0, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
914 }
915
916 /* separator item */
917 void uiItemS(uiLayout *layout)
918 {
919         uiBlock *block= layout->root->block;
920
921         uiBlockSetCurLayout(block, layout);
922         uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
923 }
924
925 /* level items */
926 void uiItemMenuF(uiLayout *layout, char *name, int icon, uiMenuCreateFunc func)
927 {
928         if(!func)
929                 return;
930
931         ui_item_menu(layout, name, icon, func, NULL, NULL);
932 }
933
934 typedef struct MenuItemLevel {
935         int opcontext;
936         char *opname;
937         char *propname;
938         PointerRNA rnapoin;
939 } MenuItemLevel;
940
941 static void menu_item_enum_opname_menu(bContext *C, uiLayout *layout, void *arg)
942 {
943         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
944
945         uiLayoutContext(layout, WM_OP_EXEC_REGION_WIN);
946         uiItemsEnumO(layout, lvl->opname, lvl->propname);
947 }
948
949 void uiItemMenuEnumO(uiLayout *layout, char *name, int icon, char *opname, char *propname)
950 {
951         wmOperatorType *ot= WM_operatortype_find(opname);
952         MenuItemLevel *lvl;
953
954         if(!ot || !ot->srna) {
955                 ui_item_disabled(layout, opname);
956                 return;
957         }
958
959         if(!name)
960                 name= ot->name;
961         if(layout->root->type == UI_LAYOUT_MENU && !icon)
962                 icon= ICON_BLANK1;
963
964         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
965         lvl->opname= opname;
966         lvl->propname= propname;
967         lvl->opcontext= layout->root->opcontext;
968
969         ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl);
970 }
971
972 static void menu_item_enum_rna_menu(bContext *C, uiLayout *layout, void *arg)
973 {
974         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
975
976         uiLayoutContext(layout, lvl->opcontext);
977         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
978 }
979
980 void uiItemMenuEnumR(uiLayout *layout, char *name, int icon, struct PointerRNA *ptr, char *propname)
981 {
982         MenuItemLevel *lvl;
983         PropertyRNA *prop;
984
985         prop= RNA_struct_find_property(ptr, propname);
986         if(!prop) {
987                 ui_item_disabled(layout, propname);
988                 return;
989         }
990
991         if(!name)
992                 name= (char*)RNA_property_ui_name(prop);
993         if(layout->root->type == UI_LAYOUT_MENU && !icon)
994                 icon= ICON_BLANK1;
995
996         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
997         lvl->rnapoin= *ptr;
998         lvl->propname= propname;
999         lvl->opcontext= layout->root->opcontext;
1000
1001         ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl);
1002 }
1003
1004 /**************************** Layout Items ***************************/
1005
1006 /* single-row layout */
1007 static void ui_litem_estimate_row(uiLayout *litem)
1008 {
1009         uiItem *item;
1010         int itemw, itemh;
1011
1012         litem->w= 0;
1013         litem->h= 0;
1014
1015         for(item=litem->items.first; item; item=item->next) {
1016                 ui_item_size(item, &itemw, &itemh);
1017
1018                 litem->w += itemw;
1019                 litem->h= MAX2(itemh, litem->h);
1020
1021                 if(item->next)
1022                         litem->w += litem->space;
1023         }
1024 }
1025
1026 static void ui_litem_layout_row(uiLayout *litem)
1027 {
1028         uiItem *item;
1029         int neww, itemw, itemh, x, y, w, tot= 0, totw= 0, extra=0, available=0;
1030
1031         x= litem->x;
1032         y= litem->y;
1033         w= litem->w;
1034
1035         for(item=litem->items.first; item; item=item->next) {
1036                 ui_item_size(item, &itemw, &itemh);
1037                 totw += itemw;
1038                 tot++;
1039         }
1040
1041         if(totw == 0)
1042                 return;
1043         
1044         /* two step to enforce minimum button with .. could be better */
1045         for(item=litem->items.first; item; item=item->next) {
1046                 ui_item_size(item, &itemw, &itemh);
1047
1048                 itemw= ui_item_fit(itemw, x-litem->x, totw, w, (tot-1)*litem->space, !item->next, UI_FIT_EXPAND);
1049                 x += itemw;
1050
1051                 if(itemw < UI_UNIT_X)
1052                         extra += UI_UNIT_X - itemw;
1053                 else
1054                         available += itemw - UI_UNIT_X;
1055
1056                 if(item->next)
1057                         x += litem->space;
1058         }
1059
1060         x= litem->x;
1061
1062         for(item=litem->items.first; item; item=item->next) {
1063                 ui_item_size(item, &itemw, &itemh);
1064
1065                 neww= ui_item_fit(itemw, x-litem->x, totw, w, (tot-1)*litem->space, !item->next, UI_FIT_EXPAND);
1066                 if(neww < UI_UNIT_X) {
1067                         if(item->next)
1068                                 itemw= UI_UNIT_X;
1069                         else
1070                                 itemw= litem->w - (x-litem->x);
1071                 }
1072                 else
1073                         itemw= ui_item_fit(itemw, x-litem->x, totw, w-extra, (tot-1)*litem->space, !item->next, UI_FIT_EXPAND);
1074
1075                 ui_item_position(item, x, y-itemh, itemw, itemh);
1076                 x += itemw;
1077
1078                 if(item->next)
1079                         x += litem->space;
1080         }
1081
1082         litem->w= x - litem->x;
1083         litem->h= litem->y - y;
1084         litem->x= x;
1085         litem->y= y;
1086 }
1087
1088 /* single-column layout */
1089 static void ui_litem_estimate_column(uiLayout *litem)
1090 {
1091         uiItem *item;
1092         int itemw, itemh;
1093
1094         litem->w= 0;
1095         litem->h= 0;
1096
1097         for(item=litem->items.first; item; item=item->next) {
1098                 ui_item_size(item, &itemw, &itemh);
1099
1100                 litem->w= MAX2(litem->w, itemw);
1101                 litem->h += itemh;
1102
1103                 if(item->next)
1104                         litem->h += litem->space;
1105         }
1106 }
1107
1108 static void ui_litem_layout_column(uiLayout *litem)
1109 {
1110         uiItem *item;
1111         int itemh, x, y;
1112
1113         x= litem->x;
1114         y= litem->y;
1115
1116         for(item=litem->items.first; item; item=item->next) {
1117                 ui_item_size(item, NULL, &itemh);
1118
1119                 y -= itemh;
1120                 ui_item_position(item, x, y, litem->w, itemh);
1121
1122                 if(item->next)
1123                         y -= litem->space;
1124         }
1125
1126         litem->h= litem->y - y;
1127         litem->x= x;
1128         litem->y= y;
1129 }
1130
1131 /* root layout */
1132 static void ui_litem_estimate_root(uiLayout *litem)
1133 {
1134         /* nothing to do */
1135 }
1136
1137 static void ui_litem_layout_root(uiLayout *litem)
1138 {
1139         if(litem->root->type == UI_LAYOUT_HEADER)
1140                 ui_litem_layout_row(litem);
1141         else
1142                 ui_litem_layout_column(litem);
1143 }
1144
1145 /* box layout */
1146 static void ui_litem_estimate_box(uiLayout *litem)
1147 {
1148         uiStyle *style= litem->root->style;
1149
1150         ui_litem_estimate_column(litem);
1151         litem->w += 2*style->boxspace;
1152         litem->h += style->boxspace;
1153 }
1154
1155 static void ui_litem_layout_box(uiLayout *litem)
1156 {
1157         uiLayoutItemBx *box= (uiLayoutItemBx*)litem;
1158         uiStyle *style= litem->root->style;
1159         uiBut *but;
1160         int w, h;
1161
1162         w= litem->w;
1163         h= litem->h;
1164
1165         litem->x += style->boxspace;
1166         litem->y -= style->boxspace;
1167
1168         if(w != 0) litem->w -= 2*style->boxspace;
1169         if(h != 0) litem->h -= 2*style->boxspace;
1170
1171         ui_litem_layout_column(litem);
1172
1173         litem->x -= style->boxspace;
1174         litem->y -= style->boxspace;
1175
1176         if(w != 0) litem->w += 2*style->boxspace;
1177         if(h != 0) litem->h += style->boxspace;
1178
1179         /* roundbox around the sublayout */
1180         but= box->roundbox;
1181         but->x1= litem->x;
1182         but->y1= litem->y;
1183         but->x2= litem->x+litem->w;
1184         but->y2= litem->y+litem->h;
1185 }
1186
1187 /* multi-column layout, automatically flowing to the next */
1188 static void ui_litem_estimate_column_flow(uiLayout *litem)
1189 {
1190         uiStyle *style= litem->root->style;
1191         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1192         uiItem *item;
1193         int col, x, y, emh, emy, miny, itemw, itemh, maxw=0;
1194         int toth, totitem;
1195
1196         /* compute max needed width and total height */
1197         toth= 0;
1198         totitem= 0;
1199         for(item=litem->items.first; item; item=item->next) {
1200                 ui_item_size(item, &itemw, &itemh);
1201                 maxw= MAX2(maxw, itemw);
1202                 toth += itemh;
1203                 totitem++;
1204         }
1205
1206         if(flow->number <= 0) {
1207                 /* auto compute number of columns, not very good */
1208                 if(maxw == 0) {
1209                         flow->totcol= 1;
1210                         return;
1211                 }
1212
1213                 flow->totcol= MAX2(litem->root->emw/maxw, 1);
1214                 flow->totcol= MIN2(flow->totcol, totitem);
1215         }
1216         else
1217                 flow->totcol= flow->number;
1218
1219         /* compute sizes */
1220         x= 0;
1221         y= 0;
1222         emy= 0;
1223         miny= 0;
1224
1225         maxw= 0;
1226         emh= toth/flow->totcol;
1227
1228         /* create column per column */
1229         col= 0;
1230         for(item=litem->items.first; item; item=item->next) {
1231                 ui_item_size(item, &itemw, &itemh);
1232
1233                 y -= itemh + style->buttonspacey;
1234                 miny= MIN2(miny, y);
1235                 emy -= itemh;
1236                 maxw= MAX2(itemw, maxw);
1237
1238                 /* decide to go to next one */
1239                 if(col < flow->totcol-1 && emy <= -emh) {
1240                         x += maxw + litem->space;
1241                         maxw= 0;
1242                         y= 0;
1243                         col++;
1244                 }
1245         }
1246
1247         litem->h= litem->y - miny;
1248 }
1249
1250 static void ui_litem_layout_column_flow(uiLayout *litem)
1251 {
1252         uiStyle *style= litem->root->style;
1253         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1254         uiItem *item;
1255         int col, x, y, w, emh, emy, miny, itemw, itemh;
1256         int toth, totitem;
1257
1258         /* compute max needed width and total height */
1259         toth= 0;
1260         totitem= 0;
1261         for(item=litem->items.first; item; item=item->next) {
1262                 ui_item_size(item, &itemw, &itemh);
1263                 toth += itemh;
1264                 totitem++;
1265         }
1266
1267         /* compute sizes */
1268         x= litem->x;
1269         y= litem->y;
1270         emy= 0;
1271         miny= 0;
1272
1273         w= litem->w;
1274         emh= toth/flow->totcol;
1275
1276         /* create column per column */
1277         col= 0;
1278         for(item=litem->items.first; item; item=item->next) {
1279                 ui_item_size(item, NULL, &itemh);
1280                 itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, (flow->totcol-1)*style->columnspace, col == flow->totcol-1, UI_FIT_EXPAND);
1281         
1282                 y -= itemh;
1283                 emy -= itemh;
1284                 ui_item_position(item, x, y, itemw, itemh);
1285                 y -= style->buttonspacey;
1286                 miny= MIN2(miny, y);
1287
1288                 /* decide to go to next one */
1289                 if(col < flow->totcol-1 && emy <= -emh) {
1290                         x += itemw + style->columnspace;
1291                         y= litem->y;
1292                         col++;
1293                 }
1294         }
1295
1296         litem->h= litem->y - miny;
1297         litem->x= x;
1298         litem->y= miny;
1299 }
1300
1301 /* free layout */
1302 static void ui_litem_estimate_free(uiLayout *litem)
1303 {
1304         uiItem *item;
1305         int itemx, itemy, itemw, itemh, minx, miny;
1306
1307         minx= 1e6;
1308         miny= 1e6;
1309         litem->w= 0;
1310         litem->h= 0;
1311
1312         for(item=litem->items.first; item; item=item->next) {
1313                 ui_item_offset(item, &itemx, &itemy);
1314                 ui_item_size(item, &itemw, &itemh);
1315
1316                 minx= MIN2(minx, itemx);
1317                 miny= MIN2(miny, itemy);
1318
1319                 litem->w= MAX2(litem->w, itemx+itemw);
1320                 litem->h= MAX2(litem->h, itemy+itemh);
1321         }
1322
1323         litem->w -= minx;
1324         litem->h -= miny;
1325 }
1326
1327 static void ui_litem_layout_free(uiLayout *litem)
1328 {
1329         uiItem *item;
1330         float scalex=1.0f, scaley=1.0f;
1331         int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
1332
1333         minx= 1e6;
1334         miny= 1e6;
1335         totw= 0;
1336         toth= 0;
1337
1338         for(item=litem->items.first; item; item=item->next) {
1339                 ui_item_offset(item, &itemx, &itemy);
1340                 ui_item_size(item, &itemw, &itemh);
1341
1342                 minx= MIN2(minx, itemx);
1343                 miny= MIN2(miny, itemy);
1344
1345                 totw= MAX2(totw, itemx+itemw);
1346                 toth= MAX2(toth, itemy+itemh);
1347         }
1348
1349         totw -= minx;
1350         toth -= miny;
1351
1352         if(litem->w && totw > litem->w)
1353                 scalex= (float)litem->w/(float)totw;
1354         if(litem->h && toth > litem->h)
1355                 scaley= (float)litem->h/(float)toth;
1356         
1357         x= litem->x;
1358         y= litem->y - scaley*toth;
1359
1360         for(item=litem->items.first; item; item=item->next) {
1361                 ui_item_offset(item, &itemx, &itemy);
1362                 ui_item_size(item, &itemw, &itemh);
1363
1364                 if(scalex != 1.0f) {
1365                         newx= itemx*scalex;
1366                         itemw= (itemx + itemw)*scalex - newx;
1367                         itemx= newx;
1368                 }
1369
1370                 if(scaley != 1.0f) {
1371                         newy= itemy*scaley;
1372                         itemh= (itemy + itemh)*scaley - newy;
1373                         itemy= newy;
1374                 }
1375
1376                 ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh);
1377         }
1378
1379         litem->w= scalex*totw;
1380         litem->h= litem->y - y;
1381         litem->x= x + litem->w;
1382         litem->y= y;
1383 }
1384
1385 /* split layout */
1386 static void ui_litem_estimate_split(uiLayout *litem)
1387 {
1388         ui_litem_estimate_row(litem);
1389 }
1390
1391 static void ui_litem_layout_split(uiLayout *litem)
1392 {
1393         uiItem *item;
1394         int itemh, x, y, w, tot=0, colw=0;
1395
1396         x= litem->x;
1397         y= litem->y;
1398         w= litem->w;
1399
1400         for(item=litem->items.first; item; item=item->next)
1401                 tot++;
1402         
1403         if(tot == 0)
1404                 return;
1405         
1406         colw= (litem->w - (tot-1)*litem->space)/tot;
1407         colw= MAX2(colw, 0);
1408
1409         for(item=litem->items.first; item; item=item->next) {
1410                 ui_item_size(item, NULL, &itemh);
1411
1412                 ui_item_position(item, x, y-itemh, colw, itemh);
1413                 x += colw;
1414
1415                 if(item->next)
1416                         x += litem->space;
1417         }
1418
1419         litem->w= x - litem->x;
1420         litem->h= litem->y - y;
1421         litem->x= x;
1422         litem->y= y;
1423 }
1424
1425 /* layout create functions */
1426 uiLayout *uiLayoutRow(uiLayout *layout, int align)
1427 {
1428         uiLayout *litem;
1429
1430         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
1431         litem->item.type= ITEM_LAYOUT_ROW;
1432         litem->root= layout->root;
1433         litem->align= align;
1434         litem->space= (align)? 0: layout->root->style->buttonspacex;
1435         BLI_addtail(&layout->items, litem);
1436
1437         uiBlockSetCurLayout(layout->root->block, litem);
1438
1439         return litem;
1440 }
1441
1442 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
1443 {
1444         uiLayout *litem;
1445
1446         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
1447         litem->item.type= ITEM_LAYOUT_COLUMN;
1448         litem->root= layout->root;
1449         litem->align= align;
1450         litem->space= (litem->align)? 0: layout->root->style->buttonspacey;
1451         BLI_addtail(&layout->items, litem);
1452
1453         uiBlockSetCurLayout(layout->root->block, litem);
1454
1455         return litem;
1456 }
1457
1458 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
1459 {
1460         uiLayoutItemFlow *flow;
1461
1462         flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
1463         flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW;
1464         flow->litem.root= layout->root;
1465         flow->litem.align= align;
1466         flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace;
1467         flow->number= number;
1468         BLI_addtail(&layout->items, flow);
1469
1470         uiBlockSetCurLayout(layout->root->block, &flow->litem);
1471
1472         return &flow->litem;
1473 }
1474
1475 uiLayout *uiLayoutBox(uiLayout *layout)
1476 {
1477         uiLayoutItemBx *box;
1478
1479         box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
1480         box->litem.item.type= ITEM_LAYOUT_BOX;
1481         box->litem.root= layout->root;
1482         box->litem.space= layout->root->style->columnspace;
1483         BLI_addtail(&layout->items, box);
1484
1485         uiBlockSetCurLayout(layout->root->block, &box->litem);
1486
1487         box->roundbox= uiDefBut(layout->root->block, ROUNDBOX, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
1488
1489         return &box->litem;
1490 }
1491
1492 uiLayout *uiLayoutFree(uiLayout *layout, int align)
1493 {
1494         uiLayout *litem;
1495
1496         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutFree");
1497         litem->item.type= ITEM_LAYOUT_FREE;
1498         litem->root= layout->root;
1499         litem->align= align;
1500         BLI_addtail(&layout->items, litem);
1501
1502         uiBlockSetCurLayout(layout->root->block, litem);
1503
1504         return litem;
1505 }
1506
1507 uiBlock *uiLayoutFreeBlock(uiLayout *layout)
1508 {
1509         uiBlock *block;
1510
1511         block= uiLayoutBlock(layout);
1512         uiLayoutFree(layout, 0);
1513
1514         return block;
1515 }
1516
1517 uiLayout *uiLayoutSplit(uiLayout *layout)
1518 {
1519         uiLayout *litem;
1520
1521         litem= uiLayoutRow(layout, 0);
1522         litem->item.type = ITEM_LAYOUT_SPLIT;
1523         litem->root= layout->root;
1524         litem->space= layout->root->style->columnspace;
1525
1526         uiBlockSetCurLayout(layout->root->block, litem);
1527
1528         return litem;
1529 }
1530
1531 /********************** Layout *******************/
1532
1533 static void ui_item_estimate(uiItem *item)
1534 {
1535         uiItem *subitem;
1536
1537         if(item->type != ITEM_BUTTON) {
1538                 uiLayout *litem= (uiLayout*)item;
1539
1540                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
1541                         ui_item_estimate(subitem);
1542
1543                 if(litem->items.first == NULL)
1544                         return;
1545
1546                 switch(litem->item.type) {
1547                         case ITEM_LAYOUT_COLUMN:
1548                                 ui_litem_estimate_column(litem);
1549                                 break;
1550                         case ITEM_LAYOUT_COLUMN_FLOW:
1551                                 ui_litem_estimate_column_flow(litem);
1552                                 break;
1553                         case ITEM_LAYOUT_ROW:
1554                                 ui_litem_estimate_row(litem);
1555                                 break;
1556                         case ITEM_LAYOUT_BOX:
1557                                 ui_litem_estimate_box(litem);
1558                                 break;
1559                         case ITEM_LAYOUT_ROOT:
1560                                 ui_litem_estimate_root(litem);
1561                                 break;
1562                         case ITEM_LAYOUT_FREE:
1563                                 ui_litem_estimate_free(litem);
1564                                 break;
1565                         case ITEM_LAYOUT_SPLIT:
1566                                 ui_litem_estimate_split(litem);
1567                                 break;
1568                         default:
1569                                 break;
1570                 }
1571         }
1572 }
1573
1574 static void ui_item_align(uiLayout *litem, int nr)
1575 {
1576         uiItem *item;
1577         uiButtonItem *bitem;
1578         uiLayoutItemBx *box;
1579
1580         for(item=litem->items.last; item; item=item->prev) {
1581                 if(item->type == ITEM_BUTTON) {
1582                         bitem= (uiButtonItem*)item;
1583                         if(ui_but_can_align(bitem->but))
1584                                 bitem->but->alignnr= nr;
1585                 }
1586                 else if(item->type == ITEM_LAYOUT_FREE);
1587                 else if(item->type == ITEM_LAYOUT_BOX) {
1588                         box= (uiLayoutItemBx*)item;
1589                         box->roundbox->alignnr= nr;
1590                         BLI_remlink(&litem->root->block->buttons, box->roundbox);
1591                         BLI_addhead(&litem->root->block->buttons, box->roundbox);
1592                 }
1593                 else
1594                         ui_item_align((uiLayout*)item, nr);
1595         }
1596 }
1597
1598 static void ui_item_layout(uiItem *item, int align)
1599 {
1600         uiItem *subitem;
1601
1602         if(item->type != ITEM_BUTTON) {
1603                 uiLayout *litem= (uiLayout*)item;
1604
1605                 if(litem->items.first == NULL)
1606                         return;
1607
1608                 if(litem->align && !align)
1609                         ui_item_align(litem, ++litem->root->block->alignnr);
1610
1611                 switch(litem->item.type) {
1612                         case ITEM_LAYOUT_COLUMN:
1613                                 ui_litem_layout_column(litem);
1614                                 break;
1615                         case ITEM_LAYOUT_COLUMN_FLOW:
1616                                 ui_litem_layout_column_flow(litem);
1617                                 break;
1618                         case ITEM_LAYOUT_ROW:
1619                                 ui_litem_layout_row(litem);
1620                                 break;
1621                         case ITEM_LAYOUT_BOX:
1622                                 ui_litem_layout_box(litem);
1623                                 break;
1624                         case ITEM_LAYOUT_ROOT:
1625                                 ui_litem_layout_root(litem);
1626                                 break;
1627                         case ITEM_LAYOUT_FREE:
1628                                 ui_litem_layout_free(litem);
1629                                 break;
1630                         case ITEM_LAYOUT_SPLIT:
1631                                 ui_litem_layout_split(litem);
1632                                 break;
1633                         default:
1634                                 break;
1635                 }
1636
1637                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
1638                         ui_item_layout(subitem, litem->align || align);
1639         }
1640 }
1641
1642 static void ui_layout_items(const bContext *C, uiBlock *block, uiLayout *layout)
1643 {
1644         ui_item_estimate(&layout->item);
1645         ui_item_layout(&layout->item, 0);
1646 }
1647
1648 static void ui_layout_end(const bContext *C, uiBlock *block, uiLayout *layout, int *x, int *y)
1649 {
1650         if(layout->root->handlefunc)
1651                 uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv);
1652
1653         ui_layout_items(C, block, layout);
1654
1655         if(x) *x= layout->x;
1656         if(y) *y= layout->y;
1657 }
1658
1659 static void ui_layout_free(uiLayout *layout)
1660 {
1661         uiItem *item, *next;
1662
1663         for(item=layout->items.first; item; item=next) {
1664                 next= item->next;
1665
1666                 if(item->type == ITEM_BUTTON)
1667                         MEM_freeN(item);
1668                 else
1669                         ui_layout_free((uiLayout*)item);
1670         }
1671
1672         MEM_freeN(layout);
1673 }
1674
1675 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
1676 {
1677         uiLayout *layout;
1678         uiLayoutRoot *root;
1679
1680         root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
1681         root->type= type;
1682         root->style= style;
1683         root->block= block;
1684         root->opcontext= WM_OP_INVOKE_REGION_WIN;
1685
1686         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
1687         layout->item.type= ITEM_LAYOUT_ROOT;
1688
1689         layout->x= x;
1690         layout->y= y;
1691         layout->root= root;
1692         layout->space= style->templatespace;
1693
1694         if(type == UI_LAYOUT_MENU)
1695                 layout->space= 0;
1696
1697         if(dir == UI_LAYOUT_HORIZONTAL) {
1698                 layout->h= size;
1699                 layout->root->emh= em*UI_UNIT_Y;
1700         }
1701         else {
1702                 layout->w= size;
1703                 layout->root->emw= em*UI_UNIT_X;
1704         }
1705
1706         block->curlayout= layout;
1707         root->layout= layout;
1708         BLI_addtail(&block->layouts, root);
1709         
1710         return layout;
1711 }
1712
1713 uiBlock *uiLayoutBlock(uiLayout *layout)
1714 {
1715         return layout->root->block;
1716 }
1717
1718 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
1719 {
1720         block->curlayout= layout;
1721 }
1722
1723 void ui_layout_add_but(uiLayout *layout, uiBut *but)
1724 {
1725         uiButtonItem *bitem;
1726         
1727         bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
1728         bitem->item.type= ITEM_BUTTON;
1729         bitem->but= but;
1730         BLI_addtail(&layout->items, bitem);
1731 }
1732
1733 void uiLayoutContext(uiLayout *layout, int opcontext)
1734 {
1735         layout->root->opcontext= opcontext;
1736 }
1737
1738 void uiLayoutFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
1739 {
1740         layout->root->handlefunc= handlefunc;
1741         layout->root->argv= argv;
1742 }
1743
1744 void uiBlockLayoutResolve(const bContext *C, uiBlock *block, int *x, int *y)
1745 {
1746         uiLayoutRoot *root;
1747
1748         if(x) *x= 0;
1749         if(y) *y= 0;
1750
1751         block->curlayout= NULL;
1752
1753         for(root=block->layouts.first; root; root=root->next) {
1754                 /* NULL in advance so we don't interfere when adding button */
1755                 ui_layout_end(C, block, root->layout, x, y);
1756                 ui_layout_free(root->layout);
1757         }
1758
1759         BLI_freelistN(&block->layouts);
1760
1761         /* XXX silly trick, interface_templates.c doesn't get linked
1762          * because it's not used by other files in this module? */
1763         {
1764                 void ui_template_fix_linking();
1765                 ui_template_fix_linking();
1766         }
1767 }
1768
1769 float uiBlockAspect(uiBlock *block)
1770 {
1771         return block->aspect; /* temporary */
1772 }
1773