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