4.1 KiB · text History af1c436
//! What an icon is, independent of how it gets drawn.

use crate::palette::NamedColor;

/// Background construction. Only `DiagonalSplit` is attested by the icons the
/// original studio shipped (the five cbz apps all use it, two-tone Casabeza
/// green over teal); the rest are reconstructions of the "gradients, patterns
/// and other things" the tool offered.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Background {
    Solid,
    DiagonalSplit,
    LinearGradient,
    RadialGradient,
    ConicGradient,
    Stripes,
    Checks,
    Dots,
    Rays,
    CornerWedge,
}

impl Background {
    pub const ALL: &'static [Background] = &[
        Background::Solid,
        Background::DiagonalSplit,
        Background::LinearGradient,
        Background::RadialGradient,
        Background::ConicGradient,
        Background::Stripes,
        Background::Checks,
        Background::Dots,
        Background::Rays,
        Background::CornerWedge,
    ];

    /// Stable identifier for documents. Distinct from [`label`], which is
    /// display text and may be reworded without breaking saved files.
    pub fn id(self) -> &'static str {
        match self {
            Background::Solid => "solid",
            Background::DiagonalSplit => "diagonal-split",
            Background::LinearGradient => "linear-gradient",
            Background::RadialGradient => "radial-gradient",
            Background::ConicGradient => "conic-gradient",
            Background::Stripes => "stripes",
            Background::Checks => "checks",
            Background::Dots => "dots",
            Background::Rays => "rays",
            Background::CornerWedge => "corner-wedge",
        }
    }

    pub fn from_id(id: &str) -> Option<Background> {
        Background::ALL.iter().copied().find(|b| b.id() == id)
    }

    pub fn label(self) -> &'static str {
        match self {
            Background::Solid => "Solid",
            Background::DiagonalSplit => "Diagonal split",
            Background::LinearGradient => "Linear gradient",
            Background::RadialGradient => "Radial gradient",
            Background::ConicGradient => "Conic gradient",
            Background::Stripes => "Stripes",
            Background::Checks => "Checks",
            Background::Dots => "Dots",
            Background::Rays => "Rays",
            Background::CornerWedge => "Corner wedge",
        }
    }

    /// Whether the second colour does anything. Solid ignores it, and the grid
    /// uses this to avoid rendering duplicate cells.
    pub fn uses_second_color(self) -> bool {
        self != Background::Solid
    }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Foreground {
    /// A Material Symbols glyph.
    Icon(char),
    /// Free text, e.g. the "1234" the numerics app shipped.
    Text(String),
}

#[derive(Clone, PartialEq, Debug)]
pub struct IconSpec {
    pub foreground: Foreground,
    /// Optional ribbon across the lower third. No shipped icon uses one, so
    /// the layout here is a reconstruction of the description, not of output.
    pub sub_banner: String,
    pub fg_color: NamedColor,
    pub bg_a: NamedColor,
    pub bg_b: NamedColor,
    pub background: Background,
    /// Rotation of the pattern in degrees; the shipped split runs corner to
    /// corner, which is 45.
    pub angle: f32,
    /// Foreground size as a fraction of the canvas.
    pub scale: f32,
    /// Draw the Android adaptive-icon safe zone and mask guides.
    pub show_guides: bool,
    pub filled: bool,
}

impl Default for IconSpec {
    fn default() -> Self {
        Self {
            foreground: Foreground::Icon('\u{e897}'), // lock
            sub_banner: String::new(),
            fg_color: NamedColor {
                role: "base-200",
                rgb: [0x0D, 0x2A, 0x2C],
            },
            bg_a: NamedColor {
                role: "primary",
                rgb: [0x00, 0xC9, 0xD4],
            },
            bg_b: NamedColor {
                role: "accent",
                rgb: [0xAA, 0xD4, 0x00],
            },
            background: Background::DiagonalSplit,
            angle: 45.0,
            scale: 0.58,
            show_guides: false,
            filled: false,
        }
    }
}