#![allow(clippy::tabs_in_doc_comments)]
use std::path::PathBuf;
use instant::Instant;
use crate::{
accelerator::AcceleratorId,
dpi::{PhysicalPosition, PhysicalSize},
keyboard::{self, ModifiersState},
menu::{MenuId, MenuType},
platform_impl,
window::{Theme, WindowId}
};
#[non_exhaustive]
#[derive(Debug, PartialEq)]
pub enum Event<'a, T: 'static> {
NewEvents(StartCause),
#[non_exhaustive]
WindowEvent { window_id: WindowId, event: WindowEvent<'a> },
#[non_exhaustive]
DeviceEvent { device_id: DeviceId, event: DeviceEvent },
UserEvent(T),
#[non_exhaustive]
MenuEvent {
window_id: Option<WindowId>,
menu_id: MenuId,
origin: MenuType
},
#[non_exhaustive]
TrayEvent {
bounds: Rectangle,
event: TrayEvent,
position: PhysicalPosition<f64>
},
GlobalShortcutEvent(AcceleratorId),
Suspended,
Resumed,
MainEventsCleared,
RedrawRequested(WindowId),
RedrawEventsCleared,
LoopDestroyed
}
impl<T: Clone> Clone for Event<'static, T> {
fn clone(&self) -> Self {
use self::Event::*;
match self {
WindowEvent { window_id, event } => WindowEvent {
window_id: *window_id,
event: event.clone()
},
UserEvent(event) => UserEvent(event.clone()),
DeviceEvent { device_id, event } => DeviceEvent {
device_id: *device_id,
event: event.clone()
},
NewEvents(cause) => NewEvents(*cause),
MainEventsCleared => MainEventsCleared,
RedrawRequested(wid) => RedrawRequested(*wid),
RedrawEventsCleared => RedrawEventsCleared,
LoopDestroyed => LoopDestroyed,
Suspended => Suspended,
Resumed => Resumed,
MenuEvent { window_id, menu_id, origin } => MenuEvent {
window_id: *window_id,
menu_id: *menu_id,
origin: *origin
},
TrayEvent { bounds, event, position } => TrayEvent {
bounds: *bounds,
event: *event,
position: *position
},
GlobalShortcutEvent(accelerator_id) => GlobalShortcutEvent(*accelerator_id)
}
}
}
impl<'a, T> Event<'a, T> {
pub fn map_nonuser_event<U>(self) -> Result<Event<'a, U>, Event<'a, T>> {
use self::Event::*;
match self {
UserEvent(_) => Err(self),
WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
NewEvents(cause) => Ok(NewEvents(cause)),
MainEventsCleared => Ok(MainEventsCleared),
RedrawRequested(wid) => Ok(RedrawRequested(wid)),
RedrawEventsCleared => Ok(RedrawEventsCleared),
LoopDestroyed => Ok(LoopDestroyed),
Suspended => Ok(Suspended),
Resumed => Ok(Resumed),
MenuEvent { window_id, menu_id, origin } => Ok(MenuEvent { window_id, menu_id, origin }),
TrayEvent { bounds, event, position } => Ok(TrayEvent { bounds, event, position }),
GlobalShortcutEvent(accelerator_id) => Ok(GlobalShortcutEvent(accelerator_id))
}
}
pub fn to_static(self) -> Option<Event<'static, T>> {
use self::Event::*;
match self {
WindowEvent { window_id, event } => event.to_static().map(|event| WindowEvent { window_id, event }),
UserEvent(event) => Some(UserEvent(event)),
DeviceEvent { device_id, event } => Some(DeviceEvent { device_id, event }),
NewEvents(cause) => Some(NewEvents(cause)),
MainEventsCleared => Some(MainEventsCleared),
RedrawRequested(wid) => Some(RedrawRequested(wid)),
RedrawEventsCleared => Some(RedrawEventsCleared),
LoopDestroyed => Some(LoopDestroyed),
Suspended => Some(Suspended),
Resumed => Some(Resumed),
MenuEvent { window_id, menu_id, origin } => Some(MenuEvent { window_id, menu_id, origin }),
TrayEvent { bounds, event, position } => Some(TrayEvent { bounds, event, position }),
GlobalShortcutEvent(accelerator_id) => Some(GlobalShortcutEvent(accelerator_id))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum StartCause {
#[non_exhaustive]
ResumeTimeReached { start: Instant, requested_resume: Instant },
#[non_exhaustive]
WaitCancelled { start: Instant, requested_resume: Option<Instant> },
Poll,
Init
}
#[non_exhaustive]
#[derive(Debug, PartialEq)]
pub enum WindowEvent<'a> {
Resized(PhysicalSize<u32>),
Moved(PhysicalPosition<i32>),
CloseRequested,
Destroyed,
DroppedFile(PathBuf),
HoveredFile(PathBuf),
HoveredFileCancelled,
ReceivedImeText(String),
Focused(bool),
#[non_exhaustive]
KeyboardInput {
device_id: DeviceId,
event: KeyEvent,
is_synthetic: bool
},
ModifiersChanged(ModifiersState),
CursorMoved {
device_id: DeviceId,
position: PhysicalPosition<f64>,
#[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
modifiers: ModifiersState
},
CursorEntered { device_id: DeviceId },
CursorLeft { device_id: DeviceId },
MouseWheel {
device_id: DeviceId,
delta: MouseScrollDelta,
phase: TouchPhase,
#[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
modifiers: ModifiersState
},
MouseInput {
device_id: DeviceId,
state: ElementState,
button: MouseButton,
#[deprecated = "Deprecated in favor of WindowEvent::ModifiersChanged"]
modifiers: ModifiersState
},
TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
Touch(Touch),
ScaleFactorChanged { scale_factor: f64, new_inner_size: &'a mut PhysicalSize<u32> },
ThemeChanged(Theme),
DecorationsClicked
}
impl Clone for WindowEvent<'static> {
fn clone(&self) -> Self {
use self::WindowEvent::*;
match self {
Resized(size) => Resized(*size),
Moved(pos) => Moved(*pos),
CloseRequested => CloseRequested,
Destroyed => Destroyed,
DroppedFile(file) => DroppedFile(file.clone()),
HoveredFile(file) => HoveredFile(file.clone()),
HoveredFileCancelled => HoveredFileCancelled,
ReceivedImeText(c) => ReceivedImeText(c.clone()),
Focused(f) => Focused(*f),
KeyboardInput { device_id, event, is_synthetic } => KeyboardInput {
device_id: *device_id,
event: event.clone(),
is_synthetic: *is_synthetic
},
ModifiersChanged(modifiers) => ModifiersChanged(*modifiers),
#[allow(deprecated)]
CursorMoved { device_id, position, modifiers } => CursorMoved {
device_id: *device_id,
position: *position,
modifiers: *modifiers
},
CursorEntered { device_id } => CursorEntered { device_id: *device_id },
CursorLeft { device_id } => CursorLeft { device_id: *device_id },
#[allow(deprecated)]
MouseWheel { device_id, delta, phase, modifiers } => MouseWheel {
device_id: *device_id,
delta: *delta,
phase: *phase,
modifiers: *modifiers
},
#[allow(deprecated)]
MouseInput { device_id, state, button, modifiers } => MouseInput {
device_id: *device_id,
state: *state,
button: *button,
modifiers: *modifiers
},
TouchpadPressure { device_id, pressure, stage } => TouchpadPressure {
device_id: *device_id,
pressure: *pressure,
stage: *stage
},
AxisMotion { device_id, axis, value } => AxisMotion {
device_id: *device_id,
axis: *axis,
value: *value
},
Touch(touch) => Touch(*touch),
ThemeChanged(theme) => ThemeChanged(*theme),
ScaleFactorChanged { .. } => {
unreachable!("Static event can't be about scale factor changing")
}
DecorationsClicked => DecorationsClicked
}
}
}
impl<'a> WindowEvent<'a> {
pub fn to_static(self) -> Option<WindowEvent<'static>> {
use self::WindowEvent::*;
match self {
Resized(size) => Some(Resized(size)),
Moved(position) => Some(Moved(position)),
CloseRequested => Some(CloseRequested),
Destroyed => Some(Destroyed),
DroppedFile(file) => Some(DroppedFile(file)),
HoveredFile(file) => Some(HoveredFile(file)),
HoveredFileCancelled => Some(HoveredFileCancelled),
ReceivedImeText(c) => Some(ReceivedImeText(c)),
Focused(focused) => Some(Focused(focused)),
KeyboardInput { device_id, event, is_synthetic } => Some(KeyboardInput { device_id, event, is_synthetic }),
ModifiersChanged(modifiers) => Some(ModifiersChanged(modifiers)),
#[allow(deprecated)]
CursorMoved { device_id, position, modifiers } => Some(CursorMoved { device_id, position, modifiers }),
CursorEntered { device_id } => Some(CursorEntered { device_id }),
CursorLeft { device_id } => Some(CursorLeft { device_id }),
#[allow(deprecated)]
MouseWheel { device_id, delta, phase, modifiers } => Some(MouseWheel { device_id, delta, phase, modifiers }),
#[allow(deprecated)]
MouseInput { device_id, state, button, modifiers } => Some(MouseInput { device_id, state, button, modifiers }),
TouchpadPressure { device_id, pressure, stage } => Some(TouchpadPressure { device_id, pressure, stage }),
AxisMotion { device_id, axis, value } => Some(AxisMotion { device_id, axis, value }),
Touch(touch) => Some(Touch(touch)),
ThemeChanged(theme) => Some(ThemeChanged(theme)),
ScaleFactorChanged { .. } => None,
DecorationsClicked => Some(DecorationsClicked)
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId(pub(crate) platform_impl::DeviceId);
impl DeviceId {
pub unsafe fn dummy() -> Self {
DeviceId(platform_impl::DeviceId::dummy())
}
}
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub enum DeviceEvent {
Added,
Removed,
#[non_exhaustive]
MouseMotion {
delta: (f64, f64)
},
#[non_exhaustive]
MouseWheel {
delta: MouseScrollDelta
},
#[non_exhaustive]
Motion {
axis: AxisId,
value: f64
},
#[non_exhaustive]
Button {
button: ButtonId,
state: ElementState
},
Key(RawKeyEvent),
#[non_exhaustive]
Text {
codepoint: char
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RawKeyEvent {
pub physical_key: keyboard::KeyCode,
pub state: ElementState
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct KeyEvent {
pub physical_key: keyboard::KeyCode,
pub logical_key: keyboard::Key<'static>,
pub text: Option<&'static str>,
pub location: keyboard::KeyLocation,
pub state: ElementState,
pub repeat: bool,
pub(crate) platform_specific: platform_impl::KeyEventExtra
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
impl KeyEvent {
pub fn text_with_all_modifiers(&self) -> Option<&str> {
self.platform_specific.text_with_all_modifiers
}
pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
self.platform_specific.key_without_modifiers.clone()
}
}
#[cfg(any(target_os = "android", target_os = "ios"))]
impl KeyEvent {
pub fn text_with_all_modifiers(&self) -> Option<&str> {
self.text.clone()
}
pub fn key_without_modifiers(&self) -> keyboard::Key<'static> {
self.logical_key.clone()
}
}
#[non_exhaustive]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TouchPhase {
Started,
Moved,
Ended,
Cancelled
}
#[non_exhaustive]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TrayEvent {
LeftClick,
RightClick,
DoubleClick
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Rectangle {
pub position: PhysicalPosition<f64>,
pub size: PhysicalSize<f64>
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Touch {
pub device_id: DeviceId,
pub phase: TouchPhase,
pub location: PhysicalPosition<f64>,
pub force: Option<Force>,
pub id: u64
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Force {
#[non_exhaustive]
Calibrated {
force: f64,
max_possible_force: f64,
altitude_angle: Option<f64>
},
Normalized(f64)
}
impl Force {
pub fn normalized(&self) -> f64 {
match self {
Force::Calibrated {
force,
max_possible_force,
altitude_angle
} => {
let force = match altitude_angle {
Some(altitude_angle) => force / altitude_angle.sin(),
None => *force
};
force / max_possible_force
}
Force::Normalized(force) => *force
}
}
}
pub type AxisId = u32;
pub type ButtonId = u32;
#[non_exhaustive]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ElementState {
Pressed,
Released
}
#[non_exhaustive]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MouseButton {
Left,
Right,
Middle,
Other(u16)
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MouseScrollDelta {
LineDelta(f32, f32),
PixelDelta(PhysicalPosition<f64>)
}