use std::time::Duration;
use crate::{PointerChange, PointerData, PointerDeviceKind, PointerSignalKind, ViewId};
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PointerReport {
pub view_id: ViewId,
pub time_stamp: Duration,
pub device: i64,
pub kind: PointerDeviceKind,
pub position: [f64; 2],
pub change: ReportedChange,
pub contact: Contact,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ReportedChange {
Add,
Remove,
Hover { buttons: i64 },
Down { buttons: i64 },
Move { buttons: i64 },
Up { buttons: i64 },
Cancel { buttons: i64 },
Scroll { delta: [f64; 2] },
ScrollInertiaCancel,
Scale { scale: f64 },
PanZoomStart,
PanZoomUpdate {
pan: [f64; 2],
scale: f64,
rotation: f64,
},
PanZoomEnd,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Contact {
pub pressure: f64,
pub pressure_min: f64,
pub pressure_max: f64,
pub distance: f64,
pub distance_max: f64,
pub size: f64,
pub radius_major: f64,
pub radius_minor: f64,
pub radius_min: f64,
pub radius_max: f64,
pub orientation: f64,
pub tilt: f64,
}
impl Default for Contact {
fn default() -> Contact {
Contact {
pressure: 1.0,
pressure_min: 1.0,
pressure_max: 1.0,
distance: 0.0,
distance_max: 0.0,
size: 0.0,
radius_major: 0.0,
radius_minor: 0.0,
radius_min: 0.0,
radius_max: 0.0,
orientation: 0.0,
tilt: 0.0,
}
}
}
impl From<PointerReport> for PointerData {
fn from(report: PointerReport) -> PointerData {
let contact = report.contact;
let mut data = PointerData {
view_id: report.view_id,
time_stamp: report.time_stamp,
kind: report.kind,
device: report.device,
physical_x: report.position[0],
physical_y: report.position[1],
pressure: contact.pressure,
pressure_min: contact.pressure_min,
pressure_max: contact.pressure_max,
distance: contact.distance,
distance_max: contact.distance_max,
size: contact.size,
radius_major: contact.radius_major,
radius_minor: contact.radius_minor,
radius_min: contact.radius_min,
radius_max: contact.radius_max,
orientation: contact.orientation,
tilt: contact.tilt,
..PointerData::default()
};
report.change.write_into(&mut data);
data
}
}
impl ReportedChange {
fn write_into(self, data: &mut PointerData) {
let (change, buttons) = match self {
ReportedChange::Add => (PointerChange::Add, 0),
ReportedChange::Remove => (PointerChange::Remove, 0),
ReportedChange::Hover { buttons } => (PointerChange::Hover, buttons),
ReportedChange::Down { buttons } => (PointerChange::Down, buttons),
ReportedChange::Move { buttons } => (PointerChange::Move, buttons),
ReportedChange::Up { buttons } => (PointerChange::Up, buttons),
ReportedChange::Cancel { buttons } => (PointerChange::Cancel, buttons),
ReportedChange::Scroll { delta } => {
data.signal_kind = Some(PointerSignalKind::Scroll);
[data.scroll_delta_x, data.scroll_delta_y] = delta;
(PointerChange::Hover, 0)
}
ReportedChange::ScrollInertiaCancel => {
data.signal_kind = Some(PointerSignalKind::ScrollInertiaCancel);
(PointerChange::Hover, 0)
}
ReportedChange::Scale { scale } => {
data.signal_kind = Some(PointerSignalKind::Scale);
data.scale = scale;
(PointerChange::Hover, 0)
}
ReportedChange::PanZoomStart => (PointerChange::PanZoomStart, 0),
ReportedChange::PanZoomUpdate {
pan,
scale,
rotation,
} => {
[data.pan_x, data.pan_y] = pan;
data.scale = scale;
data.rotation = rotation;
(PointerChange::PanZoomUpdate, 0)
}
ReportedChange::PanZoomEnd => (PointerChange::PanZoomEnd, 0),
};
data.change = change;
data.buttons = buttons;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn report(change: ReportedChange) -> PointerReport {
PointerReport {
view_id: ViewId(3),
time_stamp: Duration::from_millis(5),
device: 2,
kind: PointerDeviceKind::Mouse,
position: [10.0, 20.0],
change,
contact: Contact::default(),
}
}
#[test]
fn a_report_is_the_datum_with_what_only_the_converter_knows_left_at_zero() {
let data = PointerData::from(report(ReportedChange::Down { buttons: 1 }));
assert_eq!(data.change, PointerChange::Down);
assert_eq!(data.buttons, 1);
assert_eq!([data.physical_x, data.physical_y], [10.0, 20.0]);
assert_eq!((data.view_id, data.device), (ViewId(3), 2));
assert_eq!(data.embedder_id, 0, "no host numbers its system events");
assert_eq!(data.pressure, 1.0, "a mouse detects no pressure");
assert_eq!(data.pointer_identifier, 0);
assert_eq!([data.physical_delta_x, data.physical_delta_y], [0.0, 0.0]);
assert!(!data.synthesized);
assert!(data.signal_kind.is_none());
}
#[test]
fn a_scroll_is_a_signal_on_a_hover() {
let data = PointerData::from(report(ReportedChange::Scroll { delta: [0.0, 40.0] }));
assert_eq!(data.change, PointerChange::Hover);
assert_eq!(data.signal_kind, Some(PointerSignalKind::Scroll));
assert_eq!([data.scroll_delta_x, data.scroll_delta_y], [0.0, 40.0]);
}
#[test]
fn a_pan_zoom_update_carries_its_totals() {
let data = PointerData::from(report(ReportedChange::PanZoomUpdate {
pan: [3.0, 4.0],
scale: 1.5,
rotation: 0.25,
}));
assert_eq!(data.change, PointerChange::PanZoomUpdate);
assert_eq!([data.pan_x, data.pan_y], [3.0, 4.0]);
assert_eq!((data.scale, data.rotation), (1.5, 0.25));
assert_eq!([data.pan_delta_x, data.pan_delta_y], [0.0, 0.0]);
}
}