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