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