Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Fri, 24 Aug 2018 01:54:12 +0000 (11:54 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 24 Aug 2018 01:54:12 +0000 (11:54 +1000)
1  2 
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_layout.c
source/blender/makesrna/intern/rna_ui_api.c

index c88470bd323247652b76cbd42d869d1a3003c53a,a38f82bc5fca11ccb79ba307850af17f5006265a..e739308bd1ec0860608d054b162df391658747a8
@@@ -42,7 -42,6 +42,7 @@@ struct ID
  struct IDProperty;
  struct ListBase;
  struct ARegion;
 +struct ARegionType;
  struct ScrArea;
  struct bScreen;
  struct wmEvent;
@@@ -65,6 -64,7 +65,6 @@@ struct Image
  struct ImageUser;
  struct wmKeyConfig;
  struct wmOperatorType;
 -struct uiWidgetColors;
  struct MTex;
  struct ImBuf;
  struct bNodeTree;
@@@ -73,10 -73,6 +73,10 @@@ struct bNodeSocket
  struct wmDropBox;
  struct wmDrag;
  struct wmEvent;
 +struct wmGizmo;
 +struct wmMsgBus;
 +struct wmKeyMap;
 +struct wmKeyMapItem;
  
  typedef struct uiBut uiBut;
  typedef struct uiBlock uiBlock;
@@@ -103,8 -99,6 +103,8 @@@ enum 
        UI_EMBOSS_NONE          = 1,  /* Nothing, only icon and/or text */
        UI_EMBOSS_PULLDOWN      = 2,  /* Pulldown menu style */
        UI_EMBOSS_RADIAL        = 3,  /* Pie Menu */
 +
 +      UI_EMBOSS_UNDEFINED     = 255, /* For layout engine, use emboss from block. */
  };
  
  /* uiBlock->direction */
@@@ -113,8 -107,7 +113,8 @@@ enum 
        UI_DIR_DOWN         = (1 << 1),
        UI_DIR_LEFT         = (1 << 2),
        UI_DIR_RIGHT        = (1 << 3),
 -      UI_DIR_CENTER_Y     = (1 << 4),
 +      UI_DIR_CENTER_X     = (1 << 4),
 +      UI_DIR_CENTER_Y     = (1 << 5),
  
        UI_DIR_ALL          = (UI_DIR_UP | UI_DIR_DOWN | UI_DIR_LEFT | UI_DIR_RIGHT),
  };
  #define UI_BLOCK_POPUP_HOLD  (1 << 18)
  #define UI_BLOCK_LIST_ITEM   (1 << 19)
  #define UI_BLOCK_RADIAL      (1 << 20)
 +#define UI_BLOCK_POPOVER     (1 << 21)
 +#define UI_BLOCK_POPOVER_ONCE (1 << 22)
 +/** Always show keymaps, even for non-menus. */
 +#define UI_BLOCK_SHOW_SHORTCUT_ALWAYS (1 << 23)
  
  /* uiPopupBlockHandle->menuretval */
  #define UI_RETURN_CANCEL     (1 << 0)   /* cancel all menus cascading */
@@@ -189,13 -178,11 +189,13 @@@ enum 
        UI_BUT_COLOR_CUBIC     = (1 << 23),  /* cubic saturation for the color wheel */
        UI_BUT_LIST_ITEM       = (1 << 24),  /* This but is "inside" a list item (currently used to change theme colors). */
        UI_BUT_DRAG_MULTI      = (1 << 25),  /* edit this button as well as the active button (not just dragging) */
 -      UI_BUT_SCA_LINK_GREY   = (1 << 26),  /* used to flag if sca links shoud be gray out */
 +
        UI_BUT_HAS_SEP_CHAR    = (1 << 27),  /* but->str contains UI_SEP_CHAR, used for key shortcuts */
        UI_BUT_UPDATE_DELAY    = (1 << 28),  /* don't run updates while dragging (needed in rare cases). */
        UI_BUT_TEXTEDIT_UPDATE = (1 << 29),  /* when widget is in textedit mode, update value on each char stroke */
        UI_BUT_VALUE_CLEAR     = (1 << 30),  /* show 'x' icon to clear/unlink value of text or search button */
 +
 +      UI_BUT_OVERRIDEN       = (1 << 31),  /* RNA property of the button is overriden from linked reference data. */
  };
  
  #define UI_PANEL_WIDTH          340
@@@ -231,16 -218,11 +231,16 @@@ enum 
        UI_BUT_ALIGN_ALL         = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT),
  
        UI_BUT_BOX_ITEM          = (1 << 20), /* This but is "inside" a box item (currently used to change theme colors). */
 +
 +      UI_BUT_ACTIVE_LEFT       = (1 << 21), /* Active left part of number button */
 +      UI_BUT_ACTIVE_RIGHT      = (1 << 22), /* Active right part of number button */
 +
 +      UI_BUT_HAS_SHORTCUT      = (1 << 23), /* Button has shortcut text */
  };
  
  /* scale fixed button widths by this to account for DPI */
  
 -#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
 +#define UI_DPI_FAC (U.dpi_fac)
  /* 16 to copy ICON_DEFAULT_HEIGHT */
  #define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
  
@@@ -279,11 -261,11 +279,11 @@@ typedef enum 
        UI_BTYPE_CHECKBOX               = (13 << 9),  /* similar to toggle, display a 'tick' */
        UI_BTYPE_CHECKBOX_N             = (14 << 9),
        UI_BTYPE_COLOR                  = (15 << 9),
 +      UI_BTYPE_TAB                    = (16 << 9),
 +      UI_BTYPE_POPOVER                = (17 << 9),
        UI_BTYPE_SCROLL                 = (18 << 9),
        UI_BTYPE_BLOCK                  = (19 << 9),
        UI_BTYPE_LABEL                  = (20 << 9),
 -      UI_BTYPE_LINK                   = (22 << 9),
 -      UI_BTYPE_INLINK                 = (23 << 9),
        UI_BTYPE_KEY_EVENT              = (24 << 9),
        UI_BTYPE_HSVCUBE                = (26 << 9),
        UI_BTYPE_PULLDOWN               = (27 << 9),  /* menu (often used in headers), **_MENU /w different draw-type */
        UI_BTYPE_NODE_SOCKET            = (53 << 9),
        UI_BTYPE_SEPR                   = (54 << 9),
        UI_BTYPE_SEPR_LINE              = (55 << 9),
 -      UI_BTYPE_GRIP                   = (56 << 9),  /* resize handle (resize uilist) */
 +      UI_BTYPE_SEPR_SPACER            = (56 << 9),  /* Dynamically fill available space. */
 +      UI_BTYPE_GRIP                   = (57 << 9),  /* resize handle (resize uilist) */
  } eButType;
  
  #define BUTTYPE     (63 << 9)
   * Functions to draw various shapes, taking theme settings into account.
   * Used for code that draws its own UI style elements. */
  
 -void UI_draw_roundbox(float minx, float miny, float maxx, float maxy, float rad);
 +void UI_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]);
 +void UI_draw_anti_fan(float tri_array[][2], unsigned int length, const float color[4]);
 +
  void UI_draw_roundbox_corner_set(int type);
 +void UI_draw_roundbox_aa(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float color[4]);
 +void UI_draw_roundbox_4fv(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[4]);
 +void UI_draw_roundbox_3ubAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const unsigned char col[3], unsigned char alpha);
 +void UI_draw_roundbox_3fvAlpha(bool filled, float minx, float miny, float maxx, float maxy, float rad, const float col[3], float alpha);
 +void UI_draw_roundbox_shade_x(bool filled, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown, const float col[4]);
 +
 +#if 0 /* unused */
  int  UI_draw_roundbox_corner_get(void);
 -void UI_draw_roundbox_unfilled(float minx, float miny, float maxx, float maxy, float rad);
 +void UI_draw_roundbox_shade_y(bool filled, float minx, float miny, float maxx, float maxy, float rad, float shadeleft, float shaderight, const float col[4]);
 +#endif
 +
  void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
 -void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, float maxy, float rad);
 -void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
 -void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
 -void UI_draw_text_underline(int pos_x, int pos_y, int len, int height);
 +void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4]);
  
 -void UI_draw_safe_areas(
 -        float x1, float x2, float y1, float y2,
 +void UI_draw_safe_areas(uint pos, float x1, float x2, float y1, float y2,
          const float title_aspect[2], const float action_aspect[2]);
  
  /* state for scrolldrawing */
@@@ -407,10 -381,6 +407,10 @@@ typedef bool (*uiMenuStepFunc)(struct b
  
  
  /* interface_query.c */
 +bool UI_but_is_tool(const uiBut *but);
 +#define UI_but_is_decorator(but) \
 +      ((but)->func == ui_but_anim_decorate_cb)
 +
  bool UI_block_is_empty(const uiBlock *block);
  
  
@@@ -439,19 -409,6 +439,19 @@@ int UI_popup_menu_invoke(struct bContex
  void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
  void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
  
 +/* interface_region_popover.c */
 +
 +typedef struct uiPopover uiPopover;
 +
 +int UI_popover_panel_invoke(
 +        struct bContext *C, const char *idname,
 +        bool keep_open, struct ReportList *reports);
 +
 +uiPopover *UI_popover_begin(struct bContext *C, int menu_width) ATTR_NONNULL(1);
 +void UI_popover_end(struct bContext *C, struct uiPopover *head, struct wmKeyMap *keymap);
 +struct uiLayout *UI_popover_layout(uiPopover *head);
 +void UI_popover_once_clear(uiPopover *pup);
 +
  /* interface_region_menu_pie.c */
  /* Pie menus */
  typedef struct uiPieMenu uiPieMenu;
@@@ -501,10 -458,10 +501,10 @@@ uiBlock *UI_block_begin(const struct bC
  void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]);
  void UI_block_end(const struct bContext *C, uiBlock *block);
  void UI_block_draw(const struct bContext *C, struct uiBlock *block);
 +void UI_blocklist_update_window_matrix(const struct bContext *C, const struct ListBase *lb);
 +void UI_blocklist_draw(const struct bContext *C, const struct ListBase *lb);
  void UI_block_update_from_old(const struct bContext *C, struct uiBlock *block);
  
 -uiBlock *UI_block_find_in_region(const char *name, struct ARegion *ar);
 -
  void UI_block_emboss_set(uiBlock *block, char dt);
  
  void UI_block_free(const struct bContext *C, uiBlock *block);
@@@ -545,7 -502,6 +545,7 @@@ void    UI_block_direction_set(uiBlock 
  void    UI_block_order_flip(uiBlock *block);
  void    UI_block_flag_enable(uiBlock *block, int flag);
  void    UI_block_flag_disable(uiBlock *block, int flag);
 +void    UI_block_translate(uiBlock *block, int x, int y);
  
  int     UI_but_return_value_get(uiBut *but);
  
@@@ -712,7 -668,6 +712,7 @@@ void UI_but_string_info_get(struct bCon
  #define UI_ID_FAKE_USER     (1 << 8)
  #define UI_ID_PIN           (1 << 9)
  #define UI_ID_PREVIEWS      (1 << 10)
 +#define UI_ID_OVERRIDE      (1 << 11)
  #define UI_ID_FULL          (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL)
  
  /**
@@@ -727,9 -682,6 +727,9 @@@ enum 
  int UI_icon_from_id(struct ID *id);
  int UI_icon_from_report_type(int type);
  
 +int UI_icon_from_event_type(short event_type, short event_value);
 +int UI_icon_from_keymap_item(const struct wmKeyMapItem *kmi, int r_icon_mod[4]);
 +
  uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
  uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip);
  uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip);
@@@ -750,30 -702,22 +750,30 @@@ uiBut *uiDefSearchButO_ptr
          void *arg, int retval, int icon, int maxlen, int x, int y,
          short width, short height, float a1, float a2, const char *tip);
  
 -uiBut *uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x1, int y1, int x2, int y2);
  
 -int uiDefAutoButsRNA(
 +/* For uiDefAutoButsRNA */
 +typedef enum {
 +      /* Keep current layout for aligning label with property button. */
 +      UI_BUT_LABEL_ALIGN_NONE,
 +      /* Align label and property button vertically. */
 +      UI_BUT_LABEL_ALIGN_COLUMN,
 +      /* Split layout into a column for the label and one for property button. */
 +      UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
 +} eButLabelAlign;
 +
 +/* Return info for uiDefAutoButsRNA */
 +typedef enum {
 +      /* Returns when no buttons were added */
 +      UI_PROP_BUTS_NONE_ADDED       = (1 << 0),
 +      /* Returned when any property failed the custom check callback (check_prop) */
 +      UI_PROP_BUTS_ANY_FAILED_CHECK = (1 << 1),
 +} eAutoPropButsReturn;
 +
 +uiBut *uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x1, int y1, int x2, int y2);
 +eAutoPropButsReturn uiDefAutoButsRNA(
          uiLayout *layout, struct PointerRNA *ptr,
          bool (*check_prop)(struct PointerRNA *ptr, struct PropertyRNA *prop, void *user_data), void *user_data,
 -        const char label_align);
 -
 -/* Links
 - *
 - * Game engine logic brick links. Non-functional currently in 2.5,
 - * code to handle and draw these is disabled internally. */
 -
 -void UI_but_link_set(struct uiBut *but,  void **poin,  void ***ppoin,  short *tot,  int from, int to);
 -
 -void UI_block_links_compose(uiBlock *block);
 -uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin);
 +        eButLabelAlign label_align, const bool compact);
  
  /* use inside searchfunc to add items */
  bool    UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid);
@@@ -844,15 -788,12 +844,15 @@@ void UI_panels_begin(const struct bCont
  void UI_panels_end(const struct bContext *C, struct ARegion *ar, int *x, int *y);
  void UI_panels_draw(const struct bContext *C, struct ARegion *ar);
  
 -struct Panel *UI_panel_find_by_type(struct ARegion *ar, struct PanelType *pt);
 +struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
  struct Panel *UI_panel_begin(
 -        struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
 -        struct PanelType *pt, struct Panel *pa, bool *r_open);
 +        struct ScrArea *sa, struct ARegion *ar, struct ListBase *lb,
 +        uiBlock *block, struct PanelType *pt, struct Panel *pa,
 +        bool *r_open);
  void UI_panel_end(uiBlock *block, int width, int height);
  void UI_panels_scale(struct ARegion *ar, float new_width);
 +void UI_panel_label_offset(struct uiBlock *block, int *x, int *y);
 +int UI_panel_size_y(const struct Panel *pa);
  
  bool                       UI_panel_category_is_visible(struct ARegion *ar);
  void                       UI_panel_category_add(struct ARegion *ar, const char *name);
@@@ -865,8 -806,6 +865,8 @@@ struct PanelCategoryDyn   *UI_panel_cat
  void                       UI_panel_category_clear_all(struct ARegion *ar);
  void                       UI_panel_category_draw_all(struct ARegion *ar, const char *category_id_active);
  
 +struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
 +
  /* Handlers
   *
   * Handlers that can be registered in regions, areas and windows for
@@@ -886,6 -825,7 +886,6 @@@ void UI_popup_handlers_remove_all(struc
  void UI_init(void);
  void UI_init_userdef(struct Main *bmain);
  void UI_reinit_font(void);
 -void UI_reinit_gl_state(void);
  void UI_exit(void);
  
  /* Layout
  #define UI_LAYOUT_ALIGN_CENTER  2
  #define UI_LAYOUT_ALIGN_RIGHT   3
  
 +#define UI_ITEM_O_RETURN_PROPS  (1 << 0)
  #define UI_ITEM_R_EXPAND        (1 << 1)
  #define UI_ITEM_R_SLIDER        (1 << 2)
  #define UI_ITEM_R_TOGGLE        (1 << 3)
  #define UI_ITEM_R_NO_BG         (1 << 7)
  #define UI_ITEM_R_IMMEDIATE     (1 << 8)
  #define UI_ITEM_O_DEPRESS       (1 << 9)
 +#define UI_ITEM_R_COMPACT       (1 << 10)
  
 -/* uiTemplateOperatorPropertyButs flags */
 -#define UI_TEMPLATE_OP_PROPS_SHOW_TITLE 1
 -#define UI_TEMPLATE_OP_PROPS_SHOW_EMPTY 2
 +#define UI_HEADER_OFFSET ((void)0, 0.2f * UI_UNIT_X)
 +
 +/* uiLayoutOperatorButs flags */
 +enum {
 +      UI_TEMPLATE_OP_PROPS_SHOW_TITLE       = (1 << 0),
 +      UI_TEMPLATE_OP_PROPS_SHOW_EMPTY       = (1 << 1),
 +      UI_TEMPLATE_OP_PROPS_COMPACT          = (1 << 2),
 +      UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED    = (1 << 3),
 +};
  
  /* used for transp checkers */
  #define UI_ALPHA_CHECKER_DARK 100
@@@ -958,21 -890,20 +958,21 @@@ enum 
        UI_CNR_ALL          = (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)
  };
  
 -/* not apart of the corner flags but mixed in some functions  */
 -#define UI_RB_ALPHA (UI_CNR_ALL + 1)
 -
  uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, struct uiStyle *style);
  void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
  void UI_block_layout_resolve(uiBlock *block, int *x, int *y);
  
 +void UI_region_message_subscribe(struct ARegion *ar, struct wmMsgBus *mbus);
 +
  uiBlock *uiLayoutGetBlock(uiLayout *layout);
  
  void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
  void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr);
  void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context);
  struct MenuType *UI_but_menutype_get(uiBut *but);
 +struct PanelType *UI_but_paneltype_get(uiBut *but);
  void UI_menutype_draw(struct bContext *C, struct MenuType *mt, struct uiLayout *layout);
 +void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout *layout);
  
  /* Only for convenience. */
  void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but);
@@@ -985,9 -916,6 +985,9 @@@ void uiLayoutSetAlignment(uiLayout *lay
  void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
  void uiLayoutSetScaleX(uiLayout *layout, float scale);
  void uiLayoutSetScaleY(uiLayout *layout, float scale);
 +void uiLayoutSetEmboss(uiLayout *layout, char emboss);
 +void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
 +void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
  
  int uiLayoutGetOperatorContext(uiLayout *layout);
  bool uiLayoutGetActive(uiLayout *layout);
@@@ -998,16 -926,11 +998,16 @@@ bool uiLayoutGetKeepAspect(uiLayout *la
  int uiLayoutGetWidth(uiLayout *layout);
  float uiLayoutGetScaleX(uiLayout *layout);
  float uiLayoutGetScaleY(uiLayout *layout);
 +int uiLayoutGetEmboss(uiLayout *layout);
 +bool uiLayoutGetPropSep(uiLayout *layout);
 +bool uiLayoutGetPropDecorate(uiLayout *layout);
  
  /* layout specifiers */
  uiLayout *uiLayoutRow(uiLayout *layout, bool align);
  uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
  uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
 +uiLayout *uiLayoutGridFlow(
 +        uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align);
  uiLayout *uiLayoutBox(uiLayout *layout);
  uiLayout *uiLayoutListBox(
          uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop,
@@@ -1022,65 -945,41 +1022,65 @@@ uiLayout *uiLayoutRadial(uiLayout *layo
  void uiTemplateHeader(uiLayout *layout, struct bContext *C);
  void uiTemplateID(
          uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
 -        const char *newop, const char *openop, const char *unlinkop, int filter);
 +        const char *newop, const char *openop, const char *unlinkop,
 +        int filter, const bool live_icon);
  void uiTemplateIDBrowse(
          uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
          const char *newop, const char *openop, const char *unlinkop, int filter);
  void uiTemplateIDPreview(
          uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
          const char *newop, const char *openop, const char *unlinkop, int rows, int cols, int filter);
 +void uiTemplateIDTabs(
 +        uiLayout *layout, struct bContext *C,
 +        PointerRNA *ptr, const char *propname,
 +        const char *newop, const char *openop, const char *menu,
 +        int filter);
  void uiTemplateAnyID(
          uiLayout *layout, struct PointerRNA *ptr, const char *propname,
          const char *proptypename, const char *text);
 +void uiTemplateSearch(
 +        uiLayout *layout, struct bContext *C,
 +        struct PointerRNA *ptr, const char *propname,
 +        struct PointerRNA *searchptr, const char *searchpropname,
 +        const char *newop, const char *unlinkop);
 +void uiTemplateSearchPreview(
 +        uiLayout *layout, struct bContext *C,
 +        struct PointerRNA *ptr, const char *propname,
 +        struct PointerRNA *searchptr, const char *searchpropname,
 +        const char *newop, const char *unlinkop,
 +        const int rows, const int cols);
  void uiTemplatePathBuilder(
          uiLayout *layout, struct PointerRNA *ptr, const char *propname,
          struct PointerRNA *root_ptr, const char *text);
  uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
 +uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
 +void uiTemplateGpencilColorPreview(
 +      uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname,
 +      int rows, int cols, float scale, int filter);
 +
 +uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
 +
 +void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C);
 +
  uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
  void uiTemplatePreview(
          uiLayout *layout, struct bContext *C, struct ID *id, bool show_buttons, struct ID *parent,
          struct MTex *slot, const char *preview_id);
  void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool expand);
 +void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
  void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool show_labels, float icon_scale);
  void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateCurveMapping(
          uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
 -        bool levels, bool brush, bool neg_slope);
 +        bool levels, bool brush, bool neg_slope, bool tone);
  void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
  void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
  void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateLayers(
          uiLayout *layout, struct PointerRNA *ptr, const char *propname,
          PointerRNA *used_ptr, const char *used_propname, int active_layer);
 -void uiTemplateGameStates(
 -        uiLayout *layout, struct PointerRNA *ptr, const char *propname,
 -        PointerRNA *used_ptr, const char *used_propname, int active_state);
  void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview);
  void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management);
  void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
@@@ -1091,14 -990,12 +1091,14 @@@ void uiTemplateImageInfo(uiLayout *layo
  void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
  void UI_but_func_operator_search(uiBut *but);
  void uiTemplateOperatorSearch(uiLayout *layout);
 -void uiTemplateOperatorPropertyButs(
 +eAutoPropButsReturn uiTemplateOperatorPropertyButs(
          const struct bContext *C, uiLayout *layout, struct wmOperator *op,
 -        const char label_align, const short flag);
 +        const eButLabelAlign label_align, const short flag);
 +void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
  void uiTemplateHeader3D(uiLayout *layout, struct bContext *C);
  void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
  void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
 +void uiTemplateInputStatus(uiLayout *layout, struct bContext *C);
  void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
  void uiTemplateComponentMenu(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name);
  void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
@@@ -1154,8 -1051,10 +1154,10 @@@ void uiItemR(uiLayout *layout, struct P
  void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon);
  void uiItemEnumR_prop(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, PropertyRNA *prop, int value);
  void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value);
+ void uiItemEnumR_string_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *value, const char *name, int icon);
  void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon);
  void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+ void uiItemPointerR_prop(uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, struct PointerRNA *searchptr, PropertyRNA *searchprop, const char *name, int icon);
  void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon);
  void uiItemsFullEnumO(
          uiLayout *layout, const char *opname, const char *propname,
@@@ -1170,20 -1069,6 +1172,20 @@@ void uiItemLDrag(uiLayout *layout, stru
  void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon); /* menu */
  void uiItemV(uiLayout *layout, const char *name, int icon, int argval); /* value */
  void uiItemS(uiLayout *layout); /* separator */
 +void uiItemSpacer(uiLayout *layout); /* Special separator. */
 +
 +void uiItemPopoverPanel_ptr(
 +        uiLayout *layout, struct bContext *C,
 +        struct PanelType *pt,
 +        const char *name, int icon);
 +void uiItemPopoverPanel(
 +        uiLayout *layout, struct bContext *C,
 +        const char *panelname,
 +        const char *name, int icon);
 +void uiItemPopoverPanelFromGroup(
 +        uiLayout *layout, struct bContext *C,
 +        int space_id, int region_id,
 +        const char *context, const char *category);
  
  void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg);
  void uiItemMenuEnumO_ptr(uiLayout *layout, struct bContext *C, struct wmOperatorType *ot, const char *propname, const char *name, int icon);
@@@ -1201,7 -1086,7 +1203,7 @@@ void ED_operatortypes_ui(void)
  void ED_keymap_ui(struct wmKeyConfig *keyconf);
  
  void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
 -bool UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
 +bool UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event, const char **tooltip);
  
  bool UI_context_copy_to_selected_list(
          struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
@@@ -1221,7 -1106,6 +1223,7 @@@ void UI_context_active_but_prop_get_fil
  void UI_context_active_but_prop_get_templateID(
          struct bContext *C,
          struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
 +struct ID *UI_context_active_but_get_tab_ID(struct bContext *C);
  
  uiBut *UI_region_active_but_get(struct ARegion *ar);
  
  void UI_fontstyle_set(const struct uiFontStyle *fs);
  void UI_fontstyle_draw_ex(
          const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
 -        size_t len, float *r_xofs, float *r_yofs);
 -void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
 -void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
 -void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str);
 +        const unsigned char col[4], size_t len, float *r_xofs, float *r_yofs);
 +void UI_fontstyle_draw(
 +        const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
 +        const unsigned char col[4]);
 +void UI_fontstyle_draw_rotated(
 +        const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
 +        const unsigned char col[4]);
 +void UI_fontstyle_draw_simple(
 +        const struct uiFontStyle *fs, float x, float y, const char *str,
 +        const unsigned char col[4]);
  void UI_fontstyle_draw_simple_backdrop(
          const struct uiFontStyle *fs, float x, float y, const char *str,
 -        const unsigned char fg[4], const unsigned char bg[4]);
 +        const float col_fg[4], const float col_bg[4]);
  
  int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
  int UI_fontstyle_height_max(const struct uiFontStyle *fs);
  
 -void UI_draw_icon_tri(float x, float y, char dir);
 +void UI_draw_icon_tri(float x, float y, char dir, const float[4]);
  
  struct uiStyle *UI_style_get(void);           /* use for fonts etc */
  struct uiStyle *UI_style_get_dpi(void);       /* DPI scaled settings for drawing */
@@@ -1274,7 -1152,6 +1276,7 @@@ void UI_butstore_unregister(uiButStore 
  
  /* ui_interface_region_tooltip.c */
  struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but);
 +struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
  void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar);
  
  /* How long before a tool-tip shows. */
  
  int UI_calc_float_precision(int prec, double value);
  
 +/* widget batched drawing */
 +void UI_widgetbase_draw_cache_begin(void);
 +void UI_widgetbase_draw_cache_flush(void);
 +void UI_widgetbase_draw_cache_end(void);
 +
 +/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
 +#define USE_UI_TOOLBAR_HACK
 +
 +/* Support click-drag motion which presses the button and closes a popover (like a menu). */
 +#define USE_UI_POPOVER_ONCE
 +
  #endif  /* __UI_INTERFACE_H__ */
index f3f08b102577e956125ec272ff9fb039e0bcd4a1,140fdbe355bb34e83fb8e85db01047884bb0ce2f..ec35325416a53e8b15ff34f4ded658434e45a48e
@@@ -37,7 -37,6 +37,7 @@@
  #include "DNA_armature_types.h"
  #include "DNA_userdef_types.h"
  
 +#include "BLI_alloca.h"
  #include "BLI_listbase.h"
  #include "BLI_string.h"
  #include "BLI_rect.h"
@@@ -50,7 -49,6 +50,7 @@@
  #include "BKE_global.h"
  #include "BKE_idprop.h"
  #include "BKE_screen.h"
 +#include "BKE_animsys.h"
  
  #include "RNA_access.h"
  
  
  #include "interface_intern.h"
  
 +/* Show an icon button after each RNA button to use to quickly set keyframes,
 + * this is a way to display animation/driven/override status, see T54951. */
 +#define UI_PROP_DECORATE
 +/* Alternate draw mode where some buttons can use single icon width,
 + * giving more room for the text at the expense of nicely aligned text. */
 +#define UI_PROP_SEP_ICON_WIDTH_EXCEPTION
 +
  /************************ Structs and Defines *************************/
  
  #define UI_OPERATOR_ERROR_RET(_ot, _opname, return_statement)                 \
@@@ -80,7 -71,6 +80,7 @@@
                return_statement;                                                     \
        } (void)0                                                                 \
  
 +#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
  
  /* uiLayoutRoot */
  
@@@ -110,7 -100,6 +110,7 @@@ typedef enum uiItemType 
        ITEM_LAYOUT_COLUMN,
        ITEM_LAYOUT_COLUMN_FLOW,
        ITEM_LAYOUT_ROW_FLOW,
 +      ITEM_LAYOUT_GRID_FLOW,
        ITEM_LAYOUT_BOX,
        ITEM_LAYOUT_ABSOLUTE,
        ITEM_LAYOUT_SPLIT,
@@@ -139,10 -128,6 +139,10 @@@ enum 
        UI_ITEM_MIN       = 1 << 1,
  
        UI_ITEM_BOX_ITEM  = 1 << 2, /* The item is "inside" a box item */
 +      UI_ITEM_PROP_SEP  = 1 << 3,
 +      /* Show an icon button next to each property (to set keyframes, show status).
 +       * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
 +      UI_ITEM_PROP_DECORATE = 1 << 4,
  };
  
  typedef struct uiButtonItem {
@@@ -165,9 -150,7 +165,9 @@@ struct uiLayout 
        bool enabled;
        bool redalert;
        bool keepaspect;
 +      bool variable_size;  /* For layouts inside gridflow, they and their items shall never have a fixed maximal size. */
        char alignment;
 +      char emboss;
  };
  
  typedef struct uiLayoutItemFlow {
        int totcol;
  } uiLayoutItemFlow;
  
 +typedef struct uiLayoutItemGridFlow {
 +      uiLayout litem;
 +
 +      /* Extra parameters */
 +      bool row_major;     /* Fill first row first, instead of filling first column first. */
 +      bool even_columns;  /* Same width for all columns. */
 +      bool even_rows;     /* Same height for all rows. */
 +      /* If positive, absolute fixed number of columns.
 +       * If 0, fully automatic (based on available width).
 +       * If negative, automatic but only generates number of columns/rows multiple of given (absolute) value. */
 +      int columns_len;
 +
 +      /* Pure internal runtime storage. */
 +      int tot_items, tot_columns, tot_rows;
 +} uiLayoutItemGridFlow;
 +
  typedef struct uiLayoutItemBx {
        uiLayout litem;
        uiBut *roundbox;
@@@ -267,37 -234,29 +267,37 @@@ static int ui_layout_vary_direction(uiL
                UI_ITEM_VARY_X : UI_ITEM_VARY_Y);
  }
  
 +static bool ui_layout_variable_size(uiLayout *layout)
 +{
 +      /* Note that this code is probably a bit flacky, we'd probably want to know whether it's variable in X and/or Y,
 +       * etc. But for now it mimics previous one, with addition of variable flag set for children of gridflow layouts. */
 +      return ui_layout_vary_direction(layout) == UI_ITEM_VARY_X || layout->variable_size;
 +}
 +
  /* estimated size of text + icon */
  static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool compact)
  {
        bool variable;
 +      const int unit_x = UI_UNIT_X * (layout->scale[0] ? layout->scale[0] : 1.0f);
  
        if (icon && !name[0])
 -              return UI_UNIT_X;  /* icon only */
 +              return unit_x;  /* icon only */
  
 -      variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
 +      variable = ui_layout_variable_size(layout);
  
        if (variable) {
                if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
                        layout->item.flag |= UI_ITEM_MIN;
                }
                const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
 -              /* it may seem odd that the icon only adds (UI_UNIT_X / 4)
 +              /* it may seem odd that the icon only adds (unit_x / 4)
                 * but taking margins into account its fine */
                return (UI_fontstyle_string_width(fstyle, name) +
 -                      (UI_UNIT_X * ((compact ? 1.25f : 1.50f) +
 -                                    (icon    ? 0.25f : 0.0f))));
 +                      (unit_x * ((compact ? 1.25f : 1.50f) +
 +                                 (icon    ? 0.25f : 0.0f))));
        }
        else {
 -              return UI_UNIT_X * 10;
 +              return unit_x * 10;
        }
  }
  
@@@ -384,7 -343,6 +384,7 @@@ static int ui_layout_local_dir(uiLayou
                        return UI_LAYOUT_HORIZONTAL;
                case ITEM_LAYOUT_COLUMN:
                case ITEM_LAYOUT_COLUMN_FLOW:
 +              case ITEM_LAYOUT_GRID_FLOW:
                case ITEM_LAYOUT_SPLIT:
                case ITEM_LAYOUT_ABSOLUTE:
                case ITEM_LAYOUT_BOX:
@@@ -434,7 -392,7 +434,7 @@@ static void ui_layer_but_cb(bContext *C
  static void ui_item_array(
          uiLayout *layout, uiBlock *block, const char *name, int icon,
          PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
 -        bool expand, bool slider, bool toggle, bool icon_only)
 +        bool expand, bool slider, bool toggle, bool icon_only, bool compact, bool show_text)
  {
        uiStyle *style = layout->root->style;
        uiBut *but;
        UI_block_layout_set_current(block, sub);
  
        /* create label */
 -      if (name[0])
 +      if (name[0] && show_text) {
                uiDefBut(block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
 +      }
  
        /* create buttons */
        if (type == PROP_BOOLEAN && ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER)) {
                        /* layout for known array subtypes */
                        char str[3] = {'\0'};
  
 -                      if (!icon_only) {
 +                      if (!icon_only && show_text) {
                                if (type != PROP_BOOLEAN) {
                                        str[1] = ':';
                                }
                                RNA_property_boolean_get_array(ptr, prop, boolarr);
                        }
  
 +                      const char *str_buf = show_text ? str: "";
                        for (a = 0; a < len; a++) {
 -                              if (!icon_only) str[0] = RNA_property_array_item_char(prop, a);
 -                              if (boolarr) icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 -                              but = uiDefAutoButR(block, ptr, prop, a, str, icon, 0, 0, w, UI_UNIT_Y);
 +                              int width_item;
 +
 +                              if (!icon_only && show_text) {
 +                                      str[0] = RNA_property_array_item_char(prop, a);
 +                              }
 +                              if (boolarr) {
 +                                      icon = boolarr[a] ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 +                              }
 +
 +                              width_item = (
 +                                      (compact && type == PROP_BOOLEAN) ?
 +                                      min_ii(w, ui_text_icon_width(layout, str_buf, icon, false)) : w);
 +
 +                              but = uiDefAutoButR(block, ptr, prop, a, str_buf, icon, 0, 0, width_item, UI_UNIT_Y);
                                if (slider && but->type == UI_BTYPE_NUM)
                                        but->type = UI_BTYPE_NUM_SLIDER;
                                if (toggle && but->type == UI_BTYPE_CHECKBOX)
@@@ -681,14 -626,8 +681,14 @@@ static void ui_item_enum_expand
  
        for (item = item_array; item->identifier; item++) {
                if (!item->identifier[0]) {
 -                      if (radial && layout_radial) {
 -                              uiItemS(layout_radial);
 +                      const EnumPropertyItem *next_item = item + 1;
 +                      if (next_item->identifier) {
 +                              if (radial && layout_radial) {
 +                                      uiItemS(layout_radial);
 +                              }
 +                              else {
 +                                      uiItemS(block->curlayout);
 +                              }
                        }
                        continue;
                }
@@@ -730,49 -669,27 +730,49 @@@ static void ui_keymap_but_cb(bContext *
        RNA_boolean_set(&but->rnapoin, "oskey", (but->modifier_key & KM_OSKEY) != 0);
  }
  
 -/* create label + button for RNA property */
 -static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag)
 +/**
 + * Create label + button for RNA property
 + *
 + * \param w_hint: For varying width layout, this becomes the label width.
 + *                Otherwise it's used to fit both items into it.
 + **/
 +static uiBut *ui_item_with_label(
 +        uiLayout *layout, uiBlock *block, const char *name, int icon,
 +        PointerRNA *ptr, PropertyRNA *prop, int index,
 +        int x, int y, int w_hint, int h, int flag)
  {
        uiLayout *sub;
        uiBut *but = NULL;
        PropertyType type;
        PropertySubType subtype;
 -      int labelw;
 +      int prop_but_width = w_hint;
 +      const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
  
        sub = uiLayoutRow(layout, layout->align);
        UI_block_layout_set_current(block, sub);
  
        if (name[0]) {
 -              /* XXX UI_fontstyle_string_width is not accurate */
 -#if 0
 -              labelw = UI_fontstyle_string_width(fstyle, name);
 -              CLAMP(labelw, w / 4, 3 * w / 4);
 -#endif
 -              labelw = w / 3;
 -              uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, labelw, h, NULL, 0.0, 0.0, 0, 0, "");
 -              w = w - labelw;
 +              int w_label;
 +
 +              if (use_prop_sep) {
 +                      w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
 +              }
 +              else {
 +                      if (ui_layout_variable_size(layout)) {
 +                              /* w_hint is width for label in this case. Use a default width for property button(s) */
 +                              prop_but_width = UI_UNIT_X * 5;
 +                              w_label = w_hint;
 +                      }
 +                      else {
 +                              w_label = w_hint / 3;
 +                      }
 +              }
 +
 +              uiBut *but_label = uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
 +              if (use_prop_sep) {
 +                      but_label->drawflag |= UI_BUT_TEXT_RIGHT;
 +                      but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
 +              }
        }
  
        type = RNA_property_type(prop);
  
        if (subtype == PROP_FILEPATH || subtype == PROP_DIRPATH) {
                UI_block_layout_set_current(block, uiLayoutRow(sub, true));
 -              but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, w - UI_UNIT_X, h);
 +              but = uiDefAutoButR(block, ptr, prop, index, "", icon, x, y, prop_but_width - UI_UNIT_X, h);
  
                /* BUTTONS_OT_file_browse calls UI_context_active_but_prop_get_filebrowser */
                uiDefIconButO(
                        WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, NULL);
        }
        else if (flag & UI_ITEM_R_EVENT) {
 -              but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, w, h, ptr, prop, index, 0, 0, -1, -1, NULL);
 +              but = uiDefButR_prop(block, UI_BTYPE_KEY_EVENT, 0, name, x, y, prop_but_width, h, ptr, prop, index, 0, 0, -1, -1, NULL);
        }
        else if (flag & UI_ITEM_R_FULL_EVENT) {
                if (RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) {
  
                        WM_keymap_item_to_string(ptr->data, false, buf, sizeof(buf));
  
 -                      but = uiDefButR_prop(block, UI_BTYPE_HOTKEY_EVENT, 0, buf, x, y, w, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
 +                      but = uiDefButR_prop(block, UI_BTYPE_HOTKEY_EVENT, 0, buf, x, y, prop_but_width, h, ptr, prop, 0, 0, 0, -1, -1, NULL);
                        UI_but_func_set(but, ui_keymap_but_cb, but, NULL);
                        if (flag & UI_ITEM_R_IMMEDIATE)
                                UI_but_flag_enable(but, UI_BUT_IMMEDIATE);
                }
        }
 -      else
 -              but = uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "", icon, x, y, w, h);
 +      else {
 +              const char *str = (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY)) ? NULL : "";
 +              but = uiDefAutoButR(
 +                      block, ptr, prop, index, str, icon,
 +                      x, y, prop_but_width, h);
 +      }
  
        UI_block_layout_set_current(block, layout);
        return but;
@@@ -908,10 -821,8 +908,10 @@@ static uiBut *uiItemFullO_ptr_ex
  
        w = ui_text_icon_width(layout, name, icon, 0);
  
 -      if (flag & UI_ITEM_R_NO_BG)
 -              UI_block_emboss_set(block, UI_EMBOSS_NONE);
 +      int prev_emboss = layout->emboss;
 +      if (flag & UI_ITEM_R_NO_BG) {
 +              layout->emboss = UI_EMBOSS_NONE;
 +      }
  
        /* create the button */
        if (icon) {
        if ((layout->root->type == UI_LAYOUT_TOOLBAR) && !icon)
                but->drawflag |= UI_BUT_TEXT_LEFT;
  
 -      if (flag & UI_ITEM_R_NO_BG)
 -              UI_block_emboss_set(block, UI_EMBOSS);
 +      if (flag & UI_ITEM_R_NO_BG) {
 +              layout->emboss = prev_emboss;
 +      }
  
        if (flag & UI_ITEM_O_DEPRESS) {
                but->flag |= UI_SELECT_DRAW;
        return but;
  }
  
 -static void ui_item_hold_menu(struct bContext *C, ARegion *butregion, uiBut *but)
 +static void ui_item_menu_hold(struct bContext *C, ARegion *butregion, uiBut *but)
  {
        uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
        uiLayout *layout = UI_popup_menu_layout(pup);
        UI_popup_menu_but_set(pup, butregion, but);
  
        block->flag |= UI_BLOCK_POPUP_HOLD;
 +      block->flag |= UI_BLOCK_IS_FLIP;
 +
 +      char direction = UI_DIR_DOWN;
 +      if (!but->drawstr[0]) {
 +              if (butregion->alignment == RGN_ALIGN_LEFT) {
 +                      direction = UI_DIR_RIGHT;
 +              }
 +              else if (butregion->alignment == RGN_ALIGN_RIGHT) {
 +                      direction = UI_DIR_LEFT;
 +              }
 +              else if (butregion->alignment == RGN_ALIGN_BOTTOM) {
 +                      direction = UI_DIR_UP;
 +              }
 +              else {
 +                      direction = UI_DIR_DOWN;
 +              }
 +      }
 +      UI_block_direction_set(block, direction);
  
        const char *menu_id = but->hold_argN;
        MenuType *mt = WM_menutype_find(menu_id, true);
@@@ -1016,7 -908,7 +1016,7 @@@ void uiItemFullOMenuHold_ptr
          PointerRNA *r_opptr)
  {
        uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
 -      UI_but_func_hold_set(but, ui_item_hold_menu, BLI_strdup(menu_id));
 +      UI_but_func_hold_set(but, ui_item_menu_hold, BLI_strdup(menu_id));
  }
  
  void uiItemFullO(
@@@ -1244,15 -1136,7 +1244,15 @@@ void uiItemsFullEnumO
                bool free;
  
                if (ui_layout_is_radial(layout)) {
 +                      /* XXX: While "_all()" guarantees spatial stability, it's bad when an enum has > 8 items total,
 +                       * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the
 +                       * introduction of GP editing modes)
 +                       */
 +#if 0
                        RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
 +#else
 +                      RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
 +#endif
                }
                else {
                        RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
@@@ -1418,10 -1302,8 +1418,10 @@@ void uiItemO(uiLayout *layout, const ch
  /* RNA property items */
  
  static void ui_item_rna_size(
 -        uiLayout *layout, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop,
 -        int index, bool icon_only, int *r_w, int *r_h)
 +        uiLayout *layout, const char *name, int icon,
 +        PointerRNA *ptr, PropertyRNA *prop,
 +        int index, bool icon_only, bool compact,
 +        int *r_w, int *r_h)
  {
        PropertyType type;
        PropertySubType subtype;
                        RNA_property_enum_items_gettexted(layout->root->block->evil_C, ptr, prop, &item_array, NULL, &free);
                        for (item = item_array; item->identifier; item++) {
                                if (item->identifier[0]) {
 -                                      w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, 0));
 +                                      w = max_ii(w, ui_text_icon_width(layout, item->name, item->icon, compact));
                                }
                        }
                        if (free) {
  
        if (!w) {
                if (type == PROP_ENUM && icon_only) {
 -                      w = ui_text_icon_width(layout, "", ICON_BLANK1, 0);
 +                      w = ui_text_icon_width(layout, "", ICON_BLANK1, compact);
                        if (index != RNA_ENUM_VALUE)
                                w += 0.6f * UI_UNIT_X;
                }
                else {
 -                      w = ui_text_icon_width(layout, name, icon, 0);
 +                      /* not compact for float/int buttons, looks too squashed */
 +                      w = ui_text_icon_width(layout, name, icon, ELEM(type, PROP_FLOAT, PROP_INT) ? false : compact);
                }
        }
        h = UI_UNIT_Y;
        if (index == RNA_NO_INDEX && len > 0) {
                if (!name[0] && icon == ICON_NONE)
                        h = 0;
 -
 +              if (layout->item.flag & UI_ITEM_PROP_SEP)
 +                      h = 0;
                if (ELEM(subtype, PROP_LAYER, PROP_LAYER_MEMBER))
                        h += 2 * UI_UNIT_Y;
                else if (subtype == PROP_MATRIX)
                else
                        h += len * UI_UNIT_Y;
        }
 -      else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) {
 +      else if (ui_layout_variable_size(layout)) {
                if (type == PROP_BOOLEAN && name[0])
                        w += UI_UNIT_X / 5;
                else if (type == PROP_ENUM && !icon_only)
@@@ -1502,22 -1382,8 +1502,22 @@@ void uiItemFullR(uiLayout *layout, Poin
        PropertyType type;
        char namestr[UI_MAX_NAME_STR];
        int len, w, h;
 -      bool slider, toggle, expand, icon_only, no_bg;
 +      bool slider, toggle, expand, icon_only, no_bg, compact;
        bool is_array;
 +      const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
 +
 +#ifdef UI_PROP_DECORATE
 +      struct {
 +              bool use_prop_decorate;
 +              int len;
 +              uiLayout *layout;
 +              uiBut *but;
 +      } ui_decorate = {
 +              .use_prop_decorate = (
 +                      ((layout->item.flag & UI_ITEM_PROP_DECORATE) != 0) &&
 +                      (use_prop_sep && ptr->id.data && id_can_have_animdata(ptr->id.data))),
 +      };
 +#endif  /* UI_PROP_DECORATE */
  
        UI_block_layout_set_current(block, layout);
  
                /* pass */
        }
        else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
 -              name = ui_item_name_add_colon(name, namestr);
 +              if (use_prop_sep == false) {
 +                      name = ui_item_name_add_colon(name, namestr);
 +              }
        }
        else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
 -              name = ui_item_name_add_colon(name, namestr);
 +              if (use_prop_sep == false) {
 +                      name = ui_item_name_add_colon(name, namestr);
 +              }
        }
        else if (type == PROP_ENUM && index != RNA_ENUM_VALUE) {
 -              name = ui_item_name_add_colon(name, namestr);
 +              if (flag & UI_ITEM_R_COMPACT) {
 +                      name = "";
 +              }
 +              else {
 +                      if (use_prop_sep == false) {
 +                              name = ui_item_name_add_colon(name, namestr);
 +                      }
 +              }
        }
  
        /* menus and pie-menus don't show checkbox without this */
            /* use checkboxes only as a fallback in pie-menu's, when no icon is defined */
            ((layout->root->type == UI_LAYOUT_PIEMENU) && (icon == ICON_NONE)))
        {
 +              int prop_flag = RNA_property_flag(prop);
                if (type == PROP_BOOLEAN && ((is_array == false) || (index != RNA_NO_INDEX))) {
 -                      if (is_array) icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 -                      else icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 +                      if (prop_flag & PROP_ICONS_CONSECUTIVE) {
 +                              icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
 +                      }
 +                      else if (is_array) {
 +                              icon = (RNA_property_boolean_get_index(ptr, prop, index)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 +                      }
 +                      else {
 +                              icon = (RNA_property_boolean_get(ptr, prop)) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
 +                      }
                }
                else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
                        int enum_value = RNA_property_enum_get(ptr, prop);
 -                      if (RNA_property_flag(prop) & PROP_ENUM_FLAG) {
 +                      if (prop_flag & PROP_ICONS_CONSECUTIVE) {
 +                              icon = ICON_CHECKBOX_DEHLT; /* but->iconadd will set to correct icon */
 +                      }
 +                      else if (prop_flag & PROP_ENUM_FLAG) {
                                icon = (enum_value & value) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
                        }
                        else {
        expand = (flag & UI_ITEM_R_EXPAND) != 0;
        icon_only = (flag & UI_ITEM_R_ICON_ONLY) != 0;
        no_bg = (flag & UI_ITEM_R_NO_BG) != 0;
 +      compact = (flag & UI_ITEM_R_COMPACT) != 0;
  
        /* get size */
 -      ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, &w, &h);
 +      ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h);
  
 -      if (no_bg)
 -              UI_block_emboss_set(block, UI_EMBOSS_NONE);
 +      int prev_emboss = layout->emboss;
 +      if (no_bg) {
 +              layout->emboss = UI_EMBOSS_NONE;
 +      }
 +
 +      /* Split the label / property. */
 +      if (use_prop_sep) {
 +              uiLayout *layout_row = NULL;
 +#ifdef UI_PROP_DECORATE
 +              if (ui_decorate.use_prop_decorate) {
 +                      layout_row = uiLayoutRow(layout, true);
 +                      layout_row->space = 0;
 +                      ui_decorate.len = max_ii(1, len);
 +              }
 +#endif  /* UI_PROP_DECORATE */
 +
 +              if (name[0] == '\0') {
 +                      /* Ensure we get a column when text is not set. */
 +                      layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
 +                      layout->space = 0;
 +              }
 +              else {
 +                      const PropertySubType subtype = RNA_property_subtype(prop);
 +                      uiLayout *layout_split;
 +#ifdef UI_PROP_SEP_ICON_WIDTH_EXCEPTION
 +                      if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
 +                              w = UI_UNIT_X;
 +                              layout_split = uiLayoutRow(layout_row ? layout_row : layout, true);
 +                      }
 +                      else
 +#endif  /* UI_PROP_SEP_ICON_WIDTH_EXCEPTION */
 +                      {
 +                              layout_split = uiLayoutSplit(
 +                                      layout_row ? layout_row : layout,
 +                                      UI_ITEM_PROP_SEP_DIVIDE, true);
 +                      }
 +                      layout_split->space = 0;
 +                      uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
 +                      layout_sub->space = 0;
 +
 +                      if ((index == RNA_NO_INDEX && is_array) &&
 +                          ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0))
 +                      {
 +                              char name_with_suffix[UI_MAX_DRAW_STR + 2];
 +                              char str[2] = {'\0'};
 +                              for (int a = 0; a < len; a++) {
 +                                      str[0] = RNA_property_array_item_char(prop, a);
 +                                      const bool use_prefix = (a == 0 && name && name[0]);
 +                                      if (use_prefix) {
 +                                              char *s = name_with_suffix;
 +                                              s += STRNCPY_RLEN(name_with_suffix, name);
 +                                              *s++ = ' ';
 +                                              *s++ = str[0];
 +                                              *s++ = '\0';
 +                                      }
 +                                      but = uiDefBut(
 +                                              block, UI_BTYPE_LABEL, 0, use_prefix ? name_with_suffix : str,
 +                                              0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
 +                                      but->drawflag |= UI_BUT_TEXT_RIGHT;
 +                                      but->drawflag &= ~UI_BUT_TEXT_LEFT;
 +                              }
 +                      }
 +                      else {
 +                              if (name) {
 +                                      but = uiDefBut(
 +                                              block, UI_BTYPE_LABEL, 0, name,
 +                                              0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
 +                                      but->drawflag |= UI_BUT_TEXT_RIGHT;
 +                                      but->drawflag &= ~UI_BUT_TEXT_LEFT;
 +                              }
 +                      }
 +
 +                      /* Watch out! We can only write into the new column now. */
 +                      layout = uiLayoutColumn(layout_split, true);
 +                      layout->space = 0;
 +                      if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
 +                              /* pass (expanded enums each have their own name) */
 +                      }
 +                      else {
 +                              name = "";
 +                      }
 +              }
 +
 +#ifdef UI_PROP_DECORATE
 +              if (ui_decorate.use_prop_decorate) {
 +                      ui_decorate.layout = uiLayoutColumn(layout_row, true);
 +                      ui_decorate.layout->space = 0;
 +                      UI_block_layout_set_current(block, layout);
 +                      ui_decorate.but = block->buttons.last;
 +              }
 +#endif  /* UI_PROP_DECORATE */
 +      }
 +      /* End split. */
  
        /* array property */
 -      if (index == RNA_NO_INDEX && is_array)
 -              ui_item_array(layout, block, name, icon, ptr, prop, len, 0, 0, w, h, expand, slider, toggle, icon_only);
 +      if (index == RNA_NO_INDEX && is_array) {
 +              ui_item_array(
 +                      layout, block, name, icon, ptr, prop, len, 0, 0, w, h,
 +                      expand, slider, toggle, icon_only, compact, !use_prop_sep);
 +      }
        /* enum item */
        else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
                if (icon && name[0] && !icon_only)
                UI_but_flag_enable(but, UI_BUT_LIST_ITEM);
        }
  
 -      if (no_bg)
 -              UI_block_emboss_set(block, UI_EMBOSS);
 +#ifdef UI_PROP_DECORATE
 +      if (ui_decorate.use_prop_decorate) {
 +              const bool is_anim = RNA_property_animateable(ptr, prop);
 +              uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
 +              uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
 +              layout_col->space = 0;
 +              layout_col->emboss = UI_EMBOSS_NONE;
 +              int i;
 +              for (i = 0; i < ui_decorate.len && but_decorate; i++) {
 +                      /* The icons are set in 'ui_but_anim_flag' */
 +                      if (is_anim) {
 +                              but = uiDefIconBut(
 +                                      block, UI_BTYPE_BUT, 0, ICON_DOT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
 +                                      NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Animate property"));
 +                              UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
 +                              but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
 +                      }
 +                      else {
 +                              /* We may show other information here in future, for now use empty space. */
 +                              but = uiDefIconBut(
 +                                      block, UI_BTYPE_BUT, 0, ICON_BLANK1, 0, 0, UI_UNIT_X, UI_UNIT_Y,
 +                                      NULL, 0.0, 0.0, 0.0, 0.0, "");
 +                              but->flag |= UI_BUT_DISABLED;
 +                      }
 +                      /* Order the decorator after the button we decorate, this is used so we can always
 +                       * do a quick lookup. */
 +                      BLI_remlink(&block->buttons, but);
 +                      BLI_insertlinkafter(&block->buttons, but_decorate, but);
 +                      but_decorate = but->next;
 +              }
 +              BLI_assert(ELEM(i, 1, ui_decorate.len));
 +      }
 +#endif  /* UI_PROP_DECORATE */
 +
 +      if (no_bg) {
 +              layout->emboss = prev_emboss;
 +      }
  
        /* ensure text isn't added to icon_only buttons */
        if (but && icon_only) {
@@@ -1831,22 -1545,26 +1831,26 @@@ void uiItemEnumR(uiLayout *layout, cons
        uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, value, 0, name, icon);
  }
  
- void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon)
+ void uiItemEnumR_string_prop(
+         uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop,
+         const char *value, const char *name, int icon)
  {
-       PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
        const EnumPropertyItem *item;
        int ivalue, a;
        bool free;
  
-       if (!prop || RNA_property_type(prop) != PROP_ENUM) {
+       if (UNLIKELY(RNA_property_type(prop) != PROP_ENUM)) {
+               const char *propname = RNA_property_identifier(prop);
                ui_item_disabled(layout, propname);
-               RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               RNA_warning("not an enum property: %s.%s", RNA_struct_identifier(ptr->type), propname);
                return;
        }
  
        RNA_property_enum_items(layout->root->block->evil_C, ptr, prop, &item, NULL, &free);
  
        if (!RNA_enum_value_from_id(item, value, &ivalue)) {
+               const char *propname = RNA_property_identifier(prop);
                if (free) {
                        MEM_freeN((void *)item);
                }
        }
  }
  
+ void uiItemEnumR_string(
+         uiLayout *layout, struct PointerRNA *ptr, const char *propname,
+         const char *value, const char *name, int icon)
+ {
+       PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+       if (UNLIKELY(prop == NULL)) {
+               ui_item_disabled(layout, propname);
+               RNA_warning("enum property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               return;
+       }
+       uiItemEnumR_string_prop(layout, ptr, prop, value, name, icon);
+ }
  void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname)
  {
        PropertyRNA *prop;
  
  /* Pointer RNA button with search */
  
 -typedef struct CollItemSearch {
 -      struct CollItemSearch *next, *prev;
 -      char *name;
 -      int index;
 -      int iconid;
 -} CollItemSearch;
 -
 -static int sort_search_items_list(const void *a, const void *b)
 -{
 -      const CollItemSearch *cis1 = a;
 -      const CollItemSearch *cis2 = b;
 -
 -      if (BLI_strcasecmp(cis1->name, cis2->name) > 0)
 -              return 1;
 -      else
 -              return 0;
 -}
 -
 -static void rna_search_cb(const struct bContext *C, void *arg_but, const char *str, uiSearchItems *items)
 -{
 -      uiBut *but = arg_but;
 -      char *name;
 -      int i = 0, iconid = 0, flag = RNA_property_flag(but->rnaprop);
 -      ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
 -      CollItemSearch *cis;
 -      const bool skip_filter = !but->changed;
 -
 -      /* build a temporary list of relevant items first */
 -      RNA_PROP_BEGIN (&but->rnasearchpoin, itemptr, but->rnasearchprop)
 -      {
 -              if (flag & PROP_ID_SELF_CHECK)
 -                      if (itemptr.data == but->rnapoin.id.data)
 -                              continue;
 -
 -              /* use filter */
 -              if (RNA_property_type(but->rnaprop) == PROP_POINTER) {
 -                      if (RNA_property_pointer_poll(&but->rnapoin, but->rnaprop, &itemptr) == 0)
 -                              continue;
 -              }
 -
 -              if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
 -                      ID *id = itemptr.data;
 -                      char name_ui[MAX_ID_NAME];
 -
 -#if 0       /* this name is used for a string comparison and can't be modified, TODO */
 -                      /* if ever enabled, make name_ui be MAX_ID_NAME+1 */
 -                      BKE_id_ui_prefix(name_ui, id);
 -#else
 -                      BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
 -#endif
 -                      name = BLI_strdup(name_ui);
 -                      iconid = ui_id_icon_get(C, id, false);
 -              }
 -              else {
 -                      name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL); /* could use the string length here */
 -                      iconid = 0;
 -              }
 -
 -              if (name) {
 -                      if (skip_filter || BLI_strcasestr(name, str)) {
 -                              cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
 -                              cis->name = MEM_dupallocN(name);
 -                              cis->index = i;
 -                              cis->iconid = iconid;
 -                              BLI_addtail(items_list, cis);
 -                      }
 -                      MEM_freeN(name);
 -              }
 -
 -              i++;
 -      }
 -      RNA_PROP_END;
 -
 -      BLI_listbase_sort(items_list, sort_search_items_list);
 -
 -      /* add search items from temporary list */
 -      for (cis = items_list->first; cis; cis = cis->next) {
 -              if (false == UI_search_item_add(items, cis->name, SET_INT_IN_POINTER(cis->index), cis->iconid)) {
 -                      break;
 -              }
 -      }
 -
 -      for (cis = items_list->first; cis; cis = cis->next) {
 -              MEM_freeN(cis->name);
 -      }
 -      BLI_freelistN(items_list);
 -      MEM_freeN(items_list);
 -}
  
  static void search_id_collection(StructRNA *ptype, PointerRNA *ptr, PropertyRNA **prop)
  {
@@@ -1974,8 -1793,6 +1991,8 @@@ void ui_but_add_search(uiBut *but, Poin
  
        /* turn button into search button */
        if (searchprop) {
 +              uiRNACollectionSearch *coll_search = MEM_mallocN(sizeof(*coll_search), __func__);
 +
                but->type = UI_BTYPE_SEARCH_MENU;
                but->hardmax = MAX2(but->hardmax, 256.0f);
                but->rnasearchpoin = *searchptr;
                        but->flag |= UI_BUT_VALUE_CLEAR;
                }
  
 +              coll_search->target_ptr = *ptr;
 +              coll_search->target_prop = prop;
 +              coll_search->search_ptr = *searchptr;
 +              coll_search->search_prop = searchprop;
 +              coll_search->but_changed = &but->changed;
 +
                if (RNA_property_type(prop) == PROP_ENUM) {
                        /* XXX, this will have a menu string,
                         * but in this case we just want the text */
                        but->str[0] = 0;
                }
  
 -              UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL);
 +              UI_but_func_search_set(
 +                      but, ui_searchbox_create_generic, ui_rna_collection_search_cb,
 +                      coll_search, NULL, NULL);
 +              but->free_search_arg = true;
        }
        else if (but->type == UI_BTYPE_SEARCH_MENU) {
                /* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */
        }
  }
  
- void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
+ void uiItemPointerR_prop(
+         uiLayout *layout,
+         PointerRNA *ptr, PropertyRNA *prop,
+         PointerRNA *searchptr, PropertyRNA *searchprop,
+         const char *name, int icon)
  {
-       PropertyRNA *prop, *searchprop;
        PropertyType type;
        uiBut *but;
        uiBlock *block;
        StructRNA *icontype;
        int w, h;
        char namestr[UI_MAX_NAME_STR];
 +      const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
  
-       /* validate arguments */
-       prop = RNA_struct_find_property(ptr, propname);
-       if (!prop) {
-               RNA_warning("property not found: %s.%s",
-                           RNA_struct_identifier(ptr->type), propname);
-               return;
-       }
        type = RNA_property_type(prop);
        if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
-               RNA_warning("Property %s must be a pointer, string or enum", propname);
-               return;
-       }
-       searchprop = RNA_struct_find_property(searchptr, searchpropname);
-       if (!searchprop) {
-               RNA_warning("search collection property not found: %s.%s",
-                           RNA_struct_identifier(searchptr->type), searchpropname);
+               RNA_warning("Property %s.%s must be a pointer, string or enum",
+                           RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
                return;
        }
-       else if (RNA_property_type(searchprop) != PROP_COLLECTION) {
+       if (RNA_property_type(searchprop) != PROP_COLLECTION) {
                RNA_warning("search collection property is not a collection type: %s.%s",
-                           RNA_struct_identifier(searchptr->type), searchpropname);
+                           RNA_struct_identifier(searchptr->type), RNA_property_identifier(searchprop));
                return;
        }
  
        if (!name)
                name = RNA_property_ui_name(prop);
  
 -      name = ui_item_name_add_colon(name, namestr);
 +      if (use_prop_sep == false) {
 +              name = ui_item_name_add_colon(name, namestr);
 +      }
  
        /* create button */
        block = uiLayoutGetBlock(layout);
  
 -      ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, &w, &h);
 +      ui_item_rna_size(layout, name, icon, ptr, prop, 0, 0, false, &w, &h);
        w += UI_UNIT_X; /* X icon needs more space */
        but = ui_item_with_label(layout, block, name, icon, ptr, prop, 0, 0, 0, w, h, 0);
  
        ui_but_add_search(but, ptr, prop, searchptr, searchprop);
  }
  
+ void uiItemPointerR(
+         uiLayout *layout,
+         PointerRNA *ptr, const char *propname,
+         PointerRNA *searchptr, const char *searchpropname,
+         const char *name, int icon)
+ {
+       PropertyRNA *prop, *searchprop;
+       /* validate arguments */
+       prop = RNA_struct_find_property(ptr, propname);
+       if (!prop) {
+               RNA_warning("property not found: %s.%s",
+                           RNA_struct_identifier(ptr->type), propname);
+               return;
+       }
+       searchprop = RNA_struct_find_property(searchptr, searchpropname);
+       if (!searchprop) {
+               RNA_warning("search collection property not found: %s.%s",
+                           RNA_struct_identifier(searchptr->type), searchpropname);
+               return;
+       }
+       uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
+ }
  /* menu item */
  static void ui_item_menutype_func(bContext *C, uiLayout *layout, void *arg_mt)
  {
        layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
  }
  
 +void ui_item_paneltype_func(bContext *C, uiLayout *layout, void *arg_pt)
 +{
 +      PanelType *pt = (PanelType *)arg_pt;
 +      UI_paneltype_draw(C, pt, layout);
 +
 +      /* panels are created flipped (from event handling pov) */
 +      layout->root->block->flag ^= UI_BLOCK_IS_FLIP;
 +}
 +
  static uiBut *ui_item_menu(
          uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg, void *argN,
          const char *tip, bool force_menu)
  
        UI_block_layout_set_current(block, layout);
  
 -      if (layout->root->type == UI_LAYOUT_HEADER)
 -              UI_block_emboss_set(block, UI_EMBOSS);
 -
        if (!name)
                name = "";
        if (layout->root->type == UI_LAYOUT_MENU && !icon)
        h = UI_UNIT_Y;
  
        if (layout->root->type == UI_LAYOUT_HEADER) { /* ugly .. */
 -              if (force_menu) {
 +              if (icon == ICON_NONE && force_menu) {
 +                      /* pass */
 +              }
 +              else if (force_menu) {
                        w += UI_UNIT_X;
                }
                else {
                but->func_argN = argN;
        }
  
 -      if (layout->root->type == UI_LAYOUT_HEADER) {
 -              UI_block_emboss_set(block, UI_EMBOSS);
 -      }
        if (ELEM(layout->root->type, UI_LAYOUT_PANEL, UI_LAYOUT_TOOLBAR) ||
            (force_menu && layout->root->type != UI_LAYOUT_MENU))  /* We never want a dropdown in menu! */
        {
@@@ -2168,76 -1978,6 +2196,76 @@@ void uiItemM(uiLayout *layout, const ch
        ui_item_menu(layout, name, icon, ui_item_menutype_func, mt, NULL, TIP_(mt->description), false);
  }
  
 +/* popover */
 +void uiItemPopoverPanel_ptr(uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
 +{
 +      if (!name) {
 +              name = CTX_IFACE_(pt->translation_context, pt->label);
 +      }
 +
 +      if (layout->root->type == UI_LAYOUT_MENU && !icon) {
 +              icon = ICON_BLANK1;
 +      }
 +
 +      const bool ok = (pt->poll == NULL) || pt->poll(C, pt);
 +      if (ok && (pt->draw_header != NULL)) {
 +              layout = uiLayoutRow(layout, true);
 +              Panel panel = {
 +                      .type = pt,
 +                      .layout = layout,
 +                      .flag = PNL_POPOVER,
 +              };
 +              pt->draw_header(C, &panel);
 +      }
 +      uiBut *but = ui_item_menu(layout, name, icon, ui_item_paneltype_func, pt, NULL, NULL, true);
 +      but->type = UI_BTYPE_POPOVER;
 +      if (!ok) {
 +              but->flag |= UI_BUT_DISABLED;
 +      }
 +}
 +
 +void uiItemPopoverPanel(
 +        uiLayout *layout, bContext *C,
 +        const char *panel_type, const char *name, int icon)
 +{
 +      PanelType *pt = WM_paneltype_find(panel_type, true);
 +      if (pt == NULL) {
 +              RNA_warning("Panel type not found '%s'", panel_type);
 +              return;
 +      }
 +      uiItemPopoverPanel_ptr(layout, C, pt, name, icon);
 +}
 +
 +void uiItemPopoverPanelFromGroup(
 +        uiLayout *layout, bContext *C,
 +        int space_id, int region_id, const char *context, const char *category)
 +{
 +      SpaceType *st = BKE_spacetype_from_id(space_id);
 +      if (st == NULL) {
 +              RNA_warning("space type not found %d", space_id);
 +              return;
 +      }
 +      ARegionType *art = BKE_regiontype_from_id(st, region_id);
 +      if (art == NULL) {
 +              RNA_warning("region type not found %d", region_id);
 +              return;
 +      }
 +
 +      for (PanelType *pt = art->paneltypes.first; pt; pt = pt->next) {
 +              /* Causes too many panels, check context. */
 +              if (pt->parent_id[0] == '\0') {
 +                      if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
 +                              if ((*category == '\0') || STREQ(pt->category, category)) {
 +                                      if (pt->poll == NULL || pt->poll(C, pt)) {
 +                                              uiItemPopoverPanel_ptr(layout, C, pt, NULL, ICON_NONE);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +
  /* label item */
  static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
  {
@@@ -2328,26 -2068,6 +2356,26 @@@ void uiItemS(uiLayout *layout
        uiDefBut(block, (is_menu) ? UI_BTYPE_SEPR_LINE : UI_BTYPE_SEPR, 0, "", 0, 0, space, space, NULL, 0.0, 0.0, 0, 0, "");
  }
  
 +/* Flexible spacing. */
 +void uiItemSpacer(uiLayout *layout)
 +{
 +      uiBlock *block = layout->root->block;
 +      bool is_menu = ui_block_is_menu(block);
 +
 +      if (is_menu) {
 +              printf("Error: separator_spacer() not supported in menus.\n");
 +              return;
 +      }
 +
 +      if (block->direction & UI_DIR_RIGHT) {
 +              printf("Error: separator_spacer() only supported in horizontal blocks.\n");
 +              return;
 +      }
 +
 +      UI_block_layout_set_current(block, layout);
 +      uiDefBut(block, UI_BTYPE_SEPR_SPACER, 0, "", 0, 0, 0.3f * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
 +}
 +
  /* level items */
  void uiItemMenuF(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc func, void *arg)
  {
@@@ -2732,7 -2452,7 +2760,7 @@@ static bool ui_item_is_radial_displayab
  static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
  {
  
 -      if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE))
 +      if (ELEM(bitem->but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER))
                return false;
  
        return true;
@@@ -3005,364 -2725,6 +3033,364 @@@ static void ui_litem_layout_column_flow
        litem->y = miny;
  }
  
 +/* multi-column and multi-row layout. */
 +typedef struct UILayoutGridFlowInput {
 +      /* General layout controll settings. */
 +      const bool row_major : 1;  /* Fill rows before columns */
 +      const bool even_columns : 1;  /* All columns will have same width. */
 +      const bool even_rows : 1;  /* All rows will have same height. */
 +      const int space_x;  /* Space between columns. */
 +      const int space_y;  /* Space between rows. */
 +      /* Real data about current position and size of this layout item (either estimated, or final values). */
 +      const int litem_w;  /* Layout item width. */
 +      const int litem_x;  /* Layout item X position. */
 +      const int litem_y;  /* Layout item Y position. */
 +      /* Actual number of columns and rows to generate (computed from first pass usually). */
 +      const int tot_columns;  /* Number of columns. */
 +      const int tot_rows;  /* Number of rows. */
 +} UILayoutGridFlowInput;
 +
 +typedef struct UILayoutGridFlowOutput {
 +      int *tot_items;  /* Total number of items in this grid layout. */
 +      /* Width / X pos data. */
 +      float *global_avg_w;  /* Computed average width of the columns. */
 +      int *cos_x_array;  /* Computed X coordinate of each column. */
 +      int *widths_array;  /* Computed width of each column. */
 +      int *tot_w;  /* Computed total width. */
 +      /* Height / Y pos data. */
 +      int *global_max_h;  /* Computed height of the tallest item in the grid. */
 +      int *cos_y_array;  /* Computed Y coordinate of each column. */
 +      int *heights_array;  /* Computed height of each column. */
 +      int *tot_h;  /* Computed total height. */
 +} UILayoutGridFlowOutput;
 +
 +static void ui_litem_grid_flow_compute(
 +        ListBase *items, UILayoutGridFlowInput *parameters, UILayoutGridFlowOutput *results)
 +{
 +      uiItem *item;
 +      int i;
 +
 +      float tot_w = 0.0f, tot_h = 0.0f;
 +      float global_avg_w = 0.0f, global_totweight_w = 0.0f;
 +      int global_max_h = 0;
 +
 +      float *avg_w = NULL, *totweight_w = NULL;
 +      int *max_h = NULL;
 +
 +      BLI_assert(parameters->tot_columns != 0 || (results->cos_x_array == NULL && results->widths_array == NULL && results->tot_w == NULL));
 +      BLI_assert(parameters->tot_rows != 0 || (results->cos_y_array == NULL && results->heights_array == NULL && results->tot_h == NULL));
 +
 +      if (results->tot_items) {
 +              *results->tot_items = 0;
 +      }
 +
 +      if (items->first == NULL) {
 +              if (results->global_avg_w) {
 +                      *results->global_avg_w = 0.0f;
 +              }
 +              if (results->global_max_h) {
 +                      *results->global_max_h = 0;
 +              }
 +              return;
 +      }
 +
 +      if (parameters->tot_columns != 0) {
 +              avg_w = BLI_array_alloca(avg_w, parameters->tot_columns);
 +              totweight_w = BLI_array_alloca(totweight_w, parameters->tot_columns);
 +              memset(avg_w, 0, sizeof(*avg_w) * parameters->tot_columns);
 +              memset(totweight_w, 0, sizeof(*totweight_w) * parameters->tot_columns);
 +      }
 +      if (parameters->tot_rows != 0) {
 +              max_h = BLI_array_alloca(max_h, parameters->tot_rows);
 +              memset(max_h, 0, sizeof(*max_h) * parameters->tot_rows);
 +      }
 +
 +      for (i = 0, item = items->first; item; item = item->next, i++) {
 +              int item_w, item_h;
 +              ui_item_size(item, &item_w, &item_h);
 +
 +              global_avg_w += (float)(item_w * item_w);
 +              global_totweight_w += (float)item_w;
 +              global_max_h = max_ii(global_max_h, item_h);
 +
 +              if (parameters->tot_rows != 0 && parameters->tot_columns != 0) {
 +                      const int index_col = parameters->row_major ? i % parameters->tot_columns : i / parameters->tot_rows;
 +                      const int index_row = parameters->row_major ? i / parameters->tot_columns : i % parameters->tot_rows;
 +
 +                      avg_w[index_col] += (float)(item_w * item_w);
 +                      totweight_w[index_col] += (float)item_w;
 +
 +                      max_h[index_row] = max_ii(max_h[index_row], item_h);
 +              }
 +
 +              if (results->tot_items) {
 +                      (*results->tot_items)++;
 +              }
 +      }
 +
 +      /* Finalize computing of column average sizes */
 +      global_avg_w /= global_totweight_w;
 +      if (parameters->tot_columns != 0) {
 +              for (i = 0; i < parameters->tot_columns; i++) {
 +                      avg_w[i] /= totweight_w[i];
 +                      tot_w += avg_w[i];
 +              }
 +              if (parameters->even_columns) {
 +                      tot_w = ceilf(global_avg_w) * parameters->tot_columns;
 +              }
 +      }
 +      /* Finalize computing of rows max sizes */
 +      if (parameters->tot_rows != 0) {
 +              for (i = 0; i < parameters->tot_rows; i++) {
 +                      tot_h += max_h[i];
 +              }
 +              if (parameters->even_rows) {
 +                      tot_h = global_max_h * parameters->tot_columns;
 +              }
 +      }
 +
 +      /* Compute positions and sizes of all cells. */
 +      if (results->cos_x_array != NULL && results->widths_array != NULL) {
 +              /* We enlarge/narrow columns evenly to match available width. */
 +              const float wfac = (float)(parameters->litem_w - (parameters->tot_columns - 1) * parameters->space_x) / tot_w;
 +
 +              for (int col = 0; col < parameters->tot_columns; col++) {
 +                      results->cos_x_array[col] = (
 +                              col ?
 +                              results->cos_x_array[col - 1] + results->widths_array[col - 1] + parameters->space_x :
 +                              parameters->litem_x
 +                      );
 +                      if (parameters->even_columns) {
 +                              /* (< remaining width > - < space between remaining columns >) / < remaining columns > */
 +                              results->widths_array[col] = (
 +                                      ((parameters->litem_w - (results->cos_x_array[col] - parameters->litem_x)) -
 +                                       (parameters->tot_columns - col - 1) * parameters->space_x) / (parameters->tot_columns - col));
 +                      }
 +                      else if (col == parameters->tot_columns - 1) {
 +                              /* Last column copes width rounding errors... */
 +                              results->widths_array[col] = parameters->litem_w - (results->cos_x_array[col] - parameters->litem_x);
 +                      }
 +                      else {
 +                              results->widths_array[col] = (int)(avg_w[col] * wfac);
 +                      }
 +              }
 +      }
 +      if (results->cos_y_array != NULL && results->heights_array != NULL) {
 +              for (int row = 0; row < parameters->tot_rows; row++) {
 +                      if (parameters->even_rows) {
 +                              results->heights_array[row] = global_max_h;
 +                      }
 +                      else {
 +                              results->heights_array[row] = max_h[row];
 +                      }
 +                      results->cos_y_array[row] = (
 +                              row ?
 +                              results->cos_y_array[row - 1] - parameters->space_y - results->heights_array[row] :
 +                              parameters->litem_y - results->heights_array[row]);
 +              }
 +      }
 +
 +      if (results->global_avg_w) {
 +              *results->global_avg_w = global_avg_w;
 +      }
 +      if (results->global_max_h) {
 +              *results->global_max_h = global_max_h;
 +      }
 +      if (results->tot_w) {
 +              *results->tot_w = (int)tot_w + parameters->space_x * (parameters->tot_columns - 1);
 +      }
 +      if (results->tot_h) {
 +              *results->tot_h = tot_h + parameters->space_y * (parameters->tot_rows - 1);
 +      }
 +}
 +
 +static void ui_litem_estimate_grid_flow(uiLayout *litem)
 +{
 +      uiStyle *style = litem->root->style;
 +      uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
 +
 +      const int space_x = style->columnspace;
 +      const int space_y = style->buttonspacey;
 +
 +      /* Estimate average needed width and height per item. */
 +      {
 +              float avg_w;
 +              int max_h;
 +
 +              ui_litem_grid_flow_compute(
 +                      &litem->items,
 +                      &((UILayoutGridFlowInput) {
 +                            .row_major = gflow->row_major,
 +                            .even_columns = gflow->even_columns,
 +                            .even_rows = gflow->even_rows,
 +                            .litem_w = litem->w,
 +                            .litem_x = litem->x,
 +                            .litem_y = litem->y,
 +                            .space_x = space_x,
 +                            .space_y = space_y,
 +                      }),
 +                      &((UILayoutGridFlowOutput) {
 +                            .tot_items = &gflow->tot_items,
 +                            .global_avg_w = &avg_w,
 +                            .global_max_h = &max_h,
 +                      }));
 +
 +              if (gflow->tot_items == 0) {
 +                      litem->w = litem->h = 0;
 +                      gflow->tot_columns = gflow->tot_rows = 0;
 +                      return;
 +              }
 +
 +              /* Even in varying column width case, we fix our columns number from weighted average width of items,
 +               * a proper solving of required width would be too costly, and this should give reasonably good results
 +               * in all resonable cases... */
 +              if (gflow->columns_len > 0) {
 +                      gflow->tot_columns = gflow->columns_len;
 +              }
 +              else {
 +                      if (avg_w == 0.0f) {
 +                              gflow->tot_columns = 1;
 +                      }
 +                      else {
 +                              gflow->tot_columns = min_ii(max_ii((int)(litem->w / avg_w), 1), gflow->tot_items);
 +                      }
 +              }
 +              gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
 +
 +              /* Try to tweak number of columns and rows to get better filling of last column or row,
 +               * and apply 'modulo' value to number of columns or rows.
 +               * Note that modulo does not prevent ending with fewer columns/rows than modulo, if mandatory
 +               * to avoid empty column/row. */
 +              {
 +                      const int modulo = (gflow->columns_len < -1) ? -gflow->columns_len : 0;
 +                      const int step = modulo ? modulo : 1;
 +
 +                      if (gflow->row_major) {
 +                              /* Adjust number of columns to be mutiple of given modulo. */
 +                              if (modulo && gflow->tot_columns % modulo != 0 && gflow->tot_columns > modulo) {
 +                                      gflow->tot_columns = gflow->tot_columns - (gflow->tot_columns % modulo);
 +                              }
 +                              /* Find smallest number of columns conserving computed optimal number of rows. */
 +                              for (gflow->tot_rows = (int)ceilf((float)gflow->tot_items / gflow->tot_columns);
 +                                   (gflow->tot_columns - step) > 0 &&
 +                                   (int)ceilf((float)gflow->tot_items / (gflow->tot_columns - step)) <= gflow->tot_rows;
 +                                   gflow->tot_columns -= step);
 +                      }
 +                      else {
 +                              /* Adjust number of rows to be mutiple of given modulo. */
 +                              if (modulo && gflow->tot_rows % modulo != 0) {
 +                                      gflow->tot_rows = min_ii(gflow->tot_rows + modulo - (gflow->tot_rows % modulo), gflow->tot_items);
 +                              }
 +                              /* Find smallest number of rows conserving computed optimal number of columns. */
 +                              for (gflow->tot_columns = (int)ceilf((float)gflow->tot_items / gflow->tot_rows);
 +                                   (gflow->tot_rows - step) > 0 &&
 +                                   (int)ceilf((float)gflow->tot_items / (gflow->tot_rows - step)) <= gflow->tot_columns;
 +                                   gflow->tot_rows -= step);
 +                      }
 +              }
 +
 +              /* Set evenly-spaced axes size (quick optimization in case we have even columns and rows). */
 +              if (gflow->even_columns && gflow->even_rows) {
 +                      litem->w = (int)(gflow->tot_columns * avg_w) + space_x * (gflow->tot_columns - 1);
 +                      litem->h = (int)(gflow->tot_rows * max_h) + space_y * (gflow->tot_rows - 1);
 +                      return;
 +              }
 +      }
 +
 +      /* Now that we have our final number of columns and rows,
 +       * we can compute actual needed space for non-evenly sized axes. */
 +      {
 +              int tot_w, tot_h;
 +
 +              ui_litem_grid_flow_compute(
 +                      &litem->items,
 +                      &((UILayoutGridFlowInput) {
 +                            .row_major = gflow->row_major,
 +                            .even_columns = gflow->even_columns,
 +                            .even_rows = gflow->even_rows,
 +                            .litem_w = litem->w,
 +                            .litem_x = litem->x,
 +                            .litem_y = litem->y,
 +                            .space_x = space_x,
 +                            .space_y = space_y,
 +                            .tot_columns = gflow->tot_columns,
 +                            .tot_rows = gflow->tot_rows,
 +                      }),
 +                      &((UILayoutGridFlowOutput) {
 +                            .tot_w = &tot_w,
 +                            .tot_h = &tot_h,
 +                      }));
 +
 +              litem->w = tot_w;
 +              litem->h = tot_h;
 +      }
 +}
 +
 +static void ui_litem_layout_grid_flow(uiLayout *litem)
 +{
 +      int i;
 +      uiStyle *style = litem->root->style;
 +      uiLayoutItemGridFlow *gflow = (uiLayoutItemGridFlow *)litem;
 +      uiItem *item;
 +
 +      if (gflow->tot_items == 0) {
 +              litem->w = litem->h = 0;
 +              return;
 +      }
 +
 +      BLI_assert(gflow->tot_columns > 0);
 +      BLI_assert(gflow->tot_rows > 0);
 +
 +      const int space_x = style->columnspace;
 +      const int space_y = style->buttonspacey;
 +
 +      int *widths = BLI_array_alloca(widths, gflow->tot_columns);
 +      int *heights = BLI_array_alloca(heights, gflow->tot_rows);
 +      int *cos_x = BLI_array_alloca(cos_x, gflow->tot_columns);
 +      int *cos_y = BLI_array_alloca(cos_y, gflow->tot_rows);
 +
 +      /* This time we directly compute coordinates and sizes of all cells. */
 +      ui_litem_grid_flow_compute(
 +              &litem->items,
 +              &((UILayoutGridFlowInput) {
 +                    .row_major = gflow->row_major,
 +                    .even_columns = gflow->even_columns,
 +                    .even_rows = gflow->even_rows,
 +                    .litem_w = litem->w,
 +                    .litem_x = litem->x,
 +                    .litem_y = litem->y,
 +                    .space_x = space_x,
 +                    .space_y = space_y,
 +                    .tot_columns = gflow->tot_columns,
 +                    .tot_rows = gflow->tot_rows,
 +              }),
 +              &((UILayoutGridFlowOutput) {
 +                    .cos_x_array = cos_x,
 +                    .cos_y_array = cos_y,
 +                    .widths_array = widths,
 +                    .heights_array = heights,
 +              }));
 +
 +      for (item = litem->items.first, i = 0; item; item = item->next, i++) {
 +              const int col = gflow->row_major ? i % gflow->tot_columns : i / gflow->tot_rows;
 +              const int row = gflow->row_major ? i / gflow->tot_columns : i % gflow->tot_rows;
 +              int item_w, item_h;
 +              ui_item_size(item, &item_w, &item_h);
 +
 +              const int w = widths[col];
 +              const int h = heights[row];
 +
 +              item_w = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? w : min_ii(w, item_w);
 +              item_h = (litem->alignment == UI_LAYOUT_ALIGN_EXPAND) ? h : min_ii(h, item_h);
 +
 +              ui_item_position(item, cos_x[col], cos_y[row], item_w, item_h);
 +      }
 +
 +      litem->h = litem->y - cos_y[gflow->tot_rows - 1];
 +      litem->x = (cos_x[gflow->tot_columns - 1] - litem->x) + widths[gflow->tot_columns - 1];
 +      litem->y = litem->y - litem->h;
 +}
 +
  /* free layout */
  static void ui_litem_estimate_absolute(uiLayout *litem)
  {
@@@ -3532,32 -2894,22 +3560,32 @@@ static void ui_litem_layout_overlap(uiL
        litem->y = y - litem->h;
  }
  
 -/* layout create functions */
 -uiLayout *uiLayoutRow(uiLayout *layout, bool align)
 +static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int align)
  {
 -      uiLayout *litem;
 -
 -      litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
 -      litem->item.type = ITEM_LAYOUT_ROW;
        litem->root = layout->root;
        litem->align = align;
 +      /* Children of gridflow layout shall never have "ideal big size" returned as estimated size. */
 +      litem->variable_size = layout->variable_size || layout->item.type == ITEM_LAYOUT_GRID_FLOW;
        litem->active = true;
        litem->enabled = true;
        litem->context = layout->context;
 -      litem->space = (align) ? 0 : layout->root->style->buttonspacex;
        litem->redalert = layout->redalert;
        litem->w = layout->w;
 +      litem->emboss = layout->emboss;
 +      litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
        BLI_addtail(&layout->items, litem);
 +}
 +
 +/* layout create functions */
 +uiLayout *uiLayoutRow(uiLayout *layout, bool align)
 +{
 +      uiLayout *litem;
 +
 +      litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
 +      ui_litem_init_from_parent(litem, layout, align);
 +
 +      litem->item.type = ITEM_LAYOUT_ROW;
 +      litem->space = (align) ? 0 : layout->root->style->buttonspacex;
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3569,10 -2921,16 +3597,10 @@@ uiLayout *uiLayoutColumn(uiLayout *layo
        uiLayout *litem;
  
        litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn");
 +      ui_litem_init_from_parent(litem, layout, align);
 +
        litem->item.type = ITEM_LAYOUT_COLUMN;
 -      litem->root = layout->root;
 -      litem->align = align;
 -      litem->active = true;
 -      litem->enabled = true;
 -      litem->context = layout->context;
 -      litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
 -      litem->redalert = layout->redalert;
 -      litem->w = layout->w;
 -      BLI_addtail(&layout->items, litem);
 +      litem->space = (align) ? 0 : layout->root->style->buttonspacey;
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3584,31 -2942,17 +3612,31 @@@ uiLayout *uiLayoutColumnFlow(uiLayout *
        uiLayoutItemFlow *flow;
  
        flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
 +      ui_litem_init_from_parent(&flow->litem, layout, align);
 +
        flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW;
 -      flow->litem.root = layout->root;
 -      flow->litem.align = align;
 -      flow->litem.active = true;
 -      flow->litem.enabled = true;
 -      flow->litem.context = layout->context;
        flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
 -      flow->litem.redalert = layout->redalert;
 -      flow->litem.w = layout->w;
        flow->number = number;
 -      BLI_addtail(&layout->items, flow);
 +
 +      UI_block_layout_set_current(layout->root->block, &flow->litem);
 +
 +      return &flow->litem;
 +}
 +
 +uiLayout *uiLayoutGridFlow(
 +        uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
 +{
 +      uiLayoutItemGridFlow *flow;
 +
 +      flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__);
 +      flow->litem.item.type = ITEM_LAYOUT_GRID_FLOW;
 +      ui_litem_init_from_parent(&flow->litem, layout, align);
 +
 +      flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
 +      flow->row_major = row_major;
 +      flow->columns_len = columns_len;
 +      flow->even_columns = even_columns;
 +      flow->even_rows = even_rows;
  
        UI_block_layout_set_current(layout->root->block, &flow->litem);
  
@@@ -3620,10 -2964,15 +3648,10 @@@ static uiLayoutItemBx *ui_layout_box(ui
        uiLayoutItemBx *box;
  
        box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx");
 +      ui_litem_init_from_parent(&box->litem, layout, false);
 +
        box->litem.item.type = ITEM_LAYOUT_BOX;
 -      box->litem.root = layout->root;
 -      box->litem.active = 1;
 -      box->litem.enabled = 1;
 -      box->litem.context = layout->context;
        box->litem.space = layout->root->style->columnspace;
 -      box->litem.redalert = layout->redalert;
 -      box->litem.w = layout->w;
 -      BLI_addtail(&layout->items, box);
  
        UI_block_layout_set_current(layout->root->block, &box->litem);
  
@@@ -3651,9 -3000,14 +3679,9 @@@ uiLayout *uiLayoutRadial(uiLayout *layo
        }
  
        litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
 +      ui_litem_init_from_parent(litem, layout, false);
 +
        litem->item.type = ITEM_LAYOUT_RADIAL;
 -      litem->root = layout->root;
 -      litem->active = true;
 -      litem->enabled = true;
 -      litem->context = layout->context;
 -      litem->redalert = layout->redalert;
 -      litem->w = layout->w;
 -      BLI_addtail(&layout->root->layout->items, litem);
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3710,9 -3064,14 +3738,9 @@@ uiLayout *uiLayoutAbsolute(uiLayout *la
        uiLayout *litem;
  
        litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute");
 +      ui_litem_init_from_parent(litem, layout, align);
 +
        litem->item.type = ITEM_LAYOUT_ABSOLUTE;
 -      litem->root = layout->root;
 -      litem->align = align;
 -      litem->active = 1;
 -      litem->enabled = 1;
 -      litem->context = layout->context;
 -      litem->redalert = layout->redalert;
 -      BLI_addtail(&layout->items, litem);
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3734,9 -3093,13 +3762,9 @@@ uiLayout *uiLayoutOverlap(uiLayout *lay
        uiLayout *litem;
  
        litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap");
 +      ui_litem_init_from_parent(litem, layout, false);
 +
        litem->item.type = ITEM_LAYOUT_OVERLAP;
 -      litem->root = layout->root;
 -      litem->active = true;
 -      litem->enabled = true;
 -      litem->context = layout->context;
 -      litem->redalert = layout->redalert;
 -      BLI_addtail(&layout->items, litem);
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3748,11 -3111,17 +3776,11 @@@ uiLayout *uiLayoutSplit(uiLayout *layou
        uiLayoutItemSplit *split;
  
        split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit");
 +      ui_litem_init_from_parent(&split->litem, layout, align);
 +
        split->litem.item.type = ITEM_LAYOUT_SPLIT;
 -      split->litem.root = layout->root;
 -      split->litem.align = align;
 -      split->litem.active = true;
 -      split->litem.enabled = true;
 -      split->litem.context = layout->context;
        split->litem.space = layout->root->style->columnspace;
 -      split->litem.redalert = layout->redalert;
 -      split->litem.w = layout->w;
        split->percentage = percentage;
 -      BLI_addtail(&layout->items, split);
  
        UI_block_layout_set_current(layout->root->block, &split->litem);
  
@@@ -3794,31 -3163,6 +3822,31 @@@ void uiLayoutSetScaleY(uiLayout *layout
        layout->scale[1] = scale;
  }
  
 +void uiLayoutSetEmboss(uiLayout *layout, char emboss)
 +{
 +      layout->emboss = emboss;
 +}
 +
 +bool uiLayoutGetPropSep(uiLayout *layout)
 +{
 +      return (layout->item.flag & UI_ITEM_PROP_SEP) != 0;
 +}
 +
 +void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
 +{
 +      SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_SEP);
 +}
 +
 +bool uiLayoutGetPropDecorate(uiLayout *layout)
 +{
 +      return (layout->item.flag & UI_ITEM_PROP_DECORATE) != 0;
 +}
 +
 +void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
 +{
 +      SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_DECORATE);
 +}
 +
  bool uiLayoutGetActive(uiLayout *layout)
  {
        return layout->active;
@@@ -3859,16 -3203,6 +3887,16 @@@ float uiLayoutGetScaleY(uiLayout *layou
        return layout->scale[1];
  }
  
 +int uiLayoutGetEmboss(uiLayout *layout)
 +{
 +      if (layout->emboss == UI_EMBOSS_UNDEFINED) {
 +              return layout->root->block->dt;
 +      }
 +      else {
 +              return layout->emboss;
 +      }
 +}
 +
  /********************** Layout *******************/
  
  static void ui_item_scale(uiLayout *litem, const float scale[2])
        int x, y, w, h;
  
        for (item = litem->items.last; item; item = item->prev) {
 +              if (item->type != ITEM_BUTTON) {
 +                      uiLayout *subitem = (uiLayout *)item;
 +                      ui_item_scale(subitem, scale);
 +              }
 +
                ui_item_size(item, &w, &h);
                ui_item_offset(item, &x, &y);
  
@@@ -3925,9 -3254,6 +3953,9 @@@ static void ui_item_estimate(uiItem *it
                        case ITEM_LAYOUT_COLUMN_FLOW:
                                ui_litem_estimate_column_flow(litem);
                                break;
 +                      case ITEM_LAYOUT_GRID_FLOW:
 +                              ui_litem_estimate_grid_flow(litem);
 +                              break;
                        case ITEM_LAYOUT_ROW:
                                ui_litem_estimate_row(litem);
                                break;
@@@ -4027,9 -3353,6 +4055,9 @@@ static void ui_item_layout(uiItem *item
                        case ITEM_LAYOUT_COLUMN_FLOW:
                                ui_litem_layout_column_flow(litem);
                                break;
 +                      case ITEM_LAYOUT_GRID_FLOW:
 +                              ui_litem_layout_grid_flow(litem);
 +                              break;
                        case ITEM_LAYOUT_ROW:
                                ui_litem_layout_row(litem);
                                break;
@@@ -4126,9 -3449,6 +4154,9 @@@ uiLayout *UI_block_layout(uiBlock *bloc
        layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
        layout->item.type = ITEM_LAYOUT_ROOT;
  
 +      /* Only used when 'UI_ITEM_PROP_SEP' is set. */
 +      layout->item.flag = UI_ITEM_PROP_DECORATE;
 +
        layout->x = x;
        layout->y = y;
        layout->root = root;
        layout->active = 1;
        layout->enabled = 1;
        layout->context = NULL;
 +      layout->emboss = UI_EMBOSS_UNDEFINED;
  
        if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU)
                layout->space = 0;
  
 +      if (type == UI_LAYOUT_TOOLBAR) {
 +              block->flag |= UI_BLOCK_SHOW_SHORTCUT_ALWAYS;
 +      }
 +
        if (dir == UI_LAYOUT_HORIZONTAL) {
                layout->h = size;
                layout->root->emh = em * UI_UNIT_Y;
@@@ -4201,10 -3516,6 +4229,10 @@@ void ui_layout_add_but(uiLayout *layout
                but->context = layout->context;
                but->context->used = true;
        }
 +
 +      if (layout->emboss != UI_EMBOSS_UNDEFINED) {
 +              but->dt = layout->emboss;
 +      }
  }
  
  void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
@@@ -4284,18 -3595,6 +4312,18 @@@ MenuType *UI_but_menutype_get(uiBut *bu
        }
  }
  
 +/* this is a bit of a hack but best keep it in one place at least */
 +PanelType *UI_but_paneltype_get(uiBut *but)
 +{
 +      if (but->menu_create_func == ui_item_paneltype_func) {
 +              return (PanelType *)but->poin;
 +      }
 +      else {
 +              return NULL;
 +      }
 +}
 +
 +
  void UI_menutype_draw(bContext *C, MenuType *mt, struct uiLayout *layout)
  {
        Menu menu = {
                CTX_store_set(C, NULL);
        }
  }
 +
 +
 +static void ui_paneltype_draw_impl(
 +        bContext *C, PanelType *pt, uiLayout *layout, bool show_header)
 +{
 +      Panel *panel = MEM_callocN(sizeof(Panel), "popover panel");
 +      panel->type = pt;
 +      panel->flag = PNL_POPOVER;
 +
 +      uiLayout *last_item = layout->items.last;
 +
 +      /* Draw main panel. */
 +      if (show_header) {
 +              uiLayout *row = uiLayoutRow(layout, false);
 +              if (pt->draw_header) {
 +                      panel->layout = row;
 +                      pt->draw_header(C, panel);
 +                      panel->layout = NULL;
 +              }
 +              uiItemL(row, pt->label, ICON_NONE);
 +      }
 +
 +      panel->layout = layout;
 +      pt->draw(C, panel);
 +      panel->layout = NULL;
 +
 +      MEM_freeN(panel);
 +
 +      /* Draw child panels. */
 +      for (LinkData *link = pt->children.first; link; link = link->next) {
 +              PanelType *child_pt = link->data;
 +
 +              if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) {
 +                      /* Add space if something was added to the layout. */
 +                      if (last_item != layout->items.last) {
 +                              uiItemS(layout);
 +                              last_item = layout->items.last;
 +                      }
 +
 +                      uiLayout *col = uiLayoutColumn(layout, false);
 +                      ui_paneltype_draw_impl(C, child_pt, col, true);
 +              }
 +      }
 +}
 +
 +/**
 + * Used for popup panels only.
 + */
 +void UI_paneltype_draw(bContext *C, PanelType *pt, uiLayout *layout)
 +{
 +      if (layout->context) {
 +              CTX_store_set(C, layout->context);
 +      }
 +
 +      ui_paneltype_draw_impl(C, pt, layout, false);
 +
 +      if (layout->context) {
 +              CTX_store_set(C, NULL);
 +      }
 +
 +}
index f4c4d8a7a44990ed31585a05511afcf04ffa6b73,d647876796acf3e6d6546c01c2663676626b16b1..5001f6337270a57730c5d254452b2ddff28d16ce
@@@ -156,8 -156,7 +156,7 @@@ static void rna_uiItemEnumR_string
        /* Get translated name (label). */
        name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate);
  
-       /* XXX This will search property again :( */
-       uiItemEnumR_string(layout, ptr, propname, value, name, icon);
+       uiItemEnumR_string_prop(layout, ptr, prop, value, name, icon);
  }
  
  static void rna_uiItemPointerR(
          const char *name, const char *text_ctxt, bool translate, int icon)
  {
        PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
        if (!prop) {
                RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
                return;
        }
+       PropertyRNA *searchprop = RNA_struct_find_property(searchptr, searchpropname);
+       if (!searchprop) {
+               RNA_warning("property not found: %s.%s", RNA_struct_identifier(searchptr->type), searchpropname);
+               return;
+       }
  
        /* Get translated name (label). */
        name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate);
  
-       /* XXX This will search property again :( */
-       uiItemPointerR(layout, ptr, propname, searchptr, searchpropname, name, icon);
+       uiItemPointerR_prop(layout, ptr, prop, searchptr, searchprop, name, icon);
  }
  
  static PointerRNA rna_uiItemO(
@@@ -275,28 -277,6 +277,28 @@@ static void rna_uiItemM
        uiItemM(layout, menuname, name, icon);
  }
  
 +static void rna_uiItemPopoverPanel(
 +        uiLayout *layout, bContext *C,
 +        const char *panel_type, const char *name, const char *text_ctxt,
 +        bool translate, int icon, int icon_value)
 +{
 +      /* Get translated name (label). */
 +      name = rna_translate_ui_text(name, text_ctxt, NULL, NULL, translate);
 +
 +      if (icon_value && !icon) {
 +              icon = icon_value;
 +      }
 +
 +      uiItemPopoverPanel(layout, C, panel_type, name, icon);
 +}
 +
 +static void rna_uiItemPopoverPanelFromGroup(
 +        uiLayout *layout, bContext *C,
 +        int space_id, int region_id, const char *context, const char *category)
 +{
 +      uiItemPopoverPanelFromGroup(layout, C, space_id, region_id, context, category);
 +}
 +
  static void rna_uiTemplateAnyID(
          uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
          const char *name, const char *text_ctxt, bool translate)
@@@ -517,19 -497,6 +519,19 @@@ void RNA_api_ui_layout(StructRNA *srna
        RNA_def_function_return(func, parm);
        RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
  
 +      func = RNA_def_function(srna, "grid_flow", "uiLayoutGridFlow");
 +      RNA_def_boolean(func, "row_major", false, "", "Fill row by row, instead of column by column");
 +      RNA_def_int(func, "columns", 0, INT_MIN, INT_MAX, "",
 +                  "Number of columns, positive are absolute fixed numbers, 0 is automatic, negative are "
 +                  "automatic multiple numbers along major axis (e.g. -2 will only produce 2, 4, 6 etc. "
 +                  "columns for row major layout, and 2, 4, 6 etc. rows for column major layout)",
 +                  INT_MIN, INT_MAX);
 +      RNA_def_boolean(func, "even_columns", false, "", "All columns will have the same width");
 +      RNA_def_boolean(func, "even_rows", false, "", "All rows will have the same height");
 +      RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
 +      parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
 +      RNA_def_function_return(func, parm);
 +
        /* box layout */
        func = RNA_def_function(srna, "box", "uiLayoutBox");
        parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
        parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
        RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
  
 +      func = RNA_def_function(srna, "popover", "rna_uiItemPopoverPanel");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      parm = RNA_def_string(func, "panel", NULL, 0, "", "Identifier of the panel");
 +      api_ui_item_common(func);
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
 +      RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
 +
 +      func = RNA_def_function(srna, "popover_group", "rna_uiItemPopoverPanelFromGroup");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      parm = RNA_def_enum(func, "space_type", rna_enum_space_type_items, 0, "Space Type", "");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      parm = RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      parm = RNA_def_string(func, "context", NULL, 0, "", "panel type context");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      parm = RNA_def_string(func, "category", NULL, 0, "", "panel type category");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +
        func = RNA_def_function(srna, "separator", "uiItemS");
        RNA_def_function_ui_description(func, "Item. Inserts empty space into the layout between items");
  
 +      func = RNA_def_function(srna, "separator_spacer", "uiItemSpacer");
 +      RNA_def_function_ui_description(func, "Item. Inserts horizontal spacing empty space into the layout between items");
 +
        /* context */
        func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer");
        parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of entry in the context");
        RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block");
        RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
                     "", "Optionally limit the items which can be selected");
 +      RNA_def_boolean(func, "live_icon", false, "", "Show preview instead of fixed icon");
  
        func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
        RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
        api_ui_item_common_text(func);
  
 +      func = RNA_def_function(srna, "template_ID_tabs", "uiTemplateIDTabs");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      api_ui_item_rna_common(func);
 +      RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block");
 +      RNA_def_string(func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block");
 +      RNA_def_string(func, "menu", NULL, 0, "", "Context menu identifier");
 +      RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
 +                   "", "Optionally limit the items which can be selected");
 +
 +      func = RNA_def_function(srna, "template_search", "uiTemplateSearch");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      api_ui_item_rna_common(func);
 +      parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
 +      RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
 +                     "item from the collection");
 +
 +      func = RNA_def_function(srna, "template_search_preview", "uiTemplateSearchPreview");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      api_ui_item_rna_common(func);
 +      parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new item for the collection");
 +      RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink or delete the active "
 +                     "item from the collection");
 +      RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
 +      RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
 +
        func = RNA_def_function(srna, "template_path_builder", "rna_uiTemplatePathBuilder");
        parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
        RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
        parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
        RNA_def_function_return(func, parm);
  
 +      func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers");
 +      parm = RNA_def_pointer(func, "data", "GpencilModifier", "", "Modifier data");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
 +      RNA_def_function_return(func, parm);
 +
 +      func = RNA_def_function(srna, "template_shaderfx", "uiTemplateShaderFx");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      RNA_def_function_ui_description(func, "Generates the UI layout for shader effect");
 +      parm = RNA_def_pointer(func, "data", "ShaderFx", "", "Shader data");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
 +      RNA_def_function_return(func, parm);
 +
 +      func = RNA_def_function(srna, "template_greasepencil_color", "uiTemplateGpencilColorPreview");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      api_ui_item_rna_common(func);
 +      RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
 +      RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
 +      RNA_def_float(func, "scale", 1.0f, 0.1f, 1.5f, "Scale of the image thumbnails", "", 0.5f, 1.0f);
 +      RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL,
 +              "", "Optionally limit the items which can be selected");
 +
        func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
        RNA_def_function_ui_description(func, "Generates the UI layout for constraints");
        parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data");
        RNA_def_function_return(func, parm);
  
        func = RNA_def_function(srna, "template_preview", "uiTemplatePreview");
 -      RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds");
 +      RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lights or worlds");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
        parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block");
        RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
                       "(i.e. all previews of materials without explicit ID will have the same size...)");
  
        func = RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping");
 -      RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lamps");
 +      RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lights");
        api_ui_item_rna_common(func);
        RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display");
        RNA_def_boolean(func, "levels", false, "", "Show black/white levels");
        RNA_def_boolean(func, "brush", false, "", "Show brush options");
        RNA_def_boolean(func, "use_negative_slope", false, "", "Use a negative slope by default");
 +      RNA_def_boolean(func, "show_tone", false, "", "Show tone options");
  
        func = RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp");
        RNA_def_function_ui_description(func, "Item. A color ramp widget");
        api_ui_item_rna_common(func);
        RNA_def_boolean(func, "expand", false, "", "Expand button to show more detail");
  
 +      func = RNA_def_function(srna, "template_icon", "uiTemplateIcon");
 +      RNA_def_function_ui_description(func, "Display a large icon");
 +      parm = RNA_def_int(func, "icon_value", 0, 0, INT_MAX, "Icon to display", "", 0, INT_MAX);
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_float(func, "scale", 1.0f, 1.0f, 100.0f, "Scale", "Scale the icon size (by the button size)", 1.0f, 100.0f);
 +
        func = RNA_def_function(srna, "template_icon_view", "uiTemplateIconView");
        RNA_def_function_ui_description(func, "Enum. Large widget showing Icon previews");
        api_ui_item_rna_common(func);
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
        RNA_def_function_ui_description(func, "Inserts common 3DView header UI (selectors for context mode, shading, etc.)");
  
 +      func = RNA_def_function(srna, "template_header_3D_mode", "uiTemplateHeader3D_mode");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      RNA_def_function_ui_description(func, "");
  
        func = RNA_def_function(srna, "template_edit_mode_selection", "uiTemplateEditModeSelection");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
  
        func = RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +
 +      func = RNA_def_function(srna, "template_input_status", "uiTemplateInputStatus");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
  
        func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
        parm = RNA_def_pointer(func, "ntree", "NodeTree", "", "");