mirror of
https://github.com/libretro/RetroArch
synced 2025-04-10 15:45:19 +00:00
(XMB) Fix display of long sublabels
This commit is contained in:
parent
9e39220390
commit
7822a2d611
@ -2850,6 +2850,7 @@ static int xmb_draw_item(
|
|||||||
uintptr_t texture_switch = 0;
|
uintptr_t texture_switch = 0;
|
||||||
bool do_draw_text = false;
|
bool do_draw_text = false;
|
||||||
unsigned ticker_limit = 35 * scale_mod[0];
|
unsigned ticker_limit = 35 * scale_mod[0];
|
||||||
|
unsigned line_ticker_width = 45 * scale_mod[3];
|
||||||
xmb_node_t * node = (xmb_node_t*)
|
xmb_node_t * node = (xmb_node_t*)
|
||||||
file_list_get_userdata_at_offset(list, i);
|
file_list_get_userdata_at_offset(list, i);
|
||||||
settings_t *settings = config_get_ptr();
|
settings_t *settings = config_get_ptr();
|
||||||
@ -2951,16 +2952,27 @@ static int xmb_draw_item(
|
|||||||
&& settings->bools.menu_xmb_vertical_thumbnails)
|
&& settings->bools.menu_xmb_vertical_thumbnails)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ticker_limit = 40 * scale_mod[1];
|
ticker_limit = 40 * scale_mod[1];
|
||||||
|
line_ticker_width = 50 * scale_mod[3];
|
||||||
|
|
||||||
/* Can increase text length if thumbnail is downscaled */
|
/* Can increase text length if thumbnail is downscaled */
|
||||||
if (settings->uints.menu_xmb_thumbnail_scale_factor < 100)
|
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 +=
|
ticker_limit +=
|
||||||
(unsigned)((1.0f - ((float)settings->uints.menu_xmb_thumbnail_scale_factor / 100.0f)) *
|
(unsigned)(ticker_scale_factor * 15.0f * scale_mod[1]);
|
||||||
15.0f * scale_mod[1]);
|
|
||||||
|
line_ticker_width +=
|
||||||
|
(unsigned)(ticker_scale_factor * 10.0f * scale_mod[3]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ticker_limit = 70 * scale_mod[2];
|
{
|
||||||
|
ticker_limit = 70 * scale_mod[2];
|
||||||
|
line_ticker_width = 60 * scale_mod[3];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_entry_get_rich_label(entry, &ticker_str);
|
menu_entry_get_rich_label(entry, &ticker_str);
|
||||||
@ -2981,11 +2993,26 @@ static int xmb_draw_item(
|
|||||||
if (i == current && width > 320 && height > 240
|
if (i == current && width > 320 && height > 240
|
||||||
&& !string_is_empty(entry->sublabel))
|
&& !string_is_empty(entry->sublabel))
|
||||||
{
|
{
|
||||||
|
menu_animation_ctx_line_ticker_t line_ticker;
|
||||||
char entry_sublabel[512] = {0};
|
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,
|
xmb_draw_text(video_info, xmb, entry_sublabel,
|
||||||
node->x + xmb->margins_screen_left +
|
node->x + xmb->margins_screen_left +
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <features/features_cpu.h>
|
#include <features/features_cpu.h>
|
||||||
|
#include <lists/string_list.h>
|
||||||
|
|
||||||
#define DG_DYNARR_IMPLEMENTATION
|
#define DG_DYNARR_IMPLEMENTATION
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -386,6 +387,60 @@ static void menu_animation_ticker_loop(uint64_t idx,
|
|||||||
*width3 = width;
|
*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)
|
static void menu_delayed_animation_cb(void *userdata)
|
||||||
{
|
{
|
||||||
menu_delayed_animation_t *delayed_animation = (menu_delayed_animation_t*) 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;
|
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)
|
bool menu_animation_is_active(void)
|
||||||
{
|
{
|
||||||
return animation_is_active || ticker_is_active;
|
return animation_is_active || ticker_is_active;
|
||||||
|
@ -126,6 +126,17 @@ typedef struct menu_animation_ctx_ticker
|
|||||||
const char *spacer;
|
const char *spacer;
|
||||||
} menu_animation_ctx_ticker_t;
|
} 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 float menu_timer_t;
|
||||||
|
|
||||||
typedef struct menu_timer_ctx_entry
|
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_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);
|
float menu_animation_get_delta_time(void);
|
||||||
|
|
||||||
bool menu_animation_is_active(void);
|
bool menu_animation_is_active(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user