window.rs

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