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