(RGUI/XMB) Enable thumbnail display on mixed content playlists (history, favourites, etc.)

Move thumbnail path handling code to reusable menu_thumbnail_path.h/.c file

(XMB) Bug fixes:

- Show thumbnails correctly when 'Show associated cores in playlists' is enabled

- Prevent each thumbnail from being loaded twice (!) when changing current selection
This commit is contained in:
jdgleaver 2019-03-14 11:47:00 +00:00
parent 8064672f11
commit 28bb7c67af
7 changed files with 948 additions and 538 deletions

View File

@ -792,7 +792,8 @@ ifeq ($(HAVE_MENU_COMMON), 1)
menu/menu_displaylist.o \
menu/menu_animation.o \
menu/drivers/menu_generic.o \
menu/drivers/null.o
menu/drivers/null.o \
menu/menu_thumbnail_path.o
ifeq ($(HAVE_MENU_COMMON),1)
OBJ += menu/drivers_display/menu_display_null.o

View File

@ -1238,6 +1238,7 @@ MENU
#include "../menu/menu_shader.c"
#include "../menu/menu_displaylist.c"
#include "../menu/menu_animation.c"
#include "../menu/menu_thumbnail_path.c"
#include "../menu/drivers/null.c"
#include "../menu/drivers/menu_generic.c"

View File

@ -53,6 +53,7 @@
#include <file/config_file.h>
/* Thumbnail additions */
#include "../menu_thumbnail_path.h"
#include <streams/file_stream.h>
#include "../../tasks/tasks_internal.h"
#include <gfx/scaler/scaler.h>
@ -424,9 +425,7 @@ typedef struct
bool is_playlist;
bool entry_has_thumbnail;
bool show_thumbnail;
char *thumbnail_system;
char *thumbnail_content;
char *thumbnail_path;
menu_thumbnail_path_data_t *thumbnail_path_data;
uint32_t thumbnail_queue_size;
bool show_wallpaper;
char theme_preset_path[PATH_MAX_LENGTH]; /* Must be a fixed length array... */
@ -1608,6 +1607,7 @@ static void rgui_render(void *data, bool is_idle)
* through a list...) */
if (rgui->show_thumbnail && rgui->entry_has_thumbnail && (thumbnail.is_valid || (rgui->thumbnail_queue_size > 0)))
{
const char *thumbnail_title = NULL;
char thumbnail_title_buf[255];
unsigned title_x, title_width;
thumbnail_title_buf[0] = '\0';
@ -1615,24 +1615,28 @@ static void rgui_render(void *data, bool is_idle)
/* Draw thumbnail */
rgui_render_thumbnail();
/* Format thumbnail title */
ticker.s = thumbnail_title_buf;
ticker.len = RGUI_TERM_WIDTH(fb_width) - 10;
ticker.str = rgui->thumbnail_content;
ticker.selected = true;
menu_animation_ticker(&ticker);
title_width = utf8len(thumbnail_title_buf) * FONT_WIDTH_STRIDE;
title_x = RGUI_TERM_START_X(fb_width) + ((RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE) - title_width) / 2;
if (rgui_framebuf_data)
/* Get thumbnail title */
if (menu_thumbnail_get_label(rgui->thumbnail_path_data, &thumbnail_title))
{
/* Draw thumbnail title background */
rgui_fill_rect(rgui, rgui_framebuf_data, fb_pitch,
title_x - 5, 0, title_width + 10, FONT_HEIGHT_STRIDE, rgui_bg_filler);
/* Format thumbnail title */
ticker.s = thumbnail_title_buf;
ticker.len = RGUI_TERM_WIDTH(fb_width) - 10;
ticker.str = thumbnail_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
/* Draw thumbnail title */
blit_line((int)title_x, 0, thumbnail_title_buf, rgui->colors.hover_color);
title_width = utf8len(thumbnail_title_buf) * FONT_WIDTH_STRIDE;
title_x = RGUI_TERM_START_X(fb_width) + ((RGUI_TERM_WIDTH(fb_width) * FONT_WIDTH_STRIDE) - title_width) / 2;
if (rgui_framebuf_data)
{
/* Draw thumbnail title background */
rgui_fill_rect(rgui, rgui_framebuf_data, fb_pitch,
title_x - 5, 0, title_width + 10, FONT_HEIGHT_STRIDE, rgui_bg_filler);
/* Draw thumbnail title */
blit_line((int)title_x, 0, thumbnail_title_buf, rgui->colors.hover_color);
}
}
}
else
@ -1927,6 +1931,10 @@ static void *rgui_init(void **userdata, bool video_is_threaded)
rgui->last_width = fb_width;
rgui->last_height = fb_height;
rgui->thumbnail_path_data = menu_thumbnail_path_init();
if (!rgui->thumbnail_path_data)
goto error;
rgui->thumbnail_queue_size = 0;
/* Ensure that we start with thumbnails disabled */
rgui->show_thumbnail = false;
@ -1948,12 +1956,8 @@ static void rgui_free(void *data)
if (rgui)
{
if (!string_is_empty(rgui->thumbnail_system))
free(rgui->thumbnail_system);
if (!string_is_empty(rgui->thumbnail_content))
free(rgui->thumbnail_content);
if (!string_is_empty(rgui->thumbnail_path))
free(rgui->thumbnail_path);
if (rgui->thumbnail_path_data)
free(rgui->thumbnail_path_data);
}
fb_font_inited = menu_display_get_font_data_init();
@ -2092,151 +2096,12 @@ static void rgui_navigation_clear(void *data, bool pending_push)
rgui->scroll_y = 0;
}
static const char *rgui_thumbnail_ident(void)
{
char folder = 0;
settings_t *settings = config_get_ptr();
folder = settings->uints.menu_thumbnails;
switch (folder)
{
case 1:
return "Named_Snaps";
case 2:
return "Named_Titles";
case 3:
return "Named_Boxarts";
case 0:
default:
break;
}
return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
}
static bool rgui_update_thumbnail_path(void *userdata)
{
rgui_t *rgui = (rgui_t*)userdata;
settings_t *settings = config_get_ptr();
char new_path[PATH_MAX_LENGTH] = {0};
const char *thumbnail_base_dir = settings->paths.directory_thumbnails;
const char *thumb_ident = rgui_thumbnail_ident();
if (!string_is_empty(rgui->thumbnail_path))
{
free(rgui->thumbnail_path);
rgui->thumbnail_path = NULL;
}
/* NB: The following is copied directly from xmb.c (xmb_update_thumbnail_path()) */
if (!string_is_equal(thumb_ident, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) &&
!string_is_empty(thumbnail_base_dir) &&
!string_is_empty(rgui->thumbnail_system) &&
!string_is_empty(rgui->thumbnail_content))
{
/* Append thumbnail system directory */
fill_pathname_join(new_path, thumbnail_base_dir, rgui->thumbnail_system, sizeof(new_path));
if (!string_is_empty(new_path))
{
char *tmp_new2 = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
tmp_new2[0] = '\0';
/* Append Named_Snaps/Named_Boxarts/Named_Titles */
fill_pathname_join(tmp_new2, new_path, thumb_ident, PATH_MAX_LENGTH * sizeof(char));
strlcpy(new_path, tmp_new2, PATH_MAX_LENGTH * sizeof(char));
free(tmp_new2);
tmp_new2 = NULL;
if (!string_is_empty(new_path))
{
/* Scrub characters that are not cross-platform and/or violate the
* No-Intro filename standard:
* http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
* Replace these characters in the entry name with underscores.
*/
char *scrub_char_pointer = NULL;
char *tmp_new = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
char *tmp = strdup(rgui->thumbnail_content);
tmp_new[0] = '\0';
while((scrub_char_pointer = strpbrk(tmp, "&*/:`\"<>?\\|")))
*scrub_char_pointer = '_';
fill_pathname_join(tmp_new, new_path, tmp, PATH_MAX_LENGTH * sizeof(char));
if (!string_is_empty(tmp_new))
strlcpy(new_path, tmp_new, sizeof(new_path));
free(tmp_new);
tmp_new = NULL;
free(tmp);
tmp = NULL;
/* Append png extension */
if (!string_is_empty(new_path))
{
strlcat(new_path, file_path_str(FILE_PATH_PNG_EXTENSION), sizeof(new_path));
if (!string_is_empty(new_path))
{
rgui->thumbnail_path = strdup(new_path);
return true;
}
}
}
}
}
return false;
}
static void rgui_set_thumbnail_system(void *userdata, char *s, size_t len)
{
rgui_t *rgui = (rgui_t*)userdata;
if (!rgui)
return;
if (!string_is_empty(rgui->thumbnail_system))
free(rgui->thumbnail_system);
rgui->thumbnail_system = strdup(s);
}
static bool rgui_update_thumbnail_content(void *userdata)
{
rgui_t *rgui = (rgui_t*)userdata;
playlist_t *playlist = NULL;
size_t selection = menu_navigation_get_selection();
if (!rgui)
return false;
/* Get label of currently selected playlist entry */
playlist = playlist_get_cached();
if (playlist)
{
if (selection < playlist_get_size(playlist))
{
const char *label = NULL;
playlist_get_index(playlist, selection, NULL, &label, NULL, NULL, NULL, NULL);
if (!string_is_empty(rgui->thumbnail_content))
{
free(rgui->thumbnail_content);
rgui->thumbnail_content = NULL;
}
if (!string_is_empty(label))
{
rgui->thumbnail_content = strdup(label);
return true;
}
}
}
return false;
menu_thumbnail_set_system(rgui->thumbnail_path_data, s);
}
static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui)
@ -2245,11 +2110,18 @@ static void rgui_scan_selected_entry_thumbnail(rgui_t *rgui)
if (rgui->show_thumbnail && rgui->is_playlist)
{
if (rgui_update_thumbnail_content(rgui))
if (menu_thumbnail_set_content_playlist(rgui->thumbnail_path_data,
playlist_get_cached(), menu_navigation_get_selection()))
{
if (rgui_update_thumbnail_path(rgui))
if (menu_thumbnail_update_path(rgui->thumbnail_path_data, MENU_THUMBNAIL_RIGHT))
{
rgui->entry_has_thumbnail = request_thumbnail(rgui, rgui->thumbnail_path);
const char *thumbnail_path = NULL;
if (menu_thumbnail_get_path(rgui->thumbnail_path_data,
MENU_THUMBNAIL_RIGHT, &thumbnail_path))
{
rgui->entry_has_thumbnail = request_thumbnail(rgui, thumbnail_path);
}
}
}
}
@ -2379,7 +2251,10 @@ static void rgui_populate_entries(void *data,
return;
/* Check whether we are currently viewing a playlist */
rgui->is_playlist = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST));
rgui->is_playlist = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_LIST)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_FAVORITES_LIST)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST));
/* Set menu title */
menu_entries_get_title(rgui->menu_title, sizeof(rgui->menu_title));

View File

@ -45,6 +45,7 @@
#include "../menu_animation.h"
#include "../menu_entries.h"
#include "../menu_input.h"
#include "../menu_thumbnail_path.h"
#include "../../core_info.h"
#include "../../core.h"
@ -245,6 +246,8 @@ typedef struct xmb_handle
bool mouse_show;
bool use_ps3_layout;
bool assets_missing;
bool is_playlist;
bool is_db_manager_list;
uint8_t system_tab_end;
uint8_t tabs[XMB_SYSTEM_TAB_MAX_LENGTH];
@ -306,11 +309,7 @@ typedef struct xmb_handle
char title_name[255];
char *box_message;
char *thumbnail_system;
char *thumbnail_content;
char *savestate_thumbnail_file_path;
char *thumbnail_file_path;
char *left_thumbnail_file_path;
char *bg_file_path;
file_list_t *selection_buf_old;
@ -340,6 +339,8 @@ typedef struct xmb_handle
font_data_t *font2;
video_font_raster_block_t raster_block;
video_font_raster_block_t raster_block2;
menu_thumbnail_path_data_t *thumbnail_path_data;
} xmb_handle_t;
float scale_mod[8] = {
@ -559,32 +560,6 @@ static xmb_node_t *xmb_copy_node(const xmb_node_t *old_node)
return new_node;
}
static const char *xmb_thumbnails_ident(char pos)
{
char folder = 0;
settings_t *settings = config_get_ptr();
if (pos == 'R')
folder = settings->uints.menu_thumbnails;
if (pos == 'L')
folder = settings->uints.menu_left_thumbnails;
switch (folder)
{
case 1:
return "Named_Snaps";
case 2:
return "Named_Titles";
case 3:
return "Named_Boxarts";
case 0:
default:
break;
}
return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
}
static float *xmb_gradient_ident(video_frame_info_t *video_info)
{
switch (video_info->xmb_color_theme)
@ -952,153 +927,21 @@ end:
static void xmb_update_thumbnail_path(void *data, unsigned i, char pos)
{
menu_entry_t entry;
unsigned entry_type = 0;
char new_path[PATH_MAX_LENGTH] = {0};
settings_t *settings = config_get_ptr();
xmb_handle_t *xmb = (xmb_handle_t*)data;
playlist_t *playlist = NULL;
const char *dir_thumbnails = settings->paths.directory_thumbnails;
xmb_handle_t *xmb = (xmb_handle_t*)data;
const char *core_name = NULL;
menu_entry_init(&entry);
if (!xmb)
return;
if (!xmb || string_is_empty(dir_thumbnails))
goto end;
menu_entry_get(&entry, 0, i, NULL, true);
entry_type = menu_entry_get_type_new(&entry);
if (entry_type == FILE_TYPE_IMAGEVIEWER || entry_type == FILE_TYPE_IMAGE)
/* imageviewer content requires special treatment... */
menu_thumbnail_get_core_name(xmb->thumbnail_path_data, &core_name);
if (string_is_equal(core_name, "imageviewer"))
{
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
xmb_node_t *node = (xmb_node_t*)
file_list_get_userdata_at_offset(selection_buf, i);
if (node && !string_is_empty(node->fullpath) &&
(pos == 'R' || (pos == 'L' && string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))))
{
if (!string_is_empty(entry.path))
fill_pathname_join(
new_path,
node->fullpath,
entry.path,
sizeof(new_path));
goto end;
}
if ((pos == 'R') || (pos == 'L' && !menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT)))
menu_thumbnail_update_path(xmb->thumbnail_path_data, pos == 'R' ? MENU_THUMBNAIL_RIGHT : MENU_THUMBNAIL_LEFT);
}
else if (filebrowser_get_type() != FILEBROWSER_NONE)
{
video_driver_texture_unload(&xmb->thumbnail);
goto end;
}
playlist = playlist_get_cached();
if (playlist)
{
const char *core_name = NULL;
playlist_get_index(playlist, i,
NULL, NULL, NULL, &core_name, NULL, NULL);
if (string_is_equal(core_name, "imageviewer"))
{
if (
(pos == 'R') ||
(
pos == 'L' &&
string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
)
)
{
if (!string_is_empty(entry.label))
strlcpy(new_path, entry.label,
sizeof(new_path));
}
else
video_driver_texture_unload(&xmb->left_thumbnail);
goto end;
}
}
/* Append thumbnail system directory */
if (!string_is_empty(xmb->thumbnail_system))
fill_pathname_join(
new_path,
dir_thumbnails,
xmb->thumbnail_system,
sizeof(new_path));
if (!string_is_empty(new_path))
{
char *tmp_new2 = (char*)
malloc(PATH_MAX_LENGTH * sizeof(char));
tmp_new2[0] = '\0';
/* Append Named_Snaps/Named_Boxarts/Named_Titles */
if (pos == 'R')
fill_pathname_join(tmp_new2, new_path,
xmb_thumbnails_ident('R'), PATH_MAX_LENGTH * sizeof(char));
if (pos == 'L')
fill_pathname_join(tmp_new2, new_path,
xmb_thumbnails_ident('L'), PATH_MAX_LENGTH * sizeof(char));
strlcpy(new_path, tmp_new2,
PATH_MAX_LENGTH * sizeof(char));
free(tmp_new2);
}
/* Scrub characters that are not cross-platform and/or violate the
* No-Intro filename standard:
* http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
* Replace these characters in the entry name with underscores.
*/
if (!string_is_empty(xmb->thumbnail_content))
{
char *scrub_char_pointer = NULL;
char *tmp_new = (char*)
malloc(PATH_MAX_LENGTH * sizeof(char));
char *tmp = strdup(xmb->thumbnail_content);
tmp_new[0] = '\0';
while((scrub_char_pointer = strpbrk(tmp, "&*/:`\"<>?\\|")))
*scrub_char_pointer = '_';
/* Look for thumbnail file with this scrubbed filename */
fill_pathname_join(tmp_new,
new_path,
tmp, PATH_MAX_LENGTH * sizeof(char));
if (!string_is_empty(tmp_new))
strlcpy(new_path,
tmp_new, sizeof(new_path));
free(tmp_new);
free(tmp);
}
/* Append png extension */
if (!string_is_empty(new_path))
strlcat(new_path,
file_path_str(FILE_PATH_PNG_EXTENSION),
sizeof(new_path));
end:
if (xmb && !string_is_empty(new_path))
{
if (pos == 'R')
xmb->thumbnail_file_path = strdup(new_path);
if (pos == 'L')
xmb->left_thumbnail_file_path = strdup(new_path);
}
menu_entry_free(&entry);
else
menu_thumbnail_update_path(xmb->thumbnail_path_data, pos == 'R' ? MENU_THUMBNAIL_RIGHT : MENU_THUMBNAIL_LEFT);
}
static void xmb_update_savestate_thumbnail_path(void *data, unsigned i)
@ -1162,32 +1005,29 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i)
static void xmb_update_thumbnail_image(void *data)
{
xmb_handle_t *xmb = (xmb_handle_t*)data;
xmb_handle_t *xmb = (xmb_handle_t*)data;
const char *right_thumbnail_path = NULL;
const char *left_thumbnail_path = NULL;
if (!xmb)
return;
if (!(string_is_empty(xmb->thumbnail_file_path)))
if (menu_thumbnail_get_path(xmb->thumbnail_path_data, MENU_THUMBNAIL_RIGHT, &right_thumbnail_path))
{
if (filestream_exists(xmb->thumbnail_file_path))
task_push_image_load(xmb->thumbnail_file_path,
if (filestream_exists(right_thumbnail_path))
task_push_image_load(right_thumbnail_path,
menu_display_handle_thumbnail_upload, NULL);
else
video_driver_texture_unload(&xmb->thumbnail);
free(xmb->thumbnail_file_path);
xmb->thumbnail_file_path = NULL;
}
if (!(string_is_empty(xmb->left_thumbnail_file_path)))
if (menu_thumbnail_get_path(xmb->thumbnail_path_data, MENU_THUMBNAIL_LEFT, &left_thumbnail_path))
{
if (filestream_exists(xmb->left_thumbnail_file_path))
task_push_image_load(xmb->left_thumbnail_file_path,
if (filestream_exists(left_thumbnail_path))
task_push_image_load(left_thumbnail_path,
menu_display_handle_left_thumbnail_upload, NULL);
else
video_driver_texture_unload(&xmb->left_thumbnail);
free(xmb->left_thumbnail_file_path);
xmb->left_thumbnail_file_path = NULL;
}
}
@ -1197,32 +1037,77 @@ static void xmb_set_thumbnail_system(void *data, char*s, size_t len)
if (!xmb)
return;
if (!string_is_empty(xmb->thumbnail_system))
free(xmb->thumbnail_system);
/* There is only one mame thumbnail repo */
if (strncmp("MAME", s, 4) == 0)
strcpy(s, "MAME");
xmb->thumbnail_system = strdup(s);
menu_thumbnail_set_system(xmb->thumbnail_path_data, s);
}
static void xmb_reset_thumbnail_content(void *data)
static void xmb_unload_thumbnail_textures(void *data)
{
xmb_handle_t *xmb = (xmb_handle_t*)data;
if (!xmb)
return;
if (!string_is_empty(xmb->thumbnail_content))
free(xmb->thumbnail_content);
xmb->thumbnail_content = NULL;
if (xmb->thumbnail)
video_driver_texture_unload(&xmb->thumbnail);
if (xmb->left_thumbnail)
video_driver_texture_unload(&xmb->left_thumbnail);
}
static void xmb_set_thumbnail_content(void *data, char *s, size_t len)
{
size_t selection = menu_navigation_get_selection();
xmb_handle_t *xmb = (xmb_handle_t*)data;
if (!xmb)
return;
if (!string_is_empty(xmb->thumbnail_content))
free(xmb->thumbnail_content);
xmb->thumbnail_content = strdup(s);
if (xmb->is_playlist)
{
/* Playlist content */
if (string_is_empty(s))
menu_thumbnail_set_content_playlist(xmb->thumbnail_path_data,
playlist_get_cached(), selection);
}
else if (xmb->is_db_manager_list)
{
/* Database list content */
if (string_is_empty(s))
{
menu_entry_t entry;
menu_entry_init(&entry);
menu_entry_get(&entry, 0, selection, NULL, true);
if (!string_is_empty(entry.path))
menu_thumbnail_set_content(xmb->thumbnail_path_data, entry.path);
menu_entry_free(&entry);
}
}
else if (string_is_equal(s, "imageviewer"))
{
/* Filebrowser image updates */
menu_entry_t entry;
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
xmb_node_t *node = (xmb_node_t*)file_list_get_userdata_at_offset(selection_buf, selection);
menu_entry_init(&entry);
menu_entry_get(&entry, 0, selection, NULL, true);
if (node)
if (!string_is_empty(entry.path) && !string_is_empty(node->fullpath))
menu_thumbnail_set_content_image(xmb->thumbnail_path_data, node->fullpath, entry.path);
menu_entry_free(&entry);
}
else if (!string_is_empty(s))
{
/* Annoying leftovers...
* This is required to ensure that thumbnails are
* updated correctly when navigating deeply through
* the sublevels of database manager lists.
* Showing thumbnails on database entries is a
* pointless nuisance and a waste of CPU cycles, IMHO... */
menu_thumbnail_set_content(xmb->thumbnail_path_data, s);
}
}
static void xmb_update_savestate_thumbnail_image(void *data)
@ -1259,8 +1144,6 @@ static void xmb_selection_pointer_changed(
menu_list_t *menu_list = NULL;
file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0);
size_t selection = menu_navigation_get_selection();
const char *thumb_ident = xmb_thumbnails_ident('R');
const char *lft_thumb_ident= xmb_thumbnails_ident('L');
menu_entries_ctl(MENU_ENTRIES_CTL_LIST_GET, &menu_list);
menu_entry_init(&entry);
@ -1302,64 +1185,44 @@ static void xmb_selection_pointer_changed(
ia = xmb->items_active_alpha;
iz = xmb->items_active_zoom;
if (!string_is_equal(thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)) || !string_is_equal(lft_thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT) || menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
if ((xmb_system_tab > XMB_SYSTEM_TAB_SETTINGS && depth == 1) ||
(xmb_system_tab < XMB_SYSTEM_TAB_SETTINGS && depth == 4))
bool update_thumbnails = false;
/* Playlist updates */
if (((xmb_system_tab > XMB_SYSTEM_TAB_SETTINGS && depth == 1) ||
(xmb_system_tab < XMB_SYSTEM_TAB_SETTINGS && depth == 4)) &&
xmb->is_playlist)
{
if (!string_is_empty(entry.path))
xmb_set_thumbnail_content(xmb, entry.path, 0 /* will be ignored */);
if (!string_is_equal(thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'R');
xmb_update_thumbnail_image(xmb);
}
if (!string_is_equal(lft_thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'L');
xmb_update_thumbnail_image(xmb);
}
xmb_set_thumbnail_content(xmb, "", 0 /* will be ignored */);
update_thumbnails = true;
}
else if (((entry_type == FILE_TYPE_IMAGE || entry_type == FILE_TYPE_IMAGEVIEWER ||
entry_type == FILE_TYPE_RDB || entry_type == FILE_TYPE_RDB_ENTRY)
&& xmb_system_tab <= XMB_SYSTEM_TAB_SETTINGS))
/* Database list updates
* (pointless nuisance...) */
else if (depth == 4 && xmb->is_db_manager_list)
{
if (!string_is_empty(entry.path))
xmb_set_thumbnail_content(xmb, entry.path, 0 /* will be ignored */);
if (!string_is_equal(thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'R');
xmb_update_thumbnail_image(xmb);
}
else if (!string_is_equal(lft_thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'L');
xmb_update_thumbnail_image(xmb);
}
xmb_set_thumbnail_content(xmb, "", 0 /* will be ignored */);
update_thumbnails = true;
}
else if (filebrowser_get_type() != FILEBROWSER_NONE)
/* Filebrowser image updates */
else if (entry_type == FILE_TYPE_IMAGEVIEWER || entry_type == FILE_TYPE_IMAGE)
{
xmb_reset_thumbnail_content(xmb);
if (!string_is_equal(thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'R');
xmb_update_thumbnail_image(xmb);
}
else if (!string_is_equal(lft_thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, i, 'L');
xmb_update_thumbnail_image(xmb);
}
xmb_set_thumbnail_content(xmb, "imageviewer", 0 /* will be ignored */);
update_thumbnails = true;
}
if (update_thumbnails)
{
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
xmb_update_thumbnail_path(xmb, i /* will be ignored */, 'R');
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
xmb_update_thumbnail_path(xmb, i /* will be ignored */, 'L');
xmb_update_thumbnail_image(xmb);
}
}
xmb_update_savestate_thumbnail_path(xmb, i);
xmb_update_savestate_thumbnail_image(xmb);
}
@ -1542,12 +1405,28 @@ static void xmb_list_open_new(xmb_handle_t *xmb,
if (xmb_system_tab <= XMB_SYSTEM_TAB_SETTINGS)
{
if (xmb->depth < 4)
xmb_reset_thumbnail_content(xmb);
xmb_update_thumbnail_path(xmb, 0, 'R');
xmb_update_thumbnail_image(xmb);
xmb_update_thumbnail_path(xmb, 0, 'L');
xmb_update_thumbnail_image(xmb);
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT) || menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
/* This code is horrible, full of hacks...
* This hack ensures that thumbnails are not cleared
* when selecting an entry from a collection via
* 'load content'... */
if (xmb->depth != 5)
xmb_unload_thumbnail_textures(xmb);
if (xmb->is_playlist || xmb->is_db_manager_list)
{
xmb_set_thumbnail_content(xmb, "", 0 /* will be ignored */);
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
xmb_update_thumbnail_path(xmb, 0 /* will be ignored */, 'R');
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
xmb_update_thumbnail_path(xmb, 0 /* will be ignored */, 'L');
xmb_update_thumbnail_image(xmb);
}
}
}
}
@ -1861,37 +1740,22 @@ static void xmb_list_switch(xmb_handle_t *xmb)
xmb_list_switch_new(xmb, selection_buf, dir, selection);
xmb->categories_active_idx_old = (unsigned)xmb->categories_selection_ptr;
if (!string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT) || menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
menu_entry_t entry;
xmb_unload_thumbnail_textures(xmb);
menu_entry_init(&entry);
menu_entry_get(&entry, 0, selection, NULL, true);
if (xmb->is_playlist)
{
xmb_set_thumbnail_content(xmb, "", 0 /* will be ignored */);
if (!string_is_empty(entry.path))
xmb_set_thumbnail_content(xmb, entry.path, 0 /* will be ignored */);
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
xmb_update_thumbnail_path(xmb, 0 /* will be ignored */, 'R');
menu_entry_free(&entry);
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
xmb_update_thumbnail_path(xmb, 0 /* will be ignored */, 'L');
xmb_update_thumbnail_path(xmb, 0, 'R');
xmb_update_thumbnail_image(xmb);
}
if (!string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
menu_entry_t entry;
menu_entry_init(&entry);
menu_entry_get(&entry, 0, selection, NULL, true);
if (!string_is_empty(entry.path))
xmb_set_thumbnail_content(xmb, entry.path, 0 /* will be ignored */);
menu_entry_free(&entry);
xmb_update_thumbnail_path(xmb, 0, 'L');
xmb_update_thumbnail_image(xmb);
xmb_update_thumbnail_image(xmb);
}
}
}
@ -2241,27 +2105,29 @@ static void xmb_populate_entries(void *data,
const char *label, unsigned k)
{
xmb_handle_t *xmb = (xmb_handle_t*)data;
unsigned xmb_system_tab;
if (!xmb)
return;
/* Determine whether this is a playlist */
xmb_system_tab = xmb_get_system_tab(xmb, (unsigned)xmb->categories_selection_ptr);
xmb->is_playlist = (xmb_system_tab == XMB_SYSTEM_TAB_FAVORITES) ||
(xmb_system_tab == XMB_SYSTEM_TAB_HISTORY) ||
(xmb_system_tab == XMB_SYSTEM_TAB_IMAGES) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_HORIZONTAL_MENU)) ||
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_DEFERRED_FAVORITES_LIST)) ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_IMAGES_LIST));
xmb->is_playlist = xmb->is_playlist && !string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL));
/* Determine whether this is a database manager list */
xmb->is_db_manager_list = string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DATABASE_MANAGER_LIST));
if (menu_driver_ctl(RARCH_MENU_CTL_IS_PREVENT_POPULATE, NULL))
{
xmb_selection_pointer_changed(xmb, false);
menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL);
if (!string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, 0, 'R');
xmb_update_thumbnail_image(xmb);
}
xmb_update_savestate_thumbnail_image(xmb);
if (!string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, 0, 'L');
xmb_update_thumbnail_image(xmb);
}
return;
}
@ -2793,8 +2659,6 @@ static int xmb_draw_item(
xmb_node_t *core_node,
file_list_t *list,
float *color,
const char *thumb_ident,
const char *left_thumb_ident,
size_t i,
size_t current,
unsigned width,
@ -2908,13 +2772,9 @@ static int xmb_draw_item(
{
if (xmb->savestate_thumbnail ||
!xmb->use_ps3_layout ||
(!string_is_equal
(thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
(menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT)
&& xmb->thumbnail) ||
(!string_is_equal
(left_thumb_ident,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF))
(menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT)
&& xmb->left_thumbnail
&& settings->bools.menu_xmb_vertical_thumbnails)
)
@ -3075,8 +2935,6 @@ static void xmb_draw_items(
menu_display_ctx_rotate_draw_t rotate_draw;
xmb_node_t *core_node = NULL;
size_t end = 0;
const char *thumb_ident = xmb_thumbnails_ident('R');
const char *left_thumb_ident= xmb_thumbnails_ident('L');
if (!list || !list->size || !xmb)
return;
@ -3126,7 +2984,7 @@ static void xmb_draw_items(
&entry,
&mymat,
xmb, core_node,
list, color, thumb_ident, left_thumb_ident,
list, color,
i, current,
width, height);
menu_entry_free(&entry);
@ -3493,9 +3351,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
xmb->icon_spacing_horizontal +
pseudo_font_length + min_thumb_size) <= width))
{
if (xmb->thumbnail
&& !string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
{
/* Limit thumbnail width */
@ -3560,9 +3416,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
{
/* Left Thumbnail in the left margin */
if (xmb->left_thumbnail
&& !string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->left_thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
/* Limit left thumbnail width */
@ -3631,9 +3485,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
xmb->icon_spacing_horizontal +
pseudo_font_length + min_thumb_size) <= width))
{
if (xmb->left_thumbnail
&& !string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->left_thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
/* Limit left thumbnail width */
@ -3696,9 +3548,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
{
/* Left Thumbnail in the left margin */
if (xmb->left_thumbnail
&& !string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->left_thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
/* Limit left thumbnail width */
@ -3943,9 +3793,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
xmb->icon_spacing_horizontal +
pseudo_font_length + min_thumb_size) <= width))
{
if (xmb->thumbnail &&
!string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
{
/* Limit right thumbnail width */
@ -4007,9 +3855,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info)
xmb->icon_spacing_horizontal +
pseudo_font_length + min_thumb_size) <= width))
{
if (xmb->left_thumbnail &&
!string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (xmb->left_thumbnail && menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
/* Limit left thumbnail width */
@ -4520,6 +4366,10 @@ static void *xmb_init(void **userdata, bool video_is_threaded)
xmb_init_ribbon(xmb);
xmb->thumbnail_path_data = menu_thumbnail_path_init();
if (!xmb->thumbnail_path_data)
goto error;
return menu;
error:
@ -4567,18 +4417,13 @@ static void xmb_free(void *data)
if (!string_is_empty(xmb->box_message))
free(xmb->box_message);
if (!string_is_empty(xmb->thumbnail_system))
free(xmb->thumbnail_system);
if (!string_is_empty(xmb->thumbnail_content))
free(xmb->thumbnail_content);
if (!string_is_empty(xmb->savestate_thumbnail_file_path))
free(xmb->savestate_thumbnail_file_path);
if (!string_is_empty(xmb->thumbnail_file_path))
free(xmb->thumbnail_file_path);
if (!string_is_empty(xmb->left_thumbnail_file_path))
free(xmb->left_thumbnail_file_path);
if (!string_is_empty(xmb->bg_file_path))
free(xmb->bg_file_path);
if (xmb->thumbnail_path_data)
free(xmb->thumbnail_path_data);
}
font_driver_bind_block(NULL, NULL);
@ -5087,16 +4932,14 @@ static void xmb_context_reset_internal(xmb_handle_t *xmb,
xmb_context_reset_horizontal_list(xmb);
if (!string_is_equal(xmb_thumbnails_ident('R'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT) || menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
{
xmb_update_thumbnail_path(xmb, 0, 'R');
xmb_update_thumbnail_image(xmb);
}
if (!string_is_equal(xmb_thumbnails_ident('L'),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF)))
{
xmb_update_thumbnail_path(xmb, 0, 'L');
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_RIGHT))
xmb_update_thumbnail_path(xmb, 0, 'R');
if (menu_thumbnail_is_enabled(MENU_THUMBNAIL_LEFT))
xmb_update_thumbnail_path(xmb, 0, 'L');
xmb_update_thumbnail_image(xmb);
}
xmb_update_savestate_thumbnail_image(xmb);
@ -5801,8 +5644,8 @@ menu_ctx_driver_t menu_ctx_xmb = {
xmb_populate_entries,
xmb_toggle,
xmb_navigation_clear,
xmb_navigation_pointer_changed,
xmb_navigation_pointer_changed,
NULL, /*xmb_navigation_pointer_changed,*/ /* Note: navigation_set() is called each time navigation_increment/decrement() */
NULL, /*xmb_navigation_pointer_changed,*/ /* is called, so linking these just duplicates work... */
xmb_navigation_set,
xmb_navigation_pointer_changed,
xmb_navigation_alphabet,

View File

@ -1323,8 +1323,24 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info,
strlcpy(label_spacer, PL_LABEL_SPACER_DEFAULT, sizeof(label_spacer));
}
/* Inform menu driver of current system name */
if (!string_is_empty(info->path))
/* Inform menu driver of current system name
* > Note: history, favorites and images_history
* require special treatment here, since info->path
* is nonsensical in these cases (and we *do* need
* to call set_thumbnail_system() in these cases,
* since all three playlist types have thumbnail
* support) */
if (string_is_equal(path_playlist, "history") ||
string_is_equal(path_playlist, "favorites") ||
string_is_equal(path_playlist, "images_history"))
{
char system_name[15];
system_name[0] = '\0';
strlcpy(system_name, path_playlist, sizeof(system_name));
menu_driver_set_thumbnail_system(system_name, sizeof(system_name));
}
else if (!string_is_empty(info->path))
{
char lpl_basename[PATH_MAX_LENGTH];
lpl_basename[0] = '\0';
@ -1394,24 +1410,6 @@ static int menu_displaylist_parse_playlist(menu_displaylist_info_t *info,
}
}
/* If this is a standard collection (not a history list or
* favourites), trigger thumbnail update for current selection.
* Note: Thumbnail updates must be omitted when using RGUI,
* since this functionality is handled elsewhere... */
if (i == selection)
{
if (is_collection && !string_is_empty(label) && !is_rgui)
{
char *content_basename = strdup(label);
/* Note: If menu_driver_set_thumbnail_content() accepted a const pointer,
* we could save a string duplication here... */
menu_driver_set_thumbnail_content(content_basename, strlen(content_basename) + 1);
menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH, NULL);
menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE, NULL);
free(content_basename);
}
}
if (!string_is_empty(path))
{
/* Standard playlist entry
@ -1721,12 +1719,15 @@ static int menu_displaylist_parse_database_entry(menu_handle_t *menu,
snprintf(crc_str, sizeof(crc_str), "%08X", db_info_entry->crc32);
/* It is unclear why parsing a database should trigger a
* thumbnail update, but I guess this is here for a reason...
* Regardless, thumbnail updates must be disabled when using
/* This allows thumbnails to be shown while viewing database
* entries...
* It only makes sense to do this for the first info entry,
* since menu drivers cannot handle multiple successive
* calls of menu_driver_set_thumbnail_content()...
* Note that thumbnail updates must be disabled when using
* RGUI, since this functionality is handled elsewhere
* (and doing it here creates harmful conflicts) */
if (!string_is_equal(settings->arrays.menu_driver, "rgui"))
if ((i == 0) && !string_is_equal(settings->arrays.menu_driver, "rgui"))
{
if (!string_is_empty(db_info_entry->name))
strlcpy(thumbnail_content, db_info_entry->name,

560
menu/menu_thumbnail_path.c Normal file
View File

@ -0,0 +1,560 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (runtime_file.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <string/stdstring.h>
#include <file/file_path.h>
#include <lists/file_list.h>
#include "../configuration.h"
#include "../msg_hash.h"
#include "../paths.h"
#include "../file_path_special.h"
#include "menu_driver.h"
#include "widgets/menu_entry.h"
#include "menu_thumbnail_path.h"
/* Used fixed size char arrays here, just to avoid
* the inconvenience of having to calloc()/free()
* each individual entry by hand... */
struct menu_thumbnail_path_data
{
char system[PATH_MAX_LENGTH];
char content_path[PATH_MAX_LENGTH];
char content_label[PATH_MAX_LENGTH];
char content_core_name[PATH_MAX_LENGTH];
char content_db_name[PATH_MAX_LENGTH];
char content_img[PATH_MAX_LENGTH];
char right_path[PATH_MAX_LENGTH];
char left_path[PATH_MAX_LENGTH];
};
/* Initialisation */
/* Creates new thumbnail path data container.
* Returns handle to new menu_thumbnail_path_data_t object.
* on success, otherwise NULL.
* Note: Returned object must be free()d */
menu_thumbnail_path_data_t *menu_thumbnail_path_init()
{
menu_thumbnail_path_data_t *path_data = NULL;
path_data = (menu_thumbnail_path_data_t*)calloc(1, sizeof(*path_data));
if (!path_data)
return NULL;
return path_data;
}
/* Resets thumbnail path data
* (blanks all internal string containers) */
void menu_thumbnail_path_reset(menu_thumbnail_path_data_t *path_data)
{
if (!path_data)
return;
path_data->system[0] = '\0';
path_data->content_path[0] = '\0';
path_data->content_label[0] = '\0';
path_data->content_core_name[0] = '\0';
path_data->content_db_name[0] = '\0';
path_data->content_img[0] = '\0';
path_data->right_path[0] = '\0';
path_data->left_path[0] = '\0';
}
/* Utility Functions */
/* Returns currently set thumbnail 'type' (Named_Snaps,
* Named_Titles, Named_Boxarts) for specified thumbnail
* identifier (right, left) */
const char *menu_thumbnail_get_type(enum menu_thumbnail_id thumbnail_id)
{
settings_t *settings = config_get_ptr();
unsigned type = 0;
if (!settings)
return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
switch (thumbnail_id)
{
case MENU_THUMBNAIL_RIGHT:
type = settings->uints.menu_thumbnails;
break;
case MENU_THUMBNAIL_LEFT:
type = settings->uints.menu_left_thumbnails;
break;
default:
return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
}
switch (type)
{
case 1:
return "Named_Snaps";
case 2:
return "Named_Titles";
case 3:
return "Named_Boxarts";
case 0:
default:
break;
}
return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
}
/* Returns true if specified thumbnail is enabled
* (i.e. if 'type' is not equal to MENU_ENUM_LABEL_VALUE_OFF) */
bool menu_thumbnail_is_enabled(enum menu_thumbnail_id thumbnail_id)
{
settings_t *settings = config_get_ptr();
if (!settings)
return false;
switch (thumbnail_id)
{
case MENU_THUMBNAIL_RIGHT:
return settings->uints.menu_thumbnails != 0;
case MENU_THUMBNAIL_LEFT:
return settings->uints.menu_left_thumbnails != 0;
break;
default:
break;
}
return false;
}
/* Setters */
/* Fills content_img field of path_data using existing
* content_label field (for internal use only) */
static void fill_content_img(menu_thumbnail_path_data_t *path_data)
{
char *scrub_char_pointer = NULL;
/* Copy source label string */
strlcpy(path_data->content_img,
path_data->content_label, sizeof(path_data->content_img));
/* Scrub characters that are not cross-platform and/or violate the
* No-Intro filename standard:
* http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
* Replace these characters in the entry name with underscores */
while((scrub_char_pointer = strpbrk(path_data->content_img, "&*/:`\"<>?\\|")))
*scrub_char_pointer = '_';
/* Add PNG extension */
strlcat(path_data->content_img,
file_path_str(FILE_PATH_PNG_EXTENSION), sizeof(path_data->content_img));
}
/* Sets current 'system' (default database name).
* Returns true if 'system' is valid.
* > Used as a fallback when individual content lacks an
* associated database name */
bool menu_thumbnail_set_system(menu_thumbnail_path_data_t *path_data, const char *system)
{
if (!path_data)
return false;
/* When system is updated, must regenerate right/left
* thumbnail paths */
path_data->right_path[0] = '\0';
path_data->left_path[0] = '\0';
/* 'Reset' path_data system string */
path_data->system[0] = '\0';
if (string_is_empty(system))
return false;
/* Hack: There is only one MAME thumbnail repo,
* so filter any input starting with 'MAME...' */
if (strncmp(system, "MAME", 4) == 0)
strlcpy(path_data->system, "MAME", sizeof(path_data->system));
else
strlcpy(path_data->system, system, sizeof(path_data->system));
return true;
}
/* Sets current thumbnail content according to the specified label.
* Returns true if content is valid */
bool menu_thumbnail_set_content(menu_thumbnail_path_data_t *path_data, const char *label)
{
if (!path_data)
return false;
/* When content is updated, must regenerate right/left
* thumbnail paths */
path_data->right_path[0] = '\0';
path_data->left_path[0] = '\0';
/* 'Reset' path_data content strings */
path_data->content_path[0] = '\0';
path_data->content_label[0] = '\0';
path_data->content_core_name[0] = '\0';
path_data->content_db_name[0] = '\0';
path_data->content_img[0] = '\0';
if (string_is_empty(label))
return false;
/* Cache content label */
strlcpy(path_data->content_label, label, sizeof(path_data->content_label));
/* Determine content image name */
fill_content_img(path_data);
/* Redundant error check... */
if (string_is_empty(path_data->content_img))
return false;
return true;
}
/* Sets current thumbnail content to the specified image.
* Returns true if content is valid */
bool menu_thumbnail_set_content_image(menu_thumbnail_path_data_t *path_data, const char *img_dir, const char *img_name)
{
if (!path_data)
return false;
/* When content is updated, must regenerate right/left
* thumbnail paths */
path_data->right_path[0] = '\0';
path_data->left_path[0] = '\0';
/* 'Reset' path_data content strings */
path_data->content_path[0] = '\0';
path_data->content_label[0] = '\0';
path_data->content_core_name[0] = '\0';
path_data->content_db_name[0] = '\0';
path_data->content_img[0] = '\0';
if (string_is_empty(img_dir))
return false;
if (string_is_empty(img_name))
return false;
if (path_is_media_type(img_name) != RARCH_CONTENT_IMAGE)
return false;
/* Cache content image name */
strlcpy(path_data->content_img,
img_name, sizeof(path_data->content_img));
/* Get image label */
strlcpy(path_data->content_label,
path_remove_extension(path_data->content_img), sizeof(path_data->content_label));
/* Set file path */
fill_pathname_join(path_data->content_path,
img_dir, img_name, sizeof(path_data->content_path));
/* Set core name to "imageviewer" */
strlcpy(path_data->content_core_name,
"imageviewer", sizeof(path_data->content_core_name));
/* Set database name (arbitrarily) to "_images_"
* (required for compatibility with menu_thumbnail_update_path(),
* but not actually used...) */
strlcpy(path_data->content_db_name,
"_images_", sizeof(path_data->content_db_name));
/* Redundant error check */
if (string_is_empty(path_data->content_path))
return false;
return true;
}
/* Sets current thumbnail content to the specified playlist entry.
* Returns true if content is valid.
* > Note: It is always best to use playlists when setting
* thumbnail content, since there is no guarantee that the
* corresponding menu entry label will contain a useful
* identifier (it may be 'tainted', e.g. with the current
* core name). 'Real' labels should be extracted from source */
bool menu_thumbnail_set_content_playlist(menu_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx)
{
const char *content_path = NULL;
const char *content_label = NULL;
const char *core_name = NULL;
const char *db_name = NULL;
if (!path_data)
return false;
/* When content is updated, must regenerate right/left
* thumbnail paths */
path_data->right_path[0] = '\0';
path_data->left_path[0] = '\0';
/* 'Reset' path_data content strings */
path_data->content_path[0] = '\0';
path_data->content_label[0] = '\0';
path_data->content_core_name[0] = '\0';
path_data->content_db_name[0] = '\0';
path_data->content_img[0] = '\0';
if (!playlist)
return false;
if (idx >= playlist_get_size(playlist))
return false;
/* Read playlist values */
playlist_get_index(playlist, idx,
&content_path, &content_label, NULL, &core_name, NULL, &db_name);
/* Content without a path is invalid by definition */
if (string_is_empty(content_path))
return false;
/* Cache content path
* (This is required for imageviewer content) */
strlcpy(path_data->content_path,
content_path, sizeof(path_data->content_path));
/* Cache core name
* (This is required for imageviewer content) */
if (!string_is_empty(core_name))
strlcpy(path_data->content_core_name,
core_name, sizeof(path_data->content_core_name));
/* Get content label */
if (!string_is_empty(content_label))
strlcpy(path_data->content_label,
content_label, sizeof(path_data->content_label));
else
fill_short_pathname_representation(path_data->content_label,
content_path, sizeof(path_data->content_label));
/* Determine content image name */
fill_content_img(path_data);
/* Redundant error check... */
if (string_is_empty(path_data->content_img))
return false;
/* Thumbnail image name is done -> now check if
* per-content database name is defined */
if (!string_is_empty(db_name))
{
/* Hack: There is only one MAME thumbnail repo,
* so filter any input starting with 'MAME...' */
if (strncmp(db_name, "MAME", 4) == 0)
strlcpy(path_data->content_db_name,
"MAME", sizeof(path_data->content_db_name));
else
{
char tmp_buf[PATH_MAX_LENGTH];
tmp_buf[0] = '\0';
strlcpy(tmp_buf, db_name, sizeof(tmp_buf));
/* Remove .lpl extension
* > path_remove_extension() requires a char * (not const)
* so have to use a temporary buffer... */
strlcpy(path_data->content_db_name,
path_remove_extension(tmp_buf), sizeof(path_data->content_db_name));
}
}
return true;
}
/* Updaters */
/* Updates path for specified thumbnail identifier (right, left).
* Must be called after:
* - menu_thumbnail_set_system()
* - menu_thumbnail_set_content*()
* ...and before:
* - menu_thumbnail_get_path()
* Returns true if generated path is valid */
bool menu_thumbnail_update_path(menu_thumbnail_path_data_t *path_data, enum menu_thumbnail_id thumbnail_id)
{
settings_t *settings = config_get_ptr();
const char *type = menu_thumbnail_get_type(thumbnail_id);
const char *system_name = NULL;
char *thumbnail_path = NULL;
if (!path_data)
return false;
/* Determine which path we are updating... */
switch (thumbnail_id)
{
case MENU_THUMBNAIL_RIGHT:
thumbnail_path = path_data->right_path;
break;
case MENU_THUMBNAIL_LEFT:
thumbnail_path = path_data->left_path;
break;
default:
return false;
}
thumbnail_path[0] = '\0';
/* Sundry error checking */
if (!settings)
return false;
if (string_is_empty(settings->paths.directory_thumbnails))
return false;
if (!menu_thumbnail_is_enabled(thumbnail_id))
return false;
/* Generate new path */
/* > Check path_data for empty strings */
if (string_is_empty(path_data->content_img) ||
(string_is_empty(path_data->system) &&
string_is_empty(path_data->content_db_name)))
return false;
/* > Get current system */
system_name = string_is_empty(path_data->content_db_name) ?
path_data->system : path_data->content_db_name;
/* > Special case: thumbnail for imageviewer content
* is the image file itself */
if (string_is_equal(system_name, "images_history") ||
string_is_equal(path_data->content_core_name, "imageviewer"))
{
if (string_is_empty(path_data->content_path))
return false;
/* imageviewer content is identical for left and right thumbnails */
if (path_is_media_type(path_data->content_path) == RARCH_CONTENT_IMAGE)
strlcpy(thumbnail_path,
path_data->content_path, PATH_MAX_LENGTH * sizeof(char));
}
else
{
char tmp_buf[PATH_MAX_LENGTH];
tmp_buf[0] = '\0';
/* > Normal content: assemble path */
/* >> Base + system name */
fill_pathname_join(thumbnail_path, settings->paths.directory_thumbnails,
system_name, PATH_MAX_LENGTH * sizeof(char));
/* >> Add type */
fill_pathname_join(tmp_buf, thumbnail_path, type, sizeof(tmp_buf));
/* >> Add content image */
thumbnail_path[0] = '\0';
fill_pathname_join(thumbnail_path, tmp_buf,
path_data->content_img, PATH_MAX_LENGTH * sizeof(char));
}
/* Final error check - is cached path empty? */
if (string_is_empty(thumbnail_path))
return false;
return true;
}
/* Getters */
/* Fetches the current thumbnail file path of the
* specified thumbnail 'type'.
* Returns true if path is valid. */
bool menu_thumbnail_get_path(menu_thumbnail_path_data_t *path_data, enum menu_thumbnail_id thumbnail_id, const char **path)
{
char *thumbnail_path = NULL;
if (!path_data)
return false;
if (!path)
return false;
switch (thumbnail_id)
{
case MENU_THUMBNAIL_RIGHT:
thumbnail_path = path_data->right_path;
break;
case MENU_THUMBNAIL_LEFT:
thumbnail_path = path_data->left_path;
break;
default:
return false;
}
if (string_is_empty(thumbnail_path))
return false;
*path = thumbnail_path;
return true;
}
/* Fetches current thumbnail label.
* Returns true if label is valid. */
bool menu_thumbnail_get_label(menu_thumbnail_path_data_t *path_data, const char **label)
{
if (!path_data)
return false;
if (!label)
return false;
if (string_is_empty(path_data->content_label))
return false;
*label = path_data->content_label;
return true;
}
/* Fetches current thumbnail core name.
* Returns true if core name is valid. */
bool menu_thumbnail_get_core_name(menu_thumbnail_path_data_t *path_data, const char **core_name)
{
if (!path_data)
return false;
if (!core_name)
return false;
if (string_is_empty(path_data->content_core_name))
return false;
*core_name = path_data->content_core_name;
return true;
}

129
menu/menu_thumbnail_path.h Normal file
View File

@ -0,0 +1,129 @@
/* Copyright (C) 2010-2019 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (runtime_file.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __MENU_THUMBNAIL_PATH_H
#define __MENU_THUMBNAIL_PATH_H
#include <retro_common_api.h>
#include <libretro.h>
#include <boolean.h>
#include "../playlist.h"
RETRO_BEGIN_DECLS
/* Note: This implementation reflects the current
* setup of:
* - menu_driver_set_thumbnail_system()
* - menu_driver_set_thumbnail_content()
* - menu_driver_update_thumbnail_path()
* This is absolutely not the best way to handle things,
* but I have no interest in rewriting the existing
* menu code... */
enum menu_thumbnail_id
{
MENU_THUMBNAIL_RIGHT = 0,
MENU_THUMBNAIL_LEFT
};
/* Prevent direct access to menu_thumbnail_path_data_t members */
typedef struct menu_thumbnail_path_data menu_thumbnail_path_data_t;
/* Initialisation */
/* Creates new thumbnail path data container.
* Returns handle to new menu_thumbnail_path_data_t object.
* on success, otherwise NULL.
* Note: Returned object must be free()d */
menu_thumbnail_path_data_t *menu_thumbnail_path_init();
/* Resets thumbnail path data
* (blanks all internal string containers) */
void menu_thumbnail_path_reset(menu_thumbnail_path_data_t *path_data);
/* Utility Functions */
/* Returns currently set thumbnail 'type' (Named_Snaps,
* Named_Titles, Named_Boxarts) for specified thumbnail
* identifier (right, left) */
const char *menu_thumbnail_get_type(enum menu_thumbnail_id thumbnail_id);
/* Returns true if specified thumbnail is enabled
* (i.e. if 'type' is not equal to MENU_ENUM_LABEL_VALUE_OFF) */
bool menu_thumbnail_is_enabled(enum menu_thumbnail_id thumbnail_id);
/* Setters */
/* Sets current 'system' (default database name).
* Returns true if 'system' is valid.
* > Used as a fallback when individual content lacks an
* associated database name */
bool menu_thumbnail_set_system(menu_thumbnail_path_data_t *path_data, const char *system);
/* Sets current thumbnail content according to the specified label.
* Returns true if content is valid */
bool menu_thumbnail_set_content(menu_thumbnail_path_data_t *path_data, const char *label);
/* Sets current thumbnail content to the specified image.
* Returns true if content is valid */
bool menu_thumbnail_set_content_image(menu_thumbnail_path_data_t *path_data, const char *img_dir, const char *img_name);
/* Sets current thumbnail content to the specified playlist entry.
* Returns true if content is valid.
* > Note: It is always best to use playlists when setting
* thumbnail content, since there is no guarantee that the
* corresponding menu entry label will contain a useful
* identifier (it may be 'tainted', e.g. with the current
* core name). 'Real' labels should be extracted from source */
bool menu_thumbnail_set_content_playlist(menu_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx);
/* Updaters */
/* Updates path for specified thumbnail identifier (right, left).
* Must be called after:
* - menu_thumbnail_set_system()
* - menu_thumbnail_set_content*()
* ...and before:
* - menu_thumbnail_get_path()
* Returns true if generated path is valid */
bool menu_thumbnail_update_path(menu_thumbnail_path_data_t *path_data, enum menu_thumbnail_id thumbnail_id);
/* Getters */
/* Fetches the current thumbnail file path of the
* specified thumbnail 'type'.
* Returns true if path is valid. */
bool menu_thumbnail_get_path(menu_thumbnail_path_data_t *path_data, enum menu_thumbnail_id thumbnail_id, const char **path);
/* Fetches current thumbnail label.
* Returns true if label is valid. */
bool menu_thumbnail_get_label(menu_thumbnail_path_data_t *path_data, const char **label);
/* Fetches current thumbnail core name.
* Returns true if core name is valid. */
bool menu_thumbnail_get_core_name(menu_thumbnail_path_data_t *path_data, const char **core_name);
RETRO_END_DECLS
#endif