pack.rsannotatedpack.rssource83 lines · 4.1 KB · raw
1//! The ten pack characters: friends from the pixel icon pack. Each is one nine by nine picture (the app and
2//! the page draw it, as they know its file) with a face: where its eyes are and a [`MouthSpec`] for its mouth,
3//! so it speaks with the same mouth the drawn characters do. This is the one list of them: their ids (which
4//! the household's document stores), their words, and their faces. A test (`tests/pack.rs`) holds every face
5//! to its picture: the mouth sits on the animal and never covers an eye.
6
7use pixel_mouth::{Grow, MouthSpec, Palette, Style};
8
9/// One pack character.
10#[derive(Clone, Copy, Debug)]
11pub struct Pack {
12    /// The pack's name for the icon, which is the character's id.
13    pub id: &'static str,
14    /// The word on the picker's button.
15    pub label: &'static str,
16    /// What it is, for the picture's description.
17    pub kind: &'static str,
18    /// The cells that are its eyes (and a nose that must stay visible): no mouth covers one.
19    pub eyes: &'static [(u8, u8)],
20    /// Where its mouth is and how it is drawn, in the picture's own cells.
21    pub mouth: MouthSpec,
22    /// The pack's SVG file for the icon, exactly as the pack has it (the page draws it; the app has the same
23    /// picture as pixels from `whiskers-icons`).
24    pub svg: &'static str,
25}
26
27macro_rules! icon {
28    ($name:literal) => {
29        include_str!(concat!("../../../third-party/pixel-icons/icons/", $name, ".svg"))
30    };
31}
32
33const INK: u32 = 0x343341;
34const BEAK: u32 = 0xFFB100;
35const GREY: u32 = 0xA1A0B4;
36
37const fn cells(anchor: (f32, f32), style: Style, ink: u32) -> MouthSpec {
38    MouthSpec { anchor, size: 1.0, style, palette: Palette { ink, beak: BEAK } }
39}
40
41/// All ten, in the order of the chooser.
42pub const PACK: [Pack; 10] = [
43    Pack { id: "panda", label: "Panda", kind: "panda", eyes: &[(2, 2), (4, 2)], mouth: cells((3.0, 3.0), Style::Muzzle(Grow::Across), INK), svg: icon!("panda") },
44    Pack { id: "koala", label: "Koala", kind: "koala", eyes: &[(2, 5), (6, 5)], mouth: cells((4.0, 7.0), Style::Muzzle(Grow::Across), INK), svg: icon!("koala") },
45    Pack { id: "capybara", label: "Capybara", kind: "capybara", eyes: &[(4, 3)], mouth: cells((2.0, 4.0), Style::Muzzle(Grow::Down), INK), svg: icon!("capybara") },
46    Pack { id: "penguin", label: "Penguin", kind: "penguin", eyes: &[(4, 2)], mouth: cells((2.0, 2.0), Style::BeakSide, INK), svg: icon!("penguin") },
47    Pack { id: "fox", label: "Fox", kind: "fox", eyes: &[(2, 2), (4, 2)], mouth: cells((3.0, 4.0), Style::Muzzle(Grow::Down), INK), svg: icon!("fox") },
48    Pack { id: "rabbit-white", label: "Rabbit", kind: "white rabbit", eyes: &[(2, 4), (4, 4)], mouth: cells((3.0, 5.0), Style::Muzzle(Grow::Down), GREY), svg: icon!("rabbit-white") },
49    Pack { id: "owl-1", label: "Owl", kind: "owl", eyes: &[(3, 2), (5, 2)], mouth: cells((4.0, 3.0), Style::BeakFront, INK), svg: icon!("owl-1") },
50    Pack { id: "unicorn", label: "Unicorn", kind: "unicorn", eyes: &[(2, 3)], mouth: cells((2.0, 4.0), Style::Muzzle(Grow::Across), INK), svg: icon!("unicorn") },
51    Pack { id: "dog-shiba", label: "Dog", kind: "shiba dog", eyes: &[(3, 4), (5, 4)], mouth: cells((4.0, 7.0), Style::Muzzle(Grow::Across), INK), svg: icon!("dog-shiba") },
52    Pack { id: "sloth", label: "Sloth", kind: "sloth", eyes: &[(0, 4), (1, 4), (3, 4), (4, 4)], mouth: cells((2.0, 6.0), Style::Muzzle(Grow::Across), INK), svg: icon!("sloth") },
53];
54
55/// The pack character called `id`.
56pub fn pack(id: &str) -> Option<&'static Pack> {
57    PACK.iter().find(|p| p.id == id)
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn every_pack_character_is_found_by_its_id() {
66        for p in PACK {
67            assert_eq!(pack(p.id).map(|x| x.id), Some(p.id));
68        }
69        assert!(pack("star").is_none());
70    }
71
72    #[test]
73    fn no_two_are_described_alike_and_no_id_repeats() {
74        let mut kinds: Vec<_> = PACK.iter().map(|p| p.kind).collect();
75        kinds.sort();
76        kinds.dedup();
77        assert_eq!(kinds.len(), PACK.len());
78        let mut ids: Vec<_> = PACK.iter().map(|p| p.id).collect();
79        ids.sort();
80        ids.dedup();
81        assert_eq!(ids.len(), PACK.len());
82    }
83}