| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -15,7 +15,7 @@ const char *val_ext_gamemodes[] = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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_hero, color_text_subtitle, color_text_victory;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static lv_style_t s_hero, s_subtitle;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -74,6 +74,7 @@ static void setup_next_state() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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();
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -201,7 +202,7 @@ void val_ui_menu(bool was_idle) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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(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);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -496,12 +497,105 @@ void val_ui_game_generic(const char *gamemode) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (won) lv_obj_set_style_text_color(l_main, color_text_victory, 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_victory = lv_palette_lighten(LV_PALETTE_GREEN, 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // init default theme
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  lv_theme_default_init(
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -532,6 +626,7 @@ void val_lvgl_ui(lv_display_t *disp) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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());
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |