Rust bindings API review #51
|
@ -4,12 +4,16 @@ use embedded_graphics::prelude::*;
|
||||||
use embedded_graphics_simulator::{
|
use embedded_graphics_simulator::{
|
||||||
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
||||||
};
|
};
|
||||||
|
use lvgl::display::Display;
|
||||||
use lvgl::style::Style;
|
use lvgl::style::Style;
|
||||||
use lvgl::widgets::{Arc, Label, LabelAlign};
|
use lvgl::widgets::{Arc, Label, LabelAlign};
|
||||||
use lvgl::{self, Align, Color, Part, State, UI};
|
use lvgl::{self, Align, Color, Part, State};
|
||||||
use lvgl::{LvError, Widget};
|
use lvgl::{LvError, Widget};
|
||||||
use lvgl_sys;
|
use lvgl_sys;
|
||||||
use std::time::Instant;
|
use parking_lot::Mutex;
|
||||||
|
use std::sync::Arc as SyncArc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
|
fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
|
||||||
let mut info = lvgl_sys::lv_mem_monitor_t {
|
let mut info = lvgl_sys::lv_mem_monitor_t {
|
||||||
|
@ -36,7 +40,9 @@ fn main() -> Result<(), LvError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_arc_demo() -> Result<(), LvError> {
|
fn run_arc_demo() -> Result<(), LvError> {
|
||||||
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
lvgl::init();
|
||||||
|
|
||||||
|
let embedded_graphics_display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||||
lvgl_sys::LV_HOR_RES_MAX,
|
lvgl_sys::LV_HOR_RES_MAX,
|
||||||
lvgl_sys::LV_VER_RES_MAX,
|
lvgl_sys::LV_VER_RES_MAX,
|
||||||
));
|
));
|
||||||
|
@ -44,52 +50,60 @@ fn run_arc_demo() -> Result<(), LvError> {
|
||||||
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
||||||
let mut window = Window::new("Arc Example", &output_settings);
|
let mut window = Window::new("Arc Example", &output_settings);
|
||||||
|
|
||||||
let mut ui = UI::init()?;
|
let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display));
|
||||||
|
let display = Display::register_shared(&shared_native_display)?;
|
||||||
|
|
||||||
// Implement and register your display:
|
let mut screen = display.get_str_act()?;
|
||||||
ui.disp_drv_register(display)?;
|
|
||||||
|
|
||||||
// Create screen and widgets
|
|
||||||
let mut screen = ui.scr_act()?;
|
|
||||||
|
|
||||||
let mut screen_style = Style::default();
|
let mut screen_style = Style::default();
|
||||||
screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
|
screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
|
||||||
screen_style.set_radius(State::DEFAULT, 0);
|
screen_style.set_radius(State::DEFAULT, 0);
|
||||||
screen.add_style(Part::Main, screen_style)?;
|
screen.add_style(Part::Main, &mut screen_style)?;
|
||||||
|
|
||||||
// Create the arc object
|
// Create the arc object
|
||||||
let mut arc = Arc::new(&mut screen)?;
|
let mut arc = Arc::new()?;
|
||||||
arc.set_size(150, 150)?;
|
arc.set_size(150, 150)?;
|
||||||
arc.set_align(&mut screen, Align::Center, 0, 10)?;
|
arc.set_align(&mut screen, Align::Center, 0, 10)?;
|
||||||
arc.set_start_angle(135)?;
|
arc.set_start_angle(135)?;
|
||||||
arc.set_end_angle(135)?;
|
arc.set_end_angle(135)?;
|
||||||
|
|
||||||
let mut loading_lbl = Label::new(&mut screen)?;
|
let mut loading_lbl = Label::new()?;
|
||||||
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
|
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
|
||||||
loading_lbl.set_align(&mut arc, Align::OutTopMid, 0, -10)?;
|
loading_lbl.set_align(&mut arc, Align::OutTopMid, 0, -10)?;
|
||||||
loading_lbl.set_label_align(LabelAlign::Center)?;
|
loading_lbl.set_label_align(LabelAlign::Center)?;
|
||||||
|
|
||||||
let mut loading_style = Style::default();
|
let mut loading_style = Style::default();
|
||||||
loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
|
loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
|
||||||
loading_lbl.add_style(Part::Main, loading_style)?;
|
loading_lbl.add_style(Part::Main, &mut loading_style)?;
|
||||||
|
|
||||||
let mut angle = 0;
|
let mut angle = 0;
|
||||||
let mut forward = true;
|
let mut forward = true;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
let mut loop_started = Instant::now();
|
// LVGL timer thread
|
||||||
|
thread::spawn(|| {
|
||||||
|
let interval = Duration::from_millis(5);
|
||||||
|
loop {
|
||||||
|
thread::sleep(interval);
|
||||||
|
lvgl::tick_inc(interval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
if i > 270 {
|
if i > 270 {
|
||||||
forward = if forward { false } else { true };
|
forward = if forward { false } else { true };
|
||||||
i = 1;
|
i = 1;
|
||||||
println!("meminfo running: {:?}", mem_info());
|
println!("mem info running: {:?}", mem_info());
|
||||||
}
|
}
|
||||||
angle = if forward { angle + 1 } else { angle - 1 };
|
angle = if forward { angle + 1 } else { angle - 1 };
|
||||||
arc.set_end_angle(angle + 135)?;
|
arc.set_end_angle(angle + 135)?;
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
ui.task_handler();
|
lvgl::task_handler();
|
||||||
window.update(ui.get_display_ref().unwrap());
|
{
|
||||||
|
let eg_display = shared_native_display.lock();
|
||||||
|
window.update(&eg_display);
|
||||||
|
}
|
||||||
|
|
||||||
for event in window.events() {
|
for event in window.events() {
|
||||||
match event {
|
match event {
|
||||||
|
@ -97,9 +111,7 @@ fn run_arc_demo() -> Result<(), LvError> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
thread::sleep(Duration::from_millis(15));
|
||||||
ui.tick_inc(loop_started.elapsed());
|
|
||||||
loop_started = Instant::now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -12,25 +12,24 @@ use lvgl::{Align, Color, LvError, Part, State, Widget, UI};
|
||||||
use lvgl_sys;
|
use lvgl_sys;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc as SyncArc;
|
use std::sync::Arc as SyncArc;
|
||||||
|
use std::thread;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
fn main() -> Result<(), LvError> {
|
fn main() -> Result<(), LvError> {
|
||||||
|
lvgl::init();
|
||||||
|
|
||||||
let embedded_graphics_display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
let embedded_graphics_display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||||
lvgl_sys::LV_HOR_RES_MAX,
|
lvgl_sys::LV_HOR_RES_MAX,
|
||||||
lvgl_sys::LV_VER_RES_MAX,
|
lvgl_sys::LV_VER_RES_MAX,
|
||||||
));
|
));
|
||||||
|
|
||||||
let output_settings = OutputSettingsBuilder::new().scale(2).build();
|
let output_settings = OutputSettingsBuilder::new().scale(1).build();
|
||||||
let mut window = Window::new("PineTime", &output_settings);
|
let mut window = Window::new("PineTime", &output_settings);
|
||||||
|
|
||||||
lvgl::init();
|
|
||||||
// let mut ui = UI::init()?;
|
|
||||||
|
|
||||||
// Implement and register your display:
|
// Implement and register your display:
|
||||||
let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display));
|
let shared_native_display = SyncArc::new(Mutex::new(embedded_graphics_display));
|
||||||
let _display = Display::register_shared(&shared_native_display)?;
|
let _display = Display::register_shared(&shared_native_display)?;
|
||||||
// ui.disp_drv_register(embedded_graphics_display).unwrap();
|
|
||||||
|
|
||||||
// Create screen and widgets
|
// Create screen and widgets
|
||||||
let mut screen = DefaultDisplay::get_scr_act()?;
|
let mut screen = DefaultDisplay::get_scr_act()?;
|
||||||
|
@ -40,52 +39,52 @@ fn main() -> Result<(), LvError> {
|
||||||
screen_style.set_radius(State::DEFAULT, 0);
|
screen_style.set_radius(State::DEFAULT, 0);
|
||||||
screen.add_style(Part::Main, &mut screen_style)?;
|
screen.add_style(Part::Main, &mut screen_style)?;
|
||||||
|
|
||||||
let mut time = Label::new()?;
|
let mut time = Label::from("20:46");
|
||||||
let mut style_time = Style::default();
|
let mut style_time = Style::default();
|
||||||
// style_time.set_text_font(font_noto_sans_numeric_28);
|
// style_time.set_text_font(font_noto_sans_numeric_28);
|
||||||
style_time.set_text_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
|
style_time.set_text_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
|
||||||
time.add_style(Part::Main, &mut style_time)?;
|
time.add_style(Part::Main, &mut style_time)?;
|
||||||
time.set_align(&mut screen, Align::Center, 0, 0)?;
|
time.set_align(&mut screen, Align::Center, 0, 0)?;
|
||||||
time.set_text(CString::new("20:46").unwrap().as_c_str())?;
|
|
||||||
time.set_width(240)?;
|
time.set_width(240)?;
|
||||||
time.set_height(240)?;
|
time.set_height(240)?;
|
||||||
|
|
||||||
let mut bt = Label::new()?;
|
let mut bt = Label::from("#5794f2 \u{F293}#");
|
||||||
bt.set_width(50)?;
|
bt.set_width(50)?;
|
||||||
bt.set_height(80)?;
|
bt.set_height(80)?;
|
||||||
bt.set_recolor(true)?;
|
bt.set_recolor(true)?;
|
||||||
bt.set_text(CString::new("#5794f2 \u{F293}#").unwrap().as_c_str())?;
|
|
||||||
bt.set_label_align(LabelAlign::Left)?;
|
bt.set_label_align(LabelAlign::Left)?;
|
||||||
bt.set_align(&mut screen, Align::InTopLeft, 0, 0)?;
|
bt.set_align(&mut screen, Align::InTopLeft, 0, 0)?;
|
||||||
|
|
||||||
let mut power = Label::new()?;
|
let mut power: Label = "#fade2a 20%#".into();
|
||||||
power.set_recolor(true)?;
|
power.set_recolor(true)?;
|
||||||
power.set_width(80)?;
|
power.set_width(80)?;
|
||||||
power.set_height(20)?;
|
power.set_height(20)?;
|
||||||
power.set_text(CString::new("#fade2a 20%#").unwrap().as_c_str())?;
|
|
||||||
power.set_label_align(LabelAlign::Right)?;
|
power.set_label_align(LabelAlign::Right)?;
|
||||||
power.set_align(&mut screen, Align::InTopRight, 0, 0)?;
|
power.set_align(&mut screen, Align::InTopRight, 0, 0)?;
|
||||||
|
|
||||||
|
// LVGL timer thread
|
||||||
|
thread::spawn(|| {
|
||||||
|
let interval = Duration::from_millis(5);
|
||||||
|
loop {
|
||||||
|
thread::sleep(interval);
|
||||||
|
lvgl::tick_inc(interval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut loop_started = Instant::now();
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
if i > 59 {
|
if i > 59 {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
println!("i = {}", i);
|
|
||||||
let val = CString::new(format!("21:{:02}", i)).unwrap();
|
let val = CString::new(format!("21:{:02}", i)).unwrap();
|
||||||
time.set_text(&val)?;
|
time.set_text(&val)?;
|
||||||
i = 1 + i;
|
i = 1 + i;
|
||||||
|
|
||||||
let wait_for = lvgl::task_handler();
|
lvgl::task_handler();
|
||||||
println!("wait for = {} ms", wait_for.unwrap().as_secs());
|
|
||||||
{
|
{
|
||||||
let native_display = shared_native_display.lock();
|
let native_display = shared_native_display.lock();
|
||||||
window.update(&native_display);
|
window.update(&native_display);
|
||||||
}
|
}
|
||||||
// ui.task_handler();
|
|
||||||
// window.update(ui.get_display_ref().unwrap());
|
|
||||||
lvgl::tick_inc(loop_started.elapsed());
|
|
||||||
|
|
||||||
for event in window.events() {
|
for event in window.events() {
|
||||||
match event {
|
match event {
|
||||||
|
@ -94,8 +93,6 @@ fn main() -> Result<(), LvError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sleep(Duration::from_secs(1));
|
sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
loop_started = Instant::now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
25
lvgl-codegen/src/analysis.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/// A parameter of C functions.
|
||||||
|
///
|
||||||
|
/// This struct represents all relevant information we can extract from the C function declaration
|
||||||
|
/// of a LVGL public interface. We can use this information to do inference for how the parameter
|
||||||
|
/// should be represented in a safe Rust API.
|
||||||
|
pub struct CParameter {
|
||||||
|
/// The name of the parameter in the C code.
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
/// This is the raw representation of the Rust equivalent of the C type.
|
||||||
|
c_type: String,
|
||||||
|
|
||||||
|
/// Takes a pointer to a type that is referenced by the LVGL code permanently.
|
||||||
|
owned: bool,
|
||||||
|
|
||||||
|
/// The pointer is not marked as `*const` so the referenced object can be mutated.
|
||||||
|
mutable: bool,
|
||||||
|
|
||||||
|
/// We need to check if the value is optional in the C code. We need to check
|
||||||
|
/// the function comments for this information.
|
||||||
|
/// - "if NULL then"
|
||||||
|
/// - "if not NULL then"
|
||||||
|
/// - "NULL to"
|
||||||
|
nullable: bool,
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod analysis;
|
||||||
|
|
||||||
use inflector::cases::pascalcase::to_pascal_case;
|
use inflector::cases::pascalcase::to_pascal_case;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
@ -44,6 +46,12 @@ pub struct LvWidget {
|
||||||
methods: Vec<LvFunc>,
|
methods: Vec<LvFunc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LvWidget {
|
||||||
|
fn pascal_name(&self) -> String {
|
||||||
|
to_pascal_case(&self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Rusty for LvWidget {
|
impl Rusty for LvWidget {
|
||||||
type Parent = ();
|
type Parent = ();
|
||||||
|
|
||||||
|
@ -53,7 +61,7 @@ impl Rusty for LvWidget {
|
||||||
return Err(WrapperError::Skip);
|
return Err(WrapperError::Skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
let widget_name = format_ident!("{}", to_pascal_case(self.name.as_str()));
|
let widget_name = format_ident!("{}", self.pascal_name());
|
||||||
let methods: Vec<TokenStream> = self.methods.iter().flat_map(|m| m.code(self)).collect();
|
let methods: Vec<TokenStream> = self.methods.iter().flat_map(|m| m.code(self)).collect();
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
define_object!(#widget_name);
|
define_object!(#widget_name);
|
||||||
|
@ -90,6 +98,7 @@ impl Rusty for LvFunc {
|
||||||
type Parent = LvWidget;
|
type Parent = LvWidget;
|
||||||
|
|
||||||
fn code(&self, parent: &Self::Parent) -> WrapperResult<TokenStream> {
|
fn code(&self, parent: &Self::Parent) -> WrapperResult<TokenStream> {
|
||||||
|
let widget_name = format_ident!("{}", parent.pascal_name());
|
||||||
let templ = format!("{}{}_", LIB_PREFIX, parent.name.as_str());
|
let templ = format!("{}{}_", LIB_PREFIX, parent.name.as_str());
|
||||||
let new_name = self.name.replace(templ.as_str(), "");
|
let new_name = self.name.replace(templ.as_str(), "");
|
||||||
let func_name = format_ident!("{}", new_name);
|
let func_name = format_ident!("{}", new_name);
|
||||||
|
@ -99,12 +108,12 @@ impl Rusty for LvFunc {
|
||||||
if new_name.as_str().eq("create") {
|
if new_name.as_str().eq("create") {
|
||||||
return Ok(quote! {
|
return Ok(quote! {
|
||||||
|
|
||||||
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
|
pub fn create(parent: &mut impl crate::NativeObject, copy: Option<&#widget_name>) -> crate::LvResult<Self> {
|
||||||
where
|
|
||||||
C: crate::NativeObject,
|
|
||||||
{
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = lvgl_sys::#original_func_name(parent.raw()?.as_mut(), core::ptr::null_mut());
|
let ptr = lvgl_sys::#original_func_name(
|
||||||
|
parent.raw()?.as_mut(),
|
||||||
|
copy.map(|c| c.raw().unwrap().as_mut() as *mut lvgl_sys::lv_obj_t).unwrap_or(core::ptr::null_mut() as *mut lvgl_sys::lv_obj_t),
|
||||||
|
);
|
||||||
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
||||||
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
||||||
Ok(Self { core })
|
Ok(Self { core })
|
||||||
|
@ -114,6 +123,15 @@ impl Rusty for LvFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_at(parent: &mut impl crate::NativeObject) -> crate::LvResult<Self> {
|
||||||
|
Ok(Self::create(parent, None)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> crate::LvResult<Self> {
|
||||||
|
let mut parent = crate::display::DefaultDisplay::get_scr_act()?;
|
||||||
|
Ok(Self::create_at(&mut parent)?)
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +356,9 @@ impl Rusty for LvType {
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
let val = if self.is_str() {
|
let val = if self.is_str() {
|
||||||
quote!(&cstr_core::CStr)
|
quote!(&cstr_core::CStr)
|
||||||
|
} else if (self.literal_name.contains("lv_")) {
|
||||||
|
let ident = format_ident!("{}", name);
|
||||||
|
quote!(&#ident)
|
||||||
} else {
|
} else {
|
||||||
let ident = format_ident!("{}", name);
|
let ident = format_ident!("{}", name);
|
||||||
quote!(#ident)
|
quote!(#ident)
|
||||||
|
@ -631,13 +652,12 @@ mod test {
|
||||||
define_object!(Arc);
|
define_object!(Arc);
|
||||||
|
|
||||||
impl Arc {
|
impl Arc {
|
||||||
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
|
pub fn create(parent: &mut impl crate::NativeObject, copy: Option<&Arc>) -> crate::LvResult<Self> {
|
||||||
where
|
|
||||||
C: crate::NativeObject,
|
|
||||||
{
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = lvgl_sys::lv_arc_create(parent.raw()?.as_mut(), core::ptr::null_mut());
|
let ptr = lvgl_sys::lv_arc_create(
|
||||||
|
parent.raw()?.as_mut(),
|
||||||
|
copy.map(|c| c.raw().unwrap().as_mut() as *mut lvgl_sys::lv_obj_t).unwrap_or(core::ptr::null_mut() as *mut lvgl_sys::lv_obj_t),
|
||||||
|
);
|
||||||
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
if let Some(raw) = core::ptr::NonNull::new(ptr) {
|
||||||
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
let core = <crate::Obj as crate::Widget>::from_raw(raw);
|
||||||
Ok(Self { core })
|
Ok(Self { core })
|
||||||
|
@ -646,6 +666,16 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_at(parent: &mut impl crate::NativeObject) -> crate::LvResult<Self> {
|
||||||
|
Ok(Self::create(parent, None)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> crate::LvResult<Self> {
|
||||||
|
Ok(Self::create_at(
|
||||||
|
&mut crate::display::DefaultDisplay::get_scr_act(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use embedded_graphics::drawable;
|
||||||
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
use embedded_graphics::prelude::*;
|
use embedded_graphics::prelude::*;
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex; // TODO: Can this really be used in no_std envs with alloc?
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
@ -90,14 +90,15 @@ impl DisplayBuffer {
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let disp_buf = unsafe {
|
let disp_buf = unsafe {
|
||||||
let mut disp_buf = MaybeUninit::uninit();
|
let mut disp_buf = MaybeUninit::uninit();
|
||||||
|
// TODO: Need to find a way to not add this to LVGL memory.
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
let mut refresh_buffer1 = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
|
let mut refresh_buffer1 = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
|
||||||
let mut refresh_buffer2 = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
|
//let mut refresh_buffer2 = Box::new([lvgl_sys::lv_color_t::default(); BUF_SIZE]);
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
// let refresh_buffer2 = [lvgl_sys::lv_color_t::default(); BUF_SIZE];
|
// let refresh_buffer2 = [lvgl_sys::lv_color_t::default(); BUF_SIZE];
|
||||||
lvgl_sys::lv_disp_buf_init(
|
lvgl_sys::lv_disp_buf_init(
|
||||||
disp_buf.as_mut_ptr(),
|
disp_buf.as_mut_ptr(),
|
||||||
Box::into_raw(refresh_buffer1) as *mut cty::c_void,
|
Box::into_raw(refresh_buffer1) as *mut cty::c_void,
|
||||||
Box::into_raw(refresh_buffer2) as *mut cty::c_void,
|
// Box::into_raw(refresh_buffer2) as *mut cty::c_void,
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
//ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|||||||
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
|
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
|
||||||
);
|
);
|
||||||
disp_buf.assume_init()
|
disp_buf.assume_init()
|
||||||
|
|
||||||
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
TODO: Remove this code duplication. TODO: Remove this code duplication.
I use a I use a `Mutex` here, to satisfy the Rust guarantees. But maybe it is not necessary... some food for thought.
|
|
@ -42,6 +42,10 @@ pub(crate) fn get_str_act(disp: Option<&Display>) -> Result<Obj> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// You have to call this function periodically.
|
||||||
|
/// Expects a `tick_period` duration as argument which is the call period of this
|
||||||
|
/// function in milliseconds.
|
||||||
|
#[inline]
|
||||||
pub fn tick_inc(tick_period: Duration) {
|
pub fn tick_inc(tick_period: Duration) {
|
||||||
unsafe {
|
unsafe {
|
||||||
lvgl_sys::lv_tick_inc(tick_period.as_millis() as u32);
|
lvgl_sys::lv_tick_inc(tick_period.as_millis() as u32);
|
||||||
|
@ -49,8 +53,7 @@ pub fn tick_inc(tick_period: Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call it periodically to handle tasks.
|
/// Call it periodically to handle tasks.
|
||||||
/// Returns the duration after which it must be called again.
|
#[inline]
|
||||||
pub fn task_handler() -> Option<Duration> {
|
pub fn task_handler() {
|
||||||
let next_call_at = unsafe { lvgl_sys::lv_task_handler() };
|
unsafe { lvgl_sys::lv_task_handler() };
|
||||||
Some(Duration::from_secs(next_call_at as u64))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod lv_core;
|
mod lv_core;
|
||||||
|
|
||||||
#[cfg(feature = "lvgl_alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
// We can ONLY use `alloc::boxed::Box` if `lvgl_alloc` is enabled.
|
// We can ONLY use `alloc::boxed::Box` if `lvgl_alloc` is enabled.
|
||||||
|
|
|
@ -36,8 +36,8 @@ impl<T> Box<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_raw(self) -> *mut T {
|
pub fn into_raw(self) -> *mut T {
|
||||||
let b = mem::ManuallyDrop::new(self.0);
|
let b = mem::ManuallyDrop::new(self);
|
||||||
b.as_ptr()
|
b.0.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::display::DisplayError;
|
||||||
use crate::Widget;
|
use crate::Widget;
|
||||||
use core::convert::{TryFrom, TryInto};
|
use core::convert::{TryFrom, TryInto};
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
@ -13,6 +14,17 @@ pub enum LvError {
|
||||||
AlreadyInUse,
|
AlreadyInUse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DisplayError> for LvError {
|
||||||
|
fn from(err: DisplayError) -> Self {
|
||||||
|
use LvError::*;
|
||||||
|
match err {
|
||||||
|
DisplayError::NotAvailable => Uninitialized,
|
||||||
|
DisplayError::FailedToRegister => InvalidReference,
|
||||||
|
DisplayError::NotRegistered => Uninitialized,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub(crate) raw: lvgl_sys::lv_color_t,
|
pub(crate) raw: lvgl_sys::lv_color_t,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::widgets::Label;
|
use crate::widgets::Label;
|
||||||
use crate::{LvResult, NativeObject};
|
use crate::{LvResult, NativeObject};
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
use cstr_core::CString;
|
||||||
|
|
||||||
impl Label {
|
impl Label {
|
||||||
pub fn set_label_align(&mut self, align: LabelAlign) -> LvResult<()> {
|
pub fn set_label_align(&mut self, align: LabelAlign) -> LvResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -10,6 +13,16 @@ impl Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
impl<S: AsRef<str>> From<S> for Label {
|
||||||
|
fn from(text: S) -> Self {
|
||||||
|
let text_cstr = CString::new(text.as_ref()).unwrap();
|
||||||
|
let mut label = Label::new().unwrap();
|
||||||
|
label.set_text(text_cstr.as_c_str()).unwrap();
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum LabelAlign {
|
pub enum LabelAlign {
|
||||||
|
|
TODO: Remove this code duplication.