swamp_window_runner/
lib.rs1mod convert;
6
7use crate::convert::{
8 from_element_state, from_mouse_scroll_delta, from_touch_phase, try_from_key_code,
9 try_from_mouse_button,
10};
11use int_math::{UVec2, Vec2};
12use std::sync::{Arc, Mutex};
13use swamp_app::prelude::Resource;
14use swamp_app::prelude::{App, AppReturnValue, ApplicationExit};
15use swamp_basic_input::prelude::*;
16use swamp_screen::WindowMessage;
17use swamp_wgpu_window::{annoying_async_device_creation, WgpuWindow};
18use swamp_window::AppHandler;
19use tracing::{debug, error};
20use winit::dpi;
21use winit::keyboard::PhysicalKey;
22
23pub struct WindowState {
24 pub app: Arc<Mutex<App>>,
25 pub wgpu_window: Option<WgpuWindow>,
26 requested_surface_size: UVec2,
27 minimal_surface_size: UVec2,
28 physical_surface_size: dpi::PhysicalSize<u32>,
29}
30
31#[derive(Debug, Resource)]
32pub struct WindowHandle {
33 pub window: Arc<winit::window::Window>,
34}
35
36impl AppHandler for WindowState {
37 fn min_size(&self) -> (u16, u16) {
38 (self.minimal_surface_size.x, self.minimal_surface_size.y)
39 }
40
41 fn start_size(&self) -> (u16, u16) {
42 (self.requested_surface_size.x, self.requested_surface_size.y)
43 }
44
45 fn cursor_should_be_visible(&self) -> bool {
46 true
47 }
48
49 fn redraw(&mut self) -> bool {
50 let mut app = self.app.lock().unwrap();
51 app.update();
52 !app.has_resource::<ApplicationExit>()
53 }
54
55 fn got_focus(&mut self) {}
56
57 fn lost_focus(&mut self) {}
58
59 fn window_created(&mut self, window: Arc<winit::window::Window>) {
60 debug!("received callback for: window created");
61 let app = Arc::clone(&self.app);
62 future_runner::run_future(async move {
63 let async_device_info = annoying_async_device_creation(window)
64 .await
65 .expect("couldn't get device info");
66 app.lock().unwrap().insert_resource(async_device_info);
67 });
68 self.app
69 .lock()
70 .unwrap()
71 .send(WindowMessage::WindowCreated());
72 }
73
74 fn resized(&mut self, size: dpi::PhysicalSize<u32>) {
75 self.physical_surface_size = size;
76 self.app
77 .lock()
78 .unwrap()
79 .send(WindowMessage::Resized(UVec2::new(
80 size.width as u16,
81 size.height as u16,
82 )));
83 }
84
85 fn keyboard_input(
86 &mut self,
87 element_state: winit::event::ElementState,
88 physical_key: winit::keyboard::PhysicalKey,
89 ) {
90 if let PhysicalKey::Code(key_code) = physical_key {
91 if let Ok(converted_key) = try_from_key_code(key_code) {
92 self.app.lock().unwrap().send(InputMessage::KeyboardInput(
93 from_element_state(element_state),
94 converted_key,
95 ));
96 }
97 }
98 }
99
100 fn cursor_entered(&mut self) {}
101
102 fn cursor_left(&mut self) {}
103
104 fn cursor_moved(&mut self, physical_position: dpi::PhysicalPosition<u32>) {
106 if physical_position.x >= self.physical_surface_size.width {
107 return;
108 }
109 if physical_position.y >= self.physical_surface_size.height {
110 return;
111 }
112
113 if self.physical_surface_size.height == 0 {
114 return;
115 }
116
117 if self
118 .physical_surface_size
119 .height
120 .checked_sub(physical_position.y)
121 .is_none()
122 {
123 error!(
124 "problem! {} {:?}",
125 self.physical_surface_size.height, physical_position.y
126 );
127 }
128
129 self.app
130 .lock()
131 .unwrap()
132 .send(WindowMessage::CursorMoved(UVec2::new(
133 physical_position.x as u16,
134 ((self.physical_surface_size.height - 1) - physical_position.y) as u16,
135 )));
136 }
137
138 fn mouse_input(
139 &mut self,
140 element_state: winit::event::ElementState,
141 button: winit::event::MouseButton,
142 ) {
143 if let Ok(converted_button) = try_from_mouse_button(button) {
144 self.app.lock().unwrap().send(InputMessage::MouseInput(
145 from_element_state(element_state),
146 converted_button,
147 ));
148 }
149 }
150
151 fn mouse_wheel(
152 &mut self,
153 delta: winit::event::MouseScrollDelta,
154 touch_phase: winit::event::TouchPhase,
155 ) {
156 self.app.lock().unwrap().send(InputMessage::MouseWheel(
157 from_mouse_scroll_delta(delta),
158 from_touch_phase(touch_phase),
159 ));
160 }
161
162 fn pinch_gesture(&mut self, delta: f64, touch_phase: winit::event::TouchPhase) {
163 let virtual_wheel_y = (delta * 50.0) as i16;
164 let mouse_delta = MouseScrollDelta::LineDelta(Vec2::new(0, virtual_wheel_y));
165 self.app.lock().unwrap().send(InputMessage::MouseWheel(
166 mouse_delta,
167 from_touch_phase(touch_phase),
168 ));
169 }
170
171 fn mouse_motion(&mut self, _delta: (f64, f64)) {}
172
173 fn touch(&mut self, _touch: winit::event::Touch) {}
174
175 fn scale_factor_changed(
176 &mut self,
177 _scale_factor: f64,
178 _inner_size_writer: winit::event::InnerSizeWriter,
179 ) {
180 }
181}
182
183pub fn runner(mut app: App) -> AppReturnValue {
184 console_error_panic_hook::set_once();
185 debug!("window-runner started!");
186
187 let requested_surface_size: UVec2;
188 let minimal_surface_size: UVec2;
189 let title: String;
190
191 {
192 let window_settings = app.resource::<swamp_screen::Window>();
193
194 title = window_settings.title.clone();
195 requested_surface_size = window_settings.requested_surface_size;
196 minimal_surface_size = window_settings.minimal_surface_size;
197
198 app.create_message_type::<WindowMessage>();
199 app.create_message_type::<InputMessage>();
200 }
201
202 #[allow(clippy::arc_with_non_send_sync)]
203 let arc_app = Arc::new(Mutex::new(app));
204
205 let mut state = WindowState {
206 app: arc_app,
207 wgpu_window: None,
208 requested_surface_size,
209 minimal_surface_size,
210 physical_surface_size: dpi::PhysicalSize::new(
211 requested_surface_size.x as u32,
212 requested_surface_size.y as u32,
213 ),
214 };
215
216 swamp_window::WindowRunner::run_app(&mut state, title.as_str()).expect("run_app failed");
217
218 debug!("we returned, that is not guaranteed for all platforms");
219
220 AppReturnValue::Value(0)
221}