scrin 0.1.82

A terminal UI toolkit with panes, widgets, overlays, animations, and Aisling-powered effects/loaders.
Documentation
use crate::core::color::Color;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Modifier(pub u16);

impl Modifier {
    pub const NONE: Self = Self(0);
    pub const BOLD: Self = Self(1 << 0);
    pub const DIM: Self = Self(1 << 1);
    pub const ITALIC: Self = Self(1 << 2);
    pub const UNDERLINED: Self = Self(1 << 3);
    pub const REVERSED: Self = Self(1 << 4);
    pub const CROSSED_OUT: Self = Self(1 << 5);

    pub const fn empty() -> Self {
        Self::NONE
    }

    pub const fn contains(self, other: Self) -> bool {
        self.0 & other.0 == other.0
    }

    pub const fn union(self, other: Self) -> Self {
        Self(self.0 | other.0)
    }

    pub const fn remove(self, other: Self) -> Self {
        Self(self.0 & !other.0)
    }
}

impl std::ops::BitOr for Modifier {
    type Output = Modifier;

    fn bitor(self, rhs: Self) -> Self::Output {
        self.union(rhs)
    }
}

impl std::ops::BitOrAssign for Modifier {
    fn bitor_assign(&mut self, rhs: Self) {
        *self = self.union(rhs);
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Style {
    pub fg: Option<Color>,
    pub bg: Option<Color>,
    pub bold: bool,
    pub italic: bool,
    pub underlined: bool,
    pub dim: bool,
    pub add_modifier: Modifier,
    pub sub_modifier: Modifier,
}

impl Style {
    pub const fn new() -> Self {
        Self {
            fg: None,
            bg: None,
            bold: false,
            italic: false,
            underlined: false,
            dim: false,
            add_modifier: Modifier::NONE,
            sub_modifier: Modifier::NONE,
        }
    }

    pub const fn fg(mut self, fg: Color) -> Self {
        self.fg = Some(fg);
        self
    }

    pub const fn bg(mut self, bg: Color) -> Self {
        self.bg = Some(bg);
        self
    }

    pub const fn bold(mut self) -> Self {
        self.bold = true;
        self.add_modifier = self.add_modifier.union(Modifier::BOLD);
        self
    }

    pub const fn italic(mut self) -> Self {
        self.italic = true;
        self.add_modifier = self.add_modifier.union(Modifier::ITALIC);
        self
    }

    pub const fn underlined(mut self) -> Self {
        self.underlined = true;
        self.add_modifier = self.add_modifier.union(Modifier::UNDERLINED);
        self
    }

    pub const fn dim(mut self) -> Self {
        self.dim = true;
        self.add_modifier = self.add_modifier.union(Modifier::DIM);
        self
    }

    pub const fn reversed(mut self) -> Self {
        self.add_modifier = self.add_modifier.union(Modifier::REVERSED);
        self
    }

    pub const fn crossed_out(mut self) -> Self {
        self.add_modifier = self.add_modifier.union(Modifier::CROSSED_OUT);
        self
    }

    pub const fn add_modifier(mut self, modifier: Modifier) -> Self {
        self.add_modifier = self.add_modifier.union(modifier);
        self
    }

    pub const fn remove_modifier(mut self, modifier: Modifier) -> Self {
        self.sub_modifier = self.sub_modifier.union(modifier);
        self.add_modifier = self.add_modifier.remove(modifier);
        self
    }

    pub fn merge(&self, other: &Style) -> Style {
        Style {
            fg: other.fg.or(self.fg),
            bg: other.bg.or(self.bg),
            bold: self.bold || other.bold,
            italic: self.italic || other.italic,
            underlined: self.underlined || other.underlined,
            dim: self.dim || other.dim,
            add_modifier: self
                .add_modifier
                .union(other.add_modifier)
                .remove(other.sub_modifier),
            sub_modifier: self.sub_modifier.union(other.sub_modifier),
        }
    }

    pub fn fg_or_default(&self) -> Color {
        self.fg.unwrap_or(Color::WHITE)
    }
}

impl Default for Style {
    fn default() -> Self {
        Self::new()
    }
}

impl From<Color> for Style {
    fn from(c: Color) -> Self {
        Style::new().fg(c)
    }
}