diff options
Diffstat (limited to 'source/blender')
9 files changed, 126 insertions, 45 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index b987f970b9e..41bf5d5494e 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1312,10 +1312,6 @@ void uiDrawBlock(const bContext *C, uiBlock *block) rcti rect; int multisample_enabled; - /* early exit if cancelled */ - if ((block->flag & UI_BLOCK_RADIAL) && (block->pie_data.flags & UI_PIE_FINISHED)) - return; - /* get menu region or area region */ ar = CTX_wm_menu(C); if (!ar) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5bd85f855ba..fc9d1d9f090 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -8632,6 +8632,13 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle duration = menu->scrolltimer->duration; + event_xy[0] = event->x; + event_xy[1] = event->y; + + ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]); + + ui_block_calculate_pie_segment(block, event_xy); + if (event->type == TIMER) { if (event->customdata == menu->scrolltimer) { /* deactivate initial direction after a while */ @@ -8677,24 +8684,26 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle ED_region_tag_redraw(ar); } } - } - event_xy[0] = event->x; - event_xy[1] = event->y; + /* check pie velociy here if gesture has ended */ + if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) { + float len_sq = 10; - ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]); + /* use a time threshold to ensure we leave time to the mouse to move */ + if (duration - block->pie_data.duration_gesture > 0.02) { + len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos); + copy_v2_v2(block->pie_data.last_pos, event_xy); + block->pie_data.duration_gesture = duration; + } - ui_block_calculate_pie_segment(block, event_xy); + if (len_sq < 1.0) { + uiBut *but = ui_but_find_activated(menu->region); - if (block->pie_data.flags & UI_PIE_FINISHED) { - if ((event->type == block->pie_data.event && event->val == KM_RELEASE) || - ((event->type == RIGHTMOUSE || event->type == ESCKEY) && (event->val == KM_PRESS))) - { - menu->menuretval = UI_RETURN_OK; + if (but) { + return ui_but_pie_menu_apply(C, menu, but, true); + } + } } - - ED_region_tag_redraw(ar); - return WM_UI_HANDLER_BREAK; } if (event->type == block->pie_data.event && !is_click_style) { @@ -8714,9 +8723,18 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle block->pie_data.flags |= UI_PIE_CLICK_STYLE; } else { + float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init); uiBut *but = ui_but_find_activated(menu->region); + if (but && (U.pie_menu_confirm >= U.pie_menu_threshold) && + (sqrtf(len_sq) >= U.pie_menu_confirm)) + { + if (but) + return ui_but_pie_menu_apply(C, menu, but, true); + } + retval = ui_but_pie_menu_apply(C, menu, but, true); + } } } @@ -8726,11 +8744,23 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle switch (event->type) { case MOUSEMOVE: - if (!is_click_style && - (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ)) - { - block->pie_data.flags |= UI_PIE_DRAG_STYLE; + if (!is_click_style) { + float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init); + + if (len_sq > PIE_CLICK_THRESHOLD_SQ) + { + block->pie_data.flags |= UI_PIE_DRAG_STYLE; + } + + if ((U.pie_menu_confirm >= U.pie_menu_threshold) && + (sqrtf(len_sq) >= U.pie_menu_confirm)) + { + block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT; + copy_v2_v2(block->pie_data.last_pos, event_xy); + block->pie_data.duration_gesture = duration; + } } + ui_handle_menu_button(C, event, menu); /* mouse move should always refresh the area for pie menus */ @@ -8750,13 +8780,7 @@ static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle case ESCKEY: case RIGHTMOUSE: - if (!is_click_style) { - block->pie_data.flags |= UI_PIE_FINISHED; - menu->menuretval = 0; - ED_region_tag_redraw(ar); - } - else - menu->menuretval = UI_RETURN_CANCEL; + menu->menuretval = UI_RETURN_CANCEL; break; case AKEY: @@ -9043,6 +9067,7 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) struct ARegion *menu_region; /* we block all events, this is modal interaction, except for drop events which is described below */ int retval = WM_UI_HANDLER_BREAK; + bool reset_pie = false; menu_region = CTX_wm_menu(C); CTX_wm_menu_set(C, menu->region); @@ -9063,6 +9088,13 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) wmWindow *win = CTX_wm_window(C); /* copy values, we have to free first (closes region) */ uiPopupBlockHandle temp = *menu; + uiBlock *block = menu->region->uiblocks.first; + + /* set last pie event to allow chained pie spawning */ + if (block->flag & UI_BLOCK_RADIAL) { + win->last_pie_event = block->pie_data.event; + reset_pie = true; + } ui_popup_block_free(C, menu); UI_remove_popup_handlers(&win->modalhandlers, menu); @@ -9094,6 +9126,14 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata) /* delayed apply callbacks */ ui_apply_but_funcs_after(C); + if (reset_pie) { + /* reaqcuire window in case pie invalidates it somehow */ + wmWindow *win = CTX_wm_window(C); + + if (win) + win->last_pie_event = EVENT_NONE; + } + CTX_wm_region_set(C, menu_region); return retval; diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 2f66c4a9900..efd67effd73 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -168,9 +168,9 @@ enum { UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */ UI_PIE_DRAG_STYLE = (1 << 2), /* pie menu is drag style */ UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */ - UI_PIE_FINISHED = (1 << 4), /* pie menu finished but we still wait for a release event */ - UI_PIE_CLICK_STYLE = (1 << 5), /* pie menu changed to click style, click to confirm */ - UI_PIE_ANIMATION_FINISHED = (1 << 6), /* pie animation finished, do not calculate any more motio */ + UI_PIE_CLICK_STYLE = (1 << 4), /* pie menu changed to click style, click to confirm */ + UI_PIE_ANIMATION_FINISHED = (1 << 5), /* pie animation finished, do not calculate any more motion */ + UI_PIE_GESTURE_END_WAIT = (1 << 6), /* pie gesture selection has been done, now wait for mouse motion to end */ }; #define PIE_CLICK_THRESHOLD_SQ 50.0f @@ -310,6 +310,8 @@ struct PieMenuData { float pie_dir[2]; float pie_center_init[2]; float pie_center_spawned[2]; + float last_pos[2]; + double duration_gesture; int flags; int event; /* initial event used to fire the pie menu, store here so we can query for release */ float alphafac; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 5739ebebe64..49823d4e472 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2709,8 +2709,18 @@ static float uiPieTitleWidth(const char *name, int icon) uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event) { - uiStyle *style = UI_GetStyleDraw(); - uiPieMenu *pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu"); + uiStyle *style; + uiPieMenu *pie; + short event_type; + + wmWindow *win = CTX_wm_window(C); + + /* allow respawning a pie from the last pie event */ + if (event->type == win->lock_pie_event && event->type != win->last_pie_event) + return NULL; + + style = UI_GetStyleDraw(); + pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu"); pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS); /* may be useful later to allow spawning pies @@ -2718,10 +2728,17 @@ uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */ pie->block_radial->puphash = ui_popup_menu_hash(title); pie->block_radial->flag |= UI_BLOCK_RADIAL; - pie->block_radial->pie_data.event = event->type; + + if (win->last_pie_event != EVENT_NONE) + event_type = win->last_pie_event; + else + event_type = event->type; + + pie->block_radial->pie_data.event = event_type; + win->lock_pie_event = event_type; /* if pie is spawned by a left click, it is always assumed to be click style */ - if (event->type == LEFTMOUSE) { + if (event_type == LEFTMOUSE) { pie->block_radial->flag |= UI_PIE_CLICK_STYLE; } @@ -2785,7 +2802,8 @@ void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *even if (mt->poll && mt->poll(C, mt) == 0) return; - pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event); + if (!(pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event))) + return; layout = uiPieMenuLayout(pie); menu.layout = layout; @@ -2806,7 +2824,9 @@ void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char * uiPieMenu *pie; uiLayout *layout; - pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event); + if (!(pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event))) + return; + layout = uiPieMenuLayout(pie); layout = uiLayoutRadial(layout); @@ -2836,7 +2856,9 @@ void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, return; } - pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event); + if (!(pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event))) + return; + layout = uiPieMenuLayout(pie); layout = uiLayoutRadial(layout); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index f958c70ae50..2355d2be9e6 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3838,6 +3838,8 @@ void ui_draw_pie_center(uiBlock *block) float pie_radius_internal = U.pixelsize * U.pie_menu_threshold; float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f); + float pie_confirm_radius = U.pixelsize * (U.pie_menu_confirm); + float pie_confirm_external = U.pixelsize * (U.pie_menu_confirm + 2.0f); int subd = 40; @@ -3874,6 +3876,10 @@ void ui_draw_pie_center(uiBlock *block) glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd); glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd); + if (pie_confirm_radius > pie_radius_external) { + glColor4ub(btheme->tui.wcol_pie_menu.text_sel[0], btheme->tui.wcol_pie_menu.text_sel[1], btheme->tui.wcol_pie_menu.text_sel[2], 64); + draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, NULL, NULL, false); + } glDisable(GL_BLEND); glPopMatrix(); } diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 382fd8c1dbd..769e2573aa4 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -540,7 +540,8 @@ typedef struct UserDef { * a drag/release pie menu */ short pie_initial_timeout; /* direction in the pie menu will always be calculated from the initial position * within this time limit */ - int pie_animation_timeout; + short pie_animation_timeout; + short pie_menu_confirm; short pie_menu_radius; /* pie menu radius */ short pie_menu_threshold; /* pie menu distance from center before a direction is set */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index a17e416b5bd..4cf6bfe9a8f 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -171,11 +171,6 @@ typedef struct wmWindow { void *ghostwin; /* don't want to include ghost.h stuff */ - int winid; /* winid also in screens, is for retrieving this window after read */ - - short grabcursor; /* cursor grab mode */ - short pad; - struct bScreen *screen; /* active screen */ struct bScreen *newscreen; /* temporary when switching */ char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */ @@ -187,8 +182,14 @@ typedef struct wmWindow { short cursor; /* current mouse cursor type */ short lastcursor; /* previous cursor when setting modal one */ short modalcursor; /* the current modal cursor */ + short grabcursor; /* cursor grab mode */ short addmousemove; /* internal: tag this for extra mousemove event, makes cursors/buttons active on UI switching */ - short pad2; + + int winid; /* winid also in screens, is for retrieving this window after read */ + + short lock_pie_event; /* internal, lock pie creation from this event until released */ + short last_pie_event; /* exception to the above rule for nested pies, store last pie event for operators + * that spawn a new pie right after destruction of last pie */ struct wmEvent *eventstate; /* storage for event system */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b4968333d3f..976a89ae85f 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3250,6 +3250,10 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_text(prop, "Threshold", "Distance from center needed before a selection can be made"); + prop = RNA_def_property(srna, "pie_menu_confirm", PROP_INT, PROP_PIXEL); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Confirm Threshold", "Distance from center after which selection is made"); + prop = RNA_def_property(srna, "use_quit_dialog", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_QUIT_PROMPT); RNA_def_property_ui_text(prop, "Prompt Quit", diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 2f8ee1ca141..0218513c03f 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2188,6 +2188,12 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even } +static void wm_event_pie_filter(wmWindow *win, wmEvent *event) +{ + if (win->lock_pie_event == event->type && event->val == KM_RELEASE) + win->lock_pie_event = EVENT_NONE; +} + /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -2263,6 +2269,9 @@ void wm_event_do_handlers(bContext *C) wm_region_mouse_co(C, event); + /* take care of pie event filter */ + wm_event_pie_filter(win, event); + /* first we do priority handlers, modal + some limited keymaps */ action |= wm_handlers_do(C, event, &win->modalhandlers); |