window.rs

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