1#![doc = include_str!("../README.md")]
2#![deny(rust_2018_idioms)]
3#![deny(missing_docs)]
4
5use std::time::Instant;
6
7use imgui::{BackendFlags, ConfigFlags, Context, Io, MouseCursor};
8use sdl2::{
9 event::Event,
10 keyboard::{Mod, Scancode},
11 mouse::{Cursor, MouseState, SystemCursor},
12 video::Window,
13 EventPump,
14};
15
16pub struct SdlPlatform {
27 cursor_instance: Option<Cursor>, last_frame: Instant,
29}
30
31impl SdlPlatform {
32 pub fn new(imgui: &mut Context) -> SdlPlatform {
40 let io = imgui.io_mut();
41
42 io.backend_flags.insert(BackendFlags::HAS_MOUSE_CURSORS);
43 io.backend_flags.insert(BackendFlags::HAS_SET_MOUSE_POS);
44
45 imgui.set_platform_name(Some(format!(
46 "imgui-sdl2-support {}",
47 env!("CARGO_PKG_VERSION")
48 )));
49
50 SdlPlatform {
51 cursor_instance: None,
52 last_frame: Instant::now(),
53 }
54 }
55
56 #[deprecated = "use `new` instead"]
60 pub fn init(imgui: &mut Context) -> SdlPlatform {
61 Self::new(imgui)
62 }
63 pub fn handle_event(&mut self, context: &mut Context, event: &Event) -> bool {
70 let io = context.io_mut();
71
72 match *event {
73 Event::MouseWheel { x, y, .. } => {
74 io.add_mouse_wheel_event([x as f32, y as f32]);
75 true
76 }
77
78 Event::MouseButtonDown { mouse_btn, .. } => {
79 self.handle_mouse_button(io, &mouse_btn, true);
80 true
81 }
82
83 Event::MouseButtonUp { mouse_btn, .. } => {
84 self.handle_mouse_button(io, &mouse_btn, false);
85 true
86 }
87
88 Event::TextInput { ref text, .. } => {
89 text.chars().for_each(|c| io.add_input_character(c));
90 true
91 }
92
93 Event::KeyDown {
94 scancode: Some(key),
95 keymod,
96 ..
97 } => {
98 handle_key_modifier(io, &keymod);
99 handle_key(io, &key, true);
100 true
101 }
102
103 Event::KeyUp {
104 scancode: Some(key),
105 keymod,
106 ..
107 } => {
108 handle_key_modifier(io, &keymod);
109 handle_key(io, &key, false);
110 true
111 }
112
113 _ => false,
114 }
115 }
116
117 pub fn prepare_frame(
127 &mut self,
128 context: &mut Context,
129 window: &Window,
130 event_pump: &EventPump,
131 ) {
132 let mouse_cursor = context.mouse_cursor();
133 let io = context.io_mut();
134
135 let now = Instant::now();
137 io.update_delta_time(now.duration_since(self.last_frame));
138 self.last_frame = now;
139
140 let mouse_state = MouseState::new(event_pump);
141 let window_size = window.size();
142 let window_drawable_size = window.drawable_size();
143
144 io.display_size = [window_size.0 as f32, window_size.1 as f32];
148 io.display_framebuffer_scale = [
149 (window_drawable_size.0 as f32) / (window_size.0 as f32),
150 (window_drawable_size.1 as f32) / (window_size.1 as f32),
151 ];
152
153 if io.want_set_mouse_pos {
155 let mouse_util = window.subsystem().sdl().mouse();
156 mouse_util.warp_mouse_in_window(window, io.mouse_pos[0] as i32, io.mouse_pos[1] as i32);
157 }
158
159 io.mouse_pos = [mouse_state.x() as f32, mouse_state.y() as f32];
161
162 if !io
164 .config_flags
165 .contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE)
166 {
167 let mouse_util = window.subsystem().sdl().mouse();
168
169 match mouse_cursor {
170 Some(mouse_cursor) if !io.mouse_draw_cursor => {
171 let cursor = Cursor::from_system(to_sdl_cursor(mouse_cursor)).unwrap();
172 cursor.set();
173
174 mouse_util.show_cursor(true);
175 self.cursor_instance = Some(cursor);
176 }
177
178 _ => {
179 mouse_util.show_cursor(false);
180 self.cursor_instance = None;
181 }
182 }
183 }
184 }
185}
186
187pub fn filter_event(window: &Window, event: &Event) -> bool {
203 Some(window.id()) == event.get_window_id()
204}
205
206impl SdlPlatform {
207 fn handle_mouse_button(
208 &mut self,
209 io: &mut Io,
210 button: &sdl2::mouse::MouseButton,
211 pressed: bool,
212 ) {
213 match button {
214 sdl2::mouse::MouseButton::Left => {
215 io.add_mouse_button_event(imgui::MouseButton::Left, pressed)
216 }
217 sdl2::mouse::MouseButton::Right => {
218 io.add_mouse_button_event(imgui::MouseButton::Right, pressed)
219 }
220 sdl2::mouse::MouseButton::Middle => {
221 io.add_mouse_button_event(imgui::MouseButton::Middle, pressed)
222 }
223 sdl2::mouse::MouseButton::X1 => {
224 io.add_mouse_button_event(imgui::MouseButton::Extra1, pressed)
225 }
226 sdl2::mouse::MouseButton::X2 => {
227 io.add_mouse_button_event(imgui::MouseButton::Extra2, pressed)
228 }
229 _ => {}
230 }
231 }
232}
233
234fn handle_key(io: &mut Io, key: &Scancode, pressed: bool) {
236 let igkey = match key {
237 Scancode::A => imgui::Key::A,
238 Scancode::B => imgui::Key::B,
239 Scancode::C => imgui::Key::C,
240 Scancode::D => imgui::Key::D,
241 Scancode::E => imgui::Key::E,
242 Scancode::F => imgui::Key::F,
243 Scancode::G => imgui::Key::G,
244 Scancode::H => imgui::Key::H,
245 Scancode::I => imgui::Key::I,
246 Scancode::J => imgui::Key::J,
247 Scancode::K => imgui::Key::K,
248 Scancode::L => imgui::Key::L,
249 Scancode::M => imgui::Key::M,
250 Scancode::N => imgui::Key::N,
251 Scancode::O => imgui::Key::O,
252 Scancode::P => imgui::Key::P,
253 Scancode::Q => imgui::Key::Q,
254 Scancode::R => imgui::Key::R,
255 Scancode::S => imgui::Key::S,
256 Scancode::T => imgui::Key::T,
257 Scancode::U => imgui::Key::U,
258 Scancode::V => imgui::Key::V,
259 Scancode::W => imgui::Key::W,
260 Scancode::X => imgui::Key::X,
261 Scancode::Y => imgui::Key::Y,
262 Scancode::Z => imgui::Key::Z,
263 Scancode::Num1 => imgui::Key::Keypad1,
264 Scancode::Num2 => imgui::Key::Keypad2,
265 Scancode::Num3 => imgui::Key::Keypad3,
266 Scancode::Num4 => imgui::Key::Keypad4,
267 Scancode::Num5 => imgui::Key::Keypad5,
268 Scancode::Num6 => imgui::Key::Keypad6,
269 Scancode::Num7 => imgui::Key::Keypad7,
270 Scancode::Num8 => imgui::Key::Keypad8,
271 Scancode::Num9 => imgui::Key::Keypad9,
272 Scancode::Num0 => imgui::Key::Keypad0,
273 Scancode::Return => imgui::Key::Enter, Scancode::Escape => imgui::Key::Escape,
275 Scancode::Backspace => imgui::Key::Backspace,
276 Scancode::Tab => imgui::Key::Tab,
277 Scancode::Space => imgui::Key::Space,
278 Scancode::Minus => imgui::Key::Minus,
279 Scancode::Equals => imgui::Key::Equal,
280 Scancode::LeftBracket => imgui::Key::LeftBracket,
281 Scancode::RightBracket => imgui::Key::RightBracket,
282 Scancode::Backslash => imgui::Key::Backslash,
283 Scancode::Semicolon => imgui::Key::Semicolon,
284 Scancode::Apostrophe => imgui::Key::Apostrophe,
285 Scancode::Grave => imgui::Key::GraveAccent,
286 Scancode::Comma => imgui::Key::Comma,
287 Scancode::Period => imgui::Key::Period,
288 Scancode::Slash => imgui::Key::Slash,
289 Scancode::CapsLock => imgui::Key::CapsLock,
290 Scancode::F1 => imgui::Key::F1,
291 Scancode::F2 => imgui::Key::F2,
292 Scancode::F3 => imgui::Key::F3,
293 Scancode::F4 => imgui::Key::F4,
294 Scancode::F5 => imgui::Key::F5,
295 Scancode::F6 => imgui::Key::F6,
296 Scancode::F7 => imgui::Key::F7,
297 Scancode::F8 => imgui::Key::F8,
298 Scancode::F9 => imgui::Key::F9,
299 Scancode::F10 => imgui::Key::F10,
300 Scancode::F11 => imgui::Key::F11,
301 Scancode::F12 => imgui::Key::F12,
302 Scancode::PrintScreen => imgui::Key::PrintScreen,
303 Scancode::ScrollLock => imgui::Key::ScrollLock,
304 Scancode::Pause => imgui::Key::Pause,
305 Scancode::Insert => imgui::Key::Insert,
306 Scancode::Home => imgui::Key::Home,
307 Scancode::PageUp => imgui::Key::PageUp,
308 Scancode::Delete => imgui::Key::Delete,
309 Scancode::End => imgui::Key::End,
310 Scancode::PageDown => imgui::Key::PageDown,
311 Scancode::Right => imgui::Key::RightArrow,
312 Scancode::Left => imgui::Key::LeftArrow,
313 Scancode::Down => imgui::Key::DownArrow,
314 Scancode::Up => imgui::Key::UpArrow,
315 Scancode::KpDivide => imgui::Key::KeypadDivide,
316 Scancode::KpMultiply => imgui::Key::KeypadMultiply,
317 Scancode::KpMinus => imgui::Key::KeypadSubtract,
318 Scancode::KpPlus => imgui::Key::KeypadAdd,
319 Scancode::KpEnter => imgui::Key::KeypadEnter,
320 Scancode::Kp1 => imgui::Key::Keypad1,
321 Scancode::Kp2 => imgui::Key::Keypad2,
322 Scancode::Kp3 => imgui::Key::Keypad3,
323 Scancode::Kp4 => imgui::Key::Keypad4,
324 Scancode::Kp5 => imgui::Key::Keypad5,
325 Scancode::Kp6 => imgui::Key::Keypad6,
326 Scancode::Kp7 => imgui::Key::Keypad7,
327 Scancode::Kp8 => imgui::Key::Keypad8,
328 Scancode::Kp9 => imgui::Key::Keypad9,
329 Scancode::Kp0 => imgui::Key::Keypad0,
330 Scancode::KpPeriod => imgui::Key::KeypadDecimal,
331 Scancode::Application => imgui::Key::Menu,
332 Scancode::KpEquals => imgui::Key::KeypadEqual,
333 Scancode::Menu => imgui::Key::Menu,
334 Scancode::LCtrl => imgui::Key::LeftCtrl,
335 Scancode::LShift => imgui::Key::LeftShift,
336 Scancode::LAlt => imgui::Key::LeftAlt,
337 Scancode::LGui => imgui::Key::LeftSuper,
338 Scancode::RCtrl => imgui::Key::RightCtrl,
339 Scancode::RShift => imgui::Key::RightShift,
340 Scancode::RAlt => imgui::Key::RightAlt,
341 Scancode::RGui => imgui::Key::RightSuper,
342 _ => {
343 return;
345 }
346 };
347
348 io.add_key_event(igkey, pressed);
349}
350
351fn handle_key_modifier(io: &mut Io, keymod: &Mod) {
353 io.add_key_event(
354 imgui::Key::ModShift,
355 keymod.intersects(Mod::LSHIFTMOD | Mod::RSHIFTMOD),
356 );
357 io.add_key_event(
358 imgui::Key::ModCtrl,
359 keymod.intersects(Mod::LCTRLMOD | Mod::RCTRLMOD),
360 );
361 io.add_key_event(
362 imgui::Key::ModAlt,
363 keymod.intersects(Mod::LALTMOD | Mod::RALTMOD),
364 );
365 io.add_key_event(
366 imgui::Key::ModSuper,
367 keymod.intersects(Mod::LGUIMOD | Mod::RGUIMOD),
368 );
369}
370
371fn to_sdl_cursor(cursor: MouseCursor) -> SystemCursor {
373 match cursor {
374 MouseCursor::Arrow => SystemCursor::Arrow,
375 MouseCursor::TextInput => SystemCursor::IBeam,
376 MouseCursor::ResizeAll => SystemCursor::SizeAll,
377 MouseCursor::ResizeNS => SystemCursor::SizeNS,
378 MouseCursor::ResizeEW => SystemCursor::SizeWE,
379 MouseCursor::ResizeNESW => SystemCursor::SizeNESW,
380 MouseCursor::ResizeNWSE => SystemCursor::SizeNWSE,
381 MouseCursor::Hand => SystemCursor::Hand,
382 MouseCursor::NotAllowed => SystemCursor::No,
383 }
384}