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