UI: popover-once (click-drag for single actions)
Experimental support for using popovers like menus, use this when the user hold the mouse down (previously this did nothing). This means turning frequently accessed menu items into popovers doesn't add more clicks to the existing use case.
This commit is contained in:
@@ -144,8 +144,9 @@ enum {
|
|||||||
#define UI_BLOCK_LIST_ITEM (1 << 19)
|
#define UI_BLOCK_LIST_ITEM (1 << 19)
|
||||||
#define UI_BLOCK_RADIAL (1 << 20)
|
#define UI_BLOCK_RADIAL (1 << 20)
|
||||||
#define UI_BLOCK_POPOVER (1 << 21)
|
#define UI_BLOCK_POPOVER (1 << 21)
|
||||||
|
#define UI_BLOCK_POPOVER_ONCE (1 << 22)
|
||||||
/** Always show keymaps, even for non-menus. */
|
/** Always show keymaps, even for non-menus. */
|
||||||
#define UI_BLOCK_SHOW_SHORTCUT_ALWAYS (1 << 22)
|
#define UI_BLOCK_SHOW_SHORTCUT_ALWAYS (1 << 23)
|
||||||
|
|
||||||
/* uiPopupBlockHandle->menuretval */
|
/* uiPopupBlockHandle->menuretval */
|
||||||
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
|
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
|
||||||
@@ -429,6 +430,7 @@ typedef struct uiPopover uiPopover;
|
|||||||
uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL();
|
uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL();
|
||||||
void UI_popover_end(struct bContext *C, struct uiPopover *head);
|
void UI_popover_end(struct bContext *C, struct uiPopover *head);
|
||||||
struct uiLayout *UI_popover_layout(uiPopover *head);
|
struct uiLayout *UI_popover_layout(uiPopover *head);
|
||||||
|
void UI_popover_once_clear(uiPopover *pup);
|
||||||
|
|
||||||
/* interface_region_menu_pie.c */
|
/* interface_region_menu_pie.c */
|
||||||
/* Pie menus */
|
/* Pie menus */
|
||||||
@@ -1234,6 +1236,9 @@ void UI_widgetbase_draw_cache_end(void);
|
|||||||
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
|
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
|
||||||
#define USE_TOOLBAR_HACK
|
#define USE_TOOLBAR_HACK
|
||||||
|
|
||||||
|
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
|
||||||
|
#define USE_POPOVER_ONCE
|
||||||
|
|
||||||
bool UI_but_is_tool(const uiBut *but);
|
bool UI_but_is_tool(const uiBut *but);
|
||||||
|
|
||||||
#endif /* __UI_INTERFACE_H__ */
|
#endif /* __UI_INTERFACE_H__ */
|
||||||
|
|||||||
@@ -491,6 +491,31 @@ bool ui_but_is_editable_as_text(const uiBut *but)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ui_but_is_toggle(const uiBut *but)
|
||||||
|
{
|
||||||
|
return ELEM(
|
||||||
|
but->type,
|
||||||
|
UI_BTYPE_BUT_TOGGLE,
|
||||||
|
UI_BTYPE_TOGGLE,
|
||||||
|
UI_BTYPE_ICON_TOGGLE,
|
||||||
|
UI_BTYPE_ICON_TOGGLE_N,
|
||||||
|
UI_BTYPE_TOGGLE_N,
|
||||||
|
UI_BTYPE_CHECKBOX,
|
||||||
|
UI_BTYPE_CHECKBOX_N,
|
||||||
|
UI_BTYPE_ROW
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
bool ui_but_is_popover_once_compat(const uiBut *but)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(but->type == UI_BTYPE_BUT) ||
|
||||||
|
ui_but_is_toggle(but)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static uiBut *ui_but_prev(uiBut *but)
|
static uiBut *ui_but_prev(uiBut *but)
|
||||||
{
|
{
|
||||||
while (but->prev) {
|
while (but->prev) {
|
||||||
@@ -8323,6 +8348,28 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
|
|||||||
data->cancel = true;
|
data->cancel = true;
|
||||||
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||||
break;
|
break;
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
case LEFTMOUSE:
|
||||||
|
{
|
||||||
|
if (event->val == KM_RELEASE) {
|
||||||
|
if (block->flag & UI_BLOCK_POPOVER_ONCE) {
|
||||||
|
if (!(but->flag & UI_BUT_DISABLED)) {
|
||||||
|
if (ui_but_is_popover_once_compat(but)) {
|
||||||
|
data->cancel = false;
|
||||||
|
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||||
|
retval = WM_UI_HANDLER_BREAK;
|
||||||
|
block->handle->menuretval = UI_RETURN_OK;
|
||||||
|
}
|
||||||
|
else if (ui_but_is_editable_as_text(but)) {
|
||||||
|
ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_TEXT_EDITING);
|
||||||
|
retval = WM_UI_HANDLER_BREAK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
case MOUSEMOVE:
|
case MOUSEMOVE:
|
||||||
{
|
{
|
||||||
uiBut *but_other = ui_but_find_mouse_over(ar, event);
|
uiBut *but_other = ui_but_find_mouse_over(ar, event);
|
||||||
@@ -9466,6 +9513,15 @@ static int ui_handle_menu_event(
|
|||||||
retval = ui_handle_menu_button(C, event, menu);
|
retval = ui_handle_menu_button(C, event, menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
if (block->flag & UI_BLOCK_POPOVER_ONCE) {
|
||||||
|
if ((event->type == LEFTMOUSE) && (event->val == KM_RELEASE)) {
|
||||||
|
UI_popover_once_clear(menu->popup_create_vars.arg);
|
||||||
|
block->flag &= ~UI_BLOCK_POPOVER_ONCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* if we set a menu return value, ensure we continue passing this on to
|
/* if we set a menu return value, ensure we continue passing this on to
|
||||||
* lower menus and buttons, so always set continue then, and if we are
|
* lower menus and buttons, so always set continue then, and if we are
|
||||||
* inside the region otherwise, ensure we swallow the event */
|
* inside the region otherwise, ensure we swallow the event */
|
||||||
|
|||||||
@@ -698,6 +698,8 @@ extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
|
|||||||
extern uiBut *ui_but_find_mouse_over(struct ARegion *ar, const struct wmEvent *event);
|
extern uiBut *ui_but_find_mouse_over(struct ARegion *ar, const struct wmEvent *event);
|
||||||
bool ui_but_is_editable(const uiBut *but);
|
bool ui_but_is_editable(const uiBut *but);
|
||||||
bool ui_but_is_editable_as_text(const uiBut *but);
|
bool ui_but_is_editable_as_text(const uiBut *but);
|
||||||
|
bool ui_but_is_toggle(const uiBut *but);
|
||||||
|
bool ui_but_is_popover_once_compat(const uiBut *but);
|
||||||
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
|
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
|
||||||
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
|
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
|
||||||
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
|
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ struct uiPopover {
|
|||||||
|
|
||||||
uiMenuCreateFunc menu_func;
|
uiMenuCreateFunc menu_func;
|
||||||
void *menu_arg;
|
void *menu_arg;
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
bool is_once;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
|
static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
|
||||||
@@ -125,6 +129,11 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
|
|||||||
UI_block_region_set(block, handle->region);
|
UI_block_region_set(block, handle->region);
|
||||||
UI_block_layout_resolve(block, &width, &height);
|
UI_block_layout_resolve(block, &width, &height);
|
||||||
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
|
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
if (pup->is_once) {
|
||||||
|
UI_block_flag_enable(block, UI_BLOCK_POPOVER_ONCE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
|
UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
|
||||||
|
|
||||||
const int block_margin = U.widget_unit / 2;
|
const int block_margin = U.widget_unit / 2;
|
||||||
@@ -195,6 +204,10 @@ uiPopupBlockHandle *ui_popover_panel_create(
|
|||||||
pup->menu_func = menu_func;
|
pup->menu_func = menu_func;
|
||||||
pup->menu_arg = arg;
|
pup->menu_arg = arg;
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
pup->is_once = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Create popup block. */
|
/* Create popup block. */
|
||||||
uiPopupBlockHandle *handle;
|
uiPopupBlockHandle *handle;
|
||||||
handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
|
handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
|
||||||
@@ -262,6 +275,13 @@ uiLayout *UI_popover_layout(uiPopover *pup)
|
|||||||
return pup->layout;
|
return pup->layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
void UI_popover_once_clear(uiPopover *pup)
|
||||||
|
{
|
||||||
|
pup->is_once = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* We may want to support this in future */
|
/* We may want to support this in future */
|
||||||
|
|||||||
@@ -3204,6 +3204,20 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
|
|||||||
ui_hsv_cursor(x, y);
|
ui_hsv_cursor(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generic round-box drawing. */
|
||||||
|
static void ui_draw_roundbox(const rcti *rect, const float rad, const uiWidgetColors *wcol)
|
||||||
|
{
|
||||||
|
uiWidgetBase wtb;
|
||||||
|
widget_init(&wtb);
|
||||||
|
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
|
||||||
|
widgetbase_draw(&wtb, wcol);
|
||||||
|
|
||||||
|
/* We are drawing on top of widget bases. Flush cache. */
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
UI_widgetbase_draw_cache_flush();
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ************ separator, for menus etc ***************** */
|
/* ************ separator, for menus etc ***************** */
|
||||||
static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
|
static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
|
||||||
@@ -4336,6 +4350,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
|
|||||||
uiFontStyle *fstyle = &style->widget;
|
uiFontStyle *fstyle = &style->widget;
|
||||||
uiWidgetType *wt = NULL;
|
uiWidgetType *wt = NULL;
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
const rcti rect_orig = *rect;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* handle menus separately */
|
/* handle menus separately */
|
||||||
if (but->dt == UI_EMBOSS_PULLDOWN) {
|
if (but->dt == UI_EMBOSS_PULLDOWN) {
|
||||||
switch (but->type) {
|
switch (but->type) {
|
||||||
@@ -4611,6 +4629,25 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
|
|||||||
|
|
||||||
if (disabled)
|
if (disabled)
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
#ifdef USE_POPOVER_ONCE
|
||||||
|
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
|
||||||
|
if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
|
||||||
|
uiWidgetType wt_back = *wt;
|
||||||
|
uiWidgetType *wt_temp = widget_type(UI_WTYPE_MENU_ITEM);
|
||||||
|
wt_temp->state(wt_temp, state);
|
||||||
|
copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
|
||||||
|
wt->wcol.inner[3] = 128;
|
||||||
|
wt->wcol.roundness = 0.5f;
|
||||||
|
ui_draw_roundbox(
|
||||||
|
&rect_orig,
|
||||||
|
0.25f * min_ff(BLI_rcti_size_x(&rect_orig), BLI_rcti_size_y(&rect_orig)),
|
||||||
|
&wt_temp->wcol);
|
||||||
|
*wt = wt_back;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
wt->text(fstyle, &wt->wcol, but, rect);
|
wt->text(fstyle, &wt->wcol, but, rect);
|
||||||
if (disabled)
|
if (disabled)
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|||||||
Reference in New Issue
Block a user