graphics/
display.rs

1use alloc::boxed::Box;
2
3use core::{ffi::c_void, ptr::null_mut, slice};
4
5use file_system::Device;
6
7use crate::{Area, Point, RenderingColor, Result, ScreenWriteData, draw_buffer::Buffer};
8
9use super::lvgl;
10
11struct UserData {
12    device: Device,
13}
14
15pub struct Display {
16    display: *mut lvgl::lv_display_t,
17    _buffer_1: Buffer,
18    _buffer_2: Option<Buffer>,
19}
20
21unsafe impl Send for Display {}
22
23unsafe impl Sync for Display {}
24
25unsafe extern "C" fn binding_callback_function(
26    display: *mut lvgl::lv_disp_t,
27    area: *const lvgl::lv_area_t,
28    data: *mut u8,
29) {
30    let area: Area = unsafe { *area }.into();
31
32    let buffer_size: usize = (area.get_width()) as usize * (area.get_height()) as usize;
33
34    let buffer = unsafe { slice::from_raw_parts_mut(data as *mut RenderingColor, buffer_size) };
35
36    let screen_write_data = ScreenWriteData::new(area, buffer);
37
38    let user_data = unsafe { &*(lvgl::lv_display_get_user_data(display) as *mut UserData) };
39
40    let device = &user_data.device;
41
42    device
43        .write(screen_write_data.as_ref())
44        .expect("Error writing to display");
45
46    unsafe { lvgl::lv_display_flush_ready(display) };
47}
48
49impl Drop for Display {
50    fn drop(&mut self) {
51        unsafe {
52            lvgl::lv_display_delete(self.display);
53        }
54    }
55}
56
57impl Display {
58    pub fn new(
59        file: Device,
60        resolution: Point,
61        buffer_size: usize,
62        double_buffered: bool,
63    ) -> Result<Self> {
64        // Create the display.
65        let lvgl_display: *mut lvgl_rust_sys::_lv_display_t = unsafe {
66            lvgl::lv_display_create(resolution.get_x() as i32, resolution.get_y() as i32)
67        };
68
69        // Set the buffer(s) and the render mode.
70        let buffer_1 = Buffer::new(buffer_size);
71
72        let buffer_2 = if double_buffered {
73            Some(Buffer::new(buffer_size))
74        } else {
75            None
76        };
77
78        unsafe {
79            lvgl::lv_display_set_buffers(
80                lvgl_display,
81                buffer_1.as_ref().as_ptr() as *mut c_void,
82                buffer_2
83                    .as_ref()
84                    .map_or(null_mut(), |buffer| buffer.as_ref().as_ptr() as *mut c_void),
85                buffer_size as u32,
86                lvgl::lv_display_render_mode_t_LV_DISPLAY_RENDER_MODE_PARTIAL,
87            )
88        }
89
90        // Set the user data.
91        let user_data = Box::new(UserData { device: file });
92
93        unsafe {
94            lvgl::lv_display_set_user_data(lvgl_display, Box::into_raw(user_data) as *mut c_void)
95        };
96
97        // Set the flush callback.
98        unsafe { lvgl::lv_display_set_flush_cb(lvgl_display, Some(binding_callback_function)) }
99
100        Ok(Self {
101            display: lvgl_display,
102            _buffer_1: buffer_1,
103            _buffer_2: buffer_2,
104        })
105    }
106
107    pub fn get_object(&self) -> *mut lvgl::lv_obj_t {
108        unsafe { lvgl::lv_display_get_screen_active(self.display) }
109    }
110}