diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index af8392fa9d..5d5680ebe5 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -174,6 +174,12 @@ static void *ozone_init(void **userdata, bool video_is_threaded) if (!ozone->thumbnail_path_data) goto error; + ozone->fullscreen_thumbnails_available = false; + ozone->show_fullscreen_thumbnails = false; + ozone->animations.fullscreen_thumbnail_alpha = 0.0f; + ozone->fullscreen_thumbnail_selection = 0; + ozone->fullscreen_thumbnail_label[0] = '\0'; + ozone_sidebar_update_collapse(ozone, false); ozone->system_tab_end = 0; @@ -500,6 +506,8 @@ static void ozone_context_reset(void *data, bool is_threaded) - ozone->dimensions.sidebar_entry_icon_padding; ozone->dimensions.cursor_size = CURSOR_SIZE * scale; + ozone->dimensions.fullscreen_thumbnail_padding = FULLSCREEN_THUMBNAIL_PADDING * scale; + /* Naive font size */ ozone->title_font_glyph_width = FONT_SIZE_TITLE * 3/4; ozone->entry_font_glyph_width = FONT_SIZE_ENTRIES_LABEL * 3/4; @@ -1036,7 +1044,7 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i ticker_smooth.font = ozone->fonts.title; ticker_smooth.selected = true; ticker_smooth.field_width = (video_info->width - 128 - 47 - 180); - ticker_smooth.src_str = ozone->title; + 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); @@ -1046,7 +1054,7 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i { ticker.s = title; ticker.len = (video_info->width - 128 - 47 - 180) / ozone->title_font_glyph_width; - ticker.str = ozone->title; + ticker.str = ozone->show_fullscreen_thumbnails ? ozone->fullscreen_thumbnail_label : ozone->title; ticker.selected = true; menu_animation_ticker(&ticker); @@ -1114,7 +1122,7 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i static void ozone_draw_footer(ozone_handle_t *ozone, video_frame_info_t *video_info, settings_t *settings) { /* Separator */ - menu_display_draw_quad(video_info, 23, video_info->height - ozone->dimensions.footer_height, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); + menu_display_draw_quad(video_info, 30, video_info->height - ozone->dimensions.footer_height, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator); /* Core title or Switch icon */ if (settings->bools.menu_core_enable) @@ -1194,15 +1202,23 @@ void ozone_update_content_metadata(ozone_handle_t *ozone) size_t selection = menu_navigation_get_selection(); playlist_t *playlist = playlist_get_cached(); settings_t *settings = config_get_ptr(); + const char *core_name = NULL; + + /* Must check whether core corresponds to 'viewer' + * content even when not using a playlist, otherwise + * file browser image updates are mishandled */ + if (menu_thumbnail_get_core_name(ozone->thumbnail_path_data, &core_name)) + ozone->selection_core_is_viewer = string_is_equal(core_name, "imageviewer") + || string_is_equal(core_name, "musicplayer") + || string_is_equal(core_name, "movieplayer"); + else + ozone->selection_core_is_viewer = false; if (ozone->is_playlist && playlist) { - const char *core_name = NULL; const char *core_label = NULL; bool scroll_content_metadata = settings->bools.ozone_scroll_content_metadata; - menu_thumbnail_get_core_name(ozone->thumbnail_path_data, &core_name); - /* Fill core name */ if (!core_name || string_is_equal(core_name, "DETECT")) core_label = msg_hash_to_str(MSG_AUTODETECT); @@ -1224,10 +1240,6 @@ void ozone_update_content_metadata(ozone_handle_t *ozone) else ozone->selection_core_name_lines = 1; - ozone->selection_core_is_viewer = string_is_equal(core_label, "imageviewer") - || string_is_equal(core_label, "musicplayer") - || string_is_equal(core_label, "movieplayer"); - /* Fill play time if applicable */ if (settings->bools.content_runtime_log || settings->bools.content_runtime_log_aggregate) { @@ -1403,17 +1415,31 @@ static void ozone_selection_changed(ozone_handle_t *ozone, bool allow_animation) update_thumbnails = true; } /* Database list updates - * (pointless nuisance...) */ + * (pointless nuisance...) */ else if (ozone->depth == 4 && ozone->is_db_manager_list) { ozone_set_thumbnail_content(ozone, ""); update_thumbnails = true; } /* Filebrowser image updates */ - else if (entry_type == FILE_TYPE_IMAGEVIEWER || entry_type == FILE_TYPE_IMAGE) + else if (ozone->is_file_list) { - ozone_set_thumbnail_content(ozone, "imageviewer"); - update_thumbnails = true; + if ((entry_type == FILE_TYPE_IMAGEVIEWER) || + (entry_type == FILE_TYPE_IMAGE)) + { + ozone_set_thumbnail_content(ozone, "imageviewer"); + update_thumbnails = true; + } + else + { + /* If this is a file list and current + * entry is not an image, have to 'reset' + * content + right/left thumbnails + * (otherwise last loaded thumbnail will + * persist, and be shown on the wrong entry) */ + menu_thumbnail_set_content(ozone->thumbnail_path_data, NULL); + ozone_unload_thumbnail_textures(ozone); + } } if (update_thumbnails) @@ -1593,6 +1619,9 @@ static void ozone_frame(void *data, video_frame_info_t *video_info) font_driver_bind_block(ozone->fonts.time, NULL); font_driver_bind_block(ozone->fonts.entries_label, NULL); + /* Draw fullscreen thumbnails, if required */ + ozone_draw_fullscreen_thumbnails(ozone, video_info); + /* Message box & OSK - second layer of text */ ozone->raster_blocks.footer.carr.coords.vertices = 0; ozone->raster_blocks.entries_label.carr.coords.vertices = 0; @@ -1779,6 +1808,8 @@ static void ozone_populate_entries(void *data, const char *path, const char *lab ozone->depth = new_depth; ozone->is_playlist = ozone_is_playlist(ozone, true); ozone->is_db_manager_list = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DATABASE_MANAGER_LIST)); + ozone->is_file_list = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_FAVORITES)); + ozone->is_quick_menu = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS)); if (ozone->categories_selection_ptr == ozone->categories_active_idx_old) { @@ -1786,135 +1817,38 @@ static void ozone_populate_entries(void *data, const char *path, const char *lab ozone_list_open(ozone); } - /* Thumbnails */ - ozone_unload_thumbnail_textures(ozone); - - if (menu_thumbnail_is_enabled(ozone->thumbnail_path_data, MENU_THUMBNAIL_RIGHT) || - menu_thumbnail_is_enabled(ozone->thumbnail_path_data, MENU_THUMBNAIL_LEFT)) + /* Thumbnails + * > Note: Leave current thumbnails loaded when + * opening the quick menu - allows proper fade + * out of the fullscreen thumbnail viewer */ + if (!ozone->is_quick_menu) { - if (ozone->is_playlist) + ozone_unload_thumbnail_textures(ozone); + + if (menu_thumbnail_is_enabled(ozone->thumbnail_path_data, MENU_THUMBNAIL_RIGHT) || + menu_thumbnail_is_enabled(ozone->thumbnail_path_data, MENU_THUMBNAIL_LEFT)) { - ozone_set_thumbnail_content(ozone, ""); - ozone_update_thumbnail_image(ozone); + /* Only auto-load thumbnails if we are viewing + * a playlist or a database manager list + * > Note that we can ignore file browser lists, + * since the first selected item on such a list + * can never have a thumbnail */ + if (ozone->is_playlist || + (ozone->depth == 4 && ozone->is_db_manager_list)) + { + ozone_set_thumbnail_content(ozone, ""); + ozone_update_thumbnail_image(ozone); + } } } -} -static int ozone_menu_iterate(void *data, - void *userdata, enum menu_action action) -{ - int new_selection; - enum menu_action new_action; - menu_animation_ctx_tag tag; - file_list_t *selection_buf = NULL; - ozone_handle_t *ozone = (ozone_handle_t*) userdata; - unsigned horizontal_list_size = 0; - menu_handle_t *menu = (menu_handle_t*)data; - - if (!ozone) - return generic_menu_iterate(menu, userdata, action); - - if (ozone->horizontal_list) - horizontal_list_size = (unsigned)ozone->horizontal_list->size; - - ozone->messagebox_state = false || menu_input_dialog_get_display_kb(); - - selection_buf = menu_entries_get_selection_buf_ptr(0); - tag = (uintptr_t)selection_buf; - new_action = action; - - /* Inputs override */ - switch (action) - { - case MENU_ACTION_DOWN: - ozone->cursor_mode = false; - if (!ozone->cursor_in_sidebar) - break; - - tag = (uintptr_t)ozone; - new_selection = (int)(ozone->categories_selection_ptr + 1); - - if (new_selection >= (int)(ozone->system_tab_end + horizontal_list_size + 1)) - new_selection = 0; - - ozone_sidebar_goto(ozone, new_selection); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_UP: - ozone->cursor_mode = false; - if (!ozone->cursor_in_sidebar) - break; - - tag = (uintptr_t)ozone; - new_selection = (int)ozone->categories_selection_ptr - 1; - - if (new_selection < 0) - new_selection = horizontal_list_size + ozone->system_tab_end; - - ozone_sidebar_goto(ozone, new_selection); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_LEFT: - ozone->cursor_mode = false; - if (ozone->cursor_in_sidebar) - { - new_action = MENU_ACTION_NOOP; - break; - } - else if (ozone->depth > 1) - break; - - ozone_go_to_sidebar(ozone, tag); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_RIGHT: - ozone->cursor_mode = false; - if (!ozone->cursor_in_sidebar) - { - if (ozone->depth == 1) - new_action = MENU_ACTION_NOOP; - break; - } - - ozone_leave_sidebar(ozone, tag); - - new_action = MENU_ACTION_NOOP; - break; - case MENU_ACTION_OK: - ozone->cursor_mode = false; - if (ozone->cursor_in_sidebar) - { - ozone_leave_sidebar(ozone, tag); - new_action = MENU_ACTION_NOOP; - break; - } - break; - case MENU_ACTION_CANCEL: - ozone->cursor_mode = false; - if (ozone->cursor_in_sidebar) - { - /* Go back to main menu tab */ - if (ozone->categories_selection_ptr != 0) - ozone_sidebar_goto(ozone, 0); - - new_action = MENU_ACTION_NOOP; - break; - } - - if (menu_entries_get_stack_size(0) == 1) - { - ozone_go_to_sidebar(ozone, tag); - new_action = MENU_ACTION_NOOP; - } - break; - default: - break; - } - - return generic_menu_iterate(menu, userdata, new_action); + /* Fullscreen thumbnails are only enabled on + * playlists, database manager lists and file + * lists */ + ozone->fullscreen_thumbnails_available = + (ozone->is_playlist && ozone->depth == 1) || + (ozone->is_db_manager_list && ozone->depth == 4) || + ozone->is_file_list; } /* TODO: Fancy toggle animation */ @@ -2019,6 +1953,14 @@ static void ozone_list_insert(void *userdata, return; } + if (!string_is_empty(fullpath)) + { + if (node->fullpath) + free(node->fullpath); + + node->fullpath = strdup(fullpath); + } + file_list_set_userdata(list, i, node); } @@ -2224,13 +2166,147 @@ static bool ozone_get_load_content_animation_data(void *userdata, menu_texture_i } #endif +void ozone_hide_fullscreen_thumbnails(ozone_handle_t *ozone, bool animate) +{ + menu_animation_ctx_tag alpha_tag = (uintptr_t)&ozone->animations.fullscreen_thumbnail_alpha; + + /* Kill any existing fade in/out animations */ + menu_animation_kill_by_tag(&alpha_tag); + + /* Check whether animations are enabled */ + if (animate && (ozone->animations.fullscreen_thumbnail_alpha > 0.0f)) + { + menu_animation_ctx_entry_t animation_entry; + + /* Configure fade out animation */ + animation_entry.easing_enum = EASING_OUT_QUAD; + animation_entry.tag = alpha_tag; + animation_entry.duration = menu_thumbnail_get_fade_duration(); + animation_entry.target_value = 0.0f; + animation_entry.subject = &ozone->animations.fullscreen_thumbnail_alpha; + animation_entry.cb = NULL; + animation_entry.userdata = NULL; + + /* Push animation */ + menu_animation_push(&animation_entry); + } + /* No animation - just set thumbnail alpha to zero */ + else + ozone->animations.fullscreen_thumbnail_alpha = 0.0f; + + /* Disable fullscreen thumbnails */ + ozone->show_fullscreen_thumbnails = false; +} + +void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone) +{ + const char *thumbnail_label = NULL; + menu_animation_ctx_tag alpha_tag = (uintptr_t)&ozone->animations.fullscreen_thumbnail_alpha; + menu_animation_ctx_entry_t animation_entry; + menu_entry_t selected_entry; + + /* 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->fullscreen_thumbnails_available || + ozone->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->selection_core_is_viewer) + { + /* imageviewer content requires special treatment, + * since only the right thumbnail is ever loaded */ + if (!menu_thumbnail_is_enabled(ozone->thumbnail_path_data, MENU_THUMBNAIL_RIGHT)) + return; + + if (ozone->thumbnails.right.status != MENU_THUMBNAIL_STATUS_AVAILABLE) + return; + } + else + { + bool left_thumbnail_enabled = menu_thumbnail_is_enabled( + ozone->thumbnail_path_data, MENU_THUMBNAIL_LEFT); + + if ((ozone->thumbnails.right.status == MENU_THUMBNAIL_STATUS_AVAILABLE) && + (left_thumbnail_enabled && + ((ozone->thumbnails.left.status != MENU_THUMBNAIL_STATUS_MISSING) && + (ozone->thumbnails.left.status != MENU_THUMBNAIL_STATUS_AVAILABLE)))) + return; + + if ((ozone->thumbnails.right.status == MENU_THUMBNAIL_STATUS_MISSING) && + (!left_thumbnail_enabled || + (ozone->thumbnails.left.status != MENU_THUMBNAIL_STATUS_AVAILABLE))) + return; + } + + /* Cache selected entry label + * (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 */ + menu_entry_get_rich_label(&selected_entry, &thumbnail_label); + + /* > Sanity check */ + if (!string_is_empty(thumbnail_label)) + strlcpy( + ozone->fullscreen_thumbnail_label, + thumbnail_label, + sizeof(ozone->fullscreen_thumbnail_label)); + + /* Configure fade in animation */ + animation_entry.easing_enum = EASING_OUT_QUAD; + animation_entry.tag = alpha_tag; + animation_entry.duration = menu_thumbnail_get_fade_duration(); + animation_entry.target_value = 1.0f; + animation_entry.subject = &ozone->animations.fullscreen_thumbnail_alpha; + animation_entry.cb = NULL; + animation_entry.userdata = NULL; + + /* Push animation */ + menu_animation_push(&animation_entry); + + /* Enable fullscreen thumbnails */ + ozone->fullscreen_thumbnail_selection = (size_t)ozone->selection; + ozone->show_fullscreen_thumbnails = true; +} + static int ozone_pointer_up(void *userdata, unsigned x, unsigned y, unsigned ptr, enum menu_input_pointer_gesture gesture, menu_file_list_cbs_t *cbs, menu_entry_t *entry, unsigned action) { - size_t selection = menu_navigation_get_selection(); + ozone_handle_t *ozone = (ozone_handle_t*)userdata; + size_t selection = menu_navigation_get_selection(); + + if (!ozone) + return -1; + + /* If fullscreen thumbnail view is enabled, + * all input will disable it and otherwise + * be ignored */ + if (ozone->show_fullscreen_thumbnails) + { + ozone_hide_fullscreen_thumbnails(ozone, true); + return 0; + } switch (gesture) { @@ -2257,10 +2333,184 @@ static int ozone_pointer_up(void *userdata, return 0; } +static enum menu_action ozone_parse_menu_entry_action( + ozone_handle_t *ozone, enum menu_action action) +{ + enum menu_action new_action = action; + file_list_t *selection_buf = NULL; + unsigned horizontal_list_size = 0; + int new_selection; + menu_animation_ctx_tag tag; + + /* If fullscreen thumbnail view is active, any + * valid menu action will disable it... */ + if (ozone->show_fullscreen_thumbnails) + { + if (action != MENU_ACTION_NOOP) + { + 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 || + ((action != MENU_ACTION_SELECT) && + (action != MENU_ACTION_OK))) + return MENU_ACTION_NOOP; + } + } + + if (ozone->horizontal_list) + horizontal_list_size = (unsigned)ozone->horizontal_list->size; + + ozone->messagebox_state = false || menu_input_dialog_get_display_kb(); + selection_buf = menu_entries_get_selection_buf_ptr(0); + tag = (uintptr_t)selection_buf; + + /* Scan user inputs */ + switch (action) + { + case MENU_ACTION_START: + /* If this is a menu with thumbnails and cursor + * 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); + new_action = MENU_ACTION_NOOP; + } + break; + case MENU_ACTION_DOWN: + ozone->cursor_mode = false; + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + new_selection = (int)(ozone->categories_selection_ptr + 1); + + if (new_selection >= (int)(ozone->system_tab_end + horizontal_list_size + 1)) + new_selection = 0; + + ozone_sidebar_goto(ozone, new_selection); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_UP: + ozone->cursor_mode = false; + if (!ozone->cursor_in_sidebar) + break; + + tag = (uintptr_t)ozone; + new_selection = (int)ozone->categories_selection_ptr - 1; + + if (new_selection < 0) + new_selection = horizontal_list_size + ozone->system_tab_end; + + ozone_sidebar_goto(ozone, new_selection); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_LEFT: + ozone->cursor_mode = false; + if (ozone->cursor_in_sidebar) + { + new_action = MENU_ACTION_NOOP; + break; + } + else if (ozone->depth > 1) + break; + + ozone_go_to_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_RIGHT: + ozone->cursor_mode = false; + if (!ozone->cursor_in_sidebar) + { + if (ozone->depth == 1) + new_action = MENU_ACTION_NOOP; + break; + } + + ozone_leave_sidebar(ozone, tag); + + new_action = MENU_ACTION_NOOP; + break; + case MENU_ACTION_OK: + ozone->cursor_mode = false; + if (ozone->cursor_in_sidebar) + { + ozone_leave_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + break; + } + break; + case MENU_ACTION_CANCEL: + ozone->cursor_mode = false; + if (ozone->cursor_in_sidebar) + { + /* Go back to main menu tab */ + if (ozone->categories_selection_ptr != 0) + ozone_sidebar_goto(ozone, 0); + + new_action = MENU_ACTION_NOOP; + break; + } + + if (menu_entries_get_stack_size(0) == 1) + { + ozone_go_to_sidebar(ozone, tag); + new_action = MENU_ACTION_NOOP; + } + break; + default: + /* In all other cases, pass through input + * menu action without intervention */ + break; + } + + return new_action; +} + +/* Menu entry action callback */ +static int ozone_menu_entry_action( + void *userdata, menu_entry_t *entry, + size_t i, enum menu_action action) +{ + ozone_handle_t *ozone = (ozone_handle_t*)userdata; + enum menu_action new_action; + + if (!ozone) + generic_menu_entry_action(userdata, entry, i, action); + + /* Process input action */ + new_action = ozone_parse_menu_entry_action(ozone, action); + + /* Call standard generic_menu_entry_action() function */ + return generic_menu_entry_action(userdata, entry, i, new_action); +} + menu_ctx_driver_t menu_ctx_ozone = { NULL, /* set_texture */ ozone_messagebox, - ozone_menu_iterate, + generic_menu_iterate, ozone_render, ozone_frame, ozone_init, @@ -2307,5 +2557,5 @@ menu_ctx_driver_t menu_ctx_ozone = { #else NULL, #endif - generic_menu_entry_action + ozone_menu_entry_action }; diff --git a/menu/drivers/ozone/ozone.h b/menu/drivers/ozone/ozone.h index e5da61159c..1da024c6b6 100644 --- a/menu/drivers/ozone/ozone.h +++ b/menu/drivers/ozone/ozone.h @@ -60,6 +60,8 @@ typedef struct ozone_handle ozone_handle_t; #define SIDEBAR_ENTRY_ICON_SIZE 46 #define SIDEBAR_ENTRY_ICON_PADDING 15 +#define FULLSCREEN_THUMBNAIL_PADDING 48 + #define CURSOR_SIZE 64 #define INTERVAL_OSK_CURSOR (0.5f * 1000000) @@ -127,6 +129,8 @@ struct ozone_handle float sidebar_text_alpha; float thumbnail_bar_position; + + float fullscreen_thumbnail_alpha; } animations; bool fade_direction; /* false = left to right, true = right to left */ @@ -213,6 +217,7 @@ struct ozone_handle int cursor_size; int thumbnail_bar_width; + int fullscreen_thumbnail_padding; } dimensions; bool show_cursor; @@ -233,6 +238,11 @@ struct ozone_handle menu_thumbnail_t left; } thumbnails; + bool fullscreen_thumbnails_available; + bool show_fullscreen_thumbnails; + size_t fullscreen_thumbnail_selection; + char fullscreen_thumbnail_label[255]; + char selection_core_name[255]; char selection_playtime[255]; char selection_lastplayed[255]; @@ -241,6 +251,8 @@ struct ozone_handle bool selection_core_is_viewer; bool is_db_manager_list; + bool is_file_list; + bool is_quick_menu; bool first_frame; }; @@ -308,6 +320,9 @@ void ozone_entries_update_thumbnail_bar(ozone_handle_t *ozone, bool is_playlist, void ozone_draw_thumbnail_bar(ozone_handle_t *ozone, video_frame_info_t *video_info); +void ozone_hide_fullscreen_thumbnails(ozone_handle_t *ozone, bool animate); +void ozone_show_fullscreen_thumbnails(ozone_handle_t *ozone); + unsigned ozone_count_lines(const char *str); void ozone_update_content_metadata(ozone_handle_t *ozone); diff --git a/menu/drivers/ozone/ozone_display.c b/menu/drivers/ozone/ozone_display.c index ded97b86db..be397b33d1 100644 --- a/menu/drivers/ozone/ozone_display.c +++ b/menu/drivers/ozone/ozone_display.c @@ -419,3 +419,280 @@ void ozone_draw_messagebox(ozone_handle_t *ozone, end: string_list_free(list); } + +void ozone_draw_fullscreen_thumbnails( + ozone_handle_t *ozone, video_frame_info_t *video_info) +{ + /* Check whether fullscreen thumbnails are visible */ + if (ozone->animations.fullscreen_thumbnail_alpha > 0.0f) + { + /* Note: right thumbnail is drawn at the top + * in the sidebar, so it becomes the *left* + * thumbnail when viewed fullscreen */ + menu_thumbnail_t *right_thumbnail = &ozone->thumbnails.left; + menu_thumbnail_t *left_thumbnail = &ozone->thumbnails.right; + unsigned width = video_info->width; + unsigned height = video_info->height; + int view_width = (int)width; + int view_height = (int)height - ozone->dimensions.header_height - ozone->dimensions.footer_height - 1; + int thumbnail_margin = ozone->dimensions.fullscreen_thumbnail_padding; + bool show_right_thumbnail = false; + bool show_left_thumbnail = false; + unsigned num_thumbnails = 0; + float right_thumbnail_draw_width = 0.0f; + float right_thumbnail_draw_height = 0.0f; + float left_thumbnail_draw_width = 0.0f; + float left_thumbnail_draw_height = 0.0f; + float background_alpha = 0.85f; + 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, + }; + int frame_width = (int)((float)thumbnail_margin / 3.0f); + float frame_color[16]; + float separator_color[16]; + int thumbnail_box_width; + int thumbnail_box_height; + int right_thumbnail_x; + int left_thumbnail_x; + int thumbnail_y; + + /* Sanity check: Return immediately if this is + * a menu without thumbnails and we are not currently + * 'fading out' the fullscreen thumbnail view */ + if (!ozone->fullscreen_thumbnails_available && + ozone->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 (((size_t)ozone->selection != ozone->fullscreen_thumbnail_selection) && + (!ozone->is_quick_menu || ozone->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 == MENU_THUMBNAIL_STATUS_AVAILABLE); + show_left_thumbnail = (left_thumbnail->status == MENU_THUMBNAIL_STATUS_AVAILABLE); + + if (show_right_thumbnail) + num_thumbnails++; + + if (show_left_thumbnail) + num_thumbnails++; + + /* Do nothing if both thumbnails are missing + * > Note: Baring inexplicable internal errors, this + * can never happen... */ + if (num_thumbnails < 1) + goto error; + + /* Get base thumbnail dimensions + draw positions */ + + /* > Thumbnail bounding box height + y position + * are fixed */ + thumbnail_box_height = view_height - (thumbnail_margin * 2); + thumbnail_y = ozone->dimensions.header_height + thumbnail_margin + 1; + + /* Thumbnail bounding box width and x position + * depend upon number of active thumbnails */ + if (num_thumbnails == 2) + { + thumbnail_box_width = (view_width - (thumbnail_margin * 3) - frame_width) >> 1; + left_thumbnail_x = thumbnail_margin; + right_thumbnail_x = left_thumbnail_x + thumbnail_box_width + frame_width + thumbnail_margin; + } + else + { + thumbnail_box_width = view_width - (thumbnail_margin * 2); + left_thumbnail_x = thumbnail_margin;; + right_thumbnail_x = left_thumbnail_x; + } + + /* Sanity check */ + if ((thumbnail_box_width < 1) || + (thumbnail_box_height < 1)) + goto error; + + /* Get thumbnail draw dimensions + * > Note: The following code is a bit awkward, since + * we have to do things in a very specific order + * - i.e. we cannot determine proper thumbnail + * layout until we have thumbnail draw dimensions. + * and we cannot get draw dimensions until we have + * the bounding box dimensions... */ + if (show_right_thumbnail) + { + menu_thumbnail_get_draw_dimensions( + right_thumbnail, + thumbnail_box_width, thumbnail_box_height, 1.0f, + &right_thumbnail_draw_width, &right_thumbnail_draw_height); + + /* Sanity check */ + if ((right_thumbnail_draw_width <= 0.0f) || + (right_thumbnail_draw_height <= 0.0f)) + goto error; + } + + if (show_left_thumbnail) + { + menu_thumbnail_get_draw_dimensions( + left_thumbnail, + thumbnail_box_width, thumbnail_box_height, 1.0f, + &left_thumbnail_draw_width, &left_thumbnail_draw_height); + + /* Sanity check */ + if ((left_thumbnail_draw_width <= 0.0f) || + (left_thumbnail_draw_height <= 0.0f)) + goto error; + } + + /* Adjust thumbnail draw positions to achieve + * uniform appearance (accounting for actual + * draw dimensions...) */ + if (num_thumbnails == 2) + { + int left_padding = (thumbnail_box_width - (int)left_thumbnail_draw_width) >> 1; + int right_padding = (thumbnail_box_width - (int)right_thumbnail_draw_width) >> 1; + + /* Move thumbnails as close together as possible, + * and horizontally centre the resultant 'block' + * of images */ + left_thumbnail_x += right_padding; + right_thumbnail_x -= left_padding; + } + + /* Set colour values */ + + /* > Background */ + menu_display_set_alpha( + background_color, + background_alpha * ozone->animations.fullscreen_thumbnail_alpha); + + /* > Separators */ + memcpy(separator_color, ozone->theme->header_footer_separator, sizeof(separator_color)); + menu_display_set_alpha( + separator_color, ozone->animations.fullscreen_thumbnail_alpha); + + /* > Thumbnail frame */ + memcpy(frame_color, ozone->theme->sidebar_background, sizeof(frame_color)); + menu_display_set_alpha( + frame_color, ozone->animations.fullscreen_thumbnail_alpha); + + /* Darken background */ + menu_display_draw_quad( + video_info, + 0, + ozone->dimensions.header_height + 1, + width, + (unsigned)view_height, + width, + height, + background_color); + + /* Draw full-width separators */ + menu_display_draw_quad( + video_info, + 0, + ozone->dimensions.header_height, + width, + 1, + width, + height, + separator_color); + + menu_display_draw_quad( + video_info, + 0, + height - ozone->dimensions.footer_height, + width, + 1, + width, + height, + separator_color); + + /* Draw thumbnails */ + + /* > Right */ + if (show_right_thumbnail) + { + /* Background */ + menu_display_draw_quad( + video_info, + right_thumbnail_x - frame_width + + ((thumbnail_box_width - (int)right_thumbnail_draw_width) >> 1), + thumbnail_y - frame_width + + ((thumbnail_box_height - (int)right_thumbnail_draw_height) >> 1), + (unsigned)right_thumbnail_draw_width + (frame_width << 1), + (unsigned)right_thumbnail_draw_height + (frame_width << 1), + width, + height, + frame_color); + + /* Thumbnail */ + menu_thumbnail_draw( + video_info, + right_thumbnail, + right_thumbnail_x, + thumbnail_y, + (unsigned)thumbnail_box_width, + (unsigned)thumbnail_box_height, + MENU_THUMBNAIL_ALIGN_CENTRE, + ozone->animations.fullscreen_thumbnail_alpha, + 1.0f, + NULL); + } + + /* > Left */ + if (show_left_thumbnail) + { + /* Background */ + menu_display_draw_quad( + video_info, + left_thumbnail_x - frame_width + + ((thumbnail_box_width - (int)left_thumbnail_draw_width) >> 1), + thumbnail_y - frame_width + + ((thumbnail_box_height - (int)left_thumbnail_draw_height) >> 1), + (unsigned)left_thumbnail_draw_width + (frame_width << 1), + (unsigned)left_thumbnail_draw_height + (frame_width << 1), + width, + height, + frame_color); + + /* Thumbnail */ + menu_thumbnail_draw( + video_info, + left_thumbnail, + left_thumbnail_x, + thumbnail_y, + (unsigned)thumbnail_box_width, + (unsigned)thumbnail_box_height, + MENU_THUMBNAIL_ALIGN_CENTRE, + ozone->animations.fullscreen_thumbnail_alpha, + 1.0f, + NULL); + } + } + + return; + +error: + /* If fullscreen thumbnails are enabled at + * this point, must disable them immediately... */ + if (ozone->show_fullscreen_thumbnails) + ozone_hide_fullscreen_thumbnails(ozone, false); +} diff --git a/menu/drivers/ozone/ozone_display.h b/menu/drivers/ozone/ozone_display.h index a01a165bd9..ffe1f6c120 100644 --- a/menu/drivers/ozone/ozone_display.h +++ b/menu/drivers/ozone/ozone_display.h @@ -58,3 +58,6 @@ void ozone_draw_osk(ozone_handle_t *ozone, void ozone_draw_messagebox(ozone_handle_t *ozone, video_frame_info_t *video_info, const char *message); + +void ozone_draw_fullscreen_thumbnails( + ozone_handle_t *ozone, video_frame_info_t *video_info);