1use std::os::raw::c_void;
2
3use graphics::{
4 Logo,
5 lvgl::{
6 _lv_obj_t, LV_STATE_DEFAULT, lv_align_t_LV_ALIGN_CENTER, lv_anim_delete, lv_anim_init,
7 lv_anim_path_ease_in_out, lv_anim_set_duration, lv_anim_set_exec_cb, lv_anim_set_path_cb,
8 lv_anim_set_repeat_count, lv_anim_set_repeat_delay, lv_anim_set_reverse_delay,
9 lv_anim_set_reverse_time, lv_anim_set_values, lv_anim_set_var, lv_anim_start, lv_anim_t,
10 lv_obj_get_child, lv_obj_get_child_count, lv_obj_get_size, lv_obj_set_align,
11 lv_obj_set_style_opa, lv_obj_set_style_shadow_color,
12 },
13 theme,
14};
15
16mod error;
17
18pub use error::{Error, Result};
19
20pub struct Bootsplash {
21 animation: Box<lv_anim_t>,
22 _logo: Logo,
23}
24
25unsafe extern "C" fn load_animation_callback(object: *mut c_void, value: i32) {
26 static mut ANIMATED_PART: u8 = 2;
27 let object = object as *mut _lv_obj_t;
28
29 unsafe {
30 if (value == 255) || (value == 64) {
31 if ANIMATED_PART == 4 {
32 if value == 64 {
33 ANIMATED_PART = 1;
34 }
35 } else {
36 ANIMATED_PART += 1;
37 }
38 }
39
40 let next_part = lv_obj_get_child(object, (ANIMATED_PART - 1) as i32);
41
42 if ANIMATED_PART.is_multiple_of(2) {
43 lv_obj_set_style_opa(next_part, (255 + 64 - value) as u8, LV_STATE_DEFAULT);
46
47 let previous_part = lv_obj_get_child(object, (ANIMATED_PART - 2) as i32);
48
49 lv_obj_set_style_opa(previous_part, value as u8, LV_STATE_DEFAULT);
50 } else {
51 lv_obj_set_style_opa(next_part, value as u8, LV_STATE_DEFAULT);
54
55 if ANIMATED_PART == 1 {
56 let previous_part = lv_obj_get_child(object, 3);
57
58 lv_obj_set_style_opa(previous_part, (255 + 64 - value) as u8, LV_STATE_DEFAULT);
59 } else {
60 let previous_part = lv_obj_get_child(object, (ANIMATED_PART - 2) as i32);
61
62 lv_obj_set_style_opa(previous_part, (255 + 64 - value) as u8, LV_STATE_DEFAULT);
63 }
64 }
65 }
66}
67
68impl Bootsplash {
69 pub async fn new(graphics_manager: &'static graphics::Manager) -> Result<Self> {
70 let _lock = graphics_manager.lock().await;
71
72 unsafe {
73 let current_screen = graphics_manager.get_current_screen()?;
74
75 let screen_size = lv_obj_get_size(current_screen);
76 let factor = Logo::get_factor(screen_size.scale(0.3));
77
78 let logo = Logo::new(current_screen, factor, theme::get_primary_color())?;
79
80 let logo_inner_object = logo.get_inner_object();
81
82 lv_obj_set_align(logo_inner_object, lv_align_t_LV_ALIGN_CENTER);
83 let child_count = lv_obj_get_child_count(logo_inner_object);
84 for i in 0..child_count {
85 let part = lv_obj_get_child(logo_inner_object, i as i32);
86
87 lv_obj_set_style_opa(part, 0, LV_STATE_DEFAULT);
88 lv_obj_set_style_shadow_color(
89 part,
90 theme::get_primary_color().into_lvgl_color(),
91 LV_STATE_DEFAULT,
92 );
93 }
94
95 let mut s = Self {
96 animation: Box::new(lv_anim_t::default()),
97 _logo: logo,
98 };
99
100 lv_anim_init(&mut *s.animation);
101 lv_anim_set_var(&mut *s.animation, logo_inner_object as *mut c_void);
102 lv_anim_set_values(&mut *s.animation, 64, 255);
103 lv_anim_set_duration(&mut *s.animation, 500);
104 lv_anim_set_reverse_delay(&mut *s.animation, 0);
105 lv_anim_set_reverse_time(&mut *s.animation, 500);
106 lv_anim_set_repeat_delay(&mut *s.animation, 0);
107 lv_anim_set_repeat_count(&mut *s.animation, u32::MAX);
108 lv_anim_set_path_cb(&mut *s.animation, Some(lv_anim_path_ease_in_out));
109 lv_anim_set_exec_cb(&mut *s.animation, Some(load_animation_callback));
110 lv_anim_start(&*s.animation);
111
112 Ok(s)
113 }
114 }
115
116 pub async fn stop(self, graphics_manager: &'static graphics::Manager) -> Result<()> {
117 let _lock = graphics_manager.lock().await;
118
119 unsafe {
120 lv_anim_delete(self.animation.var, Some(load_animation_callback));
121 }
122
123 Ok(())
124 }
125}