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
use imgui::{FrameSize, ImGui, ImGuiKey, 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(imgui: &mut ImGui) -> ImGuiWinit {
        use winit::VirtualKeyCode as Key;
        imgui.set_imgui_key(ImGuiKey::Tab, Key::Tab as u8);
        imgui.set_imgui_key(ImGuiKey::LeftArrow, Key::Left as u8);
        imgui.set_imgui_key(ImGuiKey::RightArrow, Key::Right as u8);
        imgui.set_imgui_key(ImGuiKey::UpArrow, Key::Up as u8);
        imgui.set_imgui_key(ImGuiKey::DownArrow, Key::Down as u8);
        imgui.set_imgui_key(ImGuiKey::PageUp, Key::PageUp as u8);
        imgui.set_imgui_key(ImGuiKey::PageDown, Key::PageDown as u8);
        imgui.set_imgui_key(ImGuiKey::Home, Key::Home as u8);
        imgui.set_imgui_key(ImGuiKey::End, Key::End as u8);
        imgui.set_imgui_key(ImGuiKey::Delete, Key::Delete as u8);
        imgui.set_imgui_key(ImGuiKey::Backspace, Key::Back as u8);
        imgui.set_imgui_key(ImGuiKey::Enter, Key::Return as u8);
        imgui.set_imgui_key(ImGuiKey::Escape, Key::Escape as u8);
        imgui.set_imgui_key(ImGuiKey::A, Key::A as u8);
        imgui.set_imgui_key(ImGuiKey::C, Key::C as u8);
        imgui.set_imgui_key(ImGuiKey::V, Key::V as u8);
        imgui.set_imgui_key(ImGuiKey::X, Key::X as u8);
        imgui.set_imgui_key(ImGuiKey::Y, Key::Y as u8);
        imgui.set_imgui_key(ImGuiKey::Z, Key::Z as u8);

        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;
                    if let Some(key) = input.virtual_keycode {
                        imgui.set_key(key as u8, pressed);
                    }
                    match input.virtual_keycode {
                        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),
                _ => (),
            }
        }
    }
}