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