Merge pull request #9100 from jdgleaver/hide-core-options

An environment callback for selectively hiding core options
This commit is contained in:
Twinaphex 2019-07-12 19:28:48 +02:00 committed by GitHub
commit 91558822e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 238 additions and 60 deletions

View File

@ -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) */

View File

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

View File

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

View File

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

View File

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