Improvements in the bindings

This commit is contained in:
Rafael Caricio 2020-04-18 19:20:38 +02:00
parent 3aed1c3075
commit bd91097ecd
8 changed files with 152 additions and 90 deletions

6
Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[workspace]
members = [
"lvgl",
"lvgl-sys",
"examples/demo",
]

View file

@ -51,7 +51,7 @@
/* Default display refresh period. /* Default display refresh period.
* Can be changed in the display driver (`lv_disp_drv_t`).*/ * 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. /* Dot Per Inch: used to initialize default sizes.
* E.g. a button with width = LV_DPI / 2 -> half inch wide * E.g. a button with width = LV_DPI / 2 -> half inch wide

View file

@ -1,6 +1,6 @@
use lvgl_sys;
use lvgl; use lvgl;
use lvgl::{Object, Style}; use lvgl::Object;
use lvgl_sys;
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
use sdl2::pixels::Color; use sdl2::pixels::Color;
@ -13,10 +13,8 @@ use std::time::Duration;
fn main() -> Result<(), String> { fn main() -> Result<(), String> {
let sdl_context = sdl2::init()?; let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?; let video_subsystem = sdl_context.video()?;
let mut framebuffer = [ let mut framebuffer = [[Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize];
[Color::from((0, 0, 0)); lvgl_sys::LV_VER_RES_MAX as usize]; lvgl_sys::LV_HOR_RES_MAX as usize];
lvgl_sys::LV_HOR_RES_MAX as usize
];
let window = video_subsystem let window = video_subsystem
.window( .window(
@ -65,11 +63,18 @@ fn main() -> Result<(), String> {
// let mut label = lvgl::Label::new(&mut button); // let mut label = lvgl::Label::new(&mut button);
// label.set_text("Hello Mundo!\0"); // label.set_text("Hello Mundo!\0");
let font_roboto_28 = unsafe { &lvgl_sys::lv_font_roboto_28 };
let font_noto_sans_numeric_28 = unsafe { &noto_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 time = lvgl::Label::new(&mut screen);
let mut style_time = Style::default(); let mut style_time = lvgl::Style::new();
style_time.text.font = unsafe { style_time.set_text_font(font_noto_sans_numeric_28);
Some(&noto_sans_numeric_80) style_time.set_text_color(lvgl::Color::from_rgb((255, 255, 255)));
};
time.set_style(&mut style_time); time.set_style(&mut style_time);
time.set_align(&mut screen, lvgl::Align::InLeftMid, 20, 0); time.set_align(&mut screen, lvgl::Align::InLeftMid, 20, 0);
time.set_text("20:46\0"); time.set_text("20:46\0");
@ -77,10 +82,8 @@ fn main() -> Result<(), String> {
time.set_height(240); time.set_height(240);
let mut bt = lvgl::Label::new(&mut screen); let mut bt = lvgl::Label::new(&mut screen);
let mut style_bt = Style::default(); let mut style_bt = lvgl::Style::new();
style_bt.text.font = unsafe { style_bt.set_text_font(font_roboto_28);
Some(&lvgl_sys::lv_font_roboto_28)
};
let mut style_power = style_bt.clone(); let mut style_power = style_bt.clone();
bt.set_style(&mut style_bt); bt.set_style(&mut style_bt);
bt.set_width(50); 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 { unsafe {
lvgl_sys::lv_task_handler(); lvgl_sys::lv_task_handler();
@ -124,6 +129,7 @@ fn main() -> Result<(), String> {
Ok(()) Ok(())
} }
// Reference to native font for LittlevGL, defined in the file: "fonts_noto_sans_numeric_80.c"
extern "C" { extern "C" {
pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t; pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t;
} }
@ -146,7 +152,8 @@ where
fn new(mut callback: F) -> Self { fn new(mut callback: F) -> Self {
// Create a display buffer for LittlevGL // Create a display buffer for LittlevGL
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit(); let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
let mut refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>; lvgl_sys::LV_HOR_RES_MAX as usize * 10] = let mut refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>;
lvgl_sys::LV_HOR_RES_MAX as usize * 10] =
unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/ unsafe { MaybeUninit::uninit().assume_init() }; /*Declare a buffer for 10 lines*/
unsafe { unsafe {
// Initialize the display buffer // Initialize the display buffer
@ -188,17 +195,23 @@ unsafe extern "C" fn display_callback_wrapper<F>(
) where ) where
F: FnMut(Vec<Point>, Vec<Color>), F: FnMut(Vec<Point>, Vec<Color>),
{ {
// 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 _ = panic::catch_unwind(|| {
let mut i = 0; let mut i = 0;
let disp = *disp_drv; let disp = *disp_drv;
// Rust code closure reference
let closure = &mut *(disp.user_data as *mut F); let closure = &mut *(disp.user_data as *mut F);
let mut points = vec![]; let mut points = vec![];
let mut colors = vec![]; let mut colors = vec![];
for y in (*area).y1..=(*area).y2 { for y in (*area).y1..=(*area).y2 {
for x in (*area).x1..=(*area).x2 { 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)); 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 raw_color = *color_p.add(i);
let color = Color::from(( let color = Color::from((
raw_color.ch.red, raw_color.ch.red,
@ -207,10 +220,15 @@ unsafe extern "C" fn display_callback_wrapper<F>(
raw_color.ch.alpha, raw_color.ch.alpha,
)); ));
colors.push(color); colors.push(color);
i = i + 1; i = i + 1;
} }
} }
// Callback the Rust closure to flush the new points to the screen
closure(points, colors); 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);
}); });
} }

View file

@ -8,6 +8,7 @@ fn main() {
let project_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) let project_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
.canonicalize() .canonicalize()
.unwrap(); .unwrap();
let include_dir = project_dir.join("include");
let vendor = project_dir.join("vendor"); let vendor = project_dir.join("vendor");
let vendor_src = vendor.join("lvgl").join("src"); 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_misc"));
add_c_files(&mut cfg, vendor_src.join("lv_objx")); 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, vendor_src.join("lv_themes"));
add_c_files(&mut cfg, &lv_config_dir); add_c_files(&mut cfg, &lv_config_dir);
add_c_files(&mut cfg, &include_dir);
cfg.define("LV_CONF_INCLUDE_SIMPLE", Some("1")) cfg.define("LV_CONF_INCLUDE_SIMPLE", Some("1"))
.include(&vendor_src) .include(&vendor_src)
@ -69,14 +72,7 @@ fn main() {
vendor.to_str().unwrap(), vendor.to_str().unwrap(),
]; ];
bindgen::Builder::default() bindgen::Builder::default()
.header( .header(include_dir.join("lvgl_sys.h").to_str().unwrap())
vendor_src
.parent()
.unwrap()
.join("lvgl.h")
.to_str()
.unwrap(),
)
.layout_tests(false) .layout_tests(false)
.use_core() .use_core()
.ctypes_prefix("cty") .ctypes_prefix("cty")

View file

@ -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);
}

View file

@ -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*/

View file

@ -178,7 +178,7 @@ pub const LV_COLOR_16_SWAP: u32 = 0;
pub const LV_COLOR_SCREEN_TRANSP: u32 = 0; pub const LV_COLOR_SCREEN_TRANSP: u32 = 0;
pub const LV_INDEXED_CHROMA: u32 = 1; pub const LV_INDEXED_CHROMA: u32 = 1;
pub const LV_ANTIALIAS: 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_DPI: u32 = 100;
pub const LV_MEM_CUSTOM: u32 = 0; pub const LV_MEM_CUSTOM: u32 = 0;
pub const LV_MEM_SIZE: u32 = 131072; 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."] #[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); 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)] #[repr(C)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct __locale_data { pub struct __locale_data {

View file

@ -1,7 +1,7 @@
use core::mem;
use core::ptr; use core::ptr;
use cty; use cty;
use lvgl_sys; use lvgl_sys;
use core::mem;
pub trait NativeObject { pub trait NativeObject {
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>; fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
@ -9,7 +9,7 @@ pub trait NativeObject {
pub struct ObjectX<'a> { pub struct ObjectX<'a> {
raw: ptr::NonNull<lvgl_sys::lv_obj_t>, raw: ptr::NonNull<lvgl_sys::lv_obj_t>,
style: Option<&'a mut Style<'a>>, style: Option<&'a mut Style>,
} }
impl<'a> ObjectX<'a> { impl<'a> ObjectX<'a> {
@ -57,13 +57,10 @@ pub trait Object<'a>: NativeObject {
} }
} }
fn set_align<C>( fn set_align<C>(&mut self, base: &mut C, align: Align, x_mod: i32, y_mod: i32)
&mut self, where
base: &mut C, C: NativeObject,
align: Align, {
x_mod: i32,
y_mod: i32,
) where C: NativeObject {
let align = match align { let align = match align {
Align::Center => lvgl_sys::LV_ALIGN_CENTER, Align::Center => lvgl_sys::LV_ALIGN_CENTER,
Align::InTopLeft => lvgl_sys::LV_ALIGN_IN_TOP_LEFT, 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 { macro_rules! define_object {
@ -114,20 +120,23 @@ macro_rules! define_object {
} }
impl<'a> Object<'a> for $item<'a> { 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 { unsafe {
lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw()); lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw());
}; };
self.core.style = Some(style); self.core.style = Some(style);
} }
} }
} };
} }
define_object!(Button); define_object!(Button);
impl<'a> Button<'a> { impl<'a> Button<'a> {
pub fn new<C>(parent: &mut C) -> Self where C: NativeObject { pub fn new<C>(parent: &mut C) -> Self
where
C: NativeObject,
{
let raw = unsafe { let raw = unsafe {
let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut()); let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut());
ptr::NonNull::new_unchecked(ptr) ptr::NonNull::new_unchecked(ptr)
@ -147,7 +156,10 @@ pub enum LabelAlign {
define_object!(Label); define_object!(Label);
impl<'a> Label<'a> { impl<'a> Label<'a> {
pub fn new<C>(parent: &mut C) -> Self where C: NativeObject { pub fn new<C>(parent: &mut C) -> Self
where
C: NativeObject,
{
let raw = unsafe { let raw = unsafe {
let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut()); let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut());
ptr::NonNull::new_unchecked(ptr) ptr::NonNull::new_unchecked(ptr)
@ -188,64 +200,69 @@ pub enum Themes {
Pretty, Pretty,
} }
#[derive(Default)] pub struct Style {
pub struct Style<'a> { raw: lvgl_sys::lv_style_t,
raw: Option<lvgl_sys::lv_style_t>,
pub text: TextStyle<'a>,
} }
impl<'a> Style<'a> { impl Style {
pub fn new() -> Self {
let raw = unsafe {
let mut native_style = mem::MaybeUninit::<lvgl_sys::lv_style_t>::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 { fn raw(&mut self) -> *const lvgl_sys::lv_style_t {
match self.raw { &mut self.raw
Some(mut native_pointer) => { }
&mut native_pointer }
},
None => unsafe { impl Clone for Style {
let mut native_style = mem::MaybeUninit::<lvgl_sys::lv_style_t>::uninit(); fn clone(&self) -> Self {
lvgl_sys::lv_style_copy(native_style.as_mut_ptr(), &lvgl_sys::lv_style_pretty); let mut native_style = mem::MaybeUninit::<lvgl_sys::lv_style_t>::uninit();
self.raw = Some(native_style.assume_init()); unsafe {
if let Some(text_font) = self.text.font { lvgl_sys::lv_style_copy(
self.raw.as_mut().unwrap().text.font = text_font as *const lvgl_sys::lv_font_t; native_style.as_mut_ptr(),
} &self.raw as *const lvgl_sys::lv_style_t,
self.raw.as_mut().unwrap() );
Self {
raw: native_style.assume_init(),
} }
} }
} }
} }
impl<'a> Clone for Style<'a> { #[derive(Clone)]
fn clone(&self) -> Self { pub struct Color {
match self.raw { raw: lvgl_sys::lv_color_t,
Some(_) => {
let mut native_style = mem::MaybeUninit::<lvgl_sys::lv_style_t>::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(Default)] impl Color {
pub struct TextStyle<'a> { pub fn from_rgb((r, g, b): (u8, u8, u8)) -> Self {
pub font: Option<&'a lvgl_sys::lv_font_t>, let raw = unsafe { lvgl_sys::lvsys_color_make(r, g, b) };
} Self { raw }
impl<'a> Clone for TextStyle<'a> {
fn clone(&self) -> Self {
Self {
font: self.font.clone()
}
} }
} }