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::{
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
where
|
||||
F: Fn() -> Option<BufferStatus>,
|
||||
{
|
||||
pub fn new(mut handler: F) -> Self {
|
||||
impl Pointer {
|
||||
pub fn new<F>(mut handler: F) -> Self
|
||||
where
|
||||
F: Fn() -> BufferStatus,
|
||||
{
|
||||
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 {
|
||||
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;
|
||||
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,
|
||||
let info: BufferStatus = user_closure();
|
||||
match info {
|
||||
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
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
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;
|
||||
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)]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)?;
|
||||
|
|
Loading…
Reference in a new issue