use crate::source::{TileKey, TileSource};
use slint::{Image, Rgba8Pixel, SharedPixelBuffer};
pub struct SyntheticTileSource {
tile_size: u32,
}
impl Default for SyntheticTileSource {
fn default() -> Self {
Self { tile_size: 256 }
}
}
impl SyntheticTileSource {
pub fn new() -> Self {
Self::default()
}
pub fn with_tile_size(mut self, size: u32) -> Self {
self.tile_size = size;
self
}
}
impl TileSource for SyntheticTileSource {
fn tile(&self, key: TileKey) -> Option<Image> {
let size = self.tile_size;
let mut buf = SharedPixelBuffer::<Rgba8Pixel>::new(size, size);
let stride = size as usize;
let pixels = buf.make_mut_slice();
let r = (40 + (key.x.wrapping_mul(73) & 0x7f)) as u8;
let g = (40 + (key.y.wrapping_mul(151) & 0x7f)) as u8;
let b = (40 + ((key.x ^ key.y).wrapping_mul(199) & 0x7f)) as u8;
let fill = Rgba8Pixel { r, g, b, a: 255 };
let border = Rgba8Pixel {
r: 255,
g: 255,
b: 255,
a: 100,
};
let cross = Rgba8Pixel {
r: 255,
g: 255,
b: 255,
a: 60,
};
for y in 0..size as usize {
for x in 0..size as usize {
let on_border = x == 0 || y == 0 || x == stride - 1 || y == stride - 1;
let on_cross = (x == stride / 2) || (y == stride / 2);
pixels[y * stride + x] = if on_border {
border
} else if on_cross && key.z >= 4 {
cross
} else {
fill
};
}
}
Some(Image::from_rgba8(buf))
}
fn tile_size(&self) -> u32 {
self.tile_size
}
fn max_zoom(&self) -> u8 {
18
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn always_returns_a_tile() {
let src = SyntheticTileSource::new();
for key in [
TileKey { x: 0, y: 0, z: 0 },
TileKey {
x: 1234,
y: 5678,
z: 12,
},
TileKey {
x: u32::MAX,
y: u32::MAX,
z: 18,
},
] {
assert!(src.tile(key).is_some(), "{key:?}");
}
}
#[test]
fn distinct_keys_yield_distinct_tiles() {
let src = SyntheticTileSource::new();
let a = src.tile(TileKey { x: 0, y: 0, z: 5 }).unwrap();
let b = src.tile(TileKey { x: 1, y: 0, z: 5 }).unwrap();
let (aw, ah) = (a.size().width, a.size().height);
let (bw, bh) = (b.size().width, b.size().height);
assert_eq!((aw, ah), (256, 256));
assert_eq!((bw, bh), (256, 256));
}
#[test]
fn tile_size_override_takes_effect() {
let src = SyntheticTileSource::new().with_tile_size(128);
assert_eq!(src.tile_size(), 128);
let img = src.tile(TileKey { x: 0, y: 0, z: 0 }).unwrap();
assert_eq!(img.size().width, 128);
assert_eq!(img.size().height, 128);
}
}