Touch input device #27
4 changed files with 74 additions and 68 deletions
|
@ -4,13 +4,14 @@ use embedded_graphics::prelude::*;
|
||||||
use embedded_graphics_simulator::{
|
use embedded_graphics_simulator::{
|
||||||
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
||||||
};
|
};
|
||||||
use lvgl::input_device::{InputData, Pointer};
|
use lvgl::input_device::{BufferStatus, InputData, Pointer};
|
||||||
use lvgl::style::Style;
|
use lvgl::style::Style;
|
||||||
use lvgl::widgets::{Btn, Label};
|
use lvgl::widgets::{Btn, Label};
|
||||||
use lvgl::{self, Align, Color, LvError, Part, State, Widget, UI};
|
use lvgl::{self, Align, Color, LvError, Part, State, Widget, UI};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Instant;
|
use std::thread::sleep;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
fn main() -> Result<(), LvError> {
|
fn main() -> Result<(), LvError> {
|
||||||
let display: SimulatorDisplay<Rgb565> =
|
let display: SimulatorDisplay<Rgb565> =
|
||||||
|
@ -24,18 +25,17 @@ fn main() -> Result<(), LvError> {
|
||||||
// Implement and register your display:
|
// Implement and register your display:
|
||||||
ui.disp_drv_register(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
|
// Register the input mode
|
||||||
let latest_touch_point: Rc<RefCell<Option<Point>>> = Rc::new(RefCell::new(None));
|
let internal = Rc::clone(&latest_touch_status);
|
||||||
let internal = Rc::clone(&latest_touch_point);
|
|
||||||
let mut touch_screen = Pointer::new(move || {
|
let mut touch_screen = Pointer::new(move || {
|
||||||
let info = internal.borrow().clone();
|
let input_status = internal.borrow().clone();
|
||||||
if info.is_some() {
|
//println!("input_status = {:?}", input_status);
|
||||||
let point = info.unwrap();
|
input_status
|
||||||
println!("Changed to {:?}", point);
|
|
||||||
Some(InputData::Touch(point).pressed().once())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.indev_drv_register(&mut touch_screen)?;
|
ui.indev_drv_register(&mut touch_screen)?;
|
||||||
|
@ -56,6 +56,7 @@ fn main() -> Result<(), LvError> {
|
||||||
|
|
||||||
let mut btn_state = false;
|
let mut btn_state = false;
|
||||||
button.on_event(|mut btn, event| {
|
button.on_event(|mut btn, event| {
|
||||||
|
println!("Some event! {:?}", event);
|
||||||
if let lvgl::Event::Clicked = event {
|
if let lvgl::Event::Clicked = event {
|
||||||
if btn_state {
|
if btn_state {
|
||||||
let nt = CString::new("Click me!").unwrap();
|
let nt = CString::new("Click me!").unwrap();
|
||||||
|
@ -71,11 +72,22 @@ fn main() -> Result<(), LvError> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut loop_started = Instant::now();
|
let mut loop_started = Instant::now();
|
||||||
|
let mut latest_touch_point = Point::new(0, 0);
|
||||||
'running: loop {
|
'running: loop {
|
||||||
ui.task_handler();
|
ui.task_handler();
|
||||||
window.update(ui.get_display_ref().unwrap());
|
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 {
|
match event {
|
||||||
SimulatorEvent::MouseButtonUp {
|
SimulatorEvent::MouseButtonUp {
|
||||||
mouse_btn: _,
|
mouse_btn: _,
|
||||||
|
@ -83,13 +95,16 @@ fn main() -> Result<(), LvError> {
|
||||||
} => {
|
} => {
|
||||||
println!("Clicked on: {:?}", point);
|
println!("Clicked on: {:?}", point);
|
||||||
// Send a event to the button directly
|
// 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,
|
SimulatorEvent::Quit => break 'running,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(50));
|
||||||
|
|
||||||
ui.tick_inc(loop_started.elapsed());
|
ui.tick_inc(loop_started.elapsed());
|
||||||
loop_started = Instant::now();
|
loop_started = Instant::now();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::mem::Box;
|
||||||
use crate::LvResult;
|
use crate::LvResult;
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use embedded_graphics::geometry::Point;
|
use embedded_graphics::geometry::Point;
|
||||||
|
@ -26,7 +27,7 @@ pub enum InputState {
|
||||||
|
|
||||||
impl InputState {
|
impl InputState {
|
||||||
pub fn once(self) -> BufferStatus {
|
pub fn once(self) -> BufferStatus {
|
||||||
BufferStatus::Empty(self)
|
BufferStatus::Once(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn and_continued(self) -> BufferStatus {
|
pub fn and_continued(self) -> BufferStatus {
|
||||||
|
@ -36,35 +37,31 @@ impl InputState {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub enum BufferStatus {
|
pub enum BufferStatus {
|
||||||
Empty(InputState),
|
Once(InputState),
|
||||||
Buffered(InputState),
|
Buffered(InputState),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pointer<F>
|
pub struct Pointer {
|
||||||
where
|
|
||||||
F: Fn() -> Option<BufferStatus>,
|
|
||||||
{
|
|
||||||
pub(crate) driver: lvgl_sys::lv_indev_drv_t,
|
pub(crate) driver: lvgl_sys::lv_indev_drv_t,
|
||||||
pub(crate) descriptor: Option<lvgl_sys::lv_indev_t>,
|
pub(crate) descriptor: Option<lvgl_sys::lv_indev_t>,
|
||||||
handler: F,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Pointer<F>
|
impl Pointer {
|
||||||
where
|
pub fn new<F>(mut handler: F) -> Self
|
||||||
F: Fn() -> Option<BufferStatus>,
|
where
|
||||||
{
|
F: Fn() -> BufferStatus,
|
||||||
pub fn new(mut handler: F) -> Self {
|
{
|
||||||
let driver = unsafe {
|
let driver = unsafe {
|
||||||
let mut indev_drv = MaybeUninit::uninit();
|
let mut indev_drv = MaybeUninit::uninit();
|
||||||
lvgl_sys::lv_indev_drv_init(indev_drv.as_mut_ptr());
|
lvgl_sys::lv_indev_drv_init(indev_drv.as_mut_ptr());
|
||||||
let mut indev_drv = indev_drv.assume_init();
|
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.type_ = lvgl_sys::LV_INDEV_TYPE_POINTER as lvgl_sys::lv_indev_type_t;
|
||||||
indev_drv.read_cb = Some(read_input::<F>);
|
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
|
indev_drv
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
handler,
|
|
||||||
driver,
|
driver,
|
||||||
descriptor: None,
|
descriptor: None,
|
||||||
}
|
}
|
||||||
|
@ -85,47 +82,42 @@ unsafe extern "C" fn read_input<F>(
|
||||||
data: *mut lvgl_sys::lv_indev_data_t,
|
data: *mut lvgl_sys::lv_indev_data_t,
|
||||||
) -> bool
|
) -> bool
|
||||||
where
|
where
|
||||||
F: Fn() -> Option<BufferStatus>,
|
F: Fn() -> BufferStatus,
|
||||||
{
|
{
|
||||||
let mut data = *data;
|
|
||||||
// convert user data to function
|
// convert user data to function
|
||||||
let user_closure = &mut *((*indev_drv).user_data as *mut F);
|
let user_closure = &mut *((*indev_drv).user_data as *mut F);
|
||||||
// call user data
|
// call user data
|
||||||
let result: Option<BufferStatus> = user_closure();
|
let info: BufferStatus = user_closure();
|
||||||
return if let Some(info) = result {
|
match info {
|
||||||
match info {
|
BufferStatus::Once(InputState::Pressed(InputData::Touch(point))) => {
|
||||||
BufferStatus::Empty(InputState::Pressed(InputData::Touch(point))) => {
|
(*data).point.x = point.x as lvgl_sys::lv_coord_t;
|
||||||
data.point.x = point.x as lvgl_sys::lv_coord_t;
|
(*data).point.y = point.y 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.state = lvgl_sys::LV_INDEV_STATE_PR as lvgl_sys::lv_indev_state_t;
|
false
|
||||||
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;
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
BufferStatus::Empty(InputState::Released(InputData::Key(_))) => false,
|
|
||||||
BufferStatus::Empty(InputState::Pressed(InputData::Key(_))) => false,
|
|
||||||
BufferStatus::Buffered(InputState::Released(InputData::Key(_))) => true,
|
|
||||||
BufferStatus::Buffered(InputState::Pressed(InputData::Key(_))) => true,
|
|
||||||
}
|
}
|
||||||
} else {
|
BufferStatus::Once(InputState::Released(InputData::Touch(point))) => {
|
||||||
false
|
(*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;
|
||||||
|
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;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -61,6 +61,7 @@ impl From<Color> for Rgb565 {
|
||||||
///
|
///
|
||||||
/// All objects (such as Buttons/Labels/Sliders etc.) receive these generic events
|
/// All objects (such as Buttons/Labels/Sliders etc.) receive these generic events
|
||||||
/// regardless of their type.
|
/// regardless of their type.
|
||||||
|
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub enum Event<T> {
|
pub enum Event<T> {
|
||||||
/// The object has been pressed
|
/// The object has been pressed
|
||||||
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)
|
/// 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 {
|
pub enum PointerEvent {
|
||||||
DragBegin,
|
DragBegin,
|
||||||
DragEnd,
|
DragEnd,
|
||||||
|
|
|
@ -57,10 +57,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn indev_drv_register<F>(&mut self, input_device: &mut Pointer<F>) -> LvResult<()>
|
pub fn indev_drv_register(&mut self, input_device: &mut Pointer) -> LvResult<()> {
|
||||||
where
|
|
||||||
F: Fn() -> Option<BufferStatus>,
|
|
||||||
{
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let descr = lvgl_sys::lv_indev_drv_register(&mut input_device.driver as *mut _);
|
let descr = lvgl_sys::lv_indev_drv_register(&mut input_device.driver as *mut _);
|
||||||
input_device.set_descriptor(descr)?;
|
input_device.set_descriptor(descr)?;
|
||||||
|
|
Loading…
Reference in a new issue