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