UI: Search All Menus with Space Bar #113299

Merged
Harley Acheson merged 7 commits from Harley/blender:SpacebarSearch into blender-v4.0-release 2023-10-09 16:56:25 +02:00
10 changed files with 49 additions and 76 deletions

View File

@ -52,7 +52,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
bl_label = "Add Modifier"
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout

View File

@ -226,7 +226,6 @@ class NODE_MT_add(bpy.types.Menu):
bl_space_type = 'NODE_EDITOR'
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
import nodeitems_utils

View File

@ -2479,7 +2479,6 @@ class VIEW3D_MT_grease_pencil_add(Menu):
class VIEW3D_MT_add(Menu):
bl_label = "Add"
bl_translation_context = i18n_contexts.operator_default
bl_options = {'SEARCH_ON_KEY_PRESS'}
def draw(self, context):
layout = self.layout

View File

@ -411,10 +411,6 @@ enum class MenuTypeFlag {
* dependent, menu search has to scan it in different contexts.
*/
ContextDependent = (1 << 0),
/**
* Automatically start searching in the menu when pressing a key.
*/
SearchOnKeyPress = (1 << 1),
};
ENUM_OPERATORS(MenuTypeFlag, MenuTypeFlag::ContextDependent)

View File

@ -10304,45 +10304,19 @@ float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2])
return len;
}
static int ui_handle_menu_letter_press(
bContext *C, ARegion *region, uiPopupBlockHandle *menu, const wmEvent *event, uiBlock *block)
static int ui_handle_menu_letter_press(uiPopupBlockHandle *menu)
{
/* Start menu search on key press if enabled. */
/* Start menu search on spacebar press if the menu has a name. */
if (menu->menu_idname[0]) {
MenuType *mt = WM_menutype_find(menu->menu_idname, false);
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
uiAfterFunc *after = ui_afterfunc_new();
wmOperatorType *ot = WM_operatortype_find("WM_OT_search_single_menu", false);
after->optype = ot;
after->opcontext = WM_OP_INVOKE_DEFAULT;
after->opptr = MEM_cnew<PointerRNA>(__func__);
WM_operator_properties_create_ptr(after->opptr, ot);
RNA_string_set(after->opptr, "menu_idname", menu->menu_idname);
if (event->type != EVT_SPACEKEY) {
const int num_bytes = BLI_str_utf8_size_or_error(event->utf8_buf);
if (num_bytes != -1) {
char buf[sizeof(event->utf8_buf) + 1];
memcpy(buf, event->utf8_buf, num_bytes);
buf[num_bytes] = '\0';
RNA_string_set(after->opptr, "initial_query", buf);
}
}
menu->menuretval = UI_RETURN_OK;
return WM_UI_HANDLER_BREAK;
}
}
/* Handle accelerator keys that allow "pressing" a menu entry by pressing a single key. */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) {
if (but->type == UI_BTYPE_BUT) {
UI_but_execute(C, region, but);
}
else {
ui_handle_button_activate_by_type(C, region, but);
}
return WM_UI_HANDLER_BREAK;
}
uiAfterFunc *after = ui_afterfunc_new();
wmOperatorType *ot = WM_operatortype_find("WM_OT_search_single_menu", false);
after->optype = ot;
after->opcontext = WM_OP_INVOKE_DEFAULT;
after->opptr = MEM_cnew<PointerRNA>(__func__);
WM_operator_properties_create_ptr(after->opptr, ot);
RNA_string_set(after->opptr, "menu_idname", menu->menu_idname);
menu->menuretval = UI_RETURN_OK;
return WM_UI_HANDLER_BREAK;
}
return WM_UI_HANDLER_CONTINUE;
}
@ -10776,8 +10750,7 @@ static int ui_handle_menu_event(bContext *C,
case EVT_WKEY:
case EVT_XKEY:
case EVT_YKEY:
case EVT_ZKEY:
case EVT_SPACEKEY: {
case EVT_ZKEY: {
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK) &&
((event->modifier & (KM_SHIFT | KM_CTRL | KM_OSKEY)) == 0) &&
/* Only respond to explicit press to avoid the event that opened the menu
@ -10788,10 +10761,33 @@ static int ui_handle_menu_event(bContext *C,
menu, but, level, is_parent_menu, retval)) {
break;
}
retval = ui_handle_menu_letter_press(C, region, menu, event, block);
/* Handle accelerator keys. */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) {
if (but->type == UI_BTYPE_BUT) {
UI_but_execute(C, region, but);
}
else {
ui_handle_button_activate_by_type(C, region, but);
}
break;
}
}
retval = WM_UI_HANDLER_BREAK;
}
break;
}
case EVT_SPACEKEY: {
/* Press spacebar to start menu search. */
if ((level != 0) && (but == nullptr || !menu->menu_idname[0])) {
/* Search parent if the child is open but not activated or not searchable. */
menu->menuretval = UI_RETURN_OUT | UI_RETURN_OUT_PARENT;
}
else {
retval = ui_handle_menu_letter_press(menu);
}
}
}
}

View File

@ -5923,9 +5923,6 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
}
uiBlock *block = uiLayoutGetBlock(layout);
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
UI_block_flag_enable(block, UI_BLOCK_NO_ACCELERATOR_KEYS);
}
if (mt->listener) {
/* Forward the menu type listener to the block we're drawing in. */
ui_block_add_dynamic_listener(block, mt->listener);

View File

@ -405,10 +405,8 @@ static uiPopupBlockHandle *ui_popup_menu_create(
pup->slideout = ui_block_is_menu(but->block);
pup->but = but;
if (MenuType *mt = UI_but_menutype_get(but)) {
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
ED_workspace_status_text(C, TIP_("Type to search..."));
}
if (but->type == UI_BTYPE_PULLDOWN) {
ED_workspace_status_text(C, TIP_("Press spacebar to search..."));
}
}
@ -624,8 +622,8 @@ static void ui_popup_menu_create_from_menutype(bContext *C,
STRNCPY(handle->menu_idname, mt->idname);
handle->can_refresh = true;
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
ED_workspace_status_text(C, TIP_("Type to search..."));
if (mt->idname[0]) {
ED_workspace_status_text(C, TIP_("Press spacebar to search..."));
}
}

View File

@ -820,8 +820,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
{
/* This disables the status bar text that is set when opening a menu that supports search (see
* #MenuTypeFlag::SearchOnKeyPress). */
/* This disables the status bar text that is set when opening a menu. */
ED_workspace_status_text(C, nullptr);
/* If this popup is created from a popover which does NOT have keep-open flag set,

View File

@ -456,12 +456,17 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
{
const char *idname_array[] = {
/* While we could include this, it's just showing filenames to load. */
"TOPBAR_MT_file_open_recent",
(single_menu_idname && STREQ(single_menu_idname, "TOPBAR_MT_file_open_recent")) ?
nullptr :
"TOPBAR_MT_file_open_recent",
/* Showing undo history is not helpful since users may accidentally undo
* an action they intend to run. */
"TOPBAR_MT_undo_history",
};
for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
if (!idname_array[i]) {
continue;
}
MenuType *mt = WM_menutype_find(idname_array[i], false);
if (mt != nullptr) {
menu_tagged.add(mt);
@ -469,8 +474,8 @@ static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
}
}
{
/* Exclude context menus because:
if (!single_menu_idname) {
/* Exclude context menus (when not searching in a specific single menu) because:
* - The menu items are available elsewhere (and will show up multiple times).
* - Menu items depend on exact context, making search results unpredictable
* (exact number of items selected for example). See design doc #74158.

View File

@ -2009,15 +2009,6 @@ static void rna_def_menu(BlenderRNA *brna)
PropertyRNA *parm;
FunctionRNA *func;
static const EnumPropertyItem menu_flag_items[] = {
{int(MenuTypeFlag::SearchOnKeyPress),
"SEARCH_ON_KEY_PRESS",
0,
"Search on Key Press",
"Open a menu search when a key pressed while the menu is open"},
{0, nullptr, 0, nullptr, nullptr},
};
srna = RNA_def_struct(brna, "Menu", nullptr);
RNA_def_struct_ui_text(srna, "Menu", "Editor menu containing buttons");
RNA_def_struct_sdna(srna, "Menu");
@ -2082,12 +2073,6 @@ static void rna_def_menu(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, nullptr, "type->owner_id");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "type->flag");
RNA_def_property_enum_items(prop, menu_flag_items);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this menu type");
RNA_define_verify_sdna(true);
}