Touch input device #27

Open
rafaelcaricio wants to merge 15 commits from indev into master
4 changed files with 74 additions and 68 deletions
Showing only changes of commit 16b3ee0dc8 - Show all commits

View file

@ -4,13 +4,14 @@ use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use lvgl::input_device::{InputData, Pointer};
use lvgl::input_device::{BufferStatus, InputData, Pointer};
use lvgl::style::Style;
use lvgl::widgets::{Btn, Label};
use lvgl::{self, Align, Color, LvError, Part, State, Widget, UI};
use std::cell::RefCell;
use std::rc::Rc;
use std::time::Instant;
use std::thread::sleep;
use std::time::{Duration, Instant};
fn main() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> =
@ -24,18 +25,17 @@ fn main() -> Result<(), LvError> {
// Implement and register your display:
ui.disp_drv_register(display)?;
// Initial state of input
let latest_touch_status: Rc<RefCell<BufferStatus>> = Rc::new(RefCell::new(
InputData::Touch(Point::new(0, 0)).released().once(),
));
// Register the input mode
let latest_touch_point: Rc<RefCell<Option<Point>>> = Rc::new(RefCell::new(None));
let internal = Rc::clone(&latest_touch_point);
let internal = Rc::clone(&latest_touch_status);
let mut touch_screen = Pointer::new(move || {
let info = internal.borrow().clone();
if info.is_some() {
let point = info.unwrap();
println!("Changed to {:?}", point);
Some(InputData::Touch(point).pressed().once())
} else {
None
}
let input_status = internal.borrow().clone();
//println!("input_status = {:?}", input_status);
input_status
});
ui.indev_drv_register(&mut touch_screen)?;
@ -56,6 +56,7 @@ fn main() -> Result<(), LvError> {
let mut btn_state = false;
button.on_event(|mut btn, event| {
println!("Some event! {:?}", event);
if let lvgl::Event::Clicked = event {
if btn_state {
let nt = CString::new("Click me!").unwrap();
@ -71,11 +72,22 @@ fn main() -> Result<(), LvError> {
})?;
let mut loop_started = Instant::now();
let mut latest_touch_point = Point::new(0, 0);
'running: loop {
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
for event in window.events() {
let mut events = window.events().peekable();
if events.peek().is_none() {
latest_touch_status.replace(
InputData::Touch(latest_touch_point.clone())
.released()
.once(),
);
}
for event in events {
match event {
SimulatorEvent::MouseButtonUp {
mouse_btn: _,
@ -83,13 +95,16 @@ fn main() -> Result<(), LvError> {
} => {
println!("Clicked on: {:?}", point);
// Send a event to the button directly
latest_touch_point.borrow_mut().replace(point);
latest_touch_point = point.clone();
latest_touch_status.replace(InputData::Touch(point).pressed().once());
}
SimulatorEvent::Quit => break 'running,
_ => {}
}
}
sleep(Duration::from_millis(50));
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
}

View file

@ -1,3 +1,4 @@
use crate::mem::Box;
use crate::LvResult;
use core::mem::MaybeUninit;
use embedded_graphics::geometry::Point;
@ -26,7 +27,7 @@ pub enum InputState {
impl InputState {
pub fn once(self) -> BufferStatus {
BufferStatus::Empty(self)
BufferStatus::Once(self)
}
pub fn and_continued(self) -> BufferStatus {
@ -36,35 +37,31 @@ impl InputState {
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum BufferStatus {
Empty(InputState),
Once(InputState),
Buffered(InputState),
}
pub struct Pointer<F>
where
F: Fn() -> Option<BufferStatus>,
{
pub struct Pointer {
pub(crate) driver: lvgl_sys::lv_indev_drv_t,
pub(crate) descriptor: Option<lvgl_sys::lv_indev_t>,
handler: F,
}
impl<F> Pointer<F>
impl Pointer {
pub fn new<F>(mut handler: F) -> Self
where
F: Fn() -> Option<BufferStatus>,
F: Fn() -> BufferStatus,
{
pub fn new(mut handler: F) -> Self {
let driver = unsafe {
let mut indev_drv = MaybeUninit::uninit();
lvgl_sys::lv_indev_drv_init(indev_drv.as_mut_ptr());
let mut indev_drv = indev_drv.assume_init();
indev_drv.type_ = lvgl_sys::LV_INDEV_TYPE_POINTER as lvgl_sys::lv_indev_type_t;
indev_drv.read_cb = Some(read_input::<F>);
indev_drv.user_data = &mut handler as *mut _ as lvgl_sys::lv_indev_drv_user_data_t;
indev_drv.user_data = Box::into_raw(Box::new(handler).unwrap()) as *mut _
as lvgl_sys::lv_indev_drv_user_data_t;
indev_drv
};
Self {
handler,
driver,
descriptor: None,
}
@ -85,47 +82,42 @@ unsafe extern "C" fn read_input<F>(
data: *mut lvgl_sys::lv_indev_data_t,
) -> bool
where
F: Fn() -> Option<BufferStatus>,
F: Fn() -> BufferStatus,
{
let mut data = *data;
// convert user data to function
let user_closure = &mut *((*indev_drv).user_data as *mut F);
// call user data
let result: Option<BufferStatus> = user_closure();
return if let Some(info) = result {
let info: BufferStatus = user_closure();
match info {
BufferStatus::Empty(InputState::Pressed(InputData::Touch(point))) => {
data.point.x = point.x as lvgl_sys::lv_coord_t;
data.point.y = point.y as lvgl_sys::lv_coord_t;
data.state = lvgl_sys::LV_INDEV_STATE_PR as lvgl_sys::lv_indev_state_t;
BufferStatus::Once(InputState::Pressed(InputData::Touch(point))) => {
(*data).point.x = point.x as lvgl_sys::lv_coord_t;
(*data).point.y = point.y as lvgl_sys::lv_coord_t;
(*data).state = lvgl_sys::LV_INDEV_STATE_PR as lvgl_sys::lv_indev_state_t;
false
}
BufferStatus::Empty(InputState::Released(InputData::Touch(point))) => {
data.point.x = point.x as lvgl_sys::lv_coord_t;
data.point.y = point.y as lvgl_sys::lv_coord_t;
data.state = lvgl_sys::LV_INDEV_STATE_REL as lvgl_sys::lv_indev_state_t;
BufferStatus::Once(InputState::Released(InputData::Touch(point))) => {
(*data).point.x = point.x as lvgl_sys::lv_coord_t;
(*data).point.y = point.y as lvgl_sys::lv_coord_t;
(*data).state = lvgl_sys::LV_INDEV_STATE_REL as lvgl_sys::lv_indev_state_t;
false
}
BufferStatus::Buffered(InputState::Pressed(InputData::Touch(point))) => {
data.point.x = point.x as lvgl_sys::lv_coord_t;
data.point.y = point.y as lvgl_sys::lv_coord_t;
data.state = lvgl_sys::LV_INDEV_STATE_PR as lvgl_sys::lv_indev_state_t;
(*data).point.x = point.x as lvgl_sys::lv_coord_t;
(*data).point.y = point.y as lvgl_sys::lv_coord_t;
(*data).state = lvgl_sys::LV_INDEV_STATE_PR as lvgl_sys::lv_indev_state_t;
true
}
BufferStatus::Buffered(InputState::Released(InputData::Touch(point))) => {
data.point.x = point.x as lvgl_sys::lv_coord_t;
data.point.y = point.y as lvgl_sys::lv_coord_t;
data.state = lvgl_sys::LV_INDEV_STATE_REL as lvgl_sys::lv_indev_state_t;
(*data).point.x = point.x as lvgl_sys::lv_coord_t;
(*data).point.y = point.y as lvgl_sys::lv_coord_t;
(*data).state = lvgl_sys::LV_INDEV_STATE_REL as lvgl_sys::lv_indev_state_t;
true
}
BufferStatus::Empty(InputState::Released(InputData::Key(_))) => false,
BufferStatus::Empty(InputState::Pressed(InputData::Key(_))) => false,
BufferStatus::Once(InputState::Released(InputData::Key(_))) => false,
BufferStatus::Once(InputState::Pressed(InputData::Key(_))) => false,
BufferStatus::Buffered(InputState::Released(InputData::Key(_))) => true,
BufferStatus::Buffered(InputState::Pressed(InputData::Key(_))) => true,
}
} else {
false
};
}
#[cfg(test)]

View file

@ -61,6 +61,7 @@ impl From<Color> for Rgb565 {
///
/// All objects (such as Buttons/Labels/Sliders etc.) receive these generic events
/// regardless of their type.
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Event<T> {
/// The object has been pressed
Pressed,
@ -140,6 +141,7 @@ impl<S> From<Event<S>> for lvgl_sys::lv_event_t {
}
/// These events are sent only by pointer-like input devices (E.g. mouse or touchpad)
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum PointerEvent {
DragBegin,
DragEnd,

View file

@ -57,10 +57,7 @@ where
}
}
pub fn indev_drv_register<F>(&mut self, input_device: &mut Pointer<F>) -> LvResult<()>
where
F: Fn() -> Option<BufferStatus>,
{
pub fn indev_drv_register(&mut self, input_device: &mut Pointer) -> LvResult<()> {
unsafe {
let descr = lvgl_sys::lv_indev_drv_register(&mut input_device.driver as *mut _);
input_device.set_descriptor(descr)?;