use crate::common::{fresh_screen, pump};
use oxivgl::enums::ObjState;
use oxivgl::indev::{PointerIndev, PointerState};
use oxivgl::widgets::Button;
static PT_REG: PointerState = PointerState::new();
static PT_TAP: PointerState = PointerState::new();
fn find_pointer_by_userdata(target: *const core::ffi::c_void) -> Option<*mut oxivgl_sys::lv_indev_t> {
unsafe {
let mut indev = oxivgl_sys::lv_indev_get_next(core::ptr::null_mut());
while !indev.is_null() {
let is_pointer = oxivgl_sys::lv_indev_get_type(indev)
== oxivgl_sys::lv_indev_type_t_LV_INDEV_TYPE_POINTER;
if is_pointer
&& oxivgl_sys::lv_indev_get_user_data(indev) as *const core::ffi::c_void == target
{
return Some(indev);
}
indev = oxivgl_sys::lv_indev_get_next(indev);
}
None
}
}
fn find_any_pointer() -> Option<*mut oxivgl_sys::lv_indev_t> {
unsafe {
let mut indev = oxivgl_sys::lv_indev_get_next(core::ptr::null_mut());
while !indev.is_null() {
if oxivgl_sys::lv_indev_get_type(indev)
== oxivgl_sys::lv_indev_type_t_LV_INDEV_TYPE_POINTER
{
return Some(indev);
}
indev = oxivgl_sys::lv_indev_get_next(indev);
}
None
}
}
#[test]
fn pointer_registers_as_pointer_and_unregisters_on_drop() {
let _screen = fresh_screen();
let target = &PT_REG as *const PointerState as *const core::ffi::c_void;
assert!(find_pointer_by_userdata(target).is_none(), "no pointer before creation");
let pt = PointerIndev::new(&PT_REG).unwrap();
pump();
assert!(
find_pointer_by_userdata(target).is_some(),
"PointerIndev::new registers a POINTER device wired to its PointerState",
);
drop(pt);
pump();
assert!(
find_pointer_by_userdata(target).is_none(),
"dropping PointerIndev removes the device from LVGL",
);
}
#[test]
fn pointer_tap_presses_widget_at_coordinate() {
let screen = fresh_screen();
let btn = Button::new(&screen).unwrap();
btn.pos(50, 50).size(100, 40);
pump();
assert!(!btn.has_state(ObjState::PRESSED), "button starts un-pressed");
let pt = PointerIndev::new(&PT_TAP).unwrap();
let indev = find_pointer_by_userdata(&PT_TAP as *const PointerState as *const core::ffi::c_void)
.expect("pointer present");
PT_TAP.touch(100, 70);
unsafe { oxivgl_sys::lv_indev_read(indev) };
pump();
assert!(
btn.has_state(ObjState::PRESSED),
"a touch at the button's coordinate presses it",
);
PT_TAP.release();
unsafe { oxivgl_sys::lv_indev_read(indev) };
pump();
assert!(
!btn.has_state(ObjState::PRESSED),
"release clears the pressed state",
);
drop(pt);
}
#[test]
fn pointer_closure_feeds_coordinates() {
let screen = fresh_screen();
let btn = Button::new(&screen).unwrap();
btn.pos(10, 10).size(80, 30);
pump();
let phase = core::cell::Cell::new(0u8);
let pt = PointerIndev::new_with(move || {
let p = phase.get();
phase.set(p + 1);
if p == 0 { Some((40, 25)) } else { None }
})
.unwrap();
let indev = find_any_pointer().expect("closure pointer present");
unsafe { oxivgl_sys::lv_indev_read(indev) };
pump();
assert!(
btn.has_state(ObjState::PRESSED),
"closure-reported touch presses the widget at that coordinate",
);
unsafe { oxivgl_sys::lv_indev_read(indev) };
pump();
assert!(!btn.has_state(ObjState::PRESSED), "closure release clears press");
drop(pt);
pump();
assert!(find_any_pointer().is_none(), "closure pointer removed on drop");
}