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
use imgui::{FrameSize, ImGui, Ui};
use std::time::Instant;
use winit::{Event, Window};

/// Translation layer for boilerplate between imgui and winit.
#[derive(Debug, Clone)]
pub struct ImGuiWinit {
    pressed: [bool; 5],
    last_frame: Instant,
}

impl ImGuiWinit {
    pub fn new() -> ImGuiWinit {
        ImGuiWinit {
            pressed: [false; 5],
            last_frame: Instant::now(),
        }
    }

    /// Calls `ImGui::frame` with correct parameters for the window
    /// size and frame delta.
    pub fn frame<'ui>(&mut self, imgui: &'ui mut ImGui, window: &Window) -> Ui<'ui> {
        let now = Instant::now();
        let delta_time = now.duration_since(self.last_frame);
        let delta_s =
            delta_time.as_secs() as f32 + delta_time.subsec_nanos() as f32 / 1_000_000_000.0;
        self.last_frame = now;
        let physical_size = window
            .get_inner_size()
            .unwrap()
            .to_physical(window.get_hidpi_factor());
        let hidpi_factor = window.get_hidpi_factor().round();
        let logical_size = physical_size.to_logical(hidpi_factor);
        let frame_size = FrameSize {
            logical_size: logical_size.into(),
            hidpi_factor,
        };
        imgui.frame(frame_size, delta_s)
    }

    /// Passes events from `winit`'s `EventLoop` to an `ImGui` instance.
    ///
    /// This should be called from within `EventLoop::poll_events`.
    pub fn handle_event(&mut self, imgui: &mut ImGui, event: &Event) {
        use winit::ElementState::Pressed;
        use winit::WindowEvent::*;
        use winit::{Event, MouseButton, MouseScrollDelta, TouchPhase};

        let scale = imgui.display_framebuffer_scale();

        if let Event::WindowEvent { event, .. } = event {
            match event {
                KeyboardInput { input, .. } => {
                    use winit::VirtualKeyCode as Key;

                    let pressed = input.state == Pressed;
                    match input.virtual_keycode {
                        Some(Key::Tab) => imgui.set_key(0, pressed),
                        Some(Key::Left) => imgui.set_key(1, pressed),
                        Some(Key::Right) => imgui.set_key(2, pressed),
                        Some(Key::Up) => imgui.set_key(3, pressed),
                        Some(Key::Down) => imgui.set_key(4, pressed),
                        Some(Key::PageUp) => imgui.set_key(5, pressed),
                        Some(Key::PageDown) => imgui.set_key(6, pressed),
                        Some(Key::Home) => imgui.set_key(7, pressed),
                        Some(Key::End) => imgui.set_key(8, pressed),
                        Some(Key::Delete) => imgui.set_key(9, pressed),
                        Some(Key::Back) => imgui.set_key(10, pressed),
                        Some(Key::Return) => imgui.set_key(11, pressed),
                        Some(Key::Escape) => imgui.set_key(12, pressed),
                        Some(Key::A) => imgui.set_key(13, pressed),
                        Some(Key::C) => imgui.set_key(14, pressed),
                        Some(Key::V) => imgui.set_key(15, pressed),
                        Some(Key::X) => imgui.set_key(16, pressed),
                        Some(Key::Y) => imgui.set_key(17, pressed),
                        Some(Key::Z) => imgui.set_key(18, pressed),
                        Some(Key::LControl) | Some(Key::RControl) => imgui.set_key_ctrl(pressed),
                        Some(Key::LShift) | Some(Key::RShift) => imgui.set_key_shift(pressed),
                        Some(Key::LAlt) | Some(Key::RAlt) => imgui.set_key_alt(pressed),
                        Some(Key::LWin) | Some(Key::RWin) => imgui.set_key_super(pressed),
                        _ => {}
                    }
                }
                CursorMoved { position: pos, .. } => {
                    let (x, y): (f64, f64) = (*pos).into();
                    imgui.set_mouse_pos(x as f32 / scale.0, y as f32 / scale.1);
                }
                MouseInput { state, button, .. } => {
                    match button {
                        MouseButton::Left => self.pressed[0] = *state == Pressed,
                        MouseButton::Right => self.pressed[1] = *state == Pressed,
                        MouseButton::Middle => self.pressed[2] = *state == Pressed,
                        MouseButton::Other(idx) if *idx < 5 => {
                            self.pressed[*idx as usize] = *state == Pressed
                        }
                        _ => (),
                    };
                    imgui.set_mouse_down([
                        self.pressed[0],
                        self.pressed[1],
                        self.pressed[2],
                        self.pressed[3],
                        self.pressed[4],
                    ])
                }
                MouseWheel {
                    delta: MouseScrollDelta::LineDelta(_, y),
                    phase: TouchPhase::Moved,
                    ..
                } => imgui.set_mouse_wheel(y / scale.1),
                MouseWheel {
                    delta: MouseScrollDelta::PixelDelta(pos),
                    phase: TouchPhase::Moved,
                    ..
                } => imgui.set_mouse_wheel(pos.y as f32 / scale.1),
                MouseWheel {
                    phase: TouchPhase::Ended,
                    ..
                } => imgui.set_mouse_wheel(0.0),
                ReceivedCharacter(c) => imgui.add_input_character(*c),
                _ => (),
            }
        }
    }
}