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