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