window.rs

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