diff --git a/menu/cbs/menu_cbs_cancel.c b/menu/cbs/menu_cbs_cancel.c index 6ad471831a..aaaa481dfa 100644 --- a/menu/cbs/menu_cbs_cancel.c +++ b/menu/cbs/menu_cbs_cancel.c @@ -35,7 +35,7 @@ int action_cancel_pop_default(const char *path, size_t new_selection_ptr; const char *menu_label = NULL; unsigned menu_type = MENU_SETTINGS_NONE; - struct string_list *menu_search_terms = menu_driver_search_get_terms(); + menu_serch_terms_t *menu_search_terms = menu_entries_search_get_terms(); #ifdef HAVE_AUDIOMIXER settings_t *settings = config_get_ptr(); bool audio_enable_menu = settings->bools.audio_enable_menu; @@ -53,7 +53,7 @@ int action_cancel_pop_default(const char *path, * > If so, remove the last search term */ if (menu_search_terms && menu_driver_search_filter_enabled(menu_label, menu_type) && - menu_driver_search_pop()) + menu_entries_search_pop()) { bool refresh = false; @@ -109,12 +109,12 @@ static int action_cancel_core_content(const char *path, if (string_is_equal(menu_label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST))) { - struct string_list *menu_search_terms = menu_driver_search_get_terms(); + menu_serch_terms_t *menu_search_terms = menu_entries_search_get_terms(); /* Check whether search terms have been set * > If so, remove the last search term */ if (menu_search_terms && - menu_driver_search_pop()) + menu_entries_search_pop()) { bool refresh = false; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index 8f507e6057..8b50108496 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -79,19 +79,43 @@ } static void action_get_title_fill_search_filter_default( - char *s, enum msg_hash_enums lbl, size_t len) + enum msg_hash_enums lbl, char *s, size_t len) { /* Copy label value */ strlcpy(s, msg_hash_to_str(lbl), len); /* Add current search terms */ - menu_driver_search_append_terms_string(s, len); + menu_entries_search_append_terms_string(s, len); } #define DEFAULT_TITLE_SEARCH_FILTER_MACRO(func_name, lbl) \ static int (func_name)(const char *path, const char *label, unsigned menu_type, char *s, size_t len) \ { \ - action_get_title_fill_search_filter_default(s, lbl, len); \ + action_get_title_fill_search_filter_default(lbl, s, len); \ + return 0; \ +} + +static void action_get_title_fill_path_search_filter_default( + const char *path, enum msg_hash_enums lbl, char *s, size_t len) +{ + const char *title = msg_hash_to_str(lbl); + + if (!string_is_empty(title)) + strlcpy(s, title, len); + + if (!string_is_empty(path)) + { + strlcat(s, " ", len); + strlcat(s, path, len); + } + + menu_entries_search_append_terms_string(s, len); +} + +#define DEFAULT_FILL_TITLE_SEARCH_FILTER_MACRO(func_name, lbl) \ + static int (func_name)(const char *path, const char *label, unsigned menu_type, char *s, size_t len) \ +{ \ + action_get_title_fill_path_search_filter_default(path, lbl, s, len); \ return 0; \ } @@ -376,7 +400,7 @@ static int action_get_title_deferred_playlist_list(const char *path, const char strlcpy(s, playlist_file, len); /* Add current search terms */ - menu_driver_search_append_terms_string(s, len); + menu_entries_search_append_terms_string(s, len); return 0; } @@ -667,7 +691,6 @@ DEFAULT_FILL_TITLE_MACRO(action_get_title_cheat_directory, MENU_ENUM_LABEL_ DEFAULT_FILL_TITLE_MACRO(action_get_title_core_directory, MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH) DEFAULT_FILL_TITLE_MACRO(action_get_title_core_info_directory, MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH) DEFAULT_FILL_TITLE_MACRO(action_get_title_audio_filter, MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN) -DEFAULT_FILL_TITLE_MACRO(action_get_title_video_shader_preset, MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO) DEFAULT_FILL_TITLE_MACRO(action_get_title_configurations, MENU_ENUM_LABEL_VALUE_CONFIG) DEFAULT_FILL_TITLE_MACRO(action_get_title_content_database_directory, MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY) DEFAULT_FILL_TITLE_MACRO(action_get_title_savestate_directory, MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY) @@ -735,6 +758,8 @@ DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_title_deferred_music_list, MENU DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_title_deferred_video_list, MENU_ENUM_LABEL_VALUE_GOTO_VIDEO) DEFAULT_TITLE_SEARCH_FILTER_MACRO(action_get_core_updater_list, MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST) +DEFAULT_FILL_TITLE_SEARCH_FILTER_MACRO(action_get_title_video_shader_preset, MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO) + static int action_get_title_generic(char *s, size_t len, const char *path, const char *text) { @@ -802,9 +827,15 @@ static int action_get_title_default(const char *path, const char *label, unsigned menu_type, char *s, size_t len) { strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SELECT_FILE), len); - strlcat(s, " ", len); + if (!string_is_empty(path)) + { + strlcat(s, " ", len); strlcat(s, path, len); + } + + menu_entries_search_append_terms_string(s, len); + return 0; } @@ -843,7 +874,7 @@ static int action_get_title_group_settings(const char *path, const char *label, { if (info_list[i].is_playlist_tab) action_get_title_fill_search_filter_default( - s, info_list[i].val, len); + info_list[i].val, s, len); else strlcpy(s, msg_hash_to_str(info_list[i].val), len); return 0; diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index 06d414f7f0..d671faa137 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -513,13 +513,8 @@ static enum menu_action ozone_parse_menu_entry_action( /* If this is a playlist, handle 'backing out' * of a search, if required */ if (ozone->is_playlist) - { - struct string_list *menu_search_terms = - menu_driver_search_get_terms(); - if (menu_search_terms && - (menu_search_terms->size > 0)) + if (menu_entries_search_get_terms()) break; - } if (ozone->cursor_in_sidebar) { @@ -3239,7 +3234,7 @@ static void ozone_set_header(ozone_handle_t *ozone) strlcpy(ozone->title, node->console_name, sizeof(ozone->title)); /* Add current search terms */ - menu_driver_search_append_terms_string( + menu_entries_search_append_terms_string( ozone->title, sizeof(ozone->title)); } } @@ -3330,8 +3325,8 @@ static void ozone_populate_entries(void *data, * (Ozone is a fickle beast...) */ if (ozone->is_playlist) { - struct string_list *menu_search_terms = - menu_driver_search_get_terms(); + menu_serch_terms_t *menu_search_terms = + menu_entries_search_get_terms(); size_t num_search_terms = menu_search_terms ? menu_search_terms->size : 0; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 9a60aec701..0609ba0b33 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1900,7 +1900,7 @@ static void xmb_set_title(xmb_handle_t *xmb) xmb->title_name, path, sizeof(xmb->title_name)); /* Add current search terms */ - menu_driver_search_append_terms_string( + menu_entries_search_append_terms_string( xmb->title_name, sizeof(xmb->title_name)); } } diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 6b0816ceb4..242107e406 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -131,30 +131,38 @@ struct menu_displaylist_state { enum msg_hash_enums new_type; + enum filebrowser_enums filebrowser_types; char new_path_entry[4096]; char new_lbl_entry[4096]; char new_entry[4096]; }; -static struct menu_displaylist_state menu_displist_st; -/* TODO/FIXME - static public global variables */ -static enum filebrowser_enums filebrowser_types = FILEBROWSER_NONE; +static struct menu_displaylist_state menu_displist_st = { + MSG_UNKNOWN, /* new_type */ + FILEBROWSER_NONE, /* filebrowser_types */ + {'\0'}, /* new_path_entry */ + {'\0'}, /* new_lbl_entry */ + {'\0'}, /* new_entry */ +}; extern struct key_desc key_descriptors[RARCH_MAX_KEYS]; enum filebrowser_enums filebrowser_get_type(void) { - return filebrowser_types; + struct menu_displaylist_state *p_displist = &menu_displist_st; + return p_displist->filebrowser_types; } void filebrowser_clear_type(void) { - filebrowser_types = FILEBROWSER_NONE; + struct menu_displaylist_state *p_displist = &menu_displist_st; + p_displist->filebrowser_types = FILEBROWSER_NONE; } void filebrowser_set_type(enum filebrowser_enums type) { - filebrowser_types = type; + struct menu_displaylist_state *p_displist = &menu_displist_st; + p_displist->filebrowser_types = type; } static void filebrowser_parse( @@ -167,21 +175,20 @@ static void filebrowser_parse( ) { size_t i, list_size; - const struct retro_subsystem_info *subsystem; - bool ret = false; - struct string_list str_list = {0}; - unsigned items_found = 0; - unsigned files_count = 0; - unsigned dirs_count = 0; - enum menu_displaylist_ctl_state type = (enum menu_displaylist_ctl_state) - type_data; - const char *path = info->path; - bool path_is_compressed = !string_is_empty(path) - ? path_is_compressed_file(path) : false; + const struct retro_subsystem_info *subsystem = NULL; + bool ret = false; + struct string_list str_list = {0}; + unsigned items_found = 0; + enum menu_displaylist_ctl_state type = (enum menu_displaylist_ctl_state)type_data; + enum filebrowser_enums filebrowser_type = filebrowser_get_type(); + const char *path = info->path; + bool path_is_compressed = !string_is_empty(path) ? + path_is_compressed_file(path) : false; + menu_serch_terms_t *search_terms = menu_entries_search_get_terms(); if (path_is_compressed) { - if (filebrowser_types == FILEBROWSER_SELECT_FILE_SUBSYSTEM) + if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM) { rarch_system_info_t *system = runloop_get_system_info(); /* Core fully loaded, use the subsystem data */ @@ -211,7 +218,7 @@ static void filebrowser_parse( msg_hash_to_str(MENU_ENUM_LABEL_SCAN_FILE))) filter_ext = false; - if (filebrowser_types == FILEBROWSER_SELECT_FILE_SUBSYSTEM) + if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM) { rarch_system_info_t *system = runloop_get_system_info(); /* Core fully loaded, use the subsystem data */ @@ -236,7 +243,7 @@ static void filebrowser_parse( true, show_hidden_files, true, false); } - switch (filebrowser_types) + switch (filebrowser_type) { case FILEBROWSER_SCAN_DIR: #ifdef HAVE_LIBRETRODB @@ -284,28 +291,56 @@ static void filebrowser_parse( { for (i = 0; i < list_size; i++) { - char label[64]; - enum msg_hash_enums - enum_idx = MSG_UNKNOWN; - enum rarch_content_type - path_type = RARCH_CONTENT_NONE; - enum msg_file_type file_type = FILE_TYPE_NONE; - const char *path = str_list.elems[i].data; + enum msg_hash_enums enum_idx = MSG_UNKNOWN; + enum rarch_content_type path_type = RARCH_CONTENT_NONE; + enum msg_file_type file_type = FILE_TYPE_NONE; + const char *file_path = str_list.elems[i].data; - label[0] = '\0'; + if (string_is_empty(file_path)) + continue; + + if ((str_list.elems[i].attr.i != RARCH_DIRECTORY) && + ((filebrowser_type == FILEBROWSER_SELECT_DIR) || + (filebrowser_type == FILEBROWSER_SCAN_DIR) || + (filebrowser_type == FILEBROWSER_MANUAL_SCAN_DIR))) + continue; + + if (!path_is_compressed) + { + file_path = path_basename(file_path); + if (string_is_empty(file_path)) + continue; + } + + /* Check whether entry matches search terms, + * if required */ + if (search_terms) + { + bool skip_entry = false; + size_t j; + + for (j = 0; j < search_terms->size; j++) + { + const char *search_term = search_terms->terms[j]; + + if (!string_is_empty(search_term) && + !strcasestr(file_path, search_term)) + { + skip_entry = true; + break; + } + } + + if (skip_entry) + continue; + } switch (str_list.elems[i].attr.i) { case RARCH_DIRECTORY: file_type = FILE_TYPE_DIRECTORY; - - /* Need to preserve slash first time. */ - if (!string_is_empty(path) && !path_is_compressed) - path = path_basename(path); - - dirs_count++; items_found++; - menu_entries_append_enum(info->list, path, label, + menu_entries_append_enum(info->list, file_path, "", MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY, file_type, 0, 0); continue; @@ -317,7 +352,7 @@ static void filebrowser_parse( break; case RARCH_PLAIN_FILE: default: - if (filebrowser_types == FILEBROWSER_SELECT_VIDEO_FONT) + if (filebrowser_type == FILEBROWSER_SELECT_VIDEO_FONT) file_type = FILE_TYPE_VIDEO_FONT; else file_type = (enum msg_file_type)info->type_default; @@ -327,7 +362,7 @@ static void filebrowser_parse( * every archive as an archive to disallow instant loading */ case DISPLAYLIST_CORES_DETECTED: - if (path_is_compressed_file(path)) + if (path_is_compressed_file(file_path)) file_type = FILE_TYPE_CARCHIVE; break; default: @@ -336,27 +371,15 @@ static void filebrowser_parse( break; } - if ( - (filebrowser_types == FILEBROWSER_SELECT_DIR) || - (filebrowser_types == FILEBROWSER_SCAN_DIR) || - (filebrowser_types == FILEBROWSER_MANUAL_SCAN_DIR) - ) - continue; + path_type = path_is_media_type(file_path); - /* Need to preserve slash first time. */ - if (!string_is_empty(path) && !path_is_compressed) - path = path_basename(path); - - path_type = path_is_media_type(path); - - if (filebrowser_types == FILEBROWSER_SELECT_COLLECTION) + if (filebrowser_type == FILEBROWSER_SELECT_COLLECTION) file_type = FILE_TYPE_PLAYLIST_COLLECTION; if (path_type == RARCH_CONTENT_MUSIC) file_type = FILE_TYPE_MUSIC; - else if ( - builtin_mediaplayer_enable || - builtin_imageviewer_enable) + else if (builtin_mediaplayer_enable || + builtin_imageviewer_enable) { switch (path_type) { @@ -374,7 +397,7 @@ static void filebrowser_parse( else file_type = FILE_TYPE_IMAGE; #endif - if (filebrowser_types == FILEBROWSER_SELECT_IMAGE) + if (filebrowser_type == FILEBROWSER_SELECT_IMAGE) file_type = FILE_TYPE_IMAGE; break; default: @@ -384,33 +407,26 @@ static void filebrowser_parse( switch (file_type) { - case FILE_TYPE_PLAIN: - files_count++; - break; case FILE_TYPE_MOVIE: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN; - files_count++; break; case FILE_TYPE_MUSIC: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN; - files_count++; break; case FILE_TYPE_IMAGE: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE; - files_count++; break; case FILE_TYPE_IMAGEVIEWER: enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER; - files_count++; break; + case FILE_TYPE_PLAIN: default: break; } items_found++; - menu_entries_append_enum(info->list, path, label, - enum_idx, - file_type, 0, 0); + menu_entries_append_enum(info->list, file_path, "", + enum_idx, file_type, 0, 0); } } @@ -1486,7 +1502,7 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info, size_t list_size = playlist_size(playlist); bool show_inline_core_name = false; const char *menu_driver = menu_driver_ident(); - struct string_list *search_terms = menu_driver_search_get_terms(); + menu_serch_terms_t *search_terms = menu_entries_search_get_terms(); unsigned pl_show_inline_core_name = settings->uints.playlist_show_inline_core_name; bool pl_show_sublabels = settings->bools.playlist_show_sublabels; void (*sanitization)(char*); @@ -1638,7 +1654,7 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info, for (j = 0; j < search_terms->size; j++) { - const char *search_term = search_terms->elems[j].data; + const char *search_term = search_terms->terms[j]; if (!string_is_empty(search_term) && !strcasestr(menu_entry_label, search_term)) @@ -10386,7 +10402,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, #ifdef HAVE_NETWORKING { core_updater_list_t *core_list = core_updater_list_get_cached(); - struct string_list *search_terms = menu_driver_search_get_terms(); + menu_serch_terms_t *search_terms = menu_entries_search_get_terms(); bool show_experimental_cores = settings->bools.network_buildbot_show_experimental_cores; size_t selection = menu_navigation_get_selection(); @@ -10419,7 +10435,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, for (j = 0; j < search_terms->size; j++) { - const char *search_term = search_terms->elems[j].data; + const char *search_term = search_terms->terms[j]; if (!string_is_empty(search_term) && !string_is_empty(entry->display_name) && @@ -13212,27 +13228,25 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, } else { - const char *pending_selection = menu_driver_get_pending_selection(); - bool show_hidden_files = settings->bools.show_hidden_files; + const char *pending_selection = menu_driver_get_pending_selection(); + bool show_hidden_files = settings->bools.show_hidden_files; bool multimedia_builtin_mediaplayer_enable = settings->bools.multimedia_builtin_mediaplayer_enable; bool multimedia_builtin_imageviewer_enable = settings->bools.multimedia_builtin_imageviewer_enable; - bool menu_navigation_browser_filter_supported_extensions_enable = settings->bools.menu_navigation_browser_filter_supported_extensions_enable; + bool filter_supported_extensions_enable = settings->bools.menu_navigation_browser_filter_supported_extensions_enable; filebrowser_parse(info, type, show_hidden_files, multimedia_builtin_mediaplayer_enable, multimedia_builtin_imageviewer_enable, - menu_navigation_browser_filter_supported_extensions_enable + filter_supported_extensions_enable ); /* Apply pending selection */ if (!string_is_empty(pending_selection)) { - size_t selection_idx = 0; - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + size_t selection_idx = 0; - if (selection_buf && - file_list_search(selection_buf, pending_selection, &selection_idx)) + if (menu_entries_list_search(pending_selection, &selection_idx)) { menu_navigation_set_selection(selection_idx); menu_driver_navigation_set(true); diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 0fa5eb1243..d46a03f380 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -28,7 +28,6 @@ #include #include #include -#include #include "menu_defines.h" #include "menu_input.h" @@ -327,11 +326,6 @@ typedef struct { uint64_t state; - /* Holds a list of search terms that may be - * used to filter the currently displayed - * menu list */ - struct string_list *search_terms; - const menu_ctx_driver_t *driver_ctx; void *userdata; char *core_buf; @@ -507,12 +501,6 @@ void menu_explore_free(void); /* Returns true if search filter is enabled * for the specified menu list */ bool menu_driver_search_filter_enabled(const char *label, unsigned type); -bool menu_driver_search_push(const char *search_term); -bool menu_driver_search_pop(void); -struct string_list *menu_driver_search_get_terms(void); -/* Convenience function: Appends list of current - * search terms to specified string */ -void menu_driver_search_append_terms_string(char *s, size_t len); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) void menu_driver_set_last_shader_preset_path(const char *path); diff --git a/menu/menu_entries.h b/menu/menu_entries.h index 0b585fc6ed..4153222a3a 100644 --- a/menu/menu_entries.h +++ b/menu/menu_entries.h @@ -32,6 +32,9 @@ RETRO_BEGIN_DECLS #define MENU_SUBLABEL_MAX_LENGTH 1024 +#define MENU_SEARCH_FILTER_MAX_TERMS 8 +#define MENU_SEARCH_FILTER_MAX_LENGTH 64 + enum menu_entries_ctl_state { MENU_ENTRIES_CTL_NONE = 0, @@ -88,6 +91,12 @@ typedef struct menu_ctx_list enum menu_list_type type; } menu_ctx_list_t; +typedef struct menu_serch_terms +{ + size_t size; + char terms[MENU_SEARCH_FILTER_MAX_TERMS][MENU_SEARCH_FILTER_MAX_LENGTH]; +} menu_serch_terms_t; + typedef struct menu_file_list_cbs { rarch_setting_t *setting; @@ -121,6 +130,7 @@ typedef struct menu_file_list_cbs const char *label, char *s, size_t len, const char *path, char *path_buf, size_t path_buf_size); + menu_serch_terms_t search; enum msg_hash_enums enum_idx; char action_sublabel_cache[MENU_SUBLABEL_MAX_LENGTH]; char action_title_cache [512]; @@ -184,6 +194,17 @@ bool menu_entries_append_enum(file_list_t *list, bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data); +bool menu_entries_search_push(const char *search_term); +bool menu_entries_search_pop(void); +menu_serch_terms_t *menu_entries_search_get_terms(void); +/* Convenience function: Appends list of current + * search terms to specified string */ +void menu_entries_search_append_terms_string(char *s, size_t len); +/* Searches current menu list for specified 'needle' + * string. If string is found, returns true and sets + * 'idx' to the matching list entry index. */ +bool menu_entries_list_search(const char *needle, size_t *idx); + /* Menu entry interface - * * This provides an abstraction of the currently displayed diff --git a/retroarch.c b/retroarch.c index 8dbd384026..19102e1a96 100644 --- a/retroarch.c +++ b/retroarch.c @@ -3265,6 +3265,7 @@ void menu_entries_append( size_t entry_idx) { menu_ctx_list_t list_info; + size_t i; size_t idx; const char *menu_path = NULL; menu_file_list_cbs_t *cbs = NULL; @@ -3331,6 +3332,10 @@ void menu_entries_append( cbs->action_sublabel = NULL; cbs->action_get_value = NULL; + cbs->search.size = 0; + for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++) + cbs->search.terms[i][0] = '\0'; + list->list[idx].actiondata = cbs; menu_cbs_init(&p_rarch->menu_driver_state, @@ -3348,6 +3353,7 @@ bool menu_entries_append_enum( size_t entry_idx) { menu_ctx_list_t list_info; + size_t i; size_t idx; const char *menu_path = NULL; menu_file_list_cbs_t *cbs = NULL; @@ -3414,6 +3420,10 @@ bool menu_entries_append_enum( cbs->action_sublabel = NULL; cbs->action_get_value = NULL; + cbs->search.size = 0; + for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++) + cbs->search.terms[i][0] = '\0'; + list->list[idx].actiondata = cbs; if ( enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY @@ -3435,6 +3445,7 @@ void menu_entries_prepend(file_list_t *list, unsigned type, size_t directory_ptr, size_t entry_idx) { menu_ctx_list_t list_info; + size_t i; size_t idx = 0; const char *menu_path = NULL; menu_file_list_cbs_t *cbs = NULL; @@ -3498,6 +3509,10 @@ void menu_entries_prepend(file_list_t *list, cbs->action_sublabel = NULL; cbs->action_get_value = NULL; + cbs->search.size = 0; + for (i = 0; i < MENU_SEARCH_FILTER_MAX_TERMS; i++) + cbs->search.terms[i][0] = '\0'; + list->list[idx].actiondata = cbs; menu_cbs_init(&p_rarch->menu_driver_state, @@ -3712,6 +3727,219 @@ bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data) return true; } +static menu_serch_terms_t *menu_entries_search_get_terms_internal(void) +{ + struct rarch_state *p_rarch = &rarch_st; + struct menu_state *menu_st = &p_rarch->menu_driver_state; + file_list_t *list = MENU_LIST_GET(menu_st->entries.list, 0); + menu_file_list_cbs_t *cbs = NULL; + + if (!list || + (list->size < 1)) + return NULL; + + cbs = (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata; + + if (!cbs) + return NULL; + + return &cbs->search; +} + +bool menu_entries_search_push(const char *search_term) +{ + menu_serch_terms_t *search = menu_entries_search_get_terms_internal(); + char search_term_clipped[MENU_SEARCH_FILTER_MAX_LENGTH]; + size_t i; + + search_term_clipped[0] = '\0'; + + /* Sanity check + verify whether we have reached + * the maximum number of allowed search terms */ + if (!search || + string_is_empty(search_term) || + (search->size >= MENU_SEARCH_FILTER_MAX_TERMS)) + return false; + + /* Check whether search term already exists + * > Note that we clip the input search term + * to MENU_SEARCH_FILTER_MAX_LENGTH characters + * *before* comparing existing entries */ + strlcpy(search_term_clipped, search_term, + sizeof(search_term_clipped)); + + for (i = 0; i < search->size; i++) + { + if (string_is_equal(search_term_clipped, + search->terms[i])) + return false; + } + + /* Add search term */ + strlcpy(search->terms[search->size], search_term_clipped, + sizeof(search->terms[search->size])); + search->size++; + + return true; +} + +bool menu_entries_search_pop(void) +{ + menu_serch_terms_t *search = menu_entries_search_get_terms_internal(); + + /* Do nothing if list of search terms is empty */ + if (!search || + (search->size == 0)) + return false; + + /* Remove last item from the list */ + search->size--; + search->terms[search->size][0] = '\0'; + + return true; +} + +menu_serch_terms_t *menu_entries_search_get_terms(void) +{ + menu_serch_terms_t *search = menu_entries_search_get_terms_internal(); + + if (!search || + (search->size == 0)) + return NULL; + + return search; +} + +/* Convenience function: Appends list of current + * search terms to specified string */ +void menu_entries_search_append_terms_string(char *s, size_t len) +{ + menu_serch_terms_t *search = menu_entries_search_get_terms_internal(); + + if (search && + (search->size > 0) && + s) + { + size_t current_len = strlen_size(s, len); + size_t i; + + /* If buffer is already 'full', nothing + * further can be added */ + if (current_len >= len) + return; + + s += current_len; + len -= current_len; + + for (i = 0; i < search->size; i++) + { + strlcat(s, " > ", len); + strlcat(s, search->terms[i], len); + } + } +} + +/* Searches current menu list for specified 'needle' + * string. If string is found, returns true and sets + * 'idx' to the matching list entry index. */ +bool menu_entries_list_search(const char *needle, size_t *idx) +{ + struct rarch_state *p_rarch = &rarch_st; + struct menu_state *menu_st = &p_rarch->menu_driver_state; + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *list = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0); + bool match_found = false; + bool char_search = false; + char needle_char = 0; + size_t i; + + if (!list || + string_is_empty(needle) || + !idx) + goto end; + + /* Check if we are searching for a single + * Latin alphabet character */ + char_search = ((needle[1] == '\0') && (ISALPHA(needle[0]))); + if (char_search) + needle_char = TOLOWER(needle[0]); + + for (i = 0; i < list->size; i++) + { + const char *entry_label = NULL; + menu_entry_t entry; + + /* Note the we have to get the actual menu + * entry here, since we need the exact label + * that is currently displayed by the menu + * driver */ + MENU_ENTRY_INIT(entry); + entry.value_enabled = false; + entry.sublabel_enabled = false; + menu_entry_get(&entry, 0, i, NULL, true); + + /* When using the file browser, one or more + * 'utility' entries will be added to the top + * of the list (e.g. 'Parent Directory'). These + * have no bearing on the actual content of the + * list, and should be excluded from the search */ + if ((entry.type == FILE_TYPE_SCAN_DIRECTORY) || + (entry.type == FILE_TYPE_MANUAL_SCAN_DIRECTORY) || + (entry.type == FILE_TYPE_USE_DIRECTORY) || + (entry.type == FILE_TYPE_PARENT_DIRECTORY)) + continue; + + /* Get displayed entry label */ + if (!string_is_empty(entry.rich_label)) + entry_label = entry.rich_label; + else + entry_label = entry.path; + + if (string_is_empty(entry_label)) + continue; + + /* If we are performing a single character + * search, jump to the first entry whose + * first character matches */ + if (char_search) + { + if (needle_char == TOLOWER(entry_label[0])) + { + *idx = i; + match_found = true; + break; + } + } + /* Otherwise perform an exhaustive string + * comparison */ + else + { + const char *found_str = (const char *)strcasestr(entry_label, needle); + + /* Found a match with the first characters + * of the label -> best possible match, + * so quit immediately */ + if (found_str == entry_label) + { + *idx = i; + match_found = true; + break; + } + /* Found a mid-string match; this is a valid + * result, but keep searching for the best + * possible match */ + else if (found_str) + { + *idx = i; + match_found = true; + } + } + } + +end: + return match_found; +} + static void menu_display_common_image_upload( const menu_ctx_driver_t *menu_driver_ctx, void *menu_userdata, @@ -4408,21 +4636,10 @@ int menu_driver_deferred_push_content_list(file_list_t *list) struct rarch_state *p_rarch = &rarch_st; settings_t *settings = p_rarch->configuration_settings; struct menu_state *menu_st = &p_rarch->menu_driver_state; - menu_handle_t *menu_data = p_rarch->menu_driver_data; menu_list_t *menu_list = menu_st->entries.list; file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, (unsigned)0); - /* Must clear any existing menu search terms - * when switching 'tabs', since doing so - * bypasses standard backwards navigation - * (i.e. 'cancel' actions would normally - * pop the search stack - this will not - * happen if we jump to a new list directly) */ - if (menu_data->search_terms) - string_list_free(menu_data->search_terms); - menu_data->search_terms = NULL; - - menu_st->selection_ptr = 0; + menu_st->selection_ptr = 0; if (!menu_driver_displaylist_push( p_rarch, @@ -4755,131 +4972,17 @@ bool menu_driver_search_filter_enabled(const char *label, unsigned type) string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MUSIC_LIST)) || string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_LIST)) || - /* > Check for core updater */ - string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST)); + /* > Core updater */ + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST)) || + /* > File browser (Load Content) */ + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES)) || + /* > Shader presets/passes */ + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET)) || + string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PASS)); return filter_enabled; } -bool menu_driver_search_push(const char *search_term) -{ - struct rarch_state *p_rarch = &rarch_st; - menu_handle_t *menu = p_rarch->menu_driver_data; - union string_list_elem_attr attr; - - if (!menu || string_is_empty(search_term)) - return false; - - /* Initialise list, if required */ - if (!menu->search_terms) - { - menu->search_terms = string_list_new(); - - if (!menu->search_terms) - return false; - } - - /* Check whether search term already exists */ - if (string_list_find_elem(menu->search_terms, search_term)) - return false; - - /* Add search term */ - attr.i = 0; - - if (!string_list_append(menu->search_terms, - search_term, attr)) - return false; - - return true; -} - -bool menu_driver_search_pop(void) -{ - struct rarch_state *p_rarch = &rarch_st; - menu_handle_t *menu = p_rarch->menu_driver_data; - union string_list_elem_attr attr = {0}; - size_t element_index; - - if (!menu || !menu->search_terms) - return false; - - /* If we have a 'broken' list, free it - * (this cannot actually happen, but if - * we didn't free the list in this case - * then menu navigation could get 'stuck') */ - if ((menu->search_terms->size < 1) || - !menu->search_terms->elems) - goto free_list; - - /* Get index of last element in the list */ - element_index = menu->search_terms->size - 1; - - /* If this is the only element, free the - * entire list */ - if (element_index == 0) - goto free_list; - - /* Otherwise, 'reset' the element... */ - if (menu->search_terms->elems[element_index].data) - { - free(menu->search_terms->elems[element_index].data); - menu->search_terms->elems[element_index].data = NULL; - } - - if (menu->search_terms->elems[element_index].userdata) - { - free(menu->search_terms->elems[element_index].userdata); - menu->search_terms->elems[element_index].userdata = NULL; - } - - menu->search_terms->elems[element_index].attr = attr; - - /* ...and decrement the list size */ - menu->search_terms->size--; - - return true; - -free_list: - string_list_free(menu->search_terms); - menu->search_terms = NULL; - return true; -} - -struct string_list *menu_driver_search_get_terms(void) -{ - struct rarch_state *p_rarch = &rarch_st; - menu_handle_t *menu = p_rarch->menu_driver_data; - - if (!menu) - return NULL; - - return menu->search_terms; -} - -/* Convenience function: Appends list of current - * search terms to specified string */ -void menu_driver_search_append_terms_string(char *s, size_t len) -{ - struct rarch_state *p_rarch = &rarch_st; - menu_handle_t *menu = p_rarch->menu_driver_data; - - if (menu && - menu->search_terms && - (menu->search_terms->size > 0) && - s) - { - char search_str[512]; - - search_str[0] = '\0'; - - string_list_join_concat(search_str, sizeof(search_str), - menu->search_terms, " > "); - - strlcat(s, " > ", len); - strlcat(s, search_str, len); - } -} - #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) static void menu_driver_set_last_shader_path_int( const char *shader_path, @@ -5263,10 +5366,6 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) free(p_rarch->menu_driver_data->core_buf); p_rarch->menu_driver_data->core_buf = NULL; - if (menu_data->search_terms) - string_list_free(menu_data->search_terms); - menu_data->search_terms = NULL; - menu_st->entries_need_refresh = false; menu_st->entries_nonblocking_refresh = false; menu_st->entries.begin = 0; @@ -10015,8 +10114,6 @@ static void osk_update_last_codepoint( } } - - #ifdef HAVE_MENU static void menu_input_search_cb(void *userdata, const char *str) { @@ -10034,15 +10131,19 @@ static void menu_input_search_cb(void *userdata, const char *str) file_list_get_last(MENU_LIST_GET(menu_st->entries.list, 0), NULL, &label, &type, NULL); - if (menu_driver_search_filter_enabled(label, type)) + /* Do not apply search filter if string + * consists of a single Latin alphabet + * character */ + if (((str[1] != '\0') || (!ISALPHA(str[0]))) && + menu_driver_search_filter_enabled(label, type)) { /* Add search term */ - if (menu_driver_search_push(str)) + if (menu_entries_search_push(str)) { bool refresh = false; /* Reset navigation pointer */ - menu_st->selection_ptr = 0; + menu_st->selection_ptr = 0; menu_driver_navigation_set(false); /* Refresh menu */ @@ -10054,17 +10155,11 @@ static void menu_input_search_cb(void *userdata, const char *str) * first matching entry */ else { - size_t idx = 0; - struct menu_state *menu_st = &p_rarch->menu_driver_state; - menu_list_t *menu_list = menu_st->entries.list; - file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, (unsigned)0) : NULL; + size_t idx = 0; - if (!selection_buf) - goto end; - - if (file_list_search(selection_buf, str, &idx)) + if (menu_entries_list_search(str, &idx)) { - menu_st->selection_ptr = idx; + menu_st->selection_ptr = idx; menu_driver_navigation_set(true); } }