1use crate::{
2 px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Pixels, PlatformAtlas,
3 PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, Size, TestPlatform, TileId,
4 WindowAppearance, WindowBounds, WindowOptions,
5};
6use collections::HashMap;
7use parking_lot::Mutex;
8use std::{
9 rc::{Rc, Weak},
10 sync::{self, Arc},
11};
12
13#[derive(Default)]
14pub(crate) struct TestWindowHandlers {
15 pub(crate) active_status_change: Vec<Box<dyn FnMut(bool)>>,
16 pub(crate) input: Vec<Box<dyn FnMut(crate::InputEvent) -> bool>>,
17 pub(crate) moved: Vec<Box<dyn FnMut()>>,
18 pub(crate) resize: Vec<Box<dyn FnMut(Size<Pixels>, f32)>>,
19}
20
21pub struct TestWindow {
22 pub(crate) bounds: WindowBounds,
23 pub(crate) handle: AnyWindowHandle,
24 display: Rc<dyn PlatformDisplay>,
25 pub(crate) title: Option<String>,
26 pub(crate) edited: bool,
27 pub(crate) input_handler: Option<Arc<Mutex<Box<dyn PlatformInputHandler>>>>,
28 pub(crate) handlers: Arc<Mutex<TestWindowHandlers>>,
29 platform: Weak<TestPlatform>,
30 sprite_atlas: Arc<dyn PlatformAtlas>,
31}
32
33impl TestWindow {
34 pub fn new(
35 options: WindowOptions,
36 handle: AnyWindowHandle,
37 platform: Weak<TestPlatform>,
38 display: Rc<dyn PlatformDisplay>,
39 ) -> Self {
40 Self {
41 bounds: options.bounds,
42 display,
43 platform,
44 handle,
45 input_handler: None,
46 sprite_atlas: Arc::new(TestAtlas::new()),
47 handlers: Default::default(),
48 title: Default::default(),
49 edited: false,
50 }
51 }
52}
53
54impl PlatformWindow for TestWindow {
55 fn bounds(&self) -> WindowBounds {
56 self.bounds
57 }
58
59 fn content_size(&self) -> Size<Pixels> {
60 let bounds = match self.bounds {
61 WindowBounds::Fixed(bounds) => bounds,
62 WindowBounds::Maximized | WindowBounds::Fullscreen => self.display().bounds(),
63 };
64 bounds.size.map(|p| px(p.0))
65 }
66
67 fn scale_factor(&self) -> f32 {
68 2.0
69 }
70
71 fn titlebar_height(&self) -> Pixels {
72 unimplemented!()
73 }
74
75 fn appearance(&self) -> WindowAppearance {
76 unimplemented!()
77 }
78
79 fn display(&self) -> std::rc::Rc<dyn crate::PlatformDisplay> {
80 self.display.clone()
81 }
82
83 fn mouse_position(&self) -> Point<Pixels> {
84 Point::default()
85 }
86
87 fn modifiers(&self) -> crate::Modifiers {
88 crate::Modifiers::default()
89 }
90
91 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
92 self
93 }
94
95 fn set_input_handler(&mut self, input_handler: Box<dyn crate::PlatformInputHandler>) {
96 self.input_handler = Some(Arc::new(Mutex::new(input_handler)));
97 }
98
99 fn clear_input_handler(&mut self) {
100 self.input_handler = None;
101 }
102
103 fn prompt(
104 &self,
105 _level: crate::PromptLevel,
106 _msg: &str,
107 _answers: &[&str],
108 ) -> futures::channel::oneshot::Receiver<usize> {
109 self.platform.upgrade().expect("platform dropped").prompt()
110 }
111
112 fn activate(&self) {
113 *self
114 .platform
115 .upgrade()
116 .expect("platform dropped")
117 .active_window
118 .lock() = Some(self.handle);
119 }
120
121 fn set_title(&mut self, title: &str) {
122 self.title = Some(title.to_owned());
123 }
124
125 fn set_edited(&mut self, edited: bool) {
126 self.edited = edited;
127 }
128
129 fn show_character_palette(&self) {
130 unimplemented!()
131 }
132
133 fn minimize(&self) {
134 unimplemented!()
135 }
136
137 fn zoom(&self) {
138 unimplemented!()
139 }
140
141 fn toggle_full_screen(&self) {
142 unimplemented!()
143 }
144
145 fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
146 self.handlers.lock().input.push(callback)
147 }
148
149 fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
150 self.handlers.lock().active_status_change.push(callback)
151 }
152
153 fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
154 self.handlers.lock().resize.push(callback)
155 }
156
157 fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {
158 unimplemented!()
159 }
160
161 fn on_moved(&self, callback: Box<dyn FnMut()>) {
162 self.handlers.lock().moved.push(callback)
163 }
164
165 fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {
166 unimplemented!()
167 }
168
169 fn on_close(&self, _callback: Box<dyn FnOnce()>) {
170 unimplemented!()
171 }
172
173 fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
174 unimplemented!()
175 }
176
177 fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
178 unimplemented!()
179 }
180
181 fn invalidate(&self) {
182 // (self.draw.lock())().unwrap();
183 }
184
185 fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
186 self.sprite_atlas.clone()
187 }
188
189 fn as_test(&mut self) -> Option<&mut TestWindow> {
190 Some(self)
191 }
192}
193
194pub struct TestAtlasState {
195 next_id: u32,
196 tiles: HashMap<AtlasKey, AtlasTile>,
197}
198
199pub struct TestAtlas(Mutex<TestAtlasState>);
200
201impl TestAtlas {
202 pub fn new() -> Self {
203 TestAtlas(Mutex::new(TestAtlasState {
204 next_id: 0,
205 tiles: HashMap::default(),
206 }))
207 }
208}
209
210impl PlatformAtlas for TestAtlas {
211 fn get_or_insert_with<'a>(
212 &self,
213 key: &crate::AtlasKey,
214 build: &mut dyn FnMut() -> anyhow::Result<(
215 Size<crate::DevicePixels>,
216 std::borrow::Cow<'a, [u8]>,
217 )>,
218 ) -> anyhow::Result<crate::AtlasTile> {
219 let mut state = self.0.lock();
220 if let Some(tile) = state.tiles.get(key) {
221 return Ok(tile.clone());
222 }
223
224 state.next_id += 1;
225 let texture_id = state.next_id;
226 state.next_id += 1;
227 let tile_id = state.next_id;
228
229 drop(state);
230 let (size, _) = build()?;
231 let mut state = self.0.lock();
232
233 state.tiles.insert(
234 key.clone(),
235 crate::AtlasTile {
236 texture_id: AtlasTextureId {
237 index: texture_id,
238 kind: crate::AtlasTextureKind::Path,
239 },
240 tile_id: TileId(tile_id),
241 bounds: crate::Bounds {
242 origin: Point::default(),
243 size,
244 },
245 },
246 );
247
248 Ok(state.tiles[key].clone())
249 }
250
251 fn clear(&self) {
252 let mut state = self.0.lock();
253 state.tiles = HashMap::default();
254 state.next_id = 0;
255 }
256}