- added GCC warning -Wstrict-prototypes
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_screen_types.h"
33 #include "DNA_userdef_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_string.h"
37
38 #include "BKE_context.h"
39 #include "BKE_global.h"
40 #include "BKE_idprop.h"
41 #include "BKE_screen.h"
42
43 #include "RNA_access.h"
44
45 #include "UI_interface.h"
46
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "interface_intern.h"
52
53 /************************ Structs and Defines *************************/
54
55 #define RNA_NO_INDEX    -1
56 #define RNA_ENUM_VALUE  -2
57
58 #define EM_SEPR_X               6
59 #define EM_SEPR_Y               6
60
61 /* uiLayoutRoot */
62
63 typedef struct uiLayoutRoot {
64         struct uiLayoutRoot *next, *prev;
65
66         int type;
67         int opcontext;
68
69         int emw, emh;
70
71         uiMenuHandleFunc handlefunc;
72         void *argv;
73
74         uiStyle *style;
75         uiBlock *block;
76         uiLayout *layout;
77 } uiLayoutRoot;
78
79 /* Item */
80
81 typedef enum uiItemType {
82         ITEM_BUTTON,
83
84         ITEM_LAYOUT_ROW,
85         ITEM_LAYOUT_COLUMN,
86         ITEM_LAYOUT_COLUMN_FLOW,
87         ITEM_LAYOUT_ROW_FLOW,
88         ITEM_LAYOUT_BOX,
89         ITEM_LAYOUT_ABSOLUTE,
90         ITEM_LAYOUT_SPLIT,
91         ITEM_LAYOUT_OVERLAP,
92
93         ITEM_LAYOUT_ROOT
94 #if 0
95         TEMPLATE_COLUMN_FLOW,
96         TEMPLATE_SPLIT,
97         TEMPLATE_BOX,
98
99         TEMPLATE_HEADER,
100         TEMPLATE_HEADER_ID
101 #endif
102 } uiItemType;
103
104 typedef struct uiItem {
105         void *next, *prev;
106         uiItemType type;
107         int flag;
108 } uiItem;
109
110 typedef struct uiButtonItem {
111         uiItem item;
112         uiBut *but;
113 } uiButtonItem;
114
115 struct uiLayout {
116         uiItem item;
117
118         uiLayoutRoot *root;
119         bContextStore *context;
120         ListBase items;
121
122         int x, y, w, h;
123         float scale[2];
124         short space;
125         char align;
126         char active;
127         char enabled;
128         char redalert;
129         char keepaspect;
130         char alignment;
131 };
132
133 typedef struct uiLayoutItemFlow {
134         uiLayout litem;
135         int number;
136         int totcol;
137 } uiLayoutItemFlow;
138
139 typedef struct uiLayoutItemBx {
140         uiLayout litem;
141         uiBut *roundbox;
142 } uiLayoutItemBx;
143
144 typedef struct uiLayoutItemSplt {
145         uiLayout litem;
146         float percentage;
147 } uiLayoutItemSplt;
148
149 typedef struct uiLayoutItemRoot {
150         uiLayout litem;
151 } uiLayoutItemRoot;
152
153 /************************** Item ***************************/
154
155 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
156 {
157         int len= strlen(name);
158
159         if(len != 0 && len+1 < UI_MAX_NAME_STR) {
160                 BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
161                 namestr[len]= ':';
162                 namestr[len+1]= '\0';
163                 return namestr;
164         }
165
166         return name;
167 }
168
169 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
170 {
171         /* available == 0 is unlimited */
172         if(available == 0)
173                 return item;
174         
175         if(offset)
176                 *offset= 0;
177         
178         if(all > available) {
179                 /* contents is bigger than available space */
180                 if(last)
181                         return available-pos;
182                 else
183                         return (item*available)/all;
184         }
185         else {
186                 /* contents is smaller or equal to available space */
187                 if(alignment == UI_LAYOUT_ALIGN_EXPAND) {
188                         if(last)
189                                 return available-pos;
190                         else
191                                 return (item*available)/all;
192                 }
193                 else
194                         return item;
195         }
196 }
197
198 /* variable button size in which direction? */
199 #define UI_ITEM_VARY_X  1
200 #define UI_ITEM_VARY_Y  2
201
202 static int ui_layout_vary_direction(uiLayout *layout)
203 {
204         return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND)? UI_ITEM_VARY_X: UI_ITEM_VARY_Y;
205 }
206
207 /* estimated size of text + icon */
208 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, int compact)
209 {
210         int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
211
212         if(icon && !name[0])
213                 return UI_UNIT_X; /* icon only */
214         else if(icon)
215                 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* icon + text */
216         else
217                 return (variable)? UI_GetStringWidth(name) + (compact? 5: 10) + UI_UNIT_X: 10*UI_UNIT_X; /* text only */
218 }
219
220 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
221 {
222         if(item->type == ITEM_BUTTON) {
223                 uiButtonItem *bitem= (uiButtonItem*)item;
224
225                 if(r_w) *r_w= bitem->but->x2 - bitem->but->x1;
226                 if(r_h) *r_h= bitem->but->y2 - bitem->but->y1;
227         }
228         else {
229                 uiLayout *litem= (uiLayout*)item;
230
231                 if(r_w) *r_w= litem->w;
232                 if(r_h) *r_h= litem->h;
233         }
234 }
235
236 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
237 {
238         if(item->type == ITEM_BUTTON) {
239                 uiButtonItem *bitem= (uiButtonItem*)item;
240
241                 if(r_x) *r_x= bitem->but->x1;
242                 if(r_y) *r_y= bitem->but->y1;
243         }
244         else {
245                 if(r_x) *r_x= 0;
246                 if(r_y) *r_y= 0;
247         }
248 }
249
250 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
251 {
252         if(item->type == ITEM_BUTTON) {
253                 uiButtonItem *bitem= (uiButtonItem*)item;
254
255                 bitem->but->x1= x;
256                 bitem->but->y1= y;
257                 bitem->but->x2= x+w;
258                 bitem->but->y2= y+h;
259                 
260                 ui_check_but(bitem->but); /* for strlen */
261         }
262         else {
263                 uiLayout *litem= (uiLayout*)item;
264
265                 litem->x= x;
266                 litem->y= y+h;
267                 litem->w= w;
268                 litem->h= h;
269         }
270 }
271
272 /******************** Special RNA Items *********************/
273
274 static int ui_layout_local_dir(uiLayout *layout)
275 {
276         switch(layout->item.type) {
277                 case ITEM_LAYOUT_ROW:
278                 case ITEM_LAYOUT_ROOT:
279                 case ITEM_LAYOUT_OVERLAP:
280                         return UI_LAYOUT_HORIZONTAL;
281                 case ITEM_LAYOUT_COLUMN:
282                 case ITEM_LAYOUT_COLUMN_FLOW:
283                 case ITEM_LAYOUT_SPLIT:
284                 case ITEM_LAYOUT_ABSOLUTE:
285                 case ITEM_LAYOUT_BOX:
286                 default:
287                         return UI_LAYOUT_VERTICAL;
288         }
289 }
290
291 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
292 {
293         uiLayout *sub;
294
295         if(ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
296                 sub= uiLayoutRow(layout, align);
297         else
298                 sub= uiLayoutColumn(layout, align);
299         
300         sub->space= 0;
301         return sub;
302 }
303
304 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
305 {
306         wmWindow *win= CTX_wm_window(C);
307         uiBut *but= arg_but, *cbut;
308         PointerRNA *ptr= &but->rnapoin;
309         PropertyRNA *prop= but->rnaprop;
310         int i, index= GET_INT_FROM_POINTER(arg_index);
311         int shift= win->eventstate->shift;
312         int len= RNA_property_array_length(ptr, prop);
313
314         if(!shift) {
315                 RNA_property_boolean_set_index(ptr, prop, index, 1);
316
317                 for(i=0; i<len; i++)
318                         if(i != index)
319                                 RNA_property_boolean_set_index(ptr, prop, i, 0);
320
321                 RNA_property_update(C, ptr, prop);
322
323                 for(cbut=but->block->buttons.first; cbut; cbut=cbut->next)
324                         ui_check_but(cbut);
325         }
326 }
327
328 /* create buttons for an item with an RNA array */
329 static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int h, int expand, int slider, int toggle, int icon_only)
330 {
331         uiStyle *style= layout->root->style;
332         uiBut *but;
333         PropertyType type;
334         PropertySubType subtype;
335         uiLayout *sub;
336         int a, b;
337
338         /* retrieve type and subtype */
339         type= RNA_property_type(prop);
340         subtype= RNA_property_subtype(prop);
341
342         sub= ui_item_local_sublayout(layout, layout, 1);
343         uiBlockSetCurLayout(block, sub);
344
345         /* create label */
346         if(strcmp(name, "") != 0)
347                 uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
348
349         /* create buttons */
350         if(type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
351                 /* special check for layer layout */
352                 int butw, buth, unit;
353                 int cols= (len >= 20)? 2: 1;
354                 int colbuts= len/(2*cols);
355
356                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 0));
357
358                 unit= UI_UNIT_X*0.75;
359                 butw= unit;
360                 buth= unit;
361
362                 for(b=0; b<cols; b++) {
363                         uiBlockBeginAlign(block);
364
365                         for(a=0; a<colbuts; a++) {
366                                 but= uiDefAutoButR(block, ptr, prop, a+b*colbuts, "", ICON_BLANK1, x + butw*a, y+buth, butw, buth);
367                                 if(subtype == PROP_LAYER_MEMBER)
368                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+b*colbuts));
369                         }
370                         for(a=0; a<colbuts; a++) {
371                                 but= uiDefAutoButR(block, ptr, prop, a+len/2+b*colbuts, "", ICON_BLANK1, x + butw*a, y, butw, buth);
372                                 if(subtype == PROP_LAYER_MEMBER)
373                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(a+len/2+b*colbuts));
374                         }
375                         uiBlockEndAlign(block);
376
377                         x += colbuts*butw + style->buttonspacex;
378                 }
379         }
380         else if(subtype == PROP_MATRIX) {
381                 int totdim, dim_size[3];        /* 3 == RNA_MAX_ARRAY_DIMENSION */
382                 int row, col;
383
384                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, 1));
385
386                 totdim= RNA_property_array_dimension(ptr, prop, dim_size);
387                 if (totdim != 2) return;        /* only 2D matrices supported in UI so far */
388                 
389                 w /= dim_size[0];
390                 h /= dim_size[1];
391
392                 for(a=0; a<len; a++) {
393                         col= a % dim_size[0];
394                         row= a / dim_size[0];
395                         
396                         but= uiDefAutoButR(block, ptr, prop, a, "", 0, x + w*col, y+(dim_size[1]*UI_UNIT_Y)-(row*UI_UNIT_Y), w, UI_UNIT_Y);
397                         if(slider && but->type==NUM)
398                                 but->type= NUMSLI;
399                 }
400         }
401         else {
402                 if(ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand)
403                         uiDefAutoButR(block, ptr, prop, -1, "", 0, 0, 0, w, UI_UNIT_Y);
404
405                 if(!ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) || expand) {
406                         /* layout for known array subtypes */
407                         char str[3];
408
409                         for(a=0; a<len; a++) {
410                                 str[0]= RNA_property_array_item_char(prop, a);
411
412                                 if(str[0]) {
413                                         if (icon_only) {
414                                                 str[0] = '\0';
415                                         }
416                                         else if(type == PROP_BOOLEAN) {
417                                                 str[1]= '\0';
418                                         }
419                                         else {
420                                                 str[1]= ':';
421                                                 str[2]= '\0';
422                                         }
423                                 }
424
425                                 but= uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
426                                 if(slider && but->type==NUM)
427                                         but->type= NUMSLI;
428                                 if(toggle && but->type==OPTION)
429                                         but->type= TOG;
430                         }
431                 }
432         }
433
434         uiBlockSetCurLayout(block, layout);
435 }
436
437 static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, const char *uiname, int h, int icon_only)
438 {
439         uiBut *but;
440         EnumPropertyItem *item;
441         const char *identifier;
442         char *name;
443         int a, totitem, itemw, icon, value, free;
444
445         identifier= RNA_property_identifier(prop);
446         RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
447
448         uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
449         for(a=0; a<totitem; a++) {
450                 if(!item[a].identifier[0])
451                         continue;
452
453                 name= (!uiname || uiname[0])? (char*)item[a].name: "";
454                 icon= item[a].icon;
455                 value= item[a].value;
456                 itemw= ui_text_icon_width(block->curlayout, name, icon, 0);
457
458                 if(icon && strcmp(name, "") != 0 && !icon_only)
459                         but= uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
460                 else if(icon)
461                         but= uiDefIconButR(block, ROW, 0, icon, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
462                 else
463                         but= uiDefButR(block, ROW, 0, name, 0, 0, itemw, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
464
465                 if(ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
466                         but->flag |= UI_TEXT_LEFT;
467         }
468         uiBlockSetCurLayout(block, layout);
469
470         if(free)
471                 MEM_freeN(item);
472 }
473
474 /* callback for keymap item change button */
475 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
476 {
477         uiBut *but= but_v;
478
479         RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
480         RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
481         RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
482         RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
483 }
484
485 /* create label + button for RNA property */
486 static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag)
487 {
488         uiLayout *sub;
489         uiBut *but=NULL;
490         PropertyType type;
491         PropertySubType subtype;
492         int labelw;
493
494         sub= uiLayoutRow(layout, 0);
495         uiBlockSetCurLayout(block, sub);
496
497         if(strcmp(name, "") != 0) {
498                 /* XXX UI_GetStringWidth is not accurate
499                 labelw= UI_GetStringWidth(name);
500                 CLAMP(labelw, w/4, 3*w/4);*/
501                 labelw= w/3;
502                 uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
503                 w= w-labelw;
504         }
505
506         type= RNA_property_type(prop);
507         subtype= RNA_property_subtype(prop);
508
509         if(subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
510                 uiBlockSetCurLayout(block, uiLayoutRow(sub, 1));
511                 uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w-UI_UNIT_X, h);
512
513                 /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
514                 but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
515         }
516         else if(subtype == PROP_DIRECTION) {
517                 uiDefButR(block, BUT_NORMAL, 0, name, x, y, 100, 100, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL);
518         }
519         else if(flag & UI_ITEM_R_EVENT) {
520                 uiDefButR(block, KEYEVT, 0, name, x, y, w, h, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL);
521         }
522         else if(flag & UI_ITEM_R_FULL_EVENT) {
523                 if(RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
524                         char buf[128];
525
526                         WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
527
528                         but= uiDefButR(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, RNA_property_identifier(prop), 0, 0, 0, -1, -1, NULL);
529                         uiButSetFunc(but, ui_keymap_but_cb, but, NULL);
530                         if (flag & UI_ITEM_R_IMMEDIATE)
531                                 uiButSetFlag(but, UI_BUT_IMMEDIATE);
532                 }
533         }
534         else
535                 but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY))? NULL: "", icon, x, y, w, h);
536
537         uiBlockSetCurLayout(block, layout);
538         return but;
539 }
540
541 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
542 {
543         ARegion *ar= CTX_wm_region(C);
544         uiBlock *block;
545         uiBut *but, *prevbut;
546
547         memset(ptr, 0, sizeof(*ptr));
548         *prop= NULL;
549
550         if(!ar)
551                 return;
552
553         for(block=ar->uiblocks.first; block; block=block->next) {
554                 for(but=block->buttons.first; but; but= but->next) {
555                         prevbut= but->prev;
556
557                         /* find the button before the active one */
558                         if((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
559                                 if(RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
560                                         *ptr= prevbut->rnapoin;
561                                         *prop= prevbut->rnaprop;
562                                         return;
563                                 }
564                         }
565                 }
566         }
567 }
568
569 /********************* Button Items *************************/
570
571 /* disabled item */
572 static void ui_item_disabled(uiLayout *layout, const char *name)
573 {
574         uiBlock *block= layout->root->block;
575         uiBut *but;
576         int w;
577
578         uiBlockSetCurLayout(block, layout);
579
580         if(!name)
581                 name= "";
582
583         w= ui_text_icon_width(layout, name, 0, 0);
584
585         but= uiDefBut(block, LABEL, 0, (char*)name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
586         but->flag |= UI_BUT_DISABLED;
587         but->lock = 1;
588         but->lockstr = "";
589 }
590
591 /* operator items */
592 PointerRNA uiItemFullO(uiLayout *layout, const char *idname, const char *name, int icon, IDProperty *properties, int context, int flag)
593 {
594         uiBlock *block= layout->root->block;
595         wmOperatorType *ot= WM_operatortype_find(idname, 0);
596         uiBut *but;
597         int w;
598
599         if(!ot) {
600                 ui_item_disabled(layout, idname);
601                 return PointerRNA_NULL;
602         }
603
604         if(!name)
605                 name= ot->name;
606         if(layout->root->type == UI_LAYOUT_MENU && !icon)
607                 icon= ICON_BLANK1;
608
609         /* create button */
610         uiBlockSetCurLayout(block, layout);
611
612         w= ui_text_icon_width(layout, name, icon, 0);
613
614         if (flag & UI_ITEM_R_NO_BG)
615                 uiBlockSetEmboss(block, UI_EMBOSSN);
616
617         if(icon && strcmp(name, "") != 0)
618                 but= uiDefIconTextButO(block, BUT, ot->idname, context, icon, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
619         else if(icon)
620                 but= uiDefIconButO(block, BUT, ot->idname, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
621         else
622                 but= uiDefButO(block, BUT, ot->idname, context, (char*)name, 0, 0, w, UI_UNIT_Y, NULL);
623         
624         /* text alignment for toolbar buttons */
625         if((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
626                 but->flag |= UI_TEXT_LEFT;
627
628         if (flag & UI_ITEM_R_NO_BG)
629                 uiBlockSetEmboss(block, UI_EMBOSS);
630
631         /* assign properties */
632         if(properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
633                 PointerRNA *opptr= uiButGetOperatorPtrRNA(but);
634
635                 if(properties) {
636                         opptr->data= properties;
637                 }
638                 else {
639                         IDPropertyTemplate val = {0};
640                         opptr->data= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
641                 }
642
643                 return *opptr;
644         }
645
646         return PointerRNA_NULL;
647 }
648
649 static char *ui_menu_enumpropname(uiLayout *layout, const char *opname, const char *propname, int retval)
650 {
651         wmOperatorType *ot= WM_operatortype_find(opname, 0);
652         PointerRNA ptr;
653         PropertyRNA *prop;
654
655         if(!ot || !ot->srna)
656                 return "";
657
658         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
659         prop= RNA_struct_find_property(&ptr, propname);
660
661         if(prop) {
662                 EnumPropertyItem *item;
663                 int totitem, free;
664                 const char *name;
665
666                 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, &totitem, &free);
667                 if(RNA_enum_name(item, retval, &name)) {
668                         if(free) MEM_freeN(item);
669                         return (char*)name;
670                 }
671                 
672                 if(free)
673                         MEM_freeN(item);
674         }
675
676         return "";
677 }
678
679 void uiItemEnumO(uiLayout *layout, const char *opname, char *name, int icon, const char *propname, int value)
680 {
681         PointerRNA ptr;
682
683         WM_operator_properties_create(&ptr, opname);
684         RNA_enum_set(&ptr, propname, value);
685
686         if(!name)
687                 name= ui_menu_enumpropname(layout, opname, propname, value);
688
689         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
690 }
691
692 void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, int context, int flag)
693 {
694         wmOperatorType *ot= WM_operatortype_find(opname, 0);
695         PointerRNA ptr;
696         PropertyRNA *prop;
697         uiBut *bt;
698         uiBlock *block= layout->root->block;
699
700         if(!ot || !ot->srna) {
701                 ui_item_disabled(layout, opname);
702                 return;
703         }
704
705         RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
706         prop= RNA_struct_find_property(&ptr, propname);
707
708         if(prop && RNA_property_type(prop) == PROP_ENUM) {
709                 EnumPropertyItem *item;
710                 int totitem, i, free;
711                 uiLayout *split= uiLayoutSplit(layout, 0, 0);
712                 uiLayout *column= uiLayoutColumn(split, 0);
713
714                 RNA_property_enum_items(block->evil_C, &ptr, prop, &item, &totitem, &free);
715
716                 for(i=0; i<totitem; i++) {
717                         if(item[i].identifier[0]) {
718                                 if(properties) {
719                                         PointerRNA tptr;
720
721                                         WM_operator_properties_create(&tptr, opname);
722                                         if(tptr.data) {
723                                                 IDP_FreeProperty(tptr.data);
724                                                 MEM_freeN(tptr.data);
725                                         }
726                                         tptr.data= IDP_CopyProperty(properties);
727                                         RNA_enum_set(&tptr, propname, item[i].value);
728
729                                         uiItemFullO(column, opname, (char*)item[i].name, item[i].icon, tptr.data, context, flag);
730                                 }
731                                 else
732                                         uiItemEnumO(column, opname, (char*)item[i].name, item[i].icon, propname, item[i].value);
733                         }
734                         else {
735                                 if(item[i].name) {
736                                         if(i != 0) {
737                                                 column= uiLayoutColumn(split, 0);
738                                                 /* inconsistent, but menus with labels do not look good flipped */
739                                                 block->flag |= UI_BLOCK_NO_FLIP;
740                                         }
741
742                                         uiItemL(column, (char*)item[i].name, 0);
743                                         bt= block->buttons.last;
744                                         bt->flag= UI_TEXT_LEFT;
745                                 }
746                                 else
747                                         uiItemS(column);
748                         }
749                 }
750
751                 if(free)
752                         MEM_freeN(item);
753         }
754 }
755
756 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
757 {
758         uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
759 }
760
761 /* for use in cases where we have */
762 void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, char *value_str)
763 {
764         PointerRNA ptr;
765         
766         /* for getting the enum */
767         PropertyRNA *prop;
768         EnumPropertyItem *item;
769         int value, free;
770
771         WM_operator_properties_create(&ptr, opname);
772         
773         /* enum lookup */
774         if((prop= RNA_struct_find_property(&ptr, propname))) {
775                 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
776                 if(item==NULL || RNA_enum_value_from_id(item, value_str, &value)==0) {
777                         if(free) MEM_freeN(item);
778                         printf("uiItemEnumO_string: %s.%s, enum %s not found.\n", RNA_struct_identifier(ptr.type), propname, value_str);
779                         return;
780                 }
781
782                 if(free)
783                         MEM_freeN(item);
784         }
785         else {
786                 printf("uiItemEnumO_string: %s.%s not found.\n", RNA_struct_identifier(ptr.type), propname);
787                 return;
788         }
789         
790         RNA_property_enum_set(&ptr, prop, value);
791         
792         /* same as uiItemEnumO */
793         if(!name)
794                 name= ui_menu_enumpropname(layout, opname, propname, value);
795
796         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
797 }
798
799 void uiItemBooleanO(uiLayout *layout, char *name, int icon, const char *opname, const char *propname, int value)
800 {
801         PointerRNA ptr;
802
803         WM_operator_properties_create(&ptr, opname);
804         RNA_boolean_set(&ptr, propname, value);
805
806         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
807 }
808
809 void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
810 {
811         PointerRNA ptr;
812
813         WM_operator_properties_create(&ptr, opname);
814         RNA_int_set(&ptr, propname, value);
815
816         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
817 }
818
819 void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value)
820 {
821         PointerRNA ptr;
822
823         WM_operator_properties_create(&ptr, opname);
824         RNA_float_set(&ptr, propname, value);
825
826         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
827 }
828
829 void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, char *value)
830 {
831         PointerRNA ptr;
832
833         WM_operator_properties_create(&ptr, opname);
834         RNA_string_set(&ptr, propname, value);
835
836         uiItemFullO(layout, opname, name, icon, ptr.data, layout->root->opcontext, 0);
837 }
838
839 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
840 {
841         uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0);
842 }
843
844 /* RNA property items */
845
846 static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int icon_only, int *r_w, int *r_h)
847 {
848         PropertyType type;
849         PropertySubType subtype;
850         int len, w, h;
851
852         /* arbitrary extended width by type */
853         type= RNA_property_type(prop);
854         subtype= RNA_property_subtype(prop);
855         len= RNA_property_array_length(ptr, prop);
856
857         if(ELEM3(type, PROP_STRING, PROP_POINTER, PROP_ENUM) && !name[0] && !icon_only)
858                 name= "non-empty text";
859         else if(type == PROP_BOOLEAN && !name[0] && !icon_only)
860                 icon= ICON_DOT;
861
862         w= ui_text_icon_width(layout, name, icon, 0);
863         h= UI_UNIT_Y;
864
865         /* increase height for arrays */
866         if(index == RNA_NO_INDEX && len > 0) {
867                 if(!name[0] && icon == 0)
868                         h= 0;
869
870                 if(ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
871                         h += 2*UI_UNIT_Y;
872                 else if(subtype == PROP_MATRIX)
873                         h += ceil(sqrt(len))*UI_UNIT_Y;
874                 else
875                         h += len*UI_UNIT_Y;
876         }
877         else if(ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
878                 if(type == PROP_BOOLEAN && strcmp(name, "") != 0)
879                         w += UI_UNIT_X/5;
880                 else if(type == PROP_ENUM)
881                         w += UI_UNIT_X/4;
882                 else if(type == PROP_FLOAT || type == PROP_INT)
883                         w += UI_UNIT_X*3;
884         }
885
886         *r_w= w;
887         *r_h= h;
888 }
889
890 void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
891 {
892         uiBlock *block= layout->root->block;
893         uiBut *but;
894         PropertyType type;
895         char namestr[UI_MAX_NAME_STR];
896         int len, w, h, slider, toggle, expand, icon_only, no_bg;
897
898         uiBlockSetCurLayout(block, layout);
899
900         /* retrieve info */
901         type= RNA_property_type(prop);
902         len= RNA_property_array_length(ptr, prop);
903
904         /* set name and icon */
905         if(!name)
906                 name= (char*)RNA_property_ui_name(prop);
907         if(!icon)
908                 icon= RNA_property_ui_icon(prop);
909         
910         if(ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
911                 name= ui_item_name_add_colon(name, namestr);
912         else if(type == PROP_BOOLEAN && len && index == RNA_NO_INDEX)
913                 name= ui_item_name_add_colon(name, namestr);
914         else if(type == PROP_ENUM && index != RNA_ENUM_VALUE)
915                 name= ui_item_name_add_colon(name, namestr);
916
917         if(layout->root->type == UI_LAYOUT_MENU) {
918                 if(type == PROP_BOOLEAN)
919                         icon= (RNA_property_boolean_get(ptr, prop))? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
920                 else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
921                         int enum_value= RNA_property_enum_get(ptr, prop);
922                         if(RNA_property_flag(prop) & PROP_ENUM_FLAG) {
923                                 icon= (enum_value & value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
924                         }
925                         else {
926                                 icon= (enum_value == value)? ICON_CHECKBOX_HLT: ICON_CHECKBOX_DEHLT;
927                         }
928                 }
929         }
930
931         slider= (flag & UI_ITEM_R_SLIDER);
932         toggle= (flag & UI_ITEM_R_TOGGLE);
933         expand= (flag & UI_ITEM_R_EXPAND);
934         icon_only= (flag & UI_ITEM_R_ICON_ONLY);
935         no_bg= (flag & UI_ITEM_R_NO_BG);
936
937         /* get size */
938         ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
939
940         if (no_bg)
941                 uiBlockSetEmboss(block, UI_EMBOSSN);
942         
943         /* array property */
944         if(index == RNA_NO_INDEX && len > 0)
945                 ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
946         /* enum item */
947         else if(type == PROP_ENUM && index == RNA_ENUM_VALUE) {
948                 char *identifier= (char*)RNA_property_identifier(prop);
949
950                 if(icon && strcmp(name, "") != 0 && !icon_only)
951                         uiDefIconTextButR(block, ROW, 0, icon, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
952                 else if(icon)
953                         uiDefIconButR(block, ROW, 0, icon, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
954                 else
955                         uiDefButR(block, ROW, 0, name, 0, 0, w, h, ptr, identifier, -1, 0, value, -1, -1, NULL);
956         }
957         /* expanded enum */
958         else if(type == PROP_ENUM && (expand || RNA_property_flag(prop) & PROP_ENUM_FLAG))
959                 ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
960         /* property with separate label */
961         else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
962                 but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
963                 ui_but_add_search(but, ptr, prop, NULL, NULL);
964         }
965         /* single button */
966         else {
967                 but= uiDefAutoButR(block, ptr, prop, index, (char*)name, icon, 0, 0, w, h);
968
969                 if(slider && but->type==NUM)
970                         but->type= NUMSLI;
971
972                 if(toggle && but->type==OPTION)
973                         but->type= TOG;
974         }
975         
976         if (no_bg)
977                 uiBlockSetEmboss(block, UI_EMBOSS);
978 }
979
980 void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
981 {
982         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
983
984         if(!prop) {
985                 ui_item_disabled(layout, propname);
986                 printf("uiItemR: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
987                 return;
988         }
989
990         uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
991 }
992
993 void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
994 {
995         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
996
997         if(!prop || RNA_property_type(prop) != PROP_ENUM) {
998                 ui_item_disabled(layout, propname);
999                 printf("uiItemEnumR: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1000                 return;
1001         }
1002
1003         uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
1004 }
1005
1006 void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
1007 {
1008         PropertyRNA *prop= RNA_struct_find_property(ptr, propname);
1009         EnumPropertyItem *item;
1010         int ivalue, a, free;
1011
1012         if(!prop || RNA_property_type(prop) != PROP_ENUM) {
1013                 ui_item_disabled(layout, propname);
1014                 printf("uiItemEnumR_string: enum property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1015                 return;
1016         }
1017
1018         RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
1019
1020         if(!RNA_enum_value_from_id(item, value, &ivalue)) {
1021                 if(free) MEM_freeN(item);
1022                 ui_item_disabled(layout, propname);
1023                 printf("uiItemEnumR: enum property value not found: %s\n", value);
1024                 return;
1025         }
1026
1027         for(a=0; item[a].identifier; a++) {
1028                 if(item[a].value == ivalue) {
1029                         uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, name ? name : (char*)item[a].name, icon ? icon : item[a].icon);
1030                         break;
1031                 }
1032         }
1033
1034         if(free)
1035                 MEM_freeN(item);
1036 }
1037
1038 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
1039 {
1040         PropertyRNA *prop;
1041         uiBlock *block= layout->root->block;
1042         uiBut *bt;
1043
1044         prop= RNA_struct_find_property(ptr, propname);
1045
1046         if(!prop) {
1047                 ui_item_disabled(layout, propname);
1048                 return;
1049         }
1050
1051         if(RNA_property_type(prop) == PROP_ENUM) {
1052                 EnumPropertyItem *item;
1053                 int totitem, i, free;
1054                 uiLayout *split= uiLayoutSplit(layout, 0, 0);
1055                 uiLayout *column= uiLayoutColumn(split, 0);
1056
1057                 RNA_property_enum_items(block->evil_C, ptr, prop, &item, &totitem, &free);
1058
1059                 for(i=0; i<totitem; i++) {
1060                         if(item[i].identifier[0]) {
1061                                 uiItemEnumR(column, (char*)item[i].name, 0, ptr, propname, item[i].value);
1062                         }
1063                         else {
1064                                 if(item[i].name) {
1065                                         if(i != 0) {
1066                                                 column= uiLayoutColumn(split, 0);
1067                                                 /* inconsistent, but menus with labels do not look good flipped */
1068                                                 block->flag |= UI_BLOCK_NO_FLIP;
1069                                         }
1070
1071                                         uiItemL(column, (char*)item[i].name, 0);
1072                                         bt= block->buttons.last;
1073                                         bt->flag= UI_TEXT_LEFT;
1074                                 }
1075                                 else
1076                                         uiItemS(column);
1077                         }
1078                 }
1079
1080                 if(free)
1081                         MEM_freeN(item);
1082         }
1083 }
1084
1085 /* Pointer RNA button with search */
1086
1087 typedef struct CollItemSearch {
1088         struct CollItemSearch *next, *prev;
1089         char *name;
1090         int index;
1091         int iconid;
1092 } CollItemSearch;
1093
1094 int sort_search_items_list(void *a, void *b)
1095 {
1096         CollItemSearch *cis1 = (CollItemSearch *)a;
1097         CollItemSearch *cis2 = (CollItemSearch *)b;
1098         
1099         if (BLI_strcasecmp(cis1->name, cis2->name)>0)
1100                 return 1;
1101         else
1102                 return 0;
1103 }
1104
1105 static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
1106 {
1107         uiBut *but= arg_but;
1108         char *name;
1109         int i=0, iconid=0, flag= RNA_property_flag(but->rnaprop);
1110         ListBase *items_list= MEM_callocN(sizeof(ListBase), "items_list");
1111         CollItemSearch *cis;
1112         const int skip_filter= !but->changed;
1113
1114         /* build a temporary list of relevant items first */
1115         RNA_PROP_BEGIN(&but->rnasearchpoin, itemptr, but->rnasearchprop) {
1116                 if(flag & PROP_ID_SELF_CHECK)
1117                         if(itemptr.data == but->rnapoin.id.data)
1118                                 continue;
1119
1120                 /* use filter */
1121                 if(RNA_property_type(but->rnaprop)==PROP_POINTER) {
1122                         if(RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr)==0)
1123                                 continue;
1124                 }
1125
1126                 if(itemptr.type && RNA_struct_is_ID(itemptr.type)) {
1127                         ID *id= itemptr.data;
1128                         char name_ui[32];
1129
1130 #if 0           /* this name is used for a string comparison and can't be modified, TODO */
1131                         name_uiprefix_id(name_ui, id);
1132 #else
1133                         strcpy(name_ui, id->name+2);
1134 #endif
1135                         name= BLI_strdup(name_ui);
1136                         iconid= ui_id_icon_get((bContext*)C, id, 1);
1137         }
1138                 else {
1139                         name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
1140             iconid = 0;
1141                 }
1142
1143                 if(name) {
1144                         if(skip_filter || BLI_strcasestr(name, str)) {
1145                                 cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
1146                                 cis->name = MEM_dupallocN(name);
1147                                 cis->index = i;
1148                                 cis->iconid = iconid;
1149                                 BLI_addtail(items_list, cis);
1150                         }
1151                         MEM_freeN(name);
1152                 }                       
1153
1154                 i++;
1155         }
1156         RNA_PROP_END;
1157         
1158         BLI_sortlist(items_list, sort_search_items_list);
1159         
1160         /* add search items from temporary list */
1161         for (cis=items_list->first; cis; cis=cis->next) {
1162                 if (!uiSearchItemAdd(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
1163                         break;
1164                 }
1165         }
1166
1167         for (cis=items_list->first; cis; cis=cis->next) {
1168                 MEM_freeN(cis->name);
1169         }
1170         BLI_freelistN(items_list);
1171         MEM_freeN(items_list);
1172 }
1173
1174 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
1175 {
1176         StructRNA *srna;
1177
1178         /* look for collection property in Main */
1179         RNA_main_pointer_create(G.main, ptr);
1180
1181         *prop= NULL;
1182
1183         RNA_STRUCT_BEGIN(ptr, iprop) {
1184                 /* if it's a collection and has same pointer type, we've got it */
1185                 if(RNA_property_type(iprop) == PROP_COLLECTION) {
1186                         srna= RNA_property_pointer_type(ptr, iprop);
1187
1188                         if(ptype == srna) {
1189                                 *prop= iprop;
1190                                 break;
1191                         }
1192                 }
1193         }
1194         RNA_STRUCT_END;
1195 }
1196
1197 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
1198 {
1199         StructRNA *ptype;
1200         PointerRNA sptr;
1201
1202         /* for ID's we do automatic lookup */
1203         if(!searchprop) {
1204                 if(RNA_property_type(prop) == PROP_POINTER) {
1205                         ptype= RNA_property_pointer_type(ptr, prop);
1206                         search_id_collection(ptype, &sptr, &searchprop);
1207                         searchptr= &sptr;
1208                 }
1209         }
1210
1211         /* turn button into search button */
1212         if(searchprop) {
1213                 but->type= SEARCH_MENU;
1214                 but->hardmax= MAX2(but->hardmax, 256);
1215                 but->rnasearchpoin= *searchptr;
1216                 but->rnasearchprop= searchprop;
1217                 but->flag |= UI_ICON_LEFT|UI_TEXT_LEFT|UI_BUT_UNDO;
1218
1219                 uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
1220         }
1221 }
1222
1223 void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
1224 {
1225         PropertyRNA *prop, *searchprop;
1226         PropertyType type;
1227         uiBut *but;
1228         uiBlock *block;
1229         StructRNA *icontype;
1230         int w, h;
1231         
1232         /* validate arguments */
1233         prop= RNA_struct_find_property(ptr, propname);
1234
1235         if(!prop) {
1236                 printf("uiItemPointerR: property not found: %s.%s\n", RNA_struct_identifier(ptr->type), propname);
1237                 return;
1238         }
1239         
1240         type= RNA_property_type(prop);
1241         if(!ELEM(type, PROP_POINTER, PROP_STRING)) {
1242                 printf("uiItemPointerR: property %s must be a pointer or string.\n", propname);
1243                 return;
1244         }
1245
1246         searchprop= RNA_struct_find_property(searchptr, searchpropname);
1247
1248         if(!searchprop || RNA_property_type(searchprop) != PROP_COLLECTION) {
1249                 printf("uiItemPointerR: search collection property not found: %s.%s\n", RNA_struct_identifier(ptr->type), searchpropname);
1250                 return;
1251         }
1252
1253         /* get icon & name */
1254         if(!icon) {
1255                 if(type == PROP_POINTER)
1256                         icontype= RNA_property_pointer_type(ptr, prop);
1257                 else
1258                         icontype= RNA_property_pointer_type(searchptr, searchprop);
1259
1260                 icon= RNA_struct_ui_icon(icontype);
1261         }
1262         if(!name)
1263                 name= (char*)RNA_property_ui_name(prop);
1264
1265         /* create button */
1266         block= uiLayoutGetBlock(layout);
1267
1268         ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
1269         but= ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
1270
1271         ui_but_add_search(but, ptr, prop, searchptr, searchprop);
1272 }
1273
1274 /* menu item */
1275 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
1276 {
1277         MenuType *mt= (MenuType*)arg_mt;
1278         Menu menu = {0};
1279
1280         menu.type= mt;
1281         menu.layout= layout;
1282         mt->draw(C, &menu);
1283 }
1284
1285 static void ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN)
1286 {
1287         uiBlock *block= layout->root->block;
1288         uiBut *but;
1289         int w, h;
1290
1291         uiBlockSetCurLayout(block, layout);
1292
1293         if(layout->root->type == UI_LAYOUT_HEADER)
1294                 uiBlockSetEmboss(block, UI_EMBOSS);
1295
1296         if(!name)
1297                 name= "";
1298         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1299                 icon= ICON_BLANK1;
1300
1301         w= ui_text_icon_width(layout, name, icon, 1);
1302         h= UI_UNIT_Y;
1303
1304         if(layout->root->type == UI_LAYOUT_HEADER) /* ugly .. */
1305                 w -= 10;
1306
1307         if(name[0] && icon)
1308                 but= uiDefIconTextMenuBut(block, func, arg, icon, (char*)name, 0, 0, w, h, "");
1309         else if(icon)
1310                 but= uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, "");
1311         else
1312                 but= uiDefMenuBut(block, func, arg, (char*)name, 0, 0, w, h, "");
1313
1314         if(argN) { /* ugly .. */
1315                 but->poin= (char*)but;
1316                 but->func_argN= argN;
1317         }
1318
1319         if(layout->root->type == UI_LAYOUT_HEADER)
1320                 uiBlockSetEmboss(block, UI_EMBOSS);
1321         else if(layout->root->type == UI_LAYOUT_PANEL) {
1322                 but->type= MENU;
1323                 but->flag |= UI_TEXT_LEFT;
1324         }
1325 }
1326
1327 void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const char *name, int icon)
1328 {
1329         MenuType *mt;
1330
1331         mt= WM_menutype_find(menuname, FALSE);
1332
1333         if(mt==NULL) {
1334                 printf("uiItemM: not found %s\n", menuname);
1335                 return;
1336         }
1337
1338         if(!name)
1339                 name= mt->label;
1340         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1341                 icon= ICON_BLANK1;
1342
1343         ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL);
1344 }
1345
1346 /* label item */
1347 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
1348 {
1349         uiBlock *block= layout->root->block;
1350         uiBut *but;
1351         int w;
1352
1353         uiBlockSetCurLayout(block, layout);
1354
1355         if(!name)
1356                 name= "";
1357         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1358                 icon= ICON_BLANK1;
1359
1360         w= ui_text_icon_width(layout, name, icon, 0);
1361
1362         if(icon && strcmp(name, "") != 0)
1363                 but= uiDefIconTextBut(block, LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1364         else if(icon)
1365                 but= uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1366         else
1367                 but= uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1368         
1369         return but;
1370 }
1371
1372 void uiItemL(uiLayout *layout, const char *name, int icon)
1373 {
1374         uiItemL_(layout, name, icon);
1375 }
1376
1377 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, char *name, int icon)
1378 {
1379         uiBut *but= uiItemL_(layout, name, icon);
1380
1381         if(ptr && ptr->type)
1382                 if(RNA_struct_is_ID(ptr->type))
1383                         uiButSetDragID(but, ptr->id.data);
1384 }
1385
1386
1387 /* value item */
1388 void uiItemV(uiLayout *layout, char *name, int icon, int argval)
1389 {
1390         /* label */
1391         uiBlock *block= layout->root->block;
1392         float *retvalue= (block->handle)? &block->handle->retvalue: NULL;
1393         int w;
1394
1395         uiBlockSetCurLayout(block, layout);
1396
1397         if(!name)
1398                 name= "";
1399         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1400                 icon= ICON_BLANK1;
1401
1402         w= ui_text_icon_width(layout, name, icon, 0);
1403
1404         if(icon && strcmp(name, "") != 0)
1405                 uiDefIconTextButF(block, BUTM, 0, icon, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1406         else if(icon)
1407                 uiDefIconButF(block, BUTM, 0, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1408         else
1409                 uiDefButF(block, BUTM, 0, (char*)name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, argval, "");
1410 }
1411
1412 /* separator item */
1413 void uiItemS(uiLayout *layout)
1414 {
1415         uiBlock *block= layout->root->block;
1416
1417         uiBlockSetCurLayout(block, layout);
1418         uiDefBut(block, SEPR, 0, "", 0, 0, EM_SEPR_X, EM_SEPR_Y, NULL, 0.0, 0.0, 0, 0, "");
1419 }
1420
1421 /* level items */
1422 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
1423 {
1424         if(!func)
1425                 return;
1426
1427         ui_item_menu(layout, name, icon, func, arg, NULL);
1428 }
1429
1430 typedef struct MenuItemLevel {
1431         int opcontext;
1432         const char *opname;
1433         const char *propname;
1434         PointerRNA rnapoin;
1435 } MenuItemLevel;
1436
1437 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1438 {
1439         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1440
1441         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
1442         uiItemsEnumO(layout, lvl->opname, lvl->propname);
1443 }
1444
1445 void uiItemMenuEnumO(uiLayout *layout, const char *opname, const char *propname, const char *name, int icon)
1446 {
1447         wmOperatorType *ot= WM_operatortype_find(opname, 0);
1448         MenuItemLevel *lvl;
1449
1450         if(!ot || !ot->srna) {
1451                 ui_item_disabled(layout, opname);
1452                 return;
1453         }
1454
1455         if(!name)
1456                 name= ot->name;
1457         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1458                 icon= ICON_BLANK1;
1459
1460         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1461         lvl->opname= opname;
1462         lvl->propname= propname;
1463         lvl->opcontext= layout->root->opcontext;
1464
1465         ui_item_menu(layout, name, icon, menu_item_enum_opname_menu, NULL, lvl);
1466 }
1467
1468 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1469 {
1470         MenuItemLevel *lvl= (MenuItemLevel*)(((uiBut*)arg)->func_argN);
1471
1472         uiLayoutSetOperatorContext(layout, lvl->opcontext);
1473         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
1474 }
1475
1476 void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
1477 {
1478         MenuItemLevel *lvl;
1479         PropertyRNA *prop;
1480
1481         prop= RNA_struct_find_property(ptr, propname);
1482         if(!prop) {
1483                 ui_item_disabled(layout, propname);
1484                 return;
1485         }
1486
1487         if(!name)
1488                 name= (char*)RNA_property_ui_name(prop);
1489         if(layout->root->type == UI_LAYOUT_MENU && !icon)
1490                 icon= ICON_BLANK1;
1491
1492         lvl= MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1493         lvl->rnapoin= *ptr;
1494         lvl->propname= propname;
1495         lvl->opcontext= layout->root->opcontext;
1496
1497         ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl);
1498 }
1499
1500 /**************************** Layout Items ***************************/
1501
1502 /* single-row layout */
1503 static void ui_litem_estimate_row(uiLayout *litem)
1504 {
1505         uiItem *item;
1506         int itemw, itemh;
1507
1508         litem->w= 0;
1509         litem->h= 0;
1510
1511         for(item=litem->items.first; item; item=item->next) {
1512                 ui_item_size(item, &itemw, &itemh);
1513
1514                 litem->w += itemw;
1515                 litem->h= MAX2(itemh, litem->h);
1516
1517                 if(item->next)
1518                         litem->w += litem->space;
1519         }
1520 }
1521
1522 static int ui_litem_min_width(int itemw)
1523 {
1524         return MIN2(2*UI_UNIT_X, itemw);
1525 }
1526
1527 static void ui_litem_layout_row(uiLayout *litem)
1528 {
1529         uiItem *item;
1530         int x, y, w, tot, totw, neww, itemw, minw, itemh, offset;
1531         int fixedw, freew, fixedx, freex, flag= 0, lastw= 0;
1532
1533         x= litem->x;
1534         y= litem->y;
1535         w= litem->w;
1536         totw= 0;
1537         tot= 0;
1538
1539         for(item=litem->items.first; item; item=item->next) {
1540                 ui_item_size(item, &itemw, &itemh);
1541                 totw += itemw;
1542                 tot++;
1543         }
1544
1545         if(totw == 0)
1546                 return;
1547         
1548         if(w != 0)
1549                 w -= (tot-1)*litem->space;
1550         fixedw= 0;
1551
1552         /* keep clamping items to fixed minimum size until all are done */
1553         do {
1554                 freew= 0;
1555                 x= 0;
1556                 flag= 0;
1557
1558                 for(item=litem->items.first; item; item=item->next) {
1559                         if(item->flag)
1560                                 continue;
1561
1562                         ui_item_size(item, &itemw, &itemh);
1563                         minw= ui_litem_min_width(itemw);
1564
1565                         if(w - lastw > 0)
1566                                 neww= ui_item_fit(itemw, x, totw, w-lastw, !item->next, litem->alignment, NULL);
1567                         else
1568                                 neww= 0; /* no space left, all will need clamping to minimum size */
1569
1570                         x += neww;
1571
1572                         if((neww < minw || itemw == minw) && w != 0) {
1573                                 /* fixed size */
1574                                 item->flag= 1;
1575                                 fixedw += minw;
1576                                 flag= 1;
1577                                 totw -= itemw;
1578                         }
1579                         else {
1580                                 /* keep free size */
1581                                 item->flag= 0;
1582                                 freew += itemw;
1583                         }
1584                 }
1585
1586                 lastw= fixedw;
1587         } while(flag);
1588
1589         freex= 0;
1590         fixedx= 0;
1591         x= litem->x;
1592
1593         for(item=litem->items.first; item; item=item->next) {
1594                 ui_item_size(item, &itemw, &itemh);
1595                 minw= ui_litem_min_width(itemw);
1596
1597                 if(item->flag) {
1598                         /* fixed minimum size items */
1599                         itemw= ui_item_fit(minw, fixedx, fixedw, MIN2(w, fixedw), !item->next, litem->alignment, NULL);
1600                         fixedx += itemw;
1601                 }
1602                 else {
1603                         /* free size item */
1604                         itemw= ui_item_fit(itemw, freex, freew, w-fixedw, !item->next, litem->alignment, NULL);
1605                         freex += itemw;
1606                 }
1607
1608                 /* align right/center */
1609                 offset= 0;
1610                 if(litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
1611                         if(freew > 0 && freew < w-fixedw)
1612                                 offset= (w - fixedw) - freew;
1613                 }
1614                 else if(litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
1615                         if(freew > 0 && freew < w-fixedw)
1616                                 offset= ((w - fixedw) - freew)/2;
1617                 }
1618
1619                 /* position item */
1620                 ui_item_position(item, x+offset, y-itemh, itemw, itemh);
1621
1622                 x += itemw;
1623                 if(item->next)
1624                         x += litem->space;
1625         }
1626
1627         litem->w= x - litem->x;
1628         litem->h= litem->y - y;
1629         litem->x= x;
1630         litem->y= y;
1631 }
1632
1633 /* single-column layout */
1634 static void ui_litem_estimate_column(uiLayout *litem)
1635 {
1636         uiItem *item;
1637         int itemw, itemh;
1638
1639         litem->w= 0;
1640         litem->h= 0;
1641
1642         for(item=litem->items.first; item; item=item->next) {
1643                 ui_item_size(item, &itemw, &itemh);
1644
1645                 litem->w= MAX2(litem->w, itemw);
1646                 litem->h += itemh;
1647
1648                 if(item->next)
1649                         litem->h += litem->space;
1650         }
1651 }
1652
1653 static void ui_litem_layout_column(uiLayout *litem)
1654 {
1655         uiItem *item;
1656         int itemh, x, y;
1657
1658         x= litem->x;
1659         y= litem->y;
1660
1661         for(item=litem->items.first; item; item=item->next) {
1662                 ui_item_size(item, NULL, &itemh);
1663
1664                 y -= itemh;
1665                 ui_item_position(item, x, y, litem->w, itemh);
1666
1667                 if(item->next)
1668                         y -= litem->space;
1669         }
1670
1671         litem->h= litem->y - y;
1672         litem->x= x;
1673         litem->y= y;
1674 }
1675
1676 /* root layout */
1677 static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
1678 {
1679         /* nothing to do */
1680 }
1681
1682 static void ui_litem_layout_root(uiLayout *litem)
1683 {
1684         if(litem->root->type == UI_LAYOUT_HEADER)
1685                 ui_litem_layout_row(litem);
1686         else
1687                 ui_litem_layout_column(litem);
1688 }
1689
1690 /* box layout */
1691 static void ui_litem_estimate_box(uiLayout *litem)
1692 {
1693         uiStyle *style= litem->root->style;
1694
1695         ui_litem_estimate_column(litem);
1696         litem->w += 2*style->boxspace;
1697         litem->h += style->boxspace;
1698 }
1699
1700 static void ui_litem_layout_box(uiLayout *litem)
1701 {
1702         uiLayoutItemBx *box= (uiLayoutItemBx*)litem;
1703         uiStyle *style= litem->root->style;
1704         uiBut *but;
1705         int w, h;
1706
1707         w= litem->w;
1708         h= litem->h;
1709
1710         litem->x += style->boxspace;
1711
1712         if(w != 0) litem->w -= 2*style->boxspace;
1713         if(h != 0) litem->h -= 2*style->boxspace;
1714
1715         ui_litem_layout_column(litem);
1716
1717         litem->x -= style->boxspace;
1718         litem->y -= style->boxspace;
1719
1720         if(w != 0) litem->w += 2*style->boxspace;
1721         if(h != 0) litem->h += style->boxspace;
1722
1723         /* roundbox around the sublayout */
1724         but= box->roundbox;
1725         but->x1= litem->x;
1726         but->y1= litem->y;
1727         but->x2= litem->x+litem->w;
1728         but->y2= litem->y+litem->h;
1729 }
1730
1731 /* multi-column layout, automatically flowing to the next */
1732 static void ui_litem_estimate_column_flow(uiLayout *litem)
1733 {
1734         uiStyle *style= litem->root->style;
1735         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1736         uiItem *item;
1737         int col, x, y, emh, emy, miny, itemw, itemh, maxw=0;
1738         int toth, totitem;
1739
1740         /* compute max needed width and total height */
1741         toth= 0;
1742         totitem= 0;
1743         for(item=litem->items.first; item; item=item->next) {
1744                 ui_item_size(item, &itemw, &itemh);
1745                 maxw= MAX2(maxw, itemw);
1746                 toth += itemh;
1747                 totitem++;
1748         }
1749
1750         if(flow->number <= 0) {
1751                 /* auto compute number of columns, not very good */
1752                 if(maxw == 0) {
1753                         flow->totcol= 1;
1754                         return;
1755                 }
1756
1757                 flow->totcol= MAX2(litem->root->emw/maxw, 1);
1758                 flow->totcol= MIN2(flow->totcol, totitem);
1759         }
1760         else
1761                 flow->totcol= flow->number;
1762
1763         /* compute sizes */
1764         x= 0;
1765         y= 0;
1766         emy= 0;
1767         miny= 0;
1768
1769         maxw= 0;
1770         emh= toth/flow->totcol;
1771
1772         /* create column per column */
1773         col= 0;
1774         for(item=litem->items.first; item; item=item->next) {
1775                 ui_item_size(item, &itemw, &itemh);
1776
1777                 y -= itemh + style->buttonspacey;
1778                 miny= MIN2(miny, y);
1779                 emy -= itemh;
1780                 maxw= MAX2(itemw, maxw);
1781
1782                 /* decide to go to next one */
1783                 if(col < flow->totcol-1 && emy <= -emh) {
1784                         x += maxw + litem->space;
1785                         maxw= 0;
1786                         y= 0;
1787                         col++;
1788                 }
1789         }
1790
1791         litem->w= x;
1792         litem->h= litem->y - miny;
1793 }
1794
1795 static void ui_litem_layout_column_flow(uiLayout *litem)
1796 {
1797         uiStyle *style= litem->root->style;
1798         uiLayoutItemFlow *flow= (uiLayoutItemFlow*)litem;
1799         uiItem *item;
1800         int col, x, y, w, emh, emy, miny, itemw, itemh;
1801         int toth, totitem, offset;
1802
1803         /* compute max needed width and total height */
1804         toth= 0;
1805         totitem= 0;
1806         for(item=litem->items.first; item; item=item->next) {
1807                 ui_item_size(item, &itemw, &itemh);
1808                 toth += itemh;
1809                 totitem++;
1810         }
1811
1812         /* compute sizes */
1813         x= litem->x;
1814         y= litem->y;
1815         emy= 0;
1816         miny= 0;
1817
1818         w= litem->w - (flow->totcol-1)*style->columnspace;
1819         emh= toth/flow->totcol;
1820
1821         /* create column per column */
1822         col= 0;
1823         for(item=litem->items.first; item; item=item->next) {
1824                 ui_item_size(item, NULL, &itemh);
1825                 itemw= ui_item_fit(1, x-litem->x, flow->totcol, w, col == flow->totcol-1, litem->alignment, &offset);
1826         
1827                 y -= itemh;
1828                 emy -= itemh;
1829                 ui_item_position(item, x+offset, y, itemw, itemh);
1830                 y -= style->buttonspacey;
1831                 miny= MIN2(miny, y);
1832
1833                 /* decide to go to next one */
1834                 if(col < flow->totcol-1 && emy <= -emh) {
1835                         x += itemw + style->columnspace;
1836                         y= litem->y;
1837                         col++;
1838                 }
1839         }
1840
1841         litem->h= litem->y - miny;
1842         litem->x= x;
1843         litem->y= miny;
1844 }
1845
1846 /* free layout */
1847 static void ui_litem_estimate_absolute(uiLayout *litem)
1848 {
1849         uiItem *item;
1850         int itemx, itemy, itemw, itemh, minx, miny;
1851
1852         minx= 1e6;
1853         miny= 1e6;
1854         litem->w= 0;
1855         litem->h= 0;
1856
1857         for(item=litem->items.first; item; item=item->next) {
1858                 ui_item_offset(item, &itemx, &itemy);
1859                 ui_item_size(item, &itemw, &itemh);
1860
1861                 minx= MIN2(minx, itemx);
1862                 miny= MIN2(miny, itemy);
1863
1864                 litem->w= MAX2(litem->w, itemx+itemw);
1865                 litem->h= MAX2(litem->h, itemy+itemh);
1866         }
1867
1868         litem->w -= minx;
1869         litem->h -= miny;
1870 }
1871
1872 static void ui_litem_layout_absolute(uiLayout *litem)
1873 {
1874         uiItem *item;
1875         float scalex=1.0f, scaley=1.0f;
1876         int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
1877
1878         minx= 1e6;
1879         miny= 1e6;
1880         totw= 0;
1881         toth= 0;
1882
1883         for(item=litem->items.first; item; item=item->next) {
1884                 ui_item_offset(item, &itemx, &itemy);
1885                 ui_item_size(item, &itemw, &itemh);
1886
1887                 minx= MIN2(minx, itemx);
1888                 miny= MIN2(miny, itemy);
1889
1890                 totw= MAX2(totw, itemx+itemw);
1891                 toth= MAX2(toth, itemy+itemh);
1892         }
1893
1894         totw -= minx;
1895         toth -= miny;
1896
1897         if(litem->w && totw > 0)
1898                 scalex= (float)litem->w/(float)totw;
1899         if(litem->h && toth > 0)
1900                 scaley= (float)litem->h/(float)toth;
1901         
1902         x= litem->x;
1903         y= litem->y - scaley*toth;
1904
1905         for(item=litem->items.first; item; item=item->next) {
1906                 ui_item_offset(item, &itemx, &itemy);
1907                 ui_item_size(item, &itemw, &itemh);
1908
1909                 if(scalex != 1.0f) {
1910                         newx= (itemx - minx)*scalex;
1911                         itemw= (itemx - minx + itemw)*scalex - newx;
1912                         itemx= minx + newx;
1913                 }
1914
1915                 if(scaley != 1.0f) {
1916                         newy= (itemy - miny)*scaley;
1917                         itemh= (itemy - miny + itemh)*scaley - newy;
1918                         itemy= miny + newy;
1919                 }
1920
1921                 ui_item_position(item, x+itemx-minx, y+itemy-miny, itemw, itemh);
1922         }
1923
1924         litem->w= scalex*totw;
1925         litem->h= litem->y - y;
1926         litem->x= x + litem->w;
1927         litem->y= y;
1928 }
1929
1930 /* split layout */
1931 static void ui_litem_estimate_split(uiLayout *litem)
1932 {
1933         ui_litem_estimate_row(litem);
1934 }
1935
1936 static void ui_litem_layout_split(uiLayout *litem)
1937 {
1938         uiLayoutItemSplt *split= (uiLayoutItemSplt*)litem;
1939         uiItem *item;
1940         float percentage;
1941         int itemh, x, y, w, tot=0, colw=0;
1942
1943         x= litem->x;
1944         y= litem->y;
1945
1946         for(item=litem->items.first; item; item=item->next)
1947                 tot++;
1948         
1949         if(tot == 0)
1950                 return;
1951         
1952         percentage= (split->percentage == 0.0f)? 1.0f/(float)tot: split->percentage;
1953         
1954         w= (litem->w - (tot-1)*litem->space);
1955         colw= w*percentage;
1956         colw= MAX2(colw, 0);
1957
1958         for(item=litem->items.first; item; item=item->next) {
1959                 ui_item_size(item, NULL, &itemh);
1960
1961                 ui_item_position(item, x, y-itemh, colw, itemh);
1962                 x += colw;
1963
1964                 if(item->next) {
1965                         colw= (w - (int)(w*percentage))/(tot-1);
1966                         colw= MAX2(colw, 0);
1967
1968                         x += litem->space;
1969                 }
1970         }
1971
1972         litem->w= x - litem->x;
1973         litem->h= litem->y - y;
1974         litem->x= x;
1975         litem->y= y;
1976 }
1977
1978 /* overlap layout */
1979 static void ui_litem_estimate_overlap(uiLayout *litem)
1980 {
1981         uiItem *item;
1982         int itemw, itemh;
1983
1984         litem->w= 0;
1985         litem->h= 0;
1986
1987         for(item=litem->items.first; item; item=item->next) {
1988                 ui_item_size(item, &itemw, &itemh);
1989
1990                 litem->w= MAX2(itemw, litem->w);
1991                 litem->h= MAX2(itemh, litem->h);
1992         }
1993 }
1994
1995 static void ui_litem_layout_overlap(uiLayout *litem)
1996 {
1997         uiItem *item;
1998         int itemw, itemh, x, y;
1999
2000         x= litem->x;
2001         y= litem->y;
2002
2003         for(item=litem->items.first; item; item=item->next) {
2004                 ui_item_size(item, &itemw, &itemh);
2005                 ui_item_position(item, x, y-itemh, litem->w, itemh);
2006
2007                 litem->h= MAX2(litem->h, itemh);
2008         }
2009
2010         litem->x= x;
2011         litem->y= y - litem->h;
2012 }
2013
2014 /* layout create functions */
2015 uiLayout *uiLayoutRow(uiLayout *layout, int align)
2016 {
2017         uiLayout *litem;
2018
2019         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
2020         litem->item.type= ITEM_LAYOUT_ROW;
2021         litem->root= layout->root;
2022         litem->align= align;
2023         litem->active= 1;
2024         litem->enabled= 1;
2025         litem->context= layout->context;
2026         litem->space= (align)? 0: layout->root->style->buttonspacex;
2027         litem->w = layout->w;
2028         BLI_addtail(&layout->items, litem);
2029
2030         uiBlockSetCurLayout(layout->root->block, litem);
2031
2032         return litem;
2033 }
2034
2035 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
2036 {
2037         uiLayout *litem;
2038
2039         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
2040         litem->item.type= ITEM_LAYOUT_COLUMN;
2041         litem->root= layout->root;
2042         litem->align= align;
2043         litem->active= 1;
2044         litem->enabled= 1;
2045         litem->context= layout->context;
2046         litem->space= (litem->align)? 0: layout->root->style->buttonspacey;
2047         litem->w = layout->w;
2048         BLI_addtail(&layout->items, litem);
2049
2050         uiBlockSetCurLayout(layout->root->block, litem);
2051
2052         return litem;
2053 }
2054
2055 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
2056 {
2057         uiLayoutItemFlow *flow;
2058
2059         flow= MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
2060         flow->litem.item.type= ITEM_LAYOUT_COLUMN_FLOW;
2061         flow->litem.root= layout->root;
2062         flow->litem.align= align;
2063         flow->litem.active= 1;
2064         flow->litem.enabled= 1;
2065         flow->litem.context= layout->context;
2066         flow->litem.space= (flow->litem.align)? 0: layout->root->style->columnspace;
2067         flow->litem.w = layout->w;
2068         flow->number= number;
2069         BLI_addtail(&layout->items, flow);
2070
2071         uiBlockSetCurLayout(layout->root->block, &flow->litem);
2072
2073         return &flow->litem;
2074 }
2075
2076 static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
2077 {
2078         uiLayoutItemBx *box;
2079
2080         box= MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
2081         box->litem.item.type= ITEM_LAYOUT_BOX;
2082         box->litem.root= layout->root;
2083         box->litem.active= 1;
2084         box->litem.enabled= 1;
2085         box->litem.context= layout->context;
2086         box->litem.space= layout->root->style->columnspace;
2087         box->litem.w = layout->w;
2088         BLI_addtail(&layout->items, box);
2089
2090         uiBlockSetCurLayout(layout->root->block, &box->litem);
2091
2092         box->roundbox= uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
2093
2094         return box;
2095 }
2096
2097 uiLayout *uiLayoutBox(uiLayout *layout)
2098 {
2099         return (uiLayout*)ui_layout_box(layout, ROUNDBOX);
2100 }
2101
2102 uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
2103 {
2104         uiLayoutItemBx *box= ui_layout_box(layout, LISTBOX);
2105         uiBut *but= box->roundbox;
2106
2107         but->rnasearchpoin= *ptr;
2108         but->rnasearchprop= prop;
2109         but->rnapoin= *actptr;
2110         but->rnaprop= actprop;
2111
2112         return (uiLayout*)box;
2113 }
2114
2115 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
2116 {
2117         uiLayout *litem;
2118
2119         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
2120         litem->item.type= ITEM_LAYOUT_ABSOLUTE;
2121         litem->root= layout->root;
2122         litem->align= align;
2123         litem->active= 1;
2124         litem->enabled= 1;
2125         litem->context= layout->context;
2126         BLI_addtail(&layout->items, litem);
2127
2128         uiBlockSetCurLayout(layout->root->block, litem);
2129
2130         return litem;
2131 }
2132
2133 uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout)
2134 {
2135         uiBlock *block;
2136
2137         block= uiLayoutGetBlock(layout);
2138         uiLayoutAbsolute(layout, 0);
2139
2140         return block;
2141 }
2142
2143 uiLayout *uiLayoutOverlap(uiLayout *layout)
2144 {
2145         uiLayout *litem;
2146
2147         litem= MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
2148         litem->item.type= ITEM_LAYOUT_OVERLAP;
2149         litem->root= layout->root;
2150         litem->active= 1;
2151         litem->enabled= 1;
2152         litem->context= layout->context;
2153         BLI_addtail(&layout->items, litem);
2154
2155         uiBlockSetCurLayout(layout->root->block, litem);
2156
2157         return litem;
2158 }
2159
2160 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
2161 {
2162         uiLayoutItemSplt *split;
2163
2164         split= MEM_callocN(sizeof(uiLayoutItemSplt), "uiLayoutItemSplt");
2165         split->litem.item.type= ITEM_LAYOUT_SPLIT;
2166         split->litem.root= layout->root;
2167         split->litem.align= align;
2168         split->litem.active= 1;
2169         split->litem.enabled= 1;
2170         split->litem.context= layout->context;
2171         split->litem.space= layout->root->style->columnspace;
2172         split->litem.w= layout->w;
2173         split->percentage= percentage;
2174         BLI_addtail(&layout->items, split);
2175
2176         uiBlockSetCurLayout(layout->root->block, &split->litem);
2177
2178         return &split->litem;
2179 }
2180
2181 void uiLayoutSetActive(uiLayout *layout, int active)
2182 {
2183         layout->active= active;
2184 }
2185
2186 void uiLayoutSetEnabled(uiLayout *layout, int enabled)
2187 {
2188         layout->enabled= enabled;
2189 }
2190
2191 void uiLayoutSetRedAlert(uiLayout *layout, int redalert)
2192 {
2193         layout->redalert= redalert;
2194 }
2195
2196 void uiLayoutSetKeepAspect(uiLayout *layout, int keepaspect)
2197 {
2198         layout->keepaspect= keepaspect;
2199 }
2200
2201 void uiLayoutSetAlignment(uiLayout *layout, int alignment)
2202 {
2203         layout->alignment= alignment;
2204 }
2205
2206 void uiLayoutSetScaleX(uiLayout *layout, float scale)
2207 {
2208         layout->scale[0]= scale;
2209 }
2210
2211 void uiLayoutSetScaleY(uiLayout *layout, float scale)
2212 {
2213         layout->scale[1]= scale;
2214 }
2215
2216 int uiLayoutGetActive(uiLayout *layout)
2217 {
2218         return layout->active;
2219 }
2220
2221 int uiLayoutGetEnabled(uiLayout *layout)
2222 {
2223         return layout->enabled;
2224 }
2225
2226 int uiLayoutGetRedAlert(uiLayout *layout)
2227 {
2228         return layout->redalert;
2229 }
2230
2231 int uiLayoutGetKeepAspect(uiLayout *layout)
2232 {
2233         return layout->keepaspect;
2234 }
2235
2236 int uiLayoutGetAlignment(uiLayout *layout)
2237 {
2238         return layout->alignment;
2239 }
2240
2241 int uiLayoutGetWidth(uiLayout *layout)
2242 {
2243         return layout->w;
2244 }
2245
2246 float uiLayoutGetScaleX(uiLayout *layout)
2247 {
2248         return layout->scale[0];
2249 }
2250
2251 float uiLayoutGetScaleY(uiLayout *layout)
2252 {
2253         return layout->scale[0];
2254 }
2255
2256 /********************** Layout *******************/
2257
2258 static void ui_item_scale(uiLayout *litem, float scale[2])
2259 {
2260         uiItem *item;
2261         int x, y, w, h;
2262
2263         for(item=litem->items.last; item; item=item->prev) {
2264                 ui_item_size(item, &w, &h);
2265                 ui_item_offset(item, &x, &y);
2266
2267                 if(scale[0] != 0.0f) {
2268                         x *= scale[0];
2269                         w *= scale[0];
2270                 }
2271
2272                 if(scale[1] != 0.0f) {
2273                         y *= scale[1];
2274                         h *= scale[1];
2275                 }
2276
2277                 ui_item_position(item, x, y, w, h);
2278         }
2279 }
2280
2281 static void ui_item_estimate(uiItem *item)
2282 {
2283         uiItem *subitem;
2284
2285         if(item->type != ITEM_BUTTON) {
2286                 uiLayout *litem= (uiLayout*)item;
2287
2288                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2289                         ui_item_estimate(subitem);
2290
2291                 if(litem->items.first == NULL)
2292                         return;
2293
2294                 if(litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
2295                         ui_item_scale(litem, litem->scale);
2296
2297                 switch(litem->item.type) {
2298                         case ITEM_LAYOUT_COLUMN:
2299                                 ui_litem_estimate_column(litem);
2300                                 break;
2301                         case ITEM_LAYOUT_COLUMN_FLOW:
2302                                 ui_litem_estimate_column_flow(litem);
2303                                 break;
2304                         case ITEM_LAYOUT_ROW:
2305                                 ui_litem_estimate_row(litem);
2306                                 break;
2307                         case ITEM_LAYOUT_BOX:
2308                                 ui_litem_estimate_box(litem);
2309                                 break;
2310                         case ITEM_LAYOUT_ROOT:
2311                                 ui_litem_estimate_root(litem);
2312                                 break;
2313                         case ITEM_LAYOUT_ABSOLUTE:
2314                                 ui_litem_estimate_absolute(litem);
2315                                 break;
2316                         case ITEM_LAYOUT_SPLIT:
2317                                 ui_litem_estimate_split(litem);
2318                                 break;
2319                         case ITEM_LAYOUT_OVERLAP:
2320                                 ui_litem_estimate_overlap(litem);
2321                                 break;
2322                         default:
2323                                 break;
2324                 }
2325         }
2326 }
2327
2328 static void ui_item_align(uiLayout *litem, int nr)
2329 {
2330         uiItem *item;
2331         uiButtonItem *bitem;
2332         uiLayoutItemBx *box;
2333
2334         for(item=litem->items.last; item; item=item->prev) {
2335                 if(item->type == ITEM_BUTTON) {
2336                         bitem= (uiButtonItem*)item;
2337                         if(ui_but_can_align(bitem->but))
2338                                 if(!bitem->but->alignnr)
2339                                         bitem->but->alignnr= nr;
2340                 }
2341                 else if(item->type == ITEM_LAYOUT_ABSOLUTE);
2342                 else if(item->type == ITEM_LAYOUT_OVERLAP);
2343                 else if(item->type == ITEM_LAYOUT_BOX) {
2344                         box= (uiLayoutItemBx*)item;
2345                         box->roundbox->alignnr= nr;
2346                         BLI_remlink(&litem->root->block->buttons, box->roundbox);
2347                         BLI_addhead(&litem->root->block->buttons, box->roundbox);
2348                 }
2349                 else
2350                         ui_item_align((uiLayout*)item, nr);
2351         }
2352 }
2353
2354 static void ui_item_flag(uiLayout *litem, int flag)
2355 {
2356         uiItem *item;
2357         uiButtonItem *bitem;
2358
2359         for(item=litem->items.last; item; item=item->prev) {
2360                 if(item->type == ITEM_BUTTON) {
2361                         bitem= (uiButtonItem*)item;
2362                         bitem->but->flag |= flag;
2363                 }
2364                 else
2365                         ui_item_flag((uiLayout*)item, flag);
2366         }
2367 }
2368
2369 static void ui_item_layout(uiItem *item)
2370 {
2371         uiItem *subitem;
2372
2373         if(item->type != ITEM_BUTTON) {
2374                 uiLayout *litem= (uiLayout*)item;
2375
2376                 if(litem->items.first == NULL)
2377                         return;
2378
2379                 if(litem->align)
2380                         ui_item_align(litem, ++litem->root->block->alignnr);
2381                 if(!litem->active)
2382                         ui_item_flag(litem, UI_BUT_INACTIVE);
2383                 if(!litem->enabled)
2384                         ui_item_flag(litem, UI_BUT_DISABLED);
2385
2386                 switch(litem->item.type) {
2387                         case ITEM_LAYOUT_COLUMN:
2388                                 ui_litem_layout_column(litem);
2389                                 break;
2390                         case ITEM_LAYOUT_COLUMN_FLOW:
2391                                 ui_litem_layout_column_flow(litem);
2392                                 break;
2393                         case ITEM_LAYOUT_ROW:
2394                                 ui_litem_layout_row(litem);
2395                                 break;
2396                         case ITEM_LAYOUT_BOX:
2397                                 ui_litem_layout_box(litem);
2398                                 break;
2399                         case ITEM_LAYOUT_ROOT:
2400                                 ui_litem_layout_root(litem);
2401                                 break;
2402                         case ITEM_LAYOUT_ABSOLUTE:
2403                                 ui_litem_layout_absolute(litem);
2404                                 break;
2405                         case ITEM_LAYOUT_SPLIT:
2406                                 ui_litem_layout_split(litem);
2407                                 break;
2408                         case ITEM_LAYOUT_OVERLAP:
2409                                 ui_litem_layout_overlap(litem);
2410                                 break;
2411                         default:
2412                                 break;
2413                 }
2414
2415                 for(subitem=litem->items.first; subitem; subitem=subitem->next)
2416                         ui_item_layout(subitem);
2417         }
2418 }
2419
2420 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
2421 {
2422         if(layout->root->handlefunc)
2423                 uiBlockSetButmFunc(block, layout->root->handlefunc, layout->root->argv);
2424
2425         ui_item_estimate(&layout->item);
2426         ui_item_layout(&layout->item);
2427
2428         if(x) *x= layout->x;
2429         if(y) *y= layout->y;
2430 }
2431
2432 static void ui_layout_free(uiLayout *layout)
2433 {
2434         uiItem *item, *next;
2435
2436         for(item=layout->items.first; item; item=next) {
2437                 next= item->next;
2438
2439                 if(item->type == ITEM_BUTTON)
2440                         MEM_freeN(item);
2441                 else
2442                         ui_layout_free((uiLayout*)item);
2443         }
2444
2445         MEM_freeN(layout);
2446 }
2447
2448 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
2449 {
2450         uiLayout *layout;
2451         uiLayoutRoot *root;
2452
2453         root= MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
2454         root->type= type;
2455         root->style= style;
2456         root->block= block;
2457         root->opcontext= WM_OP_INVOKE_REGION_WIN;
2458
2459         layout= MEM_callocN(sizeof(uiLayout), "uiLayout");
2460         layout->item.type= ITEM_LAYOUT_ROOT;
2461
2462         layout->x= x;
2463         layout->y= y;
2464         layout->root= root;
2465         layout->space= style->templatespace;
2466         layout->active= 1;
2467         layout->enabled= 1;
2468         layout->context= NULL;
2469
2470         if(type == UI_LAYOUT_MENU)
2471                 layout->space= 0;
2472
2473         if(dir == UI_LAYOUT_HORIZONTAL) {
2474                 layout->h= size;
2475                 layout->root->emh= em*UI_UNIT_Y;
2476         }
2477         else {
2478                 layout->w= size;
2479                 layout->root->emw= em*UI_UNIT_X;
2480         }
2481
2482         block->curlayout= layout;
2483         root->layout= layout;
2484         BLI_addtail(&block->layouts, root);
2485         
2486         return layout;
2487 }
2488
2489 uiBlock *uiLayoutGetBlock(uiLayout *layout)
2490 {
2491         return layout->root->block;
2492 }
2493
2494 int uiLayoutGetOperatorContext(uiLayout *layout)
2495 {
2496         return layout->root->opcontext;
2497 }
2498
2499
2500 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
2501 {
2502         block->curlayout= layout;
2503 }
2504
2505 void ui_layout_add_but(uiLayout *layout, uiBut *but)
2506 {
2507         uiButtonItem *bitem;
2508         
2509         bitem= MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
2510         bitem->item.type= ITEM_BUTTON;
2511         bitem->but= but;
2512         BLI_addtail(&layout->items, bitem);
2513
2514         if(layout->context) {
2515                 but->context= layout->context;
2516                 but->context->used= 1;
2517         }
2518 }
2519
2520 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
2521 {
2522         layout->root->opcontext= opcontext;
2523 }
2524
2525 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
2526 {
2527         layout->root->handlefunc= handlefunc;
2528         layout->root->argv= argv;
2529 }
2530
2531 void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
2532 {
2533         uiLayoutRoot *root;
2534
2535         if(x) *x= 0;
2536         if(y) *y= 0;
2537
2538         block->curlayout= NULL;
2539
2540         for(root=block->layouts.first; root; root=root->next) {
2541                 /* NULL in advance so we don't interfere when adding button */
2542                 ui_layout_end(block, root->layout, x, y);
2543                 ui_layout_free(root->layout);
2544         }
2545
2546         BLI_freelistN(&block->layouts);
2547
2548         /* XXX silly trick, interface_templates.c doesn't get linked
2549          * because it's not used by other files in this module? */
2550         {
2551                 void ui_template_fix_linking(void);
2552                 ui_template_fix_linking();
2553         }
2554 }
2555
2556 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
2557 {
2558         uiBlock *block= layout->root->block;
2559         layout->context= CTX_store_add(&block->contexts, name, ptr);
2560 }
2561
2562
2563 /* introspect funcs */
2564 #include "BLI_dynstr.h"
2565
2566 static void ui_intro_button(DynStr *ds, uiButtonItem *bitem)
2567 {
2568         uiBut *but = bitem->but;
2569         BLI_dynstr_appendf(ds, "'type':%d, ", but->type); /* see ~ UI_interface.h:200 */
2570         BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
2571         BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : ""); // not exactly needed, rna has this
2572
2573         if(but->optype) {
2574                 char *opstr = WM_operator_pystring(but->block->evil_C, but->optype, but->opptr, 0);
2575                 BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
2576                 MEM_freeN(opstr);
2577         }
2578
2579         if(but->rnaprop) {
2580                 BLI_dynstr_appendf(ds, "'rna':'%s.%s[%d]', ", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop), but->rnaindex);
2581         }
2582
2583 }
2584
2585 static void ui_intro_items(DynStr *ds, ListBase *lb)
2586 {
2587         uiItem *item;
2588
2589         BLI_dynstr_append(ds, "[");
2590
2591         for(item=lb->first; item; item=item->next) {
2592
2593                 BLI_dynstr_append(ds, "{");
2594
2595                 /* could also use the INT but this is nicer*/
2596                 switch(item->type) {
2597                 case ITEM_BUTTON:                       BLI_dynstr_append(ds, "'type':'BUTTON', ");break;
2598                 case ITEM_LAYOUT_ROW:           BLI_dynstr_append(ds, "'type':'ROW', "); break;
2599                 case ITEM_LAYOUT_COLUMN:        BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
2600                 case ITEM_LAYOUT_COLUMN_FLOW:BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
2601                 case ITEM_LAYOUT_ROW_FLOW:      BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
2602                 case ITEM_LAYOUT_BOX:           BLI_dynstr_append(ds, "'type':'BOX', "); break;
2603                 case ITEM_LAYOUT_ABSOLUTE:      BLI_dynstr_append(ds, "'type':'ABSOLUTE', "); break;
2604                 case ITEM_LAYOUT_SPLIT:         BLI_dynstr_append(ds, "'type':'SPLIT', "); break;
2605                 case ITEM_LAYOUT_OVERLAP:       BLI_dynstr_append(ds, "'type':'OVERLAP', "); break;
2606                 case ITEM_LAYOUT_ROOT:          BLI_dynstr_append(ds, "'type':'ROOT', "); break;
2607                 default:                                        BLI_dynstr_append(ds, "'type':'UNKNOWN', "); break;
2608                 }
2609
2610                 switch(item->type) {
2611                 case ITEM_BUTTON:
2612                         ui_intro_button(ds, (uiButtonItem *)item);
2613                         break;
2614                 default:
2615                         BLI_dynstr_append(ds, "'items':");
2616                         ui_intro_items(ds, &((uiLayout*)item)->items);
2617                         break;
2618                 }
2619
2620                 BLI_dynstr_append(ds, "}");
2621
2622                 if(item != lb->last)
2623                         BLI_dynstr_append(ds, ", ");
2624         }
2625         BLI_dynstr_append(ds, "], ");
2626 }
2627
2628 static void ui_intro_uiLayout(DynStr *ds, uiLayout *layout)
2629 {
2630         ui_intro_items(ds, &layout->items);
2631 }
2632
2633 static char *str = NULL; // XXX, constant re-freeing, far from ideal.
2634 const char *uiLayoutIntrospect(uiLayout *layout)
2635 {
2636         DynStr *ds= BLI_dynstr_new();
2637
2638         if(str)
2639                 MEM_freeN(str);
2640
2641         ui_intro_uiLayout(ds, layout);
2642
2643         str = BLI_dynstr_get_cstring(ds);
2644         BLI_dynstr_free(ds);
2645
2646         return str;
2647 }