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}