From 5f7d14966c1ef667590d82f09e5bd96161ea8566 Mon Sep 17 00:00:00 2001 From: sonninnos <45124675+sonninnos@users.noreply.github.com> Date: Wed, 24 Aug 2022 13:35:54 +0300 Subject: [PATCH] (Ozone+XMB) Fullscreen thumbnail browsing (#14342) --- menu/drivers/ozone.c | 431 +++++++++++++++++++++++++++---------------- menu/drivers/xmb.c | 207 ++++++++++++--------- retroarch.c | 5 +- 3 files changed, 390 insertions(+), 253 deletions(-) diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index 89164971cc..e711e9b7df 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -456,6 +456,7 @@ struct ozone_handle size_t categories_selection_ptr; /* active tab id */ size_t categories_active_idx_old; size_t playlist_index; + size_t playlist_size; size_t playlist_collection_offset; size_t selection; /* currently selected entry */ @@ -616,6 +617,7 @@ struct ozone_handle bool pending_hide_thumbnail_bar; bool no_thumbnail_available; bool fullscreen_thumbnails_available; + bool want_fullscreen_thumbnails; bool show_fullscreen_thumbnails; bool selection_core_is_viewer; bool selection_core_is_viewer_real; @@ -3357,12 +3359,28 @@ console_iterate: video_width, video_height); } +static bool ozone_is_running_quick_menu(void) +{ + menu_entry_t entry; + + MENU_ENTRY_INIT(entry); + entry.path_enabled = false; + entry.value_enabled = false; + entry.sublabel_enabled = false; + menu_entry_get(&entry, 0, 0, NULL, true); + + return string_is_equal(entry.label, "resume_content") || + string_is_equal(entry.label, "state_slot"); +} + static void ozone_thumbnail_bar_hide_end(void *userdata) { ozone_handle_t *ozone = (ozone_handle_t*) userdata; ozone->show_thumbnail_bar = false; ozone->pending_hide_thumbnail_bar = false; - ozone->need_compute = true; + + if (!(ozone->is_quick_menu && ozone_is_running_quick_menu())) + ozone->need_compute = true; } static bool ozone_is_load_content_playlist(void *userdata) @@ -3382,18 +3400,60 @@ static bool ozone_is_load_content_playlist(void *userdata) return entry.type == FILE_TYPE_RPL_ENTRY; } -static bool ozone_is_running_quick_menu(void) +static void ozone_update_fullscreen_thumbnail_label(ozone_handle_t *ozone) { - menu_entry_t entry; + menu_entry_t selected_entry; + const char *thumbnail_label = NULL; - MENU_ENTRY_INIT(entry); - entry.path_enabled = false; - entry.value_enabled = false; - entry.sublabel_enabled = false; - menu_entry_get(&entry, 0, 0, NULL, true); + char tmpstr[64]; + tmpstr[0] = '\0'; - return string_is_equal(entry.label, "resume_content") || - string_is_equal(entry.label, "state_slot"); + /* > Get menu entry */ + MENU_ENTRY_INIT(selected_entry); + selected_entry.path_enabled = false; + selected_entry.value_enabled = false; + selected_entry.sublabel_enabled = false; + menu_entry_get(&selected_entry, 0, (size_t)ozone->selection, NULL, true); + + /* > Get entry label */ + if (!string_is_empty(selected_entry.rich_label)) + thumbnail_label = selected_entry.rich_label; + /* > State slot label */ + else if (ozone->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") + )) + { + snprintf(tmpstr, sizeof(tmpstr), "%s %d", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), + config_get_ptr()->ints.state_slot); + thumbnail_label = tmpstr; + } + else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) + { + snprintf(tmpstr, sizeof(tmpstr), "%s %d", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), + string_to_unsigned(selected_entry.path)); + thumbnail_label = tmpstr; + } + /* > Quick Menu playlist label */ + else if (ozone->is_quick_menu) + { + const struct playlist_entry *entry = NULL; + playlist_get_index(playlist_get_cached(), ozone->playlist_index, &entry); + if (entry) + thumbnail_label = entry->label; + } + else + thumbnail_label = selected_entry.path; + + /* > Sanity check */ + if (!string_is_empty(thumbnail_label)) + strlcpy( + ozone->fullscreen_thumbnail_label, + thumbnail_label, + sizeof(ozone->fullscreen_thumbnail_label)); } static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) @@ -3473,6 +3533,7 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) ozone->want_thumbnail_bar = true; ozone->fullscreen_thumbnails_available = true; + ozone_update_fullscreen_thumbnail_label(ozone); } else if (!ozone->is_state_slot) { @@ -3488,7 +3549,7 @@ static void ozone_update_savestate_thumbnail_path(void *data, unsigned i) ozone->fullscreen_thumbnails_available = false; } - if (ozone->show_thumbnail_bar != ozone->want_thumbnail_bar) + if (ozone->show_thumbnail_bar != ozone->want_thumbnail_bar && !ozone->pending_hide_thumbnail_bar) ozone->need_compute = true; } } @@ -3803,7 +3864,7 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) ozone->selection_core_is_viewer_real = ozone->selection_core_is_viewer; - if ((ozone->is_playlist && playlist) || + if ((playlist && (ozone->is_playlist || (ozone->is_quick_menu && !ozone_is_running_quick_menu()))) || (ozone->is_db_manager_list && ozone->depth == 4)) { const char *core_label = NULL; @@ -3812,23 +3873,36 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) file_list_t *list = menu_entries_get_selection_buf_ptr(0); size_t playlist_index = selection; + if (ozone->is_quick_menu) + { + bool content_runtime_log = settings->bools.content_runtime_log; + bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate; + playlist_index = ozone->playlist_index; + list_size = ozone->playlist_size; + + /* Fill play time if applicable */ + if (content_runtime_log || content_runtime_log_aggr) + playlist_get_index(playlist, playlist_index, &entry); + } /* Get playlist index corresponding * to the selected entry */ - if (list && + else if (list && (selection < list_size) && (list->list[selection].type == FILE_TYPE_RPL_ENTRY)) { bool content_runtime_log = settings->bools.content_runtime_log; bool content_runtime_log_aggr = settings->bools.content_runtime_log_aggregate; playlist_index = list->list[selection].entry_idx; + + /* Remember playlist index for Quick Menu fullscreen thumbnail title */ + ozone->playlist_index = playlist_index; + ozone->playlist_size = list_size; + /* Fill play time if applicable */ if (content_runtime_log || content_runtime_log_aggr) playlist_get_index(playlist, playlist_index, &entry); } - /* Remember playlist index for Quick Menu fullscreen thumbnail title */ - ozone->playlist_index = playlist_index; - /* Fill entry enumeration */ if (show_entry_idx) { @@ -3843,10 +3917,20 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) ozone->selection_entry_enumeration[0] = '\0'; /* Fill core name */ - if (!core_name || string_is_equal(core_name, "DETECT")) - core_label = msg_hash_to_str(MSG_AUTODETECT); + if (entry) + { + if (!entry->core_name || string_is_equal(entry->core_name, "DETECT")) + core_label = msg_hash_to_str(MSG_AUTODETECT); + else + core_label = entry->core_name; + } else - core_label = core_name; + { + if (!core_name || string_is_equal(core_name, "DETECT")) + core_label = msg_hash_to_str(MSG_AUTODETECT); + else + core_label = core_name; + } snprintf(ozone->selection_core_name, sizeof(ozone->selection_core_name), "%s %s", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_CORE), core_label); @@ -3874,7 +3958,7 @@ static void ozone_update_content_metadata(ozone_handle_t *ozone) if (entry) { - if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN) + if (entry->runtime_status == PLAYLIST_RUNTIME_UNKNOWN || ozone->is_quick_menu) runtime_update_playlist( playlist, playlist_index, directory_runtime_log, @@ -4913,7 +4997,13 @@ static void ozone_compute_entries_position( float scale_factor = ozone->last_scale_factor; if (ozone->show_thumbnail_bar != ozone->want_thumbnail_bar) - ozone_entries_update_thumbnail_bar(ozone, false, true); + { + if (!(ozone->pending_hide_thumbnail_bar && ozone->is_quick_menu)) + ozone_entries_update_thumbnail_bar(ozone, false, true); + } + + if (ozone->show_thumbnail_bar) + ozone_update_content_metadata(ozone); menu_entries_ctl(MENU_ENTRIES_CTL_START_GET, &i); @@ -6513,9 +6603,6 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) uintptr_t alpha_tag = (uintptr_t)&ozone->animations.fullscreen_thumbnail_alpha; uintptr_t scroll_tag = (uintptr_t)selection_buf; - char tmpstr[64]; - tmpstr[0] = '\0'; - /* Before showing fullscreen thumbnails, must * ensure that any existing fullscreen thumbnail * view is disabled... */ @@ -6538,10 +6625,6 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) * since only the right thumbnail is ever loaded */ if (!gfx_thumbnail_is_enabled(ozone->thumbnail_path_data, GFX_THUMBNAIL_RIGHT)) return; - - if (ozone->thumbnails.right.status != GFX_THUMBNAIL_STATUS_AVAILABLE && - ozone->thumbnails.savestate.status != GFX_THUMBNAIL_STATUS_AVAILABLE) - return; } else { @@ -6575,53 +6658,7 @@ static void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) * (used as title when fullscreen thumbnails * are shown) */ ozone->fullscreen_thumbnail_label[0] = '\0'; - - /* > Get menu entry */ - MENU_ENTRY_INIT(selected_entry); - selected_entry.path_enabled = false; - selected_entry.value_enabled = false; - selected_entry.sublabel_enabled = false; - menu_entry_get(&selected_entry, 0, (size_t)ozone->selection, NULL, true); - - /* > Get entry label */ - if (!string_is_empty(selected_entry.rich_label)) - thumbnail_label = selected_entry.rich_label; - /* > State slot label */ - else if (ozone->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") - )) - { - snprintf(tmpstr, sizeof(tmpstr), "%s %d", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - config_get_ptr()->ints.state_slot); - thumbnail_label = tmpstr; - } - else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) - { - snprintf(tmpstr, sizeof(tmpstr), "%s %d", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - string_to_unsigned(selected_entry.path)); - thumbnail_label = tmpstr; - } - /* > Quick Menu playlist label */ - else if (ozone->is_quick_menu) - { - const struct playlist_entry *entry = NULL; - playlist_get_index(playlist_get_cached(), ozone->playlist_index, &entry); - if (entry) - thumbnail_label = entry->label; - } - else - thumbnail_label = selected_entry.path; - - /* > Sanity check */ - if (!string_is_empty(thumbnail_label)) - strlcpy( - ozone->fullscreen_thumbnail_label, - thumbnail_label, - sizeof(ozone->fullscreen_thumbnail_label)); + ozone_update_fullscreen_thumbnail_label(ozone); /* Configure fade in animation */ animation_entry.easing_enum = EASING_OUT_QUAD; @@ -6650,7 +6687,7 @@ static void ozone_draw_fullscreen_thumbnails( unsigned video_height) { /* Check whether fullscreen thumbnails are visible */ - if (ozone->animations.fullscreen_thumbnail_alpha > 0.0f) + if (ozone->animations.fullscreen_thumbnail_alpha > 0.0f || ozone->want_fullscreen_thumbnails) { /* Note: right thumbnail is drawn at the top * in the sidebar, so it becomes the *left* @@ -6731,12 +6768,36 @@ static void ozone_draw_fullscreen_thumbnails( if (show_left_thumbnail) num_thumbnails++; + /* Prevent screen flashing when browsing in fullscreen thumbnail mode */ + if (ozone->is_playlist && num_thumbnails < 1 && ozone->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, + width, + (unsigned)view_height, + width, + 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) + 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 */ @@ -7323,41 +7384,6 @@ static enum menu_action ozone_parse_menu_entry_action( gfx_thumbnail_set_stream_delay(ozone->thumbnails.stream_delay); } - /* If fullscreen thumbnail view is active, any - * valid menu action will disable it... */ - if (ozone->show_fullscreen_thumbnails) - { - if (action != MENU_ACTION_NOOP && action != MENU_ACTION_TOGGLE) - { - ozone_hide_fullscreen_thumbnails(ozone, true); - - /* ...and any action other than Select/OK - * is ignored - * > We allow pass-through of Select/OK since - * users may want to run content directly - * after viewing fullscreen thumbnails, - * and having to press RetroPad A or the Return - * key twice is navigationally confusing - * > Note that we can only do this for non-pointer - * input - * > Note that we don't do this when viewing a - * file list, since there is no quick menu - * in this case - i.e. content loads directly, - * and a sudden transition from fullscreen - * thumbnail to content is jarring... - * > We also don't do this when viewing a database - * manager list, because the menu transition - * detection becomes too cumbersome... */ - if (ozone->is_file_list || - ozone->is_db_manager_list || - ozone->is_quick_menu || - ozone->is_state_slot || - ((action != MENU_ACTION_SELECT) && - (action != MENU_ACTION_OK))) - return MENU_ACTION_NOOP; - } - } - horizontal_list_size = (unsigned)ozone->horizontal_list.size; ozone->messagebox_state = menu_input_dialog_get_display_kb(); @@ -7384,9 +7410,17 @@ static enum menu_action ozone_parse_menu_entry_action( * is not in the sidebar, attempt to show * fullscreen thumbnail view */ if (ozone->fullscreen_thumbnails_available && - !ozone->cursor_in_sidebar) + !ozone->show_fullscreen_thumbnails && + !ozone->cursor_in_sidebar) { ozone_show_fullscreen_thumbnails(ozone); + ozone->want_fullscreen_thumbnails = true; + new_action = MENU_ACTION_NOOP; + } + else if (ozone->show_fullscreen_thumbnails || ozone->want_fullscreen_thumbnails) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + ozone->want_fullscreen_thumbnails = false; new_action = MENU_ACTION_NOOP; } break; @@ -7394,10 +7428,18 @@ static enum menu_action ozone_parse_menu_entry_action( ozone->cursor_mode = false; if (ozone->fullscreen_thumbnails_available && + !ozone->show_fullscreen_thumbnails && (ozone->is_state_slot || (ozone->is_quick_menu && !string_is_empty(ozone->savestate_thumbnail_file_path)))) { ozone_show_fullscreen_thumbnails(ozone); + ozone->want_fullscreen_thumbnails = true; + new_action = MENU_ACTION_NOOP; + } + else if (ozone->show_fullscreen_thumbnails && !ozone->is_playlist) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + ozone->want_fullscreen_thumbnails = false; new_action = MENU_ACTION_NOOP; } break; @@ -7425,6 +7467,9 @@ static enum menu_action ozone_parse_menu_entry_action( else if (!menu_navigation_wraparound_enable && selection == selection_total - 1) ozone_start_cursor_wiggle(ozone, MENU_ACTION_DOWN); + if (ozone->show_fullscreen_thumbnails && ozone->is_quick_menu) + return MENU_ACTION_NOOP; + /* If pointer is active and current selection * is off screen, auto select *centre* item */ if (ozone->cursor_mode) @@ -7453,6 +7498,9 @@ static enum menu_action ozone_parse_menu_entry_action( else if (!menu_navigation_wraparound_enable && selection == 0) ozone_start_cursor_wiggle(ozone, MENU_ACTION_UP); + if (ozone->show_fullscreen_thumbnails && ozone->is_quick_menu) + return MENU_ACTION_NOOP; + /* If pointer is active and current selection * is off screen, auto select *centre* item */ if (ozone->cursor_mode) @@ -7468,7 +7516,6 @@ static enum menu_action ozone_parse_menu_entry_action( { new_action = MENU_ACTION_ACCESSIBILITY_SPEAK_TITLE; ozone_start_cursor_wiggle(ozone, MENU_ACTION_LEFT); - break; } else if (ozone->depth > 1) @@ -7479,8 +7526,16 @@ static enum menu_action ozone_parse_menu_entry_action( if (!menu_navigation_wraparound_enable && selection == 0 && !is_current_entry_settings) ozone_start_cursor_wiggle(ozone, MENU_ACTION_DOWN); + if (ozone->show_fullscreen_thumbnails && (ozone->is_quick_menu && !ozone_is_running_quick_menu())) + return MENU_ACTION_NOOP; + break; } + else if (ozone->depth == 1 && ozone->show_fullscreen_thumbnails && ozone->is_playlist) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + ozone->want_fullscreen_thumbnails = false; + } ozone_go_to_sidebar(ozone, ozone_collapse_sidebar, tag); @@ -7501,6 +7556,10 @@ static enum menu_action ozone_parse_menu_entry_action( else if (!menu_navigation_wraparound_enable && selection == selection_total - 1 && !is_current_entry_settings) ozone_start_cursor_wiggle(ozone, MENU_ACTION_DOWN); + if (ozone->show_fullscreen_thumbnails && + (ozone->is_playlist || (ozone->is_quick_menu && !ozone_is_running_quick_menu()))) + return MENU_ACTION_NOOP; + break; } @@ -7521,12 +7580,23 @@ static enum menu_action ozone_parse_menu_entry_action( ozone->show_thumbnail_bar && ozone->fullscreen_thumbnails_available) { ozone_show_fullscreen_thumbnails(ozone); + ozone->want_fullscreen_thumbnails = true; new_action = MENU_ACTION_NOOP; break; } + if (ozone->show_fullscreen_thumbnails || ozone->want_fullscreen_thumbnails) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + ozone->want_fullscreen_thumbnails = false; + if (!ozone->is_state_slot && !ozone->is_playlist) + new_action = MENU_ACTION_NOOP; + break; + } + if (ozone->cursor_in_sidebar) { + ozone_refresh_sidebars(ozone, ozone_collapse_sidebar, ozone->last_height); if (!ozone->empty_playlist) ozone_leave_sidebar(ozone, ozone_collapse_sidebar, tag); new_action = MENU_ACTION_ACCESSIBILITY_SPEAK_LABEL; @@ -7555,6 +7625,14 @@ static enum menu_action ozone_parse_menu_entry_action( break; } + if (ozone->show_fullscreen_thumbnails || ozone->want_fullscreen_thumbnails) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + ozone->want_fullscreen_thumbnails = false; + new_action = MENU_ACTION_NOOP; + break; + } + if (menu_entries_get_stack_size(0) == 1) { ozone_go_to_sidebar(ozone, ozone_collapse_sidebar, tag); @@ -7572,6 +7650,9 @@ static enum menu_action ozone_parse_menu_entry_action( break; } + if (ozone->show_fullscreen_thumbnails && ozone->is_quick_menu) + return MENU_ACTION_NOOP; + /* If pointer is active and current selection * is off screen, auto select *last* item */ if (ozone->cursor_mode) @@ -7590,6 +7671,9 @@ static enum menu_action ozone_parse_menu_entry_action( break; } + if (ozone->show_fullscreen_thumbnails && ozone->is_quick_menu) + return MENU_ACTION_NOOP; + /* If pointer is active and current selection * is off screen, auto select *first* item */ if (ozone->cursor_mode) @@ -7991,6 +8075,10 @@ static void ozone_refresh_thumbnail_image(void *data, unsigned i) if (!ozone) return; + /* Refresh metadata */ + if (!i) + ozone_update_content_metadata(ozone); + /* Only refresh thumbnails if thumbnails are enabled * and we are currently viewing a playlist */ if ((gfx_thumbnail_is_enabled(ozone->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) || @@ -9289,6 +9377,7 @@ static void ozone_draw_header( float scale_factor = ozone->last_scale_factor; unsigned logo_icon_size = 60 * scale_factor; unsigned status_icon_size = 92 * scale_factor; + unsigned status_row_size = 160 * scale_factor; unsigned seperator_margin = 30 * scale_factor; enum gfx_animation_ticker_type menu_ticker_type = (enum gfx_animation_ticker_type)settings->uints.menu_ticker_type; @@ -9327,43 +9416,6 @@ static void ozone_draw_header( ozone->theme->header_footer_separator, NULL); - /* Title */ - if (use_smooth_ticker) - { - ticker_smooth.font = ozone->fonts.title.font; - ticker_smooth.selected = true; - ticker_smooth.field_width = (video_width - (128 + 47 + 180) * scale_factor); - ticker_smooth.src_str = ozone->show_fullscreen_thumbnails ? ozone->fullscreen_thumbnail_label : ozone->title; - ticker_smooth.dst_str = title; - ticker_smooth.dst_str_len = sizeof(title); - - gfx_animation_ticker_smooth(&ticker_smooth); - } - else - { - ticker.s = title; - ticker.len = (video_width - (128 + 47 + 180) * scale_factor) / ozone->fonts.title.glyph_width; - ticker.str = ozone->show_fullscreen_thumbnails ? ozone->fullscreen_thumbnail_label : ozone->title; - ticker.selected = true; - - gfx_animation_ticker(&ticker); - } - - gfx_display_draw_text( - ozone->fonts.title.font, - title, - ticker_x_offset + 128 * scale_factor, - ozone->dimensions.header_height / 2 - + ozone->fonts.title.line_centre_offset, - video_width, - video_height, - ozone->theme->text_rgba, - TEXT_ALIGN_LEFT, - 1.0f, - false, - 1.0f, - false); - /* Icon */ if (dispctx) { @@ -9427,12 +9479,13 @@ static void ozone_draw_header( if (powerstate.battery_enabled) { - timedate_offset = 95 * scale_factor; + timedate_offset = 90 * scale_factor; + status_row_size += timedate_offset; gfx_display_draw_text( ozone->fonts.time.font, msg, - video_width - 85 * scale_factor, + video_width - 55 * scale_factor, ozone->dimensions.header_height / 2 + ozone->fonts.time.line_centre_offset, video_width, @@ -9456,8 +9509,13 @@ static void ozone_draw_header( video_height, status_icon_size, status_icon_size, - ozone->icons_textures[powerstate.charging? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING : (powerstate.percent > 80)? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL : (powerstate.percent > 60)? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_80 : (powerstate.percent > 40)? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_60 : (powerstate.percent > 20)? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_40 : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_20], - video_width - (60 + 58) * scale_factor, + ozone->icons_textures[powerstate.charging ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_CHARGING + : (powerstate.percent > 80) ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_FULL + : (powerstate.percent > 60) ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_80 + : (powerstate.percent > 40) ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_60 + : (powerstate.percent > 20) ? OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_40 + : OZONE_ENTRIES_ICONS_TEXTURE_BATTERY_20], + video_width - (55 + 32) * scale_factor, 0, video_width, video_height, @@ -9489,8 +9547,8 @@ static void ozone_draw_header( gfx_display_draw_text( ozone->fonts.time.font, timedate, - video_width - (85 * scale_factor) - timedate_offset, - ozone->dimensions.header_height / 2 + video_width - (64 * scale_factor) - timedate_offset, + ozone->dimensions.header_height / 2 + ozone->fonts.time.line_centre_offset, video_width, video_height, @@ -9514,7 +9572,7 @@ static void ozone_draw_header( status_icon_size, status_icon_size, ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOCK], - video_width - (60 + 54) * scale_factor - timedate_offset, + video_width - (64 + 28) * scale_factor - timedate_offset, 0, video_width, video_height, @@ -9525,7 +9583,46 @@ static void ozone_draw_header( if (dispctx->blend_end) dispctx->blend_end(userdata); } + + status_row_size += 240 * scale_factor; } + + /* Title */ + if (use_smooth_ticker) + { + 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->show_fullscreen_thumbnails ? ozone->fullscreen_thumbnail_label : ozone->title; + ticker_smooth.dst_str = title; + ticker_smooth.dst_str_len = sizeof(title); + + gfx_animation_ticker_smooth(&ticker_smooth); + } + else + { + ticker.s = title; + ticker.len = video_width - status_row_size / ozone->fonts.title.glyph_width; + ticker.str = ozone->show_fullscreen_thumbnails ? ozone->fullscreen_thumbnail_label : ozone->title; + ticker.selected = true; + + gfx_animation_ticker(&ticker); + } + + gfx_display_draw_text( + ozone->fonts.title.font, + title, + ticker_x_offset + 128 * scale_factor, + ozone->dimensions.header_height / 2 + + ozone->fonts.title.line_centre_offset, + video_width, + video_height, + ozone->theme->text_rgba, + TEXT_ALIGN_LEFT, + 1.0f, + false, + 1.0f, + false); } static void ozone_draw_footer( @@ -9542,7 +9639,7 @@ static void ozone_draw_footer( bool menu_core_enable = settings->bools.menu_core_enable; float scale_factor = ozone->last_scale_factor; unsigned seperator_margin = 30 * scale_factor; - float footer_margin = 59 * scale_factor; + float footer_margin = 42 * scale_factor; float footer_text_y = (float)video_height - (ozone->dimensions.footer_height / 2.0f) + ozone->fonts.footer.line_centre_offset; @@ -9957,9 +10054,9 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) /* Update thumbnail */ if (gfx_thumbnail_is_enabled( - ozone->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) || + ozone->thumbnail_path_data, GFX_THUMBNAIL_RIGHT) || gfx_thumbnail_is_enabled( - ozone->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) + ozone->thumbnail_path_data, GFX_THUMBNAIL_LEFT)) { bool update_thumbnails = false; @@ -10116,6 +10213,18 @@ static void ozone_frame(void *data, video_frame_info_t *video_info) } } + if ((ozone->is_playlist || ozone->is_state_slot) && + ozone->show_fullscreen_thumbnails && (size_t)ozone->selection != ozone->fullscreen_thumbnail_selection) + { + ozone->need_compute = true; + ozone_show_fullscreen_thumbnails(ozone); + } + else if (!ozone->show_fullscreen_thumbnails && ozone->want_fullscreen_thumbnails) + { + ozone->need_compute = true; + ozone_show_fullscreen_thumbnails(ozone); + } + if (ozone->first_frame) { menu_input_get_pointer_state(&ozone->pointer); diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 10d4d43532..c3498a518e 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -412,6 +412,7 @@ typedef struct xmb_handle bool fullscreen_thumbnails_available; bool show_fullscreen_thumbnails; + bool want_fullscreen_thumbnails; bool skip_thumbnail_reset; bool show_mouse; bool show_screensaver; @@ -1160,6 +1161,62 @@ static bool xmb_is_running_quick_menu(void) string_is_equal(entry.label, "state_slot"); } +static void xmb_update_fullscreen_thumbnail_label(xmb_handle_t *xmb) +{ + menu_entry_t selected_entry; + const char *thumbnail_label = NULL; + + char tmpstr[64]; + tmpstr[0] = '\0'; + + /* > Get menu entry */ + MENU_ENTRY_INIT(selected_entry); + selected_entry.path_enabled = false; + selected_entry.value_enabled = false; + selected_entry.sublabel_enabled = false; + menu_entry_get(&selected_entry, 0, menu_navigation_get_selection(), NULL, true); + + /* > Get entry label */ + if (!string_is_empty(selected_entry.rich_label)) + thumbnail_label = selected_entry.rich_label; + /* > State slot label */ + else if (xmb->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") + )) + { + snprintf(tmpstr, sizeof(tmpstr), "%s %d", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), + config_get_ptr()->ints.state_slot); + thumbnail_label = tmpstr; + } + else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) + { + snprintf(tmpstr, sizeof(tmpstr), "%s %d", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), + string_to_unsigned(selected_entry.path)); + thumbnail_label = tmpstr; + } + /* > Quick Menu playlist label */ + else if (xmb->is_quick_menu) + { + const struct playlist_entry *entry = NULL; + playlist_get_index(playlist_get_cached(), xmb->playlist_index, &entry); + if (entry) + thumbnail_label = entry->label; + } + else + thumbnail_label = selected_entry.path; + + /* > Sanity check */ + if (!string_is_empty(thumbnail_label)) + strlcpy( + xmb->fullscreen_thumbnail_label, + thumbnail_label, + sizeof(xmb->fullscreen_thumbnail_label)); +} + static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) { settings_t *settings = config_get_ptr(); @@ -1236,6 +1293,7 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) sizeof(xmb->savestate_thumbnail_file_path)); xmb->fullscreen_thumbnails_available = true; + xmb_update_fullscreen_thumbnail_label(xmb); } } } @@ -4053,9 +4111,6 @@ static void xmb_show_fullscreen_thumbnails( uintptr_t alpha_tag = (uintptr_t) &xmb->fullscreen_thumbnail_alpha; - char tmpstr[64]; - tmpstr[0] = '\0'; - /* We can only enable fullscreen thumbnails if * current selection has at least one valid thumbnail * and all thumbnails for current selection are already @@ -4114,53 +4169,7 @@ static void xmb_show_fullscreen_thumbnails( * (used as title when fullscreen thumbnails * are shown) */ xmb->fullscreen_thumbnail_label[0] = '\0'; - - /* > Get menu entry */ - MENU_ENTRY_INIT(selected_entry); - selected_entry.path_enabled = false; - selected_entry.value_enabled = false; - selected_entry.sublabel_enabled = false; - menu_entry_get(&selected_entry, 0, selection, NULL, true); - - /* > Get entry label */ - if (!string_is_empty(selected_entry.rich_label)) - thumbnail_label = selected_entry.rich_label; - /* > State slot label */ - else if (xmb->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") - )) - { - snprintf(tmpstr, sizeof(tmpstr), "%s %d", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - config_get_ptr()->ints.state_slot); - thumbnail_label = tmpstr; - } - else if (string_to_unsigned(selected_entry.label) == MENU_ENUM_LABEL_STATE_SLOT) - { - snprintf(tmpstr, sizeof(tmpstr), "%s %d", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_STATE_SLOT), - string_to_unsigned(selected_entry.path)); - thumbnail_label = tmpstr; - } - /* > Quick Menu playlist label */ - else if (xmb->is_quick_menu) - { - const struct playlist_entry *entry = NULL; - playlist_get_index(playlist_get_cached(), xmb->playlist_index, &entry); - if (entry) - thumbnail_label = entry->label; - } - else - thumbnail_label = selected_entry.path; - - /* > Sanity check */ - if (!string_is_empty(thumbnail_label)) - strlcpy( - xmb->fullscreen_thumbnail_label, - thumbnail_label, - sizeof(xmb->fullscreen_thumbnail_label)); + xmb_update_fullscreen_thumbnail_label(xmb); /* Configure fade in animation */ animation_entry.easing_enum = EASING_OUT_QUAD; @@ -4184,42 +4193,14 @@ static enum menu_action xmb_parse_menu_entry_action( { enum menu_action new_action = action; - /* If fullscreen thumbnail view is active, any - * valid menu action will disable it... */ - if (xmb->show_fullscreen_thumbnails) - { - if (action != MENU_ACTION_NOOP && action != MENU_ACTION_TOGGLE) - { - xmb_hide_fullscreen_thumbnails(xmb, true); - - /* ...and any action other than Select/OK - * is ignored - * > We allow pass-through of Select/OK since - * users may want to run content directly - * after viewing fullscreen thumbnails, - * and having to press RetroPad A or the Return - * key twice is navigationally confusing - * > Note that we can only do this for non-pointer - * input - * > Note that we don't do this when viewing a - * file list, since there is no quick menu - * in this case - i.e. content loads directly, - * and a sudden transition from fullscreen - * thumbnail to content is jarring... */ - if (xmb->is_file_list || - xmb->is_quick_menu || - xmb->is_state_slot || - ((action != MENU_ACTION_SELECT) && - (action != MENU_ACTION_OK))) - return MENU_ACTION_NOOP; - } - } - /* Scan user inputs */ switch (action) { case MENU_ACTION_LEFT: case MENU_ACTION_RIGHT: + if (xmb->show_fullscreen_thumbnails && (xmb->is_quick_menu && !xmb_is_running_quick_menu())) + return MENU_ACTION_NOOP; + /* Check whether left/right action will * trigger a tab switch event */ if (xmb->depth == 1) @@ -4256,26 +4237,35 @@ static enum menu_action xmb_parse_menu_entry_action( /* If this is a menu with thumbnails, attempt * to show fullscreen thumbnail view */ - if (xmb->fullscreen_thumbnails_available) + if (xmb->fullscreen_thumbnails_available && + !xmb->show_fullscreen_thumbnails) { - size_t selection = menu_navigation_get_selection(); - - /* Before showing fullscreen thumbnails, must - * ensure that any existing fullscreen thumbnail - * view is disabled... */ xmb_hide_fullscreen_thumbnails(xmb, false); - if (xmb->fullscreen_thumbnails_available) - xmb_show_fullscreen_thumbnails(xmb, selection); + xmb_show_fullscreen_thumbnails(xmb, menu_navigation_get_selection()); + xmb->want_fullscreen_thumbnails = true; new_action = MENU_ACTION_NOOP; } + else if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) + { + xmb_hide_fullscreen_thumbnails(xmb, true); + xmb->want_fullscreen_thumbnails = false; + } break; case MENU_ACTION_SCAN: if (xmb->fullscreen_thumbnails_available && + !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_navigation_get_selection()); + xmb->want_fullscreen_thumbnails = true; + new_action = MENU_ACTION_NOOP; + } + else if (xmb->show_fullscreen_thumbnails && !xmb->is_playlist) + { + xmb_hide_fullscreen_thumbnails(xmb, true); + xmb->want_fullscreen_thumbnails = false; new_action = MENU_ACTION_NOOP; } break; @@ -4292,10 +4282,32 @@ static enum menu_action xmb_parse_menu_entry_action( xmb_show_fullscreen_thumbnails(xmb, menu_navigation_get_selection()); new_action = MENU_ACTION_NOOP; } + + if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) + { + xmb_hide_fullscreen_thumbnails(xmb, true); + xmb->want_fullscreen_thumbnails = false; + if (!xmb->is_state_slot && !xmb->is_playlist) + return MENU_ACTION_NOOP; + } break; case MENU_ACTION_CANCEL: if (xmb->is_state_slot) xmb->skip_thumbnail_reset = true; + + if (xmb->show_fullscreen_thumbnails || xmb->want_fullscreen_thumbnails) + { + xmb_hide_fullscreen_thumbnails(xmb, true); + xmb->want_fullscreen_thumbnails = false; + return MENU_ACTION_NOOP; + } + break; + case MENU_ACTION_UP: + case MENU_ACTION_DOWN: + case MENU_ACTION_SCROLL_UP: + case MENU_ACTION_SCROLL_DOWN: + if (xmb->show_fullscreen_thumbnails && xmb->is_quick_menu) + return MENU_ACTION_NOOP; break; default: /* In all other cases, pass through input @@ -4792,7 +4804,7 @@ static void xmb_draw_fullscreen_thumbnails( settings_t *settings, size_t selection) { /* Check whether fullscreen thumbnails are visible */ - if (xmb->fullscreen_thumbnail_alpha > 0.0f) + if (xmb->fullscreen_thumbnail_alpha > 0.0f || xmb->want_fullscreen_thumbnails) { int header_margin; int thumbnail_box_width; @@ -4902,7 +4914,9 @@ static void xmb_draw_fullscreen_thumbnails( * can never happen... * > Return instead of error to keep fullscreen * mode after menu/fullscreen toggle */ - if (num_thumbnails < 1) + 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 */ @@ -5387,6 +5401,17 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) xmb->fullscreen_thumbnails_available = true; } + /* Allow browsing playlist in fullscreen thumbnail mode */ + if ((xmb->is_playlist || xmb->is_state_slot) && + xmb->show_fullscreen_thumbnails && + xmb->fullscreen_thumbnails_available && + menu_navigation_get_selection() != xmb->fullscreen_thumbnail_selection) + xmb_show_fullscreen_thumbnails(xmb, menu_navigation_get_selection()); + else if (!xmb->show_fullscreen_thumbnails && + xmb->fullscreen_thumbnails_available && + xmb->want_fullscreen_thumbnails) + xmb_show_fullscreen_thumbnails(xmb, menu_navigation_get_selection()); + /* Note: This is incredibly ugly, but there are * so many combinations here that we would go insane * trying to rationalise this any further... */ diff --git a/retroarch.c b/retroarch.c index 19977d97d5..3964d8b03d 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2571,6 +2571,7 @@ bool command_event(enum event_command cmd, void *data) const char *core_path = "DETECT"; size_t *playlist_index = (size_t*)data; struct playlist_entry entry = {0}; + unsigned i = 0; /* the update function reads our entry as const, * so these casts are safe */ @@ -2580,9 +2581,11 @@ bool command_event(enum event_command cmd, void *data) command_playlist_update_write( NULL, *playlist_index, &entry); + /* Update playlist metadata */ + menu_driver_ctl(RARCH_MENU_CTL_REFRESH_THUMBNAIL_IMAGE, &i); + runloop_msg_queue_push(msg_hash_to_str(MSG_RESET_CORE_ASSOCIATION), 1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); break; - } case CMD_EVENT_RESTART_RETROARCH: if (!frontend_driver_set_fork(FRONTEND_FORK_RESTART))