RNA API: use bool's for enum itemf callbacks.
[blender.git] / source / blender / editors / interface / interface_layout.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation 2009.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/interface/interface_layout.c
24  *  \ingroup edinterface
25  */
26
27
28 #include <limits.h>
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_screen_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_userdef_types.h"
39
40 #include "BLI_listbase.h"
41 #include "BLI_string.h"
42 #include "BLI_rect.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_math.h"
45
46 #include "BLF_translation.h"
47
48 #include "BKE_context.h"
49 #include "BKE_global.h"
50 #include "BKE_idprop.h"
51 #include "BKE_screen.h"
52
53 #include "RNA_access.h"
54
55 #include "UI_interface.h"
56
57 #include "ED_armature.h"
58
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "interface_intern.h"
64
65 /************************ Structs and Defines *************************/
66
67 // #define USE_OP_RESET_BUT  // we may want to make this optional, disable for now.
68
69 #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement)                 \
70         if (ot == NULL) {                                                         \
71                 ui_item_disabled(layout, _opname);                                    \
72                 RNA_warning("'%s' unknown operator", _opname);                        \
73                 return_statement;                                                     \
74         } (void)0                                                                 \
75
76
77 /* uiLayoutRoot */
78
79 typedef struct uiLayoutRoot {
80         struct uiLayoutRoot *next, *prev;
81
82         int type;
83         int opcontext;
84
85         int emw, emh;
86
87         uiMenuHandleFunc handlefunc;
88         void *argv;
89
90         uiStyle *style;
91         uiBlock *block;
92         uiLayout *layout;
93 } uiLayoutRoot;
94
95 /* Item */
96
97 typedef enum uiItemType {
98         ITEM_BUTTON,
99
100         ITEM_LAYOUT_ROW,
101         ITEM_LAYOUT_COLUMN,
102         ITEM_LAYOUT_COLUMN_FLOW,
103         ITEM_LAYOUT_ROW_FLOW,
104         ITEM_LAYOUT_BOX,
105         ITEM_LAYOUT_ABSOLUTE,
106         ITEM_LAYOUT_SPLIT,
107         ITEM_LAYOUT_OVERLAP,
108
109         ITEM_LAYOUT_ROOT
110 #if 0
111         TEMPLATE_COLUMN_FLOW,
112         TEMPLATE_SPLIT,
113         TEMPLATE_BOX,
114
115         TEMPLATE_HEADER,
116         TEMPLATE_HEADER_ID
117 #endif
118 } uiItemType;
119
120 typedef struct uiItem {
121         void *next, *prev;
122         uiItemType type;
123         int flag;
124 } uiItem;
125
126 typedef struct uiButtonItem {
127         uiItem item;
128         uiBut *but;
129 } uiButtonItem;
130
131 struct uiLayout {
132         uiItem item;
133
134         uiLayoutRoot *root;
135         bContextStore *context;
136         ListBase items;
137
138         int x, y, w, h;
139         float scale[2];
140         short space;
141         bool align;
142         bool active;
143         bool enabled;
144         bool redalert;
145         bool keepaspect;
146         char alignment;
147 };
148
149 typedef struct uiLayoutItemFlow {
150         uiLayout litem;
151         int number;
152         int totcol;
153 } uiLayoutItemFlow;
154
155 typedef struct uiLayoutItemBx {
156         uiLayout litem;
157         uiBut *roundbox;
158 } uiLayoutItemBx;
159
160 typedef struct uiLayoutItemSplit {
161         uiLayout litem;
162         float percentage;
163 } uiLayoutItemSplit;
164
165 typedef struct uiLayoutItemRoot {
166         uiLayout litem;
167 } uiLayoutItemRoot;
168
169 /************************** Item ***************************/
170
171 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
172 {
173         int len = strlen(name);
174
175         if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
176                 BLI_strncpy(namestr, name, UI_MAX_NAME_STR);
177                 namestr[len] = ':';
178                 namestr[len + 1] = '\0';
179                 return namestr;
180         }
181
182         return name;
183 }
184
185 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
186 {
187         if (offset)
188                 *offset = 0;
189
190         /* available == 0 is unlimited */
191         if (available == 0)
192                 return item;
193
194         if (all > available) {
195                 /* contents is bigger than available space */
196                 if (last)
197                         return available - pos;
198                 else
199                         return (item * available) / all;
200         }
201         else {
202                 /* contents is smaller or equal to available space */
203                 if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
204                         if (last)
205                                 return available - pos;
206                         else
207                                 return (item * available) / all;
208                 }
209                 else
210                         return item;
211         }
212 }
213
214 /* variable button size in which direction? */
215 #define UI_ITEM_VARY_X  1
216 #define UI_ITEM_VARY_Y  2
217
218 static int ui_layout_vary_direction(uiLayout *layout)
219 {
220         return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y;
221 }
222
223 /* estimated size of text + icon */
224 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, int compact)
225 {
226         float f5 = 0.25f * UI_UNIT_X;
227         float f10 = 0.5f * UI_UNIT_X;
228         int variable = ui_layout_vary_direction(layout) == UI_ITEM_VARY_X;
229
230         if (icon && !name[0])
231                 return UI_UNIT_X;  /* icon only */
232         else if (icon)
233                 return (variable) ? UI_GetStringWidth(name) + (compact ? f5 : f10) + UI_UNIT_X : 10 * UI_UNIT_X;  /* icon + text */
234         else
235                 return (variable) ? UI_GetStringWidth(name) + (compact ? f5 : f10) + UI_UNIT_X : 10 * UI_UNIT_X;  /* text only */
236 }
237
238 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
239 {
240         if (item->type == ITEM_BUTTON) {
241                 uiButtonItem *bitem = (uiButtonItem *)item;
242
243                 if (r_w) *r_w = BLI_rctf_size_x(&bitem->but->rect);
244                 if (r_h) *r_h = BLI_rctf_size_y(&bitem->but->rect);
245         }
246         else {
247                 uiLayout *litem = (uiLayout *)item;
248
249                 if (r_w) *r_w = litem->w;
250                 if (r_h) *r_h = litem->h;
251         }
252 }
253
254 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
255 {
256         if (item->type == ITEM_BUTTON) {
257                 uiButtonItem *bitem = (uiButtonItem *)item;
258
259                 if (r_x) *r_x = bitem->but->rect.xmin;
260                 if (r_y) *r_y = bitem->but->rect.ymin;
261         }
262         else {
263                 if (r_x) *r_x = 0;
264                 if (r_y) *r_y = 0;
265         }
266 }
267
268 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
269 {
270         if (item->type == ITEM_BUTTON) {
271                 uiButtonItem *bitem = (uiButtonItem *)item;
272
273                 bitem->but->rect.xmin = x;
274                 bitem->but->rect.ymin = y;
275                 bitem->but->rect.xmax = x + w;
276                 bitem->but->rect.ymax = y + h;
277                 
278                 ui_check_but(bitem->but); /* for strlen */
279         }
280         else {
281                 uiLayout *litem = (uiLayout *)item;
282
283                 litem->x = x;
284                 litem->y = y + h;
285                 litem->w = w;
286                 litem->h = h;
287         }
288 }
289
290 /******************** Special RNA Items *********************/
291
292 static int ui_layout_local_dir(uiLayout *layout)
293 {
294         switch (layout->item.type) {
295                 case ITEM_LAYOUT_ROW:
296                 case ITEM_LAYOUT_ROOT:
297                 case ITEM_LAYOUT_OVERLAP:
298                         return UI_LAYOUT_HORIZONTAL;
299                 case ITEM_LAYOUT_COLUMN:
300                 case ITEM_LAYOUT_COLUMN_FLOW:
301                 case ITEM_LAYOUT_SPLIT:
302                 case ITEM_LAYOUT_ABSOLUTE:
303                 case ITEM_LAYOUT_BOX:
304                 default:
305                         return UI_LAYOUT_VERTICAL;
306         }
307 }
308
309 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, int align)
310 {
311         uiLayout *sub;
312
313         if (ui_layout_local_dir(test) == UI_LAYOUT_HORIZONTAL)
314                 sub = uiLayoutRow(layout, align);
315         else
316                 sub = uiLayoutColumn(layout, align);
317         
318         sub->space = 0;
319         return sub;
320 }
321
322 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
323 {
324         wmWindow *win = CTX_wm_window(C);
325         uiBut *but = arg_but, *cbut;
326         PointerRNA *ptr = &but->rnapoin;
327         PropertyRNA *prop = but->rnaprop;
328         int i, index = GET_INT_FROM_POINTER(arg_index);
329         int shift = win->eventstate->shift;
330         int len = RNA_property_array_length(ptr, prop);
331
332         if (!shift) {
333                 RNA_property_boolean_set_index(ptr, prop, index, true);
334
335                 for (i = 0; i < len; i++)
336                         if (i != index)
337                                 RNA_property_boolean_set_index(ptr, prop, i, 0);
338
339                 RNA_property_update(C, ptr, prop);
340
341                 for (cbut = but->block->buttons.first; cbut; cbut = cbut->next)
342                         ui_check_but(cbut);
343         }
344 }
345
346 /* create buttons for an item with an RNA array */
347 static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon,
348                           PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
349                           int expand, int slider, int toggle, int icon_only)
350 {
351         uiStyle *style = layout->root->style;
352         uiBut *but;
353         PropertyType type;
354         PropertySubType subtype;
355         uiLayout *sub;
356         unsigned int a, b;
357
358         /* retrieve type and subtype */
359         type = RNA_property_type(prop);
360         subtype = RNA_property_subtype(prop);
361
362         sub = ui_item_local_sublayout(layout, layout, 1);
363         uiBlockSetCurLayout(block, sub);
364
365         /* create label */
366         if (name[0])
367                 uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
368
369         /* create buttons */
370         if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
371                 /* special check for layer layout */
372                 int butw, buth, unit;
373                 int cols = (len >= 20) ? 2 : 1;
374                 const unsigned int colbuts = len / (2 * cols);
375                 unsigned int layer_used = 0;
376                 unsigned int layer_active = 0;
377
378                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, false));
379
380                 unit = UI_UNIT_X * 0.75;
381                 butw = unit;
382                 buth = unit;
383
384                 if (ptr->type == &RNA_Armature) {
385                         bArmature *arm = (bArmature *)ptr->data;
386                         
387                         layer_used = arm->layer_used;
388                         
389                         if (arm->edbo) {
390                                 if (arm->act_edbone) {
391                                         layer_active |= arm->act_edbone->layer;
392                                 }
393                         }
394                         else {
395                                 if (arm->act_bone) {
396                                         layer_active |= arm->act_bone->layer;
397                                 }
398                         }
399                 }
400
401                 for (b = 0; b < cols; b++) {
402                         uiBlockBeginAlign(block);
403
404                         for (a = 0; a < colbuts; a++) {
405                                 int layer_num  = a + b * colbuts;
406                                 int layer_flag = 1 << layer_num;
407                                 
408                                 if (layer_used & layer_flag) {
409                                         if (layer_active & layer_flag)
410                                                 icon = ICON_LAYER_ACTIVE;
411                                         else
412                                                 icon = ICON_LAYER_USED;
413                                 }
414                                 else {
415                                         icon = ICON_BLANK1;
416                                 }
417
418                                 but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth);
419                                 if (subtype == PROP_LAYER_MEMBER)
420                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
421                         }
422                         for (a = 0; a < colbuts; a++) {
423                                 int layer_num  = a + len / 2 + b * colbuts;
424                                 int layer_flag = 1 << layer_num;
425                                 
426                                 if (layer_used & layer_flag) {
427                                         if (layer_active & layer_flag)
428                                                 icon = ICON_LAYER_ACTIVE;
429                                         else
430                                                 icon = ICON_LAYER_USED;
431                                 }
432                                 else {
433                                         icon = ICON_BLANK1;
434                                 }
435
436                                 but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth);
437                                 if (subtype == PROP_LAYER_MEMBER)
438                                         uiButSetFunc(but, ui_layer_but_cb, but, SET_INT_IN_POINTER(layer_num));
439                         }
440                         uiBlockEndAlign(block);
441
442                         x += colbuts * butw + style->buttonspacex;
443                 }
444         }
445         else if (subtype == PROP_MATRIX) {
446                 int totdim, dim_size[3];    /* 3 == RNA_MAX_ARRAY_DIMENSION */
447                 int row, col;
448
449                 uiBlockSetCurLayout(block, uiLayoutAbsolute(layout, true));
450
451                 totdim = RNA_property_array_dimension(ptr, prop, dim_size);
452                 if (totdim != 2) return;    /* only 2D matrices supported in UI so far */
453                 
454                 w /= dim_size[0];
455                 /* h /= dim_size[1]; */ /* UNUSED */
456
457                 for (a = 0; a < len; a++) {
458                         col = a % dim_size[0];
459                         row = a / dim_size[0];
460
461                         but = uiDefAutoButR(block, ptr, prop, a, "", ICON_NONE, x + w * col, y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y), w, UI_UNIT_Y);
462                         if (slider && but->type == NUM)
463                                 but->type = NUMSLI;
464                 }
465         }
466         else if (subtype == PROP_DIRECTION && !expand) {
467                 uiDefButR_prop(block, BUT_NORMAL, 0, name, x, y, UI_UNIT_X * 3, UI_UNIT_Y * 3, ptr, prop, 0, 0, 0, -1, -1, NULL);
468         }
469         else {
470                 /* note, this block of code is a bit arbitrary and has just been made
471                  * to work with common cases, but may need to be re-worked */
472
473                 /* special case, boolean array in a menu, this could be used in a more generic way too */
474                 if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand) {
475                         uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
476                 }
477                 else {
478                         int *boolarr = NULL;
479
480                         /* even if 'expand' is fale, expanding anyway */
481
482                         /* layout for known array subtypes */
483                         char str[3] = {'\0'};
484
485                         if (!icon_only) {
486                                 if (type != PROP_BOOLEAN) {
487                                         str[1] = ':';
488                                 }
489                         }
490
491                         /* show checkboxes for rna on a non-emboss block (menu for eg) */
492                         if (type == PROP_BOOLEAN && ELEM(layout->root->block->dt, UI_EMBOSSN, UI_EMBOSSP)) {
493                                 boolarr = MEM_callocN(sizeof(int) * len, "ui_item_array");
494                                 RNA_property_boolean_get_array(ptr, prop, boolarr);
495                         }
496
497                         for (a = 0; a < len; a++) {
498                                 if (!icon_only) str[0] = RNA_property_array_item_char(prop, a);
499                                 if (boolarr) icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
500                                 but = uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
501                                 if (slider && but->type == NUM)
502                                         but->type = NUMSLI;
503                                 if (toggle && but->type == OPTION)
504                                         but->type = TOG;
505                                 if ((a == 0) && (subtype == PROP_AXISANGLE))
506                                         uiButSetUnitType(but, PROP_UNIT_ROTATION);
507                         }
508
509                         if (boolarr) {
510                                 MEM_freeN(boolarr);
511                         }
512                 }
513         }
514
515         uiBlockSetCurLayout(block, layout);
516 }
517
518 static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
519 {
520         wmWindow *win = CTX_wm_window(C);
521
522         if (!win->eventstate->shift) {
523                 uiBut *but = (uiBut *)arg1;
524                 int enum_value = GET_INT_FROM_POINTER(arg2);
525
526                 int current_value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
527                 if (!(current_value & enum_value)) {
528                         current_value = enum_value;
529                 }
530                 else {
531                         current_value &= enum_value;
532                 }
533                 RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
534         }
535 }
536 static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop,
537                                 const char *uiname, int h, int icon_only)
538 {
539         /* XXX The way this function currently handles uiname parameter is insane and inconsistent with general UI API:
540          *     * uiname is the *enum property* label.
541          *     * when it is NULL or empty, we do not draw *enum items* labels, this doubles the icon_only parameter.
542          *     * we *never* draw (i.e. really use) the enum label uiname, it is just used as a mere flag!
543          *     Unfortunately, fixing this implies an API "soft break", so better to defer it for later... :/
544          *     --mont29
545          */
546
547         uiBut *but;
548         EnumPropertyItem *item, *item_array;
549         const char *name;
550         int itemw, icon, value;
551         bool free;
552
553         RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
554
555         /* we dont want nested rows, cols in menus */
556         if (layout->root->type != UI_LAYOUT_MENU) {
557                 uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
558         }
559         else {
560                 uiBlockSetCurLayout(block, layout);
561         }
562
563         for (item = item_array; item->identifier; item++) {
564                 if (!item->identifier[0])
565                         continue;
566
567                 name = (!uiname || uiname[0]) ? item->name : "";
568                 icon = item->icon;
569                 value = item->value;
570                 itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0);
571
572                 if (icon && name[0] && !icon_only)
573                         but = uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
574                 else if (icon)
575                         but = uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
576                 else
577                         but = uiDefButR_prop(block, ROW, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
578
579                 if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
580                         uiButSetFunc(but, ui_item_enum_expand_handle, but, SET_INT_IN_POINTER(value));
581                 }
582
583                 if (ui_layout_local_dir(layout) != UI_LAYOUT_HORIZONTAL)
584                         but->drawflag |= UI_BUT_TEXT_LEFT;
585         }
586         uiBlockSetCurLayout(block, layout);
587
588         if (free) {
589                 MEM_freeN(item_array);
590         }
591 }
592
593 /* callback for keymap item change button */
594 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
595 {
596         uiBut *but = but_v;
597
598         RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
599         RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
600         RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
601         RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
602 }
603
604 /* create label + button for RNA property */
605 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)
606 {
607         uiLayout *sub;
608         uiBut *but = NULL;
609         PropertyType type;
610         PropertySubType subtype;
611         int labelw;
612
613         sub = uiLayoutRow(layout, layout->align);
614         uiBlockSetCurLayout(block, sub);
615
616         if (name[0]) {
617                 /* XXX UI_GetStringWidth is not accurate */
618 #if 0
619                 labelw = UI_GetStringWidth(name);
620                 CLAMP(labelw, w / 4, 3 * w / 4);
621 #endif
622                 labelw = w / 3;
623                 uiDefBut(block, LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
624                 w = w - labelw;
625         }
626
627         type = RNA_property_type(prop);
628         subtype = RNA_property_subtype(prop);
629
630         if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
631                 uiBlockSetCurLayout(block, uiLayoutRow(sub, true));
632                 but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w - UI_UNIT_X, h);
633
634                 /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */
635                 uiDefIconButO(block, BUT, subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" : "BUTTONS_OT_file_browse",
636                               WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
637         }
638         else if (flag & UI_ITEM_R_EVENT) {
639                 uiDefButR_prop(block, KEYEVT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
640         }
641         else if (flag & UI_ITEM_R_FULL_EVENT) {
642                 if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
643                         char buf[128];
644
645                         WM_keymap_item_to_string(ptr->data, buf, sizeof(buf));
646
647                         but = uiDefButR_prop(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
648                         uiButSetFunc(but, ui_keymap_but_cb, but, NULL);
649                         if (flag & UI_ITEM_R_IMMEDIATE)
650                                 uiButSetFlag(but, UI_BUT_IMMEDIATE);
651                 }
652         }
653         else
654                 but = uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "", icon, x, y, w, h);
655
656         uiBlockSetCurLayout(block, layout);
657         return but;
658 }
659
660 void uiFileBrowseContextProperty(const bContext *C, PointerRNA *ptr, PropertyRNA **prop)
661 {
662         ARegion *ar = CTX_wm_region(C);
663         uiBlock *block;
664         uiBut *but, *prevbut;
665
666         memset(ptr, 0, sizeof(*ptr));
667         *prop = NULL;
668
669         if (!ar)
670                 return;
671
672         for (block = ar->uiblocks.first; block; block = block->next) {
673                 for (but = block->buttons.first; but; but = but->next) {
674                         prevbut = but->prev;
675
676                         /* find the button before the active one */
677                         if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut && prevbut->rnapoin.data) {
678                                 if (RNA_property_type(prevbut->rnaprop) == PROP_STRING) {
679                                         *ptr = prevbut->rnapoin;
680                                         *prop = prevbut->rnaprop;
681                                         return;
682                                 }
683                         }
684                 }
685         }
686 }
687
688 /********************* Button Items *************************/
689
690 /**
691  * Update a buttons tip with an enum's description if possible.
692  */
693 static void ui_but_tip_from_enum_item(uiBut *but, EnumPropertyItem *item)
694 {
695         if (but->tip == NULL || but->tip[0] == '\0') {
696                 if (item->description && item->description[0]) {
697                         but->tip = item->description;
698                 }
699         }
700 }
701
702 /* disabled item */
703 static void ui_item_disabled(uiLayout *layout, const char *name)
704 {
705         uiBlock *block = layout->root->block;
706         uiBut *but;
707         int w;
708
709         uiBlockSetCurLayout(block, layout);
710
711         if (!name)
712                 name = "";
713
714         w = ui_text_icon_width(layout, name, 0, 0);
715
716         but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
717         but->flag |= UI_BUT_DISABLED;
718         but->lock = true;
719         but->lockstr = "";
720 }
721
722 /* operator items */
723 PointerRNA uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, int context, int flag)
724 {
725         uiBlock *block = layout->root->block;
726         uiBut *but;
727         int w;
728
729         if (!name) {
730                 if (ot && ot->srna)
731                         name = RNA_struct_ui_name(ot->srna);
732                 else
733                         name = "";
734         }
735
736         if (layout->root->type == UI_LAYOUT_MENU && !icon)
737                 icon = ICON_BLANK1;
738
739         /* create button */
740         uiBlockSetCurLayout(block, layout);
741
742         w = ui_text_icon_width(layout, name, icon, 0);
743
744         if (flag & UI_ITEM_R_NO_BG)
745                 uiBlockSetEmboss(block, UI_EMBOSSN);
746
747         /* create the button */
748         if (icon) {
749                 if (name[0]) {
750                         but = uiDefIconTextButO_ptr(block, BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
751                 }
752                 else {
753                         but = uiDefIconButO_ptr(block, BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
754                 }
755         }
756         else {
757                 but = uiDefButO_ptr(block, BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
758         }
759
760         assert(but->optype != NULL);
761
762         /* text alignment for toolbar buttons */
763         if ((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
764                 but->drawflag |= UI_BUT_TEXT_LEFT;
765
766         if (flag & UI_ITEM_R_NO_BG)
767                 uiBlockSetEmboss(block, UI_EMBOSS);
768
769         if (layout->redalert)
770                 uiButSetFlag(but, UI_BUT_REDALERT);
771
772         /* assign properties */
773         if (properties || (flag & UI_ITEM_O_RETURN_PROPS)) {
774                 PointerRNA *opptr = uiButGetOperatorPtrRNA(but);
775
776                 if (properties) {
777                         opptr->data = properties;
778                 }
779                 else {
780                         IDPropertyTemplate val = {0};
781                         opptr->data = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
782                 }
783
784                 return *opptr;
785         }
786
787         return PointerRNA_NULL;
788 }
789
790 PointerRNA uiItemFullO(uiLayout *layout, const char *opname, const char *name, int icon, IDProperty *properties, int context, int flag)
791 {
792         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
793
794         UI_OPERATOR_ERROR_RET(ot, opname, return PointerRNA_NULL);
795
796         return uiItemFullO_ptr(layout, ot, name, icon, properties, context, flag);
797 }
798
799 static const char *ui_menu_enumpropname(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int retval)
800 {
801         EnumPropertyItem *item;
802         bool free;
803         const char *name;
804
805         RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
806         if (RNA_enum_name(item, retval, &name)) {
807                 name = CTX_IFACE_(RNA_property_translation_context(prop), name);
808         }
809         else {
810                 name = "";
811         }
812
813         if (free) {
814                 MEM_freeN(item);
815         }
816
817         return name;
818 }
819
820 void uiItemEnumO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, const char *propname, int value)
821 {
822         PointerRNA ptr;
823         PropertyRNA *prop;
824
825         WM_operator_properties_create_ptr(&ptr, ot);
826
827         if ((prop = RNA_struct_find_property(&ptr, propname))) {
828                 /* pass */
829         }
830         else {
831                 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
832                 return;
833         }
834
835         RNA_property_enum_set(&ptr, prop, value);
836
837         if (!name)
838                 name = ui_menu_enumpropname(layout, &ptr, prop, value);
839
840         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
841 }
842 void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int icon, const char *propname, int value)
843 {
844         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
845
846         if (ot) {
847                 uiItemEnumO_ptr(layout, ot, name, icon, propname, value);
848         }
849         else {
850                 ui_item_disabled(layout, opname);
851                 RNA_warning("unknown operator '%s'", opname);
852         }
853
854 }
855
856 void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
857                       int context, int flag)
858 {
859         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
860
861         PointerRNA ptr;
862         PropertyRNA *prop;
863         uiBlock *block = layout->root->block;
864
865         if (!ot || !ot->srna) {
866                 ui_item_disabled(layout, opname);
867                 RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
868                 return;
869         }
870
871         WM_operator_properties_create_ptr(&ptr, ot);
872         /* so the context is passed to itemf functions (some need it) */
873         WM_operator_properties_sanitize(&ptr, false);
874         prop = RNA_struct_find_property(&ptr, propname);
875
876         /* don't let bad properties slip through */
877         BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
878
879         if (prop && RNA_property_type(prop) == PROP_ENUM) {
880                 EnumPropertyItem *item, *item_array = NULL;
881                 bool free;
882                 uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
883                 uiLayout *column = uiLayoutColumn(split, false);
884
885                 RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
886                 for (item = item_array; item->identifier; item++) {
887                         if (item->identifier[0]) {
888                                 PointerRNA tptr;
889
890                                 WM_operator_properties_create_ptr(&tptr, ot);
891                                 if (properties) {
892                                         if (tptr.data) {
893                                                 IDP_FreeProperty(tptr.data);
894                                                 MEM_freeN(tptr.data);
895                                         }
896                                         tptr.data = IDP_CopyProperty(properties);
897                                 }
898                                 RNA_property_enum_set(&tptr, prop, item->value);
899
900                                 uiItemFullO_ptr(column, ot, item->name, item->icon, tptr.data, context, flag);
901                                 ui_but_tip_from_enum_item(block->buttons.last, item);
902                         }
903                         else {
904                                 if (item->name) {
905                                         uiBut *but;
906                                         if (item != item_array) {
907                                                 column = uiLayoutColumn(split, false);
908                                                 /* inconsistent, but menus with labels do not look good flipped */
909                                                 block->flag |= UI_BLOCK_NO_FLIP;
910                                         }
911
912                                         if (item->icon) {
913                                                 uiItemL(column, item->name, item->icon);
914                                                 but = block->buttons.last;
915                                         }
916                                         else {
917                                                 /* Do not use uiItemL here, as our root layout is a menu one, it will add a fake blank icon! */
918                                                 but = uiDefBut(block, LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL,
919                                                                0.0, 0.0, 0, 0, "");
920                                         }
921                                         ui_but_tip_from_enum_item(but, item);
922                                 }
923                                 else {  /* XXX bug here, colums draw bottom item badly */
924                                         uiItemS(column);
925                                 }
926                         }
927                 }
928                 if (free) {
929                         MEM_freeN(item_array);
930                 }
931         }
932         else if (prop && RNA_property_type(prop) != PROP_ENUM) {
933                 RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
934                 return;
935         }
936         else {
937                 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
938                 return;
939         }
940 }
941
942 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
943 {
944         uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
945 }
946
947 /* for use in cases where we have */
948 void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
949 {
950         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
951         PointerRNA ptr;
952         PropertyRNA *prop;
953
954         UI_OPERATOR_ERROR_RET(ot, opname, return );
955
956         WM_operator_properties_create_ptr(&ptr, ot);
957
958         /* enum lookup */
959         if ((prop = RNA_struct_find_property(&ptr, propname))) {
960                 /* pass */
961         }
962         else {
963                 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
964                 return;
965         }
966
967         RNA_property_enum_set(&ptr, prop, value);
968
969         /* same as uiItemEnumO */
970         if (!name)
971                 name = ui_menu_enumpropname(layout, &ptr, prop, value);
972
973         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
974 }
975
976 void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value_str)
977 {
978         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
979         PointerRNA ptr;
980         PropertyRNA *prop;
981
982         EnumPropertyItem *item;
983         int value;
984         bool free;
985
986         UI_OPERATOR_ERROR_RET(ot, opname, return );
987
988         WM_operator_properties_create_ptr(&ptr, ot);
989
990         /* enum lookup */
991         if ((prop = RNA_struct_find_property(&ptr, propname))) {
992                 /* no need for translations here */
993                 RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
994                 if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) {
995                         if (free) {
996                                 MEM_freeN(item);
997                         }
998                         RNA_warning("%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str);
999                         return;
1000                 }
1001
1002                 if (free) {
1003                         MEM_freeN(item);
1004                 }
1005         }
1006         else {
1007                 RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1008                 return;
1009         }
1010
1011         RNA_property_enum_set(&ptr, prop, value);
1012
1013         /* same as uiItemEnumO */
1014         if (!name)
1015                 name = ui_menu_enumpropname(layout, &ptr, prop, value);
1016
1017         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
1018 }
1019
1020 void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
1021 {
1022         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1023         PointerRNA ptr;
1024
1025         UI_OPERATOR_ERROR_RET(ot, opname, return );
1026
1027         WM_operator_properties_create_ptr(&ptr, ot);
1028         RNA_boolean_set(&ptr, propname, value);
1029
1030         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
1031 }
1032
1033 void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
1034 {
1035         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1036         PointerRNA ptr;
1037
1038         UI_OPERATOR_ERROR_RET(ot, opname, return );
1039
1040         WM_operator_properties_create_ptr(&ptr, ot);
1041         RNA_int_set(&ptr, propname, value);
1042
1043         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
1044 }
1045
1046 void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value)
1047 {
1048         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1049         PointerRNA ptr;
1050
1051         UI_OPERATOR_ERROR_RET(ot, opname, return );
1052
1053         WM_operator_properties_create_ptr(&ptr, ot);
1054         RNA_float_set(&ptr, propname, value);
1055
1056         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
1057 }
1058
1059 void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value)
1060 {
1061         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1062         PointerRNA ptr;
1063
1064         UI_OPERATOR_ERROR_RET(ot, opname, return );
1065
1066         WM_operator_properties_create_ptr(&ptr, ot);
1067         RNA_string_set(&ptr, propname, value);
1068
1069         uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0);
1070 }
1071
1072 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
1073 {
1074         uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0);
1075 }
1076
1077 /* RNA property items */
1078
1079 static void ui_item_rna_size(uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
1080                              int index, int icon_only, int *r_w, int *r_h)
1081 {
1082         PropertyType type;
1083         PropertySubType subtype;
1084         int len, w = 0, h;
1085
1086         /* arbitrary extended width by type */
1087         type = RNA_property_type(prop);
1088         subtype = RNA_property_subtype(prop);
1089         len = RNA_property_array_length(ptr, prop);
1090
1091         if (!name[0] && !icon_only) {
1092                 if (ELEM(type, PROP_STRING, PROP_POINTER)) {
1093                         name = "non-empty text";
1094                 }
1095                 else if (type == PROP_BOOLEAN) {
1096                         icon = ICON_DOT;
1097                 }
1098                 else if (type == PROP_ENUM) {
1099                         /* Find the longest enum item name, instead of using a dummy text! */
1100                         EnumPropertyItem *item, *item_array;
1101                         bool free;
1102
1103                         RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free);
1104                         for (item = item_array; item->identifier; item++) {
1105                                 if (item->identifier[0]) {
1106                                         w = max_ii(w, ui_text_icon_width(layout, item->name, icon, 0));
1107                                 }
1108                         }
1109                         if (free) {
1110                                 MEM_freeN(item_array);
1111                         }
1112                 }
1113         }
1114
1115         if (!w)
1116                 w = ui_text_icon_width(layout, name, icon, 0);
1117         h = UI_UNIT_Y;
1118
1119         /* increase height for arrays */
1120         if (index == RNA_NO_INDEX && len > 0) {
1121                 if (!name[0] && icon == ICON_NONE)
1122                         h = 0;
1123
1124                 if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
1125                         h += 2 * UI_UNIT_Y;
1126                 else if (subtype == PROP_MATRIX)
1127                         h += ceil(sqrt(len)) * UI_UNIT_Y;
1128                 else
1129                         h += len * UI_UNIT_Y;
1130         }
1131         else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
1132                 if (type == PROP_BOOLEAN && name[0])
1133                         w += UI_UNIT_X / 5;
1134                 else if (type == PROP_ENUM)
1135                         w += UI_UNIT_X / 4;
1136                 else if (type == PROP_FLOAT || type == PROP_INT)
1137                         w += UI_UNIT_X * 3;
1138         }
1139
1140         *r_w = w;
1141         *r_h = h;
1142 }
1143
1144 void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
1145 {
1146         uiBlock *block = layout->root->block;
1147         uiBut *but = NULL;
1148         PropertyType type;
1149         char namestr[UI_MAX_NAME_STR];
1150         int len, w, h, slider, toggle, expand, icon_only, no_bg;
1151         bool is_array;
1152
1153         uiBlockSetCurLayout(block, layout);
1154
1155         /* retrieve info */
1156         type = RNA_property_type(prop);
1157         is_array = RNA_property_array_check(prop);
1158         len = (is_array) ? RNA_property_array_length(ptr, prop) : 0;
1159
1160         /* set name and icon */
1161         if (!name)
1162                 name = RNA_property_ui_name(prop);
1163         if (icon == ICON_NONE)
1164                 icon = RNA_property_ui_icon(prop);
1165         
1166         if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER))
1167                 name = ui_item_name_add_colon(name, namestr);
1168         else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX)
1169                 name = ui_item_name_add_colon(name, namestr);
1170         else if (type == PROP_ENUM && index != RNA_ENUM_VALUE)
1171                 name = ui_item_name_add_colon(name, namestr);
1172
1173         if (layout->root->type == UI_LAYOUT_MENU) {
1174                 if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) {
1175                         if (is_array) icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1176                         else icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1177                 }
1178                 else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
1179                         int enum_value = RNA_property_enum_get(ptr, prop);
1180                         if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
1181                                 icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1182                         }
1183                         else {
1184                                 icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1185                         }
1186                 }
1187         }
1188
1189         slider = (flag & UI_ITEM_R_SLIDER);
1190         toggle = (flag & UI_ITEM_R_TOGGLE);
1191         expand = (flag & UI_ITEM_R_EXPAND);
1192         icon_only = (flag & UI_ITEM_R_ICON_ONLY);
1193         no_bg = (flag & UI_ITEM_R_NO_BG);
1194
1195         /* get size */
1196         ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
1197
1198         if (no_bg)
1199                 uiBlockSetEmboss(block, UI_EMBOSSN);
1200         
1201         /* array property */
1202         if (index == RNA_NO_INDEX && is_array)
1203                 ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
1204         /* enum item */
1205         else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
1206                 if (icon && name[0] && !icon_only)
1207                         uiDefIconTextButR_prop(block, ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1208                 else if (icon)
1209                         uiDefIconButR_prop(block, ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1210                 else
1211                         uiDefButR_prop(block, ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
1212         }
1213         /* expanded enum */
1214         else if (type == PROP_ENUM && (expand || RNA_property_flag(prop) & PROP_ENUM_FLAG))
1215                 ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
1216         /* property with separate label */
1217         else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
1218                 but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
1219                 ui_but_add_search(but, ptr, prop, NULL, NULL);
1220                 
1221                 if (layout->redalert)
1222                         uiButSetFlag(but, UI_BUT_REDALERT);
1223         }
1224         /* single button */
1225         else {
1226                 but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
1227
1228                 if (slider && but->type == NUM)
1229                         but->type = NUMSLI;
1230
1231                 if (toggle && but->type == OPTION)
1232                         but->type = TOG;
1233                 
1234                 if (layout->redalert)
1235                         uiButSetFlag(but, UI_BUT_REDALERT);
1236         }
1237
1238         /* Mark non-embossed textfields inside a listbox. */
1239         if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == TEX) && (but->dt & UI_EMBOSSN)) {
1240                 uiButSetFlag(but, UI_BUT_LIST_ITEM);
1241         }
1242
1243         if (no_bg)
1244                 uiBlockSetEmboss(block, UI_EMBOSS);
1245 }
1246
1247 void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
1248 {
1249         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1250
1251         if (!prop) {
1252                 ui_item_disabled(layout, propname);
1253                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1254                 return;
1255         }
1256
1257         uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
1258 }
1259
1260 void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value)
1261 {
1262         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1263
1264         if (!prop || RNA_property_type(prop) != PROP_ENUM) {
1265                 ui_item_disabled(layout, propname);
1266                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1267                 return;
1268         }
1269
1270         uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
1271 }
1272
1273 void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
1274 {
1275         PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
1276         EnumPropertyItem *item;
1277         int ivalue, a;
1278         bool free;
1279
1280         if (!prop || RNA_property_type(prop) != PROP_ENUM) {
1281                 ui_item_disabled(layout, propname);
1282                 RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1283                 return;
1284         }
1285
1286         RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
1287
1288         if (!RNA_enum_value_from_id(item, value, &ivalue)) {
1289                 if (free) {
1290                         MEM_freeN(item);
1291                 }
1292                 ui_item_disabled(layout, propname);
1293                 RNA_warning("enum property value not found: %s", value);
1294                 return;
1295         }
1296
1297         for (a = 0; item[a].identifier; a++) {
1298                 if (item[a].value == ivalue) {
1299                         const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
1300
1301                         uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon);
1302                         break;
1303                 }
1304         }
1305
1306         if (free) {
1307                 MEM_freeN(item);
1308         }
1309 }
1310
1311 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
1312 {
1313         PropertyRNA *prop;
1314         uiBlock *block = layout->root->block;
1315         uiBut *bt;
1316
1317         prop = RNA_struct_find_property(ptr, propname);
1318
1319         if (!prop) {
1320                 ui_item_disabled(layout, propname);
1321                 RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1322                 return;
1323         }
1324
1325         if (RNA_property_type(prop) != PROP_ENUM) {
1326                 RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
1327                 return;
1328         }
1329         else {
1330                 EnumPropertyItem *item;
1331                 int totitem, i;
1332                 bool free;
1333                 uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
1334                 uiLayout *column = uiLayoutColumn(split, false);
1335
1336                 RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
1337
1338                 for (i = 0; i < totitem; i++) {
1339                         if (item[i].identifier[0]) {
1340                                 uiItemEnumR(column, item[i].name, ICON_NONE, ptr, propname, item[i].value);
1341                                 ui_but_tip_from_enum_item(block->buttons.last, &item[i]);
1342                         }
1343                         else {
1344                                 if (item[i].name) {
1345                                         if (i != 0) {
1346                                                 column = uiLayoutColumn(split, false);
1347                                                 /* inconsistent, but menus with labels do not look good flipped */
1348                                                 block->flag |= UI_BLOCK_NO_FLIP;
1349                                         }
1350
1351                                         uiItemL(column, item[i].name, ICON_NONE);
1352                                         bt = block->buttons.last;
1353                                         bt->drawflag = UI_BUT_TEXT_LEFT;
1354
1355                                         ui_but_tip_from_enum_item(bt, &item[i]);
1356                                 }
1357                                 else
1358                                         uiItemS(column);
1359                         }
1360                 }
1361
1362                 if (free) {
1363                         MEM_freeN(item);
1364                 }
1365         }
1366 }
1367
1368 /* Pointer RNA button with search */
1369
1370 typedef struct CollItemSearch {
1371         struct CollItemSearch *next, *prev;
1372         char *name;
1373         int index;
1374         int iconid;
1375 } CollItemSearch;
1376
1377 static int sort_search_items_list(void *a, void *b)
1378 {
1379         CollItemSearch *cis1 = (CollItemSearch *)a;
1380         CollItemSearch *cis2 = (CollItemSearch *)b;
1381         
1382         if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
1383                 return 1;
1384         else
1385                 return 0;
1386 }
1387
1388 static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
1389 {
1390         uiBut *but = arg_but;
1391         char *name;
1392         int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
1393         ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
1394         CollItemSearch *cis;
1395         const int skip_filter = !but->changed;
1396
1397         /* build a temporary list of relevant items first */
1398         RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
1399         {
1400                 if (flag & PROP_ID_SELF_CHECK)
1401                         if (itemptr.data == but->rnapoin.id.data)
1402                                 continue;
1403
1404                 /* use filter */
1405                 if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
1406                         if (RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr) == 0)
1407                                 continue;
1408                 }
1409
1410                 if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
1411                         ID *id = itemptr.data;
1412                         char name_ui[MAX_ID_NAME];
1413
1414 #if 0       /* this name is used for a string comparison and can't be modified, TODO */
1415                         /* if ever enabled, make name_ui be MAX_ID_NAME+1 */
1416                         name_uiprefix_id(name_ui, id);
1417 #else
1418                         BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
1419 #endif
1420                         name = BLI_strdup(name_ui);
1421                         iconid = ui_id_icon_get((bContext *)C, id, false);
1422                 }
1423                 else {
1424                         name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
1425                         iconid = 0;
1426                 }
1427
1428                 if (name) {
1429                         if (skip_filter || BLI_strcasestr(name, str)) {
1430                                 cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
1431                                 cis->name = MEM_dupallocN(name);
1432                                 cis->index = i;
1433                                 cis->iconid = iconid;
1434                                 BLI_addtail(items_list, cis);
1435                         }
1436                         MEM_freeN(name);
1437                 }
1438
1439                 i++;
1440         }
1441         RNA_PROP_END;
1442         
1443         BLI_sortlist(items_list, sort_search_items_list);
1444         
1445         /* add search items from temporary list */
1446         for (cis = items_list->first; cis; cis = cis->next) {
1447                 if (false == uiSearchItemAdd(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
1448                         break;
1449                 }
1450         }
1451
1452         for (cis = items_list->first; cis; cis = cis->next) {
1453                 MEM_freeN(cis->name);
1454         }
1455         BLI_freelistN(items_list);
1456         MEM_freeN(items_list);
1457 }
1458
1459 static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
1460 {
1461         StructRNA *srna;
1462
1463         /* look for collection property in Main */
1464         RNA_main_pointer_create(G.main, ptr);
1465
1466         *prop = NULL;
1467
1468         RNA_STRUCT_BEGIN (ptr, iprop)
1469         {
1470                 /* if it's a collection and has same pointer type, we've got it */
1471                 if (RNA_property_type(iprop) == PROP_COLLECTION) {
1472                         srna = RNA_property_pointer_type(ptr, iprop);
1473
1474                         if (ptype == srna) {
1475                                 *prop = iprop;
1476                                 break;
1477                         }
1478                 }
1479         }
1480         RNA_STRUCT_END;
1481 }
1482
1483 void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
1484 {
1485         StructRNA *ptype;
1486         PointerRNA sptr;
1487
1488         /* for ID's we do automatic lookup */
1489         if (!searchprop) {
1490                 if (RNA_property_type(prop) == PROP_POINTER) {
1491                         ptype = RNA_property_pointer_type(ptr, prop);
1492                         search_id_collection(ptype, &sptr, &searchprop);
1493                         searchptr = &sptr;
1494                 }
1495         }
1496
1497         /* turn button into search button */
1498         if (searchprop) {
1499                 but->type = RNA_property_is_unlink(prop) ? SEARCH_MENU_UNLINK : SEARCH_MENU;
1500                 but->hardmax = MAX2(but->hardmax, 256.0f);
1501                 but->rnasearchpoin = *searchptr;
1502                 but->rnasearchprop = searchprop;
1503                 but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
1504
1505                 if (RNA_property_type(prop) == PROP_ENUM) {
1506                         /* XXX, this will have a menu string,
1507                          * but in this case we just want the text */
1508                         but->str[0] = 0;
1509                 }
1510
1511                 uiButSetSearchFunc(but, rna_search_cb, but, NULL, NULL);
1512         }
1513 }
1514
1515 void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
1516 {
1517         PropertyRNA *prop, *searchprop;
1518         PropertyType type;
1519         uiBut *but;
1520         uiBlock *block;
1521         StructRNA *icontype;
1522         int w, h;
1523         char namestr[UI_MAX_NAME_STR];
1524         
1525         /* validate arguments */
1526         prop = RNA_struct_find_property(ptr, propname);
1527
1528         if (!prop) {
1529                 RNA_warning("property not found: %s.%s",
1530                             RNA_struct_identifier(ptr->type), propname);
1531                 return;
1532         }
1533         
1534         type = RNA_property_type(prop);
1535         if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
1536                 RNA_warning("Property %s must be a pointer, string or enum", propname);
1537                 return;
1538         }
1539
1540         searchprop = RNA_struct_find_property(searchptr, searchpropname);
1541
1542
1543         if (!searchprop) {
1544                 RNA_warning("search collection property not found: %s.%s",
1545                             RNA_struct_identifier(searchptr->type), searchpropname);
1546                 return;
1547         }
1548         else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
1549                 RNA_warning("search collection property is not a collection type: %s.%s",
1550                             RNA_struct_identifier(searchptr->type), searchpropname);
1551                 return;
1552         }
1553
1554         /* get icon & name */
1555         if (icon == ICON_NONE) {
1556                 if (type == PROP_POINTER)
1557                         icontype = RNA_property_pointer_type(ptr, prop);
1558                 else
1559                         icontype = RNA_property_pointer_type(searchptr, searchprop);
1560
1561                 icon = RNA_struct_ui_icon(icontype);
1562         }
1563         if (!name)
1564                 name = RNA_property_ui_name(prop);
1565
1566         name = ui_item_name_add_colon(name, namestr);
1567
1568         /* create button */
1569         block = uiLayoutGetBlock(layout);
1570
1571         ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
1572         w += UI_UNIT_X; /* X icon needs more space */
1573         but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
1574
1575         ui_but_add_search(but, ptr, prop, searchptr, searchprop);
1576 }
1577
1578 /* menu item */
1579 static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
1580 {
1581         MenuType *mt = (MenuType *)arg_mt;
1582         Menu menu = {NULL};
1583
1584         menu.type = mt;
1585         menu.layout = layout;
1586
1587         if (G.debug & G_DEBUG_WM) {
1588                 printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
1589         }
1590
1591         if (layout->context)
1592                 CTX_store_set(C, layout->context);
1593
1594         mt->draw(C, &menu);
1595
1596         if (layout->context)
1597                 CTX_store_set(C, NULL);
1598 }
1599
1600 static void ui_item_menu(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
1601                          const char *tip, bool force_menu)
1602 {
1603         uiBlock *block = layout->root->block;
1604         uiBut *but;
1605         int w, h;
1606
1607         uiBlockSetCurLayout(block, layout);
1608
1609         if (layout->root->type == UI_LAYOUT_HEADER)
1610                 uiBlockSetEmboss(block, UI_EMBOSS);
1611
1612         if (!name)
1613                 name = "";
1614         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1615                 icon = ICON_BLANK1;
1616
1617         w = ui_text_icon_width(layout, name, icon, 1);
1618         h = UI_UNIT_Y;
1619
1620         if (layout->root->type == UI_LAYOUT_HEADER) { /* ugly .. */
1621                 if (force_menu)
1622                         w += UI_UNIT_Y;
1623                 else
1624                         w -= UI_UNIT_Y / 2;
1625         }
1626
1627         if (name[0] && icon)
1628                 but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
1629         else if (icon)
1630                 but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
1631         else
1632                 but = uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
1633
1634         if (argN) { /* ugly .. */
1635                 but->poin = (char *)but;
1636                 but->func_argN = argN;
1637         }
1638
1639         if (layout->root->type == UI_LAYOUT_HEADER) {
1640                 uiBlockSetEmboss(block, UI_EMBOSS);
1641         }
1642         if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
1643             (force_menu && layout->root->type != UI_LAYOUT_MENU))  /* We never want a dropdown in menu! */
1644         {
1645                 but->type = MENU;
1646                 but->drawflag |= UI_BUT_TEXT_LEFT;
1647         }
1648 }
1649
1650 void uiItemM(uiLayout *layout, bContext *UNUSED(C), const char *menuname, const char *name, int icon)
1651 {
1652         MenuType *mt;
1653
1654         mt = WM_menutype_find(menuname, false);
1655
1656         if (mt == NULL) {
1657                 RNA_warning("not found %s", menuname);
1658                 return;
1659         }
1660
1661         if (!name) {
1662                 name = CTX_IFACE_(mt->translation_context, mt->label);
1663         }
1664
1665         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1666                 icon = ICON_BLANK1;
1667
1668         ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL, TIP_(mt->description), false);
1669 }
1670
1671 /* label item */
1672 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
1673 {
1674         uiBlock *block = layout->root->block;
1675         uiBut *but;
1676         int w;
1677
1678         uiBlockSetCurLayout(block, layout);
1679
1680         if (!name)
1681                 name = "";
1682         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1683                 icon = ICON_BLANK1;
1684
1685         w = ui_text_icon_width(layout, name, icon, 0);
1686
1687         if (icon && name[0])
1688                 but = uiDefIconTextBut(block, LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1689         else if (icon)
1690                 but = uiDefIconBut(block, LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1691         else
1692                 but = uiDefBut(block, LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1693
1694         /* to compensate for string size padding in ui_text_icon_width,
1695          * make text aligned right if the layout is aligned right.
1696          */
1697         if (uiLayoutGetAlignment(layout) == UI_LAYOUT_ALIGN_RIGHT) {
1698                 but->drawflag &= ~UI_BUT_TEXT_LEFT;     /* default, needs to be unset */
1699                 but->drawflag |= UI_BUT_TEXT_RIGHT;
1700         }
1701
1702         /* Mark as a label inside a listbox. */
1703         if (block->flag & UI_BLOCK_LIST_ITEM) {
1704                 but->flag |= UI_BUT_LIST_ITEM;
1705         }
1706
1707         return but;
1708 }
1709
1710 void uiItemL(uiLayout *layout, const char *name, int icon)
1711 {
1712         uiItemL_(layout, name, icon);
1713 }
1714
1715 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
1716 {
1717         uiBut *but = uiItemL_(layout, name, icon);
1718
1719         if (ptr && ptr->type)
1720                 if (RNA_struct_is_ID(ptr->type))
1721                         uiButSetDragID(but, ptr->id.data);
1722 }
1723
1724
1725 /* value item */
1726 void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
1727 {
1728         /* label */
1729         uiBlock *block = layout->root->block;
1730         float *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
1731         int w;
1732
1733         uiBlockSetCurLayout(block, layout);
1734
1735         if (!name)
1736                 name = "";
1737         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1738                 icon = ICON_BLANK1;
1739
1740         w = ui_text_icon_width(layout, name, icon, 0);
1741
1742         if (icon && name[0])
1743                 uiDefIconTextButF(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
1744         else if (icon)
1745                 uiDefIconButF(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
1746         else
1747                 uiDefButF(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
1748 }
1749
1750 /* separator item */
1751 void uiItemS(uiLayout *layout)
1752 {
1753         uiBlock *block = layout->root->block;
1754
1755         uiBlockSetCurLayout(block, layout);
1756         uiDefBut(block, SEPR, 0, "", 0, 0, 0.3f * UI_UNIT_X, 0.3f * UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1757 }
1758
1759 /* level items */
1760 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
1761 {
1762         if (!func)
1763                 return;
1764
1765         ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
1766 }
1767
1768 typedef struct MenuItemLevel {
1769         int opcontext;
1770         /* don't use pointers to the strings because python can dynamically
1771          * allocate strings and free before the menu draws, see [#27304] */
1772         char opname[OP_MAX_TYPENAME];
1773         char propname[MAX_IDPROP_NAME];
1774         PointerRNA rnapoin;
1775 } MenuItemLevel;
1776
1777 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1778 {
1779         MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
1780
1781         uiLayoutSetOperatorContext(layout, lvl->opcontext);
1782         uiItemsEnumO(layout, lvl->opname, lvl->propname);
1783 }
1784
1785 void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const char *propname, const char *name, int icon)
1786 {
1787         wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1788         MenuItemLevel *lvl;
1789         char namestr_buf[UI_MAX_NAME_STR], keybuf[128];
1790         char *namestr = namestr_buf;
1791
1792         UI_OPERATOR_ERROR_RET(ot, opname, return );
1793
1794         if (!ot->srna) {
1795                 ui_item_disabled(layout, opname);
1796                 RNA_warning("operator missing srna '%s'", opname);
1797                 return;
1798         }
1799
1800         if (name)
1801                 namestr += BLI_strncpy_rlen(namestr, name, sizeof(namestr_buf));
1802         else
1803                 namestr += BLI_strncpy_rlen(namestr, RNA_struct_ui_name(ot->srna), sizeof(namestr_buf));
1804
1805         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1806                 icon = ICON_BLANK1;
1807
1808         lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1809         BLI_strncpy(lvl->opname, opname, sizeof(lvl->opname));
1810         BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
1811         lvl->opcontext = layout->root->opcontext;
1812
1813         /* add hotkey here, lower UI code can't detect it */
1814         if (layout->root->block->flag & UI_BLOCK_LOOP) {
1815                 if (ot->prop && ot->invoke &&
1816                     WM_key_event_operator_string(C, ot->idname, layout->root->opcontext, NULL, false, keybuf, sizeof(keybuf)))
1817                 {
1818                         namestr += BLI_snprintf(namestr, sizeof(namestr_buf) - (namestr - namestr_buf), "|%s", keybuf);
1819                 }
1820         }
1821
1822         ui_item_menu(layout, namestr_buf, icon, menu_item_enum_opname_menu, NULL, lvl, RNA_struct_ui_description(ot->srna),
1823                      true);
1824 }
1825
1826 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
1827 {
1828         MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
1829
1830         uiLayoutSetOperatorContext(layout, lvl->opcontext);
1831         uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
1832 }
1833
1834 void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
1835 {
1836         MenuItemLevel *lvl;
1837         PropertyRNA *prop;
1838
1839         prop = RNA_struct_find_property(ptr, propname);
1840         if (!prop) {
1841                 ui_item_disabled(layout, propname);
1842                 RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
1843                 return;
1844         }
1845
1846         if (!name)
1847                 name = RNA_property_ui_name(prop);
1848         if (layout->root->type == UI_LAYOUT_MENU && !icon)
1849                 icon = ICON_BLANK1;
1850
1851         lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
1852         lvl->rnapoin = *ptr;
1853         BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
1854         lvl->opcontext = layout->root->opcontext;
1855
1856         ui_item_menu(layout, name, icon, menu_item_enum_rna_menu, NULL, lvl, RNA_property_description(prop), false);
1857 }
1858
1859 /**************************** Layout Items ***************************/
1860
1861 /* single-row layout */
1862 static void ui_litem_estimate_row(uiLayout *litem)
1863 {
1864         uiItem *item;
1865         int itemw, itemh;
1866
1867         litem->w = 0;
1868         litem->h = 0;
1869
1870         for (item = litem->items.first; item; item = item->next) {
1871                 ui_item_size(item, &itemw, &itemh);
1872
1873                 litem->w += itemw;
1874                 litem->h = MAX2(itemh, litem->h);
1875
1876                 if (item->next)
1877                         litem->w += litem->space;
1878         }
1879 }
1880
1881 static int ui_litem_min_width(int itemw)
1882 {
1883         return MIN2(2 * UI_UNIT_X, itemw);
1884 }
1885
1886 static void ui_litem_layout_row(uiLayout *litem)
1887 {
1888         uiItem *item;
1889         int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset;
1890         int fixedw, freew, fixedx, freex, flag = 0, lastw = 0;
1891
1892         /* x = litem->x; */ /* UNUSED */
1893         y = litem->y;
1894         w = litem->w;
1895         totw = 0;
1896         tot = 0;
1897
1898         for (item = litem->items.first; item; item = item->next) {
1899                 ui_item_size(item, &itemw, &itemh);
1900                 totw += itemw;
1901                 tot++;
1902         }
1903
1904         if (totw == 0)
1905                 return;
1906         
1907         if (w != 0)
1908                 w -= (tot - 1) * litem->space;
1909         fixedw = 0;
1910
1911         /* keep clamping items to fixed minimum size until all are done */
1912         do {
1913                 freew = 0;
1914                 x = 0;
1915                 flag = 0;
1916                 newtotw = totw;
1917
1918                 for (item = litem->items.first; item; item = item->next) {
1919                         if (item->flag)
1920                                 continue;
1921
1922                         ui_item_size(item, &itemw, &itemh);
1923                         minw = ui_litem_min_width(itemw);
1924
1925                         if (w - lastw > 0)
1926                                 neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, NULL);
1927                         else
1928                                 neww = 0;  /* no space left, all will need clamping to minimum size */
1929
1930                         x += neww;
1931
1932                         if ((neww < minw || itemw == minw) && w != 0) {
1933                                 /* fixed size */
1934                                 item->flag = 1;
1935                                 fixedw += minw;
1936                                 flag = 1;
1937                                 newtotw -= itemw;
1938                         }
1939                         else {
1940                                 /* keep free size */
1941                                 item->flag = 0;
1942                                 freew += itemw;
1943                         }
1944                 }
1945
1946                 totw = newtotw;
1947                 lastw = fixedw;
1948         } while (flag);
1949
1950         freex = 0;
1951         fixedx = 0;
1952         x = litem->x;
1953
1954         for (item = litem->items.first; item; item = item->next) {
1955                 ui_item_size(item, &itemw, &itemh);
1956                 minw = ui_litem_min_width(itemw);
1957
1958                 if (item->flag) {
1959                         /* fixed minimum size items */
1960                         itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, NULL);
1961                         fixedx += itemw;
1962                 }
1963                 else {
1964                         /* free size item */
1965                         itemw = ui_item_fit(itemw, freex, freew, w - fixedw, !item->next, litem->alignment, NULL);
1966                         freex += itemw;
1967                 }
1968
1969                 /* align right/center */
1970                 offset = 0;
1971                 if (litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
1972                         if (freew + fixedw > 0 && freew + fixedw < w)
1973                                 offset = w - (fixedw + freew);
1974                 }
1975                 else if (litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
1976                         if (freew + fixedw > 0 && freew + fixedw < w)
1977                                 offset = (w - (fixedw + freew)) / 2;
1978                 }
1979
1980                 /* position item */
1981                 ui_item_position(item, x + offset, y - itemh, itemw, itemh);
1982
1983                 x += itemw;
1984                 if (item->next)
1985                         x += litem->space;
1986         }
1987
1988         litem->w = x - litem->x;
1989         litem->h = litem->y - y;
1990         litem->x = x;
1991         litem->y = y;
1992 }
1993
1994 /* single-column layout */
1995 static void ui_litem_estimate_column(uiLayout *litem)
1996 {
1997         uiItem *item;
1998         int itemw, itemh;
1999
2000         litem->w = 0;
2001         litem->h = 0;
2002
2003         for (item = litem->items.first; item; item = item->next) {
2004                 ui_item_size(item, &itemw, &itemh);
2005
2006                 litem->w = MAX2(litem->w, itemw);
2007                 litem->h += itemh;
2008
2009                 if (item->next)
2010                         litem->h += litem->space;
2011         }
2012 }
2013
2014 static void ui_litem_layout_column(uiLayout *litem)
2015 {
2016         uiItem *item;
2017         int itemh, x, y;
2018
2019         x = litem->x;
2020         y = litem->y;
2021
2022         for (item = litem->items.first; item; item = item->next) {
2023                 ui_item_size(item, NULL, &itemh);
2024
2025                 y -= itemh;
2026                 ui_item_position(item, x, y, litem->w, itemh);
2027
2028                 if (item->next)
2029                         y -= litem->space;
2030         }
2031
2032         litem->h = litem->y - y;
2033         litem->x = x;
2034         litem->y = y;
2035 }
2036
2037 /* root layout */
2038 static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
2039 {
2040         /* nothing to do */
2041 }
2042
2043 static void ui_litem_layout_root(uiLayout *litem)
2044 {
2045         if (litem->root->type == UI_LAYOUT_HEADER)
2046                 ui_litem_layout_row(litem);
2047         else
2048                 ui_litem_layout_column(litem);
2049 }
2050
2051 /* box layout */
2052 static void ui_litem_estimate_box(uiLayout *litem)
2053 {
2054         uiStyle *style = litem->root->style;
2055
2056         ui_litem_estimate_column(litem);
2057         litem->w += 2 * style->boxspace;
2058         litem->h += style->boxspace;
2059 }
2060
2061 static void ui_litem_layout_box(uiLayout *litem)
2062 {
2063         uiLayoutItemBx *box = (uiLayoutItemBx *)litem;
2064         uiStyle *style = litem->root->style;
2065         uiBut *but;
2066         int w, h;
2067
2068         w = litem->w;
2069         h = litem->h;
2070
2071         litem->x += style->boxspace;
2072
2073         if (w != 0) litem->w -= 2 * style->boxspace;
2074         if (h != 0) litem->h -= 2 * style->boxspace;
2075
2076         ui_litem_layout_column(litem);
2077
2078         litem->x -= style->boxspace;
2079         litem->y -= style->boxspace;
2080
2081         if (w != 0) litem->w += 2 * style->boxspace;
2082         if (h != 0) litem->h += style->boxspace;
2083
2084         /* roundbox around the sublayout */
2085         but = box->roundbox;
2086         but->rect.xmin = litem->x;
2087         but->rect.ymin = litem->y;
2088         but->rect.xmax = litem->x + litem->w;
2089         but->rect.ymax = litem->y + litem->h;
2090 }
2091
2092 /* multi-column layout, automatically flowing to the next */
2093 static void ui_litem_estimate_column_flow(uiLayout *litem)
2094 {
2095         uiStyle *style = litem->root->style;
2096         uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
2097         uiItem *item;
2098         int col, x, y, emh, emy, miny, itemw, itemh, maxw = 0;
2099         int toth, totitem;
2100
2101         /* compute max needed width and total height */
2102         toth = 0;
2103         totitem = 0;
2104         for (item = litem->items.first; item; item = item->next) {
2105                 ui_item_size(item, &itemw, &itemh);
2106                 maxw = MAX2(maxw, itemw);
2107                 toth += itemh;
2108                 totitem++;
2109         }
2110
2111         if (flow->number <= 0) {
2112                 /* auto compute number of columns, not very good */
2113                 if (maxw == 0) {
2114                         flow->totcol = 1;
2115                         return;
2116                 }
2117
2118                 flow->totcol = max_ii(litem->root->emw / maxw, 1);
2119                 flow->totcol = min_ii(flow->totcol, totitem);
2120         }
2121         else
2122                 flow->totcol = flow->number;
2123
2124         /* compute sizes */
2125         x = 0;
2126         y = 0;
2127         emy = 0;
2128         miny = 0;
2129
2130         maxw = 0;
2131         emh = toth / flow->totcol;
2132
2133         /* create column per column */
2134         col = 0;
2135         for (item = litem->items.first; item; item = item->next) {
2136                 ui_item_size(item, &itemw, &itemh);
2137
2138                 y -= itemh + style->buttonspacey;
2139                 miny = min_ii(miny, y);
2140                 emy -= itemh;
2141                 maxw = max_ii(itemw, maxw);
2142
2143                 /* decide to go to next one */
2144                 if (col < flow->totcol - 1 && emy <= -emh) {
2145                         x += maxw + litem->space;
2146                         maxw = 0;
2147                         y = 0;
2148                         emy = 0; /* need to reset height again for next column */
2149                         col++;
2150                 }
2151         }
2152
2153         litem->w = x;
2154         litem->h = litem->y - miny;
2155 }
2156
2157 static void ui_litem_layout_column_flow(uiLayout *litem)
2158 {
2159         uiStyle *style = litem->root->style;
2160         uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem;
2161         uiItem *item;
2162         int col, x, y, w, emh, emy, miny, itemw, itemh;
2163         int toth, totitem, offset;
2164
2165         /* compute max needed width and total height */
2166         toth = 0;
2167         totitem = 0;
2168         for (item = litem->items.first; item; item = item->next) {
2169                 ui_item_size(item, &itemw, &itemh);
2170                 toth += itemh;
2171                 totitem++;
2172         }
2173
2174         /* compute sizes */
2175         x = litem->x;
2176         y = litem->y;
2177         emy = 0;
2178         miny = 0;
2179
2180         w = litem->w - (flow->totcol - 1) * style->columnspace;
2181         emh = toth / flow->totcol;
2182
2183         /* create column per column */
2184         col = 0;
2185         for (item = litem->items.first; item; item = item->next) {
2186                 ui_item_size(item, NULL, &itemh);
2187                 itemw = ui_item_fit(1, x - litem->x, flow->totcol, w, col == flow->totcol - 1, litem->alignment, &offset);
2188         
2189                 y -= itemh;
2190                 emy -= itemh;
2191                 ui_item_position(item, x + offset, y, itemw, itemh);
2192                 y -= style->buttonspacey;
2193                 miny = min_ii(miny, y);
2194
2195                 /* decide to go to next one */
2196                 if (col < flow->totcol - 1 && emy <= -emh) {
2197                         x += itemw + style->columnspace;
2198                         y = litem->y;
2199                         emy = 0; /* need to reset height again for next column */
2200                         col++;
2201                 }
2202         }
2203
2204         litem->h = litem->y - miny;
2205         litem->x = x;
2206         litem->y = miny;
2207 }
2208
2209 /* free layout */
2210 static void ui_litem_estimate_absolute(uiLayout *litem)
2211 {
2212         uiItem *item;
2213         int itemx, itemy, itemw, itemh, minx, miny;
2214
2215         minx = 1e6;
2216         miny = 1e6;
2217         litem->w = 0;
2218         litem->h = 0;
2219
2220         for (item = litem->items.first; item; item = item->next) {
2221                 ui_item_offset(item, &itemx, &itemy);
2222                 ui_item_size(item, &itemw, &itemh);
2223
2224                 minx = min_ii(minx, itemx);
2225                 miny = min_ii(miny, itemy);
2226
2227                 litem->w = MAX2(litem->w, itemx + itemw);
2228                 litem->h = MAX2(litem->h, itemy + itemh);
2229         }
2230
2231         litem->w -= minx;
2232         litem->h -= miny;
2233 }
2234
2235 static void ui_litem_layout_absolute(uiLayout *litem)
2236 {
2237         uiItem *item;
2238         float scalex = 1.0f, scaley = 1.0f;
2239         int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth;
2240
2241         minx = 1e6;
2242         miny = 1e6;
2243         totw = 0;
2244         toth = 0;
2245
2246         for (item = litem->items.first; item; item = item->next) {
2247                 ui_item_offset(item, &itemx, &itemy);
2248                 ui_item_size(item, &itemw, &itemh);
2249
2250                 minx = min_ii(minx, itemx);
2251                 miny = min_ii(miny, itemy);
2252
2253                 totw = max_ii(totw, itemx + itemw);
2254                 toth = max_ii(toth, itemy + itemh);
2255         }
2256
2257         totw -= minx;
2258         toth -= miny;
2259
2260         if (litem->w && totw > 0)
2261                 scalex = (float)litem->w / (float)totw;
2262         if (litem->h && toth > 0)
2263                 scaley = (float)litem->h / (float)toth;
2264         
2265         x = litem->x;
2266         y = litem->y - scaley * toth;
2267
2268         for (item = litem->items.first; item; item = item->next) {
2269                 ui_item_offset(item, &itemx, &itemy);
2270                 ui_item_size(item, &itemw, &itemh);
2271
2272                 if (scalex != 1.0f) {
2273                         newx = (itemx - minx) * scalex;
2274                         itemw = (itemx - minx + itemw) * scalex - newx;
2275                         itemx = minx + newx;
2276                 }
2277
2278                 if (scaley != 1.0f) {
2279                         newy = (itemy - miny) * scaley;
2280                         itemh = (itemy - miny + itemh) * scaley - newy;
2281                         itemy = miny + newy;
2282                 }
2283
2284                 ui_item_position(item, x + itemx - minx, y + itemy - miny, itemw, itemh);
2285         }
2286
2287         litem->w = scalex * totw;
2288         litem->h = litem->y - y;
2289         litem->x = x + litem->w;
2290         litem->y = y;
2291 }
2292
2293 /* split layout */
2294 static void ui_litem_estimate_split(uiLayout *litem)
2295 {
2296         ui_litem_estimate_row(litem);
2297 }
2298
2299 static void ui_litem_layout_split(uiLayout *litem)
2300 {
2301         uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem;
2302         uiItem *item;
2303         float percentage;
2304         const int tot = BLI_countlist(&litem->items);
2305         int itemh, x, y, w, colw = 0;
2306
2307         if (tot == 0)
2308                 return;
2309
2310         x = litem->x;
2311         y = litem->y;
2312
2313         percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage;
2314         
2315         w = (litem->w - (tot - 1) * litem->space);
2316         colw = w * percentage;
2317         colw = MAX2(colw, 0);
2318
2319         for (item = litem->items.first; item; item = item->next) {
2320                 ui_item_size(item, NULL, &itemh);
2321
2322                 ui_item_position(item, x, y - itemh, colw, itemh);
2323                 x += colw;
2324
2325                 if (item->next) {
2326                         colw = (w - (int)(w * percentage)) / (tot - 1);
2327                         colw = MAX2(colw, 0);
2328
2329                         x += litem->space;
2330                 }
2331         }
2332
2333         litem->w = x - litem->x;
2334         litem->h = litem->y - y;
2335         litem->x = x;
2336         litem->y = y;
2337 }
2338
2339 /* overlap layout */
2340 static void ui_litem_estimate_overlap(uiLayout *litem)
2341 {
2342         uiItem *item;
2343         int itemw, itemh;
2344
2345         litem->w = 0;
2346         litem->h = 0;
2347
2348         for (item = litem->items.first; item; item = item->next) {
2349                 ui_item_size(item, &itemw, &itemh);
2350
2351                 litem->w = MAX2(itemw, litem->w);
2352                 litem->h = MAX2(itemh, litem->h);
2353         }
2354 }
2355
2356 static void ui_litem_layout_overlap(uiLayout *litem)
2357 {
2358         uiItem *item;
2359         int itemw, itemh, x, y;
2360
2361         x = litem->x;
2362         y = litem->y;
2363
2364         for (item = litem->items.first; item; item = item->next) {
2365                 ui_item_size(item, &itemw, &itemh);
2366                 ui_item_position(item, x, y - itemh, litem->w, itemh);
2367
2368                 litem->h = MAX2(litem->h, itemh);
2369         }
2370
2371         litem->x = x;
2372         litem->y = y - litem->h;
2373 }
2374
2375 /* layout create functions */
2376 uiLayout *uiLayoutRow(uiLayout *layout, int align)
2377 {
2378         uiLayout *litem;
2379
2380         litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
2381         litem->item.type = ITEM_LAYOUT_ROW;
2382         litem->root = layout->root;
2383         litem->align = align;
2384         litem->active = true;
2385         litem->enabled = true;
2386         litem->context = layout->context;
2387         litem->space = (align) ? 0 : layout->root->style->buttonspacex;
2388         litem->redalert = layout->redalert;
2389         litem->w = layout->w;
2390         BLI_addtail(&layout->items, litem);
2391
2392         uiBlockSetCurLayout(layout->root->block, litem);
2393
2394         return litem;
2395 }
2396
2397 uiLayout *uiLayoutColumn(uiLayout *layout, int align)
2398 {
2399         uiLayout *litem;
2400
2401         litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
2402         litem->item.type = ITEM_LAYOUT_COLUMN;
2403         litem->root = layout->root;
2404         litem->align = align;
2405         litem->active = true;
2406         litem->enabled = true;
2407         litem->context = layout->context;
2408         litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
2409         litem->redalert = layout->redalert;
2410         litem->w = layout->w;
2411         BLI_addtail(&layout->items, litem);
2412
2413         uiBlockSetCurLayout(layout->root->block, litem);
2414
2415         return litem;
2416 }
2417
2418 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
2419 {
2420         uiLayoutItemFlow *flow;
2421
2422         flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
2423         flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW;
2424         flow->litem.root = layout->root;
2425         flow->litem.align = align;
2426         flow->litem.active = true;
2427         flow->litem.enabled = true;
2428         flow->litem.context = layout->context;
2429         flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
2430         flow->litem.redalert = layout->redalert;
2431         flow->litem.w = layout->w;
2432         flow->number = number;
2433         BLI_addtail(&layout->items, flow);
2434
2435         uiBlockSetCurLayout(layout->root->block, &flow->litem);
2436
2437         return &flow->litem;
2438 }
2439
2440 static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
2441 {
2442         uiLayoutItemBx *box;
2443
2444         box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
2445         box->litem.item.type = ITEM_LAYOUT_BOX;
2446         box->litem.root = layout->root;
2447         box->litem.active = 1;
2448         box->litem.enabled = 1;
2449         box->litem.context = layout->context;
2450         box->litem.space = layout->root->style->columnspace;
2451         box->litem.redalert = layout->redalert;
2452         box->litem.w = layout->w;
2453         BLI_addtail(&layout->items, box);
2454
2455         uiBlockSetCurLayout(layout->root->block, &box->litem);
2456
2457         box->roundbox = uiDefBut(layout->root->block, type, 0, "", 0, 0, 0, 0, NULL, 0.0, 0.0, 0, 0, "");
2458
2459         return box;
2460 }
2461
2462 uiLayout *uiLayoutBox(uiLayout *layout)
2463 {
2464         return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
2465 }
2466
2467 /* Check all buttons defined in this layout, and set any button flagged as UI_BUT_LIST_ITEM as active/selected.
2468  * Needed to handle correctly text colors of active (selected) list item.
2469  */
2470 void ui_layout_list_set_labels_active(uiLayout *layout)
2471 {
2472         uiButtonItem *bitem;
2473         for (bitem = layout->items.first; bitem; bitem = bitem->item.next) {
2474                 if (bitem->item.type != ITEM_BUTTON) {
2475                         ui_layout_list_set_labels_active((uiLayout *)(&bitem->item));
2476                 }
2477                 else if (bitem->but->flag & UI_BUT_LIST_ITEM) {
2478                         uiButSetFlag(bitem->but, UI_SELECT);
2479                 }
2480         }
2481 }
2482
2483 uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
2484                           PropertyRNA *actprop)
2485 {
2486         uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX);
2487         uiBut *but = box->roundbox;
2488
2489         but->custom_data = ui_list;
2490
2491         but->rnasearchpoin = *ptr;
2492         but->rnasearchprop = prop;
2493         but->rnapoin = *actptr;
2494         but->rnaprop = actprop;
2495
2496         /* Resizing data. */
2497         /* Note: we can't use usual "num button" value handling, as it only tries rnapoin when it is non-NULL... :/
2498          *       So just setting but->poin, not but->pointype.
2499          */
2500         but->poin = (void *)&ui_list->list_grip;
2501         but->hardmin = but->softmin = 0.0f;
2502         but->hardmax = but->softmax = 1000.0f; /* Should be more than enough! */
2503         but->a1 = 0.0f;
2504
2505         /* only for the undo string */
2506         if (but->flag & UI_BUT_UNDO) {
2507                 but->tip = RNA_property_description(actprop);
2508         }
2509
2510         return (uiLayout *)box;
2511 }
2512
2513 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align)
2514 {
2515         uiLayout *litem;
2516
2517         litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
2518         litem->item.type = ITEM_LAYOUT_ABSOLUTE;
2519         litem->root = layout->root;
2520         litem->align = align;
2521         litem->active = 1;
2522         litem->enabled = 1;
2523         litem->context = layout->context;
2524         litem->redalert = layout->redalert;
2525         BLI_addtail(&layout->items, litem);
2526
2527         uiBlockSetCurLayout(layout->root->block, litem);
2528
2529         return litem;
2530 }
2531
2532 uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout)
2533 {
2534         uiBlock *block;
2535
2536         block = uiLayoutGetBlock(layout);
2537         uiLayoutAbsolute(layout, false);
2538
2539         return block;
2540 }
2541
2542 uiLayout *uiLayoutOverlap(uiLayout *layout)
2543 {
2544         uiLayout *litem;
2545
2546         litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
2547         litem->item.type = ITEM_LAYOUT_OVERLAP;
2548         litem->root = layout->root;
2549         litem->active = true;
2550         litem->enabled = true;
2551         litem->context = layout->context;
2552         litem->redalert = layout->redalert;
2553         BLI_addtail(&layout->items, litem);
2554
2555         uiBlockSetCurLayout(layout->root->block, litem);
2556
2557         return litem;
2558 }
2559
2560 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align)
2561 {
2562         uiLayoutItemSplit *split;
2563
2564         split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
2565         split->litem.item.type = ITEM_LAYOUT_SPLIT;
2566         split->litem.root = layout->root;
2567         split->litem.align = align;
2568         split->litem.active = true;
2569         split->litem.enabled = true;
2570         split->litem.context = layout->context;
2571         split->litem.space = layout->root->style->columnspace;
2572         split->litem.redalert = layout->redalert;
2573         split->litem.w = layout->w;
2574         split->percentage = percentage;
2575         BLI_addtail(&layout->items, split);
2576
2577         uiBlockSetCurLayout(layout->root->block, &split->litem);
2578
2579         return &split->litem;
2580 }
2581
2582 void uiLayoutSetActive(uiLayout *layout, bool active)
2583 {
2584         layout->active = active;
2585 }
2586
2587 void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
2588 {
2589         layout->enabled = enabled;
2590 }
2591
2592 void uiLayoutSetRedAlert(uiLayout *layout, bool redalert)
2593 {
2594         layout->redalert = redalert;
2595 }
2596
2597 void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect)
2598 {
2599         layout->keepaspect = keepaspect;
2600 }
2601
2602 void uiLayoutSetAlignment(uiLayout *layout, char alignment)
2603 {
2604         layout->alignment = alignment;
2605 }
2606
2607 void uiLayoutSetScaleX(uiLayout *layout, float scale)
2608 {
2609         layout->scale[0] = scale;
2610 }
2611
2612 void uiLayoutSetScaleY(uiLayout *layout, float scale)
2613 {
2614         layout->scale[1] = scale;
2615 }
2616
2617 bool uiLayoutGetActive(uiLayout *layout)
2618 {
2619         return layout->active;
2620 }
2621
2622 bool uiLayoutGetEnabled(uiLayout *layout)
2623 {
2624         return layout->enabled;
2625 }
2626
2627 bool uiLayoutGetRedAlert(uiLayout *layout)
2628 {
2629         return layout->redalert;
2630 }
2631
2632 bool uiLayoutGetKeepAspect(uiLayout *layout)
2633 {
2634         return layout->keepaspect;
2635 }
2636
2637 int uiLayoutGetAlignment(uiLayout *layout)
2638 {
2639         return layout->alignment;
2640 }
2641
2642 int uiLayoutGetWidth(uiLayout *layout)
2643 {
2644         return layout->w;
2645 }
2646
2647 float uiLayoutGetScaleX(uiLayout *layout)
2648 {
2649         return layout->scale[0];
2650 }
2651
2652 float uiLayoutGetScaleY(uiLayout *layout)
2653 {
2654         return layout->scale[1];
2655 }
2656
2657 /********************** Layout *******************/
2658
2659 static void ui_item_scale(uiLayout *litem, const float scale[2])
2660 {
2661         uiItem *item;
2662         int x, y, w, h;
2663
2664         for (item = litem->items.last; item; item = item->prev) {
2665                 ui_item_size(item, &w, &h);
2666                 ui_item_offset(item, &x, &y);
2667
2668                 if (scale[0] != 0.0f) {
2669                         x *= scale[0];
2670                         w *= scale[0];
2671                 }
2672
2673                 if (scale[1] != 0.0f) {
2674                         y *= scale[1];
2675                         h *= scale[1];
2676                 }
2677
2678                 ui_item_position(item, x, y, w, h);
2679         }
2680 }
2681
2682 static void ui_item_estimate(uiItem *item)
2683 {
2684         uiItem *subitem;
2685
2686         if (item->type != ITEM_BUTTON) {
2687                 uiLayout *litem = (uiLayout *)item;
2688
2689                 for (subitem = litem->items.first; subitem; subitem = subitem->next)
2690                         ui_item_estimate(subitem);
2691
2692                 if (litem->items.first == NULL)
2693                         return;
2694
2695                 if (litem->scale[0] != 0.0f || litem->scale[1] != 0.0f)
2696                         ui_item_scale(litem, litem->scale);
2697
2698                 switch (litem->item.type) {
2699                         case ITEM_LAYOUT_COLUMN:
2700                                 ui_litem_estimate_column(litem);
2701                                 break;
2702                         case ITEM_LAYOUT_COLUMN_FLOW:
2703                                 ui_litem_estimate_column_flow(litem);
2704                                 break;
2705                         case ITEM_LAYOUT_ROW:
2706                                 ui_litem_estimate_row(litem);
2707                                 break;
2708                         case ITEM_LAYOUT_BOX:
2709                                 ui_litem_estimate_box(litem);
2710                                 break;
2711                         case ITEM_LAYOUT_ROOT:
2712                                 ui_litem_estimate_root(litem);
2713                                 break;
2714                         case ITEM_LAYOUT_ABSOLUTE:
2715                                 ui_litem_estimate_absolute(litem);
2716                                 break;
2717                         case ITEM_LAYOUT_SPLIT:
2718                                 ui_litem_estimate_split(litem);
2719                                 break;
2720                         case ITEM_LAYOUT_OVERLAP:
2721                                 ui_litem_estimate_overlap(litem);
2722                                 break;
2723                         default:
2724                                 break;
2725                 }
2726         }
2727 }
2728
2729 static void ui_item_align(uiLayout *litem, short nr)
2730 {
2731         uiItem *item;
2732         uiButtonItem *bitem;
2733         uiLayoutItemBx *box;
2734
2735         for (item = litem->items.last; item; item = item->prev) {
2736                 if (item->type == ITEM_BUTTON) {
2737                         bitem = (uiButtonItem *)item;
2738                         if (ui_but_can_align(bitem->but))
2739                                 if (!bitem->but->alignnr)
2740                                         bitem->but->alignnr = nr;
2741                 }
2742                 else if (item->type == ITEM_LAYOUT_ABSOLUTE) {
2743                         /* pass */
2744                 }
2745                 else if (item->type == ITEM_LAYOUT_OVERLAP) {
2746                         /* pass */
2747                 }
2748                 else if (item->type == ITEM_LAYOUT_BOX) {
2749                         box = (uiLayoutItemBx *)item;
2750                         box->roundbox->alignnr = nr;
2751                         BLI_remlink(&litem->root->block->buttons, box->roundbox);
2752                         BLI_addhead(&litem->root->block->buttons, box->roundbox);
2753                 }
2754                 else if (((uiLayout *)item)->align) {
2755                         ui_item_align((uiLayout *)item, nr);
2756                 }
2757         }
2758 }
2759
2760 static void ui_item_flag(uiLayout *litem, int flag)
2761 {
2762         uiItem *item;
2763         uiButtonItem *bitem;
2764
2765         for (item = litem->items.last; item; item = item->prev) {
2766                 if (item->type == ITEM_BUTTON) {
2767                         bitem = (uiButtonItem *)item;
2768                         bitem->but->flag |= flag;
2769                 }
2770                 else
2771                         ui_item_flag((uiLayout *)item, flag);
2772         }
2773 }
2774
2775 static void ui_item_layout(uiItem *item)
2776 {
2777         uiItem *subitem;
2778
2779         if (item->type != ITEM_BUTTON) {
2780                 uiLayout *litem = (uiLayout *)item;
2781
2782                 if (litem->items.first == NULL)
2783                         return;
2784
2785                 if (litem->align)
2786                         ui_item_align(litem, ++litem->root->block->alignnr);
2787                 if (!litem->active)
2788                         ui_item_flag(litem, UI_BUT_INACTIVE);
2789                 if (!litem->enabled)
2790                         ui_item_flag(litem, UI_BUT_DISABLED);
2791
2792                 switch (litem->item.type) {
2793                         case ITEM_LAYOUT_COLUMN:
2794                                 ui_litem_layout_column(litem);
2795                                 break;
2796                         case ITEM_LAYOUT_COLUMN_FLOW:
2797                                 ui_litem_layout_column_flow(litem);
2798                                 break;
2799                         case ITEM_LAYOUT_ROW:
2800                                 ui_litem_layout_row(litem);
2801                                 break;
2802                         case ITEM_LAYOUT_BOX:
2803                                 ui_litem_layout_box(litem);
2804                                 break;
2805                         case ITEM_LAYOUT_ROOT:
2806                                 ui_litem_layout_root(litem);
2807                                 break;
2808                         case ITEM_LAYOUT_ABSOLUTE:
2809                                 ui_litem_layout_absolute(litem);
2810                                 break;
2811                         case ITEM_LAYOUT_SPLIT:
2812                                 ui_litem_layout_split(litem);
2813                                 break;
2814                         case ITEM_LAYOUT_OVERLAP:
2815                                 ui_litem_layout_overlap(litem);
2816                                 break;
2817                         default:
2818                                 break;
2819                 }
2820
2821                 for (subitem = litem->items.first; subitem; subitem = subitem->next)
2822                         ui_item_layout(subitem);
2823         }
2824 }
2825
2826 static void ui_layout_end(uiBlock *block, uiLayout *layout, int *x, int *y)
2827 {
2828         if (layout->root->handlefunc)
2829                 uiBlockSetHandleFunc(block, layout->root->handlefunc, layout->root->argv);
2830
2831         ui_item_estimate(&layout->item);
2832         ui_item_layout(&layout->item);
2833
2834         if (x) *x = layout->x;
2835         if (y) *y = layout->y;
2836 }
2837
2838 static void ui_layout_free(uiLayout *layout)
2839 {
2840         uiItem *item, *next;
2841
2842         for (item = layout->items.first; item; item = next) {
2843                 next = item->next;
2844
2845                 if (item->type == ITEM_BUTTON)
2846                         MEM_freeN(item);
2847                 else
2848                         ui_layout_free((uiLayout *)item);
2849         }
2850
2851         MEM_freeN(layout);
2852 }
2853
2854 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, uiStyle *style)
2855 {
2856         uiLayout *layout;
2857         uiLayoutRoot *root;
2858
2859         root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot");
2860         root->type = type;
2861         root->style = style;
2862         root->block = block;
2863         root->opcontext = WM_OP_INVOKE_REGION_WIN;
2864
2865         layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
2866         layout->item.type = ITEM_LAYOUT_ROOT;
2867
2868         layout->x = x;
2869         layout->y = y;
2870         layout->root = root;
2871         layout->space = style->templatespace;
2872         layout->active = 1;
2873         layout->enabled = 1;
2874         layout->context = NULL;
2875
2876         if (type == UI_LAYOUT_MENU)
2877                 layout->space = 0;
2878
2879         if (dir == UI_LAYOUT_HORIZONTAL) {
2880                 layout->h = size;
2881                 layout->root->emh = em * UI_UNIT_Y;
2882         }
2883         else {
2884                 layout->w = size;
2885                 layout->root->emw = em * UI_UNIT_X;
2886         }
2887
2888         block->curlayout = layout;
2889         root->layout = layout;
2890         BLI_addtail(&block->layouts, root);
2891         
2892         return layout;
2893 }
2894
2895 uiBlock *uiLayoutGetBlock(uiLayout *layout)
2896 {
2897         return layout->root->block;
2898 }
2899
2900 int uiLayoutGetOperatorContext(uiLayout *layout)
2901 {
2902         return layout->root->opcontext;
2903 }
2904
2905
2906 void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout)
2907 {
2908         block->curlayout = layout;
2909 }
2910
2911 void ui_layout_add_but(uiLayout *layout, uiBut *but)
2912 {
2913         uiButtonItem *bitem;
2914         
2915         bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem");
2916         bitem->item.type = ITEM_BUTTON;
2917         bitem->but = but;
2918         BLI_addtail(&layout->items, bitem);
2919
2920         if (layout->context) {
2921                 but->context = layout->context;
2922                 but->context->used = true;
2923         }
2924 }
2925
2926 void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
2927 {
2928         layout->root->opcontext = opcontext;
2929 }
2930
2931 void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv)
2932 {
2933         layout->root->handlefunc = handlefunc;
2934         layout->root->argv = argv;
2935 }
2936
2937 void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
2938 {
2939         uiLayoutRoot *root;
2940
2941         if (x) *x = 0;
2942         if (y) *y = 0;
2943
2944         block->curlayout = NULL;
2945
2946         for (root = block->layouts.first; root; root = root->next) {
2947                 /* NULL in advance so we don't interfere when adding button */
2948                 ui_layout_end(block, root->layout, x, y);
2949                 ui_layout_free(root->layout);
2950         }
2951
2952         BLI_freelistN(&block->layouts);
2953
2954         /* XXX silly trick, interface_templates.c doesn't get linked
2955          * because it's not used by other files in this module? */
2956         {
2957                 UI_template_fix_linking();
2958         }
2959 }
2960
2961 void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
2962 {
2963         uiBlock *block = layout->root->block;
2964         layout->context = CTX_store_add(&block->contexts, name, ptr);
2965 }
2966
2967 void uiLayoutContextCopy(uiLayout *layout, bContextStore *context)
2968 {
2969         uiBlock *block = layout->root->block;
2970         layout->context = CTX_store_add_all(&block->contexts, context);
2971 }
2972
2973
2974 /* introspect funcs */
2975 #include "BLI_dynstr.h"
2976
2977 static void ui_intro_button(DynStr *ds, uiButtonItem *bitem)
2978 {
2979         uiBut *but = bitem->but;
2980         BLI_dynstr_appendf(ds, "'type':%d, ", but->type); /* see ~ UI_interface.h:200 */
2981         BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
2982         BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : "");  /* not exactly needed, rna has this */
2983
2984         if (but->optype) {
2985                 char *opstr = WM_operator_pystring_ex(but->block->evil_C, NULL, false, true, but->optype, but->opptr);
2986                 BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
2987                 MEM_freeN(opstr);
2988         }
2989
2990         if (but->rnaprop) {
2991                 BLI_dynstr_appendf(ds, "'rna':'%s.%s[%d]', ", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop), but->rnaindex);
2992         }
2993
2994 }
2995
2996 static void ui_intro_items(DynStr *ds, ListBase *lb)
2997 {
2998         uiItem *item;
2999
3000         BLI_dynstr_append(ds, "[");
3001
3002         for (item = lb->first; item; item = item->next) {
3003
3004                 BLI_dynstr_append(ds, "{");
3005
3006                 /* could also use the INT but this is nicer*/
3007                 switch (item->type) {
3008                         case ITEM_BUTTON:             BLI_dynstr_append(ds, "'type':'BUTTON', "); break;
3009                         case ITEM_LAYOUT_ROW:         BLI_dynstr_append(ds, "'type':'ROW', "); break;
3010                         case ITEM_LAYOUT_COLUMN:      BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
3011                         case ITEM_LAYOUT_COLUMN_FLOW: BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
3012                         case ITEM_LAYOUT_ROW_FLOW:    BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
3013                         case ITEM_LAYOUT_BOX:         BLI_dynstr_append(ds, "'type':'BOX', "); break;
3014                         case ITEM_LAYOUT_ABSOLUTE:    BLI_dynstr_append(ds, "'type':'ABSOLUTE', "); break;
3015                         case ITEM_LAYOUT_SPLIT:       BLI_dynstr_append(ds, "'type':'SPLIT', "); break;
3016                         case ITEM_LAYOUT_OVERLAP:     BLI_dynstr_append(ds, "'type':'OVERLAP', "); break;
3017                         case ITEM_LAYOUT_ROOT:        BLI_dynstr_append(ds, "'type':'ROOT', "); break;
3018                         default:                      BLI_dynstr_append(ds, "'type':'UNKNOWN', "); break;
3019                 }
3020
3021                 switch (item->type) {
3022                         case ITEM_BUTTON:
3023                                 ui_intro_button(ds, (uiButtonItem *)item);
3024                                 break;
3025                         default:
3026                                 BLI_dynstr_append(ds, "'items':");
3027                                 ui_intro_items(ds, &((uiLayout *)item)->items);
3028                                 break;
3029                 }
3030
3031                 BLI_dynstr_append(ds, "}");
3032
3033                 if (item != lb->last)
3034                         BLI_dynstr_append(ds, ", ");
3035         }
3036         BLI_dynstr_append(ds, "], ");
3037 }
3038
3039 static void ui_intro_uiLayout(DynStr *ds, uiLayout *layout)
3040 {
3041         ui_intro_items(ds, &layout->items);
3042 }
3043
3044 static char *str = NULL;  /* XXX, constant re-freeing, far from ideal. */
3045 const char *uiLayoutIntrospect(uiLayout *layout)
3046 {
3047         DynStr *ds = BLI_dynstr_new();
3048
3049         if (str) {
3050                 MEM_freeN(str);
3051         }
3052
3053         ui_intro_uiLayout(ds, layout);
3054
3055         str = BLI_dynstr_get_cstring(ds);
3056         BLI_dynstr_free(ds);
3057
3058         return str;
3059 }
3060
3061 #ifdef USE_OP_RESET_BUT
3062 static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, void *UNUSED(arg_dummy2))
3063 {
3064         WM_operator_properties_reset((wmOperator *)op_pt);
3065 }
3066 #endif
3067
3068 /* this function does not initialize the layout, functions can be called on the layout before and after */
3069 void uiLayoutOperatorButs(const bContext *C, uiLayout *layout, wmOperator *op,
3070                           bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
3071                           const char label_align, const short flag)
3072 {
3073         if (!op->properties) {
3074                 IDPropertyTemplate val = {0};
3075                 op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
3076         }
3077
3078         if (flag & UI_LAYOUT_OP_SHOW_TITLE) {
3079                 uiItemL(layout, RNA_struct_ui_name(op->type->srna), ICON_NONE);
3080         }
3081
3082         /* poll() on this operator may still fail, at the moment there is no nice feedback when this happens
3083          * just fails silently */
3084         if (!WM_operator_repeat_check(C, op)) {
3085                 uiBlockSetButLock(uiLayoutGetBlock(layout), true, "Operator can't' redo");
3086
3087                 /* XXX, could give some nicer feedback or not show redo panel at all? */
3088                 uiItemL(layout, IFACE_("* Redo Unsupported *"), ICON_NONE);
3089         }
3090
3091         /* menu */
3092         if (op->type->flag & OPTYPE_PRESET) {
3093                 /* XXX, no simple way to get WM_MT_operator_presets.bl_label from python! Label remains the same always! */
3094                 PointerRNA op_ptr;
3095                 uiLayout *row;
3096
3097                 uiLayoutGetBlock(layout)->ui_operator = op;
3098
3099                 row = uiLayoutRow(layout, true);
3100                 uiItemM(row, (bContext *)C, "WM_MT_operator_presets", NULL, ICON_NONE);
3101
3102                 WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
3103                 RNA_string_set(&op_ptr, "operator", op->type->idname);
3104                 uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMIN, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
3105
3106                 WM_operator_properties_create(&op_ptr, "WM_OT_operator_preset_add");
3107                 RNA_string_set(&op_ptr, "operator", op->type->idname);
3108                 RNA_boolean_set(&op_ptr, "remove_active", true);
3109                 uiItemFullO(row, "WM_OT_operator_preset_add", "", ICON_ZOOMOUT, op_ptr.data, WM_OP_INVOKE_DEFAULT, 0);
3110         }
3111
3112         if (op->type->ui) {
3113                 op->layout = layout;
3114                 op->type->ui((bContext *)C, op);
3115                 op->layout = NULL;
3116
3117                 /* UI_LAYOUT_OP_SHOW_EMPTY ignored */
3118         }
3119         else {
3120                 wmWindowManager *wm = CTX_wm_manager(C);
3121                 PointerRNA ptr;
3122                 int empty;
3123
3124                 RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
3125
3126                 /* main draw call */
3127                 empty = uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0;
3128
3129                 if (empty && (flag & UI_LAYOUT_OP_SHOW_EMPTY)) {
3130                         uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
3131                 }
3132         }
3133
3134 #ifdef USE_OP_RESET_BUT
3135         /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
3136          * but this is not so important if this button is drawn in those cases
3137          * (which isn't all that likely anyway) - campbell */
3138         if (op->properties->len) {
3139                 uiBlock *block;
3140                 uiBut *but;
3141                 uiLayout *col; /* needed to avoid alignment errors with previous buttons */
3142
3143                 col = uiLayoutColumn(layout, false);
3144                 block = uiLayoutGetBlock(col);
3145                 but = uiDefIconTextBut(block, BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
3146                                        NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults"));
3147                 uiButSetFunc(but, ui_layout_operator_buts__reset_cb, op, NULL);
3148         }
3149 #endif
3150
3151         /* set various special settings for buttons */
3152         {
3153                 uiBlock *block = uiLayoutGetBlock(layout);
3154                 const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
3155                 uiBut *but;
3156
3157                 
3158                 for (but = block->buttons.first; but; but = but->next) {
3159                         /* no undo for buttons for operator redo panels */
3160                         uiButClearFlag(but, UI_BUT_UNDO);
3161                         
3162                         /* only for popups, see [#36109] */
3163
3164                         /* if button is operator's default property, and a text-field, enable focus for it
3165                          *      - this is used for allowing operators with popups to rename stuff with fewer clicks
3166                          */
3167                         if (is_popup) {
3168                                 if ((but->rnaprop == op->type->prop) && (but->type == TEX)) {
3169                                         uiButSetFocusOnEnter(CTX_wm_window(C), but);
3170                                 }
3171                         }
3172                 }
3173         }
3174 }
3175
3176 /* this is a bit of a hack but best keep it in one place at least */
3177 MenuType *uiButGetMenuType(uiBut *but)
3178 {
3179         if (but->menu_create_func == ui_item_menutype_func) {
3180                 return (MenuType *)but->poin;
3181         }
3182         else {
3183                 return NULL;
3184         }
3185 }