From bd91097ecdb20c3f99b54771deb4bdc58f42a539 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Sat, 18 Apr 2020 19:20:38 +0200 Subject: [PATCH] Improvements in the bindings --- Cargo.toml | 6 ++ examples/demo/include/lv_conf.h | 2 +- examples/demo/src/main.rs | 54 ++++++++---- lvgl-sys/build.rs | 12 +-- lvgl-sys/include/lvgl_sys.c | 6 ++ lvgl-sys/include/lvgl_sys.h | 16 ++++ lvgl-sys/src/bindings.rs | 5 +- lvgl/src/objx.rs | 141 ++++++++++++++++++-------------- 8 files changed, 152 insertions(+), 90 deletions(-) create mode 100644 Cargo.toml create mode 100644 lvgl-sys/include/lvgl_sys.c create mode 100644 lvgl-sys/include/lvgl_sys.h diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..57a7ed7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +members = [ + "lvgl", + "lvgl-sys", + "examples/demo", +] diff --git a/examples/demo/include/lv_conf.h b/examples/demo/include/lv_conf.h index 71d6237..278b923 100644 --- a/examples/demo/include/lv_conf.h +++ b/examples/demo/include/lv_conf.h @@ -51,7 +51,7 @@ /* Default display refresh period. * Can be changed in the display driver (`lv_disp_drv_t`).*/ -#define LV_DISP_DEF_REFR_PERIOD 100 /*[ms]*/ +#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ /* Dot Per Inch: used to initialize default sizes. * E.g. a button with width = LV_DPI / 2 -> half inch wide diff --git a/examples/demo/src/main.rs b/examples/demo/src/main.rs index 9d98cfe..3aee305 100644 --- a/examples/demo/src/main.rs +++ b/examples/demo/src/main.rs @@ -1,6 +1,6 @@ -use lvgl_sys; use lvgl; -use lvgl::{Object, Style}; +use lvgl::Object; +use lvgl_sys; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::pixels::Color; @@ -13,10 +13,8 @@ use std::time::Duration; fn main() -> Result<(), String> { let sdl_context = sdl2::init()?; let video_subsystem = sdl_context.video()?; - let mut framebuffer = [ - [Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize]; - lvgl_sys::LV_HOR_RES_MAX as usize - ]; + let mut framebuffer = [[Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize]; + lvgl_sys::LV_HOR_RES_MAX as usize]; let window = video_subsystem .window( @@ -65,11 +63,18 @@ fn main() -> Result<(), String> { // let mut label = lvgl::Label::new(&mut button); // label.set_text("Hello Mundo!\0"); + let font_roboto_28 = unsafe { &lvgl_sys::lv_font_roboto_28 }; + let font_noto_sans_numeric_28 = unsafe { ¬o_sans_numeric_80 }; + + let mut screen_style = lvgl::Style::new(); + screen_style.set_body_main_color(lvgl::Color::from_rgb((0, 0, 0))); + screen_style.set_body_grad_color(lvgl::Color::from_rgb((0, 0, 0))); + screen.set_style(&mut screen_style); + let mut time = lvgl::Label::new(&mut screen); - let mut style_time = Style::default(); - style_time.text.font = unsafe { - Some(¬o_sans_numeric_80) - }; + let mut style_time = lvgl::Style::new(); + style_time.set_text_font(font_noto_sans_numeric_28); + style_time.set_text_color(lvgl::Color::from_rgb((255, 255, 255))); time.set_style(&mut style_time); time.set_align(&mut screen, lvgl::Align::InLeftMid, 20, 0); time.set_text("20:46\0"); @@ -77,10 +82,8 @@ fn main() -> Result<(), String> { time.set_height(240); let mut bt = lvgl::Label::new(&mut screen); - let mut style_bt = Style::default(); - style_bt.text.font = unsafe { - Some(&lvgl_sys::lv_font_roboto_28) - }; + let mut style_bt = lvgl::Style::new(); + style_bt.set_text_font(font_roboto_28); let mut style_power = style_bt.clone(); bt.set_style(&mut style_bt); bt.set_width(50); @@ -114,7 +117,9 @@ fn main() -> Result<(), String> { } } - ::std::thread::sleep(Duration::from_millis(lvgl_sys::LV_DISP_DEF_REFR_PERIOD as u64)); + ::std::thread::sleep(Duration::from_millis( + lvgl_sys::LV_DISP_DEF_REFR_PERIOD as u64, + )); unsafe { lvgl_sys::lv_task_handler(); @@ -124,6 +129,7 @@ fn main() -> Result<(), String> { Ok(()) } +// Reference to native font for LittlevGL, defined in the file: "fonts_noto_sans_numeric_80.c" extern "C" { pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t; } @@ -146,7 +152,8 @@ where fn new(mut callback: F) -> Self { // Create a display buffer for LittlevGL let mut display_buffer = MaybeUninit::::uninit(); - let mut refresh_buffer: [MaybeUninit; lvgl_sys::LV_HOR_RES_MAX as usize * 10] = + let mut refresh_buffer: [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 @@ -188,17 +195,23 @@ unsafe extern "C" fn display_callback_wrapper( ) where F: FnMut(Vec, Vec), { - // we need to make sure panics can't escape across the FFI boundary. + // We need to make sure panics can't escape across the FFI boundary. let _ = panic::catch_unwind(|| { let mut i = 0; let disp = *disp_drv; + + // Rust code closure reference 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 { + // Convert point to paint to a high-level Rust repr points.push(Point::new(x as i32, y as i32)); + + // Convert C color representation to high-level Rust let raw_color = *color_p.add(i); let color = Color::from(( raw_color.ch.red, @@ -207,10 +220,15 @@ unsafe extern "C" fn display_callback_wrapper( raw_color.ch.alpha, )); colors.push(color); + i = i + 1; } } + + // Callback the Rust closure to flush the new points to the screen closure(points, colors); - lvgl_sys::lv_disp_flush_ready(disp_drv); // Indicate you are ready with the flushing + + // Indicate to LittlevGL that you are ready with the flushing + lvgl_sys::lv_disp_flush_ready(disp_drv); }); } diff --git a/lvgl-sys/build.rs b/lvgl-sys/build.rs index b7dd261..42c81e3 100644 --- a/lvgl-sys/build.rs +++ b/lvgl-sys/build.rs @@ -8,6 +8,7 @@ fn main() { let project_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) .canonicalize() .unwrap(); + let include_dir = project_dir.join("include"); let vendor = project_dir.join("vendor"); let vendor_src = vendor.join("lvgl").join("src"); @@ -52,7 +53,9 @@ fn main() { add_c_files(&mut cfg, vendor_src.join("lv_misc")); add_c_files(&mut cfg, vendor_src.join("lv_objx")); add_c_files(&mut cfg, vendor_src.join("lv_themes")); + add_c_files(&mut cfg, vendor_src.join("lv_themes")); add_c_files(&mut cfg, &lv_config_dir); + add_c_files(&mut cfg, &include_dir); cfg.define("LV_CONF_INCLUDE_SIMPLE", Some("1")) .include(&vendor_src) @@ -69,14 +72,7 @@ fn main() { vendor.to_str().unwrap(), ]; bindgen::Builder::default() - .header( - vendor_src - .parent() - .unwrap() - .join("lvgl.h") - .to_str() - .unwrap(), - ) + .header(include_dir.join("lvgl_sys.h").to_str().unwrap()) .layout_tests(false) .use_core() .ctypes_prefix("cty") diff --git a/lvgl-sys/include/lvgl_sys.c b/lvgl-sys/include/lvgl_sys.c new file mode 100644 index 0000000..b38f81a --- /dev/null +++ b/lvgl-sys/include/lvgl_sys.c @@ -0,0 +1,6 @@ +#include "lvgl_sys.h" + +lv_color_t lvsys_color_make(uint8_t r, uint8_t g, uint8_t b) +{ + return LV_COLOR_MAKE(r, g, b); +} diff --git a/lvgl-sys/include/lvgl_sys.h b/lvgl-sys/include/lvgl_sys.h new file mode 100644 index 0000000..b55b3be --- /dev/null +++ b/lvgl-sys/include/lvgl_sys.h @@ -0,0 +1,16 @@ +#ifndef LVGL_API_H +#define LVGL_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lvgl/lvgl.h" + +lv_color_t lvsys_color_make(uint8_t r, uint8_t g, uint8_t b); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LVGL_API*/ diff --git a/lvgl-sys/src/bindings.rs b/lvgl-sys/src/bindings.rs index bbe39f1..b906401 100644 --- a/lvgl-sys/src/bindings.rs +++ b/lvgl-sys/src/bindings.rs @@ -178,7 +178,7 @@ pub const LV_COLOR_16_SWAP: u32 = 0; pub const LV_COLOR_SCREEN_TRANSP: u32 = 0; pub const LV_INDEXED_CHROMA: u32 = 1; pub const LV_ANTIALIAS: u32 = 1; -pub const LV_DISP_DEF_REFR_PERIOD: u32 = 100; +pub const LV_DISP_DEF_REFR_PERIOD: u32 = 30; pub const LV_DPI: u32 = 100; pub const LV_MEM_CUSTOM: u32 = 0; pub const LV_MEM_SIZE: u32 = 131072; @@ -11788,6 +11788,9 @@ extern "C" { #[doc = " @param src an image source path to a file or pointer to an `lv_img_dsc_t` variable."] pub fn lv_img_cache_invalidate_src(src: *const cty::c_void); } +extern "C" { + pub fn lvsys_color_make(r: u8, g: u8, b: u8) -> lv_color_t; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct __locale_data { diff --git a/lvgl/src/objx.rs b/lvgl/src/objx.rs index f621677..d34a5a4 100644 --- a/lvgl/src/objx.rs +++ b/lvgl/src/objx.rs @@ -1,7 +1,7 @@ +use core::mem; use core::ptr; use cty; use lvgl_sys; -use core::mem; pub trait NativeObject { fn raw(&self) -> ptr::NonNull; @@ -9,7 +9,7 @@ pub trait NativeObject { pub struct ObjectX<'a> { raw: ptr::NonNull, - style: Option<&'a mut Style<'a>>, + style: Option<&'a mut Style>, } impl<'a> ObjectX<'a> { @@ -57,13 +57,10 @@ pub trait Object<'a>: NativeObject { } } - fn set_align( - &mut self, - base: &mut C, - align: Align, - x_mod: i32, - y_mod: i32, - ) where C: NativeObject { + fn set_align(&mut self, base: &mut C, align: Align, x_mod: i32, y_mod: i32) + where + C: NativeObject, + { let align = match align { Align::Center => lvgl_sys::LV_ALIGN_CENTER, Align::InTopLeft => lvgl_sys::LV_ALIGN_IN_TOP_LEFT, @@ -98,7 +95,16 @@ pub trait Object<'a>: NativeObject { } } - fn set_style(&mut self, style: &'a mut Style<'a>); + fn set_style(&mut self, style: &'a mut Style); +} + +impl<'a> Object<'a> for ObjectX<'a> { + fn set_style(&mut self, style: &'a mut Style) { + unsafe { + lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw()); + }; + self.style = Some(style); + } } macro_rules! define_object { @@ -114,20 +120,23 @@ macro_rules! define_object { } impl<'a> Object<'a> for $item<'a> { - fn set_style(&mut self, style: &'a mut Style<'a>) { + fn set_style(&mut self, style: &'a mut Style) { unsafe { lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw()); }; self.core.style = Some(style); } } - } + }; } define_object!(Button); impl<'a> Button<'a> { - pub fn new(parent: &mut C) -> Self where C: NativeObject { + pub fn new(parent: &mut C) -> Self + where + C: NativeObject, + { let raw = unsafe { let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut()); ptr::NonNull::new_unchecked(ptr) @@ -147,7 +156,10 @@ pub enum LabelAlign { define_object!(Label); impl<'a> Label<'a> { - pub fn new(parent: &mut C) -> Self where C: NativeObject { + pub fn new(parent: &mut C) -> Self + where + C: NativeObject, + { let raw = unsafe { let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut()); ptr::NonNull::new_unchecked(ptr) @@ -188,64 +200,69 @@ pub enum Themes { Pretty, } -#[derive(Default)] -pub struct Style<'a> { - raw: Option, - pub text: TextStyle<'a>, +pub struct Style { + raw: lvgl_sys::lv_style_t, } -impl<'a> Style<'a> { +impl Style { + pub fn new() -> Self { + let raw = unsafe { + let mut native_style = mem::MaybeUninit::::uninit(); + lvgl_sys::lv_style_copy(native_style.as_mut_ptr(), &lvgl_sys::lv_style_pretty); + native_style.assume_init() + }; + Self { raw } + } + + /// Object's main background color. + pub fn set_body_main_color(&mut self, color: Color) { + self.raw.body.main_color = color.raw; + } + + /// Second color. If not equal to `set_body_main_color` a gradient will be drawn for the background. + pub fn set_body_grad_color(&mut self, color: Color) { + self.raw.body.grad_color = color.raw; + } + + /// Text color. + pub fn set_text_color(&mut self, color: Color) { + self.raw.text.color = color.raw; + } + + /// Font used for displaying the text. + pub fn set_text_font(&mut self, font: &lvgl_sys::lv_font_t) { + self.raw.text.font = font; + } + fn raw(&mut self) -> *const lvgl_sys::lv_style_t { - match self.raw { - Some(mut native_pointer) => { - &mut native_pointer - }, - None => unsafe { - let mut native_style = mem::MaybeUninit::::uninit(); - lvgl_sys::lv_style_copy(native_style.as_mut_ptr(), &lvgl_sys::lv_style_pretty); - self.raw = Some(native_style.assume_init()); - if let Some(text_font) = self.text.font { - self.raw.as_mut().unwrap().text.font = text_font as *const lvgl_sys::lv_font_t; - } - self.raw.as_mut().unwrap() + &mut self.raw + } +} + +impl Clone for Style { + fn clone(&self) -> Self { + let mut native_style = mem::MaybeUninit::::uninit(); + unsafe { + lvgl_sys::lv_style_copy( + native_style.as_mut_ptr(), + &self.raw as *const lvgl_sys::lv_style_t, + ); + Self { + raw: native_style.assume_init(), } } } } -impl<'a> Clone for Style<'a> { - fn clone(&self) -> Self { - match self.raw { - Some(_) => { - let mut native_style = mem::MaybeUninit::::uninit(); - unsafe { - lvgl_sys::lv_style_copy(native_style.as_mut_ptr(), self.raw.as_ref().unwrap()); - Self{ - raw: Some(native_style.assume_init()), - text: self.text.clone() - } - } - }, - None => { - Self{ - raw: None, - text: self.text.clone() - } - } - } - } +#[derive(Clone)] +pub struct Color { + raw: lvgl_sys::lv_color_t, } -#[derive(Default)] -pub struct TextStyle<'a> { - pub font: Option<&'a lvgl_sys::lv_font_t>, -} - -impl<'a> Clone for TextStyle<'a> { - fn clone(&self) -> Self { - Self { - font: self.font.clone() - } +impl Color { + pub fn from_rgb((r, g, b): (u8, u8, u8)) -> Self { + let raw = unsafe { lvgl_sys::lvsys_color_make(r, g, b) }; + Self { raw } } }