1extern crate sdl2;
2extern crate imgui;
3
4use sdl2::video::Window;
5use sdl2::mouse::{Cursor,SystemCursor,MouseState};
6use sdl2::keyboard::Scancode;
7use imgui::{Context,MouseCursor,Key,ConfigFlags};
8
9use sdl2::event::Event;
10
11pub struct ImguiSdl2 {
12 mouse_press: [bool; 5],
13 ignore_mouse: bool,
14 ignore_keyboard: bool,
15 cursor: Option<MouseCursor>,
16 sdl_cursor: Option<Cursor>,
17}
18
19struct Sdl2ClipboardBackend(sdl2::clipboard::ClipboardUtil);
20
21impl imgui::ClipboardBackend for Sdl2ClipboardBackend {
22 fn get(&mut self) -> Option<String> {
23 if !self.0.has_clipboard_text() { return None; }
24
25 self.0.clipboard_text().ok().map(String::from)
26 }
27
28 fn set(&mut self, value: &str) {
29 let _ = self.0.set_clipboard_text(value);
30 }
31}
32
33impl ImguiSdl2 {
34 pub fn new(
35 imgui: &mut Context,
36 window: &Window,
37 ) -> Self {
38 let clipboard_util = window.subsystem().clipboard();
39 imgui.set_clipboard_backend(Sdl2ClipboardBackend(clipboard_util));
40
41 imgui.io_mut().key_map[Key::Tab as usize] = Scancode::Tab as u32;
42 imgui.io_mut().key_map[Key::LeftArrow as usize] = Scancode::Left as u32;
43 imgui.io_mut().key_map[Key::RightArrow as usize] = Scancode::Right as u32;
44 imgui.io_mut().key_map[Key::UpArrow as usize] = Scancode::Up as u32;
45 imgui.io_mut().key_map[Key::DownArrow as usize] = Scancode::Down as u32;
46 imgui.io_mut().key_map[Key::PageUp as usize] = Scancode::PageUp as u32;
47 imgui.io_mut().key_map[Key::PageDown as usize] = Scancode::PageDown as u32;
48 imgui.io_mut().key_map[Key::Home as usize] = Scancode::Home as u32;
49 imgui.io_mut().key_map[Key::End as usize] = Scancode::End as u32;
50 imgui.io_mut().key_map[Key::Delete as usize] = Scancode::Delete as u32;
51 imgui.io_mut().key_map[Key::Backspace as usize] = Scancode::Backspace as u32;
52 imgui.io_mut().key_map[Key::Enter as usize] = Scancode::Return as u32;
53 imgui.io_mut().key_map[Key::Escape as usize] = Scancode::Escape as u32;
54 imgui.io_mut().key_map[Key::Space as usize] = Scancode::Space as u32;
55 imgui.io_mut().key_map[Key::A as usize] = Scancode::A as u32;
56 imgui.io_mut().key_map[Key::C as usize] = Scancode::C as u32;
57 imgui.io_mut().key_map[Key::V as usize] = Scancode::V as u32;
58 imgui.io_mut().key_map[Key::X as usize] = Scancode::X as u32;
59 imgui.io_mut().key_map[Key::Y as usize] = Scancode::Y as u32;
60 imgui.io_mut().key_map[Key::Z as usize] = Scancode::Z as u32;
61
62 Self {
63 mouse_press: [false; 5],
64 ignore_keyboard: false,
65 ignore_mouse: false,
66 cursor: None,
67 sdl_cursor: None,
68 }
69 }
70
71 pub fn ignore_event(
72 &self,
73 event: &Event,
74 ) -> bool {
75 match *event {
76 Event::KeyDown{..}
77 | Event::KeyUp{..}
78 | Event::TextEditing{..}
79 | Event::TextInput{..}
80 => self.ignore_keyboard,
81 Event::MouseMotion{..}
82 | Event::MouseButtonDown{..}
83 | Event::MouseButtonUp{..}
84 | Event::MouseWheel{..}
85 | Event::FingerDown{..}
86 | Event::FingerUp{..}
87 | Event::FingerMotion{..}
88 | Event::DollarGesture{..}
89 | Event::DollarRecord{..}
90 | Event::MultiGesture{..}
91 => self.ignore_mouse,
92 _ => false,
93 }
94 }
95
96 pub fn handle_event(
97 &mut self,
98 imgui: &mut Context,
99 event: &Event,
100 ) {
101 use sdl2::mouse::MouseButton;
102 use sdl2::keyboard;
103
104 fn set_mod(imgui: &mut Context, keymod: keyboard::Mod) {
105 let ctrl = keymod.intersects(keyboard::Mod::RCTRLMOD | keyboard::Mod::LCTRLMOD);
106 let alt = keymod.intersects(keyboard::Mod::RALTMOD | keyboard::Mod::LALTMOD);
107 let shift = keymod.intersects(keyboard::Mod::RSHIFTMOD | keyboard::Mod::LSHIFTMOD);
108 let super_ = keymod.intersects(keyboard::Mod::RGUIMOD | keyboard::Mod::LGUIMOD);
109
110 imgui.io_mut().key_ctrl = ctrl;
111 imgui.io_mut().key_alt = alt;
112 imgui.io_mut().key_shift = shift;
113 imgui.io_mut().key_super = super_;
114 }
115
116 match *event {
117 Event::MouseWheel{y, ..} => {
118 imgui.io_mut().mouse_wheel = y as f32;
119 },
120 Event::MouseButtonDown{mouse_btn, ..} => {
121 if mouse_btn != MouseButton::Unknown {
122 let index = match mouse_btn {
123 MouseButton::Left => 0,
124 MouseButton::Right => 1,
125 MouseButton::Middle => 2,
126 MouseButton::X1 => 3,
127 MouseButton::X2 => 4,
128 MouseButton::Unknown => unreachable!(),
129 };
130 self.mouse_press[index] = true;
131 }
132 },
133 Event::TextInput{ref text, .. } => {
134 for chr in text.chars() {
135 imgui.io_mut().add_input_character(chr);
136 }
137 },
138 Event::KeyDown{scancode, keymod, .. } => {
139 set_mod(imgui, keymod);
140 if let Some(scancode) = scancode {
141 imgui.io_mut().keys_down[scancode as usize] = true;
142 }
143 },
144 Event::KeyUp{scancode, keymod, .. } => {
145 set_mod(imgui, keymod);
146 if let Some(scancode) = scancode {
147 imgui.io_mut().keys_down[scancode as usize] = false;
148 }
149 },
150 _ => {},
151 }
152 }
153
154 pub fn prepare_frame(
155 &mut self,
156 io: &mut imgui::Io,
157 window: &Window,
158 mouse_state: &MouseState,
159 ) {
160 let mouse_util = window.subsystem().sdl().mouse();
161
162 let (win_w, win_h) = window.size();
163 let (draw_w, draw_h) = window.drawable_size();
164
165 io.display_size = [win_w as f32, win_h as f32];
166 io.display_framebuffer_scale = [
167 (draw_w as f32) / (win_w as f32),
168 (draw_h as f32) / (win_h as f32),
169 ];
170
171 io.mouse_down = [
174 self.mouse_press[0] || mouse_state.left(),
175 self.mouse_press[1] || mouse_state.right(),
176 self.mouse_press[2] || mouse_state.middle(),
177 self.mouse_press[3] || mouse_state.x1(),
178 self.mouse_press[4] || mouse_state.x2(),
179 ];
180 self.mouse_press = [false; 5];
181
182 let any_mouse_down = io.mouse_down.iter().any(|&b| b);
183 mouse_util.capture(any_mouse_down);
184
185 io.mouse_pos = [mouse_state.x() as f32, mouse_state.y() as f32];
186
187 self.ignore_keyboard = io.want_capture_keyboard;
188 self.ignore_mouse = io.want_capture_mouse;
189 }
190
191 pub fn prepare_render(
192 &mut self,
193 ui: &imgui::Ui,
194 window: &Window,
195 ) {
196 let io = ui.io();
197 if !io.config_flags.contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE) {
198 let mouse_util = window.subsystem().sdl().mouse();
199
200 match ui.mouse_cursor() {
201 Some(mouse_cursor) if !io.mouse_draw_cursor => {
202 mouse_util.show_cursor(true);
203
204 let sdl_cursor = match mouse_cursor {
205 MouseCursor::Arrow => SystemCursor::Arrow,
206 MouseCursor::TextInput => SystemCursor::IBeam,
207 MouseCursor::ResizeAll => SystemCursor::SizeAll,
208 MouseCursor::ResizeNS => SystemCursor::SizeNS,
209 MouseCursor::ResizeEW => SystemCursor::SizeWE,
210 MouseCursor::ResizeNESW => SystemCursor::SizeNESW,
211 MouseCursor::ResizeNWSE => SystemCursor::SizeNWSE,
212 MouseCursor::Hand => SystemCursor::Hand,
213 MouseCursor::NotAllowed => SystemCursor::No,
214 };
215
216 if self.cursor != Some(mouse_cursor) {
217 let sdl_cursor = Cursor::from_system(sdl_cursor).unwrap();
218 sdl_cursor.set();
219 self.cursor = Some(mouse_cursor);
220 self.sdl_cursor = Some(sdl_cursor);
221 }
222 }
223 _ => {
224 self.cursor = None;
225 self.sdl_cursor = None;
226 mouse_util.show_cursor(false);
227 }
228 }
229 }
230 }
231}