graphics/
window.rs

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    /// Create a new window.
61    ///
62    /// # Arguments
63    ///
64    /// * `Parent_object` - The parent object of the window.
65    ///
66    /// # Returns
67    ///
68    /// * `Result<Self>` - The result of the operation.
69    ///
70    /// # Safety
71    ///
72    /// This function is unsafe because it may dereference raw pointers (e.g. `Parent_object`).
73    ///
74    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            // Set the event callback for the window.
91            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            // Set the size of the window to 100% of the parent object.
99            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    /// Convert a raw pointer to a window object.
173    ///
174    /// # Returns
175    ///
176    /// * `Window` - The raw pointer to the window.
177    ///
178    /// # Safety
179    ///
180    /// This function is unsafe because it may dereference raw pointers (e.g. `Window`).
181    ///
182    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}