1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use std::error::Error;
use winit::event::{Event, WindowEvent, MouseButton, MouseScrollDelta, ElementState};
use winit::event_loop::EventLoop;
use crate::point::Point;
use crate::context::{InputModifiers, Context};
use crate::render::IO;
/**
A Thyme Input/Output adapter for [`winit`](https://github.com/rust-windowing/winit).
This adapter handles events from `winit` and sends them to the Thyme [`Context`](struct.Context.html).
WindowEvents should be passed to this handler, assuming [`Context.wants_mouse`](struct.Context.html#method.wants_mouse)
returns true for the given frame.
# Example
```
fn main_loop(event_loop: winit::EventLoop<()>, thyme: thyme::Context) {
event_loop.run(move |event, _, control_flow| match event {
Event::MainEventsCleared => {
// Renderer specific code here
let mut ui = context.create_frame();
// create UI here
// draw the frame and finish up rendering here
}
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => *control_flow = ControlFlow::Exit,
event => {
io.handle_event(&mut context, &event);
}
})
}
```
*/
pub struct WinitIo {
scale_factor: f32,
display_size: Point,
}
impl IO for WinitIo {
fn scale_factor(&self) -> f32 { self.scale_factor }
fn display_size(&self) -> Point { self.display_size }
}
impl WinitIo {
/// Creates a new adapter from the given `EventLoop`, with the specified initial display size,
/// in logical pixels. This may change over time.
pub fn new<T>(event_loop: &EventLoop<T>, logical_display_size: Point) -> Result<WinitIo, WinitError> {
let monitor = event_loop.primary_monitor().ok_or(WinitError::PrimaryMonitorNotFound)?;
let scale_factor = monitor.scale_factor() as f32;
Ok(WinitIo {
scale_factor,
display_size: logical_display_size * scale_factor,
})
}
/// Handles a winit `Event` and passes it to the Thyme [`Context`](struct.Context.html).
pub fn handle_event<T>(&mut self, context: &mut Context, event: &Event<T>) {
let event = match event {
Event::WindowEvent { event, .. } => event,
_ => return,
};
use WindowEvent::*;
match event {
Resized(size) => {
let (x, y): (u32, u32) = (*size).into();
let size: Point = (x as f32, y as f32).into();
self.display_size = size;
context.set_display_size(size);
},
ModifiersChanged(m) => {
context.set_input_modifiers(InputModifiers {
shift: m.shift(),
ctrl: m.ctrl(),
alt: m.alt(),
});
},
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
let scale = *scale_factor as f32;
self.scale_factor = scale;
context.set_scale_factor(scale);
},
MouseInput { state, button, .. } => {
let pressed = match state {
ElementState::Pressed => true,
ElementState::Released => false,
};
let index: usize = match button {
MouseButton::Left => 0,
MouseButton::Right => 1,
MouseButton::Middle => 2,
MouseButton::Other(index) => *index as usize + 3,
};
context.set_mouse_pressed(pressed, index);
},
MouseWheel { delta, .. } => {
match delta {
MouseScrollDelta::LineDelta(x, y) => {
// TODO configure line delta
context.add_mouse_wheel(Point::new(*x, *y));
}, MouseScrollDelta::PixelDelta(pos) => {
let x = pos.x as f32;
let y = pos.y as f32;
context.add_mouse_wheel(Point::new(x, y));
}
}
},
CursorMoved { position, .. } => {
context.set_mouse_pos((position.x as f32 / self.scale_factor, position.y as f32 / self.scale_factor).into());
},
ReceivedCharacter(c) => {
context.push_character(*c);
}
_ => (),
}
}
}
#[derive(Debug)]
pub enum WinitError {
PrimaryMonitorNotFound,
Os(winit::error::OsError),
}
impl std::fmt::Display for WinitError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use self::WinitError::*;
match self {
PrimaryMonitorNotFound => write!(f, "Primary monitor not found."),
Os(e) => write!(f, "OS Error: {}", e),
}
}
}
impl Error for WinitError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use self::WinitError::*;
match self {
PrimaryMonitorNotFound => None,
Os(e) => Some(e),
}
}
}