pub enum HorizontalAlignment {
Centered,
Left,
Right,
}
pub enum VerticalAlignment {
Centered,
Top,
Bottom,
}
pub mod color {
pub enum ColorError {
HueOutOfRange,
SaturationOutOfRange,
LightnessOutOfRange,
}
pub const BLACK: Color = Color::rgb(0, 0, 0);
pub const WHITE: Color = Color::rgb(255, 255, 255);
pub struct Color {
r: u8,
g: u8,
b: u8,
}
impl Color {
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b }
}
pub fn hsl(h: u16, s: f32, l: f32) -> Result<Self, ColorError> {
if h > 360 {
return Err(ColorError::HueOutOfRange);
}
if !(0. ..=1.).contains(&s) {
return Err(ColorError::SaturationOutOfRange);
}
if !(0. ..=1.).contains(&l) {
return Err(ColorError::LightnessOutOfRange);
}
let (r, g, b) = if s == 0. {
(l, l, l)
} else {
let q = if l < 0.5 {
l * (1_f32 + s)
} else {
l + s - l * s
};
let p = 2. * l - q;
(
Color::hue_to_rgb(p, q, f32::from(h) + 1. / 3.),
Color::hue_to_rgb(p, q, f32::from(h)),
Color::hue_to_rgb(p, q, f32::from(h) - 1. / 3.),
)
};
Ok(Self {
r: (r * 255.) as u8,
g: (g * 255.) as u8,
b: (b * 255.) as u8,
})
}
fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
if t < 0. {
t += 1.;
}
if t > 1. {
t -= 1.;
}
if t < 1. / 6. {
return p + (q - p) * 6. * t;
}
if t < 0.5 {
return q;
}
if t < 2. / 3. {
return p + (q - p) * (2. / 3. - t) * 6.;
}
p
}
pub fn red(&self) -> u8 {
self.r
}
pub fn blue(&self) -> u8 {
self.b
}
pub fn green(&self) -> u8 {
self.g
}
}
}
pub struct Text {
color: color::Color,
text: String,
}
impl Text {
pub fn new(text: &str) -> Self {
Self {
text: text.to_owned(),
color: color::BLACK,
}
}
pub const fn color(mut self, color: color::Color) -> Self {
self.color = color;
self
}
pub fn text(&self) -> &str {
&self.text
}
}
pub struct CellLayout {
horizontal_alignment: HorizontalAlignment,
vertical_alignment: VerticalAlignment,
horizontal_offset: i32,
vertical_offset: i32,
text: Option<Text>,
}
impl CellLayout {
pub fn centered() -> Self {
Self {
horizontal_alignment: HorizontalAlignment::Centered,
vertical_alignment: VerticalAlignment::Centered,
horizontal_offset: 0,
vertical_offset: 0,
text: None,
}
}
pub fn text(mut self, text: Text) -> Self {
self.text = Some(text);
self
}
pub fn align_horizontally(mut self, horizontal_alignment: HorizontalAlignment) -> Self {
self.horizontal_alignment = horizontal_alignment;
self
}
pub fn align_vertically(mut self, vertical_alignment: VerticalAlignment) -> Self {
self.vertical_alignment = vertical_alignment;
self
}
pub fn offset_horizontally(mut self, horizontal_offset: i32) -> Self {
self.horizontal_offset = horizontal_offset;
self
}
pub fn offset_vertically(mut self, vertical_offset: i32) -> Self {
self.vertical_offset = vertical_offset;
self
}
}
pub enum Layout {
Column(Column),
Row(Vec<Box<dyn Component>>),
Grid(Vec<Vec<Box<dyn Component>>>),
Cell(CellLayout),
}
pub struct Column {
components: Vec<Box<dyn Component>>,
}
impl Column {
pub fn add_to_bottom(&mut self, component: Box<dyn Component>) {
self.components.push(component);
}
pub fn add_to_top(&mut self, component: Box<dyn Component>) {
let mut components = vec![component];
components.append(&mut self.components);
self.components = components;
}
pub fn into_layout(self) -> Layout {
self.into()
}
}
impl From<Column> for Layout {
fn from(value: Column) -> Self {
Self::Column(value)
}
}
pub trait Component {
fn layout(&self) -> &Layout;
fn update(&mut self) {}
fn on_mouse_down(&mut self) {}
fn on_mouse_up(&mut self) {}
fn on_key_down(&mut self) {}
fn on_key_up(&mut self) {}
fn on_right_mouse_down(&mut self) {}
fn on_right_mouse_up(&mut self) {}
}