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