mirror of
https://github.com/libretro/RetroArch.git
synced 2025-02-04 00:06:11 +00:00
Merge pull request #9333 from jdgleaver/smooth-ticker
Add optional smooth scrolling menu ticker text
This commit is contained in:
commit
35c336e3ab
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user