API re-design #9

Merged
rafaelcaricio merged 6 commits from api_design_studies into master 2020-05-29 22:25:28 +00:00
2 changed files with 212 additions and 1 deletions
Showing only changes of commit a7bef1cd54 - Show all commits

207
lvgl/src/api.rs Normal file
View file

@ -0,0 +1,207 @@
use core::marker::PhantomData;
use core::time::Duration;
use core::sync::atomic::{AtomicBool, Ordering};
// There can only be a single reference to LittlevGL library.
static LVGL_IN_USE: AtomicBool = AtomicBool::new(false);
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum LvError {
AlreadyInUse,
}
pub struct UI {
// LittlevGL is not thread-safe by default.
_not_send: PhantomData<*const ()>
}
impl UI {
pub fn init() -> Result<Self, LvError> {
if LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) == false {
// lvgl_sys::lv_init();
Ok(Self {
_not_send: PhantomData,
})
} else {
Err(LvError::AlreadyInUse)
}
}
pub fn disp_drv_register(&mut self, _display: &mut DisplayDriver) {
// register it
// lvgl_sys::lv_disp_drv_register(&mut disp_drv);
}
pub fn tick_inc(&mut self, _tick_period: Duration) {
// lvgl_sys::lv_tick_inc(tick_period);
}
pub fn task_handler(&mut self) {
// lvgl_sys::lv_task_handler();
}
}
pub struct DisplayDriver {
refresh_lines: u32,
current_screen: Screen,
}
impl DisplayDriver {
pub fn new(refresh_lines: u32) -> Self {
Self{ refresh_lines, current_screen: Screen::new() }
}
// Ensure cannot delete the current loaded screen
pub fn load_scr(&mut self, screen: Screen) {
self.current_screen = screen;
}
pub fn scr_act(&mut self) -> &mut Screen {
&mut self.current_screen
}
}
pub trait LvObject {
fn label_create(&self) -> Label where Self: Sized {
Label{ parent: self }
}
fn btn_create<F>(&self) -> Button<F> where Self: Sized, F: FnMut() {
Button{ parent: self, event_callback: None }
}
}
pub struct Screen {
_not_send: PhantomData<*const ()>
}
impl Screen {
pub fn new() -> Self {
Self { _not_send: PhantomData }
}
}
impl LvObject for Screen {}
pub struct Label<'a> {
parent: &'a dyn LvObject,
}
impl<'a> Label<'a> {
pub fn set_text(&mut self, _text: &str) {
// set text call to unsafe...
}
}
impl<'a> LvObject for Label<'a> {}
pub struct Button<'a, F> where F: FnMut() {
parent: &'a dyn LvObject,
event_callback: Option<F>,
}
impl<'a, F> Button<'a, F> where F: FnMut() {
pub fn on_event(&mut self, callback: F) {
// add callback
self.event_callback = Some(callback);
}
}
impl<'a, F> LvObject for Button<'a, F> where F: FnMut() {}
#[cfg(test)]
mod test {
use crate::api::{UI, DisplayDriver, LvObject};
use core::time::Duration;
use std::sync::{Mutex, Arc};
#[test]
fn basic_usage() {
let mut ui = UI::init().unwrap();
let refresh_lines = 10;
let mut display = DisplayDriver::new(refresh_lines);
ui.disp_drv_register(&mut display);
let display = Arc::new(Mutex::new(display));
{
let mut disp = display.clone();
let mut d = disp.lock().unwrap();
let screen = d.scr_act();
let mut button = screen.btn_create();
let mut inner_disp = display.clone();
button.on_event(|| {
// something
let mut disp = inner_disp.lock().unwrap();
let screen = disp.scr_act();
let mut label = screen.label_create();
label.set_text("Clicked");
});
let mut label = button.label_create();
label.set_text("Click me!");
};
{
let mut disp = display.clone();
let mut d = disp.lock().unwrap();
let screen = d.scr_act();
let mut button2 = screen.btn_create();
button2.on_event(|| {
// else
});
let mut label2 = button2.label_create();
label2.set_text("Else");
};
ui.tick_inc(Duration::from_millis(5));
ui.task_handler();
}
#[test]
fn test_usage() {
// // can use Arc<Mutex<lvgl::App>> to share between threads
// let mut app = lvgl::App::init().unwrap();
//
// let disp = DisplayDriver::new();
// app.register_display_driver(&disp); // takes (&mut self, ...)
//
// let screen: &mut lvgl::Screen = disp.new_screen(); // takes (&mut self)
// disp.load_screen(&screen); // takes (&self) because it just need the ref to
// // the screen to load, as all the screens are already internal.
//
// let button = screen.new_button(); // takes (&self)
// button.on_event(|&mut app, &mut btn, ev| {
// let mut label: &mut Label = app.cur_screen().new_label();
// if let lvgl::Event::Clicked = ev {
// btn.set_text("clicked!");
// }
// app.load_screen(&screen);
// });
//
// let mut lbl_click = button.new_label();
// lbl_click.set_text("Click me!");
//
//
// // lvgl::Timer returns reference to same internal object
// app.tick(Duration::from_millis(1)); // takes (&mut self)
//
// app.task_handler(); // takes (&mut self)
//
// // Multiple Displays can be instantiated
// // Multiple Screen's in each Display
// // Screen can be instantiated independently
// // Any specific object impl Screenable(trait) (can be used anywhere Screen is used)
// // To get active screen from a Display use `lv_disp_get_scr_act(disp)`
// let screen = disp.get_active_screen();
// // To set an active screen in a Display use `lv_disp_load_scr(disp, scr)`
// disp.load_screen(screen);
//
// let mut screen = Screen::new();
// let mut button = screen.add_button();
// let mut btn_lbl = button.create_label();
}
}

View file

@ -1,7 +1,11 @@
#![no_std]
// #![no_std]
pub mod display;
mod objx;
mod api;
pub use display::DisplayDriver;
pub use objx::*;