Merge pull request #9333 from jdgleaver/smooth-ticker

Add optional smooth scrolling menu ticker text
This commit is contained in:
Twinaphex 2019-08-21 18:42:20 +02:00 committed by GitHub
commit 35c336e3ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1096 additions and 164 deletions

View File

@ -392,6 +392,7 @@ static bool menu_show_sublabels = true;
static unsigned menu_ticker_type = TICKER_TYPE_BOUNCE;
static float menu_ticker_speed = 1.0f;
static bool menu_ticker_smooth = false;
#if defined(HAVE_THREADS)
static bool menu_savestate_resume = true;

View File

@ -1453,6 +1453,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings,
SETTING_BOOL("menu_core_enable", &settings->bools.menu_core_enable, true, true, false);
SETTING_BOOL("menu_show_sublabels", &settings->bools.menu_show_sublabels, true, menu_show_sublabels, false);
SETTING_BOOL("menu_dynamic_wallpaper_enable", &settings->bools.menu_dynamic_wallpaper_enable, true, false, false);
SETTING_BOOL("menu_ticker_smooth", &settings->bools.menu_ticker_smooth, true, menu_ticker_smooth, false);
SETTING_BOOL("settings_show_input", &settings->bools.settings_show_input, true, DEFAULT_SETTINGS_SHOW_INPUT, false);
SETTING_BOOL("quick_menu_show_resume_content", &settings->bools.quick_menu_show_resume_content, true, DEFAULT_QUICK_MENU_SHOW_RESUME_CONTENT, false);
SETTING_BOOL("quick_menu_show_restart_content", &settings->bools.quick_menu_show_restart_content, true, DEFAULT_QUICK_MENU_SHOW_RESTART_CONTENT, false);

View File

@ -203,6 +203,7 @@ typedef struct settings
bool menu_use_preferred_system_color_theme;
bool menu_preferred_system_color_theme_set;
bool menu_unified_controls;
bool menu_ticker_smooth;
bool settings_show_input;
bool quick_menu_show_resume_content;
bool quick_menu_show_restart_content;

View File

@ -1247,6 +1247,8 @@ MSG_HASH(MENU_ENUM_LABEL_MENU_TICKER_TYPE,
"menu_ticker_type")
MSG_HASH(MENU_ENUM_LABEL_MENU_TICKER_SPEED,
"menu_ticker_speed")
MSG_HASH(MENU_ENUM_LABEL_MENU_TICKER_SMOOTH,
"menu_ticker_smooth")
MSG_HASH(MENU_ENUM_LABEL_UI_COMPANION_ENABLE,
"ui_companion_enable")
MSG_HASH(MENU_ENUM_LABEL_UI_COMPANION_START_ON_BOOT,

View File

@ -3402,6 +3402,14 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_MENU_TICKER_SPEED,
"Animation speed when scrolling long menu text strings."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MENU_TICKER_SMOOTH,
"Smooth Ticker Text"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_MENU_TICKER_SMOOTH,
"Use smooth scrolling animation when displaying long menu text strings. Has a small performance impact."
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_RGUI_MENU_COLOR_THEME,
"Menu Color Theme"

View File

@ -639,6 +639,7 @@ default_sublabel_macro(action_bind_sublabel_menu_rgui_internal_upscale_level,
default_sublabel_macro(action_bind_sublabel_menu_rgui_aspect_ratio, MENU_ENUM_SUBLABEL_MENU_RGUI_ASPECT_RATIO)
default_sublabel_macro(action_bind_sublabel_menu_ticker_type, MENU_ENUM_SUBLABEL_MENU_TICKER_TYPE)
default_sublabel_macro(action_bind_sublabel_menu_ticker_speed, MENU_ENUM_SUBLABEL_MENU_TICKER_SPEED)
default_sublabel_macro(action_bind_sublabel_menu_ticker_smooth, MENU_ENUM_SUBLABEL_MENU_TICKER_SMOOTH)
default_sublabel_macro(action_bind_sublabel_playlist_show_inline_core_name, MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_INLINE_CORE_NAME)
default_sublabel_macro(action_bind_sublabel_playlist_sort_alphabetical, MENU_ENUM_SUBLABEL_PLAYLIST_SORT_ALPHABETICAL)
default_sublabel_macro(action_bind_sublabel_playlist_fuzzy_archive_match, MENU_ENUM_SUBLABEL_PLAYLIST_FUZZY_ARCHIVE_MATCH)
@ -2764,6 +2765,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_MENU_TICKER_SPEED:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_ticker_speed);
break;
case MENU_ENUM_LABEL_MENU_TICKER_SMOOTH:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_ticker_smooth);
break;
case MENU_ENUM_LABEL_PLAYLIST_SHOW_INLINE_CORE_NAME:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_playlist_show_inline_core_name);
break;

View File

@ -743,9 +743,14 @@ static void materialui_render_label_value(
{
menu_entry_t entry;
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
char label_str[255];
char value_str[255];
char wrapped_sublabel_str[MENU_SUBLABEL_MAX_LENGTH];
unsigned ticker_label_x_offset = 0;
unsigned ticker_value_x_offset = 0;
unsigned ticker_str_width = 0;
int value_x_offset = 0;
unsigned entry_type = 0;
const char *sublabel_str = NULL;
bool switch_is_on = true;
@ -760,10 +765,23 @@ static void materialui_render_label_value(
float scale_factor = menu_display_get_dpi(video_info->width,
video_info->height);
settings_t *settings = config_get_ptr();
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = mui->font;
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = NULL;
ticker_smooth.dst_str_width = &ticker_str_width;
}
else
{
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
}
label_str[0] = value_str[0] = wrapped_sublabel_str[0] = '\0';
@ -778,21 +796,48 @@ static void materialui_render_label_value(
if (value_len * mui->glyph_width > usable_width / 2)
value_len = (int)((usable_width/2) / mui->glyph_width);
ticker_limit = (int)((usable_width / mui->glyph_width) - (value_len + 2));
ticker_limit = (int)((usable_width / mui->glyph_width) - (value_len + 3));
ticker.s = label_str;
ticker.len = ticker_limit;
ticker.idx = index;
ticker.str = label;
ticker.selected = selected;
if (use_smooth_ticker)
{
/* Label */
ticker_smooth.selected = selected;
ticker_smooth.field_width = ticker_limit * mui->glyph_width;
ticker_smooth.src_str = label;
ticker_smooth.dst_str = label_str;
ticker_smooth.dst_str_len = sizeof(label_str);
ticker_smooth.x_offset = &ticker_label_x_offset;
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
ticker.s = value_str;
ticker.len = value_len;
ticker.str = value;
/* Value */
ticker_smooth.field_width = (value_len + 1) * mui->glyph_width;
ticker_smooth.src_str = value;
ticker_smooth.dst_str = value_str;
ticker_smooth.dst_str_len = sizeof(value_str);
ticker_smooth.x_offset = &ticker_value_x_offset;
menu_animation_ticker(&ticker);
/* Value text is right aligned, so have to offset x
* by the 'padding' width at the end of the ticker string... */
if (menu_animation_ticker_smooth(&ticker_smooth))
value_x_offset = (ticker_value_x_offset + ticker_str_width) - ticker_smooth.field_width;
}
else
{
ticker.s = label_str;
ticker.len = ticker_limit;
ticker.idx = index;
ticker.str = label;
ticker.selected = selected;
menu_animation_ticker(&ticker);
ticker.s = value_str;
ticker.len = value_len;
ticker.str = value;
menu_animation_ticker(&ticker);
}
/* set switch_is_on */
/* set texture_switch */
@ -889,13 +934,13 @@ static void materialui_render_label_value(
}
menu_display_draw_text(mui->font, label_str,
mui->margin + icon_margin,
ticker_label_x_offset + mui->margin + icon_margin,
y + (scale_factor / 5),
width, height, color, TEXT_ALIGN_LEFT, 1.0f, false, 0, false);
if (do_draw_text)
menu_display_draw_text(mui->font, value_str,
width - mui->margin,
value_x_offset + width - mui->margin,
y + (scale_factor / 5),
width, height, color, TEXT_ALIGN_RIGHT, 1.0f, false, 0, false);
@ -1080,9 +1125,12 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
menu_display_ctx_clearcolor_t clearcolor;
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
unsigned ticker_x_offset = 0;
menu_display_ctx_draw_t draw;
char msg[255];
char title_buf[255];
char menu_title[640];
char title_buf[640];
char title_msg[255];
float black_bg[16] = {
@ -1179,17 +1227,30 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
settings_t *settings = config_get_ptr();
materialui_handle_t *mui = (materialui_handle_t*)data;
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
if (!mui)
return;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = mui->font;
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = NULL;
ticker_smooth.x_offset = &ticker_x_offset;
ticker_smooth.dst_str_width = NULL;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
}
usable_width = width - (mui->margin * 2);
msg[0] = title_buf[0] = title_msg[0] = '\0';
msg[0] = menu_title[0] = title_buf[0] = title_msg[0] = '\0';
switch (video_info->materialui_color_theme)
{
@ -1536,44 +1597,40 @@ static void materialui_frame(void *data, video_frame_info_t *video_info)
);
}
ticker_limit = (unsigned)(usable_width / mui->glyph_width);
ticker.s = title_buf;
ticker.len = ticker_limit;
ticker.idx = menu_animation_get_ticker_slow_idx();
ticker.str = mui->menu_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
/* Title */
usable_width = width - (mui->margin * 2) - title_margin;
strlcpy(menu_title, mui->menu_title, sizeof(menu_title));
if (materialui_get_core_title(title_msg, sizeof(title_msg)) == 0)
{
int ticker_limit, value_len;
char title_buf_msg_tmp[255];
char title_buf_msg[640];
strlcat(menu_title, " (", sizeof(menu_title));
strlcat(menu_title, title_msg, sizeof(menu_title));
strlcat(menu_title, ")", sizeof(menu_title));
}
title_buf_msg_tmp[0] = title_buf_msg[0] = '\0';
if (use_smooth_ticker)
{
ticker_smooth.selected = true;
ticker_smooth.field_width = (unsigned)usable_width;
ticker_smooth.src_str = menu_title;
ticker_smooth.dst_str = title_buf;
ticker_smooth.dst_str_len = sizeof(title_buf);
snprintf(title_buf_msg, sizeof(title_buf_msg), "%s (%s)",
title_buf, title_msg);
value_len = (int)utf8len(title_buf);
ticker_limit = (int)((usable_width / mui->glyph_width) - (value_len + 2));
ticker.s = title_buf_msg_tmp;
ticker.len = ticker_limit;
ticker.idx = menu_animation_get_ticker_idx();
ticker.str = title_buf_msg;
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = title_buf;
ticker.len = (unsigned)(usable_width / mui->glyph_width);
ticker.str = menu_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
strlcpy(title_buf, title_buf_msg_tmp, sizeof(title_buf));
}
if (mui->font)
menu_display_draw_text(mui->font, title_buf,
title_margin,
ticker_x_offset + title_margin,
header_height / 2 + mui->font->size / 3,
width, height, font_header_color, TEXT_ALIGN_LEFT, 1.0f, false, 0, false);

View File

@ -1027,27 +1027,56 @@ static void ozone_draw_header(ozone_handle_t *ozone, video_frame_info_t *video_i
{
char title[255];
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
static const char* const ticker_spacer = OZONE_TICKER_SPACER;
unsigned ticker_x_offset = 0;
settings_t *settings = config_get_ptr();
unsigned timedate_offset = 0;
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = ticker_spacer;
ticker_smooth.x_offset = &ticker_x_offset;
ticker_smooth.dst_str_width = NULL;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
}
/* Separator */
menu_display_draw_quad(video_info, 30, ozone->dimensions.header_height, video_info->width - 60, 1, video_info->width, video_info->height, ozone->theme->header_footer_separator);
/* Title */
ticker.s = title;
ticker.len = (video_info->width - 128 - 47 - 130) / ozone->title_font_glyph_width;
ticker.idx = menu_animation_get_ticker_idx();
ticker.str = ozone->title;
ticker.selected = true;
if (use_smooth_ticker)
{
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.dst_str = title;
ticker_smooth.dst_str_len = sizeof(title);
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = title;
ticker.len = (video_info->width - 128 - 47 - 180) / ozone->title_font_glyph_width;
ticker.str = ozone->title;
ticker.selected = true;
ozone_draw_text(video_info, ozone, title, 128, ozone->dimensions.header_height / 2 + FONT_SIZE_TITLE * 3/8, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.title, ozone->theme->text_rgba, false);
menu_animation_ticker(&ticker);
}
ozone_draw_text(video_info, ozone, title, ticker_x_offset + 128, ozone->dimensions.header_height / 2 + FONT_SIZE_TITLE * 3/8, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.title, ozone->theme->text_rgba, false);
/* Icon */
menu_display_blend_begin(video_info);

View File

@ -474,7 +474,11 @@ border_iterate:
menu_texture_item tex;
menu_entry_t entry;
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
static const char* const ticker_spacer = OZONE_TICKER_SPACER;
unsigned ticker_x_offset = 0;
unsigned ticker_str_width = 0;
int value_x_offset = 0;
char rich_label[255];
char entry_value_ticker[255];
char wrapped_sublabel_str[MENU_SUBLABEL_MAX_LENGTH];
@ -485,10 +489,25 @@ border_iterate:
bool entry_selected = false;
int text_offset = -ozone->dimensions.entry_icon_padding - ozone->dimensions.entry_icon_size;
float *icon_color = NULL;
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = ozone->fonts.entries_label;
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = ticker_spacer;
ticker_smooth.x_offset = &ticker_x_offset;
ticker_smooth.dst_str_width = &ticker_str_width;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
}
entry_selected = selection == i;
node = (ozone_node_t*) file_list_get_userdata_at_offset(selection_buf, i);
@ -510,16 +529,30 @@ border_iterate:
/* Prepare text */
menu_entry_get_rich_label(&entry, &entry_rich_label);
ticker.idx = menu_animation_get_ticker_idx();
ticker.s = rich_label;
ticker.str = entry_rich_label;
ticker.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker.len = (entry_width - entry_padding) / ozone->entry_font_glyph_width;
if (use_smooth_ticker)
{
ticker_smooth.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker_smooth.field_width = entry_width - entry_padding - 10 - ozone->dimensions.entry_icon_padding;
ticker_smooth.src_str = entry_rich_label;
ticker_smooth.dst_str = rich_label;
ticker_smooth.dst_str_len = sizeof(rich_label);
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = rich_label;
ticker.str = entry_rich_label;
ticker.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker.len = (entry_width - entry_padding - 10 - ozone->dimensions.entry_icon_padding) / ozone->entry_font_glyph_width;
menu_animation_ticker(&ticker);
}
if (ozone->empty_playlist)
{
/* Note: This entry can never be selected, so ticker_x_offset
* is irrelevant here (i.e. this text will never scroll) */
unsigned text_width = font_driver_get_message_width(ozone->fonts.entries_label, rich_label, (unsigned)strlen(rich_label), 1);
x_offset = (video_info_width - (unsigned) ozone->dimensions.sidebar_width - entry_padding * 2) / 2 - text_width / 2 - 60;
y = video_info_height / 2 - 60;
@ -588,24 +621,41 @@ border_iterate:
}
/* Draw text */
ozone_draw_text(video_info, ozone, rich_label, text_offset + (unsigned) ozone->dimensions.sidebar_width + x_offset + entry_padding + ozone->dimensions.entry_icon_size + ozone->dimensions.entry_icon_padding * 2,
ozone_draw_text(video_info, ozone, rich_label, ticker_x_offset + text_offset + (unsigned) ozone->dimensions.sidebar_width + x_offset + entry_padding + ozone->dimensions.entry_icon_size + ozone->dimensions.entry_icon_padding * 2,
y + ozone->dimensions.entry_height / 2 + FONT_SIZE_ENTRIES_LABEL * 3/8 + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_label, COLOR_TEXT_ALPHA(ozone->theme->text_rgba, alpha_uint32), false);
if (!string_is_empty(sublabel_str))
ozone_draw_text(video_info, ozone, sublabel_str, (unsigned) ozone->dimensions.sidebar_width + x_offset + entry_padding + ozone->dimensions.entry_icon_padding,
y + ozone->dimensions.entry_height + 1 + 5 + FONT_SIZE_ENTRIES_SUBLABEL + scroll_y, TEXT_ALIGN_LEFT, video_info->width, video_info->height, ozone->fonts.entries_sublabel, COLOR_TEXT_ALPHA(ozone->theme->text_sublabel_rgba, alpha_uint32), false);
/* Value */
ticker.idx = menu_animation_get_ticker_idx();
ticker.s = entry_value_ticker;
ticker.str = entry_value;
ticker.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker.len = (entry_width - ozone->dimensions.entry_icon_size - ozone->dimensions.entry_icon_padding * 2 -
((int)utf8len(entry_rich_label) * ozone->entry_font_glyph_width)) / ozone->entry_font_glyph_width;
if (use_smooth_ticker)
{
ticker_smooth.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker_smooth.field_width = (entry_width - ozone->dimensions.entry_icon_size - ozone->dimensions.entry_icon_padding * 2 -
((unsigned)utf8len(entry_rich_label) * ozone->entry_font_glyph_width));
ticker_smooth.src_str = entry_value;
ticker_smooth.dst_str = entry_value_ticker;
ticker_smooth.dst_str_len = sizeof(entry_value_ticker);
menu_animation_ticker(&ticker);
/* Value text is right aligned, so have to offset x
* by the 'padding' width at the end of the ticker string... */
if (menu_animation_ticker_smooth(&ticker_smooth))
value_x_offset = (ticker_x_offset + ticker_str_width) - ticker_smooth.field_width;
}
else
{
ticker.s = entry_value_ticker;
ticker.str = entry_value;
ticker.selected = entry_selected && !ozone->cursor_in_sidebar;
ticker.len = (entry_width - ozone->dimensions.entry_icon_size - ozone->dimensions.entry_icon_padding * 2 -
((unsigned)utf8len(entry_rich_label) * ozone->entry_font_glyph_width)) / ozone->entry_font_glyph_width;
ozone_draw_entry_value(ozone, video_info, entry_value_ticker, (unsigned) ozone->dimensions.sidebar_width + entry_padding + x_offset + entry_width - ozone->dimensions.entry_icon_padding,
y + ozone->dimensions.entry_height / 2 + FONT_SIZE_ENTRIES_LABEL * 3/8 + scroll_y, alpha_uint32, &entry);
menu_animation_ticker(&ticker);
}
ozone_draw_entry_value(ozone, video_info, entry_value_ticker,
value_x_offset + (unsigned) ozone->dimensions.sidebar_width + entry_padding + x_offset + entry_width - ozone->dimensions.entry_icon_padding,
y + ozone->dimensions.entry_height / 2 + FONT_SIZE_ENTRIES_LABEL * 3/8 + scroll_y, alpha_uint32, &entry);
icons_iterate:
y += node->height;

View File

@ -110,14 +110,30 @@ void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info)
unsigned i, sidebar_height, selection_y, selection_old_y, horizontal_list_size;
char console_title[255];
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
static const char* const ticker_spacer = OZONE_TICKER_SPACER;
unsigned ticker_x_offset = 0;
settings_t *settings = config_get_ptr();
uint32_t text_alpha = ozone->animations.sidebar_text_alpha * 255.0f;
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = ozone->fonts.sidebar;
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = ticker_spacer;
ticker_smooth.x_offset = &ticker_x_offset;
ticker_smooth.dst_str_width = NULL;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
}
selection_y = 0;
selection_old_y = 0;
@ -234,15 +250,27 @@ void ozone_draw_sidebar(ozone_handle_t *ozone, video_frame_info_t *video_info)
if (ozone->sidebar_collapsed)
goto console_iterate;
ticker.idx = menu_animation_get_ticker_idx();
ticker.len = (entry_width - ozone->dimensions.sidebar_entry_icon_size - 35) / ozone->sidebar_font_glyph_width;
ticker.s = console_title;
ticker.selected = selected;
ticker.str = node->console_name;
if (use_smooth_ticker)
{
ticker_smooth.selected = selected;
ticker_smooth.field_width = (entry_width - ozone->dimensions.sidebar_entry_icon_size - 40);
ticker_smooth.src_str = node->console_name;
ticker_smooth.dst_str = console_title;
ticker_smooth.dst_str_len = sizeof(console_title);
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.len = (entry_width - ozone->dimensions.sidebar_entry_icon_size - 40) / ozone->sidebar_font_glyph_width;
ticker.s = console_title;
ticker.selected = selected;
ticker.str = node->console_name;
ozone_draw_text(video_info, ozone, console_title, ozone->sidebar_offset + ozone->dimensions.sidebar_padding_horizontal + ozone->dimensions.sidebar_entry_icon_padding * 2 + ozone->dimensions.sidebar_entry_icon_size,
menu_animation_ticker(&ticker);
}
ozone_draw_text(video_info, ozone, console_title, ticker_x_offset + ozone->sidebar_offset + ozone->dimensions.sidebar_padding_horizontal + ozone->dimensions.sidebar_entry_icon_padding * 2 + ozone->dimensions.sidebar_entry_icon_size,
y + ozone->dimensions.sidebar_entry_height / 2 + FONT_SIZE_SIDEBAR * 3/8 + ozone->animations.scroll_y_sidebar, TEXT_ALIGN_LEFT,
video_info->width, video_info->height, ozone->fonts.sidebar, text_color, true);

View File

@ -2820,7 +2820,10 @@ static void rgui_blit_cursor(void)
}
}
static void rgui_render_osk(rgui_t *rgui, menu_animation_ctx_ticker_t *ticker)
static void rgui_render_osk(
rgui_t *rgui,
menu_animation_ctx_ticker_t *ticker, menu_animation_ctx_ticker_smooth_t *ticker_smooth,
bool use_smooth_ticker)
{
size_t fb_pitch;
unsigned fb_width, fb_height;
@ -2945,17 +2948,33 @@ static void rgui_render_osk(rgui_t *rgui, menu_animation_ctx_ticker_t *ticker)
char input_label_buf[255];
unsigned input_label_length;
int input_label_x, input_label_y;
unsigned ticker_x_offset = 0;
input_label_buf[0] = '\0';
ticker->s = input_label_buf;
ticker->len = input_label_max_length;
ticker->str = input_label;
ticker->selected = true;
menu_animation_ticker(ticker);
if (use_smooth_ticker)
{
ticker_smooth->selected = true;
ticker_smooth->field_width = input_label_max_length * FONT_WIDTH_STRIDE;
ticker_smooth->src_str = input_label;
ticker_smooth->dst_str = input_label_buf;
ticker_smooth->dst_str_len = sizeof(input_label_buf);
ticker_smooth->x_offset = &ticker_x_offset;
menu_animation_ticker_smooth(ticker_smooth);
}
else
{
ticker->s = input_label_buf;
ticker->len = input_label_max_length;
ticker->str = input_label;
ticker->selected = true;
menu_animation_ticker(ticker);
}
input_label_length = (unsigned)(utf8len(input_label_buf) * FONT_WIDTH_STRIDE);
input_label_x = osk_x + input_offset_x + ((input_label_max_length * FONT_WIDTH_STRIDE) - input_label_length) / 2;
input_label_x = ticker_x_offset + osk_x + input_offset_x + ((input_label_max_length * FONT_WIDTH_STRIDE) - input_label_length) / 2;
input_label_y = osk_y + input_offset_y;
blit_line(fb_width, input_label_x, input_label_y, input_label_buf,
@ -3087,11 +3106,14 @@ static void rgui_render(void *data,
bool is_idle)
{
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
static const char* const ticker_spacer = RGUI_TICKER_SPACER;
bool use_smooth_ticker;
unsigned x, y;
size_t i, end, fb_pitch, old_start, new_start;
unsigned fb_width, fb_height;
int bottom;
unsigned ticker_x_offset = 0;
size_t entries_end = 0;
bool msg_force = false;
bool fb_size_changed = false;
@ -3231,14 +3253,27 @@ static void rgui_render(void *data,
/* We use a single ticker for all text animations,
* with the following configuration: */
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
use_smooth_ticker = settings->bools.menu_ticker_smooth;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = NULL;
ticker_smooth.glyph_width = FONT_WIDTH_STRIDE;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = ticker_spacer;
ticker_smooth.dst_str_width = NULL;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = ticker_spacer;
}
/* Note: On-screen keyboard takes precedence over
* normal menu thumbnail/text list display modes */
if (current_display_cb)
rgui_render_osk(rgui, &ticker);
rgui_render_osk(rgui, &ticker, &ticker_smooth, use_smooth_ticker);
else if (rgui->show_fs_thumbnail && rgui->entry_has_thumbnail && (fs_thumbnail.is_valid || (rgui->thumbnail_queue_size > 0)))
{
/* If fullscreen thumbnails are enabled and we are viewing a playlist,
@ -3260,14 +3295,34 @@ static void rgui_render(void *data,
if (menu_thumbnail_get_label(rgui->thumbnail_path_data, &thumbnail_title))
{
/* Format thumbnail title */
ticker.s = thumbnail_title_buf;
ticker.len = rgui_term_layout.width - 10;
ticker.str = thumbnail_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
if (use_smooth_ticker)
{
ticker_smooth.selected = true;
ticker_smooth.field_width = (rgui_term_layout.width - 10) * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = thumbnail_title;
ticker_smooth.dst_str = thumbnail_title_buf;
ticker_smooth.dst_str_len = sizeof(thumbnail_title_buf);
ticker_smooth.x_offset = &ticker_x_offset;
title_width = (unsigned)(utf8len(thumbnail_title_buf) * FONT_WIDTH_STRIDE);
title_x = rgui_term_layout.start_x + ((rgui_term_layout.width * FONT_WIDTH_STRIDE) - title_width) / 2;
/* If title is scrolling, then width == field_width */
if (menu_animation_ticker_smooth(&ticker_smooth))
title_width = ticker_smooth.field_width;
else
title_width = (unsigned)(utf8len(thumbnail_title_buf) * FONT_WIDTH_STRIDE);
}
else
{
ticker.s = thumbnail_title_buf;
ticker.len = rgui_term_layout.width - 10;
ticker.str = thumbnail_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
title_width = (unsigned)(utf8len(thumbnail_title_buf) * FONT_WIDTH_STRIDE);
}
title_x = rgui_term_layout.start_x + ((rgui_term_layout.width * FONT_WIDTH_STRIDE) - title_width) / 2;
/* Draw thumbnail title background */
rgui_fill_rect(rgui_frame_buf.data, fb_width, fb_height,
@ -3275,7 +3330,7 @@ static void rgui_render(void *data,
rgui->colors.bg_dark_color, rgui->colors.bg_light_color, rgui->bg_thickness);
/* Draw thumbnail title */
blit_line(fb_width, (int)title_x, 0, thumbnail_title_buf,
blit_line(fb_width, ticker_x_offset + title_x, 0, thumbnail_title_buf,
rgui->colors.hover_color, rgui->colors.shadow_color);
}
}
@ -3390,17 +3445,36 @@ static void rgui_render(void *data,
title_max_len = rgui_term_layout.width - 5 - (powerstate_len > 5 ? powerstate_len : 5);
title_buf[0] = '\0';
ticker.s = title_buf;
ticker.len = title_max_len;
ticker.str = rgui->menu_title;
ticker.selected = true;
if (use_smooth_ticker)
{
ticker_smooth.selected = true;
ticker_smooth.field_width = title_max_len * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = rgui->menu_title;
ticker_smooth.dst_str = title_buf;
ticker_smooth.dst_str_len = sizeof(title_buf);
ticker_smooth.x_offset = &ticker_x_offset;
menu_animation_ticker(&ticker);
/* If title is scrolling, then title_len == title_max_len */
if (menu_animation_ticker_smooth(&ticker_smooth))
title_len = title_max_len;
else
title_len = utf8len(title_buf);
}
else
{
ticker.s = title_buf;
ticker.len = title_max_len;
ticker.str = rgui->menu_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
title_len = utf8len(title_buf);
}
string_to_upper(title_buf);
title_len = utf8len(title_buf);
title_x = rgui_term_layout.start_x +
title_x = ticker_x_offset + rgui_term_layout.start_x +
(rgui_term_layout.width - title_len) * FONT_WIDTH_STRIDE / 2;
/* Title is always centred, unless it is long enough
@ -3509,15 +3583,29 @@ static void rgui_render(void *data,
}
/* Format entry title string */
ticker.s = entry_title_buf;
ticker.len = entry_title_max_len;
ticker.str = entry_label;
ticker.selected = entry_selected;
if (use_smooth_ticker)
{
ticker_smooth.selected = entry_selected;
ticker_smooth.field_width = entry_title_max_len * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = entry_label;
ticker_smooth.dst_str = entry_title_buf;
ticker_smooth.dst_str_len = sizeof(entry_title_buf);
ticker_smooth.x_offset = &ticker_x_offset;
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = entry_title_buf;
ticker.len = entry_title_max_len;
ticker.str = entry_label;
ticker.selected = entry_selected;
menu_animation_ticker(&ticker);
}
/* Print entry title */
blit_line(fb_width, x + (2 * FONT_WIDTH_STRIDE), y,
blit_line(fb_width, ticker_x_offset + x + (2 * FONT_WIDTH_STRIDE), y,
entry_title_buf,
entry_color, rgui->colors.shadow_color);
@ -3525,14 +3613,27 @@ static void rgui_render(void *data,
if (entry_value_len > 0)
{
/* Format entry value string */
ticker.s = type_str_buf;
ticker.len = entry_value_len;
ticker.str = entry_value;
if (use_smooth_ticker)
{
ticker_smooth.field_width = entry_value_len * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = entry_value;
ticker_smooth.dst_str = type_str_buf;
ticker_smooth.dst_str_len = sizeof(type_str_buf);
ticker_smooth.x_offset = &ticker_x_offset;
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = type_str_buf;
ticker.len = entry_value_len;
ticker.str = entry_value;
menu_animation_ticker(&ticker);
}
/* Print entry value */
blit_line(fb_width, term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), y,
blit_line(fb_width, ticker_x_offset + term_end_x - ((entry_value_len + 1) * FONT_WIDTH_STRIDE), y,
type_str_buf,
entry_color, rgui->colors.shadow_color);
}
@ -3564,16 +3665,30 @@ static void rgui_render(void *data,
char sublabel_buf[MENU_SUBLABEL_MAX_LENGTH];
sublabel_buf[0] = '\0';
ticker.s = sublabel_buf;
ticker.len = core_name_len;
ticker.str = rgui->menu_sublabel;
ticker.selected = true;
if (use_smooth_ticker)
{
ticker_smooth.selected = true;
ticker_smooth.field_width = core_name_len * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = rgui->menu_sublabel;
ticker_smooth.dst_str = sublabel_buf;
ticker_smooth.dst_str_len = sizeof(sublabel_buf);
ticker_smooth.x_offset = &ticker_x_offset;
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = sublabel_buf;
ticker.len = core_name_len;
ticker.str = rgui->menu_sublabel;
ticker.selected = true;
menu_animation_ticker(&ticker);
}
blit_line(
fb_width,
rgui_term_layout.start_x + FONT_WIDTH_STRIDE,
ticker_x_offset + rgui_term_layout.start_x + FONT_WIDTH_STRIDE,
(rgui_term_layout.height * FONT_HEIGHT_STRIDE) +
rgui_term_layout.start_y + 2, sublabel_buf,
rgui->colors.hover_color, rgui->colors.shadow_color);
@ -3586,16 +3701,30 @@ static void rgui_render(void *data,
menu_entries_get_core_title(core_title, sizeof(core_title));
ticker.s = core_title_buf;
ticker.len = core_name_len;
ticker.str = core_title;
ticker.selected = true;
if (use_smooth_ticker)
{
ticker_smooth.selected = true;
ticker_smooth.field_width = core_name_len * FONT_WIDTH_STRIDE;
ticker_smooth.src_str = core_title;
ticker_smooth.dst_str = core_title_buf;
ticker_smooth.dst_str_len = sizeof(core_title_buf);
ticker_smooth.x_offset = &ticker_x_offset;
menu_animation_ticker(&ticker);
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = core_title_buf;
ticker.len = core_name_len;
ticker.str = core_title;
ticker.selected = true;
menu_animation_ticker(&ticker);
}
blit_line(
fb_width,
rgui_term_layout.start_x + FONT_WIDTH_STRIDE,
ticker_x_offset + rgui_term_layout.start_x + FONT_WIDTH_STRIDE,
(rgui_term_layout.height * FONT_HEIGHT_STRIDE) +
rgui_term_layout.start_y + 2, core_title_buf,
rgui->colors.hover_color, rgui->colors.shadow_color);

View File

@ -2845,7 +2845,9 @@ static int xmb_draw_item(
{
float icon_x, icon_y, label_offset;
menu_animation_ctx_ticker_t ticker;
menu_animation_ctx_ticker_smooth_t ticker_smooth;
char tmp[255];
unsigned ticker_x_offset = 0;
const char *ticker_str = NULL;
unsigned entry_type = 0;
const float half_size = xmb->icon_size / 2.0f;
@ -2856,10 +2858,25 @@ static int xmb_draw_item(
xmb_node_t * node = (xmb_node_t*)
file_list_get_userdata_at_offset(list, i);
settings_t *settings = config_get_ptr();
bool use_smooth_ticker = settings->bools.menu_ticker_smooth;
/* Initial ticker configuration */
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
if (use_smooth_ticker)
{
ticker_smooth.idx = menu_animation_get_ticker_fast_idx();
ticker_smooth.font = xmb->font;
ticker_smooth.font_scale = 1.0f;
ticker_smooth.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker_smooth.spacer = NULL;
ticker_smooth.x_offset = &ticker_x_offset;
ticker_smooth.dst_str_width = NULL;
}
else
{
ticker.idx = menu_animation_get_ticker_idx();
ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
ticker.spacer = NULL;
}
if (!node)
return 0;
@ -2979,14 +2996,27 @@ static int xmb_draw_item(
menu_entry_get_rich_label(entry, &ticker_str);
ticker.s = tmp;
ticker.len = ticker_limit;
ticker.idx = menu_animation_get_ticker_idx();
ticker.str = ticker_str;
ticker.selected = (i == current);
if (use_smooth_ticker)
{
ticker_smooth.selected = (i == current);
ticker_smooth.field_width = xmb->font_size * 0.5f * ticker_limit;
ticker_smooth.src_str = ticker_str;
ticker_smooth.dst_str = tmp;
ticker_smooth.dst_str_len = sizeof(tmp);
if (ticker.str)
menu_animation_ticker(&ticker);
if (ticker_smooth.src_str)
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = tmp;
ticker.len = ticker_limit;
ticker.str = ticker_str;
ticker.selected = (i == current);
if (ticker.str)
menu_animation_ticker(&ticker);
}
label_offset = xmb->margins_label_top;
@ -3028,7 +3058,7 @@ static int xmb_draw_item(
}
xmb_draw_text(video_info, xmb, tmp,
node->x + xmb->margins_screen_left +
(float)ticker_x_offset + node->x + xmb->margins_screen_left +
xmb->icon_spacing_horizontal + xmb->margins_label_left,
xmb->margins_screen_top + node->y + label_offset,
1, node->label_alpha, TEXT_ALIGN_LEFT,
@ -3036,23 +3066,31 @@ static int xmb_draw_item(
tmp[0] = '\0';
ticker.s = tmp;
ticker.len = 35 * scale_mod[7];
ticker.idx = menu_animation_get_ticker_idx();
ticker.selected = (i == current);
if (!string_is_empty(entry->value))
if (use_smooth_ticker)
{
const char *entry_value = NULL;
menu_entry_get_value(entry, &entry_value);
ticker.str = entry_value;
ticker_smooth.selected = (i == current);
ticker_smooth.field_width = xmb->font_size * 0.5f * 35 * scale_mod[7];
ticker_smooth.src_str = entry->value;
ticker_smooth.dst_str = tmp;
ticker_smooth.dst_str_len = sizeof(tmp);
menu_animation_ticker(&ticker);
if (!string_is_empty(entry->value))
menu_animation_ticker_smooth(&ticker_smooth);
}
else
{
ticker.s = tmp;
ticker.len = 35 * scale_mod[7];
ticker.selected = (i == current);
ticker.str = entry->value;
if (!string_is_empty(entry->value))
menu_animation_ticker(&ticker);
}
if (do_draw_text)
xmb_draw_text(video_info, xmb, tmp,
node->x +
(float)ticker_x_offset + node->x +
+ xmb->margins_screen_left
+ xmb->icon_spacing_horizontal
+ xmb->margins_label_left

View File

@ -65,6 +65,7 @@ typedef struct menu_animation menu_animation_t;
#define TICKER_SPEED 333
#define TICKER_SLOW_SPEED 1600
#define TICKER_FAST_SPEED 16
static const char ticker_spacer_default[] = TICKER_SPACER_DEFAULT;
@ -73,6 +74,7 @@ static retro_time_t cur_time = 0;
static retro_time_t old_time = 0;
static uint64_t ticker_idx = 0; /* updated every TICKER_SPEED ms */
static uint64_t ticker_slow_idx = 0; /* updated every TICKER_SLOW_SPEED ms */
static uint64_t ticker_fast_idx = 0; /* updated every TICKER_FAST_SPEED ms */
static float delta_time = 0.0f;
static bool animation_is_active = false;
static bool ticker_is_active = false;
@ -387,6 +389,235 @@ static void menu_animation_ticker_loop(uint64_t idx,
*width3 = width;
}
static void ticker_smooth_scan_characters(
const unsigned *char_widths, size_t num_chars, unsigned field_width, unsigned scroll_offset,
unsigned *char_offset, unsigned *num_chars_to_copy, unsigned *x_offset,
unsigned *str_width, unsigned *display_width)
{
unsigned text_width = 0;
unsigned scroll_pos = scroll_offset;
bool deferred_str_width = true;
unsigned i;
/* Initialise output variables to 'sane' values */
*char_offset = 0;
*num_chars_to_copy = 0;
*x_offset = 0;
if (str_width)
*str_width = 0;
if (display_width)
*display_width = 0;
/* Determine index of first character to copy */
if (scroll_pos == 0)
{
*char_offset = 0;
*x_offset = 0;
}
else
{
for (i = 0; i < num_chars; i++)
{
if (scroll_pos > char_widths[i])
scroll_pos -= char_widths[i];
else
{
/* Note: It's okay for char_offset to go out
* of range here (num_chars_to_copy will be zero
* in this case) */
*char_offset = i + 1;
*x_offset = char_widths[i] - scroll_pos;
break;
}
}
}
/* Determine number of characters to copy */
for (i = *char_offset; i < num_chars; i++)
{
text_width += char_widths[i];
if (*x_offset + text_width <= field_width)
(*num_chars_to_copy)++;
else
{
/* Get actual width of resultant string
* (excluding x offset + end padding)
* Note that this is only set if we exceed the
* field width - if all characters up to the end
* of the string are copied... */
if (str_width)
{
deferred_str_width = false;
*str_width = text_width - char_widths[i];
}
break;
}
}
/* ...then we have to update str_width here instead */
if (str_width)
if (deferred_str_width)
*str_width = text_width;
/* Get total display width of resultant string
* (x offset + text width + end padding) */
if (display_width)
{
*display_width = *x_offset + text_width;
*display_width = (*display_width > field_width) ? field_width : *display_width;
}
}
static void menu_animation_ticker_smooth_generic(uint64_t idx,
const unsigned *char_widths, size_t num_chars, unsigned str_width, unsigned field_width,
unsigned *char_offset, unsigned *num_chars_to_copy, unsigned *x_offset, unsigned *dst_str_width)
{
unsigned scroll_width = str_width - field_width;
unsigned scroll_offset = 0;
unsigned pause_duration = 32;
unsigned ticker_period = 2 * (scroll_width + pause_duration);
unsigned phase = idx % ticker_period;
/* Initialise output variables to 'sane' values */
*char_offset = 0;
*num_chars_to_copy = 0;
*x_offset = 0;
if (dst_str_width)
*dst_str_width = 0;
/* Sanity check */
if (num_chars < 1)
return;
/* Determine scroll offset */
if (phase < pause_duration)
scroll_offset = 0;
else if (phase < ticker_period >> 1)
scroll_offset = phase - pause_duration;
else if (phase < (ticker_period >> 1) + pause_duration)
scroll_offset = (ticker_period - (2 * pause_duration)) >> 1;
else
scroll_offset = ticker_period - phase;
ticker_smooth_scan_characters(
char_widths, num_chars, field_width, scroll_offset,
char_offset, num_chars_to_copy, x_offset, dst_str_width, NULL);
}
static void menu_animation_ticker_smooth_loop(uint64_t idx,
const unsigned *char_widths, size_t num_chars,
const unsigned *spacer_widths, size_t num_spacer_chars,
unsigned str_width, unsigned spacer_width, unsigned field_width,
unsigned *char_offset1, unsigned *num_chars_to_copy1,
unsigned *char_offset2, unsigned *num_chars_to_copy2,
unsigned *char_offset3, unsigned *num_chars_to_copy3,
unsigned *x_offset, unsigned *dst_str_width)
{
unsigned ticker_period = str_width + spacer_width;
unsigned phase = idx % ticker_period;
unsigned remaining_width = field_width;
/* Initialise output variables to 'sane' values */
*char_offset1 = 0;
*num_chars_to_copy1 = 0;
*char_offset2 = 0;
*num_chars_to_copy2 = 0;
*char_offset3 = 0;
*num_chars_to_copy3 = 0;
*x_offset = 0;
if (dst_str_width)
*dst_str_width = 0;
/* Looping text is composed of up to three strings,
* where string 1 and 2 are different regions of the
* source text and string 2 is a spacer:
*
* |----field_width----|
* [string 1][string 2][string 3]
*/
/* String 1 */
if (phase < str_width)
{
unsigned scroll_offset = phase;
unsigned display_width = 0;
unsigned str1_width = 0;
ticker_smooth_scan_characters(
char_widths, num_chars, remaining_width, scroll_offset,
char_offset1, num_chars_to_copy1, x_offset, &str1_width, &display_width);
/* Update remaining width */
remaining_width -= display_width;
/* Update dst_str_width */
if (dst_str_width)
*dst_str_width += str1_width;
}
/* String 2 */
if (remaining_width > 0)
{
unsigned scroll_offset = 0;
unsigned display_width = 0;
unsigned str2_width = 0;
unsigned x_offset2 = 0;
/* Check whether we've passed the end of string 1 */
if (phase > str_width)
scroll_offset = phase - str_width;
else
scroll_offset = 0;
ticker_smooth_scan_characters(
spacer_widths, num_spacer_chars, remaining_width, scroll_offset,
char_offset2, num_chars_to_copy2, &x_offset2, &str2_width, &display_width);
/* > Update remaining width */
remaining_width -= display_width;
/* Update dst_str_width */
if (dst_str_width)
*dst_str_width += str2_width;
/* If scroll_offset is greater than zero, it means
* string 2 is the first string to be displayed
* > ticker x offset is therefore string 2's offset */
if (scroll_offset > 0)
*x_offset = x_offset2;
}
/* String 3 */
if (remaining_width > 0)
{
/* String 3 is only shown when string 2 is shown,
* so we can take some shortcuts... */
unsigned i;
unsigned text_width = 0;
*char_offset3 = 0;
/* Determine number of characters to copy */
for (i = 0; i < num_chars; i++)
{
text_width += char_widths[i];
if (text_width <= remaining_width)
(*num_chars_to_copy3)++;
else
{
/* Update dst_str_width */
if (dst_str_width)
*dst_str_width += text_width - char_widths[i];
break;
}
}
}
}
static size_t get_line_display_ticks(size_t line_width)
{
/* Mean human reading speed for all western languages,
@ -619,6 +850,11 @@ static void menu_animation_update_time(bool timedate_enable)
last_ticker_update = 0;
static retro_time_t
last_ticker_slow_update = 0;
static retro_time_t
last_ticker_fast_update = 0;
static float ticker_fast_accumulator = 0.0L;
unsigned ticker_fast_accumulator_uint = 0;
/* Adjust ticker speed */
settings_t *settings = config_get_ptr();
@ -638,18 +874,35 @@ static void menu_animation_update_time(bool timedate_enable)
last_clock_update = cur_time;
}
if (ticker_is_active
&& cur_time - last_ticker_update >= ticker_speed)
if (ticker_is_active)
{
ticker_idx++;
last_ticker_update = cur_time;
}
if (cur_time - last_ticker_update >= ticker_speed)
{
ticker_idx++;
last_ticker_update = cur_time;
}
if (ticker_is_active
&& cur_time - last_ticker_slow_update >= ticker_slow_speed)
{
ticker_slow_idx++;
last_ticker_slow_update = cur_time;
if (cur_time - last_ticker_slow_update >= ticker_slow_speed)
{
ticker_slow_idx++;
last_ticker_slow_update = cur_time;
}
if (cur_time - last_ticker_fast_update >= TICKER_FAST_SPEED)
{
/* ticker fast updates approximately every frame, so
* have to handle the speed setting differently... */
ticker_fast_accumulator += speed_factor * 0.5f;
ticker_fast_accumulator_uint = (unsigned)ticker_fast_accumulator;
if (ticker_fast_accumulator_uint > 0)
{
ticker_fast_idx += ticker_fast_accumulator_uint;
ticker_fast_accumulator -= (float)ticker_fast_accumulator_uint;
}
last_ticker_fast_update = cur_time;
}
}
}
@ -826,6 +1079,292 @@ bool menu_animation_ticker(menu_animation_ctx_ticker_t *ticker)
return true;
}
bool menu_animation_ticker_smooth(menu_animation_ctx_ticker_smooth_t *ticker)
{
size_t i;
size_t src_str_len = 0;
size_t spacer_len = 0;
unsigned src_str_width = 0;
unsigned spacer_width = 0;
unsigned *src_char_widths = NULL;
unsigned *spacer_char_widths = NULL;
bool success = false;
bool is_active = false;
/* Sanity check */
if (string_is_empty(ticker->src_str) ||
(ticker->dst_str_len < 1) ||
(ticker->field_width < 1) ||
(!ticker->font && (ticker->glyph_width < 1)))
goto end;
/* Find the display width of each character in
* the src string + total width */
src_str_len = utf8len(ticker->src_str);
if (src_str_len < 1)
goto end;
src_char_widths = (unsigned*)calloc(src_str_len, sizeof(unsigned));
if (!src_char_widths)
goto end;
/* > If a font is provided, have to do this
* 'the hard way'
* (Note: we branch externally rather than inside
* for loop - this is ugly, but improves performance) */
if (ticker->font)
{
const char *str_ptr = ticker->src_str;
for (i = 0; i < src_str_len; i++)
{
int glyph_width = font_driver_get_message_width(
ticker->font, str_ptr, 1, ticker->font_scale);
if (glyph_width < 0)
goto end;
src_char_widths[i] = (unsigned)glyph_width;
src_str_width += (unsigned)glyph_width;
str_ptr = utf8skip(str_ptr, 1);
}
}
/* > If font is not provided, just use fallback width */
else
{
unsigned glyph_width = ticker->glyph_width;
for (i = 0; i < src_str_len; i++)
{
src_char_widths[i] = glyph_width;
src_str_width += glyph_width;
}
}
/* If total src string width is <= text field width, we
* can just copy the entire string */
if (src_str_width <= ticker->field_width)
{
utf8cpy(ticker->dst_str, ticker->dst_str_len, ticker->src_str, src_str_len);
if (ticker->dst_str_width)
*ticker->dst_str_width = src_str_width;
*ticker->x_offset = 0;
success = true;
goto end;
}
/* If entry is not selected, just clip input string
* and add '...' suffix */
if (!ticker->selected)
{
unsigned text_width;
unsigned current_width = 0;
unsigned num_chars = 0;
int period_width = 0;
if (ticker->font)
period_width = font_driver_get_message_width(ticker->font, ".", 1, ticker->font_scale);
else
period_width = ticker->glyph_width;
if (period_width < 0)
goto end;
/* Sanity check */
if (ticker->field_width < (3 * period_width))
goto end;
/* Determine number of characters to copy */
text_width = ticker->field_width - (3 * period_width);
while (true)
{
current_width += src_char_widths[num_chars];
if (current_width > text_width)
{
/* Have to go back one in order to get 'actual'
* value for dst_str_width */
current_width -= src_char_widths[num_chars];
break;
}
num_chars++;
}
/* Copy string segment + add suffix */
utf8cpy(ticker->dst_str, ticker->dst_str_len, ticker->src_str, num_chars);
strlcat(ticker->dst_str, "...", ticker->dst_str_len);
if (ticker->dst_str_width)
*ticker->dst_str_width = current_width + (3 * period_width);
*ticker->x_offset = 0;
success = true;
goto end;
}
/* If we get this far, then a scrolling animation
* is required... */
/* Use default spacer, if none is provided */
if (!ticker->spacer)
ticker->spacer = ticker_spacer_default;
/* Find the display width of each character in
* the spacer */
spacer_len = utf8len(ticker->spacer);
if (spacer_len < 1)
goto end;
spacer_char_widths = (unsigned*)calloc(spacer_len, sizeof(unsigned));
if (!spacer_char_widths)
goto end;
/* > If a font is provided, have to do this
* 'the hard way'
* (Note: we branch externally rather than inside
* for loop - this is ugly, but improves performance) */
if (ticker->font)
{
const char *str_ptr = ticker->spacer;
for (i = 0; i < spacer_len; i++)
{
int glyph_width = font_driver_get_message_width(
ticker->font, str_ptr, 1, ticker->font_scale);
if (glyph_width < 0)
goto end;
spacer_char_widths[i] = (unsigned)glyph_width;
spacer_width += (unsigned)glyph_width;
str_ptr = utf8skip(str_ptr, 1);
}
}
else
{
unsigned glyph_width = ticker->glyph_width;
for (i = 0; i < spacer_len; i++)
{
spacer_char_widths[i] = glyph_width;
spacer_width += glyph_width;
}
}
/* Determine animation type */
switch (ticker->type_enum)
{
case TICKER_TYPE_LOOP:
{
unsigned char_offset1 = 0;
unsigned num_chars1 = 0;
unsigned char_offset2 = 0;
unsigned num_chars2 = 0;
unsigned char_offset3 = 0;
unsigned num_chars3 = 0;
char tmp[PATH_MAX_LENGTH];
tmp[0] = '\0';
ticker->dst_str[0] = '\0';
menu_animation_ticker_smooth_loop(
ticker->idx,
src_char_widths, src_str_len,
spacer_char_widths, spacer_len,
src_str_width, spacer_width, ticker->field_width,
&char_offset1, &num_chars1,
&char_offset2, &num_chars2,
&char_offset3, &num_chars3,
ticker->x_offset, ticker->dst_str_width);
/* Copy 'trailing' chunk of source string, if required */
if (num_chars1 > 0)
{
utf8cpy(
ticker->dst_str, ticker->dst_str_len,
utf8skip(ticker->src_str, char_offset1), num_chars1);
}
/* Copy chunk of spacer string, if required */
if (num_chars2 > 0)
{
utf8cpy(
tmp, sizeof(tmp),
utf8skip(ticker->spacer, char_offset2), num_chars2);
strlcat(ticker->dst_str, tmp, ticker->dst_str_len);
}
/* Copy 'leading' chunk of source string, if required */
if (num_chars3 > 0)
{
utf8cpy(
tmp, sizeof(tmp),
utf8skip(ticker->src_str, char_offset3), num_chars3);
strlcat(ticker->dst_str, tmp, ticker->dst_str_len);
}
break;
}
case TICKER_TYPE_BOUNCE:
default:
{
unsigned char_offset = 0;
unsigned num_chars = 0;
ticker->dst_str[0] = '\0';
menu_animation_ticker_smooth_generic(
ticker->idx,
src_char_widths, src_str_len, src_str_width, ticker->field_width,
&char_offset, &num_chars, ticker->x_offset, ticker->dst_str_width);
/* Copy required substring */
if (num_chars > 0)
{
utf8cpy(
ticker->dst_str, ticker->dst_str_len,
utf8skip(ticker->src_str, char_offset), num_chars);
}
break;
}
}
success = true;
is_active = true;
ticker_is_active = true;
end:
if (src_char_widths)
{
free(src_char_widths);
src_char_widths = NULL;
}
if (spacer_char_widths)
{
free(spacer_char_widths);
spacer_char_widths = NULL;
}
if (!success)
{
*ticker->x_offset = 0;
if (ticker->dst_str_len > 0)
ticker->dst_str[0] = '\0';
}
return is_active;
}
bool menu_animation_line_ticker(menu_animation_ctx_line_ticker_t *line_ticker)
{
size_t i;
@ -1094,3 +1633,8 @@ uint64_t menu_animation_get_ticker_slow_idx(void)
{
return ticker_slow_idx;
}
uint64_t menu_animation_get_ticker_fast_idx(void)
{
return ticker_fast_idx;
}

View File

@ -23,6 +23,8 @@
#include <boolean.h>
#include <retro_common_api.h>
#include "../gfx/font_driver.h"
RETRO_BEGIN_DECLS
#define TICKER_SPACER_DEFAULT " | "
@ -126,6 +128,23 @@ typedef struct menu_animation_ctx_ticker
const char *spacer;
} menu_animation_ctx_ticker_t;
typedef struct menu_animation_ctx_ticker_smooth
{
bool selected;
font_data_t *font;
float font_scale;
unsigned glyph_width; /* Fallback if font == NULL */
unsigned field_width;
enum menu_animation_ticker_type type_enum;
uint64_t idx;
const char *src_str;
const char *spacer;
char *dst_str;
size_t dst_str_len;
unsigned *dst_str_width; /* May be set to NULL (RGUI + XMB do not require this info) */
unsigned *x_offset;
} menu_animation_ctx_ticker_smooth_t;
typedef struct menu_animation_ctx_line_ticker
{
size_t line_width;
@ -160,6 +179,8 @@ bool menu_animation_update(void);
bool menu_animation_ticker(menu_animation_ctx_ticker_t *ticker);
bool menu_animation_ticker_smooth(menu_animation_ctx_ticker_smooth_t *ticker);
bool menu_animation_line_ticker(menu_animation_ctx_line_ticker_t *line_ticker);
float menu_animation_get_delta_time(void);
@ -180,6 +201,8 @@ uint64_t menu_animation_get_ticker_idx(void);
uint64_t menu_animation_get_ticker_slow_idx(void);
uint64_t menu_animation_get_ticker_fast_idx(void);
RETRO_END_DECLS
#endif

View File

@ -5214,6 +5214,7 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct
{MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_MENU_TICKER_TYPE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_MENU_TICKER_SPEED, PARSE_ONLY_FLOAT},
{MENU_ENUM_LABEL_MENU_TICKER_SMOOTH, PARSE_ONLY_BOOL },
{MENU_ENUM_LABEL_MENU_RGUI_EXTENDED_ASCII, PARSE_ONLY_BOOL },
};

View File

@ -11567,6 +11567,21 @@ static bool setting_append_list(
(*list)[list_info->index - 1].action_ok = &setting_action_ok_uint;
menu_settings_list_current_add_range(list, list_info, 0.1, 10.0, 0.1, true, true);
CONFIG_BOOL(
list, list_info,
&settings->bools.menu_ticker_smooth,
MENU_ENUM_LABEL_MENU_TICKER_SMOOTH,
MENU_ENUM_LABEL_VALUE_MENU_TICKER_SMOOTH,
menu_ticker_smooth,
MENU_ENUM_LABEL_VALUE_OFF,
MENU_ENUM_LABEL_VALUE_ON,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler,
SD_FLAG_NONE);
END_SUB_GROUP(list, list_info, parent_group);
START_SUB_GROUP(list, list_info, "Navigation", &group_info, &subgroup_info, parent_group);

View File

@ -986,6 +986,7 @@ enum msg_hash_enums
MENU_LABEL(QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS),
MENU_LABEL(MENU_TICKER_TYPE),
MENU_LABEL(MENU_TICKER_SPEED),
MENU_LABEL(MENU_TICKER_SMOOTH),
MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_BOUNCE,
MENU_ENUM_LABEL_VALUE_MENU_TICKER_TYPE_LOOP,