From 2d34420648e5feacf1237abc975f8ff2a0c2a907 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 27 Mar 2019 21:39:44 +1100 Subject: UI: support an 'active default' button for pop-ups Use this for the save confirmation dialog so it has a default action when pressing enter which draws with a highlight so it's clear what the default action is (the dialog was just closing before). Resolves T57686 --- source/blender/editors/include/UI_interface.h | 5 ++++ .../blender/editors/interface/interface_handlers.c | 9 ++++++- .../blender/editors/interface/interface_intern.h | 1 + .../blender/editors/interface/interface_layout.c | 15 +++++++++++ source/blender/editors/interface/interface_query.c | 15 +++++++++++ .../blender/editors/interface/interface_widgets.c | 31 ++++++++++++++-------- source/blender/makesrna/intern/rna_ui.c | 17 ++++++++++++ source/blender/windowmanager/intern/wm_window.c | 1 + 8 files changed, 82 insertions(+), 12 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 6a9034f9097..ec88278ec88 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -193,6 +193,9 @@ enum { UI_BUT_IMMEDIATE = 1 << 20, UI_BUT_NO_UTF8 = 1 << 21, + /** For popups, pressing return activates this button, overriding the highlighed button. */ + UI_BUT_ACTIVE_DEFAULT = 1 << 23, + /** This but is "inside" a list item (currently used to change theme colors). */ UI_BUT_LIST_ITEM = 1 << 24, /** edit this button as well as the active button (not just dragging) */ @@ -1053,6 +1056,7 @@ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but); void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext); void uiLayoutSetActive(uiLayout *layout, bool active); +void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default); void uiLayoutSetActivateInit(uiLayout *layout, bool active); void uiLayoutSetEnabled(uiLayout *layout, bool enabled); void uiLayoutSetRedAlert(uiLayout *layout, bool redalert); @@ -1069,6 +1073,7 @@ int uiLayoutGetLocalDir(const uiLayout *layout); int uiLayoutGetOperatorContext(uiLayout *layout); bool uiLayoutGetActive(uiLayout *layout); +bool uiLayoutGetActiveDefault(uiLayout *layout); bool uiLayoutGetActivateInit(uiLayout *layout); bool uiLayoutGetEnabled(uiLayout *layout); bool uiLayoutGetRedAlert(uiLayout *layout); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index d1294dcfed2..c388ed40851 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -9241,9 +9241,16 @@ static int ui_handle_menu_event( menu->menuretval = UI_RETURN_CANCEL; } else if (ELEM(event->type, RETKEY, PADENTER) && event->val == KM_PRESS) { + uiBut *but_active = ui_region_find_first_but_test_flag(ar, UI_BUT_ACTIVE_DEFAULT, UI_HIDDEN); + if (but_active != NULL) { + ui_handle_button_activate(C, ar, but_active, BUTTON_ACTIVATE); + /* Get again below just incase it's disabled for eg. */ + } + but_active = ui_region_find_active_but(ar); + /* enter will always close this block, we let the event * get handled by the button if it is activated, otherwise we cancel */ - if (!ui_region_find_active_but(ar)) { + if (but_active == NULL) { menu->menuretval = UI_RETURN_CANCEL | UI_RETURN_POPUP_OK; } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 794c6c2568a..3580b2ff3a5 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -846,6 +846,7 @@ bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +uiBut *ui_region_find_first_but_test_flag(struct ARegion *ar, int flag_include, int flag_exclude); uiBut *ui_region_find_active_but(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT; bool ui_region_contains_point_px( const struct ARegion *ar, int x, int y) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index e2933f75440..6c4389aabd9 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -160,6 +160,7 @@ struct uiLayout { short space; bool align; bool active; + bool active_default; bool activate_init; bool enabled; bool redalert; @@ -1060,6 +1061,10 @@ static uiBut *uiItemFullO_ptr_ex( UI_but_flag_enable(but, UI_BUT_REDALERT); } + if (layout->active_default) { + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); + } + /* assign properties */ if (properties || r_opptr) { PointerRNA *opptr = UI_but_operator_ptr_get(but); @@ -4150,6 +4155,11 @@ void uiLayoutSetActive(uiLayout *layout, bool active) layout->active = active; } +void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default) +{ + layout->active_default = active_default; +} + void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init) { layout->activate_init = activate_init; @@ -4225,6 +4235,11 @@ bool uiLayoutGetActive(uiLayout *layout) return layout->active; } +bool uiLayoutGetActiveDefault(uiLayout *layout) +{ + return layout->active_default; +} + bool uiLayoutGetActivateInit(uiLayout *layout) { return layout->activate_init; diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 8300ee71c50..1954e20ab8b 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -469,6 +469,21 @@ uiBut *ui_region_find_active_but(ARegion *ar) return NULL; } +uiBut *ui_region_find_first_but_test_flag(ARegion *ar, int flag_include, int flag_exclude) +{ + for (uiBlock *block = ar->uiblocks.first; block; block = block->next) { + for (uiBut *but = block->buttons.first; but; but = but->next) { + if (((but->flag & flag_include) == flag_include) && + ((but->flag & flag_exclude) == 0)) + { + return but; + } + } + } + + return NULL; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index be571de4c4e..6528faca265 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -4563,23 +4563,32 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct GPU_blend(true); } + bool show_semi_highlight = false; + #ifdef USE_UI_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, drawflag); - 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; + show_semi_highlight = true; } } #endif + if (but->flag & UI_BUT_ACTIVE_DEFAULT) { + show_semi_highlight = true; + } + + if (show_semi_highlight) { + uiWidgetType wt_back = *wt; + uiWidgetType *wt_temp = widget_type(UI_WTYPE_MENU_ITEM); + wt_temp->state(wt_temp, state, drawflag); + 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; + } wt->text(fstyle, &wt->wcol, but, rect); if (disabled) { diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 7c10b3eff77..b6e75cf3507 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -881,6 +881,16 @@ static void rna_UILayout_active_set(PointerRNA *ptr, bool value) uiLayoutSetActive(ptr->data, value); } +static bool rna_UILayout_active_default_get(PointerRNA *ptr) +{ + return uiLayoutGetActiveDefault(ptr->data); +} + +static void rna_UILayout_active_default_set(PointerRNA *ptr, bool value) +{ + uiLayoutSetActiveDefault(ptr->data, value); +} + static bool rna_UILayout_activate_init_get(PointerRNA *ptr) { return uiLayoutGetActivateInit(ptr->data); @@ -1066,6 +1076,13 @@ static void rna_def_ui_layout(BlenderRNA *brna) prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_UILayout_active_get", "rna_UILayout_active_set"); + prop = RNA_def_property(srna, "active_default", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_UILayout_active_default_get", "rna_UILayout_active_default_set"); + RNA_def_property_ui_text( + prop, "Active Default", + "When true, an operator button defined after this will be activated when pressing return" + "(use with popup dialogs)"); + prop = RNA_def_property(srna, "activate_init", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_UILayout_activate_init_get", "rna_UILayout_activate_init_set"); RNA_def_property_ui_text( diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 3181ee0f937..a4c953fd958 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -433,6 +433,7 @@ static uiBlock *block_create_confirm_quit(struct bContext *C, struct ARegion *ar block, UI_BTYPE_BUT, 0, ICON_FILE_TICK, IFACE_("Save & Quit"), 0, 0, 50, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Save and quit")); UI_but_func_set(but, wm_block_confirm_quit_save, block, NULL); + UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); UI_block_bounds_set_centered(block, 10); -- cgit v1.2.3