1#[macro_use]
2extern crate glium;
3
4#[allow(unused_imports)]
5use glium::{glutin, Surface};
6use glium::glutin::dpi::LogicalSize;
7use glium::glutin::event::VirtualKeyCode;
8use glium::draw_parameters::Blend;
9use glium::glutin::event::Event::RedrawEventsCleared;
10use glium::glutin::event_loop::ControlFlow;
11
12use std::time::Duration;
13use std::time::Instant;
14use std::hash::Hasher;
15use std::hash::Hash;
16use std::collections::hash_map::DefaultHasher;
17
18pub struct UIBlueprint {
21 pub title: String,
22 pub dimensions: (u32, u32),
23 pub resizeable: bool,
24 pub maximized: bool,
25 pub preserve_aspect_ratio: bool,
26 pub frames_per_second: u32,
27}
28
29impl UIBlueprint {
30 pub fn default() -> UIBlueprint {
31 UIBlueprint {
32 title: "".to_string(),
33 dimensions: (800, 800),
34 resizeable: true,
35 maximized: false,
36 preserve_aspect_ratio: true,
37 frames_per_second: 60,
38 }
39 }
40
41 pub fn title(self, title: &str) -> UIBlueprint {
42 UIBlueprint { title: title.to_string(), ..self }
43 }
44
45 pub fn dimensions(self, dimensions: (u32, u32)) -> UIBlueprint {
46 UIBlueprint { dimensions, ..self }
47 }
48
49 pub fn resizeable(self, resizeable: bool) -> UIBlueprint {
50 UIBlueprint { resizeable, ..self }
51 }
52
53 pub fn maximized(self, maximized: bool) -> UIBlueprint {
54 UIBlueprint { maximized, ..self }
55 }
56
57 pub fn preserve_aspect_ratio(self, preserve_aspect_ratio: bool) -> UIBlueprint {
58 UIBlueprint { preserve_aspect_ratio, ..self }
59 }
60
61 pub fn frames_per_second(self, frames_per_second: u32) -> UIBlueprint {
62 UIBlueprint { frames_per_second, ..self }
63 }
64}
65
66pub trait UIController {
67 fn blueprint(&self) -> UIBlueprint;
70
71 fn next_frame(&mut self) -> Option<RgbaImageRegion>;
75
76 fn process_events(&mut self, events: &Vec<UIEvent>);
79}
80
81const VERTEX_SHADER_SRC: &str = r#"
82 #version 150
83
84 in vec2 dest;
85 in vec2 src;
86 out vec2 v_src;
87
88
89 void main() {
90 v_src = src;
91 gl_Position = vec4(dest, 0.0, 1.0);
92 }
93"#;
94
95const FRAGMENT_SHADER_SRC: &str = r#"
96 #version 150
97
98 in vec2 v_src;
99 out vec4 color;
100
101 uniform sampler2D sampler;
102
103 void main() {
104 color = texture(sampler, v_src);
105 }
106"#;
107
108
109pub struct RgbaImage {
111 width: u32,
112 height: u32,
113 bytes: Vec<u8>,
114}
115
116pub struct RgbaImageRegion<'a> {
118 width: u32,
119 height: u32,
120 bytes: &'a[u8],
121}
122
123impl<'a> RgbaImageRegion<'a> {
124 pub fn width(&self) -> u32 {
125 self.width
126 }
127
128 pub fn height(&self) -> u32 {
129 self.height
130 }
131
132 pub fn get_pixel(&self, x: u32, y: u32) -> Option<RgbaPixel> {
134 let index = (((self.width * y) + x) * 4) as usize;
135
136 if index >= self.bytes.len() {
137 return None;
138 }
139
140 Some((
141 self.bytes[index + 0],
142 self.bytes[index + 1],
143 self.bytes[index + 2],
144 self.bytes[index + 3],
145 ))
146 }
147
148}
149
150pub type RgbaPixel = (u8,u8,u8,u8);
151
152const WHITE: RgbaPixel = (255, 255, 255, 255);
153
154fn de_alpha(pixel: &RgbaPixel, background: &RgbaPixel) -> RgbaPixel {
156 let a = pixel.3 as f32 / 255.0;
157 let r = pixel.0 as f32;
158 let g = pixel.1 as f32;
159 let b = pixel.2 as f32;
160
161 let bg_r = background.0 as f32;
162 let bg_g = background.1 as f32;
163 let bg_b = background.2 as f32;
164
165 let r = ((1.0 - a) * bg_r + a * r).round() as u8;
166 let g = ((1.0 - a) * bg_g + a * g).round() as u8;
167 let b = ((1.0 - a) * bg_b + a * b).round() as u8;
168 (r,g,b,255)
169}
170
171#[test]
172fn _de_alpha() {
173 let rgba = (14, 18, 201, 128);
174 let after_de_alpha = de_alpha(&rgba, &WHITE);
175 assert_eq!(after_de_alpha, (134, 136, 228, 255));
176}
177
178impl RgbaImage {
179 pub fn new(w: u32, h: u32) -> RgbaImage {
181 RgbaImage {
182 width: w,
183 height: h,
184 bytes: vec![0; (w as usize * h as usize) * 4],
185 }
186 }
187
188 pub fn width(&self) -> u32 {
189 self.width
190 }
191
192 pub fn height(&self) -> u32 {
193 self.height
194 }
195
196 pub fn set_pixel(&mut self, x: u32, y: u32, pixel: RgbaPixel) -> bool {
198 if x >= self.width { return false; }
199 if y >= self.height { return false; }
200
201 let index = (((self.width * y) + x) * 4) as usize;
202
203 self.bytes[index + 0] = pixel.0;
204 self.bytes[index + 1] = pixel.1;
205 self.bytes[index + 2] = pixel.2;
206 self.bytes[index + 3] = pixel.3;
207
208 true
209 }
210
211 pub fn get_pixel(&self, x: u32, y: u32) -> Option<RgbaPixel> {
213 let index = (((self.width * y) + x) * 4) as usize;
214
215 if index >= self.bytes.len() {
216 return None;
217 }
218
219 Some((
220 self.bytes[index + 0],
221 self.bytes[index + 1],
222 self.bytes[index + 2],
223 self.bytes[index + 3],
224 ))
225 }
226
227 pub fn draw(&mut self, img: &RgbaImage, x: i32, y: i32) {
230 for img_y in 0..img.height {
231 for img_x in 0..img.width {
232 let pixel = img.get_pixel(img_x, img_y).unwrap();
233
234 let canvas_x = x + img_x as i32;
235 let canvas_y = y + img_y as i32;
236
237 if canvas_x >= 0 && canvas_y >= 0 {
238 let target_pixel = match self.get_pixel(canvas_x as u32, canvas_y as u32) {
239 Some(pixel) => pixel,
240 None => { continue }
241 };
242
243 let target_pixel = de_alpha(&target_pixel, &WHITE);
245 let pixel = de_alpha(&pixel, &target_pixel);
246 self.set_pixel(canvas_x as u32, canvas_y as u32, pixel);
247 }
248 }
249 }
250 }
251
252 pub fn fill(&mut self, color: RgbaPixel) {
254 for y in 0..self.height {
255 for x in 0..self.width {
256 self.set_pixel(x, y, color);
257 }
258 }
259 }
260
261 pub fn nearest_neighbor_scale(img: &RgbaImage, factor: f32) -> RgbaImage {
263 let mut new_img = RgbaImage::new(
264 (img.width as f32 * factor) as u32,
265 (img.height as f32 * factor) as u32,
266 );
267
268 let ratio_x = 1.0 / new_img.width as f32;
270 let ratio_y = 1.0 / new_img.height as f32;
271
272 for y in 0..new_img.height {
273 for x in 0..new_img.width {
274
275 let progress_x = ratio_x * x as f32;
277 let progress_y = ratio_y * y as f32;
278
279 let src_x = progress_x * img.width as f32;
280 let src_y = progress_y * img.height as f32;
281
282 let pixel = img.get_pixel(src_x as u32, src_y as u32).unwrap();
284 new_img.set_pixel(x, y, pixel);
285 }
286 }
287
288 new_img
289 }
290
291
292 pub fn as_region(&self) -> RgbaImageRegion {
293 self.get_region(
294 (0, 0),
295 (self.width() - 1, self.height() - 1),
296 ).unwrap()
297 }
298
299 pub fn get_region(&self, top_left: (u32, u32), bottom_right: (u32, u32)) -> Option<RgbaImageRegion> {
300 let (start_x, start_y) = top_left;
301 let start_index = (((self.width * start_y) + start_x) * 4) as usize;
302
303 let (end_x, end_y) = bottom_right;
304 let end_index = (((self.width * end_y) + end_x) * 4) as usize + 3;
305
306 if end_x < start_x { return None; }
307 if end_y < start_y { return None; }
308
309 if start_index >= self.bytes.len() { return None; }
310 if end_index > self.bytes.len() { return None; }
311
312 let width = 1 + end_x - start_x;
313 let height = 1 + end_y - start_y;
314 let bytes = &self.bytes[start_index..end_index+1];
315
316 Some(RgbaImageRegion {
317 width,
318 height,
319 bytes,
320 })
321 }
322}
323
324#[derive(Copy, Clone, Debug)]
325struct Vertex {
326 src: [f32; 2],
329 dest: [f32; 2],
333}
334
335fn calculate_vertices(size: &LogicalSize<f32>, pixels: &RgbaImageRegion) -> Vec<Vertex> {
336 let ui_h = size.height;
337 let ui_w = size.width;
338
339 let scalar = {
342 if ui_w > ui_h { ui_h / pixels.height as f32 }
343 else { ui_w / pixels.width as f32 }
344 };
345
346 let img_w = pixels.width as f32 * scalar;
348 let img_h = pixels.height as f32 * scalar;
349
350 let mag_x = img_w / ui_w;
353 let mag_y = img_h / ui_h;
354
355 vec![
356 Vertex { dest: [-mag_x, -mag_y ], src: [0.0, 0.0] },
357 Vertex { dest: [ mag_x, -mag_y ], src: [1.0, 0.0] },
358 Vertex { dest: [ mag_x, mag_y ], src: [1.0, 1.0] },
359 Vertex { dest: [-mag_x, mag_y ], src: [0.0, 1.0] },
360 ]
361}
362
363pub struct UI;
367
368impl UI {
369 pub fn launch<T: 'static + UIController>(mut controller: T) {
371 implement_vertex!(Vertex, dest, src);
372
373 let blueprint = controller.blueprint();
374 let event_loop = glutin::event_loop::EventLoop::new();
375
376 let (width, height) = blueprint.dimensions;
377 let mut size = LogicalSize::new(width as f32, height as f32);
378 let preserve_aspect_ratio = blueprint.preserve_aspect_ratio;
379
380 let wb = glutin::window::WindowBuilder::new()
381 .with_title(blueprint.title)
382 .with_inner_size(size)
383 .with_maximized(blueprint.maximized)
384 .with_resizable(blueprint.resizeable);
385
386 let cb = glutin::ContextBuilder::new();
387 let display = glium::Display::new(wb, cb, &event_loop).unwrap();
388
389 let indices: [u16; 6] = [0,1,2,2,3,0];
390 let indices = glium::IndexBuffer::new(
391 &display,
392 glium::index::PrimitiveType::TrianglesList,
393 &indices
394 ).unwrap();
395
396 let program = glium::Program::from_source(
397 &display,
398 VERTEX_SHADER_SRC,
399 FRAGMENT_SHADER_SRC,
400 None
401 ).unwrap();
402
403 let shape = vec![
404 Vertex { dest: [-1.0, -1.0 ], src: [0.0, 0.0] },
405 Vertex { dest: [ 1.0, -1.0 ], src: [1.0, 0.0] },
406 Vertex { dest: [ 1.0, 1.0 ], src: [1.0, 1.0] },
407 Vertex { dest: [-1.0, 1.0 ], src: [0.0, 1.0] },
408 ];
409
410 let mut vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
411
412 let draw_params = glium::DrawParameters {
416 blend: Blend::alpha_blending(),
417 .. Default::default()
418 };
419
420 let fps = blueprint.frames_per_second;
422 let refresh_interval = Duration::from_nanos(1_000_000_000 / fps as u64);
423
424 let mut ui_events = vec![];
425
426 event_loop.run(move |event, _, control_flow| {
427 let ready_for_redraw = event == RedrawEventsCleared;
428
429 if ready_for_redraw {
430 let pixels = match controller.next_frame() {
431 None => return *control_flow = glutin::event_loop::ControlFlow::Exit,
432 Some(pixels) => pixels,
433 };
434
435 let image = glium::texture::RawImage2d::from_raw_rgba_reversed(
436 pixels.bytes,
437 (pixels.width, pixels.height),
438 );
439
440 if preserve_aspect_ratio {
443 let shape = calculate_vertices(&size, &pixels);
444 vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
445 }
446
447 let texture = glium::texture::Texture2d::new(&display, image).unwrap();
448
449 let uniforms = uniform! {
450 sampler: texture.sampled()
452 .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
453 .minify_filter(glium::uniforms::MinifySamplerFilter::Nearest)
454 };
455
456 let mut frame = display.draw();
457
458 frame.clear_color(0.0,0.0,0.0,255.0);
460
461 frame.draw(&vertex_buffer, &indices, &program, &uniforms,
463 &draw_params).unwrap();
464
465 frame.finish().unwrap();
467
468 let next_frame_time = Instant::now() + refresh_interval;
470 *control_flow = ControlFlow::WaitUntil(next_frame_time);
471
472 controller.process_events(&ui_events);
475 ui_events = vec![];
476 }
477
478 match event {
480 glutin::event::Event::WindowEvent { event, .. } => match event {
481 glutin::event::WindowEvent::CloseRequested => {
482 *control_flow = glutin::event_loop::ControlFlow::Exit;
483 return;
484 },
485 glutin::event::WindowEvent::KeyboardInput { device_id, input, .. } => {
486 apply_keyboard_event(&device_id, &input, &mut ui_events);
487 },
488 glutin::event::WindowEvent::MouseInput { device_id, state, button, .. } => {
489 apply_mouse_button_event(&device_id, &state, &button, &mut ui_events);
490 },
491 glutin::event::WindowEvent::Resized(phys_size) => {
492 size = phys_size.to_logical(1.0);
493 apply_resize_event(&size, &mut ui_events);
494 },
495 glutin::event::WindowEvent::CursorMoved { device_id, position, .. } => {
496 apply_cursor_movement_event(&device_id, &position, &mut ui_events);
497 },
498 _ => return,
499 },
500 _ => {}
501 }
502
503
504
505 });
506
507 }
508}
509
510fn hash<T: Hash>(value: T) -> u64 {
511 let mut hasher = DefaultHasher::new();
512 value.hash(&mut hasher);
513 hasher.finish()
514}
515
516fn apply_resize_event(
517 size: &glutin::dpi::LogicalSize<f32>,
518 ui_events: &mut Vec<UIEvent>,
519) {
520 ui_events.push(UIEvent::Resize(ResizeEvent {
521 width: size.width as u32,
522 height: size.height as u32,
523 }));
524}
525
526
527fn apply_cursor_movement_event(
528 device_id: &glutin::event::DeviceId,
529 position: &glutin::dpi::PhysicalPosition<f64>,
530 ui_events: &mut Vec<UIEvent>,
531) {
532 let position = position.to_logical::<f32>(1.0);
533
534 ui_events.push(UIEvent::CursorMovement(CursorMovementEvent {
535 device_id: hash(device_id),
536 x: position.x as u32,
537 y: position.y as u32,
538 }));
539}
540
541
542fn apply_keyboard_event(
543 device_id: &glutin::event::DeviceId,
544 input: &glutin::event::KeyboardInput,
545 ui_events: &mut Vec<UIEvent>
546) {
547 let device_id = hash(device_id);
548
549 let action = match input.state {
550 glutin::event::ElementState::Pressed => KeyboardAction::Press,
551 glutin::event::ElementState::Released => KeyboardAction::Release,
552 };
553
554 let key = match input.virtual_keycode {
555 Some(VirtualKeyCode::Key0) => KeyboardKey::Num0,
556 Some(VirtualKeyCode::Key1) => KeyboardKey::Num1,
557 Some(VirtualKeyCode::Key2) => KeyboardKey::Num2,
558 Some(VirtualKeyCode::Key3) => KeyboardKey::Num3,
559 Some(VirtualKeyCode::Key4) => KeyboardKey::Num4,
560 Some(VirtualKeyCode::Key5) => KeyboardKey::Num5,
561 Some(VirtualKeyCode::Key6) => KeyboardKey::Num6,
562 Some(VirtualKeyCode::Key7) => KeyboardKey::Num7,
563 Some(VirtualKeyCode::Key8) => KeyboardKey::Num8,
564 Some(VirtualKeyCode::Key9) => KeyboardKey::Num9,
565 Some(VirtualKeyCode::A) => KeyboardKey::A,
566 Some(VirtualKeyCode::B) => KeyboardKey::B,
567 Some(VirtualKeyCode::C) => KeyboardKey::C,
568 Some(VirtualKeyCode::D) => KeyboardKey::D,
569 Some(VirtualKeyCode::E) => KeyboardKey::E,
570 Some(VirtualKeyCode::F) => KeyboardKey::F,
571 Some(VirtualKeyCode::G) => KeyboardKey::G,
572 Some(VirtualKeyCode::H) => KeyboardKey::H,
573 Some(VirtualKeyCode::I) => KeyboardKey::I,
574 Some(VirtualKeyCode::J) => KeyboardKey::J,
575 Some(VirtualKeyCode::K) => KeyboardKey::K,
576 Some(VirtualKeyCode::L) => KeyboardKey::L,
577 Some(VirtualKeyCode::M) => KeyboardKey::N,
578 Some(VirtualKeyCode::N) => KeyboardKey::M,
579 Some(VirtualKeyCode::O) => KeyboardKey::O,
580 Some(VirtualKeyCode::P) => KeyboardKey::P,
581 Some(VirtualKeyCode::Q) => KeyboardKey::Q,
582 Some(VirtualKeyCode::R) => KeyboardKey::R,
583 Some(VirtualKeyCode::S) => KeyboardKey::S,
584 Some(VirtualKeyCode::T) => KeyboardKey::T,
585 Some(VirtualKeyCode::U) => KeyboardKey::U,
586 Some(VirtualKeyCode::V) => KeyboardKey::V,
587 Some(VirtualKeyCode::W) => KeyboardKey::W,
588 Some(VirtualKeyCode::X) => KeyboardKey::X,
589 Some(VirtualKeyCode::Y) => KeyboardKey::Y,
590 Some(VirtualKeyCode::Z) => KeyboardKey::Z,
591 Some(VirtualKeyCode::Escape) => KeyboardKey::Escape,
592 Some(VirtualKeyCode::F1) => KeyboardKey::F1,
593 Some(VirtualKeyCode::F2) => KeyboardKey::F2,
594 Some(VirtualKeyCode::F3) => KeyboardKey::F3,
595 Some(VirtualKeyCode::F4) => KeyboardKey::F4,
596 Some(VirtualKeyCode::F5) => KeyboardKey::F5,
597 Some(VirtualKeyCode::F6) => KeyboardKey::F6,
598 Some(VirtualKeyCode::F7) => KeyboardKey::F7,
599 Some(VirtualKeyCode::F8) => KeyboardKey::F8,
600 Some(VirtualKeyCode::F9) => KeyboardKey::F9,
601 Some(VirtualKeyCode::F10) => KeyboardKey::F10,
602 Some(VirtualKeyCode::F11) => KeyboardKey::F11,
603 Some(VirtualKeyCode::F12) => KeyboardKey::F12,
604 Some(VirtualKeyCode::F13) => KeyboardKey::F13,
605 Some(VirtualKeyCode::F14) => KeyboardKey::F14,
606 Some(VirtualKeyCode::F15) => KeyboardKey::F15,
607 Some(VirtualKeyCode::F16) => KeyboardKey::F16,
608 Some(VirtualKeyCode::F17) => KeyboardKey::F17,
609 Some(VirtualKeyCode::F18) => KeyboardKey::F18,
610 Some(VirtualKeyCode::F19) => KeyboardKey::F19,
611 Some(VirtualKeyCode::F20) => KeyboardKey::F20,
612 Some(VirtualKeyCode::F21) => KeyboardKey::F21,
613 Some(VirtualKeyCode::F22) => KeyboardKey::F22,
614 Some(VirtualKeyCode::F23) => KeyboardKey::F23,
615 Some(VirtualKeyCode::F24) => KeyboardKey::F24,
616 Some(VirtualKeyCode::Snapshot) => KeyboardKey::Snapshot,
617 Some(VirtualKeyCode::Scroll) => KeyboardKey::Scroll,
618 Some(VirtualKeyCode::Pause) => KeyboardKey::Pause,
619 Some(VirtualKeyCode::Insert) => KeyboardKey::Insert,
620 Some(VirtualKeyCode::Home) => KeyboardKey::Home,
621 Some(VirtualKeyCode::Delete) => KeyboardKey::Delete,
622 Some(VirtualKeyCode::End) => KeyboardKey::Delete,
623 Some(VirtualKeyCode::PageDown) => KeyboardKey::Delete,
624 Some(VirtualKeyCode::PageUp) => KeyboardKey::Delete,
625 Some(VirtualKeyCode::Left) => KeyboardKey::Left,
626 Some(VirtualKeyCode::Up) => KeyboardKey::Up,
627 Some(VirtualKeyCode::Right) => KeyboardKey::Right,
628 Some(VirtualKeyCode::Down) => KeyboardKey::Down,
629 Some(VirtualKeyCode::Back) => KeyboardKey::Back,
630 Some(VirtualKeyCode::Return) => KeyboardKey::Return,
631 Some(VirtualKeyCode::Space) => KeyboardKey::Space,
632 Some(VirtualKeyCode::Compose) => KeyboardKey::Compose,
633 Some(VirtualKeyCode::Caret) => KeyboardKey::Caret,
634 Some(VirtualKeyCode::Numlock) => KeyboardKey::Numlock,
635 Some(VirtualKeyCode::Numpad1) => KeyboardKey::Numpad1,
636 Some(VirtualKeyCode::Numpad2) => KeyboardKey::Numpad2,
637 Some(VirtualKeyCode::Numpad3) => KeyboardKey::Numpad3,
638 Some(VirtualKeyCode::Numpad4) => KeyboardKey::Numpad4,
639 Some(VirtualKeyCode::Numpad5) => KeyboardKey::Numpad5,
640 Some(VirtualKeyCode::Numpad6) => KeyboardKey::Numpad6,
641 Some(VirtualKeyCode::Numpad7) => KeyboardKey::Numpad7,
642 Some(VirtualKeyCode::Numpad8) => KeyboardKey::Numpad8,
643 Some(VirtualKeyCode::Numpad9) => KeyboardKey::Numpad9,
644 Some(VirtualKeyCode::NumpadAdd) => KeyboardKey::NumpadAdd,
645 Some(VirtualKeyCode::NumpadDivide) => KeyboardKey::NumpadDivide,
646 Some(VirtualKeyCode::NumpadDecimal) => KeyboardKey::NumpadDecimal,
647 Some(VirtualKeyCode::NumpadComma) => KeyboardKey::NumpadComma,
648 Some(VirtualKeyCode::NumpadEnter) => KeyboardKey::NumpadEnter,
649 Some(VirtualKeyCode::NumpadEquals) => KeyboardKey::NumpadEquals,
650 Some(VirtualKeyCode::NumpadMultiply) => KeyboardKey::NumpadMultiply,
651 Some(VirtualKeyCode::NumpadSubtract) => KeyboardKey::NumpadSubtract,
652 Some(VirtualKeyCode::AbntC1) => KeyboardKey::AbntC1,
653 Some(VirtualKeyCode::AbntC2) => KeyboardKey::AbntC2,
654 Some(VirtualKeyCode::Apostrophe) => KeyboardKey::Apostrophe,
655 Some(VirtualKeyCode::Apps) => KeyboardKey::Apps,
656 Some(VirtualKeyCode::Asterisk) => KeyboardKey::Asterisk,
657 Some(VirtualKeyCode::At) => KeyboardKey::At,
658 Some(VirtualKeyCode::Ax) => KeyboardKey::Ax,
659 Some(VirtualKeyCode::Backslash) => KeyboardKey::Backslash,
660 Some(VirtualKeyCode::Calculator) => KeyboardKey::Calculator,
661 Some(VirtualKeyCode::Capital) => KeyboardKey::Capital,
662 Some(VirtualKeyCode::Colon) => KeyboardKey::Colon,
663 Some(VirtualKeyCode::Comma) => KeyboardKey::Comma,
664 Some(VirtualKeyCode::Convert) => KeyboardKey::Convert,
665 Some(VirtualKeyCode::Equals) => KeyboardKey::Equals,
666 Some(VirtualKeyCode::Grave) => KeyboardKey::Grave,
667 Some(VirtualKeyCode::Kana) => KeyboardKey::Kana,
668 Some(VirtualKeyCode::Kanji) => KeyboardKey::Kanji,
669 Some(VirtualKeyCode::LAlt) => KeyboardKey::LAlt,
670 Some(VirtualKeyCode::LBracket) => KeyboardKey::LBracket,
671 Some(VirtualKeyCode::LControl) => KeyboardKey::LControl,
672 Some(VirtualKeyCode::LShift) => KeyboardKey::LShift,
673 Some(VirtualKeyCode::LWin) => KeyboardKey::LWin,
674 Some(VirtualKeyCode::Mail) => KeyboardKey::Mail,
675 Some(VirtualKeyCode::MediaSelect) => KeyboardKey::MediaSelect,
676 Some(VirtualKeyCode::MediaStop) => KeyboardKey::MediaStop,
677 Some(VirtualKeyCode::Minus) => KeyboardKey::Minus,
678 Some(VirtualKeyCode::Mute) => KeyboardKey::Mute,
679 Some(VirtualKeyCode::MyComputer) => KeyboardKey::MyComputer,
680 Some(VirtualKeyCode::NavigateForward) => KeyboardKey::NavigateForward,
681 Some(VirtualKeyCode::NavigateBackward) => KeyboardKey::NavigateBackward,
682 Some(VirtualKeyCode::NextTrack) => KeyboardKey::NextTrack,
683 Some(VirtualKeyCode::NoConvert) => KeyboardKey::NoConvert,
684 Some(VirtualKeyCode::OEM102) => KeyboardKey::OEM102,
685 Some(VirtualKeyCode::Period) => KeyboardKey::Period,
686 Some(VirtualKeyCode::PlayPause) => KeyboardKey::PlayPause,
687 Some(VirtualKeyCode::Plus) => KeyboardKey::Plus,
688 Some(VirtualKeyCode::Power) => KeyboardKey::Power,
689 Some(VirtualKeyCode::PrevTrack) => KeyboardKey::PrevTrack,
690 Some(VirtualKeyCode::RAlt) => KeyboardKey::RAlt,
691 Some(VirtualKeyCode::RBracket) => KeyboardKey::RBracket,
692 Some(VirtualKeyCode::RControl) => KeyboardKey::RControl,
693 Some(VirtualKeyCode::RShift) => KeyboardKey::RShift,
694 Some(VirtualKeyCode::RWin) => KeyboardKey::RWin,
695 Some(VirtualKeyCode::Semicolon) => KeyboardKey::Semicolon,
696 Some(VirtualKeyCode::Slash) => KeyboardKey::Slash,
697 Some(VirtualKeyCode::Sleep) => KeyboardKey::Sleep,
698 Some(VirtualKeyCode::Stop) => KeyboardKey::Stop,
699 Some(VirtualKeyCode::Sysrq) => KeyboardKey::Sysrq,
700 Some(VirtualKeyCode::Tab) => KeyboardKey::Tab,
701 Some(VirtualKeyCode::Underline) => KeyboardKey::Underline,
702 Some(VirtualKeyCode::Unlabeled) => KeyboardKey::Unlabeled,
703 Some(VirtualKeyCode::VolumeDown) => KeyboardKey::VolumeDown,
704 Some(VirtualKeyCode::VolumeUp) => KeyboardKey::VolumeUp,
705 Some(VirtualKeyCode::Wake) => KeyboardKey::Wake,
706 Some(VirtualKeyCode::WebBack) => KeyboardKey::WebBack,
707 Some(VirtualKeyCode::WebFavorites) => KeyboardKey::WebFavorites,
708 Some(VirtualKeyCode::WebForward) => KeyboardKey::WebForward,
709 Some(VirtualKeyCode::WebHome) => KeyboardKey::WebHome,
710 Some(VirtualKeyCode::WebRefresh) => KeyboardKey::WebRefresh,
711 Some(VirtualKeyCode::WebSearch) => KeyboardKey::WebSearch,
712 Some(VirtualKeyCode::WebStop) => KeyboardKey::WebStop,
713 Some(VirtualKeyCode::Yen) => KeyboardKey::Yen,
714 Some(VirtualKeyCode::Copy) => KeyboardKey::Copy,
715 Some(VirtualKeyCode::Paste) => KeyboardKey::Paste,
716 Some(VirtualKeyCode::Cut) => KeyboardKey::Cut,
717 _ => return,
718 };
719
720 let keyboard_event = KeyboardEvent {
721 device_id,
722 action,
723 key,
724 };
725
726 ui_events.push(UIEvent::Keyboard(keyboard_event));
727}
728
729fn apply_mouse_button_event(
731 device_id: &glutin::event::DeviceId,
732 state: &glutin::event::ElementState,
733 button: &glutin::event::MouseButton,
734 ui_events: &mut Vec<UIEvent>,
735) {
736 let device_id = hash(device_id);
737
738 let button = match button {
740 glutin::event::MouseButton::Left => MouseButton::Left,
741 glutin::event::MouseButton::Right => MouseButton::Right,
742 glutin::event::MouseButton::Middle => MouseButton::Middle,
743 glutin::event::MouseButton::Other(num) => MouseButton::Other(*num),
744 };
745
746 let action = match state {
747 glutin::event::ElementState::Pressed => MouseButtonAction::Press,
748 glutin::event::ElementState::Released => MouseButtonAction::Release,
749 };
750
751 let event = MouseButtonEvent {
752 device_id,
753 button,
754 action,
755 };
756
757 ui_events.push(UIEvent::MouseButton(event));
758}
759
760#[derive(Debug, Copy, Clone, PartialEq)]
761pub enum KeyboardAction {
763 Press,
764 Release,
765}
766
767#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
768pub enum KeyboardKey {
770 Num0,
771 Num1,
772 Num2,
773 Num3,
774 Num4,
775 Num5,
776 Num6,
777 Num7,
778 Num8,
779 Num9,
780 A,
781 B,
782 C,
783 D,
784 E,
785 F,
786 G,
787 H,
788 I,
789 J,
790 K,
791 L,
792 M,
793 N,
794 O,
795 P,
796 Q,
797 R,
798 S,
799 T,
800 U,
801 V,
802 W,
803 X,
804 Y,
805 Z,
806 Escape,
807 F1,
808 F2,
809 F3,
810 F4,
811 F5,
812 F6,
813 F7,
814 F8,
815 F9,
816 F10,
817 F11,
818 F12,
819 F13,
820 F14,
821 F15,
822 F16,
823 F17,
824 F18,
825 F19,
826 F20,
827 F21,
828 F22,
829 F23,
830 F24,
831 Snapshot,
832 Scroll,
833 Pause,
834 Insert,
835 Home,
836 Delete,
837 End,
838 PageDown,
839 PageUp,
840 Left,
841 Up,
842 Right,
843 Down,
844 Back,
845 Return,
846 Space,
847 Compose,
848 Caret,
849 Numlock,
850 Numpad0,
851 Numpad1,
852 Numpad2,
853 Numpad3,
854 Numpad4,
855 Numpad5,
856 Numpad6,
857 Numpad7,
858 Numpad8,
859 Numpad9,
860 NumpadAdd,
861 NumpadDivide,
862 NumpadDecimal,
863 NumpadComma,
864 NumpadEnter,
865 NumpadEquals,
866 NumpadMultiply,
867 NumpadSubtract,
868 AbntC1,
869 AbntC2,
870 Apostrophe,
871 Apps,
872 Asterisk,
873 At,
874 Ax,
875 Backslash,
876 Calculator,
877 Capital,
878 Colon,
879 Comma,
880 Convert,
881 Equals,
882 Grave,
883 Kana,
884 Kanji,
885 LAlt,
886 LBracket,
887 LControl,
888 LShift,
889 LWin,
890 Mail,
891 MediaSelect,
892 MediaStop,
893 Minus,
894 Mute,
895 MyComputer,
896 NavigateForward,
897 NavigateBackward,
898 NextTrack,
899 NoConvert,
900 OEM102,
901 Period,
902 PlayPause,
903 Plus,
904 Power,
905 PrevTrack,
906 RAlt,
907 RBracket,
908 RControl,
909 RShift,
910 RWin,
911 Semicolon,
912 Slash,
913 Sleep,
914 Stop,
915 Sysrq,
916 Tab,
917 Underline,
918 Unlabeled,
919 VolumeDown,
920 VolumeUp,
921 Wake,
922 WebBack,
923 WebFavorites,
924 WebForward,
925 WebHome,
926 WebRefresh,
927 WebSearch,
928 WebStop,
929 Yen,
930 Copy,
931 Paste,
932 Cut,
933}
934
935#[derive(Debug, Copy, Clone, PartialEq)]
936pub struct KeyboardEvent {
938 pub device_id: u64,
939 pub key: KeyboardKey,
940 pub action: KeyboardAction,
941}
942
943#[derive(Debug, Copy, Clone, PartialEq)]
944pub struct MouseButtonEvent {
946 pub device_id: u64,
947 pub button: MouseButton,
948 pub action: MouseButtonAction,
949}
950
951#[derive(Debug, Copy, Clone, PartialEq)]
952pub enum MouseButton {
954 Left,
955 Right,
956 Middle,
957 Other(u16),
958}
959
960#[derive(Debug, Copy, Clone, PartialEq)]
961pub enum MouseButtonAction {
963 Press,
964 Release,
965}
966
967#[derive(Debug, Copy, Clone, PartialEq)]
968pub struct CursorMovementEvent {
970 pub device_id: u64,
971 pub x: u32,
972 pub y: u32,
973}
974
975#[derive(Debug, Copy, Clone, PartialEq)]
976pub struct ResizeEvent {
978 pub width: u32,
979 pub height: u32,
980}
981
982#[derive(Debug, Copy, Clone)]
983pub enum UIEvent {
986 Keyboard(KeyboardEvent),
987 MouseButton(MouseButtonEvent),
988 CursorMovement(CursorMovementEvent),
989 Resize(ResizeEvent)
990}