Refactor menu_animation.c

This commit is contained in:
twinaphex 2015-09-06 02:41:36 +02:00
parent 17797ee156
commit 8405f76ff3
12 changed files with 136 additions and 97 deletions

View File

@ -451,7 +451,7 @@ static void general_disp_set_label_perf_counters(
const char *path, unsigned *w const char *path, unsigned *w
) )
{ {
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
*s = '\0'; *s = '\0';
*w = 19; *w = 19;
@ -460,8 +460,7 @@ static void general_disp_set_label_perf_counters(
menu_action_setting_disp_set_label_perf_counters_common( menu_action_setting_disp_set_label_perf_counters_common(
counters, offset, s, len); counters, offset, s, len);
if (anim) menu_animation_set_active(anim);
anim->label.is_updated = true;
} }
static void menu_action_setting_disp_set_label_perf_counters( static void menu_action_setting_disp_set_label_perf_counters(

View File

@ -257,7 +257,7 @@ static void glui_render(void)
glui = (glui_handle_t*)menu->userdata; glui = (glui_handle_t*)menu->userdata;
menu_animation_update(disp->animation, menu_animation_update(disp->animation,
disp->animation->delta_time / IDEAL_DT); menu_animation_get_delta_time(disp->animation) / IDEAL_DT);
/* TODO/FIXME - we don't use framebuffer at all /* TODO/FIXME - we don't use framebuffer at all
* for GLUI, we should refactor this dependency * for GLUI, we should refactor this dependency
@ -383,7 +383,7 @@ static void glui_frame(void)
const struct font_renderer *font_driver = NULL; const struct font_renderer *font_driver = NULL;
driver_t *driver = driver_get_ptr(); driver_t *driver = driver_get_ptr();
menu_handle_t *menu = menu_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_navigation_t *nav = menu_navigation_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr();
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
@ -432,8 +432,7 @@ static void glui_frame(void)
disp->header_height - menu->scroll_y + glui->line_height * disp->header_height - menu->scroll_y + glui->line_height *
menu_navigation_get_selection(nav), width, glui->line_height, 1, 1, 1, 0.1); menu_navigation_get_selection(nav), width, glui->line_height, 1, 1, 1, 0.1);
anim->is_active = true; menu_animation_set_active(anim);
anim->label.is_updated = false;
glui_render_quad(gl, 0, 0, width, glui_render_quad(gl, 0, 0, width,
disp->header_height, 0.2, 0.2, 0.2, 1); disp->header_height, 0.2, 0.2, 0.2, 1);

View File

@ -257,10 +257,9 @@ static void rgui_render_background(void)
static void rgui_set_message(const char *message) static void rgui_set_message(const char *message)
{ {
menu_handle_t *menu = menu_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr();
rgui_t *rgui = NULL; rgui_t *rgui = NULL;
if (!menu || !menu->userdata || !anim || !message || !*message) if (!menu || !menu->userdata || !message || !*message)
return; return;
rgui = (rgui_t*)menu->userdata; rgui = (rgui_t*)menu->userdata;
@ -371,7 +370,7 @@ static void rgui_render(void)
menu_navigation_t *nav = menu_navigation_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr();
driver_t *driver = driver_get_ptr(); driver_t *driver = driver_get_ptr();
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
uint64_t *frame_count = video_driver_get_frame_count(); uint64_t *frame_count = video_driver_get_frame_count();
rgui_t *rgui = NULL; rgui_t *rgui = NULL;
@ -408,11 +407,9 @@ static void rgui_render(void)
rgui->last_height = frame_buf->height; rgui->last_height = frame_buf->height;
} }
/* ensures the framebuffer will be rendered on the screen */ /* ensures the framebuffer will be rendered on the screen */
menu_display_fb_set_dirty(); menu_display_fb_set_dirty();
anim->is_active = false; menu_animation_clear_active(anim);
anim->label.is_updated = false;
rgui->force_redraw = false; rgui->force_redraw = false;

View File

@ -130,7 +130,7 @@ static void rmenu_render(void)
char title_msg[64] = {0}; char title_msg[64] = {0};
menu_handle_t *menu = menu_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr();
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_list_t *menu_list = menu_list_get_ptr(); menu_list_t *menu_list = menu_list_get_ptr();
menu_navigation_t *nav = menu_navigation_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr();
uint64_t *frame_count = video_driver_get_frame_count(); uint64_t *frame_count = video_driver_get_frame_count();
@ -151,8 +151,7 @@ static void rmenu_render(void)
return; return;
menu_display_fb_unset_dirty(); menu_display_fb_unset_dirty();
anim->is_active = false; menu_animation_clear_active(anim);
anim->label.is_updated = false;
if (!menu_list->selection_buf) if (!menu_list->selection_buf)
return; return;

View File

@ -536,7 +536,7 @@ static void rmenu_xui_render(void)
const char *label = NULL; const char *label = NULL;
unsigned menu_type = 0; unsigned menu_type = 0;
menu_handle_t *menu = menu_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
menu_framebuf_t *frame_buf = menu_display_fb_get_ptr(); menu_framebuf_t *frame_buf = menu_display_fb_get_ptr();
menu_navigation_t *nav = menu_navigation_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr();
@ -552,8 +552,7 @@ static void rmenu_xui_render(void)
return; return;
menu_display_fb_unset_dirty(); menu_display_fb_unset_dirty();
anim->is_active = false; menu_animation_clear_active(anim);
anim->label.is_updated = false;
rmenu_xui_render_background(); rmenu_xui_render_background();

View File

@ -1481,7 +1481,7 @@ static void xmb_render(void)
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
menu_handle_t *menu = menu_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr();
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_input_t *menu_input = menu_input_get_ptr(); menu_input_t *menu_input = menu_input_get_ptr();
menu_navigation_t *nav = menu_navigation_get_ptr(); menu_navigation_t *nav = menu_navigation_get_ptr();
menu_list_t *menu_list = menu_list_get_ptr(); menu_list_t *menu_list = menu_list_get_ptr();
@ -1494,7 +1494,7 @@ static void xmb_render(void)
if (!xmb) if (!xmb)
return; return;
menu_animation_update(disp->animation, disp->animation->delta_time / IDEAL_DT); menu_animation_update(disp->animation, menu_animation_get_delta_time(disp->animation) / IDEAL_DT);
video_driver_get_size(NULL, &height); video_driver_get_size(NULL, &height);
@ -1525,8 +1525,7 @@ static void xmb_render(void)
if (menu_entries_get_start() >= end) if (menu_entries_get_start() >= end)
menu_entries_set_start(0); menu_entries_set_start(0);
anim->is_active = false; menu_animation_clear_active(anim);
anim->label.is_updated = false;
} }
static void xmb_frame_horizontal_list(xmb_handle_t *xmb, static void xmb_frame_horizontal_list(xmb_handle_t *xmb,

View File

@ -23,7 +23,35 @@
#include "../configuration.h" #include "../configuration.h"
#include "../performance.h" #include "../performance.h"
menu_animation_t *menu_animation_get_ptr(void) struct tween
{
bool alive;
float duration;
float running_since;
float initial_value;
float target_value;
float* subject;
int tag;
easingFunc easing;
tween_cb cb;
};
typedef struct menu_animation
{
struct tween *list;
size_t capacity;
size_t size;
size_t first_dead;
bool is_active;
/* Delta timing */
float delta_time;
retro_time_t cur_time;
retro_time_t old_time;
} menu_animation_t;
struct menu_animation_t *menu_animation_get_ptr(void)
{ {
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
if (!disp) if (!disp)
@ -259,9 +287,10 @@ static float easing_out_in_bounce(float t, float b, float c, float d)
return easing_in_bounce((t * 2) - d, b + c / 2, c / 2, d); return easing_in_bounce((t * 2) - d, b + c / 2, c / 2, d);
} }
void menu_animation_free(menu_animation_t *anim) void menu_animation_free(struct menu_animation_t *animation)
{ {
size_t i; size_t i;
struct menu_animation *anim = (struct menu_animation*)animation;
if (!anim) if (!anim)
return; return;
@ -276,26 +305,27 @@ void menu_animation_free(menu_animation_t *anim)
free(anim); free(anim);
} }
void menu_animation_kill_by_subject(menu_animation_t *animation, void menu_animation_kill_by_subject(struct menu_animation_t *animation,
size_t count, const void *subjects) size_t count, const void *subjects)
{ {
unsigned i, j, killed = 0; unsigned i, j, killed = 0;
float **sub = (float**)subjects; float **sub = (float**)subjects;
struct menu_animation *anim = (struct menu_animation*)animation;
for (i = 0; i < animation->size; ++i) for (i = 0; i < anim->size; ++i)
{ {
if (!animation->list[i].alive) if (!anim->list[i].alive)
continue; continue;
for (j = 0; j < count; ++j) for (j = 0; j < count; ++j)
{ {
if (animation->list[i].subject == sub[j]) if (anim->list[i].subject == sub[j])
{ {
animation->list[i].alive = false; anim->list[i].alive = false;
animation->list[i].subject = NULL; anim->list[i].subject = NULL;
if (i < animation->first_dead) if (i < anim->first_dead)
animation->first_dead = i; anim->first_dead = i;
killed++; killed++;
break; break;
@ -304,9 +334,10 @@ void menu_animation_kill_by_subject(menu_animation_t *animation,
} }
} }
void menu_animation_kill_by_tag(menu_animation_t *anim, int tag) void menu_animation_kill_by_tag(struct menu_animation_t *animation, int tag)
{ {
unsigned i; unsigned i;
struct menu_animation *anim = (struct menu_animation*)animation;
if (tag == -1) if (tag == -1)
return; return;
@ -324,7 +355,7 @@ void menu_animation_kill_by_tag(menu_animation_t *anim, int tag)
} }
} }
static void menu_animation_push_internal(menu_animation_t *anim, const struct tween *t) static void menu_animation_push_internal(struct menu_animation *anim, const struct tween *t)
{ {
struct tween *target = NULL; struct tween *target = NULL;
@ -345,13 +376,14 @@ static void menu_animation_push_internal(menu_animation_t *anim, const struct tw
*target = *t; *target = *t;
} }
bool menu_animation_push(menu_animation_t *anim, bool menu_animation_push(struct menu_animation_t *animation,
float duration, float duration,
float target_value, float* subject, float target_value, float* subject,
enum menu_animation_easing_type easing_enum, enum menu_animation_easing_type easing_enum,
int tag, tween_cb cb) int tag, tween_cb cb)
{ {
struct tween t; struct tween t;
struct menu_animation *anim = (struct menu_animation*)animation;
if (!subject) if (!subject)
return false; return false;
@ -489,7 +521,7 @@ bool menu_animation_push(menu_animation_t *anim,
} }
static int menu_animation_iterate( static int menu_animation_iterate(
menu_animation_t *anim, unsigned idx, struct menu_animation *anim, unsigned idx,
float dt, unsigned *active_tweens) float dt, unsigned *active_tweens)
{ {
struct tween *tween = &anim->list[idx]; struct tween *tween = &anim->list[idx];
@ -523,10 +555,11 @@ static int menu_animation_iterate(
return 0; return 0;
} }
bool menu_animation_update(menu_animation_t *anim, float dt) bool menu_animation_update(struct menu_animation_t *animation, float dt)
{ {
unsigned i; unsigned i;
unsigned active_tweens = 0; unsigned active_tweens = 0;
struct menu_animation *anim = (struct menu_animation*)animation;
for(i = 0; i < anim->size; i++) for(i = 0; i < anim->size; i++)
menu_animation_iterate(anim, i, dt, &active_tweens); menu_animation_iterate(anim, i, dt, &active_tweens);
@ -591,7 +624,7 @@ void menu_animation_ticker_generic(uint64_t idx, int max_width,
void menu_animation_ticker_str(char *s, size_t len, uint64_t idx, void menu_animation_ticker_str(char *s, size_t len, uint64_t idx,
const char *str, bool selected) const char *str, bool selected)
{ {
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation *anim = (struct menu_animation*)menu_animation_get_ptr();
int str_len = strlen(str); int str_len = strlen(str);
int offset = 0; int offset = 0;
@ -619,7 +652,7 @@ void menu_animation_update_time(void)
{ {
static retro_time_t last_clock_update = 0; static retro_time_t last_clock_update = 0;
menu_display_t *disp = menu_display_get_ptr(); menu_display_t *disp = menu_display_get_ptr();
menu_animation_t *anim = disp->animation; struct menu_animation *anim = (struct menu_animation*)disp->animation;
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
anim->cur_time = rarch_get_time_usec(); anim->cur_time = rarch_get_time_usec();
@ -634,7 +667,47 @@ void menu_animation_update_time(void)
if (((anim->cur_time - last_clock_update) > 1000000) if (((anim->cur_time - last_clock_update) > 1000000)
&& settings->menu.timedate_enable) && settings->menu.timedate_enable)
{ {
anim->label.is_updated = true; anim->is_active = true;
last_clock_update = anim->cur_time; last_clock_update = anim->cur_time;
} }
} }
void menu_animation_set_active(struct menu_animation_t *animation)
{
struct menu_animation *anim = (struct menu_animation*)animation;
if (!anim)
return;
anim->is_active = true;
}
void menu_animation_clear_active(struct menu_animation_t *animation)
{
struct menu_animation *anim = (struct menu_animation*)animation;
if (!anim)
return;
anim->is_active = false;
}
float menu_animation_get_delta_time(struct menu_animation_t *animation)
{
struct menu_animation *anim = (struct menu_animation*)animation;
if (!anim)
return 0.0f;
return anim->delta_time;
}
void *menu_animation_init(void)
{
struct menu_animation *anim = (struct menu_animation*)calloc(1, sizeof(*anim));
if (!anim)
return NULL;
return anim;
}
bool menu_animation_is_active(struct menu_animation_t *animation)
{
struct menu_animation *anim = (struct menu_animation*)animation;
if (!anim)
return false;
return anim->is_active;
}

View File

@ -33,38 +33,7 @@ extern "C" {
typedef float (*easingFunc)(float, float, float, float); typedef float (*easingFunc)(float, float, float, float);
typedef void (*tween_cb) (void); typedef void (*tween_cb) (void);
struct tween struct menu_animation_t;
{
bool alive;
float duration;
float running_since;
float initial_value;
float target_value;
float* subject;
int tag;
easingFunc easing;
tween_cb cb;
};
typedef struct menu_animation
{
struct tween *list;
size_t capacity;
size_t size;
size_t first_dead;
bool is_active;
/* Delta timing */
float delta_time;
retro_time_t cur_time;
retro_time_t old_time;
struct
{
bool is_updated;
} label;
} menu_animation_t;
enum menu_animation_easing_type enum menu_animation_easing_type
{ {
@ -112,27 +81,24 @@ enum menu_animation_easing_type
EASING_OUT_IN_BOUNCE EASING_OUT_IN_BOUNCE
}; };
void menu_animation_free( void menu_animation_free(struct menu_animation_t *animation);
menu_animation_t *animation);
void menu_animation_kill_by_subject( void menu_animation_kill_by_subject(
menu_animation_t *animation, struct menu_animation_t *animation,
size_t count, size_t count,
const void *subjects); const void *subjects);
void menu_animation_kill_by_tag(menu_animation_t *anim, int tag); void menu_animation_kill_by_tag(struct menu_animation_t *anim, int tag);
/* Use -1 for untagged */ /* Use -1 for untagged */
bool menu_animation_push( bool menu_animation_push(
menu_animation_t *animation, struct menu_animation_t *animation,
float duration, float duration,
float target_value, float* subject, float target_value, float* subject,
enum menu_animation_easing_type easing_enum, enum menu_animation_easing_type easing_enum,
int tag, tween_cb cb); int tag, tween_cb cb);
bool menu_animation_update( bool menu_animation_update(struct menu_animation_t *animation, float dt);
menu_animation_t *animation,
float dt);
/** /**
* menu_animation_ticker_str: * menu_animation_ticker_str:
@ -151,10 +117,21 @@ void menu_animation_ticker_str(char *s, size_t len, uint64_t tick,
void menu_animation_ticker_generic(uint64_t idx, int max_width, void menu_animation_ticker_generic(uint64_t idx, int max_width,
int *offset, int *width); int *offset, int *width);
menu_animation_t *menu_animation_get_ptr(void); struct menu_animation_t *menu_animation_get_ptr(void);
void menu_animation_update_time(void); void menu_animation_update_time(void);
void menu_animation_set_active(struct menu_animation_t *anim);
void menu_animation_clear_active(struct menu_animation_t *anim);
float menu_animation_get_delta_time(struct menu_animation_t *anim);
bool menu_animation_is_active(struct menu_animation_t *anim);
void *menu_animation_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -81,11 +81,10 @@ void menu_display_fb(void)
bool menu_display_update_pending(void) bool menu_display_update_pending(void)
{ {
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_framebuf_t *frame_buf = menu_display_fb_get_ptr(); menu_framebuf_t *frame_buf = menu_display_fb_get_ptr();
if ((anim && anim->is_active) || (anim && anim->label.is_updated) if (menu_animation_is_active(anim) || (frame_buf && frame_buf->dirty))
|| (frame_buf && frame_buf->dirty))
return true; return true;
return false; return false;
} }
@ -123,8 +122,7 @@ bool menu_display_init(void *data)
if (!menu) if (!menu)
return false; return false;
menu->display.animation = (menu_animation_t*)calloc menu->display.animation = menu_animation_init();
(1, sizeof(menu_animation_t));
if (!menu->display.animation) if (!menu->display.animation)
return false; return false;

View File

@ -43,7 +43,7 @@ typedef struct menu_display
bool msg_force; bool msg_force;
menu_framebuf_t frame_buf; menu_framebuf_t frame_buf;
menu_animation_t *animation; struct menu_animation_t *animation;
struct struct
{ {

View File

@ -576,7 +576,7 @@ static int menu_input_mouse(unsigned *action)
{ {
video_viewport_t vp; video_viewport_t vp;
const struct retro_keybind *binds[MAX_USERS]; const struct retro_keybind *binds[MAX_USERS];
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_input_t *menu_input = menu_input_get_ptr(); menu_input_t *menu_input = menu_input_get_ptr();
menu_framebuf_t *frame_buf= menu_display_fb_get_ptr(); menu_framebuf_t *frame_buf= menu_display_fb_get_ptr();
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
@ -654,7 +654,7 @@ static int menu_input_mouse(unsigned *action)
menu_input->mouse.scrollup || menu_input->mouse.scrollup ||
menu_input->mouse.scrolldown menu_input->mouse.scrolldown
) )
anim->is_active = true; menu_animation_set_active(anim);
return 0; return 0;
} }
@ -664,7 +664,7 @@ static int menu_input_pointer(unsigned *action)
int pointer_device, pointer_x, pointer_y; int pointer_device, pointer_x, pointer_y;
const struct retro_keybind *binds[MAX_USERS] = {NULL}; const struct retro_keybind *binds[MAX_USERS] = {NULL};
menu_input_t *menu_input = menu_input_get_ptr(); menu_input_t *menu_input = menu_input_get_ptr();
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
menu_framebuf_t *frame_buf= menu_display_fb_get_ptr(); menu_framebuf_t *frame_buf= menu_display_fb_get_ptr();
settings_t *settings = config_get_ptr(); settings_t *settings = config_get_ptr();
driver_t *driver = driver_get_ptr(); driver_t *driver = driver_get_ptr();
@ -699,7 +699,7 @@ static int menu_input_pointer(unsigned *action)
(menu_input->pointer.dy != 0) || (menu_input->pointer.dy != 0) ||
(menu_input->pointer.dx != 0) (menu_input->pointer.dx != 0)
) )
anim->is_active = true; menu_animation_set_active(anim);
return 0; return 0;
} }
@ -868,7 +868,7 @@ static int menu_input_pointer_post_iterate(menu_file_list_cbs_t *cbs,
menu_input->pointer.old_x = menu_input->pointer.x; menu_input->pointer.old_x = menu_input->pointer.x;
menu_input->pointer.old_y = menu_input->pointer.y; menu_input->pointer.old_y = menu_input->pointer.y;
s = menu_input->pointer.dy / disp->animation->delta_time * 1000000.0; s = menu_input->pointer.dy / menu_animation_get_delta_time(disp->animation) * 1000000.0;
menu_input->pointer.accel = (menu_input->pointer.accel0 + menu_input->pointer.accel1 + s) / 3; menu_input->pointer.accel = (menu_input->pointer.accel0 + menu_input->pointer.accel1 + s) / 3;
menu_input->pointer.accel0 = menu_input->pointer.accel1; menu_input->pointer.accel0 = menu_input->pointer.accel1;
menu_input->pointer.accel1 = menu_input->pointer.accel; menu_input->pointer.accel1 = menu_input->pointer.accel;
@ -988,7 +988,7 @@ unsigned menu_input_frame(retro_input_t input, retro_input_t trigger_input)
nav->scroll.acceleration = 0; nav->scroll.acceleration = 0;
} }
menu_input->delay.count += disp->animation->delta_time / IDEAL_DT; menu_input->delay.count += menu_animation_get_delta_time(disp->animation) / IDEAL_DT;
if (menu_input->keyboard.display) if (menu_input->keyboard.display)
{ {

View File

@ -1177,13 +1177,12 @@ static void setting_get_string_representation_st_float_video_refresh_rate_auto(v
if (video_monitor_fps_statistics(&video_refresh_rate, &deviation, &sample_points)) if (video_monitor_fps_statistics(&video_refresh_rate, &deviation, &sample_points))
{ {
menu_animation_t *anim = menu_animation_get_ptr(); struct menu_animation_t *anim = menu_animation_get_ptr();
snprintf(s, len, "%.3f Hz (%.1f%% dev, %u samples)", snprintf(s, len, "%.3f Hz (%.1f%% dev, %u samples)",
video_refresh_rate, 100.0 * deviation, sample_points); video_refresh_rate, 100.0 * deviation, sample_points);
if (anim) menu_animation_set_active(anim);
anim->label.is_updated = true;
} }
else else
strlcpy(s, menu_hash_to_str(MENU_VALUE_NOT_AVAILABLE), len); strlcpy(s, menu_hash_to_str(MENU_VALUE_NOT_AVAILABLE), len);