Merge pull request #9128 from jdgleaver/xmb-sublabel-ticker

(XMB) Fix display of long sublabels
This commit is contained in:
Twinaphex 2019-07-18 18:52:16 +02:00 committed by GitHub
commit 68872f7f55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 220 additions and 6 deletions

View File

@ -2850,6 +2850,7 @@ static int xmb_draw_item(
uintptr_t texture_switch = 0;
bool do_draw_text = false;
unsigned ticker_limit = 35 * scale_mod[0];
unsigned line_ticker_width = 45 * scale_mod[3];
xmb_node_t * node = (xmb_node_t*)
file_list_get_userdata_at_offset(list, i);
settings_t *settings = config_get_ptr();
@ -2952,15 +2953,26 @@ static int xmb_draw_item(
)
{
ticker_limit = 40 * scale_mod[1];
line_ticker_width = 50 * scale_mod[3];
/* Can increase text length if thumbnail is downscaled */
if (settings->uints.menu_xmb_thumbnail_scale_factor < 100)
{
float ticker_scale_factor =
1.0f - ((float)settings->uints.menu_xmb_thumbnail_scale_factor / 100.0f);
ticker_limit +=
(unsigned)((1.0f - ((float)settings->uints.menu_xmb_thumbnail_scale_factor / 100.0f)) *
15.0f * scale_mod[1]);
(unsigned)(ticker_scale_factor * 15.0f * scale_mod[1]);
line_ticker_width +=
(unsigned)(ticker_scale_factor * 10.0f * scale_mod[3]);
}
}
else
{
ticker_limit = 70 * scale_mod[2];
line_ticker_width = 60 * scale_mod[3];
}
}
menu_entry_get_rich_label(entry, &ticker_str);
@ -2981,11 +2993,26 @@ static int xmb_draw_item(
if (i == current && width > 320 && height > 240
&& !string_is_empty(entry->sublabel))
{
menu_animation_ctx_line_ticker_t line_ticker;
char entry_sublabel[512] = {0};
label_offset = - xmb->margins_label_top;
line_ticker.type_enum = (enum menu_animation_ticker_type)settings->uints.menu_ticker_type;
line_ticker.idx = menu_animation_get_ticker_idx();
word_wrap(entry_sublabel, entry->sublabel, 50 * scale_mod[3], true, 0);
line_ticker.line_width = (size_t)(line_ticker_width);
/* Note: max_lines should be calculated at runtime,
* but this is a nuisance. There is room for 4 lines
* to be displayed when using all existing XMB themes,
* so leave this value hard coded for now. */
line_ticker.max_lines = 4;
line_ticker.s = entry_sublabel;
line_ticker.len = sizeof(entry_sublabel);
line_ticker.str = entry->sublabel;
menu_animation_line_ticker(&line_ticker);
label_offset = - xmb->margins_label_top;
xmb_draw_text(video_info, xmb, entry_sublabel,
node->x + xmb->margins_screen_left +

View File

@ -23,6 +23,7 @@
#include <retro_miscellaneous.h>
#include <string/stdstring.h>
#include <features/features_cpu.h>
#include <lists/string_list.h>
#define DG_DYNARR_IMPLEMENTATION
#include <stdio.h>
@ -386,6 +387,60 @@ static void menu_animation_ticker_loop(uint64_t idx,
*width3 = width;
}
static size_t get_line_display_ticks(size_t line_width)
{
/* Mean human reading speed for all western languages,
* characters per minute */
float cpm = 1000.0f;
/* Base time for which a line should be shown, in ms */
float line_duration = (line_width * 60.0f * 1000.0f) / cpm;
/* Ticker updates (nominally) once every TICKER_SPEED ms
* > Return base number of ticks for which line should be shown */
return (size_t)(line_duration / (float)TICKER_SPEED);
}
static void menu_animation_line_ticker_generic(uint64_t idx,
size_t line_width, size_t max_lines, size_t num_lines,
size_t *line_offset)
{
size_t line_ticks = get_line_display_ticks(line_width);
/* Note: This function is only called if num_lines > max_lines */
size_t excess_lines = num_lines - max_lines;
/* Ticker will pause for one line duration when the first
* or last line is reached (this is mostly required for the
* case where num_lines == (max_lines + 1), since otherwise
* the text flicks rapidly up and down in disconcerting
* fashion...) */
size_t ticker_period = (excess_lines * 2) + 2;
size_t phase = (idx / line_ticks) % ticker_period;
/* Pause on first line */
if (phase > 0)
phase--;
/* Pause on last line */
if (phase > excess_lines)
phase--;
/* Lines scrolling upwards */
if (phase <= excess_lines)
*line_offset = phase;
/* Lines scrolling downwards */
else
*line_offset = (excess_lines * 2) - phase;
}
static void menu_animation_line_ticker_loop(uint64_t idx,
size_t line_width, size_t num_lines,
size_t *line_offset)
{
size_t line_ticks = get_line_display_ticks(line_width);
size_t ticker_period = num_lines + 1;
size_t phase = (idx / line_ticks) % ticker_period;
/* In this case, line_offset is simply equal to the phase */
*line_offset = phase;
}
static void menu_delayed_animation_cb(void *userdata)
{
menu_delayed_animation_t *delayed_animation = (menu_delayed_animation_t*) userdata;
@ -771,6 +826,125 @@ bool menu_animation_ticker(menu_animation_ctx_ticker_t *ticker)
return true;
}
bool menu_animation_line_ticker(menu_animation_ctx_line_ticker_t *line_ticker)
{
size_t i;
char *wrapped_str = NULL;
struct string_list *lines = NULL;
size_t line_offset = 0;
bool success = false;
bool is_active = false;
/* Sanity check */
if (!line_ticker)
return false;
if (string_is_empty(line_ticker->str) ||
(line_ticker->line_width < 1) ||
(line_ticker->max_lines < 1))
goto end;
/* Line wrap input string */
wrapped_str = (char*)malloc((strlen(line_ticker->str) + 1) * sizeof(char));
if (!wrapped_str)
goto end;
word_wrap(
wrapped_str,
line_ticker->str,
(int)line_ticker->line_width,
true, 0);
if (string_is_empty(wrapped_str))
goto end;
/* Split into component lines */
lines = string_split(wrapped_str, "\n");
if (!lines)
goto end;
/* Check whether total number of lines fits within
* the set limit */
if (lines->size <= line_ticker->max_lines)
{
strlcpy(line_ticker->s, wrapped_str, line_ticker->len);
success = true;
goto end;
}
/* Determine offset of first line in wrapped string */
switch (line_ticker->type_enum)
{
case TICKER_TYPE_LOOP:
{
menu_animation_line_ticker_loop(
line_ticker->idx,
line_ticker->line_width,
lines->size,
&line_offset);
break;
}
case TICKER_TYPE_BOUNCE:
default:
{
menu_animation_line_ticker_generic(
line_ticker->idx,
line_ticker->line_width,
line_ticker->max_lines,
lines->size,
&line_offset);
break;
}
}
/* Build output string from required lines */
for (i = 0; i < line_ticker->max_lines; i++)
{
size_t offset = i + line_offset;
size_t line_index = 0;
bool line_valid = true;
if (offset < lines->size)
line_index = offset;
else if (offset > lines->size)
line_index = (offset - 1) - lines->size;
else
line_valid = false;
if (line_valid)
strlcat(line_ticker->s, lines->elems[line_index].data, line_ticker->len);
if (i < line_ticker->max_lines - 1)
strlcat(line_ticker->s, "\n", line_ticker->len);
}
success = true;
is_active = true;
ticker_is_active = true;
end:
if (wrapped_str)
{
free(wrapped_str);
wrapped_str = NULL;
}
if (lines)
{
string_list_free(lines);
lines = NULL;
}
if (!success)
if (line_ticker->len > 0)
line_ticker->s[0] = '\0';
return is_active;
}
bool menu_animation_is_active(void)
{
return animation_is_active || ticker_is_active;

View File

@ -126,6 +126,17 @@ typedef struct menu_animation_ctx_ticker
const char *spacer;
} menu_animation_ctx_ticker_t;
typedef struct menu_animation_ctx_line_ticker
{
size_t line_width;
size_t max_lines;
uint64_t idx;
enum menu_animation_ticker_type type_enum;
char *s;
size_t len;
const char *str;
} menu_animation_ctx_line_ticker_t;
typedef float menu_timer_t;
typedef struct menu_timer_ctx_entry
@ -149,6 +160,8 @@ bool menu_animation_update(void);
bool menu_animation_ticker(menu_animation_ctx_ticker_t *ticker);
bool menu_animation_line_ticker(menu_animation_ctx_line_ticker_t *line_ticker);
float menu_animation_get_delta_time(void);
bool menu_animation_is_active(void);