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