use crate::geom::{self, Point2, Vector2};
use crate::window;
use crate::App;
use std::path::PathBuf;
use winit;
pub use winit::{
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
VirtualKeyCode as Key,
};
pub trait LoopEvent: From<Update> {
fn from_winit_event(_: winit::Event, _: &App) -> Option<Self>;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Update {
pub since_last: std::time::Duration,
pub since_start: std::time::Duration,
}
#[derive(Clone, Debug)]
pub enum Event {
WindowEvent {
id: window::Id,
raw: winit::WindowEvent,
simple: Option<WindowEvent>,
},
DeviceEvent(winit::DeviceId, winit::DeviceEvent),
Update(Update),
Awakened,
Suspended(bool),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct TouchEvent {
pub id: u64,
pub phase: TouchPhase,
pub position: Point2<geom::scalar::Default>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct TouchpadPressure {
pub device_id: winit::DeviceId,
pub pressure: f32,
pub stage: i64,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct AxisMotion {
pub device_id: winit::DeviceId,
pub axis: winit::AxisId,
pub value: geom::scalar::Default,
}
#[derive(Clone, Debug, PartialEq)]
pub enum WindowEvent {
Moved(Point2<geom::scalar::Default>),
KeyPressed(Key),
KeyReleased(Key),
MouseMoved(Point2<geom::scalar::Default>),
MousePressed(MouseButton),
MouseReleased(MouseButton),
MouseEntered,
MouseExited,
MouseWheel(MouseScrollDelta, TouchPhase),
Resized(Vector2<geom::scalar::Default>),
HoveredFile(PathBuf),
DroppedFile(PathBuf),
HoveredFileCancelled,
Touch(TouchEvent),
TouchPressure(TouchpadPressure),
Focused,
Unfocused,
Closed,
}
impl WindowEvent {
pub fn from_winit_window_event(
event: winit::WindowEvent,
win_w: f64,
win_h: f64,
) -> Option<Self> {
use self::WindowEvent::*;
let tw = |w: f64| w as geom::scalar::Default;
let th = |h: f64| h as geom::scalar::Default;
let tx = |x: f64| (x - win_w / 2.0) as geom::scalar::Default;
let ty = |y: f64| (-(y - win_h / 2.0)) as geom::scalar::Default;
let event = match event {
winit::WindowEvent::Resized(new_size) => {
let (new_w, new_h) = new_size.into();
let x = tw(new_w);
let y = th(new_h);
Resized(Vector2 { x, y })
}
winit::WindowEvent::Moved(new_pos) => {
let (new_x, new_y) = new_pos.into();
let x = tx(new_x);
let y = ty(new_y);
Moved(Point2 { x, y })
}
winit::WindowEvent::CloseRequested | winit::WindowEvent::Destroyed => Closed,
winit::WindowEvent::DroppedFile(path) => DroppedFile(path),
winit::WindowEvent::HoveredFile(path) => HoveredFile(path),
winit::WindowEvent::HoveredFileCancelled => HoveredFileCancelled,
winit::WindowEvent::Focused(b) => {
if b {
Focused
} else {
Unfocused
}
}
winit::WindowEvent::CursorMoved { position, .. } => {
let (x, y) = position.into();
let x = tx(x);
let y = ty(y);
MouseMoved(Point2 { x, y })
}
winit::WindowEvent::CursorEntered { .. } => MouseEntered,
winit::WindowEvent::CursorLeft { .. } => MouseExited,
winit::WindowEvent::MouseWheel { delta, phase, .. } => MouseWheel(delta, phase),
winit::WindowEvent::MouseInput { state, button, .. } => match state {
ElementState::Pressed => MousePressed(button),
ElementState::Released => MouseReleased(button),
},
winit::WindowEvent::Touch(winit::Touch {
phase,
location,
id,
..
}) => {
let (x, y) = location.into();
let x = tx(x);
let y = ty(y);
let position = Point2 { x, y };
let touch = TouchEvent {
phase,
position,
id,
};
WindowEvent::Touch(touch)
}
winit::WindowEvent::TouchpadPressure {
device_id,
pressure,
stage,
} => TouchPressure(TouchpadPressure {
device_id,
pressure,
stage,
}),
winit::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode {
Some(key) => match input.state {
ElementState::Pressed => KeyPressed(key),
ElementState::Released => KeyReleased(key),
},
None => return None,
},
winit::WindowEvent::AxisMotion { .. }
| winit::WindowEvent::Refresh
| winit::WindowEvent::ReceivedCharacter(_)
| winit::WindowEvent::HiDpiFactorChanged(_) => {
return None;
}
};
Some(event)
}
}
impl LoopEvent for Event {
fn from_winit_event(event: winit::Event, app: &App) -> Option<Self> {
let event = match event {
winit::Event::WindowEvent { window_id, event } => {
let windows = app.windows.borrow();
let (win_w, win_h) = match windows.get(&window_id) {
None => (0.0, 0.0), Some(window) => match window.surface.window().get_inner_size() {
None => (0.0, 0.0),
Some(size) => size.into(),
},
};
let raw = event.clone();
let simple = WindowEvent::from_winit_window_event(event, win_w, win_h);
Event::WindowEvent {
id: window_id,
raw,
simple,
}
}
winit::Event::DeviceEvent { device_id, event } => Event::DeviceEvent(device_id, event),
winit::Event::Awakened => Event::Awakened,
winit::Event::Suspended(b) => Event::Suspended(b),
};
Some(event)
}
}
impl From<Update> for Event {
fn from(update: Update) -> Self {
Event::Update(update)
}
}