From 35669c423cb0007d2fa577519cbbd9a7dfbfcd3d Mon Sep 17 00:00:00 2001 From: JMARyA Date: Mon, 20 Jan 2025 06:44:06 +0100 Subject: [PATCH] add border --- src/ui/mod.rs | 1 + src/ui/primitives/border.rs | 166 ++++++++++++++++++++++++++++++++++++ src/ui/primitives/flex.rs | 109 ++++++++++++++++++++++- src/ui/primitives/mod.rs | 1 + 4 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 src/ui/primitives/border.rs diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 90bb54f..3bce85f 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -23,6 +23,7 @@ pub mod prelude { pub use super::primitives::animation::{Animated, Animation, Delay, Duration, Scope, Timing}; pub use super::primitives::aspect::Aspect; pub use super::primitives::background::Background; + pub use super::primitives::border::{Border, BorderSide, BorderSize, BorderStyle}; pub use super::primitives::container::Container; pub use super::primitives::cursor::Cursor; pub use super::primitives::div::Div; diff --git a/src/ui/primitives/border.rs b/src/ui/primitives/border.rs new file mode 100644 index 0000000..12bfd56 --- /dev/null +++ b/src/ui/primitives/border.rs @@ -0,0 +1,166 @@ +use maud::{Markup, Render, html}; + +use crate::ui::{UIWidget, color::UIColor}; + +pub enum BorderSize { + _0, + _2, + _4, + _8, +} + +impl BorderSize { + pub const fn to_value(&self) -> &str { + match self { + BorderSize::_0 => "0", + BorderSize::_2 => "2", + BorderSize::_4 => "4", + BorderSize::_8 => "8", + } + } +} + +pub enum BorderSide { + X, + Y, + Start, + End, + Top, + Right, + Bottom, + Left, +} + +impl BorderSide { + pub const fn to_value(&self) -> &str { + match self { + BorderSide::X => "x", + BorderSide::Y => "y", + BorderSide::Start => "s", + BorderSide::End => "e", + BorderSide::Top => "t", + BorderSide::Right => "r", + BorderSide::Bottom => "b", + BorderSide::Left => "l", + } + } +} + +pub enum BorderStyle { + Solid, + Dashed, + Dotted, + Double, + Hidden, + None, +} + +impl BorderStyle { + pub const fn to_value(&self) -> &str { + match self { + BorderStyle::Solid => "border-solid", + BorderStyle::Dashed => "border-dashed", + BorderStyle::Dotted => "border-dotted", + BorderStyle::Double => "border-double", + BorderStyle::Hidden => "border-hidden", + BorderStyle::None => "border-none", + } + } +} + +#[allow(non_snake_case)] +pub fn Border(inner: T) -> BorderWidget { + BorderWidget(Box::new(inner), None, None, None, None) +} + +pub struct BorderWidget( + Box, + Option, + Option, + Option>, + Option, +); + +impl BorderWidget { + #[must_use] + pub fn size(mut self, size: BorderSize) -> Self { + self.1 = Some(size); + self + } + + #[must_use] + pub const fn side(mut self, side: BorderSide) -> Self { + self.2 = Some(side); + self + } + + #[must_use] + pub const fn style(mut self, style: BorderStyle) -> Self { + self.4 = Some(style); + self + } + + #[must_use] + pub fn color(mut self, color: C) -> Self { + self.3 = Some(Box::new(color)); + self + } + + fn border_class(&self) -> String { + if let Some(side) = &self.2 { + if let Some(size) = &self.1 { + return format!("border-{}-{}", side.to_value(), size.to_value()); + } + } else if let Some(size) = &self.1 { + return format!("border-{}", size.to_value()); + } + + "border".to_owned() + } +} + +impl Render for BorderWidget { + fn render(&self) -> Markup { + self.render_with_class("") + } +} + +impl UIWidget for BorderWidget { + fn can_inherit(&self) -> bool { + true + } + + fn base_class(&self) -> Vec { + let mut ret = vec![self.border_class()]; + + if let Some(color) = &self.3 { + ret.push(format!("border-{}", color.color_class())); + } + + if let Some(style) = &self.4 { + ret.push(style.to_value().to_string()); + } + + ret + } + + fn extended_class(&self) -> Vec { + let mut c = self.base_class(); + c.extend_from_slice(&self.0.extended_class()); + c + } + + fn render_with_class(&self, class: &str) -> Markup { + if self.0.as_ref().can_inherit() { + self.0 + .as_ref() + .render_with_class(&format!("{} {class}", self.base_class().join(" "))) + } else { + html! { + div class=(format!("{} {class}", self.base_class().join(" "))) { + (self.0.as_ref()) + } + } + } + } +} diff --git a/src/ui/primitives/flex.rs b/src/ui/primitives/flex.rs index b662362..2c9013a 100644 --- a/src/ui/primitives/flex.rs +++ b/src/ui/primitives/flex.rs @@ -1,11 +1,11 @@ -use crate::ui::UIWidget; +use crate::ui::{UIWidget, color::UIColor}; use maud::{Markup, Render, html}; use super::space::{Fraction, ScreenValue}; #[allow(non_snake_case)] pub fn Flex(inner: T) -> FlexWidget { - FlexWidget(Box::new(inner), vec![], false) + FlexWidget(Box::new(inner), vec![], false, None) } pub enum Justify { @@ -19,7 +19,7 @@ pub enum Justify { Stretch, } -pub struct FlexWidget(Box, Vec, bool); +pub struct FlexWidget(Box, Vec, bool, Option); impl Render for FlexWidget { fn render(&self) -> Markup { @@ -41,9 +41,65 @@ impl FlexWidget { self } + #[must_use] + pub fn divide_style(mut self, style: DivideStyle) -> Self { + self.1.push(style.to_value().to_string()); + self + } + + #[must_use] + pub fn divide_color(mut self, color: C) -> Self { + self.1.push(format!("divide-{}", color.color_class())); + self + } + + #[must_use] + pub fn divide_x(mut self, width: DivideWidth) -> Self { + let reversed = self + .3 + .as_ref() + .map(|x| match x { + Direction::Row => false, + Direction::RowReverse => true, + Direction::Column => false, + Direction::ColumnReverse => true, + }) + .unwrap_or_default(); + + self.1.push(format!("divide-x-{}", width.to_value())); + + if reversed { + self.1.push("divide-x-reverse".to_string()); + } + + self + } + + #[must_use] + pub fn divide_y(mut self, width: DivideWidth) -> Self { + let reversed = self + .3 + .as_ref() + .map(|x| match x { + Direction::Row => false, + Direction::RowReverse => true, + Direction::Column => false, + Direction::ColumnReverse => true, + }) + .unwrap_or_default(); + + self.1.push(format!("divide-y-{}", width.to_value())); + + if reversed { + self.1.push("divide-y-reverse".to_string()); + } + + self + } + #[must_use] pub fn direction(mut self, direction: Direction) -> Self { - self.1.push(format!("flex-{}", direction.to_value())); + self.3 = Some(direction); self } @@ -95,6 +151,26 @@ impl FlexWidget { } } +pub enum DivideWidth { + Custom(u64), + _0, + _2, + _4, + _8, +} + +impl DivideWidth { + pub fn to_value(&self) -> String { + match self { + DivideWidth::Custom(s) => format!("[{s}px]"), + DivideWidth::_0 => "0".to_string(), + DivideWidth::_2 => "2".to_string(), + DivideWidth::_4 => "4".to_string(), + DivideWidth::_8 => "8".to_string(), + } + } +} + pub enum Direction { Row, RowReverse, @@ -136,6 +212,11 @@ impl UIWidget for FlexWidget { fn base_class(&self) -> Vec { let mut res = vec!["flex".to_string()]; + + if let Some(direction) = &self.3 { + res.push(format!("flex-{}", direction.to_value())); + } + res.extend_from_slice(&self.1); res } @@ -399,3 +480,23 @@ impl UIWidget for OrderWidget { } } } + +pub enum DivideStyle { + Solid, + Dashed, + Dotted, + Double, + None, +} + +impl DivideStyle { + pub const fn to_value(&self) -> &str { + match self { + DivideStyle::Solid => "divide-solid", + DivideStyle::Dashed => "divide-dashed", + DivideStyle::Dotted => "divide-dotted", + DivideStyle::Double => "divide-double", + DivideStyle::None => "divide-none", + } + } +} diff --git a/src/ui/primitives/mod.rs b/src/ui/primitives/mod.rs index 25fa8b7..c2ae3dc 100644 --- a/src/ui/primitives/mod.rs +++ b/src/ui/primitives/mod.rs @@ -5,6 +5,7 @@ use super::UIWidget; pub mod animation; pub mod aspect; pub mod background; +pub mod border; pub mod container; pub mod cursor; pub mod div;