window.rs

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