use instant::Instant;
use std::path::PathBuf;
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),
DecorationsClick,
}
impl Clone for WindowEvent<'static> {
fn clone(&self) -> Self {
use self::WindowEvent::*;
return 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")
}
DecorationsClick => DecorationsClick,
};
}
}
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,
DecorationsClick => Some(DecorationsClick),
}
}
}
#[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>),
}