mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
Merge pull request #9100 from jdgleaver/hide-core-options
An environment callback for selectively hiding core options
This commit is contained in:
commit
91558822e1
@ -1218,6 +1218,26 @@ enum retro_mod
|
||||
* instead.
|
||||
*/
|
||||
|
||||
#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55
|
||||
/* struct retro_core_option_display * --
|
||||
*
|
||||
* Allows an implementation to signal the environment to show
|
||||
* or hide a variable when displaying core options. This is
|
||||
* considered a *suggestion*. The frontend is free to ignore
|
||||
* this callback, and its implementation not considered mandatory.
|
||||
*
|
||||
* 'data' points to a retro_core_option_display struct
|
||||
*
|
||||
* retro_core_option_display::key is a variable identifier
|
||||
* which has already been set by SET_VARIABLES/SET_CORE_OPTIONS.
|
||||
*
|
||||
* retro_core_option_display::visible is a boolean, specifying
|
||||
* whether variable should be displayed
|
||||
*
|
||||
* Note that all core option variables will be set visible by
|
||||
* default when calling SET_VARIABLES/SET_CORE_OPTIONS.
|
||||
*/
|
||||
|
||||
/* VFS functionality */
|
||||
|
||||
/* File paths:
|
||||
@ -2463,6 +2483,16 @@ struct retro_variable
|
||||
const char *value;
|
||||
};
|
||||
|
||||
struct retro_core_option_display
|
||||
{
|
||||
/* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */
|
||||
const char *key;
|
||||
|
||||
/* Specifies whether variable should be displayed
|
||||
* when presenting core options to the user */
|
||||
bool visible;
|
||||
};
|
||||
|
||||
/* Maximum number of values permitted for a core option
|
||||
* NOTE: This may be increased on a core-by-core basis
|
||||
* if required (doing so has no effect on the frontend) */
|
||||
|
@ -35,6 +35,7 @@ struct core_option
|
||||
struct string_list *vals;
|
||||
struct string_list *val_labels;
|
||||
size_t index;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
struct core_option_manager
|
||||
@ -106,6 +107,19 @@ const char *core_option_manager_get_val(core_option_manager_t *opt,
|
||||
const char *core_option_manager_get_val_label(core_option_manager_t *opt,
|
||||
size_t idx);
|
||||
|
||||
/**
|
||||
* core_option_manager_get_visible:
|
||||
* @opt : options manager handle
|
||||
* @idx : idx identifier of the option
|
||||
*
|
||||
* Gets whether option should be visible when displaying
|
||||
* core options in the frontend
|
||||
*
|
||||
* Returns: 'true' if option should be displayed by the frontend.
|
||||
**/
|
||||
bool core_option_manager_get_visible(core_option_manager_t *opt,
|
||||
size_t idx);
|
||||
|
||||
void core_option_manager_set_val(core_option_manager_t *opt,
|
||||
size_t idx, size_t val_idx);
|
||||
|
||||
|
@ -6068,63 +6068,86 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
info->need_push = true;
|
||||
break;
|
||||
case DISPLAYLIST_CORE_OPTIONS:
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||
|
||||
if (rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL))
|
||||
{
|
||||
size_t opts = 0;
|
||||
settings_t *settings = config_get_ptr();
|
||||
/* Number of displayed options is dynamic. If user opens
|
||||
* 'Quick Menu > Core Options', toggles something
|
||||
* that changes the number of displayed items, then
|
||||
* toggles the Quick Menu off and on again (returning
|
||||
* to the Core Options menu) the menu must be refreshed
|
||||
* (or undefined behaviour occurs).
|
||||
* The only way to check whether the number of visible
|
||||
* options has changed is to cache the last set menu size,
|
||||
* and compare this with the new size after processing
|
||||
* the current core_option_manager_t struct */
|
||||
size_t prev_count = info->list->size;
|
||||
|
||||
rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts);
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||
|
||||
if (settings->bools.game_specific_options)
|
||||
if (rarch_ctl(RARCH_CTL_HAS_CORE_OPTIONS, NULL))
|
||||
{
|
||||
if (!rarch_ctl(RARCH_CTL_IS_GAME_OPTIONS_ACTIVE, NULL))
|
||||
size_t opts = 0;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
rarch_ctl(RARCH_CTL_GET_CORE_OPTION_SIZE, &opts);
|
||||
|
||||
if (settings->bools.game_specific_options)
|
||||
{
|
||||
if (menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE),
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_CREATE),
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_CREATE,
|
||||
MENU_SETTINGS_CORE_OPTION_CREATE, 0, 0))
|
||||
count++;
|
||||
if (!rarch_ctl(RARCH_CTL_IS_GAME_OPTIONS_ACTIVE, NULL))
|
||||
{
|
||||
if (menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE),
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_CREATE),
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_CREATE,
|
||||
MENU_SETTINGS_CORE_OPTION_CREATE, 0, 0))
|
||||
count++;
|
||||
}
|
||||
else
|
||||
if (menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE),
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_IN_USE),
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_IN_USE,
|
||||
MENU_SETTINGS_CORE_OPTION_CREATE, 0, 0))
|
||||
count++;
|
||||
}
|
||||
else
|
||||
if (menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE),
|
||||
msg_hash_to_str(
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_IN_USE),
|
||||
MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS_IN_USE,
|
||||
MENU_SETTINGS_CORE_OPTION_CREATE, 0, 0))
|
||||
count++;
|
||||
}
|
||||
|
||||
if (opts != 0)
|
||||
{
|
||||
core_option_manager_t *coreopts = NULL;
|
||||
|
||||
rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
|
||||
|
||||
for (i = 0; i < opts; i++)
|
||||
if (opts != 0)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
core_option_manager_get_desc(coreopts, i), "",
|
||||
MENU_ENUM_LABEL_CORE_OPTION_ENTRY,
|
||||
(unsigned)(MENU_SETTINGS_CORE_OPTION_START + i), 0, 0);
|
||||
count++;
|
||||
core_option_manager_t *coreopts = NULL;
|
||||
|
||||
rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
|
||||
|
||||
for (i = 0; i < opts; i++)
|
||||
{
|
||||
if (core_option_manager_get_visible(coreopts, i))
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
core_option_manager_get_desc(coreopts, i), "",
|
||||
MENU_ENUM_LABEL_CORE_OPTION_ENTRY,
|
||||
(unsigned)(MENU_SETTINGS_CORE_OPTION_START + i), 0, 0);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE),
|
||||
MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE,
|
||||
MENU_SETTINGS_CORE_OPTION_NONE, 0, 0);
|
||||
|
||||
if (count != prev_count)
|
||||
{
|
||||
info->need_refresh = true;
|
||||
info->need_navigation_clear = true;
|
||||
}
|
||||
info->need_push = true;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE),
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE),
|
||||
MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE,
|
||||
MENU_SETTINGS_CORE_OPTION_NONE, 0, 0);
|
||||
info->need_push = true;
|
||||
break;
|
||||
case DISPLAYLIST_ARCHIVE_ACTION:
|
||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||
@ -8047,24 +8070,42 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned size = (unsigned)tmp_str_list->size;
|
||||
unsigned i = atoi(tmp_str_list->elems[size-1].data);
|
||||
unsigned menu_index = atoi(tmp_str_list->elems[size-1].data);
|
||||
unsigned visible_index = 0;
|
||||
unsigned option_index = 0;
|
||||
bool option_found = false;
|
||||
struct core_option *option = NULL;
|
||||
bool checked_found = false;
|
||||
unsigned checked = 0;
|
||||
unsigned i;
|
||||
|
||||
/* Note: Although we display value labels here,
|
||||
* most logic is performed using values. This seems
|
||||
* more appropriate somehow... */
|
||||
|
||||
/* Convert menu index to option index */
|
||||
if (settings->bools.game_specific_options)
|
||||
{
|
||||
val = core_option_manager_get_val(coreopts, i-1);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
val = core_option_manager_get_val(coreopts, i);
|
||||
menu_index--;
|
||||
|
||||
option = (struct core_option*)&coreopts->opts[i];
|
||||
for (i = 0; i < coreopts->size; i++)
|
||||
{
|
||||
if (core_option_manager_get_visible(coreopts, i))
|
||||
{
|
||||
if (visible_index == menu_index)
|
||||
{
|
||||
option_found = true;
|
||||
option_index = i;
|
||||
break;
|
||||
}
|
||||
visible_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (option_found)
|
||||
{
|
||||
val = core_option_manager_get_val(coreopts, option_index);
|
||||
option = (struct core_option*)&coreopts->opts[option_index];
|
||||
}
|
||||
|
||||
if (option)
|
||||
{
|
||||
@ -8077,7 +8118,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
if (!string_is_empty(val_label_str))
|
||||
{
|
||||
char val_d[256];
|
||||
snprintf(val_d, sizeof(val_d), "%d", i);
|
||||
snprintf(val_d, sizeof(val_d), "%d", option_index);
|
||||
|
||||
if (string_is_equal(val_label_str, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)))
|
||||
val_label_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
|
||||
@ -8379,25 +8420,48 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
if (tmp_str_list && tmp_str_list->size > 0)
|
||||
{
|
||||
core_option_manager_t *coreopts = NULL;
|
||||
const char *val = NULL;
|
||||
|
||||
rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
|
||||
|
||||
if (coreopts)
|
||||
{
|
||||
unsigned size = (unsigned)tmp_str_list->size;
|
||||
unsigned i = atoi(tmp_str_list->elems[size-1].data);
|
||||
unsigned menu_index = atoi(tmp_str_list->elems[size-1].data);
|
||||
unsigned visible_index = 0;
|
||||
unsigned option_index = 0;
|
||||
bool option_found = false;
|
||||
struct core_option *option = NULL;
|
||||
bool checked_found = false;
|
||||
unsigned checked = 0;
|
||||
const char *val = core_option_manager_get_val(coreopts, i-1);
|
||||
unsigned i;
|
||||
|
||||
/* Note: Although we display value labels here,
|
||||
* most logic is performed using values. This seems
|
||||
* more appropriate somehow... */
|
||||
|
||||
i--;
|
||||
/* Convert menu index to option index */
|
||||
menu_index--;
|
||||
|
||||
option = (struct core_option*)&coreopts->opts[i];
|
||||
for (i = 0; i < coreopts->size; i++)
|
||||
{
|
||||
if (core_option_manager_get_visible(coreopts, i))
|
||||
{
|
||||
if (visible_index == menu_index)
|
||||
{
|
||||
option_found = true;
|
||||
option_index = i;
|
||||
break;
|
||||
}
|
||||
visible_index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (option_found)
|
||||
{
|
||||
val = core_option_manager_get_val(coreopts, option_index);
|
||||
option = (struct core_option*)&coreopts->opts[option_index];
|
||||
}
|
||||
|
||||
if (option)
|
||||
{
|
||||
@ -8410,7 +8474,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
||||
if (!string_is_empty(val_label_str))
|
||||
{
|
||||
char val_d[256];
|
||||
snprintf(val_d, sizeof(val_d), "%d", i);
|
||||
snprintf(val_d, sizeof(val_d), "%d", option_index);
|
||||
|
||||
if (string_is_equal(val_label_str, msg_hash_to_str(MENU_ENUM_LABEL_ENABLED)))
|
||||
val_label_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
|
||||
|
69
retroarch.c
69
retroarch.c
@ -1693,6 +1693,9 @@ static bool core_option_manager_parse_variable(
|
||||
char *config_val = NULL;
|
||||
struct core_option *option = (struct core_option*)&opt->opts[idx];
|
||||
|
||||
/* All options are visible by default */
|
||||
option->visible = true;
|
||||
|
||||
if (!string_is_empty(var->key))
|
||||
option->key = strdup(var->key);
|
||||
if (!string_is_empty(var->value))
|
||||
@ -1758,6 +1761,9 @@ static bool core_option_manager_parse_option(
|
||||
struct core_option *option = (struct core_option*)&opt->opts[idx];
|
||||
const struct retro_core_option_value *values = option_def->values;
|
||||
|
||||
/* All options are visible by default */
|
||||
option->visible = true;
|
||||
|
||||
if (!string_is_empty(option_def->key))
|
||||
option->key = strdup(option_def->key);
|
||||
|
||||
@ -2133,6 +2139,26 @@ const char *core_option_manager_get_val_label(core_option_manager_t *opt, size_t
|
||||
return option->val_labels->elems[option->index].data;
|
||||
}
|
||||
|
||||
/**
|
||||
* core_option_manager_get_visible:
|
||||
* @opt : options manager handle
|
||||
* @idx : idx identifier of the option
|
||||
*
|
||||
* Gets whether option should be visible when displaying
|
||||
* core options in the frontend
|
||||
*
|
||||
* Returns: 'true' if option should be displayed by the frontend.
|
||||
**/
|
||||
bool core_option_manager_get_visible(core_option_manager_t *opt,
|
||||
size_t idx)
|
||||
{
|
||||
if (!opt)
|
||||
return NULL;
|
||||
if (idx >= opt->size)
|
||||
return NULL;
|
||||
return opt->opts[idx].visible;
|
||||
}
|
||||
|
||||
void core_option_manager_set_val(core_option_manager_t *opt,
|
||||
size_t idx, size_t val_idx)
|
||||
{
|
||||
@ -2302,6 +2328,26 @@ static struct retro_core_option_definition *core_option_manager_get_definitions(
|
||||
return option_defs;
|
||||
}
|
||||
|
||||
static void core_option_manager_set_display(core_option_manager_t *opt,
|
||||
const char *key, bool visible)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!opt || string_is_empty(key))
|
||||
return;
|
||||
|
||||
for (i = 0; i < opt->size; i++)
|
||||
{
|
||||
if (string_is_empty(opt->opts[i].key))
|
||||
continue;
|
||||
|
||||
if (string_is_equal(opt->opts[i].key, key))
|
||||
{
|
||||
opt->opts[i].visible = visible;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* DYNAMIC LIBRETRO CORE */
|
||||
|
||||
@ -2924,6 +2970,13 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
|
||||
break;
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY:
|
||||
RARCH_LOG("Environ RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.\n");
|
||||
|
||||
rarch_ctl(RARCH_CTL_CORE_OPTIONS_DISPLAY, data);
|
||||
|
||||
break;
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_MESSAGE:
|
||||
{
|
||||
const struct retro_message *msg = (const struct retro_message*)data;
|
||||
@ -19015,6 +19068,22 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data)
|
||||
runloop_core_options = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CTL_CORE_OPTIONS_DISPLAY:
|
||||
{
|
||||
const struct retro_core_option_display *core_options_display =
|
||||
(const struct retro_core_option_display*)data;
|
||||
|
||||
if (!runloop_core_options || !core_options_display)
|
||||
return false;
|
||||
|
||||
core_option_manager_set_display(
|
||||
runloop_core_options,
|
||||
core_options_display->key,
|
||||
core_options_display->visible);
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CTL_KEY_EVENT_GET:
|
||||
{
|
||||
retro_keyboard_event_t **key_event =
|
||||
|
@ -184,6 +184,7 @@ enum rarch_ctl_state
|
||||
RARCH_CTL_CORE_OPTIONS_INIT,
|
||||
RARCH_CTL_CORE_OPTIONS_INTL_INIT,
|
||||
RARCH_CTL_CORE_OPTIONS_DEINIT,
|
||||
RARCH_CTL_CORE_OPTIONS_DISPLAY,
|
||||
|
||||
/* System info */
|
||||
RARCH_CTL_SYSTEM_INFO_INIT,
|
||||
|
Loading…
x
Reference in New Issue
Block a user