From 9d615905407ba12311a396629578363c56bb5c5a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 16 Aug 2019 15:40:45 +0200 Subject: [PATCH] Merge menu_entries.c into menu_driver.c --- Makefile.common | 1 - griffin/griffin.c | 1 - menu/menu_driver.c | 1302 ++++++++++++++++++++++++++++++++++++++++++ menu/menu_entries.c | 1327 ------------------------------------------- 4 files changed, 1302 insertions(+), 1329 deletions(-) delete mode 100644 menu/menu_entries.c diff --git a/Makefile.common b/Makefile.common index 5c86cdb8cc..415b1376ec 100644 --- a/Makefile.common +++ b/Makefile.common @@ -801,7 +801,6 @@ endif ifeq ($(HAVE_MENU_COMMON), 1) OBJ += menu/menu_driver.o \ menu/menu_content.o \ - menu/menu_entries.o \ menu/menu_setting.o \ menu/widgets/menu_filebrowser.o \ menu/widgets/menu_dialog.o \ diff --git a/griffin/griffin.c b/griffin/griffin.c index a2d7d02679..12958209c7 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1230,7 +1230,6 @@ MENU #ifdef HAVE_MENU #include "../menu/menu_driver.c" -#include "../menu/menu_entries.c" #include "../menu/menu_setting.c" #include "../menu/menu_cbs.c" #include "../menu/menu_content.c" diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 4e8816c373..fbfcda5600 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -18,10 +18,13 @@ #include #include #include + #include +#include #include #include #include +#include #include #include #include @@ -56,6 +59,7 @@ #include "../dynamic.h" #include "../driver.h" #include "../retroarch.h" +#include "../version.h" #include "../defaults.h" #include "../frontend/frontend.h" #include "../list_special.h" @@ -216,11 +220,1309 @@ static retro_time_t menu_driver_datetime_last_time_us = 0; * representation string */ static char menu_datetime_cache[255] = {0}; +/* Flagged when menu entries need to be refreshed */ +static bool menu_entries_need_refresh = false; +static bool menu_entries_nonblocking_refresh = false; +static size_t menu_entries_begin = 0; +static rarch_setting_t *menu_entries_list_settings = NULL; +static menu_list_t *menu_entries_list = NULL; + +struct menu_list +{ + size_t menu_stack_size; + size_t selection_buf_size; + file_list_t **menu_stack; + file_list_t **selection_buf; +}; + +#define menu_entries_need_refresh() ((!menu_entries_nonblocking_refresh) && menu_entries_need_refresh) + menu_handle_t *menu_driver_get_ptr(void) { return menu_driver_data; } +/* This file provides an abstraction of the currently displayed + * menu. + * + * It is organized into an event-based system where the UI companion + * calls this functions and RetroArch responds by changing the global + * state (including arranging for these functions to return different + * values). + * + * Its only interaction back to the UI is to arrange for + * notify_list_loaded on the UI companion. + */ + +enum menu_entry_type menu_entry_get_type(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = NULL; + rarch_setting_t *setting = NULL; + + /* FIXME/TODO - XXX Really a special kind of ST_ACTION, + * but this should be changed */ + if (menu_setting_ctl(MENU_SETTING_CTL_IS_OF_PATH_TYPE, (void*)setting)) + return MENU_ENTRY_PATH; + + cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + setting = cbs ? cbs->setting : NULL; + + if (setting) + { + switch (setting_get_type(setting)) + { + case ST_BOOL: + return MENU_ENTRY_BOOL; + case ST_BIND: + return MENU_ENTRY_BIND; + case ST_INT: + return MENU_ENTRY_INT; + case ST_UINT: + return MENU_ENTRY_UINT; + case ST_SIZE: + return MENU_ENTRY_SIZE; + case ST_FLOAT: + return MENU_ENTRY_FLOAT; + case ST_PATH: + return MENU_ENTRY_PATH; + case ST_DIR: + return MENU_ENTRY_DIR; + case ST_STRING_OPTIONS: + return MENU_ENTRY_ENUM; + case ST_STRING: + return MENU_ENTRY_STRING; + case ST_HEX: + return MENU_ENTRY_HEX; + + default: + break; + } + } + + return MENU_ENTRY_ACTION; +} + +void menu_entry_init(menu_entry_t *entry) +{ + entry->path[0] = '\0'; + entry->label[0] = '\0'; + entry->sublabel[0] = '\0'; + entry->rich_label[0] = '\0'; + entry->value[0] = '\0'; + entry->password_value[0] = '\0'; + entry->enum_idx = MSG_UNKNOWN; + entry->entry_idx = 0; + entry->idx = 0; + entry->type = 0; + entry->spacing = 0; + entry->path_enabled = true; + entry->label_enabled = true; + entry->rich_label_enabled = true; + entry->value_enabled = true; + entry->sublabel_enabled = true; +} + +void menu_entry_get_path(menu_entry_t *entry, const char **path) +{ + if (!entry || !path) + return; + + *path = entry->path; +} + +void menu_entry_get_rich_label(menu_entry_t *entry, const char **rich_label) +{ + if (!entry || !rich_label) + return; + + if (!string_is_empty(entry->rich_label)) + *rich_label = entry->rich_label; + else + *rich_label = entry->path; +} + +void menu_entry_get_sublabel(menu_entry_t *entry, const char **sublabel) +{ + if (!entry || !sublabel) + return; + + *sublabel = entry->sublabel; +} + +void menu_entry_get_label(menu_entry_t *entry, const char **label) +{ + if (!entry || !label) + return; + + *label = entry->label; +} + +unsigned menu_entry_get_spacing(menu_entry_t *entry) +{ + if (entry) + return entry->spacing; + return 0; +} + +unsigned menu_entry_get_type_new(menu_entry_t *entry) +{ + if (!entry) + return 0; + return entry->type; +} + +uint32_t menu_entry_get_bool_value(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + bool *ptr = setting ? (bool*)setting->value.target.boolean : NULL; + if (!ptr) + return 0; + return *ptr; +} + +struct string_list *menu_entry_enum_values(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + const char *values = setting->values; + + if (!values) + return NULL; + return string_split(values, "|"); +} + +void menu_entry_enum_set_value_with_string(uint32_t i, const char *s) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + setting_set_with_string_representation(setting, s); +} + +int32_t menu_entry_bind_index(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + + if (setting) + return setting->index - 1; + return 0; +} + +void menu_entry_bind_key_set(uint32_t i, int32_t value) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; + if (keybind) + keybind->key = (enum retro_key)value; +} + +void menu_entry_bind_joykey_set(uint32_t i, int32_t value) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; + if (keybind) + keybind->joykey = value; +} + +void menu_entry_bind_joyaxis_set(uint32_t i, int32_t value) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; + if (keybind) + keybind->joyaxis = value; +} + +void menu_entry_pathdir_selected(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + + if (menu_setting_ctl(MENU_SETTING_CTL_IS_OF_PATH_TYPE, (void*)setting)) + menu_setting_ctl(MENU_SETTING_CTL_ACTION_RIGHT, setting); +} + +bool menu_entry_pathdir_allow_empty(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + uint64_t flags = setting->flags; + + return flags & SD_FLAG_ALLOW_EMPTY; +} + +uint32_t menu_entry_pathdir_for_directory(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + uint64_t flags = setting->flags; + + return flags & SD_FLAG_PATH_DIR; +} + +void menu_entry_pathdir_extensions(uint32_t i, char *s, size_t len) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + const char *values = setting->values; + + if (!values) + return; + + strlcpy(s, values, len); +} + +void menu_entry_reset(uint32_t i) +{ + menu_entry_t entry; + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, i, NULL, true); + + menu_entry_action(&entry, i, MENU_ACTION_START); +} + +void menu_entry_get_value(menu_entry_t *entry, const char **value) +{ + if (!entry || !value) + return; + + if (menu_entry_is_password(entry)) + *value = entry->password_value; + else + *value = entry->value; +} + +void menu_entry_set_value(uint32_t i, const char *s) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + setting_set_with_string_representation(setting, s); +} + +bool menu_entry_is_password(menu_entry_t *entry) +{ + return entry->enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD; +} + +uint32_t menu_entry_num_has_range(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + uint64_t flags = setting->flags; + + return (flags & SD_FLAG_HAS_RANGE); +} + +float menu_entry_num_min(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + double min = setting->min; + return (float)min; +} + +float menu_entry_num_max(uint32_t i) +{ + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + rarch_setting_t *setting = cbs ? cbs->setting : NULL; + double max = setting->max; + return (float)max; +} + +void menu_entry_get(menu_entry_t *entry, size_t stack_idx, + size_t i, void *userdata, bool use_representation) +{ + char newpath[255]; + const char *path = NULL; + const char *entry_label = NULL; + menu_file_list_cbs_t *cbs = NULL; + file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(stack_idx); + file_list_t *list = (userdata) ? (file_list_t*)userdata : selection_buf; + bool path_enabled = entry->path_enabled; + + newpath[0] = '\0'; + + if (!list) + return; + + file_list_get_at_offset(list, i, &path, &entry_label, &entry->type, + &entry->entry_idx); + + cbs = (menu_file_list_cbs_t*)list->list[i].actiondata; + entry->idx = (unsigned)i; + + if (entry->label_enabled && !string_is_empty(entry_label)) + strlcpy(entry->label, entry_label, sizeof(entry->label)); + + if (cbs) + { + const char *label = NULL; + + entry->enum_idx = cbs->enum_idx; + entry->checked = cbs->checked; + + menu_entries_get_last_stack(NULL, &label, NULL, NULL, NULL); + + if (entry->rich_label_enabled && cbs->action_label) + { + cbs->action_label(list, + entry->type, (unsigned)i, + label, path, + entry->rich_label, + sizeof(entry->rich_label)); + + if (string_is_empty(entry->rich_label)) + path_enabled = true; + } + + if ((path_enabled || entry->value_enabled) && + cbs->action_get_value && + use_representation) + { + cbs->action_get_value(list, + &entry->spacing, entry->type, + (unsigned)i, label, + entry->value, + entry->value_enabled ? sizeof(entry->value) : 0, + path, + newpath, + path_enabled ? sizeof(newpath) : 0); + + if (!string_is_empty(entry->value)) + { + if (menu_entry_is_password(entry)) + { + size_t size, i; + size = strlcpy(entry->password_value, entry->value, + sizeof(entry->password_value)); + for (i = 0; i < size; i++) + entry->password_value[i] = '*'; + } + } + } + + if (entry->sublabel_enabled) + { + if (!string_is_empty(cbs->action_sublabel_cache)) + strlcpy(entry->sublabel, + cbs->action_sublabel_cache, sizeof(entry->sublabel)); + else if (cbs->action_sublabel) + { + char tmp[MENU_SUBLABEL_MAX_LENGTH]; + tmp[0] = '\0'; + + if (cbs->action_sublabel(list, + entry->type, (unsigned)i, + label, path, + tmp, + sizeof(tmp)) > 0) + { + /* If this function callback returns true, + * we know that the value won't change - so we + * can cache it instead. */ + strlcpy(cbs->action_sublabel_cache, + tmp, sizeof(cbs->action_sublabel_cache)); + } + + strlcpy(entry->sublabel, tmp, sizeof(entry->sublabel)); + } + } + } + + if (path_enabled) + { + if (!string_is_empty(path) && !use_representation) + strlcpy(newpath, path, sizeof(newpath)); + else if (cbs && cbs->setting && cbs->setting->enum_value_idx != MSG_UNKNOWN + && !cbs->setting->dont_use_enum_idx_representation) + strlcpy(newpath, + msg_hash_to_str(cbs->setting->enum_value_idx), + sizeof(newpath)); + + if (!string_is_empty(newpath)) + strlcpy(entry->path, newpath, sizeof(entry->path)); + } +} + +bool menu_entry_is_currently_selected(unsigned id) +{ + return (id == menu_navigation_get_selection()); +} + +/* Performs whatever actions are associated with menu entry 'i'. + * + * This is the most important function because it does all the work + * associated with clicking on things in the UI. + * + * This includes loading cores and updating the + * currently displayed menu. */ +int menu_entry_select(uint32_t i) +{ + menu_entry_t entry; + + menu_navigation_set_selection(i); + + menu_entry_init(&entry); + menu_entry_get(&entry, 0, i, NULL, false); + + return menu_entry_action(&entry, i, MENU_ACTION_SELECT); +} + +int menu_entry_action(menu_entry_t *entry, + unsigned i, enum menu_action action) +{ + int ret = 0; + file_list_t *selection_buf = + menu_entries_get_selection_buf_ptr(0); + menu_file_list_cbs_t *cbs = selection_buf ? + (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; + + switch (action) + { + case MENU_ACTION_UP: + if (cbs && cbs->action_up) + ret = cbs->action_up(entry->type, entry->label); + break; + case MENU_ACTION_DOWN: + if (cbs && cbs->action_down) + ret = cbs->action_down(entry->type, entry->label); + break; + case MENU_ACTION_SCROLL_UP: + menu_driver_ctl(MENU_NAVIGATION_CTL_DESCEND_ALPHABET, NULL); + break; + case MENU_ACTION_SCROLL_DOWN: + menu_driver_ctl(MENU_NAVIGATION_CTL_ASCEND_ALPHABET, NULL); + break; + case MENU_ACTION_CANCEL: + if (cbs && cbs->action_cancel) + ret = cbs->action_cancel(entry->path, + entry->label, entry->type, i); + break; + + case MENU_ACTION_OK: + if (cbs && cbs->action_ok) + ret = cbs->action_ok(entry->path, + entry->label, entry->type, i, entry->entry_idx); + break; + case MENU_ACTION_START: + if (cbs && cbs->action_start) + ret = cbs->action_start(entry->type, entry->label); + break; + case MENU_ACTION_LEFT: + if (cbs && cbs->action_left) + ret = cbs->action_left(entry->type, entry->label, false); + break; + case MENU_ACTION_RIGHT: + if (cbs && cbs->action_right) + ret = cbs->action_right(entry->type, entry->label, false); + break; + case MENU_ACTION_INFO: + if (cbs && cbs->action_info) + ret = cbs->action_info(entry->type, entry->label); + break; + case MENU_ACTION_SELECT: + if (cbs && cbs->action_select) + ret = cbs->action_select(entry->path, + entry->label, entry->type, i); + break; + case MENU_ACTION_SEARCH: + menu_input_dialog_start_search(); + break; + + case MENU_ACTION_SCAN: + if (cbs && cbs->action_scan) + ret = cbs->action_scan(entry->path, + entry->label, entry->type, i); + break; + + default: + break; + } + + cbs = selection_buf ? (menu_file_list_cbs_t*) + selection_buf->list[i].actiondata : NULL; + + if (menu_entries_need_refresh()) + { + if (cbs && cbs->action_refresh) + { + bool refresh = false; + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + + cbs->action_refresh(selection_buf, menu_stack); + menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh); + } + } + + return ret; +} + +static void menu_list_free_list(file_list_t *list) +{ + unsigned i; + + for (i = 0; i < list->size; i++) + { + menu_ctx_list_t list_info; + + list_info.list = list; + list_info.idx = i; + list_info.list_size = list->size; + + menu_driver_ctl(RARCH_MENU_CTL_LIST_FREE, &list_info); + } + + file_list_free(list); +} + +static void menu_list_free(menu_list_t *menu_list) +{ + if (!menu_list) + return; + + if (menu_list->menu_stack) + { + unsigned i; + + for (i = 0; i < menu_list->menu_stack_size; i++) + { + if (!menu_list->menu_stack[i]) + continue; + + menu_list_free_list(menu_list->menu_stack[i]); + menu_list->menu_stack[i] = NULL; + } + + free(menu_list->menu_stack); + } + + if (menu_list->selection_buf) + { + unsigned i; + + for (i = 0; i < menu_list->selection_buf_size; i++) + { + if (!menu_list->selection_buf[i]) + continue; + + menu_list_free_list(menu_list->selection_buf[i]); + menu_list->selection_buf[i] = NULL; + } + + free(menu_list->selection_buf); + } + + free(menu_list); +} + +static menu_list_t *menu_list_new(void) +{ + unsigned i; + menu_list_t *list = (menu_list_t*)malloc(sizeof(*list)); + + if (!list) + return NULL; + + list->menu_stack_size = 1; + list->selection_buf_size = 1; + list->selection_buf = NULL; + list->menu_stack = (file_list_t**) + calloc(list->menu_stack_size, sizeof(*list->menu_stack)); + + if (!list->menu_stack) + goto error; + + list->selection_buf = (file_list_t**) + calloc(list->selection_buf_size, sizeof(*list->selection_buf)); + + if (!list->selection_buf) + goto error; + + for (i = 0; i < list->menu_stack_size; i++) + list->menu_stack[i] = (file_list_t*) + calloc(1, sizeof(*list->menu_stack[i])); + + for (i = 0; i < list->selection_buf_size; i++) + list->selection_buf[i] = (file_list_t*) + calloc(1, sizeof(*list->selection_buf[i])); + + return list; + +error: + menu_list_free(list); + return NULL; +} + +#define menu_list_get(list, idx) ((list) ? ((list)->menu_stack[(idx)]) : NULL) + +#define menu_list_get_selection(list, idx) ((list) ? ((list)->selection_buf[(idx)]) : NULL) + +#define menu_list_get_stack_size(list, idx) ((list)->menu_stack[(idx)]->size) + +static int menu_list_flush_stack_type(const char *needle, const char *label, + unsigned type, unsigned final_type) +{ + return needle ? !string_is_equal(needle, label) : (type != final_type); +} + +static bool menu_list_pop_stack(menu_list_t *list, + size_t idx, size_t *directory_ptr, bool animate) +{ + menu_ctx_list_t list_info; + bool refresh = false; + file_list_t *menu_list = menu_list_get(list, (unsigned)idx); + + if (menu_list_get_stack_size(list, idx) <= 1) + return false; + + list_info.type = MENU_LIST_PLAIN; + list_info.action = 0; + + if (animate) + menu_driver_list_cache(&list_info); + + if (menu_list->size != 0) + { + menu_ctx_list_t list_info; + + list_info.list = menu_list; + list_info.idx = menu_list->size - 1; + list_info.list_size = menu_list->size - 1; + + menu_driver_ctl(RARCH_MENU_CTL_LIST_FREE, &list_info); + } + + file_list_pop(menu_list, directory_ptr); + menu_driver_list_set_selection(menu_list); + if (animate) + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + + return true; +} + +static void menu_list_flush_stack(menu_list_t *list, + size_t idx, const char *needle, unsigned final_type) +{ + bool refresh = false; + const char *path = NULL; + const char *label = NULL; + unsigned type = 0; + size_t entry_idx = 0; + file_list_t *menu_list = menu_list_get(list, (unsigned)idx); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + file_list_get_last(menu_list, + &path, &label, &type, &entry_idx); + + while (menu_list_flush_stack_type( + needle, label, type, final_type) != 0) + { + size_t new_selection_ptr = menu_navigation_get_selection(); + + if (!menu_list_pop_stack(list, idx, &new_selection_ptr, 1)) + break; + + menu_navigation_set_selection(new_selection_ptr); + + menu_list = menu_list_get(list, (unsigned)idx); + + file_list_get_last(menu_list, + &path, &label, &type, &entry_idx); + } +} + +void menu_entries_get_at_offset(const file_list_t *list, size_t idx, + const char **path, const char **label, unsigned *file_type, + size_t *entry_idx, const char **alt) +{ + file_list_get_at_offset(list, idx, path, label, file_type, entry_idx); + file_list_get_alt_at_offset(list, idx, alt); +} + +/** + * menu_entries_elem_get_first_char: + * @list : File list handle. + * @offset : Offset index of element. + * + * Gets the first character of an element in the + * file list. + * + * Returns: first character of element in file list. + **/ +static int menu_entries_elem_get_first_char( + file_list_t *list, unsigned offset) +{ + int ret = 0; + const char *path = NULL; + + file_list_get_at_offset(list, offset, NULL, NULL, NULL, NULL); + file_list_get_alt_at_offset(list, offset, &path); + + if (path) + ret = tolower((int)*path); + + /* "Normalize" non-alphabetical entries so they + * are lumped together for purposes of jumping. */ + if (ret < 'a') + return ('a' - 1); + else if (ret > 'z') + return ('z' + 1); + return ret; +} + +static void menu_entries_build_scroll_indices(file_list_t *list) +{ + int current; + bool current_is_dir = false; + unsigned type = 0; + size_t i, scroll_value = 0; + + menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR_SCROLL_INDICES, NULL); + menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &scroll_value); + + current = menu_entries_elem_get_first_char(list, 0); + + file_list_get_at_offset(list, 0, NULL, NULL, &type, NULL); + + if (type == FILE_TYPE_DIRECTORY) + current_is_dir = true; + + for (i = 1; i < list->size; i++) + { + int first = menu_entries_elem_get_first_char(list, (unsigned)i); + bool is_dir = false; + unsigned idx = (unsigned)i; + + file_list_get_at_offset(list, idx, NULL, NULL, &type, NULL); + + if (type == FILE_TYPE_DIRECTORY) + is_dir = true; + + if ((current_is_dir && !is_dir) || (first > current)) + menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &i); + + current = first; + current_is_dir = is_dir; + } + + scroll_value = list->size - 1; + menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &scroll_value); +} + +/** + * Before a refresh, we could have deleted a + * file on disk, causing selection_ptr to + * suddendly be out of range. + * + * Ensure it doesn't overflow. + **/ +static bool menu_entries_refresh(file_list_t *list) +{ + size_t list_size; + size_t selection = menu_navigation_get_selection(); + + if (list->size) + menu_entries_build_scroll_indices(list); + + list_size = menu_entries_get_size(); + + if ((selection >= list_size) && list_size) + { + size_t idx = list_size - 1; + menu_navigation_set_selection(idx); + menu_driver_navigation_set(true); + } + else if (!list_size) + { + bool pending_push = true; + menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push); + } + + return true; +} + +menu_file_list_cbs_t *menu_entries_get_last_stack_actiondata(void) +{ + if (menu_entries_list) + { + const file_list_t *list = menu_list_get(menu_entries_list, 0); + return (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata; + } + return NULL; +} + +/* Sets title to what the name of the current menu should be. */ +int menu_entries_get_title(char *s, size_t len) +{ + unsigned menu_type = 0; + const char *path = NULL; + const char *label = NULL; + const file_list_t *list = menu_entries_list ? + menu_list_get(menu_entries_list, 0) : NULL; + menu_file_list_cbs_t *cbs = list + ? (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata + : NULL; + + if (!cbs) + return -1; + + menu_entries_get_last_stack(&path, &label, &menu_type, NULL, NULL); + + if (cbs && cbs->action_get_title) + { + int ret; + if (!string_is_empty(cbs->action_title_cache)) + { + strlcpy(s, cbs->action_title_cache, len); + return 0; + } + ret = cbs->action_get_title(path, label, menu_type, s, len); + if (ret == 1) + strlcpy(cbs->action_title_cache, s, sizeof(cbs->action_title_cache)); + return ret; + } + return 0; +} + +/* Sets 's' to the name of the current core + * (shown at the top of the UI). */ +int menu_entries_get_core_title(char *s, size_t len) +{ + struct retro_system_info *system = runloop_get_libretro_system_info(); + const char *core_name = (system && !string_is_empty(system->library_name)) ? system->library_name : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE); + const char *core_version = (system && system->library_version) ? system->library_version : ""; +#if _MSC_VER == 1200 + const char *extra_version = " msvc6"; +#elif _MSC_VER == 1300 + const char *extra_version = " msvc2002"; +#elif _MSC_VER == 1310 + const char *extra_version = " msvc2003"; +#elif _MSC_VER == 1400 + const char *extra_version = " msvc2005"; +#elif _MSC_VER == 1500 + const char *extra_version = " msvc2008"; +#elif _MSC_VER == 1600 + const char *extra_version = " msvc2010"; +#elif _MSC_VER == 1700 + const char *extra_version = " msvc2012"; +#elif _MSC_VER == 1800 + const char *extra_version = " msvc2013"; +#elif _MSC_VER == 1900 + const char *extra_version = " msvc2015"; +#elif _MSC_VER >= 1910 && _MSC_VER < 2000 + const char *extra_version = " msvc2017"; +#else + const char *extra_version = ""; +#endif + + snprintf(s, len, "%s%s - %s %s", PACKAGE_VERSION, extra_version, + core_name, core_version); + + return 0; +} + +file_list_t *menu_entries_get_menu_stack_ptr(size_t idx) +{ + menu_list_t *menu_list = menu_entries_list; + if (!menu_list) + return NULL; + return menu_list_get(menu_list, (unsigned)idx); +} + +file_list_t *menu_entries_get_selection_buf_ptr(size_t idx) +{ + menu_list_t *menu_list = menu_entries_list; + if (!menu_list) + return NULL; + return menu_list_get_selection(menu_list, (unsigned)idx); +} + +bool menu_entries_init(void) +{ + if (!menu_entries_ctl(MENU_ENTRIES_CTL_LIST_INIT, NULL)) + goto error; + + if (!menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_INIT, NULL)) + goto error; + + return true; + +error: + menu_entries_ctl(MENU_ENTRIES_CTL_LIST_DEINIT, NULL); + menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_DEINIT, NULL); + + return false; +} + +void menu_entries_set_checked(file_list_t *list, size_t entry_idx, + bool checked) +{ + menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[entry_idx].actiondata; + + if (cbs) + cbs->checked = checked; +} + +void menu_entries_append(file_list_t *list, const char *path, const char *label, + unsigned type, size_t directory_ptr, size_t entry_idx) +{ + menu_ctx_list_t list_info; + size_t idx; + const char *menu_path = NULL; + menu_file_list_cbs_t *cbs = NULL; + if (!list || !label) + return; + + file_list_append(list, path, label, type, directory_ptr, entry_idx); + + menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); + + idx = list->size - 1; + + list_info.list = list; + list_info.path = path; + list_info.fullpath = NULL; + + if (!string_is_empty(menu_path)) + list_info.fullpath = strdup(menu_path); + + list_info.label = label; + list_info.idx = idx; + list_info.entry_type = type; + + menu_driver_list_insert(&list_info); + + if (list_info.fullpath) + free(list_info.fullpath); + + file_list_free_actiondata(list, idx); + cbs = (menu_file_list_cbs_t*) + calloc(1, sizeof(menu_file_list_cbs_t)); + + if (!cbs) + return; + + file_list_set_actiondata(list, idx, cbs); + + cbs->enum_idx = MSG_UNKNOWN; + cbs->setting = menu_setting_find(label); + + menu_cbs_init(list, cbs, path, label, type, idx); +} + +bool menu_entries_append_enum(file_list_t *list, const char *path, + const char *label, + enum msg_hash_enums enum_idx, + unsigned type, size_t directory_ptr, size_t entry_idx) +{ + menu_ctx_list_t list_info; + size_t idx; + const char *menu_path = NULL; + menu_file_list_cbs_t *cbs = NULL; + if (!list || !label) + return false; + + file_list_append(list, path, label, type, directory_ptr, entry_idx); + + menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); + + idx = list->size - 1; + + list_info.fullpath = NULL; + + if (!string_is_empty(menu_path)) + list_info.fullpath = strdup(menu_path); + list_info.list = list; + list_info.path = path; + list_info.label = label; + list_info.idx = idx; + list_info.entry_type = type; + + menu_driver_list_insert(&list_info); + + if (list_info.fullpath) + free(list_info.fullpath); + + file_list_free_actiondata(list, idx); + cbs = (menu_file_list_cbs_t*) + calloc(1, sizeof(menu_file_list_cbs_t)); + + file_list_set_actiondata(list, idx, cbs); + + cbs->enum_idx = enum_idx; + + if ( enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY + && enum_idx != MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY + && enum_idx != MENU_ENUM_LABEL_RDB_ENTRY) + cbs->setting = menu_setting_find_enum(enum_idx); + + menu_cbs_init(list, cbs, path, label, type, idx); + + return true; +} + +void menu_entries_prepend(file_list_t *list, const char *path, const char *label, + enum msg_hash_enums enum_idx, + unsigned type, size_t directory_ptr, size_t entry_idx) +{ + menu_ctx_list_t list_info; + size_t idx; + const char *menu_path = NULL; + menu_file_list_cbs_t *cbs = NULL; + if (!list || !label) + return; + + file_list_prepend(list, path, label, type, directory_ptr, entry_idx); + + menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); + + idx = 0; + + list_info.fullpath = NULL; + + if (!string_is_empty(menu_path)) + list_info.fullpath = strdup(menu_path); + list_info.list = list; + list_info.path = path; + list_info.label = label; + list_info.idx = idx; + list_info.entry_type = type; + + menu_driver_list_insert(&list_info); + + if (list_info.fullpath) + free(list_info.fullpath); + + file_list_free_actiondata(list, idx); + cbs = (menu_file_list_cbs_t*) + calloc(1, sizeof(menu_file_list_cbs_t)); + + if (!cbs) + return; + + file_list_set_actiondata(list, idx, cbs); + + cbs->enum_idx = enum_idx; + cbs->setting = menu_setting_find_enum(cbs->enum_idx); + + menu_cbs_init(list, cbs, path, label, type, idx); +} + +void menu_entries_get_last_stack(const char **path, const char **label, + unsigned *file_type, enum msg_hash_enums *enum_idx, size_t *entry_idx) +{ + file_list_t *list = NULL; + if (!menu_entries_list) + return; + + list = menu_list_get(menu_entries_list, 0); + + file_list_get_last(list, + path, label, file_type, entry_idx); + + if (enum_idx) + { + menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*) + list->list[list->size - 1].actiondata; + + if (cbs) + *enum_idx = cbs->enum_idx; + } +} + +void menu_entries_flush_stack(const char *needle, unsigned final_type) +{ + menu_list_t *menu_list = menu_entries_list; + if (menu_list) + menu_list_flush_stack(menu_list, 0, needle, final_type); +} + +void menu_entries_pop_stack(size_t *ptr, size_t idx, bool animate) +{ + menu_list_t *menu_list = menu_entries_list; + if (menu_list) + menu_list_pop_stack(menu_list, idx, ptr, animate); +} + +size_t menu_entries_get_stack_size(size_t idx) +{ + menu_list_t *menu_list = menu_entries_list; + if (!menu_list) + return 0; + return menu_list_get_stack_size(menu_list, idx); +} + +size_t menu_entries_get_size(void) +{ + const file_list_t *list = NULL; + menu_list_t *menu_list = menu_entries_list; + if (!menu_list) + return 0; + list = menu_list_get_selection(menu_list, 0); + return list->size; +} + +bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data) +{ + switch (state) + { + case MENU_ENTRIES_CTL_DEINIT: + menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_DEINIT, NULL); + menu_entries_ctl(MENU_ENTRIES_CTL_LIST_DEINIT, NULL); + + menu_entries_need_refresh = false; + menu_entries_nonblocking_refresh = false; + menu_entries_begin = 0; + break; + case MENU_ENTRIES_CTL_NEEDS_REFRESH: + if (menu_entries_nonblocking_refresh) + return false; + if (!menu_entries_need_refresh) + return false; + break; + case MENU_ENTRIES_CTL_LIST_GET: + { + menu_list_t **list = (menu_list_t**)data; + if (!list) + return false; + *list = menu_entries_list; + } + return true; + case MENU_ENTRIES_CTL_LIST_DEINIT: + if (menu_entries_list) + menu_list_free(menu_entries_list); + menu_entries_list = NULL; + break; + case MENU_ENTRIES_CTL_LIST_INIT: + if (!(menu_entries_list = (menu_list_t*)menu_list_new())) + return false; + break; + case MENU_ENTRIES_CTL_SETTINGS_GET: + { + rarch_setting_t **settings = (rarch_setting_t**)data; + if (!settings) + return false; + *settings = menu_entries_list_settings; + } + break; + case MENU_ENTRIES_CTL_SETTINGS_DEINIT: + menu_setting_free(menu_entries_list_settings); + if (menu_entries_list_settings) + free(menu_entries_list_settings); + menu_entries_list_settings = NULL; + break; + case MENU_ENTRIES_CTL_SETTINGS_INIT: + menu_setting_ctl(MENU_SETTING_CTL_NEW, &menu_entries_list_settings); + + if (!menu_entries_list_settings) + return false; + break; + case MENU_ENTRIES_CTL_SET_REFRESH: + { + bool *nonblocking = (bool*)data; + + if (*nonblocking) + menu_entries_nonblocking_refresh = true; + else + menu_entries_need_refresh = true; + } + break; + case MENU_ENTRIES_CTL_UNSET_REFRESH: + { + bool *nonblocking = (bool*)data; + + if (*nonblocking) + menu_entries_nonblocking_refresh = false; + else + menu_entries_need_refresh = false; + } + break; + case MENU_ENTRIES_CTL_SET_START: + { + size_t *idx = (size_t*)data; + if (idx) + menu_entries_begin = *idx; + } + case MENU_ENTRIES_CTL_START_GET: + { + size_t *idx = (size_t*)data; + if (!idx) + return 0; + + *idx = menu_entries_begin; + } + break; + case MENU_ENTRIES_CTL_REFRESH: + if (!data) + return false; + return menu_entries_refresh((file_list_t*)data); + case MENU_ENTRIES_CTL_CLEAR: + { + unsigned i; + file_list_t *list = (file_list_t*)data; + + if (!list) + return false; + + menu_driver_list_clear(list); + + for (i = 0; i < list->size; i++) + file_list_free_actiondata(list, i); + + file_list_clear(list); + } + break; + case MENU_ENTRIES_CTL_SHOW_BACK: + /* Returns true if a Back button should be shown + * (i.e. we are at least + * one level deep in the menu hierarchy). */ + if (!menu_entries_list) + return false; + return (menu_list_get_stack_size(menu_entries_list, 0) > 1); + case MENU_ENTRIES_CTL_NONE: + default: + break; + } + + return true; +} + /* Returns the OSK key at a given position */ int menu_display_osk_ptr_at_pos(void *data, int x, int y, unsigned width, unsigned height) diff --git a/menu/menu_entries.c b/menu/menu_entries.c deleted file mode 100644 index 3284ec4264..0000000000 --- a/menu/menu_entries.c +++ /dev/null @@ -1,1327 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2014-2015 - Jay McCarthy - * Copyright (C) 2011-2017 - Daniel De Matteis - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include - -#include -#include -#include -#include - -#include "menu_driver.h" -#include "menu_cbs.h" - -#include "../core.h" -#include "../retroarch.h" -#include "../version.h" - -/* Flagged when menu entries need to be refreshed */ -static bool menu_entries_need_refresh = false; -static bool menu_entries_nonblocking_refresh = false; -static size_t menu_entries_begin = 0; -static rarch_setting_t *menu_entries_list_settings = NULL; -static menu_list_t *menu_entries_list = NULL; - -struct menu_list -{ - size_t menu_stack_size; - size_t selection_buf_size; - file_list_t **menu_stack; - file_list_t **selection_buf; -}; - -#define menu_entries_need_refresh() ((!menu_entries_nonblocking_refresh) && menu_entries_need_refresh) - -/* This file provides an abstraction of the currently displayed - * menu. - * - * It is organized into an event-based system where the UI companion - * calls this functions and RetroArch responds by changing the global - * state (including arranging for these functions to return different - * values). - * - * Its only interaction back to the UI is to arrange for - * notify_list_loaded on the UI companion. - */ - -enum menu_entry_type menu_entry_get_type(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = NULL; - rarch_setting_t *setting = NULL; - - /* FIXME/TODO - XXX Really a special kind of ST_ACTION, - * but this should be changed */ - if (menu_setting_ctl(MENU_SETTING_CTL_IS_OF_PATH_TYPE, (void*)setting)) - return MENU_ENTRY_PATH; - - cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - setting = cbs ? cbs->setting : NULL; - - if (setting) - { - switch (setting_get_type(setting)) - { - case ST_BOOL: - return MENU_ENTRY_BOOL; - case ST_BIND: - return MENU_ENTRY_BIND; - case ST_INT: - return MENU_ENTRY_INT; - case ST_UINT: - return MENU_ENTRY_UINT; - case ST_SIZE: - return MENU_ENTRY_SIZE; - case ST_FLOAT: - return MENU_ENTRY_FLOAT; - case ST_PATH: - return MENU_ENTRY_PATH; - case ST_DIR: - return MENU_ENTRY_DIR; - case ST_STRING_OPTIONS: - return MENU_ENTRY_ENUM; - case ST_STRING: - return MENU_ENTRY_STRING; - case ST_HEX: - return MENU_ENTRY_HEX; - - default: - break; - } - } - - return MENU_ENTRY_ACTION; -} - -void menu_entry_init(menu_entry_t *entry) -{ - entry->path[0] = '\0'; - entry->label[0] = '\0'; - entry->sublabel[0] = '\0'; - entry->rich_label[0] = '\0'; - entry->value[0] = '\0'; - entry->password_value[0] = '\0'; - entry->enum_idx = MSG_UNKNOWN; - entry->entry_idx = 0; - entry->idx = 0; - entry->type = 0; - entry->spacing = 0; - entry->path_enabled = true; - entry->label_enabled = true; - entry->rich_label_enabled = true; - entry->value_enabled = true; - entry->sublabel_enabled = true; -} - -void menu_entry_get_path(menu_entry_t *entry, const char **path) -{ - if (!entry || !path) - return; - - *path = entry->path; -} - -void menu_entry_get_rich_label(menu_entry_t *entry, const char **rich_label) -{ - if (!entry || !rich_label) - return; - - if (!string_is_empty(entry->rich_label)) - *rich_label = entry->rich_label; - else - *rich_label = entry->path; -} - -void menu_entry_get_sublabel(menu_entry_t *entry, const char **sublabel) -{ - if (!entry || !sublabel) - return; - - *sublabel = entry->sublabel; -} - -void menu_entry_get_label(menu_entry_t *entry, const char **label) -{ - if (!entry || !label) - return; - - *label = entry->label; -} - -unsigned menu_entry_get_spacing(menu_entry_t *entry) -{ - if (entry) - return entry->spacing; - return 0; -} - -unsigned menu_entry_get_type_new(menu_entry_t *entry) -{ - if (!entry) - return 0; - return entry->type; -} - -uint32_t menu_entry_get_bool_value(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - bool *ptr = setting ? (bool*)setting->value.target.boolean : NULL; - if (!ptr) - return 0; - return *ptr; -} - -struct string_list *menu_entry_enum_values(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - const char *values = setting->values; - - if (!values) - return NULL; - return string_split(values, "|"); -} - -void menu_entry_enum_set_value_with_string(uint32_t i, const char *s) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - setting_set_with_string_representation(setting, s); -} - -int32_t menu_entry_bind_index(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - - if (setting) - return setting->index - 1; - return 0; -} - -void menu_entry_bind_key_set(uint32_t i, int32_t value) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; - if (keybind) - keybind->key = (enum retro_key)value; -} - -void menu_entry_bind_joykey_set(uint32_t i, int32_t value) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; - if (keybind) - keybind->joykey = value; -} - -void menu_entry_bind_joyaxis_set(uint32_t i, int32_t value) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - struct retro_keybind *keybind = setting ? (struct retro_keybind*)setting->value.target.keybind : NULL; - if (keybind) - keybind->joyaxis = value; -} - -void menu_entry_pathdir_selected(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - - if (menu_setting_ctl(MENU_SETTING_CTL_IS_OF_PATH_TYPE, (void*)setting)) - menu_setting_ctl(MENU_SETTING_CTL_ACTION_RIGHT, setting); -} - -bool menu_entry_pathdir_allow_empty(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - uint64_t flags = setting->flags; - - return flags & SD_FLAG_ALLOW_EMPTY; -} - -uint32_t menu_entry_pathdir_for_directory(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - uint64_t flags = setting->flags; - - return flags & SD_FLAG_PATH_DIR; -} - -void menu_entry_pathdir_extensions(uint32_t i, char *s, size_t len) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - const char *values = setting->values; - - if (!values) - return; - - strlcpy(s, values, len); -} - -void menu_entry_reset(uint32_t i) -{ - menu_entry_t entry; - - menu_entry_init(&entry); - menu_entry_get(&entry, 0, i, NULL, true); - - menu_entry_action(&entry, i, MENU_ACTION_START); -} - -void menu_entry_get_value(menu_entry_t *entry, const char **value) -{ - if (!entry || !value) - return; - - if (menu_entry_is_password(entry)) - *value = entry->password_value; - else - *value = entry->value; -} - -void menu_entry_set_value(uint32_t i, const char *s) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - setting_set_with_string_representation(setting, s); -} - -bool menu_entry_is_password(menu_entry_t *entry) -{ - return entry->enum_idx == MENU_ENUM_LABEL_CHEEVOS_PASSWORD; -} - -uint32_t menu_entry_num_has_range(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - uint64_t flags = setting->flags; - - return (flags & SD_FLAG_HAS_RANGE); -} - -float menu_entry_num_min(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - double min = setting->min; - return (float)min; -} - -float menu_entry_num_max(uint32_t i) -{ - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - rarch_setting_t *setting = cbs ? cbs->setting : NULL; - double max = setting->max; - return (float)max; -} - -void menu_entry_get(menu_entry_t *entry, size_t stack_idx, - size_t i, void *userdata, bool use_representation) -{ - char newpath[255]; - const char *path = NULL; - const char *entry_label = NULL; - menu_file_list_cbs_t *cbs = NULL; - file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(stack_idx); - file_list_t *list = (userdata) ? (file_list_t*)userdata : selection_buf; - bool path_enabled = entry->path_enabled; - - newpath[0] = '\0'; - - if (!list) - return; - - file_list_get_at_offset(list, i, &path, &entry_label, &entry->type, - &entry->entry_idx); - - cbs = (menu_file_list_cbs_t*)list->list[i].actiondata; - entry->idx = (unsigned)i; - - if (entry->label_enabled && !string_is_empty(entry_label)) - strlcpy(entry->label, entry_label, sizeof(entry->label)); - - if (cbs) - { - const char *label = NULL; - - entry->enum_idx = cbs->enum_idx; - entry->checked = cbs->checked; - - menu_entries_get_last_stack(NULL, &label, NULL, NULL, NULL); - - if (entry->rich_label_enabled && cbs->action_label) - { - cbs->action_label(list, - entry->type, (unsigned)i, - label, path, - entry->rich_label, - sizeof(entry->rich_label)); - - if (string_is_empty(entry->rich_label)) - path_enabled = true; - } - - if ((path_enabled || entry->value_enabled) && - cbs->action_get_value && - use_representation) - { - cbs->action_get_value(list, - &entry->spacing, entry->type, - (unsigned)i, label, - entry->value, - entry->value_enabled ? sizeof(entry->value) : 0, - path, - newpath, - path_enabled ? sizeof(newpath) : 0); - - if (!string_is_empty(entry->value)) - { - if (menu_entry_is_password(entry)) - { - size_t size, i; - size = strlcpy(entry->password_value, entry->value, - sizeof(entry->password_value)); - for (i = 0; i < size; i++) - entry->password_value[i] = '*'; - } - } - } - - if (entry->sublabel_enabled) - { - if (!string_is_empty(cbs->action_sublabel_cache)) - strlcpy(entry->sublabel, - cbs->action_sublabel_cache, sizeof(entry->sublabel)); - else if (cbs->action_sublabel) - { - char tmp[MENU_SUBLABEL_MAX_LENGTH]; - tmp[0] = '\0'; - - if (cbs->action_sublabel(list, - entry->type, (unsigned)i, - label, path, - tmp, - sizeof(tmp)) > 0) - { - /* If this function callback returns true, - * we know that the value won't change - so we - * can cache it instead. */ - strlcpy(cbs->action_sublabel_cache, - tmp, sizeof(cbs->action_sublabel_cache)); - } - - strlcpy(entry->sublabel, tmp, sizeof(entry->sublabel)); - } - } - } - - if (path_enabled) - { - if (!string_is_empty(path) && !use_representation) - strlcpy(newpath, path, sizeof(newpath)); - else if (cbs && cbs->setting && cbs->setting->enum_value_idx != MSG_UNKNOWN - && !cbs->setting->dont_use_enum_idx_representation) - strlcpy(newpath, - msg_hash_to_str(cbs->setting->enum_value_idx), - sizeof(newpath)); - - if (!string_is_empty(newpath)) - strlcpy(entry->path, newpath, sizeof(entry->path)); - } -} - -bool menu_entry_is_currently_selected(unsigned id) -{ - return (id == menu_navigation_get_selection()); -} - -/* Performs whatever actions are associated with menu entry 'i'. - * - * This is the most important function because it does all the work - * associated with clicking on things in the UI. - * - * This includes loading cores and updating the - * currently displayed menu. */ -int menu_entry_select(uint32_t i) -{ - menu_entry_t entry; - - menu_navigation_set_selection(i); - - menu_entry_init(&entry); - menu_entry_get(&entry, 0, i, NULL, false); - - return menu_entry_action(&entry, i, MENU_ACTION_SELECT); -} - -int menu_entry_action(menu_entry_t *entry, - unsigned i, enum menu_action action) -{ - int ret = 0; - file_list_t *selection_buf = - menu_entries_get_selection_buf_ptr(0); - menu_file_list_cbs_t *cbs = selection_buf ? - (menu_file_list_cbs_t*)selection_buf->list[i].actiondata : NULL; - - switch (action) - { - case MENU_ACTION_UP: - if (cbs && cbs->action_up) - ret = cbs->action_up(entry->type, entry->label); - break; - case MENU_ACTION_DOWN: - if (cbs && cbs->action_down) - ret = cbs->action_down(entry->type, entry->label); - break; - case MENU_ACTION_SCROLL_UP: - menu_driver_ctl(MENU_NAVIGATION_CTL_DESCEND_ALPHABET, NULL); - break; - case MENU_ACTION_SCROLL_DOWN: - menu_driver_ctl(MENU_NAVIGATION_CTL_ASCEND_ALPHABET, NULL); - break; - case MENU_ACTION_CANCEL: - if (cbs && cbs->action_cancel) - ret = cbs->action_cancel(entry->path, - entry->label, entry->type, i); - break; - - case MENU_ACTION_OK: - if (cbs && cbs->action_ok) - ret = cbs->action_ok(entry->path, - entry->label, entry->type, i, entry->entry_idx); - break; - case MENU_ACTION_START: - if (cbs && cbs->action_start) - ret = cbs->action_start(entry->type, entry->label); - break; - case MENU_ACTION_LEFT: - if (cbs && cbs->action_left) - ret = cbs->action_left(entry->type, entry->label, false); - break; - case MENU_ACTION_RIGHT: - if (cbs && cbs->action_right) - ret = cbs->action_right(entry->type, entry->label, false); - break; - case MENU_ACTION_INFO: - if (cbs && cbs->action_info) - ret = cbs->action_info(entry->type, entry->label); - break; - case MENU_ACTION_SELECT: - if (cbs && cbs->action_select) - ret = cbs->action_select(entry->path, - entry->label, entry->type, i); - break; - case MENU_ACTION_SEARCH: - menu_input_dialog_start_search(); - break; - - case MENU_ACTION_SCAN: - if (cbs && cbs->action_scan) - ret = cbs->action_scan(entry->path, - entry->label, entry->type, i); - break; - - default: - break; - } - - cbs = selection_buf ? (menu_file_list_cbs_t*) - selection_buf->list[i].actiondata : NULL; - - if (menu_entries_need_refresh()) - { - if (cbs && cbs->action_refresh) - { - bool refresh = false; - file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); - - cbs->action_refresh(selection_buf, menu_stack); - menu_entries_ctl(MENU_ENTRIES_CTL_UNSET_REFRESH, &refresh); - } - } - - return ret; -} - -static void menu_list_free_list(file_list_t *list) -{ - unsigned i; - - for (i = 0; i < list->size; i++) - { - menu_ctx_list_t list_info; - - list_info.list = list; - list_info.idx = i; - list_info.list_size = list->size; - - menu_driver_ctl(RARCH_MENU_CTL_LIST_FREE, &list_info); - } - - file_list_free(list); -} - -static void menu_list_free(menu_list_t *menu_list) -{ - if (!menu_list) - return; - - if (menu_list->menu_stack) - { - unsigned i; - - for (i = 0; i < menu_list->menu_stack_size; i++) - { - if (!menu_list->menu_stack[i]) - continue; - - menu_list_free_list(menu_list->menu_stack[i]); - menu_list->menu_stack[i] = NULL; - } - - free(menu_list->menu_stack); - } - - if (menu_list->selection_buf) - { - unsigned i; - - for (i = 0; i < menu_list->selection_buf_size; i++) - { - if (!menu_list->selection_buf[i]) - continue; - - menu_list_free_list(menu_list->selection_buf[i]); - menu_list->selection_buf[i] = NULL; - } - - free(menu_list->selection_buf); - } - - free(menu_list); -} - -static menu_list_t *menu_list_new(void) -{ - unsigned i; - menu_list_t *list = (menu_list_t*)malloc(sizeof(*list)); - - if (!list) - return NULL; - - list->menu_stack_size = 1; - list->selection_buf_size = 1; - list->selection_buf = NULL; - list->menu_stack = (file_list_t**) - calloc(list->menu_stack_size, sizeof(*list->menu_stack)); - - if (!list->menu_stack) - goto error; - - list->selection_buf = (file_list_t**) - calloc(list->selection_buf_size, sizeof(*list->selection_buf)); - - if (!list->selection_buf) - goto error; - - for (i = 0; i < list->menu_stack_size; i++) - list->menu_stack[i] = (file_list_t*) - calloc(1, sizeof(*list->menu_stack[i])); - - for (i = 0; i < list->selection_buf_size; i++) - list->selection_buf[i] = (file_list_t*) - calloc(1, sizeof(*list->selection_buf[i])); - - return list; - -error: - menu_list_free(list); - return NULL; -} - -#define menu_list_get(list, idx) ((list) ? ((list)->menu_stack[(idx)]) : NULL) - -#define menu_list_get_selection(list, idx) ((list) ? ((list)->selection_buf[(idx)]) : NULL) - -#define menu_list_get_stack_size(list, idx) ((list)->menu_stack[(idx)]->size) - -static int menu_list_flush_stack_type(const char *needle, const char *label, - unsigned type, unsigned final_type) -{ - return needle ? !string_is_equal(needle, label) : (type != final_type); -} - -static bool menu_list_pop_stack(menu_list_t *list, - size_t idx, size_t *directory_ptr, bool animate) -{ - menu_ctx_list_t list_info; - bool refresh = false; - file_list_t *menu_list = menu_list_get(list, (unsigned)idx); - - if (menu_list_get_stack_size(list, idx) <= 1) - return false; - - list_info.type = MENU_LIST_PLAIN; - list_info.action = 0; - - if (animate) - menu_driver_list_cache(&list_info); - - if (menu_list->size != 0) - { - menu_ctx_list_t list_info; - - list_info.list = menu_list; - list_info.idx = menu_list->size - 1; - list_info.list_size = menu_list->size - 1; - - menu_driver_ctl(RARCH_MENU_CTL_LIST_FREE, &list_info); - } - - file_list_pop(menu_list, directory_ptr); - menu_driver_list_set_selection(menu_list); - if (animate) - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); - - return true; -} - -static void menu_list_flush_stack(menu_list_t *list, - size_t idx, const char *needle, unsigned final_type) -{ - bool refresh = false; - const char *path = NULL; - const char *label = NULL; - unsigned type = 0; - size_t entry_idx = 0; - file_list_t *menu_list = menu_list_get(list, (unsigned)idx); - - menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); - file_list_get_last(menu_list, - &path, &label, &type, &entry_idx); - - while (menu_list_flush_stack_type( - needle, label, type, final_type) != 0) - { - size_t new_selection_ptr = menu_navigation_get_selection(); - - if (!menu_list_pop_stack(list, idx, &new_selection_ptr, 1)) - break; - - menu_navigation_set_selection(new_selection_ptr); - - menu_list = menu_list_get(list, (unsigned)idx); - - file_list_get_last(menu_list, - &path, &label, &type, &entry_idx); - } -} - -void menu_entries_get_at_offset(const file_list_t *list, size_t idx, - const char **path, const char **label, unsigned *file_type, - size_t *entry_idx, const char **alt) -{ - file_list_get_at_offset(list, idx, path, label, file_type, entry_idx); - file_list_get_alt_at_offset(list, idx, alt); -} - -/** - * menu_entries_elem_get_first_char: - * @list : File list handle. - * @offset : Offset index of element. - * - * Gets the first character of an element in the - * file list. - * - * Returns: first character of element in file list. - **/ -static int menu_entries_elem_get_first_char( - file_list_t *list, unsigned offset) -{ - int ret = 0; - const char *path = NULL; - - file_list_get_at_offset(list, offset, NULL, NULL, NULL, NULL); - file_list_get_alt_at_offset(list, offset, &path); - - if (path) - ret = tolower((int)*path); - - /* "Normalize" non-alphabetical entries so they - * are lumped together for purposes of jumping. */ - if (ret < 'a') - return ('a' - 1); - else if (ret > 'z') - return ('z' + 1); - return ret; -} - -static void menu_entries_build_scroll_indices(file_list_t *list) -{ - int current; - bool current_is_dir = false; - unsigned type = 0; - size_t i, scroll_value = 0; - - menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR_SCROLL_INDICES, NULL); - menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &scroll_value); - - current = menu_entries_elem_get_first_char(list, 0); - - file_list_get_at_offset(list, 0, NULL, NULL, &type, NULL); - - if (type == FILE_TYPE_DIRECTORY) - current_is_dir = true; - - for (i = 1; i < list->size; i++) - { - int first = menu_entries_elem_get_first_char(list, (unsigned)i); - bool is_dir = false; - unsigned idx = (unsigned)i; - - file_list_get_at_offset(list, idx, NULL, NULL, &type, NULL); - - if (type == FILE_TYPE_DIRECTORY) - is_dir = true; - - if ((current_is_dir && !is_dir) || (first > current)) - menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &i); - - current = first; - current_is_dir = is_dir; - } - - scroll_value = list->size - 1; - menu_driver_ctl(MENU_NAVIGATION_CTL_ADD_SCROLL_INDEX, &scroll_value); -} - -/** - * Before a refresh, we could have deleted a - * file on disk, causing selection_ptr to - * suddendly be out of range. - * - * Ensure it doesn't overflow. - **/ -static bool menu_entries_refresh(file_list_t *list) -{ - size_t list_size; - size_t selection = menu_navigation_get_selection(); - - if (list->size) - menu_entries_build_scroll_indices(list); - - list_size = menu_entries_get_size(); - - if ((selection >= list_size) && list_size) - { - size_t idx = list_size - 1; - menu_navigation_set_selection(idx); - menu_driver_navigation_set(true); - } - else if (!list_size) - { - bool pending_push = true; - menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push); - } - - return true; -} - -menu_file_list_cbs_t *menu_entries_get_last_stack_actiondata(void) -{ - if (menu_entries_list) - { - const file_list_t *list = menu_list_get(menu_entries_list, 0); - return (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata; - } - return NULL; -} - -/* Sets title to what the name of the current menu should be. */ -int menu_entries_get_title(char *s, size_t len) -{ - unsigned menu_type = 0; - const char *path = NULL; - const char *label = NULL; - const file_list_t *list = menu_entries_list ? - menu_list_get(menu_entries_list, 0) : NULL; - menu_file_list_cbs_t *cbs = list - ? (menu_file_list_cbs_t*)list->list[list->size - 1].actiondata - : NULL; - - if (!cbs) - return -1; - - menu_entries_get_last_stack(&path, &label, &menu_type, NULL, NULL); - - if (cbs && cbs->action_get_title) - { - int ret; - if (!string_is_empty(cbs->action_title_cache)) - { - strlcpy(s, cbs->action_title_cache, len); - return 0; - } - ret = cbs->action_get_title(path, label, menu_type, s, len); - if (ret == 1) - strlcpy(cbs->action_title_cache, s, sizeof(cbs->action_title_cache)); - return ret; - } - return 0; -} - -/* Sets 's' to the name of the current core - * (shown at the top of the UI). */ -int menu_entries_get_core_title(char *s, size_t len) -{ - struct retro_system_info *system = runloop_get_libretro_system_info(); - const char *core_name = (system && !string_is_empty(system->library_name)) ? system->library_name : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE); - const char *core_version = (system && system->library_version) ? system->library_version : ""; -#if _MSC_VER == 1200 - const char *extra_version = " msvc6"; -#elif _MSC_VER == 1300 - const char *extra_version = " msvc2002"; -#elif _MSC_VER == 1310 - const char *extra_version = " msvc2003"; -#elif _MSC_VER == 1400 - const char *extra_version = " msvc2005"; -#elif _MSC_VER == 1500 - const char *extra_version = " msvc2008"; -#elif _MSC_VER == 1600 - const char *extra_version = " msvc2010"; -#elif _MSC_VER == 1700 - const char *extra_version = " msvc2012"; -#elif _MSC_VER == 1800 - const char *extra_version = " msvc2013"; -#elif _MSC_VER == 1900 - const char *extra_version = " msvc2015"; -#elif _MSC_VER >= 1910 && _MSC_VER < 2000 - const char *extra_version = " msvc2017"; -#else - const char *extra_version = ""; -#endif - - snprintf(s, len, "%s%s - %s %s", PACKAGE_VERSION, extra_version, - core_name, core_version); - - return 0; -} - -file_list_t *menu_entries_get_menu_stack_ptr(size_t idx) -{ - menu_list_t *menu_list = menu_entries_list; - if (!menu_list) - return NULL; - return menu_list_get(menu_list, (unsigned)idx); -} - -file_list_t *menu_entries_get_selection_buf_ptr(size_t idx) -{ - menu_list_t *menu_list = menu_entries_list; - if (!menu_list) - return NULL; - return menu_list_get_selection(menu_list, (unsigned)idx); -} - -bool menu_entries_init(void) -{ - if (!menu_entries_ctl(MENU_ENTRIES_CTL_LIST_INIT, NULL)) - goto error; - - if (!menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_INIT, NULL)) - goto error; - - return true; - -error: - menu_entries_ctl(MENU_ENTRIES_CTL_LIST_DEINIT, NULL); - menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_DEINIT, NULL); - - return false; -} - -void menu_entries_set_checked(file_list_t *list, size_t entry_idx, - bool checked) -{ - menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[entry_idx].actiondata; - - if (cbs) - cbs->checked = checked; -} - -void menu_entries_append(file_list_t *list, const char *path, const char *label, - unsigned type, size_t directory_ptr, size_t entry_idx) -{ - menu_ctx_list_t list_info; - size_t idx; - const char *menu_path = NULL; - menu_file_list_cbs_t *cbs = NULL; - if (!list || !label) - return; - - file_list_append(list, path, label, type, directory_ptr, entry_idx); - - menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); - - idx = list->size - 1; - - list_info.list = list; - list_info.path = path; - list_info.fullpath = NULL; - - if (!string_is_empty(menu_path)) - list_info.fullpath = strdup(menu_path); - - list_info.label = label; - list_info.idx = idx; - list_info.entry_type = type; - - menu_driver_list_insert(&list_info); - - if (list_info.fullpath) - free(list_info.fullpath); - - file_list_free_actiondata(list, idx); - cbs = (menu_file_list_cbs_t*) - calloc(1, sizeof(menu_file_list_cbs_t)); - - if (!cbs) - return; - - file_list_set_actiondata(list, idx, cbs); - - cbs->enum_idx = MSG_UNKNOWN; - cbs->setting = menu_setting_find(label); - - menu_cbs_init(list, cbs, path, label, type, idx); -} - -bool menu_entries_append_enum(file_list_t *list, const char *path, - const char *label, - enum msg_hash_enums enum_idx, - unsigned type, size_t directory_ptr, size_t entry_idx) -{ - menu_ctx_list_t list_info; - size_t idx; - const char *menu_path = NULL; - menu_file_list_cbs_t *cbs = NULL; - if (!list || !label) - return false; - - file_list_append(list, path, label, type, directory_ptr, entry_idx); - - menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); - - idx = list->size - 1; - - list_info.fullpath = NULL; - - if (!string_is_empty(menu_path)) - list_info.fullpath = strdup(menu_path); - list_info.list = list; - list_info.path = path; - list_info.label = label; - list_info.idx = idx; - list_info.entry_type = type; - - menu_driver_list_insert(&list_info); - - if (list_info.fullpath) - free(list_info.fullpath); - - file_list_free_actiondata(list, idx); - cbs = (menu_file_list_cbs_t*) - calloc(1, sizeof(menu_file_list_cbs_t)); - - file_list_set_actiondata(list, idx, cbs); - - cbs->enum_idx = enum_idx; - - if ( enum_idx != MENU_ENUM_LABEL_PLAYLIST_ENTRY - && enum_idx != MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY - && enum_idx != MENU_ENUM_LABEL_RDB_ENTRY) - cbs->setting = menu_setting_find_enum(enum_idx); - - menu_cbs_init(list, cbs, path, label, type, idx); - - return true; -} - -void menu_entries_prepend(file_list_t *list, const char *path, const char *label, - enum msg_hash_enums enum_idx, - unsigned type, size_t directory_ptr, size_t entry_idx) -{ - menu_ctx_list_t list_info; - size_t idx; - const char *menu_path = NULL; - menu_file_list_cbs_t *cbs = NULL; - if (!list || !label) - return; - - file_list_prepend(list, path, label, type, directory_ptr, entry_idx); - - menu_entries_get_last_stack(&menu_path, NULL, NULL, NULL, NULL); - - idx = 0; - - list_info.fullpath = NULL; - - if (!string_is_empty(menu_path)) - list_info.fullpath = strdup(menu_path); - list_info.list = list; - list_info.path = path; - list_info.label = label; - list_info.idx = idx; - list_info.entry_type = type; - - menu_driver_list_insert(&list_info); - - if (list_info.fullpath) - free(list_info.fullpath); - - file_list_free_actiondata(list, idx); - cbs = (menu_file_list_cbs_t*) - calloc(1, sizeof(menu_file_list_cbs_t)); - - if (!cbs) - return; - - file_list_set_actiondata(list, idx, cbs); - - cbs->enum_idx = enum_idx; - cbs->setting = menu_setting_find_enum(cbs->enum_idx); - - menu_cbs_init(list, cbs, path, label, type, idx); -} - -void menu_entries_get_last_stack(const char **path, const char **label, - unsigned *file_type, enum msg_hash_enums *enum_idx, size_t *entry_idx) -{ - file_list_t *list = NULL; - if (!menu_entries_list) - return; - - list = menu_list_get(menu_entries_list, 0); - - file_list_get_last(list, - path, label, file_type, entry_idx); - - if (enum_idx) - { - menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*) - list->list[list->size - 1].actiondata; - - if (cbs) - *enum_idx = cbs->enum_idx; - } -} - -void menu_entries_flush_stack(const char *needle, unsigned final_type) -{ - menu_list_t *menu_list = menu_entries_list; - if (menu_list) - menu_list_flush_stack(menu_list, 0, needle, final_type); -} - -void menu_entries_pop_stack(size_t *ptr, size_t idx, bool animate) -{ - menu_list_t *menu_list = menu_entries_list; - if (menu_list) - menu_list_pop_stack(menu_list, idx, ptr, animate); -} - -size_t menu_entries_get_stack_size(size_t idx) -{ - menu_list_t *menu_list = menu_entries_list; - if (!menu_list) - return 0; - return menu_list_get_stack_size(menu_list, idx); -} - -size_t menu_entries_get_size(void) -{ - const file_list_t *list = NULL; - menu_list_t *menu_list = menu_entries_list; - if (!menu_list) - return 0; - list = menu_list_get_selection(menu_list, 0); - return list->size; -} - -bool menu_entries_ctl(enum menu_entries_ctl_state state, void *data) -{ - switch (state) - { - case MENU_ENTRIES_CTL_DEINIT: - menu_entries_ctl(MENU_ENTRIES_CTL_SETTINGS_DEINIT, NULL); - menu_entries_ctl(MENU_ENTRIES_CTL_LIST_DEINIT, NULL); - - menu_entries_need_refresh = false; - menu_entries_nonblocking_refresh = false; - menu_entries_begin = 0; - break; - case MENU_ENTRIES_CTL_NEEDS_REFRESH: - if (menu_entries_nonblocking_refresh) - return false; - if (!menu_entries_need_refresh) - return false; - break; - case MENU_ENTRIES_CTL_LIST_GET: - { - menu_list_t **list = (menu_list_t**)data; - if (!list) - return false; - *list = menu_entries_list; - } - return true; - case MENU_ENTRIES_CTL_LIST_DEINIT: - if (menu_entries_list) - menu_list_free(menu_entries_list); - menu_entries_list = NULL; - break; - case MENU_ENTRIES_CTL_LIST_INIT: - if (!(menu_entries_list = (menu_list_t*)menu_list_new())) - return false; - break; - case MENU_ENTRIES_CTL_SETTINGS_GET: - { - rarch_setting_t **settings = (rarch_setting_t**)data; - if (!settings) - return false; - *settings = menu_entries_list_settings; - } - break; - case MENU_ENTRIES_CTL_SETTINGS_DEINIT: - menu_setting_free(menu_entries_list_settings); - if (menu_entries_list_settings) - free(menu_entries_list_settings); - menu_entries_list_settings = NULL; - break; - case MENU_ENTRIES_CTL_SETTINGS_INIT: - menu_setting_ctl(MENU_SETTING_CTL_NEW, &menu_entries_list_settings); - - if (!menu_entries_list_settings) - return false; - break; - case MENU_ENTRIES_CTL_SET_REFRESH: - { - bool *nonblocking = (bool*)data; - - if (*nonblocking) - menu_entries_nonblocking_refresh = true; - else - menu_entries_need_refresh = true; - } - break; - case MENU_ENTRIES_CTL_UNSET_REFRESH: - { - bool *nonblocking = (bool*)data; - - if (*nonblocking) - menu_entries_nonblocking_refresh = false; - else - menu_entries_need_refresh = false; - } - break; - case MENU_ENTRIES_CTL_SET_START: - { - size_t *idx = (size_t*)data; - if (idx) - menu_entries_begin = *idx; - } - case MENU_ENTRIES_CTL_START_GET: - { - size_t *idx = (size_t*)data; - if (!idx) - return 0; - - *idx = menu_entries_begin; - } - break; - case MENU_ENTRIES_CTL_REFRESH: - if (!data) - return false; - return menu_entries_refresh((file_list_t*)data); - case MENU_ENTRIES_CTL_CLEAR: - { - unsigned i; - file_list_t *list = (file_list_t*)data; - - if (!list) - return false; - - menu_driver_list_clear(list); - - for (i = 0; i < list->size; i++) - file_list_free_actiondata(list, i); - - file_list_clear(list); - } - break; - case MENU_ENTRIES_CTL_SHOW_BACK: - /* Returns true if a Back button should be shown - * (i.e. we are at least - * one level deep in the menu hierarchy). */ - if (!menu_entries_list) - return false; - return (menu_list_get_stack_size(menu_entries_list, 0) > 1); - case MENU_ENTRIES_CTL_NONE: - default: - break; - } - - return true; -}