From 633b076e38340f0181a0c8d6bf0ef7a28fbd68cb Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sat, 11 Apr 2020 19:39:20 +0200 Subject: [PATCH] Example draws widgets --- examples/demo/Cargo.toml | 1 + examples/demo/src/main.rs | 167 ++++++++++++++++++++++++++------------ lvgl-sys/build.rs | 11 ++- 3 files changed, 122 insertions(+), 57 deletions(-) diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index d744b12..8d6735f 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -9,3 +9,4 @@ edition = "2018" [dependencies] lvgl-sys = { path = "../../lvgl-sys" } sdl2 = "0.33.0" +lazy_static = "1.4.0" diff --git a/examples/demo/src/main.rs b/examples/demo/src/main.rs index ebc1df2..5cb6d2e 100644 --- a/examples/demo/src/main.rs +++ b/examples/demo/src/main.rs @@ -1,103 +1,164 @@ -use std::ffi::CString; -use std::os::raw::c_void; -use std::time::Duration; -use std::mem::MaybeUninit; - +use lazy_static; +use lvgl_sys; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::{Color, PixelFormat, PixelFormatEnum}; +use sdl2::pixels::Color; +use sdl2::rect::{Point, Rect}; +use sdl2::render::{WindowCanvas, CanvasBuilder, Canvas}; +use sdl2::video::Window; +use std::ffi::CString; +use std::mem::{MaybeUninit, ManuallyDrop}; +use std::os::raw::c_void; +use std::time::Duration; +use std::ptr::NonNull; +use std::panic; +use std::sync::mpsc::channel; -use lvgl_sys; -use lvgl_sys::{lv_btn_create, lv_color_t, lv_disp_buf_init, lv_disp_buf_t, lv_disp_drv_init, lv_disp_drv_register, lv_disp_drv_t, lv_disp_get_hor_res, lv_disp_get_scr_act, lv_disp_get_ver_res, lv_label_create, lv_label_set_text, lv_obj_set_pos, lv_obj_set_size, lv_obj_set_x, lv_obj_set_y, lv_obj_t, lv_task_handler, lv_area_t, lv_disp_flush_ready, LV_HOR_RES_MAX, lv_style_t, lv_style_copy, lv_style_btn_rel, LV_BTN_STYLE_PR, LV_BTN_STYLE_REL, lv_slider_set_style}; fn main() -> Result<(), String> { - unsafe { - lvgl_sys::lv_init(); - } - let sdl_context = sdl2::init()?; let video_subsystem = sdl_context.video()?; - let hr: u32 = unsafe { lv_disp_get_hor_res(std::ptr::null_mut()) as u32 }; - let vr: u32 = unsafe { lv_disp_get_ver_res(std::ptr::null_mut()) as u32 }; + let hr: u32 = unsafe { lvgl_sys::lv_disp_get_hor_res(std::ptr::null_mut()) as u32 }; + let vr: u32 = unsafe { lvgl_sys::lv_disp_get_ver_res(std::ptr::null_mut()) as u32 }; - let window = video_subsystem.window("TFT Display: Demo", hr, vr) + let window = video_subsystem + .window("TFT Display: Demo", hr, vr) .position_centered() .opengl() .build() .map_err(|e| e.to_string())?; - let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; + let mut canvas = window + .into_canvas() + .build().map_err(|e| e.to_string())?; - canvas.set_draw_color(Color::RGB(255, 0, 0)); + canvas.set_draw_color(Color::RGB(255, 255, 255)); canvas.clear(); canvas.present(); - let mut event_pump = sdl_context.event_pump()?; - // Create a display buffer for LittlevGL - let mut disp_buf = MaybeUninit::::uninit(); - let mut buf: [MaybeUninit; LV_HOR_RES_MAX as usize * 10] = unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/ unsafe { - lv_disp_buf_init(disp_buf.as_mut_ptr(), buf.as_mut_ptr() as *mut c_void, std::ptr::null_mut(), (hr * 10) as u32); /*Initialize the display buffer*/ + lvgl_sys::lv_init(); + } + // Create a display buffer for LittlevGL + let mut disp_buf = MaybeUninit::::uninit(); + let mut buf: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10] = + unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/ + unsafe { + // Initialize the display buffer + lvgl_sys::lv_disp_buf_init( + disp_buf.as_mut_ptr(), + buf.as_mut_ptr() as *mut c_void, + std::ptr::null_mut(), + (hr * 10) as u32, + ); } // Implement and register a function which can copy a pixel array to an area of your display: - unsafe { - unsafe extern "C" fn my_disp_flush(disp_drv: *mut lv_disp_drv_t, area: *const lv_area_t, color_p: *mut lv_color_t) { - let mut i = 1; - for y in (*area).y1..(*area).y2 { - for x in (*area).x1..(*area).x2 { - // Put a pixel to the display. - let raw_color = *color_p.add(i); - let color = Color::from((raw_color.ch.red, raw_color.ch.green, raw_color.ch.blue, raw_color.ch.alpha)); - if raw_color.ch.blue != 255 { - println!("{}x{} - {:?}", x, y, color.rgb()); - } - i = i + 1; - } - } - - lv_disp_flush_ready(disp_drv); /* Indicate you are ready with the flushing*/ + let mut display_driver = DisplayDriver::new(move |points, colors| { + for (i, point) in points.into_iter().enumerate() { + canvas.set_draw_color(colors[i]); + canvas.draw_point(point); } + canvas.present(); + }); - let mut disp_drv = MaybeUninit::::uninit().assume_init(); /*Descriptor of a display driver*/ - lv_disp_drv_init(&mut disp_drv); /*Basic initialization*/ - disp_drv.flush_cb = Some(my_disp_flush); /*Set your driver function*/ - disp_drv.buffer = disp_buf.as_mut_ptr(); /*Assign the buffer to the display*/ - lv_disp_drv_register(&mut disp_drv); /*Finally register the driver*/ + display_driver.raw.buffer = disp_buf.as_mut_ptr(); // Assign the buffer to the display + unsafe { + lvgl_sys::lv_disp_drv_register(&mut display_driver.raw); // Finally register the driver } // Create screen and widgets - let mut screen = unsafe { lv_disp_get_scr_act(std::ptr::null_mut()) }; - let mut btn = unsafe { lv_btn_create(screen, std::ptr::null_mut()) }; + let mut screen = unsafe { lvgl_sys::lv_disp_get_scr_act(std::ptr::null_mut()) }; + let mut btn = unsafe { lvgl_sys::lv_btn_create(screen, std::ptr::null_mut()) }; unsafe { - lv_obj_set_pos(btn, 10, 10); - lv_obj_set_size(btn, 200, 50) + lvgl_sys::lv_obj_set_pos(btn, 10, 10); + lvgl_sys::lv_obj_set_size(btn, 200, 50) } - let mut label = unsafe { lv_label_create(btn, std::ptr::null_mut()) }; + let mut label = unsafe { lvgl_sys::lv_label_create(btn, std::ptr::null_mut()) }; + let text = CString::new("Ewa, eu te amo!").unwrap(); unsafe { - lv_label_set_text(label, CString::new("Click me!").unwrap().as_ptr()); + lvgl_sys::lv_label_set_text(label, text.as_ptr()); } + let mut event_pump = sdl_context.event_pump()?; 'running: loop { for event in event_pump.poll_iter() { match event { - Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => { break 'running; } _ => {} } } - canvas.clear(); - canvas.present(); ::std::thread::sleep(Duration::from_millis(300)); // The rest of the game loop goes here... unsafe { - lv_task_handler(); + lvgl_sys::lv_task_handler(); } } Ok(()) } + +struct DisplayDriver + where F: FnMut(Vec, Vec) +{ + pub raw: lvgl_sys::lv_disp_drv_t, + callback: F, +} + +impl DisplayDriver + where F: FnMut(Vec, Vec) +{ + fn new(mut callback: F) -> Self { + let disp_drv = unsafe { + let mut disp_drv = MaybeUninit::::uninit().assume_init(); /*Descriptor of a display driver*/ + lvgl_sys::lv_disp_drv_init(&mut disp_drv); // Basic initialization + disp_drv.flush_cb = Some(display_callback_wrapper::); // Set your driver function + disp_drv.user_data = &mut callback as *mut _ as *mut c_void; + disp_drv + }; + Self{ raw: disp_drv, callback } + } +} + +unsafe extern "C" fn display_callback_wrapper( + disp_drv: *mut lvgl_sys::lv_disp_drv_t, + area: *const lvgl_sys::lv_area_t, + color_p: *mut lvgl_sys::lv_color_t +) + where F: FnMut(Vec, Vec) +{ + // we need to make sure panics can't escape across the FFI boundary. + let _ = panic::catch_unwind(|| { + let mut i = 0; + let mut disp = *disp_drv; + let closure = &mut *(disp.user_data as *mut F); + let mut points = vec![]; + let mut colors = vec![]; + + for y in (*area).y1..=(*area).y2 { + for x in (*area).x1..=(*area).x2 { + points.push(Point::new(x as i32, y as i32)); + let raw_color = *color_p.add(i); + let color = Color::from(( + raw_color.ch.red, + raw_color.ch.green, + raw_color.ch.blue, + raw_color.ch.alpha, + )); + colors.push(color); + i = i + 1; + } + } + closure(points, colors); + lvgl_sys::lv_disp_flush_ready(disp_drv); // Indicate you are ready with the flushing + }); +} diff --git a/lvgl-sys/build.rs b/lvgl-sys/build.rs index 1292a3e..9e01018 100644 --- a/lvgl-sys/build.rs +++ b/lvgl-sys/build.rs @@ -1,6 +1,6 @@ -use std::{env, path::PathBuf, path::Path}; -use cc::Build; use bindgen; +use cc::Build; +use std::{env, path::Path, path::PathBuf}; fn main() { let project_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) @@ -30,7 +30,11 @@ fn main() { .include(&lvgl_config_path) .compile("lvgl"); - let cc_args = ["-DLV_CONF_INCLUDE_SIMPLE=1", "-I", lvgl_config_path.to_str().unwrap()]; + let cc_args = [ + "-DLV_CONF_INCLUDE_SIMPLE=1", + "-I", + lvgl_config_path.to_str().unwrap(), + ]; bindgen::Builder::default() .header(src.parent().unwrap().join("lvgl.h").to_str().unwrap()) .clang_args(&cc_args) @@ -40,7 +44,6 @@ fn main() { .expect("Can't write bindings!"); } - fn add_c_files(build: &mut cc::Build, path: impl AsRef) { for e in path.as_ref().read_dir().unwrap() { let e = e.unwrap();