UI: Type To Search And Space Bar Search
Continue allowing spacebar search for all dropdown and context menus, but also add the ability to allow some menus to have type to search, like Add Modifiers, Objects, Nodes. Pull Request: https://projects.blender.org/blender/blender/pulls/113520
This commit is contained in:
committed by
Harley Acheson
parent
2d703e9200
commit
b688414223
@@ -52,11 +52,20 @@ 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
|
||||
ob_type = context.object.type
|
||||
geometry_nodes_supported = ob_type in {'MESH', 'CURVE', 'CURVES', 'FONT', 'SURFACE', 'VOLUME', 'POINTCLOUD'}
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "OBJECT_MT_modifier_add"
|
||||
layout.separator()
|
||||
|
||||
layout.operator_context = 'EXEC_REGION_WIN'
|
||||
|
||||
if geometry_nodes_supported:
|
||||
self.operator_modifier_add(layout, 'NODES')
|
||||
layout.separator()
|
||||
@@ -75,6 +84,7 @@ class OBJECT_MT_modifier_add(ModifierAddMenu, Menu):
|
||||
|
||||
class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
||||
bl_label = "Edit"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -98,6 +108,7 @@ class OBJECT_MT_modifier_add_edit(ModifierAddMenu, Menu):
|
||||
|
||||
class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
||||
bl_label = "Generate"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -139,6 +150,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
||||
|
||||
class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
||||
bl_label = "Deform"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -174,6 +186,7 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
|
||||
|
||||
class OBJECT_MT_modifier_add_physics(ModifierAddMenu, Menu):
|
||||
bl_label = "Physics"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@@ -226,11 +226,18 @@ 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
|
||||
|
||||
layout = self.layout
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "NODE_MT_add"
|
||||
layout.separator()
|
||||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
snode = context.space_data
|
||||
|
||||
@@ -2275,6 +2275,7 @@ class VIEW3D_MT_select_sculpt_curves(Menu):
|
||||
class VIEW3D_MT_mesh_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_mesh_add"
|
||||
bl_label = "Mesh"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2301,6 +2302,7 @@ class VIEW3D_MT_mesh_add(Menu):
|
||||
class VIEW3D_MT_curve_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_curve_add"
|
||||
bl_label = "Curve"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -2329,6 +2331,7 @@ class VIEW3D_MT_curve_add(Menu):
|
||||
class VIEW3D_MT_surface_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_surface_add"
|
||||
bl_label = "Surface"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2371,6 +2374,7 @@ class VIEW3D_MT_edit_metaball_context_menu(Menu):
|
||||
class VIEW3D_MT_metaball_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_metaball_add"
|
||||
bl_label = "Metaball"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2383,6 +2387,7 @@ class TOPBAR_MT_edit_curve_add(Menu):
|
||||
bl_idname = "TOPBAR_MT_edit_curve_add"
|
||||
bl_label = "Add"
|
||||
bl_translation_context = i18n_contexts.operator_default
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -2400,6 +2405,7 @@ class TOPBAR_MT_edit_curve_add(Menu):
|
||||
class TOPBAR_MT_edit_armature_add(Menu):
|
||||
bl_idname = "TOPBAR_MT_edit_armature_add"
|
||||
bl_label = "Armature"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2411,6 +2417,7 @@ class TOPBAR_MT_edit_armature_add(Menu):
|
||||
class VIEW3D_MT_armature_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_armature_add"
|
||||
bl_label = "Armature"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2423,6 +2430,7 @@ class VIEW3D_MT_light_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_light_add"
|
||||
bl_context = i18n_contexts.id_light
|
||||
bl_label = "Light"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2434,6 +2442,7 @@ class VIEW3D_MT_light_add(Menu):
|
||||
class VIEW3D_MT_lightprobe_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_lightprobe_add"
|
||||
bl_label = "Light Probe"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2445,6 +2454,7 @@ class VIEW3D_MT_lightprobe_add(Menu):
|
||||
class VIEW3D_MT_camera_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_camera_add"
|
||||
bl_label = "Camera"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2456,6 +2466,7 @@ class VIEW3D_MT_volume_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_volume_add"
|
||||
bl_label = "Volume"
|
||||
bl_translation_context = i18n_contexts.id_id
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2468,6 +2479,7 @@ class VIEW3D_MT_volume_add(Menu):
|
||||
class VIEW3D_MT_grease_pencil_add(Menu):
|
||||
bl_idname = "VIEW3D_MT_grease_pencil_add"
|
||||
bl_label = "Grease Pencil"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
@@ -2479,10 +2491,16 @@ 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
|
||||
|
||||
if layout.operator_context == 'EXEC_REGION_WIN':
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("WM_OT_search_single_menu", text="Search...", icon='VIEWZOOM').menu_idname = "VIEW3D_MT_add"
|
||||
layout.separator()
|
||||
|
||||
# NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context.
|
||||
|
||||
# NOTE: was `EXEC_AREA`, but this context does not have the `rv3d`, which prevents
|
||||
@@ -2570,6 +2588,7 @@ class VIEW3D_MT_add(Menu):
|
||||
|
||||
class VIEW3D_MT_image_add(Menu):
|
||||
bl_label = "Add Image"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
@@ -411,6 +411,10 @@ 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)
|
||||
|
||||
|
||||
@@ -10313,9 +10313,9 @@ float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2])
|
||||
return len;
|
||||
}
|
||||
|
||||
static int ui_handle_menu_letter_press(uiPopupBlockHandle *menu)
|
||||
static int ui_handle_menu_letter_press_search(uiPopupBlockHandle *menu, const wmEvent *event)
|
||||
{
|
||||
/* Start menu search on space-bar press if the menu has a name. */
|
||||
/* Start menu search if the menu has a name. */
|
||||
if (menu->menu_idname[0]) {
|
||||
uiAfterFunc *after = ui_afterfunc_new();
|
||||
wmOperatorType *ot = WM_operatortype_find("WM_OT_search_single_menu", false);
|
||||
@@ -10324,6 +10324,16 @@ static int ui_handle_menu_letter_press(uiPopupBlockHandle *menu)
|
||||
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) {
|
||||
/* Forward all keys except spacebar to the search. */
|
||||
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;
|
||||
}
|
||||
@@ -10759,19 +10769,37 @@ static int ui_handle_menu_event(bContext *C,
|
||||
case EVT_WKEY:
|
||||
case EVT_XKEY:
|
||||
case EVT_YKEY:
|
||||
case EVT_ZKEY: {
|
||||
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK) &&
|
||||
case EVT_ZKEY:
|
||||
case EVT_SPACEKEY: {
|
||||
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
|
||||
* activating an item when the key is held. */
|
||||
(event->flag & WM_EVENT_IS_REPEAT) == 0)
|
||||
{
|
||||
if (ui_menu_pass_event_to_parent_if_nonactive(
|
||||
menu, but, level, is_parent_menu, retval)) {
|
||||
|
||||
/* Menu search if spacebar or SearchOnKeyPress. */
|
||||
MenuType *mt = WM_menutype_find(menu->menu_idname, false);
|
||||
if ((mt && bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) ||
|
||||
event->type == EVT_SPACEKEY)
|
||||
{
|
||||
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_search(menu, event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle accelerator keys. */
|
||||
if (ui_menu_pass_event_to_parent_if_nonactive(
|
||||
menu, but, level, is_parent_menu, retval))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
@@ -10780,21 +10808,9 @@ static int ui_handle_menu_event(bContext *C,
|
||||
else {
|
||||
ui_handle_button_activate_by_type(C, region, but);
|
||||
}
|
||||
break;
|
||||
return WM_UI_HANDLER_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5963,6 +5963,9 @@ 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);
|
||||
|
||||
@@ -622,7 +622,10 @@ static void ui_popup_menu_create_from_menutype(bContext *C,
|
||||
STRNCPY(handle->menu_idname, mt->idname);
|
||||
handle->can_refresh = true;
|
||||
|
||||
if (mt->idname[0]) {
|
||||
if (bool(mt->flag & MenuTypeFlag::SearchOnKeyPress)) {
|
||||
ED_workspace_status_text(C, TIP_("Type to search..."));
|
||||
}
|
||||
else if (mt->idname[0]) {
|
||||
ED_workspace_status_text(C, TIP_("Press spacebar to search..."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2009,6 +2009,15 @@ 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");
|
||||
@@ -2073,6 +2082,12 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user