/* RetroArch - A frontend for libretro. * Copyright (C) 2011-2015 - 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 "menu.h" #include "menu_entries_cbs.h" #include "menu_action.h" #include "menu_input.h" #include "menu_entries.h" #include "menu_shader.h" #include "menu_navigation.h" #include "../file_ext.h" #include "../file_extract.h" #include "../file_ops.h" #include "../config.def.h" #include "../cheats.h" #include "../retroarch.h" #include "../performance.h" #ifdef HAVE_NETWORKING #include "../net_http.h" #endif #ifdef HAVE_LIBRETRODB #include "../database_info.h" #endif #include "menu_database.h" #include "../input/input_autodetect.h" #include "../input/input_remapping.h" #ifdef GEKKO enum { GX_RESOLUTIONS_512_192 = 0, GX_RESOLUTIONS_598_200, GX_RESOLUTIONS_640_200, GX_RESOLUTIONS_384_224, GX_RESOLUTIONS_448_224, GX_RESOLUTIONS_480_224, GX_RESOLUTIONS_512_224, GX_RESOLUTIONS_576_224, GX_RESOLUTIONS_608_224, GX_RESOLUTIONS_640_224, GX_RESOLUTIONS_340_232, GX_RESOLUTIONS_512_232, GX_RESOLUTIONS_512_236, GX_RESOLUTIONS_336_240, GX_RESOLUTIONS_352_240, GX_RESOLUTIONS_384_240, GX_RESOLUTIONS_512_240, GX_RESOLUTIONS_530_240, GX_RESOLUTIONS_608_240, GX_RESOLUTIONS_640_240, GX_RESOLUTIONS_512_384, GX_RESOLUTIONS_598_400, GX_RESOLUTIONS_640_400, GX_RESOLUTIONS_384_448, GX_RESOLUTIONS_448_448, GX_RESOLUTIONS_480_448, GX_RESOLUTIONS_512_448, GX_RESOLUTIONS_576_448, GX_RESOLUTIONS_608_448, GX_RESOLUTIONS_640_448, GX_RESOLUTIONS_340_464, GX_RESOLUTIONS_512_464, GX_RESOLUTIONS_512_472, GX_RESOLUTIONS_352_480, GX_RESOLUTIONS_384_480, GX_RESOLUTIONS_512_480, GX_RESOLUTIONS_530_480, GX_RESOLUTIONS_608_480, GX_RESOLUTIONS_640_480, GX_RESOLUTIONS_LAST, }; unsigned menu_gx_resolutions[GX_RESOLUTIONS_LAST][2] = { { 512, 192 }, { 598, 200 }, { 640, 200 }, { 384, 224 }, { 448, 224 }, { 480, 224 }, { 512, 224 }, { 576, 224 }, { 608, 224 }, { 640, 224 }, { 340, 232 }, { 512, 232 }, { 512, 236 }, { 336, 240 }, { 352, 240 }, { 384, 240 }, { 512, 240 }, { 530, 240 }, { 608, 240 }, { 640, 240 }, { 512, 384 }, { 598, 400 }, { 640, 400 }, { 384, 448 }, { 448, 448 }, { 480, 448 }, { 512, 448 }, { 576, 448 }, { 608, 448 }, { 640, 448 }, { 340, 464 }, { 512, 464 }, { 512, 472 }, { 352, 480 }, { 384, 480 }, { 512, 480 }, { 530, 480 }, { 608, 480 }, { 640, 480 }, }; unsigned menu_current_gx_resolution = GX_RESOLUTIONS_640_480; #endif static unsigned rdb_entry_start_game_selection_ptr; static int archive_open(menu_handle_t *menu) { char cat_path[PATH_MAX_LENGTH]; const char *menu_path = NULL; const char *menu_label = NULL; const char* path = NULL; unsigned int type = 0; menu_list_pop_stack(menu->menu_list); menu_list_get_last_stack(menu->menu_list, &menu_path, &menu_label, NULL); if (menu_list_get_size(menu->menu_list) == 0) return 0; menu_list_get_at_offset(menu->menu_list->selection_buf, menu->selection_ptr, &path, NULL, &type); fill_pathname_join(cat_path, menu_path, path, sizeof(cat_path)); menu_list_push_stack_refresh( menu->menu_list, cat_path, menu_label, type, menu->selection_ptr); return 0; } static void common_load_content(menu_handle_t *menu, bool persist) { rarch_main_command(persist ? RARCH_CMD_LOAD_CONTENT_PERSIST : RARCH_CMD_LOAD_CONTENT); menu_list_flush_stack(menu->menu_list, MENU_SETTINGS); menu->msg_force = true; } static int archive_load(menu_handle_t *menu) { int ret; const char *menu_path = NULL; const char *menu_label = NULL; const char* path = NULL; unsigned int type = 0; menu_list_pop_stack(menu->menu_list); menu_list_get_last_stack(menu->menu_list, &menu_path, &menu_label, NULL); if (menu_list_get_size(menu->menu_list) == 0) return 0; menu_list_get_at_offset(menu->menu_list->selection_buf, menu->selection_ptr, &path, NULL, &type); ret = rarch_defer_core(g_extern.core_info, menu_path, path, menu_label, menu->deferred_path, sizeof(menu->deferred_path)); switch (ret) { case -1: rarch_main_command(RARCH_CMD_LOAD_CORE); common_load_content(menu, false); break; case 0: menu_list_push_stack_refresh( menu->menu_list, g_settings.libretro_directory, "deferred_core_list", 0, menu->selection_ptr); break; } return 0; } static int load_or_open_zip_iterate(menu_handle_t *menu, unsigned action) { char msg[PATH_MAX_LENGTH]; snprintf(msg, sizeof(msg), "Opening compressed file\n" " \n" " - OK to open as Folder\n" " - Cancel/Back to Load \n"); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) { if (*msg && msg[0] != '\0') driver.menu_ctx->render_messagebox(msg); } switch (action) { case MENU_ACTION_OK: archive_open(menu); break; case MENU_ACTION_CANCEL: archive_load(menu); break; } return 0; } int menu_action_setting_set_current_string( rarch_setting_t *setting, const char *str) { strlcpy(setting->value.string, str, setting->size); return menu_action_generic_setting(setting); } static int action_ok_rdb_playlist_entry(const char *path, const char *label, unsigned type, size_t idx) { if (!driver.menu) return -1; rarch_playlist_load_content(driver.menu->db_playlist, rdb_entry_start_game_selection_ptr); return -1; } static int action_ok_playlist_entry(const char *path, const char *label, unsigned type, size_t idx) { if (!driver.menu) return -1; rarch_playlist_load_content(g_defaults.history, driver.menu->selection_ptr); menu_list_flush_stack(driver.menu->menu_list, MENU_SETTINGS); return -1; } static int action_ok_cheat_apply_changes(const char *path, const char *label, unsigned type, size_t idx) { cheat_manager_t *cheat = g_extern.cheat; if (!cheat) return -1; cheat_manager_apply_cheats(cheat); return 0; } /* FIXME: Ugly hack, need to be refactored badly. */ size_t hack_shader_pass = 0; static int action_ok_shader_pass_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; if (!driver.menu) return -1; (void)menu_path; #ifdef HAVE_SHADER_MANAGER menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(driver.menu->shader->pass[hack_shader_pass].source.path, menu_path, path, sizeof(driver.menu->shader->pass[hack_shader_pass].source.path)); /* This will reset any changed parameters. */ video_shader_resolve_parameters(NULL, driver.menu->shader); menu_list_flush_stack_by_needle(driver.menu->menu_list, "shader_options"); return 0; #else return -1; #endif } #ifdef HAVE_SHADER_MANAGER extern size_t hack_shader_pass; #endif static int action_ok_shader_pass(const char *path, const char *label, unsigned type, size_t idx) { hack_shader_pass = type - MENU_SETTINGS_SHADER_PASS_0; return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.video.shader_dir, label, type, idx); } static int action_ok_shader_parameters(const char *path, const char *label, unsigned type, size_t idx) { return menu_list_push_stack_refresh( driver.menu->menu_list, "", label, MENU_SETTING_ACTION, idx); } static int action_ok_push_generic_list(const char *path, const char *label, unsigned type, size_t idx) { if (path) strlcpy(driver.menu->deferred_path, path, sizeof(driver.menu->deferred_path)); return menu_list_push_stack_refresh( driver.menu->menu_list, "", label, type, idx); } static int action_ok_push_default(const char *path, const char *label, unsigned type, size_t idx) { return menu_list_push_stack_refresh( driver.menu->menu_list, label, label, type, idx); } static int action_ok_shader_preset(const char *path, const char *label, unsigned type, size_t idx) { return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.video.shader_dir, label, type, idx); } static int action_ok_push_content_list(const char *path, const char *label, unsigned type, size_t idx) { return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.menu_content_directory, label, MENU_FILE_DIRECTORY, idx); } static int action_ok_disk_image_append_list(const char *path, const char *label, unsigned type, size_t idx) { return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.menu_content_directory, label, type, idx); } static int action_ok_configurations_list(const char *path, const char *label, unsigned type, size_t idx) { const char *dir = g_settings.menu_config_directory; return menu_list_push_stack_refresh( driver.menu->menu_list, dir ? dir : label, label, type, idx); } static int action_ok_cheat_file(const char *path, const char *label, unsigned type, size_t idx) { if (!path_file_exists(g_settings.cheat_database)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Cheat Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.cheat_database, label, type, idx); } static int action_ok_audio_dsp_plugin(const char *path, const char *label, unsigned type, size_t idx) { if (!path_file_exists(path)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Audio Filter Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return 0; } static int action_ok_video_filter(const char *path, const char *label, unsigned type, size_t idx) { if (!path_file_exists(path)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Video Filter Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return 0; } static int action_ok_remap_file(const char *path, const char *label, unsigned type, size_t idx) { if (!path_file_exists(g_settings.input_remapping_directory)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Remapping Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.input_remapping_directory, label, type, idx); } static int action_ok_core_list(const char *path, const char *label, unsigned type, size_t idx) { if (!path_file_exists(g_settings.libretro_directory)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Core Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.libretro_directory, label, type, idx); } static int action_ok_remap_file_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; char remap_path[PATH_MAX_LENGTH]; if (!driver.menu) return -1; (void)remap_path; (void)menu_path; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(remap_path, menu_path, path, sizeof(remap_path)); input_remapping_load_file(remap_path); menu_list_flush_stack_by_needle(driver.menu->menu_list, "core_input_remapping_options"); return 0; } static int action_ok_cheat_file_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; char cheat_path[PATH_MAX_LENGTH]; if (!driver.menu) return -1; (void)cheat_path; (void)menu_path; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(cheat_path, menu_path, path, sizeof(cheat_path)); if (g_extern.cheat) cheat_manager_free(g_extern.cheat); g_extern.cheat = cheat_manager_load(cheat_path); if (!g_extern.cheat) return -1; menu_list_flush_stack_by_needle(driver.menu->menu_list, "core_cheat_options"); return 0; } static int action_ok_menu_wallpaper_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_label = NULL; const char *menu_path = NULL; rarch_setting_t *setting = NULL; char wallpaper_path[PATH_MAX_LENGTH]; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, &menu_label, NULL); setting = menu_action_find_setting(menu_label); if (!setting) return -1; fill_pathname_join(wallpaper_path, menu_path, path, sizeof(wallpaper_path)); if (!path_file_exists(wallpaper_path)) goto end; strlcpy(g_settings.menu.wallpaper, wallpaper_path, sizeof(g_settings.menu.wallpaper)); if (driver.menu_ctx && driver.menu_ctx->load_background) driver.menu_ctx->load_background(wallpaper_path); end: menu_list_pop_stack_by_needle(driver.menu->menu_list, setting->name); return 0; } static int action_ok_shader_preset_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; char shader_path[PATH_MAX_LENGTH]; if (!driver.menu) return -1; (void)shader_path; (void)menu_path; #ifdef HAVE_SHADER_MANAGER menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(shader_path, menu_path, path, sizeof(shader_path)); menu_shader_manager_set_preset(driver.menu->shader, video_shader_parse_type(shader_path, RARCH_SHADER_NONE), shader_path); menu_list_flush_stack_by_needle(driver.menu->menu_list, "shader_options"); return 0; #else return -1; #endif } static int action_ok_cheat(const char *path, const char *label, unsigned type, size_t idx) { menu_input_key_start_line(driver.menu, "Input Cheat", label, type, idx, menu_input_st_cheat_callback); return 0; } static int action_ok_shader_preset_save_as(const char *path, const char *label, unsigned type, size_t idx) { menu_input_key_start_line(driver.menu, "Preset Filename", label, type, idx, menu_input_st_string_callback); return 0; } static int action_ok_cheat_file_save_as(const char *path, const char *label, unsigned type, size_t idx) { menu_input_key_start_line(driver.menu, "Cheat Filename", label, type, idx, menu_input_st_string_callback); return 0; } static int action_ok_remap_file_save_as(const char *path, const char *label, unsigned type, size_t idx) { menu_input_key_start_line(driver.menu, "Remapping Filename", label, type, idx, menu_input_st_string_callback); return 0; } static int action_ok_path_use_directory(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_label = NULL; const char *menu_path = NULL; rarch_setting_t *setting = NULL; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, &menu_label, NULL); setting = menu_action_find_setting(menu_label); if (!setting) return -1; if (setting->type != ST_DIR) return -1; menu_action_setting_set_current_string(setting, menu_path); menu_list_pop_stack_by_needle(driver.menu->menu_list, setting->name); return 0; } static int action_ok_core_load_deferred(const char *path, const char *label, unsigned type, size_t idx) { if (!driver.menu) return -1; if (path) strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro)); strlcpy(g_extern.fullpath, driver.menu->deferred_path, sizeof(g_extern.fullpath)); common_load_content(driver.menu, false); return -1; } static int action_ok_database_manager_list_deferred(const char *path, const char *label, unsigned type, size_t idx) { return 0; } static int deferred_push_core_information(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; core_info_t *info = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; info = (core_info_t*)g_extern.core_info_current; menu_list_clear(list); if (info->data) { char tmp[PATH_MAX_LENGTH]; snprintf(tmp, sizeof(tmp), "Core name: %s", info->core_name ? info->core_name : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); snprintf(tmp, sizeof(tmp), "Core label: %s", info->display_name ? info->display_name : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); if (info->systemname) { snprintf(tmp, sizeof(tmp), "System name: %s", info->systemname); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->system_manufacturer) { snprintf(tmp, sizeof(tmp), "System manufacturer: %s", info->system_manufacturer); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->categories_list) { strlcpy(tmp, "Categories: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->categories_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->authors_list) { strlcpy(tmp, "Authors: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->authors_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->permissions_list) { strlcpy(tmp, "Permissions: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->permissions_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->licenses_list) { strlcpy(tmp, "License(s): ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->licenses_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->supported_extensions_list) { strlcpy(tmp, "Supported extensions: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->supported_extensions_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->firmware_count > 0) { core_info_list_update_missing_firmware( g_extern.core_info, info->path, g_settings.system_directory); menu_list_push(list, "Firmware: ", "", MENU_SETTINGS_CORE_INFO_NONE, 0); for (i = 0; i < info->firmware_count; i++) { if (info->firmware[i].desc) { snprintf(tmp, sizeof(tmp), " name: %s", info->firmware[i].desc ? info->firmware[i].desc : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); snprintf(tmp, sizeof(tmp), " status: %s, %s", info->firmware[i].missing ? "missing" : "present", info->firmware[i].optional ? "optional" : "required"); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } } } if (info->notes) { snprintf(tmp, sizeof(tmp), "Core notes: "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); for (i = 0; i < info->note_list->size; i++) { snprintf(tmp, sizeof(tmp), " %s", info->note_list->elems[i].data); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } } } else menu_list_push(list, "No information available.", "", MENU_SETTINGS_CORE_OPTION_NONE, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int create_string_list_rdb_entry_string(const char *desc, const char *label, const char *actual_string, const char *path, file_list_t *list) { char tmp[PATH_MAX_LENGTH]; union string_list_elem_attr attr; char *output_label = NULL; int str_len = 0; struct string_list *str_list = string_list_new(); if (!str_list) return -1; str_len += strlen(label) + 1; string_list_append(str_list, label, attr); str_len += strlen(actual_string) + 1; string_list_append(str_list, actual_string, attr); str_len += strlen(path) + 1; string_list_append(str_list, path, attr); output_label = (char*)calloc(str_len, sizeof(char)); if (!output_label) { string_list_free(str_list); return -1; } string_list_join_concat(output_label, str_len, str_list, "|"); snprintf(tmp, sizeof(tmp), "%s: %s", desc, actual_string); menu_list_push(list, tmp, output_label, 0, 0); if (output_label) free(output_label); string_list_free(str_list); str_list = NULL; return 0; } static uint32_t create_string_list_rdb_entry_int(const char *desc, const char *label, int actual_int, const char *path, file_list_t *list) { char tmp[PATH_MAX_LENGTH]; union string_list_elem_attr attr; char str[PATH_MAX_LENGTH]; char *output_label = NULL; int str_len = 0; struct string_list *str_list = string_list_new(); if (!str_list) return -1; str_len += strlen(label) + 1; string_list_append(str_list, label, attr); snprintf(str, sizeof(str), "%d", actual_int); str_len += strlen(str) + 1; string_list_append(str_list, str, attr); str_len += strlen(path) + 1; string_list_append(str_list, path, attr); output_label = (char*)calloc(str_len, sizeof(char)); if (!output_label) { string_list_free(str_list); return -1; } string_list_join_concat(output_label, str_len, str_list, "|"); snprintf(tmp, sizeof(tmp), "%s: %d", desc, actual_int); menu_list_push(list, tmp, output_label, 0, 0); if (output_label) free(output_label); string_list_free(str_list); str_list = NULL; return 0; } static int deferred_push_rdb_entry_detail(void *data, void *userdata, const char *path, const char *label, unsigned type) { #ifdef HAVE_LIBRETRODB content_playlist_t *playlist; char query[PATH_MAX_LENGTH]; char path_rdl[PATH_MAX_LENGTH], path_base[PATH_MAX_LENGTH]; unsigned i, j; int ret = 0; database_info_list_t *db_info = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; struct string_list *str_list = string_split(label, "|"); if (!str_list) return -1; if (!list || !menu_list) { ret = -1; goto done; } strlcpy(query, "{'name':\"", sizeof(query)); strlcat(query, str_list->elems[1].data, sizeof(query)); strlcat(query, "\"}", sizeof(query)); menu_list_clear(list); if (!(db_info = database_info_list_new(path, query))) { ret = -1; goto done; } strlcpy(path_base, path_basename(path), sizeof(path_base)); path_remove_extension(path_base); strlcat(path_base, ".rdl", sizeof(path_base)); fill_pathname_join(path_rdl, g_settings.content_database, path_base, sizeof(path_rdl)); menu_database_realloc(driver.menu, path_rdl, false); playlist = driver.menu->db_playlist; for (i = 0; i < db_info->count; i++) { char tmp[PATH_MAX_LENGTH]; database_info_t *db_info_entry = &db_info->list[i]; if (!db_info_entry) continue; if (db_info_entry->name) { snprintf(tmp, sizeof(tmp), "Name: %s", db_info_entry->name); menu_list_push(list, tmp, "rdb_entry_name", 0, 0); } if (db_info_entry->description) { snprintf(tmp, sizeof(tmp), "Description: %s", db_info_entry->description); menu_list_push(list, tmp, "rdb_entry_description", 0, 0); } if (db_info_entry->publisher) { if (create_string_list_rdb_entry_string("Publisher", "rdb_entry_publisher", db_info_entry->publisher, path, list) == -1) return -1; } if (db_info_entry->developer) { if (create_string_list_rdb_entry_string("Developer", "rdb_entry_developer", db_info_entry->developer, path, list) == -1) return -1; } if (db_info_entry->origin) { if (create_string_list_rdb_entry_string("Origin", "rdb_entry_origin", db_info_entry->origin, path, list) == -1) return -1; } if (db_info_entry->franchise) { if (create_string_list_rdb_entry_string("Franchise", "rdb_entry_franchise", db_info_entry->franchise, path, list) == -1) return -1; } if (db_info_entry->max_users) { if (create_string_list_rdb_entry_int("Max Users", "rdb_entry_max_users", db_info_entry->max_users, path, list) == -1) return -1; } if (db_info_entry->famitsu_magazine_rating) { if (create_string_list_rdb_entry_int("Famitsu Magazine Rating", "rdb_entry_famitsu_magazine_rating", db_info_entry->famitsu_magazine_rating, path, list) == -1) return -1; } if (db_info_entry->edge_magazine_rating) { if (create_string_list_rdb_entry_int("Edge Magazine Rating", "rdb_entry_edge_magazine_rating", db_info_entry->edge_magazine_rating, path, list) == -1) return -1; } if (db_info_entry->edge_magazine_issue) { if (create_string_list_rdb_entry_int("Edge Magazine Issue", "rdb_entry_edge_magazine_issue", db_info_entry->edge_magazine_issue, path, list) == -1) return -1; } if (db_info_entry->releasemonth) { if (create_string_list_rdb_entry_int("Releasedate Month", "rdb_entry_releasemonth", db_info_entry->releasemonth, path, list) == -1) return -1; } if (db_info_entry->releaseyear) { if (create_string_list_rdb_entry_int("Releasedate Year", "rdb_entry_releaseyear", db_info_entry->releaseyear, path, list) == -1) return -1; } if (db_info_entry->bbfc_rating) { if (create_string_list_rdb_entry_string("BBFC Rating", "rdb_entry_bbfc_rating", db_info_entry->bbfc_rating, path, list) == -1) return -1; } if (db_info_entry->esrb_rating) { if (create_string_list_rdb_entry_string("ESRB Rating", "rdb_entry_esrb_rating", db_info_entry->esrb_rating, path, list) == -1) return -1; } if (db_info_entry->elspa_rating) { if (create_string_list_rdb_entry_string("ELSPA Rating", "rdb_entry_elspa_rating", db_info_entry->elspa_rating, path, list) == -1) return -1; } if (db_info_entry->pegi_rating) { if (create_string_list_rdb_entry_string("PEGI Rating", "rdb_entry_pegi_rating", db_info_entry->pegi_rating, path, list) == -1) return -1; } if (db_info_entry->enhancement_hw) { if (create_string_list_rdb_entry_string("Enhancement Hardware", "rdb_entry_enhancement_hw", db_info_entry->enhancement_hw, path, list) == -1) return -1; } if (db_info_entry->cero_rating) { if (create_string_list_rdb_entry_string("CERO Rating", "rdb_entry_cero_rating", db_info_entry->cero_rating, path, list) == -1) return -1; } snprintf(tmp, sizeof(tmp), "Analog supported: %s", (db_info_entry->analog_supported == 1) ? "true" : (db_info_entry->analog_supported == -1) ? "N/A" : "false"); menu_list_push(list, tmp, "rdb_entry_analog", 0, 0); snprintf(tmp, sizeof(tmp), "Rumble supported: %s", (db_info_entry->rumble_supported == 1) ? "true" : (db_info_entry->rumble_supported == -1) ? "N/A" : "false"); menu_list_push(list, tmp, "rdb_entry_rumble", 0, 0); if (db_info_entry->crc32) { if (create_string_list_rdb_entry_string("CRC32 Checksum", "rdb_entry_crc32", db_info_entry->crc32, path, list) == -1) return -1; } if (db_info_entry->sha1) { if (create_string_list_rdb_entry_string("SHA1 Checksum", "rdb_entry_sha1", db_info_entry->sha1, path, list) == -1) return -1; } if (db_info_entry->md5) { if (create_string_list_rdb_entry_string("MD5 Checksum", "rdb_entry_md5", db_info_entry->md5, path, list) == -1) return -1; } if (playlist) { for (j = 0; j < playlist->size; j++) { char elem0[PATH_MAX_LENGTH], elem1[PATH_MAX_LENGTH]; bool match_found = false; struct string_list *tmp_str_list = string_split( playlist->entries[j].core_name, "|"); if (!tmp_str_list) continue; if (tmp_str_list->size > 0) strlcpy(elem0, tmp_str_list->elems[0].data, sizeof(elem0)); if (tmp_str_list->size > 1) strlcpy(elem1, tmp_str_list->elems[1].data, sizeof(elem1)); if (!strcmp(elem1, "crc")) { if (!strcmp(db_info_entry->crc32, elem0)) match_found = true; } else if (!strcmp(elem1, "sha1")) { if (!strcmp(db_info_entry->sha1, elem0)) match_found = true; } else if (!strcmp(elem1, "md5")) { if (!strcmp(db_info_entry->md5, elem0)) match_found = true; } string_list_free(tmp_str_list); if (!match_found) continue; rdb_entry_start_game_selection_ptr = j; menu_list_push(list, "Start Content", "rdb_entry_start_game", MENU_FILE_PLAYLIST_ENTRY, 0); } } } if (db_info->count < 1) menu_list_push(list, "No information available.", "", 0, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, str_list->elems[0].data, type); ret = 0; #endif done: #ifdef HAVE_LIBRETRODB string_list_free(str_list); #endif return ret; } static int action_ok_rdb_entry(const char *path, const char *label, unsigned type, size_t idx) { char tmp[PATH_MAX_LENGTH]; strlcpy(tmp, "deferred_rdb_entry_detail|", sizeof(tmp)); strlcat(tmp, path, sizeof(tmp)); return menu_list_push_stack_refresh( driver.menu->menu_list, label, tmp, 0, idx); } static int action_ok_cursor_manager_list_deferred(const char *path, const char *label, unsigned type, size_t idx) { return 0; } static int action_ok_core_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(g_settings.libretro, menu_path, path, sizeof(g_settings.libretro)); rarch_main_command(RARCH_CMD_LOAD_CORE); menu_list_flush_stack(driver.menu->menu_list, MENU_SETTINGS); #if defined(HAVE_DYNAMIC) /* No content needed for this core, load core immediately. */ if (driver.menu->load_no_content) { *g_extern.fullpath = '\0'; common_load_content(driver.menu, false); return -1; } return 0; /* Core selection on non-console just updates directory listing. * Will take effect on new content load. */ #elif defined(RARCH_CONSOLE) rarch_main_command(RARCH_CMD_RESTART_RETROARCH); return -1; #endif } static int action_ok_core_download(const char *path, const char *label, unsigned type, size_t idx) { return 0; } static int action_ok_compressed_archive_push(const char *path, const char *label, unsigned type, size_t idx) { if (!driver.menu) return -1; menu_list_push_stack( driver.menu->menu_list, path, "load_open_zip", 0, idx); return 0; } static int action_ok_directory_push(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; const char *menu_label = NULL; char cat_path[PATH_MAX_LENGTH]; if (!driver.menu) return -1; if (!path) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, &menu_label, NULL); fill_pathname_join(cat_path, menu_path, path, sizeof(cat_path)); return menu_list_push_stack_refresh(driver.menu->menu_list, cat_path, menu_label, type, idx); } static int action_ok_database_manager_list(const char *path, const char *label, unsigned type, size_t idx) { char rdb_path[PATH_MAX_LENGTH]; if (!path) return -1; if (!label) return -1; fill_pathname_join(rdb_path, g_settings.content_database, path, sizeof(rdb_path)); if (!path_file_exists(rdb_path)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Database Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return menu_list_push_stack_refresh( driver.menu->menu_list, rdb_path, "deferred_database_manager_list", 0, idx); } static int action_ok_cursor_manager_list(const char *path, const char *label, unsigned type, size_t idx) { char cursor_path[PATH_MAX_LENGTH]; fill_pathname_join(cursor_path, g_settings.cursor_directory, path, sizeof(cursor_path)); if (!path_file_exists(cursor_path)) { msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, "Cursor Directory doesn't exist or cannot be accessed.\n", 1, 180); return -1; } return menu_list_push_stack_refresh( driver.menu->menu_list, cursor_path, "deferred_cursor_manager_list", 0, idx); } static int action_ok_config_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; char config[PATH_MAX_LENGTH]; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(config, menu_path, path, sizeof(config)); menu_list_flush_stack(driver.menu->menu_list, MENU_SETTINGS); driver.menu->msg_force = true; if (rarch_replace_config(config)) { menu_navigation_clear(driver.menu, false); return -1; } return 0; } static int action_ok_disk_image_append(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; char image[PATH_MAX_LENGTH]; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); fill_pathname_join(image, menu_path, path, sizeof(image)); rarch_disk_control_append_image(image); rarch_main_command(RARCH_CMD_RESUME); menu_list_flush_stack(driver.menu->menu_list, MENU_SETTINGS); return -1; } static int action_ok_file_load_with_detect_core(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; int ret; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, NULL, NULL); ret = rarch_defer_core(g_extern.core_info, menu_path, path, label, driver.menu->deferred_path, sizeof(driver.menu->deferred_path)); if (ret == -1) { rarch_main_command(RARCH_CMD_LOAD_CORE); common_load_content(driver.menu, false); return -1; } if (ret == 0) menu_list_push_stack_refresh( driver.menu->menu_list, g_settings.libretro_directory, "deferred_core_list", 0, idx); return ret; } static int menu_action_setting_set_current_string_path( rarch_setting_t *setting, const char *dir, const char *path) { fill_pathname_join(setting->value.string, dir, path, setting->size); return menu_action_generic_setting(setting); } static int action_ok_file_load(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_label = NULL; const char *menu_path = NULL; rarch_setting_t *setting = NULL; if (!driver.menu) return -1; menu_list_get_last(driver.menu->menu_list->menu_stack, &menu_path, &menu_label, NULL); setting = menu_action_find_setting(menu_label); if (setting && setting->type == ST_PATH) { menu_action_setting_set_current_string_path(setting, menu_path, path); menu_list_pop_stack_by_needle(driver.menu->menu_list, setting->name); } else { if (type == MENU_FILE_IN_CARCHIVE) fill_pathname_join_delim(g_extern.fullpath, menu_path, path, '#',sizeof(g_extern.fullpath)); else fill_pathname_join(g_extern.fullpath, menu_path, path, sizeof(g_extern.fullpath)); common_load_content(driver.menu, true); return -1; } return 0; } static int action_ok_set_path(const char *path, const char *label, unsigned type, size_t idx) { const char *menu_path = NULL; const char *menu_label = NULL; rarch_setting_t *setting = NULL; if (!driver.menu) return -1; menu_list_get_last_stack(driver.menu->menu_list, &menu_path, &menu_label, NULL); setting = menu_action_find_setting(menu_label); if (!setting) return -1; menu_action_setting_set_current_string_path(setting, menu_path, path); menu_list_pop_stack_by_needle(driver.menu->menu_list, setting->name); return 0; } static int action_ok_custom_viewport(const char *path, const char *label, unsigned type, size_t idx) { /* Start with something sane. */ rarch_viewport_t *custom = (rarch_viewport_t*) &g_extern.console.screen.viewports.custom_vp; menu_list_push_stack( driver.menu->menu_list, "", "custom_viewport_1", MENU_SETTINGS_CUSTOM_VIEWPORT, idx); if (driver.video_data && driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, custom); aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (float)custom->width / custom->height; g_settings.video.aspect_ratio_idx = ASPECT_RATIO_CUSTOM; rarch_main_command(RARCH_CMD_VIDEO_SET_ASPECT_RATIO); return 0; } static int generic_action_ok_command(unsigned cmd) { if (!driver.menu) return -1; if (!rarch_main_command(cmd)) return -1; return 0; } static int action_ok_load_state(const char *path, const char *label, unsigned type, size_t idx) { if (generic_action_ok_command(RARCH_CMD_LOAD_STATE) == -1) return -1; return generic_action_ok_command(RARCH_CMD_RESUME); } static int action_ok_save_state(const char *path, const char *label, unsigned type, size_t idx) { if (generic_action_ok_command(RARCH_CMD_SAVE_STATE) == -1) return -1; return generic_action_ok_command(RARCH_CMD_RESUME); } #ifdef HAVE_NETWORKING /* HACK - we have to find some way to pass state inbetween * function pointer callback functions that don't necessarily * call each other. */ static char core_updater_path[PATH_MAX_LENGTH]; static bool zlib_extract_core_callback(const char *name, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, void *userdata) { char path[PATH_MAX_LENGTH]; /* Make directory */ fill_pathname_join(path, (const char*)userdata, name, sizeof(path)); path_basedir(path); if (!path_mkdir(path)) { RARCH_ERR("Failed to create directory: %s.\n", path); return false; } /* Ignore directories. */ if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\') return true; fill_pathname_join(path, (const char*)userdata, name, sizeof(path)); RARCH_LOG("path is: %s, CRC32: 0x%x\n", path, crc32); switch (cmode) { case 0: /* Uncompressed */ write_file(path, cdata, size); break; case 8: /* Deflate */ zlib_inflate_data_to_file(path, valid_exts, cdata, csize, size, crc32); break; } return true; } static int cb_core_updater_download(void *data_, size_t len) { FILE *f; const char* file_ext = NULL; char output_path[PATH_MAX_LENGTH], msg[PATH_MAX_LENGTH]; char *data = (char*)data_; if (!data) return -1; fill_pathname_join(output_path, g_settings.libretro_directory, core_updater_path, sizeof(output_path)); f = fopen(output_path, "wb"); if (!f) return -1; fwrite(data, 1, len, f); fclose(f); snprintf(msg, sizeof(msg), "Download complete: %s.", core_updater_path); msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, msg, 1, 90); #ifdef HAVE_ZLIB file_ext = path_get_extension(output_path); if (!g_settings.network.buildbot_auto_extract_archive) return 0; if (!strcasecmp(file_ext,"zip")) { if (!zlib_parse_file(output_path, NULL, zlib_extract_core_callback, (void*)g_settings.libretro_directory)) RARCH_LOG("Could not process ZIP file.\n"); } #endif return 0; } #endif static int action_ok_core_updater_list(const char *path, const char *label, unsigned type, size_t idx) { #ifdef HAVE_NETWORKING char core_path[PATH_MAX_LENGTH], msg[PATH_MAX_LENGTH]; fill_pathname_join(core_path, g_settings.network.buildbot_url, path, sizeof(core_path)); strlcpy(core_updater_path, path, sizeof(core_updater_path)); snprintf(msg, sizeof(msg), "Starting download: %s.", path); msg_queue_clear(g_extern.msg_queue); msg_queue_push(g_extern.msg_queue, msg, 1, 90); msg_queue_clear(g_extern.http_msg_queue); msg_queue_push(g_extern.http_msg_queue, core_path, 0, 1); net_http_set_pending_cb(cb_core_updater_download); #endif return 0; } static int action_ok_disk_cycle_tray_status(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_DISK_EJECT_TOGGLE); } static int action_ok_quit(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_QUIT); } static int action_ok_save_new_config(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_MENU_SAVE_CONFIG); } static int action_ok_resume_content(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_RESUME); } static int action_ok_restart_content(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_RESET); } static int action_ok_screenshot(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_TAKE_SCREENSHOT); } static int action_ok_file_load_or_resume(const char *path, const char *label, unsigned type, size_t idx) { if (!strcmp(driver.menu->deferred_path, g_extern.fullpath)) return generic_action_ok_command(RARCH_CMD_RESUME); else { strlcpy(g_extern.fullpath, driver.menu->deferred_path, sizeof(g_extern.fullpath)); rarch_main_command(RARCH_CMD_LOAD_CORE); rarch_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT); return -1; } } static int action_ok_shader_apply_changes(const char *path, const char *label, unsigned type, size_t idx) { return generic_action_ok_command(RARCH_CMD_SHADERS_APPLY_CHANGES); } static int action_ok_lookup_setting(const char *path, const char *label, unsigned type, size_t idx) { return menu_action_setting_set(type, label, MENU_ACTION_OK); } static int action_ok_rdb_entry_submenu(const char *path, const char *label, unsigned type, size_t idx) { int ret; union string_list_elem_attr attr; char new_label[PATH_MAX_LENGTH]; char *rdb = NULL; int len = 0; struct string_list *str_list = NULL; struct string_list *str_list2 = NULL; if (!label) return -1; str_list = string_split(label, "|"); if (!str_list) return -1; str_list2 = string_list_new(); if (!str_list2) { string_list_free(str_list); return -1; } /* element 0 : label * element 1 : value * element 2 : database path */ len += strlen(str_list->elems[1].data) + 1; string_list_append(str_list2, str_list->elems[1].data, attr); len += strlen(str_list->elems[2].data) + 1; string_list_append(str_list2, str_list->elems[2].data, attr); rdb = (char*)calloc(len, sizeof(char)); if (!rdb) { string_list_free(str_list); string_list_free(str_list2); return -1; } string_list_join_concat(rdb, len, str_list2, "|"); strlcpy(new_label, "deferred_cursor_manager_list_", sizeof(new_label)); strlcat(new_label, str_list->elems[0].data, sizeof(new_label)); ret = menu_list_push_stack_refresh( driver.menu->menu_list, rdb, new_label, 0, idx); string_list_free(str_list); string_list_free(str_list2); return ret; } static int action_cancel_lookup_setting(const char *path, const char *label, unsigned type, size_t idx) { return menu_action_setting_set(type, label, MENU_ACTION_CANCEL); } static int action_cancel_pop_default(const char *path, const char *label, unsigned type, size_t idx) { menu_apply_deferred_settings(); menu_list_pop_stack(driver.menu->menu_list); return 0; } static int action_ok_help(const char *path, const char *label, unsigned type, size_t idx) { if (!driver.menu) return -1; menu_list_push_stack( driver.menu->menu_list, "", "help", 0, 0); driver.menu->push_start_screen = false; return 0; } static int action_start_remap_file_load(unsigned type, const char *label, unsigned action) { g_settings.input.remapping_path[0] = '\0'; input_remapping_set_defaults(); return 0; } static int action_start_performance_counters_core(unsigned type, const char *label, unsigned action) { struct retro_perf_counter **counters = (struct retro_perf_counter**) perf_counters_libretro; unsigned offset = type - MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN; (void)label; (void)action; if (counters[offset]) { counters[offset]->total = 0; counters[offset]->call_cnt = 0; } return 0; } static int action_start_input_desc(unsigned type, const char *label, unsigned action) { unsigned inp_desc_index_offset = type - MENU_SETTINGS_INPUT_DESC_BEGIN; unsigned inp_desc_user = inp_desc_index_offset / RARCH_FIRST_CUSTOM_BIND; unsigned inp_desc_button_index_offset = inp_desc_index_offset - (inp_desc_user * RARCH_FIRST_CUSTOM_BIND); (void)label; (void)action; g_settings.input.remap_ids[inp_desc_user][inp_desc_button_index_offset] = g_settings.input.binds[inp_desc_user][inp_desc_button_index_offset].id; return 0; } static int action_start_shader_action_parameter(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; struct video_shader_parameter *param = NULL; if (driver.video_poke && driver.video_data && driver.video_poke->get_current_shader) shader = driver.video_poke->get_current_shader(driver.video_data); if (!shader) return 0; param = &shader->parameters[type - MENU_SETTINGS_SHADER_PARAMETER_0]; param->current = param->initial; param->current = min(max(param->minimum, param->current), param->maximum); #endif return 0; } static int action_start_shader_action_preset_parameter(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; struct video_shader_parameter *param = NULL; if (!(shader = driver.menu->shader)) return 0; param = &shader->parameters[type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0]; param->current = param->initial; param->current = min(max(param->minimum, param->current), param->maximum); #endif return 0; } static int shader_action_parameter_toggle(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; struct video_shader_parameter *param = NULL; if (driver.video_poke && driver.video_data && driver.video_poke->get_current_shader) shader = driver.video_poke->get_current_shader(driver.video_data); if (!shader) return 0; param = &shader->parameters[type - MENU_SETTINGS_SHADER_PARAMETER_0]; switch (action) { case MENU_ACTION_LEFT: param->current -= param->step; break; case MENU_ACTION_RIGHT: param->current += param->step; break; default: break; } param->current = min(max(param->minimum, param->current), param->maximum); #endif return 0; } static int shader_action_parameter_preset_toggle(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; struct video_shader_parameter *param = NULL; if (!(shader = driver.menu->shader)) return 0; param = &shader->parameters[type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0]; switch (action) { case MENU_ACTION_LEFT: param->current -= param->step; break; case MENU_ACTION_RIGHT: param->current += param->step; break; default: break; } param->current = min(max(param->minimum, param->current), param->maximum); #endif return 0; } static int action_toggle_cheat(unsigned type, const char *label, unsigned action) { cheat_manager_t *cheat = g_extern.cheat; size_t idx = type - MENU_SETTINGS_CHEAT_BEGIN; if (!cheat) return -1; switch (action) { case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: cheat->cheats[idx].state = !cheat->cheats[idx].state; cheat_manager_update(cheat, idx); break; } return 0; } static int action_toggle_input_desc(unsigned type, const char *label, unsigned action) { unsigned inp_desc_index_offset = type - MENU_SETTINGS_INPUT_DESC_BEGIN; unsigned inp_desc_user = inp_desc_index_offset / RARCH_FIRST_CUSTOM_BIND; unsigned inp_desc_button_index_offset = inp_desc_index_offset - (inp_desc_user * RARCH_FIRST_CUSTOM_BIND); switch (action) { case MENU_ACTION_LEFT: if (g_settings.input.remap_ids[inp_desc_user][inp_desc_button_index_offset] > 0) g_settings.input.remap_ids[inp_desc_user][inp_desc_button_index_offset]--; break; case MENU_ACTION_RIGHT: if (g_settings.input.remap_ids[inp_desc_user][inp_desc_button_index_offset] < RARCH_FIRST_CUSTOM_BIND) g_settings.input.remap_ids[inp_desc_user][inp_desc_button_index_offset]++; break; } return 0; } static int action_start_shader_pass(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER hack_shader_pass = type - MENU_SETTINGS_SHADER_PASS_0; struct video_shader *shader = driver.menu->shader; struct video_shader_pass *shader_pass = NULL; if (shader) shader_pass = &shader->pass[hack_shader_pass]; if (shader_pass) *shader_pass->source.path = '\0'; #endif return 0; } static int action_start_shader_scale_pass(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER unsigned pass = type - MENU_SETTINGS_SHADER_PASS_SCALE_0; struct video_shader *shader = driver.menu->shader; struct video_shader_pass *shader_pass = &shader->pass[pass]; if (shader) { shader_pass->fbo.scale_x = shader_pass->fbo.scale_y = 0; shader_pass->fbo.valid = false; } #endif return 0; } static int action_toggle_save_state(unsigned type, const char *label, unsigned action) { switch (action) { case MENU_ACTION_LEFT: /* Slot -1 is (auto) slot. */ if (g_settings.state_slot >= 0) g_settings.state_slot--; break; case MENU_ACTION_RIGHT: g_settings.state_slot++; break; } return 0; } static int action_toggle_scroll(unsigned type, const char *label, unsigned action) { unsigned scroll_speed = 0, fast_scroll_speed = 0; menu_handle_t *menu = driver.menu; if (!menu) return -1; scroll_speed = (max(menu->scroll.acceleration, 2) - 2) / 4 + 1; fast_scroll_speed = 4 + 4 * scroll_speed; switch (action) { case MENU_ACTION_LEFT: if (menu->selection_ptr > fast_scroll_speed) menu_navigation_set(menu, menu->selection_ptr - fast_scroll_speed, true); else menu_navigation_clear(menu, false); break; case MENU_ACTION_RIGHT: if (menu->selection_ptr + fast_scroll_speed < (menu_list_get_size(menu->menu_list))) menu_navigation_set(menu, menu->selection_ptr + fast_scroll_speed, true); else { if ((menu_list_get_size(menu->menu_list) > 0)) menu_navigation_set_last(menu); } break; } return 0; } static int action_toggle_mainmenu(unsigned type, const char *label, unsigned action) { menu_file_list_cbs_t *cbs = NULL; unsigned push_list = 0; menu_handle_t *menu = driver.menu; if (!menu) return -1; if (file_list_get_size(menu->menu_list->menu_stack) == 1) { if (!strcmp(driver.menu_ctx->ident, "xmb")) { menu->selection_ptr = 0; switch (action) { case MENU_ACTION_LEFT: if (menu->categories.selection_ptr == 0) break; push_list = 1; break; case MENU_ACTION_RIGHT: if (menu->categories.selection_ptr == (menu->categories.size - 1)) break; push_list = 1; break; } } } else push_list = 2; cbs = (menu_file_list_cbs_t*) menu_list_get_actiondata_at_offset(menu->menu_list->selection_buf, menu->selection_ptr); switch (push_list) { case 1: if (driver.menu_ctx->list_cache) driver.menu_ctx->list_cache(true, action); if (cbs && cbs->action_content_list_switch) return cbs->action_content_list_switch( menu->menu_list->selection_buf, menu->menu_list->menu_stack, "", "", 0); break; case 2: action_toggle_scroll(0, "", action); break; case 0: default: break; } return 0; } static int action_toggle_shader_scale_pass(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER unsigned pass = type - MENU_SETTINGS_SHADER_PASS_SCALE_0; struct video_shader *shader = NULL; struct video_shader_pass *shader_pass = NULL; if (!driver.menu) return -1; shader = driver.menu->shader; if (!shader) return -1; shader_pass = &shader->pass[pass]; if (!shader_pass) return -1; switch (action) { case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: { unsigned current_scale = shader_pass->fbo.scale_x; unsigned delta = (action == MENU_ACTION_LEFT) ? 5 : 1; current_scale = (current_scale + delta) % 6; shader_pass->fbo.valid = current_scale; shader_pass->fbo.scale_x = shader_pass->fbo.scale_y = current_scale; } break; } #endif return 0; } static int action_start_shader_filter_pass(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER unsigned pass = type - MENU_SETTINGS_SHADER_PASS_FILTER_0; struct video_shader *shader = NULL; struct video_shader_pass *shader_pass = NULL; if (!driver.menu) return -1; shader = driver.menu->shader; if (!shader) return -1; shader_pass = &shader->pass[pass]; if (!shader_pass) return -1; shader_pass->filter = RARCH_FILTER_UNSPEC; #endif return 0; } static int action_toggle_shader_filter_pass(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER unsigned pass = type - MENU_SETTINGS_SHADER_PASS_FILTER_0; struct video_shader *shader = NULL; struct video_shader_pass *shader_pass = NULL; if (!driver.menu) return -1; shader = driver.menu->shader; if (!shader) return -1; shader_pass = &shader->pass[pass]; if (!shader_pass) return -1; switch (action) { case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: { unsigned delta = (action == MENU_ACTION_LEFT) ? 2 : 1; shader_pass->filter = ((shader_pass->filter + delta) % 3); } break; } #endif return 0; } static int action_toggle_shader_filter_default(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER rarch_setting_t *setting = menu_action_find_setting("video_smooth"); if (setting) menu_action_setting_handler(setting, action); #endif return 0; } static int action_start_shader_num_passes(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; if (!driver.menu) return -1; shader = driver.menu->shader; if (!shader) return -1; if (shader->passes) shader->passes = 0; driver.menu->need_refresh = true; video_shader_resolve_parameters(NULL, driver.menu->shader); #endif return 0; } static int action_start_cheat_num_passes(unsigned type, const char *label, unsigned action) { cheat_manager_t *cheat = g_extern.cheat; if (!cheat) return -1; if (cheat->size) { cheat_manager_realloc(cheat, 0); driver.menu->need_refresh = true; } return 0; } static int action_toggle_cheat_num_passes(unsigned type, const char *label, unsigned action) { unsigned new_size = 0; cheat_manager_t *cheat = g_extern.cheat; if (!cheat) return -1; switch (action) { case MENU_ACTION_LEFT: if (cheat->size) new_size = cheat->size - 1; driver.menu->need_refresh = true; break; case MENU_ACTION_RIGHT: new_size = cheat->size + 1; driver.menu->need_refresh = true; break; } if (driver.menu->need_refresh) cheat_manager_realloc(cheat, new_size); return 0; } static int action_toggle_shader_num_passes(unsigned type, const char *label, unsigned action) { #ifdef HAVE_SHADER_MANAGER struct video_shader *shader = NULL; if (!driver.menu) return -1; shader = driver.menu->shader; if (!shader) return -1; switch (action) { case MENU_ACTION_LEFT: if (shader->passes) shader->passes--; driver.menu->need_refresh = true; break; case MENU_ACTION_RIGHT: if ((shader->passes < GFX_MAX_SHADERS)) shader->passes++; driver.menu->need_refresh = true; break; } if (driver.menu->need_refresh) video_shader_resolve_parameters(NULL, driver.menu->shader); #endif return 0; } static int action_ok_video_resolution(const char *path, const char *label, unsigned type, size_t idx) { #ifdef GEKKO if (driver.video_data) gx_set_video_mode(driver.video_data, menu_gx_resolutions [menu_current_gx_resolution][0], menu_gx_resolutions[menu_current_gx_resolution][1]); #elif defined(__CELLOS_LV2__) if (g_extern.console.screen.resolutions.list[ g_extern.console.screen.resolutions.current.idx] == CELL_VIDEO_OUT_RESOLUTION_576) { if (g_extern.console.screen.pal_enable) g_extern.console.screen.pal60_enable = true; } else { g_extern.console.screen.pal_enable = false; g_extern.console.screen.pal60_enable = false; } rarch_main_command(RARCH_CMD_REINIT); #endif return 0; } static int action_toggle_video_resolution(unsigned type, const char *label, unsigned action) { #ifdef GEKKO switch (action) { case MENU_ACTION_LEFT: if (menu_current_gx_resolution > 0) menu_current_gx_resolution--; break; case MENU_ACTION_RIGHT: if (menu_current_gx_resolution < GX_RESOLUTIONS_LAST - 1) { #ifdef HW_RVL if ((menu_current_gx_resolution + 1) > GX_RESOLUTIONS_640_480) if (CONF_GetVideo() != CONF_VIDEO_PAL) return 0; #endif menu_current_gx_resolution++; } break; } #elif defined(__CELLOS_LV2__) switch (action) { case MENU_ACTION_LEFT: if (g_extern.console.screen.resolutions.current.idx) { g_extern.console.screen.resolutions.current.idx--; g_extern.console.screen.resolutions.current.id = g_extern.console.screen.resolutions.list [g_extern.console.screen.resolutions.current.idx]; } break; case MENU_ACTION_RIGHT: if (g_extern.console.screen.resolutions.current.idx + 1 < g_extern.console.screen.resolutions.count) { g_extern.console.screen.resolutions.current.idx++; g_extern.console.screen.resolutions.current.id = g_extern.console.screen.resolutions.list [g_extern.console.screen.resolutions.current.idx]; } break; } #endif return 0; } static int action_start_performance_counters_frontend(unsigned type, const char *label, unsigned action) { struct retro_perf_counter **counters = (struct retro_perf_counter**) perf_counters_rarch; unsigned offset = type - MENU_SETTINGS_PERF_COUNTERS_BEGIN; (void)label; if (counters[offset]) { counters[offset]->total = 0; counters[offset]->call_cnt = 0; } return 0; } static int action_start_core_setting(unsigned type, const char *label, unsigned action) { unsigned idx = type - MENU_SETTINGS_CORE_OPTION_START; (void)label; core_option_set_default(g_extern.system.core_options, idx); return 0; } static int core_setting_toggle(unsigned type, const char *label, unsigned action) { unsigned idx = type - MENU_SETTINGS_CORE_OPTION_START; (void)label; switch (action) { case MENU_ACTION_LEFT: core_option_prev(g_extern.system.core_options, idx); break; case MENU_ACTION_RIGHT: core_option_next(g_extern.system.core_options, idx); break; } return 0; } static int disk_options_disk_idx_toggle(unsigned type, const char *label, unsigned action) { switch (action) { case MENU_ACTION_LEFT: rarch_main_command(RARCH_CMD_DISK_PREV); break; case MENU_ACTION_RIGHT: rarch_main_command(RARCH_CMD_DISK_NEXT); break; } return 0; } static int deferred_push_core_list_deferred(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; size_t list_size = 0; const core_info_t *info = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); core_info_list_get_supported_cores(g_extern.core_info, driver.menu->deferred_path, &info, &list_size); for (i = 0; i < list_size; i++) { menu_list_push(list, info[i].path, "", MENU_FILE_CORE, 0); menu_list_set_alt_at_offset(list, i, info[i].display_name); } menu_list_sort_on_alt(list); menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } static int deferred_push_database_manager_list_deferred(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); menu_database_populate_query(list, path, NULL); menu_list_sort_on_alt(list); menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } static int deferred_push_cursor_manager_list_deferred(void *data, void *userdata, const char *path, const char *label, unsigned type) { char *query = NULL, *rdb = NULL; char rdb_path[PATH_MAX_LENGTH]; config_file_t *conf = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); conf = config_file_new(path); if (!conf) return -1; if (!config_get_string(conf, "query", &query)) return -1; if (!config_get_string(conf, "rdb", &rdb)) return -1; fill_pathname_join(rdb_path, g_settings.content_database, rdb, sizeof(rdb_path)); menu_database_populate_query(list, rdb_path, query); menu_list_sort_on_alt(list); menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } static int deferred_push_cursor_manager_list_deferred_query_subsearch( void *data, void *userdata, const char *path, const char *label, unsigned type) { char query[PATH_MAX_LENGTH]; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; struct string_list *str_list = string_split(path, "|"); bool add_quotes = true; if (!list || !menu_list) { string_list_free(str_list); return -1; } strlcpy(query, "{'", sizeof(query)); if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_publisher")) strlcat(query, "publisher", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_developer")) strlcat(query, "developer", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_origin")) strlcat(query, "origin", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_franchise")) strlcat(query, "franchise", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_esrb_rating")) strlcat(query, "esrb_rating", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_bbfc_rating")) strlcat(query, "bbfc_rating", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_elspa_rating")) strlcat(query, "elspa_rating", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_pegi_rating")) strlcat(query, "pegi_rating", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_enhancement_hw")) strlcat(query, "enhancement_hw", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_cero_rating")) strlcat(query, "cero_rating", sizeof(query)); else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_edge_magazine_rating")) { strlcat(query, "edge_rating", sizeof(query)); add_quotes = false; } else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_edge_magazine_issue")) { strlcat(query, "edge_issue", sizeof(query)); add_quotes = false; } else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_releasemonth")) { strlcat(query, "releasemonth", sizeof(query)); add_quotes = false; } else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_releaseyear")) { strlcat(query, "releaseyear", sizeof(query)); add_quotes = false; } else if (!strcmp(label, "deferred_cursor_manager_list_rdb_entry_max_users")) { strlcat(query, "users", sizeof(query)); add_quotes = false; } strlcat(query, "':", sizeof(query)); if (add_quotes) strlcat(query, "\"", sizeof(query)); strlcat(query, str_list->elems[0].data, sizeof(query)); if (add_quotes) strlcat(query, "\"", sizeof(query)); strlcat(query, "}", sizeof(query)); #if 0 RARCH_LOG("query: %s\n", query); #endif if (query[0] == '\0') { string_list_free(str_list); return -1; } menu_list_clear(list); menu_database_populate_query(list, str_list->elems[1].data, query); menu_list_sort_on_alt(list); menu_list_populate_generic(driver.menu, list, str_list->elems[0].data, label, type); string_list_free(str_list); return 0; } #if 0 static int deferred_push_core_information(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; core_info_t *info = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; info = (core_info_t*)g_extern.core_info_current; menu_list_clear(list); if (info->data) { char tmp[PATH_MAX_LENGTH]; snprintf(tmp, sizeof(tmp), "Core name: %s", info->core_name ? info->core_name : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); snprintf(tmp, sizeof(tmp), "Core label: %s", info->display_name ? info->display_name : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); if (info->systemname) { snprintf(tmp, sizeof(tmp), "System name: %s", info->systemname); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->system_manufacturer) { snprintf(tmp, sizeof(tmp), "System manufacturer: %s", info->system_manufacturer); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->categories_list) { strlcpy(tmp, "Categories: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->categories_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->authors_list) { strlcpy(tmp, "Authors: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->authors_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->permissions_list) { strlcpy(tmp, "Permissions: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->permissions_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->licenses_list) { strlcpy(tmp, "License(s): ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->licenses_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->supported_extensions_list) { strlcpy(tmp, "Supported extensions: ", sizeof(tmp)); string_list_join_concat(tmp, sizeof(tmp), info->supported_extensions_list, ", "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } if (info->firmware_count > 0) { core_info_list_update_missing_firmware( g_extern.core_info, info->path, g_settings.system_directory); menu_list_push(list, "Firmware: ", "", MENU_SETTINGS_CORE_INFO_NONE, 0); for (i = 0; i < info->firmware_count; i++) { if (info->firmware[i].desc) { snprintf(tmp, sizeof(tmp), " name: %s", info->firmware[i].desc ? info->firmware[i].desc : ""); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); snprintf(tmp, sizeof(tmp), " status: %s, %s", info->firmware[i].missing ? "missing" : "present", info->firmware[i].optional ? "optional" : "required"); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } } } if (info->notes) { snprintf(tmp, sizeof(tmp), "Core notes: "); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); for (i = 0; i < info->note_list->size; i++) { snprintf(tmp, sizeof(tmp), " %s", info->note_list->elems[i].data); menu_list_push(list, tmp, "", MENU_SETTINGS_CORE_INFO_NONE, 0); } } } else menu_list_push(list, "No information available.", "", MENU_SETTINGS_CORE_OPTION_NONE, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } #endif static int deferred_push_performance_counters(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); menu_list_push(list, "Frontend Counters", "frontend_counters", MENU_SETTING_ACTION, 0); menu_list_push(list, "Core Counters", "core_counters", MENU_SETTING_ACTION, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static inline struct video_shader *shader_manager_get_current_shader( menu_handle_t *menu, const char *label, unsigned type) { if (!strcmp(label, "video_shader_preset_parameters")) return menu->shader; else if (!strcmp(label, "video_shader_parameters") && driver.video_poke && driver.video_data && driver.video_poke->get_current_shader) return driver.video_poke->get_current_shader(driver.video_data); return NULL; } static int deferred_push_video_shader_parameters_common(void *data, void *userdata, const char *path, const char *label, unsigned type, struct video_shader *shader, unsigned base_parameter) { unsigned i; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); for (i = 0; i < shader->num_parameters; i++) { menu_list_push(list, shader->parameters[i].desc, label, base_parameter + i, 0); } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_video_shader_preset_parameters(void *data, void *userdata, const char *path, const char *label, unsigned type) { if (!driver.menu->shader) return 0; return deferred_push_video_shader_parameters_common(data, userdata, path, label, type, driver.menu->shader, MENU_SETTINGS_SHADER_PRESET_PARAMETER_0); } static int deferred_push_video_shader_parameters(void *data, void *userdata, const char *path, const char *label, unsigned type) { struct video_shader *shader = NULL; if (driver.video_poke && driver.video_data && driver.video_poke->get_current_shader) shader = driver.video_poke->get_current_shader(driver.video_data); if (!shader) return 0; return deferred_push_video_shader_parameters_common(data, userdata, path, label, type, shader, MENU_SETTINGS_SHADER_PARAMETER_0); } static int deferred_push_settings(void *data, void *userdata, const char *path, const char *label, unsigned type) { rarch_setting_t *setting = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; settings_list_free(driver.menu->list_settings); driver.menu->list_settings = (rarch_setting_t *)setting_data_new(SL_FLAG_ALL_SETTINGS); setting = menu_action_find_setting("Driver Settings"); menu_list_clear(list); if (g_settings.menu.collapse_subgroups_enable) { for (; setting->type != ST_NONE; setting++) { if (setting->type == ST_GROUP) menu_list_push(list, setting->short_description, setting->name, menu_entries_setting_set_flags(setting), 0); } } else { for (; setting->type != ST_NONE; setting++) { char group_label[PATH_MAX_LENGTH]; char subgroup_label[PATH_MAX_LENGTH]; if (setting->type == ST_GROUP) strlcpy(group_label, setting->name, sizeof(group_label)); else if (setting->type == ST_SUB_GROUP) { char new_label[PATH_MAX_LENGTH], new_path[PATH_MAX_LENGTH]; strlcpy(subgroup_label, setting->name, sizeof(group_label)); strlcpy(new_label, group_label, sizeof(new_label)); strlcat(new_label, "|", sizeof(new_label)); strlcat(new_label, subgroup_label, sizeof(new_label)); strlcpy(new_path, group_label, sizeof(new_path)); strlcat(new_path, " - ", sizeof(new_path)); strlcat(new_path, setting->short_description, sizeof(new_path)); menu_list_push(list, new_path, new_label, MENU_SETTING_SUBGROUP, 0); } } } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_settings_subgroup(void *data, void *userdata, const char *path, const char *label, unsigned type) { char elem0[PATH_MAX_LENGTH], elem1[PATH_MAX_LENGTH]; rarch_setting_t *setting = NULL; struct string_list *str_list = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; if (label) { str_list = string_split(label, "|"); if (str_list && str_list->size > 0) strlcpy(elem0, str_list->elems[0].data, sizeof(elem0)); if (str_list && str_list->size > 1) strlcpy(elem1, str_list->elems[1].data, sizeof(elem1)); if (str_list) { string_list_free(str_list); str_list = NULL; } } settings_list_free(driver.menu->list_settings); driver.menu->list_settings = (rarch_setting_t *)setting_data_new(SL_FLAG_ALL_SETTINGS); setting = menu_action_find_setting(elem0); menu_list_clear(list); if (!setting) return -1; while (1) { if (!setting) return -1; if (setting->type == ST_SUB_GROUP) { if ((strlen(setting->name) != 0) && !strcmp(setting->name, elem1)) break; } setting++; } setting++; for (; setting->type != ST_END_SUB_GROUP; setting++) { char group_label[PATH_MAX_LENGTH]; strlcpy(group_label, setting->name, sizeof(group_label)); menu_list_push(list, setting->short_description, group_label, menu_entries_setting_set_flags(setting), 0); } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_category(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_push_list(driver.menu, (file_list_t*)data, path, label, type, SL_FLAG_ALL_SETTINGS); } static int deferred_push_shader_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; struct video_shader *shader = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; shader = driver.menu->shader; if (!shader) return -1; menu_list_clear(list); menu_list_push(list, "Apply Shader Changes", "shader_apply_changes", MENU_SETTING_ACTION, 0); menu_list_push(list, "Default Filter", "video_shader_default_filter", 0, 0); menu_list_push(list, "Load Shader Preset", "video_shader_preset", MENU_SETTING_ACTION, 0); menu_list_push(list, "Shader Preset Save As", "video_shader_preset_save_as", MENU_SETTING_ACTION, 0); menu_list_push(list, "Parameters (Current)", "video_shader_parameters", MENU_SETTING_ACTION, 0); menu_list_push(list, "Parameters (Menu)", "video_shader_preset_parameters", MENU_SETTING_ACTION, 0); menu_list_push(list, "Shader Passes", "video_shader_num_passes", 0, 0); for (i = 0; i < shader->passes; i++) { char buf[64]; snprintf(buf, sizeof(buf), "Shader #%u", i); menu_list_push(list, buf, "video_shader_pass", MENU_SETTINGS_SHADER_PASS_0 + i, 0); snprintf(buf, sizeof(buf), "Shader #%u Filter", i); menu_list_push(list, buf, "video_shader_filter_pass", MENU_SETTINGS_SHADER_PASS_FILTER_0 + i, 0); snprintf(buf, sizeof(buf), "Shader #%u Scale", i); menu_list_push(list, buf, "video_shader_scale_pass", MENU_SETTINGS_SHADER_PASS_SCALE_0 + i, 0); } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); menu_list_push(list, "Core Options", "core_options", MENU_SETTING_ACTION, 0); if (g_extern.main_is_init) { if (g_extern.has_set_input_descriptors) menu_list_push(list, "Core Input Remapping Options", "core_input_remapping_options", MENU_SETTING_ACTION, 0); menu_list_push(list, "Core Cheat Options", "core_cheat_options", MENU_SETTING_ACTION, 0); if (!g_extern.libretro_dummy && g_extern.system.disk_control.get_num_images) menu_list_push(list, "Core Disk Options", "core_disk_options", MENU_SETTING_ACTION, 0); } menu_list_push(list, "Shader Options", "shader_options", MENU_SETTING_ACTION, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_management_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); #ifdef HAVE_LIBRETRODB menu_list_push(list, "Database Manager", "database_manager_list", MENU_SETTING_ACTION, 0); menu_list_push(list, "Cursor Manager", "cursor_manager_list", MENU_SETTING_ACTION, 0); #endif if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static void push_perfcounter(menu_handle_t *menu, file_list_t *list, const struct retro_perf_counter **counters, unsigned num, unsigned id) { unsigned i; if (!counters || num == 0) return; for (i = 0; i < num; i++) if (counters[i] && counters[i]->ident) menu_list_push(list, counters[i]->ident, "", id + i, 0); } static int push_perfcounter_generic( void *data, void *userdata, const char *path, const char *label, const struct retro_perf_counter **counters, unsigned num, unsigned ident, unsigned type) { file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; if (!list || !menu_list) return -1; menu_list_clear(list); push_perfcounter(driver.menu, list, counters, num, ident); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_core_counters(void *data, void *userdata, const char *path, const char *label, unsigned type) { return push_perfcounter_generic(data, userdata, path, label, perf_counters_libretro, perf_ptr_libretro, MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN, type); } static int deferred_push_frontend_counters(void *data, void *userdata, const char *path, const char *label, unsigned type) { return push_perfcounter_generic(data, userdata, path, label, perf_counters_rarch, perf_ptr_rarch, MENU_SETTINGS_PERF_COUNTERS_BEGIN, type); } static int deferred_push_core_cheat_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; file_list_t *list = (file_list_t*)data; cheat_manager_t *cheat = g_extern.cheat; (void)userdata; (void)type; if (!list) return -1; if (!cheat) { g_extern.cheat = cheat_manager_new(0); if (!g_extern.cheat) return -1; cheat = g_extern.cheat; } menu_list_clear(list); menu_list_push(list, "Cheat File Load", "cheat_file_load", MENU_SETTING_ACTION, 0); menu_list_push(list, "Cheat File Save As", "cheat_file_save_as", MENU_SETTING_ACTION, 0); menu_list_push(list, "Cheat Passes", "cheat_num_passes", 0, 0); menu_list_push(list, "Apply Cheat Changes", "cheat_apply_changes", MENU_SETTING_ACTION, 0); for (i = 0; i < cheat->size; i++) { char cheat_label[64]; snprintf(cheat_label, sizeof(cheat_label), "Cheat #%d: ", i); if (cheat->cheats[i].desc) strlcat(cheat_label, cheat->cheats[i].desc, sizeof(cheat_label)); menu_list_push(list, cheat_label, "", MENU_SETTINGS_CHEAT_BEGIN + i, 0); } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_core_input_remapping_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned p, retro_id; file_list_t *list = (file_list_t*)data; (void)userdata; (void)type; if (!list) return -1; menu_list_clear(list); menu_list_push(list, "Remap File Load", "remap_file_load", MENU_SETTING_ACTION, 0); menu_list_push(list, "Remap File Save As", "remap_file_save_as", MENU_SETTING_ACTION, 0); for (p = 0; p < g_settings.input.max_users; p++) { for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) { char desc_label[64]; unsigned user = p + 1; const char *description = g_extern.system.input_desc_btn[p][retro_id]; if (!description) continue; snprintf(desc_label, sizeof(desc_label), "User %u %s : ", user, description); menu_list_push(list, desc_label, "", MENU_SETTINGS_INPUT_DESC_BEGIN + (p * RARCH_FIRST_CUSTOM_BIND) + retro_id, 0); } } if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_core_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; file_list_t *list = (file_list_t*)data; (void)userdata; if (!list) return -1; menu_list_clear(list); if (g_extern.system.core_options) { size_t opts = core_option_size(g_extern.system.core_options); for (i = 0; i < opts; i++) menu_list_push(list, core_option_get_desc(g_extern.system.core_options, i), "", MENU_SETTINGS_CORE_OPTION_START + i, 0); } else menu_list_push(list, "No options available.", "", MENU_SETTINGS_CORE_OPTION_NONE, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } static int deferred_push_disk_options(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; (void)userdata; if (!list) return -1; menu_list_clear(list); menu_list_push(list, "Disk Index", "disk_idx", MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX, 0); menu_list_push(list, "Disk Cycle Tray Status", "disk_cycle_tray_status", MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_CYCLE_TRAY_STATUS, 0); menu_list_push(list, "Disk Image Append", "disk_image_append", MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_IMAGE_APPEND, 0); if (driver.menu_ctx && driver.menu_ctx->populate_entries) driver.menu_ctx->populate_entries(path, label, type); return 0; } #ifdef HAVE_NETWORKING static void print_buf_lines(file_list_t *list, char *buf, int buf_size, unsigned type) { int i; char c, *line_start = buf; for (i = 0; i < buf_size; i++) { size_t ln; /* The end of the buffer, print the last bit */ if (*(buf + i) == '\0') break; if (*(buf + i) != '\n') continue; /* Found a line ending, print the line and compute new line_start */ /* Save the next char */ c = *(buf + i + 1); /* replace with \0 */ *(buf + i + 1) = '\0'; /* We need to strip the newline. */ ln = strlen(line_start) - 1; if (line_start[ln] == '\n') line_start[ln] = '\0'; menu_list_push(list, line_start, "", type, 0); /* Restore the saved char */ *(buf + i + 1) = c; line_start = buf + i + 1; } /* If the buffer was completely full, and didn't end with a newline, just * ignore the partial last line. */ } /* HACK - we have to find some way to pass state inbetween * function pointer callback functions that don't necessarily * call each other. */ static char core_updater_list_path[PATH_MAX_LENGTH]; static char core_updater_list_label[PATH_MAX_LENGTH]; static unsigned core_updater_list_type; static int cb_core_updater_list(void *data_, size_t len) { char *data = (char*)data_; file_list_t *list = NULL; if (!data) return -1; list = (file_list_t*)driver.menu->menu_list->selection_buf; if (!list) return -1; menu_list_clear(list); print_buf_lines(list, data, len, MENU_FILE_DOWNLOAD_CORE); menu_list_populate_generic(driver.menu, list, core_updater_list_path, core_updater_list_label, core_updater_list_type); return 0; } #endif static int deferred_push_core_updater_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { #ifdef HAVE_NETWORKING char url_path[PATH_MAX_LENGTH]; strlcpy(core_updater_list_path, path, sizeof(core_updater_list_path)); strlcpy(core_updater_list_label, label, sizeof(core_updater_list_label)); core_updater_list_type = type; #endif if (g_settings.network.buildbot_url[0] == '\0') { file_list_t *list = (file_list_t*)data; menu_list_clear(list); #ifdef HAVE_NETWORKING menu_list_push(list, "Buildbot URL not configured.", "", 0, 0); #else menu_list_push(list, "Network not available.", "", 0, 0); #endif menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } #ifdef HAVE_NETWORKING rarch_main_command(RARCH_CMD_NETWORK_INIT); fill_pathname_join(url_path, g_settings.network.buildbot_url, ".index", sizeof(url_path)); msg_queue_clear(g_extern.http_msg_queue); msg_queue_push(g_extern.http_msg_queue, url_path, 0, 1); net_http_set_pending_cb(cb_core_updater_list); #endif return 0; } static int deferred_push_history_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { unsigned i; size_t list_size = 0; file_list_t *list = (file_list_t*)data; (void)userdata; if (!list || !driver.menu) return -1; menu_list_clear(list); list_size = content_playlist_size(g_defaults.history); for (i = 0; i < list_size; i++) { char fill_buf[PATH_MAX_LENGTH]; const char *core_name = NULL; content_playlist_get_index(g_defaults.history, i, &path, NULL, &core_name); strlcpy(fill_buf, core_name, sizeof(fill_buf)); if (path) { char path_short[PATH_MAX_LENGTH]; fill_short_pathname_representation(path_short,path,sizeof(path_short)); snprintf(fill_buf,sizeof(fill_buf),"%s (%s)", path_short,core_name); } menu_list_push(list, fill_buf, "", MENU_FILE_PLAYLIST_ENTRY, 0); } menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } static int deferred_push_content_actions(void *data, void *userdata, const char *path, const char *label, unsigned type) { file_list_t *list = (file_list_t*)data; (void)userdata; if (!list || !driver.menu) return -1; menu_list_clear(list); if (g_extern.main_is_init && !g_extern.libretro_dummy && !strcmp(driver.menu->deferred_path, g_extern.fullpath)) { menu_list_push(list, "Resume", "file_load_or_resume", MENU_SETTING_ACTION_RUN, 0); menu_list_push(list, "Save State", "savestate", MENU_SETTING_ACTION_SAVESTATE, 0); menu_list_push(list, "Load State", "loadstate", MENU_SETTING_ACTION_LOADSTATE, 0); menu_list_push(list, "Core Information", "core_information", MENU_SETTING_ACTION_CORE_INFORMATION, 0); menu_list_push(list, "Core Options", "core_options", MENU_SETTING_ACTION_CORE_OPTIONS, 0); if (g_extern.has_set_input_descriptors) menu_list_push(list, "Core Input Remapping Options", "core_input_remapping_options", MENU_SETTING_ACTION_CORE_INPUT_REMAPPING_OPTIONS, 0); menu_list_push(list, "Core Cheat Options", "core_cheat_options", MENU_SETTING_ACTION_CORE_CHEAT_OPTIONS, 0); if ( !g_extern.libretro_dummy && g_extern.system.disk_control.get_num_images) menu_list_push(list, "Core Disk Options", "disk_options", MENU_SETTING_ACTION_CORE_DISK_OPTIONS, 0); menu_list_push(list, "Take Screenshot", "take_screenshot", MENU_SETTING_ACTION_SCREENSHOT, 0); menu_list_push(list, "Reset", "restart_content", MENU_SETTING_ACTION_RESET, 0); } else menu_list_push(list, "Run", "file_load_or_resume", MENU_SETTING_ACTION_RUN, 0); menu_list_populate_generic(driver.menu, list, path, label, type); return 0; } static int deferred_push_content_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_deferred_push((file_list_t*)data, driver.menu->menu_list->selection_buf); } static int deferred_push_database_manager_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, g_settings.content_database, label, type, MENU_FILE_RDB, "rdb", NULL); } static int deferred_push_cursor_manager_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, g_settings.cursor_directory, label, type, MENU_FILE_CURSOR, "dbc", NULL); } static int deferred_push_core_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_PLAIN, EXT_EXECUTABLES, NULL); } static int deferred_push_configurations(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_CONFIG, "cfg", NULL); } static int deferred_push_video_shader_preset(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_SHADER_PRESET, "cgp|glslp", NULL); } static int deferred_push_video_shader_pass(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_SHADER, "cg|glsl", NULL); } static int deferred_push_video_filter(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_VIDEOFILTER, "filt", NULL); } static int deferred_push_images(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_IMAGE, "png", NULL); } static int deferred_push_audio_dsp_plugin(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_AUDIOFILTER, "dsp", NULL); } static int deferred_push_cheat_file_load(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_CHEAT, "cht", NULL); } static int deferred_push_remap_file_load(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_REMAP, "rmp", NULL); } static int deferred_push_input_overlay(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_OVERLAY, "cfg", NULL); } static int deferred_push_input_osk_overlay(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_OVERLAY, "cfg", NULL); } static int deferred_push_video_font_path(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_FONT, "ttf", NULL); } static int deferred_push_content_history_path(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_PLAIN, "cfg", NULL); } static int deferred_push_detect_core_list(void *data, void *userdata, const char *path, const char *label, unsigned type) { return menu_entries_parse_list((file_list_t*)data, (file_list_t*)userdata, path, label, type, MENU_FILE_PLAIN, g_extern.core_info ? core_info_list_get_all_extensions( g_extern.core_info) : "", NULL); } static int deferred_push_default(void *data, void *userdata, const char *path, const char *label, unsigned type) { char ext_buf[PATH_MAX_LENGTH]; const char *exts = NULL; file_list_t *list = (file_list_t*)data; file_list_t *menu_list = (file_list_t*)userdata; rarch_setting_t *setting = (rarch_setting_t*) menu_action_find_setting(label); if (!list || !menu_list) return -1; if (setting && setting->browser_selection_type == ST_DIR) exts = ""; /* we ignore files anyway */ else if (g_extern.menu.info.valid_extensions) { exts = ext_buf; if (*g_extern.menu.info.valid_extensions) snprintf(ext_buf, sizeof(ext_buf), "%s", g_extern.menu.info.valid_extensions); else *ext_buf = '\0'; } else exts = g_extern.system.valid_extensions; menu_entries_parse_list(list, menu_list, path, label, type, MENU_FILE_PLAIN, exts, setting); return 0; } static int action_bind_up_or_down_generic(unsigned type, const char *label, unsigned action) { unsigned scroll_speed = (max(driver.menu->scroll.acceleration, 2) - 2) / 4 + 1; if (menu_list_get_size(driver.menu->menu_list) <= 0) return 0; switch (action) { case MENU_ACTION_UP: if (driver.menu->selection_ptr >= scroll_speed) menu_navigation_set(driver.menu, driver.menu->selection_ptr - scroll_speed, true); else { if (g_settings.menu.navigation.wraparound.vertical_enable) menu_navigation_set(driver.menu, menu_list_get_size(driver.menu->menu_list) - 1, true); else menu_navigation_set(driver.menu, 0, true); } break; case MENU_ACTION_DOWN: if (driver.menu->selection_ptr + scroll_speed < (menu_list_get_size(driver.menu->menu_list))) menu_navigation_set(driver.menu, driver.menu->selection_ptr + scroll_speed, true); else { if (g_settings.menu.navigation.wraparound.vertical_enable) menu_navigation_clear(driver.menu, false); else menu_navigation_set(driver.menu, menu_list_get_size(driver.menu->menu_list) - 1, true); } break; } return 0; } static int action_refresh_default(file_list_t *list, file_list_t *menu_list) { int ret = menu_entries_deferred_push(list, menu_list); driver.menu->need_refresh = false; return ret; } static int mouse_post_iterate(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, unsigned action) { if (!driver.menu->mouse.enable) return 0; if (driver.menu->mouse.ptr <= menu_list_get_size(driver.menu->menu_list)-1) menu_navigation_set(driver.menu, driver.menu->mouse.ptr, false); if (driver.menu->mouse.left) { if (!driver.menu->mouse.oldleft) { driver.menu->mouse.oldleft = true; if (cbs && cbs->action_ok) return cbs->action_ok(path, label, type, driver.menu->selection_ptr); } } else driver.menu->mouse.oldleft = false; if (driver.menu->mouse.right) { if (!driver.menu->mouse.oldright) { driver.menu->mouse.oldright = true; menu_list_pop_stack(driver.menu->menu_list); } } else driver.menu->mouse.oldright = false; return 0; } static int action_iterate_help(const char *label, unsigned action) { unsigned i; static const unsigned binds[] = { RETRO_DEVICE_ID_JOYPAD_UP, RETRO_DEVICE_ID_JOYPAD_DOWN, RETRO_DEVICE_ID_JOYPAD_A, RETRO_DEVICE_ID_JOYPAD_B, RETRO_DEVICE_ID_JOYPAD_SELECT, RARCH_MENU_TOGGLE, RARCH_QUIT_KEY, RETRO_DEVICE_ID_JOYPAD_X, }; char desc[ARRAY_SIZE(binds)][64]; char msg[PATH_MAX_LENGTH]; menu_handle_t *menu = driver.menu; if (!menu) return 0; if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render) driver.menu_ctx->render(); for (i = 0; i < ARRAY_SIZE(binds); i++) { const struct retro_keybind *keybind = (const struct retro_keybind*) &g_settings.input.binds[0][binds[i]]; const struct retro_keybind *auto_bind = (const struct retro_keybind*) input_get_auto_bind(0, binds[i]); input_get_bind_string(desc[i], keybind, auto_bind, sizeof(desc[i])); } snprintf(msg, sizeof(msg), "-- Welcome to RetroArch --\n" " \n" // strtok_r doesn't split empty strings. "Basic Menu controls:\n" " Scroll (Up): %-20s\n" " Scroll (Down): %-20s\n" " Accept/OK: %-20s\n" " Back: %-20s\n" " Info: %-20s\n" "Enter/Exit Menu: %-20s\n" " Exit RetroArch: %-20s\n" "Toggle Keyboard: %-20s\n" " \n" "To run content:\n" "Load a libretro core (Core).\n" "Load a content file (Load Content). \n" " \n" "See Path Settings to set directories for faster access to files.\n" " \n" "Press Accept/OK to continue.", desc[0], desc[1], desc[2], desc[3], desc[4], desc[5], desc[6], desc[7]); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) driver.menu_ctx->render_messagebox(msg); if (action == MENU_ACTION_OK) menu_list_pop(menu->menu_list->menu_stack, NULL); return 0; } static int action_iterate_info(const char *label, unsigned action) { char msg[PATH_MAX_LENGTH]; char needle[PATH_MAX_LENGTH]; unsigned info_type = 0; rarch_setting_t *current_setting = NULL; file_list_t *list = NULL; menu_handle_t *menu = driver.menu; if (!menu) return 0; list = (file_list_t*)menu->menu_list->selection_buf; if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render) driver.menu_ctx->render(); current_setting = (rarch_setting_t*)setting_data_find_setting( menu->list_settings, list->list[menu->selection_ptr].label); if (current_setting) strlcpy(needle, current_setting->name, sizeof(needle)); else if ((current_setting = (rarch_setting_t*)setting_data_find_setting( menu->list_settings, list->list[menu->selection_ptr].label))) { if (current_setting) strlcpy(needle, current_setting->name, sizeof(needle)); } else { const char *lbl = NULL; menu_list_get_at_offset(list, menu->selection_ptr, NULL, &lbl, &info_type); if (lbl) strlcpy(needle, lbl, sizeof(needle)); } setting_data_get_description(needle, msg, sizeof(msg)); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) { if (*msg && msg[0] != '\0') driver.menu_ctx->render_messagebox(msg); } if (action == MENU_ACTION_OK) menu_list_pop(menu->menu_list->menu_stack, &menu->selection_ptr); return 0; } static int action_iterate_load_open_zip(const char *label, unsigned action) { switch (g_settings.archive.mode) { case 0: return load_or_open_zip_iterate(driver.menu, action); case 1: return archive_load(driver.menu); case 2: return archive_open(driver.menu); default: break; } return 0; } static int action_iterate_menu_viewport(const char *label, unsigned action) { int stride_x = 1, stride_y = 1; char msg[PATH_MAX_LENGTH]; struct retro_game_geometry *geom = NULL; const char *base_msg = NULL; unsigned type = 0; rarch_viewport_t *custom = (rarch_viewport_t*) &g_extern.console.screen.viewports.custom_vp; menu_handle_t *menu = driver.menu; if (!menu) return -1; menu_list_get_last_stack(menu->menu_list, NULL, NULL, &type); geom = (struct retro_game_geometry*)&g_extern.system.av_info.geometry; if (g_settings.video.scale_integer) { stride_x = geom->base_width; stride_y = geom->base_height; } switch (action) { case MENU_ACTION_UP: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y -= stride_y; custom->height += stride_y; } else if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_DOWN: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->y += stride_y; if (custom->height >= (unsigned)stride_y) custom->height -= stride_y; } else custom->height += stride_y; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_LEFT: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x -= stride_x; custom->width += stride_x; } else if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_RIGHT: if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->x += stride_x; if (custom->width >= (unsigned)stride_x) custom->width -= stride_x; } else custom->width += stride_x; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); break; case MENU_ACTION_CANCEL: menu_list_pop_stack(menu->menu_list); if (!strcmp(label, "custom_viewport_2")) { menu_list_push_stack(menu->menu_list, "", "", MENU_SETTINGS_CUSTOM_VIEWPORT, menu->selection_ptr); } break; case MENU_ACTION_OK: menu_list_pop_stack(menu->menu_list); if (type == MENU_SETTINGS_CUSTOM_VIEWPORT && !g_settings.video.scale_integer) { menu_list_push_stack(menu->menu_list, "", "custom_viewport_2", 0, menu->selection_ptr); } break; case MENU_ACTION_START: if (!g_settings.video.scale_integer) { rarch_viewport_t vp; if (driver.video_data && driver.video && driver.video->viewport_info) driver.video->viewport_info(driver.video_data, &vp); if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) { custom->width += custom->x; custom->height += custom->y; custom->x = 0; custom->y = 0; } else { custom->width = vp.full_width - custom->x; custom->height = vp.full_height - custom->y; } rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); } break; case MENU_ACTION_MESSAGE: menu->msg_force = true; break; default: break; } menu_list_get_last_stack(menu->menu_list, NULL, &label, &type); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render) driver.menu_ctx->render(); if (g_settings.video.scale_integer) { custom->x = 0; custom->y = 0; custom->width = ((custom->width + geom->base_width - 1) / geom->base_width) * geom->base_width; custom->height = ((custom->height + geom->base_height - 1) / geom->base_height) * geom->base_height; base_msg = "Set scale"; snprintf(msg, sizeof(msg), "%s (%4ux%4u, %u x %u scale)", base_msg, custom->width, custom->height, custom->width / geom->base_width, custom->height / geom->base_height); } else { if (type == MENU_SETTINGS_CUSTOM_VIEWPORT) base_msg = "Set Upper-Left Corner"; else if (!strcmp(label, "custom_viewport_2")) base_msg = "Set Bottom-Right Corner"; snprintf(msg, sizeof(msg), "%s (%d, %d : %4ux%4u)", base_msg, custom->x, custom->y, custom->width, custom->height); } if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) driver.menu_ctx->render_messagebox(msg); if (!custom->width) custom->width = stride_x; if (!custom->height) custom->height = stride_y; aspectratio_lut[ASPECT_RATIO_CUSTOM].value = (float)custom->width / custom->height; rarch_main_command(RARCH_CMD_VIDEO_APPLY_STATE_CHANGES); return 0; } static int action_iterate_custom_bind(const char *label, unsigned action) { if (menu_input_bind_iterate(driver.menu)) menu_list_pop_stack(driver.menu->menu_list); return 0; } static int action_iterate_custom_bind_keyboard(const char *label, unsigned action) { if (menu_input_bind_iterate_keyboard(driver.menu)) menu_list_pop_stack(driver.menu->menu_list); return 0; } static int action_iterate_message(const char *label, unsigned action) { menu_handle_t *menu = driver.menu; if (!menu) return -1; if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render_messagebox) driver.menu_ctx->render_messagebox(menu->message_contents); if (action == MENU_ACTION_OK) menu_list_pop_stack(menu->menu_list); return 0; } static int mouse_iterate(unsigned action) { const struct retro_keybind *binds[MAX_USERS]; if (!driver.menu->mouse.enable) return 0; driver.menu->mouse.dx = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); driver.menu->mouse.dy = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); driver.menu->mouse.x += driver.menu->mouse.dx; driver.menu->mouse.y += driver.menu->mouse.dy; if (driver.menu->mouse.x < 5) driver.menu->mouse.x = 5; if (driver.menu->mouse.y < 5) driver.menu->mouse.y = 5; if (driver.menu->mouse.x > driver.menu->frame_buf.width - 5) driver.menu->mouse.x = driver.menu->frame_buf.width - 5; if (driver.menu->mouse.y > driver.menu->frame_buf.height - 5) driver.menu->mouse.y = driver.menu->frame_buf.height - 5; driver.menu->mouse.left = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT); driver.menu->mouse.right = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT); driver.menu->mouse.wheelup = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELUP) || driver.menu->mouse.y == 5; driver.menu->mouse.wheeldown = driver.input->input_state(driver.input_data, binds, 0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_WHEELDOWN) || driver.menu->mouse.y == driver.menu->frame_buf.height - 5; return 0; } static int action_iterate_main(const char *label, unsigned action) { int ret = 0; unsigned type_offset = 0; const char *label_offset = NULL; const char *path_offset = NULL; menu_file_list_cbs_t *cbs = NULL; menu_handle_t *menu = driver.menu; if (!menu) return 0; cbs = (menu_file_list_cbs_t*) menu_list_get_actiondata_at_offset(menu->menu_list->selection_buf, menu->selection_ptr); menu_list_get_at_offset(menu->menu_list->selection_buf, menu->selection_ptr, &path_offset, &label_offset, &type_offset); mouse_iterate(action); if (!strcmp(label, "help")) return action_iterate_help(label, action); else if (!strcmp(label, "info_screen")) return action_iterate_info(label, action); else if (!strcmp(label, "load_open_zip")) return action_iterate_load_open_zip(label, action); else if (!strcmp(label, "message")) return action_iterate_message(label, action); else if ( !strcmp(label, "custom_viewport_1") || !strcmp(label, "custom_viewport_2") ) return action_iterate_menu_viewport(label, action); else if ( !strcmp(label, "custom_bind") || !strcmp(label, "custom_bind_all") || !strcmp(label, "custom_bind_defaults") ) { if (g_extern.menu.bind_mode_keyboard) return action_iterate_custom_bind_keyboard(label, action); else return action_iterate_custom_bind(label, action); } if (menu->need_refresh && action != MENU_ACTION_MESSAGE) action = MENU_ACTION_REFRESH; switch (action) { case MENU_ACTION_UP: case MENU_ACTION_DOWN: if (cbs && cbs->action_up_or_down) ret = cbs->action_up_or_down(type_offset, label_offset, action); break; case MENU_ACTION_SCROLL_UP: menu_navigation_descend_alphabet(menu, &menu->selection_ptr); break; case MENU_ACTION_SCROLL_DOWN: menu_navigation_ascend_alphabet(menu, &menu->selection_ptr); break; case MENU_ACTION_CANCEL: if (cbs && cbs->action_cancel) return cbs->action_cancel(path_offset, label_offset, type_offset, menu->selection_ptr); break; case MENU_ACTION_OK: if (cbs && cbs->action_ok) return cbs->action_ok(path_offset, label_offset, type_offset, menu->selection_ptr); break; case MENU_ACTION_START: if (cbs && cbs->action_start) return cbs->action_start(type_offset, label_offset, action); break; case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: if (cbs && cbs->action_toggle) ret = cbs->action_toggle(type_offset, label_offset, action); break; case MENU_ACTION_SELECT: if (cbs && cbs->action_select) ret = cbs->action_select(type_offset, label_offset, action); break; case MENU_ACTION_REFRESH: if (cbs && cbs->action_refresh) ret = cbs->action_refresh(menu->menu_list->selection_buf, menu->menu_list->menu_stack); break; case MENU_ACTION_MESSAGE: menu->msg_force = true; break; case MENU_ACTION_SEARCH: menu_input_search_start(); break; case MENU_ACTION_TEST: break; default: break; } if (ret) return ret; ret = mouse_post_iterate(cbs, path_offset, label_offset, type_offset, action); if (driver.video_data && driver.menu_ctx && driver.menu_ctx->render) driver.menu_ctx->render(); /* Have to defer it so we let settings refresh. */ if (menu->push_start_screen) { menu_list_push_stack(menu->menu_list, "", "help", 0, 0); menu->push_start_screen = false; } return ret; } static int action_select_default(unsigned type, const char *label, unsigned action) { menu_list_push_stack(driver.menu->menu_list, "", "info_screen", 0, driver.menu->selection_ptr); return 0; } static int action_start_lookup_setting(unsigned type, const char *label, unsigned action) { return menu_action_setting_set(type, label, MENU_ACTION_START); } static void menu_action_setting_disp_set_label_cheat_num_passes( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *w = 19; strlcpy(path_buf, path, path_buf_size); snprintf(type_str, type_str_size, "%u", g_extern.cheat->buf_size); } static void menu_action_setting_disp_set_label_remap_file_load( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *w = 19; strlcpy(path_buf, path, path_buf_size); fill_pathname_base(type_str, g_settings.input.remapping_path, type_str_size); } static void menu_action_setting_disp_set_label_configurations( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *w = 19; strlcpy(path_buf, path, path_buf_size); if (*g_extern.config_path) fill_pathname_base(type_str, g_extern.config_path, type_str_size); else strlcpy(type_str, "", type_str_size); } static void menu_action_setting_disp_set_label_shader_filter_pass( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned pass = 0; static const char *modes[] = { "Don't care", "Linear", "Nearest" }; (void)pass; (void)modes; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!driver.menu->shader) return; pass = (type - MENU_SETTINGS_SHADER_PASS_FILTER_0); strlcpy(type_str, modes[driver.menu->shader->pass[pass].filter], type_str_size); #endif } static void menu_action_setting_disp_set_label_shader_num_passes( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) snprintf(type_str, type_str_size, "%u", driver.menu->shader->passes); #endif } static void menu_action_setting_disp_set_label_shader_pass( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned pass = (type - MENU_SETTINGS_SHADER_PASS_0); (void)pass; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); strlcpy(type_str, "N/A", type_str_size); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (*driver.menu->shader->pass[pass].source.path) fill_pathname_base(type_str, driver.menu->shader->pass[pass].source.path, type_str_size); #endif } static void menu_action_setting_disp_set_label_shader_default_filter( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *type_str = '\0'; *w = 19; snprintf(type_str, type_str_size, "%s", g_settings.video.smooth ? "Linear" : "Nearest"); } static void menu_action_setting_disp_set_label_shader_parameter( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) const struct video_shader_parameter *param = NULL; struct video_shader *shader = NULL; #endif if (!driver.video_poke) return; if (!driver.video_data) return; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!driver.video_poke->get_current_shader) return; shader = driver.video_poke->get_current_shader(driver.video_data); if (!shader) return; param = &shader->parameters[type - MENU_SETTINGS_SHADER_PARAMETER_0]; if (!param) return; snprintf(type_str, type_str_size, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); #endif } static void menu_action_setting_disp_set_label_shader_preset_parameter( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) const struct video_shader_parameter *param = NULL; #endif *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!driver.menu->shader) return; param = &driver.menu->shader->parameters[type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0]; if (!param) return; snprintf(type_str, type_str_size, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); #endif } static void menu_action_setting_disp_set_label_shader_scale_pass( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned pass = 0; unsigned scale_value = 0; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); (void)pass; (void)scale_value; #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!driver.menu->shader) return; pass = (type - MENU_SETTINGS_SHADER_PASS_SCALE_0); scale_value = driver.menu->shader->pass[pass].fbo.scale_x; if (!scale_value) strlcpy(type_str, "Don't care", type_str_size); else snprintf(type_str, type_str_size, "%ux", scale_value); #endif } static void menu_action_setting_disp_set_label_menu_file_core( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { const char *alt = NULL; strlcpy(type_str, "(CORE)", type_str_size); menu_list_get_alt_at_offset(list, i, &alt); *w = strlen(type_str); if (alt) strlcpy(path_buf, alt, path_buf_size); } static void menu_action_setting_disp_set_label_input_desc( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned inp_desc_index_offset = type - MENU_SETTINGS_INPUT_DESC_BEGIN; unsigned inp_desc_user = inp_desc_index_offset / RARCH_FIRST_CUSTOM_BIND; unsigned inp_desc_button_index_offset = inp_desc_index_offset - (inp_desc_user * RARCH_FIRST_CUSTOM_BIND); unsigned remap_id = g_settings.input.remap_ids [inp_desc_user][inp_desc_button_index_offset]; snprintf(type_str, type_str_size, "%s", g_settings.input.binds[inp_desc_user][remap_id].desc); *w = 19; strlcpy(path_buf, path, path_buf_size); } static void menu_action_setting_disp_set_label_cheat( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned cheat_index = type - MENU_SETTINGS_CHEAT_BEGIN; if (cheat_index < g_extern.cheat->buf_size) snprintf(type_str, type_str_size, "%s : (%s)", (g_extern.cheat->cheats[cheat_index].code != NULL) ? g_extern.cheat->cheats[cheat_index].code : "N/A", g_extern.cheat->cheats[cheat_index].state ? "ON" : "OFF" ); *w = 19; strlcpy(path_buf, path, path_buf_size); } static void menu_action_setting_disp_set_label_perf_counters( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { const struct retro_perf_counter **counters = (const struct retro_perf_counter **)perf_counters_rarch; unsigned offset = type - MENU_SETTINGS_PERF_COUNTERS_BEGIN; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); if (!counters[offset]) return; if (!counters[offset]->call_cnt) return; snprintf(type_str, type_str_size, #ifdef _WIN32 "%I64u ticks, %I64u runs.", #else "%llu ticks, %llu runs.", #endif ((unsigned long long)counters[offset]->total / (unsigned long long)counters[offset]->call_cnt), (unsigned long long)counters[offset]->call_cnt); } static void menu_action_setting_disp_set_label_libretro_perf_counters( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { const struct retro_perf_counter **counters = (const struct retro_perf_counter **)perf_counters_libretro; unsigned offset = type - MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN; *type_str = '\0'; *w = 19; strlcpy(path_buf, path, path_buf_size); if (!counters[offset]) return; if (!counters[offset]->call_cnt) return; snprintf(type_str, type_str_size, #ifdef _WIN32 "%I64u ticks, %I64u runs.", #else "%llu ticks, %llu runs.", #endif ((unsigned long long)counters[offset]->total / (unsigned long long)counters[offset]->call_cnt), (unsigned long long)counters[offset]->call_cnt); } static void menu_action_setting_disp_set_label_menu_more( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { strlcpy(type_str, "...", type_str_size); *w = 19; strlcpy(path_buf, path, path_buf_size); } static void menu_action_setting_disp_set_label_menu_disk_index( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &g_extern.system.disk_control; unsigned images = 0, current = 0; *w = 19; *type_str = '\0'; strlcpy(path_buf, path, path_buf_size); if (!control) return; images = control->get_num_images(); current = control->get_image_index(); if (current >= images) strlcpy(type_str, "No Disk", type_str_size); else snprintf(type_str, type_str_size, "%u", current + 1); } static void menu_action_setting_disp_set_label_menu_video_resolution( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { unsigned width = 0, height = 0; *w = 19; *type_str = '\0'; (void)width; (void)height; #if defined(GEKKO) snprintf(type_str, type_str_size, "%.3ux%.3u%c", menu_gx_resolutions[menu_current_gx_resolution][0], menu_gx_resolutions[menu_current_gx_resolution][1], menu_gx_resolutions[menu_current_gx_resolution][1] > 300 ? 'i' : 'p'); #elif defined(__CELLOS_LV2__) width = gfx_ctx_get_resolution_width( g_extern.console.screen.resolutions.list [g_extern.console.screen.resolutions.current.idx]); height = gfx_ctx_get_resolution_height( g_extern.console.screen.resolutions.list [g_extern.console.screen.resolutions.current.idx]); snprintf(type_str, type_str_size, "%ux%u", width, height); #endif } static void menu_action_setting_generic_disp_set_label( unsigned *w, char *type_str, size_t type_str_size, const char *path, const char *label, char *path_buf, size_t path_buf_size) { *type_str = '\0'; if (label) strlcpy(type_str, label, type_str_size); *w = strlen(type_str); strlcpy(path_buf, path, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_plain( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(FILE)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_use_directory( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, NULL, path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_directory( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(DIR)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_carchive( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(COMP)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_shader( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(SHADER)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_subgroup( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, NULL, path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_shader_preset( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(PRESET)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_in_carchive( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(CFILE)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_overlay( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(OVERLAY)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_config( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(CONFIG)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_font( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(FONT)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_filter( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(FILTER)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_url( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(URL)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_rdb( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(RDB)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_cursor( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(CURSOR)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label_menu_file_cheat( file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { menu_action_setting_generic_disp_set_label(w, type_str, type_str_size, path, "(CHEAT)", path_buf, path_buf_size); } static void menu_action_setting_disp_set_label(file_list_t* list, unsigned *w, unsigned type, unsigned i, const char *label, char *type_str, size_t type_str_size, const char *entry_label, const char *path, char *path_buf, size_t path_buf_size) { *type_str = '\0'; *w = 19; if (!strcmp(label, "performance_counters")) *w = strlen(label); if (!strcmp(label, "history_list")) *w = strlen(label); if (type >= MENU_SETTINGS_CORE_OPTION_START) strlcpy( type_str, core_option_get_val(g_extern.system.core_options, type - MENU_SETTINGS_CORE_OPTION_START), type_str_size); else setting_data_get_label(list, type_str, type_str_size, w, type, label, entry_label, i); strlcpy(path_buf, path, path_buf_size); } static void menu_entries_cbs_init_bind_select(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_select = action_select_default; } static void menu_entries_cbs_init_bind_start(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_start = action_start_lookup_setting; if (!strcmp(label, "remap_file_load")) cbs->action_start = action_start_remap_file_load; else if (!strcmp(label, "video_shader_pass")) cbs->action_start = action_start_shader_pass; else if (!strcmp(label, "video_shader_scale_pass")) cbs->action_start = action_start_shader_scale_pass; else if (!strcmp(label, "video_shader_filter_pass")) cbs->action_start = action_start_shader_filter_pass; else if (!strcmp(label, "video_shader_num_passes")) cbs->action_start = action_start_shader_num_passes; else if (!strcmp(label, "cheat_num_passes")) cbs->action_start = action_start_cheat_num_passes; else if (type >= MENU_SETTINGS_SHADER_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PARAMETER_LAST) cbs->action_start = action_start_shader_action_parameter; else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST) cbs->action_start = action_start_shader_action_preset_parameter; else if (type >= MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN && type <= MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_END) cbs->action_start = action_start_performance_counters_core; else if (type >= MENU_SETTINGS_INPUT_DESC_BEGIN && type <= MENU_SETTINGS_INPUT_DESC_END) cbs->action_start = action_start_input_desc; else if (type >= MENU_SETTINGS_PERF_COUNTERS_BEGIN && type <= MENU_SETTINGS_PERF_COUNTERS_END) cbs->action_start = action_start_performance_counters_frontend; else if ((type >= MENU_SETTINGS_CORE_OPTION_START)) cbs->action_start = action_start_core_setting; } static void menu_entries_cbs_init_bind_content_list_switch(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_content_list_switch = deferred_push_content_list; } static void menu_entries_cbs_init_bind_cancel(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_cancel = action_cancel_lookup_setting; /* TODO - add some stuff here. */ cbs->action_cancel = action_cancel_pop_default; } static int is_rdb_entry(const char *label) { return ( !(strcmp(label, "rdb_entry_publisher")) || !(strcmp(label, "rdb_entry_developer")) || !(strcmp(label, "rdb_entry_origin")) || !(strcmp(label, "rdb_entry_franchise")) || !(strcmp(label, "rdb_entry_enhancement_hw")) || !(strcmp(label, "rdb_entry_esrb_rating")) || !(strcmp(label, "rdb_entry_bbfc_rating")) || !(strcmp(label, "rdb_entry_elspa_rating")) || !(strcmp(label, "rdb_entry_pegi_rating")) || !(strcmp(label, "rdb_entry_cero_rating")) || !(strcmp(label, "rdb_entry_edge_magazine_rating")) || !(strcmp(label, "rdb_entry_edge_magazine_issue")) || !(strcmp(label, "rdb_entry_releasemonth")) || !(strcmp(label, "rdb_entry_releaseyear")) || !(strcmp(label, "rdb_entry_max_users")) ); } static int is_settings_entry(const char *label) { return ( !strcmp(label, "Driver Settings") || !strcmp(label, "General Settings") || !strcmp(label, "Video Settings") || !strcmp(label, "Shader Settings") || !strcmp(label, "Font Settings") || !strcmp(label, "Audio Settings") || !strcmp(label, "Input Settings") || !strcmp(label, "Overlay Settings") || !strcmp(label, "Menu Settings") || !strcmp(label, "UI Settings") || !strcmp(label, "Patch Settings") || !strcmp(label, "Playlist Settings") || !strcmp(label, "Onscreen Keyboard Overlay Settings") || !strcmp(label, "Core Updater Settings") || !strcmp(label, "Network Settings") || !strcmp(label, "Archive Settings") || !strcmp(label, "User Settings") || !strcmp(label, "Path Settings") || !strcmp(label, "Privacy Settings")); } static void menu_entries_cbs_init_bind_ok(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1, const char *menu_label) { rarch_setting_t *setting = menu_action_find_setting(label); if (!cbs) return; if (!driver.menu) return; cbs->action_ok = action_ok_lookup_setting; if (elem0[0] != '\0' && is_rdb_entry(elem0)) { cbs->action_ok = action_ok_rdb_entry_submenu; return; } if (!strcmp(label, "custom_bind_all")) cbs->action_ok = action_ok_lookup_setting; else if (type == MENU_SETTINGS_CUSTOM_BIND_KEYBOARD || type == MENU_SETTINGS_CUSTOM_BIND) cbs->action_ok = action_ok_lookup_setting; else if (type >= MENU_SETTINGS_SHADER_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PARAMETER_LAST) cbs->action_ok = NULL; else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST) cbs->action_ok = NULL; else if (type >= MENU_SETTINGS_CHEAT_BEGIN && type <= MENU_SETTINGS_CHEAT_END) cbs->action_ok = action_ok_cheat; else if (!strcmp(label, "savestate")) cbs->action_ok = action_ok_save_state; else if (!strcmp(label, "loadstate")) cbs->action_ok = action_ok_load_state; else if (!strcmp(label, "resume_content")) cbs->action_ok = action_ok_resume_content; else if (!strcmp(label, "restart_content")) cbs->action_ok = action_ok_restart_content; else if (!strcmp(label, "take_screenshot")) cbs->action_ok = action_ok_screenshot; else if (!strcmp(label, "file_load_or_resume")) cbs->action_ok = action_ok_file_load_or_resume; else if (!strcmp(label, "quit_retroarch")) cbs->action_ok = action_ok_quit; else if (!strcmp(label, "save_new_config")) cbs->action_ok = action_ok_save_new_config; else if (!strcmp(label, "help")) cbs->action_ok = action_ok_help; else if (!strcmp(label, "video_shader_pass")) cbs->action_ok = action_ok_shader_pass; else if (!strcmp(label, "video_shader_preset")) cbs->action_ok = action_ok_shader_preset; else if (!strcmp(label, "cheat_file_load")) cbs->action_ok = action_ok_cheat_file; else if (!strcmp(label, "audio_dsp_plugin")) cbs->action_ok = action_ok_audio_dsp_plugin; else if (!strcmp(label, "video_filter")) cbs->action_ok = action_ok_video_filter; else if (!strcmp(label, "remap_file_load")) cbs->action_ok = action_ok_remap_file; else if (!strcmp(label, "video_shader_parameters") || !strcmp(label, "video_shader_preset_parameters") ) cbs->action_ok = action_ok_shader_parameters; else if ( !strcmp(label, "shader_options") || !strcmp(label, "Input Settings") || !strcmp(label, "core_options") || !strcmp(label, "core_cheat_options") || !strcmp(label, "core_input_remapping_options") || !strcmp(label, "core_information") || !strcmp(label, "disk_options") || !strcmp(label, "settings") || !strcmp(label, "performance_counters") || !strcmp(label, "frontend_counters") || !strcmp(label, "core_counters") || !strcmp(label, "management") || !strcmp(label, "options") ) cbs->action_ok = action_ok_push_default; else if ( !strcmp(label, "load_content") || !strcmp(label, "detect_core_list") ) cbs->action_ok = action_ok_push_content_list; else if (!strcmp(label, "history_list") || !strcmp(label, "core_updater_list") || !strcmp(label, "cursor_manager_list") || !strcmp(label, "database_manager_list") || (setting && setting->browser_selection_type == ST_DIR) ) cbs->action_ok = action_ok_push_generic_list; else if (!strcmp(label, "shader_apply_changes")) cbs->action_ok = action_ok_shader_apply_changes; else if (!strcmp(label, "cheat_apply_changes")) cbs->action_ok = action_ok_cheat_apply_changes; else if (!strcmp(label, "video_shader_preset_save_as")) cbs->action_ok = action_ok_shader_preset_save_as; else if (!strcmp(label, "cheat_file_save_as")) cbs->action_ok = action_ok_cheat_file_save_as; else if (!strcmp(label, "remap_file_save_as")) cbs->action_ok = action_ok_remap_file_save_as; else if (!strcmp(label, "core_list")) cbs->action_ok = action_ok_core_list; else if (!strcmp(label, "disk_image_append")) cbs->action_ok = action_ok_disk_image_append_list; else if (!strcmp(label, "configurations")) cbs->action_ok = action_ok_configurations_list; else switch (type) { case MENU_SETTINGS_VIDEO_RESOLUTION: cbs->action_ok = action_ok_video_resolution; break; case MENU_FILE_PLAYLIST_ENTRY: if (!strcmp(label, "rdb_entry_start_game")) cbs->action_ok = action_ok_rdb_playlist_entry; else cbs->action_ok = action_ok_playlist_entry; break; case MENU_FILE_CONTENTLIST_ENTRY: cbs->action_ok = action_ok_push_generic_list; break; case MENU_FILE_CHEAT: cbs->action_ok = action_ok_cheat_file_load; break; case MENU_FILE_REMAP: cbs->action_ok = action_ok_remap_file_load; break; case MENU_FILE_SHADER_PRESET: cbs->action_ok = action_ok_shader_preset_load; break; case MENU_FILE_SHADER: cbs->action_ok = action_ok_shader_pass_load; break; case MENU_FILE_IMAGE: cbs->action_ok = action_ok_menu_wallpaper_load; break; case MENU_FILE_USE_DIRECTORY: cbs->action_ok = action_ok_path_use_directory; break; case MENU_FILE_CONFIG: cbs->action_ok = action_ok_config_load; break; case MENU_FILE_DIRECTORY: cbs->action_ok = action_ok_directory_push; break; case MENU_FILE_CARCHIVE: cbs->action_ok = action_ok_compressed_archive_push; break; case MENU_FILE_CORE: if (!strcmp(menu_label, "deferred_core_list")) cbs->action_ok = action_ok_core_load_deferred; else if (!strcmp(menu_label, "core_list")) cbs->action_ok = action_ok_core_load; else if (!strcmp(menu_label, "core_updater_list")) cbs->action_ok = action_ok_core_download; else return; break; case MENU_FILE_DOWNLOAD_CORE: cbs->action_ok = action_ok_core_updater_list; break; case MENU_FILE_DOWNLOAD_CORE_INFO: break; case MENU_FILE_RDB: if (!strcmp(menu_label, "deferred_database_manager_list")) cbs->action_ok = action_ok_database_manager_list_deferred; else if (!strcmp(menu_label, "database_manager_list") || !strcmp(menu_label, "Horizontal Menu")) cbs->action_ok = action_ok_database_manager_list; else return; break; case MENU_FILE_RDB_ENTRY: cbs->action_ok = action_ok_rdb_entry; break; case MENU_FILE_CURSOR: if (!strcmp(menu_label, "deferred_database_manager_list")) cbs->action_ok = action_ok_cursor_manager_list_deferred; else if (!strcmp(menu_label, "cursor_manager_list")) cbs->action_ok = action_ok_cursor_manager_list; break; case MENU_FILE_FONT: case MENU_FILE_OVERLAY: case MENU_FILE_AUDIOFILTER: case MENU_FILE_VIDEOFILTER: cbs->action_ok = action_ok_set_path; break; #ifdef HAVE_COMPRESSION case MENU_FILE_IN_CARCHIVE: #endif case MENU_FILE_PLAIN: if (!strcmp(menu_label, "detect_core_list")) cbs->action_ok = action_ok_file_load_with_detect_core; else if (!strcmp(menu_label, "disk_image_append")) cbs->action_ok = action_ok_disk_image_append; else cbs->action_ok = action_ok_file_load; break; case MENU_SETTINGS_CUSTOM_VIEWPORT: cbs->action_ok = action_ok_custom_viewport; break; case MENU_SETTINGS: case MENU_SETTING_GROUP: case MENU_SETTING_SUBGROUP: cbs->action_ok = action_ok_push_default; break; case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_CYCLE_TRAY_STATUS: cbs->action_ok = action_ok_disk_cycle_tray_status; break; default: return; } } static void menu_entries_cbs_init_bind_up_or_down(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_up_or_down = action_bind_up_or_down_generic; } static void menu_entries_cbs_init_bind_toggle(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1, const char *menu_label) { int i; if (!cbs) return; if (label) { if (is_settings_entry(elem0)) { cbs->action_toggle = action_toggle_scroll; return; } } cbs->action_toggle = menu_action_setting_set; switch (type) { case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX: cbs->action_toggle = disk_options_disk_idx_toggle; break; case MENU_FILE_PLAIN: case MENU_FILE_DIRECTORY: case MENU_FILE_CARCHIVE: case MENU_FILE_CORE: case MENU_FILE_RDB: case MENU_FILE_RDB_ENTRY: case MENU_FILE_CURSOR: case MENU_FILE_SHADER: case MENU_FILE_SHADER_PRESET: case MENU_FILE_IMAGE: case MENU_FILE_OVERLAY: case MENU_FILE_VIDEOFILTER: case MENU_FILE_AUDIOFILTER: case MENU_FILE_CONFIG: case MENU_FILE_USE_DIRECTORY: case MENU_FILE_PLAYLIST_ENTRY: case MENU_FILE_DOWNLOAD_CORE: case MENU_FILE_CHEAT: case MENU_FILE_REMAP: case MENU_SETTING_GROUP: if (!strcmp(menu_label, "Horizontal Menu") || !strcmp(menu_label, "Main Menu")) cbs->action_toggle = action_toggle_mainmenu; else cbs->action_toggle = action_toggle_scroll; break; case MENU_SETTING_ACTION: case MENU_FILE_CONTENTLIST_ENTRY: cbs->action_toggle = action_toggle_mainmenu; break; } if (strstr(label, "rdb_entry")) cbs->action_toggle = action_toggle_scroll; else if (type >= MENU_SETTINGS_SHADER_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PARAMETER_LAST) cbs->action_toggle = shader_action_parameter_toggle; else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST) cbs->action_toggle = shader_action_parameter_preset_toggle; else if (type >= MENU_SETTINGS_CHEAT_BEGIN && type <= MENU_SETTINGS_CHEAT_END) cbs->action_toggle = action_toggle_cheat; else if (type >= MENU_SETTINGS_INPUT_DESC_BEGIN && type <= MENU_SETTINGS_INPUT_DESC_END) cbs->action_toggle = action_toggle_input_desc; else if (!strcmp(label, "savestate") || !strcmp(label, "loadstate")) cbs->action_toggle = action_toggle_save_state; else if (!strcmp(label, "video_shader_scale_pass")) cbs->action_toggle = action_toggle_shader_scale_pass; else if (!strcmp(label, "video_shader_filter_pass")) cbs->action_toggle = action_toggle_shader_filter_pass; else if (!strcmp(label, "video_shader_default_filter")) cbs->action_toggle = action_toggle_shader_filter_default; else if (!strcmp(label, "video_shader_num_passes")) cbs->action_toggle = action_toggle_shader_num_passes; else if (!strcmp(label, "cheat_num_passes")) cbs->action_toggle = action_toggle_cheat_num_passes; else if (type == MENU_SETTINGS_VIDEO_RESOLUTION) cbs->action_toggle = action_toggle_video_resolution; else if ((type >= MENU_SETTINGS_CORE_OPTION_START)) cbs->action_toggle = core_setting_toggle; for (i = 0; i < MAX_USERS; i++) { char label_setting[PATH_MAX_LENGTH]; snprintf(label_setting, sizeof(label_setting), "input_player%d_joypad_index", i + 1); if (!strcmp(label, label_setting)) cbs->action_toggle = menu_action_setting_set; } } static void menu_entries_cbs_init_bind_refresh(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (cbs) cbs->action_refresh = action_refresh_default; } static void menu_entries_cbs_init_bind_iterate(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (cbs) cbs->action_iterate = action_iterate_main; } static void menu_entries_cbs_init_bind_get_string_representation(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; if (type >= MENU_SETTINGS_INPUT_DESC_BEGIN && type <= MENU_SETTINGS_INPUT_DESC_END) cbs->action_get_representation = menu_action_setting_disp_set_label_input_desc; else if (type >= MENU_SETTINGS_CHEAT_BEGIN && type <= MENU_SETTINGS_CHEAT_END) cbs->action_get_representation = menu_action_setting_disp_set_label_cheat; else if (type >= MENU_SETTINGS_PERF_COUNTERS_BEGIN && type <= MENU_SETTINGS_PERF_COUNTERS_END) cbs->action_get_representation = menu_action_setting_disp_set_label_perf_counters; else if (type >= MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN && type <= MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_END) cbs->action_get_representation = menu_action_setting_disp_set_label_libretro_perf_counters; else if (type >= MENU_SETTINGS_SHADER_PRESET_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PRESET_PARAMETER_LAST) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_preset_parameter; else if (type >= MENU_SETTINGS_SHADER_PARAMETER_0 && type <= MENU_SETTINGS_SHADER_PARAMETER_LAST) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_parameter; else if (!strcmp(label, "cheat_num_passes")) cbs->action_get_representation = menu_action_setting_disp_set_label_cheat_num_passes; else if (!strcmp(label, "remap_file_load")) cbs->action_get_representation = menu_action_setting_disp_set_label_remap_file_load; else if (!strcmp(label, "video_shader_filter_pass")) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_filter_pass; else if (!strcmp(label, "video_shader_scale_pass")) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_scale_pass; else if (!strcmp(label, "video_shader_num_passes")) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_num_passes; else if (!strcmp(label, "video_shader_pass")) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_pass; else if (!strcmp(label, "video_shader_default_filter")) cbs->action_get_representation = menu_action_setting_disp_set_label_shader_default_filter; else if (!strcmp(label, "configurations")) cbs->action_get_representation = menu_action_setting_disp_set_label_configurations; else { switch (type) { case MENU_FILE_CORE: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_core; break; case MENU_FILE_PLAIN: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_plain; break; case MENU_FILE_USE_DIRECTORY: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_use_directory; break; case MENU_FILE_DIRECTORY: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_directory; break; case MENU_FILE_CARCHIVE: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_carchive; break; case MENU_FILE_OVERLAY: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_overlay; break; case MENU_FILE_FONT: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_font; break; case MENU_FILE_SHADER: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_shader; break; case MENU_FILE_SHADER_PRESET: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_shader_preset; break; case MENU_FILE_CONFIG: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_config; break; case MENU_FILE_IN_CARCHIVE: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_in_carchive; break; case MENU_FILE_VIDEOFILTER: case MENU_FILE_AUDIOFILTER: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_filter; break; case MENU_FILE_DOWNLOAD_CORE: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_url; break; case MENU_FILE_RDB: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_rdb; break; case MENU_FILE_CURSOR: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_cursor; break; case MENU_FILE_CHEAT: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_cheat; break; case MENU_SETTING_SUBGROUP: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_file_subgroup; break; case MENU_SETTINGS_CUSTOM_VIEWPORT: case MENU_SETTINGS_CUSTOM_BIND_ALL: case MENU_SETTINGS_CUSTOM_BIND_DEFAULT_ALL: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_more; break; case MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_disk_index; break; case MENU_SETTINGS_VIDEO_RESOLUTION: cbs->action_get_representation = menu_action_setting_disp_set_label_menu_video_resolution; break; default: cbs->action_get_representation = menu_action_setting_disp_set_label; break; } } } static void menu_entries_cbs_init_bind_deferred_push(menu_file_list_cbs_t *cbs, const char *path, const char *label, unsigned type, size_t idx, const char *elem0, const char *elem1) { if (!cbs) return; cbs->action_deferred_push = deferred_push_default; if ((strlen(elem1) != 0) && !!strcmp(elem0, elem1)) { if (is_settings_entry(elem0)) { if (!g_settings.menu.collapse_subgroups_enable) { cbs->action_deferred_push = deferred_push_settings_subgroup; return; } } } if (strstr(label, "deferred_rdb_entry_detail")) cbs->action_deferred_push = deferred_push_rdb_entry_detail; else if (!strcmp(label, "core_updater_list")) cbs->action_deferred_push = deferred_push_core_updater_list; else if (!strcmp(label, "history_list")) cbs->action_deferred_push = deferred_push_history_list; else if (!strcmp(label, "database_manager_list")) cbs->action_deferred_push = deferred_push_database_manager_list; else if (!strcmp(label, "cursor_manager_list")) cbs->action_deferred_push = deferred_push_cursor_manager_list; else if (!strcmp(label, "cheat_file_load")) cbs->action_deferred_push = deferred_push_cheat_file_load; else if (!strcmp(label, "remap_file_load")) cbs->action_deferred_push = deferred_push_remap_file_load; else if (!strcmp(label, "content_actions")) cbs->action_deferred_push = deferred_push_content_actions; else if (!strcmp(label, "shader_options")) cbs->action_deferred_push = deferred_push_shader_options; else if (!strcmp(label, "options")) cbs->action_deferred_push = deferred_push_options; else if (!strcmp(label, "management")) cbs->action_deferred_push = deferred_push_management_options; else if (type == MENU_SETTING_GROUP) cbs->action_deferred_push = deferred_push_category; else if (!strcmp(label, "deferred_core_list")) cbs->action_deferred_push = deferred_push_core_list_deferred; else if (!strcmp(label, "deferred_database_manager_list")) cbs->action_deferred_push = deferred_push_database_manager_list_deferred; else if (!strcmp(label, "deferred_cursor_manager_list")) cbs->action_deferred_push = deferred_push_cursor_manager_list_deferred; else if ( !strcmp(label, "deferred_cursor_manager_list_rdb_entry_publisher") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_developer") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_origin") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_franchise") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_enhancement_hw") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_esrb_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_bbfc_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_elspa_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_pegi_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_cero_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_edge_magazine_rating") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_edge_magazine_issue") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_max_users") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_releasemonth") || !strcmp(label, "deferred_cursor_manager_list_rdb_entry_releaseyear") ) cbs->action_deferred_push = deferred_push_cursor_manager_list_deferred_query_subsearch; else if (!strcmp(label, "core_information")) cbs->action_deferred_push = deferred_push_core_information; else if (!strcmp(label, "performance_counters")) cbs->action_deferred_push = deferred_push_performance_counters; else if (!strcmp(label, "core_counters")) cbs->action_deferred_push = deferred_push_core_counters; else if (!strcmp(label, "video_shader_preset_parameters")) cbs->action_deferred_push = deferred_push_video_shader_preset_parameters; else if (!strcmp(label, "video_shader_parameters")) cbs->action_deferred_push = deferred_push_video_shader_parameters; else if (!strcmp(label, "settings")) cbs->action_deferred_push = deferred_push_settings; else if (!strcmp(label, "frontend_counters")) cbs->action_deferred_push = deferred_push_frontend_counters; else if (!strcmp(label, "core_options")) cbs->action_deferred_push = deferred_push_core_options; else if (!strcmp(label, "core_cheat_options")) cbs->action_deferred_push = deferred_push_core_cheat_options; else if (!strcmp(label, "core_input_remapping_options")) cbs->action_deferred_push = deferred_push_core_input_remapping_options; else if (!strcmp(label, "disk_options")) cbs->action_deferred_push = deferred_push_disk_options; else if (!strcmp(label, "core_list")) cbs->action_deferred_push = deferred_push_core_list; else if (!strcmp(label, "configurations")) cbs->action_deferred_push = deferred_push_configurations; else if (!strcmp(label, "video_shader_preset")) cbs->action_deferred_push = deferred_push_video_shader_preset; else if (!strcmp(label, "video_shader_pass")) cbs->action_deferred_push = deferred_push_video_shader_pass; else if (!strcmp(label, "video_filter")) cbs->action_deferred_push = deferred_push_video_filter; else if (!strcmp(label, "menu_wallpaper")) cbs->action_deferred_push = deferred_push_images; else if (!strcmp(label, "audio_dsp_plugin")) cbs->action_deferred_push = deferred_push_audio_dsp_plugin; else if (!strcmp(label, "input_overlay")) cbs->action_deferred_push = deferred_push_input_overlay; else if (!strcmp(label, "input_osk_overlay")) cbs->action_deferred_push = deferred_push_input_osk_overlay; else if (!strcmp(label, "video_font_path")) cbs->action_deferred_push = deferred_push_video_font_path; else if (!strcmp(label, "game_history_path")) cbs->action_deferred_push = deferred_push_content_history_path; else if (!strcmp(label, "detect_core_list")) cbs->action_deferred_push = deferred_push_detect_core_list; } void menu_entries_cbs_init(void *data, const char *path, const char *label, unsigned type, size_t idx) { struct string_list *str_list = NULL; char elem0[PATH_MAX_LENGTH], elem1[PATH_MAX_LENGTH]; const char *menu_label = NULL; menu_file_list_cbs_t *cbs = NULL; file_list_t *list = (file_list_t*)data; if (!list) return; if (!(cbs = (menu_file_list_cbs_t*)list->list[idx].actiondata)) return; menu_list_get_last_stack(driver.menu->menu_list, NULL, &menu_label, NULL); if (label) str_list = string_split(label, "|"); if (str_list && str_list->size > 0) strlcpy(elem0, str_list->elems[0].data, sizeof(elem0)); else elem0[0]='\0'; if (str_list && str_list->size > 1) strlcpy(elem1, str_list->elems[1].data, sizeof(elem1)); else elem1[0]='\0'; if (str_list) { string_list_free(str_list); str_list = NULL; } menu_entries_cbs_init_bind_ok(cbs, path, label, type, idx, elem0, elem1, menu_label); menu_entries_cbs_init_bind_cancel(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_start(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_select(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_content_list_switch(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_up_or_down(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_toggle(cbs, path, label, type, idx, elem0, elem1, menu_label); menu_entries_cbs_init_bind_deferred_push(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_refresh(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_iterate(cbs, path, label, type, idx, elem0, elem1); menu_entries_cbs_init_bind_get_string_representation(cbs, path, label, type, idx, elem0, elem1); }