#include "lvgl.h" #include "ui.h" const char *val_ext_gamemodes[] = { "TDM", "DEATHMATCH", "ESCALATION", "SPIKE RUSH", "CUSTOM", "GAME", }; static const char* M_VAL_TIME = "VAL TIME?"; static const char *val_eco_titles[] = { "BUY", "SAVE", "BONUS", "MATCH TEAM", }; static const char *val_eco_subtitles[] = { "SPEND ALL YOUR MONEY!", "MAKE SURE YOU CAN BUY NEXT ROUND!", "KEEP YOUR GUN FROM LAST ROUND!", "FOLLOW THE TEAM ECONOMY", }; 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_color_t color_text_won, color_text_lost; 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)); lv_obj_set_scrollbar_mode(o_active, LV_SCROLLBAR_MODE_OFF); 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_subtitle)) / 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_ui_game_start() { 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, "GOOD LUCK!"); state_ready = true; } static void anim_text_color_mix_hero_won(void *var, int32_t v) { lv_obj_set_style_text_color( var, lv_color_mix(color_text_hero, color_text_won, v), 0); } static void anim_text_color_mix_hero_lost(void *var, int32_t v) { lv_obj_set_style_text_color( var, lv_color_mix(color_text_hero, color_text_lost, v), 0); } void val_ui_round_start(uint8_t score, uint8_t score_enemy, val_won_t won, val_eco_decision_t eco) { assert(won <= ROUND_NONE && eco <= ECO_MATCH_TEAM); setup_next_state(); // Widgets lv_obj_t *l_score = lv_label_create(o_active); lv_obj_add_style(l_score, &s_hero, 0); lv_obj_center(l_score); lv_label_set_text_fmt(l_score, "%hhu-%hhu", score, score_enemy); lv_obj_t *l_eco = lv_label_create(o_active); lv_obj_add_style(l_eco, &s_hero, 0); lv_obj_center(l_eco); lv_label_set_text_static(l_eco, val_eco_titles[eco]); lv_obj_t *l_advice = lv_label_create(o_active); lv_obj_add_style(l_advice, &s_subtitle, 0); lv_obj_center(l_advice); lv_label_set_text_static(l_advice, val_eco_subtitles[eco]); lv_obj_update_layout(o_active); lv_obj_set_y( l_score, -(lv_obj_get_height(l_score) / 2) - 20); lv_obj_set_y( l_eco, lv_obj_get_height(l_eco) / 2); // Animations // Score and eco fade in 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, 750); lv_anim_set_var(&a_fade_in, l_score); lv_anim_timeline_add(at_active, 0, &a_fade_in); lv_anim_set_var(&a_fade_in, l_eco); lv_anim_timeline_add(at_active, 0, &a_fade_in); // Advice slide up lv_anim_t a_advice; lv_anim_init(&a_advice); lv_anim_set_var(&a_advice, l_advice); lv_anim_set_values( &a_advice, (lv_obj_get_height(o_container) + lv_obj_get_height(l_advice)) / 2, lv_obj_get_height(l_eco) + (lv_obj_get_height(l_advice) / 2) + 5); lv_anim_set_exec_cb(&a_advice, anim_y_cb); lv_anim_set_path_cb(&a_advice, lv_anim_path_ease_out); lv_anim_set_duration(&a_advice, 750); if (won != ROUND_NONE) { // Score colour lv_anim_t a_score; lv_anim_init(&a_score); lv_anim_set_var(&a_score, l_score); lv_anim_set_path_cb(&a_score, lv_anim_path_ease_in); lv_anim_set_exec_cb( &a_score, won == ROUND_WON ? anim_text_color_mix_hero_won : anim_text_color_mix_hero_lost); lv_anim_set_duration(&a_score, 2000); lv_anim_set_values(&a_score, 0, 255); lv_anim_set_completed_cb(&a_score, anim_state_ready_cb); lv_anim_timeline_add(at_active, 0, &a_score); } else { lv_anim_set_completed_cb(&a_advice, anim_state_ready_cb); } lv_anim_timeline_add(at_active, 0, &a_advice); // Eco flash lv_anim_t a_eco; lv_anim_init(&a_eco); lv_anim_set_early_apply(&a_eco, false); lv_anim_set_var(&a_eco, l_eco); lv_anim_set_path_cb(&a_eco, lv_anim_path_linear); lv_anim_set_duration(&a_eco, 1000); lv_anim_set_exec_cb(&a_eco, anim_text_color_mix_hero_sub); lv_anim_set_values(&a_eco, 255, 0); lv_anim_timeline_add(at_active_rep, 0, &a_eco); lv_anim_set_values(&a_eco, 0, 255); lv_anim_timeline_add(at_active_rep, 1000, &a_eco); lv_anim_timeline_start(at_active); } void val_ui_game_over(bool won) { 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, won ? "VICTORY" : "DEFEAT"); lv_obj_set_style_text_color(l_main, won ? color_text_won : color_text_lost, 0); 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, won ? "WELL PLAYED!" : "HARD LUCK..."); 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 if (won) { lv_anim_t a_fly; lv_anim_init(&a_fly); lv_anim_set_path_cb(&a_fly, lv_anim_path_ease_out); lv_anim_set_duration(&a_fly, 750); // Main text from top-left // Y lv_anim_set_var(&a_fly, l_main); lv_anim_set_exec_cb(&a_fly, anim_y_cb); lv_anim_set_values( &a_fly, -(lv_obj_get_height(o_container) + lv_obj_get_height(l_main)) / 2, 0); lv_anim_timeline_add(at_active, 0, &a_fly); // X lv_anim_set_exec_cb(&a_fly, anim_x_cb); lv_anim_set_values( &a_fly, -(lv_obj_get_width(o_container) + lv_obj_get_width(l_main)) / 2, 0); lv_anim_timeline_add(at_active, 0, &a_fly); // Subtitle from bottom-right // Y lv_anim_set_var(&a_fly, l_subtitle); lv_anim_set_exec_cb(&a_fly, anim_y_cb); lv_anim_set_values( &a_fly, (lv_obj_get_height(o_container) + lv_obj_get_height(l_subtitle)) / 2, (lv_obj_get_height(l_main) + lv_obj_get_height(l_subtitle)) / 2 + 5); lv_anim_timeline_add(at_active, 0, &a_fly); // X lv_anim_set_exec_cb(&a_fly, anim_x_cb); lv_anim_set_values( &a_fly, (lv_obj_get_width(o_container) + lv_obj_get_width(l_subtitle)) / 2, 0); lv_anim_set_completed_cb(&a_fly, anim_state_ready_cb); lv_anim_timeline_add(at_active, 0, &a_fly); } else { 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); } 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); color_text_won = lv_palette_lighten(LV_PALETTE_GREEN, 1); color_text_lost = lv_palette_darken(LV_PALETTE_RED, 4); // 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)); lv_obj_set_scrollbar_mode(o_container, LV_SCROLLBAR_MODE_OFF); // 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(); }