pelican_ui 2.1.0

Standard UI tools and components built off Pelican UI of the RAMP stack.
Documentation
use std::sync::Arc;
use image::RgbaImage;
use include_dir::include_dir;
use prism::Assets;

use std::fmt;
use std::fmt::Display;

use ptsd::{ColorResources, IconResources, FontResources};

pub use ptsd::Color;

#[derive(Debug, Clone)]
pub struct Theme(ptsd::Theme, BrandResources);
impl Theme {
    pub fn from(color: Color) -> Self { 
        let (theme, is_dark) = ptsd::Theme::from(color);
        Theme::new(theme, is_dark, color) 
    }

    pub fn dark(color: Color) -> Self { Theme::new(ptsd::Theme::dark(color), true, color) }
    pub fn light(color: Color) -> Self { Theme::new(ptsd::Theme::light(color), false, color) }

    fn new(mut inner: ptsd::Theme, is_dark: bool, color: Color) -> Self {
        Button::map(&mut inner.colors, is_dark, color);
        Theme(inner, BrandResources::default())
    }

    pub fn colors(&self) -> &ColorResources {&self.0.colors}
    pub fn icons(&self) -> &IconResources {&self.0.icons}
    pub fn fonts(&self) -> &FontResources {&self.0.fonts}
    pub fn brand(&self) -> &BrandResources {&self.1}
}

impl Default for Theme {
    fn default() -> Theme {
        let color = Color::from_hex("#00a2ff", 255);
        let inner = ptsd::Theme::dark(color);
        Theme::new(inner, true, color)
    }
}

#[derive(Clone, Debug)]
pub struct BrandResources {
    pub wordmark: Arc<RgbaImage>,
    pub logo: Arc<RgbaImage>,
    pub app_icon: Arc<RgbaImage>,
    pub error: Arc<RgbaImage>,
}

impl Default for BrandResources {
    fn default() -> Self {
        let dir = include_dir!("resources/brand");
        BrandResources {
            logo: Arc::new(Assets::load_svg(&Assets::load_file(&dir, "logo.svg").unwrap())),
            wordmark: Arc::new(Assets::load_svg(&Assets::load_file(&dir, "wordmark.svg").unwrap())),
            app_icon: Arc::new(Assets::load_svg(&Assets::load_file(&dir, "app_icon.svg").unwrap())),
            error: Arc::new(Assets::load_svg(&Assets::load_file(&dir, "error.svg").unwrap())),
        }
    }
}


#[derive(Copy, Clone, Debug)]
pub struct ButtonColors {
    pub primary: ButtonColorSet,
    pub secondary: ButtonColorSet,
    pub ghost: ButtonColorSet,
}

#[derive(Copy, Clone, Debug)]
pub struct ButtonColorSet {
    pub default: ButtonColorScheme,
    pub disabled: ButtonColorScheme,
    pub hover: ButtonColorScheme,
    pub pressed: ButtonColorScheme,
}

#[derive(Copy, Clone, Debug)]
pub struct ButtonColorScheme {
    pub background: Color,
    pub label: Color,
    pub outline: Color,
}

impl ButtonColorScheme {
    fn from(resources: &ColorResources, variant: Variant, state: State) -> Self {
        ButtonColorScheme {
            background: resources.get(Button(variant, state, Slot::Background)),
            label: resources.get(Button(variant, state, Slot::Label)),
            outline: resources.get(Button(variant, state, Slot::Outline)),
        }
    }
}


#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Variant { Primary, Secondary, Ghost }
impl Display for Variant {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f, "Variant::{}", match self {
    Variant::Primary => "Primary",
    Variant::Secondary => "Secondary",
    Variant::Ghost => "Ghost",
})}}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum State { Default, Hover, Pressed, Disabled }
impl Display for State {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f, "State::{}", match self {
    State::Default => "Default",
    State::Hover => "Hover",
    State::Pressed => "Pressed",
    State::Disabled => "Disabled",
})}}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Slot { Background, Label, Outline }
impl Display for Slot {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f, "Slot::{}", match self {
    Slot::Background => "Background",
    Slot::Label => "Label",
    Slot::Outline => "Outline",
})}}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Button(pub Variant, pub State, pub Slot);
impl Display for Button {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> 
    fmt::Result {write!(f, "Button({}, {}, {})", self.0, self.1, self.2)}}

impl Button {
    pub fn get(resources: &ColorResources, variant: Variant) -> ButtonColorSet {
        ButtonColorSet {
            default: ButtonColorScheme::from(resources, variant, State::Default),
            disabled: ButtonColorScheme::from(resources, variant, State::Disabled),
            hover: ButtonColorScheme::from(resources, variant, State::Hover),
            pressed: ButtonColorScheme::from(resources, variant, State::Pressed),
        }
    }

    fn map(resources: &mut ColorResources, is_dark: bool, brand: Color) {
        use Slot::*;
        use State::*;
        use Variant::*;

        resources.insert(Button(Primary, Default, Background), brand);
        resources.insert(Button(Primary, Default, Label), brand.contrasted());
        resources.insert(Button(Primary, Default, Outline), Color::TRANSPARENT);
        resources.insert(Button(Primary, Hover, Background), brand.darken(0.75));
        resources.insert(Button(Primary, Hover, Label), brand.contrasted());
        resources.insert(Button(Primary, Hover, Outline), Color::TRANSPARENT);
        resources.insert(Button(Primary, Pressed, Background),brand.darken(0.7));
        resources.insert(Button(Primary, Pressed, Label), brand.contrasted());
        resources.insert(Button(Primary, Pressed, Outline), Color::TRANSPARENT);
        resources.insert(Button(Primary, Disabled, Background), Color::from_hex("#443f3f", 255));
        resources.insert(Button(Primary, Disabled, Label), Color::BLACK);
        resources.insert(Button(Primary, Disabled, Outline), Color::TRANSPARENT);
    
        match is_dark {
            false => {
                resources.insert(Button(Secondary, Default, Background), Color::TRANSPARENT);
                resources.insert(Button(Secondary, Default, Label), Color::BLACK);
                resources.insert(Button(Secondary, Default, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Secondary, Hover, Background), Color::from_hex("#DDDDDD", 255));
                resources.insert(Button(Secondary, Hover, Label), Color::BLACK);
                resources.insert(Button(Secondary, Hover, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Secondary, Pressed, Background), Color::from_hex("#DDDDDD", 255));
                resources.insert(Button(Secondary, Pressed, Label), Color::BLACK);
                resources.insert(Button(Secondary, Pressed, Outline), Color::BLACK);
                resources.insert(Button(Secondary, Disabled, Background), Color::from_hex("#443f3f", 255));
                resources.insert(Button(Secondary, Disabled, Label), Color::BLACK);
                resources.insert(Button(Secondary, Disabled, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Ghost, Default, Background), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Default, Label), Color::BLACK);
                resources.insert(Button(Ghost, Default, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Hover, Background), Color::from_hex("#DDDDDD", 255));
                resources.insert(Button(Ghost, Hover, Label), Color::BLACK);
                resources.insert(Button(Ghost, Hover, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Pressed, Background), Color::from_hex("#DDDDDD", 255));
                resources.insert(Button(Ghost, Pressed, Label), Color::BLACK);
                resources.insert(Button(Ghost, Pressed, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Disabled, Background), Color::from_hex("#443f3f", 255));
                resources.insert(Button(Ghost, Disabled, Label), Color::BLACK);
                resources.insert(Button(Ghost, Disabled, Outline), Color::TRANSPARENT);
            },
            true => {
                resources.insert(Button(Secondary, Default, Background), Color::TRANSPARENT);
                resources.insert(Button(Secondary, Default, Label), Color::WHITE);
                resources.insert(Button(Secondary, Default, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Secondary, Hover, Background), Color::from_hex("#262322", 255));
                resources.insert(Button(Secondary, Hover, Label), Color::WHITE);
                resources.insert(Button(Secondary, Hover, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Secondary, Pressed, Background), Color::from_hex("#262322", 255));
                resources.insert(Button(Secondary, Pressed, Label), Color::BLACK);
                resources.insert(Button(Secondary, Pressed, Outline), Color::WHITE);
                resources.insert(Button(Secondary, Disabled, Background), Color::from_hex("#443f3f", 255));
                resources.insert(Button(Secondary, Disabled, Label), Color::BLACK);
                resources.insert(Button(Secondary, Disabled, Outline), Color::from_hex("#585250", 255));
                resources.insert(Button(Ghost, Default, Background), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Default, Label), Color::WHITE);
                resources.insert(Button(Ghost, Default, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Hover, Background), Color::from_hex("#262322", 255));
                resources.insert(Button(Ghost, Hover, Label), Color::WHITE);
                resources.insert(Button(Ghost, Hover, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Pressed, Background), Color::from_hex("#262322", 255));
                resources.insert(Button(Ghost, Pressed, Label), Color::BLACK);
                resources.insert(Button(Ghost, Pressed, Outline), Color::TRANSPARENT);
                resources.insert(Button(Ghost, Disabled, Background), Color::from_hex("#443f3f", 255));
                resources.insert(Button(Ghost, Disabled, Label), Color::BLACK);
                resources.insert(Button(Ghost, Disabled, Outline), Color::TRANSPARENT);
            }
        }
    }
}