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