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