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