Cleanup: replace comments with meaningful variable names
[blender.git] / source / blender / editors / interface / interface_layout.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup edinterface
19  */
20
21 #include <limits.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_screen_types.h"
30 #include "DNA_armature_types.h"
31 #include "DNA_userdef_types.h"
32
33 #include "BLI_alloca.h"
34 #include "BLI_listbase.h"
35 #include "BLI_string.h"
36 #include "BLI_rect.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_math.h"
39
40 #include "BLT_translation.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_idprop.h"
45 #include "BKE_screen.h"
46 #include "BKE_animsys.h"
47
48 #include "RNA_access.h"
49
50 #include "UI_interface.h"
51
52 #include "ED_armature.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "interface_intern.h"
58
59 /* Show an icon button after each RNA button to use to quickly set keyframes,
60  * this is a way to display animation/driven/override status, see T54951. */
61 #define UI_PROP_DECORATE
62 /* Alternate draw mode where some buttons can use single icon width,
63  * giving more room for the text at the expense of nicely aligned text. */
64 #define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
65
66 /************************ Structs and Defines *************************/
67
68 #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement) \
69   if (ot == NULL) { \
70     ui_item_disabled(layout, _opname); \
71     RNA_warning("'%s' unknown operator", _opname); \
72     return_statement; \
73   } \
74   (void)0
75
76 #define UI_ITEM_PROP_SEP_DIVIDE 0.5f
77
78 /* uiLayoutRoot */
79
80 typedef struct uiLayoutRoot {
81   struct uiLayoutRoot *next, *prev;
82
83   int type;
84   int opcontext;
85
86   int emw, emh;
87   int padding;
88
89   uiMenuHandleFunc handlefunc;
90   void *argv;
91
92   uiStyle *style;
93   uiBlock *block;
94   uiLayout *layout;
95 } uiLayoutRoot;
96
97 /* Item */
98
99 typedef enum uiItemType {
100   ITEM_BUTTON,
101
102   ITEM_LAYOUT_ROW,
103   ITEM_LAYOUT_COLUMN,
104   ITEM_LAYOUT_COLUMN_FLOW,
105   ITEM_LAYOUT_ROW_FLOW,
106   ITEM_LAYOUT_GRID_FLOW,
107   ITEM_LAYOUT_BOX,
108   ITEM_LAYOUT_ABSOLUTE,
109   ITEM_LAYOUT_SPLIT,
110   ITEM_LAYOUT_OVERLAP,
111   ITEM_LAYOUT_RADIAL,
112
113   ITEM_LAYOUT_ROOT
114 #if 0
115       TEMPLATE_COLUMN_FLOW,
116   TEMPLATE_SPLIT,
117   TEMPLATE_BOX,
118
119   TEMPLATE_HEADER,
120   TEMPLATE_HEADER_ID,
121 #endif
122 } uiItemType;
123
124 typedef struct uiItem {
125   void *next, *prev;
126   uiItemType type;
127   int flag;
128 } uiItem;
129
130 enum {
131   UI_ITEM_FIXED = 1 << 0,
132   UI_ITEM_MIN = 1 << 1,
133
134   UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
135   UI_ITEM_PROP_SEP = 1 << 3,
136   /* Show an icon button next to each property (to set keyframes, show status).
137    * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
138   UI_ITEM_PROP_DECORATE = 1 << 4,
139   UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5,
140 };
141
142 typedef struct uiButtonItem {
143   uiItem item;
144   uiBut *but;
145 } uiButtonItem;
146
147 struct uiLayout {
148   uiItem item;
149
150   uiLayoutRoot *root;
151   bContextStore *context;
152   ListBase items;
153
154   /** Sub layout to add child items, if not the layout itself. */
155   uiLayout *child_items_layout;
156
157   int x, y, w, h;
158   float scale[2];
159   short space;
160   bool align;
161   bool active;
162   bool active_default;
163   bool activate_init;
164   bool enabled;
165   bool redalert;
166   bool keepaspect;
167   /** For layouts inside gridflow, they and their items shall never have a fixed maximal size. */
168   bool variable_size;
169   char alignment;
170   char emboss;
171   /** for fixed width or height to avoid UI size changes */
172   float units[2];
173 };
174
175 typedef struct uiLayoutItemFlow {
176   uiLayout litem;
177   int number;
178   int totcol;
179 } uiLayoutItemFlow;
180
181 typedef struct uiLayoutItemGridFlow {
182   uiLayout litem;
183
184   /* Extra parameters */
185   bool row_major;    /* Fill first row first, instead of filling first column first. */
186   bool even_columns; /* Same width for all columns. */
187   bool even_rows;    /* Same height for all rows. */
188   /**
189    * - If positive, absolute fixed number of columns.
190    * - If 0, fully automatic (based on available width).
191    * - If negative, automatic but only generates number of columns/rows
192    *   multiple of given (absolute) value.
193    */
194   int columns_len;
195
196   /* Pure internal runtime storage. */
197   int tot_items, tot_columns, tot_rows;
198 } uiLayoutItemGridFlow;
199
200 typedef struct uiLayoutItemBx {
201   uiLayout litem;
202   uiBut *roundbox;
203 } uiLayoutItemBx;
204
205 typedef struct uiLayoutItemSplit {
206   uiLayout litem;
207   float percentage;
208 } uiLayoutItemSplit;
209
210 typedef struct uiLayoutItemRoot {
211   uiLayout litem;
212 } uiLayoutItemRoot;
213
214 /************************** Item ***************************/
215
216 static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_NAME_STR])
217 {
218   int len = strlen(name);
219
220   if (len != 0 && len + 1 < UI_MAX_NAME_STR) {
221     memcpy(namestr, name, len);
222     namestr[len] = ':';
223     namestr[len + 1] = '\0';
224     return namestr;
225   }
226
227   return name;
228 }
229
230 static int ui_item_fit(
231     int item, int pos, int all, int available, bool is_last, int alignment, float *extra_pixel)
232 {
233   /* available == 0 is unlimited */
234   if (ELEM(0, available, all)) {
235     return item;
236   }
237
238   if (all > available) {
239     /* contents is bigger than available space */
240     if (is_last) {
241       return available - pos;
242     }
243     else {
244       float width = *extra_pixel + (item * available) / (float)all;
245       *extra_pixel = width - (int)width;
246       return (int)width;
247     }
248   }
249   else {
250     /* contents is smaller or equal to available space */
251     if (alignment == UI_LAYOUT_ALIGN_EXPAND) {
252       if (is_last) {
253         return available - pos;
254       }
255       else {
256         float width = *extra_pixel + (item * available) / (float)all;
257         *extra_pixel = width - (int)width;
258         return (int)width;
259       }
260     }
261     else {
262       return item;
263     }
264   }
265 }
266
267 /* variable button size in which direction? */
268 #define UI_ITEM_VARY_X 1
269 #define UI_ITEM_VARY_Y 2
270
271 static int ui_layout_vary_direction(uiLayout *layout)
272 {
273   return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
274            (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
275               UI_ITEM_VARY_X :
276               UI_ITEM_VARY_Y);
277 }
278
279 static bool ui_layout_variable_size(uiLayout *layout)
280 {
281   /* Note that this code is probably a bit flacky, we'd probably want to know whether it's
282    * variable in X and/or Y, etc. But for now it mimics previous one,
283    * with addition of variable flag set for children of gridflow layouts. */
284   return ui_layout_vary_direction(layout) == UI_ITEM_VARY_X || layout->variable_size;
285 }
286
287 /* estimated size of text + icon */
288 static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact)
289 {
290   bool variable;
291   const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f);
292
293   if (icon && !name[0]) {
294     return unit_x; /* icon only */
295   }
296
297   variable = ui_layout_variable_size(layout);
298
299   if (variable) {
300     if (!icon && !name[0]) {
301       return unit_x; /* No icon or name. */
302     }
303     if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
304       layout->item.flag |= UI_ITEM_MIN;
305     }
306     const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
307     /* it may seem odd that the icon only adds (unit_x / 4)
308      * but taking margins into account its fine */
309     return (UI_fontstyle_string_width(fstyle, name) +
310             (unit_x * ((compact ? 1.25f : 1.50f) + (icon ? 0.25f : 0.0f))));
311   }
312   else {
313     return unit_x * 10;
314   }
315 }
316
317 static void ui_item_size(uiItem *item, int *r_w, int *r_h)
318 {
319   if (item->type == ITEM_BUTTON) {
320     uiButtonItem *bitem = (uiButtonItem *)item;
321
322     if (r_w) {
323       *r_w = BLI_rctf_size_x(&bitem->but->rect);
324     }
325     if (r_h) {
326       *r_h = BLI_rctf_size_y(&bitem->but->rect);
327     }
328   }
329   else {
330     uiLayout *litem = (uiLayout *)item;
331
332     if (r_w) {
333       *r_w = litem->w;
334     }
335     if (r_h) {
336       *r_h = litem->h;
337     }
338   }
339 }
340
341 static void ui_item_offset(uiItem *item, int *r_x, int *r_y)
342 {
343   if (item->type == ITEM_BUTTON) {
344     uiButtonItem *bitem = (uiButtonItem *)item;
345
346     if (r_x) {
347       *r_x = bitem->but->rect.xmin;
348     }
349     if (r_y) {
350       *r_y = bitem->but->rect.ymin;
351     }
352   }
353   else {
354     if (r_x) {
355       *r_x = 0;
356     }
357     if (r_y) {
358       *r_y = 0;
359     }
360   }
361 }
362
363 static void ui_item_position(uiItem *item, int x, int y, int w, int h)
364 {
365   if (item->type == ITEM_BUTTON) {
366     uiButtonItem *bitem = (uiButtonItem *)item;
367
368     bitem->but->rect.xmin = x;
369     bitem->but->rect.ymin = y;
370     bitem->but->rect.xmax = x + w;
371     bitem->but->rect.ymax = y + h;
372
373     ui_but_update(bitem->but); /* for strlen */
374   }
375   else {
376     uiLayout *litem = (uiLayout *)item;
377
378     litem->x = x;
379     litem->y = y + h;
380     litem->w = w;
381     litem->h = h;
382   }
383 }
384
385 static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
386 {
387   if (item->type == ITEM_BUTTON) {
388     uiButtonItem *bitem = (uiButtonItem *)item;
389
390     bitem->but->rect.xmin += delta_xmin;
391     bitem->but->rect.xmax += delta_xmax;
392
393     ui_but_update(bitem->but); /* for strlen */
394   }
395   else {
396     uiLayout *litem = (uiLayout *)item;
397
398     if (delta_xmin > 0) {
399       litem->x += delta_xmin;
400     }
401     else {
402       litem->w += delta_xmax;
403     }
404   }
405 }
406
407 /******************** Special RNA Items *********************/
408
409 int uiLayoutGetLocalDir(const uiLayout *layout)
410 {
411   switch (layout->item.type) {
412     case ITEM_LAYOUT_ROW:
413     case ITEM_LAYOUT_ROOT:
414     case ITEM_LAYOUT_OVERLAP:
415       return UI_LAYOUT_HORIZONTAL;
416     case ITEM_LAYOUT_COLUMN:
417     case ITEM_LAYOUT_COLUMN_FLOW:
418     case ITEM_LAYOUT_GRID_FLOW:
419     case ITEM_LAYOUT_SPLIT:
420     case ITEM_LAYOUT_ABSOLUTE:
421     case ITEM_LAYOUT_BOX:
422     default:
423       return UI_LAYOUT_VERTICAL;
424   }
425 }
426
427 static uiLayout *ui_item_local_sublayout(uiLayout *test, uiLayout *layout, bool align)
428 {
429   uiLayout *sub;
430
431   if (uiLayoutGetLocalDir(test) == UI_LAYOUT_HORIZONTAL) {
432     sub = uiLayoutRow(layout, align);
433   }
434   else {
435     sub = uiLayoutColumn(layout, align);
436   }
437
438   sub->space = 0;
439   return sub;
440 }
441
442 static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
443 {
444   wmWindow *win = CTX_wm_window(C);
445   uiBut *but = arg_but, *cbut;
446   PointerRNA *ptr = &but->rnapoin;
447   PropertyRNA *prop = but->rnaprop;
448   int i, index = POINTER_AS_INT(arg_index);
449   int shift = win->eventstate->shift;
450   int len = RNA_property_array_length(ptr, prop);
451
452   if (!shift) {
453     RNA_property_boolean_set_index(ptr, prop, index, true);
454
455     for (i = 0; i < len; i++) {
456       if (i != index) {
457         RNA_property_boolean_set_index(ptr, prop, i, 0);
458       }
459     }
460
461     RNA_property_update(C, ptr, prop);
462
463     for (cbut = but->block->buttons.first; cbut; cbut = cbut->next) {
464       ui_but_update(cbut);
465     }
466   }
467 }
468
469 /* create buttons for an item with an RNA array */
470 static void ui_item_array(uiLayout *layout,
471                           uiBlock *block,
472                           const char *name,
473                           int icon,
474                           PointerRNA *ptr,
475                           PropertyRNA *prop,
476                           int len,
477                           int x,
478                           int y,
479                           int w,
480                           int UNUSED(h),
481                           bool expand,
482                           bool slider,
483                           bool toggle,
484                           bool icon_only,
485                           bool compact,
486                           bool show_text)
487 {
488   uiStyle *style = layout->root->style;
489   uiBut *but;
490   PropertyType type;
491   PropertySubType subtype;
492   uiLayout *sub;
493   uint a, b;
494
495   /* retrieve type and subtype */
496   type = RNA_property_type(prop);
497   subtype = RNA_property_subtype(prop);
498
499   sub = ui_item_local_sublayout(layout, layout, 1);
500   UI_block_layout_set_current(block, sub);
501
502   /* create label */
503   if (name[0] && show_text) {
504     uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
505   }
506
507   /* create buttons */
508   if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
509     /* special check for layer layout */
510     int butw, buth, unit;
511     int cols = (len >= 20) ? 2 : 1;
512     const uint colbuts = len / (2 * cols);
513     uint layer_used = 0;
514     uint layer_active = 0;
515
516     UI_block_layout_set_current(block, uiLayoutAbsolute(layout, false));
517
518     unit = UI_UNIT_X * 0.75;
519     butw = unit;
520     buth = unit;
521
522     if (ptr->type == &RNA_Armature) {
523       bArmature *arm = (bArmature *)ptr->data;
524
525       layer_used = arm->layer_used;
526
527       if (arm->edbo) {
528         if (arm->act_edbone) {
529           layer_active |= arm->act_edbone->layer;
530         }
531       }
532       else {
533         if (arm->act_bone) {
534           layer_active |= arm->act_bone->layer;
535         }
536       }
537     }
538
539     for (b = 0; b < cols; b++) {
540       UI_block_align_begin(block);
541
542       for (a = 0; a < colbuts; a++) {
543         const int layer_num = a + b * colbuts;
544         const uint layer_flag = (1u << layer_num);
545
546         if (layer_used & layer_flag) {
547           if (layer_active & layer_flag) {
548             icon = ICON_LAYER_ACTIVE;
549           }
550           else {
551             icon = ICON_LAYER_USED;
552           }
553         }
554         else {
555           icon = ICON_BLANK1;
556         }
557
558         but = uiDefAutoButR(
559             block, ptr, prop, layer_num, "", icon, x + butw * a, y + buth, butw, buth);
560         if (subtype == PROP_LAYER_MEMBER) {
561           UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
562         }
563       }
564       for (a = 0; a < colbuts; a++) {
565         const int layer_num = a + len / 2 + b * colbuts;
566         const uint layer_flag = (1u << layer_num);
567
568         if (layer_used & layer_flag) {
569           if (layer_active & layer_flag) {
570             icon = ICON_LAYER_ACTIVE;
571           }
572           else {
573             icon = ICON_LAYER_USED;
574           }
575         }
576         else {
577           icon = ICON_BLANK1;
578         }
579
580         but = uiDefAutoButR(block, ptr, prop, layer_num, "", icon, x + butw * a, y, butw, buth);
581         if (subtype == PROP_LAYER_MEMBER) {
582           UI_but_func_set(but, ui_layer_but_cb, but, POINTER_FROM_INT(layer_num));
583         }
584       }
585       UI_block_align_end(block);
586
587       x += colbuts * butw + style->buttonspacex;
588     }
589   }
590   else if (subtype == PROP_MATRIX) {
591     int totdim, dim_size[3]; /* 3 == RNA_MAX_ARRAY_DIMENSION */
592     int row, col;
593
594     UI_block_layout_set_current(block, uiLayoutAbsolute(layout, true));
595
596     totdim = RNA_property_array_dimension(ptr, prop, dim_size);
597     if (totdim != 2) {
598       /* Only 2D matrices supported in UI so far. */
599       return;
600     }
601
602     w /= dim_size[0];
603     /* h /= dim_size[1]; */ /* UNUSED */
604
605     for (a = 0; a < len; a++) {
606       col = a % dim_size[0];
607       row = a / dim_size[0];
608
609       but = uiDefAutoButR(block,
610                           ptr,
611                           prop,
612                           a,
613                           "",
614                           ICON_NONE,
615                           x + w * col,
616                           y + (dim_size[1] * UI_UNIT_Y) - (row * UI_UNIT_Y),
617                           w,
618                           UI_UNIT_Y);
619       if (slider && but->type == UI_BTYPE_NUM) {
620         but->type = UI_BTYPE_NUM_SLIDER;
621       }
622     }
623   }
624   else if (subtype == PROP_DIRECTION && !expand) {
625     uiDefButR_prop(block,
626                    UI_BTYPE_UNITVEC,
627                    0,
628                    name,
629                    x,
630                    y,
631                    UI_UNIT_X * 3,
632                    UI_UNIT_Y * 3,
633                    ptr,
634                    prop,
635                    -1,
636                    0,
637                    0,
638                    -1,
639                    -1,
640                    NULL);
641   }
642   else {
643     /* note, this block of code is a bit arbitrary and has just been made
644      * to work with common cases, but may need to be re-worked */
645
646     /* special case, boolean array in a menu, this could be used in a more generic way too */
647     if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand) {
648       uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
649     }
650     else {
651       bool *boolarr = NULL;
652
653       /* even if 'expand' is fale, expanding anyway */
654
655       /* layout for known array subtypes */
656       char str[3] = {'\0'};
657
658       if (!icon_only && show_text) {
659         if (type != PROP_BOOLEAN) {
660           str[1] = ':';
661         }
662       }
663
664       /* show checkboxes for rna on a non-emboss block (menu for eg) */
665       if (type == PROP_BOOLEAN &&
666           ELEM(layout->root->block->dt, UI_EMBOSS_NONE, UI_EMBOSS_PULLDOWN)) {
667         boolarr = MEM_callocN(sizeof(bool) * len, __func__);
668         RNA_property_boolean_get_array(ptr, prop, boolarr);
669       }
670
671       const char *str_buf = show_text ? str : "";
672       for (a = 0; a < len; a++) {
673         int width_item;
674
675         if (!icon_only && show_text) {
676           str[0] = RNA_property_array_item_char(prop, a);
677         }
678         if (boolarr) {
679           icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
680         }
681
682         width_item = ((compact && type == PROP_BOOLEAN) ?
683                           min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) :
684                           w);
685
686         but = uiDefAutoButR(block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y);
687         if (slider && but->type == UI_BTYPE_NUM) {
688           but->type = UI_BTYPE_NUM_SLIDER;
689         }
690         if (toggle && but->type == UI_BTYPE_CHECKBOX) {
691           but->type = UI_BTYPE_TOGGLE;
692         }
693         if ((a == 0) && (subtype == PROP_AXISANGLE)) {
694           UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
695         }
696       }
697
698       if (boolarr) {
699         MEM_freeN(boolarr);
700       }
701     }
702   }
703
704   UI_block_layout_set_current(block, layout);
705 }
706
707 static void ui_item_enum_expand_handle(bContext *C, void *arg1, void *arg2)
708 {
709   wmWindow *win = CTX_wm_window(C);
710
711   if (!win->eventstate->shift) {
712     uiBut *but = (uiBut *)arg1;
713     int enum_value = POINTER_AS_INT(arg2);
714
715     int current_value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
716     if (!(current_value & enum_value)) {
717       current_value = enum_value;
718     }
719     else {
720       current_value &= enum_value;
721     }
722     RNA_property_enum_set(&but->rnapoin, but->rnaprop, current_value);
723   }
724 }
725 static void ui_item_enum_expand_exec(uiLayout *layout,
726                                      uiBlock *block,
727                                      PointerRNA *ptr,
728                                      PropertyRNA *prop,
729                                      const char *uiname,
730                                      int h,
731                                      int but_type,
732                                      bool icon_only)
733 {
734   /* XXX: The way this function currently handles uiname parameter
735    * is insane and inconsistent with general UI API:
736    *
737    * - uiname is the *enum property* label.
738    * - when it is NULL or empty, we do not draw *enum items* labels,
739    *   this doubles the icon_only parameter.
740    * - we *never* draw (i.e. really use) the enum label uiname, it is just used as a mere flag!
741    *
742    * Unfortunately, fixing this implies an API "soft break", so better to defer it for later... :/
743    * - mont29
744    */
745
746   uiBut *but;
747   uiLayout *layout_radial = NULL;
748   const EnumPropertyItem *item, *item_array;
749   const char *name;
750   int itemw, icon, value;
751   bool free;
752   bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
753
754   BLI_assert(RNA_property_type(prop) == PROP_ENUM);
755
756   if (radial) {
757     RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
758   }
759   else {
760     RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
761   }
762
763   /* we dont want nested rows, cols in menus */
764   if (radial) {
765     if (layout->root->layout == layout) {
766       layout_radial = uiLayoutRadial(layout);
767       UI_block_layout_set_current(block, layout_radial);
768     }
769     else {
770       if (layout->item.type == ITEM_LAYOUT_RADIAL) {
771         layout_radial = layout;
772       }
773       UI_block_layout_set_current(block, layout);
774     }
775   }
776   else if (layout->root->type != UI_LAYOUT_MENU) {
777     UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1));
778   }
779   else {
780     UI_block_layout_set_current(block, layout);
781   }
782
783   for (item = item_array; item->identifier; item++) {
784     const bool is_first = item == item_array;
785
786     if (!item->identifier[0]) {
787       const EnumPropertyItem *next_item = item + 1;
788
789       /* Separate items, potentially with a label. */
790       if (next_item->identifier) {
791         /* Item without identifier but with name:
792          * Add group label for the following items. */
793         if (item->name) {
794           if (!is_first) {
795             uiItemS(block->curlayout);
796           }
797           uiItemL(block->curlayout, item->name, item->icon);
798         }
799         else if (radial && layout_radial) {
800           uiItemS(layout_radial);
801         }
802         else {
803           uiItemS(block->curlayout);
804         }
805       }
806       continue;
807     }
808
809     name = (!uiname || uiname[0]) ? item->name : "";
810     icon = item->icon;
811     value = item->value;
812     itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0);
813
814     if (icon && name[0] && !icon_only) {
815       but = uiDefIconTextButR_prop(
816           block, but_type, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
817     }
818     else if (icon) {
819       but = uiDefIconButR_prop(block,
820                                but_type,
821                                0,
822                                icon,
823                                0,
824                                0,
825                                (is_first) ? itemw : ceilf(itemw - U.pixelsize),
826                                h,
827                                ptr,
828                                prop,
829                                -1,
830                                0,
831                                value,
832                                -1,
833                                -1,
834                                NULL);
835     }
836     else {
837       but = uiDefButR_prop(
838           block, but_type, 0, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL);
839     }
840
841     if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
842       /* If this is set, assert since we're clobbering someone elses callback. */
843       BLI_assert(but->func == NULL);
844       UI_but_func_set(but, ui_item_enum_expand_handle, but, POINTER_FROM_INT(value));
845     }
846
847     if (uiLayoutGetLocalDir(layout) != UI_LAYOUT_HORIZONTAL) {
848       but->drawflag |= UI_BUT_TEXT_LEFT;
849     }
850
851     /* Allow quick, inaccurate swipe motions to switch tabs
852      * (no need to keep cursor over them). */
853     if (but_type == UI_BTYPE_TAB) {
854       but->flag |= UI_BUT_DRAG_LOCK;
855     }
856   }
857   UI_block_layout_set_current(block, layout);
858
859   if (free) {
860     MEM_freeN((void *)item_array);
861   }
862 }
863 static void ui_item_enum_expand(uiLayout *layout,
864                                 uiBlock *block,
865                                 PointerRNA *ptr,
866                                 PropertyRNA *prop,
867                                 const char *uiname,
868                                 int h,
869                                 bool icon_only)
870 {
871   ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only);
872 }
873 static void ui_item_enum_expand_tabs(uiLayout *layout,
874                                      bContext *C,
875                                      uiBlock *block,
876                                      PointerRNA *ptr,
877                                      PropertyRNA *prop,
878                                      const char *uiname,
879                                      int h,
880                                      bool icon_only)
881 {
882   uiBut *last = block->buttons.last;
883
884   ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
885   BLI_assert(last != block->buttons.last);
886   for (uiBut *tab = last ? last->next : block->buttons.first; tab; tab = tab->next) {
887     UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C)));
888   }
889 }
890
891 /* callback for keymap item change button */
892 static void ui_keymap_but_cb(bContext *UNUSED(C), void *but_v, void *UNUSED(key_v))
893 {
894   uiBut *but = but_v;
895
896   RNA_boolean_set(&but->rnapoin, "shift", (but->modifier_key & KM_SHIFT) != 0);
897   RNA_boolean_set(&but->rnapoin, "ctrl", (but->modifier_key & KM_CTRL) != 0);
898   RNA_boolean_set(&but->rnapoin, "alt", (but->modifier_key & KM_ALT) != 0);
899   RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
900 }
901
902 /**
903  * Create label + button for RNA property
904  *
905  * \param w_hint: For varying width layout, this becomes the label width.
906  *                Otherwise it's used to fit both items into it.
907  */
908 static uiBut *ui_item_with_label(uiLayout *layout,
909                                  uiBlock *block,
910                                  const char *name,
911                                  int icon,
912                                  PointerRNA *ptr,
913                                  PropertyRNA *prop,
914                                  int index,
915                                  int x,
916                                  int y,
917                                  int w_hint,
918                                  int h,
919                                  int flag)
920 {
921   uiLayout *sub;
922   uiBut *but = NULL;
923   PropertyType type;
924   PropertySubType subtype;
925   int prop_but_width = w_hint;
926   const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
927
928   /* Always align item with label since text is already given enough space not to overlap. */
929   sub = uiLayoutRow(layout, true);
930   UI_block_layout_set_current(block, sub);
931
932   if (name[0]) {
933     int w_label;
934
935     if (use_prop_sep) {
936       w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
937     }
938     else {
939       if (ui_layout_variable_size(layout)) {
940         /* w_hint is width for label in this case.
941          * Use a default width for property button(s) */
942         prop_but_width = UI_UNIT_X * 5;
943         w_label = w_hint;
944       }
945       else {
946         w_label = w_hint / 3;
947       }
948     }
949
950     uiBut *but_label = uiDefBut(
951         block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
952     if (use_prop_sep) {
953       but_label->drawflag |= UI_BUT_TEXT_RIGHT;
954       but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
955     }
956   }
957
958   type = RNA_property_type(prop);
959   subtype = RNA_property_subtype(prop);
960
961   if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
962     UI_block_layout_set_current(block, uiLayoutRow(sub, true));
963     but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h);
964
965     /* BUTTONS_OT_file_browse calls UI_context_active_but_prop_get_filebrowser */
966     uiDefIconButO(block,
967                   UI_BTYPE_BUT,
968                   subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" :
969                                             "BUTTONS_OT_file_browse",
970                   WM_OP_INVOKE_DEFAULT,
971                   ICON_FILEBROWSER,
972                   x,
973                   y,
974                   UI_UNIT_X,
975                   h,
976                   NULL);
977   }
978   else if (flag & UI_ITEM_R_EVENT) {
979     but = uiDefButR_prop(block,
980                          UI_BTYPE_KEY_EVENT,
981                          0,
982                          name,
983                          x,
984                          y,
985                          prop_but_width,
986                          h,
987                          ptr,
988                          prop,
989                          index,
990                          0,
991                          0,
992                          -1,
993                          -1,
994                          NULL);
995   }
996   else if (flag & UI_ITEM_R_FULL_EVENT) {
997     if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
998       char buf[128];
999
1000       WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf));
1001
1002       but = uiDefButR_prop(block,
1003                            UI_BTYPE_HOTKEY_EVENT,
1004                            0,
1005                            buf,
1006                            x,
1007                            y,
1008                            prop_but_width,
1009                            h,
1010                            ptr,
1011                            prop,
1012                            0,
1013                            0,
1014                            0,
1015                            -1,
1016                            -1,
1017                            NULL);
1018       UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
1019       if (flag & UI_ITEM_R_IMMEDIATE) {
1020         UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
1021       }
1022     }
1023   }
1024   else {
1025     const char *str = (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "";
1026     but = uiDefAutoButR(block, ptr, prop, index, str, icon, x, y, prop_but_width, h);
1027   }
1028
1029 #ifdef UI_PROP_DECORATE
1030   /* Only for alignment. */
1031   if (layout->item.flag & UI_ITEM_PROP_SEP) {
1032     if ((layout->item.flag & UI_ITEM_PROP_DECORATE) &&
1033         (layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0) {
1034       uiItemL(sub, NULL, ICON_BLANK1);
1035     }
1036   }
1037 #endif /* UI_PROP_DECORATE */
1038
1039   UI_block_layout_set_current(block, layout);
1040   return but;
1041 }
1042
1043 void UI_context_active_but_prop_get_filebrowser(const bContext *C,
1044                                                 PointerRNA *r_ptr,
1045                                                 PropertyRNA **r_prop,
1046                                                 bool *r_is_undo)
1047 {
1048   ARegion *ar = CTX_wm_region(C);
1049   uiBlock *block;
1050   uiBut *but, *prevbut = NULL;
1051
1052   memset(r_ptr, 0, sizeof(*r_ptr));
1053   *r_prop = NULL;
1054   *r_is_undo = false;
1055
1056   if (!ar) {
1057     return;
1058   }
1059
1060   for (block = ar->uiblocks.first; block; block = block->next) {
1061     for (but = block->buttons.first; but; but = but->next) {
1062       if (but && but->rnapoin.data) {
1063         if (RNA_property_type(but->rnaprop) == PROP_STRING) {
1064           prevbut = but;
1065         }
1066       }
1067
1068       /* find the button before the active one */
1069       if ((but->flag & UI_BUT_LAST_ACTIVE) && prevbut) {
1070         *r_ptr = prevbut->rnapoin;
1071         *r_prop = prevbut->rnaprop;
1072         *r_is_undo = (prevbut->flag & UI_BUT_UNDO) != 0;
1073         return;
1074       }
1075     }
1076   }
1077 }
1078
1079 /********************* Button Items *************************/
1080
1081 /**
1082  * Update a buttons tip with an enum's description if possible.
1083  */
1084 static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
1085 {
1086   if (but->tip == NULL || but->tip[0] == '\0') {
1087     if (item->description && item->description[0]) {
1088       but->tip = item->description;
1089     }
1090   }
1091 }
1092
1093 /* disabled item */
1094 static void ui_item_disabled(uiLayout *layout, const char *name)
1095 {
1096   uiBlock *block = layout->root->block;
1097   uiBut *but;
1098   int w;
1099
1100   UI_block_layout_set_current(block, layout);
1101
1102   if (!name) {
1103     name = "";
1104   }
1105
1106   w = ui_text_icon_width(layout, name, 0, 0);
1107
1108   but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
1109   but->flag |= UI_BUT_DISABLED;
1110   but->disabled_info = "";
1111 }
1112
1113 /**
1114  * Operator Item
1115  * \param r_opptr: Optional, initialize with operator properties when not NULL.
1116  * Will always be written to even in the case of errors.
1117  */
1118 static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
1119                                  wmOperatorType *ot,
1120                                  const char *name,
1121                                  int icon,
1122                                  IDProperty *properties,
1123                                  int context,
1124                                  int flag,
1125                                  PointerRNA *r_opptr)
1126 {
1127   /* Take care to fill 'r_opptr' whatever happens. */
1128   uiBlock *block = layout->root->block;
1129   uiBut *but;
1130   int w;
1131
1132   if (!name) {
1133     if (ot && ot->srna && (flag & UI_ITEM_R_ICON_ONLY) == 0) {
1134       name = RNA_struct_ui_name(ot->srna);
1135     }
1136     else {
1137       name = "";
1138     }
1139   }
1140
1141   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
1142     icon = ICON_BLANK1;
1143   }
1144
1145   /* create button */
1146   UI_block_layout_set_current(block, layout);
1147
1148   w = ui_text_icon_width(layout, name, icon, 0);
1149
1150   int prev_emboss = layout->emboss;
1151   if (flag & UI_ITEM_R_NO_BG) {
1152     layout->emboss = UI_EMBOSS_NONE;
1153   }
1154
1155   /* create the button */
1156   if (icon) {
1157     if (name[0]) {
1158       but = uiDefIconTextButO_ptr(
1159           block, UI_BTYPE_BUT, ot, context, icon, name, 0, 0, w, UI_UNIT_Y, NULL);
1160     }
1161     else {
1162       but = uiDefIconButO_ptr(block, UI_BTYPE_BUT, ot, context, icon, 0, 0, w, UI_UNIT_Y, NULL);
1163     }
1164   }
1165   else {
1166     but = uiDefButO_ptr(block, UI_BTYPE_BUT, ot, context, name, 0, 0, w, UI_UNIT_Y, NULL);
1167   }
1168
1169   assert(but->optype != NULL);
1170
1171   /* text alignment for toolbar buttons */
1172   if ((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon) {
1173     but->drawflag |= UI_BUT_TEXT_LEFT;
1174   }
1175
1176   if (flag & UI_ITEM_R_NO_BG) {
1177     layout->emboss = prev_emboss;
1178   }
1179
1180   if (flag & UI_ITEM_O_DEPRESS) {
1181     but->flag |= UI_SELECT_DRAW;
1182   }
1183
1184   if (layout->redalert) {
1185     UI_but_flag_enable(but, UI_BUT_REDALERT);
1186   }
1187
1188   if (layout->active_default) {
1189     UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
1190   }
1191
1192   /* assign properties */
1193   if (properties || r_opptr) {
1194     PointerRNA *opptr = UI_but_operator_ptr_get(but);
1195     if (properties) {
1196       opptr->data = properties;
1197     }
1198     else {
1199       IDPropertyTemplate val = {0};
1200       opptr->data = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
1201     }
1202     if (r_opptr) {
1203       *r_opptr = *opptr;
1204     }
1205   }
1206
1207   return but;
1208 }
1209
1210 static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but)
1211 {
1212   uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
1213   uiLayout *layout = UI_popup_menu_layout(pup);
1214   uiBlock *block = layout->root->block;
1215   UI_popup_menu_but_set(pup, butregion, but);
1216
1217   block->flag |= UI_BLOCK_POPUP_HOLD;
1218   block->flag |= UI_BLOCK_IS_FLIP;
1219
1220   char direction = UI_DIR_DOWN;
1221   if (!but->drawstr[0]) {
1222     if (butregion->alignment == RGN_ALIGN_LEFT) {
1223       direction = UI_DIR_RIGHT;
1224     }
1225     else if (butregion->alignment == RGN_ALIGN_RIGHT) {
1226       direction = UI_DIR_LEFT;
1227     }
1228     else if (butregion->alignment == RGN_ALIGN_BOTTOM) {
1229       direction = UI_DIR_UP;
1230     }
1231     else {
1232       direction = UI_DIR_DOWN;
1233     }
1234   }
1235   UI_block_direction_set(block, direction);
1236
1237   const char *menu_id = but->hold_argN;
1238   MenuType *mt = WM_menutype_find(menu_id, true);
1239   if (mt) {
1240     uiLayoutSetContextFromBut(layout, but);
1241     UI_menutype_draw(C, mt, layout);
1242   }
1243   else {
1244     uiItemL(layout, "Menu Missing:", ICON_NONE);
1245     uiItemL(layout, menu_id, ICON_NONE);
1246   }
1247   UI_popup_menu_end(C, pup);
1248 }
1249
1250 void uiItemFullO_ptr(uiLayout *layout,
1251                      wmOperatorType *ot,
1252                      const char *name,
1253                      int icon,
1254                      IDProperty *properties,
1255                      int context,
1256                      int flag,
1257                      PointerRNA *r_opptr)
1258 {
1259   uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
1260 }
1261
1262 void uiItemFullOMenuHold_ptr(uiLayout *layout,
1263                              wmOperatorType *ot,
1264                              const char *name,
1265                              int icon,
1266                              IDProperty *properties,
1267                              int context,
1268                              int flag,
1269                              const char *menu_id,
1270                              PointerRNA *r_opptr)
1271 {
1272   uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
1273   UI_but_func_hold_set(but, ui_item_menu_hold, BLI_strdup(menu_id));
1274 }
1275
1276 void uiItemFullO(uiLayout *layout,
1277                  const char *opname,
1278                  const char *name,
1279                  int icon,
1280                  IDProperty *properties,
1281                  int context,
1282                  int flag,
1283                  PointerRNA *r_opptr)
1284 {
1285   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1286
1287   UI_OPERATOR_ERROR_RET(ot, opname, {
1288     if (r_opptr) {
1289       *r_opptr = PointerRNA_NULL;
1290     }
1291     return;
1292   });
1293
1294   uiItemFullO_ptr(layout, ot, name, icon, properties, context, flag, r_opptr);
1295 }
1296
1297 static const char *ui_menu_enumpropname(uiLayout *layout,
1298                                         PointerRNA *ptr,
1299                                         PropertyRNA *prop,
1300                                         int retval)
1301 {
1302   const EnumPropertyItem *item;
1303   bool free;
1304   const char *name;
1305
1306   RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
1307   if (RNA_enum_name(item, retval, &name)) {
1308     name = CTX_IFACE_(RNA_property_translation_context(prop), name);
1309   }
1310   else {
1311     name = "";
1312   }
1313
1314   if (free) {
1315     MEM_freeN((void *)item);
1316   }
1317
1318   return name;
1319 }
1320
1321 void uiItemEnumO_ptr(uiLayout *layout,
1322                      wmOperatorType *ot,
1323                      const char *name,
1324                      int icon,
1325                      const char *propname,
1326                      int value)
1327 {
1328   PointerRNA ptr;
1329   PropertyRNA *prop;
1330
1331   WM_operator_properties_create_ptr(&ptr, ot);
1332
1333   if ((prop = RNA_struct_find_property(&ptr, propname))) {
1334     /* pass */
1335   }
1336   else {
1337     RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1338     return;
1339   }
1340
1341   RNA_property_enum_set(&ptr, prop, value);
1342
1343   if (!name) {
1344     name = ui_menu_enumpropname(layout, &ptr, prop, value);
1345   }
1346
1347   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1348 }
1349 void uiItemEnumO(uiLayout *layout,
1350                  const char *opname,
1351                  const char *name,
1352                  int icon,
1353                  const char *propname,
1354                  int value)
1355 {
1356   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1357
1358   if (ot) {
1359     uiItemEnumO_ptr(layout, ot, name, icon, propname, value);
1360   }
1361   else {
1362     ui_item_disabled(layout, opname);
1363     RNA_warning("unknown operator '%s'", opname);
1364   }
1365 }
1366
1367 BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
1368 {
1369   return (layout->item.type == ITEM_LAYOUT_RADIAL) ||
1370          ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
1371 }
1372
1373 /**
1374  * Create ui items for enum items in \a item_array.
1375  *
1376  * A version of #uiItemsFullEnumO that takes pre-calculated item array.
1377  */
1378 void uiItemsFullEnumO_items(uiLayout *layout,
1379                             wmOperatorType *ot,
1380                             PointerRNA ptr,
1381                             PropertyRNA *prop,
1382                             IDProperty *properties,
1383                             int context,
1384                             int flag,
1385                             const EnumPropertyItem *item_array,
1386                             int totitem)
1387 {
1388   const char *propname = RNA_property_identifier(prop);
1389   if (RNA_property_type(prop) != PROP_ENUM) {
1390     RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
1391     return;
1392   }
1393
1394   uiLayout *target, *split = NULL;
1395   const EnumPropertyItem *item;
1396   uiBlock *block = layout->root->block;
1397   const bool radial = ui_layout_is_radial(layout);
1398
1399   if (radial) {
1400     target = uiLayoutRadial(layout);
1401   }
1402   else {
1403     split = uiLayoutSplit(layout, 0.0f, false);
1404     target = uiLayoutColumn(split, layout->align);
1405   }
1406
1407   int i;
1408   bool last_iter = false;
1409
1410   for (i = 1, item = item_array; item->identifier && !last_iter; i++, item++) {
1411     /* handle oversized pies */
1412     if (radial && (totitem > PIE_MAX_ITEMS) && (i >= PIE_MAX_ITEMS)) {
1413       if (item->name) { /* only visible items */
1414         const EnumPropertyItem *tmp;
1415
1416         /* Check if there are more visible items for the next level. If not, we don't
1417          * add a new level and add the remaining item instead of the 'more' button. */
1418         for (tmp = item + 1; tmp->identifier; tmp++) {
1419           if (tmp->name) {
1420             break;
1421           }
1422         }
1423
1424         if (tmp->identifier) { /* only true if loop above found item and did early-exit */
1425           ui_pie_menu_level_create(
1426               block, ot, propname, properties, item_array, totitem, context, flag);
1427           /* break since rest of items is handled in new pie level */
1428           break;
1429         }
1430         else {
1431           last_iter = true;
1432         }
1433       }
1434       else {
1435         continue;
1436       }
1437     }
1438
1439     if (item->identifier[0]) {
1440       PointerRNA tptr;
1441
1442       WM_operator_properties_create_ptr(&tptr, ot);
1443       if (properties) {
1444         if (tptr.data) {
1445           IDP_FreeProperty(tptr.data);
1446           MEM_freeN(tptr.data);
1447         }
1448         tptr.data = IDP_CopyProperty(properties);
1449       }
1450       RNA_property_enum_set(&tptr, prop, item->value);
1451
1452       uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag, NULL);
1453
1454       ui_but_tip_from_enum_item(block->buttons.last, item);
1455     }
1456     else {
1457       if (item->name) {
1458         uiBut *but;
1459
1460         if (item != item_array && !radial) {
1461           target = uiLayoutColumn(split, layout->align);
1462
1463           /* inconsistent, but menus with labels do not look good flipped */
1464           block->flag |= UI_BLOCK_NO_FLIP;
1465         }
1466
1467         if (item->icon || radial) {
1468           uiItemL(target, item->name, item->icon);
1469
1470           but = block->buttons.last;
1471         }
1472         else {
1473           /* Do not use uiItemL here, as our root layout is a menu one,
1474            * it will add a fake blank icon! */
1475           but = uiDefBut(block,
1476                          UI_BTYPE_LABEL,
1477                          0,
1478                          item->name,
1479                          0,
1480                          0,
1481                          UI_UNIT_X * 5,
1482                          UI_UNIT_Y,
1483                          NULL,
1484                          0.0,
1485                          0.0,
1486                          0,
1487                          0,
1488                          "");
1489         }
1490         ui_but_tip_from_enum_item(but, item);
1491       }
1492       else {
1493         if (radial) {
1494           /* invisible dummy button to ensure all items are
1495            * always at the same position */
1496           uiItemS(target);
1497         }
1498         else {
1499           /* XXX bug here, columns draw bottom item badly */
1500           uiItemS(target);
1501         }
1502       }
1503     }
1504   }
1505 }
1506
1507 void uiItemsFullEnumO(uiLayout *layout,
1508                       const char *opname,
1509                       const char *propname,
1510                       IDProperty *properties,
1511                       int context,
1512                       int flag)
1513 {
1514   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1515
1516   PointerRNA ptr;
1517   PropertyRNA *prop;
1518   uiBlock *block = layout->root->block;
1519
1520   if (!ot || !ot->srna) {
1521     ui_item_disabled(layout, opname);
1522     RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
1523     return;
1524   }
1525
1526   WM_operator_properties_create_ptr(&ptr, ot);
1527   /* so the context is passed to itemf functions (some need it) */
1528   WM_operator_properties_sanitize(&ptr, false);
1529   prop = RNA_struct_find_property(&ptr, propname);
1530
1531   /* don't let bad properties slip through */
1532   BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
1533
1534   if (prop && RNA_property_type(prop) == PROP_ENUM) {
1535     const EnumPropertyItem *item_array = NULL;
1536     int totitem;
1537     bool free;
1538
1539     if (ui_layout_is_radial(layout)) {
1540       /* XXX: While "_all()" guarantees spatial stability,
1541        * it's bad when an enum has > 8 items total,
1542        * but only a small subset will ever be shown at once
1543        * (e.g. Mode Switch menu, after the introduction of GP editing modes).
1544        */
1545 #if 0
1546       RNA_property_enum_items_gettexted_all(
1547           block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1548 #else
1549       RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1550 #endif
1551     }
1552     else {
1553       RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
1554     }
1555
1556     /* add items */
1557     uiItemsFullEnumO_items(layout, ot, ptr, prop, properties, context, flag, item_array, totitem);
1558
1559     if (free) {
1560       MEM_freeN((void *)item_array);
1561     }
1562
1563     /* intentionally don't touch UI_BLOCK_IS_FLIP here,
1564      * we don't know the context this is called in */
1565   }
1566   else if (prop && RNA_property_type(prop) != PROP_ENUM) {
1567     RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
1568     return;
1569   }
1570   else {
1571     RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1572     return;
1573   }
1574 }
1575
1576 void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
1577 {
1578   uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
1579 }
1580
1581 /* for use in cases where we have */
1582 void uiItemEnumO_value(uiLayout *layout,
1583                        const char *name,
1584                        int icon,
1585                        const char *opname,
1586                        const char *propname,
1587                        int value)
1588 {
1589   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1590   PointerRNA ptr;
1591   PropertyRNA *prop;
1592
1593   UI_OPERATOR_ERROR_RET(ot, opname, return );
1594
1595   WM_operator_properties_create_ptr(&ptr, ot);
1596
1597   /* enum lookup */
1598   if ((prop = RNA_struct_find_property(&ptr, propname))) {
1599     /* pass */
1600   }
1601   else {
1602     RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1603     return;
1604   }
1605
1606   RNA_property_enum_set(&ptr, prop, value);
1607
1608   /* same as uiItemEnumO */
1609   if (!name) {
1610     name = ui_menu_enumpropname(layout, &ptr, prop, value);
1611   }
1612
1613   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1614 }
1615
1616 void uiItemEnumO_string(uiLayout *layout,
1617                         const char *name,
1618                         int icon,
1619                         const char *opname,
1620                         const char *propname,
1621                         const char *value_str)
1622 {
1623   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1624   PointerRNA ptr;
1625   PropertyRNA *prop;
1626
1627   const EnumPropertyItem *item;
1628   int value;
1629   bool free;
1630
1631   UI_OPERATOR_ERROR_RET(ot, opname, return );
1632
1633   WM_operator_properties_create_ptr(&ptr, ot);
1634
1635   /* enum lookup */
1636   if ((prop = RNA_struct_find_property(&ptr, propname))) {
1637     /* no need for translations here */
1638     RNA_property_enum_items(layout->root->block->evil_C, &ptr, prop, &item, NULL, &free);
1639     if (item == NULL || RNA_enum_value_from_id(item, value_str, &value) == 0) {
1640       if (free) {
1641         MEM_freeN((void *)item);
1642       }
1643       RNA_warning(
1644           "%s.%s, enum %s not found", RNA_struct_identifier(ptr.type), propname, value_str);
1645       return;
1646     }
1647
1648     if (free) {
1649       MEM_freeN((void *)item);
1650     }
1651   }
1652   else {
1653     RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), propname);
1654     return;
1655   }
1656
1657   RNA_property_enum_set(&ptr, prop, value);
1658
1659   /* same as uiItemEnumO */
1660   if (!name) {
1661     name = ui_menu_enumpropname(layout, &ptr, prop, value);
1662   }
1663
1664   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1665 }
1666
1667 void uiItemBooleanO(uiLayout *layout,
1668                     const char *name,
1669                     int icon,
1670                     const char *opname,
1671                     const char *propname,
1672                     int value)
1673 {
1674   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1675   PointerRNA ptr;
1676
1677   UI_OPERATOR_ERROR_RET(ot, opname, return );
1678
1679   WM_operator_properties_create_ptr(&ptr, ot);
1680   RNA_boolean_set(&ptr, propname, value);
1681
1682   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1683 }
1684
1685 void uiItemIntO(uiLayout *layout,
1686                 const char *name,
1687                 int icon,
1688                 const char *opname,
1689                 const char *propname,
1690                 int value)
1691 {
1692   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1693   PointerRNA ptr;
1694
1695   UI_OPERATOR_ERROR_RET(ot, opname, return );
1696
1697   WM_operator_properties_create_ptr(&ptr, ot);
1698   RNA_int_set(&ptr, propname, value);
1699
1700   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1701 }
1702
1703 void uiItemFloatO(uiLayout *layout,
1704                   const char *name,
1705                   int icon,
1706                   const char *opname,
1707                   const char *propname,
1708                   float value)
1709 {
1710   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1711   PointerRNA ptr;
1712
1713   UI_OPERATOR_ERROR_RET(ot, opname, return );
1714
1715   WM_operator_properties_create_ptr(&ptr, ot);
1716   RNA_float_set(&ptr, propname, value);
1717
1718   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1719 }
1720
1721 void uiItemStringO(uiLayout *layout,
1722                    const char *name,
1723                    int icon,
1724                    const char *opname,
1725                    const char *propname,
1726                    const char *value)
1727 {
1728   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
1729   PointerRNA ptr;
1730
1731   UI_OPERATOR_ERROR_RET(ot, opname, return );
1732
1733   WM_operator_properties_create_ptr(&ptr, ot);
1734   RNA_string_set(&ptr, propname, value);
1735
1736   uiItemFullO_ptr(layout, ot, name, icon, ptr.data, layout->root->opcontext, 0, NULL);
1737 }
1738
1739 void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname)
1740 {
1741   uiItemFullO(layout, opname, name, icon, NULL, layout->root->opcontext, 0, NULL);
1742 }
1743
1744 /* RNA property items */
1745
1746 static void ui_item_rna_size(uiLayout *layout,
1747                              const char *name,
1748                              int icon,
1749                              PointerRNA *ptr,
1750                              PropertyRNA *prop,
1751                              int index,
1752                              bool icon_only,
1753                              bool compact,
1754                              int *r_w,
1755                              int *r_h)
1756 {
1757   PropertyType type;
1758   PropertySubType subtype;
1759   int len, w = 0, h;
1760
1761   /* arbitrary extended width by type */
1762   type = RNA_property_type(prop);
1763   subtype = RNA_property_subtype(prop);
1764   len = RNA_property_array_length(ptr, prop);
1765
1766   if (!name[0] && !icon_only) {
1767     if (ELEM(type, PROP_STRING, PROP_POINTER)) {
1768       name = "non-empty text";
1769     }
1770     else if (type == PROP_BOOLEAN) {
1771       icon = ICON_DOT;
1772     }
1773     else if (type == PROP_ENUM) {
1774       /* Find the longest enum item name, instead of using a dummy text! */
1775       const EnumPropertyItem *item, *item_array;
1776       bool free;
1777
1778       RNA_property_enum_items_gettexted(
1779           layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free);
1780       for (item = item_array; item->identifier; item++) {
1781         if (item->identifier[0]) {
1782           w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact));
1783         }
1784       }
1785       if (free) {
1786         MEM_freeN((void *)item_array);
1787       }
1788     }
1789   }
1790
1791   if (!w) {
1792     if (type == PROP_ENUM && icon_only) {
1793       w = ui_text_icon_width(layout, "", ICON_BLANK1, compact);
1794       if (index != RNA_ENUM_VALUE) {
1795         w += 0.6f * UI_UNIT_X;
1796       }
1797     }
1798     else {
1799       /* not compact for float/int buttons, looks too squashed */
1800       w = ui_text_icon_width(
1801           layout, name, icon, ELEM(type, PROP_FLOAT, PROP_INT) ? false : compact);
1802     }
1803   }
1804   h = UI_UNIT_Y;
1805
1806   /* increase height for arrays */
1807   if (index == RNA_NO_INDEX && len > 0) {
1808     if (!name[0] && icon == ICON_NONE) {
1809       h = 0;
1810     }
1811     if (layout->item.flag & UI_ITEM_PROP_SEP) {
1812       h = 0;
1813     }
1814     if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
1815       h += 2 * UI_UNIT_Y;
1816     }
1817     else if (subtype == PROP_MATRIX) {
1818       h += ceilf(sqrtf(len)) * UI_UNIT_Y;
1819     }
1820     else {
1821       h += len * UI_UNIT_Y;
1822     }
1823   }
1824   else if (ui_layout_variable_size(layout)) {
1825     if (type == PROP_BOOLEAN && name[0]) {
1826       w += UI_UNIT_X / 5;
1827     }
1828     else if (type == PROP_ENUM && !icon_only) {
1829       w += UI_UNIT_X / 4;
1830     }
1831     else if (type == PROP_FLOAT || type == PROP_INT) {
1832       w += UI_UNIT_X * 3;
1833     }
1834   }
1835
1836   *r_w = w;
1837   *r_h = h;
1838 }
1839
1840 void uiItemFullR(uiLayout *layout,
1841                  PointerRNA *ptr,
1842                  PropertyRNA *prop,
1843                  int index,
1844                  int value,
1845                  int flag,
1846                  const char *name,
1847                  int icon)
1848 {
1849   uiBlock *block = layout->root->block;
1850   uiBut *but = NULL;
1851   PropertyType type;
1852   char namestr[UI_MAX_NAME_STR];
1853   int len, w, h;
1854   bool slider, toggle, expand, icon_only, no_bg, compact;
1855   bool is_array;
1856   const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
1857
1858   /* By default 'use_prop_sep' uses a separate column for labels.
1859    * This is an exception for check-boxes otherwise only the small checkbox region is clickable.
1860    *
1861    * Keep using 'use_prop_sep' instead of disabling it entirely because
1862    * we need the ability to have decorators still. */
1863   bool use_prop_sep_split_label = use_prop_sep;
1864
1865 #ifdef UI_PROP_DECORATE
1866   struct {
1867     bool use_prop_decorate;
1868     int len;
1869     uiLayout *layout;
1870     uiBut *but;
1871   } ui_decorate = {
1872       .use_prop_decorate = (((layout->item.flag & UI_ITEM_PROP_DECORATE) != 0) &&
1873                             (use_prop_sep && ptr->id.data && id_can_have_animdata(ptr->id.data))),
1874   };
1875 #endif /* UI_PROP_DECORATE */
1876
1877   UI_block_layout_set_current(block, layout);
1878
1879   /* retrieve info */
1880   type = RNA_property_type(prop);
1881   is_array = RNA_property_array_check(prop);
1882   len = (is_array) ? RNA_property_array_length(ptr, prop) : 0;
1883
1884   icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
1885
1886   /* set name and icon */
1887   if (!name) {
1888     if (!icon_only) {
1889       name = RNA_property_ui_name(prop);
1890     }
1891     else {
1892       name = "";
1893     }
1894   }
1895
1896   if (icon == ICON_NONE) {
1897     icon = RNA_property_ui_icon(prop);
1898   }
1899
1900   if (flag & UI_ITEM_R_ICON_ONLY) {
1901     /* pass */
1902   }
1903   else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
1904     if (use_prop_sep == false) {
1905       name = ui_item_name_add_colon(name, namestr);
1906     }
1907   }
1908   else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
1909     if (use_prop_sep == false) {
1910       name = ui_item_name_add_colon(name, namestr);
1911     }
1912   }
1913   else if (type == PROP_ENUM && index != RNA_ENUM_VALUE) {
1914     if (flag & UI_ITEM_R_COMPACT) {
1915       name = "";
1916     }
1917     else {
1918       if (use_prop_sep == false) {
1919         name = ui_item_name_add_colon(name, namestr);
1920       }
1921     }
1922   }
1923
1924 #ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
1925   if (use_prop_sep) {
1926     if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
1927       use_prop_sep_split_label = false;
1928     }
1929   }
1930 #endif
1931
1932   /* menus and pie-menus don't show checkbox without this */
1933   if ((layout->root->type == UI_LAYOUT_MENU) ||
1934       /* use checkboxes only as a fallback in pie-menu's, when no icon is defined */
1935       ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE))) {
1936     int prop_flag = RNA_property_flag(prop);
1937     if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) {
1938       if (prop_flag & PROP_ICONS_CONSECUTIVE) {
1939         icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
1940       }
1941       else if (is_array) {
1942         icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT :
1943                                                                     ICON_CHECKBOX_DEHLT;
1944       }
1945       else {
1946         icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1947       }
1948     }
1949     else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
1950       int enum_value = RNA_property_enum_get(ptr, prop);
1951       if (prop_flag & PROP_ICONS_CONSECUTIVE) {
1952         icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
1953       }
1954       else if (prop_flag & PROP_ENUM_FLAG) {
1955         icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1956       }
1957       else {
1958         icon = (enum_value == value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
1959       }
1960     }
1961   }
1962
1963   if ((type == PROP_ENUM) && (RNA_property_flag(prop) & PROP_ENUM_FLAG)) {
1964     flag |= UI_ITEM_R_EXPAND;
1965   }
1966
1967   slider = (flag & UI_ITEM_R_SLIDER) != 0;
1968   toggle = (flag & UI_ITEM_R_TOGGLE) != 0;
1969   expand = (flag & UI_ITEM_R_EXPAND) != 0;
1970   no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
1971   compact = (flag & UI_ITEM_R_COMPACT) != 0;
1972
1973   /* get size */
1974   ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h);
1975
1976   int prev_emboss = layout->emboss;
1977   if (no_bg) {
1978     layout->emboss = UI_EMBOSS_NONE;
1979   }
1980
1981   /* Split the label / property. */
1982   uiLayout *layout_parent = layout;
1983   if (use_prop_sep) {
1984     uiLayout *layout_row = NULL;
1985 #ifdef UI_PROP_DECORATE
1986     if (ui_decorate.use_prop_decorate) {
1987       layout_row = uiLayoutRow(layout, true);
1988       layout_row->space = 0;
1989       ui_decorate.len = max_ii(1, len);
1990     }
1991 #endif /* UI_PROP_DECORATE */
1992
1993     if ((name[0] == '\0') || (use_prop_sep_split_label == false)) {
1994       /* Ensure we get a column when text is not set. */
1995       layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
1996       layout->space = 0;
1997     }
1998     else {
1999       const PropertySubType subtype = RNA_property_subtype(prop);
2000       uiLayout *layout_split = uiLayoutSplit(
2001           layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
2002       layout_split->space = 0;
2003       uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
2004       layout_sub->space = 0;
2005
2006       if ((index == RNA_NO_INDEX && is_array) &&
2007           ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0)) {
2008         char name_with_suffix[UI_MAX_DRAW_STR + 2];
2009         char str[2] = {'\0'};
2010         for (int a = 0; a < len; a++) {
2011           str[0] = RNA_property_array_item_char(prop, a);
2012           const bool use_prefix = (a == 0 && name && name[0]);
2013           if (use_prefix) {
2014             char *s = name_with_suffix;
2015             s += STRNCPY_RLEN(name_with_suffix, name);
2016             *s++ = ' ';
2017             *s++ = str[0];
2018             *s++ = '\0';
2019           }
2020           but = uiDefBut(block,
2021                          UI_BTYPE_LABEL,
2022                          0,
2023                          use_prefix ? name_with_suffix : str,
2024                          0,
2025                          0,
2026                          w,
2027                          UI_UNIT_Y,
2028                          NULL,
2029                          0.0,
2030                          0.0,
2031                          0,
2032                          0,
2033                          "");
2034           but->drawflag |= UI_BUT_TEXT_RIGHT;
2035           but->drawflag &= ~UI_BUT_TEXT_LEFT;
2036         }
2037       }
2038       else {
2039         if (name) {
2040           but = uiDefBut(
2041               block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
2042           but->drawflag |= UI_BUT_TEXT_RIGHT;
2043           but->drawflag &= ~UI_BUT_TEXT_LEFT;
2044         }
2045       }
2046
2047       /* Hack to add further items in a row into the second part of
2048        * the split layout, so the label part keeps a fixed size. */
2049       if (layout_parent && layout_parent->item.type == ITEM_LAYOUT_ROW) {
2050         layout_split = uiLayoutRow(layout_split, true);
2051         layout_parent->child_items_layout = layout_split;
2052       }
2053
2054       /* Watch out! We can only write into the new layout now. */
2055       if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
2056         /* Expanded enums each have their own name. */
2057
2058         /* Often expanded enum's are better arranged into a row,
2059          * so check the existing layout. */
2060         if (uiLayoutGetLocalDir(layout) == UI_LAYOUT_HORIZONTAL) {
2061           layout = uiLayoutRow(layout_split, true);
2062         }
2063         else {
2064           layout = uiLayoutColumn(layout_split, true);
2065         }
2066       }
2067       else {
2068         name = "";
2069         layout = uiLayoutColumn(layout_split, true);
2070       }
2071       layout->space = 0;
2072     }
2073
2074 #ifdef UI_PROP_DECORATE
2075     if (ui_decorate.use_prop_decorate) {
2076       ui_decorate.layout = uiLayoutColumn(layout_row, true);
2077       ui_decorate.layout->space = 0;
2078       UI_block_layout_set_current(block, layout);
2079       ui_decorate.but = block->buttons.last;
2080
2081       /* Clear after. */
2082       layout->item.flag |= UI_ITEM_PROP_DECORATE_NO_PAD;
2083     }
2084 #endif /* UI_PROP_DECORATE */
2085   }
2086   /* End split. */
2087
2088   /* array property */
2089   if (index == RNA_NO_INDEX && is_array) {
2090     ui_item_array(layout,
2091                   block,
2092                   name,
2093                   icon,
2094                   ptr,
2095                   prop,
2096                   len,
2097                   0,
2098                   0,
2099                   w,
2100                   h,
2101                   expand,
2102                   slider,
2103                   toggle,
2104                   icon_only,
2105                   compact,
2106                   !use_prop_sep_split_label);
2107   }
2108   /* enum item */
2109   else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
2110     if (icon && name[0] && !icon_only) {
2111       uiDefIconTextButR_prop(
2112           block, UI_BTYPE_ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2113     }
2114     else if (icon) {
2115       uiDefIconButR_prop(
2116           block, UI_BTYPE_ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2117     }
2118     else {
2119       uiDefButR_prop(
2120           block, UI_BTYPE_ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
2121     }
2122   }
2123   /* expanded enum */
2124   else if (type == PROP_ENUM && expand) {
2125     ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
2126   }
2127   /* property with separate label */
2128   else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
2129     but = ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag);
2130     ui_but_add_search(but, ptr, prop, NULL, NULL);
2131
2132     if (layout->redalert) {
2133       UI_but_flag_enable(but, UI_BUT_REDALERT);
2134     }
2135
2136     if (layout->activate_init) {
2137       UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
2138     }
2139   }
2140   /* single button */
2141   else {
2142     but = uiDefAutoButR(block, ptr, prop, index, name, icon, 0, 0, w, h);
2143
2144     if (slider && but->type == UI_BTYPE_NUM) {
2145       but->type = UI_BTYPE_NUM_SLIDER;
2146     }
2147
2148     if (toggle && but->type == UI_BTYPE_CHECKBOX) {
2149       but->type = UI_BTYPE_TOGGLE;
2150     }
2151
2152     if (layout->redalert) {
2153       UI_but_flag_enable(but, UI_BUT_REDALERT);
2154     }
2155
2156     if (layout->activate_init) {
2157       UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
2158     }
2159
2160     if (use_prop_sep && (use_prop_sep_split_label == false)) {
2161       /* When the button uses it's own text right align it. */
2162       but->drawflag |= UI_BUT_TEXT_RIGHT;
2163       but->drawflag &= ~UI_BUT_TEXT_LEFT;
2164     }
2165   }
2166
2167   /* Mark non-embossed textfields inside a listbox. */
2168   if (but && (block->flag & UI_BLOCK_LIST_ITEM) && (but->type == UI_BTYPE_TEXT) &&
2169       (but->dt & UI_EMBOSS_NONE)) {
2170     UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
2171   }
2172
2173 #ifdef UI_PROP_DECORATE
2174   if (ui_decorate.use_prop_decorate) {
2175     const bool is_anim = RNA_property_animateable(ptr, prop);
2176     uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
2177     uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
2178     layout_col->space = 0;
2179     layout_col->emboss = UI_EMBOSS_NONE;
2180     int i;
2181     for (i = 0; i < ui_decorate.len && but_decorate; i++) {
2182       /* The icons are set in 'ui_but_anim_flag' */
2183       if (is_anim) {
2184         but = uiDefIconBut(block,
2185                            UI_BTYPE_BUT,
2186                            0,
2187                            ICON_DOT,
2188                            0,
2189                            0,
2190                            UI_UNIT_X,
2191                            UI_UNIT_Y,
2192                            NULL,
2193                            0.0,
2194                            0.0,
2195                            0.0,
2196                            0.0,
2197                            TIP_("Animate property"));
2198         UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
2199         but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
2200       }
2201       else {
2202         /* We may show other information here in future, for now use empty space. */
2203         but = uiDefIconBut(block,
2204                            UI_BTYPE_BUT,
2205                            0,
2206                            ICON_BLANK1,
2207                            0,
2208                            0,
2209                            UI_UNIT_X,
2210                            UI_UNIT_Y,
2211                            NULL,
2212                            0.0,
2213                            0.0,
2214                            0.0,
2215                            0.0,
2216                            "");
2217         but->flag |= UI_BUT_DISABLED;
2218       }
2219       /* Order the decorator after the button we decorate, this is used so we can always
2220        * do a quick lookup. */
2221       BLI_remlink(&block->buttons, but);
2222       BLI_insertlinkafter(&block->buttons, but_decorate, but);
2223       but_decorate = but->next;
2224     }
2225     BLI_assert(ELEM(i, 1, ui_decorate.len));
2226
2227     layout->item.flag &= ~UI_ITEM_PROP_DECORATE_NO_PAD;
2228   }
2229 #endif /* UI_PROP_DECORATE */
2230
2231   if (no_bg) {
2232     layout->emboss = prev_emboss;
2233   }
2234
2235   /* ensure text isn't added to icon_only buttons */
2236   if (but && icon_only) {
2237     BLI_assert(but->str[0] == '\0');
2238   }
2239 }
2240
2241 void uiItemR(
2242     uiLayout *layout, PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
2243 {
2244   PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2245
2246   if (!prop) {
2247     ui_item_disabled(layout, propname);
2248     RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2249     return;
2250   }
2251
2252   uiItemFullR(layout, ptr, prop, RNA_NO_INDEX, 0, flag, name, icon);
2253 }
2254
2255 /**
2256  * Use a wrapper function since re-implementing all the logic in this function would be messy.
2257  */
2258 void uiItemFullR_with_popover(uiLayout *layout,
2259                               PointerRNA *ptr,
2260                               PropertyRNA *prop,
2261                               int index,
2262                               int value,
2263                               int flag,
2264                               const char *name,
2265                               int icon,
2266                               const char *panel_type)
2267 {
2268   uiBlock *block = layout->root->block;
2269   uiBut *but = block->buttons.last;
2270   uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
2271   but = but->next;
2272   while (but) {
2273     if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
2274       ui_but_rna_menu_convert_to_panel_type(but, panel_type);
2275       break;
2276     }
2277     but = but->next;
2278   }
2279   if (but == NULL) {
2280     const char *propname = RNA_property_identifier(prop);
2281     ui_item_disabled(layout, panel_type);
2282     RNA_warning("property could not use a popover: %s.%s (%s)",
2283                 RNA_struct_identifier(ptr->type),
2284                 propname,
2285                 panel_type);
2286   }
2287 }
2288
2289 void uiItemFullR_with_menu(uiLayout *layout,
2290                            PointerRNA *ptr,
2291                            PropertyRNA *prop,
2292                            int index,
2293                            int value,
2294                            int flag,
2295                            const char *name,
2296                            int icon,
2297                            const char *menu_type)
2298 {
2299   uiBlock *block = layout->root->block;
2300   uiBut *but = block->buttons.last;
2301   uiItemFullR(layout, ptr, prop, index, value, flag, name, icon);
2302   but = but->next;
2303   while (but) {
2304     if (but->rnaprop == prop && but->type == UI_BTYPE_MENU) {
2305       ui_but_rna_menu_convert_to_menu_type(but, menu_type);
2306       break;
2307     }
2308     but = but->next;
2309   }
2310   if (but == NULL) {
2311     const char *propname = RNA_property_identifier(prop);
2312     ui_item_disabled(layout, menu_type);
2313     RNA_warning("property could not use a menu: %s.%s (%s)",
2314                 RNA_struct_identifier(ptr->type),
2315                 propname,
2316                 menu_type);
2317   }
2318 }
2319
2320 void uiItemEnumR_prop(uiLayout *layout,
2321                       const char *name,
2322                       int icon,
2323                       struct PointerRNA *ptr,
2324                       PropertyRNA *prop,
2325                       int value)
2326 {
2327   if (RNA_property_type(prop) != PROP_ENUM) {
2328     const char *propname = RNA_property_identifier(prop);
2329     ui_item_disabled(layout, propname);
2330     RNA_warning("property not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
2331     return;
2332   }
2333
2334   uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
2335 }
2336
2337 void uiItemEnumR(uiLayout *layout,
2338                  const char *name,
2339                  int icon,
2340                  struct PointerRNA *ptr,
2341                  const char *propname,
2342                  int value)
2343 {
2344   PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2345
2346   if (prop == NULL) {
2347     ui_item_disabled(layout, propname);
2348     RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2349     return;
2350   }
2351
2352   uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
2353 }
2354
2355 void uiItemEnumR_string_prop(uiLayout *layout,
2356                              struct PointerRNA *ptr,
2357                              PropertyRNA *prop,
2358                              const char *value,
2359                              const char *name,
2360                              int icon)
2361 {
2362   const EnumPropertyItem *item;
2363   int ivalue, a;
2364   bool free;
2365
2366   if (UNLIKELY(RNA_property_type(prop) != PROP_ENUM)) {
2367     const char *propname = RNA_property_identifier(prop);
2368     ui_item_disabled(layout, propname);
2369     RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
2370     return;
2371   }
2372
2373   RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
2374
2375   if (!RNA_enum_value_from_id(item, value, &ivalue)) {
2376     const char *propname = RNA_property_identifier(prop);
2377     if (free) {
2378       MEM_freeN((void *)item);
2379     }
2380     ui_item_disabled(layout, propname);
2381     RNA_warning("enum property value not found: %s", value);
2382     return;
2383   }
2384
2385   for (a = 0; item[a].identifier; a++) {
2386     if (item[a].value == ivalue) {
2387       const char *item_name = name ?
2388                                   name :
2389                                   CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
2390       const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY;
2391
2392       uiItemFullR(
2393           layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon);
2394       break;
2395     }
2396   }
2397
2398   if (free) {
2399     MEM_freeN((void *)item);
2400   }
2401 }
2402
2403 void uiItemEnumR_string(uiLayout *layout,
2404                         struct PointerRNA *ptr,
2405                         const char *propname,
2406                         const char *value,
2407                         const char *name,
2408                         int icon)
2409 {
2410   PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
2411   if (UNLIKELY(prop == NULL)) {
2412     ui_item_disabled(layout, propname);
2413     RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2414     return;
2415   }
2416   uiItemEnumR_string_prop(layout, ptr, prop, value, name, icon);
2417 }
2418
2419 void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
2420 {
2421   PropertyRNA *prop;
2422   uiBlock *block = layout->root->block;
2423   uiBut *bt;
2424
2425   prop = RNA_struct_find_property(ptr, propname);
2426
2427   if (!prop) {
2428     ui_item_disabled(layout, propname);
2429     RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2430     return;
2431   }
2432
2433   if (RNA_property_type(prop) != PROP_ENUM) {
2434     RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
2435     return;
2436   }
2437   else {
2438     const EnumPropertyItem *item;
2439     int totitem, i;
2440     bool free;
2441     uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
2442     uiLayout *column = uiLayoutColumn(split, false);
2443
2444     RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item, &totitem, &free);
2445
2446     for (i = 0; i < totitem; i++) {
2447       if (item[i].identifier[0]) {
2448         uiItemEnumR_prop(column, item[i].name, item[i].icon, ptr, prop, item[i].value);
2449         ui_but_tip_from_enum_item(block->buttons.last, &item[i]);
2450       }
2451       else {
2452         if (item[i].name) {
2453           if (i != 0) {
2454             column = uiLayoutColumn(split, false);
2455             /* inconsistent, but menus with labels do not look good flipped */
2456             block->flag |= UI_BLOCK_NO_FLIP;
2457           }
2458
2459           uiItemL(column, item[i].name, ICON_NONE);
2460           bt = block->buttons.last;
2461           bt->drawflag = UI_BUT_TEXT_LEFT;
2462
2463           ui_but_tip_from_enum_item(bt, &item[i]);
2464         }
2465         else {
2466           uiItemS(column);
2467         }
2468       }
2469     }
2470
2471     if (free) {
2472       MEM_freeN((void *)item);
2473     }
2474   }
2475
2476   /* intentionally don't touch UI_BLOCK_IS_FLIP here,
2477    * we don't know the context this is called in */
2478 }
2479
2480 /* Pointer RNA button with search */
2481
2482 static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRNA **r_prop)
2483 {
2484   StructRNA *srna;
2485
2486   /* look for collection property in Main */
2487   /* Note: using global Main is OK-ish here, UI shall not access other Mains anyay... */
2488   RNA_main_pointer_create(G_MAIN, r_ptr);
2489
2490   *r_prop = NULL;
2491
2492   RNA_STRUCT_BEGIN (r_ptr, iprop) {
2493     /* if it's a collection and has same pointer type, we've got it */
2494     if (RNA_property_type(iprop) == PROP_COLLECTION) {
2495       srna = RNA_property_pointer_type(r_ptr, iprop);
2496
2497       if (ptype == srna) {
2498         *r_prop = iprop;
2499         break;
2500       }
2501     }
2502   }
2503   RNA_STRUCT_END;
2504 }
2505
2506 void ui_but_add_search(
2507     uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
2508 {
2509   StructRNA *ptype;
2510   PointerRNA sptr;
2511
2512   /* for ID's we do automatic lookup */
2513   if (!searchprop) {
2514     if (RNA_property_type(prop) == PROP_POINTER) {
2515       ptype = RNA_property_pointer_type(ptr, prop);
2516       search_id_collection(ptype, &sptr, &searchprop);
2517       searchptr = &sptr;
2518     }
2519   }
2520
2521   /* turn button into search button */
2522   if (searchprop) {
2523     uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
2524
2525     but->type = UI_BTYPE_SEARCH_MENU;
2526     but->hardmax = MAX2(but->hardmax, 256.0f);
2527     but->rnasearchpoin = *searchptr;
2528     but->rnasearchprop = searchprop;
2529     but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT;
2530     if (RNA_property_is_unlink(prop)) {
2531       but->flag |= UI_BUT_VALUE_CLEAR;
2532     }
2533
2534     coll_search->target_ptr = *ptr;
2535     coll_search->target_prop = prop;
2536     coll_search->search_ptr = *searchptr;
2537     coll_search->search_prop = searchprop;
2538     coll_search->but_changed = &but->changed;
2539
2540     if (RNA_property_type(prop) == PROP_ENUM) {
2541       /* XXX, this will have a menu string,
2542        * but in this case we just want the text */
2543       but->str[0] = 0;
2544     }
2545
2546     UI_but_func_search_set(but,
2547                            ui_searchbox_create_generic,
2548                            ui_rna_collection_search_cb,
2549                            coll_search,
2550                            true,
2551                            NULL,
2552                            NULL);
2553   }
2554   else if (but->type == UI_BTYPE_SEARCH_MENU) {
2555     /* In case we fail to find proper searchprop,
2556      * so other code might have already set but->type to search menu... */
2557     but->flag |= UI_BUT_DISABLED;
2558   }
2559 }
2560
2561 void uiItemPointerR_prop(uiLayout *layout,
2562                          PointerRNA *ptr,
2563                          PropertyRNA *prop,
2564                          PointerRNA *searchptr,
2565                          PropertyRNA *searchprop,
2566                          const char *name,
2567                          int icon)
2568 {
2569   PropertyType type;
2570   uiBut *but;
2571   uiBlock *block;
2572   StructRNA *icontype;
2573   int w, h;
2574   char namestr[UI_MAX_NAME_STR];
2575   const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
2576
2577   type = RNA_property_type(prop);
2578   if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
2579     RNA_warning("Property %s.%s must be a pointer, string or enum",
2580                 RNA_struct_identifier(ptr->type),
2581                 RNA_property_identifier(prop));
2582     return;
2583   }
2584   if (RNA_property_type(searchprop) != PROP_COLLECTION) {
2585     RNA_warning("search collection property is not a collection type: %s.%s",
2586                 RNA_struct_identifier(searchptr->type),
2587                 RNA_property_identifier(searchprop));
2588     return;
2589   }
2590
2591   /* get icon & name */
2592   if (icon == ICON_NONE) {
2593     if (type == PROP_POINTER) {
2594       icontype = RNA_property_pointer_type(ptr, prop);
2595     }
2596     else {
2597       icontype = RNA_property_pointer_type(searchptr, searchprop);
2598     }
2599
2600     icon = RNA_struct_ui_icon(icontype);
2601   }
2602   if (!name) {
2603     name = RNA_property_ui_name(prop);
2604   }
2605
2606   if (use_prop_sep == false) {
2607     name = ui_item_name_add_colon(name, namestr);
2608   }
2609
2610   /* create button */
2611   block = uiLayoutGetBlock(layout);
2612
2613   ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, false, &w, &h);
2614   w += UI_UNIT_X; /* X icon needs more space */
2615   but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
2616
2617   ui_but_add_search(but, ptr, prop, searchptr, searchprop);
2618 }
2619
2620 void uiItemPointerR(uiLayout *layout,
2621                     PointerRNA *ptr,
2622                     const char *propname,
2623                     PointerRNA *searchptr,
2624                     const char *searchpropname,
2625                     const char *name,
2626                     int icon)
2627 {
2628   PropertyRNA *prop, *searchprop;
2629
2630   /* validate arguments */
2631   prop = RNA_struct_find_property(ptr, propname);
2632   if (!prop) {
2633     RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
2634     return;
2635   }
2636   searchprop = RNA_struct_find_property(searchptr, searchpropname);
2637   if (!searchprop) {
2638     RNA_warning("search collection property not found: %s.%s",
2639                 RNA_struct_identifier(searchptr->type),
2640                 searchpropname);
2641     return;
2642   }
2643
2644   uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
2645 }
2646
2647 /* menu item */
2648 void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
2649 {
2650   MenuType *mt = (MenuType *)arg_mt;
2651
2652   UI_menutype_draw(C, mt, layout);
2653
2654   /* menus are created flipped (from event handling pov) */
2655   layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
2656 }
2657
2658 void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
2659 {
2660   PanelType *pt = (PanelType *)arg_pt;
2661   UI_paneltype_draw(C, pt, layout);
2662
2663   /* panels are created flipped (from event handling pov) */
2664   layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
2665 }
2666
2667 static uiBut *ui_item_menu(uiLayout *layout,
2668                            const char *name,
2669                            int icon,
2670                            uiMenuCreateFunc func,
2671                            void *arg,
2672                            void *argN,
2673                            const char *tip,
2674                            bool force_menu)
2675 {
2676   uiBlock *block = layout->root->block;
2677   uiBut *but;
2678   int w, h;
2679
2680   UI_block_layout_set_current(block, layout);
2681
2682   if (!name) {
2683     name = "";
2684   }
2685   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2686     icon = ICON_BLANK1;
2687   }
2688
2689   w = ui_text_icon_width(layout, name, icon, 1);
2690   h = UI_UNIT_Y;
2691
2692   if (layout->root->type == UI_LAYOUT_HEADER) { /* ugly .. */
2693     if (icon == ICON_NONE && force_menu) {
2694       /* pass */
2695     }
2696     else if (force_menu) {
2697       w += 0.6f * UI_UNIT_X;
2698     }
2699     else {
2700       if (name[0]) {
2701         w -= UI_UNIT_X / 2;
2702       }
2703     }
2704   }
2705
2706   if (name[0] && icon) {
2707     but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
2708   }
2709   else if (icon) {
2710     but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
2711     if (force_menu) {
2712       UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
2713     }
2714   }
2715   else {
2716     but = uiDefMenuBut(block, func, arg, name, 0, 0, w, h, tip);
2717   }
2718
2719   if (argN) {
2720     /* ugly .. */
2721     if (arg != argN) {
2722       but->poin = (char *)but;
2723     }
2724     but->func_argN = argN;
2725   }
2726
2727   if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
2728       /* We never want a dropdown in menu! */
2729       (force_menu && layout->root->type != UI_LAYOUT_MENU)) {
2730     UI_but_type_set_menu_from_pulldown(but);
2731   }
2732
2733   return but;
2734 }
2735
2736 void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon)
2737 {
2738   MenuType *mt = WM_menutype_find(menuname, false);
2739   if (mt == NULL) {
2740     RNA_warning("not found %s", menuname);
2741     return;
2742   }
2743
2744   if (!name) {
2745     name = CTX_IFACE_(mt->translation_context, mt->label);
2746   }
2747
2748   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2749     icon = ICON_BLANK1;
2750   }
2751
2752   ui_item_menu(layout,
2753                name,
2754                icon,
2755                ui_item_menutype_func,
2756                mt,
2757                NULL,
2758                mt->description ? TIP_(mt->description) : "",
2759                false);
2760 }
2761
2762 void uiItemMContents(uiLayout *layout, const char *menuname)
2763 {
2764   MenuType *mt = WM_menutype_find(menuname, false);
2765   if (mt == NULL) {
2766     RNA_warning("not found %s", menuname);
2767     return;
2768   }
2769
2770   uiBlock *block = layout->root->block;
2771   bContext *C = block->evil_C;
2772   UI_menutype_draw(C, mt, layout);
2773 }
2774
2775 /* popover */
2776 void uiItemPopoverPanel_ptr(
2777     uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
2778 {
2779   if (!name) {
2780     name = CTX_IFACE_(pt->translation_context, pt->label);
2781   }
2782
2783   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2784     icon = ICON_BLANK1;
2785   }
2786
2787   const bool ok = (pt->poll == NULL) || pt->poll(C, pt);
2788   if (ok && (pt->draw_header != NULL)) {
2789     layout = uiLayoutRow(layout, true);
2790     Panel panel = {
2791         .type = pt,
2792         .layout = layout,
2793         .flag = PNL_POPOVER,
2794     };
2795     pt->draw_header(C, &panel);
2796   }
2797   uiBut *but = ui_item_menu(layout, name, icon, ui_item_paneltype_func, pt, NULL, NULL, true);
2798   but->type = UI_BTYPE_POPOVER;
2799   if (!ok) {
2800     but->flag |= UI_BUT_DISABLED;
2801   }
2802 }
2803
2804 void uiItemPopoverPanel(
2805     uiLayout *layout, bContext *C, const char *panel_type, const char *name, int icon)
2806 {
2807   PanelType *pt = WM_paneltype_find(panel_type, true);
2808   if (pt == NULL) {
2809     RNA_warning("Panel type not found '%s'", panel_type);
2810     return;
2811   }
2812   uiItemPopoverPanel_ptr(layout, C, pt, name, icon);
2813 }
2814
2815 void uiItemPopoverPanelFromGroup(uiLayout *layout,
2816                                  bContext *C,
2817                                  int space_id,
2818                                  int region_id,
2819                                  const char *context,
2820                                  const char *category)
2821 {
2822   SpaceType *st = BKE_spacetype_from_id(space_id);
2823   if (st == NULL) {
2824     RNA_warning("space type not found %d", space_id);
2825     return;
2826   }
2827   ARegionType *art = BKE_regiontype_from_id(st, region_id);
2828   if (art == NULL) {
2829     RNA_warning("region type not found %d", region_id);
2830     return;
2831   }
2832
2833   for (PanelType *pt = art->paneltypes.first; pt; pt = pt->next) {
2834     /* Causes too many panels, check context. */
2835     if (pt->parent_id[0] == '\0') {
2836       if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
2837         if ((*category == '\0') || STREQ(pt->category, category)) {
2838           if (pt->poll == NULL || pt->poll(C, pt)) {
2839             uiItemPopoverPanel_ptr(layout, C, pt, NULL, ICON_NONE);
2840           }
2841         }
2842       }
2843     }
2844   }
2845 }
2846
2847 /* label item */
2848 static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
2849 {
2850   uiBlock *block = layout->root->block;
2851   uiBut *but;
2852   int w;
2853
2854   UI_block_layout_set_current(block, layout);
2855
2856   if (!name) {
2857     name = "";
2858   }
2859   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2860     icon = ICON_BLANK1;
2861   }
2862
2863   w = ui_text_icon_width(layout, name, icon, 0);
2864
2865   if (icon && name[0]) {
2866     but = uiDefIconTextBut(
2867         block, UI_BTYPE_LABEL, 0, icon, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
2868   }
2869   else if (icon) {
2870     but = uiDefIconBut(
2871         block, UI_BTYPE_LABEL, 0, icon, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
2872   }
2873   else {
2874     but = uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, NULL);
2875   }
2876
2877   /* to compensate for string size padding in ui_text_icon_width,
2878    * make text aligned right if the layout is aligned right.
2879    */
2880   if (uiLayoutGetAlignment(layout) == UI_LAYOUT_ALIGN_RIGHT) {
2881     but->drawflag &= ~UI_BUT_TEXT_LEFT; /* default, needs to be unset */
2882     but->drawflag |= UI_BUT_TEXT_RIGHT;
2883   }
2884
2885   /* Mark as a label inside a listbox. */
2886   if (block->flag & UI_BLOCK_LIST_ITEM) {
2887     but->flag |= UI_BUT_LIST_ITEM;
2888   }
2889
2890   if (layout->redalert) {
2891     UI_but_flag_enable(but, UI_BUT_REDALERT);
2892   }
2893
2894   return but;
2895 }
2896
2897 void uiItemL(uiLayout *layout, const char *name, int icon)
2898 {
2899   uiItemL_(layout, name, icon);
2900 }
2901
2902 void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
2903 {
2904   uiBut *but = uiItemL_(layout, name, icon);
2905
2906   if (ptr && ptr->type) {
2907     if (RNA_struct_is_ID(ptr->type)) {
2908       UI_but_drag_set_id(but, ptr->id.data);
2909     }
2910   }
2911 }
2912
2913 /* value item */
2914 void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
2915 {
2916   /* label */
2917   uiBlock *block = layout->root->block;
2918   int *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
2919   int w;
2920
2921   UI_block_layout_set_current(block, layout);
2922
2923   if (!name) {
2924     name = "";
2925   }
2926   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
2927     icon = ICON_BLANK1;
2928   }
2929
2930   w = ui_text_icon_width(layout, name, icon, 0);
2931
2932   if (icon && name[0]) {
2933     uiDefIconTextButI(block,
2934                       UI_BTYPE_BUT,
2935                       argval,
2936                       icon,
2937                       name,
2938                       0,
2939                       0,
2940                       w,
2941                       UI_UNIT_Y,
2942                       retvalue,
2943                       0.0,
2944                       0.0,
2945                       0,
2946                       -1,
2947                       "");
2948   }
2949   else if (icon) {
2950     uiDefIconButI(
2951         block, UI_BTYPE_BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
2952   }
2953   else {
2954     uiDefButI(
2955         block, UI_BTYPE_BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
2956   }
2957 }
2958
2959 /* separator item */
2960 void uiItemS_ex(uiLayout *layout, float factor)
2961 {
2962   uiBlock *block = layout->root->block;
2963   bool is_menu = ui_block_is_menu(block);
2964   int space = (is_menu) ? 0.45f * UI_UNIT_X : 0.3f * UI_UNIT_X;
2965   space *= factor;
2966
2967   UI_block_layout_set_current(block, layout);
2968   uiDefBut(block,
2969            (is_menu) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR,
2970            0,
2971            "",
2972            0,
2973            0,
2974            space,
2975            space,
2976            NULL,
2977            0.0,
2978            0.0,
2979            0,
2980            0,
2981            "");
2982 }
2983
2984 /* separator item */
2985 void uiItemS(uiLayout *layout)
2986 {
2987   uiItemS_ex(layout, 1.0f);
2988 }
2989
2990 /* Flexible spacing. */
2991 void uiItemSpacer(uiLayout *layout)
2992 {
2993   uiBlock *block = layout->root->block;
2994   const bool is_popup = ui_block_is_popup_any(block);
2995
2996   if (is_popup) {
2997     printf("Error: separator_spacer() not supported in popups.\n");
2998     return;
2999   }
3000
3001   if (block->direction & UI_DIR_RIGHT) {
3002     printf("Error: separator_spacer() only supported in horizontal blocks.\n");
3003     return;
3004   }
3005
3006   UI_block_layout_set_current(block, layout);
3007   uiDefBut(block,
3008            UI_BTYPE_SEPR_SPACER,
3009            0,
3010            "",
3011            0,
3012            0,
3013            0.3f * UI_UNIT_X,
3014            UI_UNIT_Y,
3015            NULL,
3016            0.0,
3017            0.0,
3018            0,
3019            0,
3020            "");
3021 }
3022
3023 /* level items */
3024 void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
3025 {
3026   if (!func) {
3027     return;
3028   }
3029
3030   ui_item_menu(layout, name, icon, func, arg, NULL, "", false);
3031 }
3032
3033 /**
3034  * Version of #uiItemMenuF that free's `argN`.
3035  */
3036 void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *argN)
3037 {
3038   if (!func) {
3039     return;
3040   }
3041
3042   /* Second 'argN' only ensures it gets freed. */
3043   ui_item_menu(layout, name, icon, func, argN, argN, "", false);
3044 }
3045
3046 typedef struct MenuItemLevel {
3047   int opcontext;
3048   /* don't use pointers to the strings because python can dynamically
3049    * allocate strings and free before the menu draws, see [#27304] */
3050   char opname[OP_MAX_TYPENAME];
3051   char propname[MAX_IDPROP_NAME];
3052   PointerRNA rnapoin;
3053 } MenuItemLevel;
3054
3055 static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
3056 {
3057   MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
3058
3059   uiLayoutSetOperatorContext(layout, lvl->opcontext);
3060   uiItemsEnumO(layout, lvl->opname, lvl->propname);
3061
3062   layout->root->block->flag |= UI_BLOCK_IS_FLIP;
3063
3064   /* override default, needed since this was assumed pre 2.70 */
3065   UI_block_direction_set(layout->root->block, UI_DIR_DOWN);
3066 }
3067
3068 void uiItemMenuEnumO_ptr(uiLayout *layout,
3069                          bContext *C,
3070                          wmOperatorType *ot,
3071                          const char *propname,
3072                          const char *name,
3073                          int icon)
3074 {
3075   MenuItemLevel *lvl;
3076   uiBut *but;
3077
3078   /* Caller must check */
3079   BLI_assert(ot->srna != NULL);
3080
3081   if (name == NULL) {
3082     name = RNA_struct_ui_name(ot->srna);
3083   }
3084
3085   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3086     icon = ICON_BLANK1;
3087   }
3088
3089   lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
3090   BLI_strncpy(lvl->opname, ot->idname, sizeof(lvl->opname));
3091   BLI_strncpy(lvl->propname, propname, sizeof(lvl->propname));
3092   lvl->opcontext = layout->root->opcontext;
3093
3094   but = ui_item_menu(layout,
3095                      name,
3096                      icon,
3097                      menu_item_enum_opname_menu,
3098                      NULL,
3099                      lvl,
3100                      RNA_struct_ui_description(ot->srna),
3101                      true);
3102
3103   /* add hotkey here, lower UI code can't detect it */
3104   if ((layout->root->block->flag & UI_BLOCK_LOOP) && (ot->prop && ot->invoke)) {
3105     char keybuf[128];
3106     if (WM_key_event_operator_string(
3107             C, ot->idname, layout->root->opcontext, NULL, false, keybuf, sizeof(keybuf))) {
3108       ui_but_add_shortcut(but, keybuf, false);
3109     }
3110   }
3111 }
3112
3113 void uiItemMenuEnumO(uiLayout *layout,
3114                      bContext *C,
3115                      const char *opname,
3116                      const char *propname,
3117                      const char *name,
3118                      int icon)
3119 {
3120   wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
3121
3122   UI_OPERATOR_ERROR_RET(ot, opname, return );
3123
3124   if (!ot->srna) {
3125     ui_item_disabled(layout, opname);
3126     RNA_warning("operator missing srna '%s'", opname);
3127     return;
3128   }
3129
3130   uiItemMenuEnumO_ptr(layout, C, ot, propname, name, icon);
3131 }
3132
3133 static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void *arg)
3134 {
3135   MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
3136
3137   uiLayoutSetOperatorContext(layout, lvl->opcontext);
3138   uiItemsEnumR(layout, &lvl->rnapoin, lvl->propname);
3139   layout->root->block->flag |= UI_BLOCK_IS_FLIP;
3140 }
3141
3142 void uiItemMenuEnumR_prop(
3143     uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon)
3144 {
3145   MenuItemLevel *lvl;
3146
3147   if (!name) {
3148     name = RNA_property_ui_name(prop);
3149   }
3150   if (layout->root->type == UI_LAYOUT_MENU && !icon) {
3151     icon = ICON_BLANK1;
3152   }
3153
3154   lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel");
3155   lvl->rnapoin = *ptr;
3156   BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname));
3157   lvl->opcontext = layout->root->opcontext;
3158
3159   ui_item_menu(layout,
3160                name,
3161                icon,
3162                menu_item_enum_rna_menu,
3163                NULL,
3164                lvl,
3165                RNA_property_description(prop),
3166                false);
3167 }
3168
3169 void uiItemMenuEnumR(
3170     uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon)
3171 {
3172   PropertyRNA *prop;
3173
3174   prop = RNA_struct_find_property(ptr, propname);
3175   if (!prop) {
3176     ui_item_disabled(layout, propname);
3177     RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
3178     return;
3179   }
3180
3181   uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
3182 }
3183
3184 void uiItemTabsEnumR_prop(
3185     uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool icon_only)
3186 {
3187   uiBlock *block = layout->root->block;
3188
3189   UI_block_layout_set_current(block, layout);
3190   ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only);
3191 }
3192
3193 /**************************** Layout Items ***************************/
3194
3195 /* single-row layout */
3196 static void ui_litem_estimate_row(uiLayout *litem)
3197 {
3198   uiItem *item;
3199   int itemw, itemh;
3200   bool min_size_flag = true;
3201
3202   litem->w = 0;
3203   litem->h = 0;
3204
3205   for (item = litem->items.first; item; item = item->next) {
3206     ui_item_size(item, &itemw, &itemh);
3207
3208     min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
3209
3210     litem->w += itemw;
3211     litem->h = MAX2(itemh, litem->h);
3212
3213     if (item->next) {
3214       litem->w += litem->space;
3215     }
3216   }
3217
3218   if (min_size_flag) {
3219     litem->item.flag |= UI_ITEM_MIN;
3220   }
3221 }
3222
3223 static int ui_litem_min_width(int itemw)
3224 {
3225   return MIN2(2 * UI_UNIT_X, itemw);
3226 }
3227
3228 static void ui_litem_layout_row(uiLayout *litem)
3229 {
3230   uiItem *item, *last_free_item = NULL;
3231   int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset;
3232   int fixedw, freew, fixedx, freex, flag = 0, lastw = 0;
3233   float extra_pixel;
3234
3235   /* x = litem->x; */ /* UNUSED */
3236   y = litem->y;
3237   w = litem->w;
3238   totw = 0;
3239   tot = 0;
3240
3241   for (item = litem->items.first; item; item = item->next) {
3242     ui_item_size(item, &itemw, &itemh);
3243     totw += itemw;
3244     tot++;
3245   }
3246
3247   if (totw == 0) {
3248     return;
3249   }
3250
3251   if (w != 0) {
3252     w -= (tot - 1) * litem->space;
3253   }
3254   fixedw = 0;
3255
3256   /* keep clamping items to fixed minimum size until all are done */
3257   do {
3258     freew = 0;
3259     x = 0;
3260     flag = 0;
3261     newtotw = totw;
3262     extra_pixel = 0.0f;
3263
3264     for (item = litem->items.first; item; item = item->next) {
3265       if (item->flag & UI_ITEM_FIXED) {
3266         continue;
3267       }
3268
3269       ui_item_size(item, &itemw, &itemh);
3270       minw = ui_litem_min_width(itemw);
3271
3272       if (w - lastw > 0) {
3273         neww = ui_item_fit(itemw, x, totw, w - lastw, !item->next, litem->alignment, &extra_pixel);
3274       }
3275       else {
3276         neww = 0; /* no space left, all will need clamping to minimum size */
3277       }
3278
3279       x += neww;
3280
3281       bool min_flag = item->flag & UI_ITEM_MIN;
3282       /* ignore min flag for rows with right or center alignment */
3283       if (item->type != ITEM_BUTTON &&
3284           ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
3285           litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) {
3286         min_flag = false;
3287       }
3288
3289       if ((neww < minw || min_flag) && w != 0) {
3290         /* fixed size */
3291         item->flag |= UI_ITEM_FIXED;
3292         if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
3293           minw = itemw;
3294         }
3295         fixedw += minw;
3296         flag = 1;
3297         newtotw -= itemw;
3298       }
3299       else {
3300         /* keep free size */
3301         item->flag &= ~UI_ITEM_FIXED;
3302         freew += itemw;
3303       }
3304     }
3305
3306     totw = newtotw;
3307     lastw = fixedw;
3308   } while (flag);
3309
3310   freex = 0;
3311   fixedx = 0;
3312   extra_pixel = 0.0f;
3313   x = litem->x;
3314
3315   for (item = litem->items.first; item; item = item->next) {
3316     ui_item_size(item, &itemw, &itemh);
3317     minw = ui_litem_min_width(itemw);
3318
3319     if (item->flag & UI_ITEM_FIXED) {
3320       /* fixed minimum size items */
3321       if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
3322         minw = itemw;
3323       }
3324       itemw = ui_item_fit(
3325           minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment, &extra_pixel);
3326       fixedx += itemw;
3327     }
3328     else {
3329       /* free size item */
3330       itemw = ui_item_fit(
3331           itemw, freex, freew, w - fixedw, !item->next, litem->alignment, &extra_pixel);
3332       freex += itemw;
3333       last_free_item = item;
3334     }
3335
3336     /* align right/center */
3337     offset = 0;
3338     if (litem->alignment == UI_LAYOUT_ALIGN_RIGHT) {
3339       if (freew + fixedw > 0 && freew + fixedw < w) {
3340         offset = w - (fixedw + freew);
3341       }
3342     }
3343     else if (litem->alignment == UI_LAYOUT_ALIGN_CENTER) {
3344       if (freew + fixedw > 0 && freew + fixedw < w) {
3345         offset = (w - (fixedw + freew)) / 2;
3346       }
3347     }
3348
3349     /* position item */
3350     ui_item_position(item, x + offset, y - itemh, itemw, itemh);
3351
3352     x += itemw;
3353     if (item->next) {
3354       x += litem->space;
3355     }
3356   }
3357
3358   /* add extra pixel */
3359   uiItem *last_item = litem->items.last;
3360   extra_pixel = litem->w - (x - litem->x);
3361   if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
3362       last_item && last_item->flag & UI_ITEM_FIXED) {
3363     ui_item_move(last_free_item, 0, extra_pixel);
3364     for (item = last_free_item->next; item; item = item->next) {
3365       ui_item_move(item, extra_pixel, extra_pixel);
3366     }
3367   }
3368
3369   litem->w = x - litem->x;
3370   litem->h = litem->y - y;
3371   litem->x = x;
3372   litem->y = y;
3373 }
3374
3375 /* single-column layout */
3376 static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
3377 {
3378   uiItem *item;
3379   int itemw, itemh;
3380   bool min_size_flag = true;
3381
3382   litem->w = 0;
3383   litem->h = 0;
3384
3385   for (item = litem->items.first; item; item = item->next) {
3386     ui_item_size(item, &itemw, &itemh);
3387
3388     min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
3389
3390     litem->w = MAX2(litem->w, itemw);
3391     litem->h += itemh;
3392
3393     if (item->next && (!is_box || item != litem->items.first)) {
3394       litem->h += litem->space;
3395     }
3396   }
3397
3398   if (min_size_flag) {
3399     litem->item.flag |= UI_ITEM_MIN;
3400   }
3401 }
3402
3403 static void ui_litem_layout_column(uiLayout *litem, bool is_box)
3404 {
3405   uiItem *item;
3406   int itemh, x, y;
3407
3408   x = litem->x;
3409   y = litem->y;
3410
3411   for (item = litem->items.first; item; item = item->next) {
3412     ui_item_size(item, NULL, &itemh);
3413
3414     y -= itemh;
3415     ui_item_position(item, x, y, litem->w, itemh);
3416
3417     if (item->next && (!is_box || item != litem->items.first)) {
3418       y -= litem->space;
3419     }
3420
3421     if (is_box) {
3422       item->flag |= UI_ITEM_BOX_ITEM;
3423     }
3424   }
3425
3426   litem->h = litem->y - y;
3427   litem->x = x;
3428   litem->y = y;
3429 }
3430
3431 /* calculates the angle of a specified button in a radial menu,
3432  * stores a float vector in unit circle */
3433 static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
3434 {
3435   RadialDirection dir;
3436
3437   if (itemnum >= PIE_MAX_ITEMS) {
3438     itemnum %= PIE_MAX_ITEMS;
3439     printf("Warning: Pie menus with more than %i items are currently unsupported\n",
3440            PIE_MAX_ITEMS);
3441   }
3442
3443   dir = ui_radial_dir_order[itemnum];
3444   ui_but_pie_dir(dir, vec);
3445
3446   return dir;
3447 }
3448
3449 static bool ui_item_is_radial_displayable(uiItem *item)
3450 {
3451
3452   if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == UI_BTYPE_LABEL)) {
3453     return false;
3454   }
3455
3456   return true;
3457 }
3458
3459 static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
3460 {
3461
3462   if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER)) {
3463     return false;
3464   }
3465
3466   return true;
3467 }
3468
3469 static void ui_litem_layout_radial(uiLayout *litem)
3470 {
3471   uiItem *item;
3472   int itemh, itemw, x, y;
3473   int itemnum = 0;
3474   int totitems = 0;
3475
3476   /* For the radial layout we will use Matt Ebb's design
3477    * for radiation, see http://mattebb.com/weblog/radiation/
3478    * also the old code at http://developer.blender.org/T5103
3479    */
3480
3481   int pie_radius = U.pie_menu_radius * UI_DPI_FAC;
3482
3483   x = litem->x;
3484   y = litem->y;
3485
3486   int minx = x, miny = y, maxx = x, maxy = y;
3487
3488   /* first count total items */
3489   for (item = litem->items.first; item; item = item->next) {
3490     totitems++;
3491   }
3492
3493   if (totitems < 5) {
3494     litem->root->block->pie_data.flags |= UI_PIE_DEGREES_RANGE_LARGE;
3495   }
3496
3497   for (item = litem->items.first; item; item = item->next) {
3498     /* not all button types are drawn in a radial menu, do filtering here */
3499     if (ui_item_is_radial_displayable(item)) {
3500       RadialDirection dir;
3501       float vec[2];
3502       float factor[2];
3503
3504       dir = ui_get_radialbut_vec(vec, itemnum);
3505       factor[0] = (vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f);
3506       factor[1] = (vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f);
3507
3508       itemnum++;
3509
3510       if (item->type == ITEM_BUTTON) {
3511         uiButtonItem *bitem = (uiButtonItem *)item;
3512
3513         bitem->but->pie_dir = dir;
3514         /* scale the buttons */
3515         bitem->but->rect.ymax *= 1.5f;
3516         /* add a little bit more here to include number */
3517         bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
3518         /* enable drawing as pie item if supported by widget */
3519         if (ui_item_is_radial_drawable(bitem)) {
3520           bitem->but->dt = UI_EMBOSS_RADIAL;
3521           bitem->but->drawflag |= UI_BUT_ICON_LEFT;
3522         }
3523       }
3524
3525       ui_item_size(item, &itemw, &itemh);
3526
3527       ui_item_position(item,
3528                        x + vec[0] * pie_radius + factor[0] * itemw,
3529                        y + vec[1] * pie_radius + factor[1] * itemh,
3530                        itemw,
3531                        itemh);
3532
3533       minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2);
3534       maxx = max_ii(maxx, x + vec[