(RGUI) Savestate thumbnails (#14326)
This commit is contained in:
parent
245319c389
commit
c818024bc6
|
@ -114,8 +114,8 @@ int action_switch_thumbnail(const char *path,
|
||||||
if (!settings)
|
if (!settings)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* RGUI is a special case where thumbnail 'switch' corresponds to
|
/* RGUI has its own cycling for thumbnails in order to allow
|
||||||
* toggling thumbnail view on/off.
|
* cycling all images in fullscreen mode.
|
||||||
* GLUI is a special case where thumbnail 'switch' corresponds to
|
* GLUI is a special case where thumbnail 'switch' corresponds to
|
||||||
* changing thumbnail view mode.
|
* changing thumbnail view mode.
|
||||||
* For other menu drivers, we cycle through available thumbnail
|
* For other menu drivers, we cycle through available thumbnail
|
||||||
|
|
|
@ -284,6 +284,7 @@ typedef struct
|
||||||
|
|
||||||
unsigned mini_thumbnail_max_width;
|
unsigned mini_thumbnail_max_width;
|
||||||
unsigned mini_thumbnail_max_height;
|
unsigned mini_thumbnail_max_height;
|
||||||
|
unsigned mini_thumbnail_delay;
|
||||||
unsigned last_width;
|
unsigned last_width;
|
||||||
unsigned last_height;
|
unsigned last_height;
|
||||||
unsigned window_width;
|
unsigned window_width;
|
||||||
|
@ -298,15 +299,24 @@ typedef struct
|
||||||
|
|
||||||
uint32_t thumbnail_queue_size;
|
uint32_t thumbnail_queue_size;
|
||||||
uint32_t left_thumbnail_queue_size;
|
uint32_t left_thumbnail_queue_size;
|
||||||
|
int8_t gfx_thumbnails_prev;
|
||||||
|
|
||||||
rgui_particle_t particles[RGUI_NUM_PARTICLES]; /* float alignment */
|
rgui_particle_t particles[RGUI_NUM_PARTICLES]; /* float alignment */
|
||||||
|
|
||||||
|
size_t playlist_index;
|
||||||
int16_t scroll_y;
|
int16_t scroll_y;
|
||||||
rgui_colors_t colors; /* int16_t alignment */
|
rgui_colors_t colors; /* int16_t alignment */
|
||||||
|
|
||||||
struct scaler_ctx image_scaler;
|
struct scaler_ctx image_scaler;
|
||||||
menu_input_pointer_t pointer;
|
menu_input_pointer_t pointer;
|
||||||
|
|
||||||
|
/* These have to be huge, because runloop_st->name.savestate
|
||||||
|
* has a hard-coded size of 8192...
|
||||||
|
* (the extra space here is required to silence compiler
|
||||||
|
* warnings...) */
|
||||||
|
char savestate_thumbnail_file_path[8204];
|
||||||
|
char prev_savestate_thumbnail_file_path[8204];
|
||||||
|
|
||||||
char msgbox[1024];
|
char msgbox[1024];
|
||||||
char theme_preset_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */
|
char theme_preset_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */
|
||||||
char theme_dynamic_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */
|
char theme_dynamic_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */
|
||||||
|
@ -329,6 +339,8 @@ typedef struct
|
||||||
bool shadow_enable;
|
bool shadow_enable;
|
||||||
bool extended_ascii_enable;
|
bool extended_ascii_enable;
|
||||||
bool is_playlist;
|
bool is_playlist;
|
||||||
|
bool is_quick_menu;
|
||||||
|
bool is_state_slot;
|
||||||
bool entry_has_thumbnail;
|
bool entry_has_thumbnail;
|
||||||
bool entry_has_left_thumbnail;
|
bool entry_has_left_thumbnail;
|
||||||
bool show_fs_thumbnail;
|
bool show_fs_thumbnail;
|
||||||
|
@ -2310,15 +2322,31 @@ static bool rgui_downscale_thumbnail(
|
||||||
struct texture_image *image_src,
|
struct texture_image *image_src,
|
||||||
struct texture_image *image_dst)
|
struct texture_image *image_dst)
|
||||||
{
|
{
|
||||||
|
video_driver_state_t *video_st = video_state_get_ptr();
|
||||||
|
bool thumbnail_core_aspect = !string_is_empty(rgui->savestate_thumbnail_file_path);
|
||||||
/* Determine output dimensions */
|
/* Determine output dimensions */
|
||||||
float display_aspect_ratio = (float)max_width / (float)max_height;
|
float display_aspect_ratio = (float)max_width / (float)max_height;
|
||||||
float aspect_ratio = (float)image_src->width
|
float aspect_ratio = (float)image_src->width / (float)image_src->height;
|
||||||
/ (float)image_src->height;
|
float core_aspect = (thumbnail_core_aspect && video_st)
|
||||||
|
? video_st->av_info.geometry.aspect_ratio : aspect_ratio;
|
||||||
|
|
||||||
if (aspect_ratio > display_aspect_ratio)
|
if (aspect_ratio > display_aspect_ratio)
|
||||||
{
|
{
|
||||||
image_dst->width = max_width;
|
image_dst->width = max_width;
|
||||||
image_dst->height = image_src->height * max_width / image_src->width;
|
image_dst->height = image_src->height * max_width / image_src->width;
|
||||||
|
|
||||||
|
if (thumbnail_core_aspect)
|
||||||
|
{
|
||||||
|
image_dst->height = image_dst->height * (aspect_ratio / core_aspect);
|
||||||
|
|
||||||
|
if (image_dst->height > image_src->height)
|
||||||
|
{
|
||||||
|
image_dst->height = image_src->height;
|
||||||
|
image_dst->width = (float)image_src->width * (image_dst->height / (float)image_src->height);
|
||||||
|
image_dst->width = image_dst->width / (aspect_ratio / core_aspect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Account for any possible rounding errors... */
|
/* Account for any possible rounding errors... */
|
||||||
image_dst->height = (image_dst->height < 1) ? 1 : image_dst->height;
|
image_dst->height = (image_dst->height < 1) ? 1 : image_dst->height;
|
||||||
image_dst->height = (image_dst->height > max_height) ? max_height : image_dst->height;
|
image_dst->height = (image_dst->height > max_height) ? max_height : image_dst->height;
|
||||||
|
@ -2327,6 +2355,10 @@ static bool rgui_downscale_thumbnail(
|
||||||
{
|
{
|
||||||
image_dst->height = max_height;
|
image_dst->height = max_height;
|
||||||
image_dst->width = image_src->width * max_height / image_src->height;
|
image_dst->width = image_src->width * max_height / image_src->height;
|
||||||
|
|
||||||
|
if (thumbnail_core_aspect)
|
||||||
|
image_dst->width = image_dst->width / (aspect_ratio / core_aspect);
|
||||||
|
|
||||||
/* Account for any possible rounding errors... */
|
/* Account for any possible rounding errors... */
|
||||||
image_dst->width = (image_dst->width < 1) ? 1 : image_dst->width;
|
image_dst->width = (image_dst->width < 1) ? 1 : image_dst->width;
|
||||||
image_dst->width = (image_dst->width > max_width) ? max_width : image_dst->width;
|
image_dst->width = (image_dst->width > max_width) ? max_width : image_dst->width;
|
||||||
|
@ -2531,11 +2563,26 @@ static bool rgui_load_image(void *userdata, void *data, enum menu_image_type typ
|
||||||
{
|
{
|
||||||
struct texture_image *image = (struct texture_image*)data;
|
struct texture_image *image = (struct texture_image*)data;
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
|
bool menu_rgui_inline_thumbnails =
|
||||||
|
settings->bools.menu_rgui_inline_thumbnails;
|
||||||
|
bool savestate_thumbnail_enable =
|
||||||
|
settings->bools.savestate_thumbnail_enable;
|
||||||
unsigned menu_rgui_thumbnail_downscaler =
|
unsigned menu_rgui_thumbnail_downscaler =
|
||||||
settings->uints.menu_rgui_thumbnail_downscaler;
|
settings->uints.menu_rgui_thumbnail_downscaler;
|
||||||
rgui_process_thumbnail(rgui, &rgui->mini_left_thumbnail, &rgui->left_thumbnail_queue_size,
|
|
||||||
menu_rgui_thumbnail_downscaler,
|
if (rgui->show_fs_thumbnail)
|
||||||
image);
|
rgui_process_thumbnail(rgui, &rgui->fs_thumbnail, &rgui->left_thumbnail_queue_size,
|
||||||
|
menu_rgui_thumbnail_downscaler,
|
||||||
|
image);
|
||||||
|
else if (menu_rgui_inline_thumbnails || savestate_thumbnail_enable)
|
||||||
|
rgui_process_thumbnail(rgui, &rgui->mini_left_thumbnail, &rgui->left_thumbnail_queue_size,
|
||||||
|
menu_rgui_thumbnail_downscaler,
|
||||||
|
image);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rgui->left_thumbnail_queue_size > 0)
|
||||||
|
rgui->left_thumbnail_queue_size--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -4705,6 +4752,20 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, gfx_display_t *p_disp,
|
||||||
bool delay_update);
|
bool delay_update);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool rgui_is_running_quick_menu(void)
|
||||||
|
{
|
||||||
|
menu_entry_t entry;
|
||||||
|
|
||||||
|
MENU_ENTRY_INIT(entry);
|
||||||
|
entry.path_enabled = false;
|
||||||
|
entry.value_enabled = false;
|
||||||
|
entry.sublabel_enabled = false;
|
||||||
|
menu_entry_get(&entry, 0, 0, NULL, true);
|
||||||
|
|
||||||
|
return string_is_equal(entry.label, "resume_content") ||
|
||||||
|
string_is_equal(entry.label, "state_slot");
|
||||||
|
}
|
||||||
|
|
||||||
static void rgui_render(void *data,
|
static void rgui_render(void *data,
|
||||||
unsigned width, unsigned height,
|
unsigned width, unsigned height,
|
||||||
bool is_idle)
|
bool is_idle)
|
||||||
|
@ -4745,7 +4806,7 @@ static void rgui_render(void *data,
|
||||||
|
|
||||||
bool show_fs_thumbnail =
|
bool show_fs_thumbnail =
|
||||||
rgui->show_fs_thumbnail &&
|
rgui->show_fs_thumbnail &&
|
||||||
rgui->entry_has_thumbnail &&
|
(rgui->entry_has_thumbnail || !string_is_empty(rgui->savestate_thumbnail_file_path)) &&
|
||||||
(rgui->fs_thumbnail.is_valid || (rgui->thumbnail_queue_size > 0));
|
(rgui->fs_thumbnail.is_valid || (rgui->thumbnail_queue_size > 0));
|
||||||
gfx_animation_t *p_anim = anim_get_ptr();
|
gfx_animation_t *p_anim = anim_get_ptr();
|
||||||
gfx_display_t *p_disp = disp_get_ptr();
|
gfx_display_t *p_disp = disp_get_ptr();
|
||||||
|
@ -4754,6 +4815,13 @@ static void rgui_render(void *data,
|
||||||
if (!rgui || !rgui->frame_buf.data)
|
if (!rgui || !rgui->frame_buf.data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Show thumbnails only after certain period to prevent flashing */
|
||||||
|
if (rgui->mini_thumbnail_delay > 0)
|
||||||
|
{
|
||||||
|
rgui_inline_thumbnails = false;
|
||||||
|
rgui->mini_thumbnail_delay--;
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply pending aspect ratio update */
|
/* Apply pending aspect ratio update */
|
||||||
if (rgui->aspect_update_pending)
|
if (rgui->aspect_update_pending)
|
||||||
{
|
{
|
||||||
|
@ -4948,14 +5016,35 @@ static void rgui_render(void *data,
|
||||||
const char *thumbnail_title = NULL;
|
const char *thumbnail_title = NULL;
|
||||||
char thumbnail_title_buf[255];
|
char thumbnail_title_buf[255];
|
||||||
unsigned title_x, title_width;
|
unsigned title_x, title_width;
|
||||||
|
bool is_state_slot = !string_is_empty(rgui->savestate_thumbnail_file_path);
|
||||||
thumbnail_title_buf[0] = '\0';
|
thumbnail_title_buf[0] = '\0';
|
||||||
|
|
||||||
/* Draw thumbnail */
|
/* Draw thumbnail */
|
||||||
rgui_render_fs_thumbnail(rgui, fb_width, fb_height, fb_pitch);
|
rgui_render_fs_thumbnail(rgui, fb_width, fb_height, fb_pitch);
|
||||||
|
|
||||||
/* Get thumbnail title */
|
/* Get thumbnail title */
|
||||||
if (gfx_thumbnail_get_label(rgui->thumbnail_path_data, &thumbnail_title))
|
if (gfx_thumbnail_get_label(rgui->thumbnail_path_data, &thumbnail_title) ||
|
||||||
|
is_state_slot)
|
||||||
{
|
{
|
||||||
|
/* State slot title */
|
||||||
|
if (is_state_slot)
|
||||||
|
{
|
||||||
|
if (rgui->is_quick_menu)
|
||||||
|
{
|
||||||
|
snprintf(thumbnail_title_buf, sizeof(thumbnail_title_buf), "%s %d",
|
||||||
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT),
|
||||||
|
config_get_ptr()->ints.state_slot);
|
||||||
|
thumbnail_title = thumbnail_title_buf;
|
||||||
|
}
|
||||||
|
else if (rgui->is_state_slot)
|
||||||
|
{
|
||||||
|
snprintf(thumbnail_title_buf, sizeof(thumbnail_title_buf), "%s %d",
|
||||||
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT),
|
||||||
|
(int)menu_navigation_get_selection() - 1);
|
||||||
|
thumbnail_title = thumbnail_title_buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Format thumbnail title */
|
/* Format thumbnail title */
|
||||||
if (use_smooth_ticker)
|
if (use_smooth_ticker)
|
||||||
{
|
{
|
||||||
|
@ -4993,7 +5082,7 @@ static void rgui_render(void *data,
|
||||||
|
|
||||||
/* Draw thumbnail title */
|
/* Draw thumbnail title */
|
||||||
blit_line(rgui, fb_width, ticker_x_offset + title_x,
|
blit_line(rgui, fb_width, ticker_x_offset + title_x,
|
||||||
0, thumbnail_title_buf,
|
1, thumbnail_title_buf,
|
||||||
rgui->colors.hover_color, rgui->colors.shadow_color);
|
rgui->colors.hover_color, rgui->colors.shadow_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5011,9 +5100,12 @@ static void rgui_render(void *data,
|
||||||
unsigned core_name_len = menu_timedate_enable ?
|
unsigned core_name_len = menu_timedate_enable ?
|
||||||
((timedate_x - rgui->term_layout.start_x) / rgui->font_width_stride) - 3 :
|
((timedate_x - rgui->term_layout.start_x) / rgui->font_width_stride) - 3 :
|
||||||
rgui->term_layout.width - 1;
|
rgui->term_layout.width - 1;
|
||||||
bool show_mini_thumbnails = rgui->is_playlist && rgui_inline_thumbnails;
|
bool show_mini_thumbnails = rgui_inline_thumbnails &&
|
||||||
|
(rgui->is_playlist || (rgui->is_quick_menu && !rgui_is_running_quick_menu()));
|
||||||
bool show_thumbnail = false;
|
bool show_thumbnail = false;
|
||||||
bool show_left_thumbnail = false;
|
bool show_left_thumbnail = false;
|
||||||
|
bool show_savestate_thumbnail = (!string_is_empty(rgui->savestate_thumbnail_file_path) &&
|
||||||
|
(rgui->is_state_slot || (rgui->is_quick_menu && rgui_is_running_quick_menu())));
|
||||||
unsigned thumbnail_panel_width = 0;
|
unsigned thumbnail_panel_width = 0;
|
||||||
unsigned term_mid_point = 0;
|
unsigned term_mid_point = 0;
|
||||||
size_t powerstate_len = 0;
|
size_t powerstate_len = 0;
|
||||||
|
@ -5373,7 +5465,16 @@ static void rgui_render(void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw mini thumbnails, if required */
|
/* Draw mini thumbnails, if required */
|
||||||
if (show_mini_thumbnails)
|
if (show_savestate_thumbnail)
|
||||||
|
{
|
||||||
|
thumbnail_t *thumbnail_savestate = &rgui->mini_left_thumbnail;
|
||||||
|
if (show_savestate_thumbnail && thumbnail_savestate)
|
||||||
|
rgui_render_mini_thumbnail(rgui, thumbnail_savestate,
|
||||||
|
rgui->frame_buf.data,
|
||||||
|
GFX_THUMBNAIL_LEFT,
|
||||||
|
fb_width, fb_height, fb_pitch, menu_rgui_swap_thumbnails);
|
||||||
|
}
|
||||||
|
else if (show_mini_thumbnails)
|
||||||
{
|
{
|
||||||
thumbnail_t *thumbnail1 = &rgui->mini_thumbnail;
|
thumbnail_t *thumbnail1 = &rgui->mini_thumbnail;
|
||||||
thumbnail_t *thumbnail2 = &rgui->mini_left_thumbnail;
|
thumbnail_t *thumbnail2 = &rgui->mini_left_thumbnail;
|
||||||
|
@ -5993,7 +6094,7 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui,
|
||||||
|
|
||||||
/* Allocate thumbnail buffer */
|
/* Allocate thumbnail buffer */
|
||||||
rgui->fs_thumbnail.max_width = rgui->frame_buf.width;
|
rgui->fs_thumbnail.max_width = rgui->frame_buf.width;
|
||||||
rgui->fs_thumbnail.max_height = rgui->frame_buf.height;
|
rgui->fs_thumbnail.max_height = rgui->frame_buf.height - (unsigned)(rgui->font_height_stride * 2.0f) - 1;
|
||||||
rgui->fs_thumbnail.data = (uint16_t*)calloc(
|
rgui->fs_thumbnail.data = (uint16_t*)calloc(
|
||||||
rgui->fs_thumbnail.max_width * rgui->fs_thumbnail.max_height, sizeof(uint16_t));
|
rgui->fs_thumbnail.max_width * rgui->fs_thumbnail.max_height, sizeof(uint16_t));
|
||||||
if (!rgui->fs_thumbnail.data)
|
if (!rgui->fs_thumbnail.data)
|
||||||
|
@ -6173,11 +6274,15 @@ static void *rgui_init(void **userdata, bool video_is_threaded)
|
||||||
|
|
||||||
rgui->thumbnail_queue_size = 0;
|
rgui->thumbnail_queue_size = 0;
|
||||||
rgui->left_thumbnail_queue_size = 0;
|
rgui->left_thumbnail_queue_size = 0;
|
||||||
|
rgui->gfx_thumbnails_prev = -1;
|
||||||
rgui->thumbnail_load_pending = false;
|
rgui->thumbnail_load_pending = false;
|
||||||
rgui->thumbnail_load_trigger_time = 0;
|
rgui->thumbnail_load_trigger_time = 0;
|
||||||
/* Ensure that we start with fullscreen thumbnails disabled */
|
/* Ensure that we start with fullscreen thumbnails disabled */
|
||||||
rgui->show_fs_thumbnail = false;
|
rgui->show_fs_thumbnail = false;
|
||||||
|
|
||||||
|
rgui->savestate_thumbnail_file_path[0] = '\0';
|
||||||
|
rgui->prev_savestate_thumbnail_file_path[0] = '\0';
|
||||||
|
|
||||||
/* Ensure that pointer device starts with well defined
|
/* Ensure that pointer device starts with well defined
|
||||||
* values (shoult not be necessary, but some platforms may
|
* values (shoult not be necessary, but some platforms may
|
||||||
* not handle struct initialisation correctly...) */
|
* not handle struct initialisation correctly...) */
|
||||||
|
@ -6389,7 +6494,7 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, bool download_missing)
|
||||||
/* Left thumbnail
|
/* Left thumbnail
|
||||||
* (Note: there is no need to load this when viewing
|
* (Note: there is no need to load this when viewing
|
||||||
* fullscreen thumbnails) */
|
* fullscreen thumbnails) */
|
||||||
if (!rgui->show_fs_thumbnail)
|
if (!rgui->show_fs_thumbnail && string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
{
|
{
|
||||||
if (gfx_thumbnail_get_path(rgui->thumbnail_path_data,
|
if (gfx_thumbnail_get_path(rgui->thumbnail_path_data,
|
||||||
GFX_THUMBNAIL_LEFT, &left_thumbnail_path))
|
GFX_THUMBNAIL_LEFT, &left_thumbnail_path))
|
||||||
|
@ -6400,7 +6505,18 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, bool download_missing)
|
||||||
left_thumbnail_path,
|
left_thumbnail_path,
|
||||||
&thumbnails_missing);
|
&thumbnails_missing);
|
||||||
}
|
}
|
||||||
|
else if (!string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
|
{
|
||||||
|
if (gfx_thumbnail_get_path(rgui->thumbnail_path_data,
|
||||||
|
GFX_THUMBNAIL_LEFT, &left_thumbnail_path))
|
||||||
|
rgui->entry_has_left_thumbnail = rgui_request_thumbnail(
|
||||||
|
&rgui->mini_left_thumbnail,
|
||||||
|
GFX_THUMBNAIL_LEFT,
|
||||||
|
&rgui->left_thumbnail_queue_size,
|
||||||
|
rgui->savestate_thumbnail_file_path,
|
||||||
|
&thumbnails_missing);
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset 'load pending' state */
|
/* Reset 'load pending' state */
|
||||||
rgui->thumbnail_load_pending = false;
|
rgui->thumbnail_load_pending = false;
|
||||||
|
|
||||||
|
@ -6422,6 +6538,117 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, bool download_missing)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rgui_update_savestate_thumbnail_path(void *data, unsigned i)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
rgui_t *rgui = (rgui_t*)data;
|
||||||
|
int state_slot = settings->ints.state_slot;
|
||||||
|
bool savestate_thumbnail_enable
|
||||||
|
= settings->bools.savestate_thumbnail_enable;
|
||||||
|
if (!rgui)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Cache previous savestate thumbnail path */
|
||||||
|
strlcpy(
|
||||||
|
rgui->prev_savestate_thumbnail_file_path,
|
||||||
|
rgui->savestate_thumbnail_file_path,
|
||||||
|
sizeof(rgui->prev_savestate_thumbnail_file_path));
|
||||||
|
|
||||||
|
rgui->savestate_thumbnail_file_path[0] = '\0';
|
||||||
|
|
||||||
|
/* Savestate thumbnails are only relevant
|
||||||
|
* when viewing the running quick menu or state slots */
|
||||||
|
if (!((rgui->is_quick_menu && rgui_is_running_quick_menu()) || rgui->is_state_slot))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (savestate_thumbnail_enable)
|
||||||
|
{
|
||||||
|
menu_entry_t entry;
|
||||||
|
|
||||||
|
MENU_ENTRY_INIT(entry);
|
||||||
|
entry.path_enabled = false;
|
||||||
|
entry.rich_label_enabled = false;
|
||||||
|
entry.value_enabled = false;
|
||||||
|
entry.sublabel_enabled = false;
|
||||||
|
menu_entry_get(&entry, 0, i, NULL, true);
|
||||||
|
|
||||||
|
if (!string_is_empty(entry.label))
|
||||||
|
{
|
||||||
|
if (string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT ||
|
||||||
|
string_is_equal(entry.label, "state_slot") ||
|
||||||
|
string_is_equal(entry.label, "loadstate") ||
|
||||||
|
string_is_equal(entry.label, "savestate"))
|
||||||
|
{
|
||||||
|
char path[8204];
|
||||||
|
runloop_state_t *runloop_st = runloop_state_get_ptr();
|
||||||
|
|
||||||
|
path[0] = '\0';
|
||||||
|
|
||||||
|
/* State slot dropdown */
|
||||||
|
if (string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT)
|
||||||
|
{
|
||||||
|
state_slot = i - 1;
|
||||||
|
rgui->is_state_slot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_slot > 0)
|
||||||
|
snprintf(path, sizeof(path), "%s%d",
|
||||||
|
runloop_st->name.savestate, state_slot);
|
||||||
|
else if (state_slot < 0)
|
||||||
|
fill_pathname_join_delim(path,
|
||||||
|
runloop_st->name.savestate, "auto", '.', sizeof(path));
|
||||||
|
else
|
||||||
|
strlcpy(path, runloop_st->name.savestate, sizeof(path));
|
||||||
|
|
||||||
|
strlcat(path, FILE_PATH_PNG_EXTENSION, sizeof(path));
|
||||||
|
|
||||||
|
if (path_is_valid(path))
|
||||||
|
{
|
||||||
|
strlcpy(
|
||||||
|
rgui->savestate_thumbnail_file_path, path,
|
||||||
|
sizeof(rgui->savestate_thumbnail_file_path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rgui_reset_savestate_thumbnail(void *data)
|
||||||
|
{
|
||||||
|
rgui_t *rgui = (rgui_t*)data;
|
||||||
|
|
||||||
|
rgui->mini_left_thumbnail.width = 0;
|
||||||
|
rgui->mini_left_thumbnail.height = 0;
|
||||||
|
rgui->mini_left_thumbnail.is_valid = false;
|
||||||
|
rgui->mini_left_thumbnail.path[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rgui_update_savestate_thumbnail_image(void *data)
|
||||||
|
{
|
||||||
|
rgui_t *rgui = (rgui_t*)data;
|
||||||
|
if (!rgui)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Savestate thumbnails are only relevant
|
||||||
|
* when viewing the running quick menu or state slots */
|
||||||
|
if (!((rgui->is_quick_menu && rgui_is_running_quick_menu()) || rgui->is_state_slot))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If path is empty, just reset thumbnail */
|
||||||
|
if (string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
|
rgui_reset_savestate_thumbnail(rgui);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool thumbnails_missing = false;
|
||||||
|
rgui->entry_has_left_thumbnail = rgui_request_thumbnail(
|
||||||
|
&rgui->mini_left_thumbnail,
|
||||||
|
GFX_THUMBNAIL_LEFT,
|
||||||
|
&rgui->left_thumbnail_queue_size,
|
||||||
|
rgui->savestate_thumbnail_file_path,
|
||||||
|
&thumbnails_missing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
||||||
{
|
{
|
||||||
bool has_thumbnail = false;
|
bool has_thumbnail = false;
|
||||||
|
@ -6435,7 +6662,7 @@ static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
||||||
|
|
||||||
/* Update thumbnail content/path */
|
/* Update thumbnail content/path */
|
||||||
if ((rgui->show_fs_thumbnail || menu_rgui_inline_thumbnails)
|
if ((rgui->show_fs_thumbnail || menu_rgui_inline_thumbnails)
|
||||||
&& rgui->is_playlist)
|
&& (rgui->is_playlist || rgui->is_quick_menu))
|
||||||
{
|
{
|
||||||
size_t selection = menu_navigation_get_selection();
|
size_t selection = menu_navigation_get_selection();
|
||||||
size_t list_size = menu_entries_get_size();
|
size_t list_size = menu_entries_get_size();
|
||||||
|
@ -6443,14 +6670,24 @@ static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
||||||
bool playlist_valid = false;
|
bool playlist_valid = false;
|
||||||
size_t playlist_index = selection;
|
size_t playlist_index = selection;
|
||||||
|
|
||||||
/* Get playlist index corresponding
|
if (rgui->is_playlist)
|
||||||
* to the selected entry */
|
{
|
||||||
if (list &&
|
/* Get playlist index corresponding
|
||||||
(selection < list_size) &&
|
* to the selected entry */
|
||||||
(list->list[selection].type == FILE_TYPE_RPL_ENTRY))
|
if (list &&
|
||||||
|
(selection < list_size) &&
|
||||||
|
(list->list[selection].type == FILE_TYPE_RPL_ENTRY))
|
||||||
|
{
|
||||||
|
playlist_valid = true;
|
||||||
|
playlist_index = list->list[selection].entry_idx;
|
||||||
|
rgui->playlist_index = playlist_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rgui->is_quick_menu &&
|
||||||
|
string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
{
|
{
|
||||||
playlist_valid = true;
|
playlist_valid = true;
|
||||||
playlist_index = list->list[selection].entry_idx;
|
playlist_index = rgui->playlist_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfx_thumbnail_set_content_playlist(rgui->thumbnail_path_data,
|
if (gfx_thumbnail_set_content_playlist(rgui->thumbnail_path_data,
|
||||||
|
@ -6466,6 +6703,19 @@ static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Save state thumbnails */
|
||||||
|
if (rgui->is_quick_menu || rgui->is_state_slot)
|
||||||
|
{
|
||||||
|
size_t selection = menu_navigation_get_selection();
|
||||||
|
size_t list_size = menu_entries_get_size();
|
||||||
|
|
||||||
|
if (selection < list_size)
|
||||||
|
{
|
||||||
|
rgui_update_savestate_thumbnail_path(rgui, selection);
|
||||||
|
rgui_update_savestate_thumbnail_image(rgui);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check whether thumbnails should be loaded */
|
/* Check whether thumbnails should be loaded */
|
||||||
if (has_thumbnail)
|
if (has_thumbnail)
|
||||||
{
|
{
|
||||||
|
@ -6481,6 +6731,14 @@ static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui, bool force_load)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rgui_update_thumbnail_image(void *data)
|
||||||
|
{
|
||||||
|
rgui_t *rgui = (rgui_t*)data;
|
||||||
|
|
||||||
|
if (rgui->is_playlist)
|
||||||
|
rgui_scan_selected_entry_thumbnail(rgui, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void rgui_toggle_fs_thumbnail(rgui_t *rgui,
|
static void rgui_toggle_fs_thumbnail(rgui_t *rgui,
|
||||||
bool menu_rgui_inline_thumbnails)
|
bool menu_rgui_inline_thumbnails)
|
||||||
{
|
{
|
||||||
|
@ -6493,6 +6751,9 @@ static void rgui_toggle_fs_thumbnail(rgui_t *rgui,
|
||||||
* currently inactive right thumbnail. */
|
* currently inactive right thumbnail. */
|
||||||
if (menu_rgui_inline_thumbnails)
|
if (menu_rgui_inline_thumbnails)
|
||||||
{
|
{
|
||||||
|
if (!string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
|
rgui_reset_savestate_thumbnail(rgui);
|
||||||
|
|
||||||
if (rgui->show_fs_thumbnail)
|
if (rgui->show_fs_thumbnail)
|
||||||
{
|
{
|
||||||
rgui->mini_thumbnail.width = 0;
|
rgui->mini_thumbnail.width = 0;
|
||||||
|
@ -6693,6 +6954,12 @@ static void rgui_populate_entries(void *data,
|
||||||
rgui->is_playlist = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST))
|
rgui->is_playlist = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY))
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY))
|
||||||
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST));
|
|| string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST));
|
||||||
|
|
||||||
|
/* Determine whether this is the quick menu */
|
||||||
|
rgui->is_quick_menu = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS)) ||
|
||||||
|
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_CONTENT_SETTINGS)) ||
|
||||||
|
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVESTATE_LIST));
|
||||||
|
rgui->is_state_slot = string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT;
|
||||||
|
|
||||||
/* Set menu title */
|
/* Set menu title */
|
||||||
menu_entries_get_title(rgui->menu_title, sizeof(rgui->menu_title));
|
menu_entries_get_title(rgui->menu_title, sizeof(rgui->menu_title));
|
||||||
|
@ -7116,6 +7383,18 @@ static void rgui_toggle(void *userdata, bool menu_on)
|
||||||
if (!rgui || !settings)
|
if (!rgui || !settings)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Have to reset this, otherwise savestate
|
||||||
|
* thumbnail won't update after selecting
|
||||||
|
* 'save state' option */
|
||||||
|
if (rgui->is_quick_menu)
|
||||||
|
{
|
||||||
|
rgui_reset_savestate_thumbnail(rgui);
|
||||||
|
|
||||||
|
/* Prevent thumbnail flashing after toggling menu */
|
||||||
|
if (!menu_on)
|
||||||
|
rgui->mini_thumbnail_delay = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (menu_on)
|
if (menu_on)
|
||||||
{
|
{
|
||||||
if (aspect_ratio_lock != RGUI_ASPECT_RATIO_LOCK_NONE)
|
if (aspect_ratio_lock != RGUI_ASPECT_RATIO_LOCK_NONE)
|
||||||
|
@ -7188,6 +7467,24 @@ static void rgui_context_destroy(void *data)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rgui_thumbnail_cycle_dupe(rgui_t *rgui)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
if (settings->uints.gfx_thumbnails == settings->uints.menu_left_thumbnails)
|
||||||
|
{
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
(rgui->gfx_thumbnails_prev > 0)
|
||||||
|
? rgui->gfx_thumbnails_prev
|
||||||
|
: settings->uints.gfx_thumbnails + 1);
|
||||||
|
|
||||||
|
if (settings->uints.gfx_thumbnails > 3)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static enum menu_action rgui_parse_menu_entry_action(
|
static enum menu_action rgui_parse_menu_entry_action(
|
||||||
rgui_t *rgui, menu_entry_t *entry,
|
rgui_t *rgui, menu_entry_t *entry,
|
||||||
enum menu_action action)
|
enum menu_action action)
|
||||||
|
@ -7228,30 +7525,134 @@ static enum menu_action rgui_parse_menu_entry_action(
|
||||||
rgui->restore_aspect_lock = true;
|
rgui->restore_aspect_lock = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case MENU_ACTION_SCAN:
|
if (rgui->show_fs_thumbnail)
|
||||||
case MENU_ACTION_START:
|
|
||||||
/* If this is a playlist, both the 'scan'
|
|
||||||
* command and 'start' action are used to
|
|
||||||
* toggle the fullscreen thumbnail view
|
|
||||||
* > 'scan' is more ergonomic, which is a
|
|
||||||
* benefit for RGUI because its low
|
|
||||||
* resolution framebuffer means fullscreen
|
|
||||||
* thumbnails are likely to be viewed far
|
|
||||||
* more often than with other menu drivers
|
|
||||||
* > 'start' is the regular toggle button
|
|
||||||
* for all other menu drivers, and is
|
|
||||||
* included as a fallback here for users
|
|
||||||
* with gamepads with limited numbers of
|
|
||||||
* face buttons (e.g. a NES-style pad
|
|
||||||
* does not possess a RetroPad Y/'scan'
|
|
||||||
* button) */
|
|
||||||
if (rgui->is_playlist)
|
|
||||||
{
|
{
|
||||||
|
rgui_thumbnail_cycle_dupe(rgui);
|
||||||
|
rgui_toggle_fs_thumbnail(rgui, config_get_ptr()->bools.menu_rgui_inline_thumbnails);
|
||||||
|
|
||||||
|
if (!rgui->is_state_slot && !rgui->is_playlist)
|
||||||
|
new_action = MENU_ACTION_NOOP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_ACTION_CANCEL:
|
||||||
|
if (rgui->show_fs_thumbnail)
|
||||||
|
{
|
||||||
|
rgui_thumbnail_cycle_dupe(rgui);
|
||||||
rgui_toggle_fs_thumbnail(rgui, config_get_ptr()->bools.menu_rgui_inline_thumbnails);
|
rgui_toggle_fs_thumbnail(rgui, config_get_ptr()->bools.menu_rgui_inline_thumbnails);
|
||||||
new_action = MENU_ACTION_NOOP;
|
new_action = MENU_ACTION_NOOP;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MENU_ACTION_START:
|
||||||
|
/* Playlist thumbnail fullscreen toggle */
|
||||||
|
if (rgui->is_playlist || (rgui->is_quick_menu && !rgui_is_running_quick_menu()))
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail && rgui->gfx_thumbnails_prev < 0)
|
||||||
|
rgui->gfx_thumbnails_prev = settings->uints.gfx_thumbnails;
|
||||||
|
|
||||||
|
/* Show fullscreen image from the left slot if main slot is empty */
|
||||||
|
if (!rgui->mini_thumbnail.is_valid && rgui->mini_left_thumbnail.is_valid)
|
||||||
|
{
|
||||||
|
if (rgui->show_fs_thumbnail && rgui->gfx_thumbnails_prev > 0)
|
||||||
|
{
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
rgui->gfx_thumbnails_prev);
|
||||||
|
}
|
||||||
|
else if (!rgui->show_fs_thumbnail)
|
||||||
|
{
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
settings->uints.menu_left_thumbnails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid showing the same thumbnail after returning from fullscreen mode after cycling images */
|
||||||
|
if (rgui->show_fs_thumbnail)
|
||||||
|
rgui_thumbnail_cycle_dupe(rgui);
|
||||||
|
|
||||||
|
rgui_toggle_fs_thumbnail(rgui, config_get_ptr()->bools.menu_rgui_inline_thumbnails);
|
||||||
|
new_action = MENU_ACTION_NOOP;
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail)
|
||||||
|
rgui->gfx_thumbnails_prev = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_ACTION_SCAN:
|
||||||
|
/* Save state slot fullscreen toggle */
|
||||||
|
if ((rgui->is_state_slot || rgui->is_quick_menu) &&
|
||||||
|
!string_is_empty(rgui->savestate_thumbnail_file_path))
|
||||||
|
{
|
||||||
|
rgui_toggle_fs_thumbnail(rgui, true);
|
||||||
|
new_action = MENU_ACTION_NOOP;
|
||||||
|
}
|
||||||
|
/* Playlist thumbnail cycle */
|
||||||
|
else if (rgui->is_playlist)
|
||||||
|
{
|
||||||
|
settings_t *settings = config_get_ptr();
|
||||||
|
|
||||||
|
if (settings->uints.gfx_thumbnails == 0)
|
||||||
|
{
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.menu_left_thumbnails,
|
||||||
|
settings->uints.menu_left_thumbnails + 1);
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail &&
|
||||||
|
settings->uints.gfx_thumbnails == settings->uints.menu_left_thumbnails)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.menu_left_thumbnails,
|
||||||
|
settings->uints.menu_left_thumbnails + 1);
|
||||||
|
|
||||||
|
if (settings->uints.menu_left_thumbnails > 3)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.menu_left_thumbnails, 1);
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail &&
|
||||||
|
settings->uints.gfx_thumbnails == settings->uints.menu_left_thumbnails)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.menu_left_thumbnails,
|
||||||
|
settings->uints.menu_left_thumbnails + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
settings->uints.gfx_thumbnails + 1);
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail &&
|
||||||
|
settings->uints.gfx_thumbnails == settings->uints.menu_left_thumbnails)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
settings->uints.gfx_thumbnails + 1);
|
||||||
|
|
||||||
|
if (settings->uints.gfx_thumbnails > 3)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails, 1);
|
||||||
|
|
||||||
|
if (!rgui->show_fs_thumbnail &&
|
||||||
|
settings->uints.gfx_thumbnails == settings->uints.menu_left_thumbnails)
|
||||||
|
configuration_set_uint(settings,
|
||||||
|
settings->uints.gfx_thumbnails,
|
||||||
|
settings->uints.gfx_thumbnails + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rgui_refresh_thumbnail_image(rgui, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_ACTION_UP:
|
||||||
|
case MENU_ACTION_DOWN:
|
||||||
|
case MENU_ACTION_SCROLL_UP:
|
||||||
|
case MENU_ACTION_SCROLL_DOWN:
|
||||||
|
if (rgui->show_fs_thumbnail && rgui->is_quick_menu)
|
||||||
|
new_action = MENU_ACTION_NOOP;
|
||||||
|
break;
|
||||||
|
case MENU_ACTION_LEFT:
|
||||||
|
case MENU_ACTION_RIGHT:
|
||||||
|
if (rgui->show_fs_thumbnail && (rgui->is_quick_menu && !rgui_is_running_quick_menu()))
|
||||||
|
new_action = MENU_ACTION_NOOP;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* In all other cases, pass through input
|
/* In all other cases, pass through input
|
||||||
* menu action without intervention */
|
* menu action without intervention */
|
||||||
|
@ -7310,14 +7711,14 @@ menu_ctx_driver_t menu_ctx_rgui = {
|
||||||
"rgui",
|
"rgui",
|
||||||
rgui_environ,
|
rgui_environ,
|
||||||
NULL, /* update_thumbnail_path */
|
NULL, /* update_thumbnail_path */
|
||||||
NULL, /* update_thumbnail_image */
|
rgui_update_thumbnail_image,
|
||||||
rgui_refresh_thumbnail_image,
|
rgui_refresh_thumbnail_image,
|
||||||
rgui_set_thumbnail_system,
|
rgui_set_thumbnail_system,
|
||||||
rgui_get_thumbnail_system,
|
rgui_get_thumbnail_system,
|
||||||
NULL, /* set_thumbnail_content */
|
NULL, /* set_thumbnail_content */
|
||||||
rgui_osk_ptr_at_pos,
|
rgui_osk_ptr_at_pos,
|
||||||
NULL, /* update_savestate_thumbnail_path */
|
rgui_update_savestate_thumbnail_path,
|
||||||
NULL, /* update_savestate_thumbnail_image */
|
rgui_update_savestate_thumbnail_image,
|
||||||
NULL, /* pointer_down */
|
NULL, /* pointer_down */
|
||||||
rgui_pointer_up,
|
rgui_pointer_up,
|
||||||
rgui_menu_entry_action
|
rgui_menu_entry_action
|
||||||
|
|
Loading…
Reference in New Issue