window.rs

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