1use sdl2::Sdl;
2use sdl2::mouse::MouseButton;
3use sdl2::video::Window;
4use sdl2::{pixels::Color, render::Canvas, rect::Rect};
5use sdl2::event::{Event, WindowEvent};
6use sdl2::keyboard::Keycode;
7use sdl2::audio::{AudioCallback, AudioSpecDesired, AudioDevice};
8
9use std::collections::HashMap;
10
11use crate::models::audio::Audio;
12use crate::{
13 models::api::Api,
14 event::{
15 Hotkey,
16 MouseClick,
17 Mouse,
18 Input
19 },
20 properties::{
21 rectangle::Rectangle,
22 color
23 },
24 apis::api::{
25 WINDOW_MAX_H,
26 WINDOW_MAX_W,
27 WINDOW_MIN_H,
28 WINDOW_MIN_W
29 }
30};
31
32struct SquareWave {
33 phase_inc: f32,
34 phase: f32,
35 volume: f32
36}
37
38impl AudioCallback for SquareWave {
39 type Channel = f32;
40
41 fn callback(&mut self, out: &mut [f32]) {
42 for x in out.iter_mut() {
44 *x = if self.phase <= 0.5 {
45 self.volume
46 } else {
47 -self.volume
48 };
49 self.phase = (self.phase + self.phase_inc) % 1.0;
50 }
51 }
52}
53
54pub struct SdlApi {
56 context: Sdl,
58 audio_device: AudioDevice<SquareWave>,
60 canvas: Canvas<Window>,
62 is_open: bool,
64 key_pressed: HashMap<sdl2::keyboard::Keycode, bool>,
66 window_size: (u32, u32)
68}
69
70impl SdlApi {
71 pub fn new(title: String, w: u32, h: u32) -> Self {
72 let context = sdl2::init().unwrap();
73 let video_subsystem = context.video().unwrap();
74
75 let mut window = video_subsystem.window(&title, w, h)
77 .position_centered()
78 .resizable()
79 .build()
80 .unwrap();
81
82 window.set_minimum_size(WINDOW_MIN_W, WINDOW_MIN_H).unwrap();
84 window.set_maximum_size(WINDOW_MAX_W, WINDOW_MAX_H).unwrap();
85
86 let canvas = window
87 .into_canvas()
88 .build()
89 .unwrap();
90
91 let window_size = canvas.window().size();
92 let audio_device = SdlApi::build_audio(&context);
93
94 Self {
95 context,
96 audio_device,
97 canvas,
98 is_open: true,
99 key_pressed: HashMap::new(),
100 window_size
101 }
102 }
103
104 fn build_audio(context: &Sdl) -> AudioDevice<SquareWave> {
106 let audio_subsystem = context.audio().unwrap();
107
108 let desired_spec = AudioSpecDesired {
109 freq: Some(44100),
110 channels: Some(1), samples: None };
113
114 audio_subsystem.open_playback(None, &desired_spec, |spec| {
115 SquareWave {
117 phase_inc: 440.0 / spec.freq as f32,
118 phase: 0.0,
119 volume: 0.25
120 }
121 }).unwrap()
122 }
123}
124
125impl Api for SdlApi {
126 fn clear(&mut self) {
127 self.canvas.clear();
128 }
129
130 fn draw_rect(&mut self, rect: Rectangle, color: color::Color) {
131 let filled = Some(rect.into());
132
133 self.canvas.set_draw_color(color);
134 self.canvas.fill_rect(filled).unwrap();
135 }
136
137 fn is_window_open(&self) -> bool {
138 self.is_open
139 }
140
141 fn display(&mut self) {
142 self.canvas.present();
143 }
144
145 fn events(&mut self) -> Vec<Input> {
146 let mut inputs = Vec::<Input>::new();
147 let mut event_pump = self.context.event_pump().unwrap();
148
149 for event in event_pump.poll_iter() {
151 match event {
152 Event::Quit { .. } => self.is_open = false,
153
154 Event::KeyDown { keycode, .. } => {
156 if keycode.is_some() {
157 self.key_pressed.insert(
158 keycode.unwrap(),
159 true
160 );
161 }
162 },
163
164 Event::KeyUp { keycode, .. } => {
166 if keycode.is_some() {
167 self.key_pressed.insert(
168 keycode.unwrap(),
169 false
170 );
171 }
172 },
173
174 Event::Window { win_event, .. } => {
176 if let WindowEvent::Resized(w, h) = win_event {
177 self.window_size = (w as u32, h as u32);
178 }
179 },
180
181 Event::MouseButtonDown { mouse_btn, x, y, .. } => {
183 let mouse = Mouse::new(mouse_btn, x, y);
184
185 inputs.push(Input::Mouse(mouse));
186 },
187
188 _ => {}
189 }
190 }
191
192 for kp in self.key_pressed.iter() {
194 if *kp.1 == true {
195 let hotkey = Hotkey::from(*kp.0);
196
197 inputs.push(Input::Hotkey(hotkey));
198 }
199 }
200
201 inputs
202 }
203
204 fn window_size(&self) -> (u32, u32) {
205 self.window_size
206 }
207
208}
209
210impl Audio for SdlApi {
211 fn resume_beep(&mut self) {
212 self.audio_device.resume();
213 }
214
215 fn pause_beep(&mut self) {
216 self.audio_device.pause();
217 }
218}
219
220impl From<Rectangle> for Rect {
221 fn from(r: Rectangle) -> Self {
222 Self::new(r.x, r.y, r.w, r.h)
223 }
224}
225
226impl From<color::Color> for Color {
227 fn from(c: color::Color) -> Self {
228 Self {
229 r: c.r,
230 g: c.g,
231 b: c.b,
232 a: c.a,
233 }
234 }
235}
236
237impl From<sdl2::keyboard::Keycode> for Hotkey {
238 fn from(keycode: sdl2::keyboard::Keycode) -> Self {
239 match keycode {
240 Keycode::Backspace => Self::Backspace,
241 Keycode::Tab => Self::Tab,
242 Keycode::Return => Self::Return,
243 Keycode::Escape => Self::Escape,
244 Keycode::Space => Self::Space,
245 Keycode::Exclaim => Self::Exclaim,
246 Keycode::Quotedbl => Self::Quotedbl,
247 Keycode::Hash => Self::Hash,
248 Keycode::Dollar => Self::Dollar,
249 Keycode::Percent => Self::Percent,
250 Keycode::Ampersand => Self::Ampersand,
251 Keycode::Quote => Self::Quote,
252 Keycode::LeftParen => Self::LeftParen,
253 Keycode::RightParen => Self::RightParen,
254 Keycode::Asterisk => Self::Asterisk,
255 Keycode::Plus => Self::Plus,
256 Keycode::Comma => Self::Comma,
257 Keycode::Minus => Self::Minus,
258 Keycode::Period => Self::Period,
259 Keycode::Slash => Self::Slash,
260 Keycode::Num0 => Self::Num0,
261 Keycode::Num1 => Self::Num1,
262 Keycode::Num2 => Self::Num2,
263 Keycode::Num3 => Self::Num3,
264 Keycode::Num4 => Self::Num4,
265 Keycode::Num5 => Self::Num5,
266 Keycode::Num6 => Self::Num6,
267 Keycode::Num7 => Self::Num7,
268 Keycode::Num8 => Self::Num8,
269 Keycode::Num9 => Self::Num9,
270 Keycode::Colon => Self::Colon,
271 Keycode::Semicolon => Self::Semicolon,
272 Keycode::Less => Self::Less,
273 Keycode::Equals => Self::Equals,
274 Keycode::Greater => Self::Greater,
275 Keycode::Question => Self::Question,
276 Keycode::At => Self::At,
277 Keycode::LeftBracket => Self::LeftBracket,
278 Keycode::Backslash => Self::Backslash,
279 Keycode::RightBracket => Self::RightBracket,
280 Keycode::Caret => Self::Caret,
281 Keycode::Underscore => Self::Underscore,
282 Keycode::Backquote => Self::Backquote,
283 Keycode::A => Self::A,
284 Keycode::B => Self::B,
285 Keycode::C => Self::C,
286 Keycode::D => Self::D,
287 Keycode::E => Self::E,
288 Keycode::F => Self::F,
289 Keycode::G => Self::G,
290 Keycode::H => Self::H,
291 Keycode::I => Self::I,
292 Keycode::J => Self::J,
293 Keycode::K => Self::K,
294 Keycode::L => Self::L,
295 Keycode::M => Self::M,
296 Keycode::N => Self::N,
297 Keycode::O => Self::O,
298 Keycode::P => Self::P,
299 Keycode::Q => Self::Q,
300 Keycode::R => Self::R,
301 Keycode::S => Self::S,
302 Keycode::T => Self::T,
303 Keycode::U => Self::U,
304 Keycode::V => Self::V,
305 Keycode::W => Self::W,
306 Keycode::X => Self::X,
307 Keycode::Y => Self::Y,
308 Keycode::Z => Self::Z,
309 Keycode::Delete => Self::Delete,
310 Keycode::CapsLock => Self::CapsLock,
311 Keycode::F1 => Self::F1,
312 Keycode::F2 => Self::F2,
313 Keycode::F3 => Self::F3,
314 Keycode::F4 => Self::F4,
315 Keycode::F5 => Self::F5,
316 Keycode::F6 => Self::F6,
317 Keycode::F7 => Self::F7,
318 Keycode::F8 => Self::F8,
319 Keycode::F9 => Self::F9,
320 Keycode::F10 => Self::F10,
321 Keycode::F11 => Self::F11,
322 Keycode::F12 => Self::F12,
323 Keycode::PrintScreen => Self::PrintScreen,
324 Keycode::ScrollLock => Self::ScrollLock,
325 Keycode::Pause => Self::Pause,
326 Keycode::Insert => Self::Insert,
327 Keycode::Home => Self::Home,
328 Keycode::PageUp => Self::PageUp,
329 Keycode::End => Self::End,
330 Keycode::PageDown => Self::PageDown,
331 Keycode::Right => Self::Right,
332 Keycode::Left => Self::Left,
333 Keycode::Down => Self::Down,
334 Keycode::Up => Self::Up,
335 Keycode::NumLockClear => Self::NumLockClear,
336 Keycode::KpDivide => Self::KpDivide,
337 Keycode::KpMultiply => Self::KpMultiply,
338 Keycode::KpMinus => Self::KpMinus,
339 Keycode::KpPlus => Self::KpPlus,
340 Keycode::KpEnter => Self::KpEnter,
341 Keycode::Kp1 => Self::Kp1,
342 Keycode::Kp2 => Self::Kp2,
343 Keycode::Kp3 => Self::Kp3,
344 Keycode::Kp4 => Self::Kp4,
345 Keycode::Kp5 => Self::Kp5,
346 Keycode::Kp6 => Self::Kp6,
347 Keycode::Kp7 => Self::Kp7,
348 Keycode::Kp8 => Self::Kp8,
349 Keycode::Kp9 => Self::Kp9,
350 Keycode::Kp0 => Self::Kp0,
351 Keycode::KpPeriod => Self::KpPeriod,
352 Keycode::Application => Self::Application,
353 Keycode::Power => Self::Power,
354 Keycode::KpEquals => Self::KpEquals,
355 Keycode::F13 => Self::F13,
356 Keycode::F14 => Self::F14,
357 Keycode::F15 => Self::F15,
358 Keycode::F16 => Self::F16,
359 Keycode::F17 => Self::F17,
360 Keycode::F18 => Self::F18,
361 Keycode::F19 => Self::F19,
362 Keycode::F20 => Self::F20,
363 Keycode::F21 => Self::F21,
364 Keycode::F22 => Self::F22,
365 Keycode::F23 => Self::F23,
366 Keycode::F24 => Self::F24,
367 Keycode::Execute => Self::Execute,
368 Keycode::Help => Self::Help,
369 Keycode::Menu => Self::Menu,
370 Keycode::Select => Self::Select,
371 Keycode::Stop => Self::Stop,
372 Keycode::Again => Self::Again,
373 Keycode::Undo => Self::Undo,
374 Keycode::Cut => Self::Cut,
375 Keycode::Copy => Self::Copy,
376 Keycode::Paste => Self::Paste,
377 Keycode::Find => Self::Find,
378 Keycode::Mute => Self::Mute,
379 Keycode::VolumeUp => Self::VolumeUp,
380 Keycode::VolumeDown => Self::VolumeDown,
381 Keycode::KpComma => Self::KpComma,
382 Keycode::KpEqualsAS400 => Self::KpEqualsAS400,
383 Keycode::AltErase => Self::AltErase,
384 Keycode::Sysreq => Self::Sysreq,
385 Keycode::Cancel => Self::Cancel,
386 Keycode::Clear => Self::Clear,
387 Keycode::Prior => Self::Prior,
388 Keycode::Return2 => Self::Return2,
389 Keycode::Separator => Self::Separator,
390 Keycode::Out => Self::Out,
391 Keycode::Oper => Self::Oper,
392 Keycode::ClearAgain => Self::ClearAgain,
393 Keycode::CrSel => Self::CrSel,
394 Keycode::ExSel => Self::ExSel,
395 Keycode::Kp00 => Self::Kp00,
396 Keycode::Kp000 => Self::Kp000,
397 Keycode::ThousandsSeparator => Self::ThousandsSeparator,
398 Keycode::DecimalSeparator => Self::DecimalSeparator,
399 Keycode::CurrencyUnit => Self::CurrencyUnit,
400 Keycode::CurrencySubUnit => Self::CurrencySubUnit,
401 Keycode::KpLeftParen => Self::KpLeftParen,
402 Keycode::KpRightParen => Self::KpRightParen,
403 Keycode::KpLeftBrace => Self::KpLeftBrace,
404 Keycode::KpRightBrace => Self::KpRightBrace,
405 Keycode::KpTab => Self::KpTab,
406 Keycode::KpBackspace => Self::KpBackspace,
407 Keycode::KpA => Self::KpA,
408 Keycode::KpB => Self::KpB,
409 Keycode::KpC => Self::KpC,
410 Keycode::KpD => Self::KpD,
411 Keycode::KpE => Self::KpE,
412 Keycode::KpF => Self::KpF,
413 Keycode::KpXor => Self::KpXor,
414 Keycode::KpPower => Self::KpPower,
415 Keycode::KpPercent => Self::KpPercent,
416 Keycode::KpLess => Self::KpLess,
417 Keycode::KpGreater => Self::KpGreater,
418 Keycode::KpAmpersand => Self::KpAmpersand,
419 Keycode::KpDblAmpersand => Self::KpDblAmpersand,
420 Keycode::KpVerticalBar => Self::KpVerticalBar,
421 Keycode::KpDblVerticalBar => Self::KpDblVerticalBar,
422 Keycode::KpColon => Self::KpColon,
423 Keycode::KpHash => Self::KpHash,
424 Keycode::KpSpace => Self::KpSpace,
425 Keycode::KpAt => Self::KpAt,
426 Keycode::KpExclam => Self::KpExclam,
427 Keycode::KpMemStore => Self::KpMemStore,
428 Keycode::KpMemRecall => Self::KpMemRecall,
429 Keycode::KpMemClear => Self::KpMemClear,
430 Keycode::KpMemAdd => Self::KpMemAdd,
431 Keycode::KpMemSubtract => Self::KpMemSubtract,
432 Keycode::KpMemMultiply => Self::KpMemMultiply,
433 Keycode::KpMemDivide => Self::KpMemDivide,
434 Keycode::KpPlusMinus => Self::KpPlusMinus,
435 Keycode::KpClear => Self::KpClear,
436 Keycode::KpClearEntry => Self::KpClearEntry,
437 Keycode::KpBinary => Self::KpBinary,
438 Keycode::KpOctal => Self::KpOctal,
439 Keycode::KpDecimal => Self::KpDecimal,
440 Keycode::KpHexadecimal => Self::KpHexadecimal,
441 Keycode::LCtrl => Self::LCtrl,
442 Keycode::LShift => Self::LShift,
443 Keycode::LAlt => Self::LAlt,
444 Keycode::LGui => Self::LGui,
445 Keycode::RCtrl => Self::RCtrl,
446 Keycode::RShift => Self::RShift,
447 Keycode::RAlt => Self::RAlt,
448 Keycode::RGui => Self::RGui,
449 Keycode::Mode => Self::Mode,
450 Keycode::AudioNext => Self::AudioNext,
451 Keycode::AudioPrev => Self::AudioPrev,
452 Keycode::AudioStop => Self::AudioStop,
453 Keycode::AudioPlay => Self::AudioPlay,
454 Keycode::AudioMute => Self::AudioMute,
455 Keycode::MediaSelect => Self::MediaSelect,
456 Keycode::Www => Self::Www,
457 Keycode::Mail => Self::Mail,
458 Keycode::Calculator => Self::Calculator,
459 Keycode::Computer => Self::Computer,
460 Keycode::AcSearch => Self::AcSearch,
461 Keycode::AcHome => Self::AcHome,
462 Keycode::AcBack => Self::AcBack,
463 Keycode::AcForward => Self::AcForward,
464 Keycode::AcStop => Self::AcStop,
465 Keycode::AcRefresh => Self::AcRefresh,
466 Keycode::BrightnessDown => Self::BrightnessDown,
467 Keycode::BrightnessUp => Self::BrightnessUp,
468 Keycode::DisplaySwitch => Self::DisplaySwitch,
469 Keycode::KbdIllumToggle => Self::KbdIllumToggle,
470 Keycode::KbdIllumDown => Self::KbdIllumDown,
471 Keycode::KbdIllumUp => Self::KbdIllumUp,
472 Keycode::Eject => Self::Eject,
473 Keycode::Sleep => Self::Sleep,
474 Keycode::AcBookmarks => Self::AcBookmarks,
475 }
476 }
477}
478
479impl From<MouseButton> for MouseClick {
480 fn from(button: MouseButton) -> Self {
481 match button {
482 MouseButton::Unknown => Self::Unknown,
483 MouseButton::Left => Self::Left,
484 MouseButton::Middle => Self::Middle,
485 MouseButton::Right => Self::Right,
486 MouseButton::X1 => Self::Unknown,
487 MouseButton::X2 => Self::Unknown,
488 }
489 }
490}