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
use winit::event::{Event, WindowEvent, MouseButton, MouseScrollDelta, ElementState};
use winit::event_loop::EventLoop;

use crate::point::Point;
use crate::context::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) -> WinitIo {
        let monitor = event_loop.primary_monitor();
        let scale_factor = monitor.scale_factor() as f32;
        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);
            },
            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 * 10.0, *y * 10.0));
                    }, 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);
            }
            _ => (),
        }
    }
}