imgui_sdl2/
lib.rs

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    // Merging the mousedown events we received into the current state prevents us from missing
172    // clicks that happen faster than a frame
173    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}