From 4e5e6c383366bdc4ce82425c17606792daa12439 Mon Sep 17 00:00:00 2001 From: sonninnos Date: Tue, 18 Feb 2025 09:22:09 +0200 Subject: [PATCH] GLUI: Add save state thumbnails --- gfx/gfx_thumbnail.c | 12 +- menu/cbs/menu_cbs_cancel.c | 10 - menu/cbs/menu_cbs_left.c | 21 +- menu/cbs/menu_cbs_ok.c | 9 - menu/cbs/menu_cbs_right.c | 18 +- menu/cbs/menu_cbs_start.c | 3 +- menu/drivers/materialui.c | 1020 +++++++++++++++++++++++++++++++----- menu/drivers/ozone.c | 487 ++++++++--------- menu/drivers/rgui.c | 173 +++--- menu/drivers/xmb.c | 699 +++++++++++++----------- menu/menu_driver.c | 33 +- menu/menu_setting.c | 22 - 12 files changed, 1659 insertions(+), 848 deletions(-) diff --git a/gfx/gfx_thumbnail.c b/gfx/gfx_thumbnail.c index 46a1f2451e2f..7cfc3798f7a2 100644 --- a/gfx/gfx_thumbnail.c +++ b/gfx/gfx_thumbnail.c @@ -35,7 +35,7 @@ #include "../tasks/tasks_internal.h" -#define DEFAULT_GFX_THUMBNAIL_STREAM_DELAY 83.333333f +#define DEFAULT_GFX_THUMBNAIL_STREAM_DELAY 16.66667f * 3 #define DEFAULT_GFX_THUMBNAIL_FADE_DURATION 166.66667f /* Utility structure, sent as userdata when pushing @@ -886,6 +886,16 @@ void gfx_thumbnail_get_draw_dimensions( *draw_width = *draw_width / (thumbnail_aspect / core_aspect); } + /* Final overwidth check */ + if (*draw_width > width) + { + *draw_width = (float)width; + *draw_height = (float)thumbnail->height * (*draw_width / (float)thumbnail->width); + + if (thumbnail->flags & GFX_THUMB_FLAG_CORE_ASPECT) + *draw_height = *draw_height * (thumbnail_aspect / core_aspect); + } + /* Account for scale factor * > Side note: We cannot use the gfx_display_ctx_draw_t * 'scale_factor' parameter for scaling thumbnails, diff --git a/menu/cbs/menu_cbs_cancel.c b/menu/cbs/menu_cbs_cancel.c index a0a316d4ec82..5acaf555b10b 100644 --- a/menu/cbs/menu_cbs_cancel.c +++ b/menu/cbs/menu_cbs_cancel.c @@ -83,16 +83,6 @@ int action_cancel_pop_default(const char *path, new_selection_ptr = menu_st->selection_ptr; menu_entries_pop_stack(&new_selection_ptr, 0, 1); menu_st->selection_ptr = new_selection_ptr; - - if (menu_st->driver_ctx) - { - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); - } - return 0; } diff --git a/menu/cbs/menu_cbs_left.c b/menu/cbs/menu_cbs_left.c index 2d6b8879330c..665d43016aa9 100644 --- a/menu/cbs/menu_cbs_left.c +++ b/menu/cbs/menu_cbs_left.c @@ -951,8 +951,8 @@ static int action_left_video_gpu_index(unsigned type, const char *label, static int action_left_state_slot(unsigned type, const char *label, bool wraparound) { - struct menu_state *menu_st = menu_state_get_ptr(); - settings_t *settings = config_get_ptr(); + struct menu_state *menu_st = menu_state_get_ptr(); + settings_t *settings = config_get_ptr(); settings->ints.state_slot--; if (settings->ints.state_slot < -1) @@ -960,16 +960,16 @@ static int action_left_state_slot(unsigned type, const char *label, if (menu_st->driver_ctx) { - size_t selection = menu_st->selection_ptr; if (menu_st->driver_ctx->update_savestate_thumbnail_path) menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); + menu_st->userdata, (unsigned)menu_st->selection_ptr); if (menu_st->driver_ctx->update_savestate_thumbnail_image) menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); } return 0; } + static int action_left_replay_slot(unsigned type, const char *label, bool wraparound) { @@ -980,16 +980,6 @@ static int action_left_replay_slot(unsigned type, const char *label, if (settings->ints.replay_slot < -1) settings->ints.replay_slot = 999; - if (menu_st->driver_ctx) - { - size_t selection = menu_st->selection_ptr; - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); - } - return 0; } @@ -1103,6 +1093,9 @@ static int menu_cbs_init_bind_left_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME: BIND_ACTION_LEFT(cbs, manual_content_scan_core_name_left); break; + case MENU_ENUM_LABEL_STATE_SLOT: + BIND_ACTION_LEFT(cbs, action_left_state_slot); + break; #ifdef HAVE_LAKKA case MENU_ENUM_LABEL_CPU_PERF_MODE: BIND_ACTION_LEFT(cbs, cpu_policy_mode_change); diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 50ddf3ad4cbf..44e337df959c 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -4687,15 +4687,6 @@ static int action_ok_cheat_delete(const char *path, menu_entries_pop_stack(&new_selection_ptr, 0, 1); menu_st->selection_ptr = new_selection_ptr; - if (menu_st->driver_ctx) - { - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); - } - return 0; } #endif diff --git a/menu/cbs/menu_cbs_right.c b/menu/cbs/menu_cbs_right.c index 7a6c0f913aef..a5033e3c4c1c 100644 --- a/menu/cbs/menu_cbs_right.c +++ b/menu/cbs/menu_cbs_right.c @@ -951,8 +951,8 @@ static int disk_options_disk_idx_right(unsigned type, const char *label, static int action_right_state_slot(unsigned type, const char *label, bool wraparound) { - settings_t *settings = config_get_ptr(); struct menu_state *menu_st = menu_state_get_ptr(); + settings_t *settings = config_get_ptr(); settings->ints.state_slot++; if (settings->ints.state_slot > 999) @@ -960,10 +960,9 @@ static int action_right_state_slot(unsigned type, const char *label, if (menu_st->driver_ctx) { - size_t selection = menu_st->selection_ptr; if (menu_st->driver_ctx->update_savestate_thumbnail_path) menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); + menu_st->userdata, (unsigned)menu_st->selection_ptr); if (menu_st->driver_ctx->update_savestate_thumbnail_image) menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); } @@ -975,22 +974,12 @@ static int action_right_replay_slot(unsigned type, const char *label, bool wraparound) { struct menu_state *menu_st = menu_state_get_ptr(); - size_t selection = menu_st->selection_ptr; settings_t *settings = config_get_ptr(); settings->ints.replay_slot++; if (settings->ints.replay_slot > 999) settings->ints.replay_slot = -1; - if (menu_st->driver_ctx) - { - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); - } - return 0; } @@ -1242,6 +1231,9 @@ static int menu_cbs_init_bind_right_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME: BIND_ACTION_RIGHT(cbs, manual_content_scan_core_name_right); break; + case MENU_ENUM_LABEL_STATE_SLOT: + BIND_ACTION_RIGHT(cbs, action_right_state_slot); + break; #ifdef HAVE_LAKKA case MENU_ENUM_LABEL_CPU_PERF_MODE: BIND_ACTION_RIGHT(cbs, cpu_policy_mode_change); diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index 248781f1b8ba..cf6126514db3 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -485,7 +485,6 @@ static int action_start_state_slot( unsigned type, size_t idx, size_t entry_idx) { struct menu_state *menu_st = menu_state_get_ptr(); - size_t selection = menu_st->selection_ptr; settings_t *settings = config_get_ptr(); settings->ints.state_slot = 0; @@ -494,7 +493,7 @@ static int action_start_state_slot( { if (menu_st->driver_ctx->update_savestate_thumbnail_path) menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); + menu_st->userdata, (unsigned)menu_st->selection_ptr); if (menu_st->driver_ctx->update_savestate_thumbnail_image) menu_st->driver_ctx->update_savestate_thumbnail_image(menu_st->userdata); } diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index e94184468e13..a17992b62369 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -126,7 +126,7 @@ /* Thumbnail stream delay when performing standard * menu navigation */ -#define MUI_THUMBNAIL_STREAM_DELAY_DEFAULT 83.333333f +#define MUI_THUMBNAIL_STREAM_DELAY_DEFAULT 16.66667f * 3 /* Thumbnail stream delay when performing 'fast' * navigation by dragging the scrollbar * > Must increase stream delay, otherwise it's @@ -165,6 +165,7 @@ extern int action_switch_thumbnail(const char *path, const char *label, unsigned enum materialui_list_view_type { MUI_LIST_VIEW_DEFAULT = 0, + MUI_LIST_VIEW_SAVESTATE, MUI_LIST_VIEW_PLAYLIST, MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_SMALL, MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_MEDIUM, @@ -555,25 +556,26 @@ enum materialui_handle_flags MUI_FLAG_IS_FILE_LIST = (1 << 7), MUI_FLAG_IS_DROPDOWN_LIST = (1 << 8), MUI_FLAG_IS_CORE_UPDATER_LIST = (1 << 9), - MUI_FLAG_LAST_SHOW_NAVBAR = (1 << 10), - MUI_FLAG_LAST_AUTO_ROTATE_NAVBAR = (1 << 11), - MUI_FLAG_MENU_STACK_FLUSHED = (1 << 12), + MUI_FLAG_IS_SAVESTATE_LIST = (1 << 10), + MUI_FLAG_LAST_SHOW_NAVBAR = (1 << 11), + MUI_FLAG_LAST_AUTO_ROTATE_NAVBAR = (1 << 12), + MUI_FLAG_MENU_STACK_FLUSHED = (1 << 13), /* Used to track scroll animations */ - MUI_FLAG_SCROLL_ANIMATION_ACTIVE = (1 << 13), - MUI_FLAG_USE_SMOOTH_TICKER = (1 << 14), - MUI_FLAG_TOUCH_FEEDBACK_UPDATE_SELECTION = (1 << 15), - MUI_FLAG_PRIMARY_THUMBNAIL_AVAILABLE = (1 << 16), - MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED = (1 << 17), - MUI_FLAG_PRIMARY_THUMBNAIL_BLOCKED = (1 << 18), - MUI_FLAG_SECONDARY_THUMBNAIL_BLOCKED = (1 << 19), - MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS = (1 << 20), - MUI_FLAG_SHOW_SELECTION_MARKER_SHADOW = (1 << 21), - MUI_FLAG_STATUSBAR_ENABLED = (1 << 22), - MUI_FLAG_STATUSBAR_CACHED = (1 << 23), - MUI_FLAG_SCROLLBAR_ACTIVE = (1 << 24), - MUI_FLAG_SCROLLBAR_DRAGGED = (1 << 25), - MUI_FLAG_NAVBAR_MENU_NAVIGATION_WRAPPED = (1 << 26), - MUI_FLAG_COL_DIVIDER_IS_LIST_BG = (1 << 27) + MUI_FLAG_SCROLL_ANIMATION_ACTIVE = (1 << 14), + MUI_FLAG_USE_SMOOTH_TICKER = (1 << 15), + MUI_FLAG_TOUCH_FEEDBACK_UPDATE_SELECTION = (1 << 16), + MUI_FLAG_PRIMARY_THUMBNAIL_AVAILABLE = (1 << 17), + MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED = (1 << 18), + MUI_FLAG_PRIMARY_THUMBNAIL_BLOCKED = (1 << 19), + MUI_FLAG_SECONDARY_THUMBNAIL_BLOCKED = (1 << 20), + MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS = (1 << 21), + MUI_FLAG_SHOW_SELECTION_MARKER_SHADOW = (1 << 22), + MUI_FLAG_STATUSBAR_ENABLED = (1 << 23), + MUI_FLAG_STATUSBAR_CACHED = (1 << 24), + MUI_FLAG_SCROLLBAR_ACTIVE = (1 << 25), + MUI_FLAG_SCROLLBAR_DRAGGED = (1 << 26), + MUI_FLAG_NAVBAR_MENU_NAVIGATION_WRAPPED = (1 << 27), + MUI_FLAG_COL_DIVIDER_IS_LIST_BG = (1 << 28) }; typedef struct materialui_handle @@ -599,6 +601,11 @@ typedef struct materialui_handle font_data_impl_t hint; /* ptr alignment */ } font_data; + struct + { + gfx_thumbnail_t savestate; /* uintptr_t alignment */ + } thumbnails; + size_t (*word_wrap)( char *s, size_t len, const char *src, size_t src_len, @@ -695,6 +702,11 @@ typedef struct materialui_handle last_landscape_layout_optimization; enum materialui_list_view_type list_view_type; + /* These have to be huge, because runloop_st->name.savestate + * has a hard-coded size of (PATH_MAX_LENGTH * 2)... */ + char savestate_thumbnail_file_path[(PATH_MAX_LENGTH * 2)]; + char prev_savestate_thumbnail_file_path[(PATH_MAX_LENGTH * 2)]; + char msgbox[1024]; char menu_title[NAME_MAX_LENGTH]; char fullscreen_thumbnail_label[NAME_MAX_LENGTH]; @@ -758,6 +770,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.1f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; + static const materialui_theme_t materialui_theme_cutie_cyan = { /* Text (& small inline icon) colours */ 0xC4C4C4, /* on_sys_bar */ @@ -804,6 +817,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.1f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; + static const materialui_theme_t materialui_theme_blue = { /* Text (& small inline icon) colours */ 0xDEDEDE, /* on_sys_bar */ @@ -988,7 +1002,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.3f, /* header_shadow_opacity */ 0.35f, /* landscape_border_shadow_opacity */ 0.45f, /* status_bar_shadow_opacity */ - 0.15f, /* selection_marker_shadow_opacity */ + 0.15f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; @@ -1082,7 +1096,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.3f, /* header_shadow_opacity */ 0.35f, /* landscape_border_shadow_opacity */ 0.45f, /* status_bar_shadow_opacity */ - 0.15f, /* selection_marker_shadow_opacity */ + 0.15f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; @@ -1317,7 +1331,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.4f, /* header_shadow_opacity */ 0.45f, /* landscape_border_shadow_opacity */ 0.8f, /* status_bar_shadow_opacity */ - 0.35f, /* selection_marker_shadow_opacity */ + 0.35f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; @@ -1364,7 +1378,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.4f, /* header_shadow_opacity */ 0.45f, /* landscape_border_shadow_opacity */ 0.8f, /* status_bar_shadow_opacity */ - 0.35f, /* selection_marker_shadow_opacity */ + 0.35f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; @@ -1411,7 +1425,7 @@ static const materialui_theme_t *materialui_get_theme(enum materialui_color_them 0.4f, /* header_shadow_opacity */ 0.45f, /* landscape_border_shadow_opacity */ 0.8f, /* status_bar_shadow_opacity */ - 0.35f, /* selection_marker_shadow_opacity */ + 0.35f, /* selection_marker_shadow_opacity */ 0.75f /* screen_fade_opacity */ }; @@ -2386,6 +2400,134 @@ static uintptr_t materialui_get_playlist_icon( * Playlist icons END * ============================== */ +static void materialui_update_fullscreen_thumbnail_label( + materialui_handle_t *mui) +{ + struct menu_state *menu_st = menu_state_get_ptr(); + size_t selection = menu_st->selection_ptr; + const char *thumbnail_label = NULL; + menu_entry_t selected_entry; + + /* Cache selected entry label + * (used as menu title when fullscreen thumbnails + * are shown) */ + mui->fullscreen_thumbnail_label[0] = '\0'; + + /* > Get menu entry */ + MENU_ENTRY_INITIALIZE(selected_entry); + selected_entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; + menu_entry_get(&selected_entry, 0, selection, NULL, true); + + menu_update_fullscreen_thumbnail_label( + mui->fullscreen_thumbnail_label, + sizeof(mui->fullscreen_thumbnail_label), + (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) ? false : true, + NULL); +} + +static void materialui_update_savestate_thumbnail_path(void *data, unsigned i) +{ + settings_t *settings = config_get_ptr(); + materialui_handle_t *mui = (materialui_handle_t*)data; + int state_slot = settings->ints.state_slot; + bool savestate_thumbnail = settings->bools.savestate_thumbnail_enable; + + if (!mui) + return; + + /* Cache previous savestate thumbnail path */ + strlcpy( + mui->prev_savestate_thumbnail_file_path, + mui->savestate_thumbnail_file_path, + sizeof(mui->prev_savestate_thumbnail_file_path)); + + mui->savestate_thumbnail_file_path[0] = '\0'; + + if (savestate_thumbnail) + { + menu_entry_t entry; + + MENU_ENTRY_INITIALIZE(entry); + entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; + 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, msg_hash_to_str(MENU_ENUM_LABEL_STATE_SLOT)) + || string_is_equal(entry.label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_STATE)) + || string_is_equal(entry.label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_STATE))) + { + size_t _len; + char path[PATH_MAX_LENGTH * 2]; + runloop_state_t *runloop_st = runloop_state_get_ptr(); + + /* State slot dropdown */ + if (string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT) + state_slot = i - 1; + + if (state_slot < 0) + { + path[0] = '\0'; + _len = fill_pathname_join_delim(path, + runloop_st->name.savestate, "auto", '.', sizeof(path)); + } + else + { + _len = strlcpy(path, runloop_st->name.savestate, sizeof(path)); + if (state_slot > 0) + _len += snprintf(path + _len, sizeof(path) - _len, "%d", state_slot); + } + + strlcpy(path + _len, FILE_PATH_PNG_EXTENSION, sizeof(path) - _len); + + /* Must let invalid be empty here as opposed to other drivers + * in order to see the missing image placeholder in normal list */ + if (path_is_valid(path)) + strlcpy( + mui->savestate_thumbnail_file_path, path, + sizeof(mui->savestate_thumbnail_file_path)); + + materialui_update_fullscreen_thumbnail_label(mui); + } + } + } +} + +static void materialui_update_savestate_thumbnail_image(void *data) +{ + materialui_handle_t *mui = (materialui_handle_t*)data; + + if (!mui) + return; + + /* If path is empty, just reset thumbnail */ + if (string_is_empty(mui->savestate_thumbnail_file_path)) + { + gfx_thumbnail_reset(&mui->thumbnails.savestate); + /* Allow showing missing thumbnail placeholder */ + mui->thumbnails.savestate.status = GFX_THUMBNAIL_STATUS_MISSING; + mui->thumbnails.savestate.alpha = 1.0f; + } + else + { + /* Only request thumbnail if: + * > Thumbnail has never been loaded *OR* + * > Thumbnail path has changed */ + if ( (mui->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN) + || !string_is_equal(mui->savestate_thumbnail_file_path, + mui->prev_savestate_thumbnail_file_path)) + { + gfx_thumbnail_request_file( + mui->savestate_thumbnail_file_path, + &mui->thumbnails.savestate, + config_get_ptr()->uints.gfx_thumbnail_upscale_threshold); + } + } + + mui->thumbnails.savestate.flags |= GFX_THUMB_FLAG_CORE_ASPECT; +} + static void materialui_context_reset_textures(materialui_handle_t *mui) { int i; @@ -3073,6 +3215,67 @@ static void materialui_compute_entries_box_playlist_desktop( materialui_scrollbar_init(mui, width, height, header_height); } +/* Used for savestate layout entries + * > MUI_LIST_VIEW_SAVESTATE */ +static void materialui_compute_entries_box_savestate_list( + materialui_handle_t* mui, + unsigned width, unsigned height, unsigned header_height) +{ + size_t i; + struct menu_state *menu_st = menu_state_get_ptr(); + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *list = menu_list ? MENU_LIST_GET_SELECTION(menu_list, 0) : NULL; + size_t entries_end = list ? list->size : 0; + /* Entry width is available screen width minus + * thumbnail sidebar + * > Note: If landscape optimisations are enabled, + * need to allow space for a second divider at + * the left hand edge of the sidebar */ + float node_entry_width = (float)width - + (float)(mui->landscape_optimization.border_width * 2) - + (float)mui->nav_bar_layout_width - + (float)mui->thumbnail_width_max - + (float)(mui->margin * 2) - + (float)(mui->entry_divider_width * (mui->landscape_optimization.enabled ? 2 : 1)); + float node_x = (float)mui->landscape_optimization.border_width + + (float)(mui->entry_divider_width * (mui->landscape_optimization.enabled ? 2 : 1)); + int usable_width = node_entry_width - + (int)(mui->margin * 2) - + (int)(mui->landscape_optimization.entry_margin * 2); + float sum = 0; + + if (!list) + return; + + for (i = 0; i < entries_end; i++) + { + materialui_node_t *node = (materialui_node_t*)list->list[i].userdata; + uint8_t num_sublabel_lines = 0; + + if (!node) + continue; + + num_sublabel_lines = materialui_count_sublabel_lines( + mui, usable_width, i, true); + + node->text_height = mui->font_data.list.line_height + + (num_sublabel_lines * mui->font_data.hint.line_height); + node->entry_height = node->text_height + mui->dip_base_unit_size / 10; + + node->entry_height += mui->dip_base_unit_size / 10; + node->entry_width = node_entry_width; + + node->x = node_x; + node->y = sum; + sum += node->entry_height; + } + + mui->content_height = sum; + + /* Total height is now known - can initialise scrollbar */ + materialui_scrollbar_init(mui, width, height, header_height); +} + static void (*materialui_compute_entries_box)( materialui_handle_t* mui, unsigned width, unsigned height, unsigned header_height) = materialui_compute_entries_box_default; @@ -3538,6 +3741,21 @@ static bool materialui_render_process_entry_playlist_desktop( return true; } +/* Used for savestate-layout lists + * > MUI_LIST_VIEW_SAVESTATE + * Always returns true */ +static bool materialui_render_process_entry_savestate_list( + materialui_handle_t* mui, + struct menu_state *menu_st, materialui_node_t *node, + size_t entry_idx, size_t selection, + size_t playlist_idx, + bool first_entry_found, bool last_entry_found, + unsigned thumbnail_upscale_threshold, + bool network_on_demand_thumbnails) +{ + return true; +} + static bool (*materialui_render_process_entry)( materialui_handle_t* mui, struct menu_state *menu_st, materialui_node_t *node, @@ -4920,7 +5138,328 @@ static void materialui_render_menu_entry_playlist_desktop( { mui->ticker_smooth.font = mui->font_data.list.font; mui->ticker_smooth.selected = entry_selected; - mui->ticker_smooth.field_width = (unsigned)usable_width; + mui->ticker_smooth.field_width = (unsigned)usable_width; + mui->ticker_smooth.src_str = entry_label; + mui->ticker_smooth.dst_str = label_buf; + mui->ticker_smooth.dst_str_len = sizeof(label_buf); + + gfx_animation_ticker_smooth(&mui->ticker_smooth); + } + else + { + mui->ticker.selected = entry_selected; + mui->ticker.s = label_buf; + mui->ticker.len = (size_t)(usable_width / mui->font_data.list.glyph_width); + mui->ticker.str = entry_label; + + gfx_animation_ticker(&mui->ticker); + } + + /* Draw text */ + gfx_display_draw_text(mui->font_data.list.font, label_buf, + (int)mui->ticker_x_offset + entry_x + entry_margin, + label_y, + video_width, video_height, + (entry_selected || touch_feedback_active) ? + mui->colors.list_text_highlighted : mui->colors.list_text, + TEXT_ALIGN_LEFT, 1.0f, false, 0.0f, + draw_text_outside); + } + } + + /* Draw divider */ + if (draw_divider) + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + (float)entry_x, + (float)divider_y, + (unsigned)node->entry_width, + mui->entry_divider_width, + video_width, + video_height, + mui->colors.entry_divider, + NULL); +} + +/* Used for savestate layout entries + * > MUI_LIST_VIEW_SAVESTATE */ +static void materialui_render_menu_entry_savestate_list( + materialui_handle_t *mui, + void *userdata, + unsigned video_width, + unsigned video_height, + materialui_node_t *node, + menu_entry_t *entry, + bool entry_selected, + bool touch_feedback_active, + unsigned header_height, + int x_offset) +{ + math_matrix_4x4 mymat; + const char *entry_value = NULL; + const char *entry_label = NULL; + unsigned entry_type = 0; + size_t entry_value_width = 0; + enum msg_file_type entry_file_type + = FILE_TYPE_NONE; + enum materialui_entry_value_type entry_value_type + = MUI_ENTRY_VALUE_NONE; + gfx_display_t *p_disp = disp_get_ptr(); + int entry_x = x_offset + node->x; + int entry_y = header_height - mui->scroll_y + node->y; + int divider_y = entry_y + (int)node->entry_height; + int entry_margin = (int)mui->margin + (int)mui->landscape_optimization.entry_margin; + int usable_width = (int)node->entry_width - + (int)(mui->margin * 2) - (int)(mui->landscape_optimization.entry_margin * 2); + /* Entry label is drawn at the vertical centre + * of the current node */ + int label_y = entry_y + (node->entry_height / 2.0f) + + mui->font_data.list.line_centre_offset; + int value_icon_y = 0; + uintptr_t icon_texture = 0; + bool draw_text_outside = (x_offset != 0); + /* To prevent any ugly alignment issues, we + * only draw a divider if its bottom edge is + * more than two times the divider thickness from + * the bottom edge of the list region */ + bool draw_divider = (usable_width > 0) + && (!(mui->flags & MUI_FLAG_COL_DIVIDER_IS_LIST_BG)) + && ((divider_y + (mui->entry_divider_width * 2)) < + (video_height - mui->nav_bar_layout_height - mui->status_bar.height)); + + /* Read entry parameters */ + if (!string_is_empty(entry->rich_label)) + entry_label = entry->rich_label; + else + entry_label = entry->path; + + entry_value = entry->value; + entry_type = entry->type; + entry_file_type = msg_hash_to_file_type( + msg_hash_calculate(entry_value)); + entry_value_type = materialui_get_entry_value_type( + mui, entry_value, entry->flags & MENU_ENTRY_FLAG_CHECKED, + entry_type, entry_file_type, entry->setting_type); + + /* Draw entry icon + * > Has to be done first, since it affects the left + * hand margin size for label + sublabel text */ + switch (node->icon_type) + { + case MUI_ICON_TYPE_INTERNAL: + icon_texture = mui->textures.list[node->icon_texture_index]; + break; + default: + break; + } + + if (icon_texture) + { + materialui_draw_icon( + userdata, p_disp, + video_width, + video_height, + mui->icon_size, + (uintptr_t)icon_texture, + entry_x + (int)mui->landscape_optimization.entry_margin, + entry_y + (node->entry_height / 2.0f) - (mui->icon_size / 2.0f), + 0, + 1, + mui->colors.list_icon, + &mymat); + + entry_margin += mui->icon_size; + usable_width -= mui->icon_size; + } + + /* Draw entry sublabel + * > Must be done before label + value, since it + * affects y offset positions */ + if (materialui_show_sublabel_for_entry(entry)) + { + /* Note: Due to the way the selection highlight + * marker is drawn (height is effectively 1px larger + * than the entry height, to avoid visible seams), + * drawing the label+sublabel text at the exact centre + * of the entry gives the illusion of misalignment + * > Have to offset the label downwards by half a pixel + * (rounded up) */ + int vertical_margin = ((node->entry_height - node->text_height) / 2.0f) - (float)mui->sublabel_gap + 1.0f; + int sublabel_y; + char wrapped_sublabel[MENU_LABEL_MAX_LENGTH]; + + wrapped_sublabel[0] = '\0'; + + /* Label + sublabel 'block' is drawn at the + * vertical centre of the current node. + * > Value icon is drawn in line with the centre + * of the part of the label above the baseline + * (needs a little extra padding at the top, since + * the line ascender is usually somewhat taller + * than the visible text) */ + label_y = entry_y + vertical_margin + mui->font_data.list.line_ascender; + value_icon_y = label_y + (mui->dip_base_unit_size / 60.0f) - (mui->font_data.list.line_ascender / 2.0f) - (mui->icon_size / 2.0f); + sublabel_y = entry_y + vertical_margin + mui->font_data.list.line_height + (int)mui->sublabel_gap + mui->font_data.hint.line_ascender; + + /* Wrap sublabel string */ + (mui->word_wrap)(wrapped_sublabel, sizeof(wrapped_sublabel), + entry->sublabel, strlen(entry->sublabel), + (int)((usable_width - (int)mui->sublabel_padding) + / mui->font_data.hint.glyph_width), + mui->font_data.hint.wideglyph_width, 0); + + /* Draw sublabel string + * > Note: We must allow text to be drawn off-screen + * if the current y position is negative, otherwise topmost + * entries with very long sublabels may get 'clipped' too + * early as they are scrolled upwards beyond the top edge + * of the screen */ + gfx_display_draw_text(mui->font_data.hint.font, wrapped_sublabel, + entry_x + entry_margin, + sublabel_y, + video_width, video_height, + (entry_selected || touch_feedback_active) ? + mui->colors.list_hint_text_highlighted : mui->colors.list_hint_text, + TEXT_ALIGN_LEFT, 1.0f, false, 0.0f, + draw_text_outside || (sublabel_y < 0)); + } + else + { + /* If we don't have a sublabel, entry label is drawn + * at the vertical centre of the current node */ + label_y = entry_y + (node->entry_height / 2.0f) + mui->font_data.list.line_centre_offset; + value_icon_y = entry_y + (node->entry_height / 2.0f) - (mui->icon_size / 2.0f); + } + + /* Draw entry value */ + switch (entry_value_type) + { + case MUI_ENTRY_VALUE_TEXT: + { + int value_x_offset = 0; + uint32_t entry_value_color = 0; + unsigned entry_value_width_max = (usable_width / 2) - mui->margin; + char value_buf[NAME_MAX_LENGTH]; + + value_buf[0] = '\0'; + + /* Apply ticker */ + if (0 && mui->flags & MUI_FLAG_USE_SMOOTH_TICKER) + { + mui->ticker_smooth.field_width = entry_value_width_max; + mui->ticker_smooth.src_str = entry_value; + mui->ticker_smooth.dst_str = value_buf; + mui->ticker_smooth.dst_str_len = sizeof(value_buf); + + if (gfx_animation_ticker_smooth(&mui->ticker_smooth)) + { + /* If ticker is active, then value text is effectively + * entry_value_width_max pixels wide... */ + entry_value_width = entry_value_width_max; + /* ...and since value text is right aligned, have to + * offset x position by the 'padding' width at the + * end of the ticker string */ + value_x_offset = + (int)(mui->ticker_x_offset + mui->ticker_str_width) - + (int)entry_value_width_max; + } + /* If ticker is inactive, width of value string is + * exactly mui->ticker_str_width pixels, and no x offset + * is required */ + else + entry_value_width = mui->ticker_str_width; + } + else + { + size_t entry_value_len = utf8len(entry_value); + size_t entry_value_len_max = + (size_t)(entry_value_width_max / mui->font_data.list.glyph_width); + + /* Limit length of value string */ + if (entry_value_len_max > 0) + entry_value_len_max = entry_value_len_max - 1; + if (entry_value_len > entry_value_len_max) + entry_value_len = entry_value_len_max; + + mui->ticker.s = value_buf; + mui->ticker.len = entry_value_len; + mui->ticker.str = entry_value; + + gfx_animation_ticker(&mui->ticker); + + /* Get effective width of value string + * > Approximate value - only the smooth ticker + * returns the actual width in pixels, and any + * platform too slow to run the smooth ticker + * won't appreciate the overheads of using + * font_driver_get_message_width() here... */ + entry_value_width = (entry_value_len + 1) * mui->font_data.list.glyph_width; + } + + entry_value_color = (entry_selected || touch_feedback_active) + ? mui->colors.list_text_highlighted : mui->colors.list_text; + + /* Muted/disabled color for disabled values */ + if ( string_is_equal(value_buf, "null") + || string_is_equal(value_buf, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))) + entry_value_color = mui->colors.disabled_text; + + /* Draw value string */ + gfx_display_draw_text(mui->font_data.list.font, value_buf, + entry_x + value_x_offset + node->entry_width - (int)mui->margin - (int)mui->landscape_optimization.entry_margin, + label_y, + video_width, video_height, + entry_value_color, + TEXT_ALIGN_RIGHT, 1.0f, false, 0.0f, draw_text_outside); + } + break; + case MUI_ENTRY_VALUE_CHECKMARK: + { + /* Draw checkmark */ + if (mui->textures.list[MUI_TEXTURE_CHECKMARK]) + materialui_draw_icon( + userdata, p_disp, + video_width, + video_height, + mui->icon_size, + mui->textures.list[MUI_TEXTURE_CHECKMARK], + entry_x + node->entry_width - (int)mui->margin - (int)mui->landscape_optimization.entry_margin - (int)mui->icon_size, + value_icon_y, + 0, + 1, + mui->colors.list_switch_on, + &mymat); + + entry_value_width = mui->icon_size; + } + break; + default: + entry_value_width = 0; + break; + } + + /* Draw entry label */ + if (!string_is_empty(entry_label)) + { + int label_width = usable_width; + char label_buf[NAME_MAX_LENGTH]; + + label_buf[0] = '\0'; + + label_width = (entry_value_width > 0) ? + label_width - (int)(entry_value_width + mui->margin) : label_width; + + if (usable_width > 0) + { + /* Apply ticker */ + if (mui->flags & MUI_FLAG_USE_SMOOTH_TICKER) + { + mui->ticker_smooth.font = mui->font_data.list.font; + mui->ticker_smooth.selected = entry_selected; + mui->ticker_smooth.field_width = (unsigned)label_width; mui->ticker_smooth.src_str = entry_label; mui->ticker_smooth.dst_str = label_buf; mui->ticker_smooth.dst_str_len = sizeof(label_buf); @@ -5244,6 +5783,143 @@ static void materialui_render_selected_entry_aux_playlist_desktop( } } +static bool materialui_is_savestate_list(materialui_handle_t *mui) +{ + struct menu_state *menu_st = menu_state_get_ptr(); + menu_entry_t entry; + MENU_ENTRY_INITIALIZE(entry); + entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; + menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true); + + return + ( string_is_equal(entry.label, msg_hash_to_str(MENU_ENUM_LABEL_STATE_SLOT)) + || string_is_equal(entry.label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_STATE)) + || string_is_equal(entry.label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_STATE)) + ); +} + +static bool materialui_is_savestate_slot(materialui_handle_t *mui) +{ + struct menu_state *menu_st = menu_state_get_ptr(); + menu_entry_t entry; + MENU_ENTRY_INITIALIZE(entry); + entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED; + menu_entry_get(&entry, 0, menu_st->selection_ptr, NULL, true); + + return string_to_unsigned(entry.label) == MENU_ENUM_LABEL_STATE_SLOT; +} + +/* Used for savestate layout list displays. + * Draws thumbnails + metadata for currently + * selected item. + * > MUI_LIST_VIEW_SAVESTATE */ +static void materialui_render_selected_entry_aux_savestate_list( + materialui_handle_t *mui, void *userdata, + unsigned video_width, unsigned video_height, + unsigned header_height, int x_offset, + file_list_t *list, size_t selection) +{ + math_matrix_4x4 mymat; + materialui_node_t *node = (materialui_node_t*)list->list[selection].userdata; + float background_x = (float)(x_offset + (int)mui->landscape_optimization.border_width) + node->entry_width; + float background_y = (float)header_height; + /* Note: If landscape optimisations are enabled, + * need to allow space for a second divider at + * the left hand edge of the sidebar */ + int background_width = mui->thumbnail_width_max + (mui->margin * 2) + + (mui->entry_divider_width * (mui->landscape_optimization.enabled ? + 2 : 1)); + int background_height = (int)video_height - (int)header_height - + (int)mui->nav_bar_layout_height - (int)mui->status_bar.height; + float thumbnail_x = background_x + (float)mui->margin + + (mui->landscape_optimization.enabled ? mui->entry_divider_width : 0); + float thumbnail_y = background_y + (float)mui->margin + (background_height - mui->thumbnail_height_max) / 2; + gfx_display_t *p_disp = disp_get_ptr(); + settings_t *settings = config_get_ptr(); + + /* Sanity check */ + if ( (background_width <= 0) + || (background_height <= 0)) + return; + + if (!p_disp->dispctx->handles_transform) + { + float cosine = 1.0f; /* cos(rad) = cos(0) = 1.0f */ + float sine = 0.0f; /* sine(rad) = sine(0) = 0.0f */ + gfx_display_rotate_z(p_disp, &mymat, cosine, sine, userdata); + } + + /* Draw sidebar background + * > Surface */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + background_x, + background_y, + (unsigned)background_width, + (unsigned)background_height, + video_width, + video_height, + mui->colors.side_bar_background, + NULL); + + /* > Divider */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + background_x + (float)background_width - (float)mui->entry_divider_width, + background_y, + mui->entry_divider_width, + (unsigned)background_height, + video_width, + video_height, + mui->colors.entry_divider, + NULL); + + /* > Additional divider */ + if (mui->landscape_optimization.enabled) + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + background_x, + background_y, + mui->entry_divider_width, + (unsigned)background_height, + video_width, + video_height, + mui->colors.entry_divider, + NULL); + + /* Draw thumbnails */ + if (node) + { + gfx_thumbnail_t *thumbnail = &mui->thumbnails.savestate; + + if (!materialui_is_savestate_slot(mui) && !materialui_is_savestate_list(mui)) + return; + + /* Draw primary */ + materialui_draw_thumbnail( + mui, + thumbnail, + settings, + p_disp, + userdata, + video_width, + video_height, + thumbnail_x, + thumbnail_y, + 1.0f, + &mymat); + } +} + static void (*materialui_render_selected_entry_aux)( materialui_handle_t *mui, void *userdata, unsigned video_width, unsigned video_height, @@ -5275,10 +5951,12 @@ static void materialui_render_menu_list( && (!(mui->flags & MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS)) && (mui->touch_feedback_alpha >= 0.5f) && (mui->touch_feedback_selection == menu_input->ptr); - bool entry_value_enabled = (mui->list_view_type == MUI_LIST_VIEW_DEFAULT); + bool entry_value_enabled = + (mui->list_view_type == MUI_LIST_VIEW_DEFAULT) + || (mui->list_view_type == MUI_LIST_VIEW_SAVESTATE); bool entry_sublabel_enabled = - (mui->list_view_type != MUI_LIST_VIEW_PLAYLIST_THUMB_DUAL_ICON) && - (mui->list_view_type != MUI_LIST_VIEW_PLAYLIST_THUMB_DESKTOP); + (mui->list_view_type != MUI_LIST_VIEW_PLAYLIST_THUMB_DUAL_ICON) + && (mui->list_view_type != MUI_LIST_VIEW_PLAYLIST_THUMB_DESKTOP); if (!list) return; @@ -6420,39 +7098,10 @@ static bool materialui_get_selected_thumbnails( *primary_thumbnail = &node->thumbnails.primary; *secondary_thumbnail = &node->thumbnails.secondary; - return true; -} - -static void materialui_update_fullscreen_thumbnail_label( - materialui_handle_t *mui, struct menu_state *menu_st, - size_t selection) -{ - menu_entry_t selected_entry; - const char *thumbnail_label = NULL; - - /* Cache selected entry label - * (used as menu title when fullscreen thumbnails - * are shown) */ - mui->fullscreen_thumbnail_label[0] = '\0'; - - /* > Get menu entry */ - MENU_ENTRY_INITIALIZE(selected_entry); - selected_entry.flags |= MENU_ENTRY_FLAG_LABEL_ENABLED - | MENU_ENTRY_FLAG_RICH_LABEL_ENABLED; - menu_entry_get(&selected_entry, 0, selection, NULL, true); + if (mui->flags & MUI_FLAG_IS_SAVESTATE_LIST) + *primary_thumbnail = &mui->thumbnails.savestate; - /* > Get entry label */ - if (!string_is_empty(selected_entry.rich_label)) - thumbnail_label = selected_entry.rich_label; - else - thumbnail_label = selected_entry.path; - - /* > Sanity check */ - if (!string_is_empty(thumbnail_label)) - strlcpy( - mui->fullscreen_thumbnail_label, - thumbnail_label, - sizeof(mui->fullscreen_thumbnail_label)); + return true; } /* Disables the fullscreen thumbnail view, with @@ -6520,21 +7169,6 @@ static void materialui_show_fullscreen_thumbnails( mui, selection, &primary_thumbnail, &secondary_thumbnail)) return; - /* We can only enable fullscreen thumbnails if - * current selection has at least one valid thumbnail - * and all thumbnails for current selection are already - * loaded/available */ - if ( (primary_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE) - && ( (mui->flags & MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED) - && (secondary_thumbnail->status != GFX_THUMBNAIL_STATUS_MISSING) - && (secondary_thumbnail->status != GFX_THUMBNAIL_STATUS_AVAILABLE))) - return; - - if ( (primary_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING) - && ( !(mui->flags & MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED) - || (secondary_thumbnail->status != GFX_THUMBNAIL_STATUS_AVAILABLE))) - return; - /* Menu list must be stationary while fullscreen * thumbnails are shown * > Kill any existing scroll animation @@ -6542,7 +7176,7 @@ static void materialui_show_fullscreen_thumbnails( materialui_kill_scroll_animation(mui, menu_st); /* Update thumbnail label */ - materialui_update_fullscreen_thumbnail_label(mui, menu_st, selection); + materialui_update_fullscreen_thumbnail_label(mui); /* Configure fade in animation */ animation_entry.easing_enum = EASING_OUT_QUAD; @@ -6561,6 +7195,60 @@ static void materialui_show_fullscreen_thumbnails( mui->flags |= MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS; } +static void materialui_draw_no_thumbnail_available( + materialui_handle_t *mui, + gfx_display_t *p_disp, + void *userdata, + unsigned video_width, + unsigned video_height, + unsigned x_position, + unsigned y_position, + unsigned view_width, + unsigned view_height, + math_matrix_4x4 *mymat) +{ + gfx_display_ctx_driver_t *dispctx = p_disp->dispctx; + unsigned icon_size = (unsigned)mui->icon_size * 2.00f; + uint8_t a8 = 0xFF * mui->fullscreen_thumbnail_alpha; + + y_position += (icon_size / 5.0f); + + if (dispctx) + { + gfx_display_set_alpha( + mui->colors.missing_thumbnail_icon, mui->fullscreen_thumbnail_alpha); + + if (dispctx->draw) + materialui_draw_icon( + userdata, p_disp, + video_width, + video_height, + (unsigned)icon_size, + mui->textures.list[MUI_TEXTURE_IMAGE], + x_position + ((view_width - icon_size) / 2), + video_height - y_position - icon_size - ((view_height - icon_size) / 2), + 0.0f, + 1.0f, + mui->colors.missing_thumbnail_icon, + mymat); + } + + if (mui->fullscreen_thumbnail_alpha >= 0.5f) + gfx_display_draw_text( + mui->font_data.list.font, + msg_hash_to_str(MSG_NO_THUMBNAIL_AVAILABLE), + x_position + (view_width / 2), + video_height - y_position - ((view_height - icon_size * 1.50f) / 2), + video_width, + video_height, + mui->colors.list_text | (a8 << 0), + TEXT_ALIGN_CENTER, + 1.0f, + false, + 0.0f, + true); +} + static void materialui_render_fullscreen_thumbnails(materialui_handle_t *mui, gfx_display_t *p_disp, void *userdata, unsigned video_width, unsigned video_height, @@ -6618,33 +7306,6 @@ static void materialui_render_fullscreen_thumbnails(materialui_handle_t *mui, if (show_secondary_thumbnail) num_thumbnails++; - /* Darken the screen a bit when images are not found - * to indicate fullscreen mode is still active */ - if ( (num_thumbnails < 1) - && (primary_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING) - && (secondary_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)) - { - gfx_display_set_alpha( - mui->colors.screen_fade, - mui->colors.screen_fade_opacity * mui->fullscreen_thumbnail_alpha / 2); - - /* Darken background */ - gfx_display_draw_quad( - p_disp, - userdata, - video_width, - video_height, - 0, - header_height, - (unsigned)view_width, - (unsigned)view_height, - video_width, - video_height, - mui->colors.screen_fade, - NULL); - return; - } - /* Check screen orientation * > When using portrait layouts, primary is shown * at the top, secondary at the bottom @@ -6854,6 +7515,44 @@ static void materialui_render_fullscreen_thumbnails(materialui_handle_t *mui, 1.0f, NULL); } + + /* Show "No thumbnail available" */ + if ( !show_primary_thumbnail + && !show_secondary_thumbnail) + { + unsigned bg_w = video_width / 3.0f; + unsigned bg_h = video_height / 3.0f; + + gfx_display_set_alpha( + mui->colors.thumbnail_background, mui->fullscreen_thumbnail_alpha); + + /* Darken background */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + (video_width - bg_w) / 2.0f, + video_height - bg_h - (video_height - bg_h) / 2.0f, + bg_w, + bg_h, + video_width, + video_height, + mui->colors.thumbnail_background, + NULL); + + materialui_draw_no_thumbnail_available( + mui, + p_disp, + userdata, + video_width, + video_height, + (video_width - bg_w) / 2.0f, + video_height - bg_h - (video_height - bg_h) / 2.0f, + bg_w, + bg_h, + NULL); + } } return; @@ -7333,7 +8032,12 @@ static void materialui_set_list_view_type(materialui_handle_t *mui, unsigned thumbnail_view_portrait, unsigned thumbnail_view_landscape) { - if (!(mui->flags & MUI_FLAG_IS_PLAYLIST)) + if (mui->flags & MUI_FLAG_IS_SAVESTATE_LIST) + { + mui->list_view_type = MUI_LIST_VIEW_SAVESTATE; + mui->flags &= ~MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED; + } + else if (!(mui->flags & MUI_FLAG_IS_PLAYLIST)) { /* This is not a playlist - set default list * view and register that primary thumbnail @@ -7352,6 +8056,7 @@ static void materialui_set_list_view_type(materialui_handle_t *mui, && gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT)) { mui->flags |= MUI_FLAG_PRIMARY_THUMBNAIL_AVAILABLE; + /* Get thumbnail view mode based on current * display orientation */ if (mui->flags & MUI_FLAG_IS_PORTRAIT) @@ -7428,6 +8133,12 @@ static void materialui_set_list_view_type(materialui_handle_t *mui, materialui_render_menu_entry = materialui_render_menu_entry_playlist_desktop; materialui_render_selected_entry_aux = materialui_render_selected_entry_aux_playlist_desktop; break; + case MUI_LIST_VIEW_SAVESTATE: + materialui_compute_entries_box = materialui_compute_entries_box_savestate_list; + materialui_render_process_entry = materialui_render_process_entry_savestate_list; + materialui_render_menu_entry = materialui_render_menu_entry_savestate_list; + materialui_render_selected_entry_aux = materialui_render_selected_entry_aux_savestate_list; + break; case MUI_LIST_VIEW_DEFAULT: default: materialui_compute_entries_box = materialui_compute_entries_box_default; @@ -7620,11 +8331,9 @@ static void materialui_set_thumbnail_dimensions(materialui_handle_t *mui) mui->thumbnail_width_max = (unsigned)(((float)mui->thumbnail_height_max * MUI_THUMBNAIL_DEFAULT_ASPECT_RATIO) + 0.5f); - break; case MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_LARGE: - /* Maximum height corresponds to twice the * text height when showing full playlist sublabel * metadata (core association + runtime info) @@ -7638,7 +8347,6 @@ static void materialui_set_thumbnail_dimensions(materialui_handle_t *mui) mui->thumbnail_width_max = (unsigned)(((float)mui->thumbnail_height_max * MUI_THUMBNAIL_DEFAULT_ASPECT_RATIO) + 0.5f); - break; case MUI_LIST_VIEW_PLAYLIST_THUMB_DUAL_ICON: @@ -7709,6 +8417,17 @@ static void materialui_set_thumbnail_dimensions(materialui_handle_t *mui) } break; + case MUI_LIST_VIEW_SAVESTATE: + mui->thumbnail_height_max = + (mui->font_data.list.line_height + + (3 * mui->font_data.hint.line_height)) * 4; + + /* Set thumbnail width based on max height */ + mui->thumbnail_width_max = + (unsigned)(((float)mui->thumbnail_height_max * + MUI_THUMBNAIL_DEFAULT_ASPECT_RATIO) + 0.5f); + break; + case MUI_LIST_VIEW_PLAYLIST: case MUI_LIST_VIEW_DEFAULT: default: @@ -8223,6 +8942,10 @@ static void *materialui_init(void **userdata, bool video_is_threaded) /* Enable fade in animation for missing thumbnails */ gfx_thumbnail_set_fade_missing(true); + /* Savestate thumbnail empty */ + mui->savestate_thumbnail_file_path[0] = '\0'; + mui->prev_savestate_thumbnail_file_path[0] = '\0'; + /* Ensure that fullscreen thumbnails are inactive */ mui->fullscreen_thumbnail_selection = 0; mui->fullscreen_thumbnail_alpha = 0.0f; @@ -8295,7 +9018,7 @@ static void materialui_context_bg_destroy(materialui_handle_t *mui) gfx_display_deinit_white_texture(); } -static void materialui_reset_thumbnails(void) +static void materialui_reset_thumbnails(materialui_handle_t *mui) { int i; struct menu_state *menu_st = menu_state_get_ptr(); @@ -8316,6 +9039,8 @@ static void materialui_reset_thumbnails(void) gfx_thumbnail_reset(&node->thumbnails.primary); gfx_thumbnail_reset(&node->thumbnails.secondary); } + + gfx_thumbnail_reset(&mui->thumbnails.savestate); } static void materialui_context_destroy(void *data) @@ -8347,7 +9072,7 @@ static void materialui_context_destroy(void *data) mui->font_data.hint.font = NULL; /* Free node thumbnails */ - materialui_reset_thumbnails(); + materialui_reset_thumbnails(mui); /* Free background/wallpaper textures */ materialui_context_bg_destroy(mui); @@ -8399,6 +9124,12 @@ static void materialui_animate_scroll(materialui_handle_t *mui, * potential conflicts */ menu_input->pointer.y_accel = 0.0f; + if (!duration) + { + mui->scroll_y = scroll_pos; + return; + } + /* Set 'animation active' flag */ mui->flags |= MUI_FLAG_SCROLL_ANIMATION_ACTIVE; mui->scroll_animation_selection = menu_st->selection_ptr; @@ -8439,15 +9170,19 @@ static void materialui_navigation_set(void *data, bool scroll) /* Update possible fullscreen thumbnail label */ if (mui->flags & MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS) - materialui_update_fullscreen_thumbnail_label(mui, menu_st, selection); + materialui_update_fullscreen_thumbnail_label(mui); - if (!scroll) - return; + /* Update savestate thumbnail */ + if (mui->flags & MUI_FLAG_IS_SAVESTATE_LIST) + { + materialui_update_savestate_thumbnail_path(mui, selection); + materialui_update_savestate_thumbnail_image(mui); + } materialui_animate_scroll( mui, materialui_get_scroll(mui, p_disp), - MUI_ANIM_DURATION_SCROLL); + (scroll) ? MUI_ANIM_DURATION_SCROLL : 0); } static void materialui_list_set_selection(void *data, file_list_t *list) @@ -8462,12 +9197,11 @@ static void materialui_list_set_selection(void *data, file_list_t *list) /* The navigation pointer is set back to zero */ static void materialui_navigation_clear(void *data, bool pending_push) { - size_t i = 0; struct menu_state *menu_st = menu_state_get_ptr(); materialui_handle_t *mui = (materialui_handle_t*)data; if (!mui) return; - menu_st->entries.begin = i; + menu_st->entries.begin = 0; materialui_animate_scroll(mui, 0.0f, MUI_ANIM_DURATION_SCROLL_RESET); } @@ -8839,6 +9573,17 @@ static void materialui_populate_entries(void *data, const char *path, menu_state_get_ptr()->selection_ptr = mui->settings_selection_ptr; } + if ( settings->bools.savestate_thumbnail_enable + && ( string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_SAVESTATE_LIST)) + || string_to_unsigned(path) == MENU_ENUM_LABEL_STATE_SLOT)) + { + mui->flags |= MUI_FLAG_IS_SAVESTATE_LIST; + materialui_update_savestate_thumbnail_path(mui, menu_state_get_ptr()->selection_ptr); + materialui_update_savestate_thumbnail_image(mui); + } + else + mui->flags &= ~MUI_FLAG_IS_SAVESTATE_LIST; + /* Update navigation bar tabs * > Note: We do this regardless of whether * the navigation bar is currently shown. @@ -8934,6 +9679,9 @@ static void materialui_context_reset(void *data, bool is_threaded) video_driver_supports_rgba(), 0, menu_display_handle_wallpaper_upload, NULL); + if (path_is_valid(mui->savestate_thumbnail_file_path)) + materialui_update_savestate_thumbnail_image(mui); + video_driver_monitor_reset(); } @@ -9220,7 +9968,7 @@ static void materialui_switch_list_view(materialui_handle_t *mui, || (mui->list_view_type == MUI_LIST_VIEW_PLAYLIST) || ((secondary_thumbnail_enabled_prev) && (!(mui->flags & MUI_FLAG_SECONDARY_THUMBNAIL_ENABLED)))) - materialui_reset_thumbnails(); + materialui_reset_thumbnails(mui); /* We want to 'fade in' when switching views, so * trigger normal transition animation */ @@ -9257,6 +10005,12 @@ static enum menu_action materialui_parse_menu_entry_action( * > If current selection is off screen, * auto select 'middle' item */ materialui_auto_select_onscreen_entry(mui, MUI_ONSCREEN_ENTRY_CENTRE); + + if ( (mui->flags & MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS) + && (mui->flags & MUI_FLAG_IS_SAVESTATE_LIST) + && !materialui_is_savestate_slot(mui)) + return MENU_ACTION_NOOP; + break; case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: @@ -9381,7 +10135,7 @@ static enum menu_action materialui_parse_menu_entry_action( { menu_st->selection_ptr = new_selection; if (menu_st->driver_ctx->navigation_set) - menu_st->driver_ctx->navigation_set(menu_st->userdata, true); + menu_st->driver_ctx->navigation_set(menu_st->userdata, false); } new_action = MENU_ACTION_NOOP; @@ -9401,8 +10155,7 @@ static enum menu_action materialui_parse_menu_entry_action( { menu_st->selection_ptr = new_selection; if (menu_st->driver_ctx->navigation_set) - menu_st->driver_ctx->navigation_set(menu_st->userdata, true); - materialui_auto_select_onscreen_entry(mui, MUI_ONSCREEN_ENTRY_CENTRE); + menu_st->driver_ctx->navigation_set(menu_st->userdata, false); } new_action = MENU_ACTION_NOOP; @@ -9412,6 +10165,14 @@ static enum menu_action materialui_parse_menu_entry_action( audio_driver_mixer_play_scroll_sound(true); #endif } + else if (mui->flags & MUI_FLAG_IS_SAVESTATE_LIST) + { + if (mui->flags & MUI_FLAG_SHOW_FULLSCREEN_THUMBNAILS) + materialui_hide_fullscreen_thumbnails(mui, true); + else + materialui_show_fullscreen_thumbnails(mui, menu_st, selection); + new_action = MENU_ACTION_NOOP; + } else if (!materialui_entry_onscreen(mui, selection)) new_action = MENU_ACTION_NOOP; } @@ -11322,7 +12083,20 @@ static void materialui_update_thumbnail_image(void *userdata) { struct menu_state *menu_st = menu_state_get_ptr(); materialui_refresh_thumbnail_image(userdata, menu_st->selection_ptr); - return; +} + +static void materialui_toggle(void *userdata, bool menu_on) +{ + materialui_handle_t *mui = (materialui_handle_t*)userdata; + + if (!mui) + return; + + /* Have to reset this, otherwise savestate + * thumbnail won't update after selecting + * 'save state' option */ + if (!string_is_empty(mui->savestate_thumbnail_file_path)) + gfx_thumbnail_reset(&mui->thumbnails.savestate); } menu_ctx_driver_t menu_ctx_mui = { @@ -11335,7 +12109,7 @@ menu_ctx_driver_t menu_ctx_mui = { materialui_context_reset, materialui_context_destroy, materialui_populate_entries, - NULL, + materialui_toggle, materialui_navigation_clear, NULL, NULL, @@ -11363,8 +12137,8 @@ menu_ctx_driver_t menu_ctx_mui = { materialui_refresh_thumbnail_image, NULL, gfx_display_osk_ptr_at_pos, - NULL, /* update_savestate_thumbnail_path */ - NULL, /* update_savestate_thumbnail_image */ + materialui_update_savestate_thumbnail_path, + materialui_update_savestate_thumbnail_image, materialui_pointer_down, materialui_pointer_up, materialui_menu_entry_action diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 8b46bff720e8..e9b35e4a77e3 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -67,7 +67,7 @@ #define ANIMATION_CURSOR_DURATION 166.66667f #define ANIMATION_CURSOR_PULSE 166.66667f * 3 -#define OZONE_THUMBNAIL_STREAM_DELAY 16.66667f * 5 +#define OZONE_THUMBNAIL_STREAM_DELAY 16.66667f * 3 #define OZONE_EASING_ALPHA EASING_OUT_CIRC #define OZONE_EASING_XY EASING_OUT_QUAD @@ -3743,6 +3743,9 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) || (ozone->flags & OZONE_FLAG_IS_STATE_SLOT))) return; + ozone->flags &= ~OZONE_FLAG_WANT_THUMBNAIL_BAR; + ozone->flags &= ~OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; + if (savestate_thumbnail) { menu_entry_t entry; @@ -3771,44 +3774,34 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) if (state_slot < 0) { - path[0] = '\0'; - _len = fill_pathname_join_delim(path, + path[0] = '\0'; + _len = fill_pathname_join_delim(path, runloop_st->name.savestate, "auto", '.', sizeof(path)); } else { - _len = strlcpy(path, runloop_st->name.savestate, sizeof(path)); + _len = strlcpy(path, runloop_st->name.savestate, sizeof(path)); if (state_slot > 0) - _len += snprintf(path + _len, sizeof(path) - _len, "%d", state_slot); + _len += snprintf(path + _len, sizeof(path) - _len, "%d", state_slot); } + strlcpy(path + _len, FILE_PATH_PNG_EXTENSION, sizeof(path) - _len); - if (path_is_valid(path)) - { - strlcpy( - ozone->savestate_thumbnail_file_path, path, - sizeof(ozone->savestate_thumbnail_file_path)); + strlcpy( + ozone->savestate_thumbnail_file_path, path, + sizeof(ozone->savestate_thumbnail_file_path)); - ozone->flags |= OZONE_FLAG_WANT_THUMBNAIL_BAR - | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; - menu_update_fullscreen_thumbnail_label( - ozone->fullscreen_thumbnail_label, - sizeof(ozone->fullscreen_thumbnail_label), - (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) ? true : false, - NULL); - } - else if (!(ozone->flags & OZONE_FLAG_IS_STATE_SLOT)) - ozone->flags &= ~(OZONE_FLAG_WANT_THUMBNAIL_BAR - | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE); - else - ozone->flags &= ~OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; + ozone->flags |= OZONE_FLAG_WANT_THUMBNAIL_BAR + | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; + + menu_update_fullscreen_thumbnail_label( + ozone->fullscreen_thumbnail_label, + sizeof(ozone->fullscreen_thumbnail_label), + (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) ? true : false, + NULL); } - else if (!(ozone->flags & OZONE_FLAG_SKIP_THUMBNAIL_RESET)) - ozone->flags &= ~(OZONE_FLAG_WANT_THUMBNAIL_BAR - | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE); - if ( ((ozone->show_thumbnail_bar) - != ((ozone->flags & OZONE_FLAG_WANT_THUMBNAIL_BAR) > 0) + if ( ((ozone->show_thumbnail_bar) != ((ozone->flags & OZONE_FLAG_WANT_THUMBNAIL_BAR) > 0) && (!(ozone->flags & OZONE_FLAG_PENDING_HIDE_THUMBNAIL_BAR)))) ozone->flags |= OZONE_FLAG_NEED_COMPUTE; } @@ -3832,9 +3825,9 @@ static void ozone_update_savestate_thumbnail_image(void *data) /* Only request thumbnail if: * > Thumbnail has never been loaded *OR* * > Thumbnail path has changed */ - if ((ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN) - || !string_is_equal(ozone->savestate_thumbnail_file_path, - ozone->prev_savestate_thumbnail_file_path)) + if ( (ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN) + || !string_is_equal(ozone->savestate_thumbnail_file_path, + ozone->prev_savestate_thumbnail_file_path)) { gfx_thumbnail_request_file( ozone->savestate_thumbnail_file_path, @@ -5247,20 +5240,25 @@ static void ozone_draw_no_thumbnail_available( unsigned video_width, unsigned video_height, unsigned x_position, - unsigned sidebar_width, - unsigned y_offset, + unsigned y_position, + unsigned view_width, + unsigned view_height, + bool draw_text, math_matrix_4x4 *mymat) { - unsigned icon = OZONE_ENTRIES_ICONS_TEXTURE_CORE_INFO; - unsigned icon_size = (unsigned)((float) - ozone->dimensions.sidebar_entry_icon_size * 1.5f); gfx_display_ctx_driver_t *dispctx = p_disp->dispctx; - float *col = ozone->theme->entries_icon; + unsigned icon_size = (unsigned)ozone->dimensions.sidebar_entry_icon_size * 2.0f; + float *col = ozone->theme_dynamic.entries_icon; ozone->flags |= OZONE_FLAG_NO_THUMBNAIL_AVAILABLE; + if (draw_text) + icon_size *= 2; + if (dispctx) { + gfx_display_set_alpha(col, 0.20f); + if (dispctx->blend_begin) dispctx->blend_begin(userdata); if (dispctx->draw) @@ -5271,9 +5269,9 @@ static void ozone_draw_no_thumbnail_available( video_height, icon_size, icon_size, - ozone->icons_textures[icon], - x_position + sidebar_width / 2 - icon_size / 2, - video_height / 2 - icon_size / 2 - y_offset, + ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_IMAGE], + x_position + ((view_width - icon_size) / 2), + video_height - y_position - icon_size - ((view_height - icon_size) / 2), video_width, video_height, 0.0f, @@ -5284,11 +5282,14 @@ static void ozone_draw_no_thumbnail_available( dispctx->blend_end(userdata); } + if (!draw_text) + return; + gfx_display_draw_text( ozone->fonts.footer.font, msg_hash_to_str(MSG_NO_THUMBNAIL_AVAILABLE), - x_position + sidebar_width / 2, - video_height / 2 + icon_size / 2 + ozone->fonts.footer.line_ascender - y_offset, + x_position + (view_width / 2), + video_height - y_position - ((view_height - icon_size) / 2), video_width, video_height, ozone->theme->text_rgba, @@ -5427,12 +5428,7 @@ static int ozone_get_sublabel_max_width(ozone_handle_t *ozone, if (ozone->depth == 1) sublabel_max_width -= (int)ozone->dimensions_sidebar_width; if (ozone->show_thumbnail_bar) - { - if ((ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) && menu_is_running_quick_menu()) - sublabel_max_width -= ozone->dimensions.thumbnail_bar_width - entry_padding * 2; - else - sublabel_max_width -= ozone->dimensions.thumbnail_bar_width - entry_padding; - } + sublabel_max_width -= ozone->dimensions.thumbnail_bar_width - entry_padding * 2; return sublabel_max_width; } @@ -6169,7 +6165,7 @@ static void ozone_draw_thumbnail_bar( - (unsigned)ozone->animations.thumbnail_bar_position - ozone->dimensions.sidebar_entry_icon_padding; int thumbnail_x_position = x_position - + ozone->dimensions.sidebar_entry_icon_padding * 2; + + ozone->dimensions.sidebar_entry_icon_padding; unsigned thumbnail_height = (video_height - ozone->dimensions.header_height - ozone->dimensions.spacer_2px @@ -6235,17 +6231,10 @@ static void ozone_draw_thumbnail_bar( || (ozone->flags & OZONE_FLAG_IS_STATE_SLOT)) { ozone->flags2 |= OZONE_FLAG2_SELECTION_CORE_IS_VIEWER; - show_right_thumbnail = true; show_left_thumbnail = false; - - if (!(ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE || - ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_PENDING)) - { - if (ozone->flags & OZONE_FLAG_IS_STATE_SLOT) - show_right_thumbnail = false; - else - return; - } + show_right_thumbnail = + ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE + || ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_PENDING; } else if (!(ozone->flags & OZONE_FLAG_WANT_THUMBNAIL_BAR)) return; @@ -6258,25 +6247,6 @@ static void ozone_draw_thumbnail_bar( show_left_thumbnail = false; } - /* If this entry is associated with the image viewer - * and no right thumbnail is available, show a centred - * message and return immediately */ - if ( (ozone->flags2 & OZONE_FLAG2_SELECTION_CORE_IS_VIEWER) - && (!show_right_thumbnail && !show_left_thumbnail)) - { - ozone_draw_no_thumbnail_available( - ozone, - p_disp, - userdata, - video_width, - video_height, - x_position, - sidebar_width, - 0, - mymat); - return; - } - /* Top row * > Displays one item, with the following order * of preference: @@ -6294,6 +6264,12 @@ static void ozone_draw_thumbnail_bar( + (int)(1.5f * (float)ozone->dimensions.sidebar_entry_icon_padding); right_thumbnail_alignment = GFX_THUMBNAIL_ALIGN_CENTRE; + + if (thumbnail_height > thumbnail_width) + { + thumbnail_height /= 2; + right_thumbnail_y_position += thumbnail_height / 2; + } } else { @@ -6304,6 +6280,49 @@ static void ozone_draw_thumbnail_bar( right_thumbnail_alignment = GFX_THUMBNAIL_ALIGN_BOTTOM; } + /* If this entry is associated with the image viewer + * and no thumbnails are available, show a centred + * message and return immediately */ + if ( (ozone->flags2 & OZONE_FLAG2_SELECTION_CORE_IS_VIEWER) + && (!show_right_thumbnail && !show_left_thumbnail)) + { + float background_color[16] = { + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + }; + + /* Darken background */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + thumbnail_x_position, + right_thumbnail_y_position, + thumbnail_width, + thumbnail_height, + video_width, + video_height, + background_color, + NULL); + + ozone_draw_no_thumbnail_available( + ozone, + p_disp, + userdata, + video_width, + video_height, + thumbnail_x_position, + right_thumbnail_y_position, + thumbnail_width, + thumbnail_height, + false, + mymat); + return; + } + /* > If we have a right thumbnail, show it */ if (show_right_thumbnail) { @@ -6329,16 +6348,20 @@ static void ozone_draw_thumbnail_bar( * a left thumbnail to show in its place, * display 'no thumbnail available' message */ else if (!show_left_thumbnail) + { ozone_draw_no_thumbnail_available( ozone, p_disp, userdata, video_width, video_height, - x_position, - sidebar_width, - thumbnail_height / 2, + thumbnail_x_position, + right_thumbnail_y_position + thumbnail_height, + thumbnail_width, + thumbnail_height, + false, mymat); + } /* Bottom row * > Displays one item, with the following order @@ -7092,6 +7115,22 @@ static void ozone_draw_messagebox( string_list_deinitialize(&list); } +static void ozone_set_thumbnail_delay(ozone_handle_t *ozone, bool on) +{ + if (on) + { + ozone->thumbnails.stream_delay = OZONE_THUMBNAIL_STREAM_DELAY; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); + gfx_thumbnail_set_fade_duration(-1.0f); + } + else + { + ozone->thumbnails.stream_delay = 0.0f; + gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); + gfx_thumbnail_set_fade_duration(1); + } +} + static void ozone_hide_fullscreen_thumbnails(ozone_handle_t *ozone, bool animate) { uintptr_t alpha_tag = (uintptr_t) @@ -7123,6 +7162,7 @@ static void ozone_hide_fullscreen_thumbnails(ozone_handle_t *ozone, bool animate /* Disable fullscreen thumbnails */ ozone->flags2 &= ~OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS; + ozone_set_thumbnail_delay(ozone, true); } static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) @@ -7138,48 +7178,8 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) /* Before showing fullscreen thumbnails, must * ensure that any existing fullscreen thumbnail * view is disabled... */ - ozone_hide_fullscreen_thumbnails(ozone, false); - - /* Sanity check: Return immediately if this is - * a menu without thumbnail support, or cursor - * is currently in the sidebar */ - if ( (!(ozone->flags & OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE)) - || (ozone->flags & OZONE_FLAG_CURSOR_IN_SIDEBAR)) - return; - - /* We can only enable fullscreen thumbnails if - * current selection has at least one valid thumbnail - * and all thumbnails for current selection are already - * loaded/available */ - if (ozone->flags2 & OZONE_FLAG2_SELECTION_CORE_IS_VIEWER) - { - /* imageviewer content requires special treatment, - * since only the right thumbnail is ever loaded */ - if ( !gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) - && !gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) - return; - } - else - { - bool left_thumbnail_enabled = gfx_thumbnail_is_enabled( - menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT); - - if ( !left_thumbnail_enabled - && !gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, - GFX_THUMBNAIL_RIGHT)) - return; - - if ( (ozone->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE) - && (left_thumbnail_enabled - && ((ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_MISSING) - && (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_AVAILABLE)))) - return; - - if ( (ozone->thumbnails.right.status == GFX_THUMBNAIL_STATUS_MISSING) - && (!(ozone->flags & OZONE_FLAG_IS_STATE_SLOT)) - && (!left_thumbnail_enabled || (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_AVAILABLE))) - return; - } + if (!(ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS)) + ozone_hide_fullscreen_thumbnails(ozone, false); /* Menu list must be stationary while fullscreen * thumbnails are shown @@ -7213,6 +7213,7 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) /* Enable fullscreen thumbnails */ ozone->fullscreen_thumbnail_selection = (size_t)ozone->selection; ozone->flags2 |= OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS; + ozone_set_thumbnail_delay(ozone, false); } static void ozone_draw_fullscreen_thumbnails( @@ -7222,6 +7223,11 @@ static void ozone_draw_fullscreen_thumbnails( unsigned video_width, unsigned video_height) { + static float right_thumbnail_draw_width_prev = 0.0f; + static float right_thumbnail_draw_height_prev = 0.0f; + static float left_thumbnail_draw_width_prev = 0.0f; + static float left_thumbnail_draw_height_prev = 0.0f; + /* Check whether fullscreen thumbnails are visible */ if ( (ozone->animations.fullscreen_thumbnail_alpha > 0.0f) || (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS)) @@ -7258,21 +7264,18 @@ static void ozone_draw_fullscreen_thumbnails( bool show_right_thumbnail = false; bool show_left_thumbnail = false; - /* Sanity check: Return immediately if this is - * a menu without thumbnails and we are not currently - * 'fading out' the fullscreen thumbnail view */ - if ( (!(ozone->flags & OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE)) - && (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) - goto error; - /* Sanity check: Return immediately if the view * width/height is < 1 */ if ((view_width < 1) || (view_height < 1)) goto error; /* Get number of 'active' thumbnails */ - show_right_thumbnail = (right_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE); - show_left_thumbnail = (left_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE); + show_right_thumbnail = + ( right_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE + || right_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING); + show_left_thumbnail = + ( left_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE + || left_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING); if (((ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) && !string_is_empty(ozone->savestate_thumbnail_file_path)) || (ozone->flags & OZONE_FLAG_IS_STATE_SLOT)) @@ -7288,39 +7291,6 @@ static void ozone_draw_fullscreen_thumbnails( if (show_left_thumbnail) num_thumbnails++; - /* Prevent screen flashing when browsing in fullscreen thumbnail mode */ - if ( (num_thumbnails < 1) - && (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) - && ( (right_thumbnail->status != GFX_THUMBNAIL_STATUS_MISSING) - && (left_thumbnail->status != GFX_THUMBNAIL_STATUS_MISSING))) - { - /* Darken background */ - gfx_display_draw_quad( - p_disp, - userdata, - video_width, - video_height, - 0, - ozone->dimensions.header_height + ozone->dimensions.spacer_1px, - view_width, - (unsigned)view_height, - video_width, - video_height, - background_color, - NULL); - return; - } - - /* Do nothing if both thumbnails are missing - * > Note: Baring inexplicable internal errors, this - * can never happen... - * > Return instead of error to keep fullscreen - * mode after menu/fullscreen toggle */ - if (num_thumbnails < 1 && - ( right_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING - && left_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)) - return; - /* Get base thumbnail dimensions + draw positions */ /* > Thumbnail bounding box height + y position @@ -7357,7 +7327,8 @@ static void ozone_draw_fullscreen_thumbnails( * layout until we have thumbnail draw dimensions. * and we cannot get draw dimensions until we have * the bounding box dimensions... */ - if (show_right_thumbnail) + if ( show_right_thumbnail + && right_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE) { gfx_thumbnail_get_draw_dimensions( right_thumbnail, @@ -7367,13 +7338,22 @@ static void ozone_draw_fullscreen_thumbnails( &right_thumbnail_draw_width, &right_thumbnail_draw_height); + right_thumbnail_draw_width_prev = right_thumbnail_draw_width; + right_thumbnail_draw_height_prev = right_thumbnail_draw_height; + /* Sanity check */ if ( (right_thumbnail_draw_width <= 0.0f) || (right_thumbnail_draw_height <= 0.0f)) - goto error; + show_right_thumbnail = false; + } + else if (right_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) + { + right_thumbnail_draw_width = right_thumbnail_draw_width_prev; + right_thumbnail_draw_height = right_thumbnail_draw_height_prev; } - if (show_left_thumbnail) + if ( show_left_thumbnail + && left_thumbnail->status == GFX_THUMBNAIL_STATUS_AVAILABLE) { gfx_thumbnail_get_draw_dimensions( left_thumbnail, @@ -7383,10 +7363,18 @@ static void ozone_draw_fullscreen_thumbnails( &left_thumbnail_draw_width, &left_thumbnail_draw_height); + left_thumbnail_draw_width_prev = left_thumbnail_draw_width; + left_thumbnail_draw_height_prev = left_thumbnail_draw_height; + /* Sanity check */ if ( (left_thumbnail_draw_width <= 0.0f) || (left_thumbnail_draw_height <= 0.0f)) - goto error; + show_left_thumbnail = false; + } + else if (left_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) + { + left_thumbnail_draw_width = left_thumbnail_draw_width_prev; + left_thumbnail_draw_height = left_thumbnail_draw_height_prev; } /* Adjust thumbnail draw positions to achieve @@ -7544,8 +7532,25 @@ static void ozone_draw_fullscreen_thumbnails( 1.0f, NULL); } - } + /* Show "No thumbnail available" */ + if ( !show_right_thumbnail + && !show_left_thumbnail) + { + ozone_draw_no_thumbnail_available( + ozone, + p_disp, + userdata, + video_width, + video_height, + 0, + thumbnail_y, + view_width, + view_height, + true, + NULL); + } + } return; error: @@ -7757,20 +7762,13 @@ static bool INLINE ozone_fullscreen_thumbnails_available(ozone_handle_t *ozone, struct menu_state *menu_st) { bool ret = - ( (ozone->flags & OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE)) - && (!(ozone->flags & OZONE_FLAG_CURSOR_IN_SIDEBAR)) - && (ozone->show_thumbnail_bar) - && (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) - || gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) - && ( (ozone->thumbnails.left.status == GFX_THUMBNAIL_STATUS_AVAILABLE - || (ozone->thumbnails.left.status < GFX_THUMBNAIL_STATUS_AVAILABLE - && ozone->thumbnails_left_status_prev <= GFX_THUMBNAIL_STATUS_AVAILABLE)) - || (ozone->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE - || (ozone->thumbnails.right.status < GFX_THUMBNAIL_STATUS_AVAILABLE - && ozone->thumbnails_right_status_prev <= GFX_THUMBNAIL_STATUS_AVAILABLE))); - - if (!string_is_empty(ozone->savestate_thumbnail_file_path) && - ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE) + (!(ozone->flags & OZONE_FLAG_CURSOR_IN_SIDEBAR)) + && (ozone->show_thumbnail_bar) + && ( gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) + || gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)); + + if ( !string_is_empty(ozone->savestate_thumbnail_file_path) + && ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE) ret = true; return ret; @@ -7998,20 +7996,6 @@ static void ozone_start_cursor_wiggle( ozone->flags2 |= OZONE_FLAG2_CURSOR_WIGGLING; } -static void ozone_set_thumbnail_delay(bool on) -{ - if (on) - { - gfx_thumbnail_set_stream_delay(OZONE_THUMBNAIL_STREAM_DELAY); - gfx_thumbnail_set_fade_duration(-1.0f); - } - else - { - gfx_thumbnail_set_stream_delay(0); - gfx_thumbnail_set_fade_duration(1); - } -} - static enum menu_action ozone_parse_menu_entry_action( ozone_handle_t *ozone, bool menu_navigation_wraparound_enable, @@ -8036,7 +8020,8 @@ static enum menu_action ozone_parse_menu_entry_action( * ensure that the proper value is restored * whenever the user performs regular navigation */ if ( (action != MENU_ACTION_NOOP) - && (ozone->thumbnails.stream_delay != OZONE_THUMBNAIL_STREAM_DELAY)) + && (ozone->thumbnails.stream_delay != OZONE_THUMBNAIL_STREAM_DELAY) + && !(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) { ozone->thumbnails.stream_delay = OZONE_THUMBNAIL_STREAM_DELAY; gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); @@ -8118,17 +8103,15 @@ static enum menu_action ozone_parse_menu_entry_action( && (!(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) && (!(ozone->flags & OZONE_FLAG_CURSOR_IN_SIDEBAR))) { - ozone_show_fullscreen_thumbnails(ozone); ozone->flags2 |= OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; - ozone_set_thumbnail_delay(false); + ozone_show_fullscreen_thumbnails(ozone); new_action = MENU_ACTION_NOOP; } else if ((ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) || (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS)) { - ozone_set_thumbnail_delay(true); - ozone_hide_fullscreen_thumbnails(ozone, true); ozone->flags2 &= ~OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; + ozone_hide_fullscreen_thumbnails(ozone, true); new_action = MENU_ACTION_NOOP; } break; @@ -8212,21 +8195,20 @@ static enum menu_action ozone_parse_menu_entry_action( ozone->flags &= ~(OZONE_FLAG_SKIP_THUMBNAIL_RESET | OZONE_FLAG_CURSOR_MODE); - if ( (ozone->flags & OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE) - && (!(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) + if ( (!(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) && ( (ozone->flags & OZONE_FLAG_IS_STATE_SLOT) || ((ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) && !string_is_empty(ozone->savestate_thumbnail_file_path)))) { - ozone_show_fullscreen_thumbnails(ozone); ozone->flags2 |= OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; + ozone_show_fullscreen_thumbnails(ozone); new_action = MENU_ACTION_NOOP; } else if ((ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) && ( (ozone->flags & OZONE_FLAG_IS_STATE_SLOT) || ((ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) && menu_is_running_quick_menu()))) { - ozone_hide_fullscreen_thumbnails(ozone, true); ozone->flags2 &= ~OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; + ozone_hide_fullscreen_thumbnails(ozone, true); new_action = MENU_ACTION_NOOP; } break; @@ -8434,9 +8416,8 @@ static enum menu_action ozone_parse_menu_entry_action( if ( (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) || (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS)) { - ozone_set_thumbnail_delay(true); - ozone_hide_fullscreen_thumbnails(ozone, true); ozone->flags2 &= ~OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; + ozone_hide_fullscreen_thumbnails(ozone, true); if ( (!(ozone->flags & OZONE_FLAG_IS_STATE_SLOT)) && (!(ozone->flags & OZONE_FLAG_IS_PLAYLIST)) && (!(ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST))) @@ -8505,10 +8486,9 @@ static enum menu_action ozone_parse_menu_entry_action( if ( (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) || (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS)) { - ozone_set_thumbnail_delay(true); - ozone_hide_fullscreen_thumbnails(ozone, true); ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; ozone->flags2 &= ~OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS; + ozone_hide_fullscreen_thumbnails(ozone, true); new_action = MENU_ACTION_NOOP; break; } @@ -8575,6 +8555,7 @@ static enum menu_action ozone_parse_menu_entry_action( #endif break; } + if ( (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) && (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU)) return MENU_ACTION_NOOP; @@ -8636,6 +8617,7 @@ static enum menu_action ozone_parse_menu_entry_action( #endif break; } + if ( (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) && (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU)) return MENU_ACTION_NOOP; @@ -9088,6 +9070,13 @@ static void ozone_update_thumbnail_image(void *data) want_thumbnail_bar = (ozone->flags & OZONE_FLAG_WANT_THUMBNAIL_BAR) ? true : false; if (show_thumbnail_bar != want_thumbnail_bar) ozone->flags |= OZONE_FLAG_NEED_COMPUTE; + + if (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) + menu_update_fullscreen_thumbnail_label( + ozone->fullscreen_thumbnail_label, + sizeof(ozone->fullscreen_thumbnail_label), + (ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) ? true : false, + ozone->title); } static void ozone_refresh_thumbnail_image(void *data, unsigned i) @@ -10438,12 +10427,12 @@ static void ozone_render(void *data, gfx_thumbnail_request_streams( menu_st->thumbnail_path_data, p_anim, - playlist, - selection, + playlist, selection, &ozone->thumbnails.right, &ozone->thumbnails.left, gfx_thumbnail_upscale_threshold, network_on_demand_thumbnails); + if ( (ozone->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) && (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN)) ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; @@ -10453,11 +10442,11 @@ static void ozone_render(void *data, menu_st->thumbnail_path_data, p_anim, GFX_THUMBNAIL_RIGHT, - playlist, - selection, + playlist, selection, &ozone->thumbnails.right, gfx_thumbnail_upscale_threshold, network_on_demand_thumbnails); + if (ozone->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; break; @@ -10466,11 +10455,11 @@ static void ozone_render(void *data, menu_st->thumbnail_path_data, p_anim, GFX_THUMBNAIL_LEFT, - playlist, - selection, + playlist, selection, &ozone->thumbnails.left, gfx_thumbnail_upscale_threshold, network_on_demand_thumbnails); + if (ozone->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN) ozone->thumbnails.pending = OZONE_PENDING_THUMBNAIL_NONE; break; @@ -10721,7 +10710,7 @@ static void ozone_draw_header( ticker_smooth.font = ozone->fonts.title.font; ticker_smooth.selected = true; ticker_smooth.field_width = video_width - status_row_size; - ticker_smooth.src_str = (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) + ticker_smooth.src_str = (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) ? ozone->fullscreen_thumbnail_label : ozone->title; ticker_smooth.dst_str = title; @@ -10733,7 +10722,7 @@ static void ozone_draw_header( { ticker.s = title; ticker.len = video_width - status_row_size / ozone->fonts.title.glyph_width; - ticker.str = (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS) + ticker.str = (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) ? ozone->fullscreen_thumbnail_label : ozone->title; ticker.selected = true; @@ -10809,15 +10798,9 @@ static void ozone_draw_footer( ozone->footer_labels.cycle_thumbnails.show = ozone->footer_labels.fullscreen_thumbnails.show - && !ozone->footer_labels.random_select.show + && ((ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) || (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) && !(ozone->flags & OZONE_FLAG_IS_FILE_LIST) - && !(((ozone->flags2 & OZONE_FLAG2_IS_QUICK_MENU) - && menu_is_running_quick_menu()) - || (ozone->flags & OZONE_FLAG_IS_STATE_SLOT)); - - ozone->footer_labels.cycle_thumbnails.show |= - (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) - || (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS); + && string_is_empty(ozone->savestate_thumbnail_file_path); ozone->footer_labels.clear_setting.show = !ozone->footer_labels.cycle_thumbnails.show @@ -11083,8 +11066,7 @@ static void ozone_draw_footer( video_height, icon_size, icon_size, - (ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE || - ozone->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_PENDING) + (!string_is_empty(ozone->savestate_thumbnail_file_path)) ? ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_BTN_L] : ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_START], ozone->footer_labels.fullscreen_thumbnails.x, @@ -11548,15 +11530,9 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) if (ozone->selection != new_selection) { - menu_entry_t entry; - unsigned entry_type; uintptr_t tag = (uintptr_t)selection_buf; size_t selection = new_selection; - MENU_ENTRY_INITIALIZE(entry); - menu_entry_get(&entry, 0, selection, NULL, true); - - entry_type = entry.type; ozone->selection_old = ozone->selection; ozone->selection = new_selection; @@ -11580,25 +11556,29 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) && (ozone->depth == 1 || ozone->depth == 3)) { ozone_set_thumbnail_content(ozone, ""); - update_thumbnails = true; - ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; + update_thumbnails = true; + ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; } /* Database + Explore list updates */ else if ( ((ozone->flags & OZONE_FLAG_IS_DB_MANAGER_LIST) && (ozone->depth == 4)) || (ozone->flags & OZONE_FLAG_IS_EXPLORE_LIST)) { ozone_set_thumbnail_content(ozone, ""); - update_thumbnails = true; - ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; + update_thumbnails = true; + ozone->flags &= ~OZONE_FLAG_SKIP_THUMBNAIL_RESET; } /* Filebrowser image updates */ else if (ozone->flags & OZONE_FLAG_IS_FILE_LIST) { - if ( (entry_type == FILE_TYPE_IMAGEVIEWER) - || (entry_type == FILE_TYPE_IMAGE)) + menu_entry_t entry; + MENU_ENTRY_INITIALIZE(entry); + menu_entry_get(&entry, 0, selection, NULL, true); + + if ( (entry.type == FILE_TYPE_IMAGEVIEWER) + || (entry.type == FILE_TYPE_IMAGE)) { ozone_set_thumbnail_content(ozone, "imageviewer"); - update_thumbnails = true; + update_thumbnails = true; ozone->flags |= OZONE_FLAG_WANT_THUMBNAIL_BAR | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; } @@ -11611,9 +11591,9 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) * persist, and be shown on the wrong entry) */ gfx_thumbnail_set_content(menu_st->thumbnail_path_data, NULL); ozone_unload_thumbnail_textures(ozone); - update_thumbnails = true; - ozone->flags &= ~(OZONE_FLAG_WANT_THUMBNAIL_BAR - | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE); + update_thumbnails = true; + ozone->flags &= ~(OZONE_FLAG_WANT_THUMBNAIL_BAR + | OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE); } } @@ -11724,15 +11704,6 @@ static void ozone_frame(void *data, video_frame_info_t *video_info) } } - if ( ( (size_t)ozone->selection != ozone->fullscreen_thumbnail_selection - && (ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) - || ( (ozone->flags2 & OZONE_FLAG2_WANT_FULLSCREEN_THUMBNAILS) - && !(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS))) - { - ozone->flags |= OZONE_FLAG_NEED_COMPUTE; - ozone_show_fullscreen_thumbnails(ozone); - } - if (ozone->flags & OZONE_FLAG_FIRST_FRAME) { menu_input_get_pointer_state(&ozone->pointer); @@ -11918,7 +11889,8 @@ static void ozone_frame(void *data, video_frame_info_t *video_info) ); /* Thumbnail bar */ - if (ozone->show_thumbnail_bar) + if ( ozone->show_thumbnail_bar + && !(ozone->flags2 & OZONE_FLAG2_SHOW_FULLSCREEN_THUMBNAILS)) ozone_draw_thumbnail_bar(ozone, menu_st, p_disp, @@ -12483,11 +12455,6 @@ static void ozone_populate_entries( else ozone->flags &= ~OZONE_FLAG_WANT_THUMBNAIL_BAR; } - - /* State slots must not allow fullscreen thumbnails when slot has no image */ - if ( (ozone->flags & OZONE_FLAG_IS_STATE_SLOT) - && string_is_empty(ozone->savestate_thumbnail_file_path)) - ozone->flags &= ~OZONE_FLAG_FULLSCREEN_THUMBNAILS_AVAILABLE; } static void ozone_toggle(void *userdata, bool menu_on) diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index 392378f58958..235040476098 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -2616,11 +2616,15 @@ static bool rgui_load_image( settings->uints.menu_rgui_thumbnail_downscaler; if (rgui->flags & RGUI_FLAG_SHOW_FULLSCREEN_THUMBNAIL) - rgui_process_thumbnail(rgui, &rgui->fs_thumbnail, &rgui->thumbnail_queue_size, + rgui_process_thumbnail(rgui, + &rgui->fs_thumbnail, + &rgui->thumbnail_queue_size, menu_rgui_thumbnail_downscaler, image); else - rgui_process_thumbnail(rgui, &rgui->mini_thumbnail, &rgui->thumbnail_queue_size, + rgui_process_thumbnail(rgui, + &rgui->mini_thumbnail, + &rgui->thumbnail_queue_size, menu_rgui_thumbnail_downscaler, image); @@ -2696,6 +2700,13 @@ static void rgui_render_background( (size_t)frame_buf->width * (size_t)frame_buf->height * sizeof(uint16_t)); } +/* Forward declaration */ +static void rgui_render_messagebox( + rgui_t *rgui, + const char *message, + unsigned fb_width, + unsigned fb_height); + static void rgui_render_fs_thumbnail( rgui_t *rgui, unsigned fb_width, @@ -2757,18 +2768,47 @@ static void rgui_render_fs_thumbnail( } /* Draw border */ + /* Top */ + if ((int)(fb_y_offset - border_width) >= 0) + rgui_fill_rect(frame_buf_data, fb_width, fb_height, + fb_x_offset, fb_y_offset - border_width, width, border_width, + rgui->colors.shadow_color, rgui->colors.shadow_color, false); + + /* Bottom */ + if (height + border_width <= fb_height) + rgui_fill_rect(frame_buf_data, fb_width, fb_height, + fb_x_offset, fb_y_offset + height, width, border_width, + rgui->colors.shadow_color, rgui->colors.shadow_color, false); + + /* Left */ + if ( (int)(fb_x_offset - border_width) >= 0 + && (int)(fb_y_offset - border_width) >= 0 + && (height + border_width * 2) <= fb_height) + rgui_fill_rect(frame_buf_data, fb_width, fb_height, + fb_x_offset - border_width, fb_y_offset - border_width, border_width, height + border_width * 2, + rgui->colors.shadow_color, rgui->colors.shadow_color, false); + + /* Right */ + if ( (int)(fb_y_offset - border_width) >= 0 + && (height + border_width * 2) <= fb_height) + rgui_fill_rect(frame_buf_data, fb_width, fb_height, + fb_x_offset + width, fb_y_offset - border_width, border_width, height + border_width * 2, + rgui->colors.shadow_color, rgui->colors.shadow_color, false); + } + else + { + /* Draw background */ rgui_fill_rect(frame_buf_data, fb_width, fb_height, - fb_x_offset, fb_y_offset, width - border_width, border_width, - 0, 0, false); - rgui_fill_rect(frame_buf_data, fb_width, fb_height, - fb_x_offset + width - border_width, fb_y_offset, border_width, height - border_width, - 0, 0, false); - rgui_fill_rect(frame_buf_data, fb_width, fb_height, - fb_x_offset + border_width, fb_y_offset + height - border_width, width - border_width, border_width, - 0, 0, false); - rgui_fill_rect(frame_buf_data, fb_width, fb_height, - fb_x_offset, fb_y_offset + border_width, border_width, height - border_width, - 0, 0, false); + 0, 0, fb_width, fb_height, + rgui->colors.bg_dark_color, + rgui->colors.bg_dark_color, + false); + + /* Draw "No thumbnail available" */ + if ( !(rgui->flags & RGUI_FLAG_ENTRY_HAS_THUMBNAIL) + && !(rgui->flags & RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL)) + rgui_render_messagebox(rgui, + msg_hash_to_str(MSG_NO_THUMBNAIL_AVAILABLE), fb_width, fb_height); } } @@ -2815,6 +2855,17 @@ static void rgui_render_mini_thumbnail( fb_y_offset = (rgui->term_layout.start_y + term_height) - (thumbnail->height + ((thumbnail->max_height - thumbnail->height) >> 1)); + /* Draw background */ + rgui_fill_rect(frame_buf_data, fb_width, fb_height, + rgui->term_layout.start_x + term_width - thumbnail_fullwidth, + ( ((thumbnail_id == GFX_THUMBNAIL_RIGHT) && !menu_rgui_swap_thumbnails) + || ((thumbnail_id == GFX_THUMBNAIL_LEFT) && menu_rgui_swap_thumbnails)) + ? fb_y_offset : fb_y_offset - ((thumbnail->max_height - thumbnail->height) >> 1), + thumbnail_fullwidth, thumbnail->max_height, + rgui->colors.shadow_color, + rgui->colors.shadow_color, + false); + /* Copy thumbnail to framebuffer */ for (y = 0; y < thumbnail->height; y++) { @@ -2826,7 +2877,7 @@ static void rgui_render_mini_thumbnail( } /* Draw drop shadow, if required */ - if (rgui->flags & RGUI_FLAG_SHADOW_ENABLE) + if (0 && rgui->flags & RGUI_FLAG_SHADOW_ENABLE) { rgui_color_rect(frame_buf_data, fb_width, fb_height, fb_x_offset + thumbnail->width, fb_y_offset + 1, @@ -4460,10 +4511,12 @@ static void rgui_render_messagebox( { uint16_t border_dark_color = rgui->colors.border_dark_color; uint16_t border_light_color = rgui->colors.border_light_color; + uint8_t border_width = 2; bool border_thickness = (rgui->flags & RGUI_FLAG_BORDER_THICKNESS) ? true : false; rgui_fill_rect(frame_buf_data, fb_width, fb_height, - x + 5, y + 5, width - 10, height - 10, + x + border_width, y + border_width, + width - border_width * 2, height - border_width * 2, rgui->colors.bg_dark_color, rgui->colors.bg_light_color, (rgui->flags & RGUI_FLAG_BG_THICKNESS) ? true : false); @@ -4477,9 +4530,9 @@ static void rgui_render_messagebox( uint16_t shadow_color = rgui->colors.shadow_color; rgui_color_rect(frame_buf_data, fb_width, fb_height, - x + 5, y + 5, 1, height - 5, shadow_color); + x + border_width, y + border_width, 1, height - border_width, shadow_color); rgui_color_rect(frame_buf_data, fb_width, fb_height, - x + 5, y + 5, width - 5, 1, shadow_color); + x + border_width, y + border_width, width - border_width, 1, shadow_color); rgui_color_rect(frame_buf_data, fb_width, fb_height, x + width, y + 1, 1, height, shadow_color); rgui_color_rect(frame_buf_data, fb_width, fb_height, @@ -4488,16 +4541,16 @@ static void rgui_render_messagebox( /* Draw border */ rgui_fill_rect(frame_buf_data, fb_width, fb_height, - x, y, width - 5, 5, + x, y, width - border_width, border_width, border_dark_color, border_light_color, border_thickness); rgui_fill_rect(frame_buf_data, fb_width, fb_height, - x + width - 5, y, 5, height - 5, + x + width - border_width, y, border_width, height - border_width, border_dark_color, border_light_color, border_thickness); rgui_fill_rect(frame_buf_data, fb_width, fb_height, - x + 5, y + height - 5, width - 5, 5, + x + border_width, y + height - border_width, width - border_width, border_width, border_dark_color, border_light_color, border_thickness); rgui_fill_rect(frame_buf_data, fb_width, fb_height, - x, y + 5, 5, height - 5, + x, y + border_width, border_width, height - border_width, border_dark_color, border_light_color, border_thickness); /* Draw text */ @@ -4978,12 +5031,7 @@ static void rgui_render(void *data, unsigned width, unsigned height, bool menu_rgui_particle_effect_screensaver = settings->bools.menu_rgui_particle_effect_screensaver; bool current_display_cb = false; - - bool show_fs_thumbnail = - (rgui->flags & RGUI_FLAG_SHOW_FULLSCREEN_THUMBNAIL) - && ( (rgui->flags & RGUI_FLAG_ENTRY_HAS_THUMBNAIL) - || !string_is_empty(rgui->savestate_thumbnail_file_path)) - && (rgui->fs_thumbnail.is_valid || (rgui->thumbnail_queue_size > 0)); + bool show_fs_thumbnail = (rgui->flags & RGUI_FLAG_SHOW_FULLSCREEN_THUMBNAIL); /* Sanity check */ if (!rgui || !rgui->frame_buf.data) @@ -5191,25 +5239,12 @@ static void rgui_render(void *data, unsigned width, unsigned height, /* State slot title */ if (is_state_slot) { - size_t _len = strlcpy(thumbnail_title_buf, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - sizeof(thumbnail_title_buf)); - if (rgui->flags & RGUI_FLAG_IS_QUICK_MENU) - { - snprintf(thumbnail_title_buf + _len, - sizeof(thumbnail_title_buf) - _len, - " %d", - config_get_ptr()->ints.state_slot); - thumbnail_title = thumbnail_title_buf; - } - else if (rgui->flags & RGUI_FLAG_IS_STATE_SLOT) - { - snprintf(thumbnail_title_buf + _len, - sizeof(thumbnail_title_buf) - _len, - " %d", - (int)menu_st->selection_ptr - 1); - thumbnail_title = thumbnail_title_buf; - } + menu_update_fullscreen_thumbnail_label( + thumbnail_title_buf, + sizeof(thumbnail_title_buf), + (rgui->flags & RGUI_FLAG_IS_QUICK_MENU) ? true : false, + NULL); + thumbnail_title = thumbnail_title_buf; } /* Format thumbnail title */ @@ -5247,7 +5282,7 @@ static void rgui_render(void *data, unsigned width, unsigned height, /* Draw thumbnail title background */ rgui_fill_rect(rgui->frame_buf.data, fb_width, fb_height, title_x - 5, 0, title_width + 10, rgui->font_height_stride - 1, - rgui->colors.bg_dark_color, rgui->colors.bg_light_color, + rgui->colors.shadow_color, rgui->colors.shadow_color, (rgui->flags & RGUI_FLAG_BG_THICKNESS) ? true : false); /* Draw thumbnail title */ @@ -5503,7 +5538,7 @@ static void rgui_render(void *data, unsigned width, unsigned height, thumbnail_width = thumbnail_panel_width; } - entry_title_max_len -= (thumbnail_width / rgui->font_width_stride) + 1; + entry_title_max_len -= (thumbnail_width / rgui->font_width_stride); } /* Get 'type' of entry value component */ @@ -5797,6 +5832,13 @@ static void rgui_render(void *data, unsigned width, unsigned height, if (!string_is_empty(rgui->msgbox)) { + /* Draw background */ + rgui_fill_rect(rgui->frame_buf.data, fb_width, fb_height, + 0, 0, fb_width, fb_height, + rgui->colors.bg_dark_color, + rgui->colors.bg_dark_color, + (rgui->flags & RGUI_FLAG_BG_THICKNESS) ? true : false); + rgui_render_messagebox(rgui, rgui->msgbox, fb_width, fb_height); rgui->msgbox[0] = '\0'; rgui->flags |= RGUI_FLAG_FORCE_REDRAW; @@ -6754,6 +6796,7 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, struct menu_state *menu_s bool thumbnails_missing = false; /* Right (or fullscreen) thumbnail */ + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_THUMBNAIL; if (!string_is_empty(menu_st->thumbnail_path_data->right_path)) { if (rgui_request_thumbnail( @@ -6765,8 +6808,6 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, struct menu_state *menu_s menu_st->thumbnail_path_data->right_path, &thumbnails_missing)) rgui->flags |= RGUI_FLAG_ENTRY_HAS_THUMBNAIL; - else - rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_THUMBNAIL; } /* Left thumbnail @@ -6775,6 +6816,7 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, struct menu_state *menu_s if ( !(rgui->flags & RGUI_FLAG_SHOW_FULLSCREEN_THUMBNAIL) && string_is_empty(rgui->savestate_thumbnail_file_path)) { + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; if (!string_is_empty(menu_st->thumbnail_path_data->left_path)) { if (rgui_request_thumbnail( @@ -6784,12 +6826,11 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, struct menu_state *menu_s menu_st->thumbnail_path_data->left_path, &thumbnails_missing)) rgui->flags |= RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; - else - rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; } } else if (!string_is_empty(rgui->savestate_thumbnail_file_path)) { + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; if (!string_is_empty(menu_st->thumbnail_path_data->left_path)) { if (rgui_request_thumbnail( @@ -6799,8 +6840,6 @@ static void rgui_load_current_thumbnails(rgui_t *rgui, struct menu_state *menu_s rgui->savestate_thumbnail_file_path, &thumbnails_missing)) rgui->flags |= RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; - else - rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; } } @@ -6900,10 +6939,9 @@ static void rgui_update_savestate_thumbnail_path(void *data, unsigned i) strlcpy(path + _len, FILE_PATH_PNG_EXTENSION, sizeof(path) - _len); - if (path_is_valid(path)) - strlcpy(rgui->savestate_thumbnail_file_path, - path, - sizeof(rgui->savestate_thumbnail_file_path)); + strlcpy(rgui->savestate_thumbnail_file_path, + path, + sizeof(rgui->savestate_thumbnail_file_path)); } } } @@ -6920,6 +6958,14 @@ static void rgui_reset_savestate_thumbnail(void *data) rgui->mini_left_thumbnail.height = 0; rgui->mini_left_thumbnail.is_valid = false; rgui->mini_left_thumbnail.path[0] = '\0'; + + rgui->fs_thumbnail.width = 0; + rgui->fs_thumbnail.height = 0; + rgui->fs_thumbnail.is_valid = false; + rgui->fs_thumbnail.path[0] = '\0'; + + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_THUMBNAIL; + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; } static void rgui_update_savestate_thumbnail_image(void *data) @@ -6929,11 +6975,14 @@ static void rgui_update_savestate_thumbnail_image(void *data) return; /* If path is empty, just reset thumbnail */ - if (string_is_empty(rgui->savestate_thumbnail_file_path)) + if ( string_is_empty(rgui->savestate_thumbnail_file_path) + || !path_is_valid(rgui->savestate_thumbnail_file_path)) rgui_reset_savestate_thumbnail(rgui); else { bool thumbnails_missing = false; + rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; + if (rgui_request_thumbnail( &rgui->mini_left_thumbnail, GFX_THUMBNAIL_LEFT, @@ -6941,8 +6990,6 @@ static void rgui_update_savestate_thumbnail_image(void *data) rgui->savestate_thumbnail_file_path, &thumbnails_missing)) rgui->flags |= RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; - else - rgui->flags &= ~RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL; } } @@ -8052,10 +8099,6 @@ static enum menu_action rgui_parse_menu_entry_action( new_action = MENU_ACTION_NOOP; - if ( (!(rgui->flags & RGUI_FLAG_ENTRY_HAS_THUMBNAIL)) - && (!(rgui->flags & RGUI_FLAG_ENTRY_HAS_LEFT_THUMBNAIL))) - break; - if ( (!(rgui->flags & RGUI_FLAG_SHOW_FULLSCREEN_THUMBNAIL)) && rgui->gfx_thumbnails_prev < 0) rgui->gfx_thumbnails_prev = settings->uints.gfx_thumbnails; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 27bfb60b4712..79ab37df2400 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -72,8 +72,6 @@ #define XMB_DELAY 166.66667f -#define XMB_THUMBNAIL_STREAM_DELAY 16.66667f * 5 - #define XMB_EASING_ALPHA EASING_OUT_CIRC #define XMB_EASING_XY EASING_OUT_QUAD @@ -441,6 +439,9 @@ typedef struct xmb_handle char prev_savestate_thumbnail_file_path[PATH_MAX_LENGTH * 2]; char fullscreen_thumbnail_label[NAME_MAX_LENGTH]; + char thumbnails_left_status_prev; + char thumbnails_right_status_prev; + bool allow_horizontal_animation; bool allow_dynamic_wallpaper; bool fullscreen_thumbnails_available; @@ -1283,31 +1284,29 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) if (state_slot < 0) { - path[0] = '\0'; - _len = fill_pathname_join_delim(path, + path[0] = '\0'; + _len = fill_pathname_join_delim(path, runloop_st->name.savestate, "auto", '.', sizeof(path)); } else { - _len = strlcpy(path, runloop_st->name.savestate, sizeof(path)); + _len = strlcpy(path, runloop_st->name.savestate, sizeof(path)); if (state_slot > 0) _len += snprintf(path + _len, sizeof(path) - _len, "%d", state_slot); } strlcpy(path + _len, FILE_PATH_PNG_EXTENSION, sizeof(path) - _len); - if (path_is_valid(path)) - { - strlcpy(xmb->savestate_thumbnail_file_path, path, - sizeof(xmb->savestate_thumbnail_file_path)); - - xmb->fullscreen_thumbnails_available = true; - menu_update_fullscreen_thumbnail_label( - xmb->fullscreen_thumbnail_label, - sizeof(xmb->fullscreen_thumbnail_label), - xmb->is_quick_menu, - NULL); - } + strlcpy(xmb->savestate_thumbnail_file_path, path, + sizeof(xmb->savestate_thumbnail_file_path)); + + xmb->fullscreen_thumbnails_available = true; + + menu_update_fullscreen_thumbnail_label( + xmb->fullscreen_thumbnail_label, + sizeof(xmb->fullscreen_thumbnail_label), + xmb->is_quick_menu, + NULL); } } } @@ -1355,6 +1354,13 @@ static void xmb_update_thumbnail_image(void *data) (xmb->thumbnails.pending == XMB_PENDING_THUMBNAIL_RIGHT) ? XMB_PENDING_THUMBNAIL_BOTH : XMB_PENDING_THUMBNAIL_LEFT; } + + if (xmb->want_fullscreen_thumbnails) + menu_update_fullscreen_thumbnail_label( + xmb->fullscreen_thumbnail_label, + sizeof(xmb->fullscreen_thumbnail_label), + xmb->is_quick_menu ? true : false, + xmb->title_name); } static unsigned xmb_get_system_tab(xmb_handle_t *xmb, unsigned i) @@ -1517,8 +1523,10 @@ static void xmb_set_thumbnail_content(void *data, const char *s) MENU_ENTRY_INITIALIZE(entry); entry.flags |= MENU_ENTRY_FLAG_PATH_ENABLED; menu_entry_get(&entry, 0, selection, NULL, true); + if ( !string_is_empty(entry.path) - && !string_is_empty(node->fullpath)) + && !string_is_empty(node->fullpath) + && entry.type == FILE_TYPE_IMAGEVIEWER) { gfx_thumbnail_set_content_image(menu_st->thumbnail_path_data, node->fullpath, entry.path); @@ -1858,13 +1866,11 @@ static void xmb_selection_pointer_changed( else if (xmb->is_file_list) { menu_entry_t entry; - unsigned entry_type; MENU_ENTRY_INITIALIZE(entry); menu_entry_get(&entry, 0, selection, NULL, true); - entry_type = entry.type; - if ( (entry_type == FILE_TYPE_IMAGEVIEWER) - || (entry_type == FILE_TYPE_IMAGE)) + if ( (entry.type == FILE_TYPE_IMAGEVIEWER) + || (entry.type == FILE_TYPE_IMAGE)) { xmb_set_thumbnail_content(xmb, "imageviewer"); update_thumbnails = true; @@ -1885,12 +1891,15 @@ static void xmb_selection_pointer_changed( } } - if (update_thumbnails) + if (update_thumbnails && end > 1) xmb_update_thumbnail_image(xmb); } - xmb_update_savestate_thumbnail_path(xmb, i); - xmb_update_savestate_thumbnail_image(xmb); + if (end > 1) + { + xmb_update_savestate_thumbnail_path(xmb, i); + xmb_update_savestate_thumbnail_image(xmb); + } } if ( !allow_animations @@ -3187,6 +3196,10 @@ static void xmb_populate_entries(void *data, (unsigned long)list_size); } + /* Cache previous state to prevent thumbnail flashing */ + xmb->thumbnails_left_status_prev = xmb->thumbnails.left.status; + xmb->thumbnails_right_status_prev = xmb->thumbnails.right.status; + /* By default, fullscreen thumbnails are only * enabled on playlists, database manager * lists and file lists, in cases where ordinary @@ -5387,6 +5400,20 @@ static INLINE float xmb_get_scale_factor(float menu_scale_factor, return scale_factor; } +static void xmb_set_thumbnail_delay(bool on) +{ + if (on) + { + gfx_thumbnail_set_stream_delay(-1.0f); + gfx_thumbnail_set_fade_duration(-1.0f); + } + else + { + gfx_thumbnail_set_stream_delay(0); + gfx_thumbnail_set_fade_duration(1); + } +} + /* Disables the fullscreen thumbnail view, with * an optional fade out animation */ static void xmb_hide_fullscreen_thumbnails( @@ -5419,7 +5446,9 @@ static void xmb_hide_fullscreen_thumbnails( xmb->fullscreen_thumbnail_alpha = 0.0f; /* Disable fullscreen thumbnails */ - xmb->show_fullscreen_thumbnails = false; + xmb->show_fullscreen_thumbnails = false; + xmb->want_fullscreen_thumbnails = false; + xmb_set_thumbnail_delay(true); } /* Enables (and triggers a fade in of) the fullscreen @@ -5432,49 +5461,6 @@ static void xmb_show_fullscreen_thumbnails( bool animate = !xmb->want_fullscreen_thumbnails; uintptr_t alpha_tag = (uintptr_t)&xmb->fullscreen_thumbnail_alpha; - /* We can only enable fullscreen thumbnails if - * current selection has at least one valid thumbnail - * and all thumbnails for current selection are already - * loaded/available */ - if ( (!string_is_empty(menu_st->thumbnail_path_data->content_core_name) - && string_is_equal(menu_st->thumbnail_path_data->content_core_name, - "imageviewer")) - || !string_is_empty(xmb->savestate_thumbnail_file_path)) - { - /* imageviewer content requires special treatment, - * since only one thumbnail can ever be loaded - * at a time */ - if (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT)) - { - if ( xmb->thumbnails.right.status != GFX_THUMBNAIL_STATUS_AVAILABLE - && xmb->thumbnails.savestate.status != GFX_THUMBNAIL_STATUS_AVAILABLE) - return; - } - else if (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) - { - if (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_AVAILABLE) - return; - } - else - return; - } - else - { - bool left_thumbnail_enabled = gfx_thumbnail_is_enabled( - menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT); - - if ( (xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE) - && ( left_thumbnail_enabled - && ( (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_MISSING) - && (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_AVAILABLE)))) - return; - - if ( (xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_MISSING) - && ( !left_thumbnail_enabled - || (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_AVAILABLE))) - return; - } - /* Cache selected entry label * (used as title when fullscreen thumbnails * are shown) */ @@ -5504,6 +5490,8 @@ static void xmb_show_fullscreen_thumbnails( /* Enable fullscreen thumbnails */ xmb->fullscreen_thumbnail_selection = selection; xmb->show_fullscreen_thumbnails = true; + xmb->want_fullscreen_thumbnails = true; + xmb_set_thumbnail_delay(false); } static bool INLINE xmb_fullscreen_thumbnails_available(xmb_handle_t *xmb, @@ -5511,32 +5499,14 @@ static bool INLINE xmb_fullscreen_thumbnails_available(xmb_handle_t *xmb, { bool ret = xmb->fullscreen_thumbnails_available && ( gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) - || gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) - && ( xmb->thumbnails.left.status == GFX_THUMBNAIL_STATUS_AVAILABLE - || xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE); + || gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)); - if ( xmb->is_state_slot - && ( xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_MISSING - || xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_UNKNOWN)) - ret = false; + if (xmb->is_state_slot) + ret = true; return ret; } -static void xmb_set_thumbnail_delay(bool on) -{ - if (on) - { - gfx_thumbnail_set_stream_delay(XMB_THUMBNAIL_STREAM_DELAY); - gfx_thumbnail_set_fade_duration(-1.0f); - } - else - { - gfx_thumbnail_set_stream_delay(0); - gfx_thumbnail_set_fade_duration(1); - } -} - static enum menu_action xmb_parse_menu_entry_action( xmb_handle_t *xmb, enum menu_action action) { @@ -5605,16 +5575,12 @@ static enum menu_action xmb_parse_menu_entry_action( { xmb_hide_fullscreen_thumbnails(xmb, false); xmb_show_fullscreen_thumbnails(xmb, menu_st, menu_st->selection_ptr); - xmb->want_fullscreen_thumbnails = true; - xmb_set_thumbnail_delay(false); new_action = MENU_ACTION_NOOP; } else if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) { - xmb_set_thumbnail_delay(true); xmb_hide_fullscreen_thumbnails(xmb, true); - xmb->want_fullscreen_thumbnails = false; } break; case MENU_ACTION_SCAN: @@ -5670,21 +5636,18 @@ static enum menu_action xmb_parse_menu_entry_action( break; } - if ( xmb->fullscreen_thumbnails_available - && !xmb->show_fullscreen_thumbnails + if ( !xmb->show_fullscreen_thumbnails && ( (xmb->is_state_slot) || (xmb->is_quick_menu && !string_is_empty(xmb->savestate_thumbnail_file_path)))) { xmb_hide_fullscreen_thumbnails(xmb, false); xmb_show_fullscreen_thumbnails(xmb, menu_st, menu_st->selection_ptr); - xmb->want_fullscreen_thumbnails = true; new_action = MENU_ACTION_NOOP; } else if (xmb->show_fullscreen_thumbnails && (xmb->is_state_slot || (xmb->is_quick_menu && menu_is_running_quick_menu()))) { xmb_hide_fullscreen_thumbnails(xmb, true); - xmb->want_fullscreen_thumbnails = false; new_action = MENU_ACTION_NOOP; } break; @@ -5722,9 +5685,7 @@ static enum menu_action xmb_parse_menu_entry_action( if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) { - xmb_set_thumbnail_delay(true); xmb_hide_fullscreen_thumbnails(xmb, true); - xmb->want_fullscreen_thumbnails = false; if (!xmb->is_state_slot && !xmb->is_playlist && !xmb->is_explore_list) return MENU_ACTION_NOOP; } @@ -5735,9 +5696,8 @@ static enum menu_action xmb_parse_menu_entry_action( if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) { - xmb_set_thumbnail_delay(true); + xmb->skip_thumbnail_reset = false; xmb_hide_fullscreen_thumbnails(xmb, true); - xmb->want_fullscreen_thumbnails = false; return MENU_ACTION_NOOP; } @@ -5878,7 +5838,7 @@ static void xmb_layout_ps3(xmb_handle_t *xmb, int width) xmb->cursor_size = 64.0f * scale_factor; xmb->icon_size = 128.0f * scale_factor; - xmb->icon_spacing_horizontal = 200.0f * scale_factor; + xmb->icon_spacing_horizontal = 192.0f * scale_factor; xmb->icon_spacing_vertical = 64.0f * scale_factor; xmb->margins_screen_top = (256 + 16) * scale_factor; @@ -6886,6 +6846,11 @@ static void xmb_render(void *data, default: break; } + + if (xmb->thumbnails.left.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + xmb->thumbnails_left_status_prev = xmb->thumbnails.left.status; + if (xmb->thumbnails.right.status != GFX_THUMBNAIL_STATUS_UNKNOWN) + xmb->thumbnails_right_status_prev = xmb->thumbnails.right.status; } i = menu_st->entries.begin; @@ -7045,6 +7010,69 @@ static void xmb_draw_dark_layer( dispctx->blend_end(userdata); } +static void xmb_draw_no_thumbnail_available( + xmb_handle_t *xmb, + gfx_display_t *p_disp, + void *userdata, + unsigned video_width, + unsigned video_height, + unsigned x_position, + unsigned y_position, + unsigned view_width, + unsigned view_height, + bool shadows_enable, + bool draw_text, + math_matrix_4x4 *mymat) +{ + gfx_display_ctx_driver_t *dispctx = p_disp->dispctx; + unsigned icon_size = (unsigned)xmb->icon_size; + + if (draw_text) + y_position += (icon_size / 5.0f); + + if (dispctx) + { + gfx_display_set_alpha(xmb_item_color, xmb->alpha * 0.20f); + + if (dispctx->blend_begin) + dispctx->blend_begin(userdata); + if (dispctx->draw) + xmb_draw_icon( + userdata, + p_disp, + dispctx, + video_width, + video_height, + false, + icon_size, + icon_size, + xmb->textures.list[XMB_TEXTURE_IMAGE], + x_position + ((view_width - icon_size) / 2), + video_height - y_position - ((view_height - icon_size) / 2), + video_width, + video_height, + xmb->alpha, + 0.0f, + xmb->last_scale_factor, + &xmb_item_color[0], + xmb->shadow_offset / 2, + mymat); + if (dispctx->blend_end) + dispctx->blend_end(userdata); + } + + if (!draw_text) + return; + + xmb_draw_text(shadows_enable, xmb, config_get_ptr(), + msg_hash_to_str(MSG_NO_THUMBNAIL_AVAILABLE), + x_position + (view_width / 2), + video_height - y_position - ((view_height - icon_size * 1.50f) / 2), + 1, 1, TEXT_ALIGN_CENTER, + video_width, video_height, + xmb->font2); +} + static void xmb_draw_fullscreen_thumbnails( xmb_handle_t *xmb, gfx_animation_t *p_anim, @@ -7072,12 +7100,12 @@ static void xmb_draw_fullscreen_thumbnails( int left_thumbnail_x; int thumbnail_y; gfx_thumbnail_shadow_t thumbnail_shadow; - gfx_thumbnail_t *right_thumbnail = NULL; - gfx_thumbnail_t *left_thumbnail = NULL; + gfx_thumbnail_t *right_thumbnail = &xmb->thumbnails.left; + gfx_thumbnail_t *left_thumbnail = &xmb->thumbnails.right; int view_width = (int)video_width; int view_height = (int)video_height; - int thumbnail_margin = (int)(xmb->icon_size / 2.0f); - int frame_width = (int)xmb->shadow_offset; + int thumbnail_margin = (int)xmb->icon_size / 2; + int frame_width = (int)xmb->shadow_offset * 2; uint32_t title_color = 0xFFFFFF00; uint8_t num_thumbnails = 0; float right_thumbnail_draw_width = 0.0f; @@ -7086,26 +7114,26 @@ static void xmb_draw_fullscreen_thumbnails( float left_thumbnail_draw_height = 0.0f; /* XMB doesn't have a proper theme interface, so * hard-code this alpha value for now... */ - float background_alpha = 0.95f; + float background_alpha = 0.75f; float background_color[16] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; - float header_alpha = 0.6f; + float header_alpha = 1.0f; float header_color[16] = { - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - }; - float frame_color[16] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; + float frame_color[16] = { + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + 0.05f, 0.05f, 0.05f, 1.0f, + }; bool menu_ticker_smooth = settings->bools.menu_ticker_smooth; enum gfx_animation_ticker_type menu_ticker_type = (enum gfx_animation_ticker_type)settings->uints.menu_ticker_type; @@ -7113,32 +7141,14 @@ static void xmb_draw_fullscreen_thumbnails( bool show_right_thumbnail = false; bool show_left_thumbnail = false; - header_height = show_header ? (int)((float)xmb->font_size * 1.5f) + (frame_width * 2) : 0; + header_height = show_header ? (int)((float)xmb->font_size * 1.5f) + (frame_width * 4) : 0; - /* Sanity check: Return immediately if this is - * a menu without thumbnails and we are not currently - * 'fading out' the fullscreen thumbnail view */ - if ( !xmb->fullscreen_thumbnails_available - && xmb->show_fullscreen_thumbnails) - goto error; - - /* Safety check: ensure that current - * selection matches the entry selected when - * fullscreen thumbnails were enabled - * > Note that we exclude this check if we are - * currently viewing the quick menu and the - * thumbnail view is fading out. This enables - * a smooth transition if the user presses - * RetroPad A or keyboard 'return' to enter the - * quick menu while fullscreen thumbnails are - * being displayed */ - if ( (selection != xmb->fullscreen_thumbnail_selection) - && (!xmb->is_quick_menu || xmb->show_fullscreen_thumbnails)) + /* Sanity check: Return immediately if the view + * width/height is < 1 */ + if ((view_width < 1) || (view_height < 1)) goto error; /* Get thumbnail pointers */ - right_thumbnail = &xmb->thumbnails.left; - left_thumbnail = &xmb->thumbnails.right; /* Get number of 'active' thumbnails */ show_right_thumbnail = @@ -7162,16 +7172,6 @@ static void xmb_draw_fullscreen_thumbnails( if (show_left_thumbnail) num_thumbnails++; - /* Do nothing if both thumbnails are missing - * > Note: Baring inexplicable internal errors, this - * can never happen... - * > Return instead of error to keep fullscreen - * mode after menu/fullscreen toggle */ - if ( num_thumbnails < 1 - && ( right_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING - && left_thumbnail->status == GFX_THUMBNAIL_STATUS_MISSING)) - return; - /* Get base thumbnail dimensions + draw positions */ /* > Thumbnail bounding box height + y position @@ -7220,7 +7220,7 @@ static void xmb_draw_fullscreen_thumbnails( /* Sanity check */ if ( (right_thumbnail_draw_width <= 0.0f) || (right_thumbnail_draw_height <= 0.0f)) - goto error; + show_right_thumbnail = false; } else if (right_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) { @@ -7242,7 +7242,7 @@ static void xmb_draw_fullscreen_thumbnails( /* Sanity check */ if ( (left_thumbnail_draw_width <= 0.0f) || (left_thumbnail_draw_height <= 0.0f)) - goto error; + show_left_thumbnail = false; } else if (left_thumbnail->status == GFX_THUMBNAIL_STATUS_PENDING) { @@ -7308,7 +7308,7 @@ static void xmb_draw_fullscreen_thumbnails( 0, 0, (unsigned)view_width, - (unsigned)(header_height - frame_width), + (unsigned)header_height, (unsigned)view_width, (unsigned)view_height, header_color, @@ -7466,8 +7466,44 @@ static void xmb_draw_fullscreen_thumbnails( 1.0f, &thumbnail_shadow); } - } + /* Show "No thumbnail available" */ + if ( !show_right_thumbnail + && !show_left_thumbnail) + { + unsigned bg_w = video_width / 3.0f; + unsigned bg_h = video_height / 3.0f; + + /* Darken background */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + (video_width - bg_w) / 2.0f, + video_height - bg_h - (video_height - bg_h) / 2.0f, + bg_w, + bg_h, + video_width, + video_height, + background_color, + NULL); + + xmb_draw_no_thumbnail_available( + xmb, + p_disp, + userdata, + video_width, + video_height, + (video_width - bg_w) / 2.0f, + video_height - bg_h - (video_height - bg_h) / 2.0f, + bg_w, + bg_h, + shadows_enable, + true, + NULL); + } + } return; error: @@ -7500,8 +7536,6 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) float pseudo_font_length = 0.0f; xmb_handle_t *xmb = (xmb_handle_t*)data; settings_t *settings = config_get_ptr(); - bool fade_tab_icons = false; - float fade_tab_icons_x_threshold = 0.0f; bool menu_core_enable = settings->bools.menu_core_enable; float thumbnail_scale_factor = (float)settings->uints.menu_xmb_thumbnail_scale_factor / 100.0f; bool show_title_header = settings->bools.menu_xmb_show_title_header; @@ -7551,15 +7585,15 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) pseudo_font_length = xmb->icon_spacing_horizontal * 4 - xmb->icon_size / 4.0f; left_thumbnail_margin_width = xmb->icon_size * 3.4f; right_thumbnail_margin_width = - (float)video_width - (xmb->icon_size / 6) - + (float)video_width - (xmb->icon_size / 2.0f) - (xmb->margins_screen_left * xmb_scale_mod[5]) - xmb->icon_spacing_horizontal - pseudo_font_length; thumbnail_margin_height_under = ((float)video_height * under_thumb_margin) - xmb->margins_screen_top - xmb->icon_size; thumbnail_margin_height_full = (float)video_height - xmb->margins_title_top - ((xmb->icon_size / 4.0f) * 2.0f); - left_thumbnail_margin_x = xmb->icon_size / 6.0f; - right_thumbnail_margin_x = (float)video_width - (xmb->icon_size / 6.0f) + left_thumbnail_margin_x = xmb->icon_size / 4.0f; + right_thumbnail_margin_x = (float)video_width - (xmb->icon_size / 8.0f) - right_thumbnail_margin_width; xmb->margins_title = (float)settings->ints.menu_xmb_title_margin * 10.0f; xmb->margins_title_horizontal_offset = (float)settings->ints.menu_xmb_title_margin_horizontal_offset * 10.0f; @@ -7669,6 +7703,104 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) dispctx->blend_end(userdata); } + if (dispctx && dispctx->blend_begin) + dispctx->blend_begin(userdata); + + /* Horizontal tab icons */ + if (!xmb->assets_missing) + { + for (i = 0; i <= xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL) + xmb->system_tab_end; i++) + { + xmb_node_t *node = xmb_get_node(xmb, i); + + if (!node) + continue; + + gfx_display_set_alpha(xmb_item_color, MIN(node->alpha, xmb->alpha)); + + if (xmb_item_color[3] != 0) + { + math_matrix_4x4 mymat_tmp; + uintptr_t texture = node->icon; + float x = xmb->x + xmb->categories_x_pos + + xmb->margins_screen_left + + xmb->icon_spacing_horizontal * (i + 1) + - xmb->icon_size / 2.0; + float y = xmb->margins_screen_top + + xmb->icon_size / 2.0; + float scale_factor = node->zoom; + + if (!p_disp->dispctx->handles_transform) + { + float cosine = 1.0f; /* cos(rad) = cos(0) = 1.0f */ + float sine = 0.0f; /* sine(rad) = sine(0) = 0.0f */ + + gfx_display_rotate_z(p_disp, &mymat_tmp, cosine, sine, userdata); + + if (scale_factor != 1.0f) + { + math_matrix_4x4 matrix_scaled = { + { 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f } + }; + MAT_ELEM_4X4(matrix_scaled, 0, 0) = scale_factor; + MAT_ELEM_4X4(matrix_scaled, 1, 1) = scale_factor; + MAT_ELEM_4X4(matrix_scaled, 2, 2) = 1.0f; + matrix_4x4_multiply(mymat_tmp, matrix_scaled, mymat_tmp); + } + } + + xmb_draw_icon( + userdata, + p_disp, + dispctx, + video_width, + video_height, + shadows_enable, + xmb->icon_size, + xmb->icon_size, + texture, + x, + y, + video_width, + video_height, + 1.0, + 0, /* rotation */ + scale_factor, + &xmb_item_color[0], + xmb->shadow_offset, + &mymat_tmp); + } + } + } + + selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0); + + /* List icons */ + xmb_draw_items( + userdata, + p_disp, + dispctx, + p_anim, + menu_st, + settings, + video_width, + video_height, + shadows_enable, + xmb, + selection_buf, + selection, + xmb->categories_selection_ptr, + &xmb_item_color[0], + video_width, + video_height, + &mymat); + + if (dispctx && dispctx->blend_end) + dispctx->blend_end(userdata); + /**************************/ /* Draw thumbnails: START */ /**************************/ @@ -7687,22 +7819,17 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) /* Allow browsing playlist in fullscreen thumbnail mode */ if ( (xmb->is_playlist || xmb->is_explore_list || xmb->is_state_slot) && (xmb->show_fullscreen_thumbnails) - && (xmb->fullscreen_thumbnails_available) && (menu_st->selection_ptr != xmb->fullscreen_thumbnail_selection)) xmb_show_fullscreen_thumbnails(xmb, menu_st, menu_st->selection_ptr); else if (!xmb->show_fullscreen_thumbnails - && xmb->fullscreen_thumbnails_available && xmb->want_fullscreen_thumbnails) xmb_show_fullscreen_thumbnails(xmb, menu_st, menu_st->selection_ptr); - /* Note: This is incredibly ugly, but there are - * so many combinations here that we would go insane - * trying to rationalise this any further... */ - /* Save state thumbnail, right side in PS3 layout, left in PSP layout */ if ( (xmb->is_quick_menu || xmb->is_state_slot) - && ( (xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE) - || (xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_PENDING))) + && (!string_is_empty(xmb->savestate_thumbnail_file_path)) + && (!xmb->show_fullscreen_thumbnails) + ) { float thumb_width = right_thumbnail_margin_width; float thumb_height = thumb_width - (thumb_width / 4); @@ -7725,26 +7852,75 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) thumb_y = video_height - thumbnail_margin_height_under - (xmb->icon_size * 0.55f); } - gfx_thumbnail_draw( - userdata, - video_width, - video_height, - &xmb->thumbnails.savestate, - thumb_x, - thumb_y, - scaled_thumb_width > 0.0f ? (unsigned)scaled_thumb_width : 0, - scaled_thumb_height > 0.0f ? (unsigned)scaled_thumb_height : 0, - GFX_THUMBNAIL_ALIGN_CENTRE, - 1.0f, 1.0f, &thumbnail_shadow); + if ( (xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_AVAILABLE) + || (xmb->thumbnails.savestate.status == GFX_THUMBNAIL_STATUS_PENDING)) + { + gfx_thumbnail_draw( + userdata, + video_width, + video_height, + &xmb->thumbnails.savestate, + thumb_x, + thumb_y, + scaled_thumb_width > 0.0f ? (unsigned)scaled_thumb_width : 0, + scaled_thumb_height > 0.0f ? (unsigned)scaled_thumb_height : 0, + GFX_THUMBNAIL_ALIGN_CENTRE, + 1.0f, 1.0f, &thumbnail_shadow); + } + else + { + float background_color[16] = { + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + /* Darken background */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + thumb_x, + thumb_y, + scaled_thumb_width, + scaled_thumb_height, + video_width, + video_height, + background_color, + NULL); + + xmb_draw_no_thumbnail_available( + xmb, + p_disp, + userdata, + video_width, + video_height, + thumb_x, + thumb_y, + scaled_thumb_width, + scaled_thumb_height, + shadows_enable, + false, + NULL); + } } - else if (xmb->fullscreen_thumbnails_available) + else if (xmb->fullscreen_thumbnails_available && !xmb->show_fullscreen_thumbnails) { bool show_right_thumbnail = - (xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE) - || (xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_PENDING); + (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_RIGHT)) + && ( (xmb->thumbnails.right.status == GFX_THUMBNAIL_STATUS_AVAILABLE) + || ( xmb->thumbnails.right.status < GFX_THUMBNAIL_STATUS_AVAILABLE + && xmb->thumbnails_right_status_prev <= GFX_THUMBNAIL_STATUS_AVAILABLE + && xmb->thumbnails_right_status_prev != GFX_THUMBNAIL_STATUS_UNKNOWN)); + bool show_left_thumbnail = - (xmb->thumbnails.left.status == GFX_THUMBNAIL_STATUS_AVAILABLE) - || (xmb->thumbnails.left.status == GFX_THUMBNAIL_STATUS_PENDING); + (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) + && ( (xmb->thumbnails.left.status == GFX_THUMBNAIL_STATUS_AVAILABLE) + || ( xmb->thumbnails.left.status < GFX_THUMBNAIL_STATUS_AVAILABLE + && xmb->thumbnails_left_status_prev <= GFX_THUMBNAIL_STATUS_AVAILABLE + && xmb->thumbnails_left_status_prev != GFX_THUMBNAIL_STATUS_UNKNOWN)); /* Check if we are using the proper PS3 layout, * or the aborted PSP layout */ @@ -7770,6 +7946,42 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) float right_thumb_y = thumb_y_base + thumb_y_offset; float left_thumb_y = thumb_y_base + thumb_height + (xmb->icon_size / 8) + thumb_y_offset; + float background_color[16] = { + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + + /* Darken background */ + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + thumb_x, + right_thumb_y, + scaled_thumb_width, + scaled_thumb_height, + video_width, + video_height, + background_color, + NULL); + + gfx_display_draw_quad( + p_disp, + userdata, + video_width, + video_height, + thumb_x, + left_thumb_y, + scaled_thumb_width, + scaled_thumb_height, + video_width, + video_height, + background_color, + NULL); + gfx_thumbnail_draw( userdata, video_width, @@ -7793,11 +8005,6 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) (scaled_thumb_height > 0.0f) ? (unsigned)scaled_thumb_height : 0, GFX_THUMBNAIL_ALIGN_CENTRE, 1.0f, 1.0f, &thumbnail_shadow); - - /* Horizontal tab icons overlapping the top - * right image must be faded out */ - fade_tab_icons = true; - fade_tab_icons_x_threshold = thumb_x; } /* Right *or* left, right side */ else if (show_right_thumbnail || show_left_thumbnail) @@ -8032,126 +8239,6 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_width, video_height, xmb->font); } - if (dispctx && dispctx->blend_begin) - dispctx->blend_begin(userdata); - - /* Horizontal tab icons */ - if (!xmb->assets_missing) - { - for (i = 0; i <= xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL) + xmb->system_tab_end; i++) - { - xmb_node_t *node = xmb_get_node(xmb, i); - - if (!node) - continue; - - gfx_display_set_alpha(xmb_item_color, MIN(node->alpha, xmb->alpha)); - - if (xmb_item_color[3] != 0) - { - math_matrix_4x4 mymat_tmp; - uintptr_t texture = node->icon; - float x = xmb->x + xmb->categories_x_pos - + xmb->margins_screen_left - + xmb->icon_spacing_horizontal * (i + 1) - - xmb->icon_size / 2.0; - float y = xmb->margins_screen_top - + xmb->icon_size / 2.0; - float scale_factor = node->zoom; - - /* Check whether we need to fade out icons - * overlapping the top right thumbnail image */ - if (fade_tab_icons) - { - float x_threshold = fade_tab_icons_x_threshold - (xmb->icon_size * 1.5f); - - if (x > x_threshold) - { - float fade_alpha = xmb_item_color[3]; - float fade_offset = (x - x_threshold) * 2.0f; - - if (fade_offset > xmb->icon_size) - fade_offset = xmb->icon_size; - fade_alpha *= 1.0f - (fade_offset / xmb->icon_size); - - if (fade_alpha <= 0.0f) - continue; - - gfx_display_set_alpha(xmb_item_color, fade_alpha); - } - } - - if (!p_disp->dispctx->handles_transform) - { - float cosine = 1.0f; /* cos(rad) = cos(0) = 1.0f */ - float sine = 0.0f; /* sine(rad) = sine(0) = 0.0f */ - - gfx_display_rotate_z(p_disp, &mymat_tmp, cosine, sine, userdata); - - if (scale_factor != 1.0f) - { - math_matrix_4x4 matrix_scaled = { - { 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f } - }; - MAT_ELEM_4X4(matrix_scaled, 0, 0) = scale_factor; - MAT_ELEM_4X4(matrix_scaled, 1, 1) = scale_factor; - MAT_ELEM_4X4(matrix_scaled, 2, 2) = 1.0f; - matrix_4x4_multiply(mymat_tmp, matrix_scaled, mymat_tmp); - } - } - - xmb_draw_icon( - userdata, - p_disp, - dispctx, - video_width, - video_height, - shadows_enable, - xmb->icon_size, - xmb->icon_size, - texture, - x, - y, - video_width, - video_height, - 1.0, - 0, /* rotation */ - scale_factor, - &xmb_item_color[0], - xmb->shadow_offset, - &mymat_tmp); - } - } - } - - selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0); - - /* List icons */ - xmb_draw_items( - userdata, - p_disp, - dispctx, - p_anim, - menu_st, - settings, - video_width, - video_height, - shadows_enable, - xmb, - selection_buf, - selection, - xmb->categories_selection_ptr, - &xmb_item_color[0], - video_width, - video_height, - &mymat); - - if (dispctx && dispctx->blend_end) - dispctx->blend_end(userdata); - /* Use alternative title if available */ strlcpy(title_truncated, !string_is_empty(xmb->title_name_alt) @@ -8496,7 +8583,7 @@ static void *xmb_init(void **userdata, bool video_is_threaded) xmb->fullscreen_thumbnail_label[0] = '\0'; xmb->thumbnails.pending = XMB_PENDING_THUMBNAIL_NONE; - gfx_thumbnail_set_stream_delay(XMB_THUMBNAIL_STREAM_DELAY); + gfx_thumbnail_set_stream_delay(-1.0f); gfx_thumbnail_set_fade_duration(-1.0f); gfx_thumbnail_set_fade_missing(false); diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 652df3cd2d76..e4f7c6c05d92 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -7977,39 +7977,26 @@ size_t menu_update_fullscreen_thumbnail_label( /* > State slot label */ else if ( is_quick_menu && ( - string_is_equal(selected_entry.label, "state_slot") - || string_is_equal(selected_entry.label, "loadstate") - || string_is_equal(selected_entry.label, "savestate") + string_is_equal(selected_entry.label, msg_hash_to_str(MENU_ENUM_LABEL_STATE_SLOT)) + || string_is_equal(selected_entry.label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_STATE)) + || string_is_equal(selected_entry.label, msg_hash_to_str(MENU_ENUM_LABEL_SAVE_STATE)) ) ) { - size_t _len = strlcpy(s, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - len); - _len += snprintf(s + _len, len - _len, " %d", - config_get_ptr()->ints.state_slot); - return _len; - } - else if ( is_quick_menu - && ( - string_is_equal(selected_entry.label, "replay_slot") - || string_is_equal(selected_entry.label, "record_replay") - || string_is_equal(selected_entry.label, "play_replay") - || string_is_equal(selected_entry.label, "halt_replay") - )) - { - size_t _len = strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REPLAY_SLOT), + int slot = config_get_ptr()->ints.state_slot; + size_t _len = strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), len); - _len += snprintf(s + _len, len - _len, " %d", - config_get_ptr()->ints.replay_slot); + if (slot < 0) + _len += snprintf(s + _len, len - _len, " %s", "Auto"); + else + _len += snprintf(s + _len, len - _len, " %d", slot); return _len; } else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) { size_t _len = strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), len); - _len += snprintf(s + _len, len - _len, " %d", - string_to_unsigned(selected_entry.path)); + _len += snprintf(s + _len, len - _len, " %s", selected_entry.path); return _len; } /* > Quick Menu playlist label */ diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 84c3dd381126..5ce20052dae1 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -7231,33 +7231,11 @@ int menu_action_handle_setting(rarch_setting_t *setting, break; case MENU_ACTION_LEFT: if (setting->action_left) - { ret = setting->action_left(setting, selection, false); - if (menu_st->driver_ctx) - { - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image( - menu_st->userdata); - } - } break; case MENU_ACTION_RIGHT: if (setting->action_right) - { ret = setting->action_right(setting, selection, false); - if (menu_st->driver_ctx) - { - if (menu_st->driver_ctx->update_savestate_thumbnail_path) - menu_st->driver_ctx->update_savestate_thumbnail_path( - menu_st->userdata, (unsigned)selection); - if (menu_st->driver_ctx->update_savestate_thumbnail_image) - menu_st->driver_ctx->update_savestate_thumbnail_image( - menu_st->userdata); - } - } break; case MENU_ACTION_SELECT: if (setting->action_select)