use crate::geom::{self, Point2};
use crate::glam::Vec2;
use crate::window;
use crate::App;
use std::path::PathBuf;
use winit;
pub use winit::event::{
ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
VirtualKeyCode as Key,
};
pub trait LoopEvent: 'static + From<Update> {
fn from_winit_event<'a, T>(_: &winit::event::Event<'a, T>, _: &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(Debug)]
pub enum Event {
WindowEvent {
id: window::Id,
simple: Option<WindowEvent>,
},
DeviceEvent(winit::event::DeviceId, winit::event::DeviceEvent),
Update(Update),
Suspended,
Resumed,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct TouchEvent {
pub id: u64,
pub phase: TouchPhase,
pub position: Point2,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct TouchpadPressure {
pub device_id: winit::event::DeviceId,
pub pressure: f32,
pub stage: i64,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct AxisMotion {
pub device_id: winit::event::DeviceId,
pub axis: winit::event::AxisId,
pub value: geom::scalar::Default,
}
#[derive(Clone, Debug, PartialEq)]
pub enum WindowEvent {
Moved(Point2),
KeyPressed(Key),
KeyReleased(Key),
ReceivedCharacter(char),
MouseMoved(Point2),
MousePressed(MouseButton),
MouseReleased(MouseButton),
MouseEntered,
MouseExited,
MouseWheel(MouseScrollDelta, TouchPhase),
Resized(Vec2),
HoveredFile(PathBuf),
DroppedFile(PathBuf),
HoveredFileCancelled,
Touch(TouchEvent),
TouchPressure(TouchpadPressure),
Focused,
Unfocused,
Closed,
}
impl WindowEvent {
pub fn from_winit_window_event(
event: &winit::event::WindowEvent,
win_w: f64,
win_h: f64,
scale_factor: f64,
) -> Option<Self> {
use self::WindowEvent::*;
let tw = |w: f64| w as f32;
let th = |h: f64| h as f32;
let tx = |x: f64| (x - win_w / 2.0) as f32;
let ty = |y: f64| (-(y - win_h / 2.0)) as f32;
let event = match event {
winit::event::WindowEvent::Resized(new_size) => {
let (new_w, new_h) = new_size.to_logical::<f64>(scale_factor).into();
let x = tw(new_w);
let y = th(new_h);
Resized([x, y].into())
}
winit::event::WindowEvent::Moved(new_pos) => {
let (new_x, new_y) = new_pos.to_logical::<f64>(scale_factor).into();
let x = tx(new_x);
let y = ty(new_y);
Moved([x, y].into())
}
winit::event::WindowEvent::CloseRequested | winit::event::WindowEvent::Destroyed => {
Closed
}
winit::event::WindowEvent::DroppedFile(path) => DroppedFile(path.clone()),
winit::event::WindowEvent::HoveredFile(path) => HoveredFile(path.clone()),
winit::event::WindowEvent::HoveredFileCancelled => HoveredFileCancelled,
winit::event::WindowEvent::Focused(b) => {
if b.clone() {
Focused
} else {
Unfocused
}
}
winit::event::WindowEvent::CursorMoved { position, .. } => {
let (x, y) = position.to_logical::<f64>(scale_factor).into();
let x = tx(x);
let y = ty(y);
MouseMoved([x, y].into())
}
winit::event::WindowEvent::CursorEntered { .. } => MouseEntered,
winit::event::WindowEvent::CursorLeft { .. } => MouseExited,
winit::event::WindowEvent::MouseWheel { delta, phase, .. } => {
MouseWheel(delta.clone(), phase.clone())
}
winit::event::WindowEvent::MouseInput { state, button, .. } => match state {
ElementState::Pressed => MousePressed(button.clone()),
ElementState::Released => MouseReleased(button.clone()),
},
winit::event::WindowEvent::Touch(winit::event::Touch {
phase,
location,
id,
..
}) => {
let (x, y) = location.to_logical::<f64>(scale_factor).into();
let x = tx(x);
let y = ty(y);
let position = [x, y].into();
let touch = TouchEvent {
phase: phase.clone(),
position,
id: id.clone(),
};
WindowEvent::Touch(touch)
}
winit::event::WindowEvent::TouchpadPressure {
device_id,
pressure,
stage,
} => TouchPressure(TouchpadPressure {
device_id: device_id.clone(),
pressure: pressure.clone(),
stage: stage.clone(),
}),
winit::event::WindowEvent::KeyboardInput { input, .. } => match input.virtual_keycode {
Some(key) => match input.state {
ElementState::Pressed => KeyPressed(key),
ElementState::Released => KeyReleased(key),
},
None => return None,
},
winit::event::WindowEvent::ReceivedCharacter(char) => {
WindowEvent::ReceivedCharacter(char.clone())
}
winit::event::WindowEvent::ModifiersChanged(_) => {
return None;
}
winit::event::WindowEvent::AxisMotion { .. }
| winit::event::WindowEvent::ThemeChanged(_)
| winit::event::WindowEvent::ScaleFactorChanged { .. } => {
return None;
}
winit::event::WindowEvent::Ime(_)
| winit::event::WindowEvent::TouchpadMagnify { .. }
| winit::event::WindowEvent::SmartMagnify { .. }
| winit::event::WindowEvent::TouchpadRotate { .. }
| winit::event::WindowEvent::Occluded(_) => return None,
};
Some(event)
}
}
impl LoopEvent for Event {
fn from_winit_event<'a, T>(event: &winit::event::Event<'a, T>, app: &App) -> Option<Self> {
let event = match event {
winit::event::Event::WindowEvent { window_id, event } => {
let windows = app.windows.borrow();
let (win_w, win_h, scale_factor) = match windows.get(&window_id) {
None => (0.0, 0.0, 1.0), Some(window) => {
let sf = window.tracked_state.scale_factor;
let size = window.tracked_state.physical_size;
let (w, h) = size.to_logical::<f64>(sf).into();
(w, h, sf)
}
};
let simple =
WindowEvent::from_winit_window_event(event, win_w, win_h, scale_factor);
Event::WindowEvent {
id: window_id.clone(),
simple,
}
}
winit::event::Event::DeviceEvent { device_id, event } => {
Event::DeviceEvent(device_id.clone(), event.clone())
}
winit::event::Event::Suspended => Event::Suspended,
winit::event::Event::Resumed => Event::Resumed,
winit::event::Event::NewEvents(_)
| winit::event::Event::UserEvent(_)
| winit::event::Event::MainEventsCleared
| winit::event::Event::RedrawRequested(_)
| winit::event::Event::RedrawEventsCleared
| winit::event::Event::LoopDestroyed => return None,
};
Some(event)
}
}
impl From<Update> for Event {
fn from(update: Update) -> Self {
Event::Update(update)
}
}