1use alloc::boxed::Box;
2
3use core::{mem::forget, str};
4
5use alloc::collections::VecDeque;
6
7use crate::{Color, Error, EventKind, Result, event::Event};
8
9use super::lvgl;
10
11struct UserData {
12 pub queue: VecDeque<Event>,
13 pub icon_text: [u8; 2],
14 pub icon_color: Color,
15}
16
17pub struct Window {
18 window: *mut lvgl::lv_obj_t,
19}
20
21impl Drop for Window {
22 fn drop(&mut self) {
23 unsafe {
24 let user_data = lvgl::lv_obj_get_user_data(self.window) as *mut UserData;
25
26 let _user_data = Box::from_raw(user_data);
27
28 lvgl::lv_obj_delete(self.window);
29 }
30 }
31}
32
33unsafe extern "C" fn event_callback(event: *mut lvgl::lv_event_t) {
34 unsafe {
35 let code = lvgl::lv_event_get_code(event);
36
37 let queue = lvgl::lv_event_get_user_data(event) as *mut VecDeque<Event>;
38
39 let target = lvgl::lv_event_get_target(event) as *mut lvgl::lv_obj_t;
40
41 match code {
42 lvgl::lv_event_code_t_LV_EVENT_CHILD_CREATED => {
43 lvgl::lv_obj_add_flag(target, lvgl::lv_obj_flag_t_LV_OBJ_FLAG_EVENT_BUBBLE);
44
45 (*queue).push_back(Event::new(EventKind::ChildCreated, target, None));
46 }
47 lvgl::lv_event_code_t_LV_EVENT_KEY => {
48 let key = lvgl::lv_indev_get_key(lvgl::lv_indev_active());
49
50 (*queue).push_back(Event::new(EventKind::Key, target, Some(key.into())));
51 }
52 _ => {
53 (*queue).push_back(Event::new(EventKind::from_lvgl_code(code), target, None));
54 }
55 }
56 }
57}
58
59impl Window {
60 pub unsafe fn new(parent_object: *mut lvgl::lv_obj_t) -> Result<Self> {
75 let window = unsafe { lvgl::lv_obj_create(parent_object) };
76
77 if window.is_null() {
78 return Err(Error::FailedToCreateObject);
79 }
80
81 let user_data = UserData {
82 queue: VecDeque::with_capacity(10),
83 icon_text: [b'I', b'c'],
84 icon_color: Color::BLACK,
85 };
86
87 let mut user_data = Box::new(user_data);
88
89 unsafe {
90 lvgl::lv_obj_add_event_cb(
92 window,
93 Some(event_callback),
94 lvgl::lv_event_code_t_LV_EVENT_ALL,
95 &mut user_data.queue as *mut _ as *mut core::ffi::c_void,
96 );
97 lvgl::lv_obj_set_user_data(window, Box::into_raw(user_data) as *mut core::ffi::c_void);
98 lvgl::lv_obj_set_size(window, lvgl::lv_pct(100), lvgl::lv_pct(100));
100 lvgl::lv_obj_set_style_border_width(window, 0, lvgl::LV_STATE_DEFAULT);
101 lvgl::lv_obj_set_style_radius(window, 0, lvgl::LV_STATE_DEFAULT);
102 }
103
104 Ok(Self { window })
105 }
106
107 pub fn get_identifier(&self) -> usize {
108 self.window as usize
109 }
110
111 pub fn peek_event(&self) -> Option<Event> {
112 let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
113
114 let user_data = unsafe { Box::from_raw(user_data) };
115
116 let event = user_data.queue.front().cloned();
117
118 forget(user_data);
119
120 event
121 }
122
123 pub fn pop_event(&mut self) -> Option<Event> {
124 let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
125
126 let mut user_data = unsafe { Box::from_raw(user_data) };
127
128 let event = user_data.queue.pop_front();
129
130 forget(user_data);
131
132 event
133 }
134
135 pub fn get_object(&self) -> *mut lvgl::lv_obj_t {
136 self.window
137 }
138
139 pub fn get_icon(&self) -> (&str, Color) {
140 let user_data = unsafe {
141 let user_data = lvgl::lv_obj_get_user_data(self.window) as *mut UserData;
142
143 &*user_data
144 };
145
146 unsafe {
147 (
148 str::from_utf8_unchecked(&user_data.icon_text),
149 user_data.icon_color,
150 )
151 }
152 }
153
154 pub fn set_icon(&mut self, icon_string: &str, icon_color: Color) {
155 let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
156
157 let user_data = unsafe { &mut *user_data };
158
159 let mut iterator = icon_string.chars();
160
161 if let Some(character) = iterator.next() {
162 user_data.icon_text[0] = character as u8;
163 }
164
165 if let Some(character) = iterator.next() {
166 user_data.icon_text[1] = character as u8;
167 }
168
169 user_data.icon_color = icon_color;
170 }
171
172 pub unsafe fn from_raw(window: *mut lvgl::lv_obj_t) -> Self {
183 Self { window }
184 }
185
186 pub fn into_raw(self) -> *mut lvgl::lv_obj_t {
187 let window = self.window;
188
189 forget(self);
190
191 window
192 }
193}