Core updater improvements

This commit is contained in:
jdgleaver 2020-05-27 17:00:47 +01:00
parent 02bc3ee1e8
commit 9f4a9e9cd6
18 changed files with 531 additions and 122 deletions

View File

@ -957,10 +957,13 @@ static const bool stdin_cmd_enable = false;
static const uint16_t network_remote_base_port = 55400;
#define DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE true
#define DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES false
#if defined(ANDROID) || defined(IOS)
static const bool network_on_demand_thumbnails = true;
#define DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS true
#else
static const bool network_on_demand_thumbnails = false;
#define DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS false
#endif
/* Number of entries that will be kept in content history playlist file. */

View File

@ -1369,7 +1369,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
SETTING_BOOL("netplay_request_device_p14", &settings->bools.netplay_request_devices[13], true, false, false);
SETTING_BOOL("netplay_request_device_p15", &settings->bools.netplay_request_devices[14], true, false, false);
SETTING_BOOL("netplay_request_device_p16", &settings->bools.netplay_request_devices[15], true, false, false);
SETTING_BOOL("network_on_demand_thumbnails", &settings->bools.network_on_demand_thumbnails, true, network_on_demand_thumbnails, false);
SETTING_BOOL("network_on_demand_thumbnails", &settings->bools.network_on_demand_thumbnails, true, DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS, false);
#endif
SETTING_BOOL("input_descriptor_label_show", &settings->bools.input_descriptor_label_show, true, input_descriptor_label_show, false);
SETTING_BOOL("input_descriptor_hide_unbound", &settings->bools.input_descriptor_hide_unbound, true, input_descriptor_hide_unbound, false);
@ -1435,7 +1435,8 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
SETTING_BOOL("audio_fastforward_mute", &settings->bools.audio_fastforward_mute, true, DEFAULT_AUDIO_FASTFORWARD_MUTE, false);
SETTING_BOOL("location_allow", &settings->bools.location_allow, true, false, false);
SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, DEFAULT_FONT_ENABLE, false);
SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, true, false);
SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE, false);
SETTING_BOOL("core_updater_show_experimental_cores", &settings->bools.network_buildbot_show_experimental_cores, true, DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES, false);
SETTING_BOOL("camera_allow", &settings->bools.camera_allow, true, false, false);
SETTING_BOOL("discord_allow", &settings->bools.discord_enable, true, false, false);
#if defined(VITA)

View File

@ -285,6 +285,7 @@ typedef struct settings
/* Network */
bool network_buildbot_auto_extract_archive;
bool network_buildbot_show_experimental_cores;
bool network_on_demand_thumbnails;
/* UI */

View File

@ -189,6 +189,7 @@ static void core_info_list_free(core_info_list_t *core_info_list)
free(info->databases);
free(info->notes);
free(info->required_hw_api);
free(info->description);
string_list_free(info->supported_extensions_list);
string_list_free(info->authors_list);
string_list_free(info->note_list);
@ -471,6 +472,14 @@ static core_info_list_t *core_info_list_new(const char *path,
tmp = NULL;
}
if (config_get_string(conf, "description", &tmp))
{
if (!string_is_empty(tmp))
core_info[i].description = strdup(tmp);
free(tmp);
tmp = NULL;
}
if (tmp)
free(tmp);
tmp = NULL;
@ -484,6 +493,10 @@ static core_info_list_t *core_info_list_new(const char *path,
if (config_get_bool(conf, "database_match_archive_member",
&tmp_bool))
core_info[i].database_match_archive_member = tmp_bool;
if (config_get_bool(conf, "is_experimental",
&tmp_bool))
core_info[i].is_experimental = tmp_bool;
}
core_info[i].config_data = conf;
@ -1003,6 +1016,100 @@ bool core_info_get_display_name(const char *path, char *s, size_t len)
return true;
}
/* Returns core_info parameters required for
* core updater tasks, read from specified file.
* Returned core_updater_info_t object must be
* freed using core_info_free_core_updater_info().
* Returns NULL if 'path' is invalid. */
core_updater_info_t *core_info_get_core_updater_info(const char *path)
{
char *tmp_str = NULL;
bool tmp_bool = false;
core_updater_info_t *info = NULL;
config_file_t *conf = NULL;
if (string_is_empty(path))
return NULL;
/* Read config file */
conf = config_file_new_from_path_to_string(path);
if (!conf)
return NULL;
/* Create info struct */
info = (core_updater_info_t*)calloc(1, sizeof(*info));
if (!info)
return NULL;
/* Fetch required parameters */
/* > is_experimental */
info->is_experimental = false;
if (config_get_bool(conf, "is_experimental", &tmp_bool))
info->is_experimental = tmp_bool;
/* > display_name */
info->display_name = NULL;
if (config_get_string(conf, "display_name", &tmp_str))
{
if (!string_is_empty(tmp_str))
info->display_name = tmp_str;
else
free(tmp_str);
tmp_str = NULL;
}
/* > description */
info->description = NULL;
if (config_get_string(conf, "description", &tmp_str))
{
if (!string_is_empty(tmp_str))
info->description = tmp_str;
else
free(tmp_str);
tmp_str = NULL;
}
/* > licenses */
info->licenses = NULL;
if (config_get_string(conf, "license", &tmp_str))
{
if (!string_is_empty(tmp_str))
info->licenses = tmp_str;
else
free(tmp_str);
tmp_str = NULL;
}
/* Clean up */
config_file_free(conf);
return info;
}
void core_info_free_core_updater_info(core_updater_info_t *info)
{
if (!info)
return;
if (info->display_name)
free(info->display_name);
if (info->description)
free(info->description);
if (info->licenses)
free(info->licenses);
free(info);
info = NULL;
}
static int core_info_qsort_func_path(const core_info_t *a,
const core_info_t *b)
{

View File

@ -39,6 +39,7 @@ typedef struct
{
bool supports_no_game;
bool database_match_archive_member;
bool is_experimental;
size_t firmware_count;
char *path;
void *config_data;
@ -56,6 +57,7 @@ typedef struct
char *databases;
char *notes;
char *required_hw_api;
char *description;
struct string_list *categories_list;
struct string_list *databases_list;
struct string_list *note_list;
@ -68,6 +70,16 @@ typedef struct
void *userdata;
} core_info_t;
/* A subset of core_info parameters required for
* core updater tasks */
typedef struct
{
bool is_experimental;
char *display_name;
char *description;
char *licenses;
} core_updater_info_t;
typedef struct
{
core_info_t *list;
@ -109,6 +121,14 @@ bool core_info_list_get_display_name(core_info_list_t *list,
bool core_info_get_display_name(const char *path, char *s, size_t len);
/* Returns core_info parameters required for
* core updater tasks, read from specified file.
* Returned core_updater_info_t object must be
* freed using core_info_free_core_updater_info().
* Returns NULL if 'path' is invalid. */
core_updater_info_t *core_info_get_core_updater_info(const char *path);
void core_info_free_core_updater_info(core_updater_info_t *info);
void core_info_get_name(const char *path, char *s, size_t len,
const char *path_info, const char *dir_cores,
const char *exts, bool show_hidden_files,

View File

@ -82,6 +82,18 @@ static void core_updater_list_free_entry(core_updater_list_entry_t *entry)
free(entry->display_name);
entry->display_name = NULL;
}
if (entry->description)
{
free(entry->description);
entry->description = NULL;
}
if (entry->licenses_list)
{
string_list_free(entry->licenses_list);
entry->licenses_list = NULL;
}
}
/* Creates a new, empty core updater list.
@ -410,13 +422,11 @@ static bool core_updater_list_set_paths(
char remote_core_path[PATH_MAX_LENGTH];
char local_core_path[PATH_MAX_LENGTH];
char local_info_path[PATH_MAX_LENGTH];
char display_name[255];
bool is_archive;
remote_core_path[0] = '\0';
local_core_path[0] = '\0';
local_info_path[0] = '\0';
display_name[0] = '\0';
if (!entry || string_is_empty(filename_str))
return false;
@ -518,29 +528,94 @@ static bool core_updater_list_set_paths(
entry->local_info_path = strdup(local_info_path);
/* display_name
* > Note: It's a bit rubbish that we have to
* read the actual core info files here...
* Would be better to cache this globally
* (at present, we only cache info for
* *installed* cores...) */
if (path_is_valid(local_info_path))
if (!core_info_get_display_name(
local_info_path, display_name, sizeof(display_name)))
display_name[0] = '\0';
return true;
}
/* > If info file does not exist, just use
* core filename */
if (string_is_empty(display_name))
strlcpy(display_name, filename_str, sizeof(display_name));
/* Reads info file associated with core and
* adds relevant information to updater list
* entry */
static bool core_updater_list_set_core_info(
core_updater_list_entry_t *entry,
const char *local_info_path,
const char *filename_str)
{
core_updater_info_t *core_info = NULL;
if (!entry ||
string_is_empty(local_info_path) ||
string_is_empty(filename_str))
return false;
/* Clear any existing core info */
if (entry->display_name)
{
free(entry->display_name);
entry->display_name = NULL;
}
entry->display_name = strdup(display_name);
if (entry->description)
{
free(entry->description);
entry->description = NULL;
}
if (entry->licenses_list)
{
/* Note: We can safely leave this as NULL if
* the core info file is invalid */
string_list_free(entry->licenses_list);
entry->licenses_list = NULL;
}
entry->is_experimental = false;
/* Read core info file
* > Note: It's a bit rubbish that we have to
* read the actual core info files here...
* Would be better to cache this globally
* (at present, we only cache info for
* *installed* cores...) */
core_info = core_info_get_core_updater_info(local_info_path);
if (core_info)
{
/* display_name + is_experimental */
if (!string_is_empty(core_info->display_name))
{
entry->display_name = strdup(core_info->display_name);
entry->is_experimental = core_info->is_experimental;
}
else
{
/* If display name is blank, use core filename and
* assume core is experimental (i.e. all 'fit for consumption'
* cores must have a valid/complete core info file) */
entry->display_name = strdup(filename_str);
entry->is_experimental = true;
}
/* description */
if (!string_is_empty(core_info->description))
entry->description = strdup(core_info->description);
else
entry->description = strdup("");
/* licenses_list */
if (!string_is_empty(core_info->licenses))
entry->licenses_list = string_split(core_info->licenses, "|");
/* Clean up */
core_info_free_core_updater_info(core_info);
}
else
{
/* If info file is missing, use core filename and
* assume core is experimental (i.e. all 'fit for consumption'
* cores must have a valid/complete core info file) */
entry->display_name = strdup(filename_str);
entry->is_experimental = true;
entry->description = strdup("");
}
return true;
}
@ -576,10 +651,15 @@ static bool core_updater_list_push_entry(
list_entry->remote_core_path = entry->remote_core_path;
list_entry->local_core_path = entry->local_core_path;
list_entry->local_info_path = entry->local_info_path;
/* Assign core info */
list_entry->display_name = entry->display_name;
list_entry->description = entry->description;
list_entry->licenses_list = entry->licenses_list;
list_entry->is_experimental = entry->is_experimental;
/* Copy crc */
list_entry->crc = entry->crc;
list_entry->crc = entry->crc;
/* Copy date */
memcpy(&list_entry->date, &entry->date, sizeof(core_updater_list_date_t));
@ -644,6 +724,12 @@ static void core_updater_list_add_entry(
filename_str))
goto error;
if (!core_updater_list_set_core_info(
&entry,
entry.local_info_path,
filename_str))
goto error;
/* Add entry to list */
if (!core_updater_list_push_entry(core_list, &entry))
goto error;

View File

@ -26,6 +26,8 @@
#include <retro_common_api.h>
#include <libretro.h>
#include <lists/string_list.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
@ -52,6 +54,9 @@ typedef struct
char *local_core_path;
char *local_info_path;
char *display_name;
char *description;
struct string_list *licenses_list;
bool is_experimental;
uint32_t crc;
core_updater_list_date_t date;
} core_updater_list_entry_t;

View File

@ -492,6 +492,10 @@ MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE,
"core_updater_auto_extract_archive"
)
MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
"core_updater_show_experimental_cores"
)
MSG_HASH(
MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL,
"core_updater_buildbot_url"

View File

@ -4373,6 +4373,14 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE,
"After downloading, automatically extract files contained in the downloaded archives."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
"Show Experimental Cores"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
"Include 'experimental' cores in the Core Updater download list. These are typically for development/testing purposes only, and are not recommended for general use."
)
/* Settings > Playlists */

View File

@ -60,35 +60,31 @@
static int menu_action_sublabel_file_browser_core(file_list_t *list, unsigned type, unsigned i, const char *label, const char *path, char *s, size_t len)
{
core_info_list_t *core_list = NULL;
core_info_ctx_find_t core_info;
core_info_get_list(&core_list);
/* Set sublabel prefix */
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES), len);
strlcat(s, ": ", len);
strlcpy(s, "License: ", len);
/* Search for specified core */
core_info.inf = NULL;
core_info.path = path;
if (core_list)
if (core_info_find(&core_info, path) &&
core_info.inf->licenses_list)
{
unsigned j;
for (j = 0; j < core_list->count; j++)
{
if (string_is_equal(path_basename(core_list->list[j].path),
path))
{
if (core_list->list[j].licenses_list)
{
char tmp[PATH_MAX_LENGTH];
tmp[0] = '\0';
char tmp[MENU_SUBLABEL_MAX_LENGTH];
tmp[0] = '\0';
string_list_join_concat(tmp, sizeof(tmp),
core_list->list[j].licenses_list, ", ");
strlcat(s, tmp, len);
return 1;
}
}
}
/* Add license text */
string_list_join_concat(tmp, sizeof(tmp),
core_info.inf->licenses_list, ", ");
strlcat(s, tmp, len);
return 1;
}
strlcat(s, "N/A", len);
/* No license found - set to N/A */
strlcat(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), len);
return 1;
}
@ -473,6 +469,7 @@ default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs,
default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs_port, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT)
default_sublabel_macro(action_bind_sublabel_core_updater_buildbot_assets_url, MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL)
default_sublabel_macro(action_bind_sublabel_core_updater_auto_extract_archive, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE)
default_sublabel_macro(action_bind_sublabel_core_updater_show_experimental_cores, MENU_ENUM_SUBLABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES)
default_sublabel_macro(action_bind_sublabel_netplay_refresh_rooms, MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS)
default_sublabel_macro(action_bind_sublabel_rename_entry, MENU_ENUM_SUBLABEL_RENAME_ENTRY)
default_sublabel_macro(action_bind_sublabel_delete_entry, MENU_ENUM_SUBLABEL_DELETE_ENTRY)
@ -1208,6 +1205,39 @@ static int action_bind_sublabel_core_option(
return 0;
}
static int action_bind_sublabel_core_updater_entry(
file_list_t *list,
unsigned type, unsigned i,
const char *label, const char *path,
char *s, size_t len)
{
core_updater_list_t *core_list = core_updater_list_get_cached();
const core_updater_list_entry_t *entry = NULL;
/* Set sublabel prefix */
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES), len);
strlcat(s, ": ", len);
/* Search for specified core */
if (core_list &&
core_updater_list_get_filename(core_list, path, &entry) &&
entry->licenses_list)
{
char tmp[MENU_SUBLABEL_MAX_LENGTH];
tmp[0] = '\0';
/* Add license text */
string_list_join_concat(tmp, sizeof(tmp),
entry->licenses_list, ", ");
strlcat(s, tmp, len);
return 1;
}
/* No license found - set to N/A */
strlcat(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), len);
return 1;
}
static int action_bind_sublabel_generic(
file_list_t *list,
unsigned type, unsigned i,
@ -1307,6 +1337,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
return 0;
}
if (type == FILE_TYPE_DOWNLOAD_CORE)
{
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_entry);
return 0;
}
if (cbs->enum_idx != MSG_UNKNOWN)
{
switch (cbs->enum_idx)
@ -2102,6 +2138,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_auto_extract_archive);
break;
case MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_show_experimental_cores);
break;
case MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_updater_buildbot_url);
break;

View File

@ -1425,6 +1425,7 @@ typedef struct materialui_handle
bool is_playlist;
bool is_file_list;
bool is_dropdown_list;
bool is_core_updater_list;
bool last_show_nav_bar;
bool last_auto_rotate_nav_bar;
bool menu_stack_flushed;
@ -2149,16 +2150,32 @@ static void materialui_render_messagebox(materialui_handle_t *mui,
unsigned i;
int x = 0;
int y = 0;
int usable_width = 0;
int longest_width = 0;
size_t longest_len = 0;
struct string_list *list = NULL;
char wrapped_message[MENU_SUBLABEL_MAX_LENGTH];
wrapped_message[0] = '\0';
/* Sanity check */
if (!mui || !mui->font_data.list.font)
if (string_is_empty(message) ||
!mui ||
!mui->font_data.list.font)
goto end;
usable_width = (int)video_width - (mui->margin * 4.0);
if (usable_width < 1)
goto end;
/* Split message into lines */
list = string_split(message, "\n");
word_wrap(
wrapped_message, message,
usable_width / (int)mui->font_data.list.glyph_width,
true, 0);
list = string_split(wrapped_message, "\n");
if (!list || list->elems == 0)
goto end;
@ -2177,14 +2194,11 @@ static void materialui_render_messagebox(materialui_handle_t *mui,
if (!string_is_empty(line))
{
size_t len = utf8len(line);
int width = font_driver_get_message_width(
mui->font_data.list.font, line, (unsigned)strlen(line), 1);
if (len > longest_len)
{
longest_len = len;
longest_width = font_driver_get_message_width(
mui->font_data.list.font, line, (unsigned)strlen(line), 1);
}
longest_width = (width > longest_width) ?
width : longest_width;
}
}
@ -2321,7 +2335,7 @@ static unsigned materialui_count_sublabel_lines(
word_wrap(
wrapped_sublabel_str, sublabel_str,
sublabel_width_max / (int)mui->font_data.hint.glyph_width,
false, 0);
true, 0);
/* Return number of lines in wrapped string */
return materialui_count_lines(wrapped_sublabel_str);
@ -7121,6 +7135,7 @@ static void *materialui_init(void **userdata, bool video_is_threaded)
mui->is_playlist = false;
mui->is_file_list = false;
mui->is_dropdown_list = false;
mui->is_core_updater_list = false;
mui->menu_stack_flushed = false;
mui->first_onscreen_entry = 0;
@ -7575,6 +7590,11 @@ static void materialui_populate_entries(
* scrolling via an alphabet search) */
mui->is_playlist_tab = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PLAYLISTS_TAB));
/* Check whether this is the core updater menu
* (this requires special handling when long
* pressing an entry) */
mui->is_core_updater_list = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST));
/* Check whether we are currently viewing a playlist,
* file-browser-type list or dropdown list
* (each of these is regarded as a 'plain' list,
@ -7594,7 +7614,7 @@ static void materialui_populate_entries(
* Note: MENU_ENUM_LABEL_FAVORITES is always set
* as the 'label' when navigating directories after
* selecting load content */
mui->is_file_list = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_UPDATER_LIST)) ||
mui->is_file_list = mui->is_core_updater_list ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SCAN_DIRECTORY)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SCAN_FILE)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST)) ||
@ -8942,9 +8962,17 @@ static int materialui_pointer_up(void *userdata,
}
break;
case MENU_INPUT_GESTURE_LONG_PRESS:
/* 'Reset to default' action */
if ((ptr < entries_end) && (ptr == selection))
return materialui_menu_entry_action(mui, entry, selection, MENU_ACTION_START);
{
/* If this is the core updater list, show info
* message box for current entry.
* In all other cases, perform 'reset to default'
* action */
if (mui->is_core_updater_list)
return materialui_menu_entry_action(mui, entry, selection, MENU_ACTION_INFO);
else
return materialui_menu_entry_action(mui, entry, selection, MENU_ACTION_START);
}
break;
case MENU_INPUT_GESTURE_SWIPE_LEFT:
{

View File

@ -516,21 +516,37 @@ void ozone_draw_messagebox(
const char *message)
{
unsigned i, y_position;
int x, y, longest = 0, longest_width = 0;
struct string_list *list = !string_is_empty(message)
? string_split(message, "\n") : NULL;
float scale_factor = ozone->last_scale_factor;
int x, y, longest_width = 0;
int usable_width = 0;
struct string_list *list = NULL;
float scale_factor = 0.0f;
unsigned width = video_width;
unsigned height = video_height;
char wrapped_message[MENU_SUBLABEL_MAX_LENGTH];
if (!list || !ozone || !ozone->fonts.footer.font)
{
if (list)
string_list_free(list);
return;
}
wrapped_message[0] = '\0';
if (list->elems == 0)
/* Sanity check */
if (string_is_empty(message) ||
!ozone ||
!ozone->fonts.footer.font)
goto end;
scale_factor = ozone->last_scale_factor;
usable_width = (int)width - (48 * 8 * scale_factor);
if (usable_width < 1)
goto end;
/* Split message into lines */
word_wrap(
wrapped_message, message,
usable_width / (int)ozone->fonts.footer.glyph_width,
true, 0);
list = string_split(wrapped_message, "\n");
if (!list || list->elems == 0)
goto end;
y_position = height / 2;
@ -544,13 +560,14 @@ void ozone_draw_messagebox(
for (i = 0; i < list->size; i++)
{
const char *msg = list->elems[i].data;
int len = (int)utf8len(msg);
if (len > longest)
if (!string_is_empty(msg))
{
longest = len;
longest_width = font_driver_get_message_width(
int width = font_driver_get_message_width(
ozone->fonts.footer.font, msg, (unsigned)strlen(msg), 1);
longest_width = (width > longest_width) ?
width : longest_width;
}
}
@ -606,7 +623,8 @@ void ozone_draw_messagebox(
}
end:
string_list_free(list);
if (list)
string_list_free(list);
}
void ozone_draw_fullscreen_thumbnails(

View File

@ -2768,21 +2768,28 @@ static void rgui_render_messagebox(rgui_t *rgui, const char *message)
int x, y;
size_t i, fb_pitch;
unsigned fb_width, fb_height;
unsigned width, glyphs_width, height;
struct string_list *list = NULL;
unsigned width = 0;
unsigned glyphs_width = 0;
unsigned height = 0;
struct string_list *list = NULL;
char wrapped_message[MENU_SUBLABEL_MAX_LENGTH];
if (!message || !*message)
wrapped_message[0] = '\0';
if (string_is_empty(message))
return;
list = string_split(message, "\n");
if (!list)
return;
if (list->elems == 0)
/* Split message into lines */
word_wrap(
wrapped_message, message,
rgui_term_layout.width,
false, 0);
list = string_split(wrapped_message, "\n");
if (!list || list->elems == 0)
goto end;
width = 0;
glyphs_width = 0;
gfx_display_get_fb_size(&fb_width, &fb_height,
&fb_pitch);
@ -2792,23 +2799,18 @@ static void rgui_render_messagebox(rgui_t *rgui, const char *message)
char *msg = list->elems[i].data;
unsigned msglen = (unsigned)utf8len(msg);
if (msglen > rgui_term_layout.width)
{
msg[rgui_term_layout.width - 2] = '.';
msg[rgui_term_layout.width - 1] = '.';
msg[rgui_term_layout.width - 0] = '.';
msg[rgui_term_layout.width + 1] = '\0';
msglen = rgui_term_layout.width;
}
line_width = msglen * FONT_WIDTH_STRIDE - 1 + 6 + 10;
width = MAX(width, line_width);
glyphs_width = MAX(glyphs_width, msglen);
}
height = (unsigned)(FONT_HEIGHT_STRIDE * list->size + 6 + 10);
x = (fb_width - width) / 2;
y = (fb_height - height) / 2;
x = ((int)fb_width - (int)width) / 2;
y = ((int)fb_height - (int)height) / 2;
height = (height > fb_height) ? fb_height : height;
x = (x < 0) ? 0 : x;
y = (y < 0) ? 0 : y;
if (rgui_frame_buf.data)
{
@ -2854,19 +2856,30 @@ static void rgui_render_messagebox(rgui_t *rgui, const char *message)
border_dark_color, border_light_color, border_thickness);
}
for (i = 0; i < list->size; i++)
/* Draw text */
if (rgui_frame_buf.data)
{
const char *msg = list->elems[i].data;
int offset_x = (int)(FONT_WIDTH_STRIDE * (glyphs_width - utf8len(msg)) / 2);
int offset_y = (int)(FONT_HEIGHT_STRIDE * i);
for (i = 0; i < list->size; i++)
{
const char *msg = list->elems[i].data;
int offset_x = (int)(FONT_WIDTH_STRIDE * (glyphs_width - utf8len(msg)) / 2);
int offset_y = (int)(FONT_HEIGHT_STRIDE * i);
int text_x = x + 8 + offset_x;
int text_y = y + 8 + offset_y;
if (rgui_frame_buf.data)
blit_line(fb_width, x + 8 + offset_x, y + 8 + offset_y, msg,
/* Ensure we remain within the bounds of the
* framebuffer */
if (text_y > (int)fb_height - 10 - (int)FONT_HEIGHT_STRIDE)
break;
blit_line(fb_width, text_x, text_y, msg,
rgui->colors.normal_color, rgui->colors.shadow_color);
}
}
end:
string_list_free(list);
if (list)
string_list_free(list);
}
static void rgui_blit_cursor(rgui_t *rgui)

View File

@ -902,17 +902,32 @@ static void xmb_render_messagebox_internal(
unsigned i, y_position;
int x, y, longest = 0, longest_width = 0;
float line_height = 0;
struct string_list *list = !string_is_empty(message)
? string_split(message, "\n") : NULL;
int usable_width = 0;
struct string_list *list = NULL;
char wrapped_message[MENU_SUBLABEL_MAX_LENGTH];
if (!list || !xmb || !xmb->font)
{
if (list)
string_list_free(list);
return;
}
wrapped_message[0] = '\0';
if (list->elems == 0)
/* Sanity check */
if (string_is_empty(message) ||
!xmb ||
!xmb->font)
goto end;
usable_width = (int)video_width - (xmb->margins_dialog * 8);
if (usable_width < 1)
goto end;
/* Split message into lines */
word_wrap(
wrapped_message, message,
usable_width / (xmb->font_size * 0.6f),
true, 0);
list = string_split(wrapped_message, "\n");
if (!list || list->elems == 0)
goto end;
line_height = xmb->font->size * 1.2;
@ -927,14 +942,15 @@ static void xmb_render_messagebox_internal(
/* find the longest line width */
for (i = 0; i < list->size; i++)
{
const char *msg = list->elems[i].data;
int len = (int)utf8len(msg);
const char *msg = list->elems[i].data;
if (len > longest)
if (!string_is_empty(msg))
{
longest = len;
longest_width = font_driver_get_message_width(
int width = font_driver_get_message_width(
xmb->font, msg, (unsigned)strlen(msg), 1);
longest_width = (width > longest_width) ?
width : longest_width;
}
}
@ -978,7 +994,8 @@ static void xmb_render_messagebox_internal(
0xffffffff);
end:
string_list_free(list);
if (list)
string_list_free(list);
}
static void xmb_update_savestate_thumbnail_path(void *data, unsigned i)

View File

@ -7070,6 +7070,7 @@ unsigned menu_displaylist_build_list(
{MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
@ -8828,9 +8829,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
#ifdef HAVE_NETWORKING
{
core_updater_list_t *core_list = core_updater_list_get_cached();
settings_t *settings = config_get_ptr();
bool show_experimental_cores = settings->bools.network_buildbot_show_experimental_cores;
if (core_list)
{
size_t menu_index = 0;
size_t i;
for (i = 0; i < core_updater_list_size(core_list); i++)
@ -8839,15 +8843,25 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
if (core_updater_list_get_index(core_list, i, &entry))
{
/* Skip 'experimental' cores, if required
* > Note: We always show cores that are already
* installed, regardless of status (a user should
* always have the option to update existing cores) */
if (!show_experimental_cores &&
(entry->is_experimental &&
!path_is_valid(entry->local_core_path)))
continue;
if (menu_entries_append_enum(info->list,
entry->remote_filename,
"",
MENU_ENUM_LABEL_URL_ENTRY,
MENU_ENUM_LABEL_CORE_UPDATER_ENTRY,
FILE_TYPE_DOWNLOAD_CORE, 0, 0))
{
file_list_set_alt_at_offset(
info->list, i, entry->display_name);
info->list, menu_index, entry->display_name);
menu_index++;
count++;
}
}

View File

@ -298,8 +298,35 @@ static int generic_menu_iterate(void *data,
if (cbs && cbs->enum_idx != MSG_UNKNOWN)
{
ret = menu_hash_get_help_enum(cbs->enum_idx,
menu->menu_state_msg, sizeof(menu->menu_state_msg));
#ifdef HAVE_NETWORKING
/* Core updater entries require special treatment */
if (cbs->enum_idx == MENU_ENUM_LABEL_CORE_UPDATER_ENTRY)
{
core_updater_list_t *core_list = core_updater_list_get_cached();
const core_updater_list_entry_t *entry = NULL;
const char *path = NULL;
/* Get core path */
menu_entries_get_at_offset(selection_buf, selection,
&path, NULL, NULL, NULL, NULL);
/* Search for specified core */
if (core_list && path &&
core_updater_list_get_filename(core_list, path, &entry) &&
!string_is_empty(entry->description))
strlcpy(menu->menu_state_msg, entry->description,
sizeof(menu->menu_state_msg));
else
strlcpy(menu->menu_state_msg,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE),
sizeof(menu->menu_state_msg));
ret = 0;
}
else
#endif
ret = menu_hash_get_help_enum(cbs->enum_idx,
menu->menu_state_msg, sizeof(menu->menu_state_msg));
#ifdef HAVE_ACCESSIBILITY
if (iterate_type != last_iterate_type && is_accessibility_enabled())

View File

@ -16100,7 +16100,23 @@ static bool setting_append_list(
&settings->bools.network_buildbot_auto_extract_archive,
MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE,
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE,
true,
DEFAULT_NETWORK_BUILDBOT_AUTO_EXTRACT_ARCHIVE,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE
);
CONFIG_BOOL(
list, list_info,
&settings->bools.network_buildbot_show_experimental_cores,
MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES,
DEFAULT_NETWORK_BUILDBOT_SHOW_EXPERIMENTAL_CORES,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
@ -16552,7 +16568,7 @@ static bool setting_append_list(
&settings->bools.network_on_demand_thumbnails,
MENU_ENUM_LABEL_NETWORK_ON_DEMAND_THUMBNAILS,
MENU_ENUM_LABEL_VALUE_NETWORK_ON_DEMAND_THUMBNAILS,
network_on_demand_thumbnails,
DEFAULT_NETWORK_ON_DEMAND_THUMBNAILS,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,

View File

@ -681,6 +681,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_SHADER_PARAMETERS_ENTRY,
MENU_ENUM_LABEL_RDB_ENTRY,
MENU_ENUM_LABEL_URL_ENTRY,
MENU_ENUM_LABEL_CORE_UPDATER_ENTRY,
MENU_ENUM_LABEL_CORE_OPTION_ENTRY,
MENU_ENUM_LABEL_NETWORK_INFO_ENTRY,
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY,
@ -1881,6 +1882,7 @@ enum msg_hash_enums
MENU_LABEL(START_CORE),
MENU_LABEL(CORE_UPDATER_LIST),
MENU_LABEL(CORE_UPDATER_AUTO_EXTRACT_ARCHIVE),
MENU_LABEL(CORE_UPDATER_SHOW_EXPERIMENTAL_CORES),
MENU_LABEL(CORE_UPDATER_BUILDBOT_URL),
MENU_LABEL(BUILDBOT_ASSETS_URL),
MENU_LABEL(CORE_SET_SUPPORTS_NO_CONTENT_ENABLE),