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