valconomy/firmware/main/ui.c

547 lines
16 KiB
C

#include "lvgl.h"
#include "ui.h"
static const char* M_VAL_TIME = "VAL TIME?";
const char *val_ext_gamemodes[] = {
"TDM",
"DEATHMATCH",
"ESCALATION",
"SPIKE RUSH",
"CUSTOM",
"GAME",
};
static const lv_font_t *font_normal = &lv_font_montserrat_24;
static lv_color_t color_primary, color_secondary;
static lv_color_t color_text_hero, color_text_subtitle;
static lv_style_t s_hero, s_subtitle;
static lv_obj_t *o_container = NULL;
static lv_anim_timeline_t *at_active = NULL;
static lv_anim_timeline_t *at_active_rep = NULL;
static lv_obj_t *o_active = NULL;
static bool state_ready = true;
static const void* imgfont_get_path(
const lv_font_t *font, uint32_t unicode, uint32_t unicode_next, int32_t *offset_y, void *user_data) {
LV_UNUSED(font);
LV_UNUSED(unicode_next);
LV_UNUSED(offset_y);
LV_UNUSED(user_data);
switch (unicode) {
case 0x1F319:
return &ui_img_moon;
case 0x2B50:
return &ui_img_star;
case 0x1F634:
return &ui_img_sleep;
default:
return NULL;
}
}
static void b_cfg_cb(lv_event_t *e) {
lv_obj_t *box = lv_msgbox_create(NULL);
lv_msgbox_add_title(box, "Settings");
lv_msgbox_add_text(box, "Sorry, there aren't any right now.");
lv_msgbox_add_close_button(box);
}
static void setup_next_state() {
assert(state_ready);
state_ready = false;
if (at_active) {
lv_anim_timeline_delete(at_active);
at_active = NULL;
}
if (at_active_rep) {
lv_anim_timeline_delete(at_active_rep);
at_active_rep = NULL;
}
if (o_active) {
lv_obj_delete(o_active);
o_active = NULL;
}
o_active = lv_obj_create(o_container);
lv_obj_center(o_active);
lv_obj_set_style_bg_opa(o_active, LV_OPA_0, 0);
lv_obj_set_style_border_width(o_active, 0, 0);
lv_obj_set_size(o_active, lv_pct(100), lv_pct(100));
at_active = lv_anim_timeline_create();
at_active_rep = lv_anim_timeline_create();
lv_anim_timeline_set_repeat_count(at_active_rep, LV_ANIM_REPEAT_INFINITE);
}
bool val_ui_state_ready() {
return state_ready;
}
static void anim_state_ready_cb(lv_anim_t *anim) {
lv_anim_timeline_start(at_active_rep);
state_ready = true;
}
static void anim_x_cb(void *var, int32_t v) {
lv_obj_set_x(var, v);
}
static void anim_y_cb(void *var, int32_t v) {
lv_obj_set_y(var, v);
}
static void anim_opa_cb(void *var, int32_t v) {
lv_obj_set_style_opa(var, v, 0);
}
static void anim_val_time_text(lv_anim_t *anim) {
lv_label_set_text_static(anim->var, M_VAL_TIME);
}
void val_ui_none() {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, M_VAL_TIME);
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, "SOME VAL IS ALWAYS ON THE MENU...");
lv_obj_update_layout(o_active);
lv_obj_set_pos(
l_subtitle,
-(lv_obj_get_width(l_main) - lv_obj_get_width(l_subtitle)) / 2,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
lv_label_set_text_static(l_main, "HELLO \U0001F319\u2B50!");
lv_obj_update_layout(o_active);
// Animations
lv_anim_t a_hello_in;
lv_anim_init(&a_hello_in);
lv_anim_set_var(&a_hello_in, l_main);
lv_anim_set_values(
&a_hello_in,
(lv_obj_get_height(o_container) - lv_obj_get_height(l_main)) / 2, 0);
lv_anim_set_exec_cb(&a_hello_in, anim_y_cb);
lv_anim_set_path_cb(&a_hello_in, lv_anim_path_ease_in);
lv_anim_set_duration(&a_hello_in, 500);
lv_anim_t a_hello_out;
lv_anim_init(&a_hello_out);
lv_anim_set_var(&a_hello_out, l_main);
lv_anim_set_values(&a_hello_out, 255, 0);
lv_anim_set_exec_cb(&a_hello_out, anim_opa_cb);
lv_anim_set_path_cb(&a_hello_out, lv_anim_path_linear);
lv_anim_set_duration(&a_hello_out, 500);
lv_anim_t a_val;
lv_anim_init(&a_val);
lv_anim_set_early_apply(&a_val, false);
lv_anim_set_var(&a_val, l_main);
lv_anim_set_values(&a_val, 0, 255);
lv_anim_set_start_cb(&a_val, anim_val_time_text);
lv_anim_set_exec_cb(&a_val, anim_opa_cb);
lv_anim_set_path_cb(&a_val, lv_anim_path_linear);
lv_anim_set_duration(&a_val, 500);
lv_anim_t a_sub;
lv_anim_init(&a_sub);
lv_anim_set_var(&a_sub, l_subtitle);
lv_anim_set_values(&a_sub, 0, 255);
lv_anim_set_exec_cb(&a_sub, anim_opa_cb);
lv_anim_set_path_cb(&a_sub, lv_anim_path_linear);
lv_anim_set_completed_cb(&a_sub, anim_state_ready_cb);
lv_anim_set_duration(&a_sub, 750);
lv_anim_timeline_add(at_active, 0, &a_hello_in);
lv_anim_timeline_add(at_active, 3000, &a_hello_out);
lv_anim_timeline_add(at_active, 3250, &a_val);
lv_anim_timeline_add(at_active, 3750, &a_sub);
lv_anim_timeline_start(at_active);
}
void val_ui_menu(bool was_idle) {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "LET'S GO");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, was_idle ? "WELCOME BACK!" : "GET QUEUEING!");
lv_obj_update_layout(o_active);
// Animations
lv_anim_t a_title;
lv_anim_init(&a_title);
lv_anim_set_var(&a_title, l_main);
lv_anim_set_values(
&a_title,
-(lv_obj_get_height(o_container) + lv_obj_get_height(l_main)) / 2, 0);
lv_anim_set_exec_cb(&a_title, anim_y_cb);
lv_anim_set_path_cb(&a_title, lv_anim_path_ease_in);
lv_anim_set_duration(&a_title, 500);
lv_anim_t a_sub;
lv_anim_init(&a_sub);
lv_anim_set_var(&a_sub, l_subtitle);
lv_anim_set_values(
&a_sub,
(lv_obj_get_height(o_container) + lv_obj_get_height(l_main)) / 2,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
lv_anim_set_exec_cb(&a_sub, anim_y_cb);
lv_anim_set_path_cb(&a_sub, lv_anim_path_ease_in);
lv_anim_set_completed_cb(&a_sub, anim_state_ready_cb);
lv_anim_set_duration(&a_sub, 500);
lv_anim_timeline_add(at_active, 0, &a_title);
lv_anim_timeline_add(at_active, 0, &a_sub);
// Repeating loop swing back and forth
lv_anim_t a_title_swing;
lv_anim_init(&a_title_swing);
lv_anim_set_early_apply(&a_title_swing, false);
lv_anim_set_var(&a_title_swing, l_main);
lv_anim_set_exec_cb(&a_title_swing, anim_x_cb);
// Left
lv_anim_set_path_cb(&a_title_swing, lv_anim_path_ease_out);
lv_anim_set_values(&a_title_swing, 0, -10);
lv_anim_set_duration(&a_title_swing, 500);
lv_anim_timeline_add(at_active_rep, 0, &a_title_swing);
// Left to right
lv_anim_set_path_cb(&a_title_swing, lv_anim_path_ease_in_out);
lv_anim_set_values(&a_title_swing, -10, 10);
lv_anim_set_duration(&a_title_swing, 1000);
lv_anim_timeline_add(at_active_rep, 500, &a_title_swing);
// Right to centre
lv_anim_set_path_cb(&a_title_swing, lv_anim_path_ease_in);
lv_anim_set_values(&a_title_swing, 10, 0);
lv_anim_set_duration(&a_title_swing, 500);
lv_anim_timeline_add(at_active_rep, 1500, &a_title_swing);
lv_anim_timeline_start(at_active);
}
void val_ui_idle() {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "\U0001F634");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, "COME BACK SOON...");
lv_obj_update_layout(o_active);
lv_obj_set_y(
l_subtitle,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
// Animations
lv_anim_t a_fade_in;
lv_anim_init(&a_fade_in);
lv_anim_set_values(&a_fade_in, 0, 255);
lv_anim_set_exec_cb(&a_fade_in, anim_opa_cb);
lv_anim_set_path_cb(&a_fade_in, lv_anim_path_ease_in);
lv_anim_set_duration(&a_fade_in, 1000);
lv_anim_set_var(&a_fade_in, l_main);
lv_anim_timeline_add(at_active, 0, &a_fade_in);
lv_anim_set_var(&a_fade_in, l_subtitle);
lv_anim_set_completed_cb(&a_fade_in, anim_state_ready_cb);
lv_anim_timeline_add(at_active, 0, &a_fade_in);
lv_anim_timeline_start(at_active);
}
static void anim_text_color_mix_hero_sub(void *var, int32_t v) {
lv_obj_set_style_text_color(
var, lv_color_mix(color_text_hero, color_text_subtitle, v), 0);
}
void val_ui_queue_start(bool ms_not_comp) {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "SEARCHING...");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, ms_not_comp ? "UHHH SHOULD THAT BE COMP?" : "HOPE YOU FIND A GAME QUICKLY!");
lv_obj_t *spinner = lv_spinner_create(o_active);
lv_obj_set_size(spinner, 100, 100);
lv_obj_center(spinner);
lv_obj_set_style_arc_color(spinner, color_text_hero, LV_PART_INDICATOR);
lv_spinner_set_anim_params(spinner, 1500, 200);
lv_obj_update_layout(o_active);
const int32_t offset = -60;
lv_obj_set_y(l_main, offset);
lv_obj_set_y(
l_subtitle,
offset + (lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
lv_obj_set_y(
spinner,
lv_obj_get_height(o_container) / 4);
// Animations
lv_anim_t a_title;
lv_anim_init(&a_title);
lv_anim_set_var(&a_title, l_main);
lv_anim_set_values(
&a_title,
-(lv_obj_get_width(o_container) + lv_obj_get_width(l_main)) / 2, 0);
lv_anim_set_exec_cb(&a_title, anim_x_cb);
lv_anim_set_path_cb(&a_title, lv_anim_path_ease_out);
lv_anim_set_duration(&a_title, 750);
lv_anim_t a_sub;
lv_anim_init(&a_sub);
lv_anim_set_var(&a_sub, l_subtitle);
lv_anim_set_values(
&a_sub,
(lv_obj_get_width(o_container) + lv_obj_get_width(l_subtitle)) / 2, 0);
lv_anim_set_exec_cb(&a_sub, anim_x_cb);
lv_anim_set_path_cb(&a_sub, lv_anim_path_ease_out);
lv_anim_set_completed_cb(&a_sub, anim_state_ready_cb);
lv_anim_set_duration(&a_sub, 750);
lv_anim_timeline_add(at_active, 0, &a_title);
lv_anim_timeline_add(at_active, 0, &a_sub);
if (ms_not_comp) {
lv_anim_t a_warn;
lv_anim_init(&a_warn);
lv_anim_set_early_apply(&a_warn, false);
lv_anim_set_var(&a_warn, l_subtitle);
lv_anim_set_path_cb(&a_warn, lv_anim_path_linear);
lv_anim_set_duration(&a_warn, 1000);
lv_anim_set_exec_cb(&a_warn, anim_text_color_mix_hero_sub);
lv_anim_set_values(&a_warn, 0, 255);
lv_anim_timeline_add(at_active_rep, 0, &a_warn);
lv_anim_set_values(&a_warn, 255, 0);
lv_anim_timeline_add(at_active_rep, 1000, &a_warn);
}
lv_anim_timeline_start(at_active);
}
void val_ui_match_found(bool is_premier) {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "MATCH FOUND");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, is_premier ? "DO THE COSMONAUTS PROUD!" : "I HOPE IT'S NOT SPLIT...");
lv_obj_update_layout(o_active);
// Animations
lv_anim_t a_title;
lv_anim_init(&a_title);
lv_anim_set_var(&a_title, l_main);
lv_anim_set_values(
&a_title,
(lv_obj_get_height(o_container) + lv_obj_get_height(l_main)) / 2, 0);
lv_anim_set_exec_cb(&a_title, anim_y_cb);
lv_anim_set_path_cb(&a_title, lv_anim_path_ease_in);
lv_anim_set_duration(&a_title, 500);
lv_anim_t a_sub;
lv_anim_init(&a_sub);
lv_anim_set_var(&a_sub, l_subtitle);
lv_anim_set_values(
&a_sub,
-(lv_obj_get_height(o_container) + lv_obj_get_height(l_main)) / 2,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
lv_anim_set_exec_cb(&a_sub, anim_y_cb);
lv_anim_set_path_cb(&a_sub, lv_anim_path_ease_in);
lv_anim_set_completed_cb(&a_sub, anim_state_ready_cb);
lv_anim_set_duration(&a_sub, 500);
lv_anim_timeline_add(at_active, 0, &a_title);
lv_anim_timeline_add(at_active, 0, &a_sub);
lv_anim_timeline_start(at_active);
}
void val_ui_pregame(bool is_split) {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "CHOOSE AGENT");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_static(l_subtitle, is_split ? "EWWW, SPLIT..." : "PICK SOMETHING GOOD!");
lv_obj_update_layout(o_active);
lv_obj_set_y(
l_subtitle,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
// Animations
lv_anim_t a_fade_in;
lv_anim_init(&a_fade_in);
lv_anim_set_values(&a_fade_in, 0, 255);
lv_anim_set_exec_cb(&a_fade_in, anim_opa_cb);
lv_anim_set_path_cb(&a_fade_in, lv_anim_path_ease_in);
lv_anim_set_duration(&a_fade_in, 500);
lv_anim_set_var(&a_fade_in, l_main);
lv_anim_timeline_add(at_active, 0, &a_fade_in);
lv_anim_set_var(&a_fade_in, l_subtitle);
lv_anim_set_completed_cb(&a_fade_in, anim_state_ready_cb);
lv_anim_timeline_add(at_active, 0, &a_fade_in);
lv_anim_t a_warn;
lv_anim_init(&a_warn);
lv_anim_set_early_apply(&a_warn, false);
lv_anim_set_var(&a_warn, l_main);
lv_anim_set_path_cb(&a_warn, lv_anim_path_linear);
lv_anim_set_duration(&a_warn, 2000);
lv_anim_set_exec_cb(&a_warn, anim_text_color_mix_hero_sub);
lv_anim_set_values(&a_warn, 255, 0);
lv_anim_timeline_add(at_active_rep, 0, &a_warn);
lv_anim_set_values(&a_warn, 0, 255);
lv_anim_timeline_add(at_active_rep, 2000, &a_warn);
lv_anim_timeline_start(at_active);
}
void val_ui_game_generic(const char *gamemode) {
setup_next_state();
// Widgets
lv_obj_t *l_main = lv_label_create(o_active);
lv_obj_add_style(l_main, &s_hero, 0);
lv_obj_center(l_main);
lv_label_set_text_static(l_main, "HAVE FUN!");
lv_obj_t *l_subtitle = lv_label_create(o_active);
lv_obj_add_style(l_subtitle, &s_subtitle, 0);
lv_obj_center(l_subtitle);
lv_label_set_text_fmt(l_subtitle, "ENJOY YOUR %s!", gamemode);
lv_obj_update_layout(o_active);
lv_obj_set_y(
l_subtitle,
(lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5);
// Animations
lv_anim_t a_title;
lv_anim_init(&a_title);
lv_anim_set_var(&a_title, l_main);
lv_anim_set_values(
&a_title,
-(lv_obj_get_width(o_container) + lv_obj_get_width(l_main)) / 2, 0);
lv_anim_set_exec_cb(&a_title, anim_x_cb);
lv_anim_set_path_cb(&a_title, lv_anim_path_bounce);
lv_anim_set_duration(&a_title, 750);
lv_anim_t a_sub;
lv_anim_init(&a_sub);
lv_anim_set_var(&a_sub, l_subtitle);
lv_anim_set_values(
&a_sub,
-(lv_obj_get_width(o_container) + lv_obj_get_width(l_subtitle)) / 2,
-(lv_obj_get_width(l_main) - lv_obj_get_width(l_subtitle)) / 2);
lv_anim_set_exec_cb(&a_sub, anim_x_cb);
lv_anim_set_path_cb(&a_sub, lv_anim_path_bounce);
lv_anim_set_completed_cb(&a_sub, anim_state_ready_cb);
lv_anim_set_duration(&a_sub, 750);
lv_anim_timeline_add(at_active, 0, &a_title);
lv_anim_timeline_add(at_active, 0, &a_sub);
lv_anim_timeline_start(at_active);
}
void val_lvgl_ui(lv_display_t *disp) {
color_primary = lv_color_hex(0xff4655);
color_secondary = lv_color_hex(0xf7518f);
color_text_hero = lv_palette_lighten(LV_PALETTE_GREY, 2);
color_text_subtitle = lv_palette_darken(LV_PALETTE_GREY, 1);
// init default theme
lv_theme_default_init(
disp, color_primary, color_secondary,
true, // dark theme
font_normal);
// lv_sysmon_hide_performance(disp);
lv_font_t *f_hero_emoji = lv_imgfont_create(120, imgfont_get_path, NULL);
assert(f_hero_emoji);
f_hero_emoji->fallback = &lv_font_tungsten_180;
lv_style_init(&s_hero);
lv_style_set_text_font(&s_hero, f_hero_emoji);
lv_style_set_text_color(&s_hero, color_text_hero);
lv_style_init(&s_subtitle);
lv_style_set_text_font(&s_subtitle, &lv_font_tungsten_40);
lv_style_set_text_color(&s_subtitle, color_text_subtitle);
// Background
lv_obj_t *i_bg = lv_image_create(lv_screen_active());
lv_image_set_src(i_bg, &ui_img_bg);
// Content container
o_container = lv_obj_create(lv_screen_active());
lv_obj_set_style_bg_opa(o_container, LV_OPA_0, 0);
lv_obj_set_style_border_width(o_container, 0, 0);
lv_obj_set_style_pad_all(o_container, 0, 0);
lv_obj_set_size(o_container, lv_pct(100), lv_pct(100));
// Settings button
lv_obj_t *b_cfg = lv_button_create(lv_screen_active());
lv_obj_align(b_cfg, LV_ALIGN_BOTTOM_RIGHT, -10, -10);
lv_obj_add_event_cb(b_cfg, b_cfg_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t *l_cfg = lv_label_create(b_cfg);
lv_label_set_text(l_cfg, LV_SYMBOL_SETTINGS);
lv_obj_center(l_cfg);
val_ui_none();
}