devpage_design/tiles/
mod.rs1use kurbo::Rect as KRect;
6
7use crate::display::List;
8use crate::resolve::Theme;
9
10mod cache;
11
12pub use cache::*;
13
14pub const TILE: u32 = 256;
16
17pub fn tile_rect(list: &List, scale: f64, col: u32, row: u32) -> KRect {
20 square((list.area.x as f64, list.area.y as f64), scale, col, row)
21}
22
23pub fn square((x, y): (f64, f64), scale: f64, col: u32, row: u32) -> KRect {
26 let side = TILE as f64 / scale;
27 KRect::new(
28 x + col as f64 * side,
29 y + row as f64 * side,
30 x + (col + 1) as f64 * side,
31 y + (row + 1) as f64 * side,
32 )
33}
34
35#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
37pub struct Level(pub i64);
38
39impl Level {
40 pub fn of(scale: f64) -> Level {
42 Level((scale * 1024.0).round().max(1.0) as i64)
43 }
44
45 pub fn scale(self) -> f64 {
46 self.0 as f64 / 1024.0
47 }
48}
49
50#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
53pub struct Key {
54 pub theme: Theme,
55 pub level: Level,
56 pub col: u32,
57 pub row: u32,
58}
59
60impl Key {
61 pub fn rect(&self, origin: (f64, f64)) -> KRect {
64 square(origin, self.level.scale(), self.col, self.row)
65 }
66}
67
68pub trait Tiled: Copy + Eq + std::hash::Hash {
71 fn key(&self) -> Key;
72}
73
74impl Tiled for Key {
75 fn key(&self) -> Key {
76 *self
77 }
78}
79
80#[derive(Clone, Copy, Debug)]
83pub struct View {
84 pub width: f64,
85 pub height: f64,
86 pub zoom: f64,
87 pub origin: (f64, f64),
88}
89
90impl View {
91 pub fn tiles(&self, area: KRect, level: Level) -> Vec<(u32, u32)> {
94 let side = TILE as f64;
95 let scale = level.scale();
96 let (ox, oy) = self.origin;
97 let count = |v: f64| (v * scale / side).ceil() as i64;
98 let (cols, rows) = (count(area.width()), count(area.height()));
99 let span = |o: f64, n: f64, count: i64| {
100 let first = ((-o) / side).floor().max(0.0) as i64;
101 let last = (((n - o) / side).ceil() as i64).min(count);
102 first..last.max(first)
103 };
104 let (cs, rs) = (span(ox, self.width, cols), span(oy, self.height, rows));
105 let mut out: Vec<(u32, u32)> = rs
106 .flat_map(|r| cs.clone().map(move |c| (c as u32, r as u32)))
107 .collect();
108 let (mx, my) = (
109 (self.width / 2.0 - ox) / side,
110 (self.height / 2.0 - oy) / side,
111 );
112 let d = |p: &(u32, u32)| (p.0 as f64 + 0.5 - mx).powi(2) + (p.1 as f64 + 0.5 - my).powi(2);
113 out.sort_by(|a, b| d(a).total_cmp(&d(b)));
114 out
115 }
116
117 pub fn place(&self, area: KRect, key: &Key) -> Option<KRect> {
120 let rect = square((area.x0, area.y0), key.level.scale(), key.col, key.row);
121 let (ox, oy) = self.origin;
122 let to = |x: f64, y: f64| {
123 (
124 ox + (x - area.x0) * self.zoom,
125 oy + (y - area.y0) * self.zoom,
126 )
127 };
128 let (x0, y0) = to(rect.x0, rect.y0);
129 let (x1, y1) = to(rect.x1, rect.y1);
130 (x1 >= 0.0 && y1 >= 0.0 && x0 <= self.width && y0 <= self.height)
131 .then(|| KRect::new(x0, y0, x1, y1))
132 }
133}
134
135#[cfg(test)]
136mod tests;