graphics/
window.rs

1use super::lvgl;
2use crate::{Color, Error, EventKind, Result, event::Event};
3use alloc::boxed::Box;
4use alloc::collections::VecDeque;
5use core::{mem::forget, str};
6
7struct UserData {
8    pub queue: VecDeque<Event>,
9    pub icon_text: [u8; 2],
10    pub icon_color: Color,
11}
12
13pub struct Window {
14    window: *mut lvgl::lv_obj_t,
15}
16
17impl Drop for Window {
18    fn drop(&mut self) {
19        unsafe {
20            let user_data = lvgl::lv_obj_get_user_data(self.window) as *mut UserData;
21
22            let _user_data = Box::from_raw(user_data);
23
24            lvgl::lv_obj_delete(self.window);
25        }
26    }
27}
28
29unsafe extern "C" fn event_callback(event: *mut lvgl::lv_event_t) {
30    unsafe {
31        let code = lvgl::lv_event_get_code(event);
32
33        let queue = lvgl::lv_event_get_user_data(event) as *mut VecDeque<Event>;
34
35        let target = lvgl::lv_event_get_target(event) as *mut lvgl::lv_obj_t;
36
37        match code {
38            lvgl::lv_event_code_t_LV_EVENT_CHILD_CREATED => {
39                lvgl::lv_obj_add_flag(target, lvgl::lv_obj_flag_t_LV_OBJ_FLAG_EVENT_BUBBLE);
40
41                (*queue).push_back(Event::new(EventKind::ChildCreated, target, None));
42            }
43            lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN
44            | lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN_BEGIN
45            | lvgl::lv_event_code_t_LV_EVENT_DRAW_MAIN_END
46            | lvgl::lv_event_code_t_LV_EVENT_DRAW_POST
47            | lvgl::lv_event_code_t_LV_EVENT_DRAW_POST_BEGIN
48            | lvgl::lv_event_code_t_LV_EVENT_DRAW_POST_END
49            | lvgl::lv_event_code_t_LV_EVENT_GET_SELF_SIZE
50            | lvgl::lv_event_code_t_LV_EVENT_COVER_CHECK => {
51                // Ignore draw events
52            }
53            lvgl::lv_event_code_t_LV_EVENT_KEY => {
54                let key = lvgl::lv_indev_get_key(lvgl::lv_indev_active());
55
56                (*queue).push_back(Event::new(EventKind::Key, target, Some(key.into())));
57            }
58            _ => {
59                (*queue).push_back(Event::new(EventKind::from_lvgl_code(code), target, None));
60            }
61        }
62    }
63}
64
65impl Window {
66    /// Create a new window.
67    ///
68    /// # Arguments
69    ///
70    /// * `Parent_object` - The parent object of the window.
71    ///
72    /// # Returns
73    ///
74    /// * `Result<Self>` - The result of the operation.
75    ///
76    /// # Safety
77    ///
78    /// This function is unsafe because it may dereference raw pointers (e.g. `Parent_object`).
79    ///
80    pub unsafe fn new(parent_object: *mut lvgl::lv_obj_t) -> Result<Self> {
81        let window = unsafe { lvgl::lv_obj_create(parent_object) };
82
83        if window.is_null() {
84            return Err(Error::FailedToCreateObject);
85        }
86
87        let user_data = UserData {
88            queue: VecDeque::with_capacity(10),
89            icon_text: [b'I', b'c'],
90            icon_color: Color::BLACK,
91        };
92
93        let mut user_data = Box::new(user_data);
94
95        unsafe {
96            // Set the event callback for the window.
97            lvgl::lv_obj_add_event_cb(
98                window,
99                Some(event_callback),
100                lvgl::lv_event_code_t_LV_EVENT_ALL,
101                &mut user_data.queue as *mut _ as *mut core::ffi::c_void,
102            );
103            lvgl::lv_obj_add_flag(window, lvgl::lv_obj_flag_t_LV_OBJ_FLAG_EVENT_BUBBLE);
104            lvgl::lv_obj_set_user_data(window, Box::into_raw(user_data) as *mut core::ffi::c_void);
105            // Set the size of the window to 100% of the parent object.
106            lvgl::lv_obj_set_size(window, lvgl::lv_pct(100), lvgl::lv_pct(100));
107            lvgl::lv_obj_set_style_border_width(window, 0, lvgl::LV_STATE_DEFAULT);
108            lvgl::lv_obj_set_style_radius(window, 0, lvgl::LV_STATE_DEFAULT);
109        }
110
111        Ok(Self { window })
112    }
113
114    pub fn get_identifier(&self) -> usize {
115        self.window as usize
116    }
117
118    pub fn peek_event(&self) -> Option<Event> {
119        let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
120
121        let user_data = unsafe { Box::from_raw(user_data) };
122
123        let event = user_data.queue.front().cloned();
124
125        forget(user_data);
126
127        event
128    }
129
130    pub fn pop_event(&mut self) -> Option<Event> {
131        let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
132
133        let mut user_data = unsafe { Box::from_raw(user_data) };
134
135        let event = user_data.queue.pop_front();
136
137        forget(user_data);
138
139        event
140    }
141
142    pub fn get_object(&self) -> *mut lvgl::lv_obj_t {
143        self.window
144    }
145
146    pub fn get_icon(&self) -> (&str, Color) {
147        let user_data = unsafe {
148            let user_data = lvgl::lv_obj_get_user_data(self.window) as *mut UserData;
149
150            &*user_data
151        };
152
153        unsafe {
154            (
155                str::from_utf8_unchecked(&user_data.icon_text),
156                user_data.icon_color,
157            )
158        }
159    }
160
161    pub fn set_icon(&mut self, icon_string: &str, icon_color: Color) {
162        let user_data = unsafe { lvgl::lv_obj_get_user_data(self.window) as *mut UserData };
163
164        let user_data = unsafe { &mut *user_data };
165
166        let mut iterator = icon_string.chars();
167
168        if let Some(character) = iterator.next() {
169            user_data.icon_text[0] = character as u8;
170        }
171
172        if let Some(character) = iterator.next() {
173            user_data.icon_text[1] = character as u8;
174        }
175
176        user_data.icon_color = icon_color;
177    }
178
179    /// Convert a raw pointer to a window object.
180    ///
181    /// # Returns
182    ///
183    /// * `Window` - The raw pointer to the window.
184    ///
185    /// # Safety
186    ///
187    /// This function is unsafe because it may dereference raw pointers (e.g. `Window`).
188    ///
189    pub unsafe fn from_raw(window: *mut lvgl::lv_obj_t) -> Self {
190        Self { window }
191    }
192
193    pub fn into_raw(self) -> *mut lvgl::lv_obj_t {
194        let window = self.window;
195
196        forget(self);
197
198        window
199    }
200}