Enhanced 'Load Content' file browser search functionality

This commit is contained in:
jdgleaver 2021-04-20 13:40:33 +01:00
parent 799fcdb5e0
commit b193fd0ba9
8 changed files with 404 additions and 260 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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);

View File

@ -28,7 +28,6 @@
#include <retro_common_api.h>
#include <formats/image.h>
#include <queues/task_queue.h>
#include <lists/string_list.h>
#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);

View File

@ -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

View File

@ -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);
}
}