use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: f32,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Font {
pub name: String,
pub size: f32,
pub bold: bool,
pub italic: bool,
pub underline: bool,
}
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
pub struct Padding {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
pub struct Border {
pub width: f32,
pub color: Color,
pub radius: f32,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Style {
pub background: Option<Color>,
pub foreground: Option<Color>,
pub font: Option<Font>,
pub padding: Option<Padding>,
pub border: Option<Border>,
pub width: Option<f32>,
pub height: Option<f32>,
pub horizontal_align: Option<Alignment>,
pub vertical_align: Option<Alignment>,
}
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
pub enum Alignment {
Start,
Center,
End,
}
impl Color {
pub fn new(r: u8, g: u8, b: u8, a: f32) -> Self {
Self { r, g, b, a: a.clamp(0.0, 1.0) }
}
pub fn rgb(r: u8, g: u8, b: u8) -> Self {
Self::new(r, g, b, 1.0)
}
pub fn rgba(r: u8, g: u8, b: u8, a: f32) -> Self {
Self::new(r, g, b, a)
}
pub const BLACK: Self = Self { r: 0, g: 0, b: 0, a: 1.0 };
pub const WHITE: Self = Self { r: 255, g: 255, b: 255, a: 1.0 };
pub const RED: Self = Self { r: 255, g: 0, b: 0, a: 1.0 };
pub const GREEN: Self = Self { r: 0, g: 255, b: 0, a: 1.0 };
pub const BLUE: Self = Self { r: 0, g: 0, b: 255, a: 1.0 };
pub const YELLOW: Self = Self { r: 255, g: 255, b: 0, a: 1.0 };
pub const CYAN: Self = Self { r: 0, g: 255, b: 255, a: 1.0 };
pub const MAGENTA: Self = Self { r: 255, g: 0, b: 255, a: 1.0 };
pub const GRAY: Self = Self { r: 128, g: 128, b: 128, a: 1.0 };
pub const LIGHT_GRAY: Self = Self { r: 200, g: 200, b: 200, a: 1.0 };
pub const DARK_GRAY: Self = Self { r: 64, g: 64, b: 64, a: 1.0 };
}
impl Font {
pub fn new(name: &str, size: f32, bold: bool, italic: bool, underline: bool) -> Self {
Self { name: name.to_string(), size: size.max(1.0), bold, italic, underline }
}
pub fn default() -> Self {
Self::new("Arial", 14.0, false, false, false)
}
}
impl Padding {
pub fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
Self { top: top.max(0.0), right: right.max(0.0), bottom: bottom.max(0.0), left: left.max(0.0) }
}
pub fn symmetric(vertical: f32, horizontal: f32) -> Self {
Self::new(vertical, horizontal, vertical, horizontal)
}
pub fn uniform(all: f32) -> Self {
Self::new(all, all, all, all)
}
pub const DEFAULT: Self = Self { top: 8.0, right: 8.0, bottom: 8.0, left: 8.0 };
}
impl Border {
pub fn new(width: f32, color: Color, radius: f32) -> Self {
Self { width: width.max(0.0), color, radius: radius.max(0.0) }
}
pub fn default() -> Self {
Self::new(1.0, Color::GRAY, 0.0)
}
}
impl Style {
pub fn new() -> Self {
Self {
background: None,
foreground: None,
font: None,
padding: None,
border: None,
width: None,
height: None,
horizontal_align: None,
vertical_align: None,
}
}
pub fn with_background(mut self, color: Color) -> Self {
self.background = Some(color);
self
}
pub fn with_foreground(mut self, color: Color) -> Self {
self.foreground = Some(color);
self
}
pub fn with_font(mut self, font: Font) -> Self {
self.font = Some(font);
self
}
pub fn with_padding(mut self, padding: Padding) -> Self {
self.padding = Some(padding);
self
}
pub fn with_border(mut self, border: Border) -> Self {
self.border = Some(border);
self
}
pub fn with_width(mut self, width: f32) -> Self {
self.width = Some(width.max(0.0));
self
}
pub fn with_height(mut self, height: f32) -> Self {
self.height = Some(height.max(0.0));
self
}
pub fn with_horizontal_align(mut self, align: Alignment) -> Self {
self.horizontal_align = Some(align);
self
}
pub fn with_vertical_align(mut self, align: Alignment) -> Self {
self.vertical_align = Some(align);
self
}
pub fn default() -> Self {
Self::new()
}
}