UI: support searching in menus #110855
@ -29,6 +29,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
|
||||
class OBJECT_MT_modifier_add(Menu):
|
||||
bl_label = "Add Modifier"
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
@ -225,6 +225,7 @@ class NODE_MT_add(bpy.types.Menu):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_label = "Add"
|
||||
JacquesLucke marked this conversation as resolved
Outdated
|
||||
bl_translation_context = i18n_contexts.operator_default
|
||||
bl_options = {'SEARCH_ON_KEY_PRESS'}
|
||||
|
||||
def draw(self, context):
|
||||
import nodeitems_utils
|
||||
@ -234,27 +235,16 @@ class NODE_MT_add(bpy.types.Menu):
|
||||
|
||||
snode = context.space_data
|
||||
if snode.tree_type == 'GeometryNodeTree':
|
||||
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
|
||||
layout.separator()
|
||||
layout.menu_contents("NODE_MT_geometry_node_add_all")
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
The compositor can be changed now too. The compositor can be changed now too.
|
||||
elif snode.tree_type == 'CompositorNodeTree':
|
||||
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
|
||||
layout.separator()
|
||||
layout.menu_contents("NODE_MT_compositor_node_add_all")
|
||||
elif snode.tree_type == 'ShaderNodeTree':
|
||||
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
|
||||
layout.separator()
|
||||
layout.menu_contents("NODE_MT_shader_node_add_all")
|
||||
elif snode.tree_type == 'TextureNodeTree':
|
||||
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
|
||||
layout.separator()
|
||||
layout.menu_contents("NODE_MT_texture_node_add_all")
|
||||
elif nodeitems_utils.has_node_categories(context):
|
||||
props = layout.operator("node.add_search", text="Search...", icon='VIEWZOOM')
|
||||
props.use_transform = True
|
||||
|
||||
layout.separator()
|
||||
|
||||
# Actual node sub-menus are defined by draw functions from node categories.
|
||||
nodeitems_utils.draw_node_categories_menu(self, context)
|
||||
|
||||
|
@ -2409,6 +2409,7 @@ 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
|
||||
|
@ -405,6 +405,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)
|
||||
|
||||
|
@ -175,6 +175,8 @@ enum {
|
||||
UI_BLOCK_SEARCH_ONLY = 1 << 25,
|
||||
/** Hack for quick setup (splash screen) to draw text centered. */
|
||||
UI_BLOCK_QUICK_SETUP = 1 << 26,
|
||||
/** Don't accelerator keys for the items in the block. */
|
||||
UI_BLOCK_NO_ACCELERATOR_KEYS = 1 << 27,
|
||||
};
|
||||
|
||||
/** #uiPopupBlockHandle.menuretval */
|
||||
@ -247,6 +249,15 @@ enum {
|
||||
UI_BUT_OVERRIDDEN = 1u << 31u,
|
||||
};
|
||||
|
||||
enum {
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Julian Eisel
commented
Prefer to keep this consistent with the existing button flags and using a bare enum with a similar prefix, say If we want a different convention that should be done separately. Prefer to keep this consistent with the existing button flags and using a bare enum with a similar prefix, say `UI_BUT2_`. Otherwise it make it hard to find these when you're used to the current convention, e.g. you'd typically start by typing `UI_BUT` and look at the auto-complete results when looking for a flag.
If we want a different convention that should be done separately.
|
||||
/**
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Julian Eisel
commented
This could use some documentation. What is "on init"? What is "select"? And what is this used for? This could use some documentation. What is "on init"? What is "select"? And what is this used for?
|
||||
* This is used when `UI_BUT_ACTIVATE_ON_INIT` is used, which is used to activate e.g. a search
|
||||
* box as soon as a popup opens. Usually, the text in the search box is selected by default.
|
||||
* However, sometimes this behavior is not desired, so it can be disabled with this flag.
|
||||
*/
|
||||
UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT = 1 << 0,
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Julian Eisel
commented
Maybe call this Maybe call this `..._NO_SELECT` (picky)?
|
||||
};
|
||||
|
||||
/** #uiBut.dragflag */
|
||||
enum {
|
||||
/** By default only the left part of a button triggers dragging. A questionable design to make
|
||||
@ -887,6 +898,7 @@ bool UI_but_active_drop_color(bContext *C);
|
||||
void UI_but_flag_enable(uiBut *but, int flag);
|
||||
void UI_but_flag_disable(uiBut *but, int flag);
|
||||
bool UI_but_flag_is_set(uiBut *but, int flag);
|
||||
void UI_but_flag2_enable(uiBut *but, int flag);
|
||||
|
||||
void UI_but_drawflag_enable(uiBut *but, int flag);
|
||||
void UI_but_drawflag_disable(uiBut *but, int flag);
|
||||
@ -2404,7 +2416,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C);
|
||||
void UI_but_func_operator_search(uiBut *but);
|
||||
void uiTemplateOperatorSearch(uiLayout *layout);
|
||||
|
||||
void UI_but_func_menu_search(uiBut *but);
|
||||
void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname = nullptr);
|
||||
void uiTemplateMenuSearch(uiLayout *layout);
|
||||
|
||||
/**
|
||||
|
@ -2001,7 +2001,9 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
|
||||
UI_block_layout_resolve(block, nullptr, nullptr);
|
||||
}
|
||||
ui_block_align_calc(block, CTX_wm_region(C));
|
||||
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT)) {
|
||||
if ((block->flag & UI_BLOCK_LOOP) && (block->flag & UI_BLOCK_NUMSELECT) &&
|
||||
(block->flag & UI_BLOCK_NO_ACCELERATOR_KEYS) == 0)
|
||||
{
|
||||
ui_menu_block_set_keyaccels(block); /* could use a different flag to check */
|
||||
}
|
||||
|
||||
@ -5848,6 +5850,11 @@ void UI_but_flag_enable(uiBut *but, int flag)
|
||||
but->flag |= flag;
|
||||
}
|
||||
|
||||
void UI_but_flag2_enable(uiBut *but, int flag)
|
||||
{
|
||||
but->flag2 |= flag;
|
||||
}
|
||||
|
||||
void UI_but_flag_disable(uiBut *but, int flag)
|
||||
{
|
||||
but->flag &= ~flag;
|
||||
|
@ -3480,7 +3480,12 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
|
||||
/* set cursor pos to the end of the text */
|
||||
but->editstr = data->str;
|
||||
but->pos = len;
|
||||
if (bool(but->flag2 & UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT)) {
|
||||
but->selsta = len;
|
||||
}
|
||||
else {
|
||||
but->selsta = 0;
|
||||
}
|
||||
but->selend = len;
|
||||
|
||||
/* Initialize undo history tracking. */
|
||||
@ -4316,6 +4321,9 @@ static void ui_block_open_begin(bContext *C, uiBut *but, uiHandleButtonData *dat
|
||||
}
|
||||
else if (menufunc) {
|
||||
data->menu = ui_popup_menu_create(C, data->region, but, menufunc, arg);
|
||||
if (MenuType *mt = UI_but_menutype_get(but)) {
|
||||
STRNCPY(data->menu->menu_idname, mt->idname);
|
||||
}
|
||||
if (but->block->handle) {
|
||||
data->menu->popup = but->block->handle->popup;
|
||||
}
|
||||
@ -10269,6 +10277,41 @@ 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)
|
||||
{
|
||||
/* Start menu search on key press if enabled. */
|
||||
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);
|
||||
RNA_string_set(after->opptr, "initial_query", event->utf8_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;
|
||||
}
|
||||
}
|
||||
return WM_UI_HANDLER_CONTINUE;
|
||||
}
|
||||
|
||||
static int ui_handle_menu_event(bContext *C,
|
||||
const wmEvent *event,
|
||||
uiPopupBlockHandle *menu,
|
||||
@ -10709,20 +10752,7 @@ static int ui_handle_menu_event(bContext *C,
|
||||
menu, but, level, is_parent_menu, retval)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (but = static_cast<uiBut *>(block->buttons.first); but; but = but->next) {
|
||||
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;
|
||||
retval = ui_handle_menu_letter_press(C, region, menu, event, block);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -151,6 +151,7 @@ struct uiBut {
|
||||
/** Pointer back to the layout item holding this button. */
|
||||
uiLayout *layout = nullptr;
|
||||
int flag = 0;
|
||||
int flag2 = 0;
|
||||
int drawflag = 0;
|
||||
eButType type = eButType(0);
|
||||
eButPointerType pointype = UI_BUT_POIN_NONE;
|
||||
@ -848,6 +849,8 @@ struct uiPopupBlockHandle {
|
||||
bool is_grab;
|
||||
int grab_xy_prev[2];
|
||||
/* #endif */
|
||||
|
||||
char menu_idname[64];
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -5918,9 +5918,12 @@ void UI_menutype_draw(bContext *C, MenuType *mt, uiLayout *layout)
|
||||
printf("%s: opening menu \"%s\"\n", __func__, mt->idname);
|
||||
}
|
||||
|
||||
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. */
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
uiBlockDynamicListener *listener = static_cast<uiBlockDynamicListener *>(
|
||||
MEM_mallocN(sizeof(*listener), __func__));
|
||||
listener->listener_func = mt->listener;
|
||||
|
@ -397,6 +397,12 @@ static uiPopupBlockHandle *ui_popup_menu_create(
|
||||
if (but) {
|
||||
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) {
|
||||
@ -608,7 +614,12 @@ static void ui_popup_menu_create_from_menutype(bContext *C,
|
||||
ui_item_menutype_func(C, layout, mt);
|
||||
});
|
||||
|
||||
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..."));
|
||||
}
|
||||
}
|
||||
|
||||
int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
|
||||
|
@ -575,6 +575,11 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
||||
block = handle_create_func(C, handle, arg);
|
||||
}
|
||||
|
||||
/* Don't create accelerator keys if the parent menu does not have them. */
|
||||
if (but && but->block->flag & UI_BLOCK_NO_ACCELERATOR_KEYS) {
|
||||
block->flag |= UI_BLOCK_NO_ACCELERATOR_KEYS;
|
||||
}
|
||||
|
||||
/* callbacks _must_ leave this for us, otherwise we can't call UI_block_update_from_old */
|
||||
BLI_assert(!block->endblock);
|
||||
|
||||
@ -815,6 +820,10 @@ 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
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Hans Goudey
commented
Either add a check for Either add a check for `MenuTypeFlag::SearchOnKeyPress` here or add a comment that references it.
|
||||
* #MenuTypeFlag::SearchOnKeyPress). */
|
||||
ED_workspace_status_text(C, nullptr);
|
||||
|
||||
/* If this popup is created from a popover which does NOT have keep-open flag set,
|
||||
* then close the popover too. We could extend this to other popup types too. */
|
||||
ARegion *region = handle->popup_create_vars.butregion;
|
||||
|
@ -428,8 +428,12 @@ static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data)
|
||||
* - Look up predefined editor-menus.
|
||||
* - Look up key-map items which call menus.
|
||||
*/
|
||||
static MenuSearch_Data *menu_items_from_ui_create(
|
||||
bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
|
||||
static MenuSearch_Data *menu_items_from_ui_create(bContext *C,
|
||||
wmWindow *win,
|
||||
ScrArea *area_init,
|
||||
ARegion *region_init,
|
||||
bool include_all_areas,
|
||||
const char *single_menu_idname)
|
||||
{
|
||||
MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
blender::Map<MenuType *, const char *> menu_display_name_map;
|
||||
@ -591,11 +595,18 @@ static MenuSearch_Data *menu_items_from_ui_create(
|
||||
region = region_init;
|
||||
}
|
||||
|
||||
if (single_menu_idname) {
|
||||
if (MenuType *mt = WM_menutype_find(single_menu_idname, false)) {
|
||||
if (menu_tagged.add(mt)) {
|
||||
menu_stack.push({mt});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Populate menus from the editors,
|
||||
* note that we could create a fake header, draw the header and extract the menus
|
||||
* from the buttons, however this is quite involved and can be avoided as by convention
|
||||
* each space-type has a single root-menu that headers use. */
|
||||
{
|
||||
const char *idname_array[2] = {nullptr};
|
||||
int idname_array_len = 0;
|
||||
|
||||
@ -798,8 +809,9 @@ static MenuSearch_Data *menu_items_from_ui_create(
|
||||
}
|
||||
UI_block_free(nullptr, block);
|
||||
|
||||
/* Add key-map items as a second pass,
|
||||
* so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
|
||||
if (single_menu_idname == nullptr) {
|
||||
/* Add key-map items as a second pass, so all menus are accessed from the header & top-bar
|
||||
* before key shortcuts are expanded. */
|
||||
if (menu_stack.is_empty() && (has_keymap_menu_items == false)) {
|
||||
has_keymap_menu_items = true;
|
||||
menu_types_add_from_keymap_items(
|
||||
@ -807,6 +819,7 @@ static MenuSearch_Data *menu_items_from_ui_create(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: currently this builds the full path for each menu item,
|
||||
* that could be moved into the parent menu. */
|
||||
@ -887,7 +900,7 @@ static MenuSearch_Data *menu_items_from_ui_create(
|
||||
* - Many operators need options to be set to give useful results, see: #74157.
|
||||
* - User who really prefer to list all operators can use #WM_OT_search_operator.
|
||||
*/
|
||||
if (U.flag & USER_DEVELOPER_UI) {
|
||||
if ((U.flag & USER_DEVELOPER_UI) && single_menu_idname == nullptr) {
|
||||
menu_items_from_all_operators(C, data);
|
||||
}
|
||||
|
||||
@ -1112,15 +1125,17 @@ static ARegion *ui_search_menu_create_tooltip(
|
||||
/** \name Menu Search Template Public API
|
||||
* \{ */
|
||||
|
||||
void UI_but_func_menu_search(uiBut *but)
|
||||
void UI_but_func_menu_search(uiBut *but, const char *single_menu_idname)
|
||||
{
|
||||
bContext *C = (bContext *)but->block->evil_C;
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
/* When run from top-bar scan all areas in the current window. */
|
||||
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
|
||||
MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas);
|
||||
const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)) &&
|
||||
!single_menu_idname;
|
||||
MenuSearch_Data *data = menu_items_from_ui_create(
|
||||
C, win, area, region, include_all_areas, single_menu_idname);
|
||||
UI_but_func_search_set(but,
|
||||
/* Generic callback. */
|
||||
ui_searchbox_create_menu,
|
||||
|
@ -1995,6 +1995,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");
|
||||
@ -2059,6 +2068,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);
|
||||
}
|
||||
|
||||
|
@ -1741,27 +1741,30 @@ static void WM_OT_operator_defaults(wmOperatorType *ot)
|
||||
enum SearchType {
|
||||
SEARCH_TYPE_OPERATOR = 0,
|
||||
SEARCH_TYPE_MENU = 1,
|
||||
SEARCH_TYPE_SINGLE_MENU = 2,
|
||||
};
|
||||
|
||||
struct SearchPopupInit_Data {
|
||||
SearchType search_type;
|
||||
int size[2];
|
||||
std::string single_menu_idname;
|
||||
};
|
||||
|
||||
static char g_search_text[256] = "";
|
||||
|
||||
static uiBlock *wm_block_search_menu(bContext *C, ARegion *region, void *userdata)
|
||||
{
|
||||
const SearchPopupInit_Data *init_data = static_cast<const SearchPopupInit_Data *>(userdata);
|
||||
static char search[256] = "";
|
||||
|
||||
uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS);
|
||||
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
|
||||
uiBut *but = uiDefSearchBut(block,
|
||||
search,
|
||||
g_search_text,
|
||||
0,
|
||||
ICON_VIEWZOOM,
|
||||
sizeof(search),
|
||||
sizeof(g_search_text),
|
||||
10,
|
||||
10,
|
||||
init_data->size[0],
|
||||
@ -1776,6 +1779,10 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *region, void *userdat
|
||||
else if (init_data->search_type == SEARCH_TYPE_MENU) {
|
||||
UI_but_func_menu_search(but);
|
||||
}
|
||||
else if (init_data->search_type == SEARCH_TYPE_SINGLE_MENU) {
|
||||
UI_but_func_menu_search(but, init_data->single_menu_idname.c_str());
|
||||
UI_but_flag2_enable(but, UI_BUT2_ACTIVATE_ON_INIT_NO_SELECT);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
@ -1837,16 +1844,33 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve
|
||||
}
|
||||
}
|
||||
|
||||
int search_type;
|
||||
SearchType search_type;
|
||||
if (STREQ(op->type->idname, "WM_OT_search_menu")) {
|
||||
search_type = SEARCH_TYPE_MENU;
|
||||
}
|
||||
else if (STREQ(op->type->idname, "WM_OT_search_single_menu")) {
|
||||
search_type = SEARCH_TYPE_SINGLE_MENU;
|
||||
}
|
||||
else {
|
||||
search_type = SEARCH_TYPE_OPERATOR;
|
||||
}
|
||||
|
||||
static SearchPopupInit_Data data{};
|
||||
data.search_type = SearchType(search_type);
|
||||
|
||||
if (search_type == SEARCH_TYPE_SINGLE_MENU) {
|
||||
{
|
||||
char *buffer = RNA_string_get_alloc(op->ptr, "menu_idname", nullptr, 0, nullptr);
|
||||
data.single_menu_idname = buffer;
|
||||
MEM_SAFE_FREE(buffer);
|
||||
}
|
||||
{
|
||||
char *buffer = RNA_string_get_alloc(op->ptr, "initial_query", nullptr, 0, nullptr);
|
||||
STRNCPY(g_search_text, buffer);
|
||||
MEM_SAFE_FREE(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
data.search_type = search_type;
|
||||
data.size[0] = UI_searchbox_size_x() * 2;
|
||||
data.size[1] = UI_searchbox_size_y();
|
||||
|
||||
@ -1877,6 +1901,25 @@ static void WM_OT_search_operator(wmOperatorType *ot)
|
||||
ot->poll = WM_operator_winactive;
|
||||
}
|
||||
|
||||
static void WM_OT_search_single_menu(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Search Single Menu";
|
||||
JacquesLucke marked this conversation as resolved
Outdated
Julian Eisel
commented
Not sure if I noted this before, but I'm unsure about using Not sure if I noted this before, but I'm unsure about using `__func__` for the operator idname. This breaks BPY compatibility when renaming a function (!) and it uses an "implementation-defined format" in C++ (unlike in C). See https://stackoverflow.com/questions/4384765/whats-the-difference-between-pretty-function-function-func or https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros.
|
||||
ot->idname = "WM_OT_search_single_menu";
|
||||
ot->description = "Pop-up a search for a menu in current context";
|
||||
|
||||
ot->invoke = wm_search_menu_invoke;
|
||||
ot->exec = wm_search_menu_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
|
||||
RNA_def_string(ot->srna, "menu_idname", nullptr, 0, "Menu Name", "Menu to search in");
|
||||
RNA_def_string(ot->srna,
|
||||
"initial_query",
|
||||
nullptr,
|
||||
0,
|
||||
"Initial Query",
|
||||
"Query to insert into the search box");
|
||||
}
|
||||
|
||||
static int wm_call_menu_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char idname[BKE_ST_MAXNAME];
|
||||
@ -3833,6 +3876,7 @@ void wm_operatortypes_register()
|
||||
WM_operatortype_append(WM_OT_splash_about);
|
||||
WM_operatortype_append(WM_OT_search_menu);
|
||||
WM_operatortype_append(WM_OT_search_operator);
|
||||
WM_operatortype_append(WM_OT_search_single_menu);
|
||||
WM_operatortype_append(WM_OT_call_menu);
|
||||
WM_operatortype_append(WM_OT_call_menu_pie);
|
||||
WM_operatortype_append(WM_OT_call_panel);
|
||||
|
It's more consistent to use
bl_options
to set some flags.