use crate::ei::ei_client::EiClient;
use crate::ei::ei_client::EiClientError;
use crate::ei::ei_ifs::ei_device::EiDevice;
use crate::ei::ei_ifs::ei_device::EiDeviceInterface;
use crate::ei::ei_object::EiObject;
use crate::ei::ei_object::EiVersion;
use crate::fixed::Fixed;
use crate::leaks::Tracker;
use crate::wire_ei::EiTouchscreenId;
use crate::wire_ei::ei_touchscreen::ClientCancel;
use crate::wire_ei::ei_touchscreen::ClientDown;
use crate::wire_ei::ei_touchscreen::ClientMotion;
use crate::wire_ei::ei_touchscreen::ClientUp;
use crate::wire_ei::ei_touchscreen::EiTouchscreenRequestHandler;
use crate::wire_ei::ei_touchscreen::Release;
use crate::wire_ei::ei_touchscreen::ServerCancel;
use crate::wire_ei::ei_touchscreen::ServerDown;
use crate::wire_ei::ei_touchscreen::ServerMotion;
use crate::wire_ei::ei_touchscreen::ServerUp;
use hashbrown::hash_map::Entry;
use jay_proc::jay_clone;
use std::rc::Rc;
use thiserror::Error;
pub struct EiTouchscreen {
id: EiTouchscreenId,
client: Rc<EiClient>,
tracker: Tracker<Self>,
version: EiVersion,
pub device: Rc<EiDevice>,
}
#[jay_clone(Copy)]
#[derive(Debug)]
pub enum TouchChange {
Down(f32, f32),
Motion(f32, f32),
Up,
Cancel,
}
ei_device_interface!(EiTouchscreen, ei_touchscreen, touchscreen);
impl EiTouchscreen {
pub fn send_down(&self, touchid: u32, x: Fixed, y: Fixed) {
self.client.event(ServerDown {
self_id: self.id,
touchid,
x: x.to_f32(),
y: y.to_f32(),
});
}
pub fn send_motion(&self, touchid: u32, x: Fixed, y: Fixed) {
self.client.event(ServerMotion {
self_id: self.id,
touchid,
x: x.to_f32(),
y: y.to_f32(),
});
}
pub fn send_up(&self, touchid: u32) {
self.client.event(ServerUp {
self_id: self.id,
touchid,
});
}
pub fn send_cancel(&self, touchid: u32) {
self.client.event(ServerCancel {
self_id: self.id,
touchid,
});
}
fn set_client_event(&self, touchid: u32, event: TouchChange) -> Result<(), EiTouchscreenError> {
match self.device.touch_changes.lock().entry(touchid) {
Entry::Occupied(mut o) => {
use TouchChange::*;
match (o.get(), event) {
(Motion(_, _), Motion(_, _))
| (Down(_, _), Down(_, _))
| (Up, Up)
| (Cancel, Cancel) => {
o.insert(event);
Ok(())
}
_ => Err(EiTouchscreenError::InvalidEventCombination),
}
}
Entry::Vacant(v) => {
v.insert(event);
Ok(())
}
}
}
}
impl EiTouchscreenRequestHandler for EiTouchscreen {
type Error = EiTouchscreenError;
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.destroy()?;
Ok(())
}
fn client_down(&self, req: ClientDown, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Down(req.x, req.y))
}
fn client_motion(&self, req: ClientMotion, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Motion(req.x, req.y))
}
fn client_up(&self, req: ClientUp, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Up)
}
fn client_cancel(&self, req: ClientCancel, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Cancel)
}
}
ei_object_base! {
self = EiTouchscreen;
version = self.version;
}
impl EiObject for EiTouchscreen {}
#[derive(Debug, Error)]
pub enum EiTouchscreenError {
#[error(transparent)]
EiClientError(Box<EiClientError>),
#[error("Touch frame contains an invalid combination of events")]
InvalidEventCombination,
}
efrom!(EiTouchscreenError, EiClientError);