/* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * 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 #include "menu.h" #include "menu_setting.h" #include "../driver.h" #include "../gfx/video_monitor.h" #include "../dynamic.h" #include "../input/input_autodetect.h" #include "../config.def.h" #include "../file_ext.h" #include "../performance.h" #if defined(__CELLOS_LV2__) #include #if (CELL_SDK_VERSION > 0x340000) #include #endif #endif static void menu_settings_info_list_free(rarch_setting_info_t *list_info) { if (list_info) free(list_info); list_info = NULL; } static bool menu_settings_list_append(rarch_setting_t **list, rarch_setting_info_t *list_info, rarch_setting_t value) { if (!list || !*list || !list_info) return false; if (list_info->index == list_info->size) { list_info->size *= 2; *list = (rarch_setting_t*) realloc(*list, sizeof(rarch_setting_t) * list_info->size); if (!*list) return false; } (*list)[list_info->index++] = value; return true; } static void null_write_handler(void *data) { (void)data; } static void menu_settings_list_current_add_bind_type( rarch_setting_t **list, rarch_setting_info_t *list_info, unsigned type) { unsigned idx = list_info->index - 1; (*list)[idx].bind_type = type; } static void menu_settings_list_current_add_flags( rarch_setting_t **list, rarch_setting_info_t *list_info, unsigned values) { unsigned idx = list_info->index - 1; (*list)[idx].flags |= values; if (values & SD_FLAG_IS_DEFERRED) { (*list)[idx].deferred_handler = (*list)[idx].change_handler; (*list)[idx].change_handler = null_write_handler; } } static void menu_settings_list_current_add_range( rarch_setting_t **list, rarch_setting_info_t *list_info, float min, float max, float step, bool enforce_minrange_enable, bool enforce_maxrange_enable) { unsigned idx = list_info->index - 1; (*list)[idx].min = min; (*list)[idx].step = step; (*list)[idx].max = max; (*list)[idx].enforce_minrange = enforce_minrange_enable; (*list)[idx].enforce_maxrange = enforce_maxrange_enable; menu_settings_list_current_add_flags(list, list_info, SD_FLAG_HAS_RANGE); } static void menu_settings_list_current_add_values( rarch_setting_t **list, rarch_setting_info_t *list_info, const char *values) { unsigned idx = list_info->index - 1; (*list)[idx].values = values; } static void menu_settings_list_current_add_cmd( rarch_setting_t **list, rarch_setting_info_t *list_info, enum event_command values) { unsigned idx = list_info->index - 1; (*list)[idx].cmd_trigger.idx = values; } void menu_settings_list_free(rarch_setting_t *list) { if (list) free(list); } static rarch_setting_t *menu_setting_list_new(unsigned size) { rarch_setting_t *list = (rarch_setting_t*)calloc(size, sizeof(*list)); if (!list) return NULL; return list; } int menu_setting_set_flags(rarch_setting_t *setting) { if (!setting) return 0; if (setting->flags & SD_FLAG_IS_DRIVER) return MENU_SETTING_DRIVER; switch (setting->type) { case ST_ACTION: return MENU_SETTING_ACTION; case ST_PATH: return MENU_FILE_PATH; case ST_GROUP: return MENU_SETTING_GROUP; case ST_SUB_GROUP: return MENU_SETTING_SUBGROUP; default: break; } return 0; } static int setting_generic_action_ok_default(void *data, unsigned action) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; if (setting->cmd_trigger.idx != EVENT_CMD_NONE) setting->cmd_trigger.triggered = true; return 0; } int menu_setting_generic(rarch_setting_t *setting) { if (setting_generic_action_ok_default(setting, 0) != 0) return -1; if (setting->change_handler) setting->change_handler(setting); if (setting->flags & SD_FLAG_EXIT && setting->cmd_trigger.triggered) { setting->cmd_trigger.triggered = false; return -1; } return 0; } static int setting_handler(rarch_setting_t *setting, unsigned action) { if (!setting) return -1; switch (action) { case MENU_ACTION_UP: case MENU_ACTION_DOWN: if (setting->action_up_or_down) return setting->action_up_or_down(setting, action); break; case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: if (setting->action_toggle) return setting->action_toggle(setting, action, true); break; case MENU_ACTION_OK: if (setting->action_ok) return setting->action_ok(setting, action); break; case MENU_ACTION_CANCEL: if (setting->action_cancel) return setting->action_cancel(setting, action); break; case MENU_ACTION_START: if (setting->action_start) return setting->action_start(setting); break; } return -1; } int menu_action_handle_setting(rarch_setting_t *setting, unsigned type, unsigned action, bool wraparound) { menu_displaylist_info_t info = {0}; if (!setting) return -1; switch (setting->type) { case ST_PATH: if (action == MENU_ACTION_OK) { menu_handle_t *menu = menu_driver_get_ptr(); info.list = menu->menu_list->menu_stack; info.type = type; info.directory_ptr = menu->navigation.selection_ptr; strlcpy(info.path, setting->default_value.string, sizeof(info.path)); strlcpy(info.label, setting->name, sizeof(info.label)); menu_displaylist_push_list(&info, DISPLAYLIST_GENERIC); } /* fall-through. */ case ST_BOOL: case ST_INT: case ST_UINT: case ST_HEX: case ST_FLOAT: case ST_STRING: case ST_DIR: case ST_BIND: case ST_ACTION: if (setting_handler(setting, action) == 0) return menu_setting_generic(setting); break; default: break; } return -1; } static rarch_setting_t *menu_setting_get_ptr(void) { menu_handle_t *menu = menu_driver_get_ptr(); if (!menu) return NULL; return menu->list_settings; } /** * setting_reset: * @settings : pointer to settings * @name : name of setting to search for * * Search for a setting with a specified name (@name). * * Returns: pointer to setting if found, NULL otherwise. **/ static rarch_setting_t* setting_find_setting( rarch_setting_t* settings, const char* name) { bool found = false; if (!settings || !name) return NULL; for (; settings->type != ST_NONE; settings++) { if (settings->type <= ST_GROUP && !strcmp(settings->name, name)) { found = true; break; } } if (!found) return NULL; if (settings->short_description && settings->short_description[0] == '\0') return NULL; if (settings->read_handler) settings->read_handler(settings); return settings; } rarch_setting_t *menu_setting_find(const char *label) { rarch_setting_t *settings = menu_setting_get_ptr(); if (!settings) return NULL; return setting_find_setting(settings, label); } int menu_setting_set(unsigned type, const char *label, unsigned action, bool wraparound) { int ret = 0; rarch_setting_t *setting = NULL; menu_handle_t *menu = menu_driver_get_ptr(); if (!menu) return 0; setting = menu_setting_find( menu->menu_list->selection_buf->list [menu->navigation.selection_ptr].label); if (!setting) return 0; ret = menu_action_handle_setting(setting, type, action, wraparound); if (ret == -1) return 0; return ret; } void menu_setting_apply_deferred(void) { rarch_setting_t *setting = menu_setting_get_ptr(); if (!setting) return; for (; setting->type != ST_NONE; setting++) { if (setting->type >= ST_GROUP) continue; if (!(setting->flags & SD_FLAG_IS_DEFERRED)) continue; switch (setting->type) { case ST_BOOL: if (*setting->value.boolean != setting->original_value.boolean) { setting->original_value.boolean = *setting->value.boolean; setting->deferred_handler(setting); } break; case ST_INT: if (*setting->value.integer != setting->original_value.integer) { setting->original_value.integer = *setting->value.integer; setting->deferred_handler(setting); } break; case ST_UINT: if (*setting->value.unsigned_integer != setting->original_value.unsigned_integer) { setting->original_value.unsigned_integer = *setting->value.unsigned_integer; setting->deferred_handler(setting); } break; case ST_FLOAT: if (*setting->value.fraction != setting->original_value.fraction) { setting->original_value.fraction = *setting->value.fraction; setting->deferred_handler(setting); } break; case ST_PATH: case ST_DIR: case ST_STRING: case ST_BIND: /* Always run the deferred write handler */ setting->deferred_handler(setting); break; default: break; } } } /** * setting_reset_setting: * @setting : pointer to setting * * Reset a setting's value to its defaults. **/ static void setting_reset_setting(rarch_setting_t* setting) { if (!setting) return; switch (setting->type) { case ST_BOOL: *setting->value.boolean = setting->default_value.boolean; break; case ST_INT: *setting->value.integer = setting->default_value.integer; break; case ST_UINT: *setting->value.unsigned_integer = setting->default_value.unsigned_integer; break; case ST_FLOAT: *setting->value.fraction = setting->default_value.fraction; break; case ST_BIND: *setting->value.keybind = *setting->default_value.keybind; break; case ST_STRING: case ST_PATH: case ST_DIR: if (setting->default_value.string) { if (setting->type == ST_STRING) setting_set_with_string_representation(setting, setting->default_value.string); else fill_pathname_expand_special(setting->value.string, setting->default_value.string, setting->size); } break; /* TODO */ case ST_ACTION: break; case ST_HEX: break; case ST_GROUP: break; case ST_SUB_GROUP: break; case ST_END_GROUP: break; case ST_END_SUB_GROUP: break; case ST_NONE: break; } if (setting->change_handler) setting->change_handler(setting); } /** * setting_set_with_string_representation: * @setting : pointer to setting * @value : value for the setting (string) * * Set a settings' value with a string. It is assumed * that the string has been properly formatted. **/ int setting_set_with_string_representation(rarch_setting_t* setting, const char* value) { if (!setting || !value) return -1; switch (setting->type) { case ST_INT: sscanf(value, "%d", setting->value.integer); if (setting->flags & SD_FLAG_HAS_RANGE) { if (*setting->value.integer < setting->min) *setting->value.integer = setting->min; if (*setting->value.integer > setting->max) *setting->value.integer = setting->max; } break; case ST_UINT: sscanf(value, "%u", setting->value.unsigned_integer); if (setting->flags & SD_FLAG_HAS_RANGE) { if (*setting->value.unsigned_integer < setting->min) *setting->value.unsigned_integer = setting->min; if (*setting->value.unsigned_integer > setting->max) *setting->value.unsigned_integer = setting->max; } break; case ST_FLOAT: sscanf(value, "%f", setting->value.fraction); if (setting->flags & SD_FLAG_HAS_RANGE) { if (*setting->value.fraction < setting->min) *setting->value.fraction = setting->min; if (*setting->value.fraction > setting->max) *setting->value.fraction = setting->max; } break; case ST_PATH: case ST_DIR: case ST_STRING: case ST_ACTION: strlcpy(setting->value.string, value, setting->size); break; case ST_BOOL: if (!strcmp(value, "true")) *setting->value.boolean = true; else if (!strcmp(value, "false")) *setting->value.boolean = false; break; /* TODO */ case ST_HEX: break; case ST_GROUP: break; case ST_SUB_GROUP: break; case ST_END_GROUP: break; case ST_END_SUB_GROUP: break; case ST_NONE: break; case ST_BIND: break; } if (setting->change_handler) setting->change_handler(setting); return 0; } /** * setting_get_string_representation: * @setting : pointer to setting * @s : buffer to write contents of string representation to. * @len : size of the buffer (@s) * * Get a setting value's string representation. **/ void setting_get_string_representation(void *data, char *s, size_t len) { rarch_setting_t* setting = (rarch_setting_t*)data; if (!setting || !s) return; if (setting->get_string_representation) setting->get_string_representation(setting, s, len); } /** ******* ACTION START CALLBACK FUNCTIONS ******* **/ /** * setting_action_start_savestates: * @data : pointer to setting * * Function callback for 'Savestate' action's 'Action Start' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int setting_action_start_savestates(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return -1; settings->state_slot = 0; return 0; } static int setting_action_start_bind_device(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return -1; settings->input.joypad_map[setting->index_offset] = setting->index_offset; return 0; } static int setting_generic_action_start_default(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; setting_reset_setting(setting); return 0; } static int setting_action_start_analog_dpad_mode(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; *setting->value.unsigned_integer = 0; return 0; } static int setting_action_start_libretro_device_type(void *data) { unsigned current_device, i, devices[128], types = 0, port = 0; const struct retro_controller_info *desc = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (setting_generic_action_start_default(setting) != 0) return -1; port = setting->index_offset; devices[types++] = RETRO_DEVICE_NONE; devices[types++] = RETRO_DEVICE_JOYPAD; /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!global->system.num_ports) devices[types++] = RETRO_DEVICE_ANALOG; desc = port < global->system.num_ports ? &global->system.ports[port] : NULL; if (desc) { for (i = 0; i < desc->num_types; i++) { unsigned id = desc->types[i].id; if (types < ARRAY_SIZE(devices) && id != RETRO_DEVICE_NONE && id != RETRO_DEVICE_JOYPAD) devices[types++] = id; } } current_device = RETRO_DEVICE_JOYPAD; settings->input.libretro_device[port] = current_device; pretro_set_controller_port_device(port, current_device); return 0; } static int setting_action_start_video_refresh_rate_auto( void *data) { video_monitor_reset(); return 0; } static int setting_string_action_start_generic(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; *setting->value.string = '\0'; return 0; } static int setting_bind_action_start(void *data) { struct retro_keybind *keybind = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; struct retro_keybind *def_binds = (struct retro_keybind *)retro_keybinds_1; global_t *global = global_get_ptr(); if (!setting) return -1; keybind = (struct retro_keybind*)setting->value.keybind; if (!keybind) return -1; if (!global->menu.bind_mode_keyboard) { keybind->joykey = NO_BTN; keybind->joyaxis = AXIS_NONE; return 0; } if (setting->index_offset) def_binds = (struct retro_keybind*)retro_keybinds_rest; if (!def_binds) return -1; keybind->key = def_binds[setting->bind_type - MENU_SETTINGS_BIND_BEGIN].key; return 0; } /** ******* ACTION TOGGLE CALLBACK FUNCTIONS ******* **/ /** * setting_action_toggle_analog_dpad_mode * @data : pointer to setting * @action : toggle action value. Can be either one of : * MENU_ACTION_RIGHT | MENU_ACTION_LEFT * * Function callback for 'Analog D-Pad Mode' action's 'Action Toggle' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int setting_action_toggle_analog_dpad_mode(void *data, unsigned action, bool wraparound) { unsigned port = 0; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return -1; port = setting->index_offset; switch (action) { case MENU_ACTION_LEFT: settings->input.analog_dpad_mode[port] = (settings->input.analog_dpad_mode [port] + ANALOG_DPAD_LAST - 1) % ANALOG_DPAD_LAST; break; case MENU_ACTION_RIGHT: settings->input.analog_dpad_mode[port] = (settings->input.analog_dpad_mode[port] + 1) % ANALOG_DPAD_LAST; break; } return 0; } /** * setting_action_toggle_libretro_device_type * @data : pointer to setting * @action : toggle action value. Can be either one of : * MENU_ACTION_RIGHT | MENU_ACTION_LEFT * * Function callback for 'Libretro Device Type' action's 'Action Toggle' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int setting_action_toggle_libretro_device_type( void *data, unsigned action, bool wraparound) { unsigned current_device, current_idx, i, devices[128], types = 0, port = 0; const struct retro_controller_info *desc = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!setting) return -1; port = setting->index_offset; devices[types++] = RETRO_DEVICE_NONE; devices[types++] = RETRO_DEVICE_JOYPAD; /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!global->system.num_ports) devices[types++] = RETRO_DEVICE_ANALOG; if (port < global->system.num_ports) desc = &global->system.ports[port]; if (desc) { for (i = 0; i < desc->num_types; i++) { unsigned id = desc->types[i].id; if (types < ARRAY_SIZE(devices) && id != RETRO_DEVICE_NONE && id != RETRO_DEVICE_JOYPAD) devices[types++] = id; } } current_device = settings->input.libretro_device[port]; current_idx = 0; for (i = 0; i < types; i++) { if (current_device == devices[i]) { current_idx = i; break; } } switch (action) { case MENU_ACTION_LEFT: current_device = devices [(current_idx + types - 1) % types]; settings->input.libretro_device[port] = current_device; pretro_set_controller_port_device(port, current_device); break; case MENU_ACTION_RIGHT: current_device = devices [(current_idx + 1) % types]; settings->input.libretro_device[port] = current_device; pretro_set_controller_port_device(port, current_device); break; } return 0; } /** * setting_action_toggle_savestates * @data : pointer to setting * @action : toggle action value. Can be either one of : * MENU_ACTION_RIGHT | MENU_ACTION_LEFT * * Function callback for 'SaveStates' action's 'Action Toggle' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int setting_action_toggle_savestates( void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return -1; switch (action) { case MENU_ACTION_LEFT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case MENU_ACTION_RIGHT: settings->state_slot++; break; } return 0; } /** * setting_action_toggle_bind_device * @data : pointer to setting * @action : toggle action value. Can be either one of : * MENU_ACTION_RIGHT | MENU_ACTION_LEFT * * Function callback for 'Bind Device' action's 'Action Toggle' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int setting_action_toggle_bind_device(void *data, unsigned action, bool wraparound) { unsigned *p = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return -1; p = &settings->input.joypad_map[setting->index_offset]; switch (action) { case MENU_ACTION_LEFT: if ((*p) >= settings->input.max_users) *p = settings->input.max_users - 1; else if ((*p) > 0) (*p)--; break; case MENU_ACTION_RIGHT: if (*p < settings->input.max_users) (*p)++; break; } return 0; } static int setting_bool_action_toggle_default(void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; switch (action) { case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: *setting->value.boolean = !(*setting->value.boolean); break; } return 0; } static int setting_uint_action_toggle_default(void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; switch (action) { case MENU_ACTION_LEFT: if (*setting->value.unsigned_integer != setting->min) *setting->value.unsigned_integer = *setting->value.unsigned_integer - setting->step; if (setting->enforce_minrange) { if (*setting->value.unsigned_integer < setting->min) *setting->value.unsigned_integer = setting->min; } break; case MENU_ACTION_RIGHT: *setting->value.unsigned_integer = *setting->value.unsigned_integer + setting->step; if (setting->enforce_maxrange) { if (*setting->value.unsigned_integer > setting->max) *setting->value.unsigned_integer = setting->max; } break; } return 0; } static int setting_fraction_action_toggle_default( void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; switch (action) { case MENU_ACTION_LEFT: *setting->value.fraction = *setting->value.fraction - setting->step; if (setting->enforce_minrange) { if (*setting->value.fraction < setting->min) *setting->value.fraction = setting->min; } break; case MENU_ACTION_RIGHT: *setting->value.fraction = *setting->value.fraction + setting->step; if (setting->enforce_maxrange) { if (*setting->value.fraction > setting->max) *setting->value.fraction = setting->max; } break; } return 0; } static int setting_string_action_toggle_driver(void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; switch (action) { case MENU_ACTION_LEFT: if (!find_prev_driver(setting->name, setting->value.string, setting->size)) { #if 0 if (wraparound) find_last_driver(setting->name, setting->value.string, setting->size); #endif } break; case MENU_ACTION_RIGHT: if (!find_next_driver(setting->name, setting->value.string, setting->size)) { if (wraparound) find_first_driver(setting->name, setting->value.string, setting->size); } break; } return 0; } #if defined(HAVE_DYNAMIC) || defined(HAVE_LIBRETRO_MANAGEMENT) static int core_list_action_toggle(void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t *)data; settings_t *settings = config_get_ptr(); /* If the user CANCELs the browse, then settings->libretro is now * set to a directory, which is very bad and will cause a crash * later on. I need to be able to add something to call when a * cancel happens. */ return setting_set_with_string_representation(setting, settings->libretro_directory); } #endif /** * load_content_action_toggle: * @data : pointer to setting * @action : toggle action value. Can be either one of : * MENU_ACTION_RIGHT | MENU_ACTION_LEFT * * Function callback for 'Load Content' action's 'Action Toggle' * function pointer. * * Returns: 0 on success, -1 on error. **/ static int load_content_action_toggle(void *data, unsigned action, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t *)data; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (setting_set_with_string_representation(setting, settings->menu_content_directory) != 0) return -1; if (global->menu.info.valid_extensions) setting->values = global->menu.info.valid_extensions; else setting->values = global->system.valid_extensions; return 0; } /** ******* ACTION OK CALLBACK FUNCTIONS ******* **/ static int setting_action_ok_bind_all(void *data, unsigned action) { global_t *global = global_get_ptr(); if (!global) return -1; if (global->menu.bind_mode_keyboard) menu_input_set_keyboard_bind_mode(data, MENU_INPUT_BIND_ALL); else menu_input_set_input_device_bind_mode(data, MENU_INPUT_BIND_ALL); return 0; } static int setting_action_ok_bind_defaults(void *data, unsigned action) { unsigned i; struct retro_keybind *target = NULL; const struct retro_keybind *def_binds = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; menu_handle_t *menu = menu_driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!menu) return -1; if (!setting) return -1; target = (struct retro_keybind*) &settings->input.binds[setting->index_offset][0]; def_binds = (setting->index_offset) ? retro_keybinds_rest : retro_keybinds_1; if (!target) return -1; menu->binds.begin = MENU_SETTINGS_BIND_BEGIN; menu->binds.last = MENU_SETTINGS_BIND_LAST; for (i = MENU_SETTINGS_BIND_BEGIN; i <= MENU_SETTINGS_BIND_LAST; i++, target++) { if (global->menu.bind_mode_keyboard) target->key = def_binds[i - MENU_SETTINGS_BIND_BEGIN].key; else { target->joykey = NO_BTN; target->joyaxis = AXIS_NONE; } } return 0; } static int setting_bool_action_ok_exit(void *data, unsigned action) { if (setting_generic_action_ok_default(data, 0) != 0) return -1; event_command(EVENT_CMD_RESUME); return 0; } static int setting_action_ok_video_refresh_rate_auto( void *data, unsigned action) { double video_refresh_rate, deviation = 0.0; unsigned sample_points = 0; rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; if (video_monitor_fps_statistics(&video_refresh_rate, &deviation, &sample_points)) { driver_set_refresh_rate(video_refresh_rate); /* Incase refresh rate update forced non-block video. */ event_command(EVENT_CMD_VIDEO_SET_BLOCKING_STATE); } if (setting_generic_action_ok_default(setting, 0) != 0) return -1; return 0; } static int setting_generic_action_ok_linefeed(void *data, unsigned action) { input_keyboard_line_complete_t cb = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; switch (setting->type) { case ST_UINT: cb = menu_input_st_uint_callback; break; case ST_HEX: cb = menu_input_st_hex_callback; break; case ST_STRING: cb = menu_input_st_string_callback; break; default: break; } menu_input_key_start_line(setting->short_description, setting->name, 0, 0, cb); return 0; } static int setting_action_action_ok(void *data, unsigned action) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return -1; if (setting->cmd_trigger.idx != EVENT_CMD_NONE) event_command(setting->cmd_trigger.idx); return 0; } static int setting_bind_action_ok(void *data, unsigned action) { global_t *global = global_get_ptr(); if (global->menu.bind_mode_keyboard) menu_input_set_keyboard_bind_mode(data, MENU_INPUT_BIND_SINGLE); else menu_input_set_input_device_bind_mode(data, MENU_INPUT_BIND_SINGLE); return 0; } /** ******* SET LABEL CALLBACK FUNCTIONS ******* **/ /** * setting_get_string_representation_st_bool: * @setting : pointer to setting * @s : string for the type to be represented on-screen as * a label. * @len : size of @s * * Set a settings' label value. The setting is of type ST_BOOL. **/ static void setting_get_string_representation_st_bool(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, *setting->value.boolean ? setting->boolean.on_label : setting->boolean.off_label, len); } static void setting_get_string_representation_default(void *data, char *s, size_t len) { (void)data; strlcpy(s, "...", len); } /** * setting_get_string_representation_st_float: * @setting : pointer to setting * @s : string for the type to be represented on-screen as * a label. * @len : size of @s * * Set a settings' label value. The setting is of type ST_FLOAT. **/ static void setting_get_string_representation_st_float(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) snprintf(s, len, setting->rounding_fraction, *setting->value.fraction); } static void setting_get_string_representation_st_float_video_refresh_rate_auto(void *data, char *s, size_t len) { double video_refresh_rate = 0.0; double deviation = 0.0; unsigned sample_points = 0; rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; if (video_monitor_fps_statistics(&video_refresh_rate, &deviation, &sample_points)) { snprintf(s, len, "%.3f Hz (%.1f%% dev, %u samples)", video_refresh_rate, 100.0 * deviation, sample_points); { menu_handle_t *menu = menu_driver_get_ptr(); if (menu) menu->label.is_updated = true; } } else strlcpy(s, "N/A", len); } static void setting_get_string_representation_st_dir(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, *setting->value.string ? setting->value.string : setting->dir.empty_path, len); } static void setting_get_string_representation_st_path(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, path_basename(setting->value.string), len); } static void setting_get_string_representation_st_string(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, setting->value.string, len); } static void setting_get_string_representation_st_bind(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; const struct retro_keybind* keybind = NULL; const struct retro_keybind* auto_bind = NULL; if (!setting) return; keybind = (const struct retro_keybind*)setting->value.keybind; auto_bind = (const struct retro_keybind*)input_get_auto_bind(setting->index_offset, keybind->id); input_get_bind_string(s, keybind, auto_bind, len); } static void setting_get_string_representation_int(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) snprintf(s, len, "%d", *setting->value.integer); } static void setting_get_string_representation_uint_video_monitor_index(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; if (*setting->value.unsigned_integer) snprintf(s, len, "%u", *setting->value.unsigned_integer); else strlcpy(s, "0 (Auto)", len); } static void setting_get_string_representation_uint_video_rotation(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, rotation_lut[*setting->value.unsigned_integer], len); } static void setting_get_string_representation_uint_aspect_ratio_index(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) strlcpy(s, aspectratio_lut[*setting->value.unsigned_integer].name, len); } static void setting_get_string_representation_uint_libretro_device(void *data, char *s, size_t len) { const struct retro_controller_description *desc = NULL; const char *name = NULL; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!setting) return; if (setting->index_offset < global->system.num_ports) desc = libretro_find_controller_description( &global->system.ports[setting->index_offset], settings->input.libretro_device [setting->index_offset]); if (desc) name = desc->desc; if (!name) { /* Find generic name. */ switch (settings->input.libretro_device [setting->index_offset]) { case RETRO_DEVICE_NONE: name = "None"; break; case RETRO_DEVICE_JOYPAD: name = "RetroPad"; break; case RETRO_DEVICE_ANALOG: name = "RetroPad w/ Analog"; break; default: name = "Unknown"; break; } } strlcpy(s, name, len); } static void setting_get_string_representation_uint_archive_mode(void *data, char *s, size_t len) { const char *name = "Unknown"; settings_t *settings = config_get_ptr(); (void)data; switch (settings->archive.mode) { case 0: name = "Ask"; break; case 1: name = "Load Archive"; break; case 2: name = "Open Archive"; break; } strlcpy(s, name, len); } static void setting_get_string_representation_uint_analog_dpad_mode(void *data, char *s, size_t len) { static const char *modes[] = { "None", "Left Analog", "Right Analog", }; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return; (void)data; strlcpy(s, modes[settings->input.analog_dpad_mode [setting->index_offset] % ANALOG_DPAD_LAST], len); } static void setting_get_string_representation_uint_autosave_interval(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; if (*setting->value.unsigned_integer) snprintf(s, len, "%u seconds", *setting->value.unsigned_integer); else strlcpy(s, "OFF", len); } static void setting_get_string_representation_uint_user_language(void *data, char *s, size_t len) { static const char *modes[] = { "English", "Japanese", "French", "Spanish", "German", "Italian", "Dutch", "Portuguese", "Russian", "Korean", "Chinese (Traditional)", "Chinese (Simplified)" }; settings_t *settings = config_get_ptr(); if (settings) strlcpy(s, modes[settings->user_language], len); } static void setting_get_string_representation_uint_libretro_log_level(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; static const char *modes[] = { "0 (Debug)", "1 (Info)", "2 (Warning)", "3 (Error)" }; strlcpy(s, modes[*setting->value.unsigned_integer], len); } static void setting_get_string_representation_uint(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) snprintf(s, len, "%u", *setting->value.unsigned_integer); } static void setting_get_string_representation_hex(void *data, char *s, size_t len) { rarch_setting_t *setting = (rarch_setting_t*)data; if (setting) snprintf(s, len, "%08x", *setting->value.unsigned_integer); } /** ******* LIST BUILDING HELPER FUNCTIONS ******* **/ /** * setting_action_setting: * @name : Name of setting. * @short_description : Short description of setting. * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * * Initializes a setting of type ST_ACTION. * * Returns: setting of type ST_ACTION. **/ static rarch_setting_t setting_action_setting(const char* name, const char* short_description, const char *group, const char *subgroup) { rarch_setting_t result = {0}; result.type = ST_ACTION; result.name = name; result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.change_handler = NULL; result.deferred_handler = NULL; result.read_handler = NULL; result.get_string_representation = &setting_get_string_representation_default; result.action_start = NULL; result.action_iterate = NULL; result.action_toggle = NULL; result.action_ok = setting_action_action_ok; result.action_cancel = NULL; return result; } /** * setting_group_setting: * @type : type of settting. * @name : name of setting. * * Initializes a setting of type ST_GROUP. * * Returns: setting of type ST_GROUP. **/ static rarch_setting_t setting_group_setting(enum setting_type type, const char* name) { rarch_setting_t result = {0}; result.type = type; result.name = name; result.short_description = name; result.get_string_representation = &setting_get_string_representation_default; return result; } /** * setting_subgroup_setting: * @type : type of settting. * @name : name of setting. * @parent_name : group that the subgroup setting belongs to. * * Initializes a setting of type ST_SUBGROUP. * * Returns: setting of type ST_SUBGROUP. **/ static rarch_setting_t setting_subgroup_setting(enum setting_type type, const char* name, const char *parent_name) { rarch_setting_t result = {0}; result.type = type; result.name = name; result.short_description = name; result.group = parent_name; result.get_string_representation = &setting_get_string_representation_default; return result; } /** * setting_float_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of float setting. * @default_value : Default value (in float). * @rounding : Rounding (for float-to-string representation). * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a setting of type ST_FLOAT. * * Returns: setting of type ST_FLOAT. **/ static rarch_setting_t setting_float_setting(const char* name, const char* short_description, float* target, float default_value, const char *rounding, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = ST_FLOAT; result.name = name; result.size = sizeof(float); result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.rounding_fraction = rounding; result.change_handler = change_handler; result.read_handler = read_handler; result.value.fraction = target; result.original_value.fraction = *target; result.default_value.fraction = default_value; result.action_start = setting_generic_action_start_default; result.action_toggle = setting_fraction_action_toggle_default; result.action_ok = setting_generic_action_ok_default; result.action_cancel = NULL; result.get_string_representation = &setting_get_string_representation_st_float; return result; } /** * setting_bool_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of bool setting. * @default_value : Default value (in bool format). * @off : String value for "Off" label. * @on : String value for "On" label. * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a setting of type ST_BOOL. * * Returns: setting of type ST_BOOL. **/ static rarch_setting_t setting_bool_setting(const char* name, const char* short_description, bool* target, bool default_value, const char *off, const char *on, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = ST_BOOL; result.name = name; result.size = sizeof(bool); result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.change_handler = change_handler; result.read_handler = read_handler; result.value.boolean = target; result.original_value.boolean = *target; result.default_value.boolean = default_value; result.boolean.off_label = off; result.boolean.on_label = on; result.action_start = setting_generic_action_start_default; result.action_toggle = setting_bool_action_toggle_default; result.action_ok = setting_generic_action_ok_default; result.action_cancel = NULL; result.get_string_representation = &setting_get_string_representation_st_bool; return result; } /** * setting_int_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of signed integer setting. * @default_value : Default value (in signed integer format). * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a setting of type ST_INT. * * Returns: setting of type ST_INT. **/ static rarch_setting_t setting_int_setting(const char* name, const char* short_description, int* target, int default_value, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = ST_INT; result.name = name; result.size = sizeof(int); result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.change_handler = change_handler; result.read_handler = read_handler; result.value.integer = target; result.original_value.integer = *target; result.default_value.integer = default_value; result.get_string_representation = &setting_get_string_representation_int; return result; } /** * setting_uint_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of unsigned integer setting. * @default_value : Default value (in unsigned integer format). * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a setting of type ST_UINT. * * Returns: setting of type ST_UINT. **/ static rarch_setting_t setting_uint_setting(const char* name, const char* short_description, unsigned int* target, unsigned int default_value, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = ST_UINT; result.name = name; result.size = sizeof(unsigned int); result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.change_handler = change_handler; result.read_handler = read_handler; result.value.unsigned_integer = target; result.original_value.unsigned_integer = *target; result.default_value.unsigned_integer = default_value; result.action_start = setting_generic_action_start_default; result.action_toggle = setting_uint_action_toggle_default; result.action_ok = setting_generic_action_ok_default; result.action_cancel = NULL; result.get_string_representation = &setting_get_string_representation_uint; return result; } /** * setting_hex_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of unsigned integer setting. * @default_value : Default value (in unsigned integer format). * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a setting of type ST_HEX. * * Returns: setting of type ST_HEX. **/ static rarch_setting_t setting_hex_setting(const char* name, const char* short_description, unsigned int* target, unsigned int default_value, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = ST_HEX; result.name = name; result.size = sizeof(unsigned int); result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.change_handler = change_handler; result.read_handler = read_handler; result.value.unsigned_integer = target; result.original_value.unsigned_integer = *target; result.default_value.unsigned_integer = default_value; result.action_start = setting_generic_action_start_default; result.action_toggle = NULL; result.action_ok = setting_generic_action_ok_default; result.action_cancel = NULL; result.get_string_representation = &setting_get_string_representation_hex; return result; } /** * setting_bind_setting: * @name : name of setting. * @short_description : Short description of setting. * @target : Target of bind setting. * @idx : Index of bind setting. * @idx_offset : Index offset of bind setting. * @default_value : Default value (in bind format). * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * * Initializes a setting of type ST_BIND. * * Returns: setting of type ST_BIND. **/ static rarch_setting_t setting_bind_setting(const char* name, const char* short_description, struct retro_keybind* target, uint32_t idx, uint32_t idx_offset, const struct retro_keybind* default_value, const char *group, const char *subgroup) { rarch_setting_t result = {0}; result.type = ST_BIND; result.name = name; result.size = 0; result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.value.keybind = target; result.default_value.keybind = default_value; result.index = idx; result.index_offset = idx_offset; result.action_start = setting_bind_action_start; result.action_ok = setting_bind_action_ok; result.action_cancel = NULL; result.get_string_representation = &setting_get_string_representation_st_bind; return result; } /** * setting_string_setting: * @type : type of setting. * @name : name of setting. * @short_description : Short description of setting. * @target : Target of string setting. * @size : Size of string setting. * @default_value : Default value (in string format). * @empty : TODO/FIXME: ??? * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a string setting (of type @type). * * Returns: String setting of type @type. **/ rarch_setting_t setting_string_setting(enum setting_type type, const char* name, const char* short_description, char* target, unsigned size, const char* default_value, const char *empty, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = {0}; result.type = type; result.name = name; result.size = size; result.short_description = short_description; result.group = group; result.subgroup = subgroup; result.dir.empty_path = empty; result.change_handler = change_handler; result.read_handler = read_handler; result.value.string = target; result.default_value.string = default_value; result.action_start = NULL; result.get_string_representation = &setting_get_string_representation_st_string; switch (type) { case ST_DIR: result.action_start = setting_string_action_start_generic; result.browser_selection_type = ST_DIR; result.get_string_representation = &setting_get_string_representation_st_dir; break; case ST_PATH: result.action_start = setting_string_action_start_generic; result.browser_selection_type = ST_PATH; result.get_string_representation = &setting_get_string_representation_st_path; break; default: break; } return result; } /** * setting_string_setting_options: * @type : type of settting. * @name : name of setting. * @short_description : Short description of setting. * @target : Target of bind setting. * @size : Size of string setting. * @default_value : Default value. * @empty : N/A. * @values : Values, separated by a delimiter. * @group : Group that the setting belongs to. * @subgroup : Subgroup that the setting belongs to. * @change_handler : Function callback for change handler function pointer. * @read_handler : Function callback for read handler function pointer. * * Initializes a string options list setting. * * Returns: string option list setting. **/ static rarch_setting_t setting_string_setting_options(enum setting_type type, const char* name, const char* short_description, char* target, unsigned size, const char* default_value, const char *empty, const char *values, const char *group, const char *subgroup, change_handler_t change_handler, change_handler_t read_handler) { rarch_setting_t result = setting_string_setting(type, name, short_description, target, size, default_value, empty, group, subgroup, change_handler, read_handler); result.values = values; return result; } static int setting_get_description_compare_label(uint32_t label_hash, settings_t *settings, char *s, size_t len) { switch (label_hash) { case MENU_LABEL_INPUT_DRIVER: if (!strcmp(settings->input.driver, "udev")) snprintf(s, len, " -- udev Input driver. \n" " \n" "This driver can run without X. \n" " \n" "It uses the recent evdev joypad API \n" "for joystick support. It supports \n" "hotplugging and force feedback (if \n" "supported by device). \n" " \n" "The driver reads evdev events for keyboard \n" "support. It also supports keyboard callback, \n" "mice and touchpads. \n" " \n" "By default in most distros, /dev/input nodes \n" "are root-only (mode 600). You can set up a udev \n" "rule which makes these accessible to non-root." ); else if (!strcmp(settings->input.driver, "linuxraw")) snprintf(s, len, " -- linuxraw Input driver. \n" " \n" "This driver requires an active TTY. Keyboard \n" "events are read directly from the TTY which \n" "makes it simpler, but not as flexible as udev. \n" "Mice, etc, are not supported at all. \n" " \n" "This driver uses the older joystick API \n" "(/dev/input/js*)."); else snprintf(s, len, " -- Input driver.\n" " \n" "Depending on video driver, it might \n" "force a different input driver."); break; case MENU_LABEL_LOAD_CONTENT: snprintf(s, len, " -- Load Content. \n" "Browse for content. \n" " \n" "To load content, you need a \n" "libretro core to use, and a \n" "content file. \n" " \n" "To control where the menu starts \n" " to browse for content, set \n" "Browser Directory. If not set, \n" "it will start in root. \n" " \n" "The browser will filter out \n" "extensions for the last core set \n" "in 'Core', and use that core when \n" "content is loaded." ); break; case MENU_LABEL_CORE_LIST: snprintf(s, len, " -- Core Selection. \n" " \n" "Browse for a libretro core \n" "implementation. Where the browser \n" "starts depends on your Core Directory \n" "path. If blank, it will start in root. \n" " \n" "If Core Directory is a directory, the menu \n" "will use that as top folder. If Core \n" "Directory is a full path, it will start \n" "in the folder where the file is."); break; case MENU_LABEL_HISTORY_LIST: snprintf(s, len, " -- Loading content from history. \n" " \n" "As content is loaded, content and libretro \n" "core combinations are saved to history. \n" " \n" "The history is saved to a file in the same \n" "directory as the RetroArch config file. If \n" "no config file was loaded in startup, history \n" "will not be saved or loaded, and will not exist \n" "in the main menu." ); break; case MENU_LABEL_VIDEO_DRIVER: if (!strcmp(settings->video.driver, "gl")) snprintf(s, len, " -- OpenGL Video driver. \n" " \n" "This driver allows libretro GL cores to \n" "be used in addition to software-rendered \n" "core implementations.\n" " \n" "Performance for software-rendered and \n" "libretro GL core implementations is \n" "dependent on your graphics card's \n" "underlying GL driver)."); else if (!strcmp(settings->video.driver, "sdl2")) snprintf(s, len, " -- SDL 2 Video driver.\n" " \n" "This is an SDL 2 software-rendered video \n" "driver.\n" " \n" "Performance for software-rendered libretro \n" "core implementations is dependent \n" "on your platform SDL implementation."); else if (!strcmp(settings->video.driver, "sdl")) snprintf(s, len, " -- SDL Video driver.\n" " \n" "This is an SDL 1.2 software-rendered video \n" "driver.\n" " \n" "Performance is considered to be suboptimal. \n" "Consider using it only as a last resort."); else if (!strcmp(settings->video.driver, "d3d")) snprintf(s, len, " -- Direct3D Video driver. \n" " \n" "Performance for software-rendered cores \n" "is dependent on your graphic card's \n" "underlying D3D driver)."); else if (!strcmp(settings->video.driver, "exynos")) snprintf(s, len, " -- Exynos-G2D Video Driver. \n" " \n" "This is a low-level Exynos video driver. \n" "Uses the G2D block in Samsung Exynos SoC \n" "for blit operations. \n" " \n" "Performance for software rendered cores \n" "should be optimal."); else if (!strcmp(settings->video.driver, "sunxi")) snprintf(s, len, " -- Sunxi-G2D Video Driver. \n" " \n" "This is a low-level Sunxi video driver. \n" "Uses the G2D block in Allwinner SoCs."); else snprintf(s, len, " -- Current Video driver."); break; case MENU_LABEL_AUDIO_DSP_PLUGIN: snprintf(s, len, " -- Audio DSP plugin.\n" " Processes audio before it's sent to \n" "the driver." ); break; case MENU_LABEL_AUDIO_RESAMPLER_DRIVER: if (!strcmp(settings->audio.resampler, "sinc")) snprintf(s, len, " -- Windowed SINC implementation."); else if (!strcmp(settings->audio.resampler, "CC")) snprintf(s, len, " -- Convoluted Cosine implementation."); break; case MENU_LABEL_VIDEO_SHADER_PRESET: snprintf(s, len, " -- Load Shader Preset. \n" " \n" " Load a " #ifdef HAVE_CG "Cg" #endif #ifdef HAVE_GLSL #ifdef HAVE_CG "/" #endif "GLSL" #endif #ifdef HAVE_HLSL #if defined(HAVE_CG) || defined(HAVE_HLSL) "/" #endif "HLSL" #endif " preset directly. \n" "The menu shader menu is updated accordingly. \n" " \n" "If the CGP uses scaling methods which are not \n" "simple, (i.e. source scaling, same scaling \n" "factor for X/Y), the scaling factor displayed \n" "in the menu might not be correct." ); break; case MENU_LABEL_VIDEO_SHADER_SCALE_PASS: snprintf(s, len, " -- Scale for this pass. \n" " \n" "The scale factor accumulates, i.e. 2x \n" "for first pass and 2x for second pass \n" "will give you a 4x total scale. \n" " \n" "If there is a scale factor for last \n" "pass, the result is stretched to \n" "screen with the filter specified in \n" "'Default Filter'. \n" " \n" "If 'Don't Care' is set, either 1x \n" "scale or stretch to fullscreen will \n" "be used depending if it's not the last \n" "pass or not." ); break; case MENU_LABEL_VIDEO_SHADER_NUM_PASSES: snprintf(s, len, " -- Shader Passes. \n" " \n" "RetroArch allows you to mix and match various \n" "shaders with arbitrary shader passes, with \n" "custom hardware filters and scale factors. \n" " \n" "This option specifies the number of shader \n" "passes to use. If you set this to 0, and use \n" "Apply Shader Changes, you use a 'blank' shader. \n" " \n" "The Default Filter option will affect the \n" "stretching filter."); break; case MENU_LABEL_VIDEO_SHADER_PARAMETERS: snprintf(s, len, "-- Shader Parameters. \n" " \n" "Modifies current shader directly. Will not be \n" "saved to CGP/GLSLP preset file."); break; case MENU_LABEL_VIDEO_SHADER_PRESET_PARAMETERS: snprintf(s, len, "-- Shader Preset Parameters. \n" " \n" "Modifies shader preset currently in menu." ); break; case MENU_LABEL_VIDEO_SHADER_PASS: snprintf(s, len, " -- Path to shader. \n" " \n" "All shaders must be of the same \n" "type (i.e. CG, GLSL or HLSL). \n" " \n" "Set Shader Directory to set where \n" "the browser starts to look for \n" "shaders." ); break; case MENU_LABEL_CONFIG_SAVE_ON_EXIT: snprintf(s, len, " -- Saves config to disk on exit.\n" "Useful for menu as settings can be\n" "modified. Overwrites the config.\n" " \n" "#include's and comments are not \n" "preserved. \n" " \n" "By design, the config file is \n" "considered immutable as it is \n" "likely maintained by the user, \n" "and should not be overwritten \n" "behind the user's back." #if defined(RARCH_CONSOLE) || defined(RARCH_MOBILE) "\nThis is not not the case on \n" "consoles however, where \n" "looking at the config file \n" "manually isn't really an option." #endif ); break; case MENU_LABEL_VIDEO_SHADER_FILTER_PASS: snprintf(s, len, " -- Hardware filter for this pass. \n" " \n" "If 'Don't Care' is set, 'Default \n" "Filter' will be used." ); break; case MENU_LABEL_AUTOSAVE_INTERVAL: snprintf(s, len, " -- Autosaves the non-volatile SRAM \n" "at a regular interval.\n" " \n" "This is disabled by default unless set \n" "otherwise. The interval is measured in \n" "seconds. \n" " \n" "A value of 0 disables autosave."); break; case MENU_LABEL_INPUT_BIND_DEVICE_TYPE: snprintf(s, len, " -- Input Device Type. \n" " \n" "Picks which device type to use. This is \n" "relevant for the libretro core itself." ); break; case MENU_LABEL_LIBRETRO_LOG_LEVEL: snprintf(s, len, "-- Sets log level for libretro cores \n" "(GET_LOG_INTERFACE). \n" " \n" " If a log level issued by a libretro \n" " core is below libretro_log level, it \n" " is ignored.\n" " \n" " DEBUG logs are always ignored unless \n" " verbose mode is activated (--verbose).\n" " \n" " DEBUG = 0\n" " INFO = 1\n" " WARN = 2\n" " ERROR = 3" ); break; case MENU_LABEL_STATE_SLOT_INCREASE: case MENU_LABEL_STATE_SLOT_DECREASE: snprintf(s, len, " -- State slots.\n" " \n" " With slot set to 0, save state name is *.state \n" " (or whatever defined on commandline).\n" "When slot is != 0, path will be (path)(d), \n" "where (d) is slot number."); break; case MENU_LABEL_SHADER_APPLY_CHANGES: snprintf(s, len, " -- Apply Shader Changes. \n" " \n" "After changing shader settings, use this to \n" "apply changes. \n" " \n" "Changing shader settings is a somewhat \n" "expensive operation so it has to be \n" "done explicitly. \n" " \n" "When you apply shaders, the menu shader \n" "settings are saved to a temporary file (either \n" "menu.cgp or menu.glslp) and loaded. The file \n" "persists after RetroArch exits. The file is \n" "saved to Shader Directory." ); break; case MENU_LABEL_INPUT_BIND_DEVICE_ID: snprintf(s, len, " -- Input Device. \n" " \n" "Picks which gamepad to use for user N. \n" "The name of the pad is available." ); break; case MENU_LABEL_MENU_TOGGLE: snprintf(s, len, " -- Toggles menu."); break; case MENU_LABEL_GRAB_MOUSE_TOGGLE: snprintf(s, len, " -- Toggles mouse grab.\n" " \n" "When mouse is grabbed, RetroArch hides the \n" "mouse, and keeps the mouse pointer inside \n" "the window to allow relative mouse input to \n" "work better."); break; case MENU_LABEL_DISK_NEXT: snprintf(s, len, " -- Cycles through disk images. Use after \n" "ejecting. \n" " \n" " Complete by toggling eject again."); break; case MENU_LABEL_VIDEO_FILTER: #ifdef HAVE_FILTERS_BUILTIN snprintf(s, len, " -- CPU-based video filter."); #else snprintf(s, len, " -- CPU-based video filter.\n" " \n" "Path to a dynamic library."); #endif break; case MENU_LABEL_AUDIO_DEVICE: snprintf(s, len, " -- Override the default audio device \n" "the audio driver uses.\n" "This is driver dependent. E.g.\n" #ifdef HAVE_ALSA " \n" "ALSA wants a PCM device." #endif #ifdef HAVE_OSS " \n" "OSS wants a path (e.g. /dev/dsp)." #endif #ifdef HAVE_JACK " \n" "JACK wants portnames (e.g. system:playback1\n" ",system:playback_2)." #endif #ifdef HAVE_RSOUND " \n" "RSound wants an IP address to an RSound \n" "server." #endif ); break; case MENU_LABEL_DISK_EJECT_TOGGLE: snprintf(s, len, " -- Toggles eject for disks.\n" " \n" "Used for multiple-disk content."); break; case MENU_LABEL_ENABLE_HOTKEY: snprintf(s, len, " -- Enable other hotkeys.\n" " \n" " If this hotkey is bound to either keyboard, \n" "joybutton or joyaxis, all other hotkeys will \n" "be disabled unless this hotkey is also held \n" "at the same time. \n" " \n" "This is useful for RETRO_KEYBOARD centric \n" "implementations which query a large area of \n" "the keyboard, where it is not desirable that \n" "hotkeys get in the way."); break; case MENU_LABEL_REWIND_ENABLE: snprintf(s, len, " -- Enable rewinding.\n" " \n" "This will take a performance hit, \n" "so it is disabled by default."); break; case MENU_LABEL_LIBRETRO_DIR_PATH: snprintf(s, len, " -- Core Directory. \n" " \n" "A directory for where to search for \n" "libretro core implementations."); break; case MENU_LABEL_VIDEO_REFRESH_RATE_AUTO: snprintf(s, len, " -- Refresh Rate Auto.\n" " \n" "The accurate refresh rate of our monitor (Hz).\n" "This is used to calculate audio input rate with \n" "the formula: \n" " \n" "audio_input_rate = game input rate * display \n" "refresh rate / game refresh rate\n" " \n" "If the implementation does not report any \n" "values, NTSC defaults will be assumed for \n" "compatibility.\n" " \n" "This value should stay close to 60Hz to avoid \n" "large pitch changes. If your monitor does \n" "not run at 60Hz, or something close to it, \n" "disable VSync, and leave this at its default."); break; case MENU_LABEL_VIDEO_ROTATION: snprintf(s, len, " -- Forces a certain rotation \n" "of the screen.\n" " \n" "The rotation is added to rotations which\n" "the libretro core sets (see Video Allow\n" "Rotate)."); break; case MENU_LABEL_VIDEO_SCALE: snprintf(s, len, " -- Fullscreen resolution.\n" " \n" "Resolution of 0 uses the \n" "resolution of the environment.\n"); break; case MENU_LABEL_FASTFORWARD_RATIO: snprintf(s, len, " -- Fastforward ratio." " \n" "The maximum rate at which content will\n" "be run when using fast forward.\n" " \n" " (E.g. 5.0 for 60 fps content => 300 fps \n" "cap).\n" " \n" "RetroArch will go to sleep to ensure that \n" "the maximum rate will not be exceeded.\n" "Do not rely on this cap to be perfectly \n" "accurate."); break; case MENU_LABEL_VIDEO_MONITOR_INDEX: snprintf(s, len, " -- Which monitor to prefer.\n" " \n" "0 (default) means no particular monitor \n" "is preferred, 1 and up (1 being first \n" "monitor), suggests RetroArch to use that \n" "particular monitor."); break; case MENU_LABEL_VIDEO_CROP_OVERSCAN: snprintf(s, len, " -- Forces cropping of overscanned \n" "frames.\n" " \n" "Exact behavior of this option is \n" "core-implementation specific."); break; case MENU_LABEL_VIDEO_SCALE_INTEGER: snprintf(s, len, " -- Only scales video in integer \n" "steps.\n" " \n" "The base size depends on system-reported \n" "geometry and aspect ratio.\n" " \n" "If Force Aspect is not set, X/Y will be \n" "integer scaled independently."); break; default: return -1; } return 0; } /** * setting_get_description: * @label : identifier label of setting * @s : output message * @len : size of @s * * Writes a 'Help' description message to @s if there is * one available based on the identifier label of the setting * (@label). * * Returns: 0 (always for now). TODO: make it handle -1 as well. **/ int setting_get_description(const char *label, char *s, size_t len) { settings_t *settings = config_get_ptr(); uint32_t label_hash = djb2_calculate(label); if (setting_get_description_compare_label(label_hash, settings, s, len) == 0) return 0; if (!strcmp(label, "video_disable_composition")) { snprintf(s, len, "-- Forcibly disable composition.\n" "Only valid on Windows Vista/7 for now."); } else if (!strcmp(label, "log_verbosity")) { snprintf(s, len, "-- Enable or disable verbosity level \n" "of frontend."); } else if (!strcmp(label, "perfcnt_enable")) { snprintf(s, len, "-- Enable or disable frontend \n" "performance counters."); } else if (!strcmp(label, "system_directory")) { snprintf(s, len, "-- System Directory. \n" " \n" "Sets the 'system' directory.\n" "Cores can query for this\n" "directory to load BIOSes, \n" "system-specific configs, etc."); } else if (!strcmp(label, "rgui_show_start_screen")) { snprintf(s, len, " -- Show startup screen in menu.\n" "Is automatically set to false when seen\n" "for the first time.\n" " \n" "This is only updated in config if\n" "'Save Configuration on Exit' is enabled.\n"); } else if (!strcmp(label, "core_specific_config")) { snprintf(s, len, " -- Load up a specific config file \n" "based on the core being used.\n"); } else if (!strcmp(label, "video_vsync")) { snprintf(s, len, " -- Video V-Sync.\n"); } else if (!strcmp(label, "video_hard_sync")) { snprintf(s, len, " -- Attempts to hard-synchronize \n" "CPU and GPU.\n" " \n" "Can reduce latency at cost of \n" "performance."); } else if (!strcmp(label, "video_hard_sync_frames")) { snprintf(s, len, " -- Sets how many frames CPU can \n" "run ahead of GPU when using 'GPU \n" "Hard Sync'.\n" " \n" "Maximum is 3.\n" " \n" " 0: Syncs to GPU immediately.\n" " 1: Syncs to previous frame.\n" " 2: Etc ..."); } else if (!strcmp(label, "video_frame_delay")) { snprintf(s, len, " -- Sets how many milliseconds to delay\n" "after VSync before running the core.\n" "\n" "Can reduce latency at cost of\n" "higher risk of stuttering.\n" " \n" "Maximum is 15."); } else if (!strcmp(label, "audio_rate_control_delta")) { snprintf(s, len, " -- Audio rate control.\n" " \n" "Setting this to 0 disables rate control.\n" "Any other value controls audio rate control \n" "delta.\n" " \n" "Defines how much input rate can be adjusted \n" "dynamically.\n" " \n" " Input rate is defined as: \n" " input rate * (1.0 +/- (rate control delta))"); } else if (!strcmp(label, "audio_max_timing_skew")) { snprintf(s, len, " -- Maximum audio timing skew.\n" " \n" "Defines the maximum change in input rate.\n" "You may want to increase this to enable\n" "very large changes in timing, for example\n" "running PAL cores on NTSC displays, at the\n" "cost of inaccurate audio pitch.\n" " \n" " Input rate is defined as: \n" " input rate * (1.0 +/- (max timing skew))"); } else if (!strcmp(label, "video_fullscreen")) { snprintf(s, len, " -- Toggles fullscreen."); } else if (!strcmp(label, "video_black_frame_insertion")) { snprintf(s, len, " -- Inserts a black frame inbetween \n" "frames.\n" " \n" "Useful for 120 Hz monitors who want to \n" "play 60 Hz material with eliminated \n" "ghosting.\n" " \n" "Video refresh rate should still be \n" "configured as if it is a 60 Hz monitor \n" "(divide refresh rate by 2)."); } else if (!strcmp(label, "video_threaded")) { snprintf(s, len, " -- Use threaded video driver.\n" " \n" "Using this might improve performance at \n" "possible cost of latency and more video \n" "stuttering."); } else if (!strcmp(label, "audio_volume")) { snprintf(s, len, " -- Audio volume, expressed in dB.\n" " \n" " 0 dB is normal volume. No gain will be applied.\n" "Gain can be controlled in runtime with Input\n" "Volume Up / Input Volume Down."); } else if (!strcmp(label, "block_sram_overwrite")) { snprintf(s, len, " -- Block SRAM from being overwritten \n" "when loading save states.\n" " \n" "Might potentially lead to buggy games."); } else if (!strcmp(label, "pause_nonactive")) { snprintf(s, len, " -- Pause gameplay when window focus \n" "is lost."); } else if (!strcmp(label, "video_gpu_screenshot")) { snprintf(s, len, " -- Screenshots output of GPU shaded \n" "material if available."); } else if (!strcmp(label, "screenshot_directory")) { snprintf(s, len, " -- Screenshot Directory. \n" " \n" "Directory to dump screenshots to." ); } else if (!strcmp(label, "video_swap_interval")) { snprintf(s, len, " -- VSync Swap Interval.\n" " \n" "Uses a custom swap interval for VSync. Set this \n" "to effectively halve monitor refresh rate."); } else if (!strcmp(label, "savefile_directory")) { snprintf(s, len, " -- Savefile Directory. \n" " \n" "Save all save files (*.srm) to this \n" "directory. This includes related files like \n" ".bsv, .rt, .psrm, etc...\n" " \n" "This will be overridden by explicit command line\n" "options."); } else if (!strcmp(label, "savestate_directory")) { snprintf(s, len, " -- Savestate Directory. \n" " \n" "Save all save states (*.state) to this \n" "directory.\n" " \n" "This will be overridden by explicit command line\n" "options."); } else if (!strcmp(label, "assets_directory")) { snprintf(s, len, " -- Assets Directory. \n" " \n" " This location is queried by default when \n" "menu interfaces try to look for loadable \n" "assets, etc."); } else if (!strcmp(label, "dynamic_wallpapers_directory")) { snprintf(s, len, " -- Dynamic Wallpapers Directory. \n" " \n" " The place to store wallpapers that will \n" "be loaded dynamically by the menu depending \n" "on context."); } else if (!strcmp(label, "slowmotion_ratio")) { snprintf(s, len, " -- Slowmotion ratio." " \n" "When slowmotion, content will slow\n" "down by factor."); } else if (!strcmp(label, "input_axis_threshold")) { snprintf(s, len, " -- Defines axis threshold.\n" " \n" "How far an axis must be tilted to result\n" "in a button press.\n" " Possible values are [0.0, 1.0]."); } else if (!strcmp(label, "input_turbo_period")) { snprintf(s, len, " -- Turbo period.\n" " \n" "Describes speed of which turbo-enabled\n" "buttons toggle." ); } else if (!strcmp(label, "rewind_granularity")) { snprintf(s, len, " -- Rewind granularity.\n" " \n" " When rewinding defined number of \n" "frames, you can rewind several frames \n" "at a time, increasing the rewinding \n" "speed."); } else if (!strcmp(label, "input_autodetect_enable")) { snprintf(s, len, " -- Enable input auto-detection.\n" " \n" "Will attempt to auto-configure \n" "joypads, Plug-and-Play style."); } else if (!strcmp(label, "camera_allow")) { snprintf(s, len, " -- Allow or disallow camera access by \n" "cores."); } else if (!strcmp(label, "location_allow")) { snprintf(s, len, " -- Allow or disallow location services \n" "access by cores."); } else if (!strcmp(label, "savestate_auto_save")) { snprintf(s, len, " -- Automatically saves a savestate at the \n" "end of RetroArch's lifetime.\n" " \n" "RetroArch will automatically load any savestate\n" "with this path on startup if 'Auto Load State\n" "is enabled."); } else if ( !strcmp(label, "l_x_plus") || !strcmp(label, "l_x_minus") || !strcmp(label, "l_y_plus") || !strcmp(label, "l_y_minus") ) snprintf(s, len, " -- Axis for analog stick (DualShock-esque).\n" " \n" "Bound as usual, however, if a real analog \n" "axis is bound, it can be read as a true analog.\n" " \n" "Positive X axis is right. \n" "Positive Y axis is down."); else if (!strcmp(label, "turbo")) snprintf(s, len, " -- Turbo enable.\n" " \n" "Holding the turbo while pressing another \n" "button will let the button enter a turbo \n" "mode where the button state is modulated \n" "with a periodic signal. \n" " \n" "The modulation stops when the button \n" "itself (not turbo button) is released."); else if (!strcmp(label, "exit_emulator")) snprintf(s, len, " -- Key to exit RetroArch cleanly." #if !defined(RARCH_MOBILE) && !defined(RARCH_CONSOLE) "\nKilling it in any hard way (SIGKILL, \n" "etc) will terminate without saving\n" "RAM, etc. On Unix-likes,\n" "SIGINT/SIGTERM allows\n" "a clean deinitialization." #endif ); else if (!strcmp(label, "rewind")) snprintf(s, len, " -- Hold button down to rewind.\n" " \n" "Rewind must be enabled."); else if (!strcmp(label, "load_state")) snprintf(s, len, " -- Loads state."); else if (!strcmp(label, "save_state")) snprintf(s, len, " -- Saves state."); else if (!strcmp(label, "netplay_flip_players")) snprintf(s, len, " -- Netplay flip users."); else if (!strcmp(label, "frame_advance")) snprintf(s, len, " -- Frame advance when content is paused."); else if (!strcmp(label, "slowmotion")) snprintf(s, len, " -- Hold for slowmotion."); else if (!strcmp(label, "movie_record_toggle")) snprintf(s, len, " -- Toggle between recording and not."); else if (!strcmp(label, "pause_toggle")) snprintf(s, len, " -- Toggle between paused and non-paused state."); else if (!strcmp(label, "hold_fast_forward")) snprintf(s, len, " -- Hold for fast-forward. Releasing button \n" "disables fast-forward."); else if (!strcmp(label, "shader_next")) snprintf(s, len, " -- Applies next shader in directory."); else if (!strcmp(label, "reset")) snprintf(s, len, " -- Reset the content.\n"); else if (!strcmp(label, "cheat_index_plus")) snprintf(s, len, " -- Increment cheat index.\n"); else if (!strcmp(label, "cheat_index_minus")) snprintf(s, len, " -- Decrement cheat index.\n"); else if (!strcmp(label, "cheat_toggle")) snprintf(s, len, " -- Toggle cheat index.\n"); else if (!strcmp(label, "shader_prev")) snprintf(s, len, " -- Applies previous shader in directory."); else if (!strcmp(label, "audio_mute")) snprintf(s, len, " -- Mute/unmute audio."); else if (!strcmp(label, "osk_enable")) snprintf(s, len, " -- Enable/disable on-screen keyboard."); else if (!strcmp(label, "screenshot")) snprintf(s, len, " -- Take screenshot."); else if (!strcmp(label, "volume_up")) snprintf(s, len, " -- Increases audio volume."); else if (!strcmp(label, "volume_down")) snprintf(s, len, " -- Decreases audio volume."); else if (!strcmp(label, "overlay_next")) snprintf(s, len, " -- Toggles to next overlay.\n" " \n" "Wraps around."); else snprintf(s, len, "-- No info on this item is available. --\n"); return 0; } static void get_string_representation_bind_device(void * data, char *s, size_t len) { unsigned map = 0; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); if (!setting) return; map = settings->input.joypad_map[setting->index_offset]; if (map < settings->input.max_users) { const char *device_name = settings->input.device_names[map]; if (*device_name) strlcpy(s, device_name, len); else snprintf(s, len, "N/A (port #%u)", map); } else strlcpy(s, "Disabled", len); } static void get_string_representation_savestate(void * data, char *s, size_t len) { settings_t *settings = config_get_ptr(); snprintf(s, len, "%d", settings->state_slot); if (settings->state_slot == -1) strlcat(s, " (Auto)", len); } /** * setting_get_label: * @list : File list on which to perform the search * @s : String for the type to be represented on-screen as * a label. * @len : Size of @s * @w : Width of the string (for text label representation * purposes in the menu display driver). * @type : Identifier of setting. * @menu_label : Menu Label identifier of setting. * @label : Label identifier of setting. * @idx : Index identifier of setting. * * Get associated label of a setting. **/ void setting_get_label(file_list_t *list, char *s, size_t len, unsigned *w, unsigned type, const char *menu_label, const char *label, unsigned idx) { rarch_setting_t *setting = NULL; rarch_setting_t *setting_data = menu_setting_get_ptr(); if (!setting_data || !label) return; setting = setting_find_setting(setting_data, list->list[idx].label); if (setting) setting_get_string_representation(setting, s, len); } static void general_read_handler(void *data) { rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); uint32_t hash = setting ? djb2_calculate(setting->name) : 0; if (!setting) return; switch (hash) { case MENU_LABEL_AUDIO_RATE_CONTROL_DELTA: *setting->value.fraction = settings->audio.rate_control_delta; if (*setting->value.fraction < 0.0005) { settings->audio.rate_control = false; settings->audio.rate_control_delta = 0.0; } else { settings->audio.rate_control = true; settings->audio.rate_control_delta = *setting->value.fraction; } break; case MENU_LABEL_AUDIO_MAX_TIMING_SKEW: *setting->value.fraction = settings->audio.max_timing_skew; break; case MENU_LABEL_VIDEO_REFRESH_RATE_AUTO: *setting->value.fraction = settings->video.refresh_rate; break; case MENU_LABEL_INPUT_PLAYER1_JOYPAD_INDEX: *setting->value.integer = settings->input.joypad_map[0]; break; case MENU_LABEL_INPUT_PLAYER2_JOYPAD_INDEX: *setting->value.integer = settings->input.joypad_map[1]; break; case MENU_LABEL_INPUT_PLAYER3_JOYPAD_INDEX: *setting->value.integer = settings->input.joypad_map[2]; break; case MENU_LABEL_INPUT_PLAYER4_JOYPAD_INDEX: *setting->value.integer = settings->input.joypad_map[3]; break; case MENU_LABEL_INPUT_PLAYER5_JOYPAD_INDEX: *setting->value.integer = settings->input.joypad_map[4]; break; } } static void general_write_handler(void *data) { enum event_command rarch_cmd = EVENT_CMD_NONE; menu_displaylist_info_t info = {0}; rarch_setting_t *setting = (rarch_setting_t*)data; settings_t *settings = config_get_ptr(); driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); menu_list_t *menu_list = menu_list_get_ptr(); uint32_t hash = setting ? djb2_calculate(setting->name) : 0; if (!setting) return; if (setting->cmd_trigger.idx != EVENT_CMD_NONE) { if (setting->flags & SD_FLAG_EXIT) { if (*setting->value.boolean) *setting->value.boolean = false; } if (setting->cmd_trigger.triggered || (setting->flags & SD_FLAG_CMD_APPLY_AUTO)) rarch_cmd = setting->cmd_trigger.idx; } switch (hash) { case MENU_LABEL_HELP: if (!menu_list) return; if (*setting->value.boolean) { info.list = menu_list->menu_stack; info.type = 0; info.directory_ptr = 0; strlcpy(info.label, "help", sizeof(info.label)); menu_displaylist_push_list(&info, DISPLAYLIST_GENERIC); setting_set_with_string_representation(setting, "false"); } break; case MENU_LABEL_AUDIO_MAX_TIMING_SKEW: settings->audio.max_timing_skew = *setting->value.fraction; break; case MENU_LABEL_AUDIO_RATE_CONTROL_DELTA: if (*setting->value.fraction < 0.0005) { settings->audio.rate_control = false; settings->audio.rate_control_delta = 0.0; } else { settings->audio.rate_control = true; settings->audio.rate_control_delta = *setting->value.fraction; } break; case MENU_LABEL_VIDEO_REFRESH_RATE_AUTO: if (driver->video && driver->video_data) { driver_set_refresh_rate(*setting->value.fraction); /* In case refresh rate update forced non-block video. */ rarch_cmd = EVENT_CMD_VIDEO_SET_BLOCKING_STATE; } break; case MENU_LABEL_VIDEO_SCALE: settings->video.scale = roundf(*setting->value.fraction); if (!settings->video.fullscreen) rarch_cmd = EVENT_CMD_REINIT; break; case MENU_LABEL_INPUT_PLAYER1_JOYPAD_INDEX: settings->input.joypad_map[0] = *setting->value.integer; break; case MENU_LABEL_INPUT_PLAYER2_JOYPAD_INDEX: settings->input.joypad_map[1] = *setting->value.integer; break; case MENU_LABEL_INPUT_PLAYER3_JOYPAD_INDEX: settings->input.joypad_map[2] = *setting->value.integer; break; case MENU_LABEL_INPUT_PLAYER4_JOYPAD_INDEX: settings->input.joypad_map[3] = *setting->value.integer; break; case MENU_LABEL_INPUT_PLAYER5_JOYPAD_INDEX: settings->input.joypad_map[4] = *setting->value.integer; break; case MENU_LABEL_LOG_VERBOSITY: global->verbosity = *setting->value.boolean; global->has_set_verbosity = *setting->value.boolean; break; case MENU_LABEL_VIDEO_SMOOTH: video_driver_set_filtering(1, settings->video.smooth); break; case MENU_LABEL_VIDEO_ROTATION: video_driver_set_rotation( (*setting->value.unsigned_integer + global->system.rotation) % 4); break; case MENU_LABEL_AUDIO_VOLUME: audio_driver_set_volume_gain(db_to_gain(*setting->value.fraction)); break; case MENU_LABEL_AUDIO_LATENCY: rarch_cmd = EVENT_CMD_AUDIO_REINIT; break; case MENU_LABEL_PAL60_ENABLE: if (*setting->value.boolean && global->console.screen.pal_enable) rarch_cmd = EVENT_CMD_REINIT; else setting_set_with_string_representation(setting, "false"); break; case MENU_LABEL_SYSTEM_BGM_ENABLE: if (*setting->value.boolean) { #if defined(__CELLOS_LV2__) && (CELL_SDK_VERSION > 0x340000) cellSysutilEnableBgmPlayback(); #endif } else { #if defined(__CELLOS_LV2__) && (CELL_SDK_VERSION > 0x340000) cellSysutilDisableBgmPlayback(); #endif } break; case MENU_LABEL_NETPLAY_IP_ADDRESS: #ifdef HAVE_NETPLAY global->has_set_netplay_ip_address = (setting->value.string[0] != '\0'); #endif break; case MENU_LABEL_NETPLAY_MODE: #ifdef HAVE_NETPLAY if (!global->netplay_is_client) *global->netplay_server = '\0'; global->has_set_netplay_mode = true; #endif break; case MENU_LABEL_NETPLAY_SPECTATOR_MODE_ENABLE: #ifdef HAVE_NETPLAY if (global->netplay_is_spectate) *global->netplay_server = '\0'; #endif break; case MENU_LABEL_NETPLAY_DELAY_FRAMES: #ifdef HAVE_NETPLAY global->has_set_netplay_delay_frames = (global->netplay_sync_frames > 0); #endif break; } if (rarch_cmd || setting->cmd_trigger.triggered) event_command(rarch_cmd); } #define START_GROUP(group_info, NAME) \ { \ group_info.name = NAME; \ if (!(menu_settings_list_append(list, list_info, setting_group_setting (ST_GROUP, NAME)))) return false; \ } #define END_GROUP(list, list_info) \ { \ if (!(menu_settings_list_append(list, list_info, setting_group_setting (ST_END_GROUP, 0)))) return false; \ } #define START_SUB_GROUP(list, list_info, NAME, group_info, subgroup_info) \ { \ subgroup_info.name = NAME; \ if (!(menu_settings_list_append(list, list_info, setting_subgroup_setting (ST_SUB_GROUP, NAME, group_info)))) return false; \ } #define END_SUB_GROUP(list, list_info) \ { \ if (!(menu_settings_list_append(list, list_info, setting_group_setting (ST_END_SUB_GROUP, 0)))) return false; \ } #define CONFIG_ACTION(NAME, SHORT, group_info, subgroup_info) \ { \ if (!menu_settings_list_append(list, list_info, setting_action_setting (NAME, SHORT, group_info, subgroup_info))) return false; \ } #define CONFIG_BOOL(TARGET, NAME, SHORT, DEF, OFF, ON, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!menu_settings_list_append(list, list_info, setting_bool_setting (NAME, SHORT, &TARGET, DEF, OFF, ON, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))return false; \ } #define CONFIG_INT(TARGET, NAME, SHORT, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_int_setting (NAME, SHORT, &TARGET, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_UINT(TARGET, NAME, SHORT, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_uint_setting (NAME, SHORT, &TARGET, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_FLOAT(TARGET, NAME, SHORT, DEF, ROUNDING, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_float_setting (NAME, SHORT, &TARGET, DEF, ROUNDING, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_PATH(TARGET, NAME, SHORT, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_string_setting(ST_PATH, NAME, SHORT, TARGET, sizeof(TARGET), DEF, "", group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_DIR(TARGET, NAME, SHORT, DEF, EMPTY, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_string_setting(ST_DIR, NAME, SHORT, TARGET, sizeof(TARGET), DEF, EMPTY, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_STRING(TARGET, NAME, SHORT, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_string_setting(ST_STRING, NAME, SHORT, TARGET, sizeof(TARGET), DEF, "", group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_STRING_OPTIONS(TARGET, NAME, SHORT, DEF, OPTS, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_string_setting_options(ST_STRING, NAME, SHORT, TARGET, sizeof(TARGET), DEF, "", OPTS, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_HEX(TARGET, NAME, SHORT, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER) \ { \ if (!(menu_settings_list_append(list, list_info, setting_hex_setting(NAME, SHORT, &TARGET, DEF, group_info, subgroup_info, CHANGE_HANDLER, READ_HANDLER)))) return false; \ } #define CONFIG_BIND(TARGET, PLAYER, PLAYER_OFFSET, NAME, SHORT, DEF, group_info, subgroup_info) \ { \ if (!(menu_settings_list_append(list, list_info, setting_bind_setting (NAME, SHORT, &TARGET, PLAYER, PLAYER_OFFSET, DEF, group_info, subgroup_info)))) return false; \ } #ifdef GEKKO #define MAX_GAMMA_SETTING 2 #else #define MAX_GAMMA_SETTING 1 #endif static void setting_add_special_callbacks( rarch_setting_t **list, rarch_setting_info_t *list_info, unsigned values) { unsigned idx = list_info->index - 1; if (values & SD_FLAG_ALLOW_INPUT) { (*list)[idx].action_ok = setting_generic_action_ok_linefeed; switch ((*list)[idx].type) { case ST_UINT: (*list)[idx].action_cancel = NULL; break; case ST_HEX: (*list)[idx].action_cancel = NULL; break; case ST_STRING: (*list)[idx].action_start = setting_string_action_start_generic; (*list)[idx].action_cancel = NULL; break; default: break; } } else if (values & SD_FLAG_IS_DRIVER) (*list)[idx].action_toggle = setting_string_action_toggle_driver; } static void settings_data_list_current_add_flags( rarch_setting_t **list, rarch_setting_info_t *list_info, unsigned values) { menu_settings_list_current_add_flags( list, list_info, values); setting_add_special_callbacks(list, list_info, values); } static void overlay_enable_toggle_change_handler(void *data) { rarch_setting_t *setting = (rarch_setting_t *)data; if (!setting) return; if (setting->value.boolean) event_command(EVENT_CMD_OVERLAY_INIT); else event_command(EVENT_CMD_OVERLAY_DEINIT); } static bool setting_append_list_main_menu_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Main Menu"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); #if defined(HAVE_DYNAMIC) || defined(HAVE_LIBRETRO_MANAGEMENT) CONFIG_ACTION( "core_list", "Core Selection", group_info.name, subgroup_info.name); (*list)[list_info->index - 1].size = sizeof(settings->libretro); (*list)[list_info->index - 1].value.string = settings->libretro; (*list)[list_info->index - 1].values = EXT_EXECUTABLES; // It is not a good idea to have chosen action_toggle as the place // to put this callback. It should be called whenever the browser // needs to get the directory to browse into. It's not quite like // get_string_representation, but it is close. (*list)[list_info->index - 1].action_toggle = core_list_action_toggle; menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_LOAD_CORE); settings_data_list_current_add_flags(list, list_info, SD_FLAG_BROWSER_ACTION); #endif #ifdef HAVE_NETWORKING CONFIG_ACTION( "core_updater_list", "Core Updater", group_info.name, subgroup_info.name); #endif #ifdef HAVE_LIBRETRODB CONFIG_ACTION( "content_collection_list", "Load Content (Collection)", group_info.name, subgroup_info.name); #endif if (settings->history_list_enable) { CONFIG_ACTION( "history_list", "Load Content (History)", group_info.name, subgroup_info.name); } if ( driver->menu && global->core_info && core_info_list_num_info_files(global->core_info)) { CONFIG_ACTION( "detect_core_list", "Load Content (Detect Core)", group_info.name, subgroup_info.name); settings_data_list_current_add_flags(list, list_info, SD_FLAG_BROWSER_ACTION); } CONFIG_ACTION( "load_content", "Load Content", group_info.name, subgroup_info.name); (*list)[list_info->index - 1].size = sizeof(global->fullpath); (*list)[list_info->index - 1].value.string = global->fullpath; (*list)[list_info->index - 1].action_toggle = load_content_action_toggle; menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_LOAD_CONTENT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_BROWSER_ACTION); { struct retro_system_info *info = (struct retro_system_info*) global ? &global->system.info : NULL; if (info && strcmp(info->library_name, "No Core") != 0) CONFIG_ACTION( "unload_core", "Unload Core", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_UNLOAD_CORE); } CONFIG_ACTION( "core_information", "Core Information", group_info.name, subgroup_info.name); CONFIG_ACTION( "management", "Management", group_info.name, subgroup_info.name); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_ACTION( "options", "Options", group_info.name, subgroup_info.name); CONFIG_ACTION( "settings", "Settings", group_info.name, subgroup_info.name); CONFIG_ACTION( "system_information", "System Information", group_info.name, subgroup_info.name); if (global->perfcnt_enable) { CONFIG_ACTION( "performance_counters", "Performance Counters", group_info.name, subgroup_info.name); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); } if (global->main_is_init && !global->libretro_dummy) { CONFIG_ACTION( "savestate", "Save State", group_info.name, subgroup_info.name); (*list)[list_info->index - 1].action_toggle = &setting_action_toggle_savestates; (*list)[list_info->index - 1].action_start = &setting_action_start_savestates; (*list)[list_info->index - 1].action_ok = &setting_bool_action_ok_exit; (*list)[list_info->index - 1].get_string_representation = &get_string_representation_savestate; menu_settings_list_current_add_cmd (list, list_info, EVENT_CMD_SAVE_STATE); CONFIG_ACTION( "loadstate", "Load State", group_info.name, subgroup_info.name); (*list)[list_info->index - 1].action_toggle = &setting_action_toggle_savestates; (*list)[list_info->index - 1].action_start = &setting_action_start_savestates; (*list)[list_info->index - 1].action_ok = &setting_bool_action_ok_exit; (*list)[list_info->index - 1].get_string_representation = &get_string_representation_savestate; menu_settings_list_current_add_cmd (list, list_info, EVENT_CMD_LOAD_STATE); CONFIG_ACTION( "take_screenshot", "Take Screenshot", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd (list, list_info, EVENT_CMD_TAKE_SCREENSHOT); CONFIG_ACTION( "resume_content", "Resume Content", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd (list, list_info, EVENT_CMD_RESUME); (*list)[list_info->index - 1].action_ok = &setting_bool_action_ok_exit; CONFIG_ACTION( "restart_content", "Restart Content", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_RESET); (*list)[list_info->index - 1].action_ok = &setting_bool_action_ok_exit; } #ifndef HAVE_DYNAMIC CONFIG_ACTION( "restart_retroarch", "Restart RetroArch", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_RESTART_RETROARCH); #endif CONFIG_ACTION( "configurations", "Configuration Files", group_info.name, subgroup_info.name); CONFIG_ACTION( "save_new_config", "Save New Config", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_MENU_SAVE_CONFIG); CONFIG_ACTION( "help", "Help", group_info.name, subgroup_info.name); #if !defined(IOS) /* Apple rejects iOS apps that lets you forcibly quit an application. */ CONFIG_ACTION( "quit_retroarch", "Quit RetroArch", group_info.name, subgroup_info.name); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_QUIT_RETROARCH); #endif END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_driver_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Driver Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_STRING_OPTIONS( settings->input.driver, "input_driver", "Input Driver", config_get_default_input(), config_get_input_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->input.joypad_driver, "input_joypad_driver", "Joypad Driver", config_get_default_joypad(), config_get_joypad_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->video.driver, "video_driver", "Video Driver", config_get_default_video(), config_get_video_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->audio.driver, "audio_driver", "Audio Driver", config_get_default_audio(), config_get_audio_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->audio.resampler, "audio_resampler_driver", "Audio Resampler Driver", config_get_default_audio_resampler(), config_get_audio_resampler_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->camera.driver, "camera_driver", "Camera Driver", config_get_default_camera(), config_get_camera_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->location.driver, "location_driver", "Location Driver", config_get_default_location(), config_get_location_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->menu.driver, "menu_driver", "Menu Driver", config_get_default_menu(), config_get_menu_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); CONFIG_STRING_OPTIONS( settings->record.driver, "record_driver", "Record Driver", config_get_default_record(), config_get_record_driver_options(), group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DRIVER); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_core_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Core Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->video.shared_context, "video_shared_context", "HW Shared Context Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->load_dummy_on_core_shutdown, "dummy_on_core_shutdown", "Dummy On Core Shutdown", load_dummy_on_core_shutdown, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->core.set_supports_no_game_enable, "core_set_supports_no_game_enable", "Supports No Content Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_configuration_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Configuration Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL(settings->config_save_on_exit, "config_save_on_exit", "Save Configuration on Exit", config_save_on_exit, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->core_specific_config, "core_specific_config", "Configuration Per-Core", default_core_specific_config, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->auto_overrides_enable, "auto_overrides_enable", "Load Override Files Automatically", default_auto_overrides_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->auto_remaps_enable, "auto_remaps_enable", "Load Remap Files Automatically", default_auto_remaps_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_saving_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Saving Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->sort_savefiles_enable, "sort_savefiles_enable", "Sort Saves In Folders", default_sort_savefiles_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->sort_savestates_enable, "sort_savestates_enable", "Sort Saves States In Folders", default_sort_savestates_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->block_sram_overwrite, "block_sram_overwrite", "SRAM Block overwrite", block_sram_overwrite, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #ifdef HAVE_THREADS CONFIG_UINT( settings->autosave_interval, "autosave_interval", "SRAM Autosave Interval", autosave_interval, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_AUTOSAVE_INIT); menu_settings_list_current_add_range(list, list_info, 0, 0, 10, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_autosave_interval; #endif CONFIG_BOOL( settings->savestate_auto_index, "savestate_auto_index", "Save State Auto Index", savestate_auto_index, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->savestate_auto_save, "savestate_auto_save", "Auto Save State", savestate_auto_save, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->savestate_auto_load, "savestate_auto_load", "Auto Load State", savestate_auto_load, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_logging_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Logging Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( global->verbosity, "log_verbosity", "Logging Verbosity", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT(settings->libretro_log_level, "libretro_log_level", "Core Logging Level", libretro_log_level, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1.0, true, true); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_log_level; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Performance Counters", group_info.name, subgroup_info); CONFIG_BOOL(global->perfcnt_enable, "perfcnt_enable", "Performance Counters", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_frame_throttling_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Frame Throttle Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->fastforward_ratio_throttle_enable, "fastforward_ratio_throttle_enable", "Limit Maximum Run Speed", fastforward_ratio_throttle_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_FLOAT( settings->fastforward_ratio, "fastforward_ratio", "Maximum Run Speed", fastforward_ratio, "%.1fx", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 10, 0.1, true, true); CONFIG_FLOAT( settings->slowmotion_ratio, "slowmotion_ratio", "Slow-Motion Ratio", slowmotion_ratio, "%.1fx", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 10, 1.0, true, true); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_rewind_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Rewind Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->rewind_enable, "rewind_enable", "Rewind", rewind_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REWIND_TOGGLE); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); #if 0 CONFIG_SIZE( settings->rewind_buffer_size, "rewind_buffer_size", "Rewind Buffer Size", rewind_buffer_size, group_info.name, subgroup_info.name, general_write_handler, general_read_handler) #endif CONFIG_UINT( settings->rewind_granularity, "rewind_granularity", "Rewind Granularity", rewind_granularity, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 32768, 1, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_recording_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Recording Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( global->record.enable, "record_enable", "Record Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_PATH( global->record.config, "record_config", "Record Config", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_values(list, list_info, "cfg"); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); CONFIG_STRING( global->record.path, "record_path", "Record Path", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); CONFIG_BOOL( global->record.use_output_dir, "record_use_output_dir", "Use output directory", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Miscellaneous", group_info.name, subgroup_info); CONFIG_BOOL( settings->video.post_filter_record, "video_post_filter_record", "Post filter record Enable", post_filter_record, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->video.gpu_record, "video_gpu_record", "GPU Record Enable", gpu_record, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_video_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); video_viewport_t *custom_vp = video_viewport_get_custom(); (void)global; START_GROUP(group_info, "Video Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL(settings->fps_show, "fps_show", "Display Framerate", fps_show, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Monitor", group_info.name, subgroup_info); CONFIG_UINT( settings->video.monitor_index, "video_monitor_index", "Monitor Index", monitor_index, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REINIT); menu_settings_list_current_add_range(list, list_info, 0, 1, 1, true, false); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_monitor_index; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #if !defined(RARCH_CONSOLE) && !defined(RARCH_MOBILE) CONFIG_BOOL( settings->video.fullscreen, "video_fullscreen", "Use Fullscreen mode", fullscreen, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REINIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); #endif CONFIG_BOOL( settings->video.windowed_fullscreen, "video_windowed_fullscreen", "Windowed Fullscreen Mode", windowed_fullscreen, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->video.fullscreen_x, "video_fullscreen_x", "Fullscreen Width", fullscreen_x, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( settings->video.fullscreen_y, "video_fullscreen_y", "Fullscreen Height", fullscreen_y, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_FLOAT( settings->video.refresh_rate, "video_refresh_rate", "Refresh Rate", refresh_rate, "%.3f Hz", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 0, 0.001, true, false); CONFIG_FLOAT( settings->video.refresh_rate, "video_refresh_rate_auto", "Estimated Monitor Framerate", refresh_rate, "%.3f Hz", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); (*list)[list_info->index - 1].action_start = &setting_action_start_video_refresh_rate_auto; (*list)[list_info->index - 1].action_ok = &setting_action_ok_video_refresh_rate_auto; (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_st_float_video_refresh_rate_auto; CONFIG_BOOL( settings->video.force_srgb_disable, "video_force_srgb_disable", "Force-disable sRGB FBO", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REINIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Aspect", group_info.name, subgroup_info); CONFIG_BOOL( settings->video.force_aspect, "video_force_aspect", "Force aspect ratio", force_aspect, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_FLOAT( settings->video.aspect_ratio, "video_aspect_ratio", "Aspect Ratio", aspect_ratio, "%.2f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->video.aspect_ratio_auto, "video_aspect_ratio_auto", "Auto Aspect Ratio", aspect_ratio_auto, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->video.aspect_ratio_idx, "aspect_ratio_index", "Aspect Ratio Index", aspect_ratio_idx, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd( list, list_info, EVENT_CMD_VIDEO_SET_ASPECT_RATIO); menu_settings_list_current_add_range( list, list_info, 0, LAST_ASPECT_RATIO, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_aspect_ratio_index; END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Scaling", group_info.name, subgroup_info); #if !defined(RARCH_CONSOLE) && !defined(RARCH_MOBILE) CONFIG_FLOAT( settings->video.scale, "video_scale", "Windowed Scale", scale, "%.1fx", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1.0, 10.0, 1.0, true, true); #endif CONFIG_BOOL( settings->video.scale_integer, "video_scale_integer", "Integer Scale", scale_integer, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_INT( custom_vp->x, "custom_viewport_x", "Custom Viewport X", 0, group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_INT( custom_vp->y, "custom_viewport_y", "Custom Viewport Y", 0, group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( custom_vp->width, "custom_viewport_width", "Custom Viewport Width", 0, group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( custom_vp->height, "custom_viewport_height", "Custom Viewport Height", 0, group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #ifdef GEKKO CONFIG_UINT( settings->video.viwidth, "video_viwidth", "Set Screen Width", video_viwidth, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 640, 720, 2, true, true); CONFIG_BOOL( settings->video.vfilter, "video_vfilter", "Deflicker", video_vfilter, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif CONFIG_BOOL( settings->video.smooth, "video_smooth", "Bilinear Filtering", video_smooth, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #if defined(__CELLOS_LV2__) CONFIG_BOOL( global->console.screen.pal60_enable, "pal60_enable", "Use PAL60 Mode", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif CONFIG_UINT( settings->video.rotation, "video_rotation", "Rotation", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_rotation; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #if defined(HW_RVL) || defined(_XBOX360) CONFIG_UINT( global->console.screen.gamma_correction, "video_gamma", "Gamma", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd( list, list_info, EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); menu_settings_list_current_add_range( list, list_info, 0, MAX_GAMMA_SETTING, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); #endif END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Synchronization", group_info.name, subgroup_info); #if defined(HAVE_THREADS) && !defined(RARCH_CONSOLE) CONFIG_BOOL( settings->video.threaded, "video_threaded", "Threaded Video", video_threaded, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REINIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); #endif CONFIG_BOOL( settings->video.vsync, "video_vsync", "VSync", vsync, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->video.swap_interval, "video_swap_interval", "VSync Swap Interval", swap_interval, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_VIDEO_SET_BLOCKING_STATE); menu_settings_list_current_add_range(list, list_info, 1, 4, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO|SD_FLAG_ADVANCED); CONFIG_BOOL( settings->video.hard_sync, "video_hard_sync", "Hard GPU Sync", hard_sync, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->video.hard_sync_frames, "video_hard_sync_frames", "Hard GPU Sync Frames", hard_sync_frames, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( settings->video.frame_delay, "video_frame_delay", "Frame Delay", frame_delay, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 15, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #if !defined(RARCH_MOBILE) CONFIG_BOOL( settings->video.black_frame_insertion, "video_black_frame_insertion", "Black Frame Insertion", black_frame_insertion, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Miscellaneous", group_info.name, subgroup_info); CONFIG_BOOL( settings->video.gpu_screenshot, "video_gpu_screenshot", "GPU Screenshot Enable", gpu_screenshot, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->video.allow_rotate, "video_allow_rotate", "Allow rotation", allow_rotate, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->video.crop_overscan, "video_crop_overscan", "Crop Overscan (reload)", crop_overscan, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #if defined(_XBOX1) || defined(HW_RVL) CONFIG_BOOL( global->console.softfilter_enable, "soft_filter", "Soft Filter Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd( list, list_info, EVENT_CMD_VIDEO_APPLY_STATE_CHANGES); #endif #ifdef _XBOX1 CONFIG_UINT( settings->video.swap_interval, "video_filter_flicker", "Flicker filter", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 5, 1, true, true); #endif END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_font_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Onscreen Display Settings"); START_SUB_GROUP(list, list_info, "Messages", group_info.name, subgroup_info); #ifndef RARCH_CONSOLE CONFIG_BOOL( settings->video.font_enable, "video_font_enable", "Display OSD Message", font_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif CONFIG_PATH( settings->video.font_path, "video_font_path", "OSD Message Font", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); CONFIG_FLOAT( settings->video.font_size, "video_font_size", "OSD Message Size", font_size, "%.1f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1.00, 100.00, 1.0, true, true); CONFIG_FLOAT( settings->video.msg_pos_x, "video_message_pos_x", "OSD Message X Position", message_pos_offset_x, "%.3f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 1, 0.01, true, true); CONFIG_FLOAT( settings->video.msg_pos_y, "video_message_pos_y", "OSD Message Y Position", message_pos_offset_y, "%.3f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 1, 0.01, true, true); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_audio_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Audio Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); (void)global; CONFIG_BOOL( settings->audio.enable, "audio_enable", "Audio Enable", audio_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->audio.mute_enable, "audio_mute_enable", "Audio Mute", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_FLOAT( settings->audio.volume, "audio_volume", "Audio Volume Level (dB)", audio_volume, "%.1f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, -80, 12, 1.0, true, true); #ifdef __CELLOS_LV2__ CONFIG_BOOL( global->console.sound.system_bgm_enable, "system_bgm_enable", "System BGM Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Synchronization", group_info.name, subgroup_info); CONFIG_BOOL( settings->audio.sync, "audio_sync", "Audio Sync Enable", audio_sync, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->audio.latency, "audio_latency", "Audio Latency (ms)", g_defaults.settings.out_latency ? g_defaults.settings.out_latency : out_latency, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 256, 1.0, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_IS_DEFERRED); CONFIG_FLOAT( settings->audio.rate_control_delta, "audio_rate_control_delta", "Audio Rate Control Delta", rate_control_delta, "%.3f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range( list, list_info, 0, 0, 0.001, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_FLOAT( settings->audio.max_timing_skew, "audio_max_timing_skew", "Audio Maximum Timing Skew", max_timing_skew, "%.2f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range( list, list_info, 0.01, 0.5, 0.01, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( settings->audio.block_frames, "audio_block_frames", "Block Frames", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Miscellaneous", group_info.name, subgroup_info); CONFIG_STRING( settings->audio.device, "audio_device", "Device", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT | SD_FLAG_ADVANCED); CONFIG_UINT( settings->audio.out_rate, "audio_out_rate", "Audio Output Rate (KHz)", out_rate, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_PATH( settings->audio.dsp_plugin, "audio_dsp_plugin", "DSP Plugin", settings->audio.filter_dir, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_values(list, list_info, "dsp"); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_DSP_FILTER_INIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_input_hotkey_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; unsigned i; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Input Hotkey Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); for (i = 0; i < RARCH_BIND_LIST_END; i ++) { const struct input_bind_map* keybind = (const struct input_bind_map*) &input_config_bind_map[i]; if (!keybind || !keybind->meta) continue; CONFIG_BIND(settings->input.binds[0][i], 0, 0, keybind->base, keybind->desc, &retro_keybinds_1[i], group_info.name, subgroup_info.name); menu_settings_list_current_add_bind_type(list, list_info, i + MENU_SETTINGS_BIND_BEGIN); } END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_input_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; unsigned user; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Input Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_UINT( settings->input.max_users, "input_max_users", "Max Users", MAX_USERS, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, MAX_USERS, 1, true, true); CONFIG_BOOL( settings->input.remap_binds_enable, "input_remap_binds_enable", "Remap Binds Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->input.autodetect_enable, "input_autodetect_enable", "Autoconfig Enable", input_autodetect_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->input.autoconfig_descriptor_label_show, "autoconfig_descriptor_label_show", "Display Autoconfig Descriptor Labels", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->input.input_descriptor_label_show, "input_descriptor_label_show", "Display Core Input Descriptor Labels", input_descriptor_label_show, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->input.input_descriptor_hide_unbound, "input_descriptor_hide_unbound", "Hide Unbound Core Input Descriptors", input_descriptor_hide_unbound, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Input Device Mapping", group_info.name, subgroup_info); CONFIG_BOOL( global->menu.bind_mode_keyboard, "input_bind_mode", "Bind Mode", false, "RetroPad", "RetroKeyboard", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); for (user = 0; user < settings->input.max_users; user ++) { /* These constants match the string lengths. * Keep them up to date or you'll get some really obvious bugs. * 2 is the length of '99'; we don't need more users than that. */ /* FIXME/TODO - really need to clean up this mess in some way. */ static char key[MAX_USERS][64]; static char key_type[MAX_USERS][64]; static char key_analog[MAX_USERS][64]; static char key_bind_all[MAX_USERS][64]; static char key_bind_defaults[MAX_USERS][64]; static char label[MAX_USERS][64]; static char label_type[MAX_USERS][64]; static char label_analog[MAX_USERS][64]; static char label_bind_all[MAX_USERS][64]; static char label_bind_defaults[MAX_USERS][64]; snprintf(key[user], sizeof(key[user]), "input_player%u_joypad_index", user + 1); snprintf(key_type[user], sizeof(key_type[user]), "input_libretro_device_p%u", user + 1); snprintf(key_analog[user], sizeof(key_analog[user]), "input_player%u_analog_dpad_mode", user + 1); snprintf(key_bind_all[user], sizeof(key_bind_all[user]), "input_player%u_bind_all", user + 1); snprintf(key_bind_defaults[user], sizeof(key_bind_defaults[user]), "input_player%u_bind_defaults", user + 1); snprintf(label[user], sizeof(label[user]), "User %u Device Index", user + 1); snprintf(label_type[user], sizeof(label_type[user]), "User %u Device Type", user + 1); snprintf(label_analog[user], sizeof(label_analog[user]), "User %u Analog To Digital Type", user + 1); snprintf(label_bind_all[user], sizeof(label_bind_all[user]), "User %u Bind All", user + 1); snprintf(label_bind_defaults[user], sizeof(label_bind_defaults[user]), "User %u Bind Default All", user + 1); CONFIG_UINT( settings->input.libretro_device[user], key_type[user], label_type[user], user, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); (*list)[list_info->index - 1].index = user + 1; (*list)[list_info->index - 1].index_offset = user; (*list)[list_info->index - 1].action_toggle = &setting_action_toggle_libretro_device_type; (*list)[list_info->index - 1].action_start = &setting_action_start_libretro_device_type; (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_device; CONFIG_UINT( settings->input.analog_dpad_mode[user], key_analog[user], label_analog[user], user, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); (*list)[list_info->index - 1].index = user + 1; (*list)[list_info->index - 1].index_offset = user; (*list)[list_info->index - 1].action_toggle = &setting_action_toggle_analog_dpad_mode; (*list)[list_info->index - 1].action_start = &setting_action_start_analog_dpad_mode; (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_analog_dpad_mode; CONFIG_ACTION( key[user], label[user], group_info.name, subgroup_info.name); (*list)[list_info->index - 1].index = user + 1; (*list)[list_info->index - 1].index_offset = user; (*list)[list_info->index - 1].action_start = &setting_action_start_bind_device; (*list)[list_info->index - 1].action_toggle = &setting_action_toggle_bind_device; (*list)[list_info->index - 1].get_string_representation = &get_string_representation_bind_device; CONFIG_ACTION( key_bind_all[user], label_bind_all[user], group_info.name, subgroup_info.name); (*list)[list_info->index - 1].index = user + 1; (*list)[list_info->index - 1].index_offset = user; (*list)[list_info->index - 1].action_ok = &setting_action_ok_bind_all; (*list)[list_info->index - 1].action_cancel = NULL; CONFIG_ACTION( key_bind_defaults[user], label_bind_defaults[user], group_info.name, subgroup_info.name); (*list)[list_info->index - 1].index = user + 1; (*list)[list_info->index - 1].index_offset = user; (*list)[list_info->index - 1].action_ok = &setting_action_ok_bind_defaults; (*list)[list_info->index - 1].action_cancel = NULL; } START_SUB_GROUP( list, list_info, "Turbo/Deadzone", group_info.name, subgroup_info); CONFIG_FLOAT( settings->input.axis_threshold, "input_axis_threshold", "Input Axis Threshold", axis_threshold, "%.3f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 1.00, 0.001, true, true); CONFIG_UINT( settings->input.turbo_period, "input_turbo_period", "Turbo Period", turbo_period, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 0, 1, true, false); CONFIG_UINT( settings->input.turbo_duty_cycle, "input_duty_cycle", "Duty Cycle", turbo_duty_cycle, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 0, 1, true, false); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_overlay_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { #ifdef HAVE_OVERLAY rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Overlay Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->input.overlay_enable, "input_overlay_enable", "Display Overlay", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); (*list)[list_info->index - 1].change_handler = overlay_enable_toggle_change_handler; CONFIG_PATH( settings->input.overlay, "input_overlay", "Overlay Preset", global->overlay_dir, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_values(list, list_info, "cfg"); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_OVERLAY_INIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); CONFIG_FLOAT( settings->input.overlay_opacity, "input_overlay_opacity", "Overlay Opacity", 0.7f, "%.2f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_OVERLAY_SET_ALPHA_MOD); menu_settings_list_current_add_range(list, list_info, 0, 1, 0.01, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); CONFIG_FLOAT( settings->input.overlay_scale, "input_overlay_scale", "Overlay Scale", 1.0f, "%.2f", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_OVERLAY_SET_SCALE_FACTOR); menu_settings_list_current_add_range(list, list_info, 0, 2, 0.01, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); #endif return true; } static bool setting_append_list_osk_overlay_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { #ifdef HAVE_OVERLAY rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Onscreen Keyboard Overlay Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->osk.enable, "input_osk_overlay_enable", "Display Onscreen Keyboard Overlay", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_PATH( settings->osk.overlay, "input_osk_overlay", "OSK Overlay Preset", global->osk_overlay_dir, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_values(list, list_info, "cfg"); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); #endif return true; } static bool setting_append_list_menu_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Menu Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_PATH( settings->menu.wallpaper, "menu_wallpaper", "Menu Wallpaper", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_values(list, list_info, "png"); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); CONFIG_BOOL( settings->menu.dynamic_wallpaper_enable, "menu_dynamic_wallpaper_enable", "Dynamic Wallpaper", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->menu.pause_libretro, "menu_pause_libretro", "Pause when menu activated", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_MENU_PAUSE_LIBRETRO); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); CONFIG_BOOL( settings->menu.mouse.enable, "menu_mouse_enable", "Mouse Support", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->menu.pointer.enable, "menu_pointer_enable", "Touch Support", pointer_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Navigation", group_info.name, subgroup_info); CONFIG_BOOL( settings->menu.navigation.wraparound.horizontal_enable, "menu_navigation_wraparound_horizontal_enable", "Navigation Wrap-Around Horizontal", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->menu.navigation.wraparound.vertical_enable, "menu_navigation_wraparound_vertical_enable", "Navigation Wrap-Around Vertical", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Settings View", group_info.name, subgroup_info); CONFIG_BOOL( settings->menu.collapse_subgroups_enable, "menu_collapse_subgroups_enable", "Collapse SubGroups", collapse_subgroups_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->menu.show_advanced_settings, "menu_show_advanced_settings", "Show advanced settings", show_advanced_settings, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #ifdef HAVE_THREADS CONFIG_BOOL( settings->menu.threaded_data_runloop_enable, "threaded_data_runloop_enable", "Threaded data runloop", threaded_data_runloop_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); #endif /* These colors are hints. The menu driver is not required to use them. */ CONFIG_HEX( settings->menu.entry_normal_color, "menu_entry_normal_color", "Menu entry normal color", menu_entry_normal_color, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_HEX( settings->menu.entry_hover_color, "menu_entry_hover_color", "Menu entry hover color", menu_entry_hover_color, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_HEX( settings->menu.title_color, "menu_title_color", "Menu title color", menu_title_color, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Browser", group_info.name, subgroup_info); CONFIG_BOOL( settings->menu.navigation.browser.filter.supported_extensions_enable, "menu_navigation_browser_filter_supported_extensions_enable", "Browser - Filter by supported extensions", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->menu_show_start_screen, "rgui_show_start_screen", "Show Start Screen", menu_show_start_screen, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->menu.timedate_enable, "menu_timedate_enable", "Display time / date", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->menu.core_enable, "menu_core_enable", "Display core name", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); START_SUB_GROUP(list, list_info, "Display", group_info.name, subgroup_info); CONFIG_BOOL( settings->menu.dpi.override_enable, "dpi_override_enable", "DPI Override Enable", menu_dpi_override_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->menu.dpi.override_value, "dpi_override_value", "DPI Override", menu_dpi_override_value, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 72, 999, 1, true, true); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_ui_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "UI Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->video.disable_composition, "video_disable_composition", "Disable Desktop Composition", disable_composition, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_REINIT); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); CONFIG_BOOL( settings->pause_nonactive, "pause_nonactive", "Don't run in background", pause_nonactive, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->ui.companion_start_on_boot, "ui_companion_start_on_boot", "UI Companion Start on Boot", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->ui.menubar_enable, "ui_menubar_enable", "Menubar (Windows)", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->ui.suspend_screensaver_enable, "suspend_screensaver_enable", "Suspend Screensaver", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_archive_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Archive Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_UINT( settings->archive.mode, "archive_mode", "Archive Mode", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 2, 1, true, true); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_archive_mode; END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_core_updater_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { #ifdef HAVE_NETWORKING rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Core Updater Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_STRING( settings->network.buildbot_url, "core_updater_buildbot_url", "Buildbot Core URL", buildbot_server_url, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); CONFIG_STRING( settings->network.buildbot_assets_url, "core_updater_buildbot_assets_url", "Buildbot Assets URL", buildbot_assets_server_url, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); CONFIG_BOOL( settings->network.buildbot_auto_extract_archive, "core_updater_auto_extract_archive", "Automatically extract downloaded archive", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); #endif return true; } static bool setting_append_list_netplay_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { #ifdef HAVE_NETPLAY rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Network Settings"); START_SUB_GROUP(list, list_info, "Netplay", group_info.name, subgroup_info); CONFIG_BOOL( global->netplay_enable, "netplay_enable", "Netplay Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->input.netplay_client_swap_input, "netplay_client_swap_input", "Swap Netplay Input", netplay_client_swap_input, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_STRING( global->netplay_server, "netplay_ip_address", "IP Address", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); CONFIG_BOOL( global->netplay_is_client, "netplay_mode", "Netplay Client Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( global->netplay_is_spectate, "netplay_spectator_mode_enable", "Netplay Spectator Enable", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( global->netplay_sync_frames, "netplay_delay_frames", "Netplay Delay Frames", 0, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 10, 1, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( global->netplay_port, "netplay_tcp_udp_port", "Netplay TCP/UDP Port", RARCH_DEFAULT_PORT, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 1, 99999, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); END_SUB_GROUP(list, list_info); START_SUB_GROUP( list, list_info, "Miscellaneous", group_info.name, subgroup_info); #if defined(HAVE_NETWORK_CMD) CONFIG_BOOL( settings->network_cmd_enable, "network_cmd_enable", "Network Commands", network_cmd_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_UINT( settings->network_cmd_port, "network_cmd_port", "Network Command Port", network_cmd_port, group_info.name, subgroup_info.name, NULL, NULL); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); CONFIG_BOOL( settings->stdin_cmd_enable, "stdin_cmd_enable", "stdin command", stdin_cmd_enable, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); #endif END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); #endif return true; } #if 0 static bool setting_append_list_patch_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; START_GROUP(group_info, "Patch Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( global->ups_pref, "ups_pref", "UPS Patching Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( global->bps_pref, "bps_pref", "BPS Patching Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( global->ips_pref, "ips_pref", "IPS Patching Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } #endif static bool setting_append_list_playlist_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Playlist Settings"); START_SUB_GROUP(list, list_info, "History", group_info.name, subgroup_info); CONFIG_BOOL( settings->history_list_enable, "history_list_enable", "History List Enable", true, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_UINT( settings->content_history_size, "content_history_size", "History List Size", default_content_history_size, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 0, 1.0, true, false); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_user_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "User Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_STRING( settings->username, "netplay_nickname", "Username", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); CONFIG_UINT( settings->user_language, "user_language", "Language", def_user_language, group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_range( list, list_info, 0, RETRO_LANGUAGE_LAST-1, 1, true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_user_language; END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_directory_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); START_GROUP(group_info, "Directory Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_DIR( settings->core_assets_directory, "core_assets_directory", "Core Assets Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->assets_directory, "assets_directory", "Assets Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->dynamic_wallpapers_directory, "dynamic_wallpapers_directory", "Dynamic Wallpapers Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->menu_content_directory, "rgui_browser_directory", "Browser Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->menu_config_directory, "rgui_config_directory", "Config Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->libretro_directory, "libretro_dir_path", "Core Directory", g_defaults.core_dir, "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_CORE_INFO_INIT); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->libretro_info_path, "libretro_info_path", "Core Info Directory", g_defaults.core_info_dir, "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, EVENT_CMD_CORE_INFO_INIT); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); #ifdef HAVE_LIBRETRODB CONFIG_DIR( settings->content_database, "content_database_path", "Content Database Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->cursor_directory, "cursor_directory", "Cursor Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); #endif CONFIG_DIR( settings->cheat_database, "cheat_database_path", "Cheat Database Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->video.filter_dir, "video_filter_dir", "VideoFilter Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->audio.filter_dir, "audio_filter_dir", "AudioFilter Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->video.shader_dir, "video_shader_dir", "Shader Directory", g_defaults.shader_dir, "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( global->record.output_dir, "recording_output_directory", "Recording Output Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( global->record.config_dir, "recording_config_directory", "Recording Config Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); #ifdef HAVE_OVERLAY CONFIG_DIR( global->overlay_dir, "overlay_directory", "Overlay Directory", g_defaults.overlay_dir, "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( global->osk_overlay_dir, "osk_overlay_directory", "OSK Overlay Directory", g_defaults.osk_overlay_dir, "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); #endif CONFIG_DIR( settings->screenshot_directory, "screenshot_directory", "Screenshot Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->input.autoconfig_dir, "joypad_autoconfig_dir", "Input Device Autoconfig Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->input_remapping_directory, "input_remapping_directory", "Input Remapping Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->playlist_directory, "playlist_directory", "Playlist Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( global->savefile_dir, "savefile_directory", "Savefile Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( global->savestate_dir, "savestate_directory", "Savestate Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->system_directory, "system_directory", "System Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); CONFIG_DIR( settings->extraction_directory, "extraction_directory", "Extraction Directory", "", "", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); settings_data_list_current_add_flags( list, list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_privacy_options( rarch_setting_t **list, rarch_setting_info_t *list_info) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; settings_t *settings = config_get_ptr(); START_GROUP(group_info, "Privacy Settings"); START_SUB_GROUP(list, list_info, "State", group_info.name, subgroup_info); CONFIG_BOOL( settings->camera.allow, "camera_allow", "Allow Camera", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); CONFIG_BOOL( settings->location.allow, "location_allow", "Allow Location", false, "OFF", "ON", group_info.name, subgroup_info.name, general_write_handler, general_read_handler); END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } static bool setting_append_list_input_player_options( rarch_setting_t **list, rarch_setting_info_t *list_info, unsigned user) { rarch_setting_group_info_t group_info; rarch_setting_group_info_t subgroup_info; unsigned i; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); /* This constants matches the string length. * Keep it up to date or you'll get some really obvious bugs. * 2 is the length of '99'; we don't need more users than that. */ static char buffer[MAX_USERS][7+2+1]; static char group_lbl[MAX_USERS][PATH_MAX_LENGTH]; const struct retro_keybind* const defaults = (user == 0) ? retro_keybinds_1 : retro_keybinds_rest; snprintf(buffer[user], sizeof(buffer[user]), "User %u", user + 1); snprintf(group_lbl[user], sizeof(group_lbl[user]), "Input %s Binds", buffer[user]); START_GROUP(group_info, group_lbl[user]); START_SUB_GROUP( list, list_info, buffer[user], group_info.name, subgroup_info); for (i = 0; i < RARCH_BIND_LIST_END; i ++) { char label[PATH_MAX_LENGTH]; char name[PATH_MAX_LENGTH]; bool do_add = true; const struct input_bind_map* keybind = (const struct input_bind_map*)&input_config_bind_map[i]; if (!keybind || keybind->meta) continue; if ( settings->input.input_descriptor_label_show && (i < RARCH_FIRST_META_KEY) && (global->has_set_input_descriptors) && (i != RARCH_TURBO_ENABLE) ) { if (global->system.input_desc_btn[user][i]) snprintf(label, sizeof(label), "%s %s", buffer[user], global->system.input_desc_btn[user][i]); else { snprintf(label, sizeof(label), "%s %s", buffer[user], "N/A"); if (settings->input.input_descriptor_hide_unbound) do_add = false; } } else snprintf(label, sizeof(label), "%s %s", buffer[user], keybind->desc); snprintf(name, sizeof(name), "p%u_%s", user + 1, keybind->base); if (do_add) { CONFIG_BIND( settings->input.binds[user][i], user + 1, user, strdup(name), /* TODO: Find a way to fix these memleaks. */ strdup(label), &defaults[i], group_info.name, subgroup_info.name); menu_settings_list_current_add_bind_type(list, list_info, i + MENU_SETTINGS_BIND_BEGIN); } } END_SUB_GROUP(list, list_info); END_GROUP(list, list_info); return true; } /** * menu_setting_new: * @mask : Bitmask of settings to include. * * Request a list of settings based on @mask. * * Returns: settings list composed of all requested * settings on success, otherwise NULL. **/ rarch_setting_t *menu_setting_new(unsigned mask) { rarch_setting_t terminator = { ST_NONE }; rarch_setting_t* list = NULL; rarch_setting_t* resized_list = NULL; rarch_setting_info_t *list_info = (rarch_setting_info_t*) calloc(1, sizeof(*list_info)); if (!list_info) return NULL; list_info->size = 32; list = menu_setting_list_new(list_info->size); if (!list) goto error; if (mask & SL_FLAG_MAIN_MENU) { if (!setting_append_list_main_menu_options(&list, list_info)) goto error; } if (mask & SL_FLAG_DRIVER_OPTIONS) { if (!setting_append_list_driver_options(&list, list_info)) goto error; } if (mask & SL_FLAG_CORE_OPTIONS) { if (!setting_append_list_core_options(&list, list_info)) goto error; } if (mask & SL_FLAG_CONFIGURATION_OPTIONS) { if (!setting_append_list_configuration_options(&list, list_info)) goto error; } if (mask & SL_FLAG_LOGGING_OPTIONS) { if (!setting_append_list_logging_options(&list, list_info)) goto error; } if (mask & SL_FLAG_SAVING_OPTIONS) { if (!setting_append_list_saving_options(&list, list_info)) goto error; } if (mask & SL_FLAG_REWIND_OPTIONS) { if (!setting_append_list_rewind_options(&list, list_info)) goto error; } if (mask & SL_FLAG_VIDEO_OPTIONS) { if (!setting_append_list_video_options(&list, list_info)) goto error; } if (mask & SL_FLAG_AUDIO_OPTIONS) { if (!setting_append_list_audio_options(&list, list_info)) goto error; } if (mask & SL_FLAG_INPUT_OPTIONS) { unsigned user; settings_t *settings = config_get_ptr(); if (!setting_append_list_input_options(&list, list_info)) goto error; for (user = 0; user < settings->input.max_users; user++) setting_append_list_input_player_options(&list, list_info, user); } if (mask & SL_FLAG_INPUT_HOTKEY_OPTIONS) { if (!setting_append_list_input_hotkey_options(&list, list_info)) goto error; } if (mask & SL_FLAG_RECORDING_OPTIONS) { if (!setting_append_list_recording_options(&list, list_info)) goto error; } if (mask & SL_FLAG_FRAME_THROTTLE_OPTIONS) { if (!setting_append_list_frame_throttling_options(&list, list_info)) goto error; } if (mask & SL_FLAG_FONT_OPTIONS) { if (!setting_append_list_font_options(&list, list_info)) goto error; } if (mask & SL_FLAG_OVERLAY_OPTIONS) { if (!setting_append_list_overlay_options(&list, list_info)) goto error; } if (mask & SL_FLAG_OSK_OVERLAY_OPTIONS) { if (!setting_append_list_osk_overlay_options(&list, list_info)) goto error; } if (mask & SL_FLAG_MENU_OPTIONS) { if (!setting_append_list_menu_options(&list, list_info)) goto error; } if (mask & SL_FLAG_UI_OPTIONS) { if (!setting_append_list_ui_options(&list, list_info)) goto error; } #if 0 if (mask & SL_FLAG_PATCH_OPTIONS) { if (!setting_append_list_patch_options(&list, list_info)) goto error; } #endif if (mask & SL_FLAG_PLAYLIST_OPTIONS) { if (!setting_append_list_playlist_options(&list, list_info)) goto error; } if (mask & SL_FLAG_CORE_UPDATER_OPTIONS) { if (!setting_append_list_core_updater_options(&list, list_info)) goto error; } if (mask & SL_FLAG_NETPLAY_OPTIONS) { if (!setting_append_list_netplay_options(&list, list_info)) goto error; } if (mask & SL_FLAG_ARCHIVE_OPTIONS) { if (!setting_append_list_archive_options(&list, list_info)) goto error; } if (mask & SL_FLAG_USER_OPTIONS) { if (!setting_append_list_user_options(&list, list_info)) goto error; } if (mask & SL_FLAG_DIRECTORY_OPTIONS) { if (!setting_append_list_directory_options(&list, list_info)) goto error; } if (mask & SL_FLAG_PRIVACY_OPTIONS) { if (!setting_append_list_privacy_options(&list, list_info)) goto error; } if (!(menu_settings_list_append(&list, list_info, terminator))) goto error; /* flatten this array to save ourselves some kilobytes. */ resized_list = (rarch_setting_t*) realloc(list, list_info->index * sizeof(rarch_setting_t)); if (resized_list) list = resized_list; else goto error; menu_settings_info_list_free(list_info); return list; error: RARCH_ERR("Allocation failed.\n"); menu_settings_info_list_free(list_info); menu_settings_list_free(list); return NULL; } bool menu_setting_is_of_path_type(rarch_setting_t *setting) { if ( setting && setting->type == ST_ACTION && (setting->flags & SD_FLAG_BROWSER_ACTION) && setting->action_toggle && setting->change_handler) return true; return false; } bool menu_setting_is_of_general_type(rarch_setting_t *setting) { if ( setting && (setting->type > ST_ACTION) && (setting->type < ST_GROUP) ) return true; return false; } bool menu_setting_is_of_numeric_type(rarch_setting_t *setting) { if ( setting && ((setting->type == ST_INT) || (setting->type == ST_UINT) || (setting->type == ST_FLOAT)) ) return true; return false; } bool menu_setting_is_of_enum_type(rarch_setting_t *setting) { if ( setting && (setting->type == ST_STRING) && setting->values ) return true; return false; }