embedded_graphics_simulator/window/
sdl_window.rs1use embedded_graphics::{
2 pixelcolor::Rgb888,
3 prelude::{PixelColor, Point, Size},
4};
5use sdl2::{
6 event::Event,
7 keyboard::{Keycode, Mod},
8 mouse::{MouseButton, MouseWheelDirection},
9 pixels::PixelFormatEnum,
10 render::{Canvas, Texture, TextureCreator},
11 video::WindowContext,
12 EventPump,
13};
14
15use crate::{OutputImage, OutputSettings, SimulatorDisplay};
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19pub enum SimulatorEvent {
20 KeyUp {
22 keycode: Keycode,
24 keymod: Mod,
26 repeat: bool,
28 },
29 KeyDown {
31 keycode: Keycode,
33 keymod: Mod,
35 repeat: bool,
37 },
38 MouseButtonUp {
40 mouse_btn: MouseButton,
42 point: Point,
44 },
45 MouseButtonDown {
47 mouse_btn: MouseButton,
49 point: Point,
51 },
52 MouseWheel {
54 scroll_delta: Point,
56 direction: MouseWheelDirection,
58 },
59 MouseMove {
61 point: Point,
63 },
64 Quit,
66}
67
68pub struct SdlWindow {
69 canvas: Canvas<sdl2::video::Window>,
70 event_pump: EventPump,
71 window_texture: SdlWindowTexture,
72 size: Size,
73}
74
75impl SdlWindow {
76 pub fn new<C>(
77 display: &SimulatorDisplay<C>,
78 title: &str,
79 output_settings: &OutputSettings,
80 ) -> Self
81 where
82 C: PixelColor + Into<Rgb888>,
83 {
84 let sdl_context = sdl2::init().unwrap();
85 let video_subsystem = sdl_context.video().unwrap();
86
87 let size = output_settings.framebuffer_size(display);
88
89 let window = video_subsystem
90 .window(title, size.width, size.height)
91 .position_centered()
92 .build()
93 .unwrap();
94
95 let canvas = window.into_canvas().build().unwrap();
96 let event_pump = sdl_context.event_pump().unwrap();
97
98 let window_texture = SdlWindowTextureBuilder {
99 texture_creator: canvas.texture_creator(),
100 texture_builder: |creator: &TextureCreator<WindowContext>| {
101 creator
102 .create_texture_streaming(PixelFormatEnum::RGB24, size.width, size.height)
103 .unwrap()
104 },
105 }
106 .build();
107
108 Self {
109 canvas,
110 event_pump,
111 window_texture,
112 size,
113 }
114 }
115
116 pub fn update(&mut self, framebuffer: &OutputImage<Rgb888>) {
117 self.window_texture.with_mut(|fields| {
118 fields
119 .texture
120 .update(
121 None,
122 framebuffer.data.as_ref(),
123 self.size.width as usize * 3,
124 )
125 .unwrap();
126 });
127
128 self.canvas
129 .copy(self.window_texture.borrow_texture(), None, None)
130 .unwrap();
131 self.canvas.present();
132 }
133
134 pub fn events(
137 &mut self,
138 output_settings: &OutputSettings,
139 ) -> impl Iterator<Item = SimulatorEvent> + '_ {
140 let output_settings = output_settings.clone();
141 self.event_pump
142 .poll_iter()
143 .filter_map(move |event| match event {
144 Event::Quit { .. }
145 | Event::KeyDown {
146 keycode: Some(Keycode::Escape),
147 ..
148 } => Some(SimulatorEvent::Quit),
149 Event::KeyDown {
150 keycode,
151 keymod,
152 repeat,
153 ..
154 } => keycode.map(|valid_keycode| SimulatorEvent::KeyDown {
155 keycode: valid_keycode,
156 keymod,
157 repeat,
158 }),
159 Event::KeyUp {
160 keycode,
161 keymod,
162 repeat,
163 ..
164 } => keycode.map(|valid_keycode| SimulatorEvent::KeyUp {
165 keycode: valid_keycode,
166 keymod,
167 repeat,
168 }),
169 Event::MouseButtonUp {
170 x, y, mouse_btn, ..
171 } => {
172 let point = output_settings.output_to_display(Point::new(x, y));
173 Some(SimulatorEvent::MouseButtonUp { point, mouse_btn })
174 }
175 Event::MouseButtonDown {
176 x, y, mouse_btn, ..
177 } => {
178 let point = output_settings.output_to_display(Point::new(x, y));
179 Some(SimulatorEvent::MouseButtonDown { point, mouse_btn })
180 }
181 Event::MouseWheel {
182 x, y, direction, ..
183 } => Some(SimulatorEvent::MouseWheel {
184 scroll_delta: Point::new(x, y),
185 direction,
186 }),
187 Event::MouseMotion { x, y, .. } => {
188 let point = output_settings.output_to_display(Point::new(x, y));
189 Some(SimulatorEvent::MouseMove { point })
190 }
191 _ => None,
192 })
193 }
194}
195
196#[ouroboros::self_referencing]
197struct SdlWindowTexture {
198 texture_creator: TextureCreator<WindowContext>,
199 #[borrows(texture_creator)]
200 #[covariant]
201 texture: Texture<'this>,
202}