LVGL bindings for Rust. A powerful and easy-to-use embedded GUI with many widgets, advanced visual effects (opacity, antialiasing, animations) and low memory requirements (16K RAM, 64K Flash).
I'm trying to use lvgm-rs with an asynchronous framework and I miserably fail to find the good design pattern.
To expose something simple I restarted from demo/arc example. I try to split arc.rs with 3 functions.
1st create display design and returning a handle containing: display, widget, ...
2nd update the display from previously received handle
3rd main that call both functions.
Note: doing so, we loose default RUST live cycle and everything created on the heap by 1st function disappear before calling second function.
The 1st issue to solve seems tp comes from screen.add_style(Part::Main, &mut screen_style); because of this screen depend on screen_style which is a Box that will be deleted at function return. But this might only be the visible part of the iceberg.
Any idea on how to implement a pattern to update the display from an asynchronous event would be more than welcome. Alternatively of you have some sample that could help, please let me known.
If we find a working solution, I commit to push an example on github, as I cannot be the only one with this need.
Handle + Main function
struct DisplayHandle<'a> {
pub sim_display: SimulatorDisplay<Rgb565>,
pub window: RefCell<Window>,
pub screen: Screen<'a>,
pub arc: RefCell<Arc<'a>>,
}
fn main() -> Result<(), LvError> {
let handle= mk_display() ?;
// handle.update should be callable from an asynchronous function (i.e. a system timer)
display_update(handle)?;
Ok(())
}
Function creating the display layout return a static/leak box to make sure the handle is never deleted
fn mk_display() -> Result< &'static DisplayHandle<'static>, LvError> {
const HOR_RES: u32 = 240;
const VER_RES: u32 = 240;
println!("meminfo init: {:?}", mem_info());
let mut sim_display: SimulatorDisplay<Rgb565> =
SimulatorDisplay::new(Size::new(HOR_RES, VER_RES));
let output_settings = OutputSettingsBuilder::new().scale(1).build();
let window = Window::new("Arc Example", &output_settings);
let buffer = DrawBuffer::<{ (HOR_RES * VER_RES) as usize }>::default();
let display = Display::register(buffer, HOR_RES, VER_RES, |refresh| {
sim_display.draw_iter(refresh.as_pixels()).unwrap();
})?;
let mut screen = display.get_scr_act()?;
let mut screen_style = Style::default();
screen_style.set_bg_color(Color::from_rgb((255, 255, 255)));
screen_style.set_radius(0);
screen.add_style(Part::Main, &mut screen_style);
// Create the arc object
let mut arc = Arc::create(&mut screen)?;
arc.set_size(150, 150);
arc.set_align(Align::Center, 0, 10);
arc.set_start_angle(135)?;
arc.set_end_angle(135)?;
let mut loading_lbl = Label::create(&mut screen)?;
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
loading_lbl.set_align(Align::OutTopMid, 0, 0);
//loading_lbl.set_label_align(LabelAlign::Center)?;
let mut loading_style = Style::default();
loading_style.set_text_color(Color::from_rgb((0, 0, 0)));
loading_lbl.add_style(Part::Main, &mut loading_style);
let handle = Box::new(DisplayHandle {
screen,
sim_display,
window: RefCell::new(window),
arc: RefCell::new(arc),
});
// make sure the handle is never going to be deleted
Ok(Box::leak(handle))
}
For my test, the update function is called directly from main routine, my end goal is call it from an asynchronous timer event, that potentially run in a different thread.
fn display_update (handle: &DisplayHandle) -> Result <(), LvError> {
let mut angle = 0;
let mut forward = true;
let mut i = 0;
// retrieve mutable arc handle from display handle
let mut arc= handle.arc.borrow_mut();
let mut window= handle.window.borrow_mut();
'running: loop {
let start = Instant::now();
if i > 270 {
forward = if forward { false } else { true };
i = 1;
println!("mem info running: {:?}", mem_info());
}
angle = if forward { angle + 1 } else { angle - 1 };
arc.set_end_angle(angle + 135)?;
i += 1;
lvgl::task_handler();
window.update(&handle.sim_display);
// for event in window.events() {
// match event {
// SimulatorEvent::Quit => break 'running,
// _ => {}
// }
// }
sleep(Duration::from_millis(15));
lvgl::tick_inc(Instant::now().duration_since(start));
}
}
I'm trying to use lvgm-rs with an asynchronous framework and I miserably fail to find the good design pattern.
To expose something simple I restarted from demo/arc example. I try to split
arc.rs
with 3 functions.Note: doing so, we loose default RUST live cycle and everything created on the heap by 1st function disappear before calling second function.
The 1st issue to solve seems tp comes from
screen.add_style(Part::Main, &mut screen_style);
because of this screen depend on screen_style which is a Box that will be deleted at function return. But this might only be the visible part of the iceberg.Any idea on how to implement a pattern to update the display from an asynchronous event would be more than welcome. Alternatively of you have some sample that could help, please let me known.
If we find a working solution, I commit to push an example on github, as I cannot be the only one with this need.
Handle + Main function
Function creating the display layout return a static/leak box to make sure the handle is never deleted
For my test, the update function is called directly from main routine, my end goal is call it from an asynchronous timer event, that potentially run in a different thread.