event_types 0.1.0

Types to help idiomatically represent user input events
Documentation
use crate::coordinate_space::Pixels;
use crate::geometry::{Coordinates, PointerOrientation};
use enumset::{EnumSet, EnumSetType};
use euclid::Size2D;
use typed_builder::TypedBuilder;

/// Describes a pointer's values, typically at the time of a pointer event
#[derive(TypedBuilder, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PointerProperties {
    /// Coordinates in user interface
    coordinates: Coordinates,
    /// Pointer buttons held at time of event
    #[builder(setter(into))]
    held_buttons: PointerButtonSet,
    /// Unique pointer ID
    id: PointerId,
    /// Dimensions of pointer
    #[builder(default=Size2D::new(1., 1.))]
    dimensions: Size2D<f64, Pixels>,
    /// The normalized pressure of the pointer input in the range of \[0,1\]
    // Note: default value deviates from web spec, which requires pressure=0 when pointer not touching.
    #[builder(default = 0.5)]
    pressure: f64,
    /// The normalized tangential pressure of pointer in the range of \[-1,1\]
    #[builder(default = 0.)]
    tangential_pressure: f64,
    /// The pointer's orientation (tilt or spherical angles, and twist)
    #[builder(default)]
    orientation: PointerOrientation,
    /// The device type
    pointer_type: PointerType,
    /// In a multi-pointer (e.g. multi-touch) scenario, used to identify a master pointer amongst the set of active pointers for each pointer type.
    ///
    /// - At any given time, there can be at most one primary pointer for each pointer type.
    /// - The first pointer to become active for a particular pointer type (e.g. the first finger to touch the screen in a multi-touch interaction) becomes the primary pointer for that pointer type.
    is_primary: bool,
}

impl PointerProperties {
    /// Coordinates in user interface
    pub fn coordinates(&self) -> &Coordinates {
        &self.coordinates
    }
    /// Pointer buttons held at time of event
    pub fn held_buttons(&self) -> PointerButtonSet {
        self.held_buttons
    }
    /// Unique pointer ID
    pub fn id(&self) -> PointerId {
        self.id
    }
    /// Dimensions of pointer
    pub fn dimensions(&self) -> Size2D<f64, Pixels> {
        self.dimensions
    }
    /// The normalized pressure of the pointer input in the range of \[0,1\]
    ///
    /// 0 and 1 represent the minimum and maximum pressure the hardware is capable of detecting, respectively.
    pub fn pressure(&self) -> f64 {
        self.pressure
    }
    /// The normalized tangential pressure of pointer in the range of \[-1,1\]
    ///
    /// Typically set by an additional control (e.g. a finger wheel on an airbrush stylus). Also known as barrel pressure.
    ///
    /// 0 is the neutral position of the control. Note that some hardware may only support positive values in the range of \[0,1\]
    pub fn tangential_pressure(&self) -> f64 {
        self.tangential_pressure
    }
    /// The pointer's orientation (tilt or spherical angles, and twist)
    pub fn orientation(&self) -> &PointerOrientation {
        &self.orientation
    }
    /// The device type
    pub fn pointer_type(&self) -> PointerType {
        self.pointer_type
    }
    /// In a multi-pointer (e.g. multi-touch) scenario, used to identify a master pointer amongst the set of active pointers for each pointer type.
    ///
    /// - At any given time, there can be at most one primary pointer for each pointer type.
    /// - The first pointer to become active for a particular pointer type (e.g. the first finger to touch the screen in a multi-touch interaction) becomes the primary pointer for that pointer type.
    pub fn is_primary(&self) -> bool {
        self.is_primary
    }
}

#[cfg(test)]
mod pointer_state {
    use super::*;
    use crate::{ClientPoint, ElementPoint, PagePoint, ScreenPoint};

    use assert2::assert;

    #[test]
    fn minimal_builder() {
        let c = Coordinates::new(
            ScreenPoint::new(1., 1.),
            PagePoint::new(2., 2.),
            ClientPoint::new(3., 3.),
            ElementPoint::new(4., 4.),
        );

        let state: PointerProperties = PointerProperties::builder()
            .coordinates(c.clone())
            .held_buttons(PointerButtonSet::empty())
            .id(PointerId(0))
            .pointer_type(PointerType::Mouse)
            .is_primary(true)
            .build();

        assert!(state.coordinates() == &c);
        assert!(state.held_buttons() == PointerButtonSet::empty());
        assert!(state.id() == PointerId(0));
        assert!(state.dimensions() == Size2D::new(1., 1.));
        assert!(state.pressure() == 0.5);
        assert!(state.tangential_pressure() == 0.);
        assert!(state.orientation() == &PointerOrientation::default());
        assert!(state.pointer_type() == PointerType::Mouse);
        assert!(state.is_primary() == true);
    }
}

/// Device type associated with an event
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PointerType {
    Mouse,
    /// Pen / stylus
    Pen,
    Touch,
    /// Device type cannot be detected
    Unknown,
}

impl Default for PointerType {
    fn default() -> Self {
        PointerType::Mouse
    }
}

/// A pointer button type (such as Primary/Secondary)
// note: EnumSetType also derives PartialEq and Copy and Clone for some reason
#[derive(EnumSetType, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PointerButton {
    /// Primary button (typically the left button)
    ///
    /// May also represent touch contact/pen contact
    Primary,
    /// Secondary button (typically the right button)
    Secondary,
    /// Auxiliary button (typically the middle button)
    Auxiliary,
    /// Fourth button (typically the "Back" button)
    Fourth,
    /// Fifth button (typically the "Forward" button)
    Fifth,
    /// Pen eraser button
    Eraser,
    /// A button with an unknown code
    Unknown,
}

/// A set of pointer buttons
pub type PointerButtonSet = EnumSet<PointerButton>;

/// A unique identifier for a pointer causing an event.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PointerId(pub i64);