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