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