Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Sat, 9 Jun 2018 16:58:14 +0000 (18:58 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 9 Jun 2018 16:58:14 +0000 (18:58 +0200)
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 dee3104e6f42a4d235e2aae9bc3603bcf5654bce,94a0013d96bbf08361a19d4e7f6a7f1ca2d2ed2f..42b78fa48001360d0b7bb268c6d2ac98de57e854
@@@ -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,9 -73,6 +73,9 @@@ struct bNodeSocket
  struct wmDropBox;
  struct wmDrag;
  struct wmEvent;
 +struct wmManipulator;
 +struct wmMsgBus;
 +struct wmKeyMap;
  
  typedef struct uiBut uiBut;
  typedef struct uiBlock uiBlock;
@@@ -102,8 -99,6 +102,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 */
@@@ -112,8 -107,7 +112,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 */
@@@ -188,13 -178,11 +188,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
@@@ -230,14 -218,11 +230,14 @@@ 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 */
  };
  
  /* 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)
  
@@@ -276,11 -261,11 +276,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 */
   * 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 */
@@@ -425,19 -403,6 +425,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, int space_id, int region_id, const char *idname,
 +        bool keep_open, struct ReportList *reports);
 +
 +uiPopover *UI_popover_begin(struct bContext *C) 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;
@@@ -487,10 -452,10 +487,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);
@@@ -531,7 -496,6 +531,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);
  
@@@ -695,7 -659,6 +695,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)
  
  /**
@@@ -729,30 -692,18 +729,30 @@@ uiBut *uiDefSearchButO_ptr(uiBlock *blo
                             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(uiLayout *layout, struct PointerRNA *ptr, bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), 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);
 +/* 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;
  
 -void UI_block_links_compose(uiBlock *block);
 -uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin);
 +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 *, struct PropertyRNA *),
 +        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);
@@@ -822,13 -773,11 +822,13 @@@ 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_begin(struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
 -                             struct PanelType *pt, struct Panel *pa, bool *r_open);
 +struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
 +struct Panel *UI_panel_begin(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);
  
  bool                       UI_panel_category_is_visible(struct ARegion *ar);
  void                       UI_panel_category_add(struct ARegion *ar, const char *name);
@@@ -841,8 -790,6 +841,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
@@@ -862,6 -809,7 +862,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
 +
 +/* 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),
 +};
  
  /* used for transp checkers */
  #define UI_ALPHA_CHECKER_DARK 100
@@@ -932,22 -874,20 +932,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);
- const char *uiLayoutIntrospect(uiLayout *layout); // XXX - testing
  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);
@@@ -960,8 -900,6 +959,8 @@@ 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);
  
  int uiLayoutGetOperatorContext(uiLayout *layout);
  bool uiLayoutGetActive(uiLayout *layout);
@@@ -972,15 -910,11 +971,15 @@@ bool uiLayoutGetKeepAspect(uiLayout *la
  int uiLayoutGetWidth(uiLayout *layout);
  float uiLayoutGetScaleX(uiLayout *layout);
  float uiLayoutGetScaleY(uiLayout *layout);
 +int uiLayoutGetEmboss(uiLayout *layout);
 +bool uiLayoutGetPropSep(uiLayout *layout);
  
  /* layout specifiers */
  uiLayout *uiLayoutRow(uiLayout *layout, int align);
  uiLayout *uiLayoutColumn(uiLayout *layout, int align);
  uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align);
 +uiLayout *uiLayoutGridFlow(
 +        uiLayout *layout, int row_major, int num_columns, int even_columns, int even_rows, int align);
  uiLayout *uiLayoutBox(uiLayout *layout);
  uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop,
                            struct PointerRNA *actptr, struct PropertyRNA *actprop);
@@@ -1001,30 -935,11 +1000,30 @@@ void uiTemplateIDBrowse
  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 *unlinkop,
 +        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);
 +
 +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, int show_buttons, struct ID *parent,
                         struct MTex *slot, const char *preview_id);
@@@ -1039,6 -954,8 +1038,6 @@@ void uiTemplateColorPicker(uiLayout *la
  void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color);
  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, int compact, int multiview);
  void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
  void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
@@@ -1049,11 -966,9 +1048,11 @@@ 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(const struct bContext *C, uiLayout *layout, struct wmOperator *op,
 -                                    bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
 -                                    const char label_align, const short flag);
 +eAutoPropButsReturn uiTemplateOperatorPropertyButs(
 +        const struct bContext *C, uiLayout *layout, struct wmOperator *op,
 +        bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *),
 +        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);
@@@ -1128,19 -1043,6 +1127,19 @@@ void uiItemM(uiLayout *layout, struct b
  void uiItemV(uiLayout *layout, const char *name, int icon, int argval); /* value */
  void uiItemS(uiLayout *layout); /* separator */
  
 +void uiItemPopoverPanel_ptr(
 +        uiLayout *layout, struct bContext *C,
 +        struct PanelType *pt,
 +        const char *name, int icon);
 +void uiItemPopoverPanel(
 +        uiLayout *layout, struct bContext *C,
 +        int space_id, int region_id, 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);
  void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, const char *propname, const char *name, int icon);
@@@ -1182,22 -1084,20 +1181,22 @@@ uiBut *UI_region_active_but_get(struct 
  
  /* Styled text draw */
  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);
 +void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, 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 */
@@@ -1225,7 -1125,6 +1224,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_manipulator(struct bContext *C, struct wmManipulator *mpr);
  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
 +
 +bool UI_but_is_tool(const uiBut *but);
 +
  #endif  /* __UI_INTERFACE_H__ */
index 311b898db0cfc37bd433abc279bb6591a4a86594,ce9c4d14b0a090948f2d37c7fa72e8886f145d80..64d1641be151209d33fbc2d4dc68d4d1dd35bdc0
@@@ -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"
@@@ -72,7 -71,6 +72,7 @@@
                return_statement;                                                     \
        } (void)0                                                                 \
  
 +#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
  
  /* uiLayoutRoot */
  
@@@ -102,7 -100,6 +102,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,
@@@ -131,7 -128,6 +131,7 @@@ 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,
  };
  
  typedef struct uiButtonItem {
@@@ -154,9 -150,7 +154,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 num_columns;
 +
 +      /* Pure internal runtime storage. */
 +      int tot_items, tot_columns, tot_rows;
 +} uiLayoutItemGridFlow;
 +
  typedef struct uiLayoutItemBx {
        uiLayout litem;
        uiBut *roundbox;
@@@ -256,37 -234,29 +256,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;
        }
  }
  
@@@ -373,7 -343,6 +373,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:
@@@ -423,7 -392,7 +423,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)
@@@ -712,49 -669,27 +712,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(block, UI_BTYPE_BUT, subtype == PROP_DIRPATH ? "BUTTONS_OT_directory_browse" : "BUTTONS_OT_file_browse",
                              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;
@@@ -888,10 -820,8 +888,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);
@@@ -996,7 -907,7 +996,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(
@@@ -1389,10 -1300,8 +1389,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)
@@@ -1473,9 -1380,8 +1473,9 @@@ 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);
  
        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 */
        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) {
 +              if (name[0] == '\0') {
 +                      /* Ensure we get a column when text is not set. */
 +                      layout = uiLayoutColumn(layout, true);
 +                      layout->space = 0;
 +              }
 +              else {
 +                      const PropertySubType subtype = RNA_property_subtype(prop);
 +                      uiLayout *layout_split = uiLayoutSplit(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;
 +                      name = "";
 +              }
 +      }
 +      /* 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);
 +      if (no_bg) {
 +              layout->emboss = prev_emboss;
 +      }
  
        /* ensure text isn't added to icon_only buttons */
        if (but && icon_only) {
@@@ -1805,6 -1639,94 +1805,6 @@@ void uiItemsEnumR(uiLayout *layout, str
  
  /* 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)
  {
@@@ -1846,8 -1768,6 +1846,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... */
@@@ -1889,7 -1800,6 +1889,7 @@@ void uiItemPointerR(uiLayout *layout, s
        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 (!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);
  
@@@ -1957,15 -1865,6 +1957,15 @@@ static void ui_item_menutype_func(bCont
        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)
                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! */
        {
@@@ -2037,95 -1942,6 +2037,95 @@@ void uiItemM(uiLayout *layout, bContex
        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,
 +        int space_id, int region_id, const char *panel_type,
 +        const char *name, int icon)
 +{
 +      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;
 +      }
 +
 +      PanelType *pt;
 +      for (pt = art->paneltypes.first; pt; pt = pt->next) {
 +              if (STREQ(pt->idname, panel_type)) {
 +                      break;
 +              }
 +      }
 +
 +      if (pt == NULL) {
 +              RNA_warning("area 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)
  {
@@@ -2872,355 -2688,6 +2872,355 @@@ 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->num_columns > 0) {
 +                      gflow->tot_columns = gflow->num_columns;
 +              }
 +              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->num_columns < -1) ? -gflow->num_columns : 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)
  {
@@@ -3390,32 -2857,22 +3390,32 @@@ static void ui_litem_layout_overlap(uiL
        litem->y = y - litem->h;
  }
  
 -/* layout create functions */
 -uiLayout *uiLayoutRow(uiLayout *layout, int 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);
        BLI_addtail(&layout->items, litem);
 +}
 +
 +/* layout create functions */
 +uiLayout *uiLayoutRow(uiLayout *layout, int 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);
  
@@@ -3427,10 -2884,16 +3427,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);
  
@@@ -3442,31 -2905,17 +3442,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, int row_major, int num_columns, int even_columns, int even_rows, int 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->num_columns = num_columns;
 +      flow->even_columns = even_columns;
 +      flow->even_rows = even_rows;
  
        UI_block_layout_set_current(layout->root->block, &flow->litem);
  
@@@ -3478,10 -2927,15 +3478,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);
  
@@@ -3509,9 -2963,14 +3509,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);
  
@@@ -3568,9 -3027,14 +3568,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);
  
@@@ -3592,9 -3056,13 +3592,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);
  
@@@ -3606,11 -3074,17 +3606,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);
  
@@@ -3652,21 -3126,6 +3652,21 @@@ 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 uiLayoutGetActive(uiLayout *layout)
  {
        return layout->active;
@@@ -3707,16 -3166,6 +3707,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])
@@@ -3768,9 -3217,6 +3768,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;
@@@ -3870,9 -3316,6 +3870,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;
@@@ -3976,15 -3419,10 +3976,15 @@@ uiLayout *UI_block_layout(uiBlock *bloc
        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;
@@@ -4041,10 -3479,6 +4041,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)
@@@ -4113,94 -3547,6 +4113,6 @@@ void uiLayoutSetContextFromBut(uiLayou
        }
  }
  
- /* introspect funcs */
- #include "BLI_dynstr.h"
- static void ui_intro_button(DynStr *ds, uiButtonItem *bitem)
- {
-       uiBut *but = bitem->but;
-       BLI_dynstr_appendf(ds, "'type':%d, ", (int)but->type);
-       BLI_dynstr_appendf(ds, "'draw_string':'''%s''', ", but->drawstr);
-       BLI_dynstr_appendf(ds, "'tip':'''%s''', ", but->tip ? but->tip : "");  /* not exactly needed, rna has this */
-       if (but->optype) {
-               char *opstr = WM_operator_pystring_ex(but->block->evil_C, NULL, false, true, but->optype, but->opptr);
-               BLI_dynstr_appendf(ds, "'operator':'''%s''', ", opstr ? opstr : "");
-               MEM_freeN(opstr);
-       }
-       if (but->rnaprop) {
-               BLI_dynstr_appendf(ds, "'rna':'%s.%s[%d]', ", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop), but->rnaindex);
-       }
- }
- static void ui_intro_items(DynStr *ds, ListBase *lb)
- {
-       uiItem *item;
-       BLI_dynstr_append(ds, "[");
-       for (item = lb->first; item; item = item->next) {
-               BLI_dynstr_append(ds, "{");
-               /* could also use the INT but this is nicer*/
-               switch (item->type) {
-                       case ITEM_BUTTON:             BLI_dynstr_append(ds, "'type':'BUTTON', "); break;
-                       case ITEM_LAYOUT_ROW:         BLI_dynstr_append(ds, "'type':'UI_BTYPE_ROW', "); break;
-                       case ITEM_LAYOUT_COLUMN:      BLI_dynstr_append(ds, "'type':'COLUMN', "); break;
-                       case ITEM_LAYOUT_COLUMN_FLOW: BLI_dynstr_append(ds, "'type':'COLUMN_FLOW', "); break;
-                       case ITEM_LAYOUT_ROW_FLOW:    BLI_dynstr_append(ds, "'type':'ROW_FLOW', "); break;
-                       case ITEM_LAYOUT_GRID_FLOW:   BLI_dynstr_append(ds, "'type':'GRID_FLOW', "); break;
-                       case ITEM_LAYOUT_BOX:         BLI_dynstr_append(ds, "'type':'BOX', "); break;
-                       case ITEM_LAYOUT_ABSOLUTE:    BLI_dynstr_append(ds, "'type':'ABSOLUTE', "); break;
-                       case ITEM_LAYOUT_SPLIT:       BLI_dynstr_append(ds, "'type':'SPLIT', "); break;
-                       case ITEM_LAYOUT_OVERLAP:     BLI_dynstr_append(ds, "'type':'OVERLAP', "); break;
-                       case ITEM_LAYOUT_ROOT:        BLI_dynstr_append(ds, "'type':'ROOT', "); break;
-                       default:                      BLI_dynstr_append(ds, "'type':'UNKNOWN', "); break;
-               }
-               switch (item->type) {
-                       case ITEM_BUTTON:
-                               ui_intro_button(ds, (uiButtonItem *)item);
-                               break;
-                       default:
-                               BLI_dynstr_append(ds, "'items':");
-                               ui_intro_items(ds, &((uiLayout *)item)->items);
-                               break;
-               }
-               BLI_dynstr_append(ds, "}");
-               if (item != lb->last)
-                       BLI_dynstr_append(ds, ", ");
-       }
-       BLI_dynstr_append(ds, "], ");
- }
- static void ui_intro_uiLayout(DynStr *ds, uiLayout *layout)
- {
-       ui_intro_items(ds, &layout->items);
- }
- static char *str = NULL;  /* XXX, constant re-freeing, far from ideal. */
- const char *uiLayoutIntrospect(uiLayout *layout)
- {
-       DynStr *ds = BLI_dynstr_new();
-       if (str) {
-               MEM_freeN(str);
-       }
-       ui_intro_uiLayout(ds, layout);
-       str = BLI_dynstr_get_cstring(ds);
-       BLI_dynstr_free(ds);
-       return str;
- }
  /* this is a bit of a hack but best keep it in one place at least */
  MenuType *UI_but_menutype_get(uiBut *but)
  {
        }
  }
  
 +/* 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;
 +
 +      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);
 +
 +      PanelType *pt_iter = pt;
 +      while (pt_iter->prev) {
 +              pt_iter = pt_iter->prev;
 +      }
 +      do {
 +              if (pt_iter != pt && STREQ(pt_iter->parent_id, pt->idname)) {
 +                      if (pt_iter->poll == NULL || pt_iter->poll(C, pt_iter)) {
 +                              uiItemS(layout);
 +                              uiLayout *col = uiLayoutColumn(layout, false);
 +                              ui_paneltype_draw_impl(C, pt_iter, col, true);
 +                      }
 +              }
 +      } while ((pt_iter = pt_iter->next));
 +}
 +
 +/**
 + * 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 ab4bdc8164b42bfe2e40fb92c13311be54b60c80,bf5ffa2098604bcd7ca3e0a16344231bcea420d5..618a754c1b22c54ace9197729aae1e0b5c422635
@@@ -275,29 -275,6 +275,29 @@@ static void rna_uiItemM
        uiItemM(layout, C, menuname, name, icon);
  }
  
 +static void rna_uiItemPopoverPanel(
 +        uiLayout *layout, bContext *C,
 +        int space_type, int region_type, const char *panel_type,
 +        const char *name, const char *text_ctxt,
 +        int 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, space_type, region_type, 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, int translate)
@@@ -518,19 -495,6 +518,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, "num_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_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, "panel_type", 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");
  
        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, "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");
 +
 +      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);
        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);
        RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
        RNA_def_string(func, "name", NULL, 0, "", "");
  
-       func = RNA_def_function(srna, "introspect", "uiLayoutIntrospect");
-       parm = RNA_def_string(func, "string", NULL, 1024 * 1024, "Descr", "DESCR");
-       RNA_def_function_return(func, parm);
        /* color management templates */
        func = RNA_def_function(srna, "template_colorspace_settings", "uiTemplateColorspaceSettings");
        RNA_def_function_ui_description(func, "Item. A widget to control input color space settings.");